@@ -13,8 +13,6 @@ use vortex_array::ExecutionCtx;
1313use vortex_array:: IntoArray ;
1414use vortex_array:: arrays:: Extension ;
1515use vortex_array:: arrays:: ExtensionArray ;
16- use vortex_array:: arrays:: VarBinView ;
17- use vortex_array:: arrays:: VarBinViewArray ;
1816use vortex_array:: arrays:: scalar_fn:: ScalarFnFactoryExt ;
1917use vortex_array:: dtype:: DType ;
2018use vortex_array:: expr:: Expression ;
@@ -38,9 +36,9 @@ use crate::Json;
3836
3937/// Parses JSON strings into Variant values, optionally shredding fields.
4038///
41- /// Accepts `Utf8` inputs or [`Json`] extension inputs and returns `Variant` values with the
42- /// input's nullability. Null rows stay null, the JSON literal `null` becomes a variant-null
43- /// value, and any row that fails to parse as JSON fails the whole expression.
39+ /// Accepts [`Json`] extension inputs and returns `Variant` values with the input's nullability.
40+ /// Null rows stay null, the JSON literal `null` becomes a variant-null value, and any row that
41+ /// fails to parse as JSON fails the whole expression.
4442///
4543/// A non-empty [`ShreddingSpec`] additionally shreds the selected paths into a typed shredded
4644/// child, following the [Parquet Variant shredding] rules: rows whose value does not match the
@@ -50,10 +48,10 @@ use crate::Json;
5048///
5149/// Building a Variant requires a concrete Variant encoding, so this function does not perform the
5250/// conversion itself. The Variant encoding registered with the session supplies it as an
53- /// `execute_parent` kernel keyed on the canonical string encodings (`VarBinView` for `Utf8`, and
54- /// the extension encoding for a [`Json`] input). The fallback [` execute`](ScalarFnVTable::execute)
55- /// here only canonicalizes its input to one of those encodings and re-dispatches so that kernel
56- /// runs; it errors if no Variant encoding is registered with the session.
51+ /// `execute_parent` kernel keyed on the extension encoding for a [`Json`] input. The fallback
52+ /// [` execute`](ScalarFnVTable::execute) here only canonicalizes the input to that encoding and
53+ /// re-dispatches so that kernel runs; it errors if no Variant encoding is registered with the
54+ /// session.
5755///
5856/// # Normalization
5957///
@@ -135,11 +133,10 @@ impl ScalarFnVTable for JsonToVariant {
135133 fn return_dtype ( & self , _options : & Self :: Options , arg_dtypes : & [ DType ] ) -> VortexResult < DType > {
136134 let input_dtype = & arg_dtypes[ 0 ] ;
137135 vortex_ensure ! (
138- input_dtype. is_utf8( )
139- || input_dtype
140- . as_extension_opt( )
141- . is_some_and( |ext_dtype| ext_dtype. is:: <Json >( ) ) ,
142- "JsonToVariant input must be Utf8 or a Json extension, found {input_dtype}"
136+ input_dtype
137+ . as_extension_opt( )
138+ . is_some_and( |ext_dtype| ext_dtype. is:: <Json >( ) ) ,
139+ "JsonToVariant input must be a Json extension, found {input_dtype}"
143140 ) ;
144141
145142 Ok ( DType :: Variant ( input_dtype. nullability ( ) ) )
@@ -154,24 +151,19 @@ impl ScalarFnVTable for JsonToVariant {
154151 let input = args. get ( 0 ) ?;
155152
156153 // This function does not build Variants itself: the Variant encoding registered with the
157- // session supplies the conversion as an `execute_parent` kernel keyed on the canonical
158- // string encodings (`VarBinView` for `Utf8`, the extension encoding for a `Json` input).
159- // Reaching this fallback means no such kernel fired, so canonicalize the input to one of
160- // those encodings and re-dispatch. If the input is already canonical here, no kernel is
161- // registered for it; bail with a clear error rather than looping.
154+ // session supplies the conversion as an `execute_parent` kernel keyed on the extension
155+ // encoding for a `Json` input. Reaching this fallback means no such kernel fired, so
156+ // canonicalize the input to that encoding and re-dispatch. If the input is already
157+ // canonical here, no kernel is registered for it; bail with a clear error rather than
158+ // looping.
162159 let no_kernel = || {
163160 vortex_err ! (
164161 "json_to_variant requires a registered Variant encoding to build Variant values \
165162 from JSON, but none is registered with this session"
166163 )
167164 } ;
168165
169- let canonical = if input. dtype ( ) . is_utf8 ( ) {
170- if input. is :: < VarBinView > ( ) {
171- return Err ( no_kernel ( ) ) ;
172- }
173- input. execute :: < VarBinViewArray > ( ctx) ?. into_array ( )
174- } else if input
166+ let canonical = if input
175167 . dtype ( )
176168 . as_extension_opt ( )
177169 . is_some_and ( |ext_dtype| ext_dtype. is :: < Json > ( ) )
@@ -182,7 +174,7 @@ impl ScalarFnVTable for JsonToVariant {
182174 input. execute :: < ExtensionArray > ( ctx) ?. into_array ( )
183175 } else {
184176 vortex_bail ! (
185- "JsonToVariant input must be Utf8 or a Json extension, found {}" ,
177+ "JsonToVariant input must be a Json extension, found {}" ,
186178 input. dtype( )
187179 ) ;
188180 } ;
@@ -195,16 +187,16 @@ impl ScalarFnVTable for JsonToVariant {
195187 // `json_to_variant` maps null rows to null rows and the JSON literal `null` to a
196188 // variant-null value independently of which other rows are null, so it commutes with
197189 // validity masking. Marking it not null-sensitive also lets it push through dictionaries
198- // into their (canonical-string) values, where the kernel fires directly.
190+ // into their JSON extension values, where the kernel fires directly.
199191 false
200192 }
201193}
202194
203195/// Creates a [`JsonToVariant`] expression that parses `child`'s JSON strings into Variant
204196/// values, shredding the paths selected by `shredding`.
205197///
206- /// `child` must produce `Utf8` or [`Json`] extension values; the result is `Variant` with the
207- /// input's nullability. Rows containing invalid JSON fail the expression.
198+ /// `child` must produce [`Json`] extension values; the result is `Variant` with the input's
199+ /// nullability. Rows containing invalid JSON fail the expression.
208200///
209201/// Note that this is a lossy, normalizing conversion. See [`JsonToVariant`] for the full list of
210202/// caveats.
@@ -360,36 +352,45 @@ mod tests {
360352 Ok ( ( ) )
361353 }
362354
355+ #[ test]
356+ fn utf8_input_is_rejected ( ) {
357+ let input = VarBinViewArray :: from_iter_str ( [ "1" , "2" ] ) . into_array ( ) ;
358+ let err = JsonToVariant
359+ . try_new_array ( input. len ( ) , JsonToVariantOptions :: unshredded ( ) , [ input] )
360+ . unwrap_err ( ) ;
361+
362+ assert ! (
363+ err. to_string( ) . contains( "Json extension" ) ,
364+ "unexpected error: {err}"
365+ ) ;
366+ }
367+
363368 #[ test]
364369 fn execute_without_variant_kernel_errors ( ) -> VortexResult < ( ) > {
365370 // With no Variant encoding registered, executing over an already-canonical input must
366- // surface a clear error rather than looping. Both canonical input forms are covered: a
367- // bare `Utf8`/`VarBinView`, and a `Json` extension.
368- let utf8 = VarBinViewArray :: from_iter_str ( [ "1" , "2" ] ) . into_array ( ) ;
369- let json_extension = ExtensionArray :: try_new_from_vtable (
371+ // surface a clear error rather than looping.
372+ let input = ExtensionArray :: try_new_from_vtable (
370373 Json ,
371374 EmptyMetadata ,
372375 VarBinViewArray :: from_iter_str ( [ "1" , "2" ] ) . into_array ( ) ,
373376 ) ?
374377 . into_array ( ) ;
375378
376- for input in [ utf8, json_extension] {
377- let dtype = input. dtype ( ) . clone ( ) ;
378- let array = JsonToVariant . try_new_array (
379- input. len ( ) ,
380- JsonToVariantOptions :: unshredded ( ) ,
381- [ input] ,
382- ) ?;
383-
384- let err = array
385- . execute :: < ArrayRef > ( & mut session ( ) . create_execution_ctx ( ) )
386- . unwrap_err ( ) ;
387-
388- assert ! (
389- err. to_string( ) . contains( "Variant encoding" ) ,
390- "unexpected error for {dtype}: {err}"
391- ) ;
392- }
379+ let dtype = input. dtype ( ) . clone ( ) ;
380+ let array = JsonToVariant . try_new_array (
381+ input. len ( ) ,
382+ JsonToVariantOptions :: unshredded ( ) ,
383+ [ input] ,
384+ ) ?;
385+
386+ let err = array
387+ . execute :: < ArrayRef > ( & mut session ( ) . create_execution_ctx ( ) )
388+ . unwrap_err ( ) ;
389+
390+ assert ! (
391+ err. to_string( ) . contains( "Variant encoding" ) ,
392+ "unexpected error for {dtype}: {err}"
393+ ) ;
393394 Ok ( ( ) )
394395 }
395396}
0 commit comments