This is an automated email from the ASF dual-hosted git repository.
mihaibudiu 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 26e16dcc85 [CALCITE-7776] UNNEST WITH ORDINALITY over a column of type
ANY has no ORDINALITY column
26e16dcc85 is described below
commit 26e16dcc856976078dcaaf4cb0e47093a87696bd
Author: Akash Kumar <[email protected]>
AuthorDate: Thu Sep 24 21:56:57 2026 +0530
[CALCITE-7776] UNNEST WITH ORDINALITY over a column of type ANY has no
ORDINALITY column
UNNEST of a column declared ANY (as in schema-less systems) ignored
WITH ORDINALITY: the ANY branches of SqlUnnestOperator#inferReturnType
and Uncollect#deriveRowType returned their single-column row type
before reaching the block that appends the ORDINALITY column, so the
row type had only one field regardless of WITH ORDINALITY. Aliasing
both columns (e.g. "UNNEST(t.tags) WITH ORDINALITY AS T(x, o)") then
failed validation with "List of column aliases must have same degree
as table".
Append the ORDINALITY column in the ANY branch of both methods before
returning, mirroring the existing ARRAY/MULTISET/MAP branches.
Generated-by: Claude Sonnet 5 (claude-sonnet-5)
Co-Authored-By: Claude Sonnet 5 <[email protected]>
---
.../java/org/apache/calcite/rel/core/Uncollect.java | 10 ++++++----
.../java/org/apache/calcite/sql/SqlUnnestOperator.java | 11 ++++++-----
.../org/apache/calcite/test/SqlToRelConverterTest.java | 13 +++++++++++++
.../org/apache/calcite/test/SqlToRelConverterTest.xml | 18 ++++++++++++++++++
4 files changed, 43 insertions(+), 9 deletions(-)
diff --git a/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java
b/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java
index 039a17efbf..4716cae106 100644
--- a/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java
+++ b/core/src/main/java/org/apache/calcite/rel/core/Uncollect.java
@@ -249,10 +249,12 @@ public static RelDataType deriveUncollectRowType(RelNode
rel,
&& fields.get(0).getType().getSqlTypeName() == SqlTypeName.ANY) {
// Component type is unknown to Uncollect, build a row type with input
column name
// and Any type.
- return builder
- .add(requireAlias ? itemAliases.get(0) : fields.get(0).getName(),
SqlTypeName.ANY)
- .nullable(true)
- .build();
+ builder.add(requireAlias ? itemAliases.get(0) : fields.get(0).getName(),
SqlTypeName.ANY)
+ .nullable(true);
+ if (withOrdinality) {
+ builder.add(SqlUnnestOperator.ORDINALITY_COLUMN_NAME,
SqlTypeName.INTEGER);
+ }
+ return builder.build();
}
// With multiple collections, zip semantics pads shorter collections with
diff --git a/core/src/main/java/org/apache/calcite/sql/SqlUnnestOperator.java
b/core/src/main/java/org/apache/calcite/sql/SqlUnnestOperator.java
index 61ada97823..4875631259 100644
--- a/core/src/main/java/org/apache/calcite/sql/SqlUnnestOperator.java
+++ b/core/src/main/java/org/apache/calcite/sql/SqlUnnestOperator.java
@@ -69,11 +69,12 @@ public SqlUnnestOperator(boolean withOrdinality) {
if (type.getSqlTypeName() == SqlTypeName.ANY) {
// Unnest Operator in schema less systems returns one column as the
output
// $unnest is a placeholder to specify that one column with type ANY
is output.
- return builder
- .add("$unnest",
- SqlTypeName.ANY)
- .nullable(true)
- .build();
+ builder.add("$unnest", SqlTypeName.ANY)
+ .nullable(true);
+ if (withOrdinality) {
+ builder.add(ORDINALITY_COLUMN_NAME, SqlTypeName.INTEGER);
+ }
+ return builder.build();
}
if (type.isStruct()) {
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 88fa2a27c8..acdfeb7bb6 100644
--- a/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
+++ b/core/src/test/java/org/apache/calcite/test/SqlToRelConverterTest.java
@@ -5127,6 +5127,19 @@ void checkCorrelatedMapSubQuery(boolean expand) {
sql(sql).withDynamicTable().ok();
}
+ /** Test case for
+ * <a
href="https://issues.apache.org/jira/browse/CALCITE-7776">[CALCITE-7776]
+ * UNNEST WITH ORDINALITY over a column of type ANY has no ORDINALITY
+ * column</a>. A column of a dynamic table has type ANY; UNNEST WITH
+ * ORDINALITY over such a column must still produce an ORDINALITY
+ * column, so that both it and the unnested value can be aliased. */
+ @Test void testDynamicSchemaUnnestWithOrdinality() {
+ final String sql = "select t1.c_nationkey, t3.fake_col3, t3.o\n"
+ + "from SALES.CUSTOMER as t1,\n"
+ + "unnest(t1.fake_col) with ordinality as t3(fake_col3, o)";
+ sql(sql).withDynamicTable().ok();
+ }
+
@Test void testStarDynamicSchemaUnnest() {
final String sql = "select *\n"
+ "from SALES.CUSTOMER as t1,\n"
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 2c32494f60..d217079f7a 100644
--- a/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/SqlToRelConverterTest.xml
@@ -2329,6 +2329,24 @@ LogicalProject(C_NATIONKEY=[$1], FAKE_COL3=[$2])
Uncollect
LogicalProject(FAKE_COL=[$cor0.FAKE_COL])
LogicalValues(tuples=[[{ 0 }]])
+]]>
+ </Resource>
+ </TestCase>
+ <TestCase name="testDynamicSchemaUnnestWithOrdinality">
+ <Resource name="sql">
+ <![CDATA[select t1.c_nationkey, t3.fake_col3, t3.o
+from SALES.CUSTOMER as t1,
+unnest(t1.fake_col) with ordinality as t3(fake_col3, o)]]>
+ </Resource>
+ <Resource name="plan">
+ <![CDATA[
+LogicalProject(C_NATIONKEY=[$1], FAKE_COL3=[$2], O=[$3])
+ LogicalCorrelate(correlation=[$cor0], joinType=[inner],
requiredColumns=[{0}])
+ LogicalTableScan(table=[[CATALOG, SALES, CUSTOMER]])
+ LogicalProject(FAKE_COL3=[$0], O=[$1])
+ Uncollect(withOrdinality=[true])
+ LogicalProject(FAKE_COL=[$cor0.FAKE_COL])
+ LogicalValues(tuples=[[{ 0 }]])
]]>
</Resource>
</TestCase>