@@ -16,7 +16,7 @@ use syn::{Expr, Lifetime};
1616/// Modifiers passed as key-value pairs to the `#[sqlfunc]` macro.
1717#[ derive( Debug , Default , darling:: FromMeta ) ]
1818pub ( crate ) struct Modifiers {
19- /// An optional expression that evaluates to a boolean indicating whether the function i
19+ /// An optional expression that evaluates to a boolean indicating whether the function is
2020 /// monotone with respect to its arguments. Defined for unary and binary functions.
2121 is_monotone : Option < Expr > ,
2222 /// The SQL name for the function. Applies to all functions.
@@ -37,6 +37,8 @@ pub(crate) struct Modifiers {
3737 could_error : Option < Expr > ,
3838 /// Whether the function propagates nulls. Applies to binary functions.
3939 propagates_nulls : Option < Expr > ,
40+ /// Whether the function introduces nulls. Applies to all functions.
41+ introduces_nulls : Option < Expr > ,
4042}
4143
4244/// Implementation for the `#[sqlfunc]` macro. The first parameter is the attribute
@@ -54,7 +56,10 @@ pub fn sqlfunc(
5456 let func = syn:: parse2 :: < syn:: ItemFn > ( item. clone ( ) ) ?;
5557
5658 let tokens = match determine_parameters_arena ( & func) {
57- ( 1 , arena) => unary_func ( & func, modifiers, arena) ,
59+ ( 1 , false ) => unary_func ( & func, modifiers) ,
60+ ( 1 , true ) => Err ( darling:: Error :: custom (
61+ "Unary functions do not yet support RowArena." ,
62+ ) ) ,
5863 ( 2 , arena) => binary_func ( & func, modifiers, arena) ,
5964 ( other, _) => Err ( darling:: Error :: custom ( format ! (
6065 "Unsupported function: {} parameters" ,
@@ -171,11 +176,7 @@ fn output_type(arg: &syn::ItemFn) -> Result<&syn::Type, syn::Error> {
171176}
172177
173178/// Produce a `EagerUnaryFunc` implementation.
174- fn unary_func (
175- func : & syn:: ItemFn ,
176- modifiers : Modifiers ,
177- arena : bool ,
178- ) -> darling:: Result < TokenStream > {
179+ fn unary_func ( func : & syn:: ItemFn , modifiers : Modifiers ) -> darling:: Result < TokenStream > {
179180 let fn_name = & func. sig . ident ;
180181 let struct_name = camel_case ( & func. sig . ident ) ;
181182 let input_ty = arg_type ( func, 0 ) ?;
@@ -190,16 +191,23 @@ fn unary_func(
190191 negate,
191192 could_error,
192193 propagates_nulls,
194+ introduces_nulls,
193195 } = modifiers;
194196
195197 if is_infix_op. is_some ( ) {
196- return Err ( darling:: Error :: unknown_field ( "is_infix_op" ) ) ;
198+ return Err ( darling:: Error :: unknown_field (
199+ "is_infix_op not supported for unary functions" ,
200+ ) ) ;
197201 }
198202 if negate. is_some ( ) {
199- return Err ( darling:: Error :: unknown_field ( "negate" ) ) ;
203+ return Err ( darling:: Error :: unknown_field (
204+ "negate not supported for unary functions" ,
205+ ) ) ;
200206 }
201207 if propagates_nulls. is_some ( ) {
202- return Err ( darling:: Error :: unknown_field ( "propagates_nulls" ) ) ;
208+ return Err ( darling:: Error :: unknown_field (
209+ "propagates_nulls not supported for unary functions" ,
210+ ) ) ;
203211 }
204212
205213 let preserves_uniqueness_fn = preserves_uniqueness. map ( |preserves_uniqueness| {
@@ -236,10 +244,10 @@ fn unary_func(
236244 }
237245 } ;
238246
239- let ( output_type, introduces_nulls_fn) = if let Some ( output_type) = output_type {
247+ let ( output_type, mut introduces_nulls_fn) = if let Some ( output_type) = output_type {
240248 let introduces_nulls_fn = quote ! {
241249 fn introduces_nulls( & self ) -> bool {
242- <#output_type as mz_repr:: DatumType <' _, ( ) >>:: nullable( )
250+ <#output_type as :: mz_repr:: DatumType <' _, ( ) >>:: nullable( )
243251 }
244252 } ;
245253 let output_type = quote ! { <#output_type> } ;
@@ -248,7 +256,13 @@ fn unary_func(
248256 ( quote ! { Self :: Output } , None )
249257 } ;
250258
251- let arena = arena. then ( || quote ! { , temp_storage } ) ;
259+ if let Some ( introduces_nulls) = introduces_nulls {
260+ introduces_nulls_fn = Some ( quote ! {
261+ fn introduces_nulls( & self ) -> bool {
262+ #introduces_nulls
263+ }
264+ } ) ;
265+ }
252266
253267 let could_error_fn = could_error. map ( |could_error| {
254268 quote ! {
@@ -267,7 +281,7 @@ fn unary_func(
267281 type Output = #output_ty;
268282
269283 fn call( & self , a: Self :: Input ) -> Self :: Output {
270- #fn_name( a #arena )
284+ #fn_name( a)
271285 }
272286
273287 fn output_type( & self , input_type: mz_repr:: ColumnType ) -> mz_repr:: ColumnType {
@@ -320,13 +334,18 @@ fn binary_func(
320334 negate,
321335 could_error,
322336 propagates_nulls,
337+ introduces_nulls,
323338 } = modifiers;
324339
325340 if preserves_uniqueness. is_some ( ) {
326- return Err ( darling:: Error :: unknown_field ( "preserves_uniqueness" ) ) ;
341+ return Err ( darling:: Error :: unknown_field (
342+ "preserves_uniqueness not supported for binary functions" ,
343+ ) ) ;
327344 }
328345 if inverse. is_some ( ) {
329- return Err ( darling:: Error :: unknown_field ( "inverse" ) ) ;
346+ return Err ( darling:: Error :: unknown_field (
347+ "inverse not supported for binary functions" ,
348+ ) ) ;
330349 }
331350
332351 let negate_fn = negate. map ( |negate| {
@@ -355,10 +374,10 @@ fn binary_func(
355374 }
356375 } ;
357376
358- let ( output_type, introduces_nulls_fn) = if let Some ( output_type) = output_type {
377+ let ( output_type, mut introduces_nulls_fn) = if let Some ( output_type) = output_type {
359378 let introduces_nulls_fn = quote ! {
360379 fn introduces_nulls( & self ) -> bool {
361- <#output_type as mz_repr:: DatumType <' _, ( ) >>:: nullable( )
380+ <#output_type as :: mz_repr:: DatumType <' _, ( ) >>:: nullable( )
362381 }
363382 } ;
364383 let output_type = quote ! { <#output_type> } ;
@@ -367,6 +386,14 @@ fn binary_func(
367386 ( quote ! { Self :: Output } , None )
368387 } ;
369388
389+ if let Some ( introduces_nulls) = introduces_nulls {
390+ introduces_nulls_fn = Some ( quote ! {
391+ fn introduces_nulls( & self ) -> bool {
392+ #introduces_nulls
393+ }
394+ } ) ;
395+ }
396+
370397 let arena = if arena {
371398 quote ! { , temp_storage }
372399 } else {
0 commit comments