Type System

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


TypeId

TypeId is an ergonomic enum covering all DuckDB column types:

#![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 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.