[CALCITE-7819] RelMdTableReferences returns null for TableFunctionScan with relational inputs - #5288
Conversation
7a691ee to
818a15b
Compare
zzwqqq
left a comment
There was a problem hiding this comment.
Just to make sure I’m following: are you saying getTableReferences doesn’t handle TableFunctionScan? If so, maybe the PR description could be clearer about the problem you’re trying to solve.
| */ | ||
| public @Nullable Set<RelTableRef> getTableReferences(TableFunctionScan rel, | ||
| RelMetadataQuery mq) { | ||
| return getTableReferences(rel.getInputs(), mq); |
There was a problem hiding this comment.
Should we also handle a RexSubQuery inside rexCall of TableFunctionScan
There was a problem hiding this comment.
Good catch. SubQueryRemoveRule already handles a RexSubQuery in TableFunctionScan.getCall(). I’ve added the corresponding table-reference handling and tests.
Dwrite
left a comment
There was a problem hiding this comment.
LGTM. Reusing the existing getTableReferences(List, RelMetadataQuery) helper keeps the behavior consistent with SetOp and correctly propagates metadata through TableFunctionScan.
Thanks for pointing that out. I’ve updated both the issue description and the implementation of the fix. |
|
Please squash the commits for merging |
637a952 to
5d9b599
Compare
Done. |
vlsi
left a comment
There was a problem hiding this comment.
@zzwqqq @mihaibudiu, could we hold the merge until we settle the sub-query question below? I think the relational-input part is ready as is.
Thanks, the relational-input part fixes the case from the Jira: for select * from table(tumble(table emp, descriptor(hiredate), interval '1' minute)) I now get [[CATALOG, SALES, EMP].#0] instead of null. I have concerns about the sub-query part, plus a few smaller comments.
Sub-queries in the call
I'd suggest removing the RexSubQuery handling from this PR and filing a separate Jira for it. The sub-query tables show up only in plans where the sub-query is still in the call, and only for TableFunctionScan:
Project,Filter,Join, andCalcdon't look at the sub-queries in their expressions. Withexpand=false,select (select max(sal) from emp) from deptandselect * from dept where deptno in (select deptno from emp)both return[[CATALOG, SALES, DEPT].#0], with noEMP.DEDUP(CURSOR(dept), (select count(*) from emp))now returns[DEPT.#0, EMP.#0], so where the sub-query sits changes the answer.- After
CoreRules.TABLE_FUNCTION_SCAN_SCALAR_QUERY_TO_CORRELATE, the same plan becomesProject(Correlate(Aggregate(sub-query), TableFunctionScan)), andgetTableReferencesreturnsnull, becauseRelMdTableReferenceshas noCorrelatehandler. For theDEDUPplan above I get[DEPT.#0, EMP.#0]before the rule andnullafter it.
A follow-up could handle Correlate and RexSubQuery the same way in every node. The Jira title covers only relational inputs, and the sub-query change is not mentioned in the Jira, the PR description, or the squashed commit message.
A function scan with no inputs
TABLE(RAMP(3)) used to return null and now returns an empty set, while Values still returns null. RelMdColumnOrigins makes the same choice for a leaf TableFunctionScan, so I'm fine with it, but it should be in the Javadoc: a user-defined table function that reads a table on its own is now reported as reading none.
Javadoc
Table references from TableFunctionScan.matches the other methods, but the new handler behaves differently from them in two ways that a caller can't guess: it returns an empty set when there are no inputs, and it returnsnullif the references of any input can't be determined. Please state both, plus the sub-query handling if it stays.- The helper's comment,
Returns table references from relational inputs and sub-queries., doesn't match what the helper does: it takes any list of nodes, andSetOppasses no sub-queries. What a reader needs to know is that repeated references to the same table get distinct entity numbers. Something like:Returns the union of the table references of {@code inputs}, numbering repeated references to the same table apart, or null if the references of any input cannot be determined.
Tests
- Against the code before the fix,
…SameTableInputsand…InputAndScalarSubQueryfail with a bareNullPointerExceptionfromSets.newTreeSet(null), so the report doesn't say thatnullcame back.sortsAs(...), which the neighboring tests use, would print it. - Missing cases, if the sub-query part stays: a sub-query with no relational input (for example
RAMP((select count(*) from emp))), a sub-query over an unknown node, which should returnnull, and a sub-query nested inside an expression rather than passed as a direct operand. …InputAndScalarSubQuerypasses a scalar sub-query toDEDUP, whose operands are cursors. The plan builds only becauseRelBuilderdoesn't validate operands.RAMPwould give a realistic plan.- A SQL-level test for the TUMBLE case from the Jira would match the shape of the neighboring tests (
sql(...).toRel()). - Minor: in
…ZeroInputs,assertThat(tableReferences, empty())can replace thenotNullValue()andhasSize(0)pair.
Description
Nit: there is a stray backslash before `[hr, employee].#0`.
|
@ehds please take a look at the last review and try to address the questions |
@vlsi Thanks for the thorough review. As you pointed out, other operators don’t account for sub-queries in their expressions, and Correlate isn’t handled either, so I think a separate Jira makes sense. I’ve removed the RexSubQuery handling from this PR and updated the Javadocs and tests based on your feedback. @zzwqqq @mihaibudiu what do you think? |
@ehds I think it’s ok to separate the subquery-related issues from this one. Could you please also file a Jira ticket so we don’t miss it? |
I’ve opened a separate Jira issue for the sub-query and Correlate cases: CALCITE-7825. |
vlsi
left a comment
There was a problem hiding this comment.
Thanks for the updates, my earlier comments are addressed. The sub-query handling moved to CALCITE-7825, the Javadoc states when the handler returns an empty set and when it returns null, and there is now a SQL-level test for the TUMBLE query from the Jira.
I rebased the branch on current main: RelMetadataTest, the materialized view tests, and SqlToRelConverterTest pass. Against the old RelMdTableReferences, three of the four new tests fail with but: was null.
The PR has two commits again, and the second one, Restrict TableFunctionScan table references to relational inputs, has no [CALCITE-7819] prefix. The commits should be squashed into one before the merge, either by @ehds in this PR or by the committer when merging.
|
please squash the commits so we can merge |
…n with relational inputs
c761f2d to
d27fa05
Compare
Done. |
|



Jira Link
CALCITE-7819
RelMetadataQuery#getTableReferencesreturnsnullfor a plan containing aTableFunctionScan, even when the function has a relational input containing aTableScan. For example, aTUMBLEtable function can produce:For this plan,
mq.getTableReferences(root)returnsnullinstead of a reference to \[hr, employee].#0.RelMdTableReferenceshas no handler forTableFunctionScan, so the call falls through to its catch-allRelNodehandler.Changes Proposed
Add a
TableFunctionScanhandler that collects table references from its relational inputs. It reuses the logic forSetOp, including the handling of repeated references to the same table.