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}