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>

Reply via email to