From f25e28bff4c96cbb6fe40b60984882e9a5f8fc2e Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sun, 12 Jan 2025 00:40:39 +0700 Subject: [PATCH 1/5] feat: Piped SQL and FROM queries (WIP) - `FROM Query` extending `SELECT` - `WHERE` operator - `AGGREGATE` operator - `ORDER BY` operator Signed-off-by: Andreas Reichel Signed-off-by: manticore-projects --- README.md | 18 +- src/main/java/module-info.java | 1 + .../sf/jsqlparser/expression/Expression.java | 3 - .../expression/ExpressionVisitor.java | 3 + .../expression/ExpressionVisitorAdapter.java | 6 + .../jsqlparser/parser/ASTNodeAccessImpl.java | 5 + .../statement/StatementVisitor.java | 1 - .../piped/AggregatePipeOperator.java | 80 +++ .../statement/piped/AsPipeOperator.java | 9 + .../statement/piped/CallPipeOperator.java | 9 + .../statement/piped/DropPipeOperator.java | 8 + .../statement/piped/ExceptPipeOperator.java | 8 + .../statement/piped/ExtendPipeOperator.java | 8 + .../jsqlparser/statement/piped/FromQuery.java | 203 ++++++ .../piped/IntersectPipeOperator.java | 8 + .../statement/piped/JoinPipeOperator.java | 8 + .../statement/piped/LimitPipeOperator.java | 8 + .../statement/piped/OrderByPipeOperator.java | 38 + .../statement/piped/PipeOperator.java | 7 + .../statement/piped/PipeOperatorVisitor.java | 42 ++ .../statement/piped/PivotPipeOperator.java | 8 + .../statement/piped/RenamePipeOperator.java | 8 + .../statement/piped/SelectPipeOperator.java | 38 + .../statement/piped/SetPipeOperator.java | 8 + .../piped/TableSamplePipeOperator.java | 8 + .../statement/piped/UnPivotPipeOperator.java | 8 + .../statement/piped/UnionPipeOperator.java | 8 + .../statement/piped/WherePipeOperator.java | 34 + .../statement/piped/WindowPipeOperator.java | 8 + .../statement/select/FromItemVisitor.java | 3 + .../select/FromItemVisitorAdapter.java | 6 + .../jsqlparser/statement/select/Select.java | 4 +- .../statement/select/SelectVisitor.java | 4 + .../select/SelectVisitorAdapter.java | 7 + .../sf/jsqlparser/util/AddAliasesVisitor.java | 6 + .../util/ConnectExpressionsVisitor.java | 8 +- .../sf/jsqlparser/util/TablesNamesFinder.java | 6 + .../util/deparser/AbstractDeParser.java | 14 +- .../util/deparser/AlterDeParser.java | 2 +- .../util/deparser/AlterSequenceDeParser.java | 4 +- .../util/deparser/AlterSessionDeParser.java | 2 +- .../util/deparser/AlterViewDeParser.java | 10 +- .../util/deparser/CreateIndexDeParser.java | 32 +- .../util/deparser/CreateSequenceDeParser.java | 4 +- .../util/deparser/CreateSynonymDeparser.java | 12 +- .../util/deparser/CreateTableDeParser.java | 62 +- .../util/deparser/CreateViewDeParser.java | 34 +- .../deparser/DeclareStatementDeParser.java | 22 +- .../util/deparser/DeleteDeParser.java | 42 +- .../util/deparser/DropDeParser.java | 16 +- .../util/deparser/ExecuteDeParser.java | 10 +- .../util/deparser/ExpressionDeParser.java | 653 +++++++++--------- .../util/deparser/ExpressionListDeParser.java | 10 +- .../util/deparser/GrantDeParser.java | 18 +- .../util/deparser/GroupByDeParser.java | 16 +- .../util/deparser/InsertDeParser.java | 58 +- .../util/deparser/LimitDeparser.java | 10 +- .../util/deparser/MergeDeParser.java | 52 +- .../util/deparser/OrderByDeParser.java | 16 +- ...reshMaterializedViewStatementDeParser.java | 16 +- .../util/deparser/ResetStatementDeParser.java | 4 +- .../util/deparser/SelectDeParser.java | 459 ++++++++---- .../util/deparser/SetStatementDeParser.java | 14 +- .../ShowColumnsStatementDeParser.java | 2 +- .../deparser/ShowIndexStatementDeParser.java | 2 +- .../util/deparser/ShowStatementDeParser.java | 2 +- .../deparser/ShowTablesStatementDeparser.java | 2 +- .../util/deparser/StatementDeParser.java | 231 ++++--- .../util/deparser/TableStatementDeParser.java | 35 +- .../util/deparser/UpdateDeParser.java | 54 +- .../util/deparser/UpsertDeParser.java | 28 +- .../util/deparser/UseStatementDeParser.java | 6 +- .../deparser/ValuesStatementDeParser.java | 4 +- .../validator/ExpressionValidator.java | 6 + .../validation/validator/SelectValidator.java | 6 + .../validator/StatementValidator.java | 1 + .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 139 +++- src/site/sphinx/keywords.rst | 10 +- .../statement/piped/FromQueryTest.java | 24 + .../jsqlparser/test/AssortedFeatureTests.java | 8 +- .../net/sf/jsqlparser/test/TestUtils.java | 4 +- .../util/deparser/CreateViewDeParserTest.java | 10 +- .../util/deparser/ExecuteDeParserTest.java | 2 +- .../util/deparser/StatementDeParserTest.java | 6 +- 84 files changed, 1895 insertions(+), 924 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/AggregatePipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/CallPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/ExceptPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/IntersectPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/OrderByPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/PipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/PivotPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/RenamePipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/TableSamplePipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/UnPivotPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/UnionPipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/WherePipeOperator.java create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/piped/FromQueryTest.java diff --git a/README.md b/README.md index 083165f7c..fd312baa3 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Maven deploy snapshot](https://github.com/JSQLParser/JSqlParser/actions/workflows/maven_deploy.yml/badge.svg)](https://github.com/JSQLParser/JSqlParser/actions/workflows/maven_deploy.yml) [![Gradle CI](https://github.com/JSQLParser/JSqlParser/actions/workflows/gradle.yml/badge.svg)](https://github.com/JSQLParser/JSqlParser/actions/workflows/gradle.yml) -[![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) +[![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/6f9a2d7eb98f45969749e101322634a1)](https://www.codacy.com/gh/JSQLParser/JSqlParser/dashboard?utm_source=github.com&utm_medium=referral&utm_content=JSQLParser/JSqlParser&utm_campaign=Badge_Grade) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.jsqlparser/jsqlparser/badge.svg)](http://maven-badges.herokuapp.com/maven-central/com.github.jsqlparser/jsqlparser) [![Javadocs](https://www.javadoc.io/badge/com.github.jsqlparser/jsqlparser.svg)](https://www.javadoc.io/doc/com.github.jsqlparser/jsqlparser) [![Gitter](https://badges.gitter.im/JSQLParser/JSqlParser.svg)](https://gitter.im/JSQLParser/JSqlParser?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) @@ -47,6 +47,22 @@ Assertions.assertEquals("a", a.getColumnName()); Assertions.assertEquals("b", b.getColumnName()); } ``` +## Support for `Piped SQL` + +Work is progressing for parsing `Piped SQL`, a much saner and more logical way to write queries in its semantic order. +```sql +FROM Produce +|> WHERE + item != 'bananas' + AND category IN ('fruit', 'nut') +|> AGGREGATE COUNT(*) AS num_items, SUM(sales) AS total_sales + GROUP BY item +|> ORDER BY item DESC; +``` + +For details, please see https://storage.googleapis.com/gweb-research2023-media/pubtools/1004848.pdf, https://cloud.google.com/bigquery/docs/reference/standard-sql/pipe-syntax and https://duckdb.org/docs/sql/query_syntax/from.html#from-first-syntax + +## Java Version JSQLParser-4.9 was the last JDK8 compatible version. The recent JSQLParser-5.0 depends on JDK11 and introduces API breaking changes to the AST Visitors. Please see the Migration Guide for the details. diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index 66fe1cb80..aec008326 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -38,6 +38,7 @@ exports net.sf.jsqlparser.statement.grant; exports net.sf.jsqlparser.statement.insert; exports net.sf.jsqlparser.statement.merge; + exports net.sf.jsqlparser.statement.piped; exports net.sf.jsqlparser.statement.refresh; exports net.sf.jsqlparser.statement.select; exports net.sf.jsqlparser.statement.show; diff --git a/src/main/java/net/sf/jsqlparser/expression/Expression.java b/src/main/java/net/sf/jsqlparser/expression/Expression.java index a4807583a..1f733d564 100644 --- a/src/main/java/net/sf/jsqlparser/expression/Expression.java +++ b/src/main/java/net/sf/jsqlparser/expression/Expression.java @@ -20,7 +20,4 @@ default void accept(ExpressionVisitor expressionVisitor) { this.accept(expressionVisitor, null); } - ; - - } diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java index 19067bf47..ff7887f94 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitor.java @@ -56,6 +56,7 @@ import net.sf.jsqlparser.expression.operators.relational.TSQLLeftJoin; import net.sf.jsqlparser.expression.operators.relational.TSQLRightJoin; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; import net.sf.jsqlparser.statement.select.ParenthesedSelect; @@ -680,4 +681,6 @@ default void visit(Inverse inverse) { } T visit(CosineSimilarity cosineSimilarity, S context); + + T visit(FromQuery fromQuery, S context); } diff --git a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java index 96f3c5ea2..dd97ccad2 100644 --- a/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java @@ -56,6 +56,7 @@ import net.sf.jsqlparser.expression.operators.relational.TSQLLeftJoin; import net.sf.jsqlparser.expression.operators.relational.TSQLRightJoin; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; import net.sf.jsqlparser.statement.select.OrderByElement; @@ -813,4 +814,9 @@ public T visit(CosineSimilarity cosineSimilarity, S context) { return null; } + @Override + public T visit(FromQuery fromQuery, S context) { + return null; + } + } diff --git a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java index 8ecbca8bc..fb26ff2c2 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java +++ b/src/main/java/net/sf/jsqlparser/parser/ASTNodeAccessImpl.java @@ -65,4 +65,9 @@ public T getParent(Class clazz) { return clazz.cast(parent.jjtGetValue()); } + + @Override + public String toString() { + return appendTo(new StringBuilder()).toString(); + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java index efd7ee099..e8be0a5cb 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitor.java @@ -323,5 +323,4 @@ default void visit(ParenthesedUpdate parenthesedUpdate) { default void visit(ParenthesedDelete parenthesedDelete) { this.visit(parenthesedDelete, null); } - } diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/AggregatePipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/AggregatePipeOperator.java new file mode 100644 index 000000000..a053c19dd --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/AggregatePipeOperator.java @@ -0,0 +1,80 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.SelectItem; + +import java.util.ArrayList; + +public class AggregatePipeOperator extends PipeOperator { + private final ArrayList> selectItems = new ArrayList<>(); + private final ArrayList> groupItems = new ArrayList<>(); + private boolean usingShortHandOrdering = false; + + public AggregatePipeOperator(SelectItem selectItem) { + selectItems.add(selectItem); + } + + public ArrayList> getSelectItems() { + return selectItems; + } + + public ArrayList> getGroupItems() { + return groupItems; + } + + public AggregatePipeOperator add(SelectItem selectItem) { + selectItems.add(selectItem); + return this; + } + + public AggregatePipeOperator with(SelectItem selectItem) { + return this.add(selectItem); + } + + public AggregatePipeOperator addGroupItem(SelectItem selectItem) { + groupItems.add(selectItem); + return this; + } + + public AggregatePipeOperator withGroupItem(SelectItem selectItem) { + return this.addGroupItem(selectItem); + } + + public boolean isUsingShortHandOrdering() { + return usingShortHandOrdering; + } + + public AggregatePipeOperator setShorthandOrdering(boolean usingShortHandOrdering) { + this.usingShortHandOrdering = usingShortHandOrdering; + return this; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append("AGGREGATE"); + int i = 0; + for (SelectItem selectItem : selectItems) { + builder.append(i++ > 0 ? ", " : " ").append(selectItem); + } + builder.append("\n"); + + if (!groupItems.isEmpty()) { + builder.append("\t").append("GROUP"); + if (isUsingShortHandOrdering()) { + builder.append(" AND ORDER"); + } + builder.append(" BY"); + i = 0; + for (SelectItem selectItem : groupItems) { + builder.append(i++ > 0 ? ", " : " ").append(selectItem); + } + builder.append("\n"); + } + + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java new file mode 100644 index 000000000..aea619b44 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java @@ -0,0 +1,9 @@ +package net.sf.jsqlparser.statement.piped; + +public class AsPipeOperator extends PipeOperator { + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/CallPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/CallPipeOperator.java new file mode 100644 index 000000000..982b715c1 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/CallPipeOperator.java @@ -0,0 +1,9 @@ +package net.sf.jsqlparser.statement.piped; + +public class CallPipeOperator extends PipeOperator { + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java new file mode 100644 index 000000000..95ec84630 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class DropPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/ExceptPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/ExceptPipeOperator.java new file mode 100644 index 000000000..2618eb814 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/ExceptPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class ExceptPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java new file mode 100644 index 000000000..57e86b202 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class ExtendPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java b/src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java new file mode 100644 index 000000000..874a82884 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java @@ -0,0 +1,203 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.statement.StatementVisitor; +import net.sf.jsqlparser.statement.select.FromItem; +import net.sf.jsqlparser.statement.select.FromItemVisitor; +import net.sf.jsqlparser.statement.select.Pivot; +import net.sf.jsqlparser.statement.select.Select; +import net.sf.jsqlparser.statement.select.SelectVisitor; +import net.sf.jsqlparser.statement.select.UnPivot; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; + +public class FromQuery extends Select { + private FromItem fromItem; + private final ArrayList pipeOperators = new ArrayList<>(); + + public FromQuery(FromItem fromItem) { + this.fromItem = fromItem; + } + + public FromItem getFromItem() { + return fromItem; + } + + public FromQuery setFromItem(FromItem fromItem) { + this.fromItem = fromItem; + return this; + } + + public FromQuery with(FromItem fromItem) { + return setFromItem(fromItem); + } + + public ArrayList getPipeOperators() { + return pipeOperators; + } + + public FromQuery add(PipeOperator operator) { + pipeOperators.add(operator); + return this; + } + + public void add(int index, PipeOperator element) { + pipeOperators.add(index, element); + } + + public PipeOperator remove(int index) { + return pipeOperators.remove(index); + } + + public boolean remove(Object o) { + return pipeOperators.remove(o); + } + + public void clear() { + pipeOperators.clear(); + } + + public boolean addAll(Collection c) { + return pipeOperators.addAll(c); + } + + public boolean addAll(int index, Collection c) { + return pipeOperators.addAll(index, c); + } + + public boolean removeAll(Collection c) { + return pipeOperators.removeAll(c); + } + + public boolean retainAll(Collection c) { + return pipeOperators.retainAll(c); + } + + public List subList(int fromIndex, int toIndex) { + return pipeOperators.subList(fromIndex, toIndex); + } + + public void forEach(Consumer action) { + pipeOperators.forEach(action); + } + + public Spliterator spliterator() { + return pipeOperators.spliterator(); + } + + public boolean removeIf(Predicate filter) { + return pipeOperators.removeIf(filter); + } + + public void replaceAll(UnaryOperator operator) { + pipeOperators.replaceAll(operator); + } + + public FromQuery with(PipeOperator operator) { + return this.add(operator); + } + + public PipeOperator get(int index) { + return pipeOperators.get(index); + } + + public PipeOperator set(int index, PipeOperator element) { + return pipeOperators.set(index, element); + } + + public int size() { + return pipeOperators.size(); + } + + public boolean isEmpty() { + return pipeOperators.isEmpty(); + } + + public boolean contains(Object o) { + return pipeOperators.contains(o); + } + + public int indexOf(Object o) { + return pipeOperators.indexOf(o); + } + + public int lastIndexOf(Object o) { + return pipeOperators.lastIndexOf(o); + } + + public Object[] toArray() { + return pipeOperators.toArray(); + } + + public T[] toArray(T[] a) { + return pipeOperators.toArray(a); + } + + @Override + public Alias getAlias() { + return null; + } + + @Override + public void setAlias(Alias alias) { + + } + + @Override + public Pivot getPivot() { + return null; + } + + @Override + public void setPivot(Pivot pivot) { + + } + + @Override + public UnPivot getUnPivot() { + return null; + } + + @Override + public void setUnPivot(UnPivot unpivot) { + + } + + @Override + public T accept(ExpressionVisitor expressionVisitor, S context) { + return expressionVisitor.visit(this, context); + } + + @Override + public T accept(StatementVisitor statementVisitor, S context) { + return statementVisitor.visit(this, context); + } + + @Override + public T accept(FromItemVisitor fromItemVisitor, S context) { + return fromItemVisitor.visit(this, context); + } + + @Override + public T accept(SelectVisitor selectVisitor, S context) { + return selectVisitor.visit(this, context); + } + + + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("FROM ").append(fromItem).append("\n"); + for (PipeOperator operator : pipeOperators) { + operator.appendTo(builder); + } + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/IntersectPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/IntersectPipeOperator.java new file mode 100644 index 000000000..d2ff37368 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/IntersectPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class IntersectPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java new file mode 100644 index 000000000..8b86f0693 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class JoinPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java new file mode 100644 index 000000000..97f8f9b81 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class LimitPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/OrderByPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/OrderByPipeOperator.java new file mode 100644 index 000000000..4cc6b8c39 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/OrderByPipeOperator.java @@ -0,0 +1,38 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.OrderByElement; + +import java.util.List; + +public class OrderByPipeOperator extends PipeOperator { + private List orderByElements; + + public OrderByPipeOperator(List orderByElements) { + this.orderByElements = orderByElements; + } + + public List getOrderByElements() { + return orderByElements; + } + + public OrderByPipeOperator setOrderByElements(List orderByElements) { + this.orderByElements = orderByElements; + return this; + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ") + .append("ORDER BY "); + for (OrderByElement orderByElement : orderByElements) { + builder.append(orderByElement); + } + builder.append("\n"); + return builder; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperator.java new file mode 100644 index 000000000..7dea891b9 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperator.java @@ -0,0 +1,7 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.parser.ASTNodeAccessImpl; + +public abstract class PipeOperator extends ASTNodeAccessImpl { + public abstract T accept(PipeOperatorVisitor visitor, S context); +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java b/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java new file mode 100644 index 000000000..f53bce5cd --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java @@ -0,0 +1,42 @@ +package net.sf.jsqlparser.statement.piped; + +public interface PipeOperatorVisitor { + T visit(AggregatePipeOperator aggregate, S context); + + T visit(AsPipeOperator as, S context); + + T visit(CallPipeOperator call, S context); + + T visit(DropPipeOperator drop, S context); + + T visit(ExceptPipeOperator except, S context); + + T visit(ExtendPipeOperator extend, S context); + + T visit(IntersectPipeOperator intersect, S context); + + T visit(JoinPipeOperator join, S context); + + T visit(LimitPipeOperator limit, S context); + + T visit(OrderByPipeOperator orderBy, S context); + + T visit(PivotPipeOperator pivot, S context); + + T visit(RenamePipeOperator rename, S context); + + T visit(SelectPipeOperator select, S context); + + T visit(SetPipeOperator set, S context); + + T visit(TableSamplePipeOperator tableSample, S context); + + T visit(UnionPipeOperator union, S context); + + T visit(UnPivotPipeOperator unPivot, S context); + + T visit(WherePipeOperator where, S context); + + T visit(WindowPipeOperator window, S context); +} + diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/PivotPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/PivotPipeOperator.java new file mode 100644 index 000000000..70d337189 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/PivotPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class PivotPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/RenamePipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/RenamePipeOperator.java new file mode 100644 index 000000000..1f183d158 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/RenamePipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class RenamePipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java new file mode 100644 index 000000000..222a52c6e --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java @@ -0,0 +1,38 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.SelectItem; + +import java.util.ArrayList; + +public class SelectPipeOperator extends PipeOperator { + private final ArrayList> selectItems = new ArrayList<>(); + + public SelectPipeOperator(SelectItem selectItem) { + selectItems.add(selectItem); + } + + public SelectPipeOperator add(SelectItem selectItem) { + selectItems.add(selectItem); + return this; + } + + public SelectPipeOperator with(SelectItem selectItem) { + return this.add(selectItem); + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append("SELECT"); + int i = 0; + for (SelectItem selectItem : selectItems) { + builder.append(i++ > 0 ? ", " : " ").append(selectItem); + } + builder.append("\n"); + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java new file mode 100644 index 000000000..0c88444a3 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class SetPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/TableSamplePipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/TableSamplePipeOperator.java new file mode 100644 index 000000000..cf209b966 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/TableSamplePipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class TableSamplePipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/UnPivotPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/UnPivotPipeOperator.java new file mode 100644 index 000000000..5f4b7e328 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/UnPivotPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class UnPivotPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/UnionPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/UnionPipeOperator.java new file mode 100644 index 000000000..657e2aa7f --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/UnionPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class UnionPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/WherePipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/WherePipeOperator.java new file mode 100644 index 000000000..17fe359c4 --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/WherePipeOperator.java @@ -0,0 +1,34 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.expression.Expression; + +public class WherePipeOperator extends PipeOperator { + private Expression expression; + + public WherePipeOperator(Expression expression) { + this.expression = expression; + } + + public Expression getExpression() { + return expression; + } + + public WherePipeOperator setExpression(Expression expression) { + this.expression = expression; + return this; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ") + .append("WHERE ") + .append(expression) + .append("\n"); + return builder; + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java new file mode 100644 index 000000000..639bdca6b --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java @@ -0,0 +1,8 @@ +package net.sf.jsqlparser.statement.piped; + +public class WindowPipeOperator extends PipeOperator { + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java index d98614843..0d97c4e4b 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitor.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.piped.FromQuery; public interface FromItemVisitor { @@ -66,4 +67,6 @@ default void visit(SetOperationList setOperationList) { default void visit(TableStatement tableStatement) { this.visit(tableStatement, null); } + + T visit(FromQuery fromQuery, S context); } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java index fa530e32f..1ea920707 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/FromItemVisitorAdapter.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.statement.select; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.piped.FromQuery; @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class FromItemVisitorAdapter implements FromItemVisitor { @@ -67,4 +68,9 @@ public T visit(TableStatement tableStatement, S context) { return null; } + + @Override + public T visit(FromQuery fromQuery, S context) { + return null; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Select.java b/src/main/java/net/sf/jsqlparser/statement/select/Select.java index 329bd6388..7a07105fd 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Select.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Select.java @@ -359,7 +359,9 @@ public void setUnPivot(UnPivot unPivot) { this.unPivot = unPivot; } - public abstract StringBuilder appendSelectBodyTo(StringBuilder builder); + public StringBuilder appendSelectBodyTo(StringBuilder builder) { + return builder; + }; @SuppressWarnings({"PMD.CyclomaticComplexity"}) public StringBuilder appendTo(StringBuilder builder) { 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 8a4e9667c..94357bcd9 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitor.java @@ -9,6 +9,8 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.statement.piped.FromQuery; + public interface SelectVisitor { T visit(ParenthesedSelect parenthesedSelect, S context); @@ -23,6 +25,8 @@ default void visit(PlainSelect plainSelect) { this.visit(plainSelect, null); } + T visit(FromQuery fromQuery, S context); + T visit(SetOperationList setOpList, S context); default void visit(SetOperationList setOpList) { 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 d20fdfdd1..462160e9f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/SelectVisitorAdapter.java @@ -9,6 +9,8 @@ */ package net.sf.jsqlparser.statement.select; +import net.sf.jsqlparser.statement.piped.FromQuery; + @SuppressWarnings({"PMD.UncommentedEmptyMethodBody"}) public class SelectVisitorAdapter implements SelectVisitor { @@ -22,6 +24,11 @@ public T visit(PlainSelect plainSelect, S context) { return null; } + @Override + public T visit(FromQuery fromQuery, S context) { + return null; + } + @Override public T visit(SetOperationList setOpList, S context) { for (Select select : setOpList.getSelects()) { diff --git a/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java b/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java index 80f6bb6dd..baf251ecc 100644 --- a/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java +++ b/src/main/java/net/sf/jsqlparser/util/AddAliasesVisitor.java @@ -13,6 +13,7 @@ import java.util.List; import net.sf.jsqlparser.expression.Alias; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.LateralSubSelect; import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.PlainSelect; @@ -61,6 +62,11 @@ public T visit(PlainSelect plainSelect, S context) { return null; } + @Override + public T visit(FromQuery fromQuery, S context) { + throw new UnsupportedOperationException(NOT_SUPPORTED_YET); + } + @Override public T visit(SetOperationList setOperationList, S context) { for (Select select : setOperationList.getSelects()) { diff --git a/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java b/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java index 3f0377728..ca642b7a1 100644 --- a/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java +++ b/src/main/java/net/sf/jsqlparser/util/ConnectExpressionsVisitor.java @@ -15,6 +15,7 @@ import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.BinaryExpression; import net.sf.jsqlparser.expression.Expression; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.LateralSubSelect; import net.sf.jsqlparser.statement.select.ParenthesedSelect; import net.sf.jsqlparser.statement.select.PlainSelect; @@ -39,7 +40,7 @@ public abstract class ConnectExpressionsVisitor implements SelectVisitor, SelectItemVisitor { private final List> itemsExpr = - new LinkedList>(); + new LinkedList<>(); private String alias = "expr"; public ConnectExpressionsVisitor() {} @@ -90,6 +91,11 @@ public T visit(PlainSelect plainSelect, S context) { return null; } + @Override + public T visit(FromQuery fromQuery, S context) { + throw new UnsupportedOperationException("Not supported yet."); + } + @Override public T visit(SetOperationList setOpList, S context) { for (Select select : setOpList.getSelects()) { diff --git a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java index 3e8bc9e1b..16c30f4f2 100644 --- a/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java +++ b/src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java @@ -159,6 +159,7 @@ import net.sf.jsqlparser.statement.insert.Insert; import net.sf.jsqlparser.statement.insert.ParenthesedInsert; import net.sf.jsqlparser.statement.merge.Merge; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.refresh.RefreshMaterializedViewStatement; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; @@ -857,6 +858,11 @@ public void visit(TableStatement tableStatement) { SelectVisitor.super.visit(tableStatement); } + @Override + public Void visit(FromQuery fromQuery, S context) { + return null; + } + /** * 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/AbstractDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/AbstractDeParser.java index d9915eb62..6458f79c9 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/AbstractDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/AbstractDeParser.java @@ -20,10 +20,10 @@ * @param the type of statement this DeParser supports */ abstract class AbstractDeParser { - protected StringBuilder buffer; + protected StringBuilder builder; - protected AbstractDeParser(StringBuilder buffer) { - this.buffer = buffer; + protected AbstractDeParser(StringBuilder builder) { + this.builder = builder; } public static void deparseUpdateSets(List updateSets, StringBuilder buffer, @@ -43,12 +43,12 @@ public static void deparseUpdateSets(List updateSets, StringBuilder b } } - public StringBuilder getBuffer() { - return buffer; + public StringBuilder getBuilder() { + return builder; } - public void setBuffer(StringBuilder buffer) { - this.buffer = buffer; + public void setBuilder(StringBuilder builder) { + this.builder = builder; } /** diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/AlterDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/AlterDeParser.java index 2cc04fcab..bfc00e7ef 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/AlterDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/AlterDeParser.java @@ -19,7 +19,7 @@ public AlterDeParser(StringBuilder buffer) { @Override public void deParse(Alter alter) { - buffer.append(alter.toString()); + builder.append(alter.toString()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/AlterSequenceDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/AlterSequenceDeParser.java index f01454762..b9c743bdc 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/AlterSequenceDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/AlterSequenceDeParser.java @@ -26,7 +26,7 @@ public AlterSequenceDeParser(StringBuilder buffer) { @Override public void deParse(AlterSequence statement) { - buffer.append("ALTER SEQUENCE "); - buffer.append(statement.getSequence()); + builder.append("ALTER SEQUENCE "); + builder.append(statement.getSequence()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/AlterSessionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/AlterSessionDeParser.java index 69bab62a5..a2f758486 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/AlterSessionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/AlterSessionDeParser.java @@ -19,7 +19,7 @@ public AlterSessionDeParser(StringBuilder buffer) { @Override public void deParse(AlterSession alterSession) { - buffer.append(alterSession.toString()); + builder.append(alterSession.toString()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/AlterViewDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/AlterViewDeParser.java index 07d6c1907..3c1c0bbaa 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/AlterViewDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/AlterViewDeParser.java @@ -33,15 +33,15 @@ public AlterViewDeParser(StringBuilder buffer, SelectVisitor sele @Override public void deParse(AlterView alterView) { if (alterView.isUseReplace()) { - buffer.append("REPLACE "); + builder.append("REPLACE "); } else { - buffer.append("ALTER "); + builder.append("ALTER "); } - buffer.append("VIEW ").append(alterView.getView().getFullyQualifiedName()); + builder.append("VIEW ").append(alterView.getView().getFullyQualifiedName()); if (alterView.getColumnNames() != null) { - buffer.append(PlainSelect.getStringList(alterView.getColumnNames(), true, true)); + builder.append(PlainSelect.getStringList(alterView.getColumnNames(), true, true)); } - buffer.append(" AS "); + builder.append(" AS "); alterView.getSelect().accept(selectVisitor, null); } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateIndexDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateIndexDeParser.java index a82f478d7..211361bb0 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateIndexDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateIndexDeParser.java @@ -24,46 +24,46 @@ public CreateIndexDeParser(StringBuilder buffer) { public void deParse(CreateIndex createIndex) { Index index = createIndex.getIndex(); - buffer.append("CREATE "); + builder.append("CREATE "); if (index.getType() != null) { - buffer.append(index.getType()); - buffer.append(" "); + builder.append(index.getType()); + builder.append(" "); } - buffer.append("INDEX "); + builder.append("INDEX "); if (createIndex.isUsingIfNotExists()) { - buffer.append("IF NOT EXISTS "); + builder.append("IF NOT EXISTS "); } - buffer.append(index.getName()); + builder.append(index.getName()); String using = index.getUsing(); if (using != null && createIndex.isIndexTypeBeforeOn()) { - buffer.append(" USING "); - buffer.append(using); + builder.append(" USING "); + builder.append(using); } - buffer.append(" ON "); - buffer.append(createIndex.getTable().getFullyQualifiedName()); + builder.append(" ON "); + builder.append(createIndex.getTable().getFullyQualifiedName()); if (using != null && !createIndex.isIndexTypeBeforeOn()) { - buffer.append(" USING "); - buffer.append(using); + builder.append(" USING "); + builder.append(using); } if (index.getColumnsNames() != null) { - buffer.append(" ("); - buffer.append(index.getColumnWithParams().stream() + builder.append(" ("); + builder.append(index.getColumnWithParams().stream() .map(cp -> cp.columnName + (cp.getParams() != null ? " " + String.join(" ", cp.getParams()) : "")) .collect(joining(", "))); - buffer.append(")"); + builder.append(")"); } if (createIndex.getTailParameters() != null) { for (String param : createIndex.getTailParameters()) { - buffer.append(" ").append(param); + builder.append(" ").append(param); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateSequenceDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateSequenceDeParser.java index 08ea89473..d4f475098 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateSequenceDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateSequenceDeParser.java @@ -26,7 +26,7 @@ public CreateSequenceDeParser(StringBuilder buffer) { @Override public void deParse(CreateSequence statement) { - buffer.append("CREATE SEQUENCE "); - buffer.append(statement.getSequence()); + builder.append("CREATE SEQUENCE "); + builder.append(statement.getSequence()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateSynonymDeparser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateSynonymDeparser.java index 413249d16..4c8a1e1f2 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateSynonymDeparser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateSynonymDeparser.java @@ -23,15 +23,15 @@ public CreateSynonymDeparser(StringBuilder buffer) { @Override void deParse(CreateSynonym createSynonym) { - buffer.append("CREATE "); + builder.append("CREATE "); if (createSynonym.isOrReplace()) { - buffer.append("OR REPLACE "); + builder.append("OR REPLACE "); } if (createSynonym.isPublicSynonym()) { - buffer.append("PUBLIC "); + builder.append("PUBLIC "); } - buffer.append("SYNONYM " + createSynonym.getSynonym()); - buffer.append(' '); - buffer.append("FOR " + createSynonym.getFor()); + builder.append("SYNONYM " + createSynonym.getSynonym()); + builder.append(' '); + builder.append("FOR " + createSynonym.getFor()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/CreateTableDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/CreateTableDeParser.java index 72a82c862..1d9fc85f3 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateTableDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateTableDeParser.java @@ -34,97 +34,97 @@ public CreateTableDeParser(StatementDeParser statementDeParser, StringBuilder bu @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void deParse(CreateTable createTable) { - buffer.append("CREATE "); + builder.append("CREATE "); if (createTable.isOrReplace()) { - buffer.append("OR REPLACE "); + builder.append("OR REPLACE "); } if (createTable.isUnlogged()) { - buffer.append("UNLOGGED "); + builder.append("UNLOGGED "); } String params = PlainSelect.getStringList(createTable.getCreateOptionsStrings(), false, false); if (!params.isEmpty()) { - buffer.append(params).append(' '); + builder.append(params).append(' '); } - buffer.append("TABLE "); + builder.append("TABLE "); if (createTable.isIfNotExists()) { - buffer.append("IF NOT EXISTS "); + builder.append("IF NOT EXISTS "); } - buffer.append(createTable.getTable().getFullyQualifiedName()); + builder.append(createTable.getTable().getFullyQualifiedName()); if (createTable.getColumns() != null && !createTable.getColumns().isEmpty()) { - buffer.append(" ("); + builder.append(" ("); Iterator columnIterator = createTable.getColumns().iterator(); - buffer.append(columnIterator.next()); + builder.append(columnIterator.next()); while (columnIterator.hasNext()) { - buffer.append(", ").append(columnIterator.next()); + builder.append(", ").append(columnIterator.next()); } - buffer.append(")"); + builder.append(")"); } if (createTable.getColumnDefinitions() != null) { - buffer.append(" ("); + builder.append(" ("); for (Iterator iter = createTable.getColumnDefinitions().iterator(); iter.hasNext();) { ColumnDefinition columnDefinition = iter.next(); - buffer.append(columnDefinition.getColumnName()); - buffer.append(" "); - buffer.append(columnDefinition.getColDataType().toString()); + builder.append(columnDefinition.getColumnName()); + builder.append(" "); + builder.append(columnDefinition.getColDataType().toString()); if (columnDefinition.getColumnSpecs() != null) { for (String s : columnDefinition.getColumnSpecs()) { - buffer.append(" "); - buffer.append(s); + builder.append(" "); + builder.append(s); } } if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } if (createTable.getIndexes() != null) { for (Index index : createTable.getIndexes()) { - buffer.append(", "); - buffer.append(index.toString()); + builder.append(", "); + builder.append(index.toString()); } } - buffer.append(")"); + builder.append(")"); } params = PlainSelect.getStringList(createTable.getTableOptionsStrings(), false, false); if (!"".equals(params)) { - buffer.append(' ').append(params); + builder.append(' ').append(params); } if (createTable.getRowMovement() != null) { - buffer.append(' ').append(createTable.getRowMovement().getMode().toString()) + builder.append(' ').append(createTable.getRowMovement().getMode().toString()) .append(" ROW MOVEMENT"); } if (createTable.getSelect() != null) { - buffer.append(" AS "); + builder.append(" AS "); if (createTable.isSelectParenthesis()) { - buffer.append("("); + builder.append("("); } Select sel = createTable.getSelect(); sel.accept(this.statementDeParser, null); if (createTable.isSelectParenthesis()) { - buffer.append(")"); + builder.append(")"); } } if (createTable.getLikeTable() != null) { - buffer.append(" LIKE "); + builder.append(" LIKE "); if (createTable.isSelectParenthesis()) { - buffer.append("("); + builder.append("("); } Table table = createTable.getLikeTable(); - buffer.append(table.getFullyQualifiedName()); + builder.append(table.getFullyQualifiedName()); if (createTable.isSelectParenthesis()) { - buffer.append(")"); + builder.append(")"); } } if (createTable.getSpannerInterleaveIn() != null) { - buffer.append(", ").append(createTable.getSpannerInterleaveIn()); + builder.append(", ").append(createTable.getSpannerInterleaveIn()); } } 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 8c77ddfe3..196b4d4d9 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/CreateViewDeParser.java @@ -23,7 +23,7 @@ public class CreateViewDeParser extends AbstractDeParser { public CreateViewDeParser(StringBuilder buffer) { super(buffer); SelectDeParser selectDeParser = new SelectDeParser(); - selectDeParser.setBuffer(buffer); + selectDeParser.setBuilder(buffer); ExpressionDeParser expressionDeParser = new ExpressionDeParser(selectDeParser, buffer); selectDeParser.setExpressionVisitor(expressionDeParser); selectVisitor = selectDeParser; @@ -37,16 +37,16 @@ public CreateViewDeParser(StringBuilder buffer, SelectVisitor sel @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void deParse(CreateView createView) { - buffer.append("CREATE "); + builder.append("CREATE "); if (createView.isOrReplace()) { - buffer.append("OR REPLACE "); + builder.append("OR REPLACE "); } switch (createView.getForce()) { case FORCE: - buffer.append("FORCE "); + builder.append("FORCE "); break; case NO_FORCE: - buffer.append("NO FORCE "); + builder.append("NO FORCE "); break; case NONE: break; @@ -54,36 +54,36 @@ public void deParse(CreateView createView) { // nothing } if (createView.isSecure()) { - buffer.append("SECURE "); + builder.append("SECURE "); } if (createView.getTemporary() != TemporaryOption.NONE) { - buffer.append(createView.getTemporary().name()).append(" "); + builder.append(createView.getTemporary().name()).append(" "); } if (createView.isMaterialized()) { - buffer.append("MATERIALIZED "); + builder.append("MATERIALIZED "); } - buffer.append("VIEW ").append(createView.getView().getFullyQualifiedName()); + builder.append("VIEW ").append(createView.getView().getFullyQualifiedName()); if (createView.isIfNotExists()) { - buffer.append(" IF NOT EXISTS"); + builder.append(" IF NOT EXISTS"); } if (createView.getAutoRefresh() != AutoRefreshOption.NONE) { - buffer.append(" AUTO REFRESH ").append(createView.getAutoRefresh().name()); + builder.append(" AUTO REFRESH ").append(createView.getAutoRefresh().name()); } if (createView.getColumnNames() != null) { - buffer.append("("); - buffer.append(createView.getColumnNames()); - buffer.append(")"); + builder.append("("); + builder.append(createView.getColumnNames()); + builder.append(")"); } if (createView.getViewCommentOptions() != null) { - buffer.append( + builder.append( PlainSelect.getStringList(createView.getViewCommentOptions(), false, false)); } - buffer.append(" AS "); + builder.append(" AS "); Select select = createView.getSelect(); select.accept(selectVisitor, null); if (createView.isWithReadOnly()) { - buffer.append(" WITH READ ONLY"); + builder.append(" WITH READ ONLY"); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/DeclareStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/DeclareStatementDeParser.java index 3e1db92e9..a24f63e9f 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/DeclareStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/DeclareStatementDeParser.java @@ -26,41 +26,41 @@ public DeclareStatementDeParser(ExpressionVisitor expressionVisit @Override @SuppressWarnings({"PMD.CyclomaticComplexity"}) public void deParse(DeclareStatement declare) { - buffer.append("DECLARE "); + builder.append("DECLARE "); if (declare.getUserVariable() != null) { declare.getUserVariable().accept(expressionVisitor, null); } if (declare.getType() == DeclareType.AS) { - buffer.append(" AS "); - buffer.append(declare.getTypeName()); + builder.append(" AS "); + builder.append(declare.getTypeName()); return; } if (declare.getType() == DeclareType.TABLE) { - buffer.append(" TABLE ("); + builder.append(" TABLE ("); for (int i = 0; i < declare.getColumnDefinitions().size(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } - buffer.append(declare.getColumnDefinitions().get(i).toString()); + builder.append(declare.getColumnDefinitions().get(i).toString()); } - buffer.append(")"); + builder.append(")"); } else { if (declare.getTypeDefinitions() != null) { for (int i = 0; i < declare.getTypeDefinitions().size(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } DeclareStatement.TypeDefExpr type = declare.getTypeDefinitions().get(i); if (type.userVariable != null) { type.userVariable.accept(expressionVisitor, null); - buffer.append(" "); + builder.append(" "); } - buffer.append(type.colDataType.toString()); + builder.append(type.colDataType.toString()); if (type.defaultExpr != null) { - buffer.append(" = "); + builder.append(" = "); type.defaultExpr.accept(expressionVisitor, null); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java index 11e6eb001..23b5eb32b 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/DeleteDeParser.java @@ -39,56 +39,56 @@ public DeleteDeParser(ExpressionVisitor expressionVisitor, @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void deParse(Delete delete) { if (delete.getWithItemsList() != null && !delete.getWithItemsList().isEmpty()) { - buffer.append("WITH "); + builder.append("WITH "); for (Iterator> iter = delete.getWithItemsList().iterator(); iter .hasNext();) { WithItem withItem = iter.next(); - buffer.append(withItem); + builder.append(withItem); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } - buffer.append("DELETE"); + builder.append("DELETE"); if (delete.getOracleHint() != null) { - buffer.append(delete.getOracleHint()).append(" "); + builder.append(delete.getOracleHint()).append(" "); } if (delete.getModifierPriority() != null) { - buffer.append(" ").append(delete.getModifierPriority()); + builder.append(" ").append(delete.getModifierPriority()); } if (delete.isModifierQuick()) { - buffer.append(" QUICK"); + builder.append(" QUICK"); } if (delete.isModifierIgnore()) { - buffer.append(" IGNORE"); + builder.append(" IGNORE"); } if (delete.getTables() != null && !delete.getTables().isEmpty()) { - buffer.append( + builder.append( delete.getTables().stream().map(Table::getFullyQualifiedName) .collect(joining(", ", " ", ""))); } if (delete.getOutputClause() != null) { - delete.getOutputClause().appendTo(buffer); + delete.getOutputClause().appendTo(builder); } if (delete.isHasFrom()) { - buffer.append(" FROM"); + builder.append(" FROM"); } - buffer.append(" ").append(delete.getTable().toString()); + builder.append(" ").append(delete.getTable().toString()); if (delete.getUsingList() != null && !delete.getUsingList().isEmpty()) { - buffer.append(" USING").append( + builder.append(" USING").append( delete.getUsingList().stream().map(Table::toString) .collect(joining(", ", " ", ""))); } if (delete.getJoins() != null) { for (Join join : delete.getJoins()) { if (join.isSimple()) { - buffer.append(", ").append(join); + builder.append(", ").append(join); } else { - buffer.append(" ").append(join); + builder.append(" ").append(join); } } } @@ -96,24 +96,24 @@ public void deParse(Delete delete) { deparseWhereClause(delete); if (delete.getPreferringClause() != null) { - buffer.append(" ").append(delete.getPreferringClause()); + builder.append(" ").append(delete.getPreferringClause()); } if (delete.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer).deParse(delete.getOrderByElements()); + new OrderByDeParser(expressionVisitor, builder).deParse(delete.getOrderByElements()); } if (delete.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(delete.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(delete.getLimit()); } if (delete.getReturningClause() != null) { - delete.getReturningClause().appendTo(buffer); + delete.getReturningClause().appendTo(builder); } } protected void deparseWhereClause(Delete delete) { if (delete.getWhere() != null) { - buffer.append(" WHERE "); + builder.append(" WHERE "); delete.getWhere().accept(expressionVisitor, null); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java index 709ed6e8a..64c39b505 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/DropDeParser.java @@ -20,26 +20,26 @@ public DropDeParser(StringBuilder buffer) { @Override public void deParse(Drop drop) { - buffer.append("DROP "); + builder.append("DROP "); if (drop.isUsingTemporary()) { - buffer.append("TEMPORARY "); + builder.append("TEMPORARY "); } if (drop.isMaterialized()) { - buffer.append("MATERIALIZED "); + builder.append("MATERIALIZED "); } - buffer.append(drop.getType()); + builder.append(drop.getType()); if (drop.isIfExists()) { - buffer.append(" IF EXISTS"); + builder.append(" IF EXISTS"); } - buffer.append(" ").append(drop.getName()); + builder.append(" ").append(drop.getName()); if (drop.getType().equals("FUNCTION")) { - buffer.append(Drop.formatFuncParams(drop.getParamsByType("FUNCTION"))); + builder.append(Drop.formatFuncParams(drop.getParamsByType("FUNCTION"))); } if (drop.getParameters() != null && !drop.getParameters().isEmpty()) { - buffer.append(" ") + builder.append(" ") .append(PlainSelect.getStringList(drop.getParameters(), false, false)); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExecuteDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExecuteDeParser.java index f9daaa8a9..4034bd152 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExecuteDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExecuteDeParser.java @@ -27,23 +27,23 @@ public ExecuteDeParser(ExpressionVisitor expressionVisitor, @Override public void deParse(Execute execute) { - buffer.append(execute.getExecType().name()).append(" ").append(execute.getName()); + builder.append(execute.getExecType().name()).append(" ").append(execute.getName()); if (execute.isParenthesis()) { - buffer.append(" ("); + builder.append(" ("); } else if (execute.getExprList() != null) { - buffer.append(" "); + builder.append(" "); } if (execute.getExprList() != null) { List expressions = execute.getExprList().getExpressions(); for (int i = 0; i < expressions.size(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } expressions.get(i).accept(expressionVisitor, null); } } if (execute.isParenthesis()) { - buffer.append(")"); + builder.append(")"); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index d0f175e78..759be6f68 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -119,6 +119,7 @@ import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; import net.sf.jsqlparser.statement.create.table.ColDataType; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; import net.sf.jsqlparser.statement.select.OrderByElement; @@ -161,88 +162,88 @@ public ExpressionDeParser(SelectVisitor selectVisitor, StringBuil @Override public StringBuilder visit(Addition addition, S context) { deparse(addition, " + ", null); - return buffer; + return builder; } @Override public StringBuilder visit(AndExpression andExpression, S context) { deparse(andExpression, andExpression.isUseOperator() ? " && " : " AND ", null); - return buffer; + return builder; } @Override public StringBuilder visit(Between between, S context) { between.getLeftExpression().accept(this, context); if (between.isNot()) { - buffer.append(" NOT"); + builder.append(" NOT"); } - buffer.append(" BETWEEN "); + builder.append(" BETWEEN "); between.getBetweenExpressionStart().accept(this, context); - buffer.append(" AND "); + builder.append(" AND "); between.getBetweenExpressionEnd().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(OverlapsCondition overlapsCondition, S context) { - buffer.append(overlapsCondition.toString()); - return buffer; + builder.append(overlapsCondition.toString()); + return builder; } @Override public StringBuilder visit(EqualsTo equalsTo, S context) { deparse(equalsTo, " = ", null); - return buffer; + return builder; } @Override public StringBuilder visit(Division division, S context) { deparse(division, " / ", null); - return buffer; + return builder; } @Override public StringBuilder visit(IntegerDivision division, S context) { deparse(division, " DIV ", null); - return buffer; + return builder; } @Override public StringBuilder visit(DoubleValue doubleValue, S context) { - buffer.append(doubleValue.toString()); - return buffer; + builder.append(doubleValue.toString()); + return builder; } @Override public StringBuilder visit(HexValue hexValue, S context) { - buffer.append(hexValue.toString()); - return buffer; + builder.append(hexValue.toString()); + return builder; } @Override public StringBuilder visit(NotExpression notExpr, S context) { if (notExpr.isExclamationMark()) { - buffer.append("! "); + builder.append("! "); } else { - buffer.append(NOT); + builder.append(NOT); } notExpr.getExpression().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(BitwiseRightShift expr, S context) { deparse(expr, " >> ", null); - return buffer; + return builder; } @Override public StringBuilder visit(BitwiseLeftShift expr, S context) { deparse(expr, " << ", null); - return buffer; + return builder; } public StringBuilder deparse( @@ -253,28 +254,28 @@ public StringBuilder deparse( // } expression.getLeftExpression().accept(this, context); if (expression.getOldOracleJoinSyntax() == EqualsTo.ORACLE_JOIN_RIGHT) { - buffer.append("(+)"); + builder.append("(+)"); } - buffer.append(operator); + builder.append(operator); expression.getRightExpression().accept(this, context); if (expression.getOldOracleJoinSyntax() == EqualsTo.ORACLE_JOIN_LEFT) { - buffer.append("(+)"); + builder.append("(+)"); } - return buffer; + return builder; } @Override public StringBuilder visit(GreaterThan greaterThan, S context) { deparse(greaterThan, " > ", null); - return buffer; + return builder; } @Override public StringBuilder visit(GreaterThanEquals greaterThanEquals, S context) { deparse(greaterThanEquals, " >= ", null); - return buffer; + return builder; } public void visit(Addition addition) { @@ -331,33 +332,33 @@ public StringBuilder visit(InExpression inExpression, S context) { inExpression.getLeftExpression().accept(this, context); if (inExpression .getOldOracleJoinSyntax() == SupportsOldOracleJoinSyntax.ORACLE_JOIN_RIGHT) { - buffer.append("(+)"); + builder.append("(+)"); } if (inExpression.isGlobal()) { - buffer.append(" GLOBAL"); + builder.append(" GLOBAL"); } if (inExpression.isNot()) { - buffer.append(" NOT"); + builder.append(" NOT"); } - buffer.append(" IN "); + builder.append(" IN "); inExpression.getRightExpression().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(IncludesExpression includesExpression, S context) { includesExpression.getLeftExpression().accept(this, context); - buffer.append(" INCLUDES "); + builder.append(" INCLUDES "); includesExpression.getRightExpression().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(ExcludesExpression excludesExpression, S context) { excludesExpression.getLeftExpression().accept(this, context); - buffer.append(" EXCLUDES "); + builder.append(" EXCLUDES "); excludesExpression.getRightExpression().accept(this, context); - return buffer; + return builder; } @Override @@ -372,41 +373,41 @@ public StringBuilder visit(FullTextSearch fullTextSearch, S context) { columnsListCommaSeperated.append(","); } } - buffer.append("MATCH (").append(columnsListCommaSeperated).append(") AGAINST (") + builder.append("MATCH (").append(columnsListCommaSeperated).append(") AGAINST (") .append(fullTextSearch.getAgainstValue()) .append(fullTextSearch.getSearchModifier() != null ? " " + fullTextSearch.getSearchModifier() : "") .append(")"); - return buffer; + return builder; } @Override public StringBuilder visit(SignedExpression signedExpression, S context) { - buffer.append(signedExpression.getSign()); + builder.append(signedExpression.getSign()); signedExpression.getExpression().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(IsNullExpression isNullExpression, S context) { isNullExpression.getLeftExpression().accept(this, context); if (isNullExpression.isUseNotNull()) { - buffer.append(" NOTNULL"); + builder.append(" NOTNULL"); } else if (isNullExpression.isUseIsNull()) { if (isNullExpression.isNot()) { - buffer.append(" NOT ISNULL"); + builder.append(" NOT ISNULL"); } else { - buffer.append(" ISNULL"); + builder.append(" ISNULL"); } } else { if (isNullExpression.isNot()) { - buffer.append(" IS NOT NULL"); + builder.append(" IS NOT NULL"); } else { - buffer.append(" IS NULL"); + builder.append(" IS NULL"); } } - return buffer; + return builder; } @Override @@ -414,28 +415,28 @@ public StringBuilder visit(IsBooleanExpression isBooleanExpression, S contex isBooleanExpression.getLeftExpression().accept(this, context); if (isBooleanExpression.isTrue()) { if (isBooleanExpression.isNot()) { - buffer.append(" IS NOT TRUE"); + builder.append(" IS NOT TRUE"); } else { - buffer.append(" IS TRUE"); + builder.append(" IS TRUE"); } } else { if (isBooleanExpression.isNot()) { - buffer.append(" IS NOT FALSE"); + builder.append(" IS NOT FALSE"); } else { - buffer.append(" IS FALSE"); + builder.append(" IS FALSE"); } } - return buffer; + return builder; } @Override public StringBuilder visit(JdbcParameter jdbcParameter, S context) { - buffer.append(jdbcParameter.getParameterCharacter()); + builder.append(jdbcParameter.getParameterCharacter()); if (jdbcParameter.isUseFixedIndex()) { - buffer.append(jdbcParameter.getIndex()); + builder.append(jdbcParameter.getIndex()); } - return buffer; + return builder; } @Override @@ -445,45 +446,45 @@ public StringBuilder visit(LikeExpression likeExpression, S context) { : likeExpression.getLikeKeyWord().toString(); likeExpression.getLeftExpression().accept(this, context); - buffer.append(" "); + builder.append(" "); if (likeExpression.isNot()) { - buffer.append("NOT "); + builder.append("NOT "); } - buffer.append(keywordStr).append(" "); + builder.append(keywordStr).append(" "); if (likeExpression.isUseBinary()) { - buffer.append("BINARY "); + builder.append("BINARY "); } likeExpression.getRightExpression().accept(this, context); Expression escape = likeExpression.getEscape(); if (escape != null) { - buffer.append(" ESCAPE "); + builder.append(" ESCAPE "); likeExpression.getEscape().accept(this, context); } - return buffer; + return builder; } @Override public StringBuilder visit(ExistsExpression existsExpression, S context) { if (existsExpression.isNot()) { - buffer.append("NOT EXISTS "); + builder.append("NOT EXISTS "); } else { - buffer.append("EXISTS "); + builder.append("EXISTS "); } existsExpression.getRightExpression().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(MemberOfExpression memberOfExpression, S context) { memberOfExpression.getLeftExpression().accept(this, context); if (memberOfExpression.isNot()) { - buffer.append(" NOT MEMBER OF "); + builder.append(" NOT MEMBER OF "); } else { - buffer.append(" MEMBER OF "); + builder.append(" MEMBER OF "); } memberOfExpression.getRightExpression().accept(this, context); - return buffer; + return builder; } public void visit(InExpression inExpression) { @@ -533,30 +534,30 @@ public void visit(MemberOfExpression memberOfExpression) { @Override public StringBuilder visit(LongValue longValue, S context) { - buffer.append(longValue.getStringValue()); + builder.append(longValue.getStringValue()); - return buffer; + return builder; } @Override public StringBuilder visit(MinorThan minorThan, S context) { deparse(minorThan, " < ", null); - return buffer; + return builder; } @Override public StringBuilder visit(MinorThanEquals minorThanEquals, S context) { deparse(minorThanEquals, " <= ", null); - return buffer; + return builder; } @Override public StringBuilder visit(Multiplication multiplication, S context) { deparse(multiplication, " * ", null); - return buffer; + return builder; } @Override @@ -564,7 +565,7 @@ public StringBuilder visit(NotEqualsTo notEqualsTo, S context) { deparse(notEqualsTo, " " + notEqualsTo.getStringExpression() + " ", null); - return buffer; + return builder; } @Override @@ -572,7 +573,7 @@ public StringBuilder visit(DoubleAnd doubleAnd, S context) { deparse(doubleAnd, " " + doubleAnd.getStringExpression() + " ", null); - return buffer; + return builder; } @Override @@ -580,7 +581,7 @@ public StringBuilder visit(Contains contains, S context) { deparse(contains, " " + contains.getStringExpression() + " ", null); - return buffer; + return builder; } @Override @@ -588,57 +589,57 @@ public StringBuilder visit(ContainedBy containedBy, S context) { deparse(containedBy, " " + containedBy.getStringExpression() + " ", null); - return buffer; + return builder; } @Override public StringBuilder visit(NullValue nullValue, S context) { - buffer.append(nullValue.toString()); + builder.append(nullValue.toString()); - return buffer; + return builder; } @Override public StringBuilder visit(OrExpression orExpression, S context) { deparse(orExpression, " OR ", null); - return buffer; + return builder; } @Override public StringBuilder visit(XorExpression xorExpression, S context) { deparse(xorExpression, " XOR ", null); - return buffer; + return builder; } @Override public StringBuilder visit(StringValue stringValue, S context) { if (stringValue.getPrefix() != null) { - buffer.append(stringValue.getPrefix()); + builder.append(stringValue.getPrefix()); } - buffer.append("'").append(stringValue.getValue()).append("'"); + builder.append("'").append(stringValue.getValue()).append("'"); - return buffer; + return builder; } @Override public StringBuilder visit(BooleanValue booleanValue, S context) { - buffer.append(booleanValue.getValue()); + builder.append(booleanValue.getValue()); - return buffer; + return builder; } @Override public StringBuilder visit(Subtraction subtraction, S context) { deparse(subtraction, " - ", null); - return buffer; + return builder; } protected void deparse(BinaryExpression binaryExpression, String operator, S context) { binaryExpression.getLeftExpression().accept(this, context); - buffer.append(operator); + builder.append(operator); binaryExpression.getRightExpression().accept(this, context); } @@ -647,33 +648,33 @@ protected void deparse(BinaryExpression binaryExpression, public StringBuilder visit(Select select, S context) { if (selectVisitor != null) { if (select.getWithItemsList() != null) { - buffer.append("WITH "); + builder.append("WITH "); for (Iterator> iter = select.getWithItemsList().iterator(); iter .hasNext();) { iter.next().accept(selectVisitor, null); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } - buffer.append(" "); + builder.append(" "); } - buffer.append(" "); + builder.append(" "); } select.accept(selectVisitor, null); } - return buffer; + return builder; } @Override public StringBuilder visit(TranscodingFunction transcodingFunction, S context) { if (transcodingFunction.isTranscodeStyle()) { - buffer.append("CONVERT( "); + builder.append("CONVERT( "); transcodingFunction.getExpression().accept(this, context); - buffer.append(" USING ") + builder.append(" USING ") .append(transcodingFunction.getTranscodingName()) .append(" )"); } else { - buffer + builder .append("CONVERT( ") .append(transcodingFunction.getColDataType()) .append(", "); @@ -681,32 +682,32 @@ public StringBuilder visit(TranscodingFunction transcodingFunction, S contex String transCodingName = transcodingFunction.getTranscodingName(); if (transCodingName != null && !transCodingName.isEmpty()) { - buffer.append(", ").append(transCodingName); + builder.append(", ").append(transCodingName); } - buffer.append(" )"); + builder.append(" )"); } - return buffer; + return builder; } public StringBuilder visit(TrimFunction trimFunction, S context) { - buffer.append("Trim("); + builder.append("Trim("); if (trimFunction.getTrimSpecification() != null) { - buffer.append(" ").append(trimFunction.getTrimSpecification()); + builder.append(" ").append(trimFunction.getTrimSpecification()); } if (trimFunction.getExpression() != null) { - buffer.append(" "); + builder.append(" "); trimFunction.getExpression().accept(this, context); } if (trimFunction.getFromExpression() != null) { - buffer.append(trimFunction.isUsingFromKeyword() ? " FROM " : ", "); + builder.append(trimFunction.isUsingFromKeyword() ? " FROM " : ", "); trimFunction.getFromExpression().accept(this, context); } - buffer.append(" )"); - return buffer; + builder.append(" )"); + return builder; } public void visit(LongValue longValue) { @@ -781,9 +782,9 @@ public void visit(TrimFunction trimFunction) { @Override public StringBuilder visit(RangeExpression rangeExpression, S context) { rangeExpression.getStartExpression().accept(this, context); - buffer.append(":"); + builder.append(":"); rangeExpression.getEndExpression().accept(this, context); - return buffer; + return builder; } @Override @@ -798,44 +799,44 @@ public StringBuilder visit(Column tableColumn, S context) { } } if (tableName != null && !tableName.isEmpty()) { - buffer.append(tableName).append(tableColumn.getTableDelimiter()); + builder.append(tableName).append(tableColumn.getTableDelimiter()); } - buffer.append(tableColumn.getColumnName()); + builder.append(tableColumn.getColumnName()); if (tableColumn.getArrayConstructor() != null) { tableColumn.getArrayConstructor().accept(this, context); } if (tableColumn.getCommentText() != null) { - buffer.append(" /* ").append(tableColumn.getCommentText()).append("*/ "); + builder.append(" /* ").append(tableColumn.getCommentText()).append("*/ "); } - return buffer; + return builder; } @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public StringBuilder visit(Function function, S context) { if (function.isEscaped()) { - buffer.append("{fn "); + builder.append("{fn "); } - buffer.append(function.getName()); + builder.append(function.getName()); if (function.getParameters() == null && function.getNamedParameters() == null) { - buffer.append("()"); + builder.append("()"); } else { - buffer.append("("); + builder.append("("); if (function.isDistinct()) { - buffer.append("DISTINCT "); + builder.append("DISTINCT "); } else if (function.isAllColumns()) { - buffer.append("ALL "); + builder.append("ALL "); } else if (function.isUnique()) { - buffer.append("UNIQUE "); + builder.append("UNIQUE "); } if (function.getExtraKeyword() != null) { - buffer.append(function.getExtraKeyword()).append(" "); + builder.append(function.getExtraKeyword()).append(" "); } if (function.getNamedParameters() != null) { @@ -847,28 +848,28 @@ public StringBuilder visit(Function function, S context) { Function.HavingClause havingClause = function.getHavingClause(); if (havingClause != null) { - buffer.append(" HAVING ").append(havingClause.getHavingType()).append(" "); + builder.append(" HAVING ").append(havingClause.getHavingType()).append(" "); havingClause.getExpression().accept(this, context); } if (function.getNullHandling() != null && !function.isIgnoreNullsOutside()) { switch (function.getNullHandling()) { case IGNORE_NULLS: - buffer.append(" IGNORE NULLS"); + builder.append(" IGNORE NULLS"); break; case RESPECT_NULLS: - buffer.append(" RESPECT NULLS"); + builder.append(" RESPECT NULLS"); break; } } if (function.getOrderByElements() != null) { - buffer.append(" ORDER BY "); + builder.append(" ORDER BY "); boolean comma = false; orderByDeParser.setExpressionVisitor(this); - orderByDeParser.setBuffer(buffer); + orderByDeParser.setBuilder(builder); for (OrderByElement orderByElement : function.getOrderByElements()) { if (comma) { - buffer.append(", "); + builder.append(", "); } else { comma = true; } @@ -877,43 +878,43 @@ public StringBuilder visit(Function function, S context) { } if (function.getOnOverflowTruncate() != null) { - buffer.append(" ON OVERFLOW ").append(function.getOnOverflowTruncate()); + builder.append(" ON OVERFLOW ").append(function.getOnOverflowTruncate()); } if (function.getLimit() != null) { - new LimitDeparser(this, buffer).deParse(function.getLimit()); + new LimitDeparser(this, builder).deParse(function.getLimit()); } - buffer.append(")"); + builder.append(")"); } if (function.getNullHandling() != null && function.isIgnoreNullsOutside()) { switch (function.getNullHandling()) { case IGNORE_NULLS: - buffer.append(" IGNORE NULLS"); + builder.append(" IGNORE NULLS"); break; case RESPECT_NULLS: - buffer.append(" RESPECT NULLS"); + builder.append(" RESPECT NULLS"); break; } } if (function.getAttribute() != null) { - buffer.append(".").append(function.getAttribute()); + builder.append(".").append(function.getAttribute()); } if (function.getKeep() != null) { - buffer.append(" ").append(function.getKeep()); + builder.append(" ").append(function.getKeep()); } if (function.isEscaped()) { - buffer.append("}"); + builder.append("}"); } - return buffer; + return builder; } @Override public StringBuilder visit(ParenthesedSelect selectBody, S context) { selectBody.getSelect().accept(this, context); - return buffer; + return builder; } public SelectVisitor getSelectVisitor() { @@ -926,29 +927,29 @@ public void setSelectVisitor(SelectVisitor visitor) { @Override public StringBuilder visit(DateValue dateValue, S context) { - buffer.append("{d '").append(dateValue.getValue().toString()).append("'}"); - return buffer; + builder.append("{d '").append(dateValue.getValue().toString()).append("'}"); + return builder; } @Override public StringBuilder visit(TimestampValue timestampValue, S context) { - buffer.append("{ts '").append(timestampValue.getValue().toString()).append("'}"); - return buffer; + builder.append("{ts '").append(timestampValue.getValue().toString()).append("'}"); + return builder; } @Override public StringBuilder visit(TimeValue timeValue, S context) { - buffer.append("{t '").append(timeValue.getValue().toString()).append("'}"); - return buffer; + builder.append("{t '").append(timeValue.getValue().toString()).append("'}"); + return builder; } @Override public StringBuilder visit(CaseExpression caseExpression, S context) { - buffer.append(caseExpression.isUsingBrackets() ? "(" : "").append("CASE "); + builder.append(caseExpression.isUsingBrackets() ? "(" : "").append("CASE "); Expression switchExp = caseExpression.getSwitchExpression(); if (switchExp != null) { switchExp.accept(this, context); - buffer.append(" "); + builder.append(" "); } for (Expression exp : caseExpression.getWhenClauses()) { @@ -957,38 +958,38 @@ public StringBuilder visit(CaseExpression caseExpression, S context) { Expression elseExp = caseExpression.getElseExpression(); if (elseExp != null) { - buffer.append("ELSE "); + builder.append("ELSE "); elseExp.accept(this, context); - buffer.append(" "); + builder.append(" "); } - buffer.append("END").append(caseExpression.isUsingBrackets() ? ")" : ""); - return buffer; + builder.append("END").append(caseExpression.isUsingBrackets() ? ")" : ""); + return builder; } @Override public StringBuilder visit(WhenClause whenClause, S context) { - buffer.append("WHEN "); + builder.append("WHEN "); whenClause.getWhenExpression().accept(this, context); - buffer.append(" THEN "); + builder.append(" THEN "); whenClause.getThenExpression().accept(this, context); - buffer.append(" "); - return buffer; + builder.append(" "); + return builder; } @Override public StringBuilder visit(AnyComparisonExpression anyComparisonExpression, S context) { - buffer.append(anyComparisonExpression.getAnyType().name()); + builder.append(anyComparisonExpression.getAnyType().name()); // VALUES or SELECT anyComparisonExpression.getSelect().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(Concat concat, S context) { deparse(concat, " || ", null); - return buffer; + return builder; } public void visit(RangeExpression rangeExpression) { @@ -1039,58 +1040,58 @@ public void visit(Concat concat) { @Override public StringBuilder visit(Matches matches, S context) { deparse(matches, " @@ ", null); - return buffer; + return builder; } @Override public StringBuilder visit(BitwiseAnd bitwiseAnd, S context) { deparse(bitwiseAnd, " & ", null); - return buffer; + return builder; } @Override public StringBuilder visit(BitwiseOr bitwiseOr, S context) { deparse(bitwiseOr, " | ", null); - return buffer; + return builder; } @Override public StringBuilder visit(BitwiseXor bitwiseXor, S context) { deparse(bitwiseXor, " ^ ", null); - return buffer; + return builder; } @Override public StringBuilder visit(CastExpression cast, S context) { if (cast.isImplicitCast()) { - buffer.append(cast.getColDataType()).append(" "); + builder.append(cast.getColDataType()).append(" "); cast.getLeftExpression().accept(this, context); } else if (cast.isUseCastKeyword()) { String formatStr = cast.getFormat() != null && !cast.getFormat().isEmpty() ? " FORMAT " + cast.getFormat() : ""; - buffer.append(cast.keyword).append("("); + builder.append(cast.keyword).append("("); cast.getLeftExpression().accept(this, context); - buffer.append(" AS "); - buffer.append( + builder.append(" AS "); + builder.append( cast.getColumnDefinitions().size() > 1 ? "ROW(" + Select.getStringList(cast.getColumnDefinitions()) + ")" : cast.getColDataType().toString()); - buffer.append(formatStr); - buffer.append(")"); + builder.append(formatStr); + builder.append(")"); } else { cast.getLeftExpression().accept(this, context); - buffer.append("::"); - buffer.append(cast.getColDataType()); + builder.append("::"); + builder.append(cast.getColDataType()); } - return buffer; + return builder; } @Override public StringBuilder visit(Modulo modulo, S context) { deparse(modulo, " % ", null); - return buffer; + return builder; } @Override @@ -1107,29 +1108,29 @@ public StringBuilder visit(AnalyticExpression analyticExpression, S context) List orderByElements = analyticExpression.getOrderByElements(); WindowElement windowElement = analyticExpression.getWindowElement(); - buffer.append(name).append("("); + builder.append(name).append("("); if (analyticExpression.isDistinct()) { - buffer.append("DISTINCT "); + builder.append("DISTINCT "); } if (analyticExpression.isUnique()) { - buffer.append("UNIQUE "); + builder.append("UNIQUE "); } if (expression != null) { expression.accept(this, context); if (offset != null) { - buffer.append(", "); + builder.append(", "); offset.accept(this, context); if (defaultValue != null) { - buffer.append(", "); + builder.append(", "); defaultValue.accept(this, context); } } } else if (isAllColumns) { - buffer.append("*"); + builder.append("*"); } Function.HavingClause havingClause = analyticExpression.getHavingClause(); if (havingClause != null) { - buffer.append(" HAVING ").append(havingClause.getHavingType()).append(" "); + builder.append(" HAVING ").append(havingClause.getHavingType()).append(" "); havingClause.getExpression().accept(this, context); } @@ -1137,39 +1138,40 @@ public StringBuilder visit(AnalyticExpression analyticExpression, S context) && !analyticExpression.isIgnoreNullsOutside()) { switch (analyticExpression.getNullHandling()) { case IGNORE_NULLS: - buffer.append(" IGNORE NULLS"); + builder.append(" IGNORE NULLS"); break; case RESPECT_NULLS: - buffer.append(" RESPECT NULLS"); + builder.append(" RESPECT NULLS"); break; } } if (analyticExpression.getFuncOrderBy() != null) { - buffer.append(" ORDER BY "); - buffer.append(analyticExpression.getFuncOrderBy().stream().map(OrderByElement::toString) - .collect(joining(", "))); + builder.append(" ORDER BY "); + builder.append( + analyticExpression.getFuncOrderBy().stream().map(OrderByElement::toString) + .collect(joining(", "))); } if (analyticExpression.getOnOverflowTruncate() != null) { - buffer.append(" ON OVERFLOW ").append(analyticExpression.getOnOverflowTruncate()); + builder.append(" ON OVERFLOW ").append(analyticExpression.getOnOverflowTruncate()); } if (analyticExpression.getLimit() != null) { - new LimitDeparser(this, buffer).deParse(analyticExpression.getLimit()); + new LimitDeparser(this, builder).deParse(analyticExpression.getLimit()); } - buffer.append(") "); + builder.append(") "); if (keep != null) { keep.accept(this, context); - buffer.append(" "); + builder.append(" "); } if (analyticExpression.getFilterExpression() != null) { - buffer.append("FILTER (WHERE "); + builder.append("FILTER (WHERE "); analyticExpression.getFilterExpression().accept(this, context); - buffer.append(")"); + builder.append(")"); if (analyticExpression.getType() != AnalyticType.FILTER_ONLY) { - buffer.append(" "); + builder.append(" "); } } @@ -1177,10 +1179,10 @@ public StringBuilder visit(AnalyticExpression analyticExpression, S context) && analyticExpression.isIgnoreNullsOutside()) { switch (analyticExpression.getNullHandling()) { case IGNORE_NULLS: - buffer.append(" IGNORE NULLS "); + builder.append(" IGNORE NULLS "); break; case RESPECT_NULLS: - buffer.append(" RESPECT NULLS "); + builder.append(" RESPECT NULLS "); break; } } @@ -1189,50 +1191,50 @@ public StringBuilder visit(AnalyticExpression analyticExpression, S context) case FILTER_ONLY: return null; case WITHIN_GROUP: - buffer.append("WITHIN GROUP"); + builder.append("WITHIN GROUP"); break; case WITHIN_GROUP_OVER: - buffer.append("WITHIN GROUP ("); + builder.append("WITHIN GROUP ("); analyticExpression.getWindowDefinition().getOrderBy() - .toStringOrderByElements(buffer); - buffer.append(") OVER ("); + .toStringOrderByElements(builder); + builder.append(") OVER ("); analyticExpression.getWindowDefinition().getPartitionBy() - .toStringPartitionBy(buffer); - buffer.append(")"); + .toStringPartitionBy(builder); + builder.append(")"); break; default: - buffer.append("OVER"); + builder.append("OVER"); } if (analyticExpression.getWindowName() != null) { - buffer.append(" ").append(analyticExpression.getWindowName()); + builder.append(" ").append(analyticExpression.getWindowName()); } else if (analyticExpression.getType() != AnalyticType.WITHIN_GROUP_OVER) { - buffer.append(" ("); + builder.append(" ("); if (partitionExpressionList != null && !partitionExpressionList.isEmpty()) { - buffer.append("PARTITION BY "); + builder.append("PARTITION BY "); if (analyticExpression.isPartitionByBrackets()) { - buffer.append("("); + builder.append("("); } for (int i = 0; i < ((List) partitionExpressionList).size(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } ((List) partitionExpressionList).get(i).accept(this, context); } if (analyticExpression.isPartitionByBrackets()) { - buffer.append(")"); + builder.append(")"); } - buffer.append(" "); + builder.append(" "); } if (orderByElements != null && !orderByElements.isEmpty()) { - buffer.append("ORDER BY "); + builder.append("ORDER BY "); orderByDeParser.setExpressionVisitor(this); - orderByDeParser.setBuffer(buffer); + orderByDeParser.setBuilder(builder); for (int i = 0; i < orderByElements.size(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } orderByDeParser.deParseElement(orderByElements.get(i)); } @@ -1240,39 +1242,39 @@ public StringBuilder visit(AnalyticExpression analyticExpression, S context) if (windowElement != null) { if (orderByElements != null && !orderByElements.isEmpty()) { - buffer.append(' '); + builder.append(' '); } - buffer.append(windowElement); + builder.append(windowElement); } - buffer.append(")"); + builder.append(")"); } - return buffer; + return builder; } @Override public StringBuilder visit(ExtractExpression extractExpression, S context) { - buffer.append("EXTRACT(").append(extractExpression.getName()); - buffer.append(" FROM "); + builder.append("EXTRACT(").append(extractExpression.getName()); + builder.append(" FROM "); extractExpression.getExpression().accept(this, context); - buffer.append(')'); - return buffer; + builder.append(')'); + return builder; } @Override public StringBuilder visit(IntervalExpression intervalExpression, S context) { if (intervalExpression.isUsingIntervalKeyword()) { - buffer.append("INTERVAL "); + builder.append("INTERVAL "); } if (intervalExpression.getExpression() != null) { intervalExpression.getExpression().accept(this, context); } else { - buffer.append(intervalExpression.getParameter()); + builder.append(intervalExpression.getParameter()); } if (intervalExpression.getIntervalType() != null) { - buffer.append(" ").append(intervalExpression.getIntervalType()); + builder.append(" ").append(intervalExpression.getIntervalType()); } - return buffer; + return builder; } public void visit(Matches matches) { @@ -1310,121 +1312,121 @@ public void visit(IntervalExpression intervalExpression) { @Override public StringBuilder visit(JdbcNamedParameter jdbcNamedParameter, S context) { - buffer.append(jdbcNamedParameter.toString()); - return buffer; + builder.append(jdbcNamedParameter.toString()); + return builder; } @Override public StringBuilder visit(OracleHierarchicalExpression hierarchicalExpression, S context) { - buffer.append(hierarchicalExpression.toString()); - return buffer; + builder.append(hierarchicalExpression.toString()); + return builder; } @Override public StringBuilder visit(RegExpMatchOperator regExpMatchOperator, S context) { deparse(regExpMatchOperator, " " + regExpMatchOperator.getStringExpression() + " ", null); - return buffer; + return builder; } @Override public StringBuilder visit(JsonExpression jsonExpr, S context) { - buffer.append(jsonExpr.toString()); - return buffer; + builder.append(jsonExpr.toString()); + return builder; } @Override public StringBuilder visit(JsonOperator jsonExpr, S context) { deparse(jsonExpr, " " + jsonExpr.getStringExpression() + " ", null); - return buffer; + return builder; } @Override public StringBuilder visit(UserVariable var, S context) { - buffer.append(var.toString()); - return buffer; + builder.append(var.toString()); + return builder; } @Override public StringBuilder visit(NumericBind bind, S context) { - buffer.append(bind.toString()); - return buffer; + builder.append(bind.toString()); + return builder; } @Override public StringBuilder visit(KeepExpression keepExpression, S context) { - buffer.append(keepExpression.toString()); - return buffer; + builder.append(keepExpression.toString()); + return builder; } @Override public StringBuilder visit(MySQLGroupConcat groupConcat, S context) { - buffer.append(groupConcat.toString()); - return buffer; + builder.append(groupConcat.toString()); + return builder; } @Override public StringBuilder visit(ExpressionList expressionList, S context) { ExpressionListDeParser expressionListDeParser = - new ExpressionListDeParser<>(this, buffer); + new ExpressionListDeParser<>(this, builder); expressionListDeParser.deParse(expressionList); - return buffer; + return builder; } @Override public StringBuilder visit(RowConstructor rowConstructor, S context) { if (rowConstructor.getName() != null) { - buffer.append(rowConstructor.getName()); + builder.append(rowConstructor.getName()); } ExpressionListDeParser expressionListDeParser = - new ExpressionListDeParser<>(this, buffer); + new ExpressionListDeParser<>(this, builder); expressionListDeParser.deParse(rowConstructor); - return buffer; + return builder; } @Override public StringBuilder visit(RowGetExpression rowGetExpression, S context) { rowGetExpression.getExpression().accept(this, context); - buffer.append(".").append(rowGetExpression.getColumnName()); + builder.append(".").append(rowGetExpression.getColumnName()); return null; } @Override public StringBuilder visit(OracleHint hint, S context) { - buffer.append(hint.toString()); - return buffer; + builder.append(hint.toString()); + return builder; } @Override public StringBuilder visit(TimeKeyExpression timeKeyExpression, S context) { - buffer.append(timeKeyExpression.toString()); - return buffer; + builder.append(timeKeyExpression.toString()); + return builder; } @Override public StringBuilder visit(DateTimeLiteralExpression literal, S context) { - buffer.append(literal.toString()); - return buffer; + builder.append(literal.toString()); + return builder; } @Override public StringBuilder visit(NextValExpression nextVal, S context) { - buffer.append(nextVal.isUsingNextValueFor() ? "NEXT VALUE FOR " : "NEXTVAL FOR ") + builder.append(nextVal.isUsingNextValueFor() ? "NEXT VALUE FOR " : "NEXTVAL FOR ") .append(nextVal.getName()); - return buffer; + return builder; } @Override public StringBuilder visit(CollateExpression col, S context) { - buffer.append(col.getLeftExpression().toString()).append(" COLLATE ") + builder.append(col.getLeftExpression().toString()).append(" COLLATE ") .append(col.getCollate()); - return buffer; + return builder; } @Override public StringBuilder visit(SimilarToExpression expr, S context) { deparse(expr, (expr.isNot() ? " NOT" : "") + " SIMILAR TO ", null); - return buffer; + return builder; } public void visit(JdbcNamedParameter jdbcNamedParameter) { @@ -1503,40 +1505,40 @@ public void visit(SimilarToExpression expr) { @Override public StringBuilder visit(ArrayExpression array, S context) { array.getObjExpression().accept(this, context); - buffer.append("["); + builder.append("["); if (array.getIndexExpression() != null) { array.getIndexExpression().accept(this, context); } else { if (array.getStartIndexExpression() != null) { array.getStartIndexExpression().accept(this, context); } - buffer.append(":"); + builder.append(":"); if (array.getStopIndexExpression() != null) { array.getStopIndexExpression().accept(this, context); } } - buffer.append("]"); - return buffer; + builder.append("]"); + return builder; } @Override public StringBuilder visit(ArrayConstructor aThis, S context) { if (aThis.isArrayKeyword()) { - buffer.append("ARRAY"); + builder.append("ARRAY"); } - buffer.append("["); + builder.append("["); boolean first = true; for (Expression expression : aThis.getExpressions()) { if (!first) { - buffer.append(", "); + builder.append(", "); } else { first = false; } expression.accept(this, context); } - buffer.append("]"); - return buffer; + builder.append("]"); + return builder; } @Override @@ -1547,28 +1549,28 @@ void deParse(Expression statement) { @Override public StringBuilder visit(VariableAssignment var, S context) { var.getVariable().accept(this, context); - buffer.append(" ").append(var.getOperation()).append(" "); + builder.append(" ").append(var.getOperation()).append(" "); var.getExpression().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(XMLSerializeExpr expr, S context) { // xmlserialize(xmlagg(xmltext(COMMENT_LINE) ORDER BY COMMENT_SEQUENCE) as varchar(1024)) - buffer.append("xmlserialize(xmlagg(xmltext("); + builder.append("xmlserialize(xmlagg(xmltext("); expr.getExpression().accept(this, context); - buffer.append(")"); + builder.append(")"); if (expr.getOrderByElements() != null) { - buffer.append(" ORDER BY "); + builder.append(" ORDER BY "); for (Iterator i = expr.getOrderByElements().iterator(); i.hasNext();) { - buffer.append(i.next().toString()); + builder.append(i.next().toString()); if (i.hasNext()) { - buffer.append(", "); + builder.append(", "); } } } - buffer.append(") AS ").append(expr.getDataType()).append(")"); - return buffer; + builder.append(") AS ").append(expr.getDataType()).append(")"); + return builder; } @Override @@ -1576,212 +1578,217 @@ public StringBuilder visit(TimezoneExpression var, S context) { var.getLeftExpression().accept(this, context); for (Expression expr : var.getTimezoneExpressions()) { - buffer.append(" AT TIME ZONE "); + builder.append(" AT TIME ZONE "); expr.accept(this, context); } - return buffer; + return builder; } @Override public StringBuilder visit(JsonAggregateFunction expression, S context) { - expression.append(buffer); - return buffer; + expression.append(builder); + return builder; } @Override public StringBuilder visit(JsonFunction expression, S context) { - expression.append(buffer); - return buffer; + expression.append(builder); + return builder; } @Override public StringBuilder visit(ConnectByRootOperator connectByRootOperator, S context) { - buffer.append("CONNECT_BY_ROOT "); + builder.append("CONNECT_BY_ROOT "); connectByRootOperator.getColumn().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(ConnectByPriorOperator connectByPriorOperator, S context) { - buffer.append("PRIOR "); + builder.append("PRIOR "); connectByPriorOperator.getColumn().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(OracleNamedFunctionParameter oracleNamedFunctionParameter, S context) { - buffer.append(oracleNamedFunctionParameter.getName()).append(" => "); + builder.append(oracleNamedFunctionParameter.getName()).append(" => "); oracleNamedFunctionParameter.getExpression().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(AllColumns allColumns, S context) { - buffer.append(allColumns.toString()); - return buffer; + builder.append(allColumns.toString()); + return builder; } @Override public StringBuilder visit(AllTableColumns allTableColumns, S context) { - buffer.append(allTableColumns.toString()); - return buffer; + builder.append(allTableColumns.toString()); + return builder; } @Override public StringBuilder visit(AllValue allValue, S context) { - buffer.append(allValue); - return buffer; + builder.append(allValue); + return builder; } @Override public StringBuilder visit(IsDistinctExpression isDistinctExpression, S context) { - buffer.append(isDistinctExpression.getLeftExpression()) + builder.append(isDistinctExpression.getLeftExpression()) .append(isDistinctExpression.getStringExpression()) .append(isDistinctExpression.getRightExpression()); - return buffer; + return builder; } @Override public StringBuilder visit(GeometryDistance geometryDistance, S context) { deparse(geometryDistance, " " + geometryDistance.getStringExpression() + " ", null); - return buffer; + return builder; } @Override public StringBuilder visit(TSQLLeftJoin tsqlLeftJoin, S context) { this.deparse(tsqlLeftJoin, " *= ", null); - return buffer; + return builder; } @Override public StringBuilder visit(TSQLRightJoin tsqlRightJoin, S context) { this.deparse(tsqlRightJoin, " =* ", null); - return buffer; + return builder; } @Override public StringBuilder visit(StructType structType, S context) { if (structType.getDialect() != StructType.Dialect.DUCKDB && structType.getKeyword() != null) { - buffer.append(structType.getKeyword()); + builder.append(structType.getKeyword()); } if (structType.getDialect() != StructType.Dialect.DUCKDB && structType.getParameters() != null && !structType.getParameters().isEmpty()) { - buffer.append("<"); + builder.append("<"); int i = 0; for (Map.Entry e : structType.getParameters()) { if (0 < i++) { - buffer.append(","); + builder.append(","); } // optional name if (e.getKey() != null && !e.getKey().isEmpty()) { - buffer.append(e.getKey()).append(" "); + builder.append(e.getKey()).append(" "); } // mandatory type - buffer.append(e.getValue()); + builder.append(e.getValue()); } - buffer.append(">"); + builder.append(">"); } if (structType.getArguments() != null && !structType.getArguments().isEmpty()) { if (structType.getDialect() == StructType.Dialect.DUCKDB) { - buffer.append("{ "); + builder.append("{ "); int i = 0; for (SelectItem e : structType.getArguments()) { if (0 < i++) { - buffer.append(","); + builder.append(","); } - buffer.append(e.getAlias().getName()); - buffer.append(" : "); + builder.append(e.getAlias().getName()); + builder.append(" : "); e.getExpression().accept(this, context); } - buffer.append(" }"); + builder.append(" }"); } else { - buffer.append("("); + builder.append("("); int i = 0; for (SelectItem e : structType.getArguments()) { if (0 < i++) { - buffer.append(","); + builder.append(","); } e.getExpression().accept(this, context); if (e.getAlias() != null) { - buffer.append(" as "); - buffer.append(e.getAlias().getName()); + builder.append(" as "); + builder.append(e.getAlias().getName()); } } - buffer.append(")"); + builder.append(")"); } } if (structType.getDialect() == StructType.Dialect.DUCKDB && structType.getParameters() != null && !structType.getParameters().isEmpty()) { - buffer.append("::STRUCT( "); + builder.append("::STRUCT( "); int i = 0; for (Map.Entry e : structType.getParameters()) { if (0 < i++) { - buffer.append(","); + builder.append(","); } - buffer.append(e.getKey()).append(" "); - buffer.append(e.getValue()); + builder.append(e.getKey()).append(" "); + builder.append(e.getValue()); } - buffer.append(")"); + builder.append(")"); } - return buffer; + return builder; } @Override public StringBuilder visit(LambdaExpression lambdaExpression, S context) { if (lambdaExpression.getIdentifiers().size() == 1) { - buffer.append(lambdaExpression.getIdentifiers().get(0)); + builder.append(lambdaExpression.getIdentifiers().get(0)); } else { int i = 0; - buffer.append("( "); + builder.append("( "); for (String s : lambdaExpression.getIdentifiers()) { - buffer.append(i++ > 0 ? ", " : "").append(s); + builder.append(i++ > 0 ? ", " : "").append(s); } - buffer.append(" )"); + builder.append(" )"); } - buffer.append(" -> "); + builder.append(" -> "); lambdaExpression.getExpression().accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(HighExpression highExpression, S context) { - return buffer.append(highExpression.toString()); + return builder.append(highExpression.toString()); } @Override public StringBuilder visit(LowExpression lowExpression, S context) { - return buffer.append(lowExpression.toString()); + return builder.append(lowExpression.toString()); } @Override public StringBuilder visit(Plus plus, S context) { - return buffer.append(plus.toString()); + return builder.append(plus.toString()); } @Override public StringBuilder visit(PriorTo priorTo, S context) { - return buffer.append(priorTo.toString()); + return builder.append(priorTo.toString()); } @Override public StringBuilder visit(Inverse inverse, S context) { - return buffer.append(inverse.toString()); + return builder.append(inverse.toString()); } @Override public StringBuilder visit(CosineSimilarity cosineSimilarity, S context) { deparse(cosineSimilarity, " " + cosineSimilarity.getStringExpression() + " ", context); - return buffer; + return builder; + } + + @Override + public StringBuilder visit(FromQuery fromQuery, S context) { + return null; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionListDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionListDeParser.java index cbba90f94..62b4c829b 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionListDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionListDeParser.java @@ -41,26 +41,26 @@ public void deParse(ExpressionList expressionList) { : Collections.nCopies(expressionList.size(), ""); if (expressionList instanceof ParenthesedExpressionList) { - buffer.append("("); + builder.append("("); } int i = 0; for (Expression expression : expressionList) { if (i > 0) { - buffer.append(comma); + builder.append(comma); } // @todo: remove this NameExpressionList related part String name = names.get(i); if (!name.isEmpty()) { - buffer.append(name); - buffer.append(" "); + builder.append(name); + builder.append(" "); } expression.accept(expressionVisitor, null); i++; } if (expressionList instanceof ParenthesedExpressionList) { - buffer.append(")"); + builder.append(")"); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/GrantDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/GrantDeParser.java index 212409e99..4a0f997f6 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/GrantDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/GrantDeParser.java @@ -21,26 +21,26 @@ public GrantDeParser(StringBuilder buffer) { @Override public void deParse(Grant grant) { - buffer.append("GRANT "); + builder.append("GRANT "); if (grant.getRole() != null) { - buffer.append(grant.getRole()); + builder.append(grant.getRole()); } else { for (Iterator iter = grant.getPrivileges().iterator(); iter.hasNext();) { String privilege = iter.next(); - buffer.append(privilege); + builder.append(privilege); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } - buffer.append(" ON "); - buffer.append(grant.getObjectName()); + builder.append(" ON "); + builder.append(grant.getObjectName()); } - buffer.append(" TO "); + builder.append(" TO "); for (Iterator iter = grant.getUsers().iterator(); iter.hasNext();) { String user = iter.next(); - buffer.append(user); + builder.append(user); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java index d9b1dbb82..fc20bd4cd 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/GroupByDeParser.java @@ -21,30 +21,30 @@ public GroupByDeParser(ExpressionVisitor expressionVisitor, StringBuilder buffer) { super(buffer); this.expressionListDeParser = new ExpressionListDeParser<>(expressionVisitor, buffer); - this.buffer = buffer; + this.builder = buffer; } @Override @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public void deParse(GroupByElement groupBy) { - buffer.append("GROUP BY "); + builder.append("GROUP BY "); expressionListDeParser.deParse(groupBy.getGroupByExpressionList()); int i = 0; if (!groupBy.getGroupingSets().isEmpty()) { - if (buffer.charAt(buffer.length() - 1) != ' ') { - buffer.append(' '); + if (builder.charAt(builder.length() - 1) != ' ') { + builder.append(' '); } - buffer.append("GROUPING SETS ("); + builder.append("GROUPING SETS ("); for (ExpressionList expressionList : groupBy.getGroupingSets()) { - buffer.append(i++ > 0 ? ", " : ""); + builder.append(i++ > 0 ? ", " : ""); expressionListDeParser.deParse(expressionList); } - buffer.append(")"); + builder.append(")"); } if (groupBy.isMysqlWithRollup()) { - buffer.append(" WITH ROLLUP"); + builder.append(" WITH ROLLUP"); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java index 5d30f4ec9..279c7607d 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java @@ -41,93 +41,93 @@ public InsertDeParser(ExpressionVisitor expressionVisitor, "PMD.NPathComplexity"}) public void deParse(Insert insert) { if (insert.getWithItemsList() != null && !insert.getWithItemsList().isEmpty()) { - buffer.append("WITH "); + builder.append("WITH "); for (Iterator> iter = insert.getWithItemsList().iterator(); iter .hasNext();) { WithItem withItem = iter.next(); withItem.accept(this.selectVisitor, null); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } - buffer.append("INSERT "); + builder.append("INSERT "); if (insert.getModifierPriority() != null) { - buffer.append(insert.getModifierPriority()).append(" "); + builder.append(insert.getModifierPriority()).append(" "); } if (insert.getOracleHint() != null) { - buffer.append(insert.getOracleHint()).append(" "); + builder.append(insert.getOracleHint()).append(" "); } if (insert.isModifierIgnore()) { - buffer.append("IGNORE "); + builder.append("IGNORE "); } if (insert.isOverwrite()) { - buffer.append("OVERWRITE "); + builder.append("OVERWRITE "); } else { - buffer.append("INTO "); + builder.append("INTO "); } if (insert.isTableKeyword()) { - buffer.append("TABLE "); + builder.append("TABLE "); } - buffer.append(insert.getTable().toString()); + builder.append(insert.getTable().toString()); if (insert.isOnlyDefaultValues()) { - buffer.append(" DEFAULT VALUES"); + builder.append(" DEFAULT VALUES"); } if (insert.getColumns() != null) { - buffer.append(" ("); + builder.append(" ("); for (Iterator iter = insert.getColumns().iterator(); iter.hasNext();) { Column column = iter.next(); - buffer.append(column.getColumnName()); + builder.append(column.getColumnName()); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } - buffer.append(")"); + builder.append(")"); } if (insert.getPartitions() != null) { - buffer.append(" PARTITION ("); - Partition.appendPartitionsTo(buffer, insert.getPartitions()); - buffer.append(")"); + builder.append(" PARTITION ("); + Partition.appendPartitionsTo(builder, insert.getPartitions()); + builder.append(")"); } if (insert.getOutputClause() != null) { - buffer.append(insert.getOutputClause().toString()); + builder.append(insert.getOutputClause().toString()); } if (insert.getSelect() != null) { - buffer.append(" "); + builder.append(" "); Select select = insert.getSelect(); select.accept(selectVisitor, null); } if (insert.getSetUpdateSets() != null) { - buffer.append(" SET "); - deparseUpdateSets(insert.getSetUpdateSets(), buffer, expressionVisitor); + builder.append(" SET "); + deparseUpdateSets(insert.getSetUpdateSets(), builder, expressionVisitor); } if (insert.getDuplicateUpdateSets() != null) { - buffer.append(" ON DUPLICATE KEY UPDATE "); - deparseUpdateSets(insert.getDuplicateUpdateSets(), buffer, expressionVisitor); + builder.append(" ON DUPLICATE KEY UPDATE "); + deparseUpdateSets(insert.getDuplicateUpdateSets(), builder, expressionVisitor); } // @todo: Accept some Visitors for the involved Expressions if (insert.getConflictAction() != null) { - buffer.append(" ON CONFLICT"); + builder.append(" ON CONFLICT"); if (insert.getConflictTarget() != null) { - insert.getConflictTarget().appendTo(buffer); + insert.getConflictTarget().appendTo(builder); } - insert.getConflictAction().appendTo(buffer); + insert.getConflictAction().appendTo(builder); } if (insert.getReturningClause() != null) { - insert.getReturningClause().appendTo(buffer); + insert.getReturningClause().appendTo(builder); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/LimitDeparser.java b/src/main/java/net/sf/jsqlparser/util/deparser/LimitDeparser.java index e0d496d8e..ff6b6dbf0 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/LimitDeparser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/LimitDeparser.java @@ -22,16 +22,16 @@ public LimitDeparser(ExpressionVisitor expressionVisitor, StringB @Override public void deParse(Limit limit) { - buffer.append(" LIMIT "); + builder.append(" LIMIT "); if (limit.isLimitNull()) { - buffer.append("NULL"); + builder.append("NULL"); } else { if (limit.isLimitAll()) { - buffer.append("ALL"); + builder.append("ALL"); } else { if (null != limit.getOffset()) { limit.getOffset().accept(expressionVisitor, null); - buffer.append(", "); + builder.append(", "); } if (null != limit.getRowCount()) { @@ -41,7 +41,7 @@ public void deParse(Limit limit) { } if (limit.getByExpressions() != null) { - buffer.append(" BY "); + builder.append(" BY "); limit.getByExpressions().accept(expressionVisitor, null); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java index 09bb0cfc5..5ce81c2dd 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/MergeDeParser.java @@ -32,27 +32,27 @@ public MergeDeParser(ExpressionDeParser expressionDeParser, SelectDeParser selec public void deParse(Merge merge) { List> withItemsList = merge.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - buffer.append("WITH "); + builder.append("WITH "); for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { iter.next().accept(selectDeParser, null); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } - buffer.append("MERGE "); + builder.append("MERGE "); if (merge.getOracleHint() != null) { - buffer.append(merge.getOracleHint()).append(" "); + builder.append(merge.getOracleHint()).append(" "); } - buffer.append("INTO "); + builder.append("INTO "); merge.getTable().accept(selectDeParser, null); - buffer.append(" USING "); + builder.append(" USING "); merge.getFromItem().accept(selectDeParser, null); - buffer.append(" ON "); + builder.append(" ON "); merge.getOnCondition().accept(expressionDeParser, null); List operations = merge.getOperations(); @@ -61,19 +61,19 @@ public void deParse(Merge merge) { } if (merge.getOutputClause() != null) { - merge.getOutputClause().appendTo(buffer); + merge.getOutputClause().appendTo(builder); } } @Override public StringBuilder visit(MergeDelete mergeDelete, S context) { - buffer.append(" WHEN MATCHED"); + builder.append(" WHEN MATCHED"); if (mergeDelete.getAndPredicate() != null) { - buffer.append(" AND "); + builder.append(" AND "); mergeDelete.getAndPredicate().accept(expressionDeParser, context); } - buffer.append(" THEN DELETE"); - return buffer; + builder.append(" THEN DELETE"); + return builder; } public void visit(MergeDelete mergeDelete) { @@ -82,25 +82,25 @@ public void visit(MergeDelete mergeDelete) { @Override public StringBuilder visit(MergeUpdate mergeUpdate, S context) { - buffer.append(" WHEN MATCHED"); + builder.append(" WHEN MATCHED"); if (mergeUpdate.getAndPredicate() != null) { - buffer.append(" AND "); + builder.append(" AND "); mergeUpdate.getAndPredicate().accept(expressionDeParser, context); } - buffer.append(" THEN UPDATE SET "); - deparseUpdateSets(mergeUpdate.getUpdateSets(), buffer, expressionDeParser); + builder.append(" THEN UPDATE SET "); + deparseUpdateSets(mergeUpdate.getUpdateSets(), builder, expressionDeParser); if (mergeUpdate.getWhereCondition() != null) { - buffer.append(" WHERE "); + builder.append(" WHERE "); mergeUpdate.getWhereCondition().accept(expressionDeParser, context); } if (mergeUpdate.getDeleteWhereCondition() != null) { - buffer.append(" DELETE WHERE "); + builder.append(" DELETE WHERE "); mergeUpdate.getDeleteWhereCondition().accept(expressionDeParser, context); } - return buffer; + return builder; } public void visit(MergeUpdate mergeUpdate) { @@ -109,24 +109,24 @@ public void visit(MergeUpdate mergeUpdate) { @Override public StringBuilder visit(MergeInsert mergeInsert, S context) { - buffer.append(" WHEN NOT MATCHED"); + builder.append(" WHEN NOT MATCHED"); if (mergeInsert.getAndPredicate() != null) { - buffer.append(" AND "); + builder.append(" AND "); mergeInsert.getAndPredicate().accept(expressionDeParser, context); } - buffer.append(" THEN INSERT "); + builder.append(" THEN INSERT "); if (mergeInsert.getColumns() != null) { mergeInsert.getColumns().accept(expressionDeParser, context); } - buffer.append(" VALUES "); + builder.append(" VALUES "); mergeInsert.getValues().accept(expressionDeParser, context); if (mergeInsert.getWhereCondition() != null) { - buffer.append(" WHERE "); + builder.append(" WHERE "); mergeInsert.getWhereCondition().accept(expressionDeParser, context); } - return buffer; + return builder; } public void visit(MergeInsert mergeInsert) { diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/OrderByDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/OrderByDeParser.java index 90457e73c..605c54dc2 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/OrderByDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/OrderByDeParser.java @@ -36,9 +36,9 @@ public void deParse(List orderByElementList) { public void deParse(boolean oracleSiblings, List orderByElementList) { if (oracleSiblings) { - buffer.append(" ORDER SIBLINGS BY "); + builder.append(" ORDER SIBLINGS BY "); } else { - buffer.append(" ORDER BY "); + builder.append(" ORDER BY "); } for (Iterator iterator = orderByElementList.iterator(); iterator @@ -46,7 +46,7 @@ public void deParse(boolean oracleSiblings, List orderByElementL OrderByElement orderByElement = iterator.next(); deParseElement(orderByElement); if (iterator.hasNext()) { - buffer.append(", "); + builder.append(", "); } } } @@ -54,18 +54,18 @@ public void deParse(boolean oracleSiblings, List orderByElementL public void deParseElement(OrderByElement orderBy) { orderBy.getExpression().accept(expressionVisitor, null); if (!orderBy.isAsc()) { - buffer.append(" DESC"); + builder.append(" DESC"); } else if (orderBy.isAscDescPresent()) { - buffer.append(" ASC"); + builder.append(" ASC"); } if (orderBy.getNullOrdering() != null) { - buffer.append(' '); - buffer.append(orderBy.getNullOrdering() == OrderByElement.NullOrdering.NULLS_FIRST + builder.append(' '); + builder.append(orderBy.getNullOrdering() == OrderByElement.NullOrdering.NULLS_FIRST ? "NULLS FIRST" : "NULLS LAST"); } if (orderBy.isMysqlWithRollup()) { - buffer.append(" WITH ROLLUP"); + builder.append(" WITH ROLLUP"); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/RefreshMaterializedViewStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/RefreshMaterializedViewStatementDeParser.java index 0646a65fe..444279ee6 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/RefreshMaterializedViewStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/RefreshMaterializedViewStatementDeParser.java @@ -25,26 +25,26 @@ public RefreshMaterializedViewStatementDeParser(StringBuilder buffer) { @SuppressWarnings("PMD.SwitchStmtsShouldHaveDefault") @Override public void deParse(RefreshMaterializedViewStatement view) { - buffer.append("REFRESH MATERIALIZED VIEW "); + builder.append("REFRESH MATERIALIZED VIEW "); if (view.getRefreshMode() == null) { if (view.isConcurrently()) { - buffer.append("CONCURRENTLY "); + builder.append("CONCURRENTLY "); } - buffer.append(view.getView()); + builder.append(view.getView()); return; } switch (view.getRefreshMode()) { case WITH_DATA: if (view.isConcurrently()) { - buffer.append("CONCURRENTLY "); + builder.append("CONCURRENTLY "); } - buffer.append(view.getView()); - buffer.append(" WITH DATA"); + builder.append(view.getView()); + builder.append(" WITH DATA"); break; case WITH_NO_DATA: - buffer.append(view.getView()); + builder.append(view.getView()); if (view.isConcurrently()) { - buffer.append(" WITH NO DATA"); + builder.append(" WITH NO DATA"); } break; } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ResetStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ResetStatementDeParser.java index 903bb1bbc..22eaca518 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ResetStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ResetStatementDeParser.java @@ -24,8 +24,8 @@ public ResetStatementDeParser(ExpressionVisitor expressionVisitor @Override public void deParse(ResetStatement set) { - buffer.append("RESET "); - buffer.append(set.getName()); + builder.append("RESET "); + builder.append(set.getName()); } public ExpressionVisitor getExpressionVisitor() { 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 f7ac3ccf1..dc5a36dd2 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -18,6 +18,28 @@ import net.sf.jsqlparser.expression.WindowDefinition; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.piped.AggregatePipeOperator; +import net.sf.jsqlparser.statement.piped.AsPipeOperator; +import net.sf.jsqlparser.statement.piped.CallPipeOperator; +import net.sf.jsqlparser.statement.piped.DropPipeOperator; +import net.sf.jsqlparser.statement.piped.ExceptPipeOperator; +import net.sf.jsqlparser.statement.piped.ExtendPipeOperator; +import net.sf.jsqlparser.statement.piped.FromQuery; +import net.sf.jsqlparser.statement.piped.IntersectPipeOperator; +import net.sf.jsqlparser.statement.piped.JoinPipeOperator; +import net.sf.jsqlparser.statement.piped.LimitPipeOperator; +import net.sf.jsqlparser.statement.piped.OrderByPipeOperator; +import net.sf.jsqlparser.statement.piped.PipeOperator; +import net.sf.jsqlparser.statement.piped.PipeOperatorVisitor; +import net.sf.jsqlparser.statement.piped.PivotPipeOperator; +import net.sf.jsqlparser.statement.piped.RenamePipeOperator; +import net.sf.jsqlparser.statement.piped.SelectPipeOperator; +import net.sf.jsqlparser.statement.piped.SetPipeOperator; +import net.sf.jsqlparser.statement.piped.TableSamplePipeOperator; +import net.sf.jsqlparser.statement.piped.UnPivotPipeOperator; +import net.sf.jsqlparser.statement.piped.UnionPipeOperator; +import net.sf.jsqlparser.statement.piped.WherePipeOperator; +import net.sf.jsqlparser.statement.piped.WindowPipeOperator; import net.sf.jsqlparser.statement.select.Distinct; import net.sf.jsqlparser.statement.select.Fetch; import net.sf.jsqlparser.statement.select.First; @@ -56,7 +78,8 @@ @SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"}) public class SelectDeParser extends AbstractDeParser implements SelectVisitor, SelectItemVisitor, - FromItemVisitor, PivotVisitor { + FromItemVisitor, PivotVisitor, + PipeOperatorVisitor { private ExpressionVisitor expressionVisitor; @@ -95,25 +118,25 @@ public SelectDeParser(ExpressionVisitor expressionVisitor, public StringBuilder visit(ParenthesedSelect select, S context) { List> withItemsList = select.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - buffer.append("WITH "); + builder.append("WITH "); for (WithItem withItem : withItemsList) { withItem.accept((SelectVisitor) this, context); - buffer.append(" "); + builder.append(" "); } } - buffer.append("("); + builder.append("("); select.getSelect().accept((SelectVisitor) this, context); - buffer.append(")"); + builder.append(")"); if (select.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer).deParse(select.isOracleSiblings(), + new OrderByDeParser(expressionVisitor, builder).deParse(select.isOracleSiblings(), select.getOrderByElements()); } Alias alias = select.getAlias(); if (alias != null) { - buffer.append(alias); + builder.append(alias); } Pivot pivot = select.getPivot(); if (pivot != null) { @@ -125,7 +148,7 @@ public StringBuilder visit(ParenthesedSelect select, S context) { } if (select.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(select.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(select.getLimit()); } if (select.getOffset() != null) { visit(select.getOffset()); @@ -134,13 +157,13 @@ public StringBuilder visit(ParenthesedSelect select, S context) { visit(select.getFetch()); } if (select.getIsolation() != null) { - buffer.append(select.getIsolation().toString()); + builder.append(select.getIsolation().toString()); } - return buffer; + return builder; } public void visit(Top top) { - buffer.append(top).append(" "); + builder.append(top).append(" "); } @Override @@ -149,35 +172,35 @@ public void visit(Top top) { public StringBuilder visit(PlainSelect plainSelect, S context) { List> withItemsList = plainSelect.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - buffer.append("WITH "); + builder.append("WITH "); for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { iter.next().accept((SelectVisitor) this, context); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } - buffer.append("SELECT "); + builder.append("SELECT "); if (plainSelect.getMySqlHintStraightJoin()) { - buffer.append("STRAIGHT_JOIN "); + builder.append("STRAIGHT_JOIN "); } OracleHint hint = plainSelect.getOracleHint(); if (hint != null) { - buffer.append(hint).append(" "); + builder.append(hint).append(" "); } Skip skip = plainSelect.getSkip(); if (skip != null) { - buffer.append(skip).append(" "); + builder.append(skip).append(" "); } First first = plainSelect.getFirst(); if (first != null) { - buffer.append(first).append(" "); + builder.append(first).append(" "); } deparseDistinctClause(plainSelect.getDistinct()); @@ -185,10 +208,10 @@ public StringBuilder visit(PlainSelect plainSelect, S context) { if (plainSelect.getBigQuerySelectQualifier() != null) { switch (plainSelect.getBigQuerySelectQualifier()) { case AS_STRUCT: - buffer.append("AS STRUCT "); + builder.append("AS STRUCT "); break; case AS_VALUE: - buffer.append("AS VALUE "); + builder.append("AS VALUE "); break; } } @@ -199,36 +222,36 @@ public StringBuilder visit(PlainSelect plainSelect, S context) { } if (plainSelect.getMySqlSqlCacheFlag() != null) { - buffer.append(plainSelect.getMySqlSqlCacheFlag().name()).append(" "); + builder.append(plainSelect.getMySqlSqlCacheFlag().name()).append(" "); } if (plainSelect.getMySqlSqlCalcFoundRows()) { - buffer.append("SQL_CALC_FOUND_ROWS").append(" "); + builder.append("SQL_CALC_FOUND_ROWS").append(" "); } deparseSelectItemsClause(plainSelect.getSelectItems()); if (plainSelect.getIntoTables() != null) { - buffer.append(" INTO "); + builder.append(" INTO "); for (Iterator iter = plainSelect.getIntoTables().iterator(); iter.hasNext();) { visit(iter.next(), context); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } } if (plainSelect.getFromItem() != null) { - buffer.append(" FROM "); + builder.append(" FROM "); if (plainSelect.isUsingOnly()) { - buffer.append("ONLY "); + builder.append("ONLY "); } plainSelect.getFromItem().accept(this, context); if (plainSelect.getFromItem() instanceof Table) { Table table = (Table) plainSelect.getFromItem(); if (table.getSampleClause() != null) { - table.getSampleClause().appendTo(buffer); + table.getSampleClause().appendTo(builder); } } } @@ -246,12 +269,12 @@ public StringBuilder visit(PlainSelect plainSelect, S context) { } if (plainSelect.isUsingFinal()) { - buffer.append(" FINAL"); + builder.append(" FINAL"); } if (plainSelect.getKsqlWindow() != null) { - buffer.append(" WINDOW "); - buffer.append(plainSelect.getKsqlWindow().toString()); + builder.append(" WINDOW "); + builder.append(plainSelect.getKsqlWindow().toString()); } deparseWhereClause(plainSelect); @@ -261,40 +284,40 @@ public StringBuilder visit(PlainSelect plainSelect, S context) { } if (plainSelect.getPreferringClause() != null) { - buffer.append(" ").append(plainSelect.getPreferringClause().toString()); + builder.append(" ").append(plainSelect.getPreferringClause().toString()); } if (plainSelect.getGroupBy() != null) { - buffer.append(" "); - new GroupByDeParser(expressionVisitor, buffer).deParse(plainSelect.getGroupBy()); + builder.append(" "); + new GroupByDeParser(expressionVisitor, builder).deParse(plainSelect.getGroupBy()); } if (plainSelect.getHaving() != null) { - buffer.append(" HAVING "); + builder.append(" HAVING "); plainSelect.getHaving().accept(expressionVisitor, context); } if (plainSelect.getQualify() != null) { - buffer.append(" QUALIFY "); + builder.append(" QUALIFY "); plainSelect.getQualify().accept(expressionVisitor, context); } if (plainSelect.getWindowDefinitions() != null) { - buffer.append(" WINDOW "); - buffer.append(plainSelect.getWindowDefinitions().stream() + builder.append(" WINDOW "); + builder.append(plainSelect.getWindowDefinitions().stream() .map(WindowDefinition::toString).collect(joining(", "))); } if (plainSelect.getForClause() != null) { - plainSelect.getForClause().appendTo(buffer); + plainSelect.getForClause().appendTo(builder); } deparseOrderByElementsClause(plainSelect, plainSelect.getOrderByElements()); if (plainSelect.isEmitChanges()) { - buffer.append(" EMIT CHANGES"); + builder.append(" EMIT CHANGES"); } if (plainSelect.getLimitBy() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(plainSelect.getLimitBy()); + new LimitDeparser(expressionVisitor, builder).deParse(plainSelect.getLimitBy()); } if (plainSelect.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(plainSelect.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(plainSelect.getLimit()); } if (plainSelect.getOffset() != null) { visit(plainSelect.getOffset()); @@ -303,41 +326,41 @@ public StringBuilder visit(PlainSelect plainSelect, S context) { visit(plainSelect.getFetch()); } if (plainSelect.getIsolation() != null) { - buffer.append(plainSelect.getIsolation().toString()); + builder.append(plainSelect.getIsolation().toString()); } if (plainSelect.getForMode() != null) { - buffer.append(" FOR "); - buffer.append(plainSelect.getForMode().getValue()); + builder.append(" FOR "); + builder.append(plainSelect.getForMode().getValue()); if (plainSelect.getForUpdateTable() != null) { - buffer.append(" OF ").append(plainSelect.getForUpdateTable()); + builder.append(" OF ").append(plainSelect.getForUpdateTable()); } if (plainSelect.getWait() != null) { // wait's toString will do the formatting for us - buffer.append(plainSelect.getWait()); + builder.append(plainSelect.getWait()); } if (plainSelect.isNoWait()) { - buffer.append(" NOWAIT"); + builder.append(" NOWAIT"); } else if (plainSelect.isSkipLocked()) { - buffer.append(" SKIP LOCKED"); + builder.append(" SKIP LOCKED"); } } if (plainSelect.getOptimizeFor() != null) { deparseOptimizeFor(plainSelect.getOptimizeFor()); } if (plainSelect.getForXmlPath() != null) { - buffer.append(" FOR XML PATH(").append(plainSelect.getForXmlPath()).append(")"); + builder.append(" FOR XML PATH(").append(plainSelect.getForXmlPath()).append(")"); } if (plainSelect.getIntoTempTable() != null) { - buffer.append(" INTO TEMP ").append(plainSelect.getIntoTempTable()); + builder.append(" INTO TEMP ").append(plainSelect.getIntoTempTable()); } if (plainSelect.isUseWithNoLog()) { - buffer.append(" WITH NO LOG"); + builder.append(" WITH NO LOG"); } Alias alias = plainSelect.getAlias(); if (alias != null) { - buffer.append(alias); + builder.append(alias); } Pivot pivot = plainSelect.getPivot(); if (pivot != null) { @@ -348,12 +371,12 @@ public StringBuilder visit(PlainSelect plainSelect, S context) { unpivot.accept(this, context); } - return buffer; + return builder; } protected void deparseWhereClause(PlainSelect plainSelect) { if (plainSelect.getWhere() != null) { - buffer.append(" WHERE "); + builder.append(" WHERE "); plainSelect.getWhere().accept(expressionVisitor, null); } } @@ -361,21 +384,21 @@ protected void deparseWhereClause(PlainSelect plainSelect) { protected void deparseDistinctClause(Distinct distinct) { if (distinct != null) { if (distinct.isUseUnique()) { - buffer.append("UNIQUE "); + builder.append("UNIQUE "); } else { - buffer.append("DISTINCT "); + builder.append("DISTINCT "); } if (distinct.getOnSelectItems() != null) { - buffer.append("ON ("); + builder.append("ON ("); for (Iterator> iter = distinct.getOnSelectItems().iterator(); iter .hasNext();) { SelectItem selectItem = iter.next(); selectItem.accept(this, null); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } - buffer.append(") "); + builder.append(") "); } } } @@ -386,7 +409,7 @@ protected void deparseSelectItemsClause(List> selectItems) { SelectItem selectItem = iter.next(); selectItem.accept(this, null); if (iter.hasNext()) { - buffer.append(", "); + builder.append(", "); } } } @@ -395,7 +418,7 @@ protected void deparseSelectItemsClause(List> selectItems) { protected void deparseOrderByElementsClause(PlainSelect plainSelect, List orderByElements) { if (orderByElements != null) { - new OrderByDeParser(expressionVisitor, buffer).deParse(plainSelect.isOracleSiblings(), + new OrderByDeParser(expressionVisitor, builder).deParse(plainSelect.isOracleSiblings(), orderByElements); } } @@ -404,18 +427,18 @@ protected void deparseOrderByElementsClause(PlainSelect plainSelect, public StringBuilder visit(SelectItem selectItem, S context) { selectItem.getExpression().accept(expressionVisitor, context); if (selectItem.getAlias() != null) { - buffer.append(selectItem.getAlias().toString()); + builder.append(selectItem.getAlias().toString()); } - return buffer; + return builder; } @Override public StringBuilder visit(Table tableName, S context) { - buffer.append(tableName.getFullyQualifiedName()); + builder.append(tableName.getFullyQualifiedName()); Alias alias = tableName.getAlias(); if (alias != null) { - buffer.append(alias); + builder.append(alias); } Pivot pivot = tableName.getPivot(); if (pivot != null) { @@ -427,31 +450,31 @@ public StringBuilder visit(Table tableName, S context) { } MySQLIndexHint indexHint = tableName.getIndexHint(); if (indexHint != null) { - buffer.append(indexHint); + builder.append(indexHint); } SQLServerHints sqlServerHints = tableName.getSqlServerHints(); if (sqlServerHints != null) { - buffer.append(sqlServerHints); + builder.append(sqlServerHints); } - return buffer; + return builder; } @Override public StringBuilder visit(Pivot pivot, S context) { // @todo: implement this as Visitor - buffer.append(" PIVOT (").append(PlainSelect.getStringList(pivot.getFunctionItems())); + builder.append(" PIVOT (").append(PlainSelect.getStringList(pivot.getFunctionItems())); - buffer.append(" FOR "); + builder.append(" FOR "); pivot.getForColumns().accept(expressionVisitor, context); // @todo: implement this as Visitor - buffer.append(" IN ").append(PlainSelect.getStringList(pivot.getInItems(), true, true)); + builder.append(" IN ").append(PlainSelect.getStringList(pivot.getInItems(), true, true)); - buffer.append(")"); + builder.append(")"); if (pivot.getAlias() != null) { - buffer.append(pivot.getAlias().toString()); + builder.append(pivot.getAlias().toString()); } - return buffer; + return builder; } @Override @@ -460,7 +483,7 @@ public StringBuilder visit(UnPivot unpivot, S context) { boolean includeNulls = unpivot.getIncludeNulls(); List unPivotClause = unpivot.getUnPivotClause(); List unpivotForClause = unpivot.getUnPivotForClause(); - buffer.append(" UNPIVOT").append(showOptions && includeNulls ? " INCLUDE NULLS" : "") + builder.append(" UNPIVOT").append(showOptions && includeNulls ? " INCLUDE NULLS" : "") .append(showOptions && !includeNulls ? " EXCLUDE NULLS" : "").append(" (") .append(PlainSelect.getStringList(unPivotClause, true, unPivotClause != null && unPivotClause.size() > 1)) @@ -471,53 +494,53 @@ public StringBuilder visit(UnPivot unpivot, S context) { .append(PlainSelect.getStringList(unpivot.getUnPivotInClause(), true, true)) .append(")"); if (unpivot.getAlias() != null) { - buffer.append(unpivot.getAlias().toString()); + builder.append(unpivot.getAlias().toString()); } - return buffer; + return builder; } @Override public StringBuilder visit(PivotXml pivot, S context) { List forColumns = pivot.getForColumns(); - buffer.append(" PIVOT XML (").append(PlainSelect.getStringList(pivot.getFunctionItems())) + builder.append(" PIVOT XML (").append(PlainSelect.getStringList(pivot.getFunctionItems())) .append(" FOR ").append(PlainSelect.getStringList(forColumns, true, forColumns != null && forColumns.size() > 1)) .append(" IN ("); if (pivot.isInAny()) { - buffer.append("ANY"); + builder.append("ANY"); } else if (pivot.getInSelect() != null) { - buffer.append(pivot.getInSelect()); + builder.append(pivot.getInSelect()); } else { - buffer.append(PlainSelect.getStringList(pivot.getInItems())); + builder.append(PlainSelect.getStringList(pivot.getInItems())); } - buffer.append("))"); - return buffer; + builder.append("))"); + return builder; } public void visit(Offset offset) { // OFFSET offset // or OFFSET offset (ROW | ROWS) - buffer.append(" OFFSET "); + builder.append(" OFFSET "); offset.getOffset().accept(expressionVisitor, null); if (offset.getOffsetParam() != null) { - buffer.append(" ").append(offset.getOffsetParam()); + builder.append(" ").append(offset.getOffsetParam()); } } public void visit(Fetch fetch) { - buffer.append(" FETCH "); + builder.append(" FETCH "); if (fetch.isFetchParamFirst()) { - buffer.append("FIRST "); + builder.append("FIRST "); } else { - buffer.append("NEXT "); + builder.append("NEXT "); } if (fetch.getExpression() != null) { fetch.getExpression().accept(expressionVisitor, null); } for (String p : fetch.getFetchParameters()) { - buffer.append(" ").append(p); + builder.append(" ").append(p); } } @@ -532,46 +555,46 @@ public void setExpressionVisitor(ExpressionVisitor visitor) { @SuppressWarnings({"PMD.CyclomaticComplexity"}) public void deparseJoin(Join join) { if (join.isGlobal()) { - buffer.append(" GLOBAL "); + builder.append(" GLOBAL "); } if (join.isSimple() && join.isOuter()) { - buffer.append(", OUTER "); + builder.append(", OUTER "); } else if (join.isSimple()) { - buffer.append(", "); + builder.append(", "); } else { if (join.isNatural()) { - buffer.append(" NATURAL"); + builder.append(" NATURAL"); } if (join.isRight()) { - buffer.append(" RIGHT"); + builder.append(" RIGHT"); } else if (join.isFull()) { - buffer.append(" FULL"); + builder.append(" FULL"); } else if (join.isLeft()) { - buffer.append(" LEFT"); + builder.append(" LEFT"); } else if (join.isCross()) { - buffer.append(" CROSS"); + builder.append(" CROSS"); } if (join.isOuter()) { - buffer.append(" OUTER"); + builder.append(" OUTER"); } else if (join.isInner()) { - buffer.append(" INNER"); + builder.append(" INNER"); } else if (join.isSemi()) { - buffer.append(" SEMI"); + builder.append(" SEMI"); } if (join.isStraight()) { - buffer.append(" STRAIGHT_JOIN "); + builder.append(" STRAIGHT_JOIN "); } else if (join.isApply()) { - buffer.append(" APPLY "); + builder.append(" APPLY "); } else { if (join.getJoinHint() != null) { - buffer.append(" ").append(join.getJoinHint()); + builder.append(" ").append(join.getJoinHint()); } - buffer.append(" JOIN "); + builder.append(" JOIN "); } } @@ -579,71 +602,71 @@ public void deparseJoin(Join join) { FromItem fromItem = join.getFromItem(); fromItem.accept(this, null); if (join.isWindowJoin()) { - buffer.append(" WITHIN "); - buffer.append(join.getJoinWindow().toString()); + builder.append(" WITHIN "); + builder.append(join.getJoinWindow().toString()); } for (Expression onExpression : join.getOnExpressions()) { - buffer.append(" ON "); + builder.append(" ON "); onExpression.accept(expressionVisitor, null); } if (!join.getUsingColumns().isEmpty()) { - buffer.append(" USING ("); + builder.append(" USING ("); for (Iterator iterator = join.getUsingColumns().iterator(); iterator .hasNext();) { Column column = iterator.next(); - buffer.append(column.toString()); + builder.append(column.toString()); if (iterator.hasNext()) { - buffer.append(", "); + builder.append(", "); } } - buffer.append(")"); + builder.append(")"); } } public void deparseLateralView(LateralView lateralView) { - buffer.append(" LATERAL VIEW"); + builder.append(" LATERAL VIEW"); if (lateralView.isUsingOuter()) { - buffer.append(" OUTER"); + builder.append(" OUTER"); } - buffer.append(" "); + builder.append(" "); lateralView.getGeneratorFunction().accept(expressionVisitor, null); if (lateralView.getTableAlias() != null) { - buffer.append(" ").append(lateralView.getTableAlias()); + builder.append(" ").append(lateralView.getTableAlias()); } - buffer.append(" ").append(lateralView.getColumnAlias()); + builder.append(" ").append(lateralView.getColumnAlias()); } @Override public StringBuilder visit(SetOperationList list, S context) { List> withItemsList = list.getWithItemsList(); if (withItemsList != null && !withItemsList.isEmpty()) { - buffer.append("WITH "); + builder.append("WITH "); for (Iterator> iter = withItemsList.iterator(); iter.hasNext();) { iter.next().accept((SelectVisitor) this, context); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } for (int i = 0; i < list.getSelects().size(); i++) { if (i != 0) { - buffer.append(' ').append(list.getOperations().get(i - 1)).append(' '); + builder.append(' ').append(list.getOperations().get(i - 1)).append(' '); } list.getSelects().get(i).accept((SelectVisitor) this, context); } if (list.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer).deParse(list.getOrderByElements()); + new OrderByDeParser(expressionVisitor, builder).deParse(list.getOrderByElements()); } if (list.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(list.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(list.getLimit()); } if (list.getOffset() != null) { visit(list.getOffset()); @@ -652,12 +675,12 @@ public StringBuilder visit(SetOperationList list, S context) { visit(list.getFetch()); } if (list.getIsolation() != null) { - buffer.append(list.getIsolation().toString()); + builder.append(list.getIsolation().toString()); } Alias alias = list.getAlias(); if (alias != null) { - buffer.append(alias); + builder.append(alias); } Pivot pivot = list.getPivot(); if (pivot != null) { @@ -668,75 +691,75 @@ public StringBuilder visit(SetOperationList list, S context) { unpivot.accept(this, context); } - return buffer; + return builder; } @Override public StringBuilder visit(WithItem withItem, S context) { if (withItem.isRecursive()) { - buffer.append("RECURSIVE "); + builder.append("RECURSIVE "); } - buffer.append(withItem.getAlias().getName()); + builder.append(withItem.getAlias().getName()); if (withItem.getWithItemList() != null) { - buffer.append(" ") + builder.append(" ") .append(PlainSelect.getStringList(withItem.getWithItemList(), true, true)); } - buffer.append(" AS "); + builder.append(" AS "); if (withItem.isMaterialized()) { - buffer.append("MATERIALIZED "); + builder.append("MATERIALIZED "); } StatementDeParser statementDeParser = - new StatementDeParser((ExpressionDeParser) expressionVisitor, this, buffer); + new StatementDeParser((ExpressionDeParser) expressionVisitor, this, builder); statementDeParser.deParse(withItem.getParenthesedStatement()); - return buffer; + return builder; } @Override public StringBuilder visit(LateralSubSelect lateralSubSelect, S context) { - buffer.append(lateralSubSelect.getPrefix()); + builder.append(lateralSubSelect.getPrefix()); visit((ParenthesedSelect) lateralSubSelect, context); - return buffer; + return builder; } @Override public StringBuilder visit(TableStatement tableStatement, S context) { - new TableStatementDeParser(expressionVisitor, buffer).deParse(tableStatement); - return buffer; + new TableStatementDeParser(expressionVisitor, builder).deParse(tableStatement); + return builder; } @Override public StringBuilder visit(TableFunction tableFunction, S context) { if (tableFunction.getPrefix() != null) { - buffer.append(tableFunction.getPrefix()).append(" "); + builder.append(tableFunction.getPrefix()).append(" "); } tableFunction.getFunction().accept(this.expressionVisitor, context); if (tableFunction.getAlias() != null) { - buffer.append(tableFunction.getAlias()); + builder.append(tableFunction.getAlias()); } - return buffer; + return builder; } @Override public StringBuilder visit(ParenthesedFromItem fromItem, S context) { - buffer.append("("); + builder.append("("); fromItem.getFromItem().accept(this, context); List joins = fromItem.getJoins(); if (joins != null) { for (Join join : joins) { if (join.isSimple()) { - buffer.append(", ").append(join); + builder.append(", ").append(join); } else { - buffer.append(" ").append(join); + builder.append(" ").append(join); } } } - buffer.append(")"); + builder.append(")"); if (fromItem.getAlias() != null) { - buffer.append(fromItem.getAlias().toString()); + builder.append(fromItem.getAlias().toString()); } if (fromItem.getPivot() != null) { @@ -746,13 +769,13 @@ public StringBuilder visit(ParenthesedFromItem fromItem, S context) { if (fromItem.getUnPivot() != null) { visit(fromItem.getUnPivot(), context); } - return buffer; + return builder; } @Override public StringBuilder visit(Values values, S context) { - new ValuesStatementDeParser(expressionVisitor, buffer).deParse(values); - return buffer; + new ValuesStatementDeParser(expressionVisitor, builder).deParse(values); + return builder; } @Override @@ -804,6 +827,17 @@ public void visit(TableStatement tableStatement) { visit(tableStatement, null); } + @Override + public StringBuilder visit(FromQuery fromQuery, S context) { + builder.append("FROM "); + fromQuery.getFromItem().accept(this, context); + builder.append("\n"); + for (PipeOperator operator : fromQuery.getPipeOperators()) { + operator.accept(this, context); + } + return builder; + } + public void visit(TableFunction tableFunction) { visit(tableFunction, null); } @@ -814,9 +848,9 @@ public void visit(ParenthesedFromItem fromItem) { private void deparseOptimizeFor(OptimizeFor optimizeFor) { - buffer.append(" OPTIMIZE FOR "); - buffer.append(optimizeFor.getRowCount()); - buffer.append(" ROWS"); + builder.append(" OPTIMIZE FOR "); + builder.append(optimizeFor.getRowCount()); + builder.append(" ROWS"); } @Override @@ -824,4 +858,127 @@ void deParse(PlainSelect statement) { statement.accept((SelectVisitor) this, null); } + @Override + public StringBuilder visit(AggregatePipeOperator aggregate, S context) { + builder.append("|> ").append("AGGREGATE"); + int i = 0; + for (SelectItem selectItem : aggregate.getSelectItems()) { + builder.append(i++ > 0 ? ", " : " "); + selectItem.accept(this, context); + } + builder.append("\n"); + + if (!aggregate.getGroupItems().isEmpty()) { + builder.append("\t").append("GROUP"); + if (aggregate.isUsingShortHandOrdering()) { + builder.append(" AND ORDER"); + } + builder.append(" BY"); + i = 0; + for (SelectItem selectItem : aggregate.getGroupItems()) { + builder.append(i++ > 0 ? ", " : " "); + selectItem.accept(this, context); + } + builder.append("\n"); + } + + return builder; + } + + @Override + public StringBuilder visit(AsPipeOperator as, S context) { + return builder; + } + + @Override + public StringBuilder visit(CallPipeOperator call, S context) { + return builder; + } + + @Override + public StringBuilder visit(DropPipeOperator drop, S context) { + return builder; + } + + @Override + public StringBuilder visit(ExceptPipeOperator except, S context) { + return builder; + } + + @Override + public StringBuilder visit(ExtendPipeOperator extend, S context) { + return builder; + } + + @Override + public StringBuilder visit(IntersectPipeOperator intersect, S context) { + return builder; + } + + @Override + public StringBuilder visit(JoinPipeOperator join, S context) { + return builder; + } + + @Override + public StringBuilder visit(LimitPipeOperator limit, S context) { + return builder; + } + + @Override + public StringBuilder visit(OrderByPipeOperator orderBy, S context) { + builder.append("|> "); + new OrderByDeParser(expressionVisitor, builder).deParse(orderBy.getOrderByElements()); + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(PivotPipeOperator pivot, S context) { + return builder; + } + + @Override + public StringBuilder visit(RenamePipeOperator rename, S context) { + return builder; + } + + @Override + public StringBuilder visit(SelectPipeOperator select, S context) { + return builder; + } + + @Override + public StringBuilder visit(SetPipeOperator set, S context) { + return builder; + } + + @Override + public StringBuilder visit(TableSamplePipeOperator tableSample, S context) { + return builder; + } + + @Override + public StringBuilder visit(UnionPipeOperator union, S context) { + return builder; + } + + @Override + public StringBuilder visit(UnPivotPipeOperator unPivot, S context) { + return builder; + } + + @Override + public StringBuilder visit(WherePipeOperator where, S context) { + builder.append("|> ") + .append("WHERE "); + where.getExpression().accept(expressionVisitor, context); + builder.append("\n"); + return builder; + } + + @Override + public StringBuilder visit(WindowPipeOperator window, S context) { + return null; + } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/SetStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/SetStatementDeParser.java index e38cb418c..31ff0f599 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SetStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SetStatementDeParser.java @@ -27,23 +27,23 @@ public SetStatementDeParser(ExpressionVisitor expressionVisitor, @Override public void deParse(SetStatement set) { - buffer.append("SET "); + builder.append("SET "); if (set.getEffectParameter() != null) { - buffer.append(set.getEffectParameter()).append(" "); + builder.append(set.getEffectParameter()).append(" "); } for (int i = 0; i < set.getCount(); i++) { if (i > 0) { - buffer.append(", "); + builder.append(", "); } - buffer.append(set.getName(i)); + builder.append(set.getName(i)); if (set.isUseEqual(i)) { - buffer.append(" ="); + builder.append(" ="); } - buffer.append(" "); + builder.append(" "); List expressions = set.getExpressions(i); for (int j = 0; j < expressions.size(); j++) { if (j > 0) { - buffer.append(", "); + builder.append(", "); } expressions.get(j).accept(expressionVisitor, null); } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ShowColumnsStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ShowColumnsStatementDeParser.java index ad4627a2d..9fc744010 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ShowColumnsStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ShowColumnsStatementDeParser.java @@ -19,6 +19,6 @@ public ShowColumnsStatementDeParser(StringBuilder buffer) { @Override public void deParse(ShowColumnsStatement show) { - buffer.append("SHOW COLUMNS FROM ").append(show.getTableName()); + builder.append("SHOW COLUMNS FROM ").append(show.getTableName()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ShowIndexStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ShowIndexStatementDeParser.java index 5e4a223bd..1d81d5af6 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ShowIndexStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ShowIndexStatementDeParser.java @@ -23,7 +23,7 @@ public ShowIndexStatementDeParser(StringBuilder buffer) { @Override public void deParse(ShowIndexStatement show) { - buffer.append("SHOW INDEX FROM ").append(show.getTableName()); + builder.append("SHOW INDEX FROM ").append(show.getTableName()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ShowStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ShowStatementDeParser.java index 70c5d9b2e..e03bdc963 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ShowStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ShowStatementDeParser.java @@ -19,6 +19,6 @@ public ShowStatementDeParser(StringBuilder buffer) { @Override public void deParse(ShowStatement show) { - buffer.append("SHOW ").append(show.getName()); + builder.append("SHOW ").append(show.getName()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ShowTablesStatementDeparser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ShowTablesStatementDeparser.java index a218f3f1c..127b12015 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ShowTablesStatementDeparser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ShowTablesStatementDeparser.java @@ -19,6 +19,6 @@ public ShowTablesStatementDeparser(StringBuilder buffer) { @Override void deParse(ShowTablesStatement statement) { - buffer.append(statement); + builder.append(statement); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java index cd16843fc..b078b8716 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/StatementDeParser.java @@ -107,341 +107,342 @@ public StatementDeParser(ExpressionDeParser expressionDeParser, SelectDeParser s this.expressionDeParser = expressionDeParser; this.selectDeParser = selectDeParser; - this.selectDeParser.setBuffer(buffer); + this.selectDeParser.setBuilder(buffer); this.selectDeParser.setExpressionVisitor(expressionDeParser); this.expressionDeParser.setSelectVisitor(selectDeParser); - this.expressionDeParser.setBuffer(buffer); + this.expressionDeParser.setBuilder(buffer); } @Override public StringBuilder visit(CreateIndex createIndex, S context) { - CreateIndexDeParser createIndexDeParser = new CreateIndexDeParser(buffer); + CreateIndexDeParser createIndexDeParser = new CreateIndexDeParser(builder); createIndexDeParser.deParse(createIndex); - return buffer; + return builder; } @Override public StringBuilder visit(CreateTable createTable, S context) { - CreateTableDeParser createTableDeParser = new CreateTableDeParser(this, buffer); + CreateTableDeParser createTableDeParser = new CreateTableDeParser(this, builder); createTableDeParser.deParse(createTable); - return buffer; + return builder; } @Override public StringBuilder visit(CreateView createView, S context) { - CreateViewDeParser createViewDeParser = new CreateViewDeParser(buffer); + CreateViewDeParser createViewDeParser = new CreateViewDeParser(builder); createViewDeParser.deParse(createView); - return buffer; + return builder; } @Override public StringBuilder visit(RefreshMaterializedViewStatement materializedViewStatement, S context) { - new RefreshMaterializedViewStatementDeParser(buffer).deParse(materializedViewStatement); - return buffer; + new RefreshMaterializedViewStatementDeParser(builder).deParse(materializedViewStatement); + return builder; } @Override public StringBuilder visit(AlterView alterView, S context) { - AlterViewDeParser alterViewDeParser = new AlterViewDeParser(buffer); + AlterViewDeParser alterViewDeParser = new AlterViewDeParser(builder); alterViewDeParser.deParse(alterView); - return buffer; + return builder; } @Override public StringBuilder visit(Delete delete, S context) { - DeleteDeParser deleteDeParser = new DeleteDeParser(expressionDeParser, buffer); + DeleteDeParser deleteDeParser = new DeleteDeParser(expressionDeParser, builder); deleteDeParser.deParse(delete); - return buffer; + return builder; } @Override public StringBuilder visit(Drop drop, S context) { - DropDeParser dropDeParser = new DropDeParser(buffer); + DropDeParser dropDeParser = new DropDeParser(builder); dropDeParser.deParse(drop); - return buffer; + return builder; } @Override public StringBuilder visit(Insert insert, S context) { InsertDeParser insertDeParser = - new InsertDeParser(expressionDeParser, selectDeParser, buffer); + new InsertDeParser(expressionDeParser, selectDeParser, builder); insertDeParser.deParse(insert); - return buffer; + return builder; } @Override public StringBuilder visit(ParenthesedInsert insert, S context) { List> withItemsList = insert.getWithItemsList(); addWithItemsToBuffer(withItemsList, context); - buffer.append("("); + builder.append("("); insert.getInsert().accept(this, context); - buffer.append(")"); - return buffer; + builder.append(")"); + return builder; } @Override public StringBuilder visit(ParenthesedUpdate update, S context) { List> withItemsList = update.getWithItemsList(); addWithItemsToBuffer(withItemsList, context); - buffer.append("("); + builder.append("("); update.getUpdate().accept(this, context); - buffer.append(")"); - return buffer; + builder.append(")"); + return builder; } @Override public StringBuilder visit(ParenthesedDelete delete, S context) { List> withItemsList = delete.getWithItemsList(); addWithItemsToBuffer(withItemsList, context); - buffer.append("("); + builder.append("("); delete.getDelete().accept(this, context); - buffer.append(")"); - return buffer; + builder.append(")"); + return builder; } + private StringBuilder addWithItemsToBuffer(List> withItemsList, S context) { if (withItemsList != null && !withItemsList.isEmpty()) { - buffer.append("WITH "); + builder.append("WITH "); for (WithItem withItem : withItemsList) { withItem.accept((SelectVisitor) this, context); - buffer.append(" "); + builder.append(" "); } } - return buffer; + return builder; } @Override public StringBuilder visit(Select select, S context) { select.accept((SelectVisitor) selectDeParser, context); - return buffer; + return builder; } @Override public StringBuilder visit(Truncate truncate, S context) { - buffer.append("TRUNCATE"); + builder.append("TRUNCATE"); if (truncate.isTableToken()) { - buffer.append(" TABLE"); + builder.append(" TABLE"); } if (truncate.isOnly()) { - buffer.append(" ONLY"); + builder.append(" ONLY"); } - buffer.append(" "); + builder.append(" "); if (truncate.getTables() != null && !truncate.getTables().isEmpty()) { - buffer.append(truncate.getTables().stream() + builder.append(truncate.getTables().stream() .map(Table::toString) .collect(Collectors.joining(", "))); } else { - buffer.append(truncate.getTable()); + builder.append(truncate.getTable()); } if (truncate.getCascade()) { - buffer.append(" CASCADE"); + builder.append(" CASCADE"); } - return buffer; + return builder; } @Override public StringBuilder visit(Update update, S context) { - UpdateDeParser updateDeParser = new UpdateDeParser(expressionDeParser, buffer); + UpdateDeParser updateDeParser = new UpdateDeParser(expressionDeParser, builder); updateDeParser.deParse(update); - return buffer; + return builder; } public StringBuilder visit(Analyze analyzer, S context) { - buffer.append("ANALYZE "); - buffer.append(analyzer.getTable()); - return buffer; + builder.append("ANALYZE "); + builder.append(analyzer.getTable()); + return builder; } @Override public StringBuilder visit(Alter alter, S context) { - AlterDeParser alterDeParser = new AlterDeParser(buffer); + AlterDeParser alterDeParser = new AlterDeParser(builder); alterDeParser.deParse(alter); - return buffer; + return builder; } @Override public StringBuilder visit(Statements statements, S context) { statements.accept(this, context); - return buffer; + return builder; } @Override public StringBuilder visit(Execute execute, S context) { - ExecuteDeParser executeDeParser = new ExecuteDeParser(expressionDeParser, buffer); + ExecuteDeParser executeDeParser = new ExecuteDeParser(expressionDeParser, builder); executeDeParser.deParse(execute); - return buffer; + return builder; } @Override public StringBuilder visit(SetStatement set, S context) { SetStatementDeParser setStatementDeparser = - new SetStatementDeParser(expressionDeParser, buffer); + new SetStatementDeParser(expressionDeParser, builder); setStatementDeparser.deParse(set); - return buffer; + return builder; } @Override public StringBuilder visit(ResetStatement reset, S context) { ResetStatementDeParser setStatementDeparser = - new ResetStatementDeParser(expressionDeParser, buffer); + new ResetStatementDeParser(expressionDeParser, builder); setStatementDeparser.deParse(reset); - return buffer; + return builder; } @SuppressWarnings({"PMD.CyclomaticComplexity"}) @Override public StringBuilder visit(Merge merge, S context) { - new MergeDeParser(expressionDeParser, selectDeParser, buffer).deParse(merge); - return buffer; + new MergeDeParser(expressionDeParser, selectDeParser, builder).deParse(merge); + return builder; } @Override public StringBuilder visit(SavepointStatement savepointStatement, S context) { - buffer.append(savepointStatement.toString()); - return buffer; + builder.append(savepointStatement.toString()); + return builder; } @Override public StringBuilder visit(RollbackStatement rollbackStatement, S context) { - buffer.append(rollbackStatement.toString()); - return buffer; + builder.append(rollbackStatement.toString()); + return builder; } @Override public StringBuilder visit(Commit commit, S context) { - buffer.append(commit.toString()); - return buffer; + builder.append(commit.toString()); + return builder; } @Override public StringBuilder visit(Upsert upsert, S context) { UpsertDeParser upsertDeParser = - new UpsertDeParser(expressionDeParser, selectDeParser, buffer); + new UpsertDeParser(expressionDeParser, selectDeParser, builder); upsertDeParser.deParse(upsert); - return buffer; + return builder; } @Override public StringBuilder visit(UseStatement use, S context) { - new UseStatementDeParser(buffer).deParse(use); - return buffer; + new UseStatementDeParser(builder).deParse(use); + return builder; } @Override public StringBuilder visit(ShowColumnsStatement show, S context) { - new ShowColumnsStatementDeParser(buffer).deParse(show); - return buffer; + new ShowColumnsStatementDeParser(builder).deParse(show); + return builder; } @Override public StringBuilder visit(ShowIndexStatement showIndexes, S context) { - new ShowIndexStatementDeParser(buffer).deParse(showIndexes); - return buffer; + new ShowIndexStatementDeParser(builder).deParse(showIndexes); + return builder; } @Override public StringBuilder visit(ShowTablesStatement showTables, S context) { - new ShowTablesStatementDeparser(buffer).deParse(showTables); - return buffer; + new ShowTablesStatementDeparser(builder).deParse(showTables); + return builder; } @Override public StringBuilder visit(Block block, S context) { - buffer.append("BEGIN\n"); + builder.append("BEGIN\n"); if (block.getStatements() != null) { for (Statement stmt : block.getStatements()) { stmt.accept(this, context); - buffer.append(";\n"); + builder.append(";\n"); } } - buffer.append("END"); + builder.append("END"); if (block.hasSemicolonAfterEnd()) { - buffer.append(";"); + builder.append(";"); } - return buffer; + return builder; } @Override public StringBuilder visit(Comment comment, S context) { - buffer.append(comment.toString()); - return buffer; + builder.append(comment.toString()); + return builder; } @Override public StringBuilder visit(DescribeStatement describe, S context) { - buffer.append(describe.getDescribeType()); - buffer.append(" "); - buffer.append(describe.getTable()); - return buffer; + builder.append(describe.getDescribeType()); + builder.append(" "); + builder.append(describe.getTable()); + return builder; } @Override public StringBuilder visit(ExplainStatement explainStatement, S context) { - buffer.append(explainStatement.getKeyword()).append(" "); + builder.append(explainStatement.getKeyword()).append(" "); if (explainStatement.getTable() != null) { - buffer.append(explainStatement.getTable()); + builder.append(explainStatement.getTable()); } else if (explainStatement.getOptions() != null) { - buffer.append(explainStatement.getOptions().values().stream() + builder.append(explainStatement.getOptions().values().stream() .map(ExplainStatement.Option::formatOption).collect(Collectors.joining(" "))); - buffer.append(" "); + builder.append(" "); } if (explainStatement.getStatement() != null) { explainStatement.getStatement().accept(this, context); } - return buffer; + return builder; } @Override public StringBuilder visit(ShowStatement showStatement, S context) { - new ShowStatementDeParser(buffer).deParse(showStatement); - return buffer; + new ShowStatementDeParser(builder).deParse(showStatement); + return builder; } @Override public StringBuilder visit(DeclareStatement declareStatement, S context) { - new DeclareStatementDeParser(expressionDeParser, buffer).deParse(declareStatement); - return buffer; + new DeclareStatementDeParser(expressionDeParser, builder).deParse(declareStatement); + return builder; } @Override public StringBuilder visit(Grant grant, S context) { - GrantDeParser grantDeParser = new GrantDeParser(buffer); + GrantDeParser grantDeParser = new GrantDeParser(builder); grantDeParser.deParse(grant); - return buffer; + return builder; } @Override public StringBuilder visit(CreateSchema aThis, S context) { - buffer.append(aThis.toString()); - return buffer; + builder.append(aThis.toString()); + return builder; } @Override public StringBuilder visit(CreateSequence createSequence, S context) { - new CreateSequenceDeParser(buffer).deParse(createSequence); - return buffer; + new CreateSequenceDeParser(builder).deParse(createSequence); + return builder; } @Override public StringBuilder visit(AlterSequence alterSequence, S context) { - new AlterSequenceDeParser(buffer).deParse(alterSequence); - return buffer; + new AlterSequenceDeParser(builder).deParse(alterSequence); + return builder; } @Override public StringBuilder visit(CreateFunctionalStatement createFunctionalStatement, S context) { - buffer.append(createFunctionalStatement.toString()); - return buffer; + builder.append(createFunctionalStatement.toString()); + return builder; } @Override public StringBuilder visit(CreateSynonym createSynonym, S context) { - new CreateSynonymDeparser(buffer).deParse(createSynonym); - return buffer; + new CreateSynonymDeparser(builder).deParse(createSynonym); + return builder; } @Override @@ -451,38 +452,38 @@ void deParse(Statement statement) { @Override public StringBuilder visit(AlterSession alterSession, S context) { - new AlterSessionDeParser(buffer).deParse(alterSession); - return buffer; + new AlterSessionDeParser(builder).deParse(alterSession); + return builder; } @Override public StringBuilder visit(IfElseStatement ifElseStatement, S context) { - ifElseStatement.appendTo(buffer); - return buffer; + ifElseStatement.appendTo(builder); + return builder; } @Override public StringBuilder visit(RenameTableStatement renameTableStatement, S context) { - renameTableStatement.appendTo(buffer); - return buffer; + renameTableStatement.appendTo(builder); + return builder; } @Override public StringBuilder visit(PurgeStatement purgeStatement, S context) { - purgeStatement.appendTo(buffer); - return buffer; + purgeStatement.appendTo(builder); + return builder; } @Override public StringBuilder visit(AlterSystemStatement alterSystemStatement, S context) { - alterSystemStatement.appendTo(buffer); - return buffer; + alterSystemStatement.appendTo(builder); + return builder; } @Override public StringBuilder visit(UnsupportedStatement unsupportedStatement, S context) { - unsupportedStatement.appendTo(buffer); - return buffer; + unsupportedStatement.appendTo(builder); + return builder; } public ExpressionDeParser getExpressionDeParser() { diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java index 47b271e34..73e1d429d 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/TableStatementDeParser.java @@ -10,6 +10,7 @@ package net.sf.jsqlparser.util.deparser; import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.*; /** @@ -32,10 +33,10 @@ public void deParse(TableStatement tableStatement) { } public void deparse(Offset offset) { - buffer.append(" OFFSET "); + builder.append(" OFFSET "); offset.getOffset().accept(expressionVisitor, null); if (offset.getOffsetParam() != null) { - buffer.append(" ").append(offset.getOffsetParam()); + builder.append(" ").append(offset.getOffsetParam()); } } @@ -43,50 +44,55 @@ public void deparse(Offset offset) { @Override public StringBuilder visit(ParenthesedSelect parenthesedSelect, S context) { - return buffer; + return builder; } @Override public StringBuilder visit(PlainSelect plainSelect, S context) { - return buffer; + return builder; + } + + @Override + public StringBuilder visit(FromQuery fromQuery, S context) { + return builder; } @Override public StringBuilder visit(SetOperationList setOperationList, S context) { - return buffer; + return builder; } @Override public StringBuilder visit(WithItem withItem, S context) { - return buffer; + return builder; } @Override public StringBuilder visit(Values values, S context) { - return buffer; + return builder; } @Override public StringBuilder visit(LateralSubSelect lateralSubSelect, S context) { - return buffer; + return builder; } @Override public StringBuilder visit(TableStatement tableStatement, S context) { - buffer.append("TABLE "); - buffer.append(tableStatement.getTable()); + builder.append("TABLE "); + builder.append(tableStatement.getTable()); if (tableStatement.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer) + new OrderByDeParser(expressionVisitor, builder) .deParse(tableStatement.getOrderByElements()); } if (tableStatement.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(tableStatement.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(tableStatement.getLimit()); } if (tableStatement.getOffset() != null) { deparse(tableStatement.getOffset()); @@ -94,9 +100,10 @@ public StringBuilder visit(TableStatement tableStatement, S context) { // TODO UNION - tableStatement.appendTo(buffer, tableStatement.getAlias(), tableStatement.getPivot(), + tableStatement.appendTo( + builder, tableStatement.getAlias(), tableStatement.getPivot(), tableStatement.getUnPivot()); - return buffer; + return builder; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java index a16deec83..d5dcac7f1 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/UpdateDeParser.java @@ -39,53 +39,53 @@ public UpdateDeParser(ExpressionVisitor expressionVisitor, "PMD.ExcessiveMethodLength"}) public void deParse(Update update) { if (update.getWithItemsList() != null && !update.getWithItemsList().isEmpty()) { - buffer.append("WITH "); + builder.append("WITH "); for (Iterator> iter = update.getWithItemsList().iterator(); iter .hasNext();) { WithItem withItem = iter.next(); - buffer.append(withItem); + builder.append(withItem); if (iter.hasNext()) { - buffer.append(","); + builder.append(","); } - buffer.append(" "); + builder.append(" "); } } - buffer.append("UPDATE "); + builder.append("UPDATE "); if (update.getOracleHint() != null) { - buffer.append(update.getOracleHint()).append(" "); + builder.append(update.getOracleHint()).append(" "); } if (update.getModifierPriority() != null) { - buffer.append(update.getModifierPriority()).append(" "); + builder.append(update.getModifierPriority()).append(" "); } if (update.isModifierIgnore()) { - buffer.append("IGNORE "); + builder.append("IGNORE "); } - buffer.append(update.getTable()); + builder.append(update.getTable()); if (update.getStartJoins() != null) { for (Join join : update.getStartJoins()) { if (join.isSimple()) { - buffer.append(", ").append(join); + builder.append(", ").append(join); } else { - buffer.append(" ").append(join); + builder.append(" ").append(join); } } } - buffer.append(" SET "); + builder.append(" SET "); deparseUpdateSetsClause(update); if (update.getOutputClause() != null) { - update.getOutputClause().appendTo(buffer); + update.getOutputClause().appendTo(builder); } if (update.getFromItem() != null) { - buffer.append(" FROM ").append(update.getFromItem()); + builder.append(" FROM ").append(update.getFromItem()); if (update.getJoins() != null) { for (Join join : update.getJoins()) { if (join.isSimple()) { - buffer.append(", ").append(join); + builder.append(", ").append(join); } else { - buffer.append(" ").append(join); + builder.append(" ").append(join); } } } @@ -94,29 +94,29 @@ public void deParse(Update update) { deparseWhereClause(update); if (update.getPreferringClause() != null) { - buffer.append(" ").append(update.getPreferringClause()); + builder.append(" ").append(update.getPreferringClause()); } if (update.getOrderByElements() != null) { - new OrderByDeParser(expressionVisitor, buffer).deParse(update.getOrderByElements()); + new OrderByDeParser(expressionVisitor, builder).deParse(update.getOrderByElements()); } if (update.getLimit() != null) { - new LimitDeparser(expressionVisitor, buffer).deParse(update.getLimit()); + new LimitDeparser(expressionVisitor, builder).deParse(update.getLimit()); } if (update.getReturningClause() != null) { - update.getReturningClause().appendTo(buffer); + update.getReturningClause().appendTo(builder); } } protected void deparseWhereClause(Update update) { if (update.getWhere() != null) { - buffer.append(" WHERE "); + builder.append(" WHERE "); update.getWhere().accept(expressionVisitor, null); } } protected void deparseUpdateSetsClause(Update update) { - deparseUpdateSets(update.getUpdateSets(), buffer, expressionVisitor); + deparseUpdateSets(update.getUpdateSets(), builder, expressionVisitor); } @@ -132,16 +132,16 @@ public void setExpressionVisitor(ExpressionVisitor visitor) { public StringBuilder visit(OrderByElement orderBy, S context) { orderBy.getExpression().accept(expressionVisitor, context); if (!orderBy.isAsc()) { - buffer.append(" DESC"); + builder.append(" DESC"); } else if (orderBy.isAscDescPresent()) { - buffer.append(" ASC"); + builder.append(" ASC"); } if (orderBy.getNullOrdering() != null) { - buffer.append(' '); - buffer.append(orderBy.getNullOrdering() == OrderByElement.NullOrdering.NULLS_FIRST + builder.append(' '); + builder.append(orderBy.getNullOrdering() == OrderByElement.NullOrdering.NULLS_FIRST ? "NULLS FIRST" : "NULLS LAST"); } - return buffer; + return builder; } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java index 1038d145a..0835284a4 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/UpsertDeParser.java @@ -34,36 +34,36 @@ public void deParse(Upsert upsert) { switch (upsert.getUpsertType()) { case REPLACE: case REPLACE_SET: - buffer.append("REPLACE "); + builder.append("REPLACE "); break; case INSERT_OR_ABORT: - buffer.append("INSERT OR ABORT "); + builder.append("INSERT OR ABORT "); break; case INSERT_OR_FAIL: - buffer.append("INSERT OR FAIL "); + builder.append("INSERT OR FAIL "); break; case INSERT_OR_IGNORE: - buffer.append("INSERT OR IGNORE "); + builder.append("INSERT OR IGNORE "); break; case INSERT_OR_REPLACE: - buffer.append("INSERT OR REPLACE "); + builder.append("INSERT OR REPLACE "); break; case INSERT_OR_ROLLBACK: - buffer.append("INSERT OR ROLLBACK "); + builder.append("INSERT OR ROLLBACK "); break; case UPSERT: default: - buffer.append("UPSERT "); + builder.append("UPSERT "); } if (upsert.isUsingInto()) { - buffer.append("INTO "); + builder.append("INTO "); } - buffer.append(upsert.getTable().getFullyQualifiedName()); + builder.append(upsert.getTable().getFullyQualifiedName()); if (upsert.getUpdateSets() != null) { - buffer.append(" SET "); - deparseUpdateSets(upsert.getUpdateSets(), buffer, expressionVisitor); + builder.append(" SET "); + deparseUpdateSets(upsert.getUpdateSets(), builder, expressionVisitor); } else { if (upsert.getColumns() != null) { upsert.getColumns().accept(expressionVisitor, null); @@ -74,13 +74,13 @@ public void deParse(Upsert upsert) { } if (upsert.getSelect() != null) { - buffer.append(" "); + builder.append(" "); upsert.getSelect().accept((SelectVisitor) selectVisitor, null); } if (upsert.getDuplicateUpdateSets() != null) { - buffer.append(" ON DUPLICATE KEY UPDATE "); - deparseUpdateSets(upsert.getDuplicateUpdateSets(), buffer, expressionVisitor); + builder.append(" ON DUPLICATE KEY UPDATE "); + deparseUpdateSets(upsert.getDuplicateUpdateSets(), builder, expressionVisitor); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/UseStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/UseStatementDeParser.java index c0f4a8f48..7787a37cb 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/UseStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/UseStatementDeParser.java @@ -19,10 +19,10 @@ public UseStatementDeParser(StringBuilder buffer) { @Override public void deParse(UseStatement set) { - buffer.append("USE "); + builder.append("USE "); if (set.hasSchemaKeyword()) { - buffer.append("SCHEMA "); + builder.append("SCHEMA "); } - buffer.append(set.getName()); + builder.append(set.getName()); } } diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java index 8b57da126..eb39481d0 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ValuesStatementDeParser.java @@ -24,10 +24,10 @@ public ValuesStatementDeParser(ExpressionVisitor expressionVisito @Override public void deParse(Values values) { - buffer.append("VALUES "); + builder.append("VALUES "); values.getExpressions().accept(expressionVisitor, null); if (values.getAlias() != null) { - buffer.append(" ").append(values.getAlias()); + builder.append(" ").append(values.getAlias()); } } } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java index c4fc26a94..0b6baca9d 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java @@ -119,6 +119,7 @@ import net.sf.jsqlparser.expression.operators.relational.TSQLRightJoin; import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.schema.Column; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.AllColumns; import net.sf.jsqlparser.statement.select.AllTableColumns; import net.sf.jsqlparser.statement.select.ParenthesedSelect; @@ -1291,4 +1292,9 @@ public Void visit(CosineSimilarity cosineSimilarity, S context) { return null; } + @Override + public Void visit(FromQuery fromQuery, S context) { + return null; + } + } 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 1948a78d7..49367ddf0 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 @@ -16,6 +16,7 @@ import net.sf.jsqlparser.expression.SQLServerHints; import net.sf.jsqlparser.parser.feature.Feature; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.ExceptOp; import net.sf.jsqlparser.statement.select.Fetch; import net.sf.jsqlparser.statement.select.ForMode; @@ -408,6 +409,11 @@ public void visit(TableStatement tableStatement) { visit(tableStatement, null); } + @Override + public Void visit(FromQuery fromQuery, S context) { + return null; + } + public void visit(TableFunction tableFunction) { visit(tableFunction, null); } diff --git a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java index 0e7f25a2e..d8ce6078b 100644 --- a/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java +++ b/src/main/java/net/sf/jsqlparser/util/validation/validator/StatementValidator.java @@ -112,6 +112,7 @@ public Void visit(ParenthesedDelete delete, S context) { return visit(delete.getDelete(), context); } + @Override public Void visit(Drop drop, S context) { getValidator(DropValidator.class).validate(drop); diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index d1a23a81d..6eb817dd5 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -58,6 +58,7 @@ import net.sf.jsqlparser.statement.delete.*; import net.sf.jsqlparser.statement.drop.*; import net.sf.jsqlparser.statement.insert.*; import net.sf.jsqlparser.statement.execute.*; +import net.sf.jsqlparser.statement.piped.*; import net.sf.jsqlparser.statement.select.*; import net.sf.jsqlparser.statement.refresh.*; import net.sf.jsqlparser.statement.show.*; @@ -158,6 +159,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -1432,9 +1434,10 @@ ShowTablesStatement ShowTables(): { [ { modifiers.add(ShowTablesStatement.Modifiers.FULL); } ] [ - ( - {selectionMode = ShowTablesStatement.SelectionMode.FROM; } - | { selectionMode = ShowTablesStatement.SelectionMode.IN; } + LOOKAHEAD(2) ( + { selectionMode = ShowTablesStatement.SelectionMode.FROM; } + | + { selectionMode = ShowTablesStatement.SelectionMode.IN; } ) dbName = RelObjectNameExt() ] @@ -1528,7 +1531,7 @@ Update Update(): [ outputClause = OutputClause() {update.setOutputClause(outputClause); } ] - [ + [ LOOKAHEAD(2) fromItem=FromItem() [ LOOKAHEAD(2) joins=JoinsList() ] ] @@ -2084,7 +2087,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="ALGORITHM" | tk="ALTER" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOCK" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="COSTS" | tk="COUNT" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCRYPTION" | tk="END" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXCLUDE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXTENDED" | tk="EXTRACT" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GROUP_CONCAT" | tk="GUARD" | tk="HASH" | tk="HIGH" | tk="HIGH_PRIORITY" | tk="HISTORY" | tk="HOPPING" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="ISNULL" | tk="JSON" | tk="JSON_ARRAY" | tk="JSON_ARRAYAGG" | tk="JSON_OBJECT" | tk="JSON_OBJECTAGG" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="LAST" | tk="LEADING" | tk="LESS" | tk="LINK" | tk="LOCAL" | tk="LOCK" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW" | tk="LOW_PRIORITY" | tk="MATCH" | tk="MATCHED" | tk="MATCH_ALL" | tk="MATCH_ANY" | tk="MATCH_PHRASE" | tk="MATCH_PHRASE_PREFIX" | tk="MATCH_REGEXP" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEDIUMTEXT" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODIFY" | tk="MOVEMENT" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERWRITE" | tk="PARALLEL" | tk="PARENT" | tk="PARTITION" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PLUS" | tk="PRECEDING" | tk="PRIMARY" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGEXP_LIKE" | tk="REGISTER" | tk="REMOTE" | tk="RENAME" | tk="REPEATABLE" | tk="REPLACE" | tk="RESET" | tk="RESPECT" | tk="RESTART" | tk="RESTRICT" | tk="RESTRICTED" | tk="RESUMABLE" | tk="RESUME" | tk="RETURN" | tk="RLIKE" | tk="ROLLBACK" | tk="ROLLUP" | tk="ROOT" | tk="ROW" | tk="ROWS" | tk="RR" | tk="RS" | tk="SAFE_CAST" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SEED" | tk="SEPARATOR" | tk="SEQUENCE" | tk="SESSION" | tk="SETS" | tk="SHARE" | tk="SHOW" | tk="SHUTDOWN" | tk="SIBLINGS" | tk="SIGNED" | tk="SIMILAR" | tk="SIZE" | tk="SKIP" | tk="STORED" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYNONYM" | tk="SYSTEM" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="TEXT" | tk="THAN" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TINYTEXT" | tk="TO" | tk="TRIGGER" | tk="TRUNCATE" | tk="TRY_CAST" | tk="TUMBLING" | tk="TYPE" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VERBOSE" | tk="VIEW" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WITHOUT_ARRAY_WRAPPER" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALTER" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOCK" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="COSTS" | tk="COUNT" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCRYPTION" | tk="END" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXCLUDE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXTENDED" | tk="EXTRACT" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GROUP_CONCAT" | tk="GUARD" | tk="HASH" | tk="HIGH" | tk="HIGH_PRIORITY" | tk="HISTORY" | tk="HOPPING" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="ISNULL" | tk="JSON" | tk="JSON_ARRAY" | tk="JSON_ARRAYAGG" | tk="JSON_OBJECT" | tk="JSON_OBJECTAGG" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="LAST" | tk="LEADING" | tk="LESS" | tk="LINK" | tk="LOCAL" | tk="LOCK" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW" | tk="LOW_PRIORITY" | tk="MATCH" | tk="MATCHED" | tk="MATCH_ALL" | tk="MATCH_ANY" | tk="MATCH_PHRASE" | tk="MATCH_PHRASE_PREFIX" | tk="MATCH_REGEXP" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEDIUMTEXT" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODIFY" | tk="MOVEMENT" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERWRITE" | tk="PARALLEL" | tk="PARENT" | tk="PARTITION" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PLUS" | tk="PRECEDING" | tk="PRIMARY" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGEXP_LIKE" | tk="REGISTER" | tk="REMOTE" | tk="RENAME" | tk="REPEATABLE" | tk="REPLACE" | tk="RESET" | tk="RESPECT" | tk="RESTART" | tk="RESTRICT" | tk="RESTRICTED" | tk="RESUMABLE" | tk="RESUME" | tk="RETURN" | tk="RLIKE" | tk="ROLLBACK" | tk="ROLLUP" | tk="ROOT" | tk="ROW" | tk="ROWS" | tk="RR" | tk="RS" | tk="SAFE_CAST" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SEED" | tk="SEPARATOR" | tk="SEQUENCE" | tk="SESSION" | tk="SETS" | tk="SHARE" | tk="SHOW" | tk="SHUTDOWN" | tk="SIBLINGS" | tk="SIGNED" | tk="SIMILAR" | tk="SIZE" | tk="SKIP" | tk="STORED" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYNONYM" | tk="SYSTEM" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="TEXT" | tk="THAN" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TINYTEXT" | tk="TO" | tk="TRIGGER" | tk="TRUNCATE" | tk="TRY_CAST" | tk="TUMBLING" | tk="TYPE" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VERBOSE" | tk="VIEW" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WITHOUT_ARRAY_WRAPPER" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" ) { return tk.image; } } @@ -2279,6 +2282,8 @@ Select Select() #Select: ( LOOKAHEAD(3) select = PlainSelect() | + select = FromQuery() + | LOOKAHEAD(3) select = Values() | LOOKAHEAD(3) select = ParenthesedSelect() @@ -2298,6 +2303,130 @@ Select Select() #Select: } } +FromQuery FromQuery() #FromQuery: +{ + FromQuery fromQuery; + FromItem fromItem; + PipeOperator pipeOperator; +} +{ + fromItem = FromItem() { fromQuery = new FromQuery(fromItem); } + ( + LOOKAHEAD(2) "|>" pipeOperator = PipeOperator() { fromQuery.add(pipeOperator); } + )* + + { + return fromQuery; + } +} + +PipeOperator PipeOperator() #PipeOperator: +{ + PipeOperator operator; +} +{ + ( + operator = SelectPipeOperator() +// | +// operator = ExtendPipeOperator() +// | +// operator = SetPipeOperator() +// | +// operator = DropPipeOperator() +// | +// operator = RenamePipeOperator() +// | +// operator = AsPipeOprator() + | + operator = WherePipeOperator() +// | +// operator = LimitPipeOperator() + | + operator = AggregatePipeOperator() + | + operator = OrderByPipeOperator() +// | +// operator = UnionPipeOperator(); +// | +// operator = IntersectPipeOperator(); +// | +// operator = ExceptPipeOperator(); +// | +// operator = JoinPipeOperator() + ) + { + return operator; + } +} + +SelectPipeOperator SelectPipeOperator(): +{ + SelectPipeOperator selectPipeOperator; + SelectItem selectItem; +} +{ + + selectItem = SelectItem() { selectPipeOperator = new SelectPipeOperator(selectItem); } + ( LOOKAHEAD(2) "," selectItem = SelectItem() { selectPipeOperator.add(selectItem); } )* + + { + return selectPipeOperator; + } +} + +WherePipeOperator WherePipeOperator(): +{ + WherePipeOperator wherePipeOperator; + Expression expression; +} +{ + expression = Expression() + { + wherePipeOperator = new WherePipeOperator(expression); + return wherePipeOperator; + } +} + +AggregatePipeOperator AggregatePipeOperator(): +{ + AggregatePipeOperator aggregatePipeOperator; + SelectItem selectItem; +} +{ + + selectItem = SelectItem() { aggregatePipeOperator = new AggregatePipeOperator(selectItem); } + ( LOOKAHEAD(2) "," selectItem = SelectItem() { aggregatePipeOperator.add(selectItem); } )* + + [ + LOOKAHEAD(2) [ { aggregatePipeOperator.setShorthandOrdering(true); } ] + selectItem = SelectItem() + { aggregatePipeOperator.addGroupItem(selectItem); } + + ( + LOOKAHEAD(2) "," + selectItem = SelectItem() + { aggregatePipeOperator.addGroupItem(selectItem); } + )* + ] + + { + return aggregatePipeOperator; + } +} + +OrderByPipeOperator OrderByPipeOperator(): +{ + OrderByPipeOperator orderByPipeOperator; + List orderByElements; +} +{ + orderByElements = OrderByElements() + { + orderByPipeOperator = new OrderByPipeOperator(orderByElements); + return orderByPipeOperator; + } +} + TableStatement TableStatement(): { Table table = null; diff --git a/src/site/sphinx/keywords.rst b/src/site/sphinx/keywords.rst index d301f23e6..4ed5ce43b 100644 --- a/src/site/sphinx/keywords.rst +++ b/src/site/sphinx/keywords.rst @@ -77,7 +77,7 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | QUALIFY | Yes | | +----------------------+-------------+-----------+ -| HAVING | Yes | Yes | +| HAVING | Yes | Yes | +----------------------+-------------+-----------+ | IF | Yes | Yes | +----------------------+-------------+-----------+ @@ -97,7 +97,7 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | INTERVAL | Yes | Yes | +----------------------+-------------+-----------+ -| INTO | Yes | Yes | +| INTO | Yes | Yes | +----------------------+-------------+-----------+ | IS | Yes | Yes | +----------------------+-------------+-----------+ @@ -109,7 +109,7 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | LIKE | Yes | Yes | +----------------------+-------------+-----------+ -| LIMIT | Yes | Yes | +| LIMIT | Yes | Yes | +----------------------+-------------+-----------+ | MINUS | Yes | Yes | +----------------------+-------------+-----------+ @@ -139,7 +139,9 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | OPTIMIZE | Yes | Yes | +----------------------+-------------+-----------+ -| PIVOT | Yes | Yes | +| OVERWRITE | Yes | Yes | ++----------------------+-------------+-----------+ +| PIVOT | Yes | Yes | +----------------------+-------------+-----------+ | PREFERRING | Yes | Yes | +----------------------+-------------+-----------+ diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/FromQueryTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/FromQueryTest.java new file mode 100644 index 000000000..168d1101b --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/FromQueryTest.java @@ -0,0 +1,24 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +public class FromQueryTest { + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "FROM Produce\n" + + "|> WHERE\n" + + " item != 'bananas'\n" + + " AND category IN ('fruit', 'nut')\n" + + "|> AGGREGATE COUNT(*) AS num_items, SUM(sales) AS total_sales\n" + + " GROUP BY item\n" + + "|> ORDER BY item DESC;"; + FromQuery fromQuery = (FromQuery) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + + Assertions.assertInstanceOf(WherePipeOperator.class, fromQuery.get(0)); + Assertions.assertInstanceOf(AggregatePipeOperator.class, fromQuery.get(1)); + Assertions.assertInstanceOf(OrderByPipeOperator.class, fromQuery.get(2)); + } +} diff --git a/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java b/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java index e2c488b40..07fdb858b 100644 --- a/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java +++ b/src/test/java/net/sf/jsqlparser/test/AssortedFeatureTests.java @@ -25,13 +25,13 @@ static class ReplaceColumnAndLongValues extends ExpressionDeParser { @Override public StringBuilder visit(StringValue stringValue, K parameters) { - this.getBuffer().append("?"); + this.getBuilder().append("?"); return null; } @Override public StringBuilder visit(LongValue longValue, K parameters) { - this.getBuffer().append("?"); + this.getBuilder().append("?"); return null; } } @@ -42,14 +42,14 @@ public static String cleanStatement(String sql) throws JSQLParserException { SelectDeParser selectDeparser = new SelectDeParser(expr, buffer); expr.setSelectVisitor(selectDeparser); - expr.setBuffer(buffer); + expr.setBuilder(buffer); StatementDeParser stmtDeparser = new StatementDeParser(expr, selectDeparser, buffer); Statement stmt = CCJSqlParserUtil.parse(sql); stmt.accept(stmtDeparser); - return stmtDeparser.getBuffer().toString(); + return stmtDeparser.getBuilder().toString(); } @Test diff --git a/src/test/java/net/sf/jsqlparser/test/TestUtils.java b/src/test/java/net/sf/jsqlparser/test/TestUtils.java index 60629087e..b41497ed0 100644 --- a/src/test/java/net/sf/jsqlparser/test/TestUtils.java +++ b/src/test/java/net/sf/jsqlparser/test/TestUtils.java @@ -312,7 +312,7 @@ public static void assertDeparse(Statement stmt, String statement, boolean laxDe StatementDeParser deParser = new StatementDeParser(new StringBuilder()); stmt.accept(deParser); assertEquals(buildSqlString(statement, laxDeparsingCheck), - buildSqlString(deParser.getBuffer().toString(), laxDeparsingCheck)); + buildSqlString(deParser.getBuilder().toString(), laxDeparsingCheck)); } public static String buildSqlString(final String originalSql, boolean laxDeparsingCheck) { @@ -359,7 +359,7 @@ public void testBuildSqlString() { public static void assertExpressionCanBeDeparsedAs(final Expression parsed, String expression) { ExpressionDeParser expressionDeParser = new ExpressionDeParser(); StringBuilder stringBuilder = new StringBuilder(); - expressionDeParser.setBuffer(stringBuilder); + expressionDeParser.setBuilder(stringBuilder); SelectDeParser selectDeParser = new SelectDeParser(expressionDeParser, stringBuilder); expressionDeParser.setSelectVisitor(selectDeParser); parsed.accept(expressionDeParser, null); diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java index 6149ef32b..1a8f75d81 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/CreateViewDeParserTest.java @@ -33,7 +33,7 @@ public class CreateViewDeParserTest { public void testUseExtrnalExpressionDeparser() throws JSQLParserException { StringBuilder b = new StringBuilder(); SelectDeParser selectDeParser = new SelectDeParser(); - selectDeParser.setBuffer(b); + selectDeParser.setBuilder(b); ExpressionDeParser expressionDeParser = new ExpressionDeParser(selectDeParser, b) { @Override @@ -48,11 +48,11 @@ public StringBuilder visit(Column tableColumn, K parameters) { } } if (tableName != null && !tableName.isEmpty()) { - getBuffer().append("\"").append(tableName).append("\"").append("."); + getBuilder().append("\"").append(tableName).append("\"").append("."); } - getBuffer().append("\"").append(tableColumn.getColumnName()).append("\""); - return buffer; + getBuilder().append("\"").append(tableColumn.getColumnName()).append("\""); + return builder; } }; @@ -65,7 +65,7 @@ public StringBuilder visit(Column tableColumn, K parameters) { assertEquals("CREATE VIEW test AS SELECT a, b FROM mytable", vc.toString()); assertEquals("CREATE VIEW test AS SELECT \"a\", \"b\" FROM mytable", - instance.getBuffer().toString()); + instance.getBuilder().toString()); } @Test diff --git a/src/test/java/net/sf/jsqlparser/util/deparser/ExecuteDeParserTest.java b/src/test/java/net/sf/jsqlparser/util/deparser/ExecuteDeParserTest.java index ce3b90aa6..90727d19c 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/ExecuteDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/ExecuteDeParserTest.java @@ -36,7 +36,7 @@ public class ExecuteDeParserTest { public void setUp() { buffer = new StringBuilder(); expressionVisitor = new ExpressionDeParser(); - expressionVisitor.setBuffer(buffer); + expressionVisitor.setBuilder(buffer); executeDeParser = new ExecuteDeParser(expressionVisitor, buffer); } 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 ce2733ff1..8be6d1078 100644 --- a/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java +++ b/src/test/java/net/sf/jsqlparser/util/deparser/StatementDeParserTest.java @@ -355,20 +355,20 @@ public void testIssue1608DeparseValueList() throws JSQLParserException { ExpressionDeParser expressionDeParser = new ExpressionDeParser() { @Override public StringBuilder visit(StringValue stringValue, K parameters) { - buffer.append("?"); + builder.append("?"); return null; } @Override public StringBuilder visit(LongValue longValue, K parameters) { - buffer.append("?"); + builder.append("?"); return null; } }; SelectDeParser selectDeParser = new SelectDeParser(expressionDeParser, builder); expressionDeParser.setSelectVisitor(selectDeParser); - expressionDeParser.setBuffer(builder); + expressionDeParser.setBuilder(builder); StatementDeParser statementDeParser = new StatementDeParser(expressionDeParser, selectDeParser, builder); From abf137e04ca765d8ecf5a01d65ff41da44368ca8 Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Sun, 12 Jan 2025 16:59:48 +0700 Subject: [PATCH 2/5] feat: Piped SQL and FROM queries (WIP) - `FROM Query` without `FROM` keyword - `As` operator - `Select` operator - `Extend` operator - `Window` operator - `Join` operator - proper De-Parser Signed-off-by: Andreas Reichel Signed-off-by: manticore-projects --- README.md | 2 +- .../parser/ParserKeywordsUtils.java | 1 + .../statement/piped/AsPipeOperator.java | 23 ++++ .../statement/piped/ExtendPipeOperator.java | 9 +- .../jsqlparser/statement/piped/FromQuery.java | 32 +++-- .../statement/piped/JoinPipeOperator.java | 26 +++++ .../statement/piped/SelectPipeOperator.java | 19 ++- .../statement/piped/WindowPipeOperator.java | 9 +- .../sf/jsqlparser/statement/select/Join.java | 2 +- .../util/deparser/SelectDeParser.java | 19 ++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 109 ++++++++++++++---- src/site/sphinx/keywords.rst | 2 + .../expression/ExpressionPrecedenceTest.java | 9 +- .../piped/ExtendPipeOperatorTest.java | 31 +++++ .../statement/piped/JoinPipeOperatorTest.java | 29 +++++ .../select/oracle-tests/query_factoring07.sql | 3 +- 16 files changed, 274 insertions(+), 51 deletions(-) create mode 100644 src/test/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperatorTest.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/piped/JoinPipeOperatorTest.java diff --git a/README.md b/README.md index fd312baa3..a64404aa0 100644 --- a/README.md +++ b/README.md @@ -88,7 +88,7 @@ If you like JSqlParser then please check out its related projects: ## Alternatives to JSqlParser? [**General SQL Parser**](http://www.sqlparser.com/features/introduce.php?utm_source=github-jsqlparser&utm_medium=text-general) looks pretty good, with extended SQL syntax (like PL/SQL and T-SQL) and java + .NET APIs. The tool is commercial (license available online), with a free download option. -Alternatively the dual-licensed [JOOQ](https://www.jooq.org/doc/latest/manual/sql-building/sql-parser/) provides a hand-written Parser supporting a lot of RDBMS, translation between dialects, SQL transformation, can be used as a JDBC proxy for translation and transformation purposes. +Alternatively the dual-licensed [JOOQ](https://www.jooq.org/doc/latest/manual/sql-building/sql-parser/) provides a handwritten Parser supporting a lot of RDBMS, translation between dialects, SQL transformation, can be used as a JDBC proxy for translation and transformation purposes. ## [Documentation](https://jsqlparser.github.io/JSqlParser) 1. [Samples](https://jsqlparser.github.io/JSqlParser/usage.html#parse-a-sql-statements) diff --git a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java index 9c6dc52d9..e8e3c39b7 100644 --- a/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java +++ b/src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java @@ -68,6 +68,7 @@ public class ParserKeywordsUtils { {"EXCEPT", RESTRICTED_SQL2016}, {"EXCLUDES", RESTRICTED_JSQLPARSER}, {"EXISTS", RESTRICTED_SQL2016}, + {"EXTEND", RESTRICTED_JSQLPARSER}, {"FALSE", RESTRICTED_SQL2016}, {"FETCH", RESTRICTED_SQL2016}, {"FINAL", RESTRICTED_JSQLPARSER}, diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java index aea619b44..c0fb258c7 100644 --- a/src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java +++ b/src/main/java/net/sf/jsqlparser/statement/piped/AsPipeOperator.java @@ -1,9 +1,32 @@ package net.sf.jsqlparser.statement.piped; +import net.sf.jsqlparser.expression.Alias; + public class AsPipeOperator extends PipeOperator { + private Alias alias; + + public AsPipeOperator(Alias alias) { + this.alias = alias; + } + + public Alias getAlias() { + return alias; + } + + public AsPipeOperator setAlias(Alias alias) { + this.alias = alias; + return this; + } @Override public T accept(PipeOperatorVisitor visitor, S context) { return visitor.visit(this, context); } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append(alias); + builder.append("\n"); + return builder; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java index 57e86b202..e8d6f7291 100644 --- a/src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java +++ b/src/main/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperator.java @@ -1,8 +1,9 @@ package net.sf.jsqlparser.statement.piped; -public class ExtendPipeOperator extends PipeOperator { - @Override - public T accept(PipeOperatorVisitor visitor, S context) { - return visitor.visit(this, context); +import net.sf.jsqlparser.statement.select.SelectItem; + +public class ExtendPipeOperator extends SelectPipeOperator { + public ExtendPipeOperator(SelectItem selectItem) { + super("EXTEND", selectItem); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java b/src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java index 874a82884..ee80b1a34 100644 --- a/src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java +++ b/src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java @@ -2,7 +2,6 @@ import net.sf.jsqlparser.expression.Alias; import net.sf.jsqlparser.expression.ExpressionVisitor; -import net.sf.jsqlparser.statement.StatementVisitor; import net.sf.jsqlparser.statement.select.FromItem; import net.sf.jsqlparser.statement.select.FromItemVisitor; import net.sf.jsqlparser.statement.select.Pivot; @@ -19,6 +18,7 @@ import java.util.function.UnaryOperator; public class FromQuery extends Select { + private boolean usingFromKeyword = true; private FromItem fromItem; private final ArrayList pipeOperators = new ArrayList<>(); @@ -26,6 +26,11 @@ public FromQuery(FromItem fromItem) { this.fromItem = fromItem; } + public FromQuery(FromItem fromItem, boolean usingFromKeyword) { + this.fromItem = fromItem; + this.usingFromKeyword = usingFromKeyword; + } + public FromItem getFromItem() { return fromItem; } @@ -36,7 +41,20 @@ public FromQuery setFromItem(FromItem fromItem) { } public FromQuery with(FromItem fromItem) { - return setFromItem(fromItem); + return this.setFromItem(fromItem); + } + + public boolean isUsingFromKeyword() { + return usingFromKeyword; + } + + public FromQuery setUsingFromKeyword(boolean usingFromKeyword) { + this.usingFromKeyword = usingFromKeyword; + return this; + } + + public FromQuery with(boolean usingFromKeyword) { + return this.setUsingFromKeyword(usingFromKeyword); } public ArrayList getPipeOperators() { @@ -175,11 +193,6 @@ public T accept(ExpressionVisitor expressionVisitor, S context) { return expressionVisitor.visit(this, context); } - @Override - public T accept(StatementVisitor statementVisitor, S context) { - return statementVisitor.visit(this, context); - } - @Override public T accept(FromItemVisitor fromItemVisitor, S context) { return fromItemVisitor.visit(this, context); @@ -194,7 +207,10 @@ public T accept(SelectVisitor selectVisitor, S context) { @Override public StringBuilder appendTo(StringBuilder builder) { - builder.append("FROM ").append(fromItem).append("\n"); + if (usingFromKeyword) { + builder.append("FROM "); + } + builder.append(fromItem).append("\n"); for (PipeOperator operator : pipeOperators) { operator.appendTo(builder); } diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java index 8b86f0693..67e63a856 100644 --- a/src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java +++ b/src/main/java/net/sf/jsqlparser/statement/piped/JoinPipeOperator.java @@ -1,8 +1,34 @@ package net.sf.jsqlparser.statement.piped; +import net.sf.jsqlparser.statement.select.Join; + public class JoinPipeOperator extends PipeOperator { + private Join join; + + public JoinPipeOperator(Join join) { + this.join = join; + } + + public Join getJoin() { + return join; + } + + public JoinPipeOperator setJoin(Join join) { + this.join = join; + return this; + } + @Override public T accept(PipeOperatorVisitor visitor, S context) { return visitor.visit(this, context); } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append(join); + builder.append("\n"); + return builder; + } + + } diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java index 222a52c6e..9bb669e4f 100644 --- a/src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java +++ b/src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java @@ -5,12 +5,27 @@ import java.util.ArrayList; public class SelectPipeOperator extends PipeOperator { + private final String operatorName; + private final ArrayList> selectItems = new ArrayList<>(); - public SelectPipeOperator(SelectItem selectItem) { + public SelectPipeOperator(String operatorName, SelectItem selectItem) { + this.operatorName = operatorName; selectItems.add(selectItem); } + public SelectPipeOperator(SelectItem selectItem) { + this("SELECT", selectItem); + } + + public String getOperatorName() { + return operatorName; + } + + public ArrayList> getSelectItems() { + return selectItems; + } + public SelectPipeOperator add(SelectItem selectItem) { selectItems.add(selectItem); return this; @@ -27,7 +42,7 @@ public T accept(PipeOperatorVisitor visitor, S context) { @Override public StringBuilder appendTo(StringBuilder builder) { - builder.append("|> ").append("SELECT"); + builder.append("|> ").append(operatorName); int i = 0; for (SelectItem selectItem : selectItems) { builder.append(i++ > 0 ? ", " : " ").append(selectItem); diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java index 639bdca6b..a349e6007 100644 --- a/src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java +++ b/src/main/java/net/sf/jsqlparser/statement/piped/WindowPipeOperator.java @@ -1,8 +1,9 @@ package net.sf.jsqlparser.statement.piped; -public class WindowPipeOperator extends PipeOperator { - @Override - public T accept(PipeOperatorVisitor visitor, S context) { - return visitor.visit(this, context); +import net.sf.jsqlparser.statement.select.SelectItem; + +public class WindowPipeOperator extends SelectPipeOperator { + public WindowPipeOperator(SelectItem selectItem) { + super("WINDOW", selectItem); } } diff --git a/src/main/java/net/sf/jsqlparser/statement/select/Join.java b/src/main/java/net/sf/jsqlparser/statement/select/Join.java index bbd32df01..898804de0 100644 --- a/src/main/java/net/sf/jsqlparser/statement/select/Join.java +++ b/src/main/java/net/sf/jsqlparser/statement/select/Join.java @@ -435,7 +435,7 @@ public String toString() { for (Expression onExpression : onExpressions) { builder.append(" ON ").append(onExpression); } - if (usingColumns.size() > 0) { + if (!usingColumns.isEmpty()) { builder.append(PlainSelect.getFormattedList(usingColumns, "USING", true, true)); } 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 dc5a36dd2..260f8f65c 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -829,7 +829,9 @@ public void visit(TableStatement tableStatement) { @Override public StringBuilder visit(FromQuery fromQuery, S context) { - builder.append("FROM "); + if (fromQuery.isUsingFromKeyword()) { + builder.append("FROM "); + } fromQuery.getFromItem().accept(this, context); builder.append("\n"); for (PipeOperator operator : fromQuery.getPipeOperators()) { @@ -887,6 +889,8 @@ public StringBuilder visit(AggregatePipeOperator aggregate, S context) { @Override public StringBuilder visit(AsPipeOperator as, S context) { + builder.append("|> ").append(as.getAlias()); + builder.append("\n"); return builder; } @@ -907,7 +911,7 @@ public StringBuilder visit(ExceptPipeOperator except, S context) { @Override public StringBuilder visit(ExtendPipeOperator extend, S context) { - return builder; + return visit((SelectPipeOperator) extend, context); } @Override @@ -917,6 +921,9 @@ public StringBuilder visit(IntersectPipeOperator intersect, S context) { @Override public StringBuilder visit(JoinPipeOperator join, S context) { + builder.append("|> "); + deparseJoin(join.getJoin()); + builder.append("\n"); return builder; } @@ -945,6 +952,12 @@ public StringBuilder visit(RenamePipeOperator rename, S context) { @Override public StringBuilder visit(SelectPipeOperator select, S context) { + builder.append("|> ").append(select.getOperatorName()); + int i = 0; + for (SelectItem selectItem : select.getSelectItems()) { + builder.append(i++ > 0 ? ", " : " ").append(selectItem); + } + builder.append("\n"); return builder; } @@ -979,6 +992,6 @@ public StringBuilder visit(WherePipeOperator where, S context) { @Override public StringBuilder visit(WindowPipeOperator window, S context) { - return null; + return visit((SelectPipeOperator) window, context); } } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index 6eb817dd5..d010d1cce 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -260,6 +260,7 @@ TOKEN: /* SQL Keywords. prefixed with K_ to avoid name clashes */ | | | +| | | | @@ -2278,25 +2279,29 @@ Select Select() #Select: WithIsolation withIsolation = null; } { - [ with=WithList() ] ( - LOOKAHEAD(3) select = PlainSelect() + ( + [ with=WithList() ] + ( + LOOKAHEAD(3) select = PlainSelect() + | + LOOKAHEAD(3) select = Values() + | + LOOKAHEAD(3) select = ParenthesedSelect() + ) + [ LOOKAHEAD(2) select = FromQueryFromSelect(select) ] + [ LOOKAHEAD(2) select = SetOperationList(select) ] + + [ LOOKAHEAD( ) orderByElements = OrderByElements() { select.setOrderByElements(orderByElements); } ] + + [ LOOKAHEAD() limit=LimitWithOffset() {select.setLimit(limit);} ] + [ LOOKAHEAD() offset = Offset() { select.setOffset(offset);} ] + [ LOOKAHEAD() fetch = Fetch() { select.setFetch(fetch);} ] + [ LOOKAHEAD( ) withIsolation = WithIsolation() { select.setIsolation(withIsolation);} ] + ) | select = FromQuery() - | - LOOKAHEAD(3) select = Values() - | - LOOKAHEAD(3) select = ParenthesedSelect() ) - [ LOOKAHEAD(2) select = SetOperationList(select) ] - - [ LOOKAHEAD( ) orderByElements = OrderByElements() { select.setOrderByElements(orderByElements); } ] - - [ LOOKAHEAD() limit=LimitWithOffset() {select.setLimit(limit);} ] - [ LOOKAHEAD() offset = Offset() { select.setOffset(offset);} ] - [ LOOKAHEAD() fetch = Fetch() { select.setFetch(fetch);} ] - [ LOOKAHEAD( ) withIsolation = WithIsolation() { select.setIsolation(withIsolation);} ] - { linkAST(select, jjtThis); return select.withWithItemsList(with); @@ -2310,7 +2315,7 @@ FromQuery FromQuery() #FromQuery: PipeOperator pipeOperator; } { - fromItem = FromItem() { fromQuery = new FromQuery(fromItem); } + fromItem = FromItem() { fromQuery = new FromQuery(fromItem); } ( LOOKAHEAD(2) "|>" pipeOperator = PipeOperator() { fromQuery.add(pipeOperator); } )* @@ -2320,6 +2325,28 @@ FromQuery FromQuery() #FromQuery: } } +FromQuery FromQueryFromSelect(Select select): +{ + FromQuery fromQuery; + FromItem fromItem; + PipeOperator pipeOperator; +} +{ + "|>" pipeOperator = PipeOperator() + { + fromQuery = new FromQuery(select, false); + fromQuery.add(pipeOperator); + } + ( + LOOKAHEAD(2) "|>" pipeOperator = PipeOperator() + { fromQuery.add(pipeOperator); } + )* + + { + return fromQuery; + } +} + PipeOperator PipeOperator() #PipeOperator: { PipeOperator operator; @@ -2335,14 +2362,14 @@ PipeOperator PipeOperator() #PipeOperator: // operator = DropPipeOperator() // | // operator = RenamePipeOperator() -// | -// operator = AsPipeOprator() + | + LOOKAHEAD(2) operator = AsPipeOperator() | operator = WherePipeOperator() // | // operator = LimitPipeOperator() | - operator = AggregatePipeOperator() + LOOKAHEAD(2) operator = AggregatePipeOperator() | operator = OrderByPipeOperator() // | @@ -2351,8 +2378,8 @@ PipeOperator PipeOperator() #PipeOperator: // operator = IntersectPipeOperator(); // | // operator = ExceptPipeOperator(); -// | -// operator = JoinPipeOperator() + | + operator = JoinPipeOperator() ) { return operator; @@ -2361,12 +2388,21 @@ PipeOperator PipeOperator() #PipeOperator: SelectPipeOperator SelectPipeOperator(): { + Token operatorKeyToken; SelectPipeOperator selectPipeOperator; SelectItem selectItem; } { - - selectItem = SelectItem() { selectPipeOperator = new SelectPipeOperator(selectItem); } + ( + operatorKeyToken = + | + operatorKeyToken = + | + operatorKeyToken = + ) + selectItem = SelectItem() + { selectPipeOperator = new SelectPipeOperator(operatorKeyToken.image, selectItem); } + ( LOOKAHEAD(2) "," selectItem = SelectItem() { selectPipeOperator.add(selectItem); } )* { @@ -2427,6 +2463,33 @@ OrderByPipeOperator OrderByPipeOperator(): } } +AsPipeOperator AsPipeOperator(): +{ + AsPipeOperator asPipeOperator; + Alias alias; +} +{ + alias = Alias() + { + asPipeOperator = new AsPipeOperator( alias.withUseAs(true) ); + return asPipeOperator; + } +} + +JoinPipeOperator JoinPipeOperator(): +{ + JoinPipeOperator joinPipeOperator; + Join join; +} +{ + join = JoinerExpression() + { + joinPipeOperator = new JoinPipeOperator(join); + return joinPipeOperator; + } +} + + TableStatement TableStatement(): { Table table = null; diff --git a/src/site/sphinx/keywords.rst b/src/site/sphinx/keywords.rst index 4ed5ce43b..616fe3148 100644 --- a/src/site/sphinx/keywords.rst +++ b/src/site/sphinx/keywords.rst @@ -53,6 +53,8 @@ The following Keywords are **restricted** in JSQLParser-|JSQLPARSER_VERSION| and +----------------------+-------------+-----------+ | EXISTS | Yes | Yes | +----------------------+-------------+-----------+ +| EXTEND | Yes | Yes | ++----------------------+-------------+-----------+ | FALSE | Yes | Yes | +----------------------+-------------+-----------+ | FETCH | Yes | Yes | diff --git a/src/test/java/net/sf/jsqlparser/expression/ExpressionPrecedenceTest.java b/src/test/java/net/sf/jsqlparser/expression/ExpressionPrecedenceTest.java index cbe161c43..a601f6e0a 100644 --- a/src/test/java/net/sf/jsqlparser/expression/ExpressionPrecedenceTest.java +++ b/src/test/java/net/sf/jsqlparser/expression/ExpressionPrecedenceTest.java @@ -13,7 +13,8 @@ import net.sf.jsqlparser.expression.operators.arithmetic.BitwiseAnd; import net.sf.jsqlparser.expression.operators.arithmetic.Concat; import net.sf.jsqlparser.parser.CCJSqlParserUtil; -import static org.junit.jupiter.api.Assertions.assertTrue; + +import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; /** @@ -25,8 +26,8 @@ public class ExpressionPrecedenceTest { @Test public void testGetSign() throws JSQLParserException { Expression expr = CCJSqlParserUtil.parseExpression("1&2||3"); - assertTrue(expr instanceof Concat); - assertTrue(((Concat) expr).getLeftExpression() instanceof BitwiseAnd); - assertTrue(((Concat) expr).getRightExpression() instanceof LongValue); + Assertions.assertInstanceOf(Concat.class, expr); + Assertions.assertInstanceOf(BitwiseAnd.class, ((Concat) expr).getLeftExpression()); + Assertions.assertInstanceOf(LongValue.class, ((Concat) expr).getRightExpression()); } } diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperatorTest.java new file mode 100644 index 000000000..aa0c2dda0 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/ExtendPipeOperatorTest.java @@ -0,0 +1,31 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class ExtendPipeOperatorTest { + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "FROM (\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> EXTEND item IN ('carrots', 'oranges') AS is_orange;"; + FromQuery fromQuery = (FromQuery) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + // Assertions.assertInstanceOf(ExtendPipeOperator.class, fromQuery.get(0)); + } + + @Test + void testParseAndDeparseWithoutFromKeyword() throws JSQLParserException { + String sqlStr = "(\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> EXTEND item IN ('carrots', 'oranges') AS is_orange;"; + FromQuery fromQuery = (FromQuery) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + // Assertions.assertInstanceOf(ExtendPipeOperator.class, fromQuery.get(0)); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/JoinPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/JoinPipeOperatorTest.java new file mode 100644 index 000000000..6600449cb --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/JoinPipeOperatorTest.java @@ -0,0 +1,29 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; + +class JoinPipeOperatorTest { + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "FROM (\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'bananas' AS item, 5 AS sales\n" + + ")\n" + + "|> AS produce_sales\n" + + "|> LEFT JOIN\n" + + " (\n" + + " SELECT \"apples\" AS item, 123 AS id\n" + + " ) AS produce_data\n" + + " ON produce_sales.item = produce_data.item\n" + + "|> SELECT produce_sales.item, sales, id;"; + FromQuery fromQuery = (FromQuery) TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + Assertions.assertInstanceOf(AsPipeOperator.class, fromQuery.get(0)); + Assertions.assertInstanceOf(JoinPipeOperator.class, fromQuery.get(1)); + Assertions.assertInstanceOf(SelectPipeOperator.class, fromQuery.get(2)); + } + +} diff --git a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring07.sql b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring07.sql index bd3934e5a..5a6f632f9 100644 --- a/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring07.sql +++ b/src/test/resources/net/sf/jsqlparser/statement/select/oracle-tests/query_factoring07.sql @@ -87,4 +87,5 @@ select ) --@FAILURE: Encountered unexpected token: "by" "BY" recorded first on Aug 3, 2021, 7:20:08 AM ---@SUCCESSFULLY_PARSED_AND_DEPARSED first on Nov 14, 2022, 11:44:23 AM \ No newline at end of file +--@SUCCESSFULLY_PARSED_AND_DEPARSED first on Nov 14, 2022, 11:44:23 AM +--@FAILURE: (select bsln_statistics_t(bsln_guid,metric_id,:b11,:b10,timegroup,sample_count,average,minimum,maximum,sdev,pctile_25,pctile_50,pctile_75,pctile_90,pctile_95,pctile_99,est_sample_count,est_slope,est_intercept,case when est_slope=0 then 0 else greatest(0,nvl(100-(25*power((1-est_mu1/est_slope),2)*(est_sample_count-1)),0))end,ln(1000)*est_slope+est_intercept,ln(10000)*est_slope+est_intercept)from(select metric_id,bsln_guid,timegroup,est_mu as est_slope,est_mu*ln(alpha)+x_m as est_intercept,to_number(null)as est_fit_quality,case when count_below_x_j>0 then(sum_below_x_j+(n-m+1)*(x_j-x_m))/count_below_x_j-x_j else to_number(null)end as est_mu1,est_sample_count,n as sample_count,average,minimum,maximum,sdev,pctile_25,pctile_50,pctile_75,pctile_90,pctile_95,pctile_99 from(select metric_id,bsln_guid,timegroup,max(n)as n,count(rrank)as est_sample_count,case when count(rrank)>3 then(sum(obs_value)+(max(n)-max(rrank))*max(obs_value)-(max(n)-min(rrank)+1)*min(obs_value))/(count(rrank)-1)else to_number(null)end as est_mu,(max(n)-min(rrank)+1)/(max(n)+1)as alpha,min(obs_value)as x_m,max(obs_value)as x_l,max(rrank)as l,min(rrank)as m,max(mid_tail_value)as x_j,sum(case when obs_value=:b9 and x.cume_dist<=:b8 group by metric_id,bsln_guid,timegroup))) recorded first on 12 Jan 2025, 15:47:43 \ No newline at end of file From 01dc5f3472ce5ec4b2b991569d9aa79229a4826e Mon Sep 17 00:00:00 2001 From: manticore-projects Date: Mon, 13 Jan 2025 00:19:26 +0700 Subject: [PATCH 3/5] feat: Piped SQL and FROM queries (WIP) - `Drop` operator - `Limit` operator - `Set` operator Signed-off-by: Andreas Reichel Signed-off-by: manticore-projects --- .../statement/piped/DropPipeOperator.java | 198 ++++++++++++++++++ .../statement/piped/LimitPipeOperator.java | 41 ++++ .../statement/piped/SetPipeOperator.java | 164 +++++++++++++++ .../statement/update/UpdateSet.java | 4 + .../util/deparser/SelectDeParser.java | 14 ++ .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 53 ++++- .../statement/piped/DropPipeOperatorTest.java | 25 +++ .../piped/LimitPipeOperatorTest.java | 38 ++++ .../piped/SelectPipeOperatorTest.java | 17 ++ .../statement/piped/SetPipeOperatorTest.java | 19 ++ 10 files changed, 567 insertions(+), 6 deletions(-) create mode 100644 src/test/java/net/sf/jsqlparser/statement/piped/DropPipeOperatorTest.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/piped/LimitPipeOperatorTest.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/piped/SelectPipeOperatorTest.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/piped/SetPipeOperatorTest.java diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java index 95ec84630..a4378c660 100644 --- a/src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java +++ b/src/main/java/net/sf/jsqlparser/statement/piped/DropPipeOperator.java @@ -1,8 +1,206 @@ package net.sf.jsqlparser.statement.piped; +import net.sf.jsqlparser.expression.ExpressionVisitor; +import net.sf.jsqlparser.expression.operators.relational.ExpressionList; +import net.sf.jsqlparser.schema.Column; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.IntFunction; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + public class DropPipeOperator extends PipeOperator { + private ExpressionList columns; + + public DropPipeOperator(ExpressionList columns) { + this.columns = columns; + } + + public ExpressionList getColumns() { + return columns; + } + + public DropPipeOperator setColumns(ExpressionList columns) { + this.columns = columns; + return this; + } + + public boolean containsAll(Collection c) { + return columns.containsAll(c); + } + + public Column get(int index) { + return columns.get(index); + } + + public ExpressionList addExpression(Column expression) { + return columns.addExpression(expression); + } + + public ExpressionList addExpressions(Column... expressions) { + return columns.addExpressions(expressions); + } + + public ExpressionList addExpressions(Collection expressions) { + return columns.addExpressions(expressions); + } + + public ExpressionList withExpressions(Column... expressions) { + return columns.withExpressions(expressions); + } + + public ExpressionList withExpressions(Collection expressions) { + return columns.withExpressions(expressions); + } + + public K accept(ExpressionVisitor expressionVisitor, S context) { + return columns.accept(expressionVisitor, context); + } + + public void trimToSize() { + columns.trimToSize(); + } + + public boolean addAll(int index, Collection c) { + return columns.addAll(index, c); + } + + public boolean retainAll(Collection c) { + return columns.retainAll(c); + } + + public Stream parallelStream() { + return columns.parallelStream(); + } + + public boolean addAll(Collection c) { + return columns.addAll(c); + } + + public int indexOf(Column o) { + return columns.indexOf(o); + } + + public void accept(ExpressionVisitor expressionVisitor) { + columns.accept(expressionVisitor); + } + + public void forEach(Consumer action) { + columns.forEach(action); + } + + public int lastIndexOf(Column o) { + return columns.lastIndexOf(o); + } + + public Stream stream() { + return columns.stream(); + } + + public Spliterator spliterator() { + return columns.spliterator(); + } + + public Column set(int index, Column element) { + return columns.set(index, element); + } + + public void sort(Comparator c) { + columns.sort(c); + } + + public void ensureCapacity(int minCapacity) { + columns.ensureCapacity(minCapacity); + } + + public boolean remove(Column o) { + return columns.remove(o); + } + + public Object[] toArray() { + return columns.toArray(); + } + + public Iterator iterator() { + return columns.iterator(); + } + + public T[] toArray(IntFunction generator) { + return columns.toArray(generator); + } + + public boolean add(Column column) { + return columns.add(column); + } + + public ListIterator listIterator(int index) { + return columns.listIterator(index); + } + + public void replaceAll(UnaryOperator operator) { + columns.replaceAll(operator); + } + + public List subList(int fromIndex, int toIndex) { + return columns.subList(fromIndex, toIndex); + } + + public boolean removeAll(Collection c) { + return columns.removeAll(c); + } + + public boolean isEmpty() { + return columns.isEmpty(); + } + + public void clear() { + columns.clear(); + } + + public boolean contains(Column o) { + return columns.contains(o); + } + + public Column remove(int index) { + return columns.remove(index); + } + + public boolean removeIf(Predicate filter) { + return columns.removeIf(filter); + } + + public T[] toArray(T[] a) { + return columns.toArray(a); + } + + public void add(int index, Column element) { + columns.add(index, element); + } + + public int size() { + return columns.size(); + } + + public ListIterator listIterator() { + return columns.listIterator(); + } + @Override public T accept(PipeOperatorVisitor visitor, S context) { return visitor.visit(this, context); } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append("DROP "); + columns.appendTo(builder).append("\n"); + return builder; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java index 97f8f9b81..ab0a7cc6a 100644 --- a/src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java +++ b/src/main/java/net/sf/jsqlparser/statement/piped/LimitPipeOperator.java @@ -1,8 +1,49 @@ package net.sf.jsqlparser.statement.piped; +import net.sf.jsqlparser.expression.Expression; + public class LimitPipeOperator extends PipeOperator { + private Expression limitExpression; + private Expression offsetExpression; + + public LimitPipeOperator(Expression limitExpression, Expression offsetExpression) { + this.limitExpression = limitExpression; + this.offsetExpression = offsetExpression; + } + + public LimitPipeOperator(Expression limitExpression) { + this(limitExpression, null); + } + + public Expression getLimitExpression() { + return limitExpression; + } + + public LimitPipeOperator setLimitExpression(Expression limitExpression) { + this.limitExpression = limitExpression; + return this; + } + + public Expression getOffsetExpression() { + return offsetExpression; + } + + public LimitPipeOperator setOffsetExpression(Expression offsetExpression) { + this.offsetExpression = offsetExpression; + return this; + } + @Override public T accept(PipeOperatorVisitor visitor, S context) { return visitor.visit(this, context); } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append("LIMIT ").append(limitExpression); + if (offsetExpression != null) { + builder.append(" OFFSET ").append(offsetExpression); + } + return builder; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java index 0c88444a3..f36221826 100644 --- a/src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java +++ b/src/main/java/net/sf/jsqlparser/statement/piped/SetPipeOperator.java @@ -1,8 +1,172 @@ package net.sf.jsqlparser.statement.piped; +import net.sf.jsqlparser.statement.update.UpdateSet; + +import java.util.Collection; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Spliterator; +import java.util.function.Consumer; +import java.util.function.IntFunction; +import java.util.function.Predicate; +import java.util.function.UnaryOperator; +import java.util.stream.Stream; + public class SetPipeOperator extends PipeOperator { + private List updateSets; + + public SetPipeOperator(List updateSets) { + this.updateSets = updateSets; + } + + public List getUpdateSets() { + return updateSets; + } + + public SetPipeOperator setUpdateSets(List updateSets) { + this.updateSets = updateSets; + return this; + } + + public int size() { + return updateSets.size(); + } + + public void forEach(Consumer action) { + updateSets.forEach(action); + } + + public boolean remove(Object o) { + return updateSets.remove(o); + } + + public Spliterator spliterator() { + return updateSets.spliterator(); + } + + public boolean addAll(Collection c) { + return updateSets.addAll(c); + } + + public Stream parallelStream() { + return updateSets.parallelStream(); + } + + public UpdateSet get(int index) { + return updateSets.get(index); + } + + public boolean containsAll(Collection c) { + return updateSets.containsAll(c); + } + + public List subList(int fromIndex, int toIndex) { + return updateSets.subList(fromIndex, toIndex); + } + + public ListIterator listIterator() { + return updateSets.listIterator(); + } + + public void sort(Comparator c) { + updateSets.sort(c); + } + + public T[] toArray(T[] a) { + return updateSets.toArray(a); + } + + public ListIterator listIterator(int index) { + return updateSets.listIterator(index); + } + + public Stream stream() { + return updateSets.stream(); + } + + public int lastIndexOf(Object o) { + return updateSets.lastIndexOf(o); + } + + public boolean add(UpdateSet updateSet) { + return updateSets.add(updateSet); + } + + public void clear() { + updateSets.clear(); + } + + public Iterator iterator() { + return updateSets.iterator(); + } + + public boolean retainAll(Collection c) { + return updateSets.retainAll(c); + } + + public int indexOf(Object o) { + return updateSets.indexOf(o); + } + + public T[] toArray(IntFunction generator) { + return updateSets.toArray(generator); + } + + public boolean contains(Object o) { + return updateSets.contains(o); + } + + public Object[] toArray() { + return updateSets.toArray(); + } + + public void replaceAll(UnaryOperator operator) { + updateSets.replaceAll(operator); + } + + public UpdateSet remove(int index) { + return updateSets.remove(index); + } + + public boolean addAll(int index, Collection c) { + return updateSets.addAll(index, c); + } + + public boolean removeIf(Predicate filter) { + return updateSets.removeIf(filter); + } + + public void add(int index, UpdateSet element) { + updateSets.add(index, element); + } + + public boolean removeAll(Collection c) { + return updateSets.removeAll(c); + } + + public UpdateSet set(int index, UpdateSet element) { + return updateSets.set(index, element); + } + + public boolean isEmpty() { + return updateSets.isEmpty(); + } + @Override public T accept(PipeOperatorVisitor visitor, S context) { return visitor.visit(this, context); } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append("SET"); + int i = 0; + for (UpdateSet updateSet : updateSets) { + builder.append(i++ > 0 ? ", " : " ").append(updateSet); + } + builder.append("\n"); + return builder; + } } diff --git a/src/main/java/net/sf/jsqlparser/statement/update/UpdateSet.java b/src/main/java/net/sf/jsqlparser/statement/update/UpdateSet.java index 46aa85e7d..abfd21192 100644 --- a/src/main/java/net/sf/jsqlparser/statement/update/UpdateSet.java +++ b/src/main/java/net/sf/jsqlparser/statement/update/UpdateSet.java @@ -118,4 +118,8 @@ StringBuilder appendTo(StringBuilder builder, int j) { return builder; } + @Override + public String toString() { + return appendTo(new StringBuilder(), 0).toString(); + } } 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 260f8f65c..d530c754a 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -68,6 +68,7 @@ import net.sf.jsqlparser.statement.select.UnPivot; import net.sf.jsqlparser.statement.select.Values; import net.sf.jsqlparser.statement.select.WithItem; +import net.sf.jsqlparser.statement.update.UpdateSet; import java.lang.reflect.InvocationTargetException; import java.util.Iterator; @@ -901,6 +902,9 @@ public StringBuilder visit(CallPipeOperator call, S context) { @Override public StringBuilder visit(DropPipeOperator drop, S context) { + builder.append("|> ").append("DROP "); + drop.getColumns().accept(expressionVisitor, context); + builder.append("\n"); return builder; } @@ -929,6 +933,10 @@ public StringBuilder visit(JoinPipeOperator join, S context) { @Override public StringBuilder visit(LimitPipeOperator limit, S context) { + builder.append("|> ").append("LIMIT ").append(limit.getLimitExpression()); + if (limit.getOffsetExpression() != null) { + builder.append(" OFFSET ").append(limit.getOffsetExpression()); + } return builder; } @@ -963,6 +971,12 @@ public StringBuilder visit(SelectPipeOperator select, S context) { @Override public StringBuilder visit(SetPipeOperator set, S context) { + builder.append("|> ").append("SET"); + int i = 0; + for (UpdateSet updateSet : set.getUpdateSets()) { + builder.append(i++ > 0 ? ", " : " ").append(updateSet); + } + builder.append("\n"); return builder; } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index d010d1cce..3e78a4117 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -2356,18 +2356,18 @@ PipeOperator PipeOperator() #PipeOperator: operator = SelectPipeOperator() // | // operator = ExtendPipeOperator() -// | -// operator = SetPipeOperator() -// | -// operator = DropPipeOperator() + | + operator = SetPipeOperator() + | + operator = DropPipeOperator() // | // operator = RenamePipeOperator() | LOOKAHEAD(2) operator = AsPipeOperator() | operator = WherePipeOperator() -// | -// operator = LimitPipeOperator() + | + operator = LimitPipeOperator() | LOOKAHEAD(2) operator = AggregatePipeOperator() | @@ -2399,6 +2399,8 @@ SelectPipeOperator SelectPipeOperator(): operatorKeyToken = | operatorKeyToken = + | + operatorKeyToken = ) selectItem = SelectItem() { selectPipeOperator = new SelectPipeOperator(operatorKeyToken.image, selectItem); } @@ -2489,6 +2491,45 @@ JoinPipeOperator JoinPipeOperator(): } } +SetPipeOperator SetPipeOperator(): +{ + SetPipeOperator setPipeOperator; + List updateSets; +} +{ + updateSets = UpdateSets() + { + setPipeOperator = new SetPipeOperator(updateSets); + return setPipeOperator; + } +} + +DropPipeOperator DropPipeOperator(): +{ + DropPipeOperator dropPipeOperator; + ExpressionList columns; +} +{ + columns = ColumnList() + { + dropPipeOperator = new DropPipeOperator(columns); + return dropPipeOperator; + } +} + +LimitPipeOperator LimitPipeOperator(): +{ + LimitPipeOperator limitPipeOperator; + Expression expression; +} +{ + expression = Expression() { limitPipeOperator = new LimitPipeOperator(expression); } + [ LOOKAHEAD(2) expression = Expression() { limitPipeOperator.setOffsetExpression(expression); } ] + + { + return limitPipeOperator; + } +} TableStatement TableStatement(): { diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/DropPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/DropPipeOperatorTest.java new file mode 100644 index 000000000..7022fbfcf --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/DropPipeOperatorTest.java @@ -0,0 +1,25 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class DropPipeOperatorTest { + + @Test + void testParseAndDeParseWithoutFromKeyword() throws JSQLParserException { + String sqlStr = "SELECT 'apples' AS item, 2 AS sales, 'fruit' AS category\n" + + "|> DROP sales, category;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testParseAndDeParse() throws JSQLParserException { + String sqlStr = "FROM (SELECT 1 AS x, 2 AS y) AS t\n" + + "|> DROP x\n" + + "|> SELECT t.x AS original_x, y;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/LimitPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/LimitPipeOperatorTest.java new file mode 100644 index 000000000..17c86bbab --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/LimitPipeOperatorTest.java @@ -0,0 +1,38 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.*; + +class LimitPipeOperatorTest { + + @Test + void testParseAndDeparse() throws JSQLParserException { + String sqlStr = "(\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'bananas' AS item, 5 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> ORDER BY item\n" + + "|> LIMIT 1;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void testParseAndDeparseWithOffset() throws JSQLParserException { + String sqlStr = "(\n" + + " SELECT 'apples' AS item, 2 AS sales\n" + + " UNION ALL\n" + + " SELECT 'bananas' AS item, 5 AS sales\n" + + " UNION ALL\n" + + " SELECT 'carrots' AS item, 8 AS sales\n" + + ")\n" + + "|> ORDER BY item\n" + + "|> LIMIT 1 OFFSET 2;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/SelectPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/SelectPipeOperatorTest.java new file mode 100644 index 000000000..5e4ad42ad --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/SelectPipeOperatorTest.java @@ -0,0 +1,17 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class SelectPipeOperatorTest { + + @Test + void testRename() throws JSQLParserException { + String sqlStr = "SELECT 1 AS x, 2 AS y, 3 AS z\n" + + "|> AS t\n" + + "|> RENAME y AS renamed_y\n" + + "|> SELECT *, t.y AS t_y;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/SetPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/SetPipeOperatorTest.java new file mode 100644 index 000000000..ee3bfaf0c --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/SetPipeOperatorTest.java @@ -0,0 +1,19 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + +class SetPipeOperatorTest { + + @Test + void parseAndDeparse() throws JSQLParserException { + String sqlStr = "(\n" + + " SELECT 1 AS x, 11 AS y\n" + + " UNION ALL\n" + + " SELECT 2 AS x, 22 AS y\n" + + ")\n" + + "|> SET x = x * x, y = 3;"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +} From 0544a82d6615d3c58110d12cec799d822c911171 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sat, 1 Feb 2025 13:59:31 +0700 Subject: [PATCH 4/5] doc: fixes Signed-off-by: Andreas Reichel --- README.md | 8 ++++---- src/site/sphinx/index.rst | 15 +++++++++++---- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 4b8c3484d..c01985b3c 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Gradle CI](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml/badge.svg)](https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml) -[![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) +[![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/6f9a2d7eb98f45969749e101322634a1)](https://www.codacy.com/gh/JSQLParser/JSqlParser/dashboard?utm_source=github.com&utm_medium=referral&utm_content=JSQLParser/JSqlParser&utm_campaign=Badge_Grade) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.jsqlparser/jsqlparser/badge.svg)](http://maven-badges.herokuapp.com/maven-central/com.github.jsqlparser/jsqlparser) [![Javadocs](https://www.javadoc.io/badge/com.github.jsqlparser/jsqlparser.svg)](https://www.javadoc.io/doc/com.github.jsqlparser/jsqlparser) [![Gitter](https://badges.gitter.im/JSQLParser/JSqlParser.svg)](https://gitter.im/JSQLParser/JSqlParser?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) @@ -26,7 +26,7 @@ SQL Text └─where: expression.operators.relational.EqualsTo ├─Column: a └─Column: b -*/ +*/ ``` ```java @@ -50,7 +50,7 @@ Assertions.assertEquals("a", a.getColumnName()); Assertions.assertEquals("b", b.getColumnName()); ``` -JSQLParser-4.9 was the last JDK8 compatible version. The recent JSQLParser-5.0 depends on JDK11 and introduces API breaking changes to the AST Visitors. Please see the Migration Guide for the details. +JSQLParser-4.9 was the last JDK8 compatible version. JSQLParser-5.0 and later depend on JDK11 and introduce API breaking changes to the AST Visitors. Please see the Migration Guide for the details. ## [Supported Grammar and Syntax](https://jsqlparser.github.io/JSqlParser/syntax.html) @@ -60,7 +60,7 @@ JSQLParser-4.9 was the last JDK8 compatible version. The recent JSQLParser-5.0 d |-----------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------| | Oracle
MS SQL Server and Sybase
Postgres
MySQL and MariaDB
DB2
H2 and HSQLDB and Derby
SQLite | `SELECT`
`INSERT`, `UPDATE`, `UPSERT`, `MERGE`
`DELETE`, `TRUNCATE TABLE`
`CREATE ...`, `ALTER ....`, `DROP ...`
`WITH ...` | | Salesforce SOQL | `INCLUDES`, `EXCLUDES` | -| Piped SQL (also know as FROM SQL) | | +| Piped SQL (also known as FROM SQL) | | **JSqlParser** can also be used to create SQL Statements from Java Code with a fluent API (see [Samples](https://jsqlparser.github.io/JSqlParser/usage.html#build-a-sql-statements)). diff --git a/src/site/sphinx/index.rst b/src/site/sphinx/index.rst index e28a57192..8c9e375ca 100644 --- a/src/site/sphinx/index.rst +++ b/src/site/sphinx/index.rst @@ -34,9 +34,9 @@ Java SQL Parser Library :alt: Maven Badge :target: https://mvnrepository.com/artifact/com.github.jsqlparser/jsqlparser -.. image:: https://github.com/JSQLParser/JSqlParser/actions/workflows/maven.yml/badge.svg - :alt: Maven Build Status - :target: https://github.com/JSQLParser/JSqlParser/actions/workflows/maven.yml +.. image:: https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml/badge.svg + :alt: CI Status + :target: https://github.com/JSQLParser/JSqlParser/actions/workflows/ci.yml .. image:: https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master :alt: Coverage Status @@ -50,9 +50,10 @@ Java SQL Parser Library :alt: Java Docs :target: https://javadoc.io/doc/com.github.jsqlparser/jsqlparser/latest/index.html +A huge thank you to our sponsor, [Starlake.ai](https://starlake.ai/) who simplifies data ingestion, transformation, and orchestration, enabling faster delivery of high-quality data. Starlake has been instrumental in providing Piped SQL and numerous test cases for BigQuery, Redshift, DataBricks, and DuckDB. Show your support for ongoing development by visiting Starlake.ai and giving us a star! **JSQLParser** is a SQL statement parser built from JavaCC. It translates SQLs in a traversable hierarchy of Java classes. -The upcoming 5.0 release will depend on Java 11 and introduces new Visitors. Please see the :ref:`Migration to 5.0` guide. +Since the 5.0 release JSQLParser depends on Java 11 and has introduced new Visitors. Please see the :ref:`Migration to 5.0` guide. Latest stable release: |JSQLPARSER_STABLE_VERSION_LINK| @@ -89,6 +90,11 @@ SQL Dialects * MySQL and MariaDB * PostgreSQL * H2 + * DuckDB + * Google BigQuery + * Amazon Redshift + * DataBricks + * Snowflake ******************************* Features @@ -107,6 +113,7 @@ Features * Arrays vs. T-SQL Squared Bracket Quotes * Fluent API to create SQL Statements from java Code * Statement De-Parser to write SQL from Java Objects + * Piped SQL (also known as FROM SQL) From f687f77d38e932813cd66d14a8bc6decf002c997 Mon Sep 17 00:00:00 2001 From: Andreas Reichel Date: Sat, 1 Feb 2025 17:21:05 +0700 Subject: [PATCH 5/5] feat: parsing Piped SQL Signed-off-by: Andreas Reichel --- README.md | 2 +- src/main/java/module-info.java | 1 + .../statement/piped/PipeOperatorVisitor.java | 2 +- .../piped/SetOperationPipeOperator.java | 77 +++++++++++++++++++ .../statement/piped/UnionPipeOperator.java | 8 -- .../util/deparser/ExpressionDeParser.java | 6 +- .../util/deparser/InsertDeParser.java | 2 +- .../util/deparser/SelectDeParser.java | 18 ++++- .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 51 +++++++++--- .../piped/SetOperationPipeOperatorTest.java | 39 ++++++++++ 10 files changed, 179 insertions(+), 27 deletions(-) create mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperator.java delete mode 100644 src/main/java/net/sf/jsqlparser/statement/piped/UnionPipeOperator.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperatorTest.java diff --git a/README.md b/README.md index 2ab4b20eb..4b930504b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![Maven deploy snapshot](https://github.com/JSQLParser/JSqlParser/actions/workflows/maven_deploy.yml/badge.svg)](https://github.com/JSQLParser/JSqlParser/actions/workflows/maven_deploy.yml) [![Gradle CI](https://github.com/JSQLParser/JSqlParser/actions/workflows/gradle.yml/badge.svg)](https://github.com/JSQLParser/JSqlParser/actions/workflows/gradle.yml) -[![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) +[![Coverage Status](https://coveralls.io/repos/JSQLParser/JSqlParser/badge.svg?branch=master)](https://coveralls.io/r/JSQLParser/JSqlParser?branch=master) [![Codacy Badge](https://app.codacy.com/project/badge/Grade/6f9a2d7eb98f45969749e101322634a1)](https://www.codacy.com/gh/JSQLParser/JSqlParser/dashboard?utm_source=github.com&utm_medium=referral&utm_content=JSQLParser/JSqlParser&utm_campaign=Badge_Grade) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.jsqlparser/jsqlparser/badge.svg)](http://maven-badges.herokuapp.com/maven-central/com.github.jsqlparser/jsqlparser) [![Javadocs](https://www.javadoc.io/badge/com.github.jsqlparser/jsqlparser.svg)](https://www.javadoc.io/doc/com.github.jsqlparser/jsqlparser) [![Gitter](https://badges.gitter.im/JSQLParser/JSqlParser.svg)](https://gitter.im/JSQLParser/JSqlParser?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge) diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java index aec008326..361504653 100644 --- a/src/main/java/module-info.java +++ b/src/main/java/module-info.java @@ -10,6 +10,7 @@ module net.sf.jsqlparser { requires java.sql; requires java.logging; + requires java.desktop; exports net.sf.jsqlparser; exports net.sf.jsqlparser.expression; diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java b/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java index f53bce5cd..3a176ec66 100644 --- a/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java +++ b/src/main/java/net/sf/jsqlparser/statement/piped/PipeOperatorVisitor.java @@ -31,7 +31,7 @@ public interface PipeOperatorVisitor { T visit(TableSamplePipeOperator tableSample, S context); - T visit(UnionPipeOperator union, S context); + T visit(SetOperationPipeOperator union, S context); T visit(UnPivotPipeOperator unPivot, S context); diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperator.java new file mode 100644 index 000000000..f8067e16b --- /dev/null +++ b/src/main/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperator.java @@ -0,0 +1,77 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.statement.select.ParenthesedSelect; +import net.sf.jsqlparser.statement.select.SetOperationList; + +import java.util.ArrayList; + +public class SetOperationPipeOperator extends PipeOperator { + private ArrayList selects; + private SetOperationList.SetOperationType setOperationType; + private String modifier; + + public SetOperationPipeOperator(ParenthesedSelect select, + SetOperationList.SetOperationType setOperationType, String modifier) { + this.selects = new ArrayList<>(); + this.selects.add(select); + + this.setOperationType = setOperationType; + this.modifier = modifier; + } + + public SetOperationPipeOperator add(ParenthesedSelect select) { + this.selects.add(select); + return this; + } + + public ArrayList getSelects() { + return selects; + } + + public SetOperationPipeOperator setSelects(ArrayList selects) { + this.selects = selects; + return this; + } + + public SetOperationList.SetOperationType getSetOperationType() { + return setOperationType; + } + + public SetOperationPipeOperator setSetOperationType( + SetOperationList.SetOperationType setOperationType) { + this.setOperationType = setOperationType; + return this; + } + + public String getModifier() { + return modifier; + } + + public SetOperationPipeOperator setModifier(String modifier) { + this.modifier = modifier; + return this; + } + + @Override + public StringBuilder appendTo(StringBuilder builder) { + builder.append("|> ").append(setOperationType); + if (modifier != null) { + builder.append(" ").append(modifier); + } + + int i = 0; + for (ParenthesedSelect select : selects) { + if (i++ > 0) { + builder.append(", "); + } + builder.append(select); + } + builder.append("\n"); + return builder; + } + + @Override + public T accept(PipeOperatorVisitor visitor, S context) { + return visitor.visit(this, context); + } +} diff --git a/src/main/java/net/sf/jsqlparser/statement/piped/UnionPipeOperator.java b/src/main/java/net/sf/jsqlparser/statement/piped/UnionPipeOperator.java deleted file mode 100644 index 657e2aa7f..000000000 --- a/src/main/java/net/sf/jsqlparser/statement/piped/UnionPipeOperator.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.sf.jsqlparser.statement.piped; - -public class UnionPipeOperator extends PipeOperator { - @Override - public T accept(PipeOperatorVisitor visitor, S context) { - return visitor.visit(this, context); - } -} diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java index 32d441126..94130a903 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/ExpressionDeParser.java @@ -434,11 +434,11 @@ public StringBuilder visit(IsBooleanExpression isBooleanExpression, S contex public StringBuilder visit(IsUnknownExpression isUnknownExpression, S context) { isUnknownExpression.getLeftExpression().accept(this, context); if (isUnknownExpression.isNot()) { - buffer.append(" IS NOT UNKNOWN"); + builder.append(" IS NOT UNKNOWN"); } else { - buffer.append(" IS UNKNOWN"); + builder.append(" IS UNKNOWN"); } - return buffer; + return builder; } @Override diff --git a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java index 1c79f144e..a555f2ba7 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/InsertDeParser.java @@ -91,7 +91,7 @@ public void deParse(Insert insert) { } if (insert.isOverriding()) { - buffer.append("OVERRIDING SYSTEM VALUE "); + builder.append("OVERRIDING SYSTEM VALUE "); } if (insert.getPartitions() != null) { 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 d530c754a..c17db5582 100644 --- a/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java +++ b/src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java @@ -37,7 +37,7 @@ import net.sf.jsqlparser.statement.piped.SetPipeOperator; import net.sf.jsqlparser.statement.piped.TableSamplePipeOperator; import net.sf.jsqlparser.statement.piped.UnPivotPipeOperator; -import net.sf.jsqlparser.statement.piped.UnionPipeOperator; +import net.sf.jsqlparser.statement.piped.SetOperationPipeOperator; import net.sf.jsqlparser.statement.piped.WherePipeOperator; import net.sf.jsqlparser.statement.piped.WindowPipeOperator; import net.sf.jsqlparser.statement.select.Distinct; @@ -948,6 +948,7 @@ public StringBuilder visit(OrderByPipeOperator orderBy, S context) { return builder; } + @Override public StringBuilder visit(PivotPipeOperator pivot, S context) { return builder; @@ -986,7 +987,20 @@ public StringBuilder visit(TableSamplePipeOperator tableSample, S context) { } @Override - public StringBuilder visit(UnionPipeOperator union, S context) { + public StringBuilder visit(SetOperationPipeOperator setOperationPipeOperator, S context) { + builder.append("|> ").append(setOperationPipeOperator.getSetOperationType()); + if (setOperationPipeOperator.getModifier() != null) { + builder.append(" ").append(setOperationPipeOperator.getModifier()); + } + + int i = 0; + for (ParenthesedSelect select : setOperationPipeOperator.getSelects()) { + if (i++ > 0) { + builder.append(", "); + } + builder.append(select); + } + builder.append("\n"); return builder; } diff --git a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt index ebc4c1582..2a29888b3 100644 --- a/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt +++ b/src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt @@ -69,6 +69,7 @@ import net.sf.jsqlparser.statement.merge.*; import net.sf.jsqlparser.statement.grant.*; import java.util.*; import java.util.AbstractMap.SimpleEntry; +import net.sf.jsqlparser.statement.select.SetOperationList.SetOperationType; import java.util.logging.Level; import java.util.logging.Logger; @@ -2090,7 +2091,7 @@ String RelObjectNameWithoutValue() : { Token tk = null; } { ( tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= | tk= - | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="ALGORITHM" | tk="ALTER" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOCK" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="COSTS" | tk="COUNT" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCRYPTION" | tk="END" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXCLUDE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXTENDED" | tk="EXTRACT" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GROUP_CONCAT" | tk="GUARD" | tk="HASH" | tk="HIGH" | tk="HIGH_PRIORITY" | tk="HISTORY" | tk="HOPPING" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="ISNULL" | tk="JSON" | tk="JSON_ARRAY" | tk="JSON_ARRAYAGG" | tk="JSON_OBJECT" | tk="JSON_OBJECTAGG" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="LAST" | tk="LEADING" | tk="LESS" | tk="LINK" | tk="LOCAL" | tk="LOCK" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW" | tk="LOW_PRIORITY" | tk="MATCH" | tk="MATCHED" | tk="MATCH_ALL" | tk="MATCH_ANY" | tk="MATCH_PHRASE" | tk="MATCH_PHRASE_PREFIX" | tk="MATCH_REGEXP" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEDIUMTEXT" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODIFY" | tk="MOVEMENT" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PARALLEL" | tk="PARENT" | tk="PARTITION" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PLUS" | tk="PRECEDING" | tk="PRIMARY" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGEXP_LIKE" | tk="REGISTER" | tk="REMOTE" | tk="RENAME" | tk="REPEATABLE" | tk="REPLACE" | tk="RESET" | tk="RESPECT" | tk="RESTART" | tk="RESTRICT" | tk="RESTRICTED" | tk="RESUMABLE" | tk="RESUME" | tk="RETURN" | tk="RLIKE" | tk="ROLLBACK" | tk="ROLLUP" | tk="ROOT" | tk="ROW" | tk="ROWS" | tk="RR" | tk="RS" | tk="SAFE_CAST" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SEED" | tk="SEPARATOR" | tk="SEQUENCE" | tk="SESSION" | tk="SETS" | tk="SHARE" | tk="SHOW" | tk="SHUTDOWN" | tk="SIBLINGS" | tk="SIGNED" | tk="SIMILAR" | tk="SIZE" | tk="SKIP" | tk="STORED" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYNONYM" | tk="SYSTEM" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="TEXT" | tk="THAN" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TINYTEXT" | tk="TO" | tk="TRIGGER" | tk="TRUNCATE" | tk="TRY_CAST" | tk="TUMBLING" | tk="TYPE" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VERBOSE" | tk="VIEW" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WITHOUT_ARRAY_WRAPPER" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" ) + | tk="ACTION" | tk="ACTIVE" | tk="ADD" | tk="ADVANCE" | tk="ADVISE" | tk="AGAINST" | tk="AGGREGATE" | tk="ALGORITHM" | tk="ALTER" | tk="ANALYZE" | tk="APPLY" | tk="APPROXIMATE" | tk="ARCHIVE" | tk="ARRAY" | tk="ASC" | tk="AT" | tk="AUTHORIZATION" | tk="AUTO" | tk="AUTO_INCREMENT" | tk="BASE64" | tk="BEGIN" | tk="BERNOULLI" | tk="BINARY" | tk="BIT" | tk="BLOCK" | tk="BROWSE" | tk="BUFFERS" | tk="BY" | tk="BYTE" | tk="BYTES" | tk="CACHE" | tk="CALL" | tk="CASCADE" | tk="CASE" | tk="CAST" | tk="CHANGE" | tk="CHANGES" | tk="CHAR" | tk="CHARACTER" | tk="CHECKPOINT" | tk="CLOSE" | tk="COLLATE" | tk="COLUMN" | tk="COLUMNS" | tk="COMMENT" | tk="COMMIT" | tk="CONCURRENTLY" | tk="CONFLICT" | tk="CONSTRAINTS" | tk="CONVERT" | tk="COSTS" | tk="COUNT" | tk="CS" | tk="CYCLE" | tk="DATA" | tk="DATABASE" | tk="DATETIME" | tk="DBA_RECYCLEBIN" | tk="DDL" | tk="DECLARE" | tk="DEFERRABLE" | tk="DELAYED" | tk="DELETE" | tk="DESC" | tk="DESCRIBE" | tk="DISABLE" | tk="DISCONNECT" | tk="DIV" | tk="DML" | tk="DO" | tk="DOMAIN" | tk="DROP" | tk="DUMP" | tk="DUPLICATE" | tk="ELEMENTS" | tk="EMIT" | tk="ENABLE" | tk="ENCRYPTION" | tk="END" | tk="ENGINE" | tk="ERROR" | tk="ESCAPE" | tk="EXCLUDE" | tk="EXEC" | tk="EXECUTE" | tk="EXPLAIN" | tk="EXPLICIT" | tk="EXTENDED" | tk="EXTRACT" | tk="FILTER" | tk="FIRST" | tk="FLUSH" | tk="FN" | tk="FOLLOWING" | tk="FORMAT" | tk="FULLTEXT" | tk="FUNCTION" | tk="GRANT" | tk="GROUP_CONCAT" | tk="GUARD" | tk="HASH" | tk="HIGH" | tk="HIGH_PRIORITY" | tk="HISTORY" | tk="HOPPING" | tk="INCLUDE" | tk="INCLUDE_NULL_VALUES" | tk="INCREMENT" | tk="INDEX" | tk="INSERT" | tk="INTERLEAVE" | tk="INTERPRET" | tk="INVALIDATE" | tk="INVERSE" | tk="ISNULL" | tk="JSON" | tk="JSON_ARRAY" | tk="JSON_ARRAYAGG" | tk="JSON_OBJECT" | tk="JSON_OBJECTAGG" | tk="KEEP" | tk="KEY" | tk="KEYS" | tk="LAST" | tk="LEADING" | tk="LESS" | tk="LINK" | tk="LOCAL" | tk="LOCK" | tk="LOCKED" | tk="LOG" | tk="LONGTEXT" | tk="LOOP" | tk="LOW" | tk="LOW_PRIORITY" | tk="MATCH" | tk="MATCHED" | tk="MATCH_ALL" | tk="MATCH_ANY" | tk="MATCH_PHRASE" | tk="MATCH_PHRASE_PREFIX" | tk="MATCH_REGEXP" | tk="MATERIALIZED" | tk="MAX" | tk="MAXVALUE" | tk="MEDIUMTEXT" | tk="MEMBER" | tk="MERGE" | tk="MIN" | tk="MINVALUE" | tk="MODIFY" | tk="MOVEMENT" | tk="NEXT" | tk="NO" | tk="NOCACHE" | tk="NOKEEP" | tk="NOLOCK" | tk="NOMAXVALUE" | tk="NOMINVALUE" | tk="NOORDER" | tk="NOTHING" | tk="NOTNULL" | tk="NOVALIDATE" | tk="NOWAIT" | tk="NULLS" | tk="OF" | tk="OFF" | tk="OPEN" | tk="OVER" | tk="OVERFLOW" | tk="OVERLAPS" | tk="OVERRIDING" | tk="OVERWRITE" | tk="PARALLEL" | tk="PARENT" | tk="PARTITION" | tk="PATH" | tk="PERCENT" | tk="PLACING" | tk="PLAN" | tk="PLUS" | tk="PRECEDING" | tk="PRIMARY" | tk="PURGE" | tk="QUERY" | tk="QUICK" | tk="QUIESCE" | tk="RANGE" | tk="RAW" | tk="READ" | tk="RECURSIVE" | tk="RECYCLEBIN" | tk="REFERENCES" | tk="REFRESH" | tk="REGEXP" | tk="REGEXP_LIKE" | tk="REGISTER" | tk="REMOTE" | tk="RENAME" | tk="REPEATABLE" | tk="REPLACE" | tk="RESET" | tk="RESPECT" | tk="RESTART" | tk="RESTRICT" | tk="RESTRICTED" | tk="RESUMABLE" | tk="RESUME" | tk="RETURN" | tk="RLIKE" | tk="ROLLBACK" | tk="ROLLUP" | tk="ROOT" | tk="ROW" | tk="ROWS" | tk="RR" | tk="RS" | tk="SAFE_CAST" | tk="SAVEPOINT" | tk="SCHEMA" | tk="SECURE" | tk="SEED" | tk="SEPARATOR" | tk="SEQUENCE" | tk="SESSION" | tk="SETS" | tk="SHARE" | tk="SHOW" | tk="SHUTDOWN" | tk="SIBLINGS" | tk="SIGNED" | tk="SIMILAR" | tk="SIZE" | tk="SKIP" | tk="STORED" | tk="STRING" | tk="STRUCT" | tk="SUMMARIZE" | tk="SUSPEND" | tk="SWITCH" | tk="SYNONYM" | tk="SYSTEM" | tk="TABLE" | tk="TABLESPACE" | tk="TEMP" | tk="TEMPORARY" | tk="TEXT" | tk="THAN" | tk="THEN" | tk="TIMEOUT" | tk="TIMESTAMPTZ" | tk="TIMEZONE" | tk="TINYTEXT" | tk="TO" | tk="TRIGGER" | tk="TRUNCATE" | tk="TRY_CAST" | tk="TUMBLING" | tk="TYPE" | tk="UNLOGGED" | tk="UNQIESCE" | tk="UNSIGNED" | tk="UPDATE" | tk="UPSERT" | tk="UR" | tk="USER" | tk="VALIDATE" | tk="VERBOSE" | tk="VIEW" | tk="VOLATILE" | tk="WAIT" | tk="WITHIN" | tk="WITHOUT" | tk="WITHOUT_ARRAY_WRAPPER" | tk="WORK" | tk="XML" | tk="XMLAGG" | tk="XMLDATA" | tk="XMLSCHEMA" | tk="XMLTEXT" | tk="XSINIL" | tk="YAML" | tk="YES" | tk="ZONE" ) { return tk.image; } } @@ -2355,15 +2356,12 @@ PipeOperator PipeOperator() #PipeOperator: } { ( + // SELECT covers also EXTEND, WINDOW and RENAME operator = SelectPipeOperator() -// | -// operator = ExtendPipeOperator() | operator = SetPipeOperator() | operator = DropPipeOperator() -// | -// operator = RenamePipeOperator() | LOOKAHEAD(2) operator = AsPipeOperator() | @@ -2374,12 +2372,9 @@ PipeOperator PipeOperator() #PipeOperator: LOOKAHEAD(2) operator = AggregatePipeOperator() | operator = OrderByPipeOperator() -// | -// operator = UnionPipeOperator(); -// | -// operator = IntersectPipeOperator(); -// | -// operator = ExceptPipeOperator(); + | + // covers UNION, INTERSET, EXCEPT + operator = SetOperationPipeOperator() | operator = JoinPipeOperator() ) @@ -2533,6 +2528,40 @@ LimitPipeOperator LimitPipeOperator(): } } +SetOperationPipeOperator SetOperationPipeOperator(): +{ + SetOperationPipeOperator setOperationPipeOperator = null; + SetOperationType setOperationType; + Token modifierToken; + ParenthesedSelect select; +} +{ + ( + ( + ( modifierToken= | modifierToken= ) { setOperationType = SetOperationType.UNION; } + select = ParenthesedSelect() { setOperationPipeOperator = new SetOperationPipeOperator(select, setOperationType, modifierToken.image); } + ) + | + ( + modifierToken= { setOperationType = SetOperationType.INTERSECT; } + select = ParenthesedSelect() { setOperationPipeOperator = new SetOperationPipeOperator(select, setOperationType, modifierToken.image); } + ) + | + ( + modifierToken= { setOperationType = SetOperationType.EXCEPT; } + select = ParenthesedSelect() { setOperationPipeOperator = new SetOperationPipeOperator(select, setOperationType, modifierToken.image); } + ) + ) + + ( + LOOKAHEAD(2) "," select = ParenthesedSelect() { setOperationPipeOperator.add(select); } + )* + + { + return setOperationPipeOperator; + } +} + TableStatement TableStatement(): { Table table = null; diff --git a/src/test/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperatorTest.java b/src/test/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperatorTest.java new file mode 100644 index 000000000..9e0fca6f4 --- /dev/null +++ b/src/test/java/net/sf/jsqlparser/statement/piped/SetOperationPipeOperatorTest.java @@ -0,0 +1,39 @@ +package net.sf.jsqlparser.statement.piped; + +import net.sf.jsqlparser.JSQLParserException; +import net.sf.jsqlparser.test.TestUtils; +import org.junit.jupiter.api.Test; + + +class SetOperationPipeOperatorTest { + + @Test + void parseAndDeparseUnion() throws JSQLParserException { + String sqlStr = + "SELECT 3\n" + + "|> UNION ALL\n" + + " (SELECT 1),\n" + + " (SELECT 2);"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + // @todo: parse SELECT * FROM UNNEST(ARRAY[2, 3, 3, 5]) AS number + + @Test + void parseAndDeparseIntersect() throws JSQLParserException { + String sqlStr = + "SELECT * FROM UNNEST(ARRAY[1, 2, 3, 3, 4]) AS number\n" + + "|> INTERSECT DISTINCT\n" + + " (SELECT * FROM UNNEST(ARRAY[2, 3, 3, 5]) AS number);"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } + + @Test + void parseAndDeparseExcept() throws JSQLParserException { + String sqlStr = + "SELECT * FROM UNNEST(ARRAY[1, 2, 3, 3, 4]) AS number\n" + + "|> EXCEPT DISTINCT\n" + + " (SELECT * FROM UNNEST(ARRAY[1, 2]) AS number);"; + TestUtils.assertSqlCanBeParsedAndDeparsed(sqlStr, true); + } +}