Skip to content

Commit

Permalink
feat: add DataType::Tuple (#138)
Browse files Browse the repository at this point in the history
  • Loading branch information
KKould authored Feb 13, 2024
1 parent b6a3726 commit d1d5202
Show file tree
Hide file tree
Showing 12 changed files with 232 additions and 29 deletions.
17 changes: 13 additions & 4 deletions src/binder/aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -136,8 +136,12 @@ impl<'a, T: Transaction> Binder<'a, T> {
}
}
ScalarExpression::Constant(_) | ScalarExpression::ColumnRef { .. } => (),
ScalarExpression::Empty => unreachable!(),
ScalarExpression::Reference { .. } => unreachable!(),
ScalarExpression::Reference { .. } | ScalarExpression::Empty => unreachable!(),
ScalarExpression::Tuple(args) => {
for expr in args {
self.visit_column_agg_expr(expr)?;
}
}
}

Ok(())
Expand Down Expand Up @@ -310,8 +314,13 @@ impl<'a, T: Transaction> Binder<'a, T> {
Ok(())
}
ScalarExpression::Constant(_) => Ok(()),
ScalarExpression::Empty => unreachable!(),
ScalarExpression::Reference { .. } => unreachable!(),
ScalarExpression::Reference { .. } | ScalarExpression::Empty => unreachable!(),
ScalarExpression::Tuple(args) => {
for expr in args {
self.validate_having_orderby(expr)?;
}
Ok(())
}
}
}
}
8 changes: 8 additions & 0 deletions src/binder/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ impl<'a, T: Transaction> Binder<'a, T> {
)))),
})
}
Expr::Tuple(exprs) => {
let mut bond_exprs = Vec::with_capacity(exprs.len());

for expr in exprs {
bond_exprs.push(self.bind_expr(expr)?);
}
Ok(ScalarExpression::Tuple(bond_exprs))
}
_ => {
todo!()
}
Expand Down
4 changes: 3 additions & 1 deletion src/errors.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::expression::BinaryOperator;
use crate::types::LogicalType;
use chrono::ParseError;
use kip_db::KernelError;
Expand Down Expand Up @@ -161,9 +162,10 @@ pub enum DatabaseError {
AggMiss(String),
#[error("copy error: {0}")]
UnsupportedCopySource(String),
#[error("the {0} cannot support {1} for calculations")]
UnsupportedBinaryOperator(LogicalType, BinaryOperator),
#[error("can not compare two types: {0} and {1}")]
Incomparable(LogicalType, LogicalType),

#[error("transaction already exists")]
TransactionAlreadyExists,
#[error("no transaction begin")]
Expand Down
10 changes: 10 additions & 0 deletions src/expression/evaluator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,16 @@ impl ScalarExpression {
.unwrap_or_else(|| &NULL_VALUE)
.clone());
}
ScalarExpression::Tuple(exprs) => {
let mut values = Vec::with_capacity(exprs.len());

for expr in exprs {
values.push(expr.eval(tuple)?);
}
Ok(Arc::new(DataValue::Tuple(
(!values.is_empty()).then_some(values),
)))
}
ScalarExpression::Empty => unreachable!(),
}
}
Expand Down
57 changes: 46 additions & 11 deletions src/expression/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ pub enum ScalarExpression {
expr: Box<ScalarExpression>,
pos: usize,
},
Tuple(Vec<ScalarExpression>),
}

impl ScalarExpression {
Expand All @@ -91,18 +92,13 @@ impl ScalarExpression {
self
}
}
pub fn unpack_reference(&self) -> &ScalarExpression {
if let ScalarExpression::Reference { expr, .. } = self {
expr.unpack_reference()
} else {
self
}
}

