Query planner should evaluate non boolean expressions (#4022)
This commit is contained in:
parent
1c09e1863d
commit
6277aab0e1
3 changed files with 97 additions and 8 deletions
|
@ -136,17 +136,26 @@ impl<'a> TreeBuilder<'a> {
|
|||
| Value::Uuid(_)
|
||||
| Value::Constant(_)
|
||||
| Value::Geometry(_)
|
||||
| Value::Datetime(_) => Ok(Node::Computed(Arc::new(v.to_owned()))),
|
||||
| Value::Datetime(_)
|
||||
| Value::Param(_)
|
||||
| Value::Function(_) => Ok(Node::Computable),
|
||||
Value::Array(a) => self.eval_array(stk, a).await,
|
||||
Value::Subquery(s) => self.eval_subquery(stk, s).await,
|
||||
Value::Param(p) => {
|
||||
let v = stk.run(|stk| p.compute(stk, self.ctx, self.opt, self.txn, None)).await?;
|
||||
stk.run(|stk| self.eval_value(stk, group, &v)).await
|
||||
}
|
||||
_ => Ok(Node::Unsupported(format!("Unsupported value: {}", v))),
|
||||
}
|
||||
}
|
||||
|
||||
async fn compute(&self, stk: &mut Stk, v: &Value, n: Node) -> Result<Node, Error> {
|
||||
Ok(if n == Node::Computable {
|
||||
match v.compute(stk, self.ctx, self.opt, self.txn, None).await {
|
||||
Ok(v) => Node::Computed(Arc::new(v)),
|
||||
Err(_) => Node::Unsupported(format!("Unsupported value: {}", v)),
|
||||
}
|
||||
} else {
|
||||
n
|
||||
})
|
||||
}
|
||||
|
||||
async fn eval_array(&mut self, stk: &mut Stk, a: &Array) -> Result<Node, Error> {
|
||||
let mut values = Vec::with_capacity(a.len());
|
||||
for v in &a.0 {
|
||||
|
@ -289,9 +298,15 @@ impl<'a> TreeBuilder<'a> {
|
|||
if let Some(re) = self.resolved_expressions.get(e).cloned() {
|
||||
return Ok(re.into());
|
||||
}
|
||||
let left = stk.run(|stk| self.eval_value(stk, group, l)).await?;
|
||||
let right = stk.run(|stk| self.eval_value(stk, group, r)).await?;
|
||||
// If both values are computable, then we can delegate the computation to the parent
|
||||
if left == Node::Computable && right == Node::Computable {
|
||||
return Ok(Node::Computable);
|
||||
}
|
||||
let exp = Arc::new(e.clone());
|
||||
let left = Arc::new(stk.run(|stk| self.eval_value(stk, group, l)).await?);
|
||||
let right = Arc::new(stk.run(|stk| self.eval_value(stk, group, r)).await?);
|
||||
let left = Arc::new(self.compute(stk, l, left).await?);
|
||||
let right = Arc::new(self.compute(stk, r, right).await?);
|
||||
let mut io = None;
|
||||
if let Some((id, local_irs, remote_irs)) = left.is_indexed_field() {
|
||||
io = self.lookup_index_options(
|
||||
|
@ -552,6 +567,7 @@ pub(super) enum Node {
|
|||
IndexedField(Idiom, Vec<IndexRef>),
|
||||
RecordField(Idiom, RecordOptions),
|
||||
NonIndexedField(Idiom),
|
||||
Computable,
|
||||
Computed(Arc<Value>),
|
||||
Unsupported(String),
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ pub enum Error {
|
|||
InvalidRange,
|
||||
#[error("expected uuid-strand to end")]
|
||||
ExpectedStrandEnd,
|
||||
#[error("missing a uuid seperator")]
|
||||
#[error("missing a uuid separator")]
|
||||
MissingSeperator,
|
||||
}
|
||||
|
||||
|
|
|
@ -2527,3 +2527,76 @@ async fn select_with_exact_operator() -> Result<(), Error> {
|
|||
//
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn select_with_non_boolean_expression() -> Result<(), Error> {
|
||||
let dbs = new_ds().await?;
|
||||
let ses = Session::owner().with_ns("test").with_db("test");
|
||||
//
|
||||
let sql = "
|
||||
DEFINE INDEX idx ON t FIELDS v;
|
||||
CREATE t:1 set v = 1;
|
||||
CREATE t:2 set v = 2;
|
||||
LET $p1 = 1;
|
||||
LET $p3 = 3;
|
||||
SELECT * FROM t WHERE v > math::max([0, 1]);
|
||||
SELECT * FROM t WHERE v > math::max([0, 1]) EXPLAIN;
|
||||
SELECT * FROM t WHERE v > 3 - math::max([0, 2]);
|
||||
SELECT * FROM t WHERE v > 3 - math::max([0, 2]) EXPLAIN;
|
||||
SELECT * FROM t WHERE v > 3 - math::max([0, 1]) - 1;
|
||||
SELECT * FROM t WHERE v > 3 - math::max([0, 1]) - 1 EXPLAIN;
|
||||
SELECT * FROM t WHERE v > 3 - ( math::max([0, 1]) + 1 );
|
||||
SELECT * FROM t WHERE v > 3 - ( math::max([0, 1]) + 1 ) EXPLAIN;
|
||||
SELECT * FROM t WHERE v > $p3 - ( math::max([0, $p1]) + $p1 );
|
||||
SELECT * FROM t WHERE v > $p3 - ( math::max([0, $p1]) + $p1 ) EXPLAIN;
|
||||
";
|
||||
let mut res = dbs.execute(&sql, &ses, None).await?;
|
||||
//
|
||||
assert_eq!(res.len(), 15);
|
||||
skip_ok(&mut res, 5)?;
|
||||
//
|
||||
for i in 0..5 {
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
r#"[
|
||||
{
|
||||
id: t:2,
|
||||
v: 2
|
||||
}
|
||||
]"#,
|
||||
);
|
||||
assert_eq!(format!("{:#}", tmp), format!("{:#}", val), "{i}");
|
||||
//
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
r#"[
|
||||
{
|
||||
detail: {
|
||||
plan: {
|
||||
from: {
|
||||
inclusive: false,
|
||||
value: 1
|
||||
},
|
||||
index: 'idx',
|
||||
to: {
|
||||
inclusive: false,
|
||||
value: NONE
|
||||
}
|
||||
},
|
||||
table: 't'
|
||||
},
|
||||
operation: 'Iterate Index'
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
type: 'Memory'
|
||||
},
|
||||
operation: 'Collector'
|
||||
}
|
||||
]"#,
|
||||
);
|
||||
assert_eq!(format!("{:#}", tmp), format!("{:#}", val), "{i}");
|
||||
}
|
||||
//
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue