Skip to content

Commit 468aefa

Browse files
zhangconanzhangkenan
andauthored
support opengauss "on duplicate key update nothing" grammar (#2303)
* support opengauss "on duplicate key nothing" grammar * use import single classes instead of wildcard imports in Insert class. * use import single classes instead of wildcard imports in Insert class. * use './gradlew :spotlessApply' adjust code format. --------- Co-authored-by: zhangkenan <[email protected]>
1 parent 90cc63f commit 468aefa

File tree

10 files changed

+226
-17
lines changed

10 files changed

+226
-17
lines changed

src/main/java/net/sf/jsqlparser/statement/insert/ConflictActionType.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
package net.sf.jsqlparser.statement.insert;
1111

1212
public enum ConflictActionType {
13-
DO_NOTHING, DO_UPDATE;
13+
NOTHING, DO_NOTHING, DO_UPDATE;
1414

1515
public static ConflictActionType from(String type) {
1616
return Enum.valueOf(ConflictActionType.class, type.toUpperCase());

src/main/java/net/sf/jsqlparser/statement/insert/Insert.java

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,12 @@ public class Insert implements Statement {
5252
private OutputClause outputClause;
5353
private InsertConflictTarget conflictTarget;
5454
private InsertConflictAction conflictAction;
55+
private InsertDuplicateAction duplicateAction;
5556

5657
public List<UpdateSet> getDuplicateUpdateSets() {
58+
if (duplicateAction != null) {
59+
return duplicateAction.getUpdateSets();
60+
}
5761
return duplicateUpdateSets;
5862
}
5963

@@ -62,7 +66,13 @@ public List<UpdateSet> getSetUpdateSets() {
6266
}
6367

6468
public Insert withDuplicateUpdateSets(List<UpdateSet> duplicateUpdateSets) {
65-
this.duplicateUpdateSets = duplicateUpdateSets;
69+
if (duplicateAction != null) {
70+
duplicateAction.setConflictActionType(ConflictActionType.DO_UPDATE);
71+
duplicateAction.setUpdateSets(duplicateUpdateSets);
72+
} else {
73+
duplicateAction = new InsertDuplicateAction(ConflictActionType.DO_UPDATE);
74+
duplicateAction.setUpdateSets(duplicateUpdateSets);
75+
}
6676
return this;
6777
}
6878

@@ -157,7 +167,8 @@ public boolean isUseSelectBrackets() {
157167

158168
@Deprecated
159169
public boolean isUseDuplicate() {
160-
return duplicateUpdateSets != null && !duplicateUpdateSets.isEmpty();
170+
return duplicateAction != null && duplicateAction.getUpdateSets() != null
171+
&& !duplicateAction.getUpdateSets().isEmpty();
161172
}
162173

163174
public InsertModifierPriority getModifierPriority() {
@@ -331,9 +342,9 @@ public String toString() {
331342
sql = UpdateSet.appendUpdateSetsTo(sql, setUpdateSets);
332343
}
333344

334-
if (duplicateUpdateSets != null && !duplicateUpdateSets.isEmpty()) {
345+
if (duplicateAction != null) {
335346
sql.append(" ON DUPLICATE KEY UPDATE ");
336-
sql = UpdateSet.appendUpdateSetsTo(sql, duplicateUpdateSets);
347+
duplicateAction.appendTo(sql);
337348
}
338349

339350
if (conflictAction != null) {
@@ -392,4 +403,12 @@ public Insert addColumns(Collection<Column> columns) {
392403
collection.addAll(columns);
393404
return this.withColumns(collection);
394405
}
406+
407+
public InsertDuplicateAction getDuplicateAction() {
408+
return duplicateAction;
409+
}
410+
411+
public void setDuplicateAction(InsertDuplicateAction duplicateAction) {
412+
this.duplicateAction = duplicateAction;
413+
}
395414
}
Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
/*-
2+
* #%L
3+
* JSQLParser library
4+
* %%
5+
* Copyright (C) 2004 - 2025 JSQLParser
6+
* %%
7+
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
8+
* #L%
9+
*/
10+
package net.sf.jsqlparser.statement.insert;
11+
12+
import net.sf.jsqlparser.expression.Expression;
13+
import net.sf.jsqlparser.schema.Column;
14+
import net.sf.jsqlparser.statement.update.UpdateSet;
15+
16+
import java.io.Serializable;
17+
import java.util.ArrayList;
18+
import java.util.Collection;
19+
import java.util.List;
20+
import java.util.Objects;
21+
22+
/**
23+
* on duplicate key is one of:
24+
*
25+
* ON DUPLICATE KEY UPDATE NOTHING ON DUPLICATE KEY UPDATE { column_name = { expression | DEFAULT }
26+
* | ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) | ( column_name [, ...]
27+
* ) = ( sub-SELECT ) } [, ...] [ WHERE condition ]
28+
*
29+
* @author zhangconan
30+
*/
31+
public class InsertDuplicateAction implements Serializable {
32+
33+
ConflictActionType conflictActionType;
34+
Expression whereExpression;
35+
private List<UpdateSet> updateSets;
36+
37+
public InsertDuplicateAction(ConflictActionType conflictActionType) {
38+
this.conflictActionType = Objects.requireNonNull(conflictActionType,
39+
"The Conflict Action Type is mandatory and must not be Null.");
40+
}
41+
42+
public List<UpdateSet> getUpdateSets() {
43+
return updateSets;
44+
}
45+
46+
public void setUpdateSets(List<UpdateSet> updateSets) {
47+
this.updateSets = updateSets;
48+
}
49+
50+
public InsertDuplicateAction withUpdateSets(List<UpdateSet> updateSets) {
51+
this.setUpdateSets(updateSets);
52+
return this;
53+
}
54+
55+
public ConflictActionType getConflictActionType() {
56+
return conflictActionType;
57+
}
58+
59+
public void setConflictActionType(ConflictActionType conflictActionType) {
60+
this.conflictActionType = Objects.requireNonNull(conflictActionType,
61+
"The Conflict Action Type is mandatory and must not be Null.");
62+
}
63+
64+
public InsertDuplicateAction withConflictActionType(ConflictActionType conflictActionType) {
65+
setConflictActionType(conflictActionType);
66+
return this;
67+
}
68+
69+
public InsertDuplicateAction addUpdateSet(Column column, Expression expression) {
70+
return this.addUpdateSet(new UpdateSet());
71+
}
72+
73+
public InsertDuplicateAction addUpdateSet(UpdateSet updateSet) {
74+
if (updateSets == null) {
75+
updateSets = new ArrayList<>();
76+
}
77+
this.updateSets.add(updateSet);
78+
return this;
79+
}
80+
81+
public InsertDuplicateAction withUpdateSets(Collection<UpdateSet> updateSets) {
82+
this.setUpdateSets(new ArrayList<>(updateSets));
83+
return this;
84+
}
85+
86+
public Expression getWhereExpression() {
87+
return whereExpression;
88+
}
89+
90+
public void setWhereExpression(Expression whereExpression) {
91+
this.whereExpression = whereExpression;
92+
}
93+
94+
public InsertDuplicateAction withWhereExpression(Expression whereExpression) {
95+
setWhereExpression(whereExpression);
96+
return this;
97+
}
98+
99+
@SuppressWarnings("PMD.SwitchStmtsShouldHaveDefault")
100+
public StringBuilder appendTo(StringBuilder builder) {
101+
switch (conflictActionType) {
102+
case NOTHING:
103+
builder.append(" NOTHING ");
104+
break;
105+
default:
106+
UpdateSet.appendUpdateSetsTo(builder, updateSets);
107+
108+
if (whereExpression != null) {
109+
builder.append(" WHERE ").append(whereExpression);
110+
}
111+
break;
112+
}
113+
return builder;
114+
}
115+
116+
@Override
117+
public String toString() {
118+
return appendTo(new StringBuilder()).toString();
119+
}
120+
}

src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@
1414
import net.sf.jsqlparser.schema.Table;
1515
import net.sf.jsqlparser.statement.Statement;
1616
import net.sf.jsqlparser.statement.StatementVisitor;
17+
import net.sf.jsqlparser.statement.insert.ConflictActionType;
18+
import net.sf.jsqlparser.statement.insert.InsertDuplicateAction;
1719
import net.sf.jsqlparser.statement.select.PlainSelect;
1820
import net.sf.jsqlparser.statement.select.Select;
1921
import net.sf.jsqlparser.statement.select.SetOperationList;
@@ -35,6 +37,7 @@ public class Upsert implements Statement {
3537
private List<UpdateSet> duplicateUpdateSets;
3638
private UpsertType upsertType = UpsertType.UPSERT;
3739
private boolean isUsingInto;
40+
private InsertDuplicateAction duplicateAction;
3841

3942
public List<UpdateSet> getUpdateSets() {
4043
return updateSets;
@@ -46,11 +49,20 @@ public Upsert setUpdateSets(List<UpdateSet> updateSets) {
4649
}
4750

4851
public List<UpdateSet> getDuplicateUpdateSets() {
52+
if (duplicateAction != null) {
53+
return duplicateAction.getUpdateSets();
54+
}
4955
return duplicateUpdateSets;
5056
}
5157

5258
public Upsert setDuplicateUpdateSets(List<UpdateSet> duplicateUpdateSets) {
53-
this.duplicateUpdateSets = duplicateUpdateSets;
59+
if (duplicateAction != null) {
60+
duplicateAction.setConflictActionType(ConflictActionType.DO_UPDATE);
61+
duplicateAction.setUpdateSets(duplicateUpdateSets);
62+
} else {
63+
duplicateAction = new InsertDuplicateAction(ConflictActionType.DO_UPDATE);
64+
duplicateAction.setUpdateSets(duplicateUpdateSets);
65+
}
5466
return this;
5567
}
5668

@@ -181,9 +193,9 @@ public String toString() {
181193
}
182194
}
183195

184-
if (duplicateUpdateSets != null) {
196+
if (duplicateAction != null) {
185197
sb.append(" ON DUPLICATE KEY UPDATE ");
186-
UpdateSet.appendUpdateSetsTo(sb, duplicateUpdateSets);
198+
duplicateAction.appendTo(sb);
187199
}
188200

189201
return sb.toString();
@@ -219,4 +231,12 @@ public Upsert addColumns(Collection<? extends Column> columns) {
219231
collection.addAll(columns);
220232
return this.withColumns(collection);
221233
}
234+
235+
public InsertDuplicateAction getDuplicateAction() {
236+
return duplicateAction;
237+
}
238+
239+
public void setDuplicateAction(InsertDuplicateAction duplicateAction) {
240+
this.duplicateAction = duplicateAction;
241+
}
222242
}

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

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
import net.sf.jsqlparser.expression.ExpressionVisitor;
1313
import net.sf.jsqlparser.schema.Column;
1414
import net.sf.jsqlparser.schema.Partition;
15+
import net.sf.jsqlparser.statement.insert.ConflictActionType;
1516
import net.sf.jsqlparser.statement.insert.Insert;
1617
import net.sf.jsqlparser.statement.select.Select;
1718
import net.sf.jsqlparser.statement.select.SelectVisitor;
@@ -29,8 +30,7 @@ public InsertDeParser() {
2930
}
3031

3132
public InsertDeParser(ExpressionVisitor<StringBuilder> expressionVisitor,
32-
SelectVisitor<StringBuilder> selectVisitor,
33-
StringBuilder buffer) {
33+
SelectVisitor<StringBuilder> selectVisitor, StringBuilder buffer) {
3434
super(buffer);
3535
this.expressionVisitor = expressionVisitor;
3636
this.selectVisitor = selectVisitor;
@@ -115,9 +115,14 @@ public void deParse(Insert insert) {
115115
deparseUpdateSets(insert.getSetUpdateSets(), builder, expressionVisitor);
116116
}
117117

118-
if (insert.getDuplicateUpdateSets() != null) {
118+
if (insert.getDuplicateAction() != null) {
119119
builder.append(" ON DUPLICATE KEY UPDATE ");
120-
deparseUpdateSets(insert.getDuplicateUpdateSets(), builder, expressionVisitor);
120+
if (ConflictActionType.DO_UPDATE
121+
.equals(insert.getDuplicateAction().getConflictActionType())) {
122+
deparseUpdateSets(insert.getDuplicateUpdateSets(), builder, expressionVisitor);
123+
} else {
124+
insert.getDuplicateAction().appendTo(builder);
125+
}
121126
}
122127

123128
// @todo: Accept some Visitors for the involved Expressions

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
package net.sf.jsqlparser.util.deparser;
1111

1212
import net.sf.jsqlparser.expression.ExpressionVisitor;
13+
import net.sf.jsqlparser.statement.insert.ConflictActionType;
1314
import net.sf.jsqlparser.statement.select.SelectVisitor;
1415
import net.sf.jsqlparser.statement.upsert.Upsert;
1516

@@ -78,9 +79,14 @@ public void deParse(Upsert upsert) {
7879
upsert.getSelect().accept((SelectVisitor<StringBuilder>) selectVisitor, null);
7980
}
8081

81-
if (upsert.getDuplicateUpdateSets() != null) {
82+
if (upsert.getDuplicateAction() != null) {
8283
builder.append(" ON DUPLICATE KEY UPDATE ");
83-
deparseUpdateSets(upsert.getDuplicateUpdateSets(), builder, expressionVisitor);
84+
if (ConflictActionType.DO_UPDATE
85+
.equals(upsert.getDuplicateAction().getConflictActionType())) {
86+
deparseUpdateSets(upsert.getDuplicateUpdateSets(), builder, expressionVisitor);
87+
} else {
88+
upsert.getDuplicateAction().appendTo(builder);
89+
}
8490
}
8591
}
8692
}

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

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2742,6 +2742,8 @@ Insert Insert():
27422742

27432743
InsertConflictTarget conflictTarget = null;
27442744
InsertConflictAction conflictAction = null;
2745+
2746+
InsertDuplicateAction duplicateAction = null;
27452747
}
27462748
{
27472749
<K_INSERT> { insert.setOracleHint(getOracleHint()); }
@@ -2780,7 +2782,7 @@ Insert Insert():
27802782
)
27812783

27822784
[ LOOKAHEAD(2) <K_ON> <K_DUPLICATE> <K_KEY> <K_UPDATE>
2783-
duplicateUpdateSets = UpdateSets() { insert.withDuplicateUpdateSets(duplicateUpdateSets); }
2785+
duplicateAction = InsertDuplicateAction() { insert.setDuplicateAction(duplicateAction); }
27842786
]
27852787

27862788
[
@@ -2860,6 +2862,30 @@ InsertConflictAction InsertConflictAction():
28602862
.withWhereExpression(whereExpression); }
28612863
}
28622864

2865+
InsertDuplicateAction InsertDuplicateAction():
2866+
{
2867+
InsertDuplicateAction duplicateAction;
2868+
Expression whereExpression = null;
2869+
List<UpdateSet> updateSets;
2870+
}
2871+
{
2872+
(
2873+
LOOKAHEAD(2) (
2874+
<K_NOTHING> { duplicateAction = new InsertDuplicateAction( ConflictActionType.NOTHING ); }
2875+
)
2876+
|
2877+
(
2878+
{ duplicateAction = new InsertDuplicateAction( ConflictActionType.DO_UPDATE ); }
2879+
updateSets = UpdateSets() { duplicateAction.setUpdateSets(updateSets); }
2880+
[ whereExpression = WhereClause() ]
2881+
)
2882+
)
2883+
2884+
{ return duplicateAction
2885+
.withWhereExpression(whereExpression); }
2886+
}
2887+
2888+
28632889
OutputClause OutputClause():
28642890
{
28652891
List<SelectItem<?>> selectItemList = null;
@@ -2895,6 +2921,7 @@ Upsert Upsert():
28952921

28962922
Select select = null;
28972923
List<UpdateSet> duplicateUpdateSets;
2924+
InsertDuplicateAction duplicateAction = null;
28982925
Token tk = null;
28992926
}
29002927
{
@@ -2925,7 +2952,7 @@ Upsert Upsert():
29252952

29262953
[
29272954
<K_ON> <K_DUPLICATE> <K_KEY> <K_UPDATE>
2928-
duplicateUpdateSets = UpdateSets() { upsert.setDuplicateUpdateSets(duplicateUpdateSets); }
2955+
duplicateAction = InsertDuplicateAction() { upsert.setDuplicateAction(duplicateAction); }
29292956
]
29302957

29312958
{

src/test/java/net/sf/jsqlparser/statement/insert/InsertTest.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -917,4 +917,9 @@ void insertDemo() {
917917
insert, "INSERT INTO test VALUES ('A', 'B')");
918918
}
919919

920+
@Test
921+
public void testSimpleDuplicateInsert() throws JSQLParserException {
922+
assertSqlCanBeParsedAndDeparsed(
923+
"INSERT INTO example (num, name, address, tel) VALUES (1, 'name', 'test ', '1234-1234') ON DUPLICATE KEY update NOTHING");
924+
}
920925
}

0 commit comments

Comments
 (0)