ops in their own modules

main
Ziyang Hu 2 years ago
parent efefdbf8c7
commit 55304c621e

@ -29,6 +29,12 @@ pub(crate) enum EvalError {
#[error("Cannot apply `{0}` to `{1:?}`")]
OpTypeMismatch(String, Vec<StaticValue>),
#[error("Optimized before partial eval")]
OptimizedBeforePartialEval,
#[error("Arity mismatch for {0}, {1} arguments given ")]
ArityMismatch(String, usize),
}
type Result<T> = result::Result<T, EvalError>;
@ -43,7 +49,10 @@ impl RowEvalContext for () {
}
}
pub(crate) trait ExprEvalContext {}
pub(crate) trait ExprEvalContext {
fn resolve<'a>(&'a self, key: &str) -> Option<Expr<'a>>;
fn resolve_table_col<'a>(&'a self, binding: &str, col: &str) -> Option<(TableId, ColId)>;
}
fn extract_optimized_bin_args(args: Vec<Expr>) -> (Expr, Expr) {
let mut args = args.into_iter();
@ -55,8 +64,120 @@ fn extract_optimized_u_args(args: Vec<Expr>) -> Expr {
}
impl<'a> Expr<'a> {
pub(crate) fn partial_eval<C: ExprEvalContext + 'a>(&'a self, ctx: &'a C) -> Result<Self> {
todo!()
pub(crate) fn partial_eval<C: ExprEvalContext + 'a>(self, ctx: &'a C) -> Result<Self> {
let res = match self {
v @ (Expr::Const(_) |
Expr::TableCol(_, _) |
Expr::TupleSetIdx(_)) => v,
Expr::List(l) => Expr::List(l.into_iter().map(|v| v.partial_eval(ctx)).collect::<Result<Vec<_>>>()?),
Expr::Dict(d) => Expr::Dict(d.into_iter().map(|(k, v)| -> Result<(String, Expr)> {
Ok((k, v.partial_eval(ctx)?))
}).collect::<Result<BTreeMap<_, _>>>()?),
Expr::Variable(var) => ctx.resolve(&var).ok_or(EvalError::UnresolvedVariable(var))?,
Expr::FieldAcc(f, arg) => {
let expr = match *arg {
Expr::Variable(var) => {
if let Some((tid, cid)) = ctx.resolve_table_col(&var, &f) {
return Ok(Expr::TableCol(tid, cid));
} else {
ctx.resolve(&var)
.ok_or(EvalError::UnresolvedVariable(var))?
.partial_eval(ctx)?
}
}
expr => expr.partial_eval(ctx)?
};
match expr {
Expr::Const(Value::Null) => Expr::Const(Value::Null),
Expr::Const(Value::Dict(mut d)) => {
Expr::Const(d.remove(&f as &str).unwrap_or(Value::Null))
}
v @ (Expr::IdxAcc(_, _) |
Expr::FieldAcc(_, _) |
Expr::TableCol(_, _) |
Expr::Apply(_, _) |
Expr::ApplyAgg(_, _, _)) => {
Expr::FieldAcc(f, v.into())
}
Expr::Dict(mut d) => {
d.remove(&f as &str).unwrap_or(Expr::Const(Value::Null))
}
v => return Err(EvalError::FieldAccess(f, Value::from(v).to_static()))
}
}
Expr::IdxAcc(i, arg) => {
let arg = arg.partial_eval(ctx)?;
match arg {
Expr::Const(Value::Null) => Expr::Const(Value::Null),
Expr::Const(Value::List(mut l)) => {
if i >= l.len() {
Expr::Const(Value::Null)
} else {
Expr::Const(l.swap_remove(i))
}
}
Expr::List(mut l) => {
if i >= l.len() {
Expr::Const(Value::Null)
} else {
l.swap_remove(i)
}
}
v @ (Expr::IdxAcc(_, _) |
Expr::FieldAcc(_, _) |
Expr::TableCol(_, _) |
Expr::Apply(_, _) |
Expr::ApplyAgg(_, _, _)) => {
Expr::IdxAcc(i, v.into())
}
v => return Err(EvalError::IndexAccess(i, Value::from(v).to_static()))
}
}
Expr::Apply(op, args) => {
let args = args.into_iter().map(|v| v.partial_eval(ctx)).collect::<Result<Vec<_>>>()?;
if op.has_side_effect() {
Expr::Apply(op, args)
} else {
match op.partial_eval(args.clone())? {
Some(v) => v,
None => Expr::Apply(op, args)
}
}
}
Expr::ApplyAgg(op, a_args, args) => {
let a_args = a_args.into_iter().map(|v| v.partial_eval(ctx)).collect::<Result<Vec<_>>>()?;
let args = args.into_iter().map(|v| v.partial_eval(ctx)).collect::<Result<Vec<_>>>()?;
if op.has_side_effect() {
Expr::ApplyAgg(op, a_args, args)
} else {
match op.partial_eval(a_args.clone(), args.clone())? {
Some(v) => v,
None => Expr::ApplyAgg(op, a_args, args)
}
}
}
Expr::Add(_) |
Expr::Sub(_) |
Expr::Mul(_) |
Expr::Div(_) |
Expr::Pow(_) |
Expr::Mod(_) |
Expr::StrCat(_) |
Expr::Eq(_) |
Expr::Ne(_) |
Expr::Gt(_) |
Expr::Ge(_) |
Expr::Lt(_) |
Expr::Le(_) |
Expr::Negate(_) |
Expr::Minus(_) |
Expr::IsNull(_) |
Expr::NotNull(_) |
Expr::Coalesce(_) |
Expr::Or(_) |
Expr::And(_) => return Err(EvalError::OptimizedBeforePartialEval)
};
Ok(res)
}
pub(crate) fn optimize_ops(self) -> Self {
match self {

@ -2,7 +2,7 @@ use crate::data::op::{AggOp, Op, OpAdd, OpAnd, OpCoalesce, OpDiv, OpEq, OpGe, Op
use crate::data::tuple_set::{ColId, TableId, TupleSetIdx};
use crate::data::value::{StaticValue, Value};
use std::collections::BTreeMap;
use std::fmt::{format, write, Debug, Formatter};
use std::fmt::{Debug, Formatter};
use std::result;
use std::sync::Arc;

@ -1,4 +1,4 @@
use crate::data::expr::{Expr, ExprError};
use crate::data::expr::{Expr};
use crate::data::op::{
Op, OpAdd, OpAnd, OpCoalesce, OpConcat, OpDiv, OpEq, OpGe, OpGt, OpLe, OpLt, OpMerge, OpMinus,
OpMod, OpMul, OpNe, OpNegate, OpOr, OpPow, OpStrCat, OpSub, UnresolvedOp,
@ -249,7 +249,6 @@ fn build_expr_infix<'a>(
#[cfg(test)]
pub(crate) mod tests {
use super::*;
use crate::data::expr::StaticExpr;
use crate::parser::CozoParser;
use pest::Parser;

@ -1,12 +1,21 @@
use std::cmp::max;
use std::collections::BTreeMap;
use crate::data::eval::{EvalError, ExprEvalContext, RowEvalContext};
mod arithmetic;
mod text;
mod comparison;
mod boolean;
mod combine;
use crate::data::eval::{EvalError};
use crate::data::expr::Expr;
use crate::data::typing::Typing;
use crate::data::value::{StaticValue, Value};
use std::fmt::{Debug, Formatter};
use std::result;
pub(crate) use arithmetic::*;
pub(crate) use text::*;
pub(crate) use comparison::*;
pub(crate) use boolean::*;
pub(crate) use combine::*;
type Result<T> = result::Result<T, EvalError>;
pub(crate) trait Op: Send + Sync {
@ -16,6 +25,9 @@ pub(crate) trait Op: Send + Sync {
fn arity(&self) -> Option<usize> {
Some(1)
}
fn has_side_effect(&self) -> bool {
false
}
fn name(&self) -> &str;
fn non_null_args(&self) -> bool {
true
@ -85,7 +97,36 @@ pub(crate) trait Op: Send + Sync {
self.name()
)
}
fn expr_eval(&self, ctx: &dyn ExprEvalContext, args: ()) -> () {}
fn partial_eval<'a>(&self, args: Vec<Expr<'a>>) -> Result<Option<Expr<'a>>> {
if let Some(arity) = self.arity() {
if arity != args.len() {
return Err(EvalError::ArityMismatch(self.name().to_string(), arity))
}
}
let mut has_null = false;
match args.iter().map(|v| {
match v {
Expr::Const(v) => {
if *v == Value::Null {
has_null = true;
}
Some(v.clone())
}
_ => None
}
}).collect::<Vec<_>>().into_iter().collect::<Option<Vec<Value>>>() {
Some(args) => {
Ok(Some(Expr::Const(self.eval(has_null, args)?)))
}
None => {
if self.non_null_args() && has_null {
Ok(Some(Expr::Const(Value::Null)))
} else {
Ok(None)
}
}
}
}
}
pub(crate) trait AggOp: Send + Sync {
@ -95,12 +136,12 @@ pub(crate) trait AggOp: Send + Sync {
fn arity(&self) -> Option<usize> {
Some(1)
}
fn name(&self) -> &str;
fn row_eval(&self, ctx: (), args: ()) -> () {
unimplemented!()
fn has_side_effect(&self) -> bool {
false
}
fn expr_eval(&self, ctx: (), args: ()) -> () {
self.row_eval(ctx, args)
fn name(&self) -> &str;
fn partial_eval<'a>(&self, a_args: Vec<Expr<'a>>, args: Vec<Expr<'a>>) -> Result<Option<Expr<'a>>> {
todo!()
}
}
@ -122,318 +163,7 @@ impl AggOp for UnresolvedOp {
}
}
pub(crate) struct OpAdd;
impl Op for OpAdd {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"+"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpSub;
impl Op for OpSub {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"-"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpMul;
impl Op for OpMul {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"*"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpDiv;
impl Op for OpDiv {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"/"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpMod;
impl Op for OpMod {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"%"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = match (left, right) {
(Value::Int(l), Value::Int(r)) => (l % r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpPow;
impl Op for OpPow {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"**"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpStrCat;
impl Op for OpStrCat {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"++"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
match (left, right) {
(Value::Text(l), Value::Text(r)) => {
let mut l = l.into_owned();
l += r.as_ref();
Ok(l.into())
}
(l, r) => Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
)),
}
}
}
pub(crate) struct OpEq;
impl Op for OpEq {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"=="
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
Ok((left == right).into())
}
}
pub(crate) struct OpNe;
impl Op for OpNe {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"!="
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
Ok((left != right).into())
}
}
pub(crate) struct OpGt;
impl Op for OpGt {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
">"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(Value::Text(l), Value::Text(r)) => (l > r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpGe;
impl Op for OpGe {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
">="
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(Value::Text(l), Value::Text(r)) => (l >= r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpLt;
impl Op for OpLt {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"<"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(Value::Text(l), Value::Text(r)) => (l < r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpLe;
impl Op for OpLe {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"<="
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(Value::Text(l), Value::Text(r)) => (l <= r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpNegate;
@ -451,229 +181,3 @@ impl Op for OpNegate {
}
}
}
pub(crate) struct OpMinus;
impl Op for OpMinus {
fn name(&self) -> &str {
"--"
}
fn eval_one_non_null<'a>(&self, arg: Value<'a>) -> Result<Value<'a>> {
match arg {
Value::Int(i) => Ok((-i).into()),
Value::Float(i) => Ok((-i).into()),
v => Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.to_static()],
)),
}
}
}
pub(crate) struct OpIsNull;
impl Op for OpIsNull {
fn name(&self) -> &str {
"is_null"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, has_null: bool, _args: Vec<Value<'a>>) -> Result<Value<'a>> {
Ok(has_null.into())
}
fn eval_one<'a>(&self, arg: Value<'a>) -> Result<Value<'a>> {
Ok((arg == Value::Null).into())
}
}
pub(crate) struct OpNotNull;
impl Op for OpNotNull {
fn name(&self) -> &str {
"not_null"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, has_null: bool, _args: Vec<Value<'a>>) -> Result<Value<'a>> {
Ok((!has_null).into())
}
fn eval_one<'a>(&self, arg: Value<'a>) -> Result<Value<'a>> {
Ok((arg != Value::Null).into())
}
}
pub(crate) struct OpCoalesce;
impl Op for OpCoalesce {
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
"~~"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, _has_null: bool, args: Vec<Value<'a>>) -> Result<Value<'a>> {
for arg in args {
if arg != Value::Null {
return Ok(arg);
}
}
Ok(Value::Null)
}
fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
match (left, right) {
(Value::Null, v) => Ok(v),
(l, _r) => Ok(l)
}
}
}
pub(crate) struct OpOr;
impl Op for OpOr {
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
"||"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, has_null: bool, args: Vec<Value<'a>>) -> Result<Value<'a>> {
for arg in args {
match arg {
Value::Null => {}
Value::Bool(true) => return Ok(Value::Bool(true)),
Value::Bool(false) => {}
v => return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.to_static()],
)),
}
}
if has_null {
Ok(Value::Null)
} else {
Ok(Value::Bool(false))
}
}
fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
match (left, right) {
(Value::Null, Value::Bool(true)) => Ok(true.into()),
(Value::Null, Value::Bool(false)) => Ok(Value::Null),
(Value::Bool(true), Value::Null) => Ok(true.into()),
(Value::Bool(false), Value::Null) => Ok(Value::Null),
(Value::Bool(l), Value::Bool(r)) => Ok((l || r).into()),
(l, r) => Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
))
}
}
}
pub(crate) struct OpAnd;
impl Op for OpAnd {
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
"&&"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, has_null: bool, args: Vec<Value<'a>>) -> Result<Value<'a>> {
for arg in args {
match arg {
Value::Null => {}
Value::Bool(false) => return Ok(Value::Bool(false)),
Value::Bool(true) => {}
v => return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.to_static()],
)),
}
}
if has_null {
Ok(Value::Null)
} else {
Ok(Value::Bool(true))
}
}
fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
match (left, right) {
(Value::Null, Value::Bool(false)) => Ok(false.into()),
(Value::Null, Value::Bool(true)) => Ok(Value::Null),
(Value::Bool(false), Value::Null) => Ok(false.into()),
(Value::Bool(true), Value::Null) => Ok(Value::Null),
(Value::Bool(l), Value::Bool(r)) => Ok((l && r).into()),
(l, r) => Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
))
}
}
}
pub(crate) struct OpConcat;
impl Op for OpConcat {
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
"concat"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, _has_null: bool, args: Vec<Value<'a>>) -> Result<Value<'a>> {
let mut coll = vec![];
for v in args.into_iter() {
match v {
Value::Null => {}
Value::List(l) => coll.extend(l),
v => return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.to_static()],
)),
}
}
Ok(coll.into())
}
}
pub(crate) struct OpMerge;
impl Op for OpMerge {
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
"merge"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, has_null: bool, args: Vec<Value<'a>>) -> Result<Value<'a>> {
let mut coll = BTreeMap::new();
for v in args.into_iter() {
match v {
Value::Null => {}
Value::Dict(d) => coll.extend(d),
v => return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.to_static()],
)),
}
}
Ok(coll.into())
}
}

