[CALCITE-7614] UNNEST of an unqualified struct-rooted array path fails validation: "Column 's.s' not found"#5033
Conversation
|
@julianhyde could you review this small |
| int size = identifier.names.size(); | ||
| int i = size - 1; | ||
| // Snapshot: resolution below may rewrite identifier's names in place [CALCITE-7614] | ||
| final SqlIdentifier identifierSnapshot = |
There was a problem hiding this comment.
I would call this "originalIdentifier"
|
CI is not happy, can you take a look? |
|
Fixed. |
|
Please squash the commits so we can merge this. |
…s validation: "Column 's.s' not found" When the operand of UNNEST is an unqualified identifier whose leading component is a PEEK_FIELDS struct column (e.g. UNNEST(s.arr) where s is a PEEK_FIELDS struct containing array field arr), validation failed with "Column 's.s' not found in table 't'", while the table-qualified form UNNEST(r.s.arr) worked. While DelegatingScope.fullyQualify resolves the qualifying table for the unqualified operand, that resolution re-enters validation of the UNNEST namespace, which rewrites the very same operand identifier's names in place to the fully-qualified form. fullyQualify then re-qualified the already-qualified identifier, duplicating the struct-column segment and producing the doubled "s.s". Fix fullyQualify to qualify a copy of the identifier taken before the re-entrant resolution, so the PEEK_FIELDS branch always works from the original names. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
|
|
Squashed |
|
@takaaki7 Please note that Calcite does not recommend using agents like Claude as collaborators; please only include your own contributions in subsequent submissions. |
|
I don't think we have a policy not to use agents. A tool that solves the problem is a good tool. But the users should scrutinize code from the agents carefully before submitting a PR, ensuring that it is compact and clear. Sometimes these agents solve simple problems in very complicated ways. You cannot expect other reviewers to clean up after agents, you have to do it yourself before you submit. |
|
Thanks for the feedbacks. Understood on the co-author tags. I'll properly review things on my end to avoid AI slop. |



Jira Link
CALCITE-7614
Changes Proposed
When the operand of
UNNESTis an unqualified identifier whose leading component is aPEEK_FIELDSstruct column, validation fails:Root cause
DelegatingScope.fullyQualifyqualifies the unqualified operand by first resolving the table that owns thePEEK_FIELDScolumn. That resolution re-enters validation of theUNNESTnamespace, which expands the same operandSqlIdentifierand rewrites its name list in place to the fully-qualified form (SqlValidatorImpl.validateIdentifier→SqlIdentifier.assignNamesFrom). Control then returns tofullyQualify, which re-qualifies the now-already-qualified identifier, prepending the table/struct segment a second time and producing the doubledS.S.The table-qualified form is unaffected because re-qualifying
r.s.arris idempotent.Fix
DelegatingScope.fullyQualifynow snapshots the identifier before the re-entrant resolution and builds the qualifiedPEEK_FIELDSidentifier from that snapshot, so it always works from the original names. The change is a no-op when no re-entrant rewrite occurs. The production change is confined toDelegatingScope.java.Tests
SqlValidatorTest.testUnnestPeekFieldsArrayColumncovering qualified/unqualified ×CROSS JOIN/comma-join.PEEK_FIELDSstruct type containing an array field (Fixture.peekArrayType) and aDEPT_NESTED_PEEK(DEPTNO, S)table in the mock catalog (MockCatalogReaderSimple), since no such column existed.SqlAdvisorTest's expected SALES completion list to include the new table../gradlew :core:testpasses (15649 tests, 0 failed).