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 b59191844..956d636b5 100644 --- a/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java +++ b/src/main/java/net/sf/jsqlparser/parser/feature/Feature.java @@ -306,6 +306,11 @@ public enum Feature { */ values, + /** + * SQL "TABLE table_name [ORDER BY column_name] [LIMIT number [OFFSET number]]“ + */ + tableStatement, + /** * SQL "UPDATE" statement is allowed * diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java index 1d3643f50..04a6b9d9e 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java @@ -22,4 +22,6 @@ public interface SelectVisitor { void visit(Values aThis); void visit(LateralSubSelect lateralSubSelect); + + void visit(TableStatement tableStatement); } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java index 91c6f32c2..a349a9005 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java @@ -41,4 +41,9 @@ public void visit(Values aThis) { public void visit(LateralSubSelect lateralSubSelect) { } + + @Override + public void visit(TableStatement tableStatement) { + + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/TableStatement.java b/src/main/java/net/sf/jsqlparser/statement/select/TableStatement.java new file mode 100644 index 000000000..b665b16a6 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/select/TableStatement.java @@ -0,0 +1,59 @@ +/*- + * #%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.select; + +import net.sf.jsqlparser.schema.Table; + +/** + * @see `TABLE table_name [ORDER + * BY column_name] [LIMIT number [OFFSET number]]` Union not currently supported + * + * @author jxnu-liguobin + */ +public class TableStatement extends Select { + + private Table table; + + public Table getTable() { + return table; + } + + public void setTable(Table table) { + this.table = table; + } + + @Override + public StringBuilder appendSelectBodyTo(StringBuilder builder) { + builder.append("TABLE ").append(table.getName()); + return builder; + } + + @SuppressWarnings({"PMD.CyclomaticComplexity"}) + @Override + public StringBuilder appendTo(StringBuilder builder) { + + appendSelectBodyTo(builder); + + builder.append(orderByToString(false, orderByElements)); + + if (limit != null) { + builder.append(limit); + } + if (offset != null) { + builder.append(offset); + } + return builder; + } + + @Override + public void accept(SelectVisitor selectVisitor) { + selectVisitor.visit(this); + } +} diff --git a/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java b/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java index 3303c091f..58ca4326f 100644 --- a/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java +++ b/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java @@ -9,6 +9,8 @@ */ package net.sf.jsqlparser.util; +import java.util.LinkedList; +import java.util.List; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.statement.select.LateralSubSelect; import net.sf.jsqlparser.statement.select.ParenthesedSelect; @@ -18,12 +20,10 @@ import net.sf.jsqlparser.statement.select.SelectItemVisitor; import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.statement.select.SetOperationList; +import net.sf.jsqlparser.statement.select.TableStatement; import net.sf.jsqlparser.statement.select.Values; import net.sf.jsqlparser.statement.select.WithItem; -import java.util.LinkedList; -import java.util.List; - /** * Add aliases to every column and expression selected by a select - statement. Existing aliases are * recognized and preserved. This class standard uses a prefix of A and a counter to generate new @@ -112,4 +112,9 @@ public void visit(Values aThis) { public void visit(LateralSubSelect lateralSubSelect) { lateralSubSelect.getSelect().accept(this); } + + @Override + public void visit(TableStatement tableStatement) { + throw new UnsupportedOperationException("Not supported yet."); + } } diff --git a/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java b/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java index 479bc3c3e..46b746f0a 100644 --- a/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java +++ b/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java @@ -9,6 +9,8 @@ */ package net.sf.jsqlparser.util; +import java.util.LinkedList; +import java.util.List; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.BinaryExpression; import net.sf.jsqlparser.statement.select.LateralSubSelect; @@ -19,12 +21,10 @@ import net.sf.jsqlparser.statement.select.SelectItemVisitor; import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.statement.select.SetOperationList; +import net.sf.jsqlparser.statement.select.TableStatement; import net.sf.jsqlparser.statement.select.Values; import net.sf.jsqlparser.statement.select.WithItem; -import java.util.LinkedList; -import java.util.List; - /** * Connect all selected expressions with a binary expression. Out of select a,b from table one gets * select a || b as expr from table. The type of binary expression is set by overwriting this class @@ -103,4 +103,8 @@ public void visit(Values aThis) { throw new UnsupportedOperationException("Not supported yet."); } + @Override + public void visit(TableStatement tableStatement) { + throw new UnsupportedOperationException("Not supported yet."); + } } diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 44f0859a5..b3b697e4d 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -167,6 +167,7 @@ import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.statement.select.SetOperationList; import net.sf.jsqlparser.statement.select.TableFunction; +import net.sf.jsqlparser.statement.select.TableStatement; import net.sf.jsqlparser.statement.select.Values; import net.sf.jsqlparser.statement.select.WithItem; import net.sf.jsqlparser.statement.show.ShowIndexStatement; @@ -691,6 +692,11 @@ public void visit(LateralSubSelect lateralSubSelect) { lateralSubSelect.getSelect().accept((SelectVisitor) this); } + @Override + public void visit(TableStatement tableStatement) { + tableStatement.getTable().accept(this); + } + /** * Initializes table names collector. Important is the usage of Column instances to find table * names. This is only allowed for expression parsing, where a better place for tablenames could diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java index 75aac7a9e..7c4c0e1fb 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -9,6 +9,10 @@ */ package net.sf.jsqlparser.util.deparser; +import static java.util.stream.Collectors.joining; + +import java.util.Iterator; +import java.util.List; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.ExpressionVisitor; @@ -40,16 +44,12 @@ import net.sf.jsqlparser.statement.select.SetOperationList; import net.sf.jsqlparser.statement.select.Skip; import net.sf.jsqlparser.statement.select.TableFunction; +import net.sf.jsqlparser.statement.select.TableStatement; import net.sf.jsqlparser.statement.select.Top; import net.sf.jsqlparser.statement.select.UnPivot; import net.sf.jsqlparser.statement.select.Values; import net.sf.jsqlparser.statement.select.WithItem; -import java.util.Iterator; -import java.util.List; - -import static java.util.stream.Collectors.joining; - @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public class SelectDeParser extends AbstractDeParser implements SelectVisitor, SelectItemVisitor, FromItemVisitor, PivotVisitor { @@ -589,6 +589,11 @@ public void visit(LateralSubSelect lateralSubSelect) { visit((ParenthesedSelect) lateralSubSelect); } + @Override + public void visit(TableStatement tableStatement) { + new TableStatementDeParser(expressionVisitor, buffer).deParse(tableStatement); + } + @Override public void visit(TableFunction tableFunction) { buffer.append(tableFunction.toString()); diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java new file mode 100644 index 000000000..962849c6e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java @@ -0,0 +1,98 @@ +/*- + * #%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.util.deparser; + +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.statement.select.LateralSubSelect; +import net.sf.jsqlparser.statement.select.Offset; +import net.sf.jsqlparser.statement.select.ParenthesedSelect; +import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.SelectVisitor; +import net.sf.jsqlparser.statement.select.SetOperationList; +import net.sf.jsqlparser.statement.select.TableStatement; +import net.sf.jsqlparser.statement.select.Values; +import net.sf.jsqlparser.statement.select.WithItem; + +/** + * @author jxnu-liguobin + */ +public class TableStatementDeParser extends AbstractDeParser + implements SelectVisitor { + + private final ExpressionVisitor expressionVisitor; + + public TableStatementDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { + super(buffer); + this.expressionVisitor = expressionVisitor; + } + + @Override + public void deParse(TableStatement tableStatement) { + tableStatement.accept(this); + } + + public void visit(Offset offset) { + buffer.append(" OFFSET "); + offset.getOffset().accept(expressionVisitor); + if (offset.getOffsetParam() != null) { + buffer.append(" ").append(offset.getOffsetParam()); + } + + } + + @Override + public void visit(ParenthesedSelect parenthesedSelect) { + + } + + @Override + public void visit(PlainSelect plainSelect) { + + } + + @Override + public void visit(SetOperationList setOpList) { + + } + + @Override + public void visit(WithItem withItem) { + + } + + @Override + public void visit(Values aThis) { + + } + + @Override + public void visit(LateralSubSelect lateralSubSelect) { + + } + + @Override + public void visit(TableStatement tableStatement) { + buffer.append("TABLE "); + buffer.append(tableStatement.getTable()); + if (tableStatement.getOrderByElements() != null) { + new OrderByDeParser(expressionVisitor, buffer) + .deParse(tableStatement.getOrderByElements()); + } + + if (tableStatement.getLimit() != null) { + new LimitDeparser(expressionVisitor, buffer).deParse(tableStatement.getLimit()); + } + if (tableStatement.getOffset() != null) { + visit(tableStatement.getOffset()); + } + + // TODO UNION + } +} diff --git a/src/main/java/net/sf/jsqlparser/util/validation/feature/FeaturesAllowed.java b/src/main/java/net/sf/jsqlparser/util/validation/feature/FeaturesAllowed.java index 04c9a1277..3ada0ec28 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/feature/FeaturesAllowed.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/feature/FeaturesAllowed.java @@ -38,13 +38,14 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS Feature.jdbcParameter, Feature.jdbcNamedParameter).unmodifyable(); - public static final FeaturesAllowed EXPRESSIONS = new FeaturesAllowed("EXPRESSIONS", Feature.exprLike, - Feature.exprSimilarTo); + public static final FeaturesAllowed EXPRESSIONS = + new FeaturesAllowed("EXPRESSIONS", Feature.exprLike, + Feature.exprSimilarTo); /** * all {@link Feature}' within SQL SELECT without modification features like - * {@link Feature#selectInto}, but jdbc-features like - * {@link Feature#jdbcParameter} and {@link Feature#jdbcNamedParameter} + * {@link Feature#selectInto}, but jdbc-features like {@link Feature#jdbcParameter} and + * {@link Feature#jdbcNamedParameter} */ public static final FeaturesAllowed SELECT = new FeaturesAllowed("SELECT", // select features @@ -86,22 +87,25 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS Feature.distinctOn, Feature.orderBy, Feature.orderByNullOrdering, + Feature.tableStatement, Feature.function).unmodifyable(); /** - * all {@link Feature}' for SQL INSERT including {@link #SELECT} and - * {@link Feature#selectInto} + * all {@link Feature}' for SQL INSERT including {@link #SELECT} and {@link Feature#selectInto} */ - public static final FeaturesAllowed INSERT = new FeaturesAllowed("INSERT", Feature.insert, Feature.insertFromSelect, - Feature.insertModifierIgnore, Feature.insertModifierPriority, Feature.insertReturningAll, - Feature.insertReturningExpressionList, Feature.insertUseSet, - Feature.insertValues, Feature.selectInto).add(SELECT).unmodifyable(); + public static final FeaturesAllowed INSERT = + new FeaturesAllowed("INSERT", Feature.insert, Feature.insertFromSelect, + Feature.insertModifierIgnore, Feature.insertModifierPriority, + Feature.insertReturningAll, + Feature.insertReturningExpressionList, Feature.insertUseSet, + Feature.insertValues, Feature.selectInto).add(SELECT).unmodifyable(); /** * all {@link Feature}' for SQL UPDATE including {@link #SELECT} */ - public static final FeaturesAllowed UPDATE = new FeaturesAllowed("UPDATE", Feature.update, Feature.updateJoins, + public static final FeaturesAllowed UPDATE = new FeaturesAllowed("UPDATE", Feature.update, + Feature.updateJoins, Feature.updateFrom, Feature.updateLimit, Feature.updateOrderBy, Feature.updateReturning, Feature.updateUseSelect) .add(SELECT).unmodifyable(); @@ -109,55 +113,66 @@ public class FeaturesAllowed implements FeatureSetValidation, ModifyableFeatureS /** * all {@link Feature}' for SQL UPDATE including {@link #SELECT} */ - public static final FeaturesAllowed DELETE = new FeaturesAllowed("DELETE", Feature.delete, Feature.deleteJoin, - Feature.deleteLimit, Feature.deleteOrderBy, Feature.deleteTables, Feature.deleteReturningExpressionList, - Feature.truncate) - .add(SELECT).unmodifyable(); + public static final FeaturesAllowed DELETE = + new FeaturesAllowed("DELETE", Feature.delete, Feature.deleteJoin, + Feature.deleteLimit, Feature.deleteOrderBy, Feature.deleteTables, + Feature.deleteReturningExpressionList, + Feature.truncate) + .add(SELECT).unmodifyable(); /** * all {@link Feature}' for SQL MERGE other similar commands */ - public static final FeaturesAllowed MERGE = new FeaturesAllowed("MERGE", Feature.merge, Feature.upsert, - Feature.insertUseDuplicateKeyUpdate).unmodifyable(); + public static final FeaturesAllowed MERGE = + new FeaturesAllowed("MERGE", Feature.merge, Feature.upsert, + Feature.insertUseDuplicateKeyUpdate).unmodifyable(); /** * all DML {@link Feature}'s */ - public static final FeaturesAllowed DML = new FeaturesAllowed("DML").add(SELECT, INSERT, UPDATE, DELETE, MERGE) - .unmodifyable(); + public static final FeaturesAllowed DML = + new FeaturesAllowed("DML").add(SELECT, INSERT, UPDATE, DELETE, MERGE) + .unmodifyable(); - public static final FeaturesAllowed EXECUTE = new FeaturesAllowed("EXECUTE", Feature.execute).unmodifyable(); + public static final FeaturesAllowed EXECUTE = + new FeaturesAllowed("EXECUTE", Feature.execute).unmodifyable(); /** * all "CREATE" {@link Feature}'s */ public static final FeaturesAllowed CREATE = new FeaturesAllowed("CREATE", Feature.createIndex, - Feature.createSchema, Feature.createSequence, Feature.createTable, Feature.createTableUnlogged, + Feature.createSchema, Feature.createSequence, Feature.createTable, + Feature.createTableUnlogged, Feature.createTableCreateOptionStrings, Feature.createTableTableOptionStrings, - Feature.createTableIfNotExists, Feature.createTableRowMovement, Feature.createTableFromSelect, + Feature.createTableIfNotExists, Feature.createTableRowMovement, + Feature.createTableFromSelect, Feature.createTrigger, Feature.createView).unmodifyable(); /** * all "ALTER" {@link Feature}'s */ - public static final FeaturesAllowed ALTER = new FeaturesAllowed("ALTER", Feature.alterTable, Feature.alterSequence, - Feature.alterView, Feature.alterIndex) - .unmodifyable(); + public static final FeaturesAllowed ALTER = + new FeaturesAllowed("ALTER", Feature.alterTable, Feature.alterSequence, + Feature.alterView, Feature.alterIndex) + .unmodifyable(); /** * all "DROP" {@link Feature}'s */ - public static final FeaturesAllowed DROP = new FeaturesAllowed("DROP", Feature.drop, Feature.dropTable, - Feature.dropIndex, Feature.dropView, Feature.dropSchema, Feature.dropSequence, Feature.dropTableIfExists, - Feature.dropIndexIfExists, Feature.dropViewIfExists, Feature.dropSchemaIfExists, - Feature.dropSequenceIfExists) - .unmodifyable(); + public static final FeaturesAllowed DROP = + new FeaturesAllowed("DROP", Feature.drop, Feature.dropTable, + Feature.dropIndex, Feature.dropView, Feature.dropSchema, Feature.dropSequence, + Feature.dropTableIfExists, + Feature.dropIndexIfExists, Feature.dropViewIfExists, Feature.dropSchemaIfExists, + Feature.dropSequenceIfExists) + .unmodifyable(); /** * all DDL {@link Feature}'s */ - public static final FeaturesAllowed DDL = new FeaturesAllowed("DDL").add(CREATE, ALTER, DROP).unmodifyable(); + public static final FeaturesAllowed DDL = + new FeaturesAllowed("DDL").add(CREATE, ALTER, DROP).unmodifyable(); private Set names = new LinkedHashSet<>(); private Set features = new HashSet<>(); @@ -278,7 +293,8 @@ public ValidationException getMessage(Feature feature) { @Override public String getName() { - return names.isEmpty() ? FeatureSetValidation.super.getName() : names.stream().collect(Collectors.joining(SEPERATOR)); + return names.isEmpty() ? FeatureSetValidation.super.getName() + : names.stream().collect(Collectors.joining(SEPERATOR)); } @@ -289,7 +305,8 @@ public Set getFeatures() { private List collectNames(FeatureSetValidation fs) { String name = fs.getName(); - return Stream.of(name.split(SEPERATOR_REGEX)).map(String::trim).collect(Collectors.toList()); + return Stream.of(name.split(SEPERATOR_REGEX)).map(String::trim) + .collect(Collectors.toList()); } } 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 d631344d8..3486261ed 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 @@ -60,6 +60,7 @@ public enum MySqlVersion implements Version { Feature.insert, Feature.insertValues, Feature.values, + Feature.tableStatement, Feature.insertFromSelect, Feature.insertUseSet, Feature.insertModifierPriority, Feature.insertModifierIgnore, Feature.insertUseDuplicateKeyUpdate, diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java index 88166c1b5..3cba4a988 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/SelectValidator.java @@ -9,6 +9,7 @@ */ package net.sf.jsqlparser.util.validation.validator; +import java.util.List; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.MySQLIndexHint; import net.sf.jsqlparser.expression.SQLServerHints; @@ -33,6 +34,7 @@ import net.sf.jsqlparser.statement.select.SelectVisitor; import net.sf.jsqlparser.statement.select.SetOperationList; import net.sf.jsqlparser.statement.select.TableFunction; +import net.sf.jsqlparser.statement.select.TableStatement; import net.sf.jsqlparser.statement.select.UnPivot; import net.sf.jsqlparser.statement.select.UnionOp; import net.sf.jsqlparser.statement.select.Values; @@ -41,8 +43,6 @@ import net.sf.jsqlparser.util.validation.ValidationUtil; import net.sf.jsqlparser.util.validation.metadata.NamedObject; -import java.util.List; - /** * @author gitmotte */ @@ -306,6 +306,11 @@ public void visit(LateralSubSelect lateralSubSelect) { validateOptional(lateralSubSelect.getSelect(), e -> e.accept(this)); } + @Override + public void visit(TableStatement tableStatement) { + getValidator(TableStatementValidator.class).validate(tableStatement); + } + @Override public void visit(TableFunction tableFunction) { validateFeature(Feature.tableFunction); diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/TableStatementValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/TableStatementValidator.java new file mode 100644 index 000000000..4b954126e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/TableStatementValidator.java @@ -0,0 +1,27 @@ +/*- + * #%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.util.validation.validator; + +import net.sf.jsqlparser.parser.feature.Feature; +import net.sf.jsqlparser.statement.select.TableStatement; +import net.sf.jsqlparser.util.validation.ValidationCapability; + +/** + * @author jxnu-liguobin + */ +public class TableStatementValidator extends AbstractValidator { + + @Override + public void validate(TableStatement statement) { + for (ValidationCapability c : getCapabilities()) { + validateFeature(c, Feature.tableStatement); + } + } +} diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 6e6cce16b..547324944 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -676,6 +676,8 @@ Statement SingleStatement() : | stm = Select() | + stm = TableStatement() + | LOOKAHEAD(3) stm = Upsert() | LOOKAHEAD(2) stm = Alter() @@ -2002,6 +2004,24 @@ Select Select() #Select: } } +TableStatement TableStatement(): +{ + Table table = null; + List orderByElements = null; + Limit limit = null; + Offset offset = null; + TableStatement tableStatement = new TableStatement(); +}{ + + table = Table() + { tableStatement.setTable(table); } + [ LOOKAHEAD( ) orderByElements = OrderByElements() { tableStatement.setOrderByElements(orderByElements); } ] + [ LOOKAHEAD() limit=LimitWithOffset() { tableStatement.setLimit(limit);} ] + [ LOOKAHEAD() offset = Offset() { tableStatement.setOffset(offset);} ] + { return tableStatement; } + /* Support operationList */ +} + ParenthesedSelect ParenthesedSelect() #ParenthesedSelect: { ParenthesedSelect parenthesedSelect = new ParenthesedSelect(); diff --git a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java index 0b78f60d0..f5010099e 100644 --- a/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java +++ b/src/test/java/net/sf/jsqlparser/parser/CCJSqlParserUtilTest.java @@ -9,6 +9,12 @@ */ package net.sf.jsqlparser.parser; +import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; + import java.io.ByteArrayInputStream; import java.io.StringReader; import java.nio.charset.StandardCharsets; @@ -19,7 +25,6 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Level; - import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; @@ -29,15 +34,9 @@ import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.statement.Statement; import net.sf.jsqlparser.statement.Statements; - -import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertThrows; -import static org.junit.jupiter.api.Assertions.assertTrue; - import net.sf.jsqlparser.statement.UnsupportedStatement; import net.sf.jsqlparser.statement.select.PlainSelect; +import net.sf.jsqlparser.statement.select.TableStatement; import net.sf.jsqlparser.test.MemoryLeakVerifier; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.function.Executable; @@ -336,6 +335,13 @@ public void testCondExpressionIssue1482() throws JSQLParserException { assertEquals("test_table_enum.f1_enum IN ('TEST2'::test.test_enum)", expr.toString()); } + @Test + public void testTableStatementIssue1836() throws JSQLParserException { + TableStatement expr = (TableStatement) CCJSqlParserUtil + .parse("TABLE columns ORDER BY column_name LIMIT 10 OFFSET 10"); + assertEquals("TABLE columns ORDER BY column_name LIMIT 10 OFFSET 10", expr.toString()); + } + @Test public void testCondExpressionIssue1482_2() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseCondExpression( diff --git a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java index f4a0b77f6..5fb760b93 100644 --- a/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java +++ b/src/test/java/net/sf/jsqlparser/statement/select/SelectTest.java @@ -9,6 +9,28 @@ */ package net.sf.jsqlparser.statement.select; +import static net.sf.jsqlparser.test.TestUtils.assertDeparse; +import static net.sf.jsqlparser.test.TestUtils.assertExpressionCanBeDeparsedAs; +import static net.sf.jsqlparser.test.TestUtils.assertExpressionCanBeParsedAndDeparsed; +import static net.sf.jsqlparser.test.TestUtils.assertOracleHintExists; +import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; +import static net.sf.jsqlparser.test.TestUtils.assertStatementCanBeDeparsedAs; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertInstanceOf; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.junit.jupiter.api.Assertions.fail; + +import java.io.IOException; +import java.io.StringReader; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.List; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.AllValue; @@ -56,29 +78,6 @@ import org.junit.jupiter.params.ParameterizedTest; import org.junit.jupiter.params.provider.ValueSource; -import java.io.IOException; -import java.io.StringReader; -import java.nio.charset.Charset; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.List; - -import static net.sf.jsqlparser.test.TestUtils.assertDeparse; -import static net.sf.jsqlparser.test.TestUtils.assertExpressionCanBeDeparsedAs; -import static net.sf.jsqlparser.test.TestUtils.assertExpressionCanBeParsedAndDeparsed; -import static net.sf.jsqlparser.test.TestUtils.assertOracleHintExists; -import static net.sf.jsqlparser.test.TestUtils.assertSqlCanBeParsedAndDeparsed; -import static net.sf.jsqlparser.test.TestUtils.assertStatementCanBeDeparsedAs; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertFalse; -import static org.junit.jupiter.api.Assertions.assertInstanceOf; -import static org.junit.jupiter.api.Assertions.assertNotEquals; -import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertNull; -import static org.junit.jupiter.api.Assertions.assertTrue; -import static org.junit.jupiter.api.Assertions.fail; - @Execution(ExecutionMode.CONCURRENT) public class SelectTest { @@ -4615,6 +4614,20 @@ public void testMultiColumnAliasIssue849_2() throws JSQLParserException { "SELECT * FROM crosstab('select rowid, attribute, value from ct where attribute = ''att2'' or attribute = ''att3'' order by 1,2') AS ct(row_name text, category_1 text, category_2 text, category_3 text)"); } + @Test + public void testTableStatementIssue1836() throws JSQLParserException { + assertSqlCanBeParsedAndDeparsed( + "TABLE columns ORDER BY column_name LIMIT 10 OFFSET 10"); + assertSqlCanBeParsedAndDeparsed( + "TABLE columns ORDER BY column_name LIMIT 10"); + assertSqlCanBeParsedAndDeparsed( + "TABLE columns ORDER BY column_name"); + assertSqlCanBeParsedAndDeparsed( + "TABLE columns LIMIT 10 OFFSET 10"); + assertSqlCanBeParsedAndDeparsed( + "TABLE columns LIMIT 10"); + } + @Test public void testLimitClauseDroppedIssue845() throws JSQLParserException { assertEquals("SELECT * FROM employee ORDER BY emp_id LIMIT 10 OFFSET 2", CCJSqlParserUtil diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java index e0f2d0b97..4248ef494 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java @@ -9,6 +9,13 @@ */ package net.sf.jsqlparser.util.deparser; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.spy; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import net.sf.jsqlparser.JSQLParserException; import net.sf.jsqlparser.expression.Expression; import net.sf.jsqlparser.expression.LongValue; @@ -26,6 +33,7 @@ import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.PlainSelect; import net.sf.jsqlparser.statement.select.SelectVisitor; +import net.sf.jsqlparser.statement.select.TableStatement; import net.sf.jsqlparser.statement.select.WithItem; import net.sf.jsqlparser.statement.update.Update; import net.sf.jsqlparser.statement.update.UpdateSet; @@ -37,14 +45,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -import static org.mockito.BDDMockito.then; -import static org.mockito.Mockito.mock; -import static org.mockito.Mockito.spy; - @ExtendWith(MockitoExtension.class) public class StatementDeParserTest { @@ -56,8 +56,12 @@ public class StatementDeParserTest { private StatementDeParser statementDeParser; + private TableStatementDeParser tableStatementDeParser; + @BeforeEach public void setUp() { + tableStatementDeParser = + new TableStatementDeParser(expressionDeParser, new StringBuilder()); statementDeParser = new StatementDeParser(expressionDeParser, selectDeParser, new StringBuilder()); } @@ -326,6 +330,13 @@ public void testIssue1500AllColumns() throws JSQLParserException { selectBody.accept(new SelectDeParser()); } + @Test + public void testIssue1836() throws JSQLParserException { + String sqlStr = "TABLE columns ORDER BY column_name LIMIT 10 OFFSET 10;"; + TableStatement tableStatement = (TableStatement) CCJSqlParserUtil.parse(sqlStr); + tableStatement.accept(tableStatementDeParser); + } + @Test public void testIssue1500AllTableColumns() throws JSQLParserException { String sqlStr = "select count(a.*) from some_table a"; diff --git a/src/test/java/net/sf/jsqlparser/util/validation/validator/TableStatementValidatorTest.java b/src/test/java/net/sf/jsqlparser/util/validation/validator/TableStatementValidatorTest.java new file mode 100644 index 000000000..c71b8448e --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/util/validation/validator/TableStatementValidatorTest.java @@ -0,0 +1,38 @@ +/*- + * #%L + * JSQLParser library + * %% + * Copyright (C) 2004 - 2020 JSQLParser + * %% + * Dual licensed under GNU LGPL 2.1 or Apache License 2.0 + * #L% + */ +package net.sf.jsqlparser.util.validation.validator; + +import java.util.Arrays; +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.parser.feature.Feature; +import net.sf.jsqlparser.util.validation.ValidationTestAsserts; +import net.sf.jsqlparser.util.validation.feature.FeaturesAllowed; +import net.sf.jsqlparser.util.validation.feature.MySqlVersion; +import net.sf.jsqlparser.util.validation.feature.PostgresqlVersion; +import org.junit.jupiter.api.Test; + +public class TableStatementValidatorTest extends ValidationTestAsserts { + + @Test + public void testValidationSelectAllowed() throws JSQLParserException { + String sql = "TABLE columns ORDER BY column_name LIMIT 10 OFFSET 10"; + validateNoErrors(sql, 1, MySqlVersion.V8_0); + } + + @Test + public void testValidationSelectNotAllowed() throws JSQLParserException { + String sql = "TABLE columns ORDER BY column_name LIMIT 10 OFFSET 10"; + validateNotAllowed(sql, 1, 1, FeaturesAllowed.DDL, Feature.select, Feature.tableStatement); + + validateNotSupported(sql, 1, 1, Arrays.asList( + PostgresqlVersion.V14), Feature.tableStatement); + } + +}