Skip to content

Commit f217f70

Browse files
authored
feat: add expression_evaluation.rs and add arithmetic to proof_of_sql_parser::utility (#81)
# Rationale for this change This PR replaces #56 since we made substantial changes to evaluations in #70, #74, #76 and #78. Please review #87 first or look at the second commit. <!-- Why are you proposing this change? If this is already explained clearly in the linked Jira ticket then this section is not needed. Explaining clearly why changes are proposed helps reviewers understand your changes and offer better suggestions for fixes. --> # What changes are included in this PR? - add `PostprocessingEvaluator` - add arithmetic to `proof_of_sql_parser::utility` <!-- There is no need to duplicate the description in the ticket here but it is sometimes worth providing a summary of the individual changes in this PR. --> # Are these changes tested? Yes <!-- We typically require tests for all PRs in order to: 1. Prevent the code from being accidentally broken by subsequent changes 2. Serve as another way to document the expected behavior of the code If tests are not included in your PR, please explain why (for example, are they covered by existing tests)? -->
1 parent c3feb4b commit f217f70

File tree

5 files changed

+406
-0
lines changed

5 files changed

+406
-0
lines changed

crates/proof-of-sql-parser/src/utility.rs

+36
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,42 @@ pub fn or(left: Box<Expression>, right: Box<Expression>) -> Box<Expression> {
5353
})
5454
}
5555

