Skip to content

Commit 3908529

Browse files
committed
[feat] Fixed onError for Oracle, added onEmptyClause, addedParsingType, formatJson for Body
1 parent d39df7f commit 3908529

File tree

3 files changed

+240
-61
lines changed

3 files changed

+240
-61
lines changed

src/main/java/net/sf/jsqlparser/expression/JsonTableFunction.java

Lines changed: 124 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ public enum JsonTableOnErrorType {
3636
ERROR, NULL, EMPTY
3737
}
3838

39+
public enum JsonTableOnEmptyType {
40+
ERROR, NULL, EMPTY
41+
}
42+
43+
public enum JsonTableParsingType {
44+
STRICT, LAX
45+
}
46+
3947
public static class JsonTablePassingClause extends ASTNodeAccessImpl implements Serializable {
4048
private Expression valueExpression;
4149
private String parameterName;
@@ -78,10 +86,28 @@ public String toString() {
7886
}
7987

8088
public static class JsonTableWrapperClause extends ASTNodeAccessImpl implements Serializable {
89+
private boolean beforePathExpression;
8190
private JsonFunction.JsonWrapperType wrapperType;
8291
private JsonFunction.JsonWrapperMode wrapperMode;
8392
private boolean array;
8493

94+
/**
95+
* Creates a wrapper clause. Depending on the dialect, this clause can come before or after the PATH expression.
96+
* <ul>
97+
* <li>Trino: after PATH</li>
98+
* <li>Oracle: before PATH</li>
99+
* </ul>
100+
*
101+
* @param beforePathExpression A flag to determine wether the clause is rendered before or after the PATH expression
102+
*/
103+
public JsonTableWrapperClause(boolean beforePathExpression) {
104+
this.beforePathExpression = beforePathExpression;
105+
}
106+
107+
public boolean isBeforePathExpression() {
108+
return beforePathExpression;
109+
}
110+
85111
public JsonFunction.JsonWrapperType getWrapperType() {
86112
return wrapperType;
87113
}
@@ -159,6 +185,15 @@ public String toString() {
159185

160186
public static class JsonTableOnErrorClause extends ASTNodeAccessImpl implements Serializable {
161187
private JsonTableOnErrorType type;
188+
private boolean beforeColumns = true;
189+
190+
public JsonTableOnErrorClause(boolean beforeColumns) {
191+
this.beforeColumns = beforeColumns;
192+
}
193+
194+
public boolean isBeforeColumns() {
195+
return beforeColumns;
196+
}
162197

163198
public JsonTableOnErrorType getType() {
164199
return type;
@@ -175,6 +210,48 @@ public String toString() {
175210
}
176211
}
177212

213+
public static class JsonTableOnEmptyClause extends ASTNodeAccessImpl implements Serializable {
214+
private JsonTableOnEmptyType type;
215+
216+
public JsonTableOnEmptyClause() {
217+
}
218+
219+
public JsonTableOnEmptyType getType() {
220+
return type;
221+
}
222+
223+
public JsonTableOnEmptyClause setType(JsonTableOnEmptyType type) {
224+
this.type = type;
225+
return this;
226+
}
227+
228+
@Override
229+
public String toString() {
230+
return type + " ON EMPTY";
231+
}
232+
}
233+
234+
public static class JsonTableParsingTypeClause extends ASTNodeAccessImpl implements Serializable {
235+
private JsonTableParsingType type;
236+
237+
public JsonTableParsingTypeClause() {
238+
}
239+
240+
public JsonTableParsingType getType() {
241+
return type;
242+
}
243+
244+
public JsonTableParsingTypeClause setType(JsonTableParsingType type) {
245+
this.type = type;
246+
return this;
247+
}
248+
249+
@Override
250+
public String toString() {
251+
return "TYPE(" + type + ")";
252+
}
253+
}
254+
178255
public static class JsonTablePlanTerm extends ASTNodeAccessImpl implements Serializable {
179256
private JsonTablePlanExpression nestedPlanExpression;
180257
private String name;
@@ -532,10 +609,13 @@ public String toString() {
532609
builder.append(scalarsType);
533610
builder.append(" SCALARS");
534611
}
612+
if (wrapperClause != null && wrapperClause.isBeforePathExpression()) {
613+
builder.append(" ").append(wrapperClause);
614+
}
535615
if (pathExpression != null) {
536616
builder.append(" PATH ").append(pathExpression);
537617
}
538-
if (wrapperClause != null) {
618+
if (wrapperClause != null && !wrapperClause.isBeforePathExpression()) {
539619
builder.append(" ").append(wrapperClause);
540620
}
541621
if (quotesClause != null) {
@@ -595,11 +675,23 @@ public String toString() {
595675
private JsonTableColumnsClause columnsClause;
596676
private JsonTablePlanClause planClause;
597677
private JsonTableOnErrorClause onErrorClause;
678+
private JsonTableParsingTypeClause parsingTypeClause;
679+
private JsonTableOnEmptyClause onEmptyClause;
680+
private boolean formatJson;
598681

599682
public JsonTableFunction() {
600683
setName("JSON_TABLE");
601684
}
602685

686+
public boolean getFormatJson() {
687+
return formatJson;
688+
}
689+
690+
public JsonTableFunction setFormatJson(boolean formatJson) {
691+
this.formatJson = formatJson;
692+
return this;
693+
}
694+
603695
public Expression getJsonInputExpression() {
604696
return jsonInputExpression;
605697
}
@@ -663,6 +755,24 @@ public JsonTableFunction setOnErrorClause(JsonTableOnErrorClause onErrorClause)
663755
return this;
664756
}
665757

758+
public JsonTableParsingTypeClause getParsingTypeClause() {
759+
return parsingTypeClause;
760+
}
761+
762+
public JsonTableFunction setParsingTypeClause(JsonTableParsingTypeClause parsingTypeClause) {
763+
this.parsingTypeClause = parsingTypeClause;
764+
return this;
765+
}
766+
767+
public JsonTableOnEmptyClause getOnEmptyClause() {
768+
return onEmptyClause;
769+
}
770+
771+
public JsonTableFunction setOnEmptyClause(JsonTableOnEmptyClause onEmptyClause) {
772+
this.onEmptyClause = onEmptyClause;
773+
return this;
774+
}
775+
666776
public List<Expression> getAllExpressions() {
667777
List<Expression> expressions = new ArrayList<>();
668778
if (jsonInputExpression != null) {
@@ -692,6 +802,9 @@ public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {
692802
public String toString() {
693803
StringBuilder builder = new StringBuilder("JSON_TABLE(");
694804
builder.append(jsonInputExpression);
805+
if (formatJson) {
806+
builder.append(" FORMAT JSON");
807+
}
695808
if (jsonPathExpression != null) {
696809
builder.append(", ").append(jsonPathExpression);
697810
}
@@ -709,11 +822,20 @@ public String toString() {
709822
first = false;
710823
}
711824
}
825+
if (onErrorClause != null && onErrorClause.isBeforeColumns()) {
826+
builder.append(" ").append(onErrorClause);
827+
}
828+
if (parsingTypeClause != null) {
829+
builder.append(" ").append(parsingTypeClause);
830+
}
831+
if (onEmptyClause != null) {
832+
builder.append(" ").append(onEmptyClause);
833+
}
712834
builder.append(" ").append(columnsClause);
713835
if (planClause != null) {
714836
builder.append(" ").append(planClause);
715837
}
716-
if (onErrorClause != null) {
838+
if (onErrorClause != null && !onErrorClause.isBeforeColumns()) {
717839
builder.append(" ").append(onErrorClause);
718840
}
719841
builder.append(")");

src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt

Lines changed: 58 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -926,6 +926,7 @@ String NonReservedWord() :
926926
| tk=<K_KILL:"KILL">
927927
| tk=<K_FN:"FN">
928928
| tk=<K_LAST: "LAST">
929+
| tk=<K_LAX: "LAX">
929930
| tk=<K_LEADING:"LEADING">
930931
| tk=<K_LESS:"LESS">
931932
| tk=<K_LEVEL:"LEVEL">
@@ -9419,9 +9420,9 @@ JsonFunction.JsonOnResponseBehavior JsonTableOnEmptyBehavior() : {
94199420
}
94209421
}
94219422

9422-
JsonTableFunction.JsonTableWrapperClause JsonTableWrapperClause() : {
9423+
JsonTableFunction.JsonTableWrapperClause JsonTableWrapperClause(boolean beforePathExpr) : {
94239424
JsonTableFunction.JsonTableWrapperClause wrapperClause =
9424-
new JsonTableFunction.JsonTableWrapperClause();
9425+
new JsonTableFunction.JsonTableWrapperClause(beforePathExpr);
94259426
Token token;
94269427
}
94279428
{
@@ -9508,7 +9509,7 @@ JsonTableFunction.JsonTableColumnDefinition JsonTableColumnDefinition() : {
95089509
columnDefinition = valueColumnDefinition;
95099510
}
95109511
(
9511-
<K_FOR> JsonKeyword("ORDINALITY") { valueColumnDefinition.setForOrdinality(true); }
9512+
<K_FOR> <K_ORDINALITY> { valueColumnDefinition.setForOrdinality(true); }
95129513
|
95139514
[ dataType = ColDataType() { valueColumnDefinition.setDataType(dataType); } ]
95149515
[
@@ -9523,8 +9524,11 @@ JsonTableFunction.JsonTableColumnDefinition JsonTableColumnDefinition() : {
95239524
)
95249525
JsonKeyword("SCALARS")
95259526
]
9527+
// In Oracle, the wrapper clause comes before the PATH expression
9528+
[ wrapperClause = JsonTableWrapperClause(true) { valueColumnDefinition.setWrapperClause(wrapperClause); } ]
95269529
[ <K_PATH> expression = Expression() { valueColumnDefinition.setPathExpression(expression); } ]
9527-
[ wrapperClause = JsonTableWrapperClause() { valueColumnDefinition.setWrapperClause(wrapperClause); } ]
9530+
// In Truno the wrapper clause comes after the PATH expression
9531+
[ wrapperClause = JsonTableWrapperClause(false) { valueColumnDefinition.setWrapperClause(wrapperClause); } ]
95289532
[
95299533
LOOKAHEAD({
95309534
getToken(1).kind == K_KEEP
@@ -9657,16 +9661,18 @@ JsonTableFunction.JsonTablePlanClause JsonTablePlanClause() : {
96579661
}
96589662
}
96599663

9660-
JsonTableFunction.JsonTableOnErrorClause JsonTableOnErrorClause() : {
9664+
JsonTableFunction.JsonTableOnErrorClause JsonTableOnErrorClause(boolean beforeColumns) : {
96619665
JsonTableFunction.JsonTableOnErrorClause onErrorClause =
9662-
new JsonTableFunction.JsonTableOnErrorClause();
9666+
new JsonTableFunction.JsonTableOnErrorClause(beforeColumns);
96639667
Token token;
96649668
}
96659669
{
96669670
(
96679671
<K_ERROR> { onErrorClause.setType(JsonTableFunction.JsonTableOnErrorType.ERROR); }
96689672
|
96699673
<K_EMPTY> { onErrorClause.setType(JsonTableFunction.JsonTableOnErrorType.EMPTY); }
9674+
|
9675+
<K_NULL> { onErrorClause.setType(JsonTableFunction.JsonTableOnErrorType.NULL); }
96709676
)
96719677
<K_ON> <K_ERROR>
96729678
{
@@ -9676,6 +9682,44 @@ JsonTableFunction.JsonTableOnErrorClause JsonTableOnErrorClause() : {
96769682
}
96779683
}
96789684

9685+
JsonTableFunction.JsonTableOnEmptyClause JsonTableOnEmptyClause() : {
9686+
JsonTableFunction.JsonTableOnEmptyClause onEmptyClause =
9687+
new JsonTableFunction.JsonTableOnEmptyClause();
9688+
Token token;
9689+
}
9690+
{
9691+
(
9692+
<K_ERROR> { onEmptyClause.setType(JsonTableFunction.JsonTableOnEmptyType.ERROR); }
9693+
|
9694+
<K_EMPTY> { onEmptyClause.setType(JsonTableFunction.JsonTableOnEmptyType.EMPTY); }
9695+
|
9696+
<K_NULL> { onEmptyClause.setType(JsonTableFunction.JsonTableOnEmptyType.NULL); }
9697+
)
9698+
<K_ON> <K_EMPTY>
9699+
{
9700+
if (onEmptyClause.getType() != null) {
9701+
return onEmptyClause;
9702+
}
9703+
}
9704+
}
9705+
9706+
JsonTableFunction.JsonTableParsingTypeClause JsonTableParsingTypeClause() : {
9707+
JsonTableFunction.JsonTableParsingTypeClause parsingType = new JsonTableFunction.JsonTableParsingTypeClause();
9708+
}
9709+
{
9710+
<K_TYPE>
9711+
<OPENING_BRACKET>
9712+
(
9713+
<K_STRICT> { parsingType.setType(JsonTableFunction.JsonTableParsingType.STRICT); }
9714+
|
9715+
<K_LAX> { parsingType.setType(JsonTableFunction.JsonTableParsingType.LAX); }
9716+
)
9717+
<CLOSING_BRACKET>
9718+
{
9719+
return parsingType;
9720+
}
9721+
}
9722+
96799723
JsonTableFunction JsonTableBody() : {
96809724
JsonTableFunction function = new JsonTableFunction();
96819725
Expression jsonInput;
@@ -9685,12 +9729,15 @@ JsonTableFunction JsonTableBody() : {
96859729
JsonTableFunction.JsonTableColumnsClause columnsClause;
96869730
JsonTableFunction.JsonTablePlanClause planClause = null;
96879731
JsonTableFunction.JsonTableOnErrorClause onErrorClause = null;
9732+
JsonTableFunction.JsonTableParsingTypeClause parsingTypeClause = null;
9733+
JsonTableFunction.JsonTableOnEmptyClause onEmptyClause = null;
96889734
}
96899735
{
96909736
"("
96919737
jsonInput = Expression() {
96929738
function.setJsonInputExpression(jsonInput);
96939739
}
9740+
[ <K_FORMAT> <K_JSON> { function.setFormatJson(true); } ]
96949741
[
96959742
","
96969743
jsonPath = Expression() {
@@ -9708,9 +9755,12 @@ JsonTableFunction JsonTableBody() : {
97089755
passingClause = JsonTablePassingClause() { function.addPassingClause(passingClause); }
97099756
)*
97109757
]
9758+
[ LOOKAHEAD(3) onErrorClause = JsonTableOnErrorClause(true) { function.setOnErrorClause(onErrorClause); } ]
9759+
[ parsingTypeClause = JsonTableParsingTypeClause() { function.setParsingTypeClause(parsingTypeClause); } ]
9760+
[ onEmptyClause = JsonTableOnEmptyClause() { function.setOnEmptyClause(onEmptyClause); } ]
97119761
columnsClause = JsonTableColumnsClause() { function.setColumnsClause(columnsClause); }
97129762
[ planClause = JsonTablePlanClause() { function.setPlanClause(planClause); } ]
9713-
[ onErrorClause = JsonTableOnErrorClause() { function.setOnErrorClause(onErrorClause); } ]
9763+
[ onErrorClause = JsonTableOnErrorClause(false) { function.setOnErrorClause(onErrorClause); } ]
97149764
")"
97159765
{
97169766
return function;
@@ -10211,6 +10261,7 @@ ColDataType DataType():
1021110261
]
1021210262
[
1021310263
LOOKAHEAD(2) "(" ( tk=<S_LONG> { precision = Integer.valueOf(tk.image); } | tk=<K_MAX> { precision = Integer.MAX_VALUE; } )
10264+
[ <K_BYTE> | <K_CHAR> ]
1021410265
[ "," tk = <S_LONG> { scale = Integer.valueOf(tk.image); } ]
1021510266
")"
1021610267
]

0 commit comments

Comments
 (0)