@@ -68,6 +68,18 @@ def prune_blobs(self, blob_names: list[str], query_statistics, selection) -> lis
6868 and cond .right .schema_column .type
6969 not in (OrsoTypes .DATE , OrsoTypes .TIME , OrsoTypes .TIMESTAMP )
7070 ]
71+ # Handle AnyOp* comparisons where left is a literal and right is an identifier
72+ valid_conditions_any = [
73+ cond
74+ for cond in selection
75+ if cond .value == "AnyOpEq"
76+ and cond .left .node_type == NodeType .LITERAL
77+ and cond .right .node_type == NodeType .IDENTIFIER
78+ and cond .right .schema_column .type
79+ not in (OrsoTypes .DATE , OrsoTypes .TIME , OrsoTypes .TIMESTAMP )
80+ and cond .left .schema_column .type
81+ not in (OrsoTypes .DATE , OrsoTypes .TIME , OrsoTypes .TIMESTAMP )
82+ ]
7183
7284 for condition in valid_conditions :
7385 column_name = condition .left .source_column .encode ()
@@ -87,6 +99,35 @@ def prune_blobs(self, blob_names: list[str], query_statistics, selection) -> lis
8799 skip_blob = True
88100 break
89101
102+ # Evaluate AnyOp* conditions (literal = ANY(column)) safely using element min/max
103+ for condition in valid_conditions_any :
104+ column_name = condition .right .source_column .encode ()
105+ literal_value = condition .left .value
106+ # Skip NULL literals — unsafe to prune
107+ if literal_value is None :
108+ continue
109+ if type (literal_value ) is numpy .datetime64 :
110+ # convert to python datetime for consistent to_int conversion
111+ literal_value = literal_value .astype ("M8[ms]" ).astype ("O" )
112+ if hasattr (literal_value , "item" ):
113+ literal_value = literal_value .item ()
114+ literal_value = to_int (literal_value )
115+ # Skip NULL_FLAG values (NaN/unconvertible) that appear as the NULL sentinel
116+ NULL_FLAG = - (1 << 63 )
117+ if literal_value == NULL_FLAG :
118+ continue
119+ max_value = cached_stats .upper_bounds .get (column_name )
120+ min_value = cached_stats .lower_bounds .get (column_name )
121+
122+ if max_value is not None and min_value is not None :
123+ # convert AnyOpEq -> Eq, AnyOpGt -> Gt, etc.
124+ op_name = condition .value [5 :]
125+ prune = handlers .get (op_name )
126+ if prune and prune (literal_value , min_value , max_value ):
127+ query_statistics .blobs_pruned += 1
128+ skip_blob = True
129+ break
130+
90131 if not skip_blob :
91132 new_blob_names .append (blob_name )
92133
0 commit comments