This is an automated email from the ASF dual-hosted git repository.
zhenchen 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 b12a9cefb6 [CALCITE-7335] RelToSqlConverter generate sql containing
Scala subqueries includes redundant parentheses
b12a9cefb6 is described below
commit b12a9cefb67eefdd3b24ca2ac5893afeb021b80f
Author: Zhen Chen <[email protected]>
AuthorDate: Wed Dec 17 10:00:26 2025 +0800
[CALCITE-7335] RelToSqlConverter generate sql containing Scala subqueries
includes redundant parentheses
---
.../calcite/sql/fun/SqlStdOperatorTable.java | 14 +++++---
.../calcite/rel/rel2sql/RelToSqlConverterTest.java | 41 +++++++++++++++-------
2 files changed, 39 insertions(+), 16 deletions(-)
diff --git
a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
index 074c3103f2..2a26a78929 100644
--- a/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
+++ b/core/src/main/java/org/apache/calcite/sql/fun/SqlStdOperatorTable.java
@@ -2391,7 +2391,7 @@ public class SqlStdOperatorTable extends
ReflectiveSqlOperatorTable {
new SqlInternalOperator(
"$SCALAR_QUERY",
SqlKind.SCALAR_QUERY,
- 0,
+ 100, // High precedence to prevent SqlCall from adding extra
parentheses
false,
ReturnTypes.RECORD_TO_SCALAR,
null,
@@ -2401,9 +2401,15 @@ public class SqlStdOperatorTable extends
ReflectiveSqlOperatorTable {
SqlCall call,
int leftPrec,
int rightPrec) {
- final SqlWriter.Frame frame = writer.startList("(", ")");
- call.operand(0).unparse(writer, 0, 0);
- writer.endList(frame);
+ final SqlNode operand = call.operand(0);
+ if (operand.getKind() == SqlKind.SELECT) {
+ operand.unparse(writer, leftPrec, rightPrec);
+ } else {
+ final SqlWriter.Frame frame =
+ writer.startList(SqlWriter.FrameTypeEnum.SUB_QUERY, "(", ")");
+ operand.unparse(writer, 0, 0);
+ writer.endList(frame);
+ }
}
@Override public boolean argumentMustBeScalar(int ordinal) {
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 d2125c0ec8..06e1b93358 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
@@ -8627,9 +8627,9 @@ private void checkLiteral2(String expression, String
expected) {
+ "HAVING \"t1\".\"department_id\" = MIN(\"t1\".\"department_id\"))
\"t4\" ON \"employee\".\"department_id\" = \"t4\".\"department_id0\"";
final String expectedNoExpand = "SELECT \"department_id\"\n"
+ "FROM \"foodmart\".\"employee\"\n"
- + "WHERE \"department_id\" = (((SELECT
MIN(\"employee\".\"department_id\")\n"
+ + "WHERE \"department_id\" = (SELECT
MIN(\"employee\".\"department_id\")\n"
+ "FROM \"foodmart\".\"department\"\n"
- + "WHERE 1 = 2)))";
+ + "WHERE 1 = 2)";
final String expected = "SELECT \"employee\".\"department_id\"\n"
+ "FROM \"foodmart\".\"employee\"\n"
+ "INNER JOIN (SELECT \"t1\".\"department_id\" AS \"department_id0\",
MIN(\"t1\".\"department_id\") AS \"EXPR$0\"\n"
@@ -9802,17 +9802,17 @@ private void checkLiteral2(String expression, String
expected) {
final String sql0 = "update \"foodmart\".\"product\" a set \"product_id\"
= "
+ "(select \"product_class_id\" from \"foodmart\".\"product_class\" b "
+ "where a.\"product_class_id\" = b.\"product_class_id\")";
- final String expected0 = "UPDATE \"foodmart\".\"product\" SET
\"product_id\" = (((SELECT "
+ final String expected0 = "UPDATE \"foodmart\".\"product\" SET
\"product_id\" = (SELECT "
+ "\"product_class_id\"\nFROM \"foodmart\".\"product_class\"\nWHERE
\"product\""
- + ".\"product_class_id\" = \"product_class_id\")))";
+ + ".\"product_class_id\" = \"product_class_id\")";
sql(sql0).ok(expected0);
final String sql1 = "update \"foodmart\".\"product\" a set \"brand_name\"
= "
+ "(select cast(\"product_category\" as varchar(60)) from
\"foodmart\".\"product_class\" b "
+ "where a.\"product_class_id\" = b.\"product_class_id\")";
- final String expected1 = "UPDATE \"foodmart\".\"product\" SET
\"brand_name\" = (((SELECT CAST"
+ final String expected1 = "UPDATE \"foodmart\".\"product\" SET
\"brand_name\" = (SELECT CAST"
+ "(\"product_category\" AS VARCHAR(60) CHARACTER SET
\"ISO-8859-1\")\nFROM \"foodmart\""
- + ".\"product_class\"\nWHERE \"product\".\"product_class_id\" =
\"product_class_id\")))";
+ + ".\"product_class\"\nWHERE \"product\".\"product_class_id\" =
\"product_class_id\")";
sql(sql1).ok(expected1);
final String sql2 = "update \"foodmart\".\"product\"\n"
@@ -10972,10 +10972,10 @@ private void checkLiteral2(String expression, String
expected) {
final String expected = "SELECT "
+ "\"DEPTNO\", "
+ "\"DNAME\", "
- + "(((SELECT COUNT(*) AS \"COUNT\"\n"
+ + "(SELECT COUNT(*) AS \"COUNT\"\n"
+ "FROM \"scott\".\"EMP\"\n"
+ "GROUP BY \"DEPTNO\"\n"
- + "HAVING \"DEPTNO\" = \"DEPT\".\"DEPTNO\"))) AS \"$f2\"\n"
+ + "HAVING \"DEPTNO\" = \"DEPT\".\"DEPTNO\") AS \"$f2\"\n"
+ "FROM \"scott\".\"DEPT\"";
relFn(relFn).ok(expected);
@@ -11053,9 +11053,9 @@ private void checkLiteral2(String expression, String
expected) {
final String expected = "SELECT \"EMP\".\"EMPNO\"\n"
+ "FROM \"SCOTT\".\"EMP\"\n"
+ "INNER JOIN \"SCOTT\".\"DEPT\" ON \"EMP\".\"DEPTNO\" =
\"DEPT\".\"DEPTNO\"\n"
- + "WHERE \"DEPT\".\"DEPTNO\" = (((SELECT MIN(\"DEPTNO\")\n"
+ + "WHERE \"DEPT\".\"DEPTNO\" = (SELECT MIN(\"DEPTNO\")\n"
+ "FROM \"SCOTT\".\"DEPT\"\n"
- + "WHERE \"DEPTNO\" = \"EMP\".\"DEPTNO\")))";
+ + "WHERE \"DEPTNO\" = \"EMP\".\"DEPTNO\")";
HepProgramBuilder builder = new HepProgramBuilder();
builder.addRuleClass(FilterJoinRule.FilterIntoJoinRule.class);
@@ -11083,8 +11083,8 @@ private void checkLiteral2(String expression, String
expected) {
+ "FROM \"SCOTT\".\"EMP\" AS \"$cor1\",\n"
+ "LATERAL (SELECT *\nFROM \"SCOTT\".\"DEPT\"\n"
+ "WHERE \"$cor1\".\"DEPTNO\" = \"DEPTNO\") AS \"t\"\n"
- + "WHERE \"t\".\"DEPTNO\" = (((SELECT MIN(\"DEPTNO\")\n"
- + "FROM \"SCOTT\".\"DEPT\"\nWHERE \"DEPTNO\" =
\"$cor1\".\"DEPTNO\")))";
+ + "WHERE \"t\".\"DEPTNO\" = (SELECT MIN(\"DEPTNO\")\n"
+ + "FROM \"SCOTT\".\"DEPT\"\nWHERE \"DEPTNO\" = \"$cor1\".\"DEPTNO\")";
HepProgramBuilder builder = new HepProgramBuilder();
builder.addRuleClass(JoinToCorrelateRule.class);
builder.addRuleClass(FilterCorrelateRule.class);
@@ -11099,6 +11099,23 @@ private void checkLiteral2(String expression, String
expected) {
.ok(expected);
}
+ /** Test case of
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-7335">[CALCITE-7335]
+ * RelToSqlConverter generate sql containing Scala subqueries
+ * includes redundant parentheses</a>. */
+ @Test void testScalarSubqueryInSelectList() {
+ final String sql = "SELECT\n"
+ + " (SELECT COUNT(*)\n"
+ + " FROM \"employee\"\n"
+ + " WHERE v.\"product_id\" >= 2), 3\n"
+ + "FROM \"product\" AS v";
+ final String expected = "SELECT (SELECT COUNT(*)\n"
+ + "FROM \"foodmart\".\"employee\"\n"
+ + "WHERE \"product\".\"product_id\" >= 2), 3\n"
+ + "FROM \"foodmart\".\"product\"";
+ sql(sql).ok(expected);
+ }
+
/** Fluid interface to run tests. */
static class Sql {
private final CalciteAssert.SchemaSpec schemaSpec;