Type System

quack-rs describes DuckDB column types with two types: TypeId, a plain enum of DuckDB's type ids, and LogicalType, an owned handle for full type descriptions such as DECIMAL(18, 3), LIST(VARCHAR) or a STRUCT. This page also maps each DuckDB type to its Rust type and vector read/write methods.


TypeId

TypeId is an 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). The list below names the variants; it is a listing, not compilable code:

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
TypeId::Any
TypeId::Varint           // SQL name BIGNUM (VARINT before DuckDB 1.4)
TypeId::SqlNull
TypeId::IntegerLiteral
TypeId::StringLiteral
TypeId::Geometry         // duckdb-1-5-3
TypeId::Variant          // duckdb-1-5-3

TypeId implements Copy, Clone, Debug, PartialEq, Eq, Hash and Display.

SQL name

#![allow(unused)]
fn main() {
use quack_rs::types::TypeId;
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. It panics if the value does not match any known constant; TypeId::try_from_duckdb_type(raw) returns None instead.

#![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 an RAII wrapper around DuckDB's duckdb_logical_type. Creating one calls into DuckDB, so this block is compiled but not run:

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

For a type a TypeId fully describes, pass the TypeId to a builder's param or returns method; the builder creates and destroys the LogicalType internally. For a parameterized type (DECIMAL, LIST, MAP, STRUCT, UNION, ENUM, ARRAY), build a LogicalType and pass it to param_logical or returns_logical.

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

Every constructor except from_raw panics on invalid input (for example a composite TypeId passed to new, or a DECIMAL width outside 1–38) and has a try_* counterpart (try_new, try_decimal, try_struct_type, …) that returns Result<LogicalType, LogicalTypeError> instead. UNION types accept at most MAX_UNION_MEMBERS (255) members.

Introspection methods

All introspection methods are unsafe: they call into DuckDB, so the handle must be valid and the C API initialized.

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. The most common types:

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
HUGEINTHugeIntread_i128write_i128
UHUGEINTUHugeIntread_u128write_u128
VARCHARVarcharread_strwrite_varchar
BLOBBlobread_blobwrite_blob
UUIDUuidread_uuidwrite_uuid
DATEDateread_datewrite_date
TIMETimeread_timewrite_time
TIMESTAMPTimestampread_timestampwrite_timestamp
INTERVALIntervalread_intervalwrite_interval

The timestamp variants (TIMESTAMP_S, _MS, _NS, TIMESTAMPTZ), TIMETZ and DECIMAL have matching read_*/write_* methods as well.

NULLs are handled separately — see NULL Handling & Strings.