@@ -9,8 +9,9 @@ mod logical_type;
9
9
mod value;
10
10
mod vector;
11
11
12
+ /// The duckdb Arrow table function interface
12
13
#[ cfg( feature = "vtab-arrow" ) ]
13
- mod arrow;
14
+ pub mod arrow;
14
15
#[ cfg( feature = "vtab-arrow" ) ]
15
16
pub use self :: arrow:: {
16
17
arrow_arraydata_to_query_params, arrow_ffi_to_query_params, arrow_recordbatch_to_query_params,
@@ -66,11 +67,45 @@ pub trait VTab: Sized {
66
67
type BindData : Sized + Free ;
67
68
68
69
/// Bind data to the table function
69
- fn bind ( bind : & BindInfo , data : * mut Self :: BindData ) -> Result < ( ) , Box < dyn std:: error:: Error > > ;
70
+ ///
71
+ /// # Safety
72
+ ///
73
+ /// This function is unsafe because it dereferences raw pointers (`data`) and manipulates the memory directly.
74
+ /// The caller must ensure that:
75
+ ///
76
+ /// - The `data` pointer is valid and points to a properly initialized `BindData` instance.
77
+ /// - The lifetime of `data` must outlive the execution of `bind` to avoid dangling pointers, especially since
78
+ /// `bind` does not take ownership of `data`.
79
+ /// - Concurrent access to `data` (if applicable) must be properly synchronized.
80
+ /// - The `bind` object must be valid and correctly initialized.
81
+ unsafe fn bind ( bind : & BindInfo , data : * mut Self :: BindData ) -> Result < ( ) , Box < dyn std:: error:: Error > > ;
70
82
/// Initialize the table function
71
- fn init ( init : & InitInfo , data : * mut Self :: InitData ) -> Result < ( ) , Box < dyn std:: error:: Error > > ;
83
+ ///
84
+ /// # Safety
85
+ ///
86
+ /// This function is unsafe because it performs raw pointer dereferencing on the `data` argument.
87
+ /// The caller is responsible for ensuring that:
88
+ ///
89
+ /// - The `data` pointer is non-null and points to a valid `InitData` instance.
90
+ /// - There is no data race when accessing `data`, meaning if `data` is accessed from multiple threads,
91
+ /// proper synchronization is required.
92
+ /// - The lifetime of `data` extends beyond the scope of this call to avoid use-after-free errors.
93
+ unsafe fn init ( init : & InitInfo , data : * mut Self :: InitData ) -> Result < ( ) , Box < dyn std:: error:: Error > > ;
72
94
/// The actual function
73
- fn func ( func : & FunctionInfo , output : & mut DataChunk ) -> Result < ( ) , Box < dyn std:: error:: Error > > ;
95
+ ///
96
+ /// # Safety
97
+ ///
98
+ /// This function is unsafe because it:
99
+ ///
100
+ /// - Dereferences multiple raw pointers (`func` to access `init_info` and `bind_info`).
101
+ ///
102
+ /// The caller must ensure that:
103
+ ///
104
+ /// - All pointers (`func`, `output`, internal `init_info`, and `bind_info`) are valid and point to the expected types of data structures.
105
+ /// - The `init_info` and `bind_info` data pointed to remains valid and is not freed until after this function completes.
106
+ /// - No other threads are concurrently mutating the data pointed to by `init_info` and `bind_info` without proper synchronization.
107
+ /// - The `output` parameter is correctly initialized and can safely be written to.
108
+ unsafe fn func ( func : & FunctionInfo , output : & mut DataChunk ) -> Result < ( ) , Box < dyn std:: error:: Error > > ;
74
109
/// Does the table function support pushdown
75
110
/// default is false
76
111
fn supports_pushdown ( ) -> bool {
@@ -197,7 +232,7 @@ mod test {
197
232
type InitData = HelloInitData ;
198
233
type BindData = HelloBindData ;
199
234
200
- fn bind ( bind : & BindInfo , data : * mut HelloBindData ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
235
+ unsafe fn bind ( bind : & BindInfo , data : * mut HelloBindData ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
201
236
bind. add_result_column ( "column0" , LogicalType :: new ( LogicalTypeId :: Varchar ) ) ;
202
237
let param = bind. get_parameter ( 0 ) . to_string ( ) ;
203
238
unsafe {
@@ -206,14 +241,14 @@ mod test {
206
241
Ok ( ( ) )
207
242
}
208
243
209
- fn init ( _: & InitInfo , data : * mut HelloInitData ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
244
+ unsafe fn init ( _: & InitInfo , data : * mut HelloInitData ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
210
245
unsafe {
211
246
( * data) . done = false ;
212
247
}
213
248
Ok ( ( ) )
214
249
}
215
250
216
- fn func ( func : & FunctionInfo , output : & mut DataChunk ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
251
+ unsafe fn func ( func : & FunctionInfo , output : & mut DataChunk ) -> Result < ( ) , Box < dyn std:: error:: Error > > {
217
252
let init_info = func. get_init_data :: < HelloInitData > ( ) ;
218
253
let bind_info = func. get_bind_data :: < HelloBindData > ( ) ;
219
254
@@ -244,7 +279,7 @@ mod test {
244
279
type InitData = HelloInitData ;
245
280
type BindData = HelloBindData ;
246
281
247
- fn bind ( bind : & BindInfo , data : * mut HelloBindData ) -> Result < ( ) , Box < dyn Error > > {
282
+ unsafe fn bind ( bind : & BindInfo , data : * mut HelloBindData ) -> Result < ( ) , Box < dyn Error > > {
248
283
bind. add_result_column ( "column0" , LogicalType :: new ( LogicalTypeId :: Varchar ) ) ;
249
284
let param = bind. get_named_parameter ( "name" ) . unwrap ( ) . to_string ( ) ;
250
285
assert ! ( bind. get_named_parameter( "unknown_name" ) . is_none( ) ) ;
@@ -254,11 +289,11 @@ mod test {
254
289
Ok ( ( ) )
255
290
}
256
291
257
- fn init ( init_info : & InitInfo , data : * mut HelloInitData ) -> Result < ( ) , Box < dyn Error > > {
292
+ unsafe fn init ( init_info : & InitInfo , data : * mut HelloInitData ) -> Result < ( ) , Box < dyn Error > > {
258
293
HelloVTab :: init ( init_info, data)
259
294
}
260
295
261
- fn func ( func : & FunctionInfo , output : & mut DataChunk ) -> Result < ( ) , Box < dyn Error > > {
296
+ unsafe fn func ( func : & FunctionInfo , output : & mut DataChunk ) -> Result < ( ) , Box < dyn Error > > {
262
297
HelloVTab :: func ( func, output)
263
298
}
264
299
0 commit comments