Skip to content

[CALCITE-7669] Uncollect should support the Trino semantics of UNNEST - #5118

Draft
mihaibudiu wants to merge 2 commits into
apache:mainfrom
mihaibudiu:issue7669
Draft

[CALCITE-7669] Uncollect should support the Trino semantics of UNNEST#5118
mihaibudiu wants to merge 2 commits into
apache:mainfrom
mihaibudiu:issue7669

Conversation

@mihaibudiu

Copy link
Copy Markdown
Contributor

Jira Link

CALCITE-7669

Changes Proposed

There are two separate commits, if independent interest. The first commit only strengthens the validator for rejecting UNNEST on the right side of some JOIN operators.

The semantics of the UNNEST operator changes depending on conformance: for Presto/Trino UNNEST(a) where a is a ROW ARRAY produces a single column; for other conformances it produces as many columns as there are fields in ROW.

This PR makes the choice of semantics explicit at all levels of the representation: the Uncollect operator, and the Enumerable representation by adding a new boolean flag to control the behavior. The flag clearly affects type inference too.

This PR is a stand-alone fragment extracted from #5031

Signed-off-by: Mihai Budiu <mbudiu@feldera.com>
Signed-off-by: Mihai Budiu <mbudiu@feldera.com>
@sonarqubecloud

Copy link
Copy Markdown

@xuzifu666 xuzifu666 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the overall implementation is fine; I've left some comments for reference.

? typeFactory.enforceTypeWithNullability(componentType, true)
RelDataType elementType = componentType.isStruct()
? typeFactory.builder().kind(componentType.getStructKind())
.addAll(componentType.getFieldList()).build()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The return type here is NOT NULL, so the isNullable mentioned above(line 101) isn't actually used in this branch; it might be worth verifying whether this is appropriate.
In Trino, the output columns of UNNEST(array of nullable row) are nullable.

@SuppressWarnings({"rawtypes", "unchecked"})
private static final Function1<List<Object>, Enumerable<Object>> STRUCT_LIST_AS_ENUMERABLE =
a0 -> a0 == null ? Linq4j.emptyEnumerable()
: Linq4j.asEnumerable(a0).select(e -> (Object) ((List) e).toArray());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Arrays containing NULL elements, such as UNNEST(ARRAY[ROW(1,'x'), CAST(NULL AS ROW(...))]), trigger a direct NPE (the SCALAR path avoids this issue as it performs no conversion).
Trino currently produces a row of NULLs for this case.
It is recommended to change the logic to e == null ? null : ... and add a test case that includes NULL elements.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An attempt to fix this bug has revealed some independent problems in RelToLixTranslator, which need to be fixed fix. I will file a separate issue and mark this as draft until the other one is fixed.

Comment thread core/src/main/java/org/apache/calcite/rel/core/Uncollect.java
@mihaibudiu
mihaibudiu marked this pull request as draft July 27, 2026 23:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants