Skip to content

Commit e9e8122

Browse files
Maxxenmatthewgapp
andcommitted
apply scalar function patch
Co-authored-by: Matthew Gapp <[email protected]>
1 parent 1e29fc1 commit e9e8122

File tree

16 files changed

+1317
-101
lines changed

16 files changed

+1317
-101
lines changed

crates/duckdb/Cargo.toml

+2
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,8 @@ default = []
2222
bundled = ["libduckdb-sys/bundled"]
2323
json = ["libduckdb-sys/json", "bundled"]
2424
parquet = ["libduckdb-sys/parquet", "bundled"]
25+
vscalar = []
26+
vscalar-arrow = []
2527
vtab = []
2628
vtab-loadable = ["vtab", "duckdb-loadable-macros"]
2729
vtab-excel = ["vtab", "calamine"]

crates/duckdb/examples/hello-ext-capi/main.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ extern crate libduckdb_sys;
44

55
use duckdb::{
66
core::{DataChunkHandle, Inserter, LogicalTypeHandle, LogicalTypeId},
7-
vtab::{BindInfo, FunctionInfo, InitInfo, VTab},
7+
vtab::{BindInfo, InitInfo, TableFunctionInfo, VTab},
88
Connection, Result,
99
};
1010
use duckdb_loadable_macros::duckdb_entrypoint_c_api;
@@ -43,7 +43,7 @@ impl VTab for HelloVTab {
4343
})
4444
}
4545

