Bug fix: query planner double index (#2690)

This commit is contained in:
Emmanuel Keller 2023-09-12 17:36:43 +01:00 committed by GitHub
parent c51912ab81
commit 34fc0cc6e6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23

View file

@ -52,15 +52,15 @@ struct TreeBuilder<'a> {
table: &'a Table, table: &'a Table,
with: &'a Option<With>, with: &'a Option<With>,
indexes: Option<Arc<[DefineIndexStatement]>>, indexes: Option<Arc<[DefineIndexStatement]>>,
index_lookup: HashMap<Idiom, IndexRef>, index_lookup: HashMap<Idiom, Option<Arc<Vec<IndexRef>>>>,
index_map: IndexMap, index_map: IndexMap,
with_indexes: Vec<IndexRef>, with_indexes: Vec<IndexRef>,
} }
impl<'a> TreeBuilder<'a> { impl<'a> TreeBuilder<'a> {
async fn find_index(&mut self, i: &Idiom) -> Result<Option<IndexRef>, Error> { async fn find_indexes(&mut self, i: &Idiom) -> Result<Option<Arc<Vec<IndexRef>>>, Error> {
if let Some(ir) = self.index_lookup.get(i) { if let Some(irs) = self.index_lookup.get(i) {
return Ok(Some(*ir)); return Ok(irs.clone());
} }
if self.indexes.is_none() { if self.indexes.is_none() {
let indexes = self let indexes = self
@ -72,22 +72,28 @@ impl<'a> TreeBuilder<'a> {
.await?; .await?;
self.indexes = Some(indexes); self.indexes = Some(indexes);
} }
let mut irs = Vec::new();
if let Some(indexes) = &self.indexes { if let Some(indexes) = &self.indexes {
for ix in indexes.as_ref() { for ix in indexes.as_ref() {
if ix.cols.len() == 1 && ix.cols[0].eq(i) { if ix.cols.len() == 1 && ix.cols[0].eq(i) {
let ir = self.index_lookup.len() as IndexRef; let ir = self.index_map.definitions.len() as IndexRef;
if let Some(With::Index(ixs)) = self.with { if let Some(With::Index(ixs)) = self.with {
if ixs.contains(&ix.name.0) { if ixs.contains(&ix.name.0) {
self.with_indexes.push(ir); self.with_indexes.push(ir);
} }
} }
self.index_lookup.insert(i.clone(), ir);
self.index_map.definitions.insert(ir, ix.clone()); self.index_map.definitions.insert(ir, ix.clone());
return Ok(Some(ir)); irs.push(ir);
} }
} }
} }
Ok(None) let irs = if irs.is_empty() {
None
} else {
Some(Arc::new(irs))
};
self.index_lookup.insert(i.clone(), irs.clone());
Ok(irs)
} }
#[cfg_attr(not(target_arch = "wasm32"), async_recursion)] #[cfg_attr(not(target_arch = "wasm32"), async_recursion)]
@ -110,11 +116,12 @@ impl<'a> TreeBuilder<'a> {
} }
async fn eval_idiom(&mut self, i: &Idiom) -> Result<Node, Error> { async fn eval_idiom(&mut self, i: &Idiom) -> Result<Node, Error> {
Ok(if let Some(ix) = self.find_index(i).await? { if let Some(irs) = self.find_indexes(i).await? {
Node::IndexedField(i.to_owned(), ix) if !irs.is_empty() {
} else { return Ok(Node::IndexedField(i.to_owned(), irs));
Node::NonIndexedField }
}) }
Ok(Node::NonIndexedField)
} }
async fn eval_expression(&mut self, e: &Expression) -> Result<Node, Error> { async fn eval_expression(&mut self, e: &Expression) -> Result<Node, Error> {
@ -138,10 +145,10 @@ impl<'a> TreeBuilder<'a> {
}); });
} }
let mut io = None; let mut io = None;
if let Some((id, ix)) = left.is_indexed_field() { if let Some((id, irs)) = left.is_indexed_field() {
io = self.lookup_index_option(ix, o, id, &right, e); io = self.lookup_index_option(irs.as_slice(), o, id, &right, e);
} else if let Some((id, ix)) = right.is_indexed_field() { } else if let Some((id, irs)) = right.is_indexed_field() {
io = self.lookup_index_option(ix, o, id, &left, e); io = self.lookup_index_option(irs.as_slice(), o, id, &left, e);
}; };
Ok(Node::Expression { Ok(Node::Expression {
io, io,
@ -155,32 +162,34 @@ impl<'a> TreeBuilder<'a> {
fn lookup_index_option( fn lookup_index_option(
&mut self, &mut self,
ir: IndexRef, irs: &[IndexRef],
op: &Operator, op: &Operator,
id: &Idiom, id: &Idiom,
v: &Node, v: &Node,
e: &Expression, e: &Expression,
) -> Option<IndexOption> { ) -> Option<IndexOption> {
if let Some(v) = v.is_scalar() { if let Some(v) = v.is_scalar() {
if let Some(ix) = self.index_map.definitions.get(&ir) { for ir in irs {
let op = match &ix.index { if let Some(ix) = self.index_map.definitions.get(ir) {
Index::Idx => Self::eval_index_operator(op, v), let op = match &ix.index {
Index::Uniq => Self::eval_index_operator(op, v), Index::Idx => Self::eval_index_operator(op, v),
Index::Search { Index::Uniq => Self::eval_index_operator(op, v),
.. Index::Search {
} => { ..
if let Operator::Matches(mr) = op { } => {
Some(IndexOperator::Matches(v.clone().to_raw_string(), *mr)) if let Operator::Matches(mr) = op {
} else { Some(IndexOperator::Matches(v.clone().to_raw_string(), *mr))
None } else {
None
}
} }
Index::MTree(_) => None,
};
if let Some(op) = op {
let io = IndexOption::new(*ir, id.clone(), op);
self.index_map.options.insert(Arc::new(e.clone()), io.clone());
return Some(io);
} }
Index::MTree(_) => None,
};
if let Some(op) = op {
let io = IndexOption::new(ir, id.clone(), op);
self.index_map.options.insert(Arc::new(e.clone()), io.clone());
return Some(io);
} }
} }
} }
@ -223,7 +232,7 @@ pub(super) enum Node {
right: Box<Node>, right: Box<Node>,
exp: Arc<Expression>, exp: Arc<Expression>,
}, },
IndexedField(Idiom, IndexRef), IndexedField(Idiom, Arc<Vec<IndexRef>>),
NonIndexedField, NonIndexedField,
Scalar(Value), Scalar(Value),
Unsupported(String), Unsupported(String),
@ -238,9 +247,9 @@ impl Node {
} }
} }
pub(super) fn is_indexed_field(&self) -> Option<(&Idiom, IndexRef)> { pub(super) fn is_indexed_field(&self) -> Option<(&Idiom, Arc<Vec<IndexRef>>)> {
if let Node::IndexedField(id, ix) = self { if let Node::IndexedField(id, irs) = self {
Some((id, *ix)) Some((id, irs.clone()))
} else { } else {
None None
} }