From 6778964e18e7f880088590dd07aa446fd4b9414a Mon Sep 17 00:00:00 2001 From: Ramit Gupta Date: Wed, 29 Jul 2026 13:29:59 +0530 Subject: [PATCH] HIVE-29782:ALTER VIEW ADD PARTITION does not honor non string partition columns Change-Id: I56fa674c2d7c8db6187d75e9fd2f5d39a3ec766e Change-Id: I790b126f63e73d03dc0ef2d04ed1e71d37f79028 --- .../add/AlterViewAddPartitionAnalyzer.java | 22 +- .../ddl/view/create/CreateViewAnalyzer.java | 7 + .../partitioned_view_add_parts_complex.q | 5 + .../partitioned_view_add_parts.q | 32 +++ .../partitioned_view_add_parts_complex.q.out | 19 ++ .../llap/partitioned_view_add_parts.q.out | 193 ++++++++++++++++++ 6 files changed, 275 insertions(+), 3 deletions(-) create mode 100644 ql/src/test/queries/clientnegative/partitioned_view_add_parts_complex.q create mode 100644 ql/src/test/queries/clientpositive/partitioned_view_add_parts.q create mode 100644 ql/src/test/results/clientnegative/partitioned_view_add_parts_complex.q.out create mode 100644 ql/src/test/results/clientpositive/llap/partitioned_view_add_parts.q.out diff --git a/ql/src/java/org/apache/hadoop/hive/ql/ddl/table/partition/add/AlterViewAddPartitionAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/ddl/table/partition/add/AlterViewAddPartitionAnalyzer.java index a412fa5e45f2..83650194a945 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/ddl/table/partition/add/AlterViewAddPartitionAnalyzer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/ddl/table/partition/add/AlterViewAddPartitionAnalyzer.java @@ -21,6 +21,7 @@ import java.util.Map; import org.apache.hadoop.hive.common.TableName; +import org.apache.hadoop.hive.metastore.api.FieldSchema; import org.apache.hadoop.hive.ql.Driver; import org.apache.hadoop.hive.ql.ErrorMsg; import org.apache.hadoop.hive.ql.QueryState; @@ -31,6 +32,13 @@ import org.apache.hadoop.hive.ql.metadata.Table; import org.apache.hadoop.hive.ql.parse.HiveParser; import org.apache.hadoop.hive.ql.parse.SemanticException; +import org.apache.hadoop.hive.ql.plan.ExprNodeConstantDesc; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspector; +import org.apache.hadoop.hive.serde2.objectinspector.ObjectInspectorConverters; +import org.apache.hadoop.hive.serde2.objectinspector.primitive.PrimitiveObjectInspectorFactory; +import org.apache.hadoop.hive.serde2.typeinfo.TypeInfo; +import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory; +import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoUtils; /** * Analyzer for add partition commands for views. @@ -79,10 +87,10 @@ protected void postProcess(TableName tableName, Table table, AlterTableAddPartit } else { where.append(" AND "); } + FieldSchema partCol = table.getColumnByName(entry.getKey()); where.append(HiveUtils.unparseIdentifier(entry.getKey(), conf)); - where.append(" = '"); - where.append(HiveUtils.escapeString(entry.getValue())); - where.append("'"); + where.append(" = "); + where.append(formatPartitionLiteral(partCol, entry.getValue())); } where.append(")"); } @@ -97,4 +105,12 @@ protected void postProcess(TableName tableName, Table table, AlterTableAddPartit inputs.addAll(driver.getPlan().getInputs()); } } + + private static String formatPartitionLiteral(FieldSchema partCol, String partSpecValue) { + TypeInfo typeInfo = TypeInfoFactory.getPrimitiveTypeInfo(partCol.getType()); + ObjectInspector partColOI = TypeInfoUtils.getStandardJavaObjectInspectorFromTypeInfo(typeInfo); + Object converted = ObjectInspectorConverters.getConverter( + PrimitiveObjectInspectorFactory.javaStringObjectInspector, partColOI).convert(partSpecValue); + return new ExprNodeConstantDesc(typeInfo, converted).getExprString(); + } } diff --git a/ql/src/java/org/apache/hadoop/hive/ql/ddl/view/create/CreateViewAnalyzer.java b/ql/src/java/org/apache/hadoop/hive/ql/ddl/view/create/CreateViewAnalyzer.java index 38d4081f5208..5ddc1ae8285f 100644 --- a/ql/src/java/org/apache/hadoop/hive/ql/ddl/view/create/CreateViewAnalyzer.java +++ b/ql/src/java/org/apache/hadoop/hive/ql/ddl/view/create/CreateViewAnalyzer.java @@ -45,6 +45,7 @@ import org.apache.hadoop.hive.ql.parse.SemanticAnalyzer; import org.apache.hadoop.hive.ql.parse.SemanticException; import org.apache.hadoop.hive.ql.parse.StorageFormat; +import org.apache.hadoop.hive.serde2.typeinfo.TypeInfoFactory; /** * Analyzer for create view commands. @@ -189,6 +190,12 @@ private List getPartitionColumns(List partitionColumnNames) while (columnNameIterator.hasNext()) { String columnName = columnNameIterator.next(); FieldSchema fieldSchema = schemaIterator.next(); + try { + TypeInfoFactory.getPrimitiveTypeInfo(fieldSchema.getType()); + } catch (Exception e) { + throw new SemanticException(ErrorMsg.PARTITION_COLUMN_NON_PRIMITIVE.getMsg() + " Found " + + columnName + " of type: " + fieldSchema.getType()); + } if (!fieldSchema.getName().equals(columnName)) { throw new SemanticException(ErrorMsg.VIEW_PARTITION_MISMATCH.getMsg()); } diff --git a/ql/src/test/queries/clientnegative/partitioned_view_add_parts_complex.q b/ql/src/test/queries/clientnegative/partitioned_view_add_parts_complex.q new file mode 100644 index 000000000000..034aa7e81b1d --- /dev/null +++ b/ql/src/test/queries/clientnegative/partitioned_view_add_parts_complex.q @@ -0,0 +1,5 @@ +-- Negative: non-primitive partition column on CREATE VIEW (PARTITION_COLUMN_NON_PRIMITIVE) +create table pv_complex_src (id int, p struct) stored as orc; +insert into pv_complex_src values (1, named_struct('f', 'x')); + +create view pv_complex partitioned on (p) as select id, p from pv_complex_src; diff --git a/ql/src/test/queries/clientpositive/partitioned_view_add_parts.q b/ql/src/test/queries/clientpositive/partitioned_view_add_parts.q new file mode 100644 index 000000000000..db317f307de3 --- /dev/null +++ b/ql/src/test/queries/clientpositive/partitioned_view_add_parts.q @@ -0,0 +1,32 @@ +create table src_t ( + label string, + p_int int, + p_bool boolean, + p_date date, + p_dec decimal(10,2) +) stored as orc; + +insert into src_t values + ('row1', 42, true, '2024-06-01', 99.50); + +create view vp_int partitioned on (p_int) as select label, p_int from src_t; +alter view vp_int add partition (p_int=42); +show partitions vp_int; + +create view vp_bool partitioned on (p_bool) as select label, p_bool from src_t; +alter view vp_bool add partition (p_bool=true); +show partitions vp_bool; + +create view vp_date partitioned on (p_date) as select label, p_date from src_t; +alter view vp_date add partition (p_date='2024-06-01'); +show partitions vp_date; + +create view vp_dec partitioned on (p_dec) as select label, p_dec from src_t; +alter view vp_dec add partition (p_dec=99.50); +show partitions vp_dec; + +drop view vp_int; +drop view vp_bool; +drop view vp_date; +drop view vp_dec; +drop table src_t; diff --git a/ql/src/test/results/clientnegative/partitioned_view_add_parts_complex.q.out b/ql/src/test/results/clientnegative/partitioned_view_add_parts_complex.q.out new file mode 100644 index 000000000000..0e9fa008275c --- /dev/null +++ b/ql/src/test/results/clientnegative/partitioned_view_add_parts_complex.q.out @@ -0,0 +1,19 @@ +PREHOOK: query: create table pv_complex_src (id int, p struct) stored as orc +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@pv_complex_src +POSTHOOK: query: create table pv_complex_src (id int, p struct) stored as orc +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@pv_complex_src +PREHOOK: query: insert into pv_complex_src values (1, named_struct('f', 'x')) +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +PREHOOK: Output: default@pv_complex_src +POSTHOOK: query: insert into pv_complex_src values (1, named_struct('f', 'x')) +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +POSTHOOK: Output: default@pv_complex_src +POSTHOOK: Lineage: pv_complex_src.id SCRIPT [] +POSTHOOK: Lineage: pv_complex_src.p SCRIPT [] +FAILED: SemanticException [Error 10126]: Partition column must be of primitive type. Found p of type: struct diff --git a/ql/src/test/results/clientpositive/llap/partitioned_view_add_parts.q.out b/ql/src/test/results/clientpositive/llap/partitioned_view_add_parts.q.out new file mode 100644 index 000000000000..035ca5781a75 --- /dev/null +++ b/ql/src/test/results/clientpositive/llap/partitioned_view_add_parts.q.out @@ -0,0 +1,193 @@ +PREHOOK: query: create table src_t ( + label string, + p_int int, + p_bool boolean, + p_date date, + p_dec decimal(10,2) +) stored as orc +PREHOOK: type: CREATETABLE +PREHOOK: Output: database:default +PREHOOK: Output: default@src_t +POSTHOOK: query: create table src_t ( + label string, + p_int int, + p_bool boolean, + p_date date, + p_dec decimal(10,2) +) stored as orc +POSTHOOK: type: CREATETABLE +POSTHOOK: Output: database:default +POSTHOOK: Output: default@src_t +PREHOOK: query: insert into src_t values + ('row1', 42, true, '2024-06-01', 99.50) +PREHOOK: type: QUERY +PREHOOK: Input: _dummy_database@_dummy_table +PREHOOK: Output: default@src_t +POSTHOOK: query: insert into src_t values + ('row1', 42, true, '2024-06-01', 99.50) +POSTHOOK: type: QUERY +POSTHOOK: Input: _dummy_database@_dummy_table +POSTHOOK: Output: default@src_t +POSTHOOK: Lineage: src_t.label SCRIPT [] +POSTHOOK: Lineage: src_t.p_bool SCRIPT [] +POSTHOOK: Lineage: src_t.p_date SCRIPT [] +POSTHOOK: Lineage: src_t.p_dec SCRIPT [] +POSTHOOK: Lineage: src_t.p_int SCRIPT [] +PREHOOK: query: create view vp_int partitioned on (p_int) as select label, p_int from src_t +PREHOOK: type: CREATEVIEW +PREHOOK: Input: default@src_t +PREHOOK: Output: database:default +PREHOOK: Output: default@vp_int +POSTHOOK: query: create view vp_int partitioned on (p_int) as select label, p_int from src_t +POSTHOOK: type: CREATEVIEW +POSTHOOK: Input: default@src_t +POSTHOOK: Output: database:default +POSTHOOK: Output: default@vp_int +POSTHOOK: Lineage: vp_int.label SIMPLE [(src_t)src_t.FieldSchema(name:label, type:string, comment:null), ] +PREHOOK: query: alter view vp_int add partition (p_int=42) +PREHOOK: type: ALTERTABLE_ADDPARTS +PREHOOK: Input: default@src_t +PREHOOK: Input: default@vp_int +PREHOOK: Output: default@vp_int +POSTHOOK: query: alter view vp_int add partition (p_int=42) +POSTHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: Input: default@src_t +POSTHOOK: Input: default@vp_int +POSTHOOK: Output: default@vp_int +POSTHOOK: Output: default@vp_int@p_int=42 +PREHOOK: query: show partitions vp_int +PREHOOK: type: SHOWPARTITIONS +PREHOOK: Input: default@vp_int +POSTHOOK: query: show partitions vp_int +POSTHOOK: type: SHOWPARTITIONS +POSTHOOK: Input: default@vp_int +p_int=42 +PREHOOK: query: create view vp_bool partitioned on (p_bool) as select label, p_bool from src_t +PREHOOK: type: CREATEVIEW +PREHOOK: Input: default@src_t +PREHOOK: Output: database:default +PREHOOK: Output: default@vp_bool +POSTHOOK: query: create view vp_bool partitioned on (p_bool) as select label, p_bool from src_t +POSTHOOK: type: CREATEVIEW +POSTHOOK: Input: default@src_t +POSTHOOK: Output: database:default +POSTHOOK: Output: default@vp_bool +POSTHOOK: Lineage: vp_bool.label SIMPLE [(src_t)src_t.FieldSchema(name:label, type:string, comment:null), ] +PREHOOK: query: alter view vp_bool add partition (p_bool=true) +PREHOOK: type: ALTERTABLE_ADDPARTS +PREHOOK: Input: default@src_t +PREHOOK: Input: default@vp_bool +PREHOOK: Output: default@vp_bool +POSTHOOK: query: alter view vp_bool add partition (p_bool=true) +POSTHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: Input: default@src_t +POSTHOOK: Input: default@vp_bool +POSTHOOK: Output: default@vp_bool +POSTHOOK: Output: default@vp_bool@p_bool=true +PREHOOK: query: show partitions vp_bool +PREHOOK: type: SHOWPARTITIONS +PREHOOK: Input: default@vp_bool +POSTHOOK: query: show partitions vp_bool +POSTHOOK: type: SHOWPARTITIONS +POSTHOOK: Input: default@vp_bool +p_bool=true +PREHOOK: query: create view vp_date partitioned on (p_date) as select label, p_date from src_t +PREHOOK: type: CREATEVIEW +PREHOOK: Input: default@src_t +PREHOOK: Output: database:default +PREHOOK: Output: default@vp_date +POSTHOOK: query: create view vp_date partitioned on (p_date) as select label, p_date from src_t +POSTHOOK: type: CREATEVIEW +POSTHOOK: Input: default@src_t +POSTHOOK: Output: database:default +POSTHOOK: Output: default@vp_date +POSTHOOK: Lineage: vp_date.label SIMPLE [(src_t)src_t.FieldSchema(name:label, type:string, comment:null), ] +PREHOOK: query: alter view vp_date add partition (p_date='2024-06-01') +PREHOOK: type: ALTERTABLE_ADDPARTS +PREHOOK: Input: default@src_t +PREHOOK: Input: default@vp_date +PREHOOK: Output: default@vp_date +POSTHOOK: query: alter view vp_date add partition (p_date='2024-06-01') +POSTHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: Input: default@src_t +POSTHOOK: Input: default@vp_date +POSTHOOK: Output: default@vp_date +POSTHOOK: Output: default@vp_date@p_date=2024-06-01 +PREHOOK: query: show partitions vp_date +PREHOOK: type: SHOWPARTITIONS +PREHOOK: Input: default@vp_date +POSTHOOK: query: show partitions vp_date +POSTHOOK: type: SHOWPARTITIONS +POSTHOOK: Input: default@vp_date +p_date=2024-06-01 +PREHOOK: query: create view vp_dec partitioned on (p_dec) as select label, p_dec from src_t +PREHOOK: type: CREATEVIEW +PREHOOK: Input: default@src_t +PREHOOK: Output: database:default +PREHOOK: Output: default@vp_dec +POSTHOOK: query: create view vp_dec partitioned on (p_dec) as select label, p_dec from src_t +POSTHOOK: type: CREATEVIEW +POSTHOOK: Input: default@src_t +POSTHOOK: Output: database:default +POSTHOOK: Output: default@vp_dec +POSTHOOK: Lineage: vp_dec.label SIMPLE [(src_t)src_t.FieldSchema(name:label, type:string, comment:null), ] +PREHOOK: query: alter view vp_dec add partition (p_dec=99.50) +PREHOOK: type: ALTERTABLE_ADDPARTS +PREHOOK: Input: default@src_t +PREHOOK: Input: default@vp_dec +PREHOOK: Output: default@vp_dec +POSTHOOK: query: alter view vp_dec add partition (p_dec=99.50) +POSTHOOK: type: ALTERTABLE_ADDPARTS +POSTHOOK: Input: default@src_t +POSTHOOK: Input: default@vp_dec +POSTHOOK: Output: default@vp_dec +POSTHOOK: Output: default@vp_dec@p_dec=99.5 +PREHOOK: query: show partitions vp_dec +PREHOOK: type: SHOWPARTITIONS +PREHOOK: Input: default@vp_dec +POSTHOOK: query: show partitions vp_dec +POSTHOOK: type: SHOWPARTITIONS +POSTHOOK: Input: default@vp_dec +p_dec=99.5 +PREHOOK: query: drop view vp_int +PREHOOK: type: DROPVIEW +PREHOOK: Input: default@vp_int +PREHOOK: Output: default@vp_int +POSTHOOK: query: drop view vp_int +POSTHOOK: type: DROPVIEW +POSTHOOK: Input: default@vp_int +POSTHOOK: Output: default@vp_int +PREHOOK: query: drop view vp_bool +PREHOOK: type: DROPVIEW +PREHOOK: Input: default@vp_bool +PREHOOK: Output: default@vp_bool +POSTHOOK: query: drop view vp_bool +POSTHOOK: type: DROPVIEW +POSTHOOK: Input: default@vp_bool +POSTHOOK: Output: default@vp_bool +PREHOOK: query: drop view vp_date +PREHOOK: type: DROPVIEW +PREHOOK: Input: default@vp_date +PREHOOK: Output: default@vp_date +POSTHOOK: query: drop view vp_date +POSTHOOK: type: DROPVIEW +POSTHOOK: Input: default@vp_date +POSTHOOK: Output: default@vp_date +PREHOOK: query: drop view vp_dec +PREHOOK: type: DROPVIEW +PREHOOK: Input: default@vp_dec +PREHOOK: Output: default@vp_dec +POSTHOOK: query: drop view vp_dec +POSTHOOK: type: DROPVIEW +POSTHOOK: Input: default@vp_dec +POSTHOOK: Output: default@vp_dec +PREHOOK: query: drop table src_t +PREHOOK: type: DROPTABLE +PREHOOK: Input: default@src_t +PREHOOK: Output: database:default +PREHOOK: Output: default@src_t +POSTHOOK: query: drop table src_t +POSTHOOK: type: DROPTABLE +POSTHOOK: Input: default@src_t +POSTHOOK: Output: database:default +POSTHOOK: Output: default@src_t