diff --git a/src/db/eval.rs b/src/db/eval.rs index dbcd0021..32bcfb1b 100644 --- a/src/db/eval.rs +++ b/src/db/eval.rs @@ -13,96 +13,423 @@ use crate::relation::table::MegaTuple; use crate::relation::value; -impl<'s> Session<'s> { - pub fn tuple_eval<'a>(&self, value: &'a Value<'a>, tuples: &'a MegaTuple) -> Result> { - let res: Value = match value { - v @ (Value::Null | - Value::Bool(_) | - Value::Int(_) | - Value::Float(_) | - Value::Uuid(_) | - Value::Text(_)) => v.clone(), - Value::List(l) => { - let l = l.into_iter().map(|v| self.tuple_eval(v, tuples)).collect::>>()?; - Value::List(l) - } - Value::Dict(d) => { - let d = d.into_iter() - .map(|(k, v)| - self.tuple_eval(v, tuples).map(|v| (k.clone(), v))) - .collect::>>()?; - Value::Dict(d) - } - Value::Variable(v) => { - return Err(LogicError(format!("Cannot resolve variable {}", v))); - } - Value::TupleRef(tid, cid) => { - let targets = if cid.is_key { &tuples.keys } else { &tuples.vals }; - let target = targets.get(tid.id as usize).ok_or_else(|| { - LogicError("Tuple ref out of bound".to_string()) - })?; - if matches!(target.data_kind(), Ok(DataKind::Empty)) { - Value::Null - } else { - target.get(cid.id as usize) - .ok_or_else(|| LogicError("Tuple ref out of bound".to_string()))? - } +pub fn tuple_eval<'a>(value: &'a Value<'a>, tuples: &'a MegaTuple) -> Result> { + let res: Value = match value { + v @ (Value::Null | + Value::Bool(_) | + Value::Int(_) | + Value::Float(_) | + Value::Uuid(_) | + Value::Text(_)) => v.clone(), + Value::List(l) => { + let l = l.into_iter().map(|v| tuple_eval(v, tuples)).collect::>>()?; + Value::List(l) + } + Value::Dict(d) => { + let d = d.into_iter() + .map(|(k, v)| + tuple_eval(v, tuples).map(|v| (k.clone(), v))) + .collect::>>()?; + Value::Dict(d) + } + Value::Variable(v) => { + return Err(LogicError(format!("Cannot resolve variable {}", v))); + } + Value::TupleRef(tid, cid) => { + let targets = if cid.is_key { &tuples.keys } else { &tuples.vals }; + let target = targets.get(tid.id as usize).ok_or_else(|| { + LogicError("Tuple ref out of bound".to_string()) + })?; + if matches!(target.data_kind(), Ok(DataKind::Empty)) { + Value::Null + } else { + target.get(cid.id as usize) + .ok_or_else(|| LogicError("Tuple ref out of bound".to_string()))? } - Value::Apply(op, args) => { - match op.as_ref() { - value::OP_STR_CAT => self.str_cat_values(args, tuples)?, - value::OP_ADD => self.add_values(args, tuples)?, - value::OP_SUB => self.sub_values(args, tuples)?, - value::OP_MUL => self.mul_values(args, tuples)?, - value::OP_DIV => self.div_values(args, tuples)?, - value::OP_EQ => self.eq_values(args, tuples)?, - value::OP_NE => self.ne_values(args, tuples)?, - value::OP_OR => self.or_values(args, tuples)?, - value::OP_AND => self.and_values(args, tuples)?, - value::OP_MOD => self.mod_values(args, tuples)?, - value::OP_GT => self.gt_values(args, tuples)?, - value::OP_GE => self.ge_values(args, tuples)?, - value::OP_LT => self.lt_values(args, tuples)?, - value::OP_LE => self.le_values(args, tuples)?, - value::OP_POW => self.pow_values(args, tuples)?, - value::OP_COALESCE => self.coalesce_values(args, tuples)?, - value::OP_NEGATE => self.negate_values(args, tuples)?, - value::OP_MINUS => self.minus_values(args, tuples)?, - value::METHOD_IS_NULL => self.is_null_values(args, tuples)?, - value::METHOD_NOT_NULL => self.not_null_values(args, tuples)?, - value::METHOD_CONCAT => self.concat_values(args, tuples)?, - value::METHOD_MERGE => self.merge_values(args, tuples)?, - _ => { todo!() } - } + } + Value::Apply(op, args) => { + match op.as_ref() { + value::OP_STR_CAT => str_cat_values(args, tuples)?, + value::OP_ADD => add_values(args, tuples)?, + value::OP_SUB => sub_values(args, tuples)?, + value::OP_MUL => mul_values(args, tuples)?, + value::OP_DIV => div_values(args, tuples)?, + value::OP_EQ => eq_values(args, tuples)?, + value::OP_NE => ne_values(args, tuples)?, + value::OP_OR => or_values(args, tuples)?, + value::OP_AND => and_values(args, tuples)?, + value::OP_MOD => mod_values(args, tuples)?, + value::OP_GT => gt_values(args, tuples)?, + value::OP_GE => ge_values(args, tuples)?, + value::OP_LT => lt_values(args, tuples)?, + value::OP_LE => le_values(args, tuples)?, + value::OP_POW => pow_values(args, tuples)?, + value::OP_COALESCE => coalesce_values(args, tuples)?, + value::OP_NEGATE => negate_values(args, tuples)?, + value::OP_MINUS => minus_values(args, tuples)?, + value::METHOD_IS_NULL => is_null_values(args, tuples)?, + value::METHOD_NOT_NULL => not_null_values(args, tuples)?, + value::METHOD_CONCAT => concat_values(args, tuples)?, + value::METHOD_MERGE => merge_values(args, tuples)?, + _ => { todo!() } } - Value::FieldAccess(field, arg) => { - let arg = self.tuple_eval(arg, tuples)?; - match arg { - Value::Dict(mut d) => { - d.remove(field.as_ref()).unwrap_or(Value::Null) - } - _ => return Err(LogicError("Field access failed".to_string())) + } + Value::FieldAccess(field, arg) => { + let arg = tuple_eval(arg, tuples)?; + match arg { + Value::Dict(mut d) => { + d.remove(field.as_ref()).unwrap_or(Value::Null) } + _ => return Err(LogicError("Field access failed".to_string())) } - Value::IdxAccess(idx, arg) => { - let arg = self.tuple_eval(arg, tuples)?; - match arg { - Value::List(mut l) => { - if *idx >= l.len() { - Value::Null - } else { - l.swap_remove(*idx) - } + } + Value::IdxAccess(idx, arg) => { + let arg = tuple_eval(arg, tuples)?; + match arg { + Value::List(mut l) => { + if *idx >= l.len() { + Value::Null + } else { + l.swap_remove(*idx) } - _ => return Err(LogicError("Idx access failed".to_string())) } + _ => return Err(LogicError("Idx access failed".to_string())) } - Value::EndSentinel => { - return Err(LogicError("Encountered end sentinel".to_string())); - } - }; - Ok(res) + } + Value::EndSentinel => { + return Err(LogicError("Encountered end sentinel".to_string())); + } + }; + Ok(res) +} + +fn coalesce_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + for v in args { + match tuple_eval(v, tuples)? { + Value::Null => {} + v => return Ok(v) + } } + Ok(Value::Null) +} + + +fn str_cat_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut ret = String::new(); + for v in args { + let v = tuple_eval(v, tuples)?; + match v { + Value::Null => return Ok(Value::Null), + Value::Text(s) => ret += s.as_ref(), + _ => return Err(InvalidArgument) + } + }; + Ok(ret.into()) +} + +fn add_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok(match (left, right) { + (Value::Int(l), Value::Int(r)) => (l + r).into(), + (Value::Float(l), Value::Int(r)) => (l + (r as f64)).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) + r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l.into_inner() + r.into_inner()).into(), + (_, _) => return Err(CozoError::InvalidArgument) + }) +} + +fn sub_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok(match (left, right) { + (Value::Int(l), Value::Int(r)) => (l + r).into(), + (Value::Float(l), Value::Int(r)) => (l - (r as f64)).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) - r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l.into_inner() - r.into_inner()).into(), + (_, _) => return Err(CozoError::InvalidArgument) + }) +} + +fn minus_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let left = tuple_eval(args.get(0).unwrap(), tuples)?; + Ok(match left { + Value::Int(l) => (-l).into(), + Value::Float(l) => (-l).into(), + _ => return Err(CozoError::InvalidArgument) + }) +} + +fn negate_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let left = tuple_eval(args.get(0).unwrap(), tuples)?; + Ok(match left { + Value::Bool(l) => (!l).into(), + _ => return Err(CozoError::InvalidArgument) + }) +} + +fn is_null_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let left = tuple_eval(args.get(0).unwrap(), tuples)?; + Ok((left == Value::Null).into()) +} + +fn not_null_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let left = tuple_eval(args.get(0).unwrap(), tuples)?; + Ok((left != Value::Null).into()) +} + +fn pow_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok(match (left, right) { + (Value::Int(l), Value::Int(r)) => ((l as f64).powf(r as f64)).into(), + (Value::Float(l), Value::Int(r)) => ((l.into_inner()).powf(r as f64)).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64).powf(r.into_inner())).into(), + (Value::Float(l), Value::Float(r)) => ((l.into_inner()).powf(r.into_inner())).into(), + (_, _) => return Err(CozoError::InvalidArgument) + }) +} + +fn gt_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok(match (left, right) { + (Value::Int(l), Value::Int(r)) => (l > r).into(), + (Value::Float(l), Value::Int(r)) => (l > (r as f64).into()).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) > r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l > r).into(), + (_, _) => return Err(CozoError::InvalidArgument) + }) +} + +fn lt_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok(match (left, right) { + (Value::Int(l), Value::Int(r)) => (l < r).into(), + (Value::Float(l), Value::Int(r)) => (l < (r as f64).into()).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) < r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l < r).into(), + (_, _) => return Err(CozoError::InvalidArgument) + }) +} + +fn ge_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok(match (left, right) { + (Value::Int(l), Value::Int(r)) => (l >= r).into(), + (Value::Float(l), Value::Int(r)) => (l >= (r as f64).into()).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) >= r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l >= r).into(), + (_, _) => return Err(CozoError::InvalidArgument) + }) +} + +fn le_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok(match (left, right) { + (Value::Int(l), Value::Int(r)) => (l <= r).into(), + (Value::Float(l), Value::Int(r)) => (l <= (r as f64).into()).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) <= r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l <= r).into(), + (_, _) => return Err(CozoError::InvalidArgument) + }) +} + +fn mod_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok(match (left, right) { + (Value::Int(l), Value::Int(r)) => (l % r).into(), + (_, _) => return Err(CozoError::InvalidArgument) + }) +} + +fn mul_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok(match (left, right) { + (Value::Int(l), Value::Int(r)) => (l * r).into(), + (Value::Float(l), Value::Int(r)) => (l * (r as f64)).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) * r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l.into_inner() * r.into_inner()).into(), + (_, _) => return Err(CozoError::InvalidArgument) + }) +} + +fn div_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok(match (left, right) { + (Value::Int(l), Value::Int(r)) => (l as f64 / r as f64).into(), + (Value::Float(l), Value::Int(r)) => (l / (r as f64)).into(), + (Value::Int(l), Value::Float(r)) => ((l as f64) / r.into_inner()).into(), + (Value::Float(l), Value::Float(r)) => (l.into_inner() / r.into_inner()).into(), + (_, _) => return Err(CozoError::InvalidArgument) + }) +} + +fn eq_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok((left == right).into()) +} + +fn ne_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut args = args.into_iter(); + let left = tuple_eval(args.next().unwrap(), tuples)?; + if left == Value::Null { + return Ok(Value::Null); + } + let right = tuple_eval(args.next().unwrap(), tuples)?; + if right == Value::Null { + return Ok(Value::Null); + } + Ok((left != right).into()) +} + +fn or_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut accum = -1; + for v in args.into_iter() { + let v = tuple_eval(v, tuples)?; + match v { + Value::Null => accum = max(accum, 0), + Value::Bool(false) => {} + Value::Bool(true) => return Ok(true.into()), + _ => return Err(CozoError::InvalidArgument) + } + } + Ok(match accum { + -1 => false.into(), + 0 => Value::Null, + _ => unreachable!() + }) +} + +fn concat_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut coll = vec![]; + for v in args.into_iter() { + let v = tuple_eval(v, tuples)?; + match v { + Value::Null => {} + Value::List(l) => coll.extend(l), + _ => return Err(CozoError::InvalidArgument) + } + } + Ok(coll.into()) +} + +fn merge_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut coll = BTreeMap::new(); + for v in args.into_iter() { + let v = tuple_eval(v, tuples)?; + match v { + Value::Null => {} + Value::Dict(d) => coll.extend(d), + _ => return Err(CozoError::InvalidArgument) + } + } + Ok(coll.into()) +} + +fn and_values<'a>(args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { + let mut accum = 1; + for v in args.into_iter() { + let v = tuple_eval(v, tuples)?; + match v { + Value::Null => accum = min(accum, 0), + Value::Bool(true) => {} + Value::Bool(false) => return Ok(false.into()), + _ => return Err(CozoError::InvalidArgument) + } + } + Ok(match accum { + 1 => true.into(), + 0 => Value::Null, + _ => unreachable!() + }) +} + +impl<'s> Session<'s> { pub fn partial_cnf_eval<'a>(&self, mut value: Value<'a>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { loop { @@ -274,16 +601,6 @@ impl<'s> Session<'s> { } impl<'s> Session<'s> { - fn coalesce_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - for v in args { - match self.tuple_eval(v, tuples)? { - Value::Null => {} - v => return Ok(v) - } - } - Ok(Value::Null) - } - fn coalesce_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let res = args.into_iter().try_fold(vec![], |mut accum, cur| { @@ -318,19 +635,6 @@ impl<'s> Session<'s> { } } - fn str_cat_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut ret = String::new(); - for v in args { - let v = self.tuple_eval(v, tuples)?; - match v { - Value::Null => return Ok(Value::Null), - Value::Text(s) => ret += s.as_ref(), - _ => return Err(InvalidArgument) - } - }; - Ok(ret.into()) - } - fn str_cat_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -348,25 +652,6 @@ impl<'s> Session<'s> { }) } - fn add_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok(match (left, right) { - (Value::Int(l), Value::Int(r)) => (l + r).into(), - (Value::Float(l), Value::Int(r)) => (l + (r as f64)).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) + r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l.into_inner() + r.into_inner()).into(), - (_, _) => return Err(CozoError::InvalidArgument) - }) - } - fn add_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -387,25 +672,6 @@ impl<'s> Session<'s> { }) } - fn sub_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok(match (left, right) { - (Value::Int(l), Value::Int(r)) => (l + r).into(), - (Value::Float(l), Value::Int(r)) => (l - (r as f64)).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) - r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l.into_inner() - r.into_inner()).into(), - (_, _) => return Err(CozoError::InvalidArgument) - }) - } - fn sub_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -426,15 +692,6 @@ impl<'s> Session<'s> { }) } - fn minus_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let left = self.tuple_eval(args.get(0).unwrap(), tuples)?; - Ok(match left { - Value::Int(l) => (-l).into(), - Value::Float(l) => (-l).into(), - _ => return Err(CozoError::InvalidArgument) - }) - } - fn minus_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -452,14 +709,6 @@ impl<'s> Session<'s> { }) } - fn negate_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let left = self.tuple_eval(args.get(0).unwrap(), tuples)?; - Ok(match left { - Value::Bool(l) => (!l).into(), - _ => return Err(CozoError::InvalidArgument) - }) - } - fn negate_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -476,11 +725,6 @@ impl<'s> Session<'s> { }) } - fn is_null_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let left = self.tuple_eval(args.get(0).unwrap(), tuples)?; - Ok((left == Value::Null).into()) - } - fn is_null_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -494,11 +738,6 @@ impl<'s> Session<'s> { Ok((true, false.into())) } - fn not_null_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let left = self.tuple_eval(args.get(0).unwrap(), tuples)?; - Ok((left != Value::Null).into()) - } - fn not_null_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -512,25 +751,6 @@ impl<'s> Session<'s> { Ok((true, true.into())) } - fn pow_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok(match (left, right) { - (Value::Int(l), Value::Int(r)) => ((l as f64).powf(r as f64)).into(), - (Value::Float(l), Value::Int(r)) => ((l.into_inner()).powf(r as f64)).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64).powf(r.into_inner())).into(), - (Value::Float(l), Value::Float(r)) => ((l.into_inner()).powf(r.into_inner())).into(), - (_, _) => return Err(CozoError::InvalidArgument) - }) - } - fn pow_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -551,25 +771,6 @@ impl<'s> Session<'s> { }) } - fn gt_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok(match (left, right) { - (Value::Int(l), Value::Int(r)) => (l > r).into(), - (Value::Float(l), Value::Int(r)) => (l > (r as f64).into()).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) > r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l > r).into(), - (_, _) => return Err(CozoError::InvalidArgument) - }) - } - fn gt_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -590,25 +791,6 @@ impl<'s> Session<'s> { }) } - fn lt_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok(match (left, right) { - (Value::Int(l), Value::Int(r)) => (l < r).into(), - (Value::Float(l), Value::Int(r)) => (l < (r as f64).into()).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) < r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l < r).into(), - (_, _) => return Err(CozoError::InvalidArgument) - }) - } - fn lt_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -629,25 +811,6 @@ impl<'s> Session<'s> { }) } - fn ge_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok(match (left, right) { - (Value::Int(l), Value::Int(r)) => (l >= r).into(), - (Value::Float(l), Value::Int(r)) => (l >= (r as f64).into()).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) >= r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l >= r).into(), - (_, _) => return Err(CozoError::InvalidArgument) - }) - } - fn ge_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -668,25 +831,6 @@ impl<'s> Session<'s> { }) } - fn le_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok(match (left, right) { - (Value::Int(l), Value::Int(r)) => (l <= r).into(), - (Value::Float(l), Value::Int(r)) => (l <= (r as f64).into()).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) <= r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l <= r).into(), - (_, _) => return Err(CozoError::InvalidArgument) - }) - } - fn le_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -707,22 +851,6 @@ impl<'s> Session<'s> { }) } - fn mod_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok(match (left, right) { - (Value::Int(l), Value::Int(r)) => (l % r).into(), - (_, _) => return Err(CozoError::InvalidArgument) - }) - } - fn mod_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -740,25 +868,6 @@ impl<'s> Session<'s> { }) } - fn mul_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok(match (left, right) { - (Value::Int(l), Value::Int(r)) => (l * r).into(), - (Value::Float(l), Value::Int(r)) => (l * (r as f64)).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) * r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l.into_inner() * r.into_inner()).into(), - (_, _) => return Err(CozoError::InvalidArgument) - }) - } - fn mul_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -779,25 +888,6 @@ impl<'s> Session<'s> { }) } - fn div_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok(match (left, right) { - (Value::Int(l), Value::Int(r)) => (l as f64 / r as f64).into(), - (Value::Float(l), Value::Int(r)) => (l / (r as f64)).into(), - (Value::Int(l), Value::Float(r)) => ((l as f64) / r.into_inner()).into(), - (Value::Float(l), Value::Float(r)) => (l.into_inner() / r.into_inner()).into(), - (_, _) => return Err(CozoError::InvalidArgument) - }) - } - fn div_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -818,19 +908,6 @@ impl<'s> Session<'s> { }) } - fn eq_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok((left == right).into()) - } - fn eq_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -845,19 +922,6 @@ impl<'s> Session<'s> { Ok((true, (left == right).into())) } - fn ne_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut args = args.into_iter(); - let left = self.tuple_eval(args.next().unwrap(), tuples)?; - if left == Value::Null { - return Ok(Value::Null); - } - let right = self.tuple_eval(args.next().unwrap(), tuples)?; - if right == Value::Null { - return Ok(Value::Null); - } - Ok((left != right).into()) - } - fn ne_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut args = args.into_iter(); @@ -872,24 +936,6 @@ impl<'s> Session<'s> { Ok((true, (left != right).into())) } - fn or_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut accum = -1; - for v in args.into_iter() { - let v = self.tuple_eval(v, tuples)?; - match v { - Value::Null => accum = max(accum, 0), - Value::Bool(false) => {} - Value::Bool(true) => return Ok(true.into()), - _ => return Err(CozoError::InvalidArgument) - } - } - Ok(match accum { - -1 => false.into(), - 0 => Value::Null, - _ => unreachable!() - }) - } - fn or_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let res = args.into_iter().map(|v| self.partial_eval(v, params, table_bindings)) @@ -957,19 +1003,6 @@ impl<'s> Session<'s> { } } - fn concat_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut coll = vec![]; - for v in args.into_iter() { - let v = self.tuple_eval(v, tuples)?; - match v { - Value::Null => {} - Value::List(l) => coll.extend(l), - _ => return Err(CozoError::InvalidArgument) - } - } - Ok(coll.into()) - } - fn concat_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut total_ret = vec![]; @@ -1012,19 +1045,6 @@ impl<'s> Session<'s> { } } - fn merge_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut coll = BTreeMap::new(); - for v in args.into_iter() { - let v = self.tuple_eval(v, tuples)?; - match v { - Value::Null => {} - Value::Dict(d) => coll.extend(d), - _ => return Err(CozoError::InvalidArgument) - } - } - Ok(coll.into()) - } - fn merge_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let mut total_ret = vec![]; @@ -1067,24 +1087,6 @@ impl<'s> Session<'s> { } } - fn and_values<'a>(&self, args: &'a [Value<'a>], tuples: &'a MegaTuple) -> Result> { - let mut accum = 1; - for v in args.into_iter() { - let v = self.tuple_eval(v, tuples)?; - match v { - Value::Null => accum = min(accum, 0), - Value::Bool(true) => {} - Value::Bool(false) => return Ok(false.into()), - _ => return Err(CozoError::InvalidArgument) - } - } - Ok(match accum { - 1 => true.into(), - 0 => Value::Null, - _ => unreachable!() - }) - } - fn and_values_partial<'a>(&self, args: Vec>, params: &BTreeMap>, table_bindings: &AccessorMap) -> Result<(bool, Value<'a>)> { let res = args.into_iter().map(|v| self.partial_eval(v, params, table_bindings)) diff --git a/src/db/plan.rs b/src/db/plan.rs index 8e36f2b9..2d55bc82 100644 --- a/src/db/plan.rs +++ b/src/db/plan.rs @@ -4,11 +4,13 @@ use std::cmp::Ordering; use pest::iterators::Pair; use cozorocks::{IteratorPtr}; use crate::db::engine::Session; +use crate::db::eval::tuple_eval; use crate::db::query::{FromEl, Selection}; use crate::db::table::{ColId, TableId, TableInfo}; +use crate::error::CozoError::LogicError; use crate::relation::value::{StaticValue, Value}; use crate::parser::Rule; -use crate::error::Result; +use crate::error::{Result}; use crate::relation::data::{DataKind, EMPTY_DATA}; use crate::relation::table::MegaTuple; use crate::relation::tuple::{CowSlice, CowTuple, OwnTuple, Tuple}; @@ -160,6 +162,7 @@ pub enum MegaTupleIt<'a> { KeySortedWithAssocIt { main: Box>, associates: Vec<(u32, IteratorPtr<'a>)> }, CartesianProdIt { left: Box>, right: Box> }, MergeJoinIt { left: Box>, right: Box>, left_keys: Vec<(TableId, ColId)>, right_keys: Vec<(TableId, ColId)> }, + FilterIt { it: Box>, filter: Value<'a> }, } impl<'a> MegaTupleIt<'a> { @@ -218,6 +221,12 @@ impl<'a> MegaTupleIt<'a> { }) } MegaTupleIt::MergeJoinIt { .. } => todo!(), + MegaTupleIt::FilterIt { it, filter } => { + Box::new(FilterIterator { + it: Box::new(it.iter()), + filter, + }) + } } } } @@ -326,7 +335,10 @@ impl<'a> Iterator for KeySortedWithAssocIterator<'a> { Some(Err(e)) => return Some(Err(e)), Some(Ok(MegaTuple { mut keys, mut vals })) => { // extract key from main - let k = keys.pop().unwrap(); + let k = match keys.pop() { + None => return Some(Err(LogicError("Empty keys".to_string()))), + Some(k) => k + }; let l = self.associates.len(); // initialize vector for associate values let mut assoc_vals: Vec> = iter::repeat_with(|| None).take(l).collect(); @@ -447,6 +459,34 @@ impl<'a> Iterator for CartesianProdIterator<'a> { } } +pub struct FilterIterator<'a> { + it: Box> + 'a>, + filter: &'a Value<'a>, +} + +impl<'a> Iterator for FilterIterator<'a> { + type Item = Result; + + fn next(&mut self) -> Option { + for t in self.it.by_ref() { + match t { + Ok(t) => { + match tuple_eval(self.filter, &t) { + Ok(Value::Bool(true)) => { + return Some(Ok(t)); + } + Ok(Value::Bool(false)) | Ok(Value::Null) => {} + Ok(_v) => return Some(Err(LogicError("Unexpected type in filter".to_string()))), + Err(e) => return Some(Err(e)) + } + } + Err(e) => return Some(Err(e)) + } + } + None + } +} + #[cfg(test)] mod tests { @@ -456,6 +496,7 @@ mod tests { use crate::db::engine::Engine; use crate::parser::{Parser, Rule}; use pest::Parser as PestParser; + use crate::db::eval::tuple_eval; use crate::db::plan::{MegaTupleIt}; use crate::db::query::FromEl; use crate::relation::value::Value; @@ -528,19 +569,20 @@ mod tests { let tbl = rel_tbls.pop().unwrap(); let it = sess.iter_node(tbl); + let it = MegaTupleIt::FilterIt { filter: where_vals, it: it.into() }; for tuple in it.iter() { let tuple = tuple.unwrap(); - match sess.tuple_eval(&where_vals, &tuple).unwrap() { - Value::Bool(true) => { - let extracted = sess.tuple_eval(&vals, &tuple).unwrap(); - println!("{}", extracted); - } - Value::Null | - Value::Bool(_) => { - println!(" Ignore {:?}", &tuple); - } - _ => panic!("Bad type") - } + // match tuple_eval(&where_vals, &tuple).unwrap() { + // Value::Bool(true) => { + let extracted = tuple_eval(&vals, &tuple).unwrap(); + println!("{}", extracted); + // } + // Value::Null | + // Value::Bool(_) => { + // println!(" Ignore {:?}", &tuple); + // } + // _ => panic!("Bad type") + // } } let duration = start.elapsed(); let duration2 = start2.elapsed(); @@ -576,9 +618,9 @@ mod tests { let mut n = 0; for el in it.iter() { let el = el.unwrap(); - if n % 4096 == 0 { - println!("{}: {:?}", n, el) - } + // if n % 4096 == 0 { + // println!("{}: {:?}", n, el) + // } let _x = el.keys.into_iter().map(|v| v.iter().map(|_v| ()).collect::>()).collect::>(); let _y = el.vals.into_iter().map(|v| v.iter().map(|_v| ()).collect::>()).collect::>(); n += 1;