HIVE-29580: CBO: Ambiguous column reference not detected in some CTE/CTAS/other queries - #6676
Open
konstantinb wants to merge 6 commits into
Open
HIVE-29580: CBO: Ambiguous column reference not detected in some CTE/CTAS/other queries#6676konstantinb wants to merge 6 commits into
konstantinb wants to merge 6 commits into
Conversation
…CTAS/other queries
konstantinb
marked this pull request as ready for review
August 13, 2026 00:26
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.



What changes were proposed in this pull request?
HIVE-29580: under CBO, detect ambiguous by-name references to duplicate-named columns that
escape a subquery/CTE boundary, instead of silently binding to an arbitrary candidate.
Mechanism. When the outer RowResolver is built at a subquery boundary and a duplicate alias
collides (
CalcitePlannerblock 9), the survivingColumnInfois marked (ambiguousName); theduplicate remains bound under its internal name, so positional use keeps working. A later
by-name reference through the boundary alias fails with the existing
AMBIGUOUS_COLUMN(Error 10007). Check sites:TypeCheckProcFactory(qualified and unqualifiedcolumn resolution) and
JoinCondTypeCheckProcFactory(both join-condition processors). Themarker is propagated through intermediate projections (
genColListRegex, windowing projection)and excluded from
ColumnInfo.equals/hashCode/isSameColumnForRR.Hive-internal SQL generators fixed along the way (their own output tripped the check —
both regressions were caught by precommit on earlier iterations of this PR and fixed here):
MergeRewriteremitted the target's partition columns twice into the rewritten MERGE sourceprojection;
appendNonPartitionColsOfTargetTablenow omits them for natively partitionedtables (non-native tables keep all columns). No plan/golden churn: the optimizer already
pruned the duplicates before EXPLAIN.
SELECT DISTINCT *over an internal alias) synthesizes onegroup-by reference per RowResolver entry — unique by construction — so the markers are
cleared on that rewrite-private projection (
genColListRegexcopies; the subquery's ownRowResolver keeps its markers for user-written references).
Why are the changes needed?
This completes the reference-time model documented in HIVE-20215. Its author noted in 2018 that
a query of exactly this shape "compile[s] successfully but it should throw an error since
reference to t.c1 is ambiguous" and expected HIVE-19770 to fix it. HIVE-19770 shipped the
tolerance (duplicate renamed to its internal name at the boundary) and a reference-time guard,
but the rename destroys the ambiguity information at exactly the boundary the guard needs it,
so the promised rejection never fired.
The silent binding is a wrong-results hazard, not a cosmetic one:
limit_join_transpose.qcontained a derived table joining on
valuewhose two escapedkeycolumns hold differentdata — whatever
src2.keyreturned was an arbitrary pick between unequal columns. A CTAS oversuch a reference silently persists the arbitrary choice into a table. Standard SQL
(e.g. PostgreSQL) rejects these references outright.
Design notes and deliberate choices
Semantic equality of the candidates is deliberately not considered: it is undecidable in
general and unstable (constant folding can flip it). This means a reference whose candidates
are provably equal via a join predicate (
cross_prod_3.q'son A.key = B.key) is stillrejected — PostgreSQL rejects the same shape for the same reason.
preserving HIVE-19770's behavior. Pinned by the
*_toleratedtests, including master's ownpre-existing
clientpositive/ambiguous_col.q, which is untouched.HIVE-19770/HIVE-20215 deliberately diverged the planners in 2018.
ambiguous_col_noncbo_baseline.qdocuments the non-CBO baseline;ambiguous_col_unreferenced_tolerated.qis its CBO mirror, so the divergence readsshape-by-shape across the pair.
view alias reuse —
ambiguous_col_lateral_view_alias.qis its only coverage). Forboundary shapes the marker now fires earlier, which is why the four pre-existing negative
goldens (
ambiguous_col.q,ambiguous_col_2.q,cbo_ambiguous_colref_in_gby.q,cte_col_alias_clash.q) change message format: same rejection, now with the 10007 error code.CTE materialization (Hive-generated CTAS). The reference-time case is still covered by the
marker (
ambiguous_col_ctas.q— kept as a guard that a user CTAS is never exempted shouldan authorship-based exemption ever be added). Rejecting duplicate definitions in CTAS
remains open under HIVE-12825/HIVE-18568.
if reviewers prefer one.
master-equivalent silent binding — the patch never behaves worse than master.
Does this PR introduce any user-facing change?
Yes (backward incompatible): queries that reference a duplicate-named column through a
subquery/CTE boundary by name now fail to compile under CBO with Error 10007. Two existing
tests relied on such references and were updated with explicit column aliases, preserving their
plans and result data:
cross_prod_3.q(candidates provably equal — the harmless instance) andlimit_join_transpose.q(candidates genuinely unequal — the wrong-results instance). The JIRAshould carry the incompatible-change label.
How was this patch tested?
ambiguous_col_rejected.q(CBO) andambiguous_col_noncbo_baseline.q(non-CBO baseline), consolidated in the
hive.cli.errors.ignoreformat (resourceplan.qprecedent) so each file reads as a boundary spec with one FAILED line per statement.
unqualified), unqualified reference site, USING-clause expansion, DISTINCT + windowing
(marker must survive the windowing projection), lateral view alias reuse (RowResolver guard),
CTAS persistence case.
ambiguous_col_tolerated.q,ambiguous_col_unreferenced_tolerated.q,ambiguous_col_union_distinct_tolerated.q(pins the UNION DISTINCT fix value-sensitively:branches differing only in the duplicate-named column must not collapse).
TestColumnInfo(marker plumbing),TestTypeCheckProcFactory(check helper;file refactored to the
Enclosedrunner to host parameter-free tests alongside the existingparameterized ones),
TestJoinCondTypeCheckProcFactory(driven through the production walkerentry point),
TestSemanticAnalyzer(compile-level CBO rejection/tolerance plus directgenColListRegexpropagation tests),TestMultiInsertSqlGenerator(MERGE projection).test; 13 of the 16 new unit tests fail without this patch (the other 3 are negative controls
that pin the check against over-reach).
TestDbTxnManager2/TestTxnCommands2variants and the MERGE qtests run greenwith zero golden churn.