Skip to content

Commit 8a043ff

Browse files
author
B Vadlamani
committed
stabby_df_lts
1 parent 0ea49bb commit 8a043ff

2 files changed

Lines changed: 112 additions & 49 deletions

File tree

datafusion/ffi/src/table_provider.rs

Lines changed: 79 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ use datafusion_proto::logical_plan::{
3636
use datafusion_proto::protobuf::LogicalExprList;
3737
use prost::Message;
3838

39-
use stabby::vec::Vec as StabbyVec;
39+
use stabby::vec::Vec as SVec;
4040
use tokio::runtime::Handle;
4141

4242
use super::execution_plan::FFI_ExecutionPlan;
@@ -108,8 +108,8 @@ pub struct FFI_TableProvider {
108108
scan: unsafe extern "C" fn(
109109
provider: &Self,
110110
session: FFI_SessionRef,
111-
projections: FfiOption<StabbyVec<usize>>,
112-
filters_serialized: StabbyVec<u8>,
111+
projections: FfiOption<SVec<usize>>,
112+
filters_serialized: SVec<u8>,
113113
limit: FfiOption<usize>,
114114
) -> FfiFuture<FFIResult<FFI_ExecutionPlan>>,
115115

@@ -122,9 +122,8 @@ pub struct FFI_TableProvider {
122122
supports_filters_pushdown: Option<
123123
unsafe extern "C" fn(
124124
provider: &FFI_TableProvider,
125-
filters_serialized: StabbyVec<u8>,
126-
)
127-
-> FFIResult<StabbyVec<FfiTableProviderFilterPushDown>>,
125+
filters_serialized: SVec<u8>,
126+
) -> FFIResult<SVec<FfiTableProviderFilterPushDown>>,
128127
>,
129128

130129
insert_into: unsafe extern "C" fn(
@@ -191,7 +190,7 @@ fn supports_filters_pushdown_internal(
191190
filters_serialized: &[u8],
192191
task_ctx: &Arc<TaskContext>,
193192
codec: &dyn LogicalExtensionCodec,
194-
) -> Result<StabbyVec<FfiTableProviderFilterPushDown>> {
193+
) -> Result<SVec<FfiTableProviderFilterPushDown>> {
195194
let filters = match filters_serialized.is_empty() {
196195
true => vec![],
197196
false => {
@@ -203,7 +202,7 @@ fn supports_filters_pushdown_internal(
203202
};
204203
let filters_borrowed: Vec<&Expr> = filters.iter().collect();
205204

206-
let results: StabbyVec<_> = provider
205+
let results: SVec<_> = provider
207206
.supports_filters_pushdown(&filters_borrowed)?
208207
.iter()
209208
.map(|v| v.into())
@@ -214,8 +213,8 @@ fn supports_filters_pushdown_internal(
214213

215214
unsafe extern "C" fn supports_filters_pushdown_fn_wrapper(
216215
provider: &FFI_TableProvider,
217-
filters_serialized: StabbyVec<u8>,
218-
) -> FFIResult<StabbyVec<FfiTableProviderFilterPushDown>> {
216+
filters_serialized: SVec<u8>,
217+
) -> FFIResult<SVec<FfiTableProviderFilterPushDown>> {
219218
let logical_codec: Arc<dyn LogicalExtensionCodec> = (&provider.logical_codec).into();
220219
let task_ctx = rresult_return!(<Arc<TaskContext>>::try_from(
221220
&provider.logical_codec.task_ctx_provider
@@ -233,8 +232,8 @@ unsafe extern "C" fn supports_filters_pushdown_fn_wrapper(
233232
unsafe extern "C" fn scan_fn_wrapper(
234233
provider: &FFI_TableProvider,
235234
session: FFI_SessionRef,
236-
projections: FfiOption<StabbyVec<usize>>,
237-
filters_serialized: StabbyVec<u8>,
235+
projections: FfiOption<SVec<usize>>,
236+
filters_serialized: SVec<u8>,
238237
limit: FfiOption<usize>,
239238
) -> FfiFuture<FFIResult<FFI_ExecutionPlan>> {
240239
let task_ctx: Result<Arc<TaskContext>, DataFusionError> =
@@ -270,11 +269,12 @@ unsafe extern "C" fn scan_fn_wrapper(
270269
}
271270
};
272271

273-
let projections: Vec<_> = projections.into_iter().collect();
272+
let projections: Option<Vec<usize>> =
273+
projections.into_option().map(|p| p.into_iter().collect());
274274

275275
let plan = rresult_return!(
276276
internal_provider
277-
.scan(session, Some(&projections), &filters, limit.into())
277+
.scan(session, projections.as_ref(), &filters, limit.into())
278278
.await
279279
);
280280

@@ -391,6 +391,9 @@ impl FFI_TableProvider {
391391
runtime: Option<Handle>,
392392
logical_codec: FFI_LogicalExtensionCodec,
393393
) -> Self {
394+
if let Some(provider) = provider.as_any().downcast_ref::<ForeignTableProvider>() {
395+
return provider.0.clone();
396+
}
394397
let private_data = Box::new(ProviderPrivateData { provider, runtime });
395398

396399
Self {
@@ -462,7 +465,7 @@ impl TableProvider for ForeignTableProvider {
462465
) -> Result<Arc<dyn ExecutionPlan>> {
463466
let session = FFI_SessionRef::new(session, None, self.0.logical_codec.clone());
464467

465-
let projections: FfiOption<StabbyVec<usize>> = projection
468+
let projections: FfiOption<SVec<usize>> = projection
466469
.map(|p| p.iter().map(|v| v.to_owned()).collect())
467470
.into();
468471

@@ -476,7 +479,7 @@ impl TableProvider for ForeignTableProvider {
476479
let maybe_plan = (self.0.scan)(
477480
&self.0,
478481
session,
479-
projections.unwrap_or_default(),
482+
projections,
480483
filters_serialized,
481484
limit.into(),
482485
)
@@ -663,8 +666,9 @@ mod tests {
663666

664667
let provider = Arc::new(MemTable::try_new(schema, vec![vec![batch1]])?);
665668

666-
let ffi_provider =
669+
let mut ffi_provider =
667670
FFI_TableProvider::new(provider, true, None, task_ctx_provider, None);
671+
ffi_provider.library_marker_id = crate::mock_foreign_marker_id;
668672

669673
let foreign_table_provider: Arc<dyn TableProvider> = (&ffi_provider).into();
670674

@@ -717,4 +721,62 @@ mod tests {
717721

718722
Ok(())
719723
}
724+
725+
#[tokio::test]
726+
async fn test_scan_with_none_projection_returns_all_columns() -> Result<()> {
727+
use arrow::datatypes::Field;
728+
use datafusion::arrow::array::Float32Array;
729+
use datafusion::arrow::datatypes::DataType;
730+
use datafusion::arrow::record_batch::RecordBatch;
731+
use datafusion::datasource::MemTable;
732+
use datafusion::physical_plan::collect;
733+
734+
let schema = Arc::new(Schema::new(vec![
735+
Field::new("a", DataType::Float32, false),
736+
Field::new("b", DataType::Float32, false),
737+
Field::new("c", DataType::Float32, false),
738+
]));
739+
740+
let batch = RecordBatch::try_new(
741+
Arc::clone(&schema),
742+
vec![
743+
Arc::new(Float32Array::from(vec![1.0, 2.0])),
744+
Arc::new(Float32Array::from(vec![3.0, 4.0])),
745+
Arc::new(Float32Array::from(vec![5.0, 6.0])),
746+
],
747+
)?;
748+
749+
let provider =
750+
Arc::new(MemTable::try_new(Arc::clone(&schema), vec![vec![batch]])?);
751+
752+
let ctx = Arc::new(SessionContext::new());
753+
let task_ctx_provider = Arc::clone(&ctx) as Arc<dyn TaskContextProvider>;
754+
let task_ctx_provider = FFI_TaskContextProvider::from(&task_ctx_provider);
755+
756+
// Wrap in FFI and force the foreign path (not local bypass)
757+
let mut ffi_provider =
758+
FFI_TableProvider::new(provider, true, None, task_ctx_provider, None);
759+
ffi_provider.library_marker_id = crate::mock_foreign_marker_id;
760+
761+
let foreign_table_provider: Arc<dyn TableProvider> = (&ffi_provider).into();
762+
763+
// Call scan with projection=None, meaning "return all columns"
764+
let plan = foreign_table_provider
765+
.scan(&ctx.state(), None, &[], None)
766+
.await?;
767+
assert_eq!(
768+
plan.schema().fields().len(),
769+
3,
770+
"scan(projection=None) should return all columns; got {}",
771+
plan.schema().fields().len()
772+
);
773+
774+
// Also verify we can execute and get correct data
775+
let batches = collect(plan, ctx.task_ctx()).await?;
776+
assert_eq!(batches.len(), 1);
777+
assert_eq!(batches[0].num_columns(), 3);
778+
assert_eq!(batches[0].num_rows(), 2);
779+
780+
Ok(())
781+
}
720782
}

datafusion/ffi/src/udf/mod.rs

Lines changed: 33 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,12 @@ use return_type_args::{
3535
FFI_ReturnFieldArgs, ForeignReturnFieldArgs, ForeignReturnFieldArgsOwned,
3636
};
3737

38-
use stabby::string::String as StabbyString;
39-
use stabby::vec::Vec as StabbyVec;
38+
use stabby::string::String as SString;
39+
use stabby::vec::Vec as SVec;
4040

4141
use crate::arrow_wrappers::{WrappedArray, WrappedSchema};
42+
use crate::config::FFI_ConfigOptions;
43+
use crate::expr::columnar_value::FFI_ColumnarValue;
4244
use crate::util::{
4345
FFIResult, rvec_wrapped_to_vec_datatype, vec_datatype_to_rvec_wrapped,
4446
};
@@ -52,10 +54,10 @@ pub mod return_type_args;
5254
#[derive(Debug)]
5355
pub struct FFI_ScalarUDF {
5456
/// FFI equivalent to the `name` of a [`ScalarUDF`]
55-
pub name: StabbyString,
57+
pub name: SString,
5658

5759
/// FFI equivalent to the `aliases` of a [`ScalarUDF`]
58-
pub aliases: StabbyVec<StabbyString>,
60+
pub aliases: SVec<SString>,
5961

6062
/// FFI equivalent to the `volatility` of a [`ScalarUDF`]
6163
pub volatility: FfiVolatility,
@@ -70,11 +72,12 @@ pub struct FFI_ScalarUDF {
7072
/// within an AbiStable wrapper.
7173
pub invoke_with_args: unsafe extern "C" fn(
7274
udf: &Self,
73-
args: StabbyVec<WrappedArray>,
74-
arg_fields: StabbyVec<WrappedSchema>,
75+
args: SVec<WrappedArray>,
76+
arg_fields: SVec<WrappedSchema>,
7577
num_rows: usize,
7678
return_field: WrappedSchema,
77-
) -> FFIResult<WrappedArray>,
79+
config_options: FFI_ConfigOptions,
80+
) -> FFIResult<FFI_ColumnarValue>,
7881

7982
/// See [`ScalarUDFImpl`] for details on short_circuits
8083
pub short_circuits: bool,
@@ -85,8 +88,8 @@ pub struct FFI_ScalarUDF {
8588
/// appropriate calls on the underlying [`ScalarUDF`]
8689
pub coerce_types: unsafe extern "C" fn(
8790
udf: &Self,
88-
arg_types: StabbyVec<WrappedSchema>,
89-
) -> FFIResult<StabbyVec<WrappedSchema>>,
91+
arg_types: SVec<WrappedSchema>,
92+
) -> FFIResult<SVec<WrappedSchema>>,
9093

9194
/// Used to create a clone on the provider of the udf. This should
9295
/// only need to be called by the receiver of the udf.
@@ -137,8 +140,8 @@ unsafe extern "C" fn return_field_from_args_fn_wrapper(
137140

138141
unsafe extern "C" fn coerce_types_fn_wrapper(
139142
udf: &FFI_ScalarUDF,
140-
arg_types: StabbyVec<WrappedSchema>,
141-
) -> FFIResult<StabbyVec<WrappedSchema>> {
143+
arg_types: SVec<WrappedSchema>,
144+
) -> FFIResult<SVec<WrappedSchema>> {
142145
let arg_types = rresult_return!(rvec_wrapped_to_vec_datatype(&arg_types));
143146

144147
let arg_fields = arg_types
@@ -156,11 +159,12 @@ unsafe extern "C" fn coerce_types_fn_wrapper(
156159

157160
unsafe extern "C" fn invoke_with_args_fn_wrapper(
158161
udf: &FFI_ScalarUDF,
159-
args: StabbyVec<WrappedArray>,
160-
arg_fields: StabbyVec<WrappedSchema>,
162+
args: SVec<WrappedArray>,
163+
arg_fields: SVec<WrappedSchema>,
161164
number_rows: usize,
162165
return_field: WrappedSchema,
163-
) -> FFIResult<WrappedArray> {
166+
config_options: FFI_ConfigOptions,
167+
) -> FFIResult<FFI_ColumnarValue> {
164168
unsafe {
165169
let args = args
166170
.into_iter()
@@ -182,28 +186,22 @@ unsafe extern "C" fn invoke_with_args_fn_wrapper(
182186
})
183187
.collect::<Result<Vec<FieldRef>>>();
184188
let arg_fields = rresult_return!(arg_fields);
189+
let config_options = rresult_return!(ConfigOptions::try_from(config_options));
190+
let config_options = Arc::new(config_options);
185191

186192
let args = ScalarFunctionArgs {
187193
args,
188194
arg_fields,
189195
number_rows,
190196
return_field,
191-
// TODO: pass config options: https://github.com/apache/datafusion/issues/17035
192-
config_options: Arc::new(ConfigOptions::default()),
197+
config_options,
193198
};
194199

195-
let result = rresult_return!(
200+
rresult!(
196201
udf.inner()
197202
.invoke_with_args(args)
198-
.and_then(|r| r.to_array(number_rows))
199-
);
200-
201-
let (result_array, result_schema) = rresult_return!(to_ffi(&result.to_data()));
202-
203-
RResult::ROk(WrappedArray {
204-
array: result_array,
205-
schema: WrappedSchema(result_schema),
206-
})
203+
.and_then(FFI_ColumnarValue::try_from)
204+
)
207205
}
208206
}
209207

@@ -233,6 +231,10 @@ impl Clone for FFI_ScalarUDF {
233231

234232
impl From<Arc<ScalarUDF>> for FFI_ScalarUDF {
235233
fn from(udf: Arc<ScalarUDF>) -> Self {
234+
if let Some(udf) = udf.inner().as_any().downcast_ref::<ForeignScalarUDF>() {
235+
return udf.udf.clone();
236+
}
237+
236238
let name = udf.name().into();
237239
let aliases = udf.aliases().iter().map(|a| a.to_owned().into()).collect();
238240
let volatility = udf.signature().volatility.into();
@@ -367,8 +369,7 @@ impl ScalarUDFImpl for ForeignScalarUDF {
367369
arg_fields,
368370
number_rows,
369371
return_field,
370-
// TODO: pass config options: https://github.com/apache/datafusion/issues/17035
371-
config_options: _config_options,
372+
config_options,
372373
} = invoke_args;
373374

374375
let args = args
@@ -394,10 +395,11 @@ impl ScalarUDFImpl for ForeignScalarUDF {
394395
let arg_fields = arg_fields_wrapped
395396
.into_iter()
396397
.map(WrappedSchema)
397-
.collect::<StabbyVec<_>>();
398+
.collect::<SVec<_>>();
398399

399400
let return_field = return_field.as_ref().clone();
400401
let return_field = WrappedSchema(FFI_ArrowSchema::try_from(return_field)?);
402+
let config_options = config_options.as_ref().into();
401403

402404
let result = unsafe {
403405
(self.udf.invoke_with_args)(
@@ -406,13 +408,12 @@ impl ScalarUDFImpl for ForeignScalarUDF {
406408
arg_fields,
407409
number_rows,
408410
return_field,
411+
config_options,
409412
)
410413
};
411414

412415
let result = df_result!(result)?;
413-
let result_array: ArrayRef = result.try_into()?;
414-
415-
Ok(ColumnarValue::Array(result_array))
416+
result.try_into()
416417
}
417418

418419
fn aliases(&self) -> &[String] {

0 commit comments

Comments
 (0)