This is an automated email from the ASF dual-hosted git repository.

mihaibudiu pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/calcite.git


The following commit(s) were added to refs/heads/main by this push:
     new fc9af0751c [CALCITE-7585] SqlMerge unparse EXISTS predicates in ON 
clause without parentheses
fc9af0751c is described below

commit fc9af0751c649b3055a780d7d47ddc94b33c4138
Author: zzwqqq <[email protected]>
AuthorDate: Sun Jun 14 07:46:06 2026 +0800

    [CALCITE-7585] SqlMerge unparse EXISTS predicates in ON clause without 
parentheses
---
 .../java/org/apache/calcite/sql/SqlDelete.java     |  3 +-
 .../main/java/org/apache/calcite/sql/SqlMerge.java |  5 ++--
 .../org/apache/calcite/sql/SqlSelectOperator.java  |  3 +-
 .../java/org/apache/calcite/sql/SqlUpdate.java     |  3 +-
 .../main/java/org/apache/calcite/sql/SqlUtil.java  | 34 ++++++++++------------
 .../calcite/rel/rel2sql/RelToSqlConverterTest.java | 17 +++++++++++
 6 files changed, 40 insertions(+), 25 deletions(-)

diff --git a/core/src/main/java/org/apache/calcite/sql/SqlDelete.java 
b/core/src/main/java/org/apache/calcite/sql/SqlDelete.java
index c9da35c48b..7b3cf41c5c 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlDelete.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlDelete.java
@@ -152,7 +152,8 @@ public SqlNode getTargetTable() {
     }
     SqlNode condition = this.condition;
     if (condition != null) {
-      SqlUtil.unparseWhereClause(writer, condition, opLeft, opRight);
+      writer.sep("WHERE");
+      SqlUtil.unparseConditionClause(writer, condition, opLeft, opRight);
     }
     writer.endList(frame);
   }
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlMerge.java 
b/core/src/main/java/org/apache/calcite/sql/SqlMerge.java
index ddadf32959..df450974a5 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlMerge.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlMerge.java
@@ -197,9 +197,8 @@ public void setSourceSelect(SqlSelect sourceSelect) {
     writer.keyword("USING");
     source.unparse(writer, opLeft, opRight);
 
-    writer.newlineAndIndent();
-    writer.keyword("ON");
-    condition.unparse(writer, opLeft, opRight);
+    writer.sep("ON");
+    SqlUtil.unparseConditionClause(writer, condition, opLeft, opRight);
 
     SqlUpdate updateCall = this.updateCall;
     if (updateCall != null) {
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java 
b/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java
index 7e37ac732f..8605eef7b3 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlSelectOperator.java
@@ -173,7 +173,8 @@ public SqlSelect createCall(
 
     SqlNode where = select.where;
     if (where != null) {
-      SqlUtil.unparseWhereClause(writer, where, 0, 0);
+      writer.sep("WHERE");
+      SqlUtil.unparseConditionClause(writer, where, 0, 0);
     }
     if (select.groupBy != null) {
       SqlNodeList groupBy =
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java 
b/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java
index 22d669efcf..0f743540d1 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUpdate.java
@@ -202,7 +202,8 @@ public void setSourceSelect(SqlSelect sourceSelect) {
     writer.endList(setFrame);
     SqlNode condition = this.condition;
     if (condition != null) {
-      SqlUtil.unparseWhereClause(writer, condition, opLeft, opRight);
+      writer.sep("WHERE");
+      SqlUtil.unparseConditionClause(writer, condition, opLeft, opRight);
     }
     writer.endList(frame);
   }
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java 
b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
index 1bafd7cfff..b5c91a1c7a 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUtil.java
@@ -455,34 +455,30 @@ public static void unparseBinarySyntax(
   }
 
   /**
-   * Unparses a WHERE clause.
+   * Unparses a condition using a
+   * {@link SqlWriter.FrameTypeEnum#WHERE_LIST} frame, which provides
+   * predicate-list formatting.
    *
-   * <p>Unparsing the condition in a {@link SqlWriter.FrameTypeEnum#WHERE_LIST}
-   * frame lets sub-queries in predicates recognize that they need
-   * parentheses.
-   *
-   * @param writer   Writer
-   * @param where WHERE condition
+   * @param writer Writer
+   * @param condition Condition
    * @param leftPrec Left precedence
    * @param rightPrec Right precedence
    */
-  public static void unparseWhereClause(SqlWriter writer, SqlNode where,
-      int leftPrec, int rightPrec) {
-    writer.sep("WHERE");
-
+  public static void unparseConditionClause(SqlWriter writer,
+      SqlNode condition, int leftPrec, int rightPrec) {
     if (!writer.isAlwaysUseParentheses()) {
-      SqlNode node = where;
+      SqlNode node = condition;
 
       // Decide whether to split on ORs or ANDs.
-      SqlBinaryOperator whereSep = SqlStdOperatorTable.AND;
+      SqlBinaryOperator conditionSep = SqlStdOperatorTable.AND;
       if ((node instanceof SqlCall)
           && node.getKind() == SqlKind.OR) {
-        whereSep = SqlStdOperatorTable.OR;
+        conditionSep = SqlStdOperatorTable.OR;
       }
 
-      // Unroll whereClause.
+      // Unroll condition.
       final List<SqlNode> list = new ArrayList<>(0);
-      while (node.getKind() == whereSep.kind) {
+      while (node.getKind() == conditionSep.kind) {
         assert node instanceof SqlCall;
         final SqlCall call1 = (SqlCall) node;
         list.add(0, call1.operand(1));
@@ -490,10 +486,10 @@ public static void unparseWhereClause(SqlWriter writer, 
SqlNode where,
       }
       list.add(0, node);
 
-      writer.list(SqlWriter.FrameTypeEnum.WHERE_LIST, whereSep,
-          new SqlNodeList(list, where.getParserPosition()));
+      writer.list(SqlWriter.FrameTypeEnum.WHERE_LIST, conditionSep,
+          new SqlNodeList(list, condition.getParserPosition()));
     } else {
-      where.unparse(writer, leftPrec, rightPrec);
+      condition.unparse(writer, leftPrec, rightPrec);
     }
   }
 
diff --git 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
index 97d782fcae..4e2825bb3b 100644
--- 
a/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
+++ 
b/core/src/test/java/org/apache/calcite/rel/rel2sql/RelToSqlConverterTest.java
@@ -10046,6 +10046,23 @@ private void checkLiteral2(String expression, String 
expected) {
     sql(sql7)
         .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
         .ok(expected7);
+
+    // [CALCITE-7585] SqlMerge unparse EXISTS predicates in ON clause
+    // without parentheses.
+    final String sql8 = "merge into \"DEPT\" as \"t\"\n"
+        + "using \"DEPT\" as \"s\"\n"
+        + "on exists (select 1 from \"EMP\" as \"e\" where \"e\".\"DEPTNO\" = 
\"s\".\"DEPTNO\")\n"
+        + "when matched then\n"
+        + "update set \"DNAME\" = \"s\".\"DNAME\"";
+    final String expected8 = "MERGE INTO \"SCOTT\".\"DEPT\" AS \"DEPT0\"\n"
+        + "USING \"SCOTT\".\"DEPT\"\n"
+        + "ON EXISTS (SELECT *\n"
+        + "FROM \"SCOTT\".\"EMP\"\n"
+        + "WHERE \"DEPTNO\" = \"DEPT\".\"DEPTNO\")\n"
+        + "WHEN MATCHED THEN UPDATE SET \"DNAME\" = \"DEPT\".\"DNAME\"";
+    sql(sql8)
+        .schema(CalciteAssert.SchemaSpec.JDBC_SCOTT)
+        .ok(expected8);
   }
 
   /** Test case for

Reply via email to