46-
fn func(func: &FunctionInfo<Self>, output: &mut DataChunkHandle) -> Result<(), Box<dyn std::error::Error>> {
46+
fn func(func: &TableFunctionInfo<Self>, output: &mut DataChunkHandle) -> Result<(), Box<dyn std::error::Error>> {
4747
let init_data = func.get_init_data();
4848
let bind_data = func.get_bind_data();
4949
if init_data.done.swap(true, Ordering::Relaxed) {

crates/duckdb/examples/hello-ext/main.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ extern crate libduckdb_sys;
66

77
use duckdb::{
88
core::{DataChunkHandle, Inserter, LogicalTypeHandle, LogicalTypeId},
9-
vtab::{BindInfo, FunctionInfo, InitInfo, VTab},
9+
vtab::{BindInfo, InitInfo, TableFunctionInfo, VTab},
1010
Connection, Result,
1111
};
1212
use duckdb_loadable_macros::duckdb_entrypoint;
@@ -43,7 +43,7 @@ impl VTab for HelloVTab {
4343
})
4444
}
4545

46-
fn func(func: &FunctionInfo<Self>, output: &mut DataChunkHandle) -> Result<(), Box<dyn std::error::Error>> {
46+
fn func(func: &TableFunctionInfo<Self>, output: &mut DataChunkHandle) -> Result<(), Box<dyn std::error::Error>> {
4747
let init_data = func.get_init_data();
4848
let bind_data = func.get_bind_data();
4949
if init_data.done.swap(true, Ordering::Relaxed) {

crates/duckdb/src/core/vector.rs

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
use std::{any::Any, ffi::CString, slice};
22

3-
use libduckdb_sys::{duckdb_array_type_array_size, duckdb_array_vector_get_child, DuckDbString};
3+
use libduckdb_sys::{
4+
duckdb_array_type_array_size, duckdb_array_vector_get_child, duckdb_validity_row_is_valid, DuckDbString,
5+
};
46

57
use super::LogicalTypeHandle;
68
use crate::ffi::{
@@ -55,6 +57,24 @@ impl FlatVector {
5557
self.capacity
5658
}
5759

60+
/// Returns true if the row at the given index is null
61+
pub fn row_is_null(&self, row: u64) -> bool {
62+
// use idx_t entry_idx = row_idx / 64; idx_t idx_in_entry = row_idx % 64; bool is_valid = validity_mask[entry_idx] & (1 « idx_in_entry);
63+
// as the row is valid function is slower
64+
let valid = unsafe {
65+
let validity = duckdb_vector_get_validity(self.ptr);
66+
67+
// validity can return a NULL pointer if the entire vector is valid
68+
if validity.is_null() {
69+
return false;
70+
}
71+
72+
duckdb_validity_row_is_valid(validity, row)
73+
};
74+
75+
!valid
76+
}
77+
5878
/// Returns an unsafe mutable pointer to the vector’s
5979
pub fn as_mut_ptr<T>(&self) -> *mut T {
6080
unsafe { duckdb_vector_get_data(self.ptr).cast() }
@@ -65,11 +85,21 @@ impl FlatVector {
6585
unsafe { slice::from_raw_parts(self.as_mut_ptr(), self.capacity()) }
6686
}
6787

88+
/// Returns a slice of the vector up to a certain length
89+
pub fn as_slice_with_len<T>(&self, len: usize) -> &[T] {
90+
unsafe { slice::from_raw_parts(self.as_mut_ptr(), len) }
91+
}
92+
6893
/// Returns a mutable slice of the vector
6994
pub fn as_mut_slice<T>(&mut self) -> &mut [T] {
7095
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), self.capacity()) }
7196
}
7297

98+
/// Returns a mutable slice of the vector up to a certain length
99+
pub fn as_mut_slice_with_len<T>(&mut self, len: usize) -> &mut [T] {
100+
unsafe { slice::from_raw_parts_mut(self.as_mut_ptr(), len) }
101+
}
102+
73103
/// Returns the logical type of the vector
74104
pub fn logical_type(&self) -> LogicalTypeHandle {
75105
unsafe { LogicalTypeHandle::new(duckdb_vector_get_column_type(self.ptr)) }

crates/duckdb/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,10 @@ pub mod types;
126126
#[cfg(feature = "vtab")]
127127
pub mod vtab;
128128

129+
/// The duckdb table function interface
130+
#[cfg(feature = "vscalar")]
131+
pub mod vscalar;
132+
129133
#[cfg(test)]
130134
mod test_all_types;
131135

crates/duckdb/src/r2d2.rs

+17-1
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,9 @@
4040
//! .unwrap()
4141
//! }
4242
//! ```
43-
use crate::{Config, Connection, Error, Result};
43+
use crate::{vscalar::VScalar, vtab::VTab, Config, Connection, Error, Result};
4444
use std::{
45+
fmt::Debug,
4546
path::Path,
4647
sync::{Arc, Mutex},
4748
};
@@ -78,6 +79,21 @@ impl DuckdbConnectionManager {
7879
connection: Arc::new(Mutex::new(Connection::open_in_memory_with_flags(config)?)),
7980
})
8081
}
82+
83+
/// Register a table function.
84+
pub fn register_table_function<T: VTab>(&self, name: &str) -> Result<()> {
85+
let conn = self.connection.lock().unwrap();
86+
conn.register_table_function::<T>(name)
87+
}
88+
89+
/// Register a scalar function.
90+
pub fn register_scalar<S: VScalar>(&self, name: &str) -> Result<()>
91+
where
92+
S::State: Debug,
93+
{
94+
let conn = self.connection.lock().unwrap();
95+
conn.register_scalar_function::<S>(name)
96+
}
8197
}
8298

8399
impl r2d2::ManageConnection for DuckdbConnectionManager {

crates/duckdb/src/raw_statement.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ impl RawStatement {
8181

8282
#[inline]
8383
pub fn step(&self) -> Option<StructArray> {
84-
self.result?;
84+
let out = self.result?;
8585
unsafe {
8686
let mut arrays = FFI_ArrowArray::empty();
8787
if ffi::duckdb_query_arrow_array(
88-
self.result_unwrap(),
88+
out,
8989
&mut std::ptr::addr_of_mut!(arrays) as *mut _ as *mut ffi::duckdb_arrow_array,
9090
)
9191
.ne(&ffi::DuckDBSuccess)
@@ -99,7 +99,7 @@ impl RawStatement {
9999

100100
let mut schema = FFI_ArrowSchema::empty();
101101
if ffi::duckdb_query_arrow_schema(
102-
self.result_unwrap(),
102+
out,
103103
&mut std::ptr::addr_of_mut!(schema) as *mut _ as *mut ffi::duckdb_arrow_schema,
104104
) != ffi::DuckDBSuccess
105105
{
@@ -260,6 +260,7 @@ impl RawStatement {
260260
unsafe {
261261
let mut out: ffi::duckdb_arrow = ptr::null_mut();
262262
let rc = ffi::duckdb_execute_prepared_arrow(self.ptr, &mut out);
263+
println!("error code: {}", rc);
263264
result_from_duckdb_arrow(rc, out)?;
264265

265266
let rows_changed = ffi::duckdb_arrow_rows_changed(out);

crates/duckdb/src/types/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
pub use self::{
66
from_sql::{FromSql, FromSqlError, FromSqlResult},
77
ordered_map::OrderedMap,
8+
string::DuckString,
89
to_sql::{ToSql, ToSqlOutput},
910
value::Value,
1011
value_ref::{EnumType, ListType, TimeUnit, ValueRef},
@@ -25,6 +26,7 @@ mod value;
2526
mod value_ref;
2627

2728
mod ordered_map;
29+
mod string;
2830

2931
/// Empty struct that can be used to fill in a query parameter as `NULL`.
3032
///

crates/duckdb/src/types/string.rs

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use libduckdb_sys::{duckdb_string_t, duckdb_string_t_data, duckdb_string_t_length};
2+
3+
/// Wrapper for underlying duck string type with a lifetime bound to a &mut duckdb_string_t
4+
pub struct DuckString<'a> {
5+
ptr: &'a mut duckdb_string_t,
6+
}
7+
8+
impl<'a> DuckString<'a> {
9+
pub(crate) fn new(ptr: &'a mut duckdb_string_t) -> Self {
10+
DuckString { ptr }
11+
}
12+
}
13+
14+
impl<'a> DuckString<'a> {
15+
/// convert duckdb_string_t to a copy on write string
16+
pub fn as_str(&mut self) -> std::borrow::Cow<'a, str> {
17+
String::from_utf8_lossy(self.as_bytes())
18+
}
19+
20+
/// convert duckdb_string_t to a byte slice
21+
pub fn as_bytes(&mut self) -> &'a [u8] {
22+
unsafe {
23+
let len = duckdb_string_t_length(*self.ptr);
24+
let c_ptr = duckdb_string_t_data(self.ptr);
25+
std::slice::from_raw_parts(c_ptr as *const u8, len as usize)
26+
}
27+
}
28+
}

0 commit comments

Comments
 (0)