@@ -5,10 +5,10 @@ use std::ffi::c_void;
55use delta_kernel:: expressions:: {
66 ArrayData , BinaryExpression , BinaryExpressionOp , BinaryPredicate , BinaryPredicateOp ,
77 ColumnName , Expression , ExpressionRef , ExpressionStructPatch , JunctionPredicate ,
8- JunctionPredicateOp , MapData , MapToStructExpression , OpaqueExpression , OpaqueExpressionOpRef ,
9- OpaquePredicate , OpaquePredicateOpRef , ParseJsonExpression , Predicate , Scalar , StructData ,
10- UnaryExpression , UnaryExpressionOp , UnaryPredicate , UnaryPredicateOp , VariadicExpression ,
11- VariadicExpressionOp ,
8+ JunctionPredicateOp , MapData , MapToStructExpression , MapToStructOptions , OpaqueExpression ,
9+ OpaqueExpressionOpRef , OpaquePredicate , OpaquePredicateOpRef , ParseJsonExpression , Predicate ,
10+ Scalar , StructData , UnaryExpression , UnaryExpressionOp , UnaryPredicate , UnaryPredicateOp ,
11+ VariadicExpression , VariadicExpressionOp ,
1212} ;
1313
1414use super :: kernel_visitor:: NullTypeTag ;
@@ -174,9 +174,10 @@ pub struct EngineExpressionVisitor {
174174 /// `child_list_id`. The `output_schema` handle specifies the schema to parse the JSON
175175 /// into.
176176 pub visit_parse_json : VisitParseJsonFn ,
177- /// Visits the `MapToStruct` expression belonging to the list identified by `sibling_list_id`.
178- /// The sub-expression (map column) will be in a _one_ item list identified by `child_list_id`.
179- /// The output struct schema is determined by the evaluator's result type.
177+ /// Visits a `MapToStruct` expression with default options. The FFI does not currently
178+ /// represent [`MapToStructOptions`], so expressions with configured options are reported
179+ /// through `visit_unknown` without visiting the child expression. The sub-expression is in
180+ /// the one-item list identified by `child_list_id`.
180181 pub visit_map_to_struct : VisitUnaryFn ,
181182 /// Visits the `LessThan` binary operator belonging to the list identified by
182183 /// `sibling_list_id`. The operands will be in a _two_ item list identified by
@@ -696,7 +697,13 @@ fn visit_expression_impl(
696697 schema_handle
697698 ) ;
698699 }
699- Expression :: MapToStruct ( MapToStructExpression { map_expr } ) => {
700+ // TODO: Add a dedicated FFI representation for MapToStructOptions.
701+ Expression :: MapToStruct ( map_to_struct)
702+ if map_to_struct. options != MapToStructOptions :: default ( ) =>
703+ {
704+ visit_unknown ( visitor, sibling_list_id, "map_to_struct" )
705+ }
706+ Expression :: MapToStruct ( MapToStructExpression { map_expr, .. } ) => {
700707 let child_list_id = call ! ( visitor, make_field_list, 1 ) ;
701708 visit_expression_impl ( visitor, map_expr, child_list_id) ;
702709 call ! ( visitor, visit_map_to_struct, sibling_list_id, child_list_id) ;
@@ -771,7 +778,7 @@ fn visit_predicate_internal(predicate: &Predicate, visitor: &mut EngineExpressio
771778
772779#[ cfg( test) ]
773780mod tests {
774- use delta_kernel:: expressions:: { lit, Expression , Scalar } ;
781+ use delta_kernel:: expressions:: { lit, Expression , MapToStructOptions , Scalar } ;
775782 use rstest:: rstest;
776783
777784 use super :: * ;
@@ -791,6 +798,10 @@ mod tests {
791798 sibling_list_id : usize ,
792799 parts : Vec < String > ,
793800 } ,
801+ Unknown {
802+ sibling_list_id : usize ,
803+ name : String ,
804+ } ,
794805 }
795806
796807 #[ derive( Default ) ]
@@ -847,6 +858,18 @@ mod tests {
847858 } ) ;
848859 }
849860
861+ extern "C" fn visit_unknown_name (
862+ data : * mut c_void ,
863+ sibling_list_id : usize ,
864+ name : KernelStringSlice ,
865+ ) {
866+ let builder = unsafe { & mut * ( data as * mut TestExpressionBuilder ) } ;
867+ let name = unsafe { String :: try_from_slice ( & name) } . unwrap ( ) ;
868+ builder. events . push ( LiteralEvent :: Unknown {
869+ sibling_list_id,
870+ name,
871+ } ) ;
872+ }
850873 macro_rules! ignore_fn {
851874 ( $fn_name: ident $( , $arg_type: ty) * ) => {
852875 extern "C" fn $fn_name(
@@ -925,7 +948,7 @@ mod tests {
925948 visit_field_patch : ignore_field_patch,
926949 visit_opaque_expr : ignore_opaque_expr,
927950 visit_opaque_pred : ignore_opaque_pred,
928- visit_unknown : ignore_string_slice ,
951+ visit_unknown : visit_unknown_name ,
929952 }
930953 }
931954
@@ -992,4 +1015,25 @@ mod tests {
9921015 assert_eq ! ( top_level_id, 0 ) ;
9931016 assert_eq ! ( builder. events, vec![ expected] ) ;
9941017 }
1018+
1019+ #[ test]
1020+ fn timezone_aware_map_to_struct_visits_unknown ( ) {
1021+ let expression = Expression :: map_to_struct (
1022+ Expression :: column ( [ "partitionValues" ] ) ,
1023+ MapToStructOptions :: default ( ) . with_timestamp_timezone ( "America/Los_Angeles" ) ,
1024+ ) ;
1025+ let mut builder = TestExpressionBuilder :: default ( ) ;
1026+ let mut visitor = test_visitor ( & mut builder) ;
1027+
1028+ let top_level_id = visit_expression_internal ( & expression, & mut visitor) ;
1029+
1030+ assert_eq ! ( top_level_id, 0 ) ;
1031+ assert_eq ! (
1032+ builder. events,
1033+ vec![ LiteralEvent :: Unknown {
1034+ sibling_list_id: 0 ,
1035+ name: "map_to_struct" . to_string( ) ,
1036+ } ]
1037+ ) ;
1038+ }
9951039}
0 commit comments