Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions crates/duckdb/src/vtab/value.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::ffi::{duckdb_destroy_value, duckdb_free, duckdb_get_int64, duckdb_get_varchar, duckdb_value};
use crate::core::LogicalTypeHandle;
use crate::ffi::{duckdb_destroy_value, duckdb_free, duckdb_get_int64, duckdb_get_value_type, duckdb_get_varchar, duckdb_value};
use std::{ffi::CStr, fmt, os::raw::c_void};

/// The Value object holds a single arbitrary value of any type that can be
Expand Down Expand Up @@ -30,6 +31,15 @@ impl Value {
pub fn to_int64(&self) -> i64 {
unsafe { duckdb_get_int64(self.ptr) }
}

/// Returns a LogicalTypeHandle representing the type of this value.
pub fn logical_type(&self) -> LogicalTypeHandle {
// SAFETY: The returned LogicalTypeHandle frees allocated memory when dropped.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not true. duckdb_get_value_type returns a borrowed pointer to internal memory owned by the Value, not a new allocation. The C API docs say: "The type itself must not be destroyed". But LogicalTypeHandle::Drop calls duckdb_destroy_logical_type, causing double-free/corruption when dropped. I suggest returning an owned copy.

Alternatively, if sufficient, implement logical_type_id and return LogicalTypeId, which doesn't have this ownership problem.

unsafe {
let lt_handle = duckdb_get_value_type(self.ptr);
LogicalTypeHandle { ptr: lt_handle }
}
}
}

impl fmt::Display for Value {
Expand All @@ -47,7 +57,7 @@ impl fmt::Display for Value {
#[cfg(test)]
mod tests {
use super::*;
use crate::ffi::duckdb_create_varchar;
use crate::ffi::{duckdb_create_varchar, DUCKDB_TYPE_DUCKDB_TYPE_VARCHAR};
use std::ffi::CString;

#[test]
Expand All @@ -57,4 +67,13 @@ mod tests {
let val = Value::from(duckdb_val);
assert_eq!(val.to_string(), "some value");
}

#[test]
fn test_logical_type() {
let c_str = CString::new("some value").unwrap();
let duckdb_val = unsafe { duckdb_create_varchar(c_str.as_ptr()) };
let val = Value::from(duckdb_val);
let logical_type = val.logical_type();
assert_eq!(logical_type.raw_id(), DUCKDB_TYPE_DUCKDB_TYPE_VARCHAR);
}
}