Skip to content

Commit 9be3636

Browse files
committed
Merge upstream/master into refactor/constraint-inspection-20261002
Preserve the merged canonical index options, foreign-key state, and shared ALTER rendering alongside the separate constraint AST. Migrate new upstream tests to the constraint API and verify stale-field classification with operation-aware column rendering. Signed-off-by: minleejae <mmj9808@gmail.com>
2 parents 00a8400 + 40ed289 commit 9be3636

65 files changed

Lines changed: 4444 additions & 426 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

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)