Skip to content

Commit c13f7ee

Browse files
committed
Merge upstream/master into refactor/ddl-visitors-20261001
Signed-off-by: minleejae <mmj9808@gmail.com>
2 parents 7f8bb7f + 40ed289 commit c13f7ee

69 files changed

Lines changed: 4761 additions & 554 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎src/main/java/net/sf/jsqlparser/expression/CastExpression.java‎

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,17 @@
99
*/
1010
package net.sf.jsqlparser.expression;
1111

12-
import java.util.Locale;
13-
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
14-
import net.sf.jsqlparser.statement.create.table.ColDataType;
15-
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
16-
import net.sf.jsqlparser.statement.select.Select;
17-
1812
import java.util.ArrayList;
13+
import java.util.Locale;
1914
import java.util.Set;
2015
import java.util.logging.Level;
2116
import java.util.logging.Logger;
2217
import java.util.regex.Matcher;
2318
import java.util.regex.Pattern;
19+
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
20+
import net.sf.jsqlparser.statement.create.table.ColDataType;
21+
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
22+
import net.sf.jsqlparser.statement.select.Select;
2423

2524
public class CastExpression extends ASTNodeAccessImpl implements Expression {
2625
private final static Pattern PATTERN =
@@ -204,7 +203,7 @@ public String toString() {
204203
if (isImplicitCast) {
205204
return colDataType + " " + leftExpression;
206205
} else if (keyword != null && !keyword.isEmpty()) {
207-
return columnDefinitions.size() > 1
206+
return !columnDefinitions.isEmpty()
208207
? keyword + "(" + leftExpression + " AS ROW("
209208
+ Select.getStringList(columnDefinitions) + ")" + formatStr + ")"
210209
: keyword + "(" + leftExpression + " AS " + colDataType.toString() + formatStr

‎src/main/java/net/sf/jsqlparser/expression/ColumnsTransformer.java‎

Lines changed: 46 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ public enum ColumnsTransformerType {
3131
private ColumnsTransformerType type;
3232
private Expression applyExpression;
3333
private ParenthesedExpressionList<Column> exceptColumns;
34+
private StringValue exceptPattern;
3435
private List<SelectItem<?>> replaceItems;
36+
private boolean strict;
3537

3638
public ColumnsTransformer(ColumnsTransformerType type) {
3739
this.type = type;
@@ -61,6 +63,39 @@ public ParenthesedExpressionList<Column> getExceptColumns() {
6163

6264
public ColumnsTransformer setExceptColumns(ParenthesedExpressionList<Column> exceptColumns) {
6365
this.exceptColumns = exceptColumns;
66+
if (exceptColumns != null) {
67+
this.exceptPattern = null;
68+
}
69+
return this;
70+
}
71+
72+
/**
73+
* The re2 pattern of the ClickHouse {@code EXCEPT 'pattern'} form, mutually exclusive with
74+
* {@link #getExceptColumns()}.
75+
*/
76+
public StringValue getExceptPattern() {
77+
return exceptPattern;
78+
}
79+
80+
public ColumnsTransformer setExceptPattern(StringValue exceptPattern) {
81+
this.exceptPattern = exceptPattern;
82+
if (exceptPattern != null) {
83+
this.exceptColumns = null;
84+
}
85+
return this;
86+
}
87+
88+
/**
89+
* The {@code STRICT} modifier of ClickHouse {@code EXCEPT}/{@code REPLACE} transformers: named
90+
* columns must exist, otherwise the database rejects the query. Meaningless for {@code APPLY}
91+
* and {@code EXCLUDE}.
92+
*/
93+
public boolean isStrict() {
94+
return strict;
95+
}
96+
97+
public ColumnsTransformer setStrict(boolean strict) {
98+
this.strict = strict;
6499
return this;
65100
}
66101

@@ -81,6 +116,13 @@ void collectExpressions(List<Expression> expressions) {
81116
}
82117
break;
83118
case EXCEPT:
119+
if (exceptPattern != null) {
120+
expressions.add(exceptPattern);
121+
}
122+
if (exceptColumns != null) {
123+
expressions.addAll(exceptColumns);
124+
}
125+
break;
84126
case EXCLUDE:
85127
if (exceptColumns != null) {
86128
expressions.addAll(exceptColumns);
@@ -104,13 +146,15 @@ public StringBuilder appendTo(StringBuilder builder) {
104146
builder.append("APPLY(").append(applyExpression).append(")");
105147
break;
106148
case EXCEPT:
107-
builder.append("EXCEPT ").append(exceptColumns);
149+
builder.append("EXCEPT").append(strict ? " STRICT" : "").append(" ")
150+
.append(exceptPattern != null ? exceptPattern : exceptColumns);
108151
break;
109152
case EXCLUDE:
110153
builder.append("EXCLUDE ").append(exceptColumns);
111154
break;
112155
case REPLACE:
113-
builder.append("REPLACE(").append(Select.getStringList(replaceItems)).append(")");
156+
builder.append("REPLACE").append(strict ? " STRICT" : "").append("(")
157+
.append(Select.getStringList(replaceItems)).append(")");
114158
break;
115159
default:
116160
throw new IllegalStateException("Unhandled ColumnsTransformerType: " + type);

‎src/main/java/net/sf/jsqlparser/expression/ExpressionVisitorAdapter.java‎

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,17 @@ public <S> T visit(Function function, S context) {
113113
if (function.getParameters() != null) {
114114
subExpressions.addAll(function.getParameters());
115115
}
116+
if (function.getNamedParameters() != null) {
117+
subExpressions.addAll(function.getNamedParameters());
118+
}
116119
if (function.getChainedParameters() != null) {
117120
subExpressions.addAll(function.getChainedParameters());
118121
}
122+
// an attribute name is not a column reference, only an attribute expression is visited
123+
if (function.getAttribute() instanceof Expression
124+
&& function.getAttribute() != function.getAttributeColumn()) {
125+
subExpressions.add((Expression) function.getAttribute());
126+
}
119127
if (function.getKeep() != null) {
120128
subExpressions.add(function.getKeep());
121129
}
@@ -284,7 +292,8 @@ public <S> T visit(IsUnknownExpression isUnknownExpression, S context) {
284292

285293
@Override
286294
public <S> T visit(LikeExpression likeExpression, S context) {
287-
return visitBinaryExpression(likeExpression, context);
295+
return visitExpressions(likeExpression, context, likeExpression.getLeftExpression(),
296+
likeExpression.getRightExpression(), likeExpression.getEscape());
288297
}
289298

290299
@Override
@@ -319,7 +328,11 @@ public <S> T visit(ContainedBy containedBy, S context) {
319328

320329
@Override
321330
public <S> T visit(Column column, S context) {
322-
return applyExpression(column, context);
331+
T result = applyExpression(column, context);
332+
if (column.getArrayConstructor() != null) {
333+
column.getArrayConstructor().accept(this, context);
334+
}
335+
return result;
323336
}
324337

325338
@Override
@@ -358,12 +371,14 @@ public <S> T visit(ExistsExpression existsExpression, S context) {
358371

359372
@Override
360373
public <S> T visit(MemberOfExpression memberOfExpression, S context) {
361-
return memberOfExpression.getRightExpression().accept(this, context);
374+
return visitExpressions(memberOfExpression, context,
375+
memberOfExpression.getLeftExpression(), memberOfExpression.getRightExpression());
362376
}
363377

364378
@Override
365379
public <S> T visit(AnyComparisonExpression anyComparisonExpression, S context) {
366-
return applyExpression(anyComparisonExpression, context);
380+
return visitExpressions(anyComparisonExpression, context,
381+
anyComparisonExpression.getSelect());
367382
}
368383

369384
@Override
@@ -535,7 +550,10 @@ protected <S> T visitBinaryExpression(BinaryExpression binaryExpression, S conte
535550

536551
@Override
537552
public <S> T visit(JsonExpression jsonExpr, S context) {
538-
return jsonExpr.getExpression().accept(this, context);
553+
ArrayList<Expression> subExpressions = new ArrayList<>();
554+
subExpressions.add(jsonExpr.getExpression());
555+
subExpressions.addAll(jsonExpr.getIdents());
556+
return visitExpressions(jsonExpr, context, subExpressions);
539557
}
540558

541559
@Override
@@ -728,13 +746,28 @@ public <S> T visit(XMLSerializeExpr xmlSerializeExpr, S context) {
728746

729747
@Override
730748
public <S> T visit(TimezoneExpression timezoneExpression, S context) {
731-
return timezoneExpression.getLeftExpression().accept(this, context);
749+
ArrayList<Expression> subExpressions = new ArrayList<>();
750+
subExpressions.add(timezoneExpression.getLeftExpression());
751+
subExpressions.addAll(timezoneExpression.getTimezoneExpressions());
752+
return visitExpressions(timezoneExpression, context, subExpressions);
732753
}
733754

734755
@Override
735756
public <S> T visit(JsonAggregateFunction jsonAggregateFunction, S context) {
736-
return visitExpressions(jsonAggregateFunction, context,
737-
jsonAggregateFunction.getExpression(), jsonAggregateFunction.getFilterExpression());
757+
ArrayList<Expression> subExpressions = new ArrayList<>();
758+
subExpressions.add(jsonAggregateFunction.getExpression());
759+
if (jsonAggregateFunction.getKey() instanceof Expression) {
760+
subExpressions.add((Expression) jsonAggregateFunction.getKey());
761+
}
762+
if (jsonAggregateFunction.getValue() instanceof Expression) {
763+
subExpressions.add((Expression) jsonAggregateFunction.getValue());
764+
}
765+
addOrderByExpressions(subExpressions,
766+
jsonAggregateFunction.getExpressionOrderByElements());
767+
subExpressions.add(jsonAggregateFunction.getFilterExpression());
768+
subExpressions.addAll(jsonAggregateFunction.getPartitionExpressionList());
769+
addOrderByExpressions(subExpressions, jsonAggregateFunction.getOrderByElements());
770+
return visitExpressions(jsonAggregateFunction, context, subExpressions);
738771
}
739772

740773
@Override
@@ -834,7 +867,8 @@ public <S> T visit(TranscodingFunction transcodingFunction, S context) {
834867

835868
@Override
836869
public <S> T visit(TrimFunction trimFunction, S context) {
837-
return trimFunction.getExpression().accept(this, context);
870+
return visitExpressions(trimFunction, context, trimFunction.getExpression(),
871+
trimFunction.getFromExpression());
838872
}
839873

840874
@Override

‎src/main/java/net/sf/jsqlparser/expression/SpannerInterleaveIn.java‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@
99
*/
1010
package net.sf.jsqlparser.expression;
1111

12-
import java.util.Locale;
13-
import net.sf.jsqlparser.schema.Table;
14-
12+
import java.io.Serializable;
1513
import java.util.Collections;
1614
import java.util.List;
15+
import java.util.Locale;
16+
import net.sf.jsqlparser.schema.Table;
1717

18-
public class SpannerInterleaveIn {
18+
public class SpannerInterleaveIn implements Serializable {
1919

2020
private Table table;
2121
private OnDelete onDelete;

‎src/main/java/net/sf/jsqlparser/expression/StringValue.java‎

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -123,14 +123,14 @@ public String getNotExcapedValue() {
123123
if (quoteStr != null && quoteStr.startsWith("$")) {
124124
return value;
125125
}
126-
StringBuilder buffer = new StringBuilder(value);
127-
int index = 0;
128-
int deletesNum = 0;
129-
while ((index = value.indexOf("''", index)) != -1) {
130-
buffer.deleteCharAt(index - deletesNum);
131-
index += 2;
132-
deletesNum++;
126+
StringBuilder buffer = new StringBuilder(value.length());
127+
int from = 0;
128+
int index;
129+
while ((index = value.indexOf("''", from)) != -1) {
130+
buffer.append(value, from, index + 1);
131+
from = index + 2;
133132
}
133+
buffer.append(value, from, value.length());
134134
return buffer.toString();
135135
}
136136

‎src/main/java/net/sf/jsqlparser/schema/Column.java‎

Lines changed: 49 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,14 @@ public Column(List<String> nameParts) {
4949
}
5050

5151
public Column(List<String> nameParts, List<String> delimiters) {
52-
this(
53-
nameParts.size() > 1 ? new Table(nameParts.subList(0, nameParts.size() - 1),
54-
delimiters.subList(0, delimiters.size() - 1)) : null,
55-
nameParts.get(nameParts.size() - 1));
52+
if (nameParts.size() > 1) {
53+
setTable(new Table(nameParts.subList(0, nameParts.size() - 1),
54+
delimiters.subList(0, delimiters.size() - 1)));
55+
// The final component is already separated from the table name.
56+
setName(nameParts.get(nameParts.size() - 1), false);
57+
} else {
58+
setColumnName(nameParts.get(0));
59+
}
5660
setTableDelimiter(delimiters.isEmpty() ? "." : delimiters.get(delimiters.size() - 1));
5761
}
5862

@@ -149,36 +153,25 @@ public void setColumnName(String name) {
149153
}
150154

151155
public void setName(String name, boolean splitNamesOnDelimiter) {
152-
if (MultiPartName.isQuoted(name) && name.contains(".") && splitNamesOnDelimiter) {
153-
String[] parts = MultiPartName.unquote(name).split("\\.");
154-
switch (parts.length) {
155-
case 3:
156-
this.table = new Table("\"" + parts[0] + "\".\"" + parts[1] + "\"");
157-
this.columnName = "\"" + parts[2] + "\"";
158-
break;
159-
case 2:
160-
this.table = new Table("\"" + parts[0] + "\"");
161-
this.columnName = "\"" + parts[1] + "\"";
162-
break;
163-
case 1:
164-
this.columnName = "\"" + parts[0] + "\"";
165-
break;
166-
default:
167-
throw new RuntimeException("Invalid column name: " + name);
156+
if (name.contains(".") && splitNamesOnDelimiter) {
157+
List<String> parts = splitName(name);
158+
if (parts.size() == 1 && MultiPartName.isQuoted(name)) {
159+
parts.clear();
160+
for (String identifier : MultiPartName.unquote(name).split("\\.")) {
161+
parts.add("\"" + identifier + "\"");
162+
}
168163
}
169-
} else if (name.contains(".") && splitNamesOnDelimiter) {
170-
String[] parts = MultiPartName.unquote(name).split("\\.");
171-
switch (parts.length) {
164+
switch (parts.size()) {
172165
case 3:
173-
this.table = new Table(parts[0] + "." + parts[1]);
174-
this.columnName = parts[2];
166+
this.table = new Table(parts.subList(0, 2));
167+
this.columnName = parts.get(2);
175168
break;
176169
case 2:
177-
this.table = new Table(parts[0]);
178-
this.columnName = parts[1];
170+
this.table = new Table(parts.get(0), false);
171+
this.columnName = parts.get(1);
179172
break;
180173
case 1:
181-
this.columnName = parts[0];
174+
this.columnName = parts.get(0);
182175
break;
183176
default:
184177
throw new RuntimeException("Invalid column name: " + name);
@@ -188,6 +181,34 @@ public void setName(String name, boolean splitNamesOnDelimiter) {
188181
}
189182
}
190183

184+
private static List<String> splitName(String name) {
185+
List<String> parts = new ArrayList<>();
186+
int start = 0;
187+
char quote = 0;
188+
for (int i = 0; i < name.length(); i++) {
189+
char ch = name.charAt(i);
190+
if (quote != 0) {
191+
if (ch == quote) {
192+
if (i + 1 < name.length() && name.charAt(i + 1) == quote) {
193+
i++;
194+
} else {
195+
quote = 0;
196+
}
197+
}
198+
} else if (ch == '"' || ch == '`' || ch == '[') {
199+
quote = ch == '[' ? ']' : ch;
200+
} else if (ch == '.') {
201+
parts.add(name.substring(start, i));
202+
start = i + 1;
203+
}
204+
}
205+
parts.add(name.substring(start));
206+
while (!parts.isEmpty() && parts.get(parts.size() - 1).isEmpty()) {
207+
parts.remove(parts.size() - 1);
208+
}
209+
return parts;
210+
}
211+
191212
public String getTableDelimiter() {
192213
return tableDelimiter;
193214
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2026 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement;
11+
12+
/**
13+
* An explicit CASCADE or RESTRICT clause. A null field leaves the clause omitted and preserves the
14+
* database's default behavior for that statement.
15+
*/
16+
public enum CascadeBehavior {
17+
CASCADE, RESTRICT
18+
}

0 commit comments

Comments
 (0)