Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
package net.sf.jsqlparser.statement.insert;

public enum ConflictActionType {
DO_NOTHING, DO_UPDATE;
NOTHING, DO_NOTHING, DO_UPDATE;

public static ConflictActionType from(String type) {
return Enum.valueOf(ConflictActionType.class, type.toUpperCase());
Expand Down
27 changes: 23 additions & 4 deletions src/main/java/net/sf/jsqlparser/statement/insert/Insert.java
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@ public class Insert implements Statement {
private OutputClause outputClause;
private InsertConflictTarget conflictTarget;
private InsertConflictAction conflictAction;
private InsertDuplicateAction duplicateAction;

public List<UpdateSet> getDuplicateUpdateSets() {
if (duplicateAction != null) {
return duplicateAction.getUpdateSets();
}
return duplicateUpdateSets;
}

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

public Insert withDuplicateUpdateSets(List<UpdateSet> duplicateUpdateSets) {
this.duplicateUpdateSets = duplicateUpdateSets;
if (duplicateAction != null) {
duplicateAction.setConflictActionType(ConflictActionType.DO_UPDATE);
duplicateAction.setUpdateSets(duplicateUpdateSets);
} else {
duplicateAction = new InsertDuplicateAction(ConflictActionType.DO_UPDATE);
duplicateAction.setUpdateSets(duplicateUpdateSets);
}
return this;
}

Expand Down Expand Up @@ -157,7 +167,8 @@ public boolean isUseSelectBrackets() {

@Deprecated
public boolean isUseDuplicate() {
return duplicateUpdateSets != null && !duplicateUpdateSets.isEmpty();
return duplicateAction != null && duplicateAction.getUpdateSets() != null
&& !duplicateAction.getUpdateSets().isEmpty();
}

public InsertModifierPriority getModifierPriority() {
Expand Down Expand Up @@ -331,9 +342,9 @@ public String toString() {
sql = UpdateSet.appendUpdateSetsTo(sql, setUpdateSets);
}

if (duplicateUpdateSets != null && !duplicateUpdateSets.isEmpty()) {
if (duplicateAction != null) {
sql.append(" ON DUPLICATE KEY UPDATE ");
sql = UpdateSet.appendUpdateSetsTo(sql, duplicateUpdateSets);
duplicateAction.appendTo(sql);
}

if (conflictAction != null) {
Expand Down Expand Up @@ -392,4 +403,12 @@ public Insert addColumns(Collection<Column> columns) {
collection.addAll(columns);
return this.withColumns(collection);
}

public InsertDuplicateAction getDuplicateAction() {
return duplicateAction;
}

public void setDuplicateAction(InsertDuplicateAction duplicateAction) {
this.duplicateAction = duplicateAction;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*-
* #%L
* JSQLParser library
* %%
* Copyright (C) 2004 - 2025 JSQLParser
* %%
* Dual licensed under GNU LGPL 2.1 or Apache License 2.0
* #L%
*/
package net.sf.jsqlparser.statement.insert;

import net.sf.jsqlparser.expression.Expression;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.update.UpdateSet;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Objects;

/**
* on duplicate key is one of:
*
* ON DUPLICATE KEY UPDATE NOTHING ON DUPLICATE KEY UPDATE { column_name = { expression | DEFAULT }
* | ( column_name [, ...] ) = [ ROW ] ( { expression | DEFAULT } [, ...] ) | ( column_name [, ...]
* ) = ( sub-SELECT ) } [, ...] [ WHERE condition ]
*
* @author zhangconan
*/
public class InsertDuplicateAction implements Serializable {

ConflictActionType conflictActionType;
Expression whereExpression;
private List<UpdateSet> updateSets;

public InsertDuplicateAction(ConflictActionType conflictActionType) {
this.conflictActionType = Objects.requireNonNull(conflictActionType,
"The Conflict Action Type is mandatory and must not be Null.");
}

public List<UpdateSet> getUpdateSets() {
return updateSets;
}

public void setUpdateSets(List<UpdateSet> updateSets) {
this.updateSets = updateSets;
}

public InsertDuplicateAction withUpdateSets(List<UpdateSet> updateSets) {
this.setUpdateSets(updateSets);
return this;
}

public ConflictActionType getConflictActionType() {
return conflictActionType;
}

public void setConflictActionType(ConflictActionType conflictActionType) {
this.conflictActionType = Objects.requireNonNull(conflictActionType,
"The Conflict Action Type is mandatory and must not be Null.");
}

public InsertDuplicateAction withConflictActionType(ConflictActionType conflictActionType) {
setConflictActionType(conflictActionType);
return this;
}

public InsertDuplicateAction addUpdateSet(Column column, Expression expression) {
return this.addUpdateSet(new UpdateSet());
}

public InsertDuplicateAction addUpdateSet(UpdateSet updateSet) {
if (updateSets == null) {
updateSets = new ArrayList<>();
}
this.updateSets.add(updateSet);
return this;
}

public InsertDuplicateAction withUpdateSets(Collection<UpdateSet> updateSets) {
this.setUpdateSets(new ArrayList<>(updateSets));
return this;
}

public Expression getWhereExpression() {
return whereExpression;
}

public void setWhereExpression(Expression whereExpression) {
this.whereExpression = whereExpression;
}

public InsertDuplicateAction withWhereExpression(Expression whereExpression) {
setWhereExpression(whereExpression);
return this;
}

@SuppressWarnings("PMD.SwitchStmtsShouldHaveDefault")
public StringBuilder appendTo(StringBuilder builder) {
switch (conflictActionType) {
case NOTHING:
builder.append(" NOTHING ");
break;
default:
UpdateSet.appendUpdateSetsTo(builder, updateSets);

if (whereExpression != null) {
builder.append(" WHERE ").append(whereExpression);
}
break;
}
return builder;
}

@Override
public String toString() {
return appendTo(new StringBuilder()).toString();
}
}
26 changes: 23 additions & 3 deletions src/main/java/net/sf/jsqlparser/statement/upsert/Upsert.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
import net.sf.jsqlparser.schema.Table;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.StatementVisitor;
import net.sf.jsqlparser.statement.insert.ConflictActionType;
import net.sf.jsqlparser.statement.insert.InsertDuplicateAction;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SetOperationList;
Expand All @@ -35,6 +37,7 @@ public class Upsert implements Statement {
private List<UpdateSet> duplicateUpdateSets;
private UpsertType upsertType = UpsertType.UPSERT;
private boolean isUsingInto;
private InsertDuplicateAction duplicateAction;

public List<UpdateSet> getUpdateSets() {
return updateSets;
Expand All @@ -46,11 +49,20 @@ public Upsert setUpdateSets(List<UpdateSet> updateSets) {
}

public List<UpdateSet> getDuplicateUpdateSets() {
if (duplicateAction != null) {
return duplicateAction.getUpdateSets();
}
return duplicateUpdateSets;
}

public Upsert setDuplicateUpdateSets(List<UpdateSet> duplicateUpdateSets) {
this.duplicateUpdateSets = duplicateUpdateSets;
if (duplicateAction != null) {
duplicateAction.setConflictActionType(ConflictActionType.DO_UPDATE);
duplicateAction.setUpdateSets(duplicateUpdateSets);
} else {
duplicateAction = new InsertDuplicateAction(ConflictActionType.DO_UPDATE);
duplicateAction.setUpdateSets(duplicateUpdateSets);
}
return this;
}

Expand Down Expand Up @@ -181,9 +193,9 @@ public String toString() {
}
}

if (duplicateUpdateSets != null) {
if (duplicateAction != null) {
sb.append(" ON DUPLICATE KEY UPDATE ");
UpdateSet.appendUpdateSetsTo(sb, duplicateUpdateSets);
duplicateAction.appendTo(sb);
}

return sb.toString();
Expand Down Expand Up @@ -219,4 +231,12 @@ public Upsert addColumns(Collection<? extends Column> columns) {
collection.addAll(columns);
return this.withColumns(collection);
}

public InsertDuplicateAction getDuplicateAction() {
return duplicateAction;
}

public void setDuplicateAction(InsertDuplicateAction duplicateAction) {
this.duplicateAction = duplicateAction;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.schema.Partition;
import net.sf.jsqlparser.statement.insert.ConflictActionType;
import net.sf.jsqlparser.statement.insert.Insert;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectVisitor;
Expand All @@ -29,8 +30,7 @@ public InsertDeParser() {
}

public InsertDeParser(ExpressionVisitor<StringBuilder> expressionVisitor,
SelectVisitor<StringBuilder> selectVisitor,
StringBuilder buffer) {
SelectVisitor<StringBuilder> selectVisitor, StringBuilder buffer) {
super(buffer);
this.expressionVisitor = expressionVisitor;
this.selectVisitor = selectVisitor;
Expand Down Expand Up @@ -115,9 +115,14 @@ public void deParse(Insert insert) {
deparseUpdateSets(insert.getSetUpdateSets(), builder, expressionVisitor);
}

if (insert.getDuplicateUpdateSets() != null) {
if (insert.getDuplicateAction() != null) {
builder.append(" ON DUPLICATE KEY UPDATE ");
deparseUpdateSets(insert.getDuplicateUpdateSets(), builder, expressionVisitor);
if (ConflictActionType.DO_UPDATE
.equals(insert.getDuplicateAction().getConflictActionType())) {
deparseUpdateSets(insert.getDuplicateUpdateSets(), builder, expressionVisitor);
} else {
insert.getDuplicateAction().appendTo(builder);
}
}

// @todo: Accept some Visitors for the involved Expressions
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
package net.sf.jsqlparser.util.deparser;

import net.sf.jsqlparser.expression.ExpressionVisitor;
import net.sf.jsqlparser.statement.insert.ConflictActionType;
import net.sf.jsqlparser.statement.select.SelectVisitor;
import net.sf.jsqlparser.statement.upsert.Upsert;

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

if (upsert.getDuplicateUpdateSets() != null) {
if (upsert.getDuplicateAction() != null) {
builder.append(" ON DUPLICATE KEY UPDATE ");
deparseUpdateSets(upsert.getDuplicateUpdateSets(), builder, expressionVisitor);
if (ConflictActionType.DO_UPDATE
.equals(upsert.getDuplicateAction().getConflictActionType())) {
deparseUpdateSets(upsert.getDuplicateUpdateSets(), builder, expressionVisitor);
} else {
upsert.getDuplicateAction().appendTo(builder);
}
}
}
}
Expand Down
31 changes: 29 additions & 2 deletions src/main/jjtree/net/sf/jsqlparser/parser/JSqlParserCC.jjt
Original file line number Diff line number Diff line change
Expand Up @@ -2742,6 +2742,8 @@ Insert Insert():

InsertConflictTarget conflictTarget = null;
InsertConflictAction conflictAction = null;

InsertDuplicateAction duplicateAction = null;
}
{
<K_INSERT> { insert.setOracleHint(getOracleHint()); }
Expand Down Expand Up @@ -2780,7 +2782,7 @@ Insert Insert():
)

[ LOOKAHEAD(2) <K_ON> <K_DUPLICATE> <K_KEY> <K_UPDATE>
duplicateUpdateSets = UpdateSets() { insert.withDuplicateUpdateSets(duplicateUpdateSets); }
duplicateAction = InsertDuplicateAction() { insert.setDuplicateAction(duplicateAction); }
]

[
Expand Down Expand Up @@ -2860,6 +2862,30 @@ InsertConflictAction InsertConflictAction():
.withWhereExpression(whereExpression); }
}

InsertDuplicateAction InsertDuplicateAction():
{
InsertDuplicateAction duplicateAction;
Expression whereExpression = null;
List<UpdateSet> updateSets;
}
{
(
LOOKAHEAD(2) (
<K_NOTHING> { duplicateAction = new InsertDuplicateAction( ConflictActionType.NOTHING ); }
)
|
(
{ duplicateAction = new InsertDuplicateAction( ConflictActionType.DO_UPDATE ); }
updateSets = UpdateSets() { duplicateAction.setUpdateSets(updateSets); }
[ whereExpression = WhereClause() ]
)
)

{ return duplicateAction
.withWhereExpression(whereExpression); }
}


OutputClause OutputClause():
{
List<SelectItem<?>> selectItemList = null;
Expand Down Expand Up @@ -2895,6 +2921,7 @@ Upsert Upsert():

Select select = null;
List<UpdateSet> duplicateUpdateSets;
InsertDuplicateAction duplicateAction = null;
Token tk = null;
}
{
Expand Down Expand Up @@ -2925,7 +2952,7 @@ Upsert Upsert():

[
<K_ON> <K_DUPLICATE> <K_KEY> <K_UPDATE>
duplicateUpdateSets = UpdateSets() { upsert.setDuplicateUpdateSets(duplicateUpdateSets); }
duplicateAction = InsertDuplicateAction() { upsert.setDuplicateAction(duplicateAction); }
]

{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -917,4 +917,9 @@ void insertDemo() {
insert, "INSERT INTO test VALUES ('A', 'B')");
}

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