Skip to content

Commit 1157f74

Browse files
committed
feat: support OPTION hints after MERGE and INSERT ... VALUES, and the OPTIMIZE FOR (@var UNKNOWN) parameter form
Completes the follow-ups declared in the limitations of #2472: - attach the OPTION clause to MERGE statements, which rejected it before, mirroring the existing UPDATE and DELETE attach points - render the OPTION clause when deparsing INSERT ... VALUES: it was parsed into the Values select but silently dropped from the output - model the OPTIMIZE FOR (@variable_name UNKNOWN) parameter form as a new UnknownVariable expression (the @var = literal form already worked via VariableAssignment) Signed-off-by: 付典 <fudianchn@gmail.com>
1 parent 7013909 commit 1157f74

13 files changed

Lines changed: 203 additions & 2 deletions

File tree

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,12 @@ default void visit(UserVariable userVariable) {
531531
this.visit(userVariable, null);
532532
}
533533

534+
<S> T visit(UnknownVariable unknownVariable, S context);
535+
536+
default void visit(UnknownVariable unknownVariable) {
537+
this.visit(unknownVariable, null);
538+
}
539+
534540
<S> T visit(NumericBind numericBind, S context);
535541

536542
default void visit(NumericBind numericBind) {

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,11 @@ public <S> T visit(UserVariable userVariable, S context) {
536536
return applyExpression(userVariable, context);
537537
}
538538

539+
@Override
540+
public <S> T visit(UnknownVariable unknownVariable, S context) {
541+
return applyExpression(unknownVariable, context);
542+
}
543+
539544
@Override
540545
public <S> T visit(NumericBind numericBind, S context) {
541546
return applyExpression(numericBind, context);
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2019 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0.
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.expression;
11+
12+
import net.sf.jsqlparser.parser.ASTNodeAccessImpl;
13+
14+
/**
15+
* A user variable followed by the bare {@code UNKNOWN} keyword, as used in the SQL Server (T-SQL)
16+
* {@code OPTIMIZE FOR (@variable_name UNKNOWN)} query hint parameter form, see
17+
* <a href="https://learn.microsoft.com/en-us/sql/t-sql/queries/hints-transact-sql-query">Hints
18+
* (Transact-SQL) - Query Hints</a>.
19+
*/
20+
public class UnknownVariable extends ASTNodeAccessImpl implements Expression {
21+
22+
private UserVariable variable;
23+
24+
public UnknownVariable() {
25+
// empty constructor
26+
}
27+
28+
public UnknownVariable(UserVariable variable) {
29+
this.variable = variable;
30+
}
31+
32+
public UserVariable getVariable() {
33+
return variable;
34+
}
35+
36+
public void setVariable(UserVariable variable) {
37+
this.variable = variable;
38+
}
39+
40+
public UnknownVariable withVariable(UserVariable variable) {
41+
this.setVariable(variable);
42+
return this;
43+
}
44+
45+
@Override
46+
public <T, S> T accept(ExpressionVisitor<T> expressionVisitor, S context) {
47+
return expressionVisitor.visit(this, context);
48+
}
49+
50+
@Override
51+
public String toString() {
52+
return variable.toString() + " UNKNOWN";
53+
}
54+
}

src/main/java/net/sf/jsqlparser/statement/merge/Merge.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import net.sf.jsqlparser.statement.Statement;
1818
import net.sf.jsqlparser.statement.StatementVisitor;
1919
import net.sf.jsqlparser.statement.select.FromItem;
20+
import net.sf.jsqlparser.statement.select.OptionClause;
2021
import net.sf.jsqlparser.statement.select.ParenthesedSelect;
2122
import net.sf.jsqlparser.statement.select.WithItem;
2223

@@ -41,6 +42,7 @@ public class Merge implements Statement {
4142
private List<MergeOperation> operations;
4243

4344
private OutputClause outputClause;
45+
private OptionClause option;
4446

4547
private void deriveOperationsFromStandardClauses() {
4648
List<MergeOperation> operations = new ArrayList<>();
@@ -214,6 +216,19 @@ public Merge setOutputClause(OutputClause outputClause) {
214216
return this;
215217
}
216218

219+
public OptionClause getOption() {
220+
return option;
221+
}
222+
223+
public Merge setOption(OptionClause option) {
224+
this.option = option;
225+
return this;
226+
}
227+
228+
public Merge withOption(OptionClause option) {
229+
return setOption(option);
230+
}
231+
217232
@Override
218233
@SuppressWarnings({"PMD.CyclomaticComplexity", "PMD.NPathComplexity"})
219234
public String toString() {
@@ -248,6 +263,10 @@ public String toString() {
248263
b.append(outputClause);
249264
}
250265

266+
if (option != null) {
267+
b.append(option);
268+
}
269+
251270
return b.toString();
252271
}
253272

src/main/java/net/sf/jsqlparser/util/TablesNamesFinder.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,12 @@ public <S> Void visit(UserVariable userVariable, S context) {
11371137
return null;
11381138
}
11391139

1140+
@Override
1141+
public <S> Void visit(UnknownVariable unknownVariable, S context) {
1142+
1143+
return null;
1144+
}
1145+
11401146
@Override
11411147
public <S> Void visit(NumericBind numericBind, S context) {
11421148

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@
7474
import net.sf.jsqlparser.expression.TimezoneExpression;
7575
import net.sf.jsqlparser.expression.TranscodingFunction;
7676
import net.sf.jsqlparser.expression.TrimFunction;
77+
import net.sf.jsqlparser.expression.UnknownVariable;
7778
import net.sf.jsqlparser.expression.UserVariable;
7879
import net.sf.jsqlparser.expression.VariableAssignment;
7980
import net.sf.jsqlparser.expression.WhenClause;
@@ -1417,6 +1418,12 @@ public <S> StringBuilder visit(UserVariable var, S context) {
14171418
return builder;
14181419
}
14191420

1421+
@Override
1422+
public <S> StringBuilder visit(UnknownVariable var, S context) {
1423+
builder.append(var.toString());
1424+
return builder;
1425+
}
1426+
14201427
@Override
14211428
public <S> StringBuilder visit(NumericBind bind, S context) {
14221429
builder.append(bind.toString());

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ public void deParse(Merge merge) {
6363
if (merge.getOutputClause() != null) {
6464
merge.getOutputClause().appendTo(builder);
6565
}
66+
67+
if (merge.getOption() != null) {
68+
builder.append(merge.getOption());
69+
}
6670
}
6771

6872
@Override

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ public ValuesStatementDeParser(ExpressionVisitor<StringBuilder> expressionVisito
2626
public void deParse(Values values) {
2727
builder.append("VALUES ");
2828
values.getExpressions().accept(expressionVisitor, null);
29+
if (values.getOption() != null) {
30+
builder.append(values.getOption());
31+
}
2932
if (values.getAlias() != null) {
3033
builder.append(" ").append(values.getAlias());
3134
}

src/main/java/net/sf/jsqlparser/util/validation/validator/ExpressionValidator.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
import net.sf.jsqlparser.expression.TimezoneExpression;
6969
import net.sf.jsqlparser.expression.TranscodingFunction;
7070
import net.sf.jsqlparser.expression.TrimFunction;
71+
import net.sf.jsqlparser.expression.UnknownVariable;
7172
import net.sf.jsqlparser.expression.UserVariable;
7273
import net.sf.jsqlparser.expression.VariableAssignment;
7374
import net.sf.jsqlparser.expression.WhenClause;
@@ -819,6 +820,12 @@ public <S> Void visit(UserVariable var, S context) {
819820
return null;
820821
}
821822

823+
@Override
824+
public <S> Void visit(UnknownVariable var, S context) {
825+
// nothing to validate
826+
return null;
827+
}
828+
822829
@Override
823830
public <S> Void visit(NumericBind bind, S context) {
824831
// nothing to validate

src/main/java/net/sf/jsqlparser/util/validation/validator/MergeValidator.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
import net.sf.jsqlparser.parser.feature.Feature;
1313
import net.sf.jsqlparser.statement.merge.*;
14+
import net.sf.jsqlparser.statement.select.OptionHint;
1415
import net.sf.jsqlparser.statement.update.UpdateSet;
1516
import net.sf.jsqlparser.util.validation.ValidationCapability;
1617

@@ -31,6 +32,14 @@ public void validate(Merge merge) {
3132
merge.getOperations().forEach(operation -> operation.accept(this, null));
3233
}
3334
validateOptionalFromItems(merge.getFromItem());
35+
if (merge.getOption() != null) {
36+
for (OptionHint optionHint : merge.getOption().getOptionHints()) {
37+
validateOptionalExpression(optionHint.getValue());
38+
if (optionHint.getParameters() != null) {
39+
optionHint.getParameters().forEach(this::validateOptionalExpression);
40+
}
41+
}
42+
}
3443
}
3544

3645
@Override

0 commit comments

Comments
 (0)