From 6bcd19fd00608e3dec8a2c211e2e5d2d9b9429ab Mon Sep 17 00:00:00 2001 From: Konstantin Bereznyakov Date: Tue, 4 Aug 2026 16:58:44 -0700 Subject: [PATCH 1/5] HIVE-29580: CBO: Ambiguous column reference not detected in some CTE/CTAS/other queries --- .../hadoop/hive/ql/exec/ColumnInfo.java | 16 +++ .../hadoop/hive/ql/parse/CalcitePlanner.java | 15 +++ .../hive/ql/parse/SemanticAnalyzer.java | 5 + .../type/JoinCondTypeCheckProcFactory.java | 2 + .../ql/parse/type/TypeCheckProcFactory.java | 10 ++ .../parse/type/TestAmbiguousColumnName.java | 58 ++++++++++ .../clientnegative/ambiguous_col_2_noncbo.q | 3 + .../ambiguous_col_aggregate_noncbo.q | 3 + .../clientnegative/ambiguous_col_cte.q | 3 + .../clientnegative/ambiguous_col_cte_noncbo.q | 4 + .../ambiguous_col_cte_unreferenced_noncbo.q | 3 + .../ambiguous_col_distinct_window.q | 1 + .../ambiguous_col_exists_having_noncbo.q | 3 + .../ambiguous_col_exists_noncbo.q | 3 + .../clientnegative/ambiguous_col_join_cond.q | 7 ++ .../ambiguous_col_join_cond_unqual.q | 5 + .../clientnegative/ambiguous_col_join_using.q | 1 + .../ambiguous_col_join_wildcard_noncbo.q | 4 + .../ambiguous_col_lateral_view_alias.q | 7 ++ .../ambiguous_col_nested_star_noncbo.q | 2 + .../clientnegative/ambiguous_col_noncbo.q | 3 + .../clientnegative/ambiguous_col_union.q | 1 + .../ambiguous_col_union_noncbo.q | 2 + .../ambiguous_col_unqualified_ref.q | 8 ++ .../ambiguous_col_unreferenced_noncbo.q | 2 + .../ambiguous_colref_in_gby_noncbo.q | 3 + .../queries/clientnegative/ctas_dup_column.q | 1 + .../clientnegative/ctas_dup_column_join.q | 3 + .../ctas_dup_column_join_noncbo.q | 4 + .../clientnegative/ctas_dup_column_noncbo.q | 2 + .../clientpositive/ambiguous_col_tolerated.q | 14 +++ .../ambiguous_col_unreferenced_tolerated.q | 13 +++ .../clientnegative/ambiguous_col.q.out | 2 +- .../clientnegative/ambiguous_col_2.q.out | 2 +- .../ambiguous_col_2_noncbo.q.out | 9 ++ .../ambiguous_col_aggregate_noncbo.q.out | 1 + .../clientnegative/ambiguous_col_cte.q.out | 1 + .../ambiguous_col_cte_noncbo.q.out | 1 + ...mbiguous_col_cte_unreferenced_noncbo.q.out | 1 + .../ambiguous_col_distinct_window.q.out | 1 + .../ambiguous_col_exists_having_noncbo.q.out | 1 + .../ambiguous_col_exists_noncbo.q.out | 1 + .../ambiguous_col_join_cond.q.out | 1 + .../ambiguous_col_join_cond_unqual.q.out | 1 + .../ambiguous_col_join_using.q.out | 1 + .../ambiguous_col_join_wildcard_noncbo.q.out | 17 +++ .../ambiguous_col_lateral_view_alias.q.out | 9 ++ .../ambiguous_col_nested_star_noncbo.q.out | 1 + .../clientnegative/ambiguous_col_noncbo.q.out | 1 + .../clientnegative/ambiguous_col_union.q.out | 1 + .../ambiguous_col_union_noncbo.q.out | 1 + .../ambiguous_col_unqualified_ref.q.out | 1 + .../ambiguous_col_unreferenced_noncbo.q.out | 1 + .../ambiguous_colref_in_gby_noncbo.q.out | 9 ++ .../cbo_ambiguous_colref_in_gby.q.out | 2 +- .../clientnegative/ctas_dup_column.q.out | 1 + .../clientnegative/ctas_dup_column_join.q.out | 17 +++ .../ctas_dup_column_join_noncbo.q.out | 17 +++ .../ctas_dup_column_noncbo.q.out | 1 + .../clientnegative/cte_col_alias_clash.q.out | 2 +- .../llap/ambiguous_col_tolerated.q.out | 101 ++++++++++++++++++ ...ambiguous_col_unreferenced_tolerated.q.out | 101 ++++++++++++++++++ 62 files changed, 513 insertions(+), 4 deletions(-) create mode 100644 ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestAmbiguousColumnName.java create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_2_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_aggregate_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_cte.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_distinct_window.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_exists_having_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_exists_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_join_cond.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_join_cond_unqual.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_join_using.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_join_wildcard_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_lateral_view_alias.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_nested_star_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_union.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_union_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_unqualified_ref.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_unreferenced_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ambiguous_colref_in_gby_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ctas_dup_column.q create mode 100644 ql/src/test/queries/clientnegative/ctas_dup_column_join.q create mode 100644 ql/src/test/queries/clientnegative/ctas_dup_column_join_noncbo.q create mode 100644 ql/src/test/queries/clientnegative/ctas_dup_column_noncbo.q create mode 100644 ql/src/test/queries/clientpositive/ambiguous_col_tolerated.q create mode 100644 ql/src/test/queries/clientpositive/ambiguous_col_unreferenced_tolerated.q create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_2_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_aggregate_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_cte.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_distinct_window.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_exists_having_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_exists_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_join_cond.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_join_cond_unqual.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_join_using.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_join_wildcard_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_lateral_view_alias.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_nested_star_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_union.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_union_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_unqualified_ref.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_unreferenced_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ambiguous_colref_in_gby_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ctas_dup_column.q.out create mode 100644 ql/src/test/results/clientnegative/ctas_dup_column_join.q.out create mode 100644 ql/src/test/results/clientnegative/ctas_dup_column_join_noncbo.q.out create mode 100644 ql/src/test/results/clientnegative/ctas_dup_column_noncbo.q.out create mode 100644 ql/src/test/results/clientpositive/llap/ambiguous_col_tolerated.q.out create mode 100644 ql/src/test/results/clientpositive/llap/ambiguous_col_unreferenced_tolerated.q.out diff --git a/ql/src/java/org/apache/hadoop/hive/ql/exec/ColumnInfo.java b/ql/src/java/org/apache/hadoop/hive/ql/exec/ColumnInfo.java index b96936904ff2..ca132cfd00ac 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/exec/ColumnInfo.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/exec/ColumnInfo.java @@ -59,6 +59,8 @@ public class ColumnInfo implements Serializable { private boolean isHiddenVirtualCol; + private boolean ambiguousName; + private String typeName; private final boolean nullable; @@ -129,9 +131,23 @@ public ColumnInfo(ColumnInfo columnInfo) { this.isVirtualCol = columnInfo.getIsVirtualCol(); this.isHiddenVirtualCol = columnInfo.isHiddenVirtualCol(); this.nullable = columnInfo.nullable; + this.ambiguousName = columnInfo.ambiguousName; this.setType(columnInfo.getType()); } + /** + * True when this column's alias collided with another column's at a subquery/CTE boundary: + * the column stays usable positionally (star expansion, count(*)) but any by-name reference + * is ambiguous and must be rejected. + */ + public boolean hasAmbiguousName() { + return ambiguousName; + } + + public void setAmbiguousName(boolean ambiguousName) { + this.ambiguousName = ambiguousName; + } + public String getTypeName() { return this.typeName; } diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java index 25489f477f55..266c6b07edcf 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java @@ -1556,6 +1556,11 @@ public RelNode apply(RelOptCluster cluster, RelOptSchema relOptSchema, SchemaPlu resultSchema = convertRowSchemaToResultSetSchema(relToHiveRR.get(calcitePlan), (forViewCreation || getQB().isMaterializedView()) ? false : HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVE_RESULTSET_USE_UNIQUE_COLUMN_NAMES)); + if (getQB().isCTAS()) { + // check the non-uniquified names: getNewColAlias would rename a duplicate away + ParseUtils.validateColumnNameUniqueness( + convertRowSchemaToResultSetSchema(relToHiveRR.get(calcitePlan), false)); + } } catch (SemanticException e) { semanticException = e; throw new RuntimeException(e); @@ -4545,6 +4550,7 @@ && isRegex( ColumnInfo colInfo = outputRR.getColumnInfos().get(i); ColumnInfo newColInfo = new ColumnInfo(colInfo.getInternalName(), colInfo.getType(), colInfo.getTabAlias(), colInfo.getIsVirtualCol()); + newColInfo.setAmbiguousName(colInfo.hasAmbiguousName()); groupByOutputRowResolver.put(colInfo.getTabAlias(), colInfo.getAlias(), newColInfo); if (gbyKeyExpressions != null && gbyKeyExpressions.size() == outputRR.getColumnInfos().size()) { groupByOutputRowResolver.putExpression(gbyKeyExpressions.get(i), colInfo); @@ -4887,6 +4893,15 @@ private RelNode genLogicalPlan(QB qb, boolean outerMostQB, } else if ("".equals(tmp[0]) || tmp[1] == null) { // ast expression is not a valid column name for table tmp[1] = colInfo.getInternalName(); + } else if (newRR.get(alias, tmp[1]) != null) { + // Duplicate alias escaping the subquery boundary: tolerated for positional use + // (HIVE-19770), but poison the name so a later by-name reference fails (HIVE-29580). + // Binding the duplicate to its internal name here is deliberate, not redundant: + // putWithCheck would otherwise do it via its own fallback AND call keepAmbiguousInfo, + // whose reference-time throw in RowResolver.get would then shadow this marker with a + // differently formatted message. Do not "simplify" this line away. + newRR.get(alias, tmp[1]).setAmbiguousName(true); + tmp[1] = colInfo.getInternalName(); } newRR.putWithCheck(alias, tmp[1], colInfo.getInternalName(), newCi); } diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java index 7042cff53874..dc6143e0f0f4 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java @@ -4014,6 +4014,7 @@ Integer genColListRegex(String colRegex, String tabAlias, ASTNode sel, colList.add(Pair.of(colInfo, colSrcRR)); oColInfo = new ColumnInfo(getColumnInternalName(pos), colInfo.getType(), colInfo.getTabAlias(), colInfo.getIsVirtualCol(), colInfo.isHiddenVirtualCol()); + oColInfo.setAmbiguousName(colInfo.hasAmbiguousName()); inputColsProcessed.put(colInfo, oColInfo); } if (ensureUniqueCols) { @@ -4101,6 +4102,7 @@ Integer genColListRegex(String colRegex, String tabAlias, ASTNode sel, colList.add(Pair.of(colInfo, input)); oColInfo = new ColumnInfo(getColumnInternalName(pos), colInfo.getType(), colInfo.getTabAlias(), colInfo.getIsVirtualCol(), colInfo.isHiddenVirtualCol()); + oColInfo.setAmbiguousName(colInfo.hasAmbiguousName()); inputColsProcessed.put(colInfo, oColInfo); } assert nonNull(tmp); @@ -7988,6 +7990,9 @@ protected Operator genFileSinkPlan(String dest, QB qb, Operator input) if (tblDesc != null) { tblDesc.setCols(new ArrayList<>(fieldSchemas)); tblDesc.setPartCols(new ArrayList<>(partitionColumns)); + // must precede the column-stats auto-gather pipeline, which fails on duplicates + // with a misleading "ambiguous column reference" + ParseUtils.validateColumnNameUniqueness(tblDesc.getCols()); } else if (viewDesc != null) { viewDesc.setCols(new ArrayList<>(fieldSchemas)); viewDesc.setPartCols(new ArrayList<>(partitionColumns)); diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/type/JoinCondTypeCheckProcFactory.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/type/JoinCondTypeCheckProcFactory.java index 6ebbbb7f7bba..8586cafa07dd 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/type/JoinCondTypeCheckProcFactory.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/type/JoinCondTypeCheckProcFactory.java @@ -87,6 +87,7 @@ public Object process(Node nd, Stack stack, NodeProcessorCtx procCtx, if (!qualifiedAccess) { colInfo = getColInfo(ctx, null, tableOrCol, expr); // It's a column. + checkAmbiguousName(colInfo); return exprFactory.createColumnRefExpr(colInfo, ctx.getInputRRList()); } else if (hasTableAlias(ctx, tableOrCol, expr)) { return null; @@ -179,6 +180,7 @@ protected T processQualifiedColRef(TypeCheckCtx ctx, ASTNode expr, ErrorMsg.INVALID_COLUMN.getMsg(), expr.getChild(1)), expr); return null; } + checkAmbiguousName(colInfo); ColumnInfo newColumnInfo = new ColumnInfo(colInfo); newColumnInfo.setTabAlias(tableAlias); List listRR = new ArrayList<>(jctx.getInputRRList()); diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/type/TypeCheckProcFactory.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/type/TypeCheckProcFactory.java index 1eb1d17297f7..778073d8e080 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/type/TypeCheckProcFactory.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/type/TypeCheckProcFactory.java @@ -594,6 +594,13 @@ protected IntervalExprProcessor getIntervalExprProcessor() { return new IntervalExprProcessor(); } + static void checkAmbiguousName(ColumnInfo colInfo) throws SemanticException { + if (colInfo != null && colInfo.hasAmbiguousName()) { + throw new SemanticException(ErrorMsg.AMBIGUOUS_COLUMN.getMsg( + colInfo.getAlias() + " in " + colInfo.getTabAlias())); + } + } + /** * Processor for table columns. */ @@ -659,6 +666,7 @@ public Object process(Node nd, Stack stack, NodeProcessorCtx procCtx, return null; } // It's a column. + checkAmbiguousName(colInfo); return exprFactory.toExpr(colInfo, usedRR, offset); } else { // It's a table alias. @@ -693,6 +701,7 @@ public Object process(Node nd, Stack stack, NodeProcessorCtx procCtx, } } else { // It's a column. + checkAmbiguousName(colInfo); return exprFactory.toExpr(colInfo, usedRR, offset); } } @@ -1299,6 +1308,7 @@ protected T processQualifiedColRef(TypeCheckCtx ctx, ASTNode expr, ErrorMsg.INVALID_COLUMN.getMsg(), expr.getChild(1)), expr); return null; } + checkAmbiguousName(colInfo); return exprFactory.toExpr(colInfo, usedRR, offset); } diff --git a/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestAmbiguousColumnName.java b/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestAmbiguousColumnName.java new file mode 100644 index 000000000000..8832ffcbfd3e --- /dev/null +++ b/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestAmbiguousColumnName.java @@ -0,0 +1,58 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hive.ql.parse.type; + +import org.apache.hadoop.hive.ql.exec.ColumnInfo; +import org.apache.hadoop.hive.ql.parse.SemanticException; +import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory; +import org.junit.Assert; +import org.junit.Test; + +public class TestAmbiguousColumnName { + + private static ColumnInfo colInfo() { + ColumnInfo colInfo = new ColumnInfo("_col0", TypeInfoFactory.stringTypeInfo, "t", false); + colInfo.setAlias("c"); + return colInfo; + } + + @Test + public void testCopyConstructorPreservesAmbiguousName() { + ColumnInfo original = colInfo(); + original.setAmbiguousName(true); + Assert.assertTrue(new ColumnInfo(original).hasAmbiguousName()); + } + + @Test + public void testCheckAmbiguousNameThrows() { + ColumnInfo marked = colInfo(); + marked.setAmbiguousName(true); + try { + TypeCheckProcFactory.checkAmbiguousName(marked); + Assert.fail("expected SemanticException"); + } catch (SemanticException e) { + Assert.assertTrue(e.getMessage(), e.getMessage().contains("Ambiguous column reference c in t")); + } + } + + @Test + public void testCheckAmbiguousNameNoThrow() throws SemanticException { + TypeCheckProcFactory.checkAmbiguousName(colInfo()); + } +} diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_2_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_2_noncbo.q new file mode 100644 index 000000000000..6608bac70b6e --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_2_noncbo.q @@ -0,0 +1,3 @@ +set hive.cbo.enable=false; +create table t1nc (c1 int); +explain select t.c1 from (select t11.c1, t12.c1 from t1nc as t11 inner join t1nc as t12 on t11.c1 = t12.c1) as t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_aggregate_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_aggregate_noncbo.q new file mode 100644 index 000000000000..46c7e07f7b58 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_aggregate_noncbo.q @@ -0,0 +1,3 @@ +--! qt:dataset:src +set hive.cbo.enable=false; +select count(*) from (select key, key from src) subq; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_cte.q b/ql/src/test/queries/clientnegative/ambiguous_col_cte.q new file mode 100644 index 000000000000..77917888fa99 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_cte.q @@ -0,0 +1,3 @@ +with bse as (select 'a' as delivery_date, concat('a') as delivery_date), + tpm as (select * from bse) +select tpm.delivery_date from tpm; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q new file mode 100644 index 000000000000..d70bdbf38035 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q @@ -0,0 +1,4 @@ +set hive.cbo.enable=false; +with bse as (select 'a' as delivery_date, concat('a') as delivery_date), + tpm as (select * from bse) +select tpm.delivery_date from tpm; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q new file mode 100644 index 000000000000..42be3a8d6ffb --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q @@ -0,0 +1,3 @@ +set hive.cbo.enable=false; +with c1 as (select 'a' as c, 'b' as c, 'x' as d) +select d from c1; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_distinct_window.q b/ql/src/test/queries/clientnegative/ambiguous_col_distinct_window.q new file mode 100644 index 000000000000..460aee697f6b --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_distinct_window.q @@ -0,0 +1 @@ +select x.c from (select distinct *, rank() over (order by d) r from (select 'a' as c, 'b' as c, 'x' as d) t) x; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_exists_having_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_exists_having_noncbo.q new file mode 100644 index 000000000000..0dcbe35d1980 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_exists_having_noncbo.q @@ -0,0 +1,3 @@ +--! qt:dataset:src +set hive.cbo.enable=false; +select value, count(1) from src group by value having exists (select 'x' as c, 'y' as c from src b where b.value = src.value); diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_exists_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_exists_noncbo.q new file mode 100644 index 000000000000..10afc68f2492 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_exists_noncbo.q @@ -0,0 +1,3 @@ +--! qt:dataset:src +set hive.cbo.enable=false; +select key from src a where exists (select 'x' as c, 'y' as c from src b where b.key = a.key); diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_join_cond.q b/ql/src/test/queries/clientnegative/ambiguous_col_join_cond.q new file mode 100644 index 000000000000..d48d8215a7f7 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_join_cond.q @@ -0,0 +1,7 @@ +-- the duplicate alias is referenced only in the join condition, via a qualified name. +-- Unparse translation is disabled below on purpose: when it is on, the ON clause is also +-- walked by the generic type check, which would make this test pass even if the ambiguity +-- check in JoinCondTypeCheckProcFactory were removed. +set hive.materializedview.rewriting.sql=false; +set hive.materializedview.rewriting.sql.subquery=false; +select t.d from (select 'a' as c, 'b' as c, 'x' as d) t join (select 'a' as e) u on t.c = u.e; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_join_cond_unqual.q b/ql/src/test/queries/clientnegative/ambiguous_col_join_cond_unqual.q new file mode 100644 index 000000000000..d05f686c6fc4 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_join_cond_unqual.q @@ -0,0 +1,5 @@ +-- same as ambiguous_col_join_cond.q but the reference is unqualified, which is resolved by a +-- different processor override. See that file for why unparse translation is disabled here. +set hive.materializedview.rewriting.sql=false; +set hive.materializedview.rewriting.sql.subquery=false; +select t.d from (select 'a' as c, 'b' as c, 'x' as d) t join (select 'a' as e) u on c = u.e; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_join_using.q b/ql/src/test/queries/clientnegative/ambiguous_col_join_using.q new file mode 100644 index 000000000000..3d87fb4c3f77 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_join_using.q @@ -0,0 +1 @@ +select t.c from (select * from (select 'a' as c, 'b' as c) s join (select 'a' as c) u using (c)) t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_join_wildcard_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_join_wildcard_noncbo.q new file mode 100644 index 000000000000..51512c86f12a --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_join_wildcard_noncbo.q @@ -0,0 +1,4 @@ +set hive.cbo.enable=false; +create table wj3 (k int, v int); +create table wj4 (k int, w int); +select t.v from (select a.*, b.* from wj3 a join wj4 b on a.k = b.k) t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_lateral_view_alias.q b/ql/src/test/queries/clientnegative/ambiguous_col_lateral_view_alias.q new file mode 100644 index 000000000000..1007f67229ae --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_lateral_view_alias.q @@ -0,0 +1,7 @@ +-- The lateral view reuses the table alias, so the exploded column collides with the base table +-- column under the same table alias. This is caught by the reference-time check in +-- RowResolver.get (ambiguousColumns), not by the duplicate-alias marker: the message form +-- "Ambiguous column reference: t.c" identifies that path. Keep this test: it is the only +-- coverage of that check, which would otherwise look like dead code and get removed. +create table lv_dup_alias (c int, arr array); +select t.c from lv_dup_alias t lateral view explode(t.arr) t as c; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_nested_star_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_nested_star_noncbo.q new file mode 100644 index 000000000000..117e84a6cf94 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_nested_star_noncbo.q @@ -0,0 +1,2 @@ +set hive.cbo.enable=false; +select * from (select * from (select 'a' as c, 'b' as c) a) b; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_noncbo.q new file mode 100644 index 000000000000..b7dd03bbcfc9 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_noncbo.q @@ -0,0 +1,3 @@ +--! qt:dataset:src +set hive.cbo.enable=false; +FROM (SELECT key, concat(value) AS key FROM src) a SELECT a.key; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_union.q b/ql/src/test/queries/clientnegative/ambiguous_col_union.q new file mode 100644 index 000000000000..eaa72afd8983 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_union.q @@ -0,0 +1 @@ +select t.c from (select 'a' as c, 'b' as c union all select 'x', 'y') t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_union_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_union_noncbo.q new file mode 100644 index 000000000000..0316b7850008 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_union_noncbo.q @@ -0,0 +1,2 @@ +set hive.cbo.enable=false; +select t.c from (select 'a' as c, 'b' as c union all select 'x', 'y') t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_unqualified_ref.q b/ql/src/test/queries/clientnegative/ambiguous_col_unqualified_ref.q new file mode 100644 index 000000000000..ecb497fb137e --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_unqualified_ref.q @@ -0,0 +1,8 @@ +-- The inner CTE references the duplicated alias by an UNQUALIFIED name, which is resolved by +-- TypeCheckProcFactory.ColumnExprProcessor (the "It's a column" branch) rather than by +-- processQualifiedColRef. Every other ambiguity test uses a qualified reference, so this is the +-- only coverage of that check site. The error names the definition-site alias (bse), matching +-- what the non-CBO path reports for the same query. +with bse as (select 'a' as delivery_date, concat('a') as delivery_date), + tpm as (select delivery_date from bse) +select tpm.delivery_date from tpm; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_unreferenced_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_unreferenced_noncbo.q new file mode 100644 index 000000000000..544b50b90e07 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_unreferenced_noncbo.q @@ -0,0 +1,2 @@ +set hive.cbo.enable=false; +select t.d from (select 'a' as c, 'b' as c, 'x' as d) t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_colref_in_gby_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_colref_in_gby_noncbo.q new file mode 100644 index 000000000000..72a61e4680de --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_colref_in_gby_noncbo.q @@ -0,0 +1,3 @@ +set hive.cbo.enable=false; +create table t1gnc (a int); +select s.a from (select a, a from t1gnc) s group by s.a; diff --git a/ql/src/test/queries/clientnegative/ctas_dup_column.q b/ql/src/test/queries/clientnegative/ctas_dup_column.q new file mode 100644 index 000000000000..45247fdf9a89 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ctas_dup_column.q @@ -0,0 +1 @@ +create table ctas_dup_col as select 'a' as c, 'b' as c; diff --git a/ql/src/test/queries/clientnegative/ctas_dup_column_join.q b/ql/src/test/queries/clientnegative/ctas_dup_column_join.q new file mode 100644 index 000000000000..f7318f6d2a9d --- /dev/null +++ b/ql/src/test/queries/clientnegative/ctas_dup_column_join.q @@ -0,0 +1,3 @@ +create table cj1 (k int, v int); +create table cj2 (k int, w int); +create table ctas_dup_join as select a.k, b.k from cj1 a join cj2 b on a.k = b.k; diff --git a/ql/src/test/queries/clientnegative/ctas_dup_column_join_noncbo.q b/ql/src/test/queries/clientnegative/ctas_dup_column_join_noncbo.q new file mode 100644 index 000000000000..6aa6e614da31 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ctas_dup_column_join_noncbo.q @@ -0,0 +1,4 @@ +set hive.cbo.enable=false; +create table cj3 (k int, v int); +create table cj4 (k int, w int); +create table ctas_dup_join_nc as select a.k, b.k from cj3 a join cj4 b on a.k = b.k; diff --git a/ql/src/test/queries/clientnegative/ctas_dup_column_noncbo.q b/ql/src/test/queries/clientnegative/ctas_dup_column_noncbo.q new file mode 100644 index 000000000000..ff96420c548d --- /dev/null +++ b/ql/src/test/queries/clientnegative/ctas_dup_column_noncbo.q @@ -0,0 +1,2 @@ +set hive.cbo.enable=false; +create table ctas_dup_col_noncbo as select 'a' as c, 'b' as c; diff --git a/ql/src/test/queries/clientpositive/ambiguous_col_tolerated.q b/ql/src/test/queries/clientpositive/ambiguous_col_tolerated.q new file mode 100644 index 000000000000..1864cb885bb4 --- /dev/null +++ b/ql/src/test/queries/clientpositive/ambiguous_col_tolerated.q @@ -0,0 +1,14 @@ +select 'a' as c, 'b' as c; +select 'a' as c, 'b' as c order by c; +select * from (select 'a' as c, 'b' as c) t; +create table dup_alias_ins (x string, y string); +insert into dup_alias_ins select 'a' as c, 'b' as c; +select x, y from dup_alias_ins; + +set hive.cbo.enable=false; + +select 'a' as c, 'b' as c; +select 'a' as c, 'b' as c order by c; +select * from (select 'a' as c, 'b' as c) t; +insert into dup_alias_ins select 'c' as c, 'd' as c; +select x, y from dup_alias_ins order by x; diff --git a/ql/src/test/queries/clientpositive/ambiguous_col_unreferenced_tolerated.q b/ql/src/test/queries/clientpositive/ambiguous_col_unreferenced_tolerated.q new file mode 100644 index 000000000000..6fc2eaaf8a1e --- /dev/null +++ b/ql/src/test/queries/clientpositive/ambiguous_col_unreferenced_tolerated.q @@ -0,0 +1,13 @@ +--! qt:dataset:src +select t.d from (select 'a' as c, 'b' as c, 'x' as d) t; +with c1 as (select 'a' as c, 'b' as c, 'x' as d) +select d from c1; +select count(1) from (select 'a' as c, 'b' as c) t; +select count(*) from (select key, key from src) subq; +create table wjt1 (k int, v int); +create table wjt2 (k int, w int); +select t.v from (select a.*, b.* from wjt1 a join wjt2 b on a.k = b.k) t; +select * from (select * from (select 'a' as c, 'b' as c) a) b; +select count(*) from src a where exists (select 'x' as c, 'y' as c from src b where b.key = a.key); +select count(*) from src where exists (select 'a' as c, 'b' as c from src); +select count(*) from (select value from src group by value having exists (select 'x' as c, 'y' as c from src b where b.value = src.value)) t; diff --git a/ql/src/test/results/clientnegative/ambiguous_col.q.out b/ql/src/test/results/clientnegative/ambiguous_col.q.out index 170e277d0ee3..a2915a4a5d3d 100644 --- a/ql/src/test/results/clientnegative/ambiguous_col.q.out +++ b/ql/src/test/results/clientnegative/ambiguous_col.q.out @@ -1 +1 @@ -FAILED: SemanticException Ambiguous column reference: a.key +FAILED: SemanticException [Error 10007]: Ambiguous column reference key in a diff --git a/ql/src/test/results/clientnegative/ambiguous_col_2.q.out b/ql/src/test/results/clientnegative/ambiguous_col_2.q.out index bc6fb4d112a5..ac4bd4063f24 100644 --- a/ql/src/test/results/clientnegative/ambiguous_col_2.q.out +++ b/ql/src/test/results/clientnegative/ambiguous_col_2.q.out @@ -6,4 +6,4 @@ POSTHOOK: query: create table t1(c1 int) POSTHOOK: type: CREATETABLE POSTHOOK: Output: database:default POSTHOOK: Output: default@t1 -FAILED: SemanticException Ambiguous column reference: t.c1 +FAILED: SemanticException [Error 10007]: Ambiguous column reference c1 in t diff --git a/ql/src/test/results/clientnegative/ambiguous_col_2_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_2_noncbo.q.out new file mode 100644 index 000000000000..d6ce2f43b330 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_2_noncbo.q.out @@ -0,0 +1,9 @@ +PREHOOK: query: create table t1nc (c1 int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@t1nc +POSTHOOK: query: create table t1nc (c1 int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@t1nc +FAILED: SemanticException [Error 10007]: Ambiguous column reference c1 in t diff --git a/ql/src/test/results/clientnegative/ambiguous_col_aggregate_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_aggregate_noncbo.q.out new file mode 100644 index 000000000000..40952cdc22bb --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_aggregate_noncbo.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference key in subq diff --git a/ql/src/test/results/clientnegative/ambiguous_col_cte.q.out b/ql/src/test/results/clientnegative/ambiguous_col_cte.q.out new file mode 100644 index 000000000000..19c117e1a600 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_cte.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference delivery_date in tpm diff --git a/ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out new file mode 100644 index 000000000000..533d31a557c0 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference delivery_date in bse diff --git a/ql/src/test/results/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q.out new file mode 100644 index 000000000000..bb9278bc19fe --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in c1 diff --git a/ql/src/test/results/clientnegative/ambiguous_col_distinct_window.q.out b/ql/src/test/results/clientnegative/ambiguous_col_distinct_window.q.out new file mode 100644 index 000000000000..a19c1eba9da2 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_distinct_window.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in x diff --git a/ql/src/test/results/clientnegative/ambiguous_col_exists_having_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_exists_having_noncbo.q.out new file mode 100644 index 000000000000..f18587c08360 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_exists_having_noncbo.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in sq_1 diff --git a/ql/src/test/results/clientnegative/ambiguous_col_exists_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_exists_noncbo.q.out new file mode 100644 index 000000000000..f18587c08360 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_exists_noncbo.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in sq_1 diff --git a/ql/src/test/results/clientnegative/ambiguous_col_join_cond.q.out b/ql/src/test/results/clientnegative/ambiguous_col_join_cond.q.out new file mode 100644 index 000000000000..58aee7c08949 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_join_cond.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in t diff --git a/ql/src/test/results/clientnegative/ambiguous_col_join_cond_unqual.q.out b/ql/src/test/results/clientnegative/ambiguous_col_join_cond_unqual.q.out new file mode 100644 index 000000000000..58aee7c08949 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_join_cond_unqual.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in t diff --git a/ql/src/test/results/clientnegative/ambiguous_col_join_using.q.out b/ql/src/test/results/clientnegative/ambiguous_col_join_using.q.out new file mode 100644 index 000000000000..2f33a44abe85 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_join_using.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in s diff --git a/ql/src/test/results/clientnegative/ambiguous_col_join_wildcard_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_join_wildcard_noncbo.q.out new file mode 100644 index 000000000000..d9e59b52badc --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_join_wildcard_noncbo.q.out @@ -0,0 +1,17 @@ +PREHOOK: query: create table wj3 (k int, v int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@wj3 +POSTHOOK: query: create table wj3 (k int, v int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@wj3 +PREHOOK: query: create table wj4 (k int, w int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@wj4 +POSTHOOK: query: create table wj4 (k int, w int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@wj4 +FAILED: SemanticException [Error 10007]: Ambiguous column reference k in t diff --git a/ql/src/test/results/clientnegative/ambiguous_col_lateral_view_alias.q.out b/ql/src/test/results/clientnegative/ambiguous_col_lateral_view_alias.q.out new file mode 100644 index 000000000000..df3a1e7efdd7 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_lateral_view_alias.q.out @@ -0,0 +1,9 @@ +PREHOOK: query: create table lv_dup_alias (c int, arr array) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@lv_dup_alias +POSTHOOK: query: create table lv_dup_alias (c int, arr array) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@lv_dup_alias +FAILED: SemanticException Ambiguous column reference: t.c diff --git a/ql/src/test/results/clientnegative/ambiguous_col_nested_star_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_nested_star_noncbo.q.out new file mode 100644 index 000000000000..53d5a7a85c38 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_nested_star_noncbo.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in a diff --git a/ql/src/test/results/clientnegative/ambiguous_col_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_noncbo.q.out new file mode 100644 index 000000000000..a2915a4a5d3d --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_noncbo.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference key in a diff --git a/ql/src/test/results/clientnegative/ambiguous_col_union.q.out b/ql/src/test/results/clientnegative/ambiguous_col_union.q.out new file mode 100644 index 000000000000..58aee7c08949 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_union.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in t diff --git a/ql/src/test/results/clientnegative/ambiguous_col_union_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_union_noncbo.q.out new file mode 100644 index 000000000000..b75f8a02dc10 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_union_noncbo.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in __u1-subquery1 diff --git a/ql/src/test/results/clientnegative/ambiguous_col_unqualified_ref.q.out b/ql/src/test/results/clientnegative/ambiguous_col_unqualified_ref.q.out new file mode 100644 index 000000000000..533d31a557c0 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_unqualified_ref.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference delivery_date in bse diff --git a/ql/src/test/results/clientnegative/ambiguous_col_unreferenced_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_unreferenced_noncbo.q.out new file mode 100644 index 000000000000..58aee7c08949 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_unreferenced_noncbo.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in t diff --git a/ql/src/test/results/clientnegative/ambiguous_colref_in_gby_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_colref_in_gby_noncbo.q.out new file mode 100644 index 000000000000..58234a65ac4f --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_colref_in_gby_noncbo.q.out @@ -0,0 +1,9 @@ +PREHOOK: query: create table t1gnc (a int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@t1gnc +POSTHOOK: query: create table t1gnc (a int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@t1gnc +FAILED: SemanticException [Error 10007]: Ambiguous column reference a in s diff --git a/ql/src/test/results/clientnegative/cbo_ambiguous_colref_in_gby.q.out b/ql/src/test/results/clientnegative/cbo_ambiguous_colref_in_gby.q.out index c3b7baacdf15..8f04d4e45a4d 100644 --- a/ql/src/test/results/clientnegative/cbo_ambiguous_colref_in_gby.q.out +++ b/ql/src/test/results/clientnegative/cbo_ambiguous_colref_in_gby.q.out @@ -6,4 +6,4 @@ POSTHOOK: query: create table t1 (a int) POSTHOOK: type: CREATETABLE POSTHOOK: Output: database:default POSTHOOK: Output: default@t1 -FAILED: SemanticException Ambiguous column reference: s.a +FAILED: SemanticException [Error 10007]: Ambiguous column reference a in s diff --git a/ql/src/test/results/clientnegative/ctas_dup_column.q.out b/ql/src/test/results/clientnegative/ctas_dup_column.q.out new file mode 100644 index 000000000000..60c2f38795a2 --- /dev/null +++ b/ql/src/test/results/clientnegative/ctas_dup_column.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10036]: Duplicate column name: c diff --git a/ql/src/test/results/clientnegative/ctas_dup_column_join.q.out b/ql/src/test/results/clientnegative/ctas_dup_column_join.q.out new file mode 100644 index 000000000000..8746031f6caa --- /dev/null +++ b/ql/src/test/results/clientnegative/ctas_dup_column_join.q.out @@ -0,0 +1,17 @@ +PREHOOK: query: create table cj1 (k int, v int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@cj1 +POSTHOOK: query: create table cj1 (k int, v int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@cj1 +PREHOOK: query: create table cj2 (k int, w int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@cj2 +POSTHOOK: query: create table cj2 (k int, w int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@cj2 +FAILED: SemanticException [Error 10036]: Duplicate column name: k diff --git a/ql/src/test/results/clientnegative/ctas_dup_column_join_noncbo.q.out b/ql/src/test/results/clientnegative/ctas_dup_column_join_noncbo.q.out new file mode 100644 index 000000000000..47007d97e78e --- /dev/null +++ b/ql/src/test/results/clientnegative/ctas_dup_column_join_noncbo.q.out @@ -0,0 +1,17 @@ +PREHOOK: query: create table cj3 (k int, v int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@cj3 +POSTHOOK: query: create table cj3 (k int, v int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@cj3 +PREHOOK: query: create table cj4 (k int, w int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@cj4 +POSTHOOK: query: create table cj4 (k int, w int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@cj4 +FAILED: SemanticException [Error 10036]: Duplicate column name: k diff --git a/ql/src/test/results/clientnegative/ctas_dup_column_noncbo.q.out b/ql/src/test/results/clientnegative/ctas_dup_column_noncbo.q.out new file mode 100644 index 000000000000..60c2f38795a2 --- /dev/null +++ b/ql/src/test/results/clientnegative/ctas_dup_column_noncbo.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10036]: Duplicate column name: c diff --git a/ql/src/test/results/clientnegative/cte_col_alias_clash.q.out b/ql/src/test/results/clientnegative/cte_col_alias_clash.q.out index 686e3689d3cc..475dc7384b71 100644 --- a/ql/src/test/results/clientnegative/cte_col_alias_clash.q.out +++ b/ql/src/test/results/clientnegative/cte_col_alias_clash.q.out @@ -6,4 +6,4 @@ POSTHOOK: query: create table t1(int_col int, bigint_col bigint) POSTHOOK: type: CREATETABLE POSTHOOK: Output: database:default POSTHOOK: Output: default@t1 -FAILED: SemanticException Ambiguous column reference: .a +FAILED: SemanticException [Error 10007]: Ambiguous column reference a in cte1 diff --git a/ql/src/test/results/clientpositive/llap/ambiguous_col_tolerated.q.out b/ql/src/test/results/clientpositive/llap/ambiguous_col_tolerated.q.out new file mode 100644 index 000000000000..a0aa072f341a --- /dev/null +++ b/ql/src/test/results/clientpositive/llap/ambiguous_col_tolerated.q.out @@ -0,0 +1,101 @@ +PREHOOK: query: select 'a' as c, 'b' as c +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select 'a' as c, 'b' as c +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +a b +PREHOOK: query: select 'a' as c, 'b' as c order by c +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select 'a' as c, 'b' as c order by c +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +a b +PREHOOK: query: select * from (select 'a' as c, 'b' as c) t +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select * from (select 'a' as c, 'b' as c) t +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +a b +PREHOOK: query: create table dup_alias_ins (x string, y string) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@dup_alias_ins +POSTHOOK: query: create table dup_alias_ins (x string, y string) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@dup_alias_ins +PREHOOK: query: insert into dup_alias_ins select 'a' as c, 'b' as c +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +PREHOOK: Output: default@dup_alias_ins +POSTHOOK: query: insert into dup_alias_ins select 'a' as c, 'b' as c +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +POSTHOOK: Output: default@dup_alias_ins +POSTHOOK: Lineage: dup_alias_ins.x SIMPLE [] +POSTHOOK: Lineage: dup_alias_ins.y SIMPLE [] +PREHOOK: query: select x, y from dup_alias_ins +PREHOOK: type: QUERY +PREHOOK: Input: default@dup_alias_ins +#### A masked pattern was here #### +POSTHOOK: query: select x, y from dup_alias_ins +POSTHOOK: type: QUERY +POSTHOOK: Input: default@dup_alias_ins +#### A masked pattern was here #### +a b +PREHOOK: query: select 'a' as c, 'b' as c +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select 'a' as c, 'b' as c +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +a b +PREHOOK: query: select 'a' as c, 'b' as c order by c +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select 'a' as c, 'b' as c order by c +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +a b +PREHOOK: query: select * from (select 'a' as c, 'b' as c) t +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select * from (select 'a' as c, 'b' as c) t +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +a b +PREHOOK: query: insert into dup_alias_ins select 'c' as c, 'd' as c +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +PREHOOK: Output: default@dup_alias_ins +POSTHOOK: query: insert into dup_alias_ins select 'c' as c, 'd' as c +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +POSTHOOK: Output: default@dup_alias_ins +POSTHOOK: Lineage: dup_alias_ins.x SIMPLE [] +POSTHOOK: Lineage: dup_alias_ins.y SIMPLE [] +PREHOOK: query: select x, y from dup_alias_ins order by x +PREHOOK: type: QUERY +PREHOOK: Input: default@dup_alias_ins +#### A masked pattern was here #### +POSTHOOK: query: select x, y from dup_alias_ins order by x +POSTHOOK: type: QUERY +POSTHOOK: Input: default@dup_alias_ins +#### A masked pattern was here #### +a b +c d diff --git a/ql/src/test/results/clientpositive/llap/ambiguous_col_unreferenced_tolerated.q.out b/ql/src/test/results/clientpositive/llap/ambiguous_col_unreferenced_tolerated.q.out new file mode 100644 index 000000000000..dc25bfa8bd04 --- /dev/null +++ b/ql/src/test/results/clientpositive/llap/ambiguous_col_unreferenced_tolerated.q.out @@ -0,0 +1,101 @@ +PREHOOK: query: select t.d from (select 'a' as c, 'b' as c, 'x' as d) t +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select t.d from (select 'a' as c, 'b' as c, 'x' as d) t +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +x +PREHOOK: query: with c1 as (select 'a' as c, 'b' as c, 'x' as d) +select d from c1 +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: with c1 as (select 'a' as c, 'b' as c, 'x' as d) +select d from c1 +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +x +PREHOOK: query: select count(1) from (select 'a' as c, 'b' as c) t +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select count(1) from (select 'a' as c, 'b' as c) t +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +1 +PREHOOK: query: select count(*) from (select key, key from src) subq +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: select count(*) from (select key, key from src) subq +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +500 +PREHOOK: query: create table wjt1 (k int, v int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@wjt1 +POSTHOOK: query: create table wjt1 (k int, v int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@wjt1 +PREHOOK: query: create table wjt2 (k int, w int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@wjt2 +POSTHOOK: query: create table wjt2 (k int, w int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@wjt2 +PREHOOK: query: select t.v from (select a.*, b.* from wjt1 a join wjt2 b on a.k = b.k) t +PREHOOK: type: QUERY +PREHOOK: Input: default@wjt1 +PREHOOK: Input: default@wjt2 +#### A masked pattern was here #### +POSTHOOK: query: select t.v from (select a.*, b.* from wjt1 a join wjt2 b on a.k = b.k) t +POSTHOOK: type: QUERY +POSTHOOK: Input: default@wjt1 +POSTHOOK: Input: default@wjt2 +#### A masked pattern was here #### +PREHOOK: query: select * from (select * from (select 'a' as c, 'b' as c) a) b +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select * from (select * from (select 'a' as c, 'b' as c) a) b +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +a b +PREHOOK: query: select count(*) from src a where exists (select 'x' as c, 'y' as c from src b where b.key = a.key) +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: select count(*) from src a where exists (select 'x' as c, 'y' as c from src b where b.key = a.key) +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +500 +Warning: Shuffle Join MERGEJOIN[18][tables = [$hdt$_0, $hdt$_1]] in Stage 'Reducer 2' is a cross product +PREHOOK: query: select count(*) from src where exists (select 'a' as c, 'b' as c from src) +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: select count(*) from src where exists (select 'a' as c, 'b' as c from src) +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +500 +PREHOOK: query: select count(*) from (select value from src group by value having exists (select 'x' as c, 'y' as c from src b where b.value = src.value)) t +PREHOOK: type: QUERY +PREHOOK: Input: default@src +#### A masked pattern was here #### +POSTHOOK: query: select count(*) from (select value from src group by value having exists (select 'x' as c, 'y' as c from src b where b.value = src.value)) t +POSTHOOK: type: QUERY +POSTHOOK: Input: default@src +#### A masked pattern was here #### +309 From 3ce723056c48456c29c51d562b778ab8e2c76ce0 Mon Sep 17 00:00:00 2001 From: Konstantin Bereznyakov Date: Wed, 5 Aug 2026 12:51:24 -0700 Subject: [PATCH 2/5] HIVE-29580: merge fixes + CTAS corrections --- .../hadoop/hive/ql/parse/CalcitePlanner.java | 5 ----- .../hadoop/hive/ql/parse/SemanticAnalyzer.java | 3 --- .../hive/ql/parse/rewrite/MergeRewriter.java | 2 +- .../rewrite/sql/MultiInsertSqlGenerator.java | 12 ++++++++++++ .../queries/clientnegative/ambiguous_col_ctas.q | 9 +++++++++ .../queries/clientnegative/ambiguous_col_cte.q | 4 ++-- .../clientnegative/ambiguous_col_cte_noncbo.q | 4 ++-- .../ambiguous_col_unqualified_ref.q | 6 +++--- .../queries/clientnegative/ctas_dup_column.q | 1 - .../clientnegative/ctas_dup_column_join.q | 3 --- .../ctas_dup_column_join_noncbo.q | 4 ---- .../clientnegative/ctas_dup_column_noncbo.q | 2 -- .../clientnegative/ambiguous_col_ctas.q.out | 1 + .../clientnegative/ambiguous_col_cte.q.out | 2 +- .../ambiguous_col_cte_noncbo.q.out | 2 +- .../ambiguous_col_unqualified_ref.q.out | 2 +- .../clientnegative/ctas_dup_column.q.out | 1 - .../clientnegative/ctas_dup_column_join.q.out | 17 ----------------- .../ctas_dup_column_join_noncbo.q.out | 17 ----------------- .../clientnegative/ctas_dup_column_noncbo.q.out | 1 - 20 files changed, 33 insertions(+), 65 deletions(-) create mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_ctas.q delete mode 100644 ql/src/test/queries/clientnegative/ctas_dup_column.q delete mode 100644 ql/src/test/queries/clientnegative/ctas_dup_column_join.q delete mode 100644 ql/src/test/queries/clientnegative/ctas_dup_column_join_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ctas_dup_column_noncbo.q create mode 100644 ql/src/test/results/clientnegative/ambiguous_col_ctas.q.out delete mode 100644 ql/src/test/results/clientnegative/ctas_dup_column.q.out delete mode 100644 ql/src/test/results/clientnegative/ctas_dup_column_join.q.out delete mode 100644 ql/src/test/results/clientnegative/ctas_dup_column_join_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ctas_dup_column_noncbo.q.out diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java index 266c6b07edcf..5edda6e42057 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java @@ -1556,11 +1556,6 @@ public RelNode apply(RelOptCluster cluster, RelOptSchema relOptSchema, SchemaPlu resultSchema = convertRowSchemaToResultSetSchema(relToHiveRR.get(calcitePlan), (forViewCreation || getQB().isMaterializedView()) ? false : HiveConf.getBoolVar(conf, HiveConf.ConfVars.HIVE_RESULTSET_USE_UNIQUE_COLUMN_NAMES)); - if (getQB().isCTAS()) { - // check the non-uniquified names: getNewColAlias would rename a duplicate away - ParseUtils.validateColumnNameUniqueness( - convertRowSchemaToResultSetSchema(relToHiveRR.get(calcitePlan), false)); - } } catch (SemanticException e) { semanticException = e; throw new RuntimeException(e); diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java index dc6143e0f0f4..d76cfb12fdcd 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/SemanticAnalyzer.java @@ -7990,9 +7990,6 @@ protected Operator genFileSinkPlan(String dest, QB qb, Operator input) if (tblDesc != null) { tblDesc.setCols(new ArrayList<>(fieldSchemas)); tblDesc.setPartCols(new ArrayList<>(partitionColumns)); - // must precede the column-stats auto-gather pipeline, which fails on duplicates - // with a misleading "ambiguous column reference" - ParseUtils.validateColumnNameUniqueness(tblDesc.getCols()); } else if (viewDesc != null) { viewDesc.setCols(new ArrayList<>(fieldSchemas)); viewDesc.setPartCols(new ArrayList<>(partitionColumns)); diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/rewrite/MergeRewriter.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/rewrite/MergeRewriter.java index f3a17b5c8b2a..1c32517f6883 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/rewrite/MergeRewriter.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/rewrite/MergeRewriter.java @@ -113,7 +113,7 @@ private void handleSource(boolean hasWhenNotMatchedClause, String sourceAlias, S sqlGenerator.append("FROM\n"); sqlGenerator.append("(SELECT "); sqlGenerator.appendAcidSelectColumns(Operation.MERGE); - sqlGenerator.appendAllColsOfTargetTable(); + sqlGenerator.appendNonPartitionColsOfTargetTable(); addSourceColumnsForRowLineage(isRowLineageSupported, sqlGenerator, "", conf); sqlGenerator.append(" FROM ").appendTargetTableName().append(") "); sqlGenerator.appendSubQueryAlias(); diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/rewrite/sql/MultiInsertSqlGenerator.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/rewrite/sql/MultiInsertSqlGenerator.java index 449449037a58..4b209ab531de 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/rewrite/sql/MultiInsertSqlGenerator.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/rewrite/sql/MultiInsertSqlGenerator.java @@ -169,6 +169,18 @@ public void appendAllColsOfTargetTable(String prefix) { public void appendAllColsOfTargetTable() { appendCols(targetTable.getAllCols(), FieldSchema::getName); } + + /** + * Appends the target table's columns, omitting the partition columns when the table uses native + * partitioning: appendAcidSelectColumns has already emitted those, and emitting them a second + * time yields a projection with duplicate column names, making any by-name reference to them + * ambiguous. Non-native tables (e.g. Iceberg) carry partition columns as regular columns, so for + * those all columns are appended. + */ + public void appendNonPartitionColsOfTargetTable() { + appendCols(targetTable.hasNonNativePartitionSupport() + ? targetTable.getAllCols() : targetTable.getCols(), FieldSchema::getName); + } public void appendCols(List columns, Function stringConverter) { appendCols(columns, null, null, stringConverter); diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_ctas.q b/ql/src/test/queries/clientnegative/ambiguous_col_ctas.q new file mode 100644 index 000000000000..0183aeb93065 --- /dev/null +++ b/ql/src/test/queries/clientnegative/ambiguous_col_ctas.q @@ -0,0 +1,9 @@ +-- A CTAS whose SELECT contains a cross-alias ambiguous reference. Without the ambiguity check +-- this silently persists one arbitrarily-chosen candidate into a table ('FIRST', discarding +-- 'SECOND') and reports nothing, so every downstream reader treats the arbitrary choice as fact. +-- Keep this test if the check ever gains an exemption for statements Hive generates for itself +-- (rewritten MERGE/UPDATE/DELETE, materialised CTEs): a USER CTAS must never be exempted. +create table ctas_ambiguous_ref as + with bse as (select 'FIRST' as c, 'SECOND' as c), + tpm as (select * from bse) + select tpm.c from tpm; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_cte.q b/ql/src/test/queries/clientnegative/ambiguous_col_cte.q index 77917888fa99..4a6f15096cbb 100644 --- a/ql/src/test/queries/clientnegative/ambiguous_col_cte.q +++ b/ql/src/test/queries/clientnegative/ambiguous_col_cte.q @@ -1,3 +1,3 @@ -with bse as (select 'a' as delivery_date, concat('a') as delivery_date), +with bse as (select 'a' as c, 'b' as c), tpm as (select * from bse) -select tpm.delivery_date from tpm; +select tpm.c from tpm; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q index d70bdbf38035..8674dbde35fd 100644 --- a/ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q +++ b/ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q @@ -1,4 +1,4 @@ set hive.cbo.enable=false; -with bse as (select 'a' as delivery_date, concat('a') as delivery_date), +with bse as (select 'a' as c, 'b' as c), tpm as (select * from bse) -select tpm.delivery_date from tpm; +select tpm.c from tpm; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_unqualified_ref.q b/ql/src/test/queries/clientnegative/ambiguous_col_unqualified_ref.q index ecb497fb137e..1f9566d23afb 100644 --- a/ql/src/test/queries/clientnegative/ambiguous_col_unqualified_ref.q +++ b/ql/src/test/queries/clientnegative/ambiguous_col_unqualified_ref.q @@ -3,6 +3,6 @@ -- processQualifiedColRef. Every other ambiguity test uses a qualified reference, so this is the -- only coverage of that check site. The error names the definition-site alias (bse), matching -- what the non-CBO path reports for the same query. -with bse as (select 'a' as delivery_date, concat('a') as delivery_date), - tpm as (select delivery_date from bse) -select tpm.delivery_date from tpm; +with bse as (select 'a' as c, 'b' as c), + tpm as (select c from bse) +select tpm.c from tpm; diff --git a/ql/src/test/queries/clientnegative/ctas_dup_column.q b/ql/src/test/queries/clientnegative/ctas_dup_column.q deleted file mode 100644 index 45247fdf9a89..000000000000 --- a/ql/src/test/queries/clientnegative/ctas_dup_column.q +++ /dev/null @@ -1 +0,0 @@ -create table ctas_dup_col as select 'a' as c, 'b' as c; diff --git a/ql/src/test/queries/clientnegative/ctas_dup_column_join.q b/ql/src/test/queries/clientnegative/ctas_dup_column_join.q deleted file mode 100644 index f7318f6d2a9d..000000000000 --- a/ql/src/test/queries/clientnegative/ctas_dup_column_join.q +++ /dev/null @@ -1,3 +0,0 @@ -create table cj1 (k int, v int); -create table cj2 (k int, w int); -create table ctas_dup_join as select a.k, b.k from cj1 a join cj2 b on a.k = b.k; diff --git a/ql/src/test/queries/clientnegative/ctas_dup_column_join_noncbo.q b/ql/src/test/queries/clientnegative/ctas_dup_column_join_noncbo.q deleted file mode 100644 index 6aa6e614da31..000000000000 --- a/ql/src/test/queries/clientnegative/ctas_dup_column_join_noncbo.q +++ /dev/null @@ -1,4 +0,0 @@ -set hive.cbo.enable=false; -create table cj3 (k int, v int); -create table cj4 (k int, w int); -create table ctas_dup_join_nc as select a.k, b.k from cj3 a join cj4 b on a.k = b.k; diff --git a/ql/src/test/queries/clientnegative/ctas_dup_column_noncbo.q b/ql/src/test/queries/clientnegative/ctas_dup_column_noncbo.q deleted file mode 100644 index ff96420c548d..000000000000 --- a/ql/src/test/queries/clientnegative/ctas_dup_column_noncbo.q +++ /dev/null @@ -1,2 +0,0 @@ -set hive.cbo.enable=false; -create table ctas_dup_col_noncbo as select 'a' as c, 'b' as c; diff --git a/ql/src/test/results/clientnegative/ambiguous_col_ctas.q.out b/ql/src/test/results/clientnegative/ambiguous_col_ctas.q.out new file mode 100644 index 000000000000..a88aa731e433 --- /dev/null +++ b/ql/src/test/results/clientnegative/ambiguous_col_ctas.q.out @@ -0,0 +1 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in tpm diff --git a/ql/src/test/results/clientnegative/ambiguous_col_cte.q.out b/ql/src/test/results/clientnegative/ambiguous_col_cte.q.out index 19c117e1a600..a88aa731e433 100644 --- a/ql/src/test/results/clientnegative/ambiguous_col_cte.q.out +++ b/ql/src/test/results/clientnegative/ambiguous_col_cte.q.out @@ -1 +1 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference delivery_date in tpm +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in tpm diff --git a/ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out index 533d31a557c0..2a604e3b5d28 100644 --- a/ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out +++ b/ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out @@ -1 +1 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference delivery_date in bse +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in bse diff --git a/ql/src/test/results/clientnegative/ambiguous_col_unqualified_ref.q.out b/ql/src/test/results/clientnegative/ambiguous_col_unqualified_ref.q.out index 533d31a557c0..2a604e3b5d28 100644 --- a/ql/src/test/results/clientnegative/ambiguous_col_unqualified_ref.q.out +++ b/ql/src/test/results/clientnegative/ambiguous_col_unqualified_ref.q.out @@ -1 +1 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference delivery_date in bse +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in bse diff --git a/ql/src/test/results/clientnegative/ctas_dup_column.q.out b/ql/src/test/results/clientnegative/ctas_dup_column.q.out deleted file mode 100644 index 60c2f38795a2..000000000000 --- a/ql/src/test/results/clientnegative/ctas_dup_column.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10036]: Duplicate column name: c diff --git a/ql/src/test/results/clientnegative/ctas_dup_column_join.q.out b/ql/src/test/results/clientnegative/ctas_dup_column_join.q.out deleted file mode 100644 index 8746031f6caa..000000000000 --- a/ql/src/test/results/clientnegative/ctas_dup_column_join.q.out +++ /dev/null @@ -1,17 +0,0 @@ -PREHOOK: query: create table cj1 (k int, v int) -PREHOOK: type: CREATETABLE -PREHOOK: Output: database:default -PREHOOK: Output: default@cj1 -POSTHOOK: query: create table cj1 (k int, v int) -POSTHOOK: type: CREATETABLE -POSTHOOK: Output: database:default -POSTHOOK: Output: default@cj1 -PREHOOK: query: create table cj2 (k int, w int) -PREHOOK: type: CREATETABLE -PREHOOK: Output: database:default -PREHOOK: Output: default@cj2 -POSTHOOK: query: create table cj2 (k int, w int) -POSTHOOK: type: CREATETABLE -POSTHOOK: Output: database:default -POSTHOOK: Output: default@cj2 -FAILED: SemanticException [Error 10036]: Duplicate column name: k diff --git a/ql/src/test/results/clientnegative/ctas_dup_column_join_noncbo.q.out b/ql/src/test/results/clientnegative/ctas_dup_column_join_noncbo.q.out deleted file mode 100644 index 47007d97e78e..000000000000 --- a/ql/src/test/results/clientnegative/ctas_dup_column_join_noncbo.q.out +++ /dev/null @@ -1,17 +0,0 @@ -PREHOOK: query: create table cj3 (k int, v int) -PREHOOK: type: CREATETABLE -PREHOOK: Output: database:default -PREHOOK: Output: default@cj3 -POSTHOOK: query: create table cj3 (k int, v int) -POSTHOOK: type: CREATETABLE -POSTHOOK: Output: database:default -POSTHOOK: Output: default@cj3 -PREHOOK: query: create table cj4 (k int, w int) -PREHOOK: type: CREATETABLE -PREHOOK: Output: database:default -PREHOOK: Output: default@cj4 -POSTHOOK: query: create table cj4 (k int, w int) -POSTHOOK: type: CREATETABLE -POSTHOOK: Output: database:default -POSTHOOK: Output: default@cj4 -FAILED: SemanticException [Error 10036]: Duplicate column name: k diff --git a/ql/src/test/results/clientnegative/ctas_dup_column_noncbo.q.out b/ql/src/test/results/clientnegative/ctas_dup_column_noncbo.q.out deleted file mode 100644 index 60c2f38795a2..000000000000 --- a/ql/src/test/results/clientnegative/ctas_dup_column_noncbo.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10036]: Duplicate column name: c From e06b6bf9e3238eaf8b0c6a63b332e71e1c172026 Mon Sep 17 00:00:00 2001 From: Konstantin Bereznyakov Date: Thu, 6 Aug 2026 11:00:50 -0700 Subject: [PATCH 3/5] HIVE-29580: a genGBLogicalPlan tweak + more impacted tests/test rewrites --- .../hadoop/hive/ql/parse/CalcitePlanner.java | 6 +++ .../ambiguous_col_union_distinct_tolerated.q | 10 +++++ .../queries/clientpositive/cross_prod_3.q | 4 +- .../clientpositive/limit_join_transpose.q | 24 ++++++----- ...biguous_col_union_distinct_tolerated.q.out | 20 ++++++++++ .../clientpositive/llap/cross_prod_3.q.out | 4 +- .../llap/limit_join_transpose.q.out | 40 +++++++++---------- 7 files changed, 75 insertions(+), 33 deletions(-) create mode 100644 ql/src/test/queries/clientpositive/ambiguous_col_union_distinct_tolerated.q create mode 100644 ql/src/test/results/clientpositive/llap/ambiguous_col_union_distinct_tolerated.q.out diff --git a/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java b/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java index 5edda6e42057..58fd2085272b 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/parse/CalcitePlanner.java @@ -3616,6 +3616,12 @@ private RelNode genGBLogicalPlan(QB qb, RelNode srcRel) throws SemanticException // As we said before, here we use genSelectLogicalPlan to rewrite AllColRef srcRel = genSelectLogicalPlan(qb, srcRel, srcRel, null, null, true).getKey(); RowResolver rr = relToHiveRR.get(srcRel); + // genSelectDIAST synthesizes one reference per rslvMap entry, each unique by + // construction, so clear the HIVE-29580 ambiguity markers on this rewrite-private + // projection; the subquery's own RowResolver keeps them for user-written references. + for (ColumnInfo colInfo : rr.getColumnInfos()) { + colInfo.setAmbiguousName(false); + } qbp.setSelExprForClause(destClauseName, genSelectDIAST(rr)); } } diff --git a/ql/src/test/queries/clientpositive/ambiguous_col_union_distinct_tolerated.q b/ql/src/test/queries/clientpositive/ambiguous_col_union_distinct_tolerated.q new file mode 100644 index 000000000000..72a791aec4ec --- /dev/null +++ b/ql/src/test/queries/clientpositive/ambiguous_col_union_distinct_tolerated.q @@ -0,0 +1,10 @@ +-- SORT_QUERY_RESULTS +-- HIVE-29580: UNION DISTINCT is rewritten into SELECT DISTINCT * over an internal alias, and +-- the rewrite synthesizes by-name group-by references from the RowResolver it enumerated. +-- Duplicate output aliases in the branches must not trip the ambiguity check there: the +-- references are unique by construction. Both statements must compile, deduplicate across all +-- columns, and keep both duplicate columns' values intact. + +select 'a' as c, 'b' as c union select 'a', 'b' union select 'a', 'x'; + +select distinct * from (select 'a' as c, 'b' as c union all select 'a', 'b' union all select 'a', 'x') t; diff --git a/ql/src/test/queries/clientpositive/cross_prod_3.q b/ql/src/test/queries/clientpositive/cross_prod_3.q index a1024f42d163..9efcee56a1ed 100644 --- a/ql/src/test/queries/clientpositive/cross_prod_3.q +++ b/ql/src/test/queries/clientpositive/cross_prod_3.q @@ -11,4 +11,6 @@ insert overwrite table X_n2 select distinct * from src order by key limit 10; create table Y_n0 as select * from src order by key limit 1; -explain select * from Y_n0, (select * from X_n2 as A join X_n2 as B on A.key=B.key) as C where Y_n0.key=C.key; +-- HIVE-29580: the derived table's columns are aliased explicitly because "select *" over the +-- self-join projects two columns named key (and value), making the C.key reference ambiguous. +explain select * from Y_n0, (select A.key, A.value, B.key as key2, B.value as value2 from X_n2 as A join X_n2 as B on A.key=B.key) as C where Y_n0.key=C.key; diff --git a/ql/src/test/queries/clientpositive/limit_join_transpose.q b/ql/src/test/queries/clientpositive/limit_join_transpose.q index 4c484bd81354..2ac401f292e0 100644 --- a/ql/src/test/queries/clientpositive/limit_join_transpose.q +++ b/ql/src/test/queries/clientpositive/limit_join_transpose.q @@ -1,6 +1,10 @@ --! qt:dataset:src1 --! qt:dataset:src +-- HIVE-29580: the derived tables' columns are aliased explicitly because "select *" over the +-- src2/src3 join projects two columns named key (and value), making the src2.key references +-- ambiguous; the two key candidates are not even equal here since the join is on value. + SET hive.vectorized.execution.enabled=false; set hive.mapred.mode=nonstrict; set hive.optimize.limittranspose=false; @@ -50,7 +54,7 @@ limit 1; explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -58,7 +62,7 @@ limit 1; select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -71,7 +75,7 @@ set hive.optimize.limittranspose.reductiontuples=0; explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -79,7 +83,7 @@ limit 1; select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -107,7 +111,7 @@ limit 1; explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -115,7 +119,7 @@ limit 0; select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -170,7 +174,7 @@ limit 1 offset 1; explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -178,7 +182,7 @@ limit 1 offset 1; select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -191,7 +195,7 @@ set hive.optimize.limittranspose.reductiontuples=0; explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -199,7 +203,7 @@ limit 1 offset 1; select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key diff --git a/ql/src/test/results/clientpositive/llap/ambiguous_col_union_distinct_tolerated.q.out b/ql/src/test/results/clientpositive/llap/ambiguous_col_union_distinct_tolerated.q.out new file mode 100644 index 000000000000..98f54127948a --- /dev/null +++ b/ql/src/test/results/clientpositive/llap/ambiguous_col_union_distinct_tolerated.q.out @@ -0,0 +1,20 @@ +PREHOOK: query: select 'a' as c, 'b' as c union select 'a', 'b' union select 'a', 'x' +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select 'a' as c, 'b' as c union select 'a', 'b' union select 'a', 'x' +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +a b +a x +PREHOOK: query: select distinct * from (select 'a' as c, 'b' as c union all select 'a', 'b' union all select 'a', 'x') t +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +POSTHOOK: query: select distinct * from (select 'a' as c, 'b' as c union all select 'a', 'b' union all select 'a', 'x') t +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +#### A masked pattern was here #### +a b +a x diff --git a/ql/src/test/results/clientpositive/llap/cross_prod_3.q.out b/ql/src/test/results/clientpositive/llap/cross_prod_3.q.out index 6e6278f6f74c..78fdff96bb55 100644 --- a/ql/src/test/results/clientpositive/llap/cross_prod_3.q.out +++ b/ql/src/test/results/clientpositive/llap/cross_prod_3.q.out @@ -30,12 +30,12 @@ POSTHOOK: Output: database:default POSTHOOK: Output: default@Y_n0 POSTHOOK: Lineage: y_n0.key SIMPLE [(src)src.FieldSchema(name:key, type:string, comment:default), ] POSTHOOK: Lineage: y_n0.value SIMPLE [(src)src.FieldSchema(name:value, type:string, comment:default), ] -PREHOOK: query: explain select * from Y_n0, (select * from X_n2 as A join X_n2 as B on A.key=B.key) as C where Y_n0.key=C.key +PREHOOK: query: explain select * from Y_n0, (select A.key, A.value, B.key as key2, B.value as value2 from X_n2 as A join X_n2 as B on A.key=B.key) as C where Y_n0.key=C.key PREHOOK: type: QUERY PREHOOK: Input: default@x_n2 PREHOOK: Input: default@y_n0 #### A masked pattern was here #### -POSTHOOK: query: explain select * from Y_n0, (select * from X_n2 as A join X_n2 as B on A.key=B.key) as C where Y_n0.key=C.key +POSTHOOK: query: explain select * from Y_n0, (select A.key, A.value, B.key as key2, B.value as value2 from X_n2 as A join X_n2 as B on A.key=B.key) as C where Y_n0.key=C.key POSTHOOK: type: QUERY POSTHOOK: Input: default@x_n2 POSTHOOK: Input: default@y_n0 diff --git a/ql/src/test/results/clientpositive/llap/limit_join_transpose.q.out b/ql/src/test/results/clientpositive/llap/limit_join_transpose.q.out index e1228b6403b9..ad73abc03936 100644 --- a/ql/src/test/results/clientpositive/llap/limit_join_transpose.q.out +++ b/ql/src/test/results/clientpositive/llap/limit_join_transpose.q.out @@ -352,7 +352,7 @@ POSTHOOK: Input: default@src PREHOOK: query: explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -363,7 +363,7 @@ PREHOOK: Input: default@src POSTHOOK: query: explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -505,7 +505,7 @@ STAGE PLANS: PREHOOK: query: select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -515,7 +515,7 @@ PREHOOK: Input: default@src #### A masked pattern was here #### POSTHOOK: query: select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -527,7 +527,7 @@ POSTHOOK: Input: default@src PREHOOK: query: explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -538,7 +538,7 @@ PREHOOK: Input: default@src POSTHOOK: query: explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -693,7 +693,7 @@ STAGE PLANS: PREHOOK: query: select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -703,7 +703,7 @@ PREHOOK: Input: default@src #### A masked pattern was here #### POSTHOOK: query: select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -936,7 +936,7 @@ POSTHOOK: Input: default@src PREHOOK: query: explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -947,7 +947,7 @@ PREHOOK: Input: default@src POSTHOOK: query: explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -967,7 +967,7 @@ STAGE PLANS: PREHOOK: query: select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -977,7 +977,7 @@ PREHOOK: Input: default@src #### A masked pattern was here #### POSTHOOK: query: select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -1393,7 +1393,7 @@ POSTHOOK: Input: default@src PREHOOK: query: explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -1404,7 +1404,7 @@ PREHOOK: Input: default@src POSTHOOK: query: explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -1564,7 +1564,7 @@ STAGE PLANS: PREHOOK: query: select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -1574,7 +1574,7 @@ PREHOOK: Input: default@src #### A masked pattern was here #### POSTHOOK: query: select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -1586,7 +1586,7 @@ POSTHOOK: Input: default@src PREHOOK: query: explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -1597,7 +1597,7 @@ PREHOOK: Input: default@src POSTHOOK: query: explain select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -1770,7 +1770,7 @@ STAGE PLANS: PREHOOK: query: select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key @@ -1780,7 +1780,7 @@ PREHOOK: Input: default@src #### A masked pattern was here #### POSTHOOK: query: select * from src src1 right outer join ( - select * + select src2.key, src2.value, src3.key as key3, src3.value as value3 from src src2 left outer join src src3 on src2.value = src3.value) src2 on src1.key = src2.key From 5df1f198f1da139f6b58e070d1b21faccb37ac69 Mon Sep 17 00:00:00 2001 From: Konstantin Bereznyakov Date: Mon, 10 Aug 2026 15:59:10 -0700 Subject: [PATCH 4/5] HIVE-29580: consolidated tests using ignore errors precedent --- .../clientnegative/ambiguous_col_2_noncbo.q | 3 - .../ambiguous_col_aggregate_noncbo.q | 3 - .../clientnegative/ambiguous_col_cte.q | 3 - .../clientnegative/ambiguous_col_cte_noncbo.q | 4 -- .../ambiguous_col_cte_unreferenced_noncbo.q | 3 - .../ambiguous_col_exists_having_noncbo.q | 3 - .../ambiguous_col_exists_noncbo.q | 3 - .../ambiguous_col_join_wildcard_noncbo.q | 4 -- .../ambiguous_col_nested_star_noncbo.q | 2 - .../clientnegative/ambiguous_col_noncbo.q | 3 - .../clientnegative/ambiguous_col_union.q | 1 - .../ambiguous_col_union_noncbo.q | 2 - .../ambiguous_col_unreferenced_noncbo.q | 2 - .../ambiguous_colref_in_gby_noncbo.q | 3 - .../ambiguous_col_noncbo_baseline.q | 57 +++++++++++++++++++ .../clientpositive/ambiguous_col_rejected.q | 18 ++++++ .../ambiguous_col_2_noncbo.q.out | 9 --- .../ambiguous_col_aggregate_noncbo.q.out | 1 - .../ambiguous_col_cte_noncbo.q.out | 1 - ...mbiguous_col_cte_unreferenced_noncbo.q.out | 1 - .../ambiguous_col_exists_having_noncbo.q.out | 1 - .../ambiguous_col_exists_noncbo.q.out | 1 - .../ambiguous_col_join_wildcard_noncbo.q.out | 17 ------ .../ambiguous_col_nested_star_noncbo.q.out | 1 - .../clientnegative/ambiguous_col_noncbo.q.out | 1 - .../clientnegative/ambiguous_col_union.q.out | 1 - .../ambiguous_col_union_noncbo.q.out | 1 - .../ambiguous_col_unreferenced_noncbo.q.out | 1 - .../ambiguous_colref_in_gby_noncbo.q.out | 9 --- .../llap/ambiguous_col_noncbo_baseline.q.out | 44 ++++++++++++++ .../llap/ambiguous_col_rejected.q.out} | 1 + 31 files changed, 120 insertions(+), 84 deletions(-) delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_2_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_aggregate_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_cte.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_exists_having_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_exists_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_join_wildcard_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_nested_star_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_union.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_union_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_col_unreferenced_noncbo.q delete mode 100644 ql/src/test/queries/clientnegative/ambiguous_colref_in_gby_noncbo.q create mode 100644 ql/src/test/queries/clientpositive/ambiguous_col_noncbo_baseline.q create mode 100644 ql/src/test/queries/clientpositive/ambiguous_col_rejected.q delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_2_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_aggregate_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_exists_having_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_exists_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_join_wildcard_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_nested_star_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_union.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_union_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_col_unreferenced_noncbo.q.out delete mode 100644 ql/src/test/results/clientnegative/ambiguous_colref_in_gby_noncbo.q.out create mode 100644 ql/src/test/results/clientpositive/llap/ambiguous_col_noncbo_baseline.q.out rename ql/src/test/results/{clientnegative/ambiguous_col_cte.q.out => clientpositive/llap/ambiguous_col_rejected.q.out} (50%) diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_2_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_2_noncbo.q deleted file mode 100644 index 6608bac70b6e..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_2_noncbo.q +++ /dev/null @@ -1,3 +0,0 @@ -set hive.cbo.enable=false; -create table t1nc (c1 int); -explain select t.c1 from (select t11.c1, t12.c1 from t1nc as t11 inner join t1nc as t12 on t11.c1 = t12.c1) as t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_aggregate_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_aggregate_noncbo.q deleted file mode 100644 index 46c7e07f7b58..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_aggregate_noncbo.q +++ /dev/null @@ -1,3 +0,0 @@ ---! qt:dataset:src -set hive.cbo.enable=false; -select count(*) from (select key, key from src) subq; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_cte.q b/ql/src/test/queries/clientnegative/ambiguous_col_cte.q deleted file mode 100644 index 4a6f15096cbb..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_cte.q +++ /dev/null @@ -1,3 +0,0 @@ -with bse as (select 'a' as c, 'b' as c), - tpm as (select * from bse) -select tpm.c from tpm; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q deleted file mode 100644 index 8674dbde35fd..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_cte_noncbo.q +++ /dev/null @@ -1,4 +0,0 @@ -set hive.cbo.enable=false; -with bse as (select 'a' as c, 'b' as c), - tpm as (select * from bse) -select tpm.c from tpm; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q deleted file mode 100644 index 42be3a8d6ffb..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q +++ /dev/null @@ -1,3 +0,0 @@ -set hive.cbo.enable=false; -with c1 as (select 'a' as c, 'b' as c, 'x' as d) -select d from c1; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_exists_having_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_exists_having_noncbo.q deleted file mode 100644 index 0dcbe35d1980..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_exists_having_noncbo.q +++ /dev/null @@ -1,3 +0,0 @@ ---! qt:dataset:src -set hive.cbo.enable=false; -select value, count(1) from src group by value having exists (select 'x' as c, 'y' as c from src b where b.value = src.value); diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_exists_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_exists_noncbo.q deleted file mode 100644 index 10afc68f2492..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_exists_noncbo.q +++ /dev/null @@ -1,3 +0,0 @@ ---! qt:dataset:src -set hive.cbo.enable=false; -select key from src a where exists (select 'x' as c, 'y' as c from src b where b.key = a.key); diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_join_wildcard_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_join_wildcard_noncbo.q deleted file mode 100644 index 51512c86f12a..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_join_wildcard_noncbo.q +++ /dev/null @@ -1,4 +0,0 @@ -set hive.cbo.enable=false; -create table wj3 (k int, v int); -create table wj4 (k int, w int); -select t.v from (select a.*, b.* from wj3 a join wj4 b on a.k = b.k) t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_nested_star_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_nested_star_noncbo.q deleted file mode 100644 index 117e84a6cf94..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_nested_star_noncbo.q +++ /dev/null @@ -1,2 +0,0 @@ -set hive.cbo.enable=false; -select * from (select * from (select 'a' as c, 'b' as c) a) b; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_noncbo.q deleted file mode 100644 index b7dd03bbcfc9..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_noncbo.q +++ /dev/null @@ -1,3 +0,0 @@ ---! qt:dataset:src -set hive.cbo.enable=false; -FROM (SELECT key, concat(value) AS key FROM src) a SELECT a.key; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_union.q b/ql/src/test/queries/clientnegative/ambiguous_col_union.q deleted file mode 100644 index eaa72afd8983..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_union.q +++ /dev/null @@ -1 +0,0 @@ -select t.c from (select 'a' as c, 'b' as c union all select 'x', 'y') t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_union_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_union_noncbo.q deleted file mode 100644 index 0316b7850008..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_union_noncbo.q +++ /dev/null @@ -1,2 +0,0 @@ -set hive.cbo.enable=false; -select t.c from (select 'a' as c, 'b' as c union all select 'x', 'y') t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_col_unreferenced_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_col_unreferenced_noncbo.q deleted file mode 100644 index 544b50b90e07..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_col_unreferenced_noncbo.q +++ /dev/null @@ -1,2 +0,0 @@ -set hive.cbo.enable=false; -select t.d from (select 'a' as c, 'b' as c, 'x' as d) t; diff --git a/ql/src/test/queries/clientnegative/ambiguous_colref_in_gby_noncbo.q b/ql/src/test/queries/clientnegative/ambiguous_colref_in_gby_noncbo.q deleted file mode 100644 index 72a61e4680de..000000000000 --- a/ql/src/test/queries/clientnegative/ambiguous_colref_in_gby_noncbo.q +++ /dev/null @@ -1,3 +0,0 @@ -set hive.cbo.enable=false; -create table t1gnc (a int); -select s.a from (select a, a from t1gnc) s group by s.a; diff --git a/ql/src/test/queries/clientpositive/ambiguous_col_noncbo_baseline.q b/ql/src/test/queries/clientpositive/ambiguous_col_noncbo_baseline.q new file mode 100644 index 000000000000..29611b72ceb0 --- /dev/null +++ b/ql/src/test/queries/clientpositive/ambiguous_col_noncbo_baseline.q @@ -0,0 +1,57 @@ +--! qt:dataset:src +-- HIVE-29580: baseline of the non-CBO planner's PRE-EXISTING duplicate-alias strictness, which +-- the ticket deliberately leaves untouched. Every statement below fails; the FAILED messages +-- appear in the golden in statement order (hive.cli.errors.ignore format, resourceplan.q +-- precedent). The first section rejects duplicates at DEFINITION time even when never referenced +-- by name — CBO tolerates those same shapes since HIVE-19770/HIVE-20215: see +-- ambiguous_col_unreferenced_tolerated.q, this file's CBO mirror. The second section rejects +-- ambiguous REFERENCES, which CBO rejects too (ambiguous_col_rejected.q and ambiguous_col.q). +set hive.cli.errors.ignore=true; +set hive.cbo.enable=false; + +-- ==== definition-time rejections: the duplicate is never referenced by name ==== + +-- another column of the derived table is referenced +select t.d from (select 'a' as c, 'b' as c, 'x' as d) t; + +-- same, through a CTE +with c1 as (select 'a' as c, 'b' as c, 'x' as d) +select d from c1; + +-- only counted, no column referenced +select count(*) from (select key, key from src) subq; + +-- duplicate created by a wildcard join expansion +create table wj3 (k int, v int); +create table wj4 (k int, w int); +select t.v from (select a.*, b.* from wj3 a join wj4 b on a.k = b.k) t; + +-- duplicate crosses two nested star boundaries +select * from (select * from (select 'a' as c, 'b' as c) a) b; + +-- duplicate defined inside an EXISTS subquery +select key from src a where exists (select 'x' as c, 'y' as c from src b where b.key = a.key); + +-- duplicate defined inside an EXISTS in HAVING +select value, count(1) from src group by value having exists (select 'x' as c, 'y' as c from src b where b.value = src.value); + +-- ==== reference-time rejections: the duplicate name is referenced ==== + +-- expression aliased onto an existing column name, then referenced +FROM (SELECT key, concat(value) AS key FROM src) a SELECT a.key; + +-- the HIVE-20215 self-join example +create table t1nc (c1 int); +explain select t.c1 from (select t11.c1, t12.c1 from t1nc as t11 inner join t1nc as t12 on t11.c1 = t12.c1) as t; + +-- qualified reference through a consuming CTE +with bse as (select 'a' as c, 'b' as c), + tpm as (select * from bse) +select tpm.c from tpm; + +-- reference into a UNION ALL branch +select t.c from (select 'a' as c, 'b' as c union all select 'x', 'y') t; + +-- ambiguous reference used as a GROUP BY key +create table t1gnc (a int); +select s.a from (select a, a from t1gnc) s group by s.a; diff --git a/ql/src/test/queries/clientpositive/ambiguous_col_rejected.q b/ql/src/test/queries/clientpositive/ambiguous_col_rejected.q new file mode 100644 index 000000000000..3ea266da7e96 --- /dev/null +++ b/ql/src/test/queries/clientpositive/ambiguous_col_rejected.q @@ -0,0 +1,18 @@ +-- HIVE-29580: queries whose by-name reference targets a duplicate-named column that escaped a +-- subquery/CTE boundary. Before HIVE-29580 these compiled under CBO with the reference silently +-- bound to an arbitrary candidate; they are rejected now. hive.cli.errors.ignore lets all +-- rejections live in one reviewable file (resourceplan.q precedent); each statement's FAILED +-- message appears in the golden in statement order. Mechanism-specific rejections have their own +-- clientnegative tests: ambiguous_col{,_2,_ctas,_distinct_window,_join_cond,_join_cond_unqual, +-- _join_using,_lateral_view_alias,_unqualified_ref}.q. The non-CBO baseline for these shapes is +-- ambiguous_col_noncbo_baseline.q. +set hive.cli.errors.ignore=true; + +-- the JIRA shape: duplicate alias escapes a CTE, then a qualified reference through the +-- consuming CTE's alias +with bse as (select 'a' as c, 'b' as c), + tpm as (select * from bse) +select tpm.c from tpm; + +-- duplicate alias escapes a UNION ALL branch into the derived-table alias +select t.c from (select 'a' as c, 'b' as c union all select 'x', 'y') t; diff --git a/ql/src/test/results/clientnegative/ambiguous_col_2_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_2_noncbo.q.out deleted file mode 100644 index d6ce2f43b330..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_2_noncbo.q.out +++ /dev/null @@ -1,9 +0,0 @@ -PREHOOK: query: create table t1nc (c1 int) -PREHOOK: type: CREATETABLE -PREHOOK: Output: database:default -PREHOOK: Output: default@t1nc -POSTHOOK: query: create table t1nc (c1 int) -POSTHOOK: type: CREATETABLE -POSTHOOK: Output: database:default -POSTHOOK: Output: default@t1nc -FAILED: SemanticException [Error 10007]: Ambiguous column reference c1 in t diff --git a/ql/src/test/results/clientnegative/ambiguous_col_aggregate_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_aggregate_noncbo.q.out deleted file mode 100644 index 40952cdc22bb..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_aggregate_noncbo.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference key in subq diff --git a/ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out deleted file mode 100644 index 2a604e3b5d28..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_cte_noncbo.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference c in bse diff --git a/ql/src/test/results/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q.out deleted file mode 100644 index bb9278bc19fe..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_cte_unreferenced_noncbo.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference c in c1 diff --git a/ql/src/test/results/clientnegative/ambiguous_col_exists_having_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_exists_having_noncbo.q.out deleted file mode 100644 index f18587c08360..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_exists_having_noncbo.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference c in sq_1 diff --git a/ql/src/test/results/clientnegative/ambiguous_col_exists_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_exists_noncbo.q.out deleted file mode 100644 index f18587c08360..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_exists_noncbo.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference c in sq_1 diff --git a/ql/src/test/results/clientnegative/ambiguous_col_join_wildcard_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_join_wildcard_noncbo.q.out deleted file mode 100644 index d9e59b52badc..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_join_wildcard_noncbo.q.out +++ /dev/null @@ -1,17 +0,0 @@ -PREHOOK: query: create table wj3 (k int, v int) -PREHOOK: type: CREATETABLE -PREHOOK: Output: database:default -PREHOOK: Output: default@wj3 -POSTHOOK: query: create table wj3 (k int, v int) -POSTHOOK: type: CREATETABLE -POSTHOOK: Output: database:default -POSTHOOK: Output: default@wj3 -PREHOOK: query: create table wj4 (k int, w int) -PREHOOK: type: CREATETABLE -PREHOOK: Output: database:default -PREHOOK: Output: default@wj4 -POSTHOOK: query: create table wj4 (k int, w int) -POSTHOOK: type: CREATETABLE -POSTHOOK: Output: database:default -POSTHOOK: Output: default@wj4 -FAILED: SemanticException [Error 10007]: Ambiguous column reference k in t diff --git a/ql/src/test/results/clientnegative/ambiguous_col_nested_star_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_nested_star_noncbo.q.out deleted file mode 100644 index 53d5a7a85c38..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_nested_star_noncbo.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference c in a diff --git a/ql/src/test/results/clientnegative/ambiguous_col_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_noncbo.q.out deleted file mode 100644 index a2915a4a5d3d..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_noncbo.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference key in a diff --git a/ql/src/test/results/clientnegative/ambiguous_col_union.q.out b/ql/src/test/results/clientnegative/ambiguous_col_union.q.out deleted file mode 100644 index 58aee7c08949..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_union.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference c in t diff --git a/ql/src/test/results/clientnegative/ambiguous_col_union_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_union_noncbo.q.out deleted file mode 100644 index b75f8a02dc10..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_union_noncbo.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference c in __u1-subquery1 diff --git a/ql/src/test/results/clientnegative/ambiguous_col_unreferenced_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_col_unreferenced_noncbo.q.out deleted file mode 100644 index 58aee7c08949..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_col_unreferenced_noncbo.q.out +++ /dev/null @@ -1 +0,0 @@ -FAILED: SemanticException [Error 10007]: Ambiguous column reference c in t diff --git a/ql/src/test/results/clientnegative/ambiguous_colref_in_gby_noncbo.q.out b/ql/src/test/results/clientnegative/ambiguous_colref_in_gby_noncbo.q.out deleted file mode 100644 index 58234a65ac4f..000000000000 --- a/ql/src/test/results/clientnegative/ambiguous_colref_in_gby_noncbo.q.out +++ /dev/null @@ -1,9 +0,0 @@ -PREHOOK: query: create table t1gnc (a int) -PREHOOK: type: CREATETABLE -PREHOOK: Output: database:default -PREHOOK: Output: default@t1gnc -POSTHOOK: query: create table t1gnc (a int) -POSTHOOK: type: CREATETABLE -POSTHOOK: Output: database:default -POSTHOOK: Output: default@t1gnc -FAILED: SemanticException [Error 10007]: Ambiguous column reference a in s diff --git a/ql/src/test/results/clientpositive/llap/ambiguous_col_noncbo_baseline.q.out b/ql/src/test/results/clientpositive/llap/ambiguous_col_noncbo_baseline.q.out new file mode 100644 index 000000000000..3ab30363d785 --- /dev/null +++ b/ql/src/test/results/clientpositive/llap/ambiguous_col_noncbo_baseline.q.out @@ -0,0 +1,44 @@ +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in t +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in c1 +FAILED: SemanticException [Error 10007]: Ambiguous column reference key in subq +PREHOOK: query: create table wj3 (k int, v int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@wj3 +POSTHOOK: query: create table wj3 (k int, v int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@wj3 +PREHOOK: query: create table wj4 (k int, w int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@wj4 +POSTHOOK: query: create table wj4 (k int, w int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@wj4 +FAILED: SemanticException [Error 10007]: Ambiguous column reference k in t +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in a +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in sq_1 +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in sq_1 +FAILED: SemanticException [Error 10007]: Ambiguous column reference key in a +PREHOOK: query: create table t1nc (c1 int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@t1nc +POSTHOOK: query: create table t1nc (c1 int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@t1nc +FAILED: SemanticException [Error 10007]: Ambiguous column reference c1 in t +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in bse +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in __u1-subquery1 +PREHOOK: query: create table t1gnc (a int) +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@t1gnc +POSTHOOK: query: create table t1gnc (a int) +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@t1gnc +FAILED: SemanticException [Error 10007]: Ambiguous column reference a in s diff --git a/ql/src/test/results/clientnegative/ambiguous_col_cte.q.out b/ql/src/test/results/clientpositive/llap/ambiguous_col_rejected.q.out similarity index 50% rename from ql/src/test/results/clientnegative/ambiguous_col_cte.q.out rename to ql/src/test/results/clientpositive/llap/ambiguous_col_rejected.q.out index a88aa731e433..513edd2228c5 100644 --- a/ql/src/test/results/clientnegative/ambiguous_col_cte.q.out +++ b/ql/src/test/results/clientpositive/llap/ambiguous_col_rejected.q.out @@ -1 +1,2 @@ FAILED: SemanticException [Error 10007]: Ambiguous column reference c in tpm +FAILED: SemanticException [Error 10007]: Ambiguous column reference c in t From 31b98088bc5eb5312295d98d61ab629cde464a0c Mon Sep 17 00:00:00 2001 From: Konstantin Bereznyakov Date: Tue, 11 Aug 2026 10:43:47 -0700 Subject: [PATCH 5/5] HIVE-29580: unit test coverage --- .../TestColumnInfo.java} | 31 +-- .../hive/ql/parse/TestSemanticAnalyzer.java | 111 ++++++++++ .../sql/TestMultiInsertSqlGenerator.java | 82 +++++++ .../TestJoinCondTypeCheckProcFactory.java | 108 ++++++++++ .../parse/type/TestTypeCheckProcFactory.java | 201 +++++++++++------- 5 files changed, 428 insertions(+), 105 deletions(-) rename ql/src/test/org/apache/hadoop/hive/ql/{parse/type/TestAmbiguousColumnName.java => exec/TestColumnInfo.java} (58%) create mode 100644 ql/src/test/org/apache/hadoop/hive/ql/parse/rewrite/sql/TestMultiInsertSqlGenerator.java create mode 100644 ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestJoinCondTypeCheckProcFactory.java diff --git a/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestAmbiguousColumnName.java b/ql/src/test/org/apache/hadoop/hive/ql/exec/TestColumnInfo.java similarity index 58% rename from ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestAmbiguousColumnName.java rename to ql/src/test/org/apache/hadoop/hive/ql/exec/TestColumnInfo.java index 8832ffcbfd3e..5fbe0b85c3ed 100644 --- a/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestAmbiguousColumnName.java +++ b/ql/src/test/org/apache/hadoop/hive/ql/exec/TestColumnInfo.java @@ -16,43 +16,24 @@ * limitations under the License. */ -package org.apache.hadoop.hive.ql.parse.type; +package org.apache.hadoop.hive.ql.exec; -import org.apache.hadoop.hive.ql.exec.ColumnInfo; -import org.apache.hadoop.hive.ql.parse.SemanticException; import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory; import org.junit.Assert; import org.junit.Test; -public class TestAmbiguousColumnName { +public class TestColumnInfo { - private static ColumnInfo colInfo() { + @Test + public void testAmbiguousNameDefaultsToFalse() { ColumnInfo colInfo = new ColumnInfo("_col0", TypeInfoFactory.stringTypeInfo, "t", false); - colInfo.setAlias("c"); - return colInfo; + Assert.assertFalse(colInfo.hasAmbiguousName()); } @Test public void testCopyConstructorPreservesAmbiguousName() { - ColumnInfo original = colInfo(); + ColumnInfo original = new ColumnInfo("_col0", TypeInfoFactory.stringTypeInfo, "t", false); original.setAmbiguousName(true); Assert.assertTrue(new ColumnInfo(original).hasAmbiguousName()); } - - @Test - public void testCheckAmbiguousNameThrows() { - ColumnInfo marked = colInfo(); - marked.setAmbiguousName(true); - try { - TypeCheckProcFactory.checkAmbiguousName(marked); - Assert.fail("expected SemanticException"); - } catch (SemanticException e) { - Assert.assertTrue(e.getMessage(), e.getMessage().contains("Ambiguous column reference c in t")); - } - } - - @Test - public void testCheckAmbiguousNameNoThrow() throws SemanticException { - TypeCheckProcFactory.checkAmbiguousName(colInfo()); - } } diff --git a/ql/src/test/org/apache/hadoop/hive/ql/parse/TestSemanticAnalyzer.java b/ql/src/test/org/apache/hadoop/hive/ql/parse/TestSemanticAnalyzer.java index 17ac1b353bf2..99be8a464152 100644 --- a/ql/src/test/org/apache/hadoop/hive/ql/parse/TestSemanticAnalyzer.java +++ b/ql/src/test/org/apache/hadoop/hive/ql/parse/TestSemanticAnalyzer.java @@ -21,6 +21,7 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertThrows; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; @@ -33,13 +34,17 @@ import static org.mockito.Mockito.when; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import com.google.common.collect.Sets; +import org.antlr.runtime.CommonToken; +import org.apache.commons.lang3.tuple.Pair; import org.apache.hadoop.hive.common.MaterializationSnapshot; import org.apache.hadoop.hive.common.type.Date; import org.apache.hadoop.hive.conf.HiveConf; @@ -55,6 +60,7 @@ import org.apache.hadoop.hive.ql.QueryProperties.QueryType; import org.apache.hadoop.hive.ql.QueryState; import org.apache.hadoop.hive.ql.cache.results.QueryResultsCache; +import org.apache.hadoop.hive.ql.exec.ColumnInfo; import org.apache.hadoop.hive.ql.exec.FileSinkOperator; import org.apache.hadoop.hive.ql.exec.Operator; import org.apache.hadoop.hive.ql.lockmgr.DbTxnManager; @@ -66,6 +72,7 @@ import org.apache.hadoop.hive.ql.security.HadoopDefaultAuthenticator; import org.apache.hadoop.hive.ql.session.SessionState; import org.apache.hadoop.hive.serde2.io.DateWritableV2; +import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory; import org.junit.AfterClass; import org.junit.Assert; import org.junit.BeforeClass; @@ -545,4 +552,108 @@ private void testMaterializeCTEUsesDDLFactory(boolean cboEnabled) throws Excepti cteAnalyzer[0] instanceof CreateTableAnalyzer); } } + + // ==== HIVE-29580: duplicate column aliases escaping a subquery/CTE boundary ==== + + private BaseSemanticAnalyzer analyzeWithCbo(String query) throws Exception { + HiveConf cboConf = new HiveConf(conf); + cboConf.setBoolVar(HiveConf.ConfVars.HIVE_CBO_ENABLED, true); + SessionState.start(cboConf); + Context ctx = new Context(cboConf); + ASTNode astNode = ParseUtils.parse(query, ctx); + QueryState queryState = new QueryState.Builder().withHiveConf(cboConf).build(); + BaseSemanticAnalyzer analyzer = SemanticAnalyzerFactory.get(queryState, astNode); + analyzer.initCtx(ctx); + try { + analyzer.analyze(astNode, ctx); + } finally { + analyzer.endAnalysis(astNode); + } + return analyzer; + } + + private void assertCboRejectsAmbiguous(String query, String expectedReference) { + SemanticException e = assertThrows(SemanticException.class, () -> analyzeWithCbo(query)); + assertTrue(e.getMessage(), + e.getMessage().contains("Ambiguous column reference " + expectedReference)); + } + + @Test + public void testCboRejectsAmbiguousReferenceAcrossCteBoundary() throws Exception { + assertCboRejectsAmbiguous( + "with bse as (select 'a' as c, 'b' as c), tpm as (select * from bse) select tpm.c from tpm", + "c in tpm"); + } + + @Test + public void testCboAmbiguityMarkerSurvivesWindowingProjection() throws Exception { + assertCboRejectsAmbiguous( + "select x.c from (select distinct *, rank() over (order by d) r" + + " from (select 'a' as c, 'b' as c, 'x' as d) t) x", + "c in x"); + } + + @Test + public void testCboToleratesUnionDistinctWithDuplicateAliases() throws Exception { + // UNION DISTINCT is rewritten into SELECT DISTINCT * whose group by references are + // synthesized by genSelectDIAST; despite the duplicate output alias this must compile + assertNotNull(analyzeWithCbo("select x.key, z.value, y.value" + + " from table1 x join table2 y on x.key = y.key" + + " join (select * from table1 union select * from table2) z on x.value = z.value" + + " union" + + " select x.key, z.value, y.value" + + " from table1 x join table2 y on x.key = y.key" + + " join (select * from table1 union select * from table2) z on x.value = z.value")); + } + + private static ColumnInfo stringCol(String internalName, String tab, String alias, boolean markedAmbiguous) { + ColumnInfo colInfo = new ColumnInfo(internalName, TypeInfoFactory.stringTypeInfo, tab, false); + colInfo.setAlias(alias); + colInfo.setAmbiguousName(markedAmbiguous); + return colInfo; + } + + private SemanticAnalyzer newAnalyzerForDirectCalls() throws Exception { + SessionState.start(conf); + QueryState queryState = new QueryState.Builder().withHiveConf(conf).build(); + SemanticAnalyzer analyzer = new SemanticAnalyzer(queryState); + analyzer.initCtx(new Context(conf)); + // genColListRegex consults tableMask, which analyzeInternal normally initializes + analyzer.tableMask = new TableMask(analyzer, conf, true); + return analyzer; + } + + private static ASTNode allColRef() { + return new ASTNode(new CommonToken(HiveParser.TOK_ALLCOLREF, "TOK_ALLCOLREF")); + } + + @Test + public void testGenColListRegexPropagatesAmbiguousNameMarker() throws Exception { + SemanticAnalyzer analyzer = newAnalyzerForDirectCalls(); + RowResolver input = new RowResolver(); + input.put("t", "c", stringCol("_c0", "t", "c", true)); + input.put("t", "d", stringCol("_c1", "t", "d", false)); + RowResolver output = new RowResolver(); + + analyzer.genColListRegex(".*", "t", allColRef(), new ArrayList<>(), + new HashSet<>(), input, null, 0, output, new ArrayList<>(Arrays.asList("t")), false); + + assertTrue(output.get("t", "c").hasAmbiguousName()); + assertFalse(output.get("t", "d").hasAmbiguousName()); + } + + @Test + public void testGenColListRegexPropagatesAmbiguousNameMarkerForNamedJoin() throws Exception { + SemanticAnalyzer analyzer = newAnalyzerForDirectCalls(); + RowResolver colSrcRR = new RowResolver(); + colSrcRR.put("l", "c", stringCol("_l0", "l", "c", true)); + colSrcRR.put("r", "c", stringCol("_r0", "r", "c", false)); + colSrcRR.setNamedJoinInfo(new NamedJoinInfo(Arrays.asList("l", "r"), Arrays.asList("c"), JoinType.INNER)); + RowResolver output = new RowResolver(); + + analyzer.genColListRegex(".*", null, allColRef(), new ArrayList<>(), + new HashSet<>(), colSrcRR, colSrcRR, 0, output, new ArrayList<>(Arrays.asList("l", "r")), false); + + assertTrue(output.get("l", "c").hasAmbiguousName()); + } } diff --git a/ql/src/test/org/apache/hadoop/hive/ql/parse/rewrite/sql/TestMultiInsertSqlGenerator.java b/ql/src/test/org/apache/hadoop/hive/ql/parse/rewrite/sql/TestMultiInsertSqlGenerator.java new file mode 100644 index 000000000000..c148b28c5e7d --- /dev/null +++ b/ql/src/test/org/apache/hadoop/hive/ql/parse/rewrite/sql/TestMultiInsertSqlGenerator.java @@ -0,0 +1,82 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hive.ql.parse.rewrite.sql; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import org.apache.hadoop.hive.conf.HiveConf; +import org.apache.hadoop.hive.metastore.api.FieldSchema; +import org.apache.hadoop.hive.ql.Context.Operation; +import org.apache.hadoop.hive.ql.metadata.Table; +import org.junit.Assert; +import org.junit.Test; +import org.mockito.Mockito; + +public class TestMultiInsertSqlGenerator { + + private static final List DATA_COLS = Arrays.asList( + new FieldSchema("a", "int", null), new FieldSchema("b", "string", null)); + private static final List ALL_COLS = Arrays.asList( + new FieldSchema("a", "int", null), new FieldSchema("b", "string", null), + new FieldSchema("p", "string", null)); + private static final HiveConf CONF = new HiveConf(); + + private static MultiInsertSqlGenerator generator(boolean nonNativePartitionSupport) { + Table table = Mockito.mock(Table.class); + Mockito.when(table.getCols()).thenReturn(DATA_COLS); + Mockito.when(table.getAllCols()).thenReturn(ALL_COLS); + Mockito.when(table.hasNonNativePartitionSupport()).thenReturn(nonNativePartitionSupport); + return new MultiInsertSqlGenerator(table, "t", CONF, null) { + @Override + public void appendAcidSelectColumns(Operation operation) { + } + + @Override + public List getDeleteValues(Operation operation) { + return Collections.emptyList(); + } + + @Override + public List getSortKeys(Operation operation) { + return Collections.emptyList(); + } + }; + } + + /** + * HIVE-29580: for natively partitioned tables the partition columns are emitted by + * appendAcidSelectColumns, so they must be omitted here or the rewritten projection contains + * duplicate column names. + */ + @Test + public void testAppendNonPartitionColsOmitsPartitionColsForNativeTable() { + MultiInsertSqlGenerator generator = generator(false); + generator.appendNonPartitionColsOfTargetTable(); + Assert.assertEquals("`a`, `b`", generator.toString()); + } + + @Test + public void testAppendNonPartitionColsKeepsAllColsForNonNativeTable() { + MultiInsertSqlGenerator generator = generator(true); + generator.appendNonPartitionColsOfTargetTable(); + Assert.assertEquals("`a`, `b`, `p`", generator.toString()); + } +} diff --git a/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestJoinCondTypeCheckProcFactory.java b/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestJoinCondTypeCheckProcFactory.java new file mode 100644 index 000000000000..34ec2c81df01 --- /dev/null +++ b/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestJoinCondTypeCheckProcFactory.java @@ -0,0 +1,108 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.hadoop.hive.ql.parse.type; + +import java.util.Map; + +import org.antlr.runtime.CommonToken; +import org.apache.calcite.jdbc.JavaTypeFactoryImpl; +import org.apache.calcite.rex.RexBuilder; +import org.apache.calcite.rex.RexNode; +import org.apache.hadoop.hive.ql.exec.ColumnInfo; +import org.apache.hadoop.hive.ql.optimizer.calcite.HiveTypeSystemImpl; +import org.apache.hadoop.hive.ql.parse.ASTNode; +import org.apache.hadoop.hive.ql.parse.HiveParser; +import org.apache.hadoop.hive.ql.parse.JoinType; +import org.apache.hadoop.hive.ql.parse.RowResolver; +import org.apache.hadoop.hive.ql.parse.SemanticException; +import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory; +import org.junit.Assert; +import org.junit.Test; + +/** + * Tests for the ambiguity checks in JoinCondTypeCheckProcFactory (HIVE-29580): a join condition + * referencing a duplicate-named column that escaped a subquery boundary must be rejected, both + * through the qualified (JoinCondDefaultExprProcessor) and the unqualified + * (JoinCondColumnExprProcessor) resolution paths. The expressions are type checked through the + * same walker entry point the planner uses. + */ +public class TestJoinCondTypeCheckProcFactory { + + private static ASTNode node(int type, String text) { + return new ASTNode(new CommonToken(type, text)); + } + + private static ASTNode unqualifiedRef(String col) { + ASTNode tableOrCol = node(HiveParser.TOK_TABLE_OR_COL, "TOK_TABLE_OR_COL"); + tableOrCol.addChild(node(HiveParser.Identifier, col)); + return tableOrCol; + } + + private static ASTNode qualifiedRef(String tab, String col) { + ASTNode dot = node(HiveParser.DOT, "."); + dot.addChild(unqualifiedRef(tab)); + dot.addChild(node(HiveParser.Identifier, col)); + return dot; + } + + private static RowResolver singleColRR(String tab, String col, boolean markedAmbiguous) { + RowResolver rr = new RowResolver(); + ColumnInfo colInfo = new ColumnInfo(tab + "_" + col, TypeInfoFactory.stringTypeInfo, tab, false); + colInfo.setAlias(col); + colInfo.setAmbiguousName(markedAmbiguous); + rr.put(tab, col, colInfo); + return rr; + } + + private static Map typeCheck(ASTNode expr, boolean leftColumnMarked) + throws SemanticException { + RowResolver leftRR = singleColRR("t", "c", leftColumnMarked); + RowResolver rightRR = singleColRR("u", "e", false); + RexBuilder rexBuilder = new RexBuilder(new JavaTypeFactoryImpl(new HiveTypeSystemImpl())); + JoinTypeCheckCtx ctx = new JoinTypeCheckCtx(leftRR, rightRR, rexBuilder, JoinType.INNER); + return RexNodeTypeCheck.genExprNodeJoinCond(expr, ctx, rexBuilder); + } + + private static void assertThrowsAmbiguous(ASTNode expr) { + SemanticException e = Assert.assertThrows(SemanticException.class, () -> typeCheck(expr, true)); + Assert.assertTrue(e.getMessage(), e.getMessage().contains("Ambiguous column reference c in t")); + } + + @Test + public void testQualifiedRefToMarkedColumnThrows() { + assertThrowsAmbiguous(qualifiedRef("t", "c")); + } + + @Test + public void testUnqualifiedRefToMarkedColumnThrows() { + assertThrowsAmbiguous(unqualifiedRef("c")); + } + + @Test + public void testQualifiedRefToCleanColumnResolves() throws SemanticException { + ASTNode expr = qualifiedRef("t", "c"); + Assert.assertNotNull(typeCheck(expr, false).get(expr)); + } + + @Test + public void testUnqualifiedRefToCleanColumnResolves() throws SemanticException { + ASTNode expr = unqualifiedRef("c"); + Assert.assertNotNull(typeCheck(expr, false).get(expr)); + } +} diff --git a/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestTypeCheckProcFactory.java b/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestTypeCheckProcFactory.java index 3740d9814517..9eb1b333cde0 100644 --- a/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestTypeCheckProcFactory.java +++ b/ql/src/test/org/apache/hadoop/hive/ql/parse/type/TestTypeCheckProcFactory.java @@ -21,14 +21,18 @@ import java.util.Arrays; import java.util.Collection; +import org.apache.hadoop.hive.ql.exec.ColumnInfo; +import org.apache.hadoop.hive.ql.parse.SemanticException; import org.apache.hadoop.hive.ql.parse.type.TypeCheckProcFactory.DefaultExprProcessor; import org.apache.hadoop.hive.ql.plan.ExprNodeConstantDesc; import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils; import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorUtils.PrimitiveTypeEntry; import org.apache.hadoop.hive.serde2.typeinfo.PrimitiveTypeInfo; +import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.experimental.runners.Enclosed; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; import org.junit.runners.Parameterized.Parameters; @@ -37,107 +41,144 @@ import org.mockito.MockitoAnnotations; /** - * Parametrized test for the TypeCheckProcFactory. - * + * Tests for the TypeCheckProcFactory. */ -@RunWith(Parameterized.class) +@RunWith(Enclosed.class) public class TestTypeCheckProcFactory { - @Mock - private PrimitiveTypeInfo typeInfo; - @Mock - private ExprNodeConstantDesc nodeDesc; - - private DefaultExprProcessor testSubject; - - @Parameters(name = "{1}") - public static Collection data() { - return Arrays.asList(new Object[][] {{"127", PrimitiveObjectInspectorUtils.byteTypeEntry, (byte) 127, true}, - {"32767", PrimitiveObjectInspectorUtils.shortTypeEntry, (short) 32767, true}, - {"2147483647", PrimitiveObjectInspectorUtils.intTypeEntry, 2147483647, true}, - {"9223372036854775807", PrimitiveObjectInspectorUtils.longTypeEntry, 9223372036854775807L, true}, - {"111.1", PrimitiveObjectInspectorUtils.floatTypeEntry, 111.1f, false}, - {"111.1", PrimitiveObjectInspectorUtils.doubleTypeEntry, 111.1d, false}}); - } - private final BigDecimal maxValue; - private final PrimitiveTypeEntry constType; - private final Object expectedValue; - private final boolean intType; - - public TestTypeCheckProcFactory(String maxValue, PrimitiveTypeEntry constType, Object expectedValue, - boolean intType) { - this.maxValue = new BigDecimal(maxValue); - this.constType = constType; - this.expectedValue = expectedValue; - this.intType = intType; - } + /** + * Parametrized tests for constant interpretation. + */ + @RunWith(Parameterized.class) + public static class ConstantInterpretationTest { + @Mock + private PrimitiveTypeInfo typeInfo; + @Mock + private ExprNodeConstantDesc nodeDesc; + + private DefaultExprProcessor testSubject; + + @Parameters(name = "{1}") + public static Collection data() { + return Arrays.asList(new Object[][] {{"127", PrimitiveObjectInspectorUtils.byteTypeEntry, (byte) 127, true}, + {"32767", PrimitiveObjectInspectorUtils.shortTypeEntry, (short) 32767, true}, + {"2147483647", PrimitiveObjectInspectorUtils.intTypeEntry, 2147483647, true}, + {"9223372036854775807", PrimitiveObjectInspectorUtils.longTypeEntry, 9223372036854775807L, true}, + {"111.1", PrimitiveObjectInspectorUtils.floatTypeEntry, 111.1f, false}, + {"111.1", PrimitiveObjectInspectorUtils.doubleTypeEntry, 111.1d, false}}); + } - @Before - public void init() { - MockitoAnnotations.initMocks(this); - testSubject = ExprNodeTypeCheck.getExprNodeDefaultExprProcessor(); - } + private final BigDecimal maxValue; + private final PrimitiveTypeEntry constType; + private final Object expectedValue; + private final boolean intType; + + public ConstantInterpretationTest(String maxValue, PrimitiveTypeEntry constType, Object expectedValue, + boolean intType) { + this.maxValue = new BigDecimal(maxValue); + this.constType = constType; + this.expectedValue = expectedValue; + this.intType = intType; + } - public void testOneCase(Object constValue) throws Exception { - Mockito.when(nodeDesc.getValue()).thenReturn(constValue); - Mockito.when(typeInfo.getPrimitiveTypeEntry()).thenReturn(constType); + @Before + public void init() { + MockitoAnnotations.initMocks(this); + testSubject = ExprNodeTypeCheck.getExprNodeDefaultExprProcessor(); + } - ExprNodeConstantDesc result = (ExprNodeConstantDesc) testSubject.interpretNodeAsConstant(typeInfo, nodeDesc); + public void testOneCase(Object constValue) throws Exception { + Mockito.when(nodeDesc.getValue()).thenReturn(constValue); + Mockito.when(typeInfo.getPrimitiveTypeEntry()).thenReturn(constType); - Assert.assertNotNull(result); - Assert.assertEquals(expectedValue, result.getValue()); - } + ExprNodeConstantDesc result = (ExprNodeConstantDesc) testSubject.interpretNodeAsConstant(typeInfo, nodeDesc); - public void testNullCase(Object constValue) throws Exception { - Mockito.when(nodeDesc.getValue()).thenReturn(constValue); - Mockito.when(typeInfo.getPrimitiveTypeEntry()).thenReturn(constType); + Assert.assertNotNull(result); + Assert.assertEquals(expectedValue, result.getValue()); + } - ExprNodeConstantDesc result = (ExprNodeConstantDesc) testSubject.interpretNodeAsConstant(typeInfo, nodeDesc); + public void testNullCase(Object constValue) throws Exception { + Mockito.when(nodeDesc.getValue()).thenReturn(constValue); + Mockito.when(typeInfo.getPrimitiveTypeEntry()).thenReturn(constType); - Assert.assertNull(result); - } + ExprNodeConstantDesc result = (ExprNodeConstantDesc) testSubject.interpretNodeAsConstant(typeInfo, nodeDesc); - @Test - public void testWithSring() throws Exception { - testOneCase(maxValue.toString()); - } + Assert.assertNull(result); + } - @Test - public void testWithLSuffix() throws Exception { - if (intType) { - testOneCase(maxValue.toString() + "L"); + @Test + public void testWithSring() throws Exception { + testOneCase(maxValue.toString()); } - } - @Test - public void testWithZeroFraction() throws Exception { - if (intType) { - testOneCase(maxValue.toString() + ".0"); + @Test + public void testWithLSuffix() throws Exception { + if (intType) { + testOneCase(maxValue.toString() + "L"); + } } - } - @Test - public void testWithFSuffix() throws Exception { - testOneCase(maxValue.toString() + "f"); - } + @Test + public void testWithZeroFraction() throws Exception { + if (intType) { + testOneCase(maxValue.toString() + ".0"); + } + } - @Test - public void testWithDSuffix() throws Exception { - testOneCase(maxValue.toString() + "D"); - } + @Test + public void testWithFSuffix() throws Exception { + testOneCase(maxValue.toString() + "f"); + } - @Test - public void testOverflow() throws Exception { - if (intType) { - testNullCase(maxValue.add(BigDecimal.valueOf(1L)).toString()); + @Test + public void testWithDSuffix() throws Exception { + testOneCase(maxValue.toString() + "D"); } - } - @Test - public void testWithNonZeroFraction() throws Exception { - if (intType) { - testNullCase("100.1"); + @Test + public void testOverflow() throws Exception { + if (intType) { + testNullCase(maxValue.add(BigDecimal.valueOf(1L)).toString()); + } + } + + @Test + public void testWithNonZeroFraction() throws Exception { + if (intType) { + testNullCase("100.1"); + } } } + /** + * Tests for checkAmbiguousName (HIVE-29580). The planner-side call sites are covered by the + * ambiguous_col* qtests. + */ + public static class CheckAmbiguousNameTest { + + private static ColumnInfo colInfo() { + ColumnInfo colInfo = new ColumnInfo("_col0", TypeInfoFactory.stringTypeInfo, "t", false); + colInfo.setAlias("c"); + return colInfo; + } + + @Test + public void testCheckAmbiguousNameThrows() { + ColumnInfo marked = colInfo(); + marked.setAmbiguousName(true); + SemanticException e = Assert.assertThrows(SemanticException.class, + () -> TypeCheckProcFactory.checkAmbiguousName(marked)); + Assert.assertTrue(e.getMessage(), e.getMessage().contains("Ambiguous column reference c in t")); + } + + @Test + public void testCheckAmbiguousNameNoThrow() throws SemanticException { + TypeCheckProcFactory.checkAmbiguousName(colInfo()); + } + + @Test + public void testCheckAmbiguousNameNullTolerant() throws SemanticException { + TypeCheckProcFactory.checkAmbiguousName(null); + } + } }