@ -0,0 +1,178 @@
use std::result;
use crate::data::eval::EvalError;
use crate::data::op::Op;
use crate::data::value::Value;
type Result<T> = result::Result<T, EvalError>;
pub(crate) struct OpAdd;
impl Op for OpAdd {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"+"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpSub;
impl Op for OpSub {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"-"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpMul;
impl Op for OpMul {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"*"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpDiv;
impl Op for OpDiv {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"/"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpMod;
impl Op for OpMod {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"%"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = match (left, right) {
(Value::Int(l), Value::Int(r)) => (l % r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpPow;
impl Op for OpPow {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"**"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpMinus;
impl Op for OpMinus {
fn name(&self) -> &str {
"--"
}
fn eval_one_non_null<'a>(&self, arg: Value<'a>) -> Result<Value<'a>> {
match arg {
Value::Int(i) => Ok((-i).into()),
Value::Float(i) => Ok((-i).into()),
v => Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.to_static()],
)),
}
}
}

@ -0,0 +1,158 @@
use std::result;
use crate::data::eval::EvalError;
use crate::data::op::Op;
use crate::data::value::Value;
type Result<T> = result::Result<T, EvalError>;
pub(crate) struct OpIsNull;
impl Op for OpIsNull {
fn name(&self) -> &str {
"is_null"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, has_null: bool, _args: Vec<Value<'a>>) -> Result<Value<'a>> {
Ok(has_null.into())
}
fn eval_one<'a>(&self, arg: Value<'a>) -> Result<Value<'a>> {
Ok((arg == Value::Null).into())
}
}
pub(crate) struct OpNotNull;
impl Op for OpNotNull {
fn name(&self) -> &str {
"not_null"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, has_null: bool, _args: Vec<Value<'a>>) -> Result<Value<'a>> {
Ok((!has_null).into())
}
fn eval_one<'a>(&self, arg: Value<'a>) -> Result<Value<'a>> {
Ok((arg != Value::Null).into())
}
}
pub(crate) struct OpCoalesce;
impl Op for OpCoalesce {
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
"~~"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, _has_null: bool, args: Vec<Value<'a>>) -> Result<Value<'a>> {
for arg in args {
if arg != Value::Null {
return Ok(arg);
}
}
Ok(Value::Null)
}
fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
match (left, right) {
(Value::Null, v) => Ok(v),
(l, _r) => Ok(l)
}
}
}
pub(crate) struct OpOr;
impl Op for OpOr {
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
"||"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, has_null: bool, args: Vec<Value<'a>>) -> Result<Value<'a>> {
for arg in args {
match arg {
Value::Null => {}
Value::Bool(true) => return Ok(Value::Bool(true)),
Value::Bool(false) => {}
v => return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.to_static()],
)),
}
}
if has_null {
Ok(Value::Null)
} else {
Ok(Value::Bool(false))
}
}
fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
match (left, right) {
(Value::Null, Value::Bool(true)) => Ok(true.into()),
(Value::Null, Value::Bool(false)) => Ok(Value::Null),
(Value::Bool(true), Value::Null) => Ok(true.into()),
(Value::Bool(false), Value::Null) => Ok(Value::Null),
(Value::Bool(l), Value::Bool(r)) => Ok((l || r).into()),
(l, r) => Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
))
}
}
}
pub(crate) struct OpAnd;
impl Op for OpAnd {
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
"&&"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, has_null: bool, args: Vec<Value<'a>>) -> Result<Value<'a>> {
for arg in args {
match arg {
Value::Null => {}
Value::Bool(false) => return Ok(Value::Bool(false)),
Value::Bool(true) => {}
v => return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.to_static()],
)),
}
}
if has_null {
Ok(Value::Null)
} else {
Ok(Value::Bool(true))
}
}
fn eval_two<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
match (left, right) {
(Value::Null, Value::Bool(false)) => Ok(false.into()),
(Value::Null, Value::Bool(true)) => Ok(Value::Null),
(Value::Bool(false), Value::Null) => Ok(false.into()),
(Value::Bool(true), Value::Null) => Ok(Value::Null),
(Value::Bool(l), Value::Bool(r)) => Ok((l && r).into()),
(l, r) => Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
))
}
}
}

