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

rubenql 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 b65f010d3a [CALCITE-7140] Improve constant reduction of expressions 
containing SqlRowOperator
b65f010d3a is described below

commit b65f010d3a813e5607fba549c48908d23ad5c5f8
Author: Ruben Quesada Lopez <[email protected]>
AuthorDate: Wed Aug 20 11:23:20 2025 +0100

    [CALCITE-7140] Improve constant reduction of expressions containing 
SqlRowOperator
---
 .../calcite/rel/rules/ReduceExpressionsRule.java   |  8 -------
 .../java/org/apache/calcite/rex/RexBuilder.java    | 21 +++++++++--------
 .../org/apache/calcite/test/RelOptRulesTest.java   | 17 ++++++++++++++
 .../org/apache/calcite/test/RelOptRulesTest.xml    | 26 ++++++++++++++++++++++
 4 files changed, 55 insertions(+), 17 deletions(-)

diff --git 
a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java 
b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
index 783e3b7bb1..605f212a76 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/ReduceExpressionsRule.java
@@ -64,7 +64,6 @@
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlKind;
 import org.apache.calcite.sql.SqlOperator;
-import org.apache.calcite.sql.fun.SqlRowOperator;
 import org.apache.calcite.sql.type.SqlTypeName;
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.tools.RelBuilderFactory;
@@ -1147,13 +1146,6 @@ private void analyzeCall(RexCall call, Constancy 
callConstancy) {
         callConstancy = Constancy.NON_CONSTANT;
       }
 
