diff --git a/src/binder.rs b/src/binder.rs index b408cf6..d5b403d 100644 --- a/src/binder.rs +++ b/src/binder.rs @@ -13,7 +13,7 @@ use crate::{ UnaryOperator, UpdateStatementAST, AGGREGATE_FUNCTION_NAMES, }, tuple::Tuple, - value::{boolean::BooleanValue, Value}, + value::Value, }; #[derive(Debug, PartialEq, Eq, Clone)] @@ -719,26 +719,42 @@ impl Binder { } impl BoundExpressionAST { - pub fn eval(&self, tuples: &Vec<&Tuple>, schemas: &Vec<&Schema>) -> Value { + pub fn eval(&self, tuples: &Vec<&Tuple>, schemas: &Vec<&Schema>) -> Result { match self { BoundExpressionAST::Path(path_expression) => { let tuple = &tuples[path_expression.table_index]; let values = tuple.values(schemas[path_expression.table_index]); - values[path_expression.column_index].clone() + Ok(values[path_expression.column_index].clone()) } - BoundExpressionAST::Literal(literal_expression) => literal_expression.value.clone(), - BoundExpressionAST::Unary(_) => { - // let operand = unary_expression.operand.eval(tuples, schemas); - // TODO: - unimplemented!() + BoundExpressionAST::Literal(literal_expression) => Ok(literal_expression.value.clone()), + BoundExpressionAST::Unary(unary_expression) => { + let operand = unary_expression.operand.eval(tuples, schemas)?; + match unary_expression.operator { + UnaryOperator::Negate => operand.perform_negate(), + UnaryOperator::Not => operand.perform_not(), + UnaryOperator::IsNull => operand.perform_is_null(), + UnaryOperator::IsNotNull => operand.perform_is_not_null(), + } } BoundExpressionAST::Binary(binary_expression) => { - let left = binary_expression.left.eval(tuples, schemas); - let right = binary_expression.right.eval(tuples, schemas); + let left = binary_expression.left.eval(tuples, schemas)?; + let right = binary_expression.right.eval(tuples, schemas)?; match binary_expression.operator { - BinaryOperator::Equal => Value::Boolean(BooleanValue(left.perform_eq(&right))), - // TODO: implement other operators - _ => unimplemented!(), + BinaryOperator::Equal => left.perform_equal(&right), + BinaryOperator::NotEqual => left.perform_not_equal(&right), + BinaryOperator::LessThan => left.perform_less_than(&right), + BinaryOperator::LessThanOrEqual => left.perform_less_than_or_equal(&right), + BinaryOperator::GreaterThan => left.perform_greater_than(&right), + BinaryOperator::GreaterThanOrEqual => { + left.perform_greater_than_or_equal(&right) + } + BinaryOperator::Add => left.perform_add(&right), + BinaryOperator::Subtract => left.perform_subtract(&right), + BinaryOperator::Multiply => left.perform_multiply(&right), + BinaryOperator::Divide => left.perform_divide(&right), + BinaryOperator::Modulo => left.perform_modulo(&right), + BinaryOperator::And => left.perform_and(&right), + BinaryOperator::Or => left.perform_or(&right), } } // TODO: function call diff --git a/src/executor/aggregate_executor.rs b/src/executor/aggregate_executor.rs index be07bac..1b37125 100644 --- a/src/executor/aggregate_executor.rs +++ b/src/executor/aggregate_executor.rs @@ -3,9 +3,10 @@ use std::collections::HashMap; use anyhow::Result; use crate::{ + catalog::DataType, plan::AggregatePlan, tuple::Tuple, - value::{integer::IntegerValue, Value}, + value::{boolean::BooleanValue, integer::IntegerValue, Value}, }; use super::{Executor, ExecutorContext}; @@ -25,12 +26,16 @@ impl AggregateExecutor<'_> { while let Some(tuple) = self.child.next()? { let mut keys = vec![]; for expression in &self.plan.group_by { - keys.push(expression.eval(&vec![&tuple], &vec![&self.plan.child.schema()])); + keys.push(expression.eval(&vec![&tuple], &vec![&self.plan.child.schema()])?); } for (i, expression) in self.plan.aggregate_functions.iter().enumerate() { let value = match &*expression.function_name { "COUNT" => Value::Integer(IntegerValue(1)), - _ => unimplemented!(), + _ => expression + .arguments + .first() + .ok_or(anyhow::anyhow!("SUM argument error"))? + .eval(&vec![&tuple], &vec![&self.plan.child.schema()])?, }; self.aggregate_table.add( keys.clone(), @@ -40,7 +45,14 @@ impl AggregateExecutor<'_> { ); } } - self.result = self.aggregate_table.aggregate(); + self.result = self.aggregate_table.aggregate( + self.plan + .aggregate_functions + .clone() + .into_iter() + .map(|f| f.function_name) + .collect(), + )?; Ok(()) } pub fn next(&mut self) -> Result> { @@ -89,12 +101,12 @@ impl AggregateTable { } } - fn aggregate(&self) -> Vec> { + fn aggregate(&self, function_names: Vec) -> Result>> { let mut result = vec![]; for (key, value) in self.map.iter() { match value { AggregateTableValue::Table(table) => { - let mut rows = table.aggregate(); + let mut rows = table.aggregate(function_names.clone())?; for row in &mut rows { row.insert(0, key.clone()); } @@ -103,22 +115,95 @@ impl AggregateTable { AggregateTableValue::Value(values_list) => { let mut row = vec![]; row.push(key.clone()); - for values in values_list { - let mut sum = 0; - for value in values { - match value { - Value::Integer(v) => { - sum += v.0; + for (i, values) in values_list.iter().enumerate() { + match &*function_names[i] { + "COUNT" => { + let mut sum = 0; + for value in values { + if value.is_null_value() { + continue; + } + sum += 1; } - _ => unimplemented!(), + row.push(Value::Integer(IntegerValue(sum))); } + "SUM" => { + let mut sum = 0; + for value in values { + if value.is_null_value() { + continue; + } + match value.convert_to(&DataType::Integer)? { + Value::Integer(v) => { + sum += v.0; + } + _ => unimplemented!(), + } + } + row.push(Value::Integer(IntegerValue(sum))); + } + "MAX" => { + let mut max = Value::Integer(IntegerValue(i64::MIN)); + for value in values { + if value.is_null_value() { + continue; + } + match value.convert_to(&DataType::Integer)? { + Value::Integer(v) => { + if value.perform_greater_than(&max)? + == Value::Boolean(BooleanValue(true)) + { + max = Value::Integer(v); + } + } + _ => unimplemented!(), + } + } + row.push(max); + } + "MIN" => { + let mut min = Value::Integer(IntegerValue(i64::MAX)); + for value in values { + if value.is_null_value() { + continue; + } + match value.convert_to(&DataType::Integer)? { + Value::Integer(v) => { + if value.perform_less_than(&min)? + == Value::Boolean(BooleanValue(true)) + { + min = Value::Integer(v); + } + } + _ => unimplemented!(), + } + } + row.push(min); + } + "AVG" => { + let mut sum = 0; + let mut count = 0; + for value in values { + if value.is_null_value() { + continue; + } + match value.convert_to(&DataType::Integer)? { + Value::Integer(v) => { + sum += v.0; + count += 1; + } + _ => unimplemented!(), + } + } + row.push(Value::Integer(IntegerValue(sum / count))); + } + _ => Err(anyhow::anyhow!("unknown aggregate function error"))?, } - row.push(Value::Integer(IntegerValue(sum))); } result.push(row); } } } - result + Ok(result) } } diff --git a/src/executor/filter_executor.rs b/src/executor/filter_executor.rs index fca4d29..4dbeab3 100644 --- a/src/executor/filter_executor.rs +++ b/src/executor/filter_executor.rs @@ -26,7 +26,7 @@ impl FilterExecutor<'_> { if self .plan .condition - .eval(&tuples, &vec![&self.plan.child.schema()]) + .eval(&tuples, &vec![&self.plan.child.schema()])? == Value::Boolean(BooleanValue(true)) { return Ok(Some(row)); diff --git a/src/executor/insert_executor.rs b/src/executor/insert_executor.rs index f5349d4..c385591 100644 --- a/src/executor/insert_executor.rs +++ b/src/executor/insert_executor.rs @@ -31,7 +31,7 @@ impl InsertExecutor<'_> { let raw_value = self.plan.values[i].eval( &vec![&Tuple::new(None, &vec![])], &vec![&Schema { columns: vec![] }], - ); + )?; raw_value.convert_to(&c.data_type) }) .collect::>>()?; diff --git a/src/executor/nested_loop_join_executor.rs b/src/executor/nested_loop_join_executor.rs index e02505b..49b9f5a 100644 --- a/src/executor/nested_loop_join_executor.rs +++ b/src/executor/nested_loop_join_executor.rs @@ -60,7 +60,7 @@ impl NestedLoopJoinExecutor<'_> { // condition check let condition_result = self.plan.conditions[depth - 1].as_ref().map_or_else( - || true, + || Ok(true), |condition| { let tuples = self .tuples @@ -73,9 +73,11 @@ impl NestedLoopJoinExecutor<'_> { .iter() .map(|child| child.schema()) .collect::>(); - condition.eval(&tuples, &schemas) == Value::Boolean(BooleanValue(true)) + condition + .eval(&tuples, &schemas) + .map(|v| v == Value::Boolean(BooleanValue(true))) }, - ); + )?; if !condition_result { self.tuples[depth] = self.children[depth].next()?; @@ -133,7 +135,7 @@ impl NestedLoopJoinExecutor<'_> { } let condition_result = self.plan.conditions[depth - 1].as_ref().map_or_else( - || true, + || Ok(true), |condition| { // for left join dummy tuple let dummy = Tuple::temp_tuple(&vec![]); @@ -148,9 +150,11 @@ impl NestedLoopJoinExecutor<'_> { .iter() .map(|child| child.schema()) .collect::>(); - condition.eval(&tuples, &schemas) == Value::Boolean(BooleanValue(true)) + condition + .eval(&tuples, &schemas) + .map(|v| v == Value::Boolean(BooleanValue(true))) }, - ); + )?; if !condition_result { self.tuples[depth] = self.children[depth].next()?; diff --git a/src/executor/project_executor.rs b/src/executor/project_executor.rs index d5d5480..3aeb61e 100644 --- a/src/executor/project_executor.rs +++ b/src/executor/project_executor.rs @@ -1,6 +1,6 @@ use anyhow::Result; -use crate::{plan::ProjectPlan, tuple::Tuple, value::Value}; +use crate::{plan::ProjectPlan, tuple::Tuple}; use super::{Executor, ExecutorContext}; @@ -28,7 +28,7 @@ impl ProjectExecutor<'_> { .expression .eval(&tuples, &vec![&self.plan.child.schema()]) }) - .collect::>(); + .collect::>>()?; return Ok(Some(Tuple::temp_tuple(&values))); } Ok(None) diff --git a/src/executor/update_executor.rs b/src/executor/update_executor.rs index 1c50053..612cc8d 100644 --- a/src/executor/update_executor.rs +++ b/src/executor/update_executor.rs @@ -28,7 +28,7 @@ impl UpdateExecutor<'_> { for assignment in self.plan.assignments.iter() { new_values[assignment.column_index] = assignment .value - .eval(&vec![&row], &vec![&self.plan.child.schema()]); + .eval(&vec![&row], &vec![&self.plan.child.schema()])?; } self.table_heap.delete(rid)?; self.table_heap.insert(&new_values)?; diff --git a/src/parser.rs b/src/parser.rs index 64d33a3..42b09a2 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -130,8 +130,7 @@ pub struct UnaryExpressionAST { } #[derive(Debug, PartialEq, Eq, Clone)] pub enum UnaryOperator { - Plus, - Minus, + Negate, Not, IsNull, IsNotNull, @@ -150,11 +149,11 @@ pub enum BinaryOperator { LessThanOrEqual, GreaterThan, GreaterThanOrEqual, - Plus, - Minus, - Asterisk, - Slash, - Percent, + Add, + Subtract, + Multiply, + Divide, + Modulo, And, Or, } @@ -579,9 +578,9 @@ impl Parser { fn arithmetic_expression(&mut self) -> Result { let left = self.term_expression()?; let operator = if self.consume_token(Token::Plus) { - BinaryOperator::Plus + BinaryOperator::Add } else if self.consume_token(Token::Minus) { - BinaryOperator::Minus + BinaryOperator::Subtract } else { return Ok(left); }; @@ -595,11 +594,11 @@ impl Parser { fn term_expression(&mut self) -> Result { let left = self.factor_expression()?; let operator = if self.consume_token(Token::Asterisk) { - BinaryOperator::Asterisk + BinaryOperator::Multiply } else if self.consume_token(Token::Slash) { - BinaryOperator::Slash + BinaryOperator::Divide } else if self.consume_token(Token::Percent) { - BinaryOperator::Percent + BinaryOperator::Modulo } else { return Ok(left); }; @@ -620,19 +619,11 @@ impl Parser { let path = self.path_expression()?; Ok(ExpressionAST::Path(path)) } - Token::Plus => { - self.consume_token_or_error(Token::Plus)?; - let operand = self.factor_expression()?; - Ok(ExpressionAST::Unary(UnaryExpressionAST { - operator: UnaryOperator::Plus, - operand: Box::new(operand), - })) - } Token::Minus => { self.consume_token_or_error(Token::Minus)?; let operand = self.factor_expression()?; Ok(ExpressionAST::Unary(UnaryExpressionAST { - operator: UnaryOperator::Minus, + operator: UnaryOperator::Negate, operand: Box::new(operand), })) } @@ -1165,7 +1156,6 @@ mod tests { is_deleted AND True, is_deleted OR True, NOT is_deleted, - +age, -age, COUNT(id), foo.bar, @@ -1186,7 +1176,7 @@ mod tests { assert_eq!( select_statement.select_elements[0].expression, ExpressionAST::Binary(BinaryExpressionAST { - operator: BinaryOperator::Plus, + operator: BinaryOperator::Add, left: Box::new(ExpressionAST::Path(PathExpressionAST { path: vec![String::from("age")], })), @@ -1198,7 +1188,7 @@ mod tests { assert_eq!( select_statement.select_elements[1].expression, ExpressionAST::Binary(BinaryExpressionAST { - operator: BinaryOperator::Minus, + operator: BinaryOperator::Subtract, left: Box::new(ExpressionAST::Path(PathExpressionAST { path: vec![String::from("age")], })), @@ -1210,7 +1200,7 @@ mod tests { assert_eq!( select_statement.select_elements[2].expression, ExpressionAST::Binary(BinaryExpressionAST { - operator: BinaryOperator::Asterisk, + operator: BinaryOperator::Multiply, left: Box::new(ExpressionAST::Path(PathExpressionAST { path: vec![String::from("age")], })), @@ -1222,7 +1212,7 @@ mod tests { assert_eq!( select_statement.select_elements[3].expression, ExpressionAST::Binary(BinaryExpressionAST { - operator: BinaryOperator::Slash, + operator: BinaryOperator::Divide, left: Box::new(ExpressionAST::Path(PathExpressionAST { path: vec![String::from("age")], })), @@ -1234,7 +1224,7 @@ mod tests { assert_eq!( select_statement.select_elements[4].expression, ExpressionAST::Binary(BinaryExpressionAST { - operator: BinaryOperator::Percent, + operator: BinaryOperator::Modulo, left: Box::new(ExpressionAST::Path(PathExpressionAST { path: vec![String::from("age")], })), @@ -1351,7 +1341,7 @@ mod tests { assert_eq!( select_statement.select_elements[14].expression, ExpressionAST::Unary(UnaryExpressionAST { - operator: UnaryOperator::Plus, + operator: UnaryOperator::Negate, operand: Box::new(ExpressionAST::Path(PathExpressionAST { path: vec![String::from("age")], })), @@ -1359,15 +1349,6 @@ mod tests { ); assert_eq!( select_statement.select_elements[15].expression, - ExpressionAST::Unary(UnaryExpressionAST { - operator: UnaryOperator::Minus, - operand: Box::new(ExpressionAST::Path(PathExpressionAST { - path: vec![String::from("age")], - })), - }) - ); - assert_eq!( - select_statement.select_elements[16].expression, ExpressionAST::FunctionCall(FunctionCallExpressionAST { function_name: String::from("COUNT"), arguments: vec![ExpressionAST::Path(PathExpressionAST { @@ -1376,41 +1357,41 @@ mod tests { }) ); assert_eq!( - select_statement.select_elements[17].expression, + select_statement.select_elements[16].expression, ExpressionAST::Path(PathExpressionAST { path: vec![String::from("foo"), String::from("bar")], }) ); assert_eq!( - select_statement.select_elements[18].expression, + select_statement.select_elements[17].expression, ExpressionAST::Literal(LiteralExpressionAST { value: Value::Integer(IntegerValue(1)), }) ); assert_eq!( - select_statement.select_elements[19].expression, + select_statement.select_elements[18].expression, ExpressionAST::Literal(LiteralExpressionAST { value: Value::Varchar(VarcharValue(String::from("foo"))), }) ); assert_eq!( - select_statement.select_elements[20].expression, + select_statement.select_elements[19].expression, ExpressionAST::Literal(LiteralExpressionAST { value: Value::Boolean(BooleanValue(true)), }) ); assert_eq!( - select_statement.select_elements[21].expression, + select_statement.select_elements[20].expression, ExpressionAST::Literal(LiteralExpressionAST { value: Value::Null }) ); assert_eq!( - select_statement.select_elements[22].expression, + select_statement.select_elements[21].expression, ExpressionAST::Path(PathExpressionAST { path: vec![String::from("age")], }) ); assert_eq!( - select_statement.select_elements[23].expression, + select_statement.select_elements[22].expression, ExpressionAST::Unary(UnaryExpressionAST { operator: UnaryOperator::IsNull, operand: Box::new(ExpressionAST::Path(PathExpressionAST { @@ -1419,7 +1400,7 @@ mod tests { }) ); assert_eq!( - select_statement.select_elements[24].expression, + select_statement.select_elements[23].expression, ExpressionAST::Unary(UnaryExpressionAST { operator: UnaryOperator::IsNotNull, operand: Box::new(ExpressionAST::Path(PathExpressionAST { diff --git a/src/value.rs b/src/value.rs index c1fcf01..f8ac16d 100644 --- a/src/value.rs +++ b/src/value.rs @@ -53,22 +53,242 @@ impl Value { DataType::Boolean => Value::Boolean(BooleanValue::from(bytes)), } } - pub fn perform_eq(&self, other: &Self) -> bool { - match self { - Value::Integer(value) => value.perform_equal(other), - Value::Varchar(value) => value.perform_equal(other), - Value::Boolean(value) => value.perform_equal(other), - Value::Null => false, - } - } + pub fn convert_to(&self, data_type: &DataType) -> Result { match self { Value::Integer(value) => value.convert_to(data_type), Value::Varchar(value) => value.convert_to(data_type), Value::Boolean(value) => value.convert_to(data_type), - Value::Null => Some(Value::Null), + Value::Null => Err(anyhow!("Cannot convert NULL to {:?}", data_type)), + } + } + + // unary operators + pub fn perform_is_null(&self) -> Result { + match self { + Value::Null => Ok(Value::Boolean(BooleanValue(true))), + _ => Ok(Value::Boolean(BooleanValue(false))), + } + } + pub fn perform_is_not_null(&self) -> Result { + match self { + Value::Null => Ok(Value::Boolean(BooleanValue(false))), + _ => Ok(Value::Boolean(BooleanValue(true))), + } + } + pub fn perform_not(&self) -> Result { + if let Value::Null = self { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Boolean)? { + Value::Boolean(value) => Ok(Value::Boolean(value.perform_not())), + _ => unreachable!(), + } + } + pub fn perform_negate(&self) -> Result { + if self.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => Ok(Value::Integer(value.perform_negate()?)), + _ => unreachable!(), + } + } + + pub fn perform_equal(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match (self, other) { + (Value::Varchar(value), Value::Varchar(other_value)) => { + Ok(Value::Boolean(value.perform_equal(other_value))) + } + _ => match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => { + Ok(Value::Boolean(value.perform_equal(&other_value))) + } + _ => unreachable!(), + }, + _ => unreachable!(), + }, + } + } + pub fn perform_not_equal(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match (self, other) { + (Value::Varchar(value), Value::Varchar(other_value)) => { + Ok(Value::Boolean(value.perform_not_equal(other_value))) + } + _ => match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => { + Ok(Value::Boolean(value.perform_not_equal(&other_value))) + } + _ => unreachable!(), + }, + _ => unreachable!(), + }, + } + } + pub fn perform_less_than(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => { + Ok(Value::Boolean(value.perform_less_than(&other_value))) + } + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + pub fn perform_less_than_or_equal(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => Ok(Value::Boolean( + value.perform_less_than_or_equal(&other_value), + )), + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + pub fn perform_greater_than(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => { + Ok(Value::Boolean(value.perform_greater_than(&other_value))) + } + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + pub fn perform_greater_than_or_equal(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => Ok(Value::Boolean( + value.perform_greater_than_or_equal(&other_value), + )), + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + + // binary operators + pub fn perform_add(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => Ok(Value::Integer(value.perform_add(&other_value)?)), + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + pub fn perform_subtract(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => { + Ok(Value::Integer(value.perform_subtract(&other_value)?)) + } + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + pub fn perform_multiply(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => { + Ok(Value::Integer(value.perform_multiply(&other_value)?)) + } + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + pub fn perform_divide(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => { + Ok(Value::Integer(value.perform_divide(&other_value)?)) + } + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + pub fn perform_modulo(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Integer)? { + Value::Integer(value) => match other.convert_to(&DataType::Integer)? { + Value::Integer(other_value) => { + Ok(Value::Integer(value.perform_modulo(&other_value)?)) + } + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + pub fn perform_and(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Boolean)? { + Value::Boolean(value) => match other.convert_to(&DataType::Boolean)? { + Value::Boolean(other_value) => Ok(Value::Boolean(value.perform_and(&other_value))), + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + pub fn perform_or(&self, other: &Value) -> Result { + if self.is_null_value() || other.is_null_value() { + return Ok(Value::Null); + } + match self.convert_to(&DataType::Boolean)? { + Value::Boolean(value) => match other.convert_to(&DataType::Boolean)? { + Value::Boolean(other_value) => Ok(Value::Boolean(value.perform_or(&other_value))), + _ => unreachable!(), + }, + _ => unreachable!(), + } + } + + pub fn is_null_value(&self) -> bool { + match self { + Value::Null => true, + _ => false, } - .ok_or(anyhow!("Cannot convert {:?} to {:?}", self, data_type)) } } diff --git a/src/value/boolean.rs b/src/value/boolean.rs index cd8b810..42b0963 100644 --- a/src/value/boolean.rs +++ b/src/value/boolean.rs @@ -1,3 +1,5 @@ +use anyhow::Result; + use crate::catalog::DataType; use super::{integer::IntegerValue, varchar::VarcharValue, Value}; @@ -21,19 +23,21 @@ impl BooleanValue { 1 } - pub fn convert_to(&self, data_type: &DataType) -> Option { + pub fn convert_to(&self, data_type: &DataType) -> Result { match data_type { - DataType::Integer => Some(Value::Integer(IntegerValue(if self.0 { 1 } else { 0 }))), - DataType::Varchar => Some(Value::Varchar(VarcharValue(self.0.to_string()))), - DataType::Boolean => Some(Value::Boolean(BooleanValue(self.0))), + DataType::Integer => Ok(Value::Integer(IntegerValue(if self.0 { 1 } else { 0 }))), + DataType::Varchar => Ok(Value::Varchar(VarcharValue(self.0.to_string()))), + DataType::Boolean => Ok(Value::Boolean(BooleanValue(self.0))), } } - pub fn perform_equal(&self, other: &Value) -> bool { - match other { - Value::Integer(other) => self.0 == (other.0 != 0), - Value::Boolean(other) => self.0 == other.0, - _ => false, - } + pub fn perform_not(&self) -> BooleanValue { + BooleanValue(!self.0) + } + pub fn perform_and(&self, other: &BooleanValue) -> BooleanValue { + BooleanValue(self.0 && other.0) + } + pub fn perform_or(&self, other: &BooleanValue) -> BooleanValue { + BooleanValue(self.0 || other.0) } } diff --git a/src/value/integer.rs b/src/value/integer.rs index f248449..98640a8 100644 --- a/src/value/integer.rs +++ b/src/value/integer.rs @@ -1,3 +1,5 @@ +use anyhow::Result; + use crate::catalog::DataType; use super::{boolean::BooleanValue, varchar::VarcharValue, Value}; @@ -22,48 +24,66 @@ impl IntegerValue { 8 } - pub fn convert_to(&self, data_type: &DataType) -> Option { + pub fn convert_to(&self, data_type: &DataType) -> Result { match data_type { - DataType::Integer => Some(Value::Integer(IntegerValue(self.0))), - DataType::Varchar => Some(Value::Varchar(VarcharValue(self.0.to_string()))), - DataType::Boolean => Some(Value::Boolean(BooleanValue(self.0 != 0))), + DataType::Integer => Ok(Value::Integer(IntegerValue(self.0))), + DataType::Varchar => Ok(Value::Varchar(VarcharValue(self.0.to_string()))), + DataType::Boolean => Ok(Value::Boolean(BooleanValue(self.0 != 0))), } } - pub fn perform_equal(&self, other: &Value) -> bool { - match other { - Value::Integer(other) => self.0 == other.0, - _ => false, - } + pub fn perform_negate(&self) -> Result { + self.0.checked_neg().map_or_else( + || Err(anyhow::anyhow!("Integer overflow")), + |value| Ok(IntegerValue(value)), + ) } - pub fn perform_not_equal(&self, other: &Value) -> bool { - match other { - Value::Integer(other) => self.0 != other.0, - _ => true, - } + pub fn perform_add(&self, other: &IntegerValue) -> Result { + self.0.checked_add(other.0).map_or_else( + || Err(anyhow::anyhow!("Integer overflow")), + |value| Ok(IntegerValue(value)), + ) } - pub fn perform_less_than(&self, other: &Value) -> bool { - match other { - Value::Integer(other) => self.0 < other.0, - _ => false, - } + pub fn perform_subtract(&self, other: &IntegerValue) -> Result { + self.0.checked_sub(other.0).map_or_else( + || Err(anyhow::anyhow!("Integer overflow")), + |value| Ok(IntegerValue(value)), + ) } - pub fn perform_less_than_or_equal(&self, other: &Value) -> bool { - match other { - Value::Integer(other) => self.0 <= other.0, - _ => false, - } + pub fn perform_multiply(&self, other: &IntegerValue) -> Result { + self.0.checked_mul(other.0).map_or_else( + || Err(anyhow::anyhow!("Integer overflow")), + |value| Ok(IntegerValue(value)), + ) } - pub fn perform_greater_than(&self, other: &Value) -> bool { - match other { - Value::Integer(other) => self.0 > other.0, - _ => false, - } + pub fn perform_divide(&self, other: &IntegerValue) -> Result { + self.0.checked_div(other.0).map_or_else( + || Err(anyhow::anyhow!("Integer overflow")), + |value| Ok(IntegerValue(value)), + ) } - pub fn perform_greater_than_or_equal(&self, other: &Value) -> bool { - match other { - Value::Integer(other) => self.0 >= other.0, - _ => false, - } + pub fn perform_modulo(&self, other: &IntegerValue) -> Result { + self.0.checked_rem(other.0).map_or_else( + || Err(anyhow::anyhow!("Integer overflow")), + |value| Ok(IntegerValue(value)), + ) + } + pub fn perform_equal(&self, other: &IntegerValue) -> BooleanValue { + BooleanValue(self.0 == other.0) + } + pub fn perform_not_equal(&self, other: &IntegerValue) -> BooleanValue { + BooleanValue(self.0 != other.0) + } + pub fn perform_less_than(&self, other: &IntegerValue) -> BooleanValue { + BooleanValue(self.0 < other.0) + } + pub fn perform_less_than_or_equal(&self, other: &IntegerValue) -> BooleanValue { + BooleanValue(self.0 <= other.0) + } + pub fn perform_greater_than(&self, other: &IntegerValue) -> BooleanValue { + BooleanValue(self.0 > other.0) + } + pub fn perform_greater_than_or_equal(&self, other: &IntegerValue) -> BooleanValue { + BooleanValue(self.0 >= other.0) } } diff --git a/src/value/varchar.rs b/src/value/varchar.rs index 48d60bd..4cabc26 100644 --- a/src/value/varchar.rs +++ b/src/value/varchar.rs @@ -1,3 +1,5 @@ +use anyhow::Result; + use crate::catalog::DataType; use super::{boolean::BooleanValue, integer::IntegerValue, Value}; @@ -33,26 +35,18 @@ impl VarcharValue { 4 + self.0.len() } - pub fn convert_to(&self, data_type: &DataType) -> Option { + pub fn convert_to(&self, data_type: &DataType) -> Result { match data_type { - DataType::Integer => self - .0 - .parse::() - .ok() - .map(|v| Value::Integer(IntegerValue(v))), - DataType::Varchar => Some(Value::Varchar(self.clone())), - DataType::Boolean => self - .0 - .parse::() - .ok() - .map(|v| Value::Boolean(BooleanValue(v))), + DataType::Integer => Ok(Value::Integer(IntegerValue(0))), + DataType::Varchar => Ok(Value::Varchar(self.clone())), + DataType::Boolean => Ok(Value::Boolean(BooleanValue(false))), } } - pub fn perform_equal(&self, other: &Value) -> bool { - match other { - Value::Varchar(other) => self.0 == other.0, - _ => false, - } + pub fn perform_equal(&self, other: &VarcharValue) -> BooleanValue { + BooleanValue(self.0 == other.0) + } + pub fn perform_not_equal(&self, other: &VarcharValue) -> BooleanValue { + BooleanValue(self.0 != other.0) } }