From 657443cfb075fdba2af122e5d48133b2564a29a6 Mon Sep 17 00:00:00 2001 From: Minjae Lee Date: Thu, 10 Sep 2026 18:43:07 +0900 Subject: [PATCH 1/2] Support PostgreSQL conflict index elements, OVERRIDING USER and MERGE RETURNING --- .../jsqlparser/statement/ReturningClause.java | 7 +- .../statement/StatementVisitorAdapter.java | 4 + .../statement/create/table/Index.java | 22 ++- .../jsqlparser/statement/insert/Insert.java | 28 ++- .../insert/InsertConflictTarget.java | 173 ++++++++++++------ .../sf/jsqlparser/statement/merge/Merge.java | 19 ++ .../sf/jsqlparser/util/TablesNamesFinder.java | 4 + .../util/deparser/ExpressionDeParser.java | 4 +- .../util/deparser/InsertDeParser.java | 5 +- .../util/deparser/MergeDeParser.java | 5 + .../validation/validator/InsertValidator.java | 4 + .../validation/validator/MergeValidator.java | 4 + .../net/sf/jsqlparser/parser/JSqlParserCC.jjt | 66 ++++--- .../insert/PostgreSQLConflictTargetTest.java | 164 +++++++++++++++++ .../merge/PostgreSQLMergeReturningTest.java | 78 ++++++++ 15 files changed, 498 insertions(+), 89 deletions(-) create mode 100644 src/test/java/net/sf/jsqlparser/statement/insert/PostgreSQLConflictTargetTest.java create mode 100644 src/test/java/net/sf/jsqlparser/statement/merge/PostgreSQLMergeReturningTest.java diff --git a/src/main/java/net/sf/jsqlparser/statement/ReturningClause.java b/src/main/java/net/sf/jsqlparser/statement/ReturningClause.java index c37a6dfd58..1236ec4499 100644 --- a/src/main/java/net/sf/jsqlparser/statement/ReturningClause.java +++ b/src/main/java/net/sf/jsqlparser/statement/ReturningClause.java @@ -15,6 +15,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.function.Consumer; import net.sf.jsqlparser.expression.ExpressionVisitorAdapter; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.MultiPartName; @@ -86,6 +87,10 @@ public List getOutputAliases() { } public StringBuilder appendTo(StringBuilder builder) { + return appendTo(builder, item -> builder.append(item)); + } + + public StringBuilder appendTo(StringBuilder builder, Consumer> itemPrinter) { builder.append(" ").append(keyword).append(" "); if (outputAliases != null && !outputAliases.isEmpty()) { builder.append("WITH ("); @@ -101,7 +106,7 @@ public StringBuilder appendTo(StringBuilder builder) { if (i > 0) { builder.append(", "); } - builder.append(get(i)); + itemPrinter.accept(get(i)); } if (dataItems != null && !dataItems.isEmpty()) { diff --git a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java index 1d4808641b..ef5ed487f3 100644 --- a/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java +++ b/src/main/java/net/sf/jsqlparser/statement/StatementVisitorAdapter.java @@ -296,6 +296,9 @@ public T visit(Insert insert, S context) { expressionVisitor.visitUpdateSets(conflictAction.getUpdateSets(), context); } + if (insert.getConflictTarget() != null) { + insert.getConflictTarget().accept(expressionVisitor, context); + } visitReturningClause(insert.getReturningClause(), context); return null; } @@ -457,6 +460,7 @@ public T visit(Merge merge, S context) { expressionVisitor.visitExpression(merge.getOnCondition(), context); mergeOperationVisitor.visit(merge.getOperations(), context); selectVisitor.visitOutputClause(merge.getOutputClause(), context); + visitReturningClause(merge.getReturningClause(), context); return null; } diff --git a/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java b/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java index c57ad83891..0aa9bd8969 100644 --- a/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java +++ b/src/main/java/net/sf/jsqlparser/statement/create/table/Index.java @@ -331,6 +331,7 @@ public enum NullOrdering { public final String columnName; public final List params; private final Expression expression; + private boolean expressionParenthesized = true; private String collation; private String operatorClass; private List