From db7e29ab940753a320f3b630424b845335af785d Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Thu, 13 Aug 2026 17:22:33 -0700 Subject: [PATCH] [CALCITE-7718] Lambda capturing ROW field crashes at compilation with assertion failure Signed-off-by: Mihai Budiu --- .../org/apache/calcite/plan/RelOptUtil.java | 13 --------- .../calcite/test/SqlToRelConverterTest.java | 28 +++++++++++++++++++ .../calcite/test/SqlToRelConverterTest.xml | 24 ++++++++++++++++ core/src/test/resources/sql/lambda.iq | 26 +++++++++++++++++ 4 files changed, 78 insertions(+), 13 deletions(-) diff --git a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java index 97146b625aa3..42e86b5c4be5 100644 --- a/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java +++ b/core/src/main/java/org/apache/calcite/plan/RelOptUtil.java @@ -70,7 +70,6 @@ import org.apache.calcite.rex.RexExecutorImpl; import org.apache.calcite.rex.RexFieldAccess; import org.apache.calcite.rex.RexInputRef; -import org.apache.calcite.rex.RexLambda; import org.apache.calcite.rex.RexLiteral; import org.apache.calcite.rex.RexLocalRef; import org.apache.calcite.rex.RexNode; @@ -3371,12 +3370,6 @@ private static RexShuttle pushShuttle(final Project project) { @Override public RexNode visitInputRef(RexInputRef ref) { return project.getProjects().get(ref.getIndex()); } - - @Override public RexNode visitLambda(RexLambda lambda) { - // Lambda body references are at a different scope level. - // Do not remap indices inside lambda body against this project. - return lambda; - } }; } @@ -3400,12 +3393,6 @@ private static RexShuttle pushShuttle(final Calc calc) { @Override public RexNode visitInputRef(RexInputRef ref) { return projects.get(ref.getIndex()); } - - @Override public RexNode visitLambda(RexLambda lambda) { - // Lambda body references are at a different scope level. - // Do not remap indices inside lambda body against this calc. - return lambda; - } }; } diff --git a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java index 05093c2d3c2e..e1d3359862e0 100644 --- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java +++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java @@ -158,6 +158,34 @@ public static void checkActualAndReferenceFiles() { } + /** Test case for + * [CALCITE-7718] + * Lambda capturing ROW field crashes at compilation with assertion + * failure. */ + @Test void testLambdaExpressionWithStructCaptureMerge() { + final String sql = "select \"EXISTS\"(array(1, 2), x -> x = t.r.\"EXPR$0\")\n" + + "from (select ROW(1, 2) as r) as t"; + fixture() + .withFactory(c -> + c.withOperatorTable(t -> SqlValidatorTest.operatorTableFor(SqlLibrary.SPARK))) + .withSql(sql) + .ok(); + } + + /** Test case for + * [CALCITE-7718] + * Lambda capturing ROW field crashes at compilation with assertion + * failure. */ + @Test void testLambdaExpressionWithStructCaptureMergeOverScan() { + final String sql = "select \"EXISTS\"(array(1, 2), x -> x = t.r.\"EXPR$0\")\n" + + "from (select ROW(deptno, sal) as r from emp) as t"; + fixture() + .withFactory(c -> + c.withOperatorTable(t -> SqlValidatorTest.operatorTableFor(SqlLibrary.SPARK))) + .withSql(sql) + .ok(); + } + /** Test case for * [CALCITE-3679] * Allow lambda expressions in SQL queries. */ diff --git a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml index bafc21fc6261..bc0062238562 100644 --- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml +++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml @@ -5151,6 +5151,30 @@ LogicalProject(EXPR$0=[HIGHER_ORDER_FUNCTION($7, (X, DEPTNO) -> +(DEPTNO, 1))]) OR(=(N, 1), =(N, 3)))]) LogicalValues(tuples=[[{ 0 }]]) +]]> + + + + + x = t.r."EXPR$0") +from (select ROW(1, 2) as r) as t]]> + + + =(X, ROW(1, 2).EXPR$0))]) + LogicalValues(tuples=[[{ 0 }]]) +]]> + + + + + x = t.r."EXPR$0") +from (select ROW(deptno, sal) as r from emp) as t]]> + + + =(X, ROW($7, $5).EXPR$0))]) + LogicalTableScan(table=[[CATALOG, SALES, EMP]]) ]]> diff --git a/core/src/test/resources/sql/lambda.iq b/core/src/test/resources/sql/lambda.iq index 82808ff19dad..accc60b4e8f4 100644 --- a/core/src/test/resources/sql/lambda.iq +++ b/core/src/test/resources/sql/lambda.iq @@ -145,3 +145,29 @@ select "EXISTS"(array(1, 2, 3), x -> "EXISTS"(array(1, 2, 3), y -> x + y = 4)) a (1 row) !ok + +# [CALCITE-7718] Lambda capturing ROW field crashes at compilation with +# assertion failure. +# Lambda captures a field of a struct value from the enclosing query. +select "EXISTS"(array(1, 2), x -> x = t.r."EXPR$0") from (select ROW(1, 2) as r) as t; ++--------+ +| EXPR$0 | ++--------+ +| true | ++--------+ +(1 row) + +!ok + +# Same, but the captured struct is built from table columns +# Jane is in dept 10 +select "EXISTS"(array(5, 10), x -> x = t.r."EXPR$0") +from (select ROW(deptno, 1) as r from emp where ename = 'Jane') as t; ++--------+ +| EXPR$0 | ++--------+ +| true | ++--------+ +(1 row) + +!ok