pub fn try_reference(&mut self, output_exprs: &[ScalarExpression]) {
let fn_output_column = |expr: &ScalarExpression| expr.unpack_alias().output_column();
let self_column = fn_output_column(self);
if let Some((pos, _)) = output_exprs
.iter()
.find_position(|expr| self.output_name() == expr.output_name())
.find_position(|expr| self_column.summary() == fn_output_column(expr).summary())
{
let expr = Box::new(mem::replace(self, ScalarExpression::Empty));
*self = ScalarExpression::Reference { expr, pos };
Expand Down Expand Up @@ -168,6 +164,11 @@ impl ScalarExpression {
ScalarExpression::Constant(_)
| ScalarExpression::ColumnRef(_)
| ScalarExpression::Reference { .. } => (),
ScalarExpression::Tuple(exprs) => {
for expr in exprs {
expr.try_reference(output_exprs);
}
}
}
}

Expand All @@ -183,7 +184,34 @@ impl ScalarExpression {
..
} => left_expr.has_count_star() || right_expr.has_count_star(),
ScalarExpression::AggCall { args, .. } => args.iter().any(Self::has_count_star),
_ => false,
ScalarExpression::Constant(_) | ScalarExpression::ColumnRef(_) => false,
ScalarExpression::In { expr, args, .. } => {
expr.has_count_star() || args.iter().any(Self::has_count_star)
}
ScalarExpression::Between {
expr,
left_expr,
right_expr,
..
} => expr.has_count_star() || left_expr.has_count_star() || right_expr.has_count_star(),
ScalarExpression::SubString {
expr,
from_expr,
for_expr,
} => {
expr.has_count_star()
|| matches!(
from_expr.as_ref().map(|expr| expr.has_count_star()),
Some(true)
)
|| matches!(
for_expr.as_ref().map(|expr| expr.has_count_star()),
Some(true)
)
}
ScalarExpression::Empty => unreachable!(),
ScalarExpression::Reference { expr, .. } => expr.has_count_star(),
ScalarExpression::Tuple(args) => args.iter().any(Self::has_count_star),
}
}

Expand Down Expand Up @@ -211,6 +239,7 @@ impl ScalarExpression {
expr.return_type()
}
ScalarExpression::Empty => unreachable!(),
ScalarExpression::Tuple(_) => LogicalType::Tuple,
}
}

Expand Down Expand Up @@ -244,7 +273,7 @@ impl ScalarExpression {
columns_collect(left_expr, vec, only_column_ref);
columns_collect(right_expr, vec, only_column_ref);
}
ScalarExpression::AggCall { args, .. } => {
ScalarExpression::AggCall { args, .. } | ScalarExpression::Tuple(args) => {
for expr in args {
columns_collect(expr, vec, only_column_ref)
}
Expand Down Expand Up @@ -328,6 +357,7 @@ impl ScalarExpression {
)
}
ScalarExpression::Reference { .. } | ScalarExpression::Empty => unreachable!(),
ScalarExpression::Tuple(args) => args.iter().any(Self::has_agg_call),
}
}

Expand Down Expand Up @@ -432,6 +462,10 @@ impl ScalarExpression {
}
ScalarExpression::Reference { expr, .. } => expr.output_name(),
ScalarExpression::Empty => unreachable!(),
ScalarExpression::Tuple(args) => {
let args_str = args.iter().map(|expr| expr.output_name()).join(", ");
format!("({})", args_str)
}
}
}

Expand All @@ -441,7 +475,8 @@ impl ScalarExpression {
ScalarExpression::Alias {
alias: AliasType::Expr(expr),
..
} => expr.output_column(),
}
| ScalarExpression::Reference { expr, .. } => expr.output_column(),
_ => Arc::new(ColumnCatalog::new(
self.output_name(),
true,
Expand Down
13 changes: 8 additions & 5 deletions src/expression/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,7 @@ impl ScalarExpression {
left_expr.exist_column(table_name, col_id)
|| right_expr.exist_column(table_name, col_id)
}
ScalarExpression::AggCall { args, .. } => args
ScalarExpression::AggCall { args, .. } | ScalarExpression::Tuple(args) => args
.iter()
.any(|expr| expr.exist_column(table_name, col_id)),
ScalarExpression::In { expr, args, .. } => {
Expand Down Expand Up @@ -729,6 +729,7 @@ impl ScalarExpression {

let _ = mem::replace(self, new_expr);
}
// FIXME: Maybe `ScalarExpression::Tuple` can be replaced?
_ => (),
}

Expand Down Expand Up @@ -991,11 +992,13 @@ impl ScalarExpression {
| ScalarExpression::In { .. }
| ScalarExpression::Between { .. }
| ScalarExpression::SubString { .. } => expr.convert_binary(table_name, id),
ScalarExpression::Reference { .. } | ScalarExpression::Empty => unreachable!(),
ScalarExpression::Tuple(_)
| ScalarExpression::Reference { .. }
| ScalarExpression::Empty => unreachable!(),
},
ScalarExpression::Constant(_)
| ScalarExpression::ColumnRef(_)
| ScalarExpression::AggCall { .. } => Ok(None),
ScalarExpression::Constant(_) | ScalarExpression::ColumnRef(_) => Ok(None),
// FIXME: support `convert_binary`
ScalarExpression::Tuple(_) | ScalarExpression::AggCall { .. } => Ok(None),
ScalarExpression::Reference { .. } | ScalarExpression::Empty => unreachable!(),
}
}
Expand Down
48 changes: 43 additions & 5 deletions src/expression/value_compute.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use crate::errors::DatabaseError;
use crate::expression::{BinaryOperator, UnaryOperator};
use crate::types::value::DataValue;
use crate::types::value::{DataValue, ValueRef};
use crate::types::LogicalType;
use regex::Regex;

