Skip to content

Commit abf137e

Browse files
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 <andreas@manticore-projects.com> Signed-off-by: manticore-projects <andreas@manticore-projects.com>
1 parent f25e28b commit abf137e

File tree

16 files changed

+274
-51
lines changed

16 files changed

+274
-51
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,7 +88,7 @@ If you like JSqlParser then please check out its related projects:
8888
## Alternatives to JSqlParser?
8989
[**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.
9090

91-
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.
91+
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.
9292

9393
## [Documentation](https://jsqlparser.github.io/JSqlParser)
9494
1. [Samples](https://jsqlparser.github.io/JSqlParser/usage.html#parse-a-sql-statements)

src/main/java/net/sf/jsqlparser/parser/ParserKeywordsUtils.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ public class ParserKeywordsUtils {
6868
{"EXCEPT", RESTRICTED_SQL2016},
6969
{"EXCLUDES", RESTRICTED_JSQLPARSER},
7070
{"EXISTS", RESTRICTED_SQL2016},
71+
{"EXTEND", RESTRICTED_JSQLPARSER},
7172
{"FALSE", RESTRICTED_SQL2016},
7273
{"FETCH", RESTRICTED_SQL2016},
7374
{"FINAL", RESTRICTED_JSQLPARSER},
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,32 @@
11
package net.sf.jsqlparser.statement.piped;
22

3+
import net.sf.jsqlparser.expression.Alias;
4+
35
public class AsPipeOperator extends PipeOperator {
6+
private Alias alias;
7+
8+
public AsPipeOperator(Alias alias) {
9+
this.alias = alias;
10+
}
11+
12+
public Alias getAlias() {
13+
return alias;
14+
}
15+
16+
public AsPipeOperator setAlias(Alias alias) {
17+
this.alias = alias;
18+
return this;
19+
}
420

521
@Override
622
public <T, S> T accept(PipeOperatorVisitor<T> visitor, S context) {
723
return visitor.visit(this, context);
824
}
25+
26+
@Override
27+
public StringBuilder appendTo(StringBuilder builder) {
28+
builder.append("|> ").append(alias);
29+
builder.append("\n");
30+
return builder;
31+
}
932
}
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package net.sf.jsqlparser.statement.piped;
22

3-
public class ExtendPipeOperator extends PipeOperator {
4-
@Override
5-
public <T, S> T accept(PipeOperatorVisitor<T> visitor, S context) {
6-
return visitor.visit(this, context);
3+
import net.sf.jsqlparser.statement.select.SelectItem;
4+
5+
public class ExtendPipeOperator extends SelectPipeOperator {
6+
public ExtendPipeOperator(SelectItem<?> selectItem) {
7+
super("EXTEND", selectItem);
78
}
89
}

src/main/java/net/sf/jsqlparser/statement/piped/FromQuery.java

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@
22

33
import net.sf.jsqlparser.expression.Alias;
44
import net.sf.jsqlparser.expression.ExpressionVisitor;
5-
import net.sf.jsqlparser.statement.StatementVisitor;
65
import net.sf.jsqlparser.statement.select.FromItem;
76
import net.sf.jsqlparser.statement.select.FromItemVisitor;
87
import net.sf.jsqlparser.statement.select.Pivot;
@@ -19,13 +18,19 @@
1918
import java.util.function.UnaryOperator;
2019

2120
public class FromQuery extends Select {
21+
private boolean usingFromKeyword = true;
2222
private FromItem fromItem;
2323
private final ArrayList<PipeOperator> pipeOperators = new ArrayList<>();
2424

2525
public FromQuery(FromItem fromItem) {
2626
this.fromItem = fromItem;
2727
}
2828

29+
public FromQuery(FromItem fromItem, boolean usingFromKeyword) {
30+
this.fromItem = fromItem;
31+
this.usingFromKeyword = usingFromKeyword;
32+
}
33+
2934
public FromItem getFromItem() {
3035
return fromItem;
3136
}
@@ -36,7 +41,20 @@ public FromQuery setFromItem(FromItem fromItem) {
3641
}
3742

3843
public FromQuery with(FromItem fromItem) {
39-
return setFromItem(fromItem);
44+
return this.setFromItem(fromItem);
45+
}
46+
47+
public boolean isUsingFromKeyword() {
48+
return usingFromKeyword;
49+
}
50+
51+
public FromQuery setUsingFromKeyword(boolean usingFromKeyword) {
52+
this.usingFromKeyword = usingFromKeyword;
53+
return this;
54+
}
55+
56+
public FromQuery with(boolean usingFromKeyword) {
57+
return this.setUsingFromKeyword(usingFromKeyword);
4058
}
4159

4260
public ArrayList<PipeOperator> getPipeOperators() {
@@ -175,11 +193,6 @@ public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {
175193
return expressionVisitor.visit(this, context);
176194
}
177195

178-
@Override
179-
public <T, S> T accept(StatementVisitor<T> statementVisitor, S context) {
180-
return statementVisitor.visit(this, context);
181-
}
182-
183196
@Override
184197
public <T, S> T accept(FromItemVisitor<T> fromItemVisitor, S context) {
185198
return fromItemVisitor.visit(this, context);
@@ -194,7 +207,10 @@ public <T, S> T accept(SelectVisitor<T> selectVisitor, S context) {
194207

195208
@Override
196209
public StringBuilder appendTo(StringBuilder builder) {
197-
builder.append("FROM ").append(fromItem).append("\n");
210+
if (usingFromKeyword) {
211+
builder.append("FROM ");
212+
}
213+
builder.append(fromItem).append("\n");
198214
for (PipeOperator operator : pipeOperators) {
199215
operator.appendTo(builder);
200216
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,34 @@
11
package net.sf.jsqlparser.statement.piped;
22

3+
import net.sf.jsqlparser.statement.select.Join;
4+
35
public class JoinPipeOperator extends PipeOperator {
6+
private Join join;
7+
8+
public JoinPipeOperator(Join join) {
9+
this.join = join;
10+
}
11+
12+
public Join getJoin() {
13+
return join;
14+
}
15+
16+
public JoinPipeOperator setJoin(Join join) {
17+
this.join = join;
18+
return this;
19+
}
20+
421
@Override
522
public <T, S> T accept(PipeOperatorVisitor<T> visitor, S context) {
623
return visitor.visit(this, context);
724
}
25+
26+
@Override
27+
public StringBuilder appendTo(StringBuilder builder) {
28+
builder.append("|> ").append(join);
29+
builder.append("\n");
30+
return builder;
31+
}
32+
33+
834
}

src/main/java/net/sf/jsqlparser/statement/piped/SelectPipeOperator.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,27 @@
55
import java.util.ArrayList;
66

77
public class SelectPipeOperator extends PipeOperator {
8+
private final String operatorName;
9+
810
private final ArrayList<SelectItem<?>> selectItems = new ArrayList<>();
911

10-
public SelectPipeOperator(SelectItem<?> selectItem) {
12+
public SelectPipeOperator(String operatorName, SelectItem<?> selectItem) {
13+
this.operatorName = operatorName;
1114
selectItems.add(selectItem);
1215
}
1316

17+
public SelectPipeOperator(SelectItem<?> selectItem) {
18+
this("SELECT", selectItem);
19+
}
20+
21+
public String getOperatorName() {
22+
return operatorName;
23+
}
24+
25+
public ArrayList<SelectItem<?>> getSelectItems() {
26+
return selectItems;
27+
}
28+
1429
public SelectPipeOperator add(SelectItem<?> selectItem) {
1530
selectItems.add(selectItem);
1631
return this;
@@ -27,7 +42,7 @@ public <T, S> T accept(PipeOperatorVisitor<T> visitor, S context) {
2742

2843
@Override
2944
public StringBuilder appendTo(StringBuilder builder) {
30-
builder.append("|> ").append("SELECT");
45+
builder.append("|> ").append(operatorName);
3146
int i = 0;
3247
for (SelectItem<?> selectItem : selectItems) {
3348
builder.append(i++ > 0 ? ", " : " ").append(selectItem);
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package net.sf.jsqlparser.statement.piped;
22

3-
public class WindowPipeOperator extends PipeOperator {
4-
@Override
5-
public <T, S> T accept(PipeOperatorVisitor<T> visitor, S context) {
6-
return visitor.visit(this, context);
3+
import net.sf.jsqlparser.statement.select.SelectItem;
4+
5+
public class WindowPipeOperator extends SelectPipeOperator {
6+
public WindowPipeOperator(SelectItem<?> selectItem) {
7+
super("WINDOW", selectItem);
78
}
89
}

src/main/java/net/sf/jsqlparser/statement/select/Join.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ public String toString() {
435435
for (Expression onExpression : onExpressions) {
436436
builder.append(" ON ").append(onExpression);
437437
}
438-
if (usingColumns.size() > 0) {
438+
if (!usingColumns.isEmpty()) {
439439
builder.append(PlainSelect.getFormattedList(usingColumns, "USING", true, true));
440440
}
441441

src/main/java/net/sf/jsqlparser/util/deparser/SelectDeParser.java

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -829,7 +829,9 @@ public void visit(TableStatement tableStatement) {
829829

830830
@Override
831831
public <S> StringBuilder visit(FromQuery fromQuery, S context) {
832-
builder.append("FROM ");
832+
if (fromQuery.isUsingFromKeyword()) {
833+
builder.append("FROM ");
834+
}
833835
fromQuery.getFromItem().accept(this, context);
834836
builder.append("\n");
835837
for (PipeOperator operator : fromQuery.getPipeOperators()) {
@@ -887,6 +889,8 @@ public <S> StringBuilder visit(AggregatePipeOperator aggregate, S context) {
887889

888890
@Override
889891
public <S> StringBuilder visit(AsPipeOperator as, S context) {
892+
builder.append("|> ").append(as.getAlias());
893+
builder.append("\n");
890894
return builder;
891895
}
892896

@@ -907,7 +911,7 @@ public <S> StringBuilder visit(ExceptPipeOperator except, S context) {
907911

908912
@Override
909913
public <S> StringBuilder visit(ExtendPipeOperator extend, S context) {
910-
return builder;
914+
return visit((SelectPipeOperator) extend, context);
911915
}
912916

913917
@Override
@@ -917,6 +921,9 @@ public <S> StringBuilder visit(IntersectPipeOperator intersect, S context) {
917921

918922
@Override
919923
public <S> StringBuilder visit(JoinPipeOperator join, S context) {
924+
builder.append("|> ");
925+
deparseJoin(join.getJoin());
926+
builder.append("\n");
920927
return builder;
921928
}
922929

@@ -945,6 +952,12 @@ public <S> StringBuilder visit(RenamePipeOperator rename, S context) {
945952

946953
@Override
947954
public <S> StringBuilder visit(SelectPipeOperator select, S context) {
955+
builder.append("|> ").append(select.getOperatorName());
956+
int i = 0;
957+
for (SelectItem<?> selectItem : select.getSelectItems()) {
958+
builder.append(i++ > 0 ? ", " : " ").append(selectItem);
959+
}
960+
builder.append("\n");
948961
return builder;
949962
}
950963

@@ -979,6 +992,6 @@ public <S> StringBuilder visit(WherePipeOperator where, S context) {
979992

980993
@Override
981994
public <S> StringBuilder visit(WindowPipeOperator window, S context) {
982-
return null;
995+
return visit((SelectPipeOperator) window, context);
983996
}
984997
}

0 commit comments

Comments
 (0)