@ -0,0 +1,63 @@
use std::collections::BTreeMap;
use std::result;
use crate::data::eval::EvalError;
use crate::data::op::Op;
use crate::data::value::Value;
type Result<T> = result::Result<T, EvalError>;
pub(crate) struct OpConcat;
impl Op for OpConcat {
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
"concat"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, _has_null: bool, args: Vec<Value<'a>>) -> Result<Value<'a>> {
let mut coll = vec![];
for v in args.into_iter() {
match v {
Value::Null => {}
Value::List(l) => coll.extend(l),
v => return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.to_static()],
)),
}
}
Ok(coll.into())
}
}
pub(crate) struct OpMerge;
impl Op for OpMerge {
fn arity(&self) -> Option<usize> {
None
}
fn name(&self) -> &str {
"merge"
}
fn non_null_args(&self) -> bool {
false
}
fn eval<'a>(&self, has_null: bool, args: Vec<Value<'a>>) -> Result<Value<'a>> {
let mut coll = BTreeMap::new();
for v in args.into_iter() {
match v {
Value::Null => {}
Value::Dict(d) => coll.extend(d),
v => return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![v.to_static()],
)),
}
}
Ok(coll.into())
}
}

@ -0,0 +1,142 @@
use std::result;
use crate::data::eval::EvalError;
use crate::data::op::Op;
use crate::data::value::Value;
type Result<T> = result::Result<T, EvalError>;
pub(crate) struct OpEq;
impl Op for OpEq {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"=="
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
Ok((left == right).into())
}
}
pub(crate) struct OpNe;
impl Op for OpNe {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"!="
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
Ok((left != right).into())
}
}
pub(crate) struct OpGt;
impl Op for OpGt {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
">"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(Value::Text(l), Value::Text(r)) => (l > r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpGe;
impl Op for OpGe {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
">="
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(Value::Text(l), Value::Text(r)) => (l >= r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpLt;
impl Op for OpLt {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"<"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(Value::Text(l), Value::Text(r)) => (l < r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}
pub(crate) struct OpLe;
impl Op for OpLe {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"<="
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
let res: Value = 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(),
(Value::Text(l), Value::Text(r)) => (l <= r).into(),
(l, r) => {
return Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
));
}
};
Ok(res)
}
}

@ -0,0 +1,31 @@
use std::result;
use crate::data::eval::EvalError;
use crate::data::op::Op;
use crate::data::value::Value;
type Result<T> = result::Result<T, EvalError>;
pub(crate) struct OpStrCat;
impl Op for OpStrCat {
fn arity(&self) -> Option<usize> {
Some(2)
}
fn name(&self) -> &str {
"++"
}
fn eval_two_non_null<'a>(&self, left: Value<'a>, right: Value<'a>) -> Result<Value<'a>> {
match (left, right) {
(Value::Text(l), Value::Text(r)) => {
let mut l = l.into_owned();
l += r.as_ref();
Ok(l.into())
}
(l, r) => Err(EvalError::OpTypeMismatch(
self.name().to_string(),
vec![l.to_static(), r.to_static()],
)),
}
}
}

@ -1,6 +1,4 @@
use crate::data::tuple::TupleError::UndefinedDataTag;
use crate::data::value::Value;
use chrono::format::Item;
use cozorocks::{PinnableSlicePtr, PinnableSlicePtrShared, SlicePtr, SlicePtrShared};
use std::borrow::Cow;
use std::cell::RefCell;

@ -1,6 +1,5 @@
use crate::data::tuple::{OwnTuple, ReifiedTuple, Tuple, TupleError};
use crate::data::tuple::{OwnTuple, ReifiedTuple, TupleError};
use crate::data::value::Value;
use cozorocks::{PinnableSlicePtr, PinnableSlicePtrShared, SlicePtr, SlicePtrShared};
use std::cmp::Ordering;
use std::fmt::{Debug, Formatter};
use std::result;

@ -3,20 +3,19 @@ use crate::data::tuple::{DataKind, OwnTuple, Tuple, TupleError};
use crate::data::tuple_set::MIN_TABLE_ID_BOUND;
use crate::data::typing::Typing;
use crate::data::value::{StaticValue, Value};
use crate::runtime::instance::DbInstanceError::TableDoesNotExist;
use crate::runtime::options::{
default_options, default_read_options, default_txn_db_options, default_txn_options,
default_write_options,
};
use cozorocks::{
destroy_db, BridgeError, DbPtr, OptionsPtrShared, PinnableSlicePtr, ReadOptionsPtr, TDbOptions,
TransactOptions, TransactionPtr, WriteOptionsPtr,
destroy_db, BridgeError, DbPtr, OptionsPtrShared, ReadOptionsPtr, TDbOptions,
TransactionPtr, WriteOptionsPtr,
};
use lazy_static::lazy_static;
use log::error;
use std::collections::{BTreeMap, BTreeSet};
use std::sync::atomic::{AtomicU32, Ordering};
use std::sync::{Arc, LockResult, Mutex, PoisonError, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::sync::{Arc, Mutex, RwLock, RwLockReadGuard, RwLockWriteGuard};
use std::{mem, result};
#[derive(thiserror::Error, Debug)]

Loading…
Cancel
Save