Expand All @@ -18,6 +18,13 @@ fn unpack_utf8(value: DataValue) -> Option<String> {
}
}

fn unpack_tuple(value: DataValue) -> Option<Vec<ValueRef>> {
match value {
DataValue::Tuple(inner) => inner,
_ => None,
}
}

pub fn unary_op(value: &DataValue, op: &UnaryOperator) -> Result<DataValue, DatabaseError> {
let mut value_type = value.logical_type();
let mut value = value.clone();
Expand Down Expand Up @@ -169,7 +176,12 @@ macro_rules! numeric_binary_compute {

DataValue::Boolean(value)
}
_ => todo!("unsupported operator"),
_ => {
return Err(DatabaseError::UnsupportedBinaryOperator(
*$unified_type,
*$op,
))
}
}
};
}
Expand Down Expand Up @@ -446,7 +458,7 @@ pub fn binary_op(

DataValue::Boolean(value)
}
_ => todo!("unsupported operator"),
_ => return Err(DatabaseError::UnsupportedBinaryOperator(unified_type, *op)),
}
}
LogicalType::Boolean => {
Expand All @@ -472,7 +484,7 @@ pub fn binary_op(

DataValue::Boolean(value)
}
_ => todo!("unsupported operator"),
_ => return Err(DatabaseError::UnsupportedBinaryOperator(unified_type, *op)),
}
}
LogicalType::Varchar(_) => {
Expand Down Expand Up @@ -542,11 +554,37 @@ pub fn binary_op(

DataValue::Utf8(value)
}
_ => todo!("unsupported operator"),
_ => return Err(DatabaseError::UnsupportedBinaryOperator(unified_type, *op)),
}
}
LogicalType::SqlNull => return Ok(DataValue::Null),
LogicalType::Invalid => return Err(DatabaseError::InvalidType),
LogicalType::Tuple => {
let left_value = unpack_tuple(left.clone().cast(&unified_type)?);
let right_value = unpack_tuple(right.clone().cast(&unified_type)?);

match op {
BinaryOperator::Eq => {
let value = match (left_value, right_value) {
(Some(v1), Some(v2)) => Some(v1 == v2),
(None, None) => Some(true),
(_, _) => None,
};

DataValue::Boolean(value)
}
BinaryOperator::NotEq => {
let value = match (left_value, right_value) {
(Some(v1), Some(v2)) => Some(v1 != v2),
(None, None) => Some(false),
(_, _) => None,
};

DataValue::Boolean(value)
}
_ => return Err(DatabaseError::UnsupportedBinaryOperator(unified_type, *op)),
}
}
};

Ok(value)
Expand Down
1 change: 1 addition & 0 deletions src/optimizer/core/histogram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,7 @@ impl Histogram {
| LogicalType::Decimal(_, _) => {
value.clone().cast(&LogicalType::Double).unwrap().double()
}
LogicalType::Tuple => unreachable!(),
}
.unwrap_or(0.0)
};
Expand Down
4 changes: 3 additions & 1 deletion src/types/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ pub enum LogicalType {
DateTime,
// decimal (precision, scale)
Decimal(Option<u8>, Option<u8>),
Tuple,
}

impl LogicalType {
Expand Down Expand Up @@ -97,6 +98,7 @@ impl LogicalType {
LogicalType::Decimal(_, _) => Some(16),
LogicalType::Date => Some(4),
LogicalType::DateTime => Some(8),
LogicalType::Tuple => unreachable!(),
}
}

Expand Down Expand Up @@ -288,7 +290,7 @@ impl LogicalType {
LogicalType::Varchar(_) => false,
LogicalType::Date => matches!(to, LogicalType::DateTime | LogicalType::Varchar(_)),
LogicalType::DateTime => matches!(to, LogicalType::Date | LogicalType::Varchar(_)),
LogicalType::Decimal(_, _) => false,
LogicalType::Decimal(_, _) | LogicalType::Tuple => false,
}
}
}
Expand Down
Loading

0 comments on commit d1d5202

Please sign in to comment.