#[non_exhaustive]pub enum Value {
Show 26 variants
Null,
Boolean(bool),
TinyInt(i8),
SmallInt(i16),
Integer(i32),
BigInt(i64),
HugeInt(i128),
UTinyInt(u8),
USmallInt(u16),
UInteger(u32),
UBigInt(u64),
UHugeInt(u128),
Float(f32),
Double(f64),
Decimal {
unscaled: i128,
width: u8,
scale: u8,
},
Varchar(String),
Blob(Vec<u8>),
Date(i32),
Time(i64),
TimeTz(i64),
Timestamp(i64),
TimestampTz(i64),
Interval {
months: i32,
days: i32,
micros: i64,
},
List {
element: LogicalType,
values: Vec<Value>,
},
Struct(Vec<(String, Value)>),
Map {
key: Box<LogicalType>,
value: Box<LogicalType>,
entries: Vec<(Value, Value)>,
},
}Expand description
A single SQL value.
PartialEq here is Rust equality and not SQL equality. Two nulls compare equal and two NaNs
compare equal, both of which SQL disagrees with. That is the right behaviour for a test
assertion and the wrong behaviour for a WHERE clause, and the WHERE clause gets its
comparison from the kernels rather than from here.
Variants (Non-exhaustive)§
This enum is marked as non-exhaustive
Null
NULL, of no particular type.
Boolean(bool)
BOOLEAN.
TinyInt(i8)
TINYINT.
SmallInt(i16)
SMALLINT.
Integer(i32)
INTEGER.
BigInt(i64)
BIGINT.
HugeInt(i128)
HUGEINT.
UTinyInt(u8)
UTINYINT.
USmallInt(u16)
USMALLINT.
UInteger(u32)
UINTEGER.
UBigInt(u64)
UBIGINT.
UHugeInt(u128)
UHUGEINT.
Float(f32)
FLOAT.
Double(f64)
DOUBLE.
Decimal
DECIMAL(width, scale), carrying the unscaled integer.
Fields
Varchar(String)
VARCHAR.
Blob(Vec<u8>)
BLOB.
Date(i32)
DATE, days since 1970-01-01.
Time(i64)
TIME, microseconds since midnight.
TimeTz(i64)
TIME WITH TIME ZONE, microseconds since midnight UTC.
An arm of its own rather than a Value::Time under a type that says the zone, because the
plan holds a constant’s type and its value in two places and checks that the two agree, and
because printing one is not printing the other: a zoned time carries the offset after it.
Timestamp(i64)
TIMESTAMP, microseconds since 1970-01-01 00:00:00.
TimestampTz(i64)
TIMESTAMP WITH TIME ZONE, microseconds since 1970-01-01 00:00:00 UTC.
The same instant a Value::Timestamp holds, and what makes it a different value is what a
reader is entitled to conclude from it. A TIMESTAMP is a wall clock reading with no zone
behind it and this is a point in time, so the one thing this arm knows that the other does
not is which moment it is.
Interval
INTERVAL, the months, days and microseconds triple.
Three fields rather than one duration because interval arithmetic with months is not associative with days, and DuckDB’s specific behaviour is what tests assert on. A month is not 30 days and this representation is what refuses to pretend otherwise.
List
A list, carrying its element type so that an empty list still knows what it is empty of.
Struct(Vec<(String, Value)>)
A struct, in field order.
Map
A map, in insertion order, carrying both of its types so that an empty map still knows what it is empty of.
Pairs rather than a struct per entry, even though that is how a map is stored underneath and how
DuckDB stores one. A Value is what a result is read out as and what a test asserts on, and an
assertion about a map should read as an assertion about a map rather than about a list of two
field structs. The vector is where the other shape lives, and it is the shape that matters for
the bytes.
Order is kept rather than sorted. DuckDB prints a map in the order it was built in and nothing here is entitled to decide that the keys wanted sorting.
The two types are boxed and the list’s one is not, which looks inconsistent and is not. A
LogicalType is 32 bytes and this enum is 64, so a list fits its type and its values in an arm
with room to spare while two types and a vector would need 96 and every BOOLEAN in the system
would get 32 bytes wider to pay for it. LogicalType::Map boxes them for the same reason, so
the boxes here are the ones it already has rather than new ones.
Implementations§
Source§impl Value
impl Value
Sourcepub fn map(
key: LogicalType,
value: LogicalType,
entries: Vec<(Self, Self)>,
) -> Self
pub fn map( key: LogicalType, value: LogicalType, entries: Vec<(Self, Self)>, ) -> Self
A map of these entries, keyed and valued by these types.
Here because Value::Map holds its two types boxed and a caller should not have to say so.
Every other arm of this enum is built as a literal and this one would be too if it were not for
the boxes.
Sourcepub fn footprint(&self) -> usize
pub fn footprint(&self) -> usize
How many bytes this value takes, counting what it owns on the heap.
What the memory limit charges for a value held in a buffer. It is the enum itself plus the string, the blob, the list or the struct behind it, and it counts capacity rather than length, because capacity is what was taken from the allocator and a string built by pushing bytes usually has more of it than it needs.
The enum is as wide as its widest arm whatever is in it, so a BOOLEAN costs the same as a
HUGEINT here. That is not a rounding error, it is the layout: a row of booleans held as
values really does cost that.
Sourcepub fn logical_type(&self) -> LogicalType
pub fn logical_type(&self) -> LogicalType
The type of this value.
Sourcepub fn as_i64(&self) -> Option<i64>
pub fn as_i64(&self) -> Option<i64>
The value as an i64, for the integer types that fit in one.
Used by the planner for the places where a literal has to be a small integer, LIMIT and
OFFSET being the obvious ones. Returns None rather than saturating, because a LIMIT
that silently became i64::MAX is worse than an error.
Source§impl Value
impl Value
Sourcepub fn to_string_at_offset(&self, offset_seconds: i32) -> String
pub fn to_string_at_offset(&self, offset_seconds: i32) -> String
Formats a value in a session offset rather than the UTC fallback used by std::fmt::Display.