Type System

quack-rs provides TypeId and LogicalType to bridge Rust types and DuckDB column types.


TypeId

TypeId is an ergonomic enum covering DuckDB's column types (the GEOMETRY and VARIANT types added in DuckDB 1.5.x are exposed behind the duckdb-1-5-3 feature — see Known Limitations):

#![allow(unused)]
fn main() {
use quack_rs::types::TypeId;

TypeId::Boolean
TypeId::TinyInt     // i8
TypeId::SmallInt    // i16
TypeId::Integer     // i32
TypeId::BigInt      // i64
TypeId::UTinyInt    // u8
TypeId::USmallInt   // u16
TypeId::UInteger    // u32
TypeId::UBigInt     // u64
TypeId::HugeInt     // i128
TypeId::UHugeInt    // u128
TypeId::Float       // f32
TypeId::Double      // f64
TypeId::Timestamp
TypeId::TimestampTz
TypeId::TimestampS
TypeId::TimestampMs
TypeId::TimestampNs
TypeId::Date
TypeId::Time
TypeId::TimeTz
TypeId::Interval
TypeId::Varchar
TypeId::Blob
TypeId::Decimal
TypeId::Enum
TypeId::List
TypeId::Struct
TypeId::Map
TypeId::Uuid
TypeId::Union
TypeId::Bit
TypeId::Array
TypeId::TimeNs      // duckdb-1-5
TypeId::Any              // duckdb-1-5
TypeId::Varint           // duckdb-1-5
TypeId::SqlNull          // duckdb-1-5
TypeId::IntegerLiteral   // duckdb-1-5
TypeId::StringLiteral    // duckdb-1-5
TypeId::Geometry         // duckdb-1-5-3
TypeId::Variant          // duckdb-1-5-3
}

TypeId is Copy, Clone, Debug, PartialEq, Eq, and Display.

SQL name

#![allow(unused)]
fn main() {
assert_eq!(TypeId::BigInt.sql_name(), "BIGINT");
assert_eq!(TypeId::Varchar.sql_name(), "VARCHAR");
assert_eq!(format!("{}", TypeId::Timestamp), "TIMESTAMP");
}

DuckDB constant

TypeId::to_duckdb_type() returns the DUCKDB_TYPE_* integer constant from libduckdb-sys. You rarely need this directly — it's called internally by LogicalType::new.

Reverse conversion

TypeId::from_duckdb_type(raw) converts a raw DUCKDB_TYPE constant back into a TypeId. Panics if the value does not match any known constant.

#![allow(unused)]
fn main() {
use quack_rs::types::TypeId;

let type_id = TypeId::from_duckdb_type(libduckdb_sys::DUCKDB_TYPE_DUCKDB_TYPE_BIGINT);
assert_eq!(type_id, TypeId::BigInt);
}

LogicalType

LogicalType is a RAII wrapper around DuckDB's duckdb_logical_type. It is used internally by the function builders.

#![allow(unused)]
fn main() {
use quack_rs::types::{LogicalType, TypeId};

let lt = LogicalType::new(TypeId::Varchar);
// lt.as_raw() returns the duckdb_logical_type pointer
// Drop calls duckdb_destroy_logical_type automatically
}

Pitfall L7: duckdb_create_logical_type allocates memory that must be freed with duckdb_destroy_logical_type. LogicalType's Drop implementation does this automatically, preventing the memory leak that occurs when calling the DuckDB C API directly. See Pitfall L7.

You almost never need to create LogicalType directly. The function builders (ScalarFunctionBuilder, AggregateFunctionBuilder) create and destroy them internally.

Constructors

ConstructorCreates
LogicalType::new(type_id)Simple type from a TypeId
LogicalType::from_raw(ptr)Takes ownership of a raw duckdb_logical_type handle (unsafe)
LogicalType::decimal(width, scale)DECIMAL(width, scale)
LogicalType::list(element_type)LIST<element_type> from a TypeId
LogicalType::list_from_logical(element)LIST<element> from an existing LogicalType
LogicalType::map(key, value)MAP<key, value> from TypeIds
LogicalType::map_from_logical(key, value)MAP<key, value> from existing LogicalTypes
LogicalType::struct_type(fields)STRUCT from &[(&str, TypeId)]
LogicalType::struct_type_from_logical(fields)STRUCT from &[(&str, LogicalType)]
LogicalType::union_type(members)UNION from &[(&str, TypeId)]
LogicalType::union_type_from_logical(members)UNION from &[(&str, LogicalType)]
LogicalType::enum_type(members)ENUM from &[&str]
LogicalType::array(element_type, size)ARRAY<element_type>[size] from a TypeId
LogicalType::array_from_logical(element, size)ARRAY<element>[size] from an existing LogicalType

Introspection methods

All introspection methods are unsafe (require a valid DuckDB runtime handle).

MethodReturnsApplicable to
get_type_id()TypeIdAny
get_alias()Option<String>Any
set_alias(alias)()Any
decimal_width()u8DECIMAL
decimal_scale()u8DECIMAL
decimal_internal_type()TypeIdDECIMAL
enum_internal_type()TypeIdENUM
enum_dictionary_size()u32ENUM
enum_dictionary_value(index)StringENUM
list_child_type()LogicalTypeLIST
map_key_type()LogicalTypeMAP
map_value_type()LogicalTypeMAP
struct_child_count()u64STRUCT
struct_child_name(index)StringSTRUCT
struct_child_type(index)LogicalTypeSTRUCT
union_member_count()u64UNION
union_member_name(index)StringUNION
union_member_type(index)LogicalTypeUNION
array_size()u64ARRAY
array_child_type()LogicalTypeARRAY

Rust type ↔ DuckDB type mapping

When reading from or writing to vectors, use the corresponding VectorReader/VectorWriter method:

DuckDB typeTypeIdReader methodWriter method
BOOLEANBooleanread_boolwrite_bool
TINYINTTinyIntread_i8write_i8
SMALLINTSmallIntread_i16write_i16
INTEGERIntegerread_i32write_i32
BIGINTBigIntread_i64write_i64
UTINYINTUTinyIntread_u8write_u8
USMALLINTUSmallIntread_u16write_u16
UINTEGERUIntegerread_u32write_u32
UBIGINTUBigIntread_u64write_u64
FLOATFloatread_f32write_f32
DOUBLEDoubleread_f64write_f64
VARCHARVarcharread_strwrite_varchar
INTERVALIntervalread_intervalwrite_interval

NULLs are handled separately — see NULL Handling & Strings.