proof_of_sql/base/database/
column.rs

1use super::{LiteralValue, OwnedColumn, TableRef};
2use crate::base::{
3    math::decimal::Precision,
4    posql_time::{PoSQLTimeUnit, PoSQLTimeZone},
5    scalar::{Scalar, ScalarExt},
6    slice_ops::slice_cast_with,
7};
8use alloc::vec::Vec;
9use bumpalo::Bump;
10use core::{
11    fmt,
12    fmt::{Display, Formatter},
13    mem::size_of,
14};
15use serde::{Deserialize, Serialize};
16use sqlparser::ast::Ident;
17
18/// Represents a read-only view of a column in an in-memory,
19/// column-oriented database.
20///
21/// Note: The types here should correspond to native SQL database types.
22/// See `<https://ignite.apache.org/docs/latest/sql-reference/data-types>` for
23/// a description of the native types used by Apache Ignite.
24#[derive(Debug, Eq, PartialEq, Clone, Copy)]
25#[non_exhaustive]
26pub enum Column<'a, S: Scalar> {
27    /// Boolean columns
28    Boolean(&'a [bool]),
29    /// u8 columns
30    Uint8(&'a [u8]),
31    /// i8 columns
32    TinyInt(&'a [i8]),
33    /// i16 columns
34    SmallInt(&'a [i16]),
35    /// i32 columns
36    Int(&'a [i32]),
37    /// i64 columns
38    BigInt(&'a [i64]),
39    /// i128 columns
40    Int128(&'a [i128]),
41    /// Decimal columns with a max width of 252 bits
42    ///  - the backing store maps to the type `S`
43    Decimal75(Precision, i8, &'a [S]),
44    /// Scalar columns
45    Scalar(&'a [S]),
46    /// String columns
47    ///  - the first element maps to the str values.
48    ///  - the second element maps to the str hashes (see [`crate::base::scalar::Scalar`]).
49    VarChar((&'a [&'a str], &'a [S])),
50    /// Timestamp columns with timezone
51    /// - the first element maps to the stored `TimeUnit`
52    /// - the second element maps to a timezone
53    /// - the third element maps to columns of timeunits since unix epoch
54    TimestampTZ(PoSQLTimeUnit, PoSQLTimeZone, &'a [i64]),
55    /// Variable length binary columns
56    VarBinary((&'a [&'a [u8]], &'a [S])),
57}
58
59impl<'a, S: Scalar> Column<'a, S> {
60    /// Provides the column type associated with the column
61    #[must_use]
62    pub fn column_type(&self) -> ColumnType {
63        match self {
64            Self::Boolean(_) => ColumnType::Boolean,
65            Self::Uint8(_) => ColumnType::Uint8,
66            Self::TinyInt(_) => ColumnType::TinyInt,
67            Self::SmallInt(_) => ColumnType::SmallInt,
68            Self::Int(_) => ColumnType::Int,
69            Self::BigInt(_) => ColumnType::BigInt,
70            Self::VarChar(_) => ColumnType::VarChar,
71            Self::Int128(_) => ColumnType::Int128,
72            Self::Scalar(_) => ColumnType::Scalar,
73            Self::Decimal75(precision, scale, _) => ColumnType::Decimal75(*precision, *scale),
74            Self::TimestampTZ(time_unit, timezone, _) => {
75                ColumnType::TimestampTZ(*time_unit, *timezone)
76            }
77            Self::VarBinary(..) => ColumnType::VarBinary,
78        }
79    }
80    /// Returns the length of the column.
81    /// # Panics
82    /// this function requires that `col` and `scals` have the same length.
83    #[must_use]
84    pub fn len(&self) -> usize {
85        match self {
86            Self::Boolean(col) => col.len(),
87            Self::Uint8(col) => col.len(),
88            Self::TinyInt(col) => col.len(),
89            Self::SmallInt(col) => col.len(),
90            Self::Int(col) => col.len(),
91            Self::BigInt(col) | Self::TimestampTZ(_, _, col) => col.len(),
92            Self::VarChar((col, scals)) => {
93                assert_eq!(col.len(), scals.len());
94                col.len()
95            }
96            Self::VarBinary((col, scals)) => {
97                assert_eq!(col.len(), scals.len());
98                col.len()
99            }
100            Self::Int128(col) => col.len(),
101            Self::Scalar(col) | Self::Decimal75(_, _, col) => col.len(),
102        }
103    }
104    /// Returns `true` if the column has no elements.
105    #[must_use]
106    pub fn is_empty(&self) -> bool {
107        self.len() == 0
108    }
109
110    /// Generate a constant column from a literal value with a given length
111    pub fn from_literal_with_length(
112        literal: &LiteralValue,
113        length: usize,
114        alloc: &'a Bump,
115    ) -> Self {
116        match literal {
117            LiteralValue::Boolean(value) => {
118                Column::Boolean(alloc.alloc_slice_fill_copy(length, *value))
119            }
120            LiteralValue::Uint8(value) => {
121                Column::Uint8(alloc.alloc_slice_fill_copy(length, *value))
122            }
123            LiteralValue::TinyInt(value) => {
124                Column::TinyInt(alloc.alloc_slice_fill_copy(length, *value))
125            }
126            LiteralValue::SmallInt(value) => {
127                Column::SmallInt(alloc.alloc_slice_fill_copy(length, *value))
128            }
129            LiteralValue::Int(value) => Column::Int(alloc.alloc_slice_fill_copy(length, *value)),
130            LiteralValue::BigInt(value) => {
131                Column::BigInt(alloc.alloc_slice_fill_copy(length, *value))
132            }
133            LiteralValue::Int128(value) => {
134                Column::Int128(alloc.alloc_slice_fill_copy(length, *value))
135            }
136            LiteralValue::Scalar(value) => {
137                Column::Scalar(alloc.alloc_slice_fill_copy(length, (*value).into()))
138            }
139            LiteralValue::Decimal75(precision, scale, value) => Column::Decimal75(
140                *precision,
141                *scale,
142                alloc.alloc_slice_fill_copy(length, value.into_scalar()),
143            ),
144            LiteralValue::TimeStampTZ(tu, tz, value) => {
145                Column::TimestampTZ(*tu, *tz, alloc.alloc_slice_fill_copy(length, *value))
146            }
147            LiteralValue::VarChar(string) => Column::VarChar((
148                alloc.alloc_slice_fill_with(length, |_| alloc.alloc_str(string) as &str),
149                alloc.alloc_slice_fill_copy(length, S::from(string)),
150            )),
151            LiteralValue::VarBinary(bytes) => {
152                // Convert the bytes to a slice of bytes references
153                let bytes_slice = alloc
154                    .alloc_slice_fill_with(length, |_| alloc.alloc_slice_copy(bytes) as &[_]);
155
156                // Convert the bytes to scalars using from_byte_slice_via_hash
157                let scalars =
158                    alloc.alloc_slice_fill_copy(length, S::from_byte_slice_via_hash(bytes));
159
160                Column::VarBinary((bytes_slice, scalars))
161            }
162        }
163    }
164
165    /// Generate a `Int128` `rho` column [0, 1, 2, ..., length - 1]
166    pub fn rho(length: usize, alloc: &'a Bump) -> Self {
167        let raw_rho = (0..length as i128).collect::<Vec<_>>();
168        let rho = alloc.alloc_slice_copy(raw_rho.as_slice());
169        Column::<S>::Int128(rho as &[_])
170    }
171
172    /// Convert an `OwnedColumn` to a `Column`
173    pub fn from_owned_column(owned_column: &'a OwnedColumn<S>, alloc: &'a Bump) -> Self {
174        match owned_column {
175            OwnedColumn::Boolean(col) => Column::Boolean(col.as_slice()),
176            OwnedColumn::Uint8(col) => Column::Uint8(col.as_slice()),
177            OwnedColumn::TinyInt(col) => Column::TinyInt(col.as_slice()),
178            OwnedColumn::SmallInt(col) => Column::SmallInt(col.as_slice()),
179            OwnedColumn::Int(col) => Column::Int(col.as_slice()),
180            OwnedColumn::BigInt(col) => Column::BigInt(col.as_slice()),
181            OwnedColumn::Int128(col) => Column::Int128(col.as_slice()),
182            OwnedColumn::Decimal75(precision, scale, col) => {
183                Column::Decimal75(*precision, *scale, col.as_slice())
184            }
185            OwnedColumn::Scalar(col) => Column::Scalar(col.as_slice()),
186            OwnedColumn::VarChar(col) => {
187                let scalars = col.iter().map(S::from).collect::<Vec<_>>();
188                let strs = col
189                    .iter()
190                    .map(|s| s.as_str() as &'a str)
191                    .collect::<Vec<_>>();
192                Column::VarChar((
193                    alloc.alloc_slice_clone(strs.as_slice()),
194                    alloc.alloc_slice_copy(scalars.as_slice()),
195                ))
196            }
197            OwnedColumn::VarBinary(col) => {
198                let scalars = col
199                    .iter()
200                    .map(|b| S::from_byte_slice_via_hash(b))
201                    .collect::<Vec<_>>();
202                let bytes = col.iter().map(|s| s as &'a [u8]).collect::<Vec<_>>();
203                Column::VarBinary((
204                    alloc.alloc_slice_clone(&bytes),
205                    alloc.alloc_slice_copy(scalars.as_slice()),
206                ))
207            }
208            OwnedColumn::TimestampTZ(tu, tz, col) => Column::TimestampTZ(*tu, *tz, col.as_slice()),
209        }
210    }
211
212    /// Returns the column as a slice of booleans if it is a boolean column. Otherwise, returns None.
213    pub(crate) fn as_boolean(&self) -> Option<&'a [bool]> {
214        match self {
215            Self::Boolean(col) => Some(col),
216            _ => None,
217        }
218    }
219
220    /// Returns the column as a slice of u8 if it is a uint8 column. Otherwise, returns None.
221    pub(crate) fn as_uint8(&self) -> Option<&'a [u8]> {
222        match self {
223            Self::Uint8(col) => Some(col),
224            _ => None,
225        }
226    }
227
228    /// Returns the column as a slice of i8 if it is a tinyint column. Otherwise, returns None.
229    pub(crate) fn as_tinyint(&self) -> Option<&'a [i8]> {
230        match self {
231            Self::TinyInt(col) => Some(col),
232            _ => None,
233        }
234    }
235
236    /// Returns the column as a slice of i16 if it is a smallint column. Otherwise, returns None.
237    pub(crate) fn as_smallint(&self) -> Option<&'a [i16]> {
238        match self {
239            Self::SmallInt(col) => Some(col),
240            _ => None,
241        }
242    }
243
244    /// Returns the column as a slice of i32 if it is an int column. Otherwise, returns None.
245    pub(crate) fn as_int(&self) -> Option<&'a [i32]> {
246        match self {
247            Self::Int(col) => Some(col),
248            _ => None,
249        }
250    }
251
252    /// Returns the column as a slice of i64 if it is a bigint column. Otherwise, returns None.
253    pub(crate) fn as_bigint(&self) -> Option<&'a [i64]> {
254        match self {
255            Self::BigInt(col) => Some(col),
256            _ => None,
257        }
258    }
259
260    /// Returns the column as a slice of i128 if it is an int128 column. Otherwise, returns None.
261    pub(crate) fn as_int128(&self) -> Option<&'a [i128]> {
262        match self {
263            Self::Int128(col) => Some(col),
264            _ => None,
265        }
266    }
267
268    /// Returns the column as a slice of scalars if it is a scalar column. Otherwise, returns None.
269    pub(crate) fn as_scalar(&self) -> Option<&'a [S]> {
270        match self {
271            Self::Scalar(col) => Some(col),
272            _ => None,
273        }
274    }
275
276    /// Returns the column as a slice of scalars if it is a decimal75 column. Otherwise, returns None.
277    pub(crate) fn as_decimal75(&self) -> Option<&'a [S]> {
278        match self {
279            Self::Decimal75(_, _, col) => Some(col),
280            _ => None,
281        }
282    }
283
284    /// Returns the column as a slice of strings and a slice of scalars if it is a varchar column. Otherwise, returns None.
285    pub(crate) fn as_varchar(&self) -> Option<(&'a [&'a str], &'a [S])> {
286        match self {
287            Self::VarChar((col, scals)) => Some((col, scals)),
288            _ => None,
289        }
290    }
291
292    /// Returns the column as a slice of strings and a slice of scalars if it is a varchar column. Otherwise, returns None.
293    pub(crate) fn as_varbinary(&self) -> Option<(&'a [&'a [u8]], &'a [S])> {
294        match self {
295            Self::VarBinary((col, scals)) => Some((col, scals)),
296            _ => None,
297        }
298    }
299
300    /// Returns the column as a slice of i64 if it is a timestamp column. Otherwise, returns None.
301    pub(crate) fn as_timestamptz(&self) -> Option<&'a [i64]> {
302        match self {
303            Self::TimestampTZ(_, _, col) => Some(col),
304            _ => None,
305        }
306    }
307
308    /// Returns element at index as scalar
309    ///
310    /// Note that if index is out of bounds, this function will return None
311    pub(crate) fn scalar_at(&self, index: usize) -> Option<S> {
312        (index < self.len()).then_some(match self {
313            Self::Boolean(col) => S::from(col[index]),
314            Self::Uint8(col) => S::from(col[index]),
315            Self::TinyInt(col) => S::from(col[index]),
316            Self::SmallInt(col) => S::from(col[index]),
317            Self::Int(col) => S::from(col[index]),
318            Self::BigInt(col) | Self::TimestampTZ(_, _, col) => S::from(col[index]),
319            Self::Int128(col) => S::from(col[index]),
320            Self::Scalar(col) | Self::Decimal75(_, _, col) => col[index],
321            Self::VarChar((_, scals)) | Self::VarBinary((_, scals)) => scals[index],
322        })
323    }
324
325    /// Convert a column to a vector of Scalar values with scaling
326    #[expect(clippy::missing_panics_doc)]
327    pub(crate) fn to_scalar_with_scaling(self, scale: i8) -> Vec<S> {
328        let scale_factor = S::pow10(u8::try_from(scale).expect("Upscale factor is nonnegative"));
329        match self {
330            Self::Boolean(col) => slice_cast_with(col, |b| S::from(b) * scale_factor),
331            Self::Decimal75(_, _, col) => slice_cast_with(col, |s| *s * scale_factor),
332            Self::VarChar((_, values)) => slice_cast_with(values, |s| *s * scale_factor),
333            Self::VarBinary((_, values)) => slice_cast_with(values, |s| *s * scale_factor),
334            Self::Uint8(col) => slice_cast_with(col, |i| S::from(i) * scale_factor),
335            Self::TinyInt(col) => slice_cast_with(col, |i| S::from(i) * scale_factor),
336            Self::SmallInt(col) => slice_cast_with(col, |i| S::from(i) * scale_factor),
337            Self::Int(col) => slice_cast_with(col, |i| S::from(i) * scale_factor),
338            Self::BigInt(col) => slice_cast_with(col, |i| S::from(i) * scale_factor),
339            Self::Int128(col) => slice_cast_with(col, |i| S::from(i) * scale_factor),
340            Self::Scalar(col) => slice_cast_with(col, |i| S::from(i) * scale_factor),
341            Self::TimestampTZ(_, _, col) => slice_cast_with(col, |i| S::from(i) * scale_factor),
342        }
343    }
344}
345
346/// Represents the supported data types of a column in an in-memory,
347/// column-oriented database.
348///
349/// See `<https://ignite.apache.org/docs/latest/sql-reference/data-types>` for
350/// a description of the native types used by Apache Ignite.
351#[derive(Eq, PartialEq, Debug, Clone, Hash, Serialize, Deserialize, Copy)]
352#[cfg_attr(test, derive(proptest_derive::Arbitrary))]
353pub enum ColumnType {
354    /// Mapped to bool
355    #[serde(alias = "BOOLEAN", alias = "boolean")]
356    Boolean,
357    /// Mapped to u8
358    #[serde(alias = "UINT8", alias = "uint8")]
359    Uint8,
360    /// Mapped to i8
361    #[serde(alias = "TINYINT", alias = "tinyint")]
362    TinyInt,
363    /// Mapped to i16
364    #[serde(alias = "SMALLINT", alias = "smallint")]
365    SmallInt,
366    /// Mapped to i32
367    #[serde(alias = "INT", alias = "int")]
368    Int,
369    /// Mapped to i64
370    #[serde(alias = "BIGINT", alias = "bigint")]
371    BigInt,
372    /// Mapped to i128
373    #[serde(rename = "Decimal", alias = "DECIMAL", alias = "decimal")]
374    Int128,
375    /// Mapped to String
376    #[serde(alias = "VARCHAR", alias = "varchar")]
377    VarChar,
378    /// Mapped to i256
379    #[serde(rename = "Decimal75", alias = "DECIMAL75", alias = "decimal75")]
380    Decimal75(Precision, i8),
381    /// Mapped to i64
382    #[serde(alias = "TIMESTAMP", alias = "timestamp")]
383    #[cfg_attr(test, proptest(skip))]
384    TimestampTZ(PoSQLTimeUnit, PoSQLTimeZone),
385    /// Mapped to `S`
386    #[serde(alias = "SCALAR", alias = "scalar")]
387    #[cfg_attr(test, proptest(skip))]
388    Scalar,
389    /// Mapped to [u8]
390    #[serde(alias = "BINARY", alias = "BINARY")]
391    VarBinary,
392}
393
394impl ColumnType {
395    /// Returns true if this column is numeric and false otherwise
396    #[must_use]
397    pub fn is_numeric(&self) -> bool {
398        matches!(
399            self,
400            ColumnType::Uint8
401                | ColumnType::TinyInt
402                | ColumnType::SmallInt
403                | ColumnType::Int
404                | ColumnType::BigInt
405                | ColumnType::Int128
406                | ColumnType::Scalar
407                | ColumnType::Decimal75(_, _)
408        )
409    }
410
411    /// Returns true if this column is an integer and false otherwise
412    #[must_use]
413    pub fn is_integer(&self) -> bool {
414        matches!(
415            self,
416            ColumnType::Uint8
417                | ColumnType::TinyInt
418                | ColumnType::SmallInt
419                | ColumnType::Int
420                | ColumnType::BigInt
421                | ColumnType::Int128
422        )
423    }
424
425    /// Returns the floor of the sqrt of the negative min integer.
426    /// Returns `None` if the type is not a signed integer.
427    /// `sqrt_negative_min(NumericalType) = floor(sqrt(-NumericalType::MIN))`
428    #[must_use]
429    #[cfg_attr(not(test), expect(dead_code))]
430    #[expect(clippy::trivially_copy_pass_by_ref)]
431    fn sqrt_negative_min(&self) -> Option<u64> {
432        match self {
433            ColumnType::TinyInt => Some(11),
434            ColumnType::SmallInt => Some(181),
435            ColumnType::Int => Some(46_340),
436            ColumnType::BigInt => Some(3_037_000_499),
437            ColumnType::Int128 => Some(13_043_817_825_332_782_212),
438            _ => None,
439        }
440    }
441
442    /// Returns the number of bits in the integer type if it is an integer type. Otherwise, return None.
443    fn to_integer_bits(self) -> Option<usize> {
444        match self {
445            ColumnType::Uint8 | ColumnType::TinyInt => Some(8),
446            ColumnType::SmallInt => Some(16),
447            ColumnType::Int => Some(32),
448            ColumnType::BigInt => Some(64),
449            ColumnType::Int128 => Some(128),
450            _ => None,
451        }
452    }
453
454    /// Returns the [`ColumnType`] of the signed integer type with the given number of bits if it is a valid integer type.
455    ///
456    /// Otherwise, return None.
457    fn from_signed_integer_bits(bits: usize) -> Option<Self> {
458        match bits {
459            8 => Some(ColumnType::TinyInt),
460            16 => Some(ColumnType::SmallInt),
461            32 => Some(ColumnType::Int),
462            64 => Some(ColumnType::BigInt),
463            128 => Some(ColumnType::Int128),
464            _ => None,
465        }
466    }
467
468    /// Returns the [`ColumnType`] of the unsigned integer type with the given number of bits if it is a valid integer type.
469    ///
470    /// Otherwise, return None.
471    fn from_unsigned_integer_bits(bits: usize) -> Option<Self> {
472        match bits {
473            8 => Some(ColumnType::Uint8),
474            _ => None,
475        }
476    }
477
478    /// Returns the larger integer type of two [`ColumnType`]s if they are both integers.
479    ///
480    /// If either of the columns is not an integer, return None.
481    #[must_use]
482    pub fn max_integer_type(&self, other: &Self) -> Option<Self> {
483        // If either of the columns is not an integer, return None
484        if !self.is_integer() || !other.is_integer() {
485            return None;
486        }
487        self.to_integer_bits().and_then(|self_bits| {
488            other
489                .to_integer_bits()
490                .and_then(|other_bits| Self::from_signed_integer_bits(self_bits.max(other_bits)))
491        })
492    }
493
494    /// Returns the larger integer type of two [`ColumnType`]s if they are both integers.
495    ///
496    /// If either of the columns is not an integer, return None.
497    #[must_use]
498    pub fn max_unsigned_integer_type(&self, other: &Self) -> Option<Self> {
499        // If either of the columns is not an integer, return None
500        if !self.is_integer() || !other.is_integer() {
501            return None;
502        }
503        self.to_integer_bits().and_then(|self_bits| {
504            other
505                .to_integer_bits()
506                .and_then(|other_bits| Self::from_unsigned_integer_bits(self_bits.max(other_bits)))
507        })
508    }
509
510    /// Returns the precision of a [`ColumnType`] if it is converted to a decimal wrapped in `Some()`. If it can not be converted to a decimal, return None.
511    #[must_use]
512    pub fn precision_value(&self) -> Option<u8> {
513        match self {
514            Self::Uint8 | Self::TinyInt => Some(3_u8),
515            Self::SmallInt => Some(5_u8),
516            Self::Int => Some(10_u8),
517            Self::BigInt | Self::TimestampTZ(_, _) => Some(19_u8),
518            Self::Int128 => Some(39_u8),
519            Self::Decimal75(precision, _) => Some(precision.value()),
520            // Scalars are not in database & are only used for typeless comparisons for testing so we return 0
521            // so that they do not cause errors when used in comparisons.
522            Self::Scalar => Some(0_u8),
523            Self::Boolean | Self::VarChar | Self::VarBinary => None,
524        }
525    }
526    /// Returns scale of a [`ColumnType`] if it is convertible to a decimal wrapped in `Some()`. Otherwise return None.
527    #[must_use]
528    pub fn scale(&self) -> Option<i8> {
529        match self {
530            Self::Decimal75(_, scale) => Some(*scale),
531            Self::TinyInt
532            | Self::Uint8
533            | Self::SmallInt
534            | Self::Int
535            | Self::BigInt
536            | Self::Int128
537            | Self::Scalar => Some(0),
538            Self::Boolean | Self::VarBinary | Self::VarChar => None,
539            Self::TimestampTZ(tu, _) => match tu {
540                PoSQLTimeUnit::Second => Some(0),
541                PoSQLTimeUnit::Millisecond => Some(3),
542                PoSQLTimeUnit::Microsecond => Some(6),
543                PoSQLTimeUnit::Nanosecond => Some(9),
544            },
545        }
546    }
547
548    /// Returns the byte size of the column type.
549    #[must_use]
550    pub fn byte_size(&self) -> usize {
551        match self {
552            Self::Boolean => size_of::<bool>(),
553            Self::Uint8 => size_of::<u8>(),
554            Self::TinyInt => size_of::<i8>(),
555            Self::SmallInt => size_of::<i16>(),
556            Self::Int => size_of::<i32>(),
557            Self::BigInt | Self::TimestampTZ(_, _) => size_of::<i64>(),
558            Self::Int128 => size_of::<i128>(),
559            Self::Scalar | Self::Decimal75(_, _) | Self::VarBinary | Self::VarChar => {
560                size_of::<[u64; 4]>()
561            }
562        }
563    }
564
565    #[expect(clippy::cast_possible_truncation)]
566    /// Returns the bit size of the column type.
567    #[must_use]
568    pub fn bit_size(&self) -> u32 {
569        self.byte_size() as u32 * 8
570    }
571
572    /// Returns if the column type supports signed values.
573    #[must_use]
574    pub const fn is_signed(&self) -> bool {
575        match self {
576            Self::TinyInt
577            | Self::SmallInt
578            | Self::Int
579            | Self::BigInt
580            | Self::Int128
581            | Self::TimestampTZ(_, _) => true,
582            Self::Decimal75(_, _)
583            | Self::Scalar
584            | Self::VarBinary
585            | Self::VarChar
586            | Self::Boolean
587            | Self::Uint8 => false,
588        }
589    }
590
591    /// Returns if the column type supports signed values.
592    #[must_use]
593    pub fn min_scalar<S: Scalar>(&self) -> Option<S> {
594        match self {
595            ColumnType::TinyInt => Some(S::from(i8::MIN)),
596            ColumnType::SmallInt => Some(S::from(i16::MIN)),
597            ColumnType::Int => Some(S::from(i32::MIN)),
598            ColumnType::BigInt => Some(S::from(i64::MIN)),
599            ColumnType::Int128 => Some(S::from(i128::MIN)),
600            _ => None,
601        }
602    }
603}
604
605/// Display the column type as a str name (in all caps)
606impl Display for ColumnType {
607    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
608        match self {
609            ColumnType::Boolean => write!(f, "BOOLEAN"),
610            ColumnType::Uint8 => write!(f, "UINT8"),
611            ColumnType::TinyInt => write!(f, "TINYINT"),
612            ColumnType::SmallInt => write!(f, "SMALLINT"),
613            ColumnType::Int => write!(f, "INT"),
614            ColumnType::BigInt => write!(f, "BIGINT"),
615            ColumnType::Int128 => write!(f, "DECIMAL"),
616            ColumnType::Decimal75(precision, scale) => {
617                write!(
618                    f,
619                    "DECIMAL75(PRECISION: {:?}, SCALE: {scale})",
620                    precision.value()
621                )
622            }
623            ColumnType::VarChar => write!(f, "VARCHAR"),
624            ColumnType::VarBinary => write!(f, "BINARY"),
625            ColumnType::Scalar => write!(f, "SCALAR"),
626            ColumnType::TimestampTZ(timeunit, timezone) => {
627                write!(f, "TIMESTAMP(TIMEUNIT: {timeunit}, TIMEZONE: {timezone})")
628            }
629        }
630    }
631}
632
633/// Reference of a SQL column
634#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
635pub struct ColumnRef {
636    column_id: Ident,
637    table_ref: TableRef,
638    column_type: ColumnType,
639}
640
641impl ColumnRef {
642    /// Create a new `ColumnRef` from a table, column identifier and column type
643    #[must_use]
644    pub fn new(table_ref: TableRef, column_id: Ident, column_type: ColumnType) -> Self {
645        Self {
646            column_id,
647            table_ref,
648            column_type,
649        }
650    }
651
652    /// Returns the table reference of this column
653    #[must_use]
654    pub fn table_ref(&self) -> TableRef {
655        self.table_ref.clone()
656    }
657
658    /// Returns the column identifier of this column
659    #[must_use]
660    pub fn column_id(&self) -> Ident {
661        self.column_id.clone()
662    }
663
664    /// Returns the column type of this column
665    #[must_use]
666    pub fn column_type(&self) -> &ColumnType {
667        &self.column_type
668    }
669}
670
671/// This type is used to represent the metadata
672/// of a column in a table. Namely: it's name and type.
673///
674/// This is the analog of a `Field` in Apache Arrow.
675#[derive(Debug, PartialEq, Eq, Clone, Hash, Serialize, Deserialize)]
676pub struct ColumnField {
677    name: Ident,
678    data_type: ColumnType,
679}
680
681impl ColumnField {
682    /// Create a new `ColumnField` from a name and a type
683    #[must_use]
684    pub fn new(name: Ident, data_type: ColumnType) -> ColumnField {
685        ColumnField { name, data_type }
686    }
687
688    /// Returns the name of the column
689    #[must_use]
690    pub fn name(&self) -> Ident {
691        self.name.clone()
692    }
693
694    /// Returns the type of the column
695    #[must_use]
696    pub fn data_type(&self) -> ColumnType {
697        self.data_type
698    }
699}
700
701#[cfg(test)]
702mod tests {
703    use super::*;
704    use crate::{base::scalar::test_scalar::TestScalar, proof_primitive::dory::DoryScalar};
705    use alloc::{string::String, vec};
706
707    #[test]
708    fn column_type_serializes_to_string() {
709        let column_type = ColumnType::TimestampTZ(PoSQLTimeUnit::Second, PoSQLTimeZone::utc());
710        let serialized = serde_json::to_string(&column_type).unwrap();
711        assert_eq!(serialized, r#"{"TimestampTZ":["Second",{"offset":0}]}"#);
712
713        let column_type = ColumnType::Boolean;
714        let serialized = serde_json::to_string(&column_type).unwrap();
715        assert_eq!(serialized, r#""Boolean""#);
716
717        let column_type = ColumnType::TinyInt;
718        let serialized = serde_json::to_string(&column_type).unwrap();
719        assert_eq!(serialized, r#""TinyInt""#);
720
721        let column_type = ColumnType::SmallInt;
722        let serialized = serde_json::to_string(&column_type).unwrap();
723        assert_eq!(serialized, r#""SmallInt""#);
724
725        let column_type = ColumnType::Int;
726        let serialized = serde_json::to_string(&column_type).unwrap();
727        assert_eq!(serialized, r#""Int""#);
728
729        let column_type = ColumnType::BigInt;
730        let serialized = serde_json::to_string(&column_type).unwrap();
731        assert_eq!(serialized, r#""BigInt""#);
732
733        let column_type = ColumnType::Int128;
734        let serialized = serde_json::to_string(&column_type).unwrap();
735        assert_eq!(serialized, r#""Decimal""#);
736
737        let column_type = ColumnType::VarChar;
738        let serialized = serde_json::to_string(&column_type).unwrap();
739        assert_eq!(serialized, r#""VarChar""#);
740
741        let column_type = ColumnType::Scalar;
742        let serialized = serde_json::to_string(&column_type).unwrap();
743        assert_eq!(serialized, r#""Scalar""#);
744
745        let column_type = ColumnType::Decimal75(Precision::new(1).unwrap(), 0);
746        let serialized = serde_json::to_string(&column_type).unwrap();
747        assert_eq!(serialized, r#"{"Decimal75":[1,0]}"#);
748    }
749
750    #[test]
751    fn we_can_deserialize_columns_from_valid_strings() {
752        let expected_column_type =
753            ColumnType::TimestampTZ(PoSQLTimeUnit::Second, PoSQLTimeZone::utc());
754        let deserialized: ColumnType =
755            serde_json::from_str(r#"{"TimestampTZ":["Second",{"offset":0}]}"#).unwrap();
756        assert_eq!(deserialized, expected_column_type);
757
758        let expected_column_type = ColumnType::Boolean;
759        let deserialized: ColumnType = serde_json::from_str(r#""Boolean""#).unwrap();
760        assert_eq!(deserialized, expected_column_type);
761
762        let expected_column_type = ColumnType::TinyInt;
763        let deserialized: ColumnType = serde_json::from_str(r#""TinyInt""#).unwrap();
764        assert_eq!(deserialized, expected_column_type);
765
766        let expected_column_type = ColumnType::SmallInt;
767        let deserialized: ColumnType = serde_json::from_str(r#""SmallInt""#).unwrap();
768        assert_eq!(deserialized, expected_column_type);
769
770        let expected_column_type = ColumnType::Int;
771        let deserialized: ColumnType = serde_json::from_str(r#""Int""#).unwrap();
772        assert_eq!(deserialized, expected_column_type);
773
774        let expected_column_type = ColumnType::BigInt;
775        let deserialized: ColumnType = serde_json::from_str(r#""BigInt""#).unwrap();
776        assert_eq!(deserialized, expected_column_type);
777
778        let expected_column_type = ColumnType::TinyInt;
779        let deserialized: ColumnType = serde_json::from_str(r#""TINYINT""#).unwrap();
780        assert_eq!(deserialized, expected_column_type);
781
782        let expected_column_type = ColumnType::SmallInt;
783        let deserialized: ColumnType = serde_json::from_str(r#""SMALLINT""#).unwrap();
784        assert_eq!(deserialized, expected_column_type);
785
786        let expected_column_type = ColumnType::Int128;
787        let deserialized: ColumnType = serde_json::from_str(r#""DECIMAL""#).unwrap();
788        assert_eq!(deserialized, expected_column_type);
789
790        let expected_column_type = ColumnType::Int128;
791        let deserialized: ColumnType = serde_json::from_str(r#""Decimal""#).unwrap();
792        assert_eq!(deserialized, expected_column_type);
793
794        let expected_column_type = ColumnType::VarChar;
795        let deserialized: ColumnType = serde_json::from_str(r#""VarChar""#).unwrap();
796        assert_eq!(deserialized, expected_column_type);
797
798        let expected_column_type = ColumnType::Scalar;
799        let deserialized: ColumnType = serde_json::from_str(r#""SCALAR""#).unwrap();
800        assert_eq!(deserialized, expected_column_type);
801
802        let expected_column_type = ColumnType::Decimal75(Precision::new(75).unwrap(), i8::MAX);
803        let deserialized: ColumnType = serde_json::from_str(r#"{"Decimal75":[75, 127]}"#).unwrap();
804        assert_eq!(deserialized, expected_column_type);
805
806        let expected_column_type =
807            ColumnType::Decimal75(Precision::new(u8::MIN + 1).unwrap(), i8::MIN);
808        let deserialized: ColumnType = serde_json::from_str(r#"{"Decimal75":[1, -128]}"#).unwrap();
809        assert_eq!(deserialized, expected_column_type);
810
811        let expected_column_type = ColumnType::Decimal75(Precision::new(1).unwrap(), 0);
812        let deserialized: ColumnType = serde_json::from_str(r#"{"Decimal75":[1, 0]}"#).unwrap();
813        assert_eq!(deserialized, expected_column_type);
814    }
815
816    #[test]
817    fn we_can_deserialize_columns_from_lowercase_or_uppercase_strings() {
818        assert_eq!(
819            serde_json::from_str::<ColumnType>(r#""boolean""#).unwrap(),
820            ColumnType::Boolean
821        );
822        assert_eq!(
823            serde_json::from_str::<ColumnType>(r#""BOOLEAN""#).unwrap(),
824            ColumnType::Boolean
825        );
826
827        assert_eq!(
828            serde_json::from_str::<ColumnType>(r#""bigint""#).unwrap(),
829            ColumnType::BigInt
830        );
831        assert_eq!(
832            serde_json::from_str::<ColumnType>(r#""BIGINT""#).unwrap(),
833            ColumnType::BigInt
834        );
835        assert_eq!(
836            serde_json::from_str::<ColumnType>(r#""TINYINT""#).unwrap(),
837            ColumnType::TinyInt
838        );
839        assert_eq!(
840            serde_json::from_str::<ColumnType>(r#""tinyint""#).unwrap(),
841            ColumnType::TinyInt
842        );
843        assert_eq!(
844            serde_json::from_str::<ColumnType>(r#""SMALLINT""#).unwrap(),
845            ColumnType::SmallInt
846        );
847        assert_eq!(
848            serde_json::from_str::<ColumnType>(r#""smallint""#).unwrap(),
849            ColumnType::SmallInt
850        );
851        assert_eq!(
852            serde_json::from_str::<ColumnType>(r#""int""#).unwrap(),
853            ColumnType::Int
854        );
855        assert_eq!(
856            serde_json::from_str::<ColumnType>(r#""INT""#).unwrap(),
857            ColumnType::Int
858        );
859        assert_eq!(
860            serde_json::from_str::<ColumnType>(r#""decimal""#).unwrap(),
861            ColumnType::Int128
862        );
863        assert_eq!(
864            serde_json::from_str::<ColumnType>(r#""DECIMAL""#).unwrap(),
865            ColumnType::Int128
866        );
867
868        assert_eq!(
869            serde_json::from_str::<ColumnType>(r#""VARCHAR""#).unwrap(),
870            ColumnType::VarChar
871        );
872        assert_eq!(
873            serde_json::from_str::<ColumnType>(r#""varchar""#).unwrap(),
874            ColumnType::VarChar
875        );
876
877        assert_eq!(
878            serde_json::from_str::<ColumnType>(r#""SCALAR""#).unwrap(),
879            ColumnType::Scalar
880        );
881        assert_eq!(
882            serde_json::from_str::<ColumnType>(r#""scalar""#).unwrap(),
883            ColumnType::Scalar
884        );
885        assert_eq!(
886            serde_json::from_str::<ColumnType>(r#"{"decimal75":[1,0]}"#).unwrap(),
887            ColumnType::Decimal75(Precision::new(1).unwrap(), 0)
888        );
889        assert_eq!(
890            serde_json::from_str::<ColumnType>(r#"{"DECIMAL75":[1,0]}"#).unwrap(),
891            ColumnType::Decimal75(Precision::new(1).unwrap(), 0)
892        );
893
894        assert_eq!(
895            serde_json::from_str::<ColumnType>(r#"{"decimal75":[10,5]}"#).unwrap(),
896            ColumnType::Decimal75(Precision::new(10).unwrap(), 5)
897        );
898
899        assert_eq!(
900            serde_json::from_str::<ColumnType>(r#"{"DECIMAL75":[1,-128]}"#).unwrap(),
901            ColumnType::Decimal75(Precision::new(1).unwrap(), -128)
902        );
903    }
904
905    #[test]
906    fn we_cannot_deserialize_columns_from_invalid_strings() {
907        let deserialized: Result<ColumnType, _> = serde_json::from_str(r#""BooLean""#);
908        assert!(deserialized.is_err());
909
910        let deserialized: Result<ColumnType, _> = serde_json::from_str(r#""Tinyint""#);
911        assert!(deserialized.is_err());
912
913        let deserialized: Result<ColumnType, _> = serde_json::from_str(r#""Smallint""#);
914        assert!(deserialized.is_err());
915
916        let deserialized: Result<ColumnType, _> = serde_json::from_str(r#""iNt""#);
917        assert!(deserialized.is_err());
918
919        let deserialized: Result<ColumnType, _> = serde_json::from_str(r#""Bigint""#);
920        assert!(deserialized.is_err());
921
922        let deserialized: Result<ColumnType, _> = serde_json::from_str(r#""DecImal""#);
923        assert!(deserialized.is_err());
924
925        let deserialized: Result<ColumnType, _> = serde_json::from_str(r#""DecImal75""#);
926        assert!(deserialized.is_err());
927
928        let deserialized: Result<ColumnType, _> =
929            serde_json::from_str(r#"{"TimestampTZ":["Utc","Second"]}"#);
930        assert!(deserialized.is_err());
931
932        let deserialized: Result<ColumnType, _> = serde_json::from_str(r#""Varchar""#);
933        assert!(deserialized.is_err());
934
935        let deserialized: Result<ColumnType, _> = serde_json::from_str(r#""ScaLar""#);
936        assert!(deserialized.is_err());
937    }
938
939    #[test]
940    fn we_can_convert_columntype_to_json_string_and_back() {
941        let boolean = ColumnType::Boolean;
942        let boolean_json = serde_json::to_string(&boolean).unwrap();
943        assert_eq!(boolean_json, "\"Boolean\"");
944        assert_eq!(
945            serde_json::from_str::<ColumnType>(&boolean_json).unwrap(),
946            boolean
947        );
948
949        let tinyint = ColumnType::TinyInt;
950        let tinyint_json = serde_json::to_string(&tinyint).unwrap();
951        assert_eq!(tinyint_json, "\"TinyInt\"");
952        assert_eq!(
953            serde_json::from_str::<ColumnType>(&tinyint_json).unwrap(),
954            tinyint
955        );
956
957        let smallint = ColumnType::SmallInt;
958        let smallint_json = serde_json::to_string(&smallint).unwrap();
959        assert_eq!(smallint_json, "\"SmallInt\"");
960        assert_eq!(
961            serde_json::from_str::<ColumnType>(&smallint_json).unwrap(),
962            smallint
963        );
964
965        let int = ColumnType::Int;
966        let int_json = serde_json::to_string(&int).unwrap();
967        assert_eq!(int_json, "\"Int\"");
968        assert_eq!(serde_json::from_str::<ColumnType>(&int_json).unwrap(), int);
969
970        let bigint = ColumnType::BigInt;
971        let bigint_json = serde_json::to_string(&bigint).unwrap();
972        assert_eq!(bigint_json, "\"BigInt\"");
973        assert_eq!(
974            serde_json::from_str::<ColumnType>(&bigint_json).unwrap(),
975            bigint
976        );
977
978        let int128 = ColumnType::Int128;
979        let int128_json = serde_json::to_string(&int128).unwrap();
980        assert_eq!(int128_json, "\"Decimal\"");
981        assert_eq!(
982            serde_json::from_str::<ColumnType>(&int128_json).unwrap(),
983            int128
984        );
985
986        let varchar = ColumnType::VarChar;
987        let varchar_json = serde_json::to_string(&varchar).unwrap();
988        assert_eq!(varchar_json, "\"VarChar\"");
989        assert_eq!(
990            serde_json::from_str::<ColumnType>(&varchar_json).unwrap(),
991            varchar
992        );
993
994        let scalar = ColumnType::Scalar;
995        let scalar_json = serde_json::to_string(&scalar).unwrap();
996        assert_eq!(scalar_json, "\"Scalar\"");
997        assert_eq!(
998            serde_json::from_str::<ColumnType>(&scalar_json).unwrap(),
999            scalar
1000        );
1001
1002        let decimal75 = ColumnType::Decimal75(Precision::new(75).unwrap(), 0);
1003        let decimal75_json = serde_json::to_string(&decimal75).unwrap();
1004        assert_eq!(decimal75_json, r#"{"Decimal75":[75,0]}"#);
1005        assert_eq!(
1006            serde_json::from_str::<ColumnType>(&decimal75_json).unwrap(),
1007            decimal75
1008        );
1009    }
1010
1011    #[test]
1012    fn we_can_get_the_len_of_a_column() {
1013        let precision = 10;
1014        let scale = 2;
1015
1016        let scalar_values = [
1017            TestScalar::from(1),
1018            TestScalar::from(2),
1019            TestScalar::from(3),
1020        ];
1021
1022        // Test non-empty columns
1023        let column = Column::<DoryScalar>::Boolean(&[true, false, true]);
1024        assert_eq!(column.len(), 3);
1025        assert!(!column.is_empty());
1026
1027        let column = Column::<DoryScalar>::TinyInt(&[1, 2, 3]);
1028        assert_eq!(column.len(), 3);
1029        assert!(!column.is_empty());
1030
1031        let column = Column::<TestScalar>::SmallInt(&[1, 2, 3]);
1032        assert_eq!(column.len(), 3);
1033        assert!(!column.is_empty());
1034
1035        let column = Column::<TestScalar>::Int(&[1, 2, 3]);
1036        assert_eq!(column.len(), 3);
1037        assert!(!column.is_empty());
1038
1039        let column = Column::<TestScalar>::BigInt(&[1, 2, 3]);
1040        assert_eq!(column.len(), 3);
1041        assert!(!column.is_empty());
1042
1043        let column = Column::VarChar((&["a", "b", "c"], &scalar_values));
1044        assert_eq!(column.len(), 3);
1045        assert!(!column.is_empty());
1046
1047        let column = Column::<DoryScalar>::Int128(&[1, 2, 3]);
1048        assert_eq!(column.len(), 3);
1049        assert!(!column.is_empty());
1050
1051        let column = Column::Scalar(&scalar_values);
1052        assert_eq!(column.len(), 3);
1053        assert!(!column.is_empty());
1054
1055        let decimal_data = [
1056            TestScalar::from(1),
1057            TestScalar::from(2),
1058            TestScalar::from(3),
1059        ];
1060
1061        let precision = Precision::new(precision).unwrap();
1062        let column = Column::Decimal75(precision, scale, &decimal_data);
1063        assert_eq!(column.len(), 3);
1064        assert!(!column.is_empty());
1065
1066        // Test empty columns
1067        let column = Column::<DoryScalar>::Boolean(&[]);
1068        assert_eq!(column.len(), 0);
1069        assert!(column.is_empty());
1070
1071        let column = Column::<DoryScalar>::TinyInt(&[]);
1072        assert_eq!(column.len(), 0);
1073        assert!(column.is_empty());
1074
1075        let column = Column::<TestScalar>::SmallInt(&[]);
1076        assert_eq!(column.len(), 0);
1077        assert!(column.is_empty());
1078
1079        let column = Column::<TestScalar>::Int(&[]);
1080        assert_eq!(column.len(), 0);
1081        assert!(column.is_empty());
1082
1083        let column = Column::<TestScalar>::BigInt(&[]);
1084        assert_eq!(column.len(), 0);
1085        assert!(column.is_empty());
1086
1087        let column = Column::<DoryScalar>::VarChar((&[], &[]));
1088        assert_eq!(column.len(), 0);
1089        assert!(column.is_empty());
1090
1091        let column = Column::<TestScalar>::Int128(&[]);
1092        assert_eq!(column.len(), 0);
1093        assert!(column.is_empty());
1094
1095        let column = Column::<DoryScalar>::Scalar(&[]);
1096        assert_eq!(column.len(), 0);
1097        assert!(column.is_empty());
1098
1099        let column: Column<'_, TestScalar> = Column::Decimal75(precision, scale, &[]);
1100        assert_eq!(column.len(), 0);
1101        assert!(column.is_empty());
1102    }
1103
1104    #[test]
1105    fn we_can_convert_owned_columns_to_columns_round_trip() {
1106        let alloc = Bump::new();
1107        // Integers
1108        let owned_col: OwnedColumn<TestScalar> = OwnedColumn::Int128(vec![1, 2, 3, 4, 5]);
1109        let col = Column::<TestScalar>::from_owned_column(&owned_col, &alloc);
1110        assert_eq!(col, Column::Int128(&[1, 2, 3, 4, 5]));
1111        let new_owned_col = (&col).into();
1112        assert_eq!(owned_col, new_owned_col);
1113
1114        // Booleans
1115        let owned_col: OwnedColumn<TestScalar> =
1116            OwnedColumn::Boolean(vec![true, false, true, false, true]);
1117        let col = Column::<TestScalar>::from_owned_column(&owned_col, &alloc);
1118        assert_eq!(col, Column::Boolean(&[true, false, true, false, true]));
1119        let new_owned_col = (&col).into();
1120        assert_eq!(owned_col, new_owned_col);
1121
1122        // Strings
1123        let strs = [
1124            "Space and Time",
1125            "Tér és Idő",
1126            "Пространство и время",
1127            "Spațiu și Timp",
1128            "Spazju u Ħin",
1129        ];
1130        let scalars = strs.iter().map(TestScalar::from).collect::<Vec<_>>();
1131        let owned_col = OwnedColumn::VarChar(
1132            strs.iter()
1133                .map(ToString::to_string)
1134                .collect::<Vec<String>>(),
1135        );
1136        let col = Column::<TestScalar>::from_owned_column(&owned_col, &alloc);
1137        assert_eq!(col, Column::VarChar((&strs, &scalars)));
1138        let new_owned_col = (&col).into();
1139        assert_eq!(owned_col, new_owned_col);
1140
1141        // Decimals
1142        let scalars: Vec<TestScalar> = [1, 2, 3, 4, 5].iter().map(TestScalar::from).collect();
1143        let owned_col: OwnedColumn<TestScalar> =
1144            OwnedColumn::Decimal75(Precision::new(75).unwrap(), 127, scalars.clone());
1145        let col = Column::<TestScalar>::from_owned_column(&owned_col, &alloc);
1146        assert_eq!(
1147            col,
1148            Column::Decimal75(Precision::new(75).unwrap(), 127, &scalars)
1149        );
1150        let new_owned_col = (&col).into();
1151        assert_eq!(owned_col, new_owned_col);
1152    }
1153
1154    #[test]
1155    fn we_can_get_the_data_size_of_a_column() {
1156        let column = Column::<DoryScalar>::Boolean(&[true, false, true]);
1157        assert_eq!(column.column_type().byte_size(), 1);
1158        assert_eq!(column.column_type().bit_size(), 8);
1159
1160        let column = Column::<TestScalar>::TinyInt(&[1, 2, 3, 4]);
1161        assert_eq!(column.column_type().byte_size(), 1);
1162        assert_eq!(column.column_type().bit_size(), 8);
1163
1164        let column = Column::<TestScalar>::SmallInt(&[1, 2, 3, 4]);
1165        assert_eq!(column.column_type().byte_size(), 2);
1166        assert_eq!(column.column_type().bit_size(), 16);
1167
1168        let column = Column::<TestScalar>::Int(&[1, 2, 3]);
1169        assert_eq!(column.column_type().byte_size(), 4);
1170        assert_eq!(column.column_type().bit_size(), 32);
1171
1172        let column = Column::<TestScalar>::BigInt(&[1]);
1173        assert_eq!(column.column_type().byte_size(), 8);
1174        assert_eq!(column.column_type().bit_size(), 64);
1175
1176        let column = Column::<DoryScalar>::Int128(&[1, 2]);
1177        assert_eq!(column.column_type().byte_size(), 16);
1178        assert_eq!(column.column_type().bit_size(), 128);
1179
1180        let scalar_values = [
1181            TestScalar::from(1),
1182            TestScalar::from(2),
1183            TestScalar::from(3),
1184        ];
1185
1186        let column = Column::VarChar((&["a", "b", "c", "d", "e"], &scalar_values));
1187        assert_eq!(column.column_type().byte_size(), 32);
1188        assert_eq!(column.column_type().bit_size(), 256);
1189
1190        let column = Column::Scalar(&scalar_values);
1191        assert_eq!(column.column_type().byte_size(), 32);
1192        assert_eq!(column.column_type().bit_size(), 256);
1193
1194        let precision = 10;
1195        let scale = 2;
1196        let decimal_data = [
1197            TestScalar::from(1),
1198            TestScalar::from(2),
1199            TestScalar::from(3),
1200        ];
1201
1202        let precision = Precision::new(precision).unwrap();
1203        let column = Column::Decimal75(precision, scale, &decimal_data);
1204        assert_eq!(column.column_type().byte_size(), 32);
1205        assert_eq!(column.column_type().bit_size(), 256);
1206
1207        let column: Column<'_, DoryScalar> =
1208            Column::TimestampTZ(PoSQLTimeUnit::Second, PoSQLTimeZone::utc(), &[1, 2, 3]);
1209        assert_eq!(column.column_type().byte_size(), 8);
1210        assert_eq!(column.column_type().bit_size(), 64);
1211    }
1212
1213    #[test]
1214    fn we_can_get_length_of_varbinary_column() {
1215        let raw_bytes: &[&[u8]] = &[b"foo", b"bar", b""];
1216        let scalars: Vec<TestScalar> = raw_bytes
1217            .iter()
1218            .map(|b| TestScalar::from_le_bytes_mod_order(b))
1219            .collect();
1220
1221        let column = Column::VarBinary((raw_bytes, &scalars));
1222        assert_eq!(column.len(), 3);
1223        assert!(!column.is_empty());
1224        assert_eq!(column.column_type(), ColumnType::VarBinary);
1225    }
1226
1227    #[test]
1228    fn we_can_convert_varbinary_owned_column_to_column_and_back() {
1229        use bumpalo::Bump;
1230        let alloc = Bump::new();
1231
1232        let owned_varbinary = OwnedColumn::VarBinary(vec![b"abc".to_vec(), b"xyz".to_vec()]);
1233
1234        let column = Column::<TestScalar>::from_owned_column(&owned_varbinary, &alloc);
1235        match column {
1236            Column::VarBinary((bytes, scalars)) => {
1237                assert_eq!(bytes.len(), 2);
1238                assert_eq!(scalars.len(), 2);
1239                assert_eq!(bytes[0], b"abc");
1240                assert_eq!(bytes[1], b"xyz");
1241            }
1242            _ => panic!("Expected VarBinary column"),
1243        }
1244
1245        let round_trip_owned: OwnedColumn<TestScalar> = (&column).into();
1246        assert_eq!(owned_varbinary, round_trip_owned);
1247    }
1248
1249    #[test]
1250    fn we_can_get_min_scalar() {
1251        assert_eq!(
1252            ColumnType::TinyInt.min_scalar(),
1253            Some(TestScalar::from(i8::MIN))
1254        );
1255        assert_eq!(
1256            ColumnType::SmallInt.min_scalar(),
1257            Some(TestScalar::from(i16::MIN))
1258        );
1259        assert_eq!(
1260            ColumnType::Int.min_scalar(),
1261            Some(TestScalar::from(i32::MIN))
1262        );
1263        assert_eq!(
1264            ColumnType::BigInt.min_scalar(),
1265            Some(TestScalar::from(i64::MIN))
1266        );
1267        assert_eq!(
1268            ColumnType::Int128.min_scalar(),
1269            Some(TestScalar::from(i128::MIN))
1270        );
1271        assert_eq!(ColumnType::Uint8.min_scalar::<TestScalar>(), None);
1272        assert_eq!(ColumnType::Scalar.min_scalar::<TestScalar>(), None);
1273        assert_eq!(ColumnType::Boolean.min_scalar::<TestScalar>(), None);
1274        assert_eq!(ColumnType::VarBinary.min_scalar::<TestScalar>(), None);
1275        assert_eq!(
1276            ColumnType::TimestampTZ(PoSQLTimeUnit::Second, PoSQLTimeZone::new(0))
1277                .min_scalar::<TestScalar>(),
1278            None
1279        );
1280        assert_eq!(
1281            ColumnType::Decimal75(Precision::new(1).unwrap(), 1).min_scalar::<TestScalar>(),
1282            None
1283        );
1284        assert_eq!(ColumnType::VarChar.min_scalar::<TestScalar>(), None);
1285    }
1286
1287    #[test]
1288    fn we_can_get_sqrt_negative_min() {
1289        for column_type in [
1290            ColumnType::TinyInt,
1291            ColumnType::SmallInt,
1292            ColumnType::Int,
1293            ColumnType::BigInt,
1294            ColumnType::Int128,
1295        ] {
1296            let floor = TestScalar::from(column_type.sqrt_negative_min().unwrap());
1297            let ceiling = floor + TestScalar::ONE;
1298            let floor_squared = floor * floor;
1299            let ceiling_squared = ceiling * ceiling;
1300            let negative_min_scalar = -column_type.min_scalar::<TestScalar>().unwrap();
1301            assert!(floor_squared <= negative_min_scalar);
1302            assert!(negative_min_scalar < ceiling_squared);
1303        }
1304        for column_type in [
1305            ColumnType::Uint8,
1306            ColumnType::Scalar,
1307            ColumnType::Boolean,
1308            ColumnType::VarBinary,
1309            ColumnType::TimestampTZ(PoSQLTimeUnit::Second, PoSQLTimeZone::new(1)),
1310            ColumnType::Decimal75(Precision::new(1).unwrap(), 1),
1311            ColumnType::VarChar,
1312        ] {
1313            assert_eq!(column_type.sqrt_negative_min(), None);
1314        }
1315    }
1316}