@@ -29,8 +29,8 @@ use crate::push_decoder::{DecoderBuilderConfig, PushDecoderStreamState};
2929use crate :: row_filter:: { RowFilterGenerator , build_projection_read_plan} ;
3030use crate :: row_group_filter:: { BloomFilterStatistics , RowGroupAccessPlanFilter } ;
3131use crate :: {
32- ParquetAccessPlan , ParquetFileMetrics , ParquetFileReaderFactory ,
33- apply_file_schema_type_coercions, coerce_int96_to_resolution ,
32+ Int96Coercer , ParquetAccessPlan , ParquetFileMetrics , ParquetFileReaderFactory ,
33+ apply_file_schema_type_coercions,
3434} ;
3535use arrow:: array:: RecordBatch ;
3636use arrow:: datatypes:: DataType ;
@@ -121,6 +121,10 @@ pub(super) struct ParquetMorselizer {
121121 pub enable_row_group_stats_pruning : bool ,
122122 /// Coerce INT96 timestamps to specific TimeUnit
123123 pub coerce_int96 : Option < TimeUnit > ,
124+ /// Optional timezone applied to INT96-coerced timestamps. When `Some`, the
125+ /// coerced column type becomes `Timestamp(<coerce_int96>, Some(<tz>))`.
126+ /// No effect when `coerce_int96` is `None`.
127+ pub coerce_int96_tz : Option < Arc < str > > ,
124128 /// Optional parquet FileDecryptionProperties
125129 #[ cfg( feature = "parquet_encryption" ) ]
126130 pub file_decryption_properties : Option < Arc < FileDecryptionProperties > > ,
@@ -283,6 +287,7 @@ struct PreparedParquetOpen {
283287 enable_row_group_stats_pruning : bool ,
284288 limit : Option < usize > ,
285289 coerce_int96 : Option < TimeUnit > ,
290+ coerce_int96_tz : Option < Arc < str > > ,
286291 expr_adapter_factory : Arc < dyn PhysicalExprAdapterFactory > ,
287292 predicate_creation_errors : Count ,
288293 max_predicate_cache_size : Option < usize > ,
@@ -653,6 +658,7 @@ impl ParquetMorselizer {
653658 enable_row_group_stats_pruning : self . enable_row_group_stats_pruning ,
654659 limit : self . limit ,
655660 coerce_int96 : self . coerce_int96 ,
661+ coerce_int96_tz : self . coerce_int96_tz . clone ( ) ,
656662 expr_adapter_factory : Arc :: clone ( & self . expr_adapter_factory ) ,
657663 predicate_creation_errors,
658664 max_predicate_cache_size : self . max_predicate_cache_size ,
@@ -780,11 +786,13 @@ impl MetadataLoadedParquetOpen {
780786 }
781787
782788 if let Some ( ref coerce) = prepared. coerce_int96
783- && let Some ( merged) = coerce_int96_to_resolution (
789+ && let Some ( merged) = Int96Coercer :: new (
784790 reader_metadata. parquet_schema ( ) ,
785791 & physical_file_schema,
786792 coerce,
787793 )
794+ . with_timezone ( prepared. coerce_int96_tz . clone ( ) )
795+ . coerce ( )
788796 {
789797 physical_file_schema = Arc :: new ( merged) ;
790798 options = options. with_schema ( Arc :: clone ( & physical_file_schema) ) ;
@@ -1603,6 +1611,10 @@ mod test {
16031611 enable_bloom_filter : self . enable_bloom_filter ,
16041612 enable_row_group_stats_pruning : self . enable_row_group_stats_pruning ,
16051613 coerce_int96 : self . coerce_int96 ,
1614+ // End-to-end coercion behavior (including timezone) is
1615+ // covered by parquet.slt. No opener-level test currently
1616+ // needs a non-default value here.
1617+ coerce_int96_tz : None ,
16061618 #[ cfg( feature = "parquet_encryption" ) ]
16071619 file_decryption_properties : None ,
16081620 expr_adapter_factory : Arc :: new ( DefaultPhysicalExprAdapterFactory ) ,
0 commit comments