This is an automated email from the ASF dual-hosted git repository.

kasakrisz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new eccaafe60b3 HIVE-29819: Fix Iceberg COW UPDATE for null identity 
partition column filters (#6763)
eccaafe60b3 is described below

commit eccaafe60b38c457e0af889c2256545c320b4839
Author: kokila-19 <[email protected]>
AuthorDate: Mon Sep 14 13:45:33 2026 +0530

    HIVE-29819: Fix Iceberg COW UPDATE for null identity partition column 
filters (#6763)
    
    Column pruning dropped partition columns from the TableScan while filters 
above
    the scan still referenced them. Keep filter-referenced partition columns in 
the
    Iceberg scan projection.
---
 .../update_iceberg_cow_null_identity_partition.q   |  35 ++
 .../results/positive/iceberg_colstats_folded.q.out |   6 +-
 .../positive/iceberg_colstats_granularity.q.out    |   8 +-
 .../positive/iceberg_insert_into_partition.q.out   |   4 +-
 .../iceberg_insert_overwrite_partition.q.out       |   4 +-
 .../iceberg_partition_pruner_cache_key.q.out       |   4 +-
 .../positive/iceberg_pcr_null_partition.q.out      |   2 +-
 ...pdate_iceberg_cow_null_identity_partition.q.out | 518 +++++++++++++++++++++
 .../hive/ql/optimizer/ColumnPrunerProcFactory.java |  72 +++
 9 files changed, 639 insertions(+), 14 deletions(-)

diff --git 
a/iceberg/iceberg-handler/src/test/queries/positive/update_iceberg_cow_null_identity_partition.q
 
b/iceberg/iceberg-handler/src/test/queries/positive/update_iceberg_cow_null_identity_partition.q
new file mode 100644
index 00000000000..e88b8915fd6
--- /dev/null
+++ 
b/iceberg/iceberg-handler/src/test/queries/positive/update_iceberg_cow_null_identity_partition.q
@@ -0,0 +1,35 @@
+-- SORT_QUERY_RESULTS
+
+set hive.explain.user=false;
+
+drop table if exists iceberg_cow_partitioned;
+
+create external table iceberg_cow_partitioned (
+  index int,
+  string_col string,
+  boolean_col boolean,
+  str_col string,
+  tinyint_col int
+) partitioned by spec(str_col, tinyint_col)
+stored by iceberg
+tblproperties ('write.update.mode'='copy-on-write');
+
+insert into iceberg_cow_partitioned partition (str_col, tinyint_col)
+  values (1, 'a', true, null, 1);
+
+explain update iceberg_cow_partitioned set str_col = 'UPDATED NULLS' where 
str_col is null;
+update iceberg_cow_partitioned set str_col = 'UPDATED NULLS' where str_col is 
null;
+
+select * from iceberg_cow_partitioned;
+
+-- Disable vectorization
+
+set hive.vectorized.execution.enabled=false;
+
+insert into iceberg_cow_partitioned partition (str_col, tinyint_col)
+  values (2, 'b', false, null, 2);
+
+explain update iceberg_cow_partitioned set str_col = 'UPDATED NULLS' where 
str_col is null;
+update iceberg_cow_partitioned set str_col = 'UPDATED NULLS' where str_col is 
null;
+
+select * from iceberg_cow_partitioned;
diff --git 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_colstats_folded.q.out
 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_colstats_folded.q.out
index f046c4e5874..2dc19a43757 100644
--- 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_colstats_folded.q.out
+++ 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_colstats_folded.q.out
@@ -141,12 +141,12 @@ STAGE PLANS:
                 TableScan
                   alias: ice_folded
                   filterExpr: ((id > 4) and (p = 'a')) (type: boolean)
-                  Statistics: Num rows: 2 Data size: 8 Basic stats: COMPLETE 
Column stats: COMPLETE
+                  Statistics: Num rows: 2 Data size: 376 Basic stats: COMPLETE 
Column stats: COMPLETE
                   Filter Operator
                     predicate: (id > 4) (type: boolean)
-                    Statistics: Num rows: 1 Data size: 4 Basic stats: COMPLETE 
Column stats: COMPLETE
+                    Statistics: Num rows: 1 Data size: 188 Basic stats: 
COMPLETE Column stats: COMPLETE
                     Select Operator
-                      Statistics: Num rows: 1 Data size: 4 Basic stats: 
COMPLETE Column stats: COMPLETE
+                      Statistics: Num rows: 1 Data size: 188 Basic stats: 
COMPLETE Column stats: COMPLETE
                       Group By Operator
                         aggregations: count()
                         minReductionHashAggr: 0.4
diff --git 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_colstats_granularity.q.out
 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_colstats_granularity.q.out
index f8711b175f1..9461d2cfbf2 100644
--- 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_colstats_granularity.q.out
+++ 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_colstats_granularity.q.out
@@ -71,7 +71,7 @@ STAGE PLANS:
                 TableScan
                   alias: ice_p
                   filterExpr: (p = 'a') (type: boolean)
-                  Statistics: Num rows: 2 Data size: 8 Basic stats: COMPLETE 
Column stats: COMPLETE
+                  Statistics: Num rows: 2 Data size: 376 Basic stats: COMPLETE 
Column stats: COMPLETE
                   Select Operator
                     expressions: id (type: int), 'a' (type: string)
                     outputColumnNames: _col0, _col1
@@ -156,7 +156,7 @@ STAGE PLANS:
                 TableScan
                   alias: ice_p
                   filterExpr: (p = 'a') (type: boolean)
-                  Statistics: Num rows: 2 Data size: 8 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Statistics: Num rows: 2 Data size: 376 Basic stats: COMPLETE 
Column stats: PARTIAL
                   Select Operator
                     expressions: id (type: int), 'a' (type: string)
                     outputColumnNames: _col0, _col1
@@ -198,7 +198,7 @@ STAGE PLANS:
                 TableScan
                   alias: ice_p
                   filterExpr: (p = 'a') (type: boolean)
-                  Statistics: Num rows: 2 Data size: 8 Basic stats: COMPLETE 
Column stats: COMPLETE
+                  Statistics: Num rows: 2 Data size: 376 Basic stats: COMPLETE 
Column stats: COMPLETE
                   Select Operator
                     expressions: id (type: int), 'a' (type: string)
                     outputColumnNames: _col0, _col1
@@ -275,7 +275,7 @@ STAGE PLANS:
                 TableScan
                   alias: ice_p
                   filterExpr: (p = 'a') (type: boolean)
-                  Statistics: Num rows: 2 Data size: 8 Basic stats: COMPLETE 
Column stats: COMPLETE
+                  Statistics: Num rows: 2 Data size: 376 Basic stats: COMPLETE 
Column stats: COMPLETE
                   Select Operator
                     expressions: id (type: int), 'a' (type: string)
                     outputColumnNames: _col0, _col1
diff --git 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_insert_into_partition.q.out
 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_insert_into_partition.q.out
index ec615722ee6..64b1f98bcc8 100644
--- 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_insert_into_partition.q.out
+++ 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_insert_into_partition.q.out
@@ -267,7 +267,7 @@ STAGE PLANS:
                 TableScan
                   alias: ice_parquet_int
                   filterExpr: (pcol = 2) (type: boolean)
-                  Statistics: Num rows: 2 Data size: 182 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Statistics: Num rows: 2 Data size: 190 Basic stats: COMPLETE 
Column stats: PARTIAL
                   Select Operator
                     expressions: strcol (type: string), intcol (type: int), 3 
(type: int)
                     outputColumnNames: _col0, _col1, _col2
@@ -374,7 +374,7 @@ STAGE PLANS:
                 TableScan
                   alias: ice_parquet_int
                   filterExpr: (pcol = 2) (type: boolean)
-                  Statistics: Num rows: 2 Data size: 182 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Statistics: Num rows: 2 Data size: 190 Basic stats: COMPLETE 
Column stats: PARTIAL
                   Select Operator
                     expressions: strcol (type: string), intcol (type: int), 4 
(type: int)
                     outputColumnNames: _col0, _col1, _col2
diff --git 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_insert_overwrite_partition.q.out
 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_insert_overwrite_partition.q.out
index cb6f6d671c9..e40017d1fe5 100644
--- 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_insert_overwrite_partition.q.out
+++ 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_insert_overwrite_partition.q.out
@@ -57,7 +57,7 @@ STAGE PLANS:
                 TableScan
                   alias: ice_parquet_int
                   filterExpr: (pcol = 2) (type: boolean)
-                  Statistics: Num rows: 2 Data size: 182 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Statistics: Num rows: 2 Data size: 190 Basic stats: COMPLETE 
Column stats: PARTIAL
                   Select Operator
                     expressions: strcol (type: string), intcol (type: int), 1 
(type: int)
                     outputColumnNames: _col0, _col1, _col2
@@ -164,7 +164,7 @@ STAGE PLANS:
                 TableScan
                   alias: ice_parquet_int
                   filterExpr: (pcol = 2) (type: boolean)
-                  Statistics: Num rows: 2 Data size: 376 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Statistics: Num rows: 2 Data size: 384 Basic stats: COMPLETE 
Column stats: PARTIAL
                   Select Operator
                     expressions: strcol (type: string), intcol (type: int), 1 
(type: int)
                     outputColumnNames: _col0, _col1, _col2
diff --git 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_partition_pruner_cache_key.q.out
 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_partition_pruner_cache_key.q.out
index fb78a8a72b8..25fb1c3fb4c 100644
--- 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_partition_pruner_cache_key.q.out
+++ 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_partition_pruner_cache_key.q.out
@@ -272,9 +272,9 @@ STAGE PLANS:
                 TableScan
                   alias: tbl_ice_pp_key
                   filterExpr: (a > 2) (type: boolean)
-                  Statistics: Num rows: 8 Data size: 51110 Basic stats: 
COMPLETE Column stats: PARTIAL
+                  Statistics: Num rows: 8 Data size: 32 Basic stats: COMPLETE 
Column stats: PARTIAL
                   Select Operator
-                    Statistics: Num rows: 8 Data size: 51110 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    Statistics: Num rows: 8 Data size: 32 Basic stats: 
COMPLETE Column stats: PARTIAL
                     Group By Operator
                       aggregations: count()
                       minReductionHashAggr: 0.99
diff --git 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_pcr_null_partition.q.out
 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_pcr_null_partition.q.out
index 262bae9056e..05fb89172b9 100644
--- 
a/iceberg/iceberg-handler/src/test/results/positive/iceberg_pcr_null_partition.q.out
+++ 
b/iceberg/iceberg-handler/src/test/results/positive/iceberg_pcr_null_partition.q.out
@@ -58,7 +58,7 @@ STAGE PLANS:
                 TableScan
                   alias: ice_01
                   filterExpr: ds is null (type: boolean)
-                  Statistics: Num rows: 1 Data size: 171 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Statistics: Num rows: 1 Data size: 355 Basic stats: COMPLETE 
Column stats: PARTIAL
                   Select Operator
                     expressions: key (type: string), value (type: string), 
null (type: string)
                     outputColumnNames: _col0, _col1, _col2
diff --git 
a/iceberg/iceberg-handler/src/test/results/positive/update_iceberg_cow_null_identity_partition.q.out
 
b/iceberg/iceberg-handler/src/test/results/positive/update_iceberg_cow_null_identity_partition.q.out
new file mode 100644
index 00000000000..0a4da3ba403
--- /dev/null
+++ 
b/iceberg/iceberg-handler/src/test/results/positive/update_iceberg_cow_null_identity_partition.q.out
@@ -0,0 +1,518 @@
+PREHOOK: query: drop table if exists iceberg_cow_partitioned
+PREHOOK: type: DROPTABLE
+PREHOOK: Output: database:default
+POSTHOOK: query: drop table if exists iceberg_cow_partitioned
+POSTHOOK: type: DROPTABLE
+POSTHOOK: Output: database:default
+PREHOOK: query: create external table iceberg_cow_partitioned (
+  index int,
+  string_col string,
+  boolean_col boolean,
+  str_col string,
+  tinyint_col int
+) partitioned by spec(str_col, tinyint_col)
+stored by iceberg
+tblproperties ('write.update.mode'='copy-on-write')
+PREHOOK: type: CREATETABLE
+PREHOOK: Output: database:default
+PREHOOK: Output: default@iceberg_cow_partitioned
+POSTHOOK: query: create external table iceberg_cow_partitioned (
+  index int,
+  string_col string,
+  boolean_col boolean,
+  str_col string,
+  tinyint_col int
+) partitioned by spec(str_col, tinyint_col)
+stored by iceberg
+tblproperties ('write.update.mode'='copy-on-write')
+POSTHOOK: type: CREATETABLE
+POSTHOOK: Output: database:default
+POSTHOOK: Output: default@iceberg_cow_partitioned
+PREHOOK: query: insert into iceberg_cow_partitioned partition (str_col, 
tinyint_col)
+  values (1, 'a', true, null, 1)
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@iceberg_cow_partitioned
+POSTHOOK: query: insert into iceberg_cow_partitioned partition (str_col, 
tinyint_col)
+  values (1, 'a', true, null, 1)
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@iceberg_cow_partitioned
+PREHOOK: query: explain update iceberg_cow_partitioned set str_col = 'UPDATED 
NULLS' where str_col is null
+PREHOOK: type: QUERY
+PREHOOK: Input: default@iceberg_cow_partitioned
+PREHOOK: Output: default@iceberg_cow_partitioned
+POSTHOOK: query: explain update iceberg_cow_partitioned set str_col = 'UPDATED 
NULLS' where str_col is null
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@iceberg_cow_partitioned
+POSTHOOK: Output: default@iceberg_cow_partitioned
+STAGE DEPENDENCIES:
+  Stage-1 is a root stage
+  Stage-2 depends on stages: Stage-1
+  Stage-0 depends on stages: Stage-2
+  Stage-3 depends on stages: Stage-0
+
+STAGE PLANS:
+  Stage: Stage-1
+    Tez
+#### A masked pattern was here ####
+      Edges:
+        Map 1 <- Union 2 (CONTAINS)
+        Reducer 4 <- Map 3 (SIMPLE_EDGE), Reducer 7 (SIMPLE_EDGE), Union 2 
(CONTAINS)
+        Reducer 6 <- Map 5 (SIMPLE_EDGE), Union 2 (CONTAINS)
+        Reducer 7 <- Map 5 (SIMPLE_EDGE)
+#### A masked pattern was here ####
+      Vertices:
+        Map 1 
+            Map Operator Tree:
+                TableScan
+                  alias: iceberg_cow_partitioned
+                  filterExpr: str_col is null (type: boolean)
+                  Statistics: Num rows: 1 Data size: 281 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Select Operator
+                    expressions: PARTITION__SPEC__ID (type: int), 
PARTITION__HASH (type: bigint), FILE__PATH (type: string), ROW__POSITION (type: 
bigint), index (type: int), string_col (type: string), boolean_col (type: 
boolean), 'UPDATED NULLS' (type: string), tinyint_col (type: int)
+                    outputColumnNames: _col0, _col1, _col2, _col3, _col4, 
_col5, _col6, _col7, _col8
+                    Statistics: Num rows: 1 Data size: 398 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    File Output Operator
+                      compressed: false
+                      Statistics: Num rows: 3 Data size: 1259 Basic stats: 
COMPLETE Column stats: PARTIAL
+                      table:
+                          input format: 
org.apache.iceberg.mr.hive.HiveIcebergInputFormat
+                          output format: 
org.apache.iceberg.mr.hive.HiveIcebergOutputFormat
+                          serde: org.apache.iceberg.mr.hive.HiveIcebergSerDe
+                          name: default.iceberg_cow_partitioned
+            Execution mode: vectorized
+        Map 3 
+            Map Operator Tree:
+                TableScan
+                  alias: iceberg_cow_partitioned
+                  filterExpr: str_col is not null (type: boolean)
+                  Statistics: Num rows: 1 Data size: 272 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Filter Operator
+                    predicate: (FILE__PATH is not null and str_col is not 
null) (type: boolean)
+                    Statistics: Num rows: 1 Data size: 272 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    Select Operator
+                      expressions: index (type: int), string_col (type: 
string), boolean_col (type: boolean), str_col (type: string), tinyint_col 
(type: int), PARTITION__SPEC__ID (type: int), PARTITION__HASH (type: bigint), 
FILE__PATH (type: string), ROW__POSITION (type: bigint)
+                      outputColumnNames: _col0, _col1, _col2, _col3, _col4, 
_col5, _col6, _col7, _col8
+                      Statistics: Num rows: 1 Data size: 476 Basic stats: 
COMPLETE Column stats: PARTIAL
+                      Reduce Output Operator
+                        key expressions: _col7 (type: string)
+                        null sort order: z
+                        sort order: +
+                        Map-reduce partition columns: _col7 (type: string)
+                        Statistics: Num rows: 1 Data size: 476 Basic stats: 
COMPLETE Column stats: PARTIAL
+                        value expressions: _col0 (type: int), _col1 (type: 
string), _col2 (type: boolean), _col3 (type: string), _col4 (type: int), _col5 
(type: int), _col6 (type: bigint), _col8 (type: bigint)
+            Execution mode: vectorized
+        Map 5 
+            Map Operator Tree:
+                TableScan
+                  alias: iceberg_cow_partitioned
+                  filterExpr: str_col is null (type: boolean)
+                  Statistics: Num rows: 1 Data size: 281 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Filter Operator
+                    predicate: str_col is null (type: boolean)
+                    Reduce Output Operator
+                      key expressions: FILE__PATH (type: string)
+                      null sort order: a
+                      sort order: +
+                      Map-reduce partition columns: FILE__PATH (type: string)
+                      Statistics: Num rows: 1 Data size: 281 Basic stats: 
COMPLETE Column stats: PARTIAL
+                      value expressions: index (type: int), string_col (type: 
string), boolean_col (type: boolean), tinyint_col (type: int), 
PARTITION__SPEC__ID (type: int), PARTITION__HASH (type: bigint)
+                  Filter Operator
+                    predicate: (FILE__PATH is not null and str_col is null) 
(type: boolean)
+                    Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    Reduce Output Operator
+                      key expressions: FILE__PATH (type: string)
+                      null sort order: a
+                      sort order: +
+                      Map-reduce partition columns: FILE__PATH (type: string)
+                      Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+            Execution mode: vectorized
+        Reducer 4 
+            Reduce Operator Tree:
+              Merge Join Operator
+                condition map:
+                     Left Semi Join 0 to 1
+                keys:
+                  0 _col7 (type: string)
+                  1 _col0 (type: string)
+                outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, 
_col6, _col7, _col8
+                Statistics: Num rows: 1 Data size: 476 Basic stats: COMPLETE 
Column stats: PARTIAL
+                Select Operator
+                  expressions: _col5 (type: int), _col6 (type: bigint), _col7 
(type: string), _col8 (type: bigint), _col0 (type: int), _col1 (type: string), 
_col2 (type: boolean), _col3 (type: string), _col4 (type: int)
+                  outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, 
_col6, _col7, _col8
+                  Statistics: Num rows: 1 Data size: 476 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  File Output Operator
+                    compressed: false
+                    Statistics: Num rows: 3 Data size: 1259 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    table:
+                        input format: 
org.apache.iceberg.mr.hive.HiveIcebergInputFormat
+                        output format: 
org.apache.iceberg.mr.hive.HiveIcebergOutputFormat
+                        serde: org.apache.iceberg.mr.hive.HiveIcebergSerDe
+                        name: default.iceberg_cow_partitioned
+        Reducer 6 
+            Execution mode: vectorized
+            Reduce Operator Tree:
+              Select Operator
+                expressions: VALUE._col0 (type: int), VALUE._col1 (type: 
string), VALUE._col2 (type: boolean), VALUE._col4 (type: int), VALUE._col5 
(type: int), VALUE._col6 (type: bigint), KEY.reducesinkkey0 (type: string)
+                outputColumnNames: _col0, _col1, _col2, _col4, _col5, _col6, 
_col7
+                Statistics: Num rows: 1 Data size: 293 Basic stats: COMPLETE 
Column stats: PARTIAL
+                PTF Operator
+                  Function definitions:
+                      Input definition
+                        input alias: ptf_0
+                        type: WINDOWING
+                      Windowing table definition
+                        input alias: ptf_1
+                        name: windowingtablefunction
+                        order by: _col7 ASC NULLS FIRST
+                        partition by: _col7
+                        raw input shape:
+                        window functions:
+                            window function definition
+                              alias: row_number_window_0
+                              name: row_number
+                              window function: GenericUDAFRowNumberEvaluator
+                              window frame: ROWS PRECEDING(MAX)~FOLLOWING(MAX)
+                              isPivotResult: true
+                  Statistics: Num rows: 1 Data size: 293 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Filter Operator
+                    predicate: (row_number_window_0 = 1) (type: boolean)
+                    Statistics: Num rows: 1 Data size: 293 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    Select Operator
+                      expressions: _col5 (type: int), _col6 (type: bigint), 
_col7 (type: string), -1L (type: bigint), _col0 (type: int), _col1 (type: 
string), _col2 (type: boolean), null (type: string), _col4 (type: int)
+                      outputColumnNames: _col0, _col1, _col2, _col3, _col4, 
_col5, _col6, _col7, _col8
+                      Statistics: Num rows: 1 Data size: 385 Basic stats: 
COMPLETE Column stats: PARTIAL
+                      File Output Operator
+                        compressed: false
+                        Statistics: Num rows: 3 Data size: 1259 Basic stats: 
COMPLETE Column stats: PARTIAL
+                        table:
+                            input format: 
org.apache.iceberg.mr.hive.HiveIcebergInputFormat
+                            output format: 
org.apache.iceberg.mr.hive.HiveIcebergOutputFormat
+                            serde: org.apache.iceberg.mr.hive.HiveIcebergSerDe
+                            name: default.iceberg_cow_partitioned
+        Reducer 7 
+            Execution mode: vectorized
+            Reduce Operator Tree:
+              Select Operator
+                expressions: KEY.reducesinkkey0 (type: string)
+                outputColumnNames: _col7
+                Statistics: Num rows: 1 Data size: 184 Basic stats: COMPLETE 
Column stats: PARTIAL
+                PTF Operator
+                  Function definitions:
+                      Input definition
+                        input alias: ptf_0
+                        output shape: _col7: string
+                        type: WINDOWING
+                      Windowing table definition
+                        input alias: ptf_1
+                        name: windowingtablefunction
+                        order by: _col7 ASC NULLS FIRST
+                        partition by: _col7
+                        raw input shape:
+                        window functions:
+                            window function definition
+                              alias: row_number_window_0
+                              name: row_number
+                              window function: GenericUDAFRowNumberEvaluator
+                              window frame: ROWS PRECEDING(MAX)~FOLLOWING(MAX)
+                              isPivotResult: true
+                  Statistics: Num rows: 1 Data size: 184 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Filter Operator
+                    predicate: (row_number_window_0 = 1) (type: boolean)
+                    Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    Select Operator
+                      expressions: _col7 (type: string)
+                      outputColumnNames: _col0
+                      Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+                      Group By Operator
+                        keys: _col0 (type: string)
+                        minReductionHashAggr: 0.99
+                        mode: hash
+                        outputColumnNames: _col0
+                        Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+                        Reduce Output Operator
+                          key expressions: _col0 (type: string)
+                          null sort order: z
+                          sort order: +
+                          Map-reduce partition columns: _col0 (type: string)
+                          Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+        Union 2 
+            Vertex: Union 2
+
+  Stage: Stage-2
+    Dependency Collection
+
+  Stage: Stage-0
+    Move Operator
+      tables:
+          replace: false
+          table:
+              input format: org.apache.iceberg.mr.hive.HiveIcebergInputFormat
+              output format: org.apache.iceberg.mr.hive.HiveIcebergOutputFormat
+              serde: org.apache.iceberg.mr.hive.HiveIcebergSerDe
+              name: default.iceberg_cow_partitioned
+
+  Stage: Stage-3
+    Stats Work
+      Basic Stats Work:
+
+PREHOOK: query: update iceberg_cow_partitioned set str_col = 'UPDATED NULLS' 
where str_col is null
+PREHOOK: type: QUERY
+PREHOOK: Input: default@iceberg_cow_partitioned
+PREHOOK: Output: default@iceberg_cow_partitioned
+POSTHOOK: query: update iceberg_cow_partitioned set str_col = 'UPDATED NULLS' 
where str_col is null
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@iceberg_cow_partitioned
+POSTHOOK: Output: default@iceberg_cow_partitioned
+PREHOOK: query: select * from iceberg_cow_partitioned
+PREHOOK: type: QUERY
+PREHOOK: Input: default@iceberg_cow_partitioned
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: select * from iceberg_cow_partitioned
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@iceberg_cow_partitioned
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1      a       true    UPDATED NULLS   1
+PREHOOK: query: insert into iceberg_cow_partitioned partition (str_col, 
tinyint_col)
+  values (2, 'b', false, null, 2)
+PREHOOK: type: QUERY
+PREHOOK: Input: _dummy_database@_dummy_table
+PREHOOK: Output: default@iceberg_cow_partitioned
+POSTHOOK: query: insert into iceberg_cow_partitioned partition (str_col, 
tinyint_col)
+  values (2, 'b', false, null, 2)
+POSTHOOK: type: QUERY
+POSTHOOK: Input: _dummy_database@_dummy_table
+POSTHOOK: Output: default@iceberg_cow_partitioned
+PREHOOK: query: explain update iceberg_cow_partitioned set str_col = 'UPDATED 
NULLS' where str_col is null
+PREHOOK: type: QUERY
+PREHOOK: Input: default@iceberg_cow_partitioned
+PREHOOK: Output: default@iceberg_cow_partitioned
+POSTHOOK: query: explain update iceberg_cow_partitioned set str_col = 'UPDATED 
NULLS' where str_col is null
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@iceberg_cow_partitioned
+POSTHOOK: Output: default@iceberg_cow_partitioned
+STAGE DEPENDENCIES:
+  Stage-1 is a root stage
+  Stage-2 depends on stages: Stage-1
+  Stage-0 depends on stages: Stage-2
+  Stage-3 depends on stages: Stage-0
+
+STAGE PLANS:
+  Stage: Stage-1
+    Tez
+#### A masked pattern was here ####
+      Edges:
+        Map 1 <- Union 2 (CONTAINS)
+        Reducer 4 <- Map 3 (SIMPLE_EDGE), Reducer 7 (SIMPLE_EDGE), Union 2 
(CONTAINS)
+        Reducer 6 <- Map 5 (SIMPLE_EDGE), Union 2 (CONTAINS)
+        Reducer 7 <- Map 5 (SIMPLE_EDGE)
+#### A masked pattern was here ####
+      Vertices:
+        Map 1 
+            Map Operator Tree:
+                TableScan
+                  alias: iceberg_cow_partitioned
+                  filterExpr: str_col is null (type: boolean)
+                  Statistics: Num rows: 1 Data size: 380 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Select Operator
+                    expressions: PARTITION__SPEC__ID (type: int), 
PARTITION__HASH (type: bigint), FILE__PATH (type: string), ROW__POSITION (type: 
bigint), index (type: int), string_col (type: string), boolean_col (type: 
boolean), 'UPDATED NULLS' (type: string), tinyint_col (type: int)
+                    outputColumnNames: _col0, _col1, _col2, _col3, _col4, 
_col5, _col6, _col7, _col8
+                    Statistics: Num rows: 1 Data size: 497 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    File Output Operator
+                      compressed: false
+                      Statistics: Num rows: 3 Data size: 1565 Basic stats: 
COMPLETE Column stats: PARTIAL
+                      table:
+                          input format: 
org.apache.iceberg.mr.hive.HiveIcebergInputFormat
+                          output format: 
org.apache.iceberg.mr.hive.HiveIcebergOutputFormat
+                          serde: org.apache.iceberg.mr.hive.HiveIcebergSerDe
+                          name: default.iceberg_cow_partitioned
+        Map 3 
+            Map Operator Tree:
+                TableScan
+                  alias: iceberg_cow_partitioned
+                  filterExpr: str_col is not null (type: boolean)
+                  Statistics: Num rows: 1 Data size: 380 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Filter Operator
+                    predicate: FILE__PATH is not null (type: boolean)
+                    Statistics: Num rows: 1 Data size: 380 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    Select Operator
+                      expressions: index (type: int), string_col (type: 
string), boolean_col (type: boolean), str_col (type: string), tinyint_col 
(type: int), PARTITION__SPEC__ID (type: int), PARTITION__HASH (type: bigint), 
FILE__PATH (type: string), ROW__POSITION (type: bigint)
+                      outputColumnNames: _col0, _col1, _col2, _col3, _col4, 
_col5, _col6, _col7, _col8
+                      Statistics: Num rows: 1 Data size: 584 Basic stats: 
COMPLETE Column stats: PARTIAL
+                      Reduce Output Operator
+                        key expressions: _col7 (type: string)
+                        null sort order: z
+                        sort order: +
+                        Map-reduce partition columns: _col7 (type: string)
+                        Statistics: Num rows: 1 Data size: 584 Basic stats: 
COMPLETE Column stats: PARTIAL
+                        value expressions: _col0 (type: int), _col1 (type: 
string), _col2 (type: boolean), _col3 (type: string), _col4 (type: int), _col5 
(type: int), _col6 (type: bigint), _col8 (type: bigint)
+        Map 5 
+            Map Operator Tree:
+                TableScan
+                  alias: iceberg_cow_partitioned
+                  filterExpr: str_col is null (type: boolean)
+                  Statistics: Num rows: 1 Data size: 380 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Filter Operator
+                    predicate: str_col is null (type: boolean)
+                    Reduce Output Operator
+                      key expressions: FILE__PATH (type: string)
+                      null sort order: a
+                      sort order: +
+                      Map-reduce partition columns: FILE__PATH (type: string)
+                      Statistics: Num rows: 1 Data size: 380 Basic stats: 
COMPLETE Column stats: PARTIAL
+                      value expressions: index (type: int), string_col (type: 
string), boolean_col (type: boolean), tinyint_col (type: int), 
PARTITION__SPEC__ID (type: int), PARTITION__HASH (type: bigint)
+                  Filter Operator
+                    predicate: (FILE__PATH is not null and str_col is null) 
(type: boolean)
+                    Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    Reduce Output Operator
+                      key expressions: FILE__PATH (type: string)
+                      null sort order: a
+                      sort order: +
+                      Map-reduce partition columns: FILE__PATH (type: string)
+                      Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+        Reducer 4 
+            Reduce Operator Tree:
+              Merge Join Operator
+                condition map:
+                     Left Semi Join 0 to 1
+                keys:
+                  0 _col7 (type: string)
+                  1 _col0 (type: string)
+                outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, 
_col6, _col7, _col8
+                Statistics: Num rows: 1 Data size: 584 Basic stats: COMPLETE 
Column stats: PARTIAL
+                Select Operator
+                  expressions: _col5 (type: int), _col6 (type: bigint), _col7 
(type: string), _col8 (type: bigint), _col0 (type: int), _col1 (type: string), 
_col2 (type: boolean), _col3 (type: string), _col4 (type: int)
+                  outputColumnNames: _col0, _col1, _col2, _col3, _col4, _col5, 
_col6, _col7, _col8
+                  Statistics: Num rows: 1 Data size: 584 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  File Output Operator
+                    compressed: false
+                    Statistics: Num rows: 3 Data size: 1565 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    table:
+                        input format: 
org.apache.iceberg.mr.hive.HiveIcebergInputFormat
+                        output format: 
org.apache.iceberg.mr.hive.HiveIcebergOutputFormat
+                        serde: org.apache.iceberg.mr.hive.HiveIcebergSerDe
+                        name: default.iceberg_cow_partitioned
+        Reducer 6 
+            Reduce Operator Tree:
+              Select Operator
+                expressions: VALUE._col0 (type: int), VALUE._col1 (type: 
string), VALUE._col2 (type: boolean), VALUE._col4 (type: int), VALUE._col5 
(type: int), VALUE._col6 (type: bigint), KEY.reducesinkkey0 (type: string)
+                outputColumnNames: _col0, _col1, _col2, _col4, _col5, _col6, 
_col7
+                Statistics: Num rows: 1 Data size: 392 Basic stats: COMPLETE 
Column stats: PARTIAL
+                PTF Operator
+                  Function definitions:
+                      Input definition
+                        input alias: ptf_0
+                        type: WINDOWING
+                      Windowing table definition
+                        input alias: ptf_1
+                        name: windowingtablefunction
+                        order by: _col7 ASC NULLS FIRST
+                        partition by: _col7
+                        raw input shape:
+                        window functions:
+                            window function definition
+                              alias: row_number_window_0
+                              name: row_number
+                              window function: GenericUDAFRowNumberEvaluator
+                              window frame: ROWS PRECEDING(MAX)~FOLLOWING(MAX)
+                              isPivotResult: true
+                  Statistics: Num rows: 1 Data size: 392 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Filter Operator
+                    predicate: (row_number_window_0 = 1) (type: boolean)
+                    Statistics: Num rows: 1 Data size: 392 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    Select Operator
+                      expressions: _col5 (type: int), _col6 (type: bigint), 
_col7 (type: string), -1L (type: bigint), _col0 (type: int), _col1 (type: 
string), _col2 (type: boolean), null (type: string), _col4 (type: int)
+                      outputColumnNames: _col0, _col1, _col2, _col3, _col4, 
_col5, _col6, _col7, _col8
+                      Statistics: Num rows: 1 Data size: 484 Basic stats: 
COMPLETE Column stats: PARTIAL
+                      File Output Operator
+                        compressed: false
+                        Statistics: Num rows: 3 Data size: 1565 Basic stats: 
COMPLETE Column stats: PARTIAL
+                        table:
+                            input format: 
org.apache.iceberg.mr.hive.HiveIcebergInputFormat
+                            output format: 
org.apache.iceberg.mr.hive.HiveIcebergOutputFormat
+                            serde: org.apache.iceberg.mr.hive.HiveIcebergSerDe
+                            name: default.iceberg_cow_partitioned
+        Reducer 7 
+            Reduce Operator Tree:
+              Select Operator
+                expressions: KEY.reducesinkkey0 (type: string)
+                outputColumnNames: _col7
+                Statistics: Num rows: 1 Data size: 184 Basic stats: COMPLETE 
Column stats: PARTIAL
+                PTF Operator
+                  Function definitions:
+                      Input definition
+                        input alias: ptf_0
+                        output shape: _col7: string
+                        type: WINDOWING
+                      Windowing table definition
+                        input alias: ptf_1
+                        name: windowingtablefunction
+                        order by: _col7 ASC NULLS FIRST
+                        partition by: _col7
+                        raw input shape:
+                        window functions:
+                            window function definition
+                              alias: row_number_window_0
+                              name: row_number
+                              window function: GenericUDAFRowNumberEvaluator
+                              window frame: ROWS PRECEDING(MAX)~FOLLOWING(MAX)
+                              isPivotResult: true
+                  Statistics: Num rows: 1 Data size: 184 Basic stats: COMPLETE 
Column stats: PARTIAL
+                  Filter Operator
+                    predicate: (row_number_window_0 = 1) (type: boolean)
+                    Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+                    Select Operator
+                      expressions: _col7 (type: string)
+                      outputColumnNames: _col0
+                      Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+                      Group By Operator
+                        keys: _col0 (type: string)
+                        minReductionHashAggr: 0.99
+                        mode: hash
+                        outputColumnNames: _col0
+                        Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+                        Reduce Output Operator
+                          key expressions: _col0 (type: string)
+                          null sort order: z
+                          sort order: +
+                          Map-reduce partition columns: _col0 (type: string)
+                          Statistics: Num rows: 1 Data size: 184 Basic stats: 
COMPLETE Column stats: PARTIAL
+        Union 2 
+            Vertex: Union 2
+
+  Stage: Stage-2
+    Dependency Collection
+
+  Stage: Stage-0
+    Move Operator
+      tables:
+          replace: false
+          table:
+              input format: org.apache.iceberg.mr.hive.HiveIcebergInputFormat
+              output format: org.apache.iceberg.mr.hive.HiveIcebergOutputFormat
+              serde: org.apache.iceberg.mr.hive.HiveIcebergSerDe
+              name: default.iceberg_cow_partitioned
+
+  Stage: Stage-3
+    Stats Work
+      Basic Stats Work:
+
+PREHOOK: query: update iceberg_cow_partitioned set str_col = 'UPDATED NULLS' 
where str_col is null
+PREHOOK: type: QUERY
+PREHOOK: Input: default@iceberg_cow_partitioned
+PREHOOK: Output: default@iceberg_cow_partitioned
+POSTHOOK: query: update iceberg_cow_partitioned set str_col = 'UPDATED NULLS' 
where str_col is null
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@iceberg_cow_partitioned
+POSTHOOK: Output: default@iceberg_cow_partitioned
+PREHOOK: query: select * from iceberg_cow_partitioned
+PREHOOK: type: QUERY
+PREHOOK: Input: default@iceberg_cow_partitioned
+PREHOOK: Output: hdfs://### HDFS PATH ###
+POSTHOOK: query: select * from iceberg_cow_partitioned
+POSTHOOK: type: QUERY
+POSTHOOK: Input: default@iceberg_cow_partitioned
+POSTHOOK: Output: hdfs://### HDFS PATH ###
+1      a       true    UPDATED NULLS   1
+2      b       false   UPDATED NULLS   2
diff --git 
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/ColumnPrunerProcFactory.java 
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/ColumnPrunerProcFactory.java
index 8306c650ebb..6a79d2587f2 100644
--- 
a/ql/src/java/org/apache/hadoop/hive/ql/optimizer/ColumnPrunerProcFactory.java
+++ 
b/ql/src/java/org/apache/hadoop/hive/ql/optimizer/ColumnPrunerProcFactory.java
@@ -38,6 +38,7 @@
 import org.apache.hadoop.hive.ql.exec.AbstractMapJoinOperator;
 import org.apache.hadoop.hive.ql.exec.ColumnInfo;
 import org.apache.hadoop.hive.ql.exec.CommonJoinOperator;
+import org.apache.hadoop.hive.ql.exec.FileSinkOperator;
 import org.apache.hadoop.hive.ql.exec.FilterOperator;
 import org.apache.hadoop.hive.ql.exec.GroupByOperator;
 import org.apache.hadoop.hive.ql.exec.JoinOperator;
@@ -65,6 +66,7 @@
 import org.apache.hadoop.hive.ql.plan.ExprNodeColumnDesc;
 import org.apache.hadoop.hive.ql.plan.ExprNodeDesc;
 import org.apache.hadoop.hive.ql.plan.ExprNodeDescUtils;
+import org.apache.hadoop.hive.ql.plan.ExprNodeGenericFuncDesc;
 import org.apache.hadoop.hive.ql.plan.GroupByDesc;
 import org.apache.hadoop.hive.ql.plan.JoinDesc;
 import org.apache.hadoop.hive.ql.plan.MapJoinDesc;
@@ -496,6 +498,7 @@ public Object process(Node nd, Stack<Node> stack, 
NodeProcessorCtx ctx,
       }
 
       cols = cols == null ? new ArrayList<FieldNode>() : cols;
+      cols = includePartitionColumnsFromScanFilters(scanOp, cols);
 
       cppCtx.getPrunedColLists().put((Operator<? extends OperatorDesc>) nd, 
cols);
       RowSchema inputRS = scanOp.getSchema();
@@ -503,6 +506,75 @@ public Object process(Node nd, Stack<Node> stack, 
NodeProcessorCtx ctx,
 
       return null;
     }
+
+    /**
+     * For storage handlers with non-native partitions (Iceberg), keep 
identity partition source
+     * columns in the scan when they are referenced by pushed storage filters 
or filters above the
+     * scan in the local read pipeline. Without this, filters can reference 
partition columns that
+     * were pruned from the read projection.
+     */
+    private static List<FieldNode> 
includePartitionColumnsFromScanFilters(TableScanOperator scanOp,
+        List<FieldNode> cols) {
+      TableScanDesc desc = scanOp.getConf();
+      Table table = desc.getTableMetadata();
+      if (table == null || !table.hasNonNativePartitionSupport()) {
+        return cols;
+      }
+
+      ExprNodeGenericFuncDesc filterExpr = desc.getFilterExpr();
+      if (filterExpr != null) {
+        cols = mergeFieldNodesWithDesc(cols, filterExpr);
+      }
+
+      if (scanOp.getChildOperators() != null) {
+        for (Operator<? extends OperatorDesc> child : 
scanOp.getChildOperators()) {
+          cols = mergePartitionColumnsFromFiltersAboveScan(child, cols);
+        }
+      }
+      return cols;
+    }
+
+    /**
+     * Walks operators above a TableScan in the local read pipeline and merges 
columns referenced by
+     * Filter predicates. Traversal follows passthrough operators (Select, 
PTF, lateral view join,
+     * Limit), mirroring predicate pushdown boundaries in {@code 
OpProcFactory.SimpleFilterPPD}.
+     * Stops at shuffle, join, grouping and sink operators.
+     */
+    private static List<FieldNode> mergePartitionColumnsFromFiltersAboveScan(
+        Operator<? extends OperatorDesc> op, List<FieldNode> cols) {
+      if (isScanPipelineBoundary(op)) {
+        return cols;
+      }
+
+      if (op instanceof FilterOperator filterOperator) {
+        cols = mergeFieldNodesWithDesc(cols, 
filterOperator.getConf().getPredicate());
+      } else if (!isPassthroughOperatorAboveScan(op)) {
+        return cols;
+      }
+
+      if (op.getChildOperators() == null) {
+        return cols;
+      }
+      for (Operator<? extends OperatorDesc> child : op.getChildOperators()) {
+        cols = mergePartitionColumnsFromFiltersAboveScan(child, cols);
+      }
+      return cols;
+    }
+
+    private static boolean isPassthroughOperatorAboveScan(Operator<? extends 
OperatorDesc> op) {
+      return op instanceof SelectOperator
+          || op instanceof PTFOperator
+          || op instanceof LateralViewJoinOperator
+          || op instanceof LimitOperator;
+    }
+
+    private static boolean isScanPipelineBoundary(Operator<? extends 
OperatorDesc> op) {
+      return op instanceof ReduceSinkOperator
+          || op instanceof GroupByOperator
+          || op instanceof CommonJoinOperator
+          || op instanceof UnionOperator
+          || op instanceof FileSinkOperator;
+    }
   }
 
   /** Sets up needed columns for TSOP. Mainly, transfers column names from 
input

Reply via email to