-      // Row operator itself can't be reduced to a literal, but if
-      // the operands are constants, we still want to reduce those
-      if ((callConstancy == Constancy.REDUCIBLE_CONSTANT)
-          && (call.getOperator() instanceof SqlRowOperator)) {
-        callConstancy = Constancy.NON_CONSTANT;
-      }
-
       if (callConstancy == Constancy.NON_CONSTANT) {
         // any REDUCIBLE_CONSTANT children are now known to be maximal
         // reducible subtrees, so they can be added to the result
diff --git a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java 
b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
index fd884af9e5..d5492f0634 100644
--- a/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
+++ b/core/src/main/java/org/apache/calcite/rex/RexBuilder.java
@@ -28,6 +28,7 @@
 import org.apache.calcite.rel.type.RelDataTypeField;
 import org.apache.calcite.rel.type.RelDataTypeSystemImpl;
 import org.apache.calcite.runtime.FlatLists;
+import org.apache.calcite.runtime.SqlFunctions;
 import org.apache.calcite.sql.SqlAggFunction;
 import org.apache.calcite.sql.SqlCollation;
 import org.apache.calcite.sql.SqlIntervalQualifier;
@@ -49,7 +50,6 @@
 import org.apache.calcite.sql.type.SqlTypeUtil;
 import org.apache.calcite.util.DateString;
 import org.apache.calcite.util.NlsString;
-import org.apache.calcite.util.Pair;
 import org.apache.calcite.util.Sarg;
 import org.apache.calcite.util.TimeString;
 import org.apache.calcite.util.TimeWithTimeZoneString;
@@ -2186,16 +2186,19 @@ public RexNode makeLiteral(@Nullable Object value, 
RelDataType type,
       }
     case ROW:
       operands = new ArrayList<>();
-      //noinspection unchecked
-      for (Pair<RelDataTypeField, Object> pair
-          : Pair.zip(type.getFieldList(), (List<Object>) value)) {
-        final RexNode e = pair.right instanceof RexLiteral
-            ? (RexNode) pair.right
-            : makeLiteral(pair.right, pair.left.getType(), allowCast);
+      for (int i = 0; i < type.getFieldList().size(); i++) {
+        final RelDataTypeField relDataTypeField = type.getFieldList().get(i);
+        final Object fieldValue = SqlFunctions.structAccess(value, i, 
relDataTypeField.getName());
+        final RexNode e = fieldValue instanceof RexLiteral
+            ? (RexNode) fieldValue
+            : makeLiteral(fieldValue, relDataTypeField.getType(), allowCast);
         operands.add(e);
       }
-      return new RexLiteral((Comparable) FlatLists.of(operands), type,
-          sqlTypeName);
+      if (allowCast) {
+        return makeCall(type, SqlStdOperatorTable.ROW, operands);
+      } else {
+        return new RexLiteral((Comparable) FlatLists.of(operands), type, 
sqlTypeName);
+      }
     case GEOMETRY:
       return new RexLiteral((Comparable) value, guessType(value),
           SqlTypeName.GEOMETRY);
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java 
b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index c8971b62e0..32626d9df4 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -4194,6 +4194,23 @@ private void 
checkPushJoinThroughUnionOnRightDoesNotMatchSemiOrAntiJoin(JoinRelT
         .check();
   }
 
+  /** Test case for
+   * <a 
href="https://issues.apache.org/jira/browse/CALCITE-7140";>[CALCITE-7140]
+   * Improve constant reduction of expressions containing SqlRowOperator</a>. 
*/
+  @Test void testReduceConstantsWithRow() {
+    final String sql = "SELECT 1+1, ARRAY[1+1, 2+2], ROW('a', 3+3), 
MAP['a'||'b', 6+6],\n"
+        + "ROW(1+2, ARRAY[1+2, 2+3], ROW('a', 3+4), MAP['ab'||'cd', 6+7]),\n"
+        + "ARRAY[2*3, 2, 1],\n"
+        + "ARRAY[ROW(4*2, 'a'), ROW(4+4, 'b')],\n"
+        + "ARRAY[MAP['abc'||'def', 8+8], MAP['ghi'||'jkl', 9+9]],\n"
+        + "ARRAY[ROW(1+2, ARRAY[1+1, 2+2], ROW('a', 3+3), MAP['x'||'y', 
8+8])],\n"
+        + "CARDINALITY(ARRAY[2*3, 2*2, 1*4]),\n"
+        + "CARDINALITY(ARRAY[ROW(4*3, 'm'), ROW(4+6, 'b')]),\n"
+        + "CARDINALITY(ARRAY[MAP['ac'||'bd', 1+8], MAP['gi'||'jl', 1+9]]),\n"
+        + "CARDINALITY(ARRAY[ROW(1+7, ARRAY[1+4, 4+2], ROW('t', 5+5), 
MAP['y'||'z', 9+9])])";
+    sql(sql).withRule(CoreRules.PROJECT_REDUCE_EXPRESSIONS).check();
+  }
+
   @Test void testPullNull() {
     final String sql = "select *\n"
         + "from emp\n"
diff --git 
a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml 
b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index abfd5f064b..708e61277a 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -15700,6 +15700,32 @@ LogicalProject($0=[$3], $1=[$4])
     LogicalProject(EMPNO=[$0], SAL=[$5], DEPTNO=[$7])
       LogicalFilter(condition=[=($5, 5000)])
         LogicalTableScan(table=[[CATALOG, SALES, EMP]])
+]]>
+    </Resource>
+  </TestCase>
+  <TestCase name="testReduceConstantsWithRow">
+    <Resource name="sql">
+      <![CDATA[SELECT 1+1, ARRAY[1+1, 2+2], ROW('a', 3+3), MAP['a'||'b', 6+6],
+ROW(1+2, ARRAY[1+2, 2+3], ROW('a', 3+4), MAP['ab'||'cd', 6+7]),
+ARRAY[2*3, 2, 1],
+ARRAY[ROW(4*2, 'a'), ROW(4+4, 'b')],
+ARRAY[MAP['abc'||'def', 8+8], MAP['ghi'||'jkl', 9+9]],
+ARRAY[ROW(1+2, ARRAY[1+1, 2+2], ROW('a', 3+3), MAP['x'||'y', 8+8])],
+CARDINALITY(ARRAY[2*3, 2*2, 1*4]),
+CARDINALITY(ARRAY[ROW(4*3, 'm'), ROW(4+6, 'b')]),
+CARDINALITY(ARRAY[MAP['ac'||'bd', 1+8], MAP['gi'||'jl', 1+9]]),
+CARDINALITY(ARRAY[ROW(1+7, ARRAY[1+4, 4+2], ROW('t', 5+5), MAP['y'||'z', 
9+9])])]]>
+    </Resource>
+    <Resource name="planBefore">
+      <![CDATA[
+LogicalProject(EXPR$0=[+(1, 1)], EXPR$1=[ARRAY(+(1, 1), +(2, 2))], 
EXPR$2=[ROW('a', +(3, 3))], EXPR$3=[MAP(||('a', 'b'), +(6, 6))], 
EXPR$4=[ROW(+(1, 2), ARRAY(+(1, 2), +(2, 3)), ROW('a', +(3, 4)), MAP(||('ab', 
'cd'), +(6, 7)))], EXPR$5=[ARRAY(*(2, 3), 2, 1)], EXPR$6=[ARRAY(ROW(*(4, 2), 
'a'), ROW(+(4, 4), 'b'))], EXPR$7=[ARRAY(MAP(||('abc', 'def'), +(8, 8)), 
MAP(||('ghi', 'jkl'), +(9, 9)))], EXPR$8=[ARRAY(ROW(+(1, 2), ARRAY(+(1, 1), 
+(2, 2)), ROW('a', +(3, 3)), MAP(||('x', 'y'), +(8, 8))) [...]
+  LogicalValues(tuples=[[{ 0 }]])
+]]>
+    </Resource>
+    <Resource name="planAfter">
+      <![CDATA[
+LogicalProject(EXPR$0=[2], EXPR$1=[ARRAY(2, 4)], EXPR$2=[ROW('a', 6)], 
EXPR$3=[MAP('ab', 12)], EXPR$4=[ROW(3, ARRAY(3, 5), ROW('a', 7), MAP('abcd', 
13))], EXPR$5=[ARRAY(6, 2, 1)], EXPR$6=[ARRAY(ROW(8, 'a'), ROW(8, 'b'))], 
EXPR$7=[ARRAY(MAP('abcdef', 16), MAP('ghijkl', 18))], EXPR$8=[ARRAY(ROW(3, 
ARRAY(2, 4), ROW('a', 6), MAP('xy', 16)))], EXPR$9=[3], EXPR$10=[2], 
EXPR$11=[2], EXPR$12=[1])
+  LogicalValues(tuples=[[{ 0 }]])
 ]]>
     </Resource>
   </TestCase>

Reply via email to