1use std::ffi::c_void;
19use std::hash::{Hash, Hasher};
20use std::sync::Arc;
21
22use arrow::array::Array;
23use arrow::datatypes::{DataType, Field};
24use arrow::error::ArrowError;
25use arrow::ffi::{FFI_ArrowSchema, from_ffi, to_ffi};
26use arrow_schema::FieldRef;
27use datafusion_common::config::ConfigOptions;
28use datafusion_common::{DataFusionError, Result, internal_err};
29use datafusion_expr::type_coercion::functions::fields_with_udf;
30use datafusion_expr::{
31 ColumnarValue, ReturnFieldArgs, ScalarFunctionArgs, ScalarUDF, ScalarUDFImpl,
32 Signature,
33};
34use return_type_args::{
35 FFI_ReturnFieldArgs, ForeignReturnFieldArgs, ForeignReturnFieldArgsOwned,
36};
37
38use stabby::string::String as SString;
39use stabby::vec::Vec as SVec;
40
41use crate::arrow_wrappers::{WrappedArray, WrappedSchema};
42use crate::config::FFI_ConfigOptions;
43use crate::expr::columnar_value::FFI_ColumnarValue;
44use crate::util::{
45 FFI_Result, rvec_wrapped_to_vec_datatype, vec_datatype_to_rvec_wrapped,
46};
47use crate::volatility::FFI_Volatility;
48use crate::{df_result, sresult, sresult_return};
49
50pub mod return_type_args;
51
52#[repr(C)]
54#[derive(Debug)]
55pub struct FFI_ScalarUDF {
56 pub name: SString,
58
59 pub aliases: SVec<SString>,
61
62 pub volatility: FFI_Volatility,
64
65 pub return_field_from_args: unsafe extern "C" fn(
67 udf: &Self,
68 args: FFI_ReturnFieldArgs,
69 ) -> FFI_Result<WrappedSchema>,
70
71 pub invoke_with_args: unsafe extern "C" fn(
74 udf: &Self,
75 args: SVec<WrappedArray>,
76 arg_fields: SVec<WrappedSchema>,
77 num_rows: usize,
78 return_field: WrappedSchema,
79 config_options: FFI_ConfigOptions,
80 ) -> FFI_Result<FFI_ColumnarValue>,
81
82 pub short_circuits: bool,
84
85 pub coerce_types: unsafe extern "C" fn(
90 udf: &Self,
91 arg_types: SVec<WrappedSchema>,
92 ) -> FFI_Result<SVec<WrappedSchema>>,
93
94 pub clone: unsafe extern "C" fn(udf: &Self) -> Self,
97
98 pub release: unsafe extern "C" fn(udf: &mut Self),
100
101 pub private_data: *mut c_void,
104
105 pub library_marker_id: extern "C" fn() -> usize,
109}
110
111unsafe impl Send for FFI_ScalarUDF {}
112unsafe impl Sync for FFI_ScalarUDF {}
113
114pub struct ScalarUDFPrivateData {
115 pub udf: Arc<ScalarUDF>,
116}
117
118impl FFI_ScalarUDF {
119 fn inner(&self) -> &Arc<ScalarUDF> {
120 let private_data = self.private_data as *const ScalarUDFPrivateData;
121 unsafe { &(*private_data).udf }
122 }
123}
124
125unsafe extern "C" fn return_field_from_args_fn_wrapper(
126 udf: &FFI_ScalarUDF,
127 args: FFI_ReturnFieldArgs,
128) -> FFI_Result<WrappedSchema> {
129 let args: ForeignReturnFieldArgsOwned = sresult_return!((&args).try_into());
130 let args_ref: ForeignReturnFieldArgs = (&args).into();
131
132 let return_type = udf
133 .inner()
134 .return_field_from_args((&args_ref).into())
135 .and_then(|f| FFI_ArrowSchema::try_from(&f).map_err(DataFusionError::from))
136 .map(WrappedSchema);
137
138 sresult!(return_type)
139}
140
141unsafe extern "C" fn coerce_types_fn_wrapper(
142 udf: &FFI_ScalarUDF,
143 arg_types: SVec<WrappedSchema>,
144) -> FFI_Result<SVec<WrappedSchema>> {
145 let arg_types = sresult_return!(rvec_wrapped_to_vec_datatype(&arg_types));
146
147 let arg_fields = arg_types
148 .iter()
149 .map(|dt| Arc::new(Field::new("f", dt.clone(), true)))
150 .collect::<Vec<_>>();
151 let return_types =
152 sresult_return!(fields_with_udf(&arg_fields, udf.inner().as_ref()))
153 .into_iter()
154 .map(|f| f.data_type().to_owned())
155 .collect::<Vec<_>>();
156
157 sresult!(vec_datatype_to_rvec_wrapped(&return_types))
158}
159
160unsafe extern "C" fn invoke_with_args_fn_wrapper(
161 udf: &FFI_ScalarUDF,
162 args: SVec<WrappedArray>,
163 arg_fields: SVec<WrappedSchema>,
164 number_rows: usize,
165 return_field: WrappedSchema,
166 config_options: FFI_ConfigOptions,
167) -> FFI_Result<FFI_ColumnarValue> {
168 unsafe {
169 let args = args
170 .into_iter()
171 .map(|arr| {
172 from_ffi(arr.array, &arr.schema.0)
173 .map(|v| ColumnarValue::Array(arrow::array::make_array(v)))
174 })
175 .collect::<std::result::Result<_, _>>();
176
177 let args = sresult_return!(args);
178 let return_field = sresult_return!(Field::try_from(&return_field.0)).into();
179
180 let arg_fields = arg_fields
181 .into_iter()
182 .map(|wrapped_field| {
183 Field::try_from(&wrapped_field.0)
184 .map(Arc::new)
185 .map_err(DataFusionError::from)
186 })
187 .collect::<Result<Vec<FieldRef>>>();
188 let arg_fields = sresult_return!(arg_fields);
189 let config_options = sresult_return!(ConfigOptions::try_from(config_options));
190 let config_options = Arc::new(config_options);
191
192 let args = ScalarFunctionArgs {
193 args,
194 arg_fields,
195 number_rows,
196 return_field,
197 config_options,
198 };
199
200 sresult!(
201 udf.inner()
202 .invoke_with_args(args)
203 .and_then(FFI_ColumnarValue::try_from)
204 )
205 }
206}
207
208unsafe extern "C" fn release_fn_wrapper(udf: &mut FFI_ScalarUDF) {
209 unsafe {
210 debug_assert!(!udf.private_data.is_null());
211 let private_data = Box::from_raw(udf.private_data as *mut ScalarUDFPrivateData);
212 drop(private_data);
213 udf.private_data = std::ptr::null_mut();
214 }
215}
216
217unsafe extern "C" fn clone_fn_wrapper(udf: &FFI_ScalarUDF) -> FFI_ScalarUDF {
218 unsafe {
219 let private_data = udf.private_data as *const ScalarUDFPrivateData;
220 let udf_data = &(*private_data);
221
222 Arc::clone(&udf_data.udf).into()
223 }
224}
225
226impl Clone for FFI_ScalarUDF {
227 fn clone(&self) -> Self {
228 unsafe { (self.clone)(self) }
229 }
230}
231
232impl From<Arc<ScalarUDF>> for FFI_ScalarUDF {
233 fn from(udf: Arc<ScalarUDF>) -> Self {
234 if let Some(udf) = udf.inner().downcast_ref::<ForeignScalarUDF>() {
235 return udf.udf.clone();
236 }
237
238 let name = udf.name().into();
239 let aliases = udf.aliases().iter().map(|a| a.to_owned().into()).collect();
240 let volatility = udf.signature().volatility.into();
241 let short_circuits = udf.short_circuits();
242
243 let private_data = Box::new(ScalarUDFPrivateData { udf });
244
245 Self {
246 name,
247 aliases,
248 volatility,
249 short_circuits,
250 invoke_with_args: invoke_with_args_fn_wrapper,
251 return_field_from_args: return_field_from_args_fn_wrapper,
252 coerce_types: coerce_types_fn_wrapper,
253 clone: clone_fn_wrapper,
254 release: release_fn_wrapper,
255 private_data: Box::into_raw(private_data) as *mut c_void,
256 library_marker_id: crate::get_library_marker_id,
257 }
258 }
259}
260
261impl Drop for FFI_ScalarUDF {
262 fn drop(&mut self) {
263 unsafe { (self.release)(self) }
264 }
265}
266
267#[derive(Debug)]
274pub struct ForeignScalarUDF {
275 name: String,
276 aliases: Vec<String>,
277 udf: FFI_ScalarUDF,
278 signature: Signature,
279}
280
281unsafe impl Send for ForeignScalarUDF {}
282unsafe impl Sync for ForeignScalarUDF {}
283
284impl PartialEq for ForeignScalarUDF {
285 fn eq(&self, other: &Self) -> bool {
286 let Self {
287 name,
288 aliases,
289 udf,
290 signature,
291 } = self;
292 name == &other.name
293 && aliases == &other.aliases
294 && std::ptr::eq(udf, &other.udf)
295 && signature == &other.signature
296 }
297}
298impl Eq for ForeignScalarUDF {}
299
300impl Hash for ForeignScalarUDF {
301 fn hash<H: Hasher>(&self, state: &mut H) {
302 let Self {
303 name,
304 aliases,
305 udf,
306 signature,
307 } = self;
308 name.hash(state);
309 aliases.hash(state);
310 std::ptr::hash(udf, state);
311 signature.hash(state);
312 }
313}
314
315impl From<&FFI_ScalarUDF> for Arc<dyn ScalarUDFImpl> {
316 fn from(udf: &FFI_ScalarUDF) -> Self {
317 if (udf.library_marker_id)() == crate::get_library_marker_id() {
318 Arc::clone(udf.inner().inner())
319 } else {
320 let name = udf.name.to_string();
321 let signature = Signature::user_defined((&udf.volatility).into());
322
323 let aliases = udf.aliases.iter().map(|s| s.to_string()).collect();
324
325 Arc::new(ForeignScalarUDF {
326 name,
327 udf: udf.clone(),
328 aliases,
329 signature,
330 })
331 }
332 }
333}
334
335impl ScalarUDFImpl for ForeignScalarUDF {
336 fn name(&self) -> &str {
337 &self.name
338 }
339
340 fn signature(&self) -> &Signature {
341 &self.signature
342 }
343
344 fn return_type(&self, _arg_types: &[DataType]) -> Result<DataType> {
345 internal_err!("ForeignScalarUDF implements return_field_from_args instead.")
346 }
347
348 fn return_field_from_args(&self, args: ReturnFieldArgs) -> Result<FieldRef> {
349 let args: FFI_ReturnFieldArgs = args.try_into()?;
350
351 let result = unsafe { (self.udf.return_field_from_args)(&self.udf, args) };
352
353 let result = df_result!(result);
354
355 result.and_then(|r| {
356 Field::try_from(&r.0)
357 .map(Arc::new)
358 .map_err(DataFusionError::from)
359 })
360 }
361
362 fn invoke_with_args(&self, invoke_args: ScalarFunctionArgs) -> Result<ColumnarValue> {
363 let ScalarFunctionArgs {
364 args,
365 arg_fields,
366 number_rows,
367 return_field,
368 config_options,
369 } = invoke_args;
370
371 let args = args
372 .into_iter()
373 .map(|v| v.to_array(number_rows))
374 .collect::<Result<Vec<_>>>()?
375 .into_iter()
376 .map(|v| {
377 to_ffi(&v.to_data()).map(|(ffi_array, ffi_schema)| WrappedArray {
378 array: ffi_array,
379 schema: WrappedSchema(ffi_schema),
380 })
381 })
382 .collect::<std::result::Result<Vec<_>, ArrowError>>()?
383 .into_iter()
384 .collect();
385
386 let arg_fields_wrapped = arg_fields
387 .iter()
388 .map(FFI_ArrowSchema::try_from)
389 .collect::<std::result::Result<Vec<_>, ArrowError>>()?;
390
391 let arg_fields = arg_fields_wrapped
392 .into_iter()
393 .map(WrappedSchema)
394 .collect::<SVec<_>>();
395
396 let return_field = Arc::unwrap_or_clone(return_field);
397 let return_field = WrappedSchema(FFI_ArrowSchema::try_from(return_field)?);
398 let config_options = config_options.as_ref().into();
399
400 let result = unsafe {
401 (self.udf.invoke_with_args)(
402 &self.udf,
403 args,
404 arg_fields,
405 number_rows,
406 return_field,
407 config_options,
408 )
409 };
410
411 let result = df_result!(result)?;
412 result.try_into()
413 }
414
415 fn aliases(&self) -> &[String] {
416 &self.aliases
417 }
418
419 fn short_circuits(&self) -> bool {
420 self.udf.short_circuits
421 }
422
423 fn coerce_types(&self, arg_types: &[DataType]) -> Result<Vec<DataType>> {
424 unsafe {
425 let arg_types = vec_datatype_to_rvec_wrapped(arg_types)?;
426 let result_types = df_result!((self.udf.coerce_types)(&self.udf, arg_types))?;
427 Ok(rvec_wrapped_to_vec_datatype(&result_types)?)
428 }
429 }
430}
431
432#[cfg(test)]
433mod tests {
434 use super::*;
435
436 #[test]
437 fn test_round_trip_scalar_udf() -> Result<()> {
438 let original_udf = datafusion::functions::math::abs::AbsFunc::new();
439 let original_udf = Arc::new(ScalarUDF::from(original_udf));
440
441 let mut local_udf: FFI_ScalarUDF = Arc::clone(&original_udf).into();
442 local_udf.library_marker_id = crate::mock_foreign_marker_id;
443
444 let foreign_udf: Arc<dyn ScalarUDFImpl> = (&local_udf).into();
445
446 assert_eq!(original_udf.name(), foreign_udf.name());
447
448 Ok(())
449 }
450
451 #[test]
452 fn test_ffi_udf_local_bypass() -> Result<()> {
453 use datafusion::functions::math::abs::AbsFunc;
454 let original_udf = AbsFunc::new();
455 let original_udf = Arc::new(ScalarUDF::from(original_udf));
456
457 let mut ffi_udf = FFI_ScalarUDF::from(original_udf);
458
459 let foreign_udf: Arc<dyn ScalarUDFImpl> = (&ffi_udf).into();
461 assert!(foreign_udf.is::<AbsFunc>());
462
463 ffi_udf.library_marker_id = crate::mock_foreign_marker_id;
465 let foreign_udf: Arc<dyn ScalarUDFImpl> = (&ffi_udf).into();
466 assert!(foreign_udf.is::<ForeignScalarUDF>());
467
468 Ok(())
469 }
470}