From 02b6f95be2f8370445b181594f3adaae734ee7a2 Mon Sep 17 00:00:00 2001 From: jxnu-liguobin Date: Thu, 14 Dec 2023 10:43:58 +0800 Subject: [PATCH 1/6] CreateView with comment for mysql --- .../sf/jsqlparser/parser/feature/Feature.java | 6 ++ .../view/ColumnWithCommentExpression.java | 58 ++++++++++++++++++ .../statement/create/view/CreateView.java | 30 ++++++--- .../util/deparser/CreateViewDeParser.java | 4 ++ .../validation/feature/MariaDbVersion.java | 21 ++++--- .../util/validation/feature/MySqlVersion.java | 13 ++-- .../validator/CreateViewValidator.java | 2 + .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 61 ++++++++++++++++++- .../statement/create/CreateViewTest.java | 36 ++++++++--- .../validator/CreateViewValidatorTest.java | 17 +++++- 10 files changed, 213 insertions(+), 35 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/statement/create/view/ColumnWithCommentExpression.java diff --git a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java index 3d5825f5d..b59191844 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java @@ -483,6 +483,12 @@ public enum Feature { * SQL "CREATE MATERIALIZED VIEW" statement is allowed */ createViewMaterialized, + + /** + * SQL "CREATE VIEW(x comment 'x', y comment 'y') comment 'view'" statement is allowed + */ + createViewWithComment, + /** * SQL "CREATE TABLE" statement is allowed * diff --git a/src/main/java/net/sf/jsqlparser/statement/create/view/ColumnWithCommentExpression.java b/src/main/java/net/sf/jsqlparser/statement/create/view/ColumnWithCommentExpression.java new file mode 100644 index 000000000..0ef3773c2 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/create/view/ColumnWithCommentExpression.java @@ -0,0 +1,58 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2019 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.statement.create.view; + +import java.io.Serializable; + +public class ColumnWithCommentExpression implements Serializable { + + private String columnName; + private String commentText; + + @Override + public String toString() { + StringBuilder b = new StringBuilder(); + if (columnName != null) { + b.append(columnName); + } + if (commentText != null) { + b.append(" COMMENT "); + b.append(commentText); + } + return b.toString(); + } + + public String getColumnName() { + return columnName; + } + + public void setColumnName(String columnName) { + this.columnName = columnName; + } + + public String getCommentText() { + return commentText; + } + + public void setCommentText(String commentText) { + this.commentText = commentText; + } + + public ColumnWithCommentExpression withCommentText(String commentText) { + setCommentText(commentText); + return this; + } + + public ColumnWithCommentExpression withColumnName(String columnName) { + setColumnName(columnName); + return this; + } + +} diff --git a/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java b/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java index a623beb41..7bfe71cad 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java @@ -25,13 +25,14 @@ public class CreateView implements Statement { private Table view; private Select select; private boolean orReplace = false; - private List columnNames = null; + private List columnNames = null; private boolean materialized = false; private ForceOption force = ForceOption.NONE; private TemporaryOption temp = TemporaryOption.NONE; private AutoRefreshOption autoRefresh = AutoRefreshOption.NONE; private boolean withReadOnly = false; private boolean ifNotExists = false; + private List viewCommentOptions = null; @Override public void accept(StatementVisitor statementVisitor) { @@ -65,11 +66,11 @@ public void setSelect(Select select) { this.select = select; } - public List getColumnNames() { + public List getColumnNames() { return columnNames; } - public void setColumnNames(List columnNames) { + public void setColumnNames(List columnNames) { this.columnNames = columnNames; } @@ -147,6 +148,9 @@ public String toString() { if (columnNames != null) { sql.append(PlainSelect.getStringList(columnNames, true, true)); } + if (viewCommentOptions != null) { + sql.append(PlainSelect.getStringList(viewCommentOptions, false, false)); + } sql.append(" AS ").append(select); if (isWithReadOnly()) { sql.append(" WITH READ ONLY"); @@ -182,7 +186,7 @@ public CreateView withOrReplace(boolean orReplace) { return this; } - public CreateView withColumnNames(List columnNames) { + public CreateView withColumnNames(List columnNames) { this.setColumnNames(columnNames); return this; } @@ -202,15 +206,25 @@ public CreateView withWithReadOnly(boolean withReadOnly) { return this; } - public CreateView addColumnNames(String... columnNames) { - List collection = Optional.ofNullable(getColumnNames()).orElseGet(ArrayList::new); + public CreateView addColumnNames(ColumnWithCommentExpression... columnNames) { + List collection = + Optional.ofNullable(getColumnNames()).orElseGet(ArrayList::new); Collections.addAll(collection, columnNames); return this.withColumnNames(collection); } - public CreateView addColumnNames(Collection columnNames) { - List collection = Optional.ofNullable(getColumnNames()).orElseGet(ArrayList::new); + public CreateView addColumnNames(Collection columnNames) { + List collection = + Optional.ofNullable(getColumnNames()).orElseGet(ArrayList::new); collection.addAll(columnNames); return this.withColumnNames(collection); } + + public List getViewCommentOptions() { + return viewCommentOptions; + } + + public void setViewCommentOptions(List viewCommentOptions) { + this.viewCommentOptions = viewCommentOptions; + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java index 13973b06e..cce764f6b 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java @@ -69,6 +69,10 @@ public void deParse(CreateView createView) { if (createView.getColumnNames() != null) { buffer.append(PlainSelect.getStringList(createView.getColumnNames(), true, true)); } + if (createView.getViewCommentOptions() != null) { + buffer.append( + PlainSelect.getStringList(createView.getViewCommentOptions(), false, false)); + } buffer.append(" AS "); Select select = createView.getSelect(); diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java index 185da5664..983adb4fd 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/MariaDbVersion.java @@ -9,11 +9,10 @@ */ package net.sf.jsqlparser.util.validation.feature; -import net.sf.jsqlparser.parser.feature.Feature; - import java.util.Collections; import java.util.EnumSet; import java.util.Set; +import net.sf.jsqlparser.parser.feature.Feature; /** * Please add Features supported and place a link to public documentation @@ -41,7 +40,8 @@ public enum MariaDbVersion implements Version { Feature.selectForUpdateSkipLocked, // https://mariadb.com/kb/en/join-syntax/ - Feature.join, Feature.joinSimple, Feature.joinRight, Feature.joinNatural, Feature.joinLeft, + Feature.join, Feature.joinSimple, Feature.joinRight, Feature.joinNatural, + Feature.joinLeft, Feature.joinCross, Feature.joinOuter, Feature.joinInner, Feature.joinStraight, Feature.joinUsingColumns, @@ -64,8 +64,10 @@ public enum MariaDbVersion implements Version { // https://mariadb.com/kb/en/insert/ Feature.insert, Feature.insertValues, Feature.values, - Feature.insertFromSelect, Feature.insertModifierPriority, Feature.insertModifierIgnore, - Feature.insertUseSet, Feature.insertUseDuplicateKeyUpdate, Feature.insertReturningExpressionList, + Feature.insertFromSelect, Feature.insertModifierPriority, + Feature.insertModifierIgnore, + Feature.insertUseSet, Feature.insertUseDuplicateKeyUpdate, + Feature.insertReturningExpressionList, // https://mariadb.com/kb/en/update/ Feature.update, @@ -96,7 +98,8 @@ public enum MariaDbVersion implements Version { Feature.dropView, // https://mariadb.com/kb/en/drop-sequence/ Feature.dropSequence, Feature.dropTableIfExists, Feature.dropIndexIfExists, - Feature.dropViewIfExists, Feature.dropSchemaIfExists, Feature.dropSequenceIfExists, + Feature.dropViewIfExists, Feature.dropSchemaIfExists, + Feature.dropSequenceIfExists, // https://mariadb.com/kb/en/replace/ Feature.upsert, @@ -110,9 +113,11 @@ public enum MariaDbVersion implements Version { // https://mariadb.com/kb/en/create-view/ Feature.createView, Feature.createOrReplaceView, + Feature.createViewWithComment, // https://mariadb.com/kb/en/create-table/ - Feature.createTable, Feature.createTableCreateOptionStrings, Feature.createTableTableOptionStrings, + Feature.createTable, Feature.createTableCreateOptionStrings, + Feature.createTableTableOptionStrings, Feature.createTableFromSelect, Feature.createTableIfNotExists, // https://mariadb.com/kb/en/create-index/ Feature.createIndex, @@ -143,7 +148,7 @@ public enum MariaDbVersion implements Version { Feature.commit, // https://mariadb.com/kb/en/optimizer-hints/ Feature.mySqlHintStraightJoin, - Feature.mysqlCalcFoundRows, + Feature.mysqlCalcFoundRows, Feature.mysqlSqlCacheFlag)), ORACLE_MODE("oracle_mode", V10_5_4.copy().add(Feature.selectUnique).getFeatures()); diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java index 01bbce4c1..d631344d8 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/MySqlVersion.java @@ -9,11 +9,10 @@ */ package net.sf.jsqlparser.util.validation.feature; -import net.sf.jsqlparser.parser.feature.Feature; - import java.util.Collections; import java.util.EnumSet; import java.util.Set; +import net.sf.jsqlparser.parser.feature.Feature; /** * Please add Features supported and place a link to public documentation @@ -33,7 +32,8 @@ public enum MySqlVersion implements Version { // https://dev.mysql.com/doc/refman/8.0/en/select.html Feature.select, Feature.selectGroupBy, Feature.selectHaving, - Feature.limit, Feature.limitOffset, Feature.offset, Feature.offsetParam, Feature.orderBy, + Feature.limit, Feature.limitOffset, Feature.offset, Feature.offsetParam, + Feature.orderBy, Feature.selectForUpdate, Feature.selectForUpdateOfTable, Feature.selectForUpdateNoWait, @@ -51,7 +51,8 @@ public enum MySqlVersion implements Version { Feature.function, // https://dev.mysql.com/doc/refman/8.0/en/join.html - Feature.join, Feature.joinSimple, Feature.joinLeft, Feature.joinRight, Feature.joinOuter, + Feature.join, Feature.joinSimple, Feature.joinLeft, Feature.joinRight, + Feature.joinOuter, Feature.joinNatural, Feature.joinInner, Feature.joinCross, Feature.joinStraight, Feature.joinUsingColumns, @@ -99,9 +100,11 @@ public enum MySqlVersion implements Version { Feature.createSchema, // https://dev.mysql.com/doc/refman/8.0/en/create-view.html Feature.createView, + Feature.createViewWithComment, Feature.createOrReplaceView, // https://dev.mysql.com/doc/refman/8.0/en/create-table.html - Feature.createTable, Feature.createTableCreateOptionStrings, Feature.createTableTableOptionStrings, + Feature.createTable, Feature.createTableCreateOptionStrings, + Feature.createTableTableOptionStrings, Feature.createTableFromSelect, Feature.createTableIfNotExists, // https://dev.mysql.com/doc/refman/8.0/en/create-index.html Feature.createIndex, diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidator.java index 2723cfc25..e2910ada3 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidator.java @@ -33,6 +33,8 @@ public void validate(CreateView createView) { Feature.createViewTemporary); validateFeature(c, createView.isMaterialized(), Feature.createViewMaterialized); validateName(c, NamedObject.view, createView.getView().getFullyQualifiedName(), false); + validateFeature(c, createView.getViewCommentOptions() != null, + Feature.createViewWithComment); } SelectValidator v = getValidator(SelectValidator.class); Select select = createView.getSelect(); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 2045dfdda..27c21543e 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5705,13 +5705,46 @@ Analyze Analyze(): } } +ColumnWithCommentExpression ColumnWithCommentExpressionItem(): +{ + Token tk = null; + String item = null; + ColumnWithCommentExpression columnWithCommentExp = new ColumnWithCommentExpression(); +} +{ + ( item = RelObjectName() { columnWithCommentExp.withColumnName(item); } ) + [ + tk= { columnWithCommentExp.withColumnName(item).withCommentText(tk.image); } + ] + { + return columnWithCommentExp; + } +} + +List ColumnWithCommentExpressionItemList(): +{ + List retval = new ArrayList(); + ColumnWithCommentExpression img = null; +} +{ + "(" + img = ColumnWithCommentExpressionItem() { retval.add(img); } + ( "," img=ColumnWithCommentExpressionItem() { retval.add(img); } )* + + ")" + { + return retval; + } +} + CreateView CreateView(boolean isUsingOrReplace): { CreateView createView = new CreateView(); Table view = null; Select select = null; - List columnNames = null; + List columnNames = null; Token tk = null; + List commentTokens = null; } { { createView.setOrReplace(isUsingOrReplace);} @@ -5727,13 +5760,36 @@ CreateView CreateView(boolean isUsingOrReplace): view=Table() { createView.setView(view); } [LOOKAHEAD(3) (tk= | tk=) { createView.setAutoRefresh(AutoRefreshOption.from(tk.image)); } ] [LOOKAHEAD(3) {createView.setIfNotExists(true);}] - [ columnNames = ColumnsNamesList() { createView.setColumnNames(columnNames); } ] + [ columnNames = ColumnWithCommentExpressionItemList( ) { createView.setColumnNames(columnNames); } ] + [ commentTokens=CreateViewTailComment( ) { createView.setViewCommentOptions(commentTokens);} ] select=Select( ) { createView.setSelect(select); } [ { createView.setWithReadOnly(true); } ] { return createView; } } +List CreateViewTailComment(): +{ + Token tk = null; + Token tk2 = null; + String op = null; + List result = new ArrayList(); +} +{ + tk= + [ "=" { op = "="; } ] + tk2 = { + result.add(""); + result.add(tk.image); + if (op != null) { + result.add(op); + } + result.add(tk2.image); + } + { return result;} +} + + ReferentialAction.Action Action(): { ReferentialAction.Action action = null; @@ -5778,7 +5834,6 @@ List CreateParameter(): Token tk = null, tk2 = null; Expression exp = null; ColDataType colDataType; - List param = new ArrayList(); } { diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java index 3499a83be..3488dff08 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java @@ -9,8 +9,14 @@ */ package net.sf.jsqlparser.statement.create; -import java.io.StringReader; +import static net.sf.jsqlparser.test.TestUtils.*; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.StringReader; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.parser.CCJSqlParserManager; import net.sf.jsqlparser.parser.CCJSqlParserUtil; @@ -20,14 +26,7 @@ import net.sf.jsqlparser.statement.create.view.CreateView; import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.PlainSelect; -import static net.sf.jsqlparser.test.TestUtils.*; -import static org.assertj.core.api.Assertions.assertThatThrownBy; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; - import org.assertj.core.api.ThrowableAssert.ThrowingCallable; -import static org.junit.jupiter.api.Assertions.assertTrue; - import org.junit.jupiter.api.Test; public class CreateViewTest { @@ -212,4 +211,25 @@ public void testCreateMaterializedViewIfNotExists() throws JSQLParserException { assertTrue(createView.isIfNotExists()); } + @Test + public void testCreateViewWithColumnComment() throws JSQLParserException { + String stmt = + "CREATE VIEW v14(c1 COMMENT 'comment1', c2 COMMENT 'comment2') AS SELECT c1, C2 FROM t1 WITH READ ONLY"; + assertSqlCanBeParsedAndDeparsed(stmt); + } + + @Test + public void testCreateViewWithTableComment1() throws JSQLParserException { + String stmt = + "CREATE VIEW v14(c1 COMMENT 'comment1', c2 COMMENT 'comment2') COMMENT 'view' AS SELECT c1, C2 FROM t1 WITH READ ONLY"; + assertSqlCanBeParsedAndDeparsed(stmt); + } + + @Test + public void testCreateViewWithTableComment2() throws JSQLParserException { + String stmt = + "CREATE VIEW v14(c1 COMMENT 'comment1', c2 COMMENT 'comment2') COMMENT = 'view' AS SELECT c1, C2 FROM t1 WITH READ ONLY"; + assertSqlCanBeParsedAndDeparsed(stmt); + } + } diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidatorTest.java index 92d4cd294..4c94bd041 100644 --- a/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidatorTest.java +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/CreateViewValidatorTest.java @@ -37,18 +37,21 @@ public void testValidateCreateViewNotAllowed() throws JSQLParserException { @Test public void testValidateCreateViewMaterialized() throws JSQLParserException { - validateNoErrors("CREATE MATERIALIZED VIEW myview AS SELECT * FROM mytab", 1, DatabaseType.ORACLE); + validateNoErrors("CREATE MATERIALIZED VIEW myview AS SELECT * FROM mytab", 1, + DatabaseType.ORACLE); } @Test public void testValidateCreateOrReplaceView() throws JSQLParserException { - validateNoErrors("CREATE OR REPLACE VIEW myview AS SELECT * FROM mytab", 1, DatabaseType.ORACLE, + validateNoErrors("CREATE OR REPLACE VIEW myview AS SELECT * FROM mytab", 1, + DatabaseType.ORACLE, DatabaseType.POSTGRESQL, DatabaseType.MYSQL, DatabaseType.MARIADB, DatabaseType.H2); } @Test public void testValidateCreateForceView() throws JSQLParserException { - validateNoErrors("CREATE FORCE VIEW myview AS SELECT * FROM mytab", 1, DatabaseType.ORACLE, DatabaseType.H2); + validateNoErrors("CREATE FORCE VIEW myview AS SELECT * FROM mytab", 1, DatabaseType.ORACLE, + DatabaseType.H2); } @Test @@ -66,4 +69,12 @@ public void testValidateCreateViewWith() throws JSQLParserException { validateNoErrors(sql, 1, DatabaseType.DATABASES); } } + + @Test + public void testValidateCreateViewWithComment() throws JSQLParserException { + validateNoErrors( + "CREATE VIEW v14(c1 COMMENT 'comment1', c2 COMMENT 'comment2') COMMENT = 'view' AS SELECT c1, C2 FROM t1 WITH READ ONLY", + 1, + DatabaseType.MYSQL, DatabaseType.MARIADB); + } } From 4b84142596df35326423ca5ecba179a38d1fa3d6 Mon Sep 17 00:00:00 2001 From: jxnu-liguobin Date: Thu, 14 Dec 2023 10:51:07 +0800 Subject: [PATCH 2/6] Add test --- .../sf/jsqlparser/statement/create/CreateViewTest.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java index 3488dff08..a3ad4a79c 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java @@ -216,6 +216,14 @@ public void testCreateViewWithColumnComment() throws JSQLParserException { String stmt = "CREATE VIEW v14(c1 COMMENT 'comment1', c2 COMMENT 'comment2') AS SELECT c1, C2 FROM t1 WITH READ ONLY"; assertSqlCanBeParsedAndDeparsed(stmt); + + String stmt2 = + "CREATE VIEW v14(c1 COMMENT 'comment1', c2) AS SELECT c1, C2 FROM t1 WITH READ ONLY"; + assertSqlCanBeParsedAndDeparsed(stmt2); + + String stmt3 = + "CREATE VIEW v14(c1, c2) COMMENT = 'view' AS SELECT c1, C2 FROM t1 WITH READ ONLY"; + assertSqlCanBeParsedAndDeparsed(stmt3); } @Test From 7cad552fc8889124d1dae042f1a30b801459c086 Mon Sep 17 00:00:00 2001 From: jxnu-liguobin Date: Thu, 14 Dec 2023 11:52:22 +0800 Subject: [PATCH 3/6] Fix --- .../create/table/ColumnDefinition.java | 11 +++- .../view/ColumnWithCommentExpression.java | 58 ------------------- .../statement/create/view/CreateView.java | 17 +++--- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 32 +++++----- 4 files changed, 35 insertions(+), 83 deletions(-) delete mode 100644 src/main/java/net/sf/jsqlparser/statement/create/view/ColumnWithCommentExpression.java diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java b/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java index f19962d8e..b41f3df58 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java @@ -9,14 +9,13 @@ */ package net.sf.jsqlparser.statement.create.table; -import net.sf.jsqlparser.statement.select.PlainSelect; - import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; +import net.sf.jsqlparser.statement.select.PlainSelect; /** * Globally used definition class for columns. @@ -65,10 +64,18 @@ public void setColumnName(String string) { @Override public String toString() { + String spec = toStringDataTypeAndSpec(); + if (spec.isEmpty()) { + return columnName; + } return columnName + " " + toStringDataTypeAndSpec(); } public String toStringDataTypeAndSpec() { + if (colDataType == null) { + return (columnSpecs == null || columnSpecs.isEmpty() ? "" + : PlainSelect.getStringList(columnSpecs, false, false)); + } return colDataType + (columnSpecs != null && !columnSpecs.isEmpty() ? " " + PlainSelect.getStringList(columnSpecs, false, false) : ""); diff --git a/src/main/java/net/sf/jsqlparser/statement/create/view/ColumnWithCommentExpression.java b/src/main/java/net/sf/jsqlparser/statement/create/view/ColumnWithCommentExpression.java deleted file mode 100644 index 0ef3773c2..000000000 --- a/src/main/java/net/sf/jsqlparser/statement/create/view/ColumnWithCommentExpression.java +++ /dev/null @@ -1,58 +0,0 @@ -/*- - * #%L - * JSQLParser library - * %% - * Copyright (C) 2004 - 2019 JSQLParser - * %% - * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 - * #L% - */ -package net.sf.jsqlparser.statement.create.view; - -import java.io.Serializable; - -public class ColumnWithCommentExpression implements Serializable { - - private String columnName; - private String commentText; - - @Override - public String toString() { - StringBuilder b = new StringBuilder(); - if (columnName != null) { - b.append(columnName); - } - if (commentText != null) { - b.append(" COMMENT "); - b.append(commentText); - } - return b.toString(); - } - - public String getColumnName() { - return columnName; - } - - public void setColumnName(String columnName) { - this.columnName = columnName; - } - - public String getCommentText() { - return commentText; - } - - public void setCommentText(String commentText) { - this.commentText = commentText; - } - - public ColumnWithCommentExpression withCommentText(String commentText) { - setCommentText(commentText); - return this; - } - - public ColumnWithCommentExpression withColumnName(String columnName) { - setColumnName(columnName); - return this; - } - -} diff --git a/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java b/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java index 7bfe71cad..acd6e9809 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java @@ -17,6 +17,7 @@ import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.create.table.ColumnDefinition; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; @@ -25,7 +26,7 @@ public class CreateView implements Statement { private Table view; private Select select; private boolean orReplace = false; - private List columnNames = null; + private List columnNames = null; private boolean materialized = false; private ForceOption force = ForceOption.NONE; private TemporaryOption temp = TemporaryOption.NONE; @@ -66,11 +67,11 @@ public void setSelect(Select select) { this.select = select; } - public List getColumnNames() { + public List getColumnNames() { return columnNames; } - public void setColumnNames(List columnNames) { + public void setColumnNames(List columnNames) { this.columnNames = columnNames; } @@ -186,7 +187,7 @@ public CreateView withOrReplace(boolean orReplace) { return this; } - public CreateView withColumnNames(List columnNames) { + public CreateView withColumnNames(List columnNames) { this.setColumnNames(columnNames); return this; } @@ -206,15 +207,15 @@ public CreateView withWithReadOnly(boolean withReadOnly) { return this; } - public CreateView addColumnNames(ColumnWithCommentExpression... columnNames) { - List collection = + public CreateView addColumnNames(ColumnDefinition... columnNames) { + List collection = Optional.ofNullable(getColumnNames()).orElseGet(ArrayList::new); Collections.addAll(collection, columnNames); return this.withColumnNames(collection); } - public CreateView addColumnNames(Collection columnNames) { - List collection = + public CreateView addColumnNames(Collection columnNames) { + List collection = Optional.ofNullable(getColumnNames()).orElseGet(ArrayList::new); collection.addAll(columnNames); return this.withColumnNames(collection); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 27c21543e..f479dccfa 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5705,33 +5705,35 @@ Analyze Analyze(): } } -ColumnWithCommentExpression ColumnWithCommentExpressionItem(): +ColumnDefinition ColumnDefinitionItem(): { Token tk = null; + Token tk2 = null; String item = null; - ColumnWithCommentExpression columnWithCommentExp = new ColumnWithCommentExpression(); + ColumnDefinition columnWithComment = new ColumnDefinition(); } { - ( item = RelObjectName() { columnWithCommentExp.withColumnName(item); } ) + ( item = RelObjectName() { columnWithComment.withColumnName(item); } ) [ - tk= { columnWithCommentExp.withColumnName(item).withCommentText(tk.image); } + tk= tk2= { + columnWithComment.addColumnSpecs(tk.image).addColumnSpecs(tk2.image); + } ] { - return columnWithCommentExp; + return columnWithComment; } } -List ColumnWithCommentExpressionItemList(): +List ColumnDefinitionItemList(): { - List retval = new ArrayList(); - ColumnWithCommentExpression img = null; + List retval = new ArrayList(); + ColumnDefinition img = null; } { - "(" - img = ColumnWithCommentExpressionItem() { retval.add(img); } - ( "," img=ColumnWithCommentExpressionItem() { retval.add(img); } )* - - ")" + "(" + img = ColumnDefinitionItem() { retval.add(img); } + ( "," img=ColumnDefinitionItem() { retval.add(img); } )* + ")" { return retval; } @@ -5742,7 +5744,7 @@ CreateView CreateView(boolean isUsingOrReplace): CreateView createView = new CreateView(); Table view = null; Select select = null; - List columnNames = null; + List columnNames = null; Token tk = null; List commentTokens = null; } @@ -5760,7 +5762,7 @@ CreateView CreateView(boolean isUsingOrReplace): view=Table() { createView.setView(view); } [LOOKAHEAD(3) (tk= | tk=) { createView.setAutoRefresh(AutoRefreshOption.from(tk.image)); } ] [LOOKAHEAD(3) {createView.setIfNotExists(true);}] - [ columnNames = ColumnWithCommentExpressionItemList( ) { createView.setColumnNames(columnNames); } ] + [ columnNames = ColumnDefinitionItemList( ) { createView.setColumnNames(columnNames); } ] [ commentTokens=CreateViewTailComment( ) { createView.setViewCommentOptions(commentTokens);} ] select=Select( ) { createView.setSelect(select); } From a0a7525736949335c5e2489749bfd4a14865f98e Mon Sep 17 00:00:00 2001 From: jxnu-liguobin Date: Thu, 14 Dec 2023 11:54:51 +0800 Subject: [PATCH 4/6] Fix --- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index f479dccfa..5f56221db 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -5713,12 +5713,8 @@ ColumnDefinition ColumnDefinitionItem(): ColumnDefinition columnWithComment = new ColumnDefinition(); } { - ( item = RelObjectName() { columnWithComment.withColumnName(item); } ) - [ - tk= tk2= { - columnWithComment.addColumnSpecs(tk.image).addColumnSpecs(tk2.image); - } - ] + ( item=RelObjectName() { columnWithComment.withColumnName(item); } ) + [ tk= tk2= { columnWithComment.addColumnSpecs(tk.image).addColumnSpecs(tk2.image); } ] { return columnWithComment; } @@ -5731,7 +5727,7 @@ List ColumnDefinitionItemList(): } { "(" - img = ColumnDefinitionItem() { retval.add(img); } + img=ColumnDefinitionItem() { retval.add(img); } ( "," img=ColumnDefinitionItem() { retval.add(img); } )* ")" { @@ -5762,8 +5758,8 @@ CreateView CreateView(boolean isUsingOrReplace): view=Table() { createView.setView(view); } [LOOKAHEAD(3) (tk= | tk=) { createView.setAutoRefresh(AutoRefreshOption.from(tk.image)); } ] [LOOKAHEAD(3) {createView.setIfNotExists(true);}] - [ columnNames = ColumnDefinitionItemList( ) { createView.setColumnNames(columnNames); } ] - [ commentTokens=CreateViewTailComment( ) { createView.setViewCommentOptions(commentTokens);} ] + [ columnNames=ColumnDefinitionItemList( ) { createView.setColumnNames(columnNames); } ] + [ commentTokens=CreateViewTailComment( ) { createView.setViewCommentOptions(commentTokens); } ] select=Select( ) { createView.setSelect(select); } [ { createView.setWithReadOnly(true); } ] From 2c88a41401083f59e95d9f333a4f8682a468bdf5 Mon Sep 17 00:00:00 2001 From: jxnu-liguobin Date: Thu, 14 Dec 2023 11:59:30 +0800 Subject: [PATCH 5/6] Fix --- .../jsqlparser/statement/create/table/ColumnDefinition.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java b/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java index b41f3df58..db4d3784e 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java @@ -73,8 +73,8 @@ public String toString() { public String toStringDataTypeAndSpec() { if (colDataType == null) { - return (columnSpecs == null || columnSpecs.isEmpty() ? "" - : PlainSelect.getStringList(columnSpecs, false, false)); + return columnSpecs == null || columnSpecs.isEmpty() ? "" + : PlainSelect.getStringList(columnSpecs, false, false); } return colDataType + (columnSpecs != null && !columnSpecs.isEmpty() ? " " + PlainSelect.getStringList(columnSpecs, false, false) From 72f6d86473d110545337c15f4c1d24bf7dd509ac Mon Sep 17 00:00:00 2001 From: jxnu-liguobin Date: Thu, 14 Dec 2023 14:26:46 +0800 Subject: [PATCH 6/6] Fix --- .../java/net/sf/jsqlparser/schema/Column.java | 30 ++++++++++++---- .../create/table/ColumnDefinition.java | 11 ++---- .../statement/create/view/CreateView.java | 33 +++++------------ .../util/deparser/CreateViewDeParser.java | 4 ++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 36 +++++++------------ .../statement/create/CreateViewTest.java | 1 - 6 files changed, 50 insertions(+), 65 deletions(-) diff --git a/src/main/java/net/sf/jsqlparser/schema/Column.java b/src/main/java/net/sf/jsqlparser/schema/Column.java index 684e0faf5..3f7721ca3 100644 --- a/src/main/java/net/sf/jsqlparser/schema/Column.java +++ b/src/main/java/net/sf/jsqlparser/schema/Column.java @@ -9,13 +9,12 @@ */ package net.sf.jsqlparser.schema; +import java.util.List; import net.sf.jsqlparser.expression.ArrayConstructor; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; import net.sf.jsqlparser.parser.ASTNodeAccessImpl; -import java.util.List; - /** * A column. It can have the table name it belongs to. */ @@ -23,6 +22,7 @@ public class Column extends ASTNodeAccessImpl implements Expression, MultiPartNa private Table table; private String columnName; + private String commentText; private ArrayConstructor arrayConstructor; public Column() {} @@ -56,19 +56,19 @@ public Column setArrayConstructor(ArrayConstructor arrayConstructor) { *

* The inference is based only on local information, and not on the whole SQL command. For * example, consider the following query:

- * + * *
      *  SELECT x FROM Foo
      * 
- * + * *
Given the {@code Column} called {@code x}, this method would return * {@code null}, and not the info about the table {@code Foo}. On the other hand, consider: *
- * + * *
      *  SELECT t.x FROM Foo t
      * 
- * + * *
Here, we will get a {@code Table} object for a table called {@code t}. But * because the inference is local, such object will not know that {@code t} is just an alias for * {@code Foo}. @@ -114,6 +114,11 @@ public String getFullyQualifiedName(boolean aliases) { fqn.append(columnName); } + if (commentText != null) { + fqn.append(" COMMENT "); + fqn.append(commentText); + } + if (arrayConstructor != null) { fqn.append(arrayConstructor); } @@ -146,4 +151,17 @@ public Column withColumnName(String columnName) { this.setColumnName(columnName); return this; } + + public Column withCommentText(String commentText) { + this.setCommentText(commentText); + return this; + } + + public void setCommentText(String commentText) { + this.commentText = commentText; + } + + public String getCommentText() { + return commentText; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java b/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java index db4d3784e..f19962d8e 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/ColumnDefinition.java @@ -9,13 +9,14 @@ */ package net.sf.jsqlparser.statement.create.table; +import net.sf.jsqlparser.statement.select.PlainSelect; + import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; -import net.sf.jsqlparser.statement.select.PlainSelect; /** * Globally used definition class for columns. @@ -64,18 +65,10 @@ public void setColumnName(String string) { @Override public String toString() { - String spec = toStringDataTypeAndSpec(); - if (spec.isEmpty()) { - return columnName; - } return columnName + " " + toStringDataTypeAndSpec(); } public String toStringDataTypeAndSpec() { - if (colDataType == null) { - return columnSpecs == null || columnSpecs.isEmpty() ? "" - : PlainSelect.getStringList(columnSpecs, false, false); - } return colDataType + (columnSpecs != null && !columnSpecs.isEmpty() ? " " + PlainSelect.getStringList(columnSpecs, false, false) : ""); diff --git a/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java b/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java index acd6e9809..8381e50af 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/view/CreateView.java @@ -9,15 +9,12 @@ */ package net.sf.jsqlparser.statement.create.view; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; import java.util.List; -import java.util.Optional; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.StatementVisitor; -import net.sf.jsqlparser.statement.create.table.ColumnDefinition; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.Select; @@ -26,7 +23,7 @@ public class CreateView implements Statement { private Table view; private Select select; private boolean orReplace = false; - private List columnNames = null; + private ExpressionList columnNames = null; private boolean materialized = false; private ForceOption force = ForceOption.NONE; private TemporaryOption temp = TemporaryOption.NONE; @@ -67,11 +64,11 @@ public void setSelect(Select select) { this.select = select; } - public List getColumnNames() { + public ExpressionList getColumnNames() { return columnNames; } - public void setColumnNames(List columnNames) { + public void setColumnNames(ExpressionList columnNames) { this.columnNames = columnNames; } @@ -147,7 +144,9 @@ public String toString() { sql.append(" AUTO REFRESH ").append(autoRefresh.name()); } if (columnNames != null) { - sql.append(PlainSelect.getStringList(columnNames, true, true)); + sql.append("("); + sql.append(columnNames); + sql.append(")"); } if (viewCommentOptions != null) { sql.append(PlainSelect.getStringList(viewCommentOptions, false, false)); @@ -187,7 +186,7 @@ public CreateView withOrReplace(boolean orReplace) { return this; } - public CreateView withColumnNames(List columnNames) { + public CreateView withColumnNames(ExpressionList columnNames) { this.setColumnNames(columnNames); return this; } @@ -207,20 +206,6 @@ public CreateView withWithReadOnly(boolean withReadOnly) { return this; } - public CreateView addColumnNames(ColumnDefinition... columnNames) { - List collection = - Optional.ofNullable(getColumnNames()).orElseGet(ArrayList::new); - Collections.addAll(collection, columnNames); - return this.withColumnNames(collection); - } - - public CreateView addColumnNames(Collection columnNames) { - List collection = - Optional.ofNullable(getColumnNames()).orElseGet(ArrayList::new); - collection.addAll(columnNames); - return this.withColumnNames(collection); - } - public List getViewCommentOptions() { return viewCommentOptions; } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java index cce764f6b..1f5662e68 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java @@ -67,7 +67,9 @@ public void deParse(CreateView createView) { buffer.append(" AUTO REFRESH ").append(createView.getAutoRefresh().name()); } if (createView.getColumnNames() != null) { - buffer.append(PlainSelect.getStringList(createView.getColumnNames(), true, true)); + buffer.append("("); + buffer.append(createView.getColumnNames()); + buffer.append(")"); } if (createView.getViewCommentOptions() != null) { buffer.append( diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 5f56221db..91f4df886 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -1767,16 +1767,18 @@ Column Column() #Column : { List data = new ArrayList(); ArrayConstructor arrayConstructor = null; + Token tk = null; } { data = RelObjectNameList() - + [ tk= ] // @todo: we better should return a SEQUENCE instead of a COLUMN [ "." { data.add("nextval"); } ] [ LOOKAHEAD(2) arrayConstructor = ArrayConstructor(false) ] { Column col = new Column(data); + if (tk != null) { col.withCommentText(tk.image); } if (arrayConstructor!=null) { col.setArrayConstructor(arrayConstructor); } @@ -5705,42 +5707,28 @@ Analyze Analyze(): } } -ColumnDefinition ColumnDefinitionItem(): -{ - Token tk = null; - Token tk2 = null; - String item = null; - ColumnDefinition columnWithComment = new ColumnDefinition(); -} +ExpressionList ColumnWithCommentList(): { - ( item=RelObjectName() { columnWithComment.withColumnName(item); } ) - [ tk= tk2= { columnWithComment.addColumnSpecs(tk.image).addColumnSpecs(tk2.image); } ] - { - return columnWithComment; - } -} - -List ColumnDefinitionItemList(): -{ - List retval = new ArrayList(); - ColumnDefinition img = null; + ExpressionList expressions = new ExpressionList(); + Column img = null; } { "(" - img=ColumnDefinitionItem() { retval.add(img); } - ( "," img=ColumnDefinitionItem() { retval.add(img); } )* + img=Column() { expressions.add(img); } + ( "," img=Column() { expressions.add(img); } )* ")" { - return retval; + return expressions; } } + CreateView CreateView(boolean isUsingOrReplace): { CreateView createView = new CreateView(); Table view = null; Select select = null; - List columnNames = null; + ExpressionList columnNames = null; Token tk = null; List commentTokens = null; } @@ -5758,7 +5746,7 @@ CreateView CreateView(boolean isUsingOrReplace): view=Table() { createView.setView(view); } [LOOKAHEAD(3) (tk= | tk=) { createView.setAutoRefresh(AutoRefreshOption.from(tk.image)); } ] [LOOKAHEAD(3) {createView.setIfNotExists(true);}] - [ columnNames=ColumnDefinitionItemList( ) { createView.setColumnNames(columnNames); } ] + [ columnNames=ColumnWithCommentList( ) { createView.setColumnNames(columnNames); } ] [ commentTokens=CreateViewTailComment( ) { createView.setViewCommentOptions(commentTokens); } ] select=Select( ) { createView.setSelect(select); } diff --git a/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java b/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java index a3ad4a79c..240a22fc3 100644 --- a/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/create/CreateViewTest.java @@ -9,7 +9,6 @@ */ package net.sf.jsqlparser.statement.create; -import static net.sf.jsqlparser.test.TestUtils.*; import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; import static org.assertj.core.api.Assertions.assertThatThrownBy; import static org.junit.jupiter.api.Assertions.assertEquals;