56+
/// Construct a new boxed `Expression` A + B
57+
pub fn add(left: Box<Expression>, right: Box<Expression>) -> Box<Expression> {
58+
Box::new(Expression::Binary {
59+
op: BinaryOperator::Add,
60+
left,
61+
right,
62+
})
63+
}
64+
65+
/// Construct a new boxed `Expression` A - B
66+
pub fn sub(left: Box<Expression>, right: Box<Expression>) -> Box<Expression> {
67+
Box::new(Expression::Binary {
68+
op: BinaryOperator::Subtract,
69+
left,
70+
right,
71+
})
72+
}
73+
74+
/// Construct a new boxed `Expression` A * B
75+
pub fn mul(left: Box<Expression>, right: Box<Expression>) -> Box<Expression> {
76+
Box::new(Expression::Binary {
77+
op: BinaryOperator::Multiply,
78+
left,
79+
right,
80+
})
81+
}
82+
83+
/// Construct a new boxed `Expression` A / B
84+
pub fn div(left: Box<Expression>, right: Box<Expression>) -> Box<Expression> {
85+
Box::new(Expression::Binary {
86+
op: BinaryOperator::Division,
87+
left,
88+
right,
89+
})
90+
}
91+
5692
/// Get table from schema and name.
5793
///
5894
/// If the schema is `None`, the table is assumed to be in the default schema.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
use super::{ExpressionEvaluationError, ExpressionEvaluationResult};
2+
use crate::base::{
3+
database::{OwnedColumn, OwnedTable},
4+
math::decimal::{try_into_to_scalar, Precision},
5+
scalar::Scalar,
6+
};
7+
use proof_of_sql_parser::{
8+
intermediate_ast::{BinaryOperator, Expression, Literal, UnaryOperator},
9+
Identifier,
10+
};
11+
12+
impl<S: Scalar> OwnedTable<S> {
13+
/// Evaluate an expression on the table.
14+
pub fn evaluate(&self, expr: &Expression) -> ExpressionEvaluationResult<OwnedColumn<S>> {
15+
match expr {
16+
Expression::Column(identifier) => self.evaluate_column(identifier),
17+
Expression::Literal(lit) => self.evaluate_literal(lit),
18+
Expression::Binary { op, left, right } => self.evaluate_binary_expr(*op, left, right),
19+
Expression::Unary { op, expr } => self.evaluate_unary_expr(*op, expr),
20+
_ => Err(ExpressionEvaluationError::Unsupported(format!(
21+
"Expression {:?} is not supported yet",
22+
expr
23+
))),
24+
}
25+
}
26+
27+
fn evaluate_column(
28+
&self,
29+
identifier: &Identifier,
30+
) -> ExpressionEvaluationResult<OwnedColumn<S>> {
31+
Ok(self
32+
.inner_table()
33+
.get(identifier)
34+
.ok_or(ExpressionEvaluationError::ColumnNotFound(
35+
identifier.to_string(),
36+
))?
37+
.clone())
38+
}
39+
40+
fn evaluate_literal(&self, lit: &Literal) -> ExpressionEvaluationResult<OwnedColumn<S>> {
41+
let len = self.num_rows();
42+
match lit {
43+
Literal::Boolean(b) => Ok(OwnedColumn::Boolean(vec![*b; len])),
44+
Literal::BigInt(i) => Ok(OwnedColumn::BigInt(vec![*i; len])),
45+
Literal::Int128(i) => Ok(OwnedColumn::Int128(vec![*i; len])),
46+
Literal::Decimal(d) => {
47+
let scale = d.scale();
48+
let precision = Precision::new(d.precision())?;
49+
let scalar = try_into_to_scalar(d, precision, scale)?;
50+
Ok(OwnedColumn::Decimal75(precision, scale, vec![scalar; len]))
51+
}
52+
Literal::VarChar(s) => Ok(OwnedColumn::VarChar(vec![s.clone(); len])),
53+
Literal::Timestamp(its) => Ok(OwnedColumn::TimestampTZ(
54+
its.timeunit(),
55+
its.timezone(),
56+
vec![its.timestamp().timestamp(); len],
57+
)),
58+
}
59+
}
60+
61+
fn evaluate_unary_expr(
62+
&self,
63+
op: UnaryOperator,
64+
expr: &Expression,
65+
) -> ExpressionEvaluationResult<OwnedColumn<S>> {
66+
let column = self.evaluate(expr)?;
67+
match op {
68+
UnaryOperator::Not => Ok(column.element_wise_not()?),
69+
}
70+
}
71+
72+
fn evaluate_binary_expr(
73+
&self,
74+
op: BinaryOperator,
75+
left: &Expression,
76+
right: &Expression,
77+
) -> ExpressionEvaluationResult<OwnedColumn<S>> {
78+
let left = self.evaluate(left)?;
79+
let right = self.evaluate(right)?;
80+
match op {
81+
BinaryOperator::And => Ok(left.element_wise_and(&right)?),
82+
BinaryOperator::Or => Ok(left.element_wise_or(&right)?),
83+
BinaryOperator::Equal => Ok(left.element_wise_eq(&right)?),
84+
BinaryOperator::GreaterThanOrEqual => Ok(left.element_wise_ge(&right)?),
85+
BinaryOperator::LessThanOrEqual => Ok(left.element_wise_le(&right)?),
86+
BinaryOperator::Add => Ok((left + right)?),
87+
BinaryOperator::Subtract => Ok((left - right)?),
88+
BinaryOperator::Multiply => Ok((left * right)?),
89+
BinaryOperator::Division => Ok((left / right)?),
90+
}
91+
}
92+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
use crate::base::{database::ColumnOperationError, math::decimal::DecimalError};
2+
use thiserror::Error;
3+
4+
/// Errors from evaluation of `Expression`s.
5+
#[derive(Error, Debug, PartialEq, Eq)]
6+
pub enum ExpressionEvaluationError {
7+
/// Column not found
8+
#[error("Column not found: {0}")]
9+
ColumnNotFound(String),
10+
/// Error in column operation
11+
#[error(transparent)]
12+
ColumnOperationError(#[from] ColumnOperationError),
13+
/// Expression not yet supported
14+
#[error("Expression {0} is not supported yet")]
15+
Unsupported(String),
16+
/// Error in decimal conversion
17+
#[error(transparent)]
18+
DecimalConversionError(#[from] DecimalError),
19+
}
20+
21+
/// Result type for expression evaluation
22+
pub type ExpressionEvaluationResult<T> = std::result::Result<T, ExpressionEvaluationError>;

0 commit comments

Comments
 (0)