From f0079bbdd691c0d06b1b3407dbd875b4123dcfba Mon Sep 17 00:00:00 2001 From: Mihai Budiu Date: Wed, 15 Jul 2026 11:37:07 -0700 Subject: [PATCH] [SQL] Fix lambda handling of struct fields Signed-off-by: Mihai Budiu --- .../calciteCompiler/SqlToRelCompiler.java | 5 ++ .../ir/expression/DBSPZSetExpression.java | 14 +++-- .../compiler/sql/simple/Regression3Tests.java | 61 +++++++++++++++++++ sql-to-dbsp-compiler/calcite_version.env | 2 +- 4 files changed, 76 insertions(+), 6 deletions(-) diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/main/java/org/dbsp/sqlCompiler/compiler/frontend/calciteCompiler/SqlToRelCompiler.java b/sql-to-dbsp-compiler/SQL-compiler/src/main/java/org/dbsp/sqlCompiler/compiler/frontend/calciteCompiler/SqlToRelCompiler.java index 57782723dfb..305f1e183f8 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/main/java/org/dbsp/sqlCompiler/compiler/frontend/calciteCompiler/SqlToRelCompiler.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/main/java/org/dbsp/sqlCompiler/compiler/frontend/calciteCompiler/SqlToRelCompiler.java @@ -692,6 +692,11 @@ public boolean isGroupByAlias() { public boolean isHavingAlias() { return true; } + + @Override + public boolean allowLambdaClosure() { + return false; + } } /** Add a new set of operators to the operator table. Creates a new validator, converter */ diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/main/java/org/dbsp/sqlCompiler/ir/expression/DBSPZSetExpression.java b/sql-to-dbsp-compiler/SQL-compiler/src/main/java/org/dbsp/sqlCompiler/ir/expression/DBSPZSetExpression.java index 4b6bd947aaa..3159d2227d5 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/main/java/org/dbsp/sqlCompiler/ir/expression/DBSPZSetExpression.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/main/java/org/dbsp/sqlCompiler/ir/expression/DBSPZSetExpression.java @@ -177,12 +177,16 @@ public DBSPExpression castRecursive(DBSPExpression expression, DBSPType type) { return expression.cast(expression.getNode(), type, DBSPCastExpression.CastType.SqlUnsafe); } else if (type.is(DBSPTypeArray.class)) { DBSPTypeArray array = type.to(DBSPTypeArray.class); - DBSPArrayExpression vecLit = expression.to(DBSPArrayExpression.class); - if (vecLit.data == null) { - return new DBSPArrayExpression(array, type.mayBeNull); + if (expression.is(DBSPArrayExpression.class)) { + DBSPArrayExpression vecLit = expression.to(DBSPArrayExpression.class); + if (vecLit.data == null) { + return new DBSPArrayExpression(array, type.mayBeNull); + } + List fields = Linq.map(vecLit.data, e -> castRecursive(e, array.getElementType())); + return new DBSPArrayExpression(expression.getNode(), type, fields); + } else { + return expression.cast(CalciteObject.EMPTY, type, DBSPCastExpression.CastType.SqlUnsafe); } - List fields = Linq.map(vecLit.data, e -> castRecursive(e, array.getElementType())); - return new DBSPArrayExpression(expression.getNode(), type, fields); } else if (type.is(DBSPTypeTupleBase.class)) { DBSPTypeTupleBase tuple = type.to(DBSPTypeTupleBase.class); DBSPExpression[] fields = new DBSPExpression[tuple.size()]; diff --git a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java index 53c5bd5554c..617821c2f01 100644 --- a/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java +++ b/sql-to-dbsp-compiler/SQL-compiler/src/test/java/org/dbsp/sqlCompiler/compiler/sql/simple/Regression3Tests.java @@ -728,4 +728,65 @@ public void testEnforcePositiveInputs() { this.runtimeFail(compiler, "REMOVE FROM T VALUES (1);", "Table t: negative weight found"); } + + @Test + public void issue6453() { + var ccs = this.getCCS(""" + CREATE TABLE t (id INT, arr ROW(name VARCHAR, score INT) ARRAY); + CREATE MATERIALIZED VIEW v AS + SELECT id, TRANSFORM(arr, x -> x.name) AS names FROM t;"""); + String insert = """ + INSERT INTO t VALUES + -- Simple single-element array + (1, ARRAY[ + ROW('alice', 10) + ]), + + -- Multi-element array + (2, ARRAY[ + ROW('bob', 5), + ROW('carol', 7), + ROW('dave', 3) + ]), + + -- Empty array; direct casts of ARRAY[] do not work + (3, ARRAY_REMOVE(ARRAY[NULL], NULL)), + + -- Array with NULL element + (4, ARRAY[ + NULL, + ROW('eve', 42) + ]), + + -- Repeated names, varied scores + (5, ARRAY[ + ROW('zoe', 1), + ROW('zoe', 99), + ROW('max', 50) + ]), + + -- Stress test: longer array + (6, ARRAY[ + ROW('p1', 10), + ROW('p2', 20), + ROW('p3', 30), + ROW('p4', 40) + ]);"""; + String expected = """ + id | names + ------------- + 1 | { alice} + 2 | { bob, carol, dave} + 3 | {} + 4 | {NULL, eve} + 5 | { zoe, zoe, max} + 6 | { p1, p2, p3, p4}"""; + ccs.stepWeightOne(insert, expected); + + ccs = this.getCCS(""" + CREATE TABLE t (id INT, arr ROW(name VARCHAR, score INT) ARRAY); + CREATE MATERIALIZED VIEW v AS + SELECT id, TRANSFORM(arr, x -> (x).name) AS names FROM t;"""); + ccs.stepWeightOne(insert, expected); + } } diff --git a/sql-to-dbsp-compiler/calcite_version.env b/sql-to-dbsp-compiler/calcite_version.env index 062f571c5a4..6a5138dd66a 100644 --- a/sql-to-dbsp-compiler/calcite_version.env +++ b/sql-to-dbsp-compiler/calcite_version.env @@ -3,5 +3,5 @@ CALCITE_REPO="https://github.com/apache/calcite.git" #CALCITE_REPO="https://github.com/mihaibudiu/calcite" CALCITE_BRANCH="main" CALCITE_CURRENT="1.42.0" -CALCITE_NEXT_COMMIT="7311760481af747175d0119ebdb83d58c14fc684" +CALCITE_NEXT_COMMIT="0c28ff962775c2d03273b7094fc92589bfb3ae6a" CALCITE_NEXT="1.43.0"