proof_of_sql/base/database/
columnar_value.rs

1use crate::base::{
2    database::{Column, ColumnType, LiteralValue},
3    scalar::Scalar,
4};
5use bumpalo::Bump;
6use snafu::Snafu;
7
8/// The result of evaluating an expression.
9///
10/// Inspired by [`datafusion_expr_common::ColumnarValue`]
11#[derive(Debug, Eq, PartialEq, Clone)]
12pub enum ColumnarValue<'a, S: Scalar> {
13    /// A [ `ColumnarValue::Column` ] is a list of values.
14    Column(Column<'a, S>),
15    /// A [ `ColumnarValue::Literal` ] is a single value with indeterminate size.
16    Literal(LiteralValue),
17}
18
19/// Errors from operations on [`ColumnarValue`]s.
20#[derive(Snafu, Debug, PartialEq, Eq)]
21pub enum ColumnarValueError {
22    /// Attempt to convert a `[ColumnarValue::Column]` to a column of a different length
23    ColumnLengthMismatch {
24        /// The length of the `[ColumnarValue::Column]`
25        columnar_value_length: usize,
26        /// The length we attempted to convert the `[ColumnarValue::Column]` to
27        attempt_to_convert_length: usize,
28    },
29}
30
31impl<'a, S: Scalar> ColumnarValue<'a, S> {
32    /// Provides the column type associated with the column
33    #[must_use]
34    pub fn column_type(&self) -> ColumnType {
35        match self {
36            Self::Column(column) => column.column_type(),
37            Self::Literal(literal) => literal.column_type(),
38        }
39    }
40
41    /// Converts the [`ColumnarValue`] to a [`Column`]
42    pub fn into_column(
43        &self,
44        num_rows: usize,
45        alloc: &'a Bump,
46    ) -> Result<Column<'a, S>, ColumnarValueError> {
47        match self {
48            Self::Column(column) => {
49                if column.len() == num_rows {
50                    Ok(*column)
51                } else {
52                    Err(ColumnarValueError::ColumnLengthMismatch {
53                        columnar_value_length: column.len(),
54                        attempt_to_convert_length: num_rows,
55                    })
56                }
57            }
58            Self::Literal(literal) => {
59                Ok(Column::from_literal_with_length(literal, num_rows, alloc))
60            }
61        }
62    }
63}
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use crate::base::scalar::test_scalar::TestScalar;
69    use core::convert::Into;
70
71    #[test]
72    fn we_can_get_column_type_of_columnar_values() {
73        let column = ColumnarValue::Column(Column::<TestScalar>::Int(&[1, 2, 3]));
74        assert_eq!(column.column_type(), ColumnType::Int);
75
76        let column = ColumnarValue::<TestScalar>::Literal(LiteralValue::Boolean(true));
77        assert_eq!(column.column_type(), ColumnType::Boolean);
78    }
79
80    #[test]
81    fn we_can_transform_columnar_values_into_columns() {
82        let bump = Bump::new();
83
84        let columnar_value = ColumnarValue::Column(Column::<TestScalar>::Int(&[1, 2, 3]));
85        let column = columnar_value.into_column(3, &bump).unwrap();
86        assert_eq!(column, Column::Int(&[1, 2, 3]));
87
88        let columnar_value = ColumnarValue::<TestScalar>::Literal(LiteralValue::Boolean(false));
89        let column = columnar_value.into_column(5, &bump).unwrap();
90        assert_eq!(column, Column::Boolean(&[false; 5]));
91
92        // Check whether it works if `num_rows` is 0
93        let columnar_value = ColumnarValue::<TestScalar>::Literal(LiteralValue::TinyInt(2));
94        let column = columnar_value.into_column(0, &bump).unwrap();
95        assert_eq!(column, Column::TinyInt(&[]));
96
97        let columnar_value = ColumnarValue::Column(Column::<TestScalar>::SmallInt(&[]));
98        let column = columnar_value.into_column(0, &bump).unwrap();
99        assert_eq!(column, Column::SmallInt(&[]));
100    }
101
102    #[test]
103    fn we_cannot_transform_columnar_values_into_columns_of_different_length() {
104        let bump = Bump::new();
105
106        let columnar_value = ColumnarValue::Column(Column::<TestScalar>::Int(&[1, 2, 3]));
107        let res = columnar_value.into_column(2, &bump);
108        assert_eq!(
109            res,
110            Err(ColumnarValueError::ColumnLengthMismatch {
111                columnar_value_length: 3,
112                attempt_to_convert_length: 2,
113            })
114        );
115
116        let strings = ["a", "b", "c"];
117        let scalars: Vec<TestScalar> = strings.iter().map(Into::into).collect();
118        let columnar_value =
119            ColumnarValue::Column(Column::<TestScalar>::VarChar((&strings, &scalars)));
120        let res = columnar_value.into_column(0, &bump);
121        assert_eq!(
122            res,
123            Err(ColumnarValueError::ColumnLengthMismatch {
124                columnar_value_length: 3,
125                attempt_to_convert_length: 0,
126            })
127        );
128
129        let columnar_value = ColumnarValue::Column(Column::<TestScalar>::Boolean(&[]));
130        let res = columnar_value.into_column(1, &bump);
131        assert_eq!(
132            res,
133            Err(ColumnarValueError::ColumnLengthMismatch {
134                columnar_value_length: 0,
135                attempt_to_convert_length: 1,
136            })
137        );
138    }
139}