Skip to main content

query_planning/expr/
literal.rs

1//! Typed scalar literal IR.
2//!
3//! SQL nulls carry an explicit [`DataType`] in [`LiteralValue::Null`] because
4//! they have no value to infer a type from. Decimal, date, timestamp,
5//! duration, and interval literals use Arrow-compatible raw encodings;
6//! whether a literal is supported in a given expression context is decided
7//! during expression lowering. This module does not make that decision.
8
9use std::fmt;
10
11use arrow::datatypes::{DataType, IntervalUnit, TimeUnit};
12
13/// Typed scalar literal in native expression IR; nulls carry an explicit [`DataType`].
14///
15/// [`Self::data_type`] is total: every variant names one Arrow type, so
16/// validation types a literal without a schema. `PartialEq` only, because
17/// `Float32` and `Float64` carry NaN; two literals that compare equal have the
18/// same type and the same non-NaN value.
19#[derive(Debug, Clone, PartialEq)]
20pub enum LiteralValue {
21    /// Boolean scalar.
22    Boolean(bool),
23    /// Signed 8-bit integer scalar.
24    Int8(i8),
25    /// Signed 16-bit integer scalar.
26    Int16(i16),
27    /// Signed 32-bit integer scalar.
28    Int32(i32),
29    /// Signed 64-bit integer scalar.
30    Int64(i64),
31    /// Unsigned 8-bit integer scalar.
32    UInt8(u8),
33    /// Unsigned 16-bit integer scalar.
34    UInt16(u16),
35    /// Unsigned 32-bit integer scalar.
36    UInt32(u32),
37    /// Unsigned 64-bit integer scalar.
38    UInt64(u64),
39    /// 32-bit floating-point scalar.
40    Float32(f32),
41    /// 64-bit floating-point scalar.
42    Float64(f64),
43    /// UTF-8 string scalar with Arrow `Utf8` type.
44    Utf8(String),
45    /// UTF-8 string scalar with Arrow `LargeUtf8` type.
46    LargeUtf8(String),
47    /// Arrow `Decimal128` scalar.
48    ///
49    /// `raw` is the unscaled integer payload. `precision` and `scale` are the
50    /// Arrow decimal metadata; the mathematical value is `raw * 10^-scale`.
51    Decimal128 {
52        /// Unscaled 128-bit decimal payload.
53        raw: i128,
54        /// Maximum number of significant decimal digits.
55        precision: u8,
56        /// Decimal scale in Arrow's representation.
57        scale: i8,
58    },
59    /// Arrow `Date32` scalar, encoded as days since the Unix epoch.
60    Date32(i32),
61    /// Arrow `Date64` scalar, encoded as milliseconds since the Unix epoch.
62    Date64(i64),
63    /// Arrow `Time32` scalar.
64    ///
65    /// `raw` is the count of `unit` intervals since midnight.
66    Time32 {
67        /// Time-of-day value in the given unit.
68        raw: i32,
69        /// Time resolution. Arrow permits only seconds and milliseconds.
70        unit: TimeUnit,
71    },
72    /// Arrow `Time64` scalar.
73    ///
74    /// `raw` is the count of `unit` intervals since midnight.
75    Time64 {
76        /// Time-of-day value in the given unit.
77        raw: i64,
78        /// Time resolution. Arrow permits only microseconds and nanoseconds.
79        unit: TimeUnit,
80    },
81    /// Arrow timestamp scalar without a timezone.
82    ///
83    /// `raw` is the count of `unit` intervals since the Unix epoch.
84    Timestamp {
85        /// Epoch-relative timestamp value in the given unit.
86        raw: i64,
87        /// Timestamp resolution.
88        unit: TimeUnit,
89    },
90    /// Arrow duration scalar.
91    ///
92    /// `raw` is the count of `unit` intervals.
93    Duration {
94        /// Duration value in the given unit.
95        raw: i64,
96        /// Duration resolution.
97        unit: TimeUnit,
98    },
99    /// Arrow `Interval(MonthDayNano)` scalar.
100    IntervalMonthDayNano {
101        /// Month component.
102        months: i32,
103        /// Day component.
104        days: i32,
105        /// Nanosecond component.
106        nanoseconds: i64,
107    },
108    /// Typed SQL null literal.
109    Null(DataType),
110}
111
112impl LiteralValue {
113    /// Return the Arrow data type represented by this literal.
114    pub fn data_type(&self) -> DataType {
115        match self {
116            Self::Boolean(_) => DataType::Boolean,
117            Self::Int8(_) => DataType::Int8,
118            Self::Int16(_) => DataType::Int16,
119            Self::Int32(_) => DataType::Int32,
120            Self::Int64(_) => DataType::Int64,
121            Self::UInt8(_) => DataType::UInt8,
122            Self::UInt16(_) => DataType::UInt16,
123            Self::UInt32(_) => DataType::UInt32,
124            Self::UInt64(_) => DataType::UInt64,
125            Self::Float32(_) => DataType::Float32,
126            Self::Float64(_) => DataType::Float64,
127            Self::Utf8(_) => DataType::Utf8,
128            Self::LargeUtf8(_) => DataType::LargeUtf8,
129            Self::Decimal128 { precision, scale, .. } => DataType::Decimal128(*precision, *scale),
130            Self::Date32(_) => DataType::Date32,
131            Self::Date64(_) => DataType::Date64,
132            Self::Time32 { unit, .. } => DataType::Time32(*unit),
133            Self::Time64 { unit, .. } => DataType::Time64(*unit),
134            Self::Timestamp { unit, .. } => DataType::Timestamp(*unit, None),
135            Self::Duration { unit, .. } => DataType::Duration(*unit),
136            Self::IntervalMonthDayNano { .. } => DataType::Interval(IntervalUnit::MonthDayNano),
137            Self::Null(data_type) => data_type.clone(),
138        }
139    }
140
141    /// Zero of an integer type, or `None` for any other type. Count merging
142    /// uses it to read a merged global count's null as zero.
143    pub(crate) fn integer_zero(data_type: &DataType) -> Option<Self> {
144        match data_type {
145            DataType::Int8 => Some(Self::Int8(0)),
146            DataType::Int16 => Some(Self::Int16(0)),
147            DataType::Int32 => Some(Self::Int32(0)),
148            DataType::Int64 => Some(Self::Int64(0)),
149            DataType::UInt8 => Some(Self::UInt8(0)),
150            DataType::UInt16 => Some(Self::UInt16(0)),
151            DataType::UInt32 => Some(Self::UInt32(0)),
152            DataType::UInt64 => Some(Self::UInt64(0)),
153            _ => None,
154        }
155    }
156}
157
158impl fmt::Display for LiteralValue {
159    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
160        match self {
161            Self::Boolean(value) => write!(f, "{value}"),
162            Self::Int8(value) => write!(f, "{value}"),
163            Self::Int16(value) => write!(f, "{value}"),
164            Self::Int32(value) => write!(f, "{value}"),
165            Self::Int64(value) => write!(f, "{value}"),
166            Self::UInt8(value) => write!(f, "{value}"),
167            Self::UInt16(value) => write!(f, "{value}"),
168            Self::UInt32(value) => write!(f, "{value}"),
169            Self::UInt64(value) => write!(f, "{value}"),
170            Self::Float32(value) => write!(f, "{value}"),
171            Self::Float64(value) => write!(f, "{value}"),
172            Self::Utf8(value) | Self::LargeUtf8(value) => write!(f, "{value:?}"),
173            Self::Decimal128 { raw, precision, scale } => {
174                write!(f, "DECIMAL128({raw}, precision={precision}, scale={scale})")
175            },
176            Self::Date32(value) => write!(f, "DATE32({value})"),
177            Self::Date64(value) => write!(f, "DATE64({value})"),
178            Self::Time32 { raw, unit } => write!(f, "TIME32({raw}, {unit:?})"),
179            Self::Time64 { raw, unit } => write!(f, "TIME64({raw}, {unit:?})"),
180            Self::Timestamp { raw, unit } => write!(f, "TIMESTAMP({raw}, {unit:?})"),
181            Self::Duration { raw, unit } => write!(f, "DURATION({raw}, {unit:?})"),
182            Self::IntervalMonthDayNano { months, days, nanoseconds } => {
183                write!(f, "INTERVAL(months={months}, days={days}, nanoseconds={nanoseconds})")
184            },
185            Self::Null(data_type) => write!(f, "NULL::{data_type}"),
186        }
187    }
188}