From cfdd7c195c029e7e5a9f7266d88b8f51f567a2ce Mon Sep 17 00:00:00 2001 From: hchockarprasad Date: Wed, 25 Oct 2023 15:54:04 +0530 Subject: [PATCH] Fix index plan for idiom param value (#2865) --- lib/src/idx/planner/tree.rs | 9 ++++++++- lib/src/sql/value/value.rs | 5 +++++ lib/tests/planner.rs | 40 +++++++++++++++++++++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/lib/src/idx/planner/tree.rs b/lib/src/idx/planner/tree.rs index fe6f36a8..eef85932 100644 --- a/lib/src/idx/planner/tree.rs +++ b/lib/src/idx/planner/tree.rs @@ -4,7 +4,7 @@ use crate::err::Error; use crate::idx::planner::plan::{IndexOperator, IndexOption}; use crate::sql::index::Index; use crate::sql::statements::DefineIndexStatement; -use crate::sql::{Array, Cond, Expression, Idiom, Operator, Subquery, Table, Value, With}; +use crate::sql::{Array, Cond, Expression, Idiom, Operator, Part, Subquery, Table, Value, With}; use async_recursion::async_recursion; use std::collections::HashMap; use std::sync::Arc; @@ -126,6 +126,13 @@ impl<'a> TreeBuilder<'a> { } async fn eval_idiom(&mut self, i: &Idiom) -> Result { + // Compute the idiom value if it is a param + if let Some(Part::Start(x)) = i.0.first() { + if x.is_param() { + let v = i.compute(self.ctx, self.opt, self.txn, None).await?; + return self.eval_value(&v).await; + } + } if let Some(irs) = self.find_indexes(i).await? { if !irs.is_empty() { return Ok(Node::IndexedField(i.to_owned(), irs)); diff --git a/lib/src/sql/value/value.rs b/lib/src/sql/value/value.rs index bd3006ca..95db24c7 100644 --- a/lib/src/sql/value/value.rs +++ b/lib/src/sql/value/value.rs @@ -991,6 +991,11 @@ impl Value { } } + /// Check if this Value is a Param + pub fn is_param(&self) -> bool { + matches!(self, Value::Param(_)) + } + /// Check if this Value is a Geometry of a specific type pub fn is_geometry_type(&self, types: &[String]) -> bool { match self { diff --git a/lib/tests/planner.rs b/lib/tests/planner.rs index b2e39fce..3f94b45e 100644 --- a/lib/tests/planner.rs +++ b/lib/tests/planner.rs @@ -846,3 +846,43 @@ async fn select_index_single_range_operator_more_or_equal() -> Result<(), Error> async fn select_unique_single_range_operator_more_or_equal() -> Result<(), Error> { select_single_range_operator(true, ">=", EXPLAIN_MORE_OR_EQUAL, RESULT_MORE_OR_EQUAL).await } + +#[tokio::test] +async fn select_with_idiom_param_value() -> Result<(), Error> { + let dbs = new_ds().await?; + let ses = Session::owner().with_ns("test").with_db("test"); + let sql = format!( + " + CREATE person:tobie SET name = 'Tobie', genre='m', company='SurrealDB'; + CREATE person:jaime SET name = 'Jaime', genre='m', company='SurrealDB'; + DEFINE INDEX name ON TABLE person COLUMNS name UNIQUE; + LET $name = 'Tobie'; + LET $nameObj = {{name:'Tobie'}}; + SELECT name FROM person WHERE name = $nameObj.name EXPLAIN;" + ); + let mut res = dbs.execute(&sql, &ses, None).await?; + assert_eq!(res.len(), 6); + res.remove(0).result?; + res.remove(0).result?; + res.remove(0).result?; + res.remove(0).result?; + res.remove(0).result?; + let tmp = res.remove(0).result?; + let val = Value::parse( + r#"[ + { + detail: { + plan: { + index: 'name', + operator: '=', + value: 'Tobie' + }, + table: 'person' + }, + operation: 'Iterate Index' + } + ]"#, + ); + assert_eq!(format!("{:#}", tmp), format!("{:#}", val)); + Ok(()) +}