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>