Bug fix: Implements the union strategy on unique indexes (#3674)
This commit is contained in:
parent
87da9c0b01
commit
0e3fb7b365
4 changed files with 107 additions and 1 deletions
|
@ -605,6 +605,10 @@ impl<'a> Processor<'a> {
|
|||
}
|
||||
// Everything ok
|
||||
return Ok(());
|
||||
} else {
|
||||
return Err(Error::QueryNotExecutedDetail {
|
||||
message: "No Iterator has been found.".to_string(),
|
||||
});
|
||||
}
|
||||
}
|
||||
Err(Error::QueryNotExecutedDetail {
|
||||
|
|
|
@ -10,6 +10,7 @@ use crate::idx::ft::{FtIndex, MatchRef};
|
|||
use crate::idx::planner::iterators::{
|
||||
DocIdsIterator, IndexEqualThingIterator, IndexRangeThingIterator, IndexUnionThingIterator,
|
||||
MatchesThingIterator, ThingIterator, UniqueEqualThingIterator, UniqueRangeThingIterator,
|
||||
UniqueUnionThingIterator,
|
||||
};
|
||||
use crate::idx::planner::knn::KnnPriorityList;
|
||||
use crate::idx::planner::plan::IndexOperator::Matches;
|
||||
|
@ -338,6 +339,9 @@ impl QueryExecutor {
|
|||
IndexOperator::Equality(value) => {
|
||||
Some(ThingIterator::UniqueEqual(UniqueEqualThingIterator::new(opt, ix, value)))
|
||||
}
|
||||
IndexOperator::Union(value) => {
|
||||
Some(ThingIterator::UniqueUnion(UniqueUnionThingIterator::new(opt, ix, value)))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -18,6 +18,7 @@ pub(crate) enum ThingIterator {
|
|||
IndexUnion(IndexUnionThingIterator),
|
||||
UniqueEqual(UniqueEqualThingIterator),
|
||||
UniqueRange(UniqueRangeThingIterator),
|
||||
UniqueUnion(UniqueUnionThingIterator),
|
||||
Matches(MatchesThingIterator),
|
||||
Knn(DocIdsIterator),
|
||||
}
|
||||
|
@ -34,6 +35,7 @@ impl ThingIterator {
|
|||
ThingIterator::IndexRange(i) => i.next_batch(tx, size).await,
|
||||
ThingIterator::UniqueRange(i) => i.next_batch(tx, size).await,
|
||||
ThingIterator::IndexUnion(i) => i.next_batch(tx, size).await,
|
||||
ThingIterator::UniqueUnion(i) => i.next_batch(tx, size).await,
|
||||
ThingIterator::Matches(i) => i.next_batch(tx, size).await,
|
||||
ThingIterator::Knn(i) => i.next_batch(tx, size).await,
|
||||
}
|
||||
|
@ -368,6 +370,45 @@ impl UniqueRangeThingIterator {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) struct UniqueUnionThingIterator {
|
||||
keys: VecDeque<Key>,
|
||||
}
|
||||
|
||||
impl UniqueUnionThingIterator {
|
||||
pub(super) fn new(opt: &Options, ix: &DefineIndexStatement, a: &Array) -> Self {
|
||||
// We create a VecDeque to hold the key for each value in the array.
|
||||
let keys: VecDeque<Key> =
|
||||
a.0.iter()
|
||||
.map(|v| {
|
||||
let a = Array::from(v.clone());
|
||||
let key = Index::new(opt.ns(), opt.db(), &ix.what, &ix.name, &a, None).into();
|
||||
key
|
||||
})
|
||||
.collect();
|
||||
Self {
|
||||
keys,
|
||||
}
|
||||
}
|
||||
|
||||
async fn next_batch(
|
||||
&mut self,
|
||||
txn: &Transaction,
|
||||
limit: u32,
|
||||
) -> Result<Vec<(Thing, Option<DocId>)>, Error> {
|
||||
let mut run = txn.lock().await;
|
||||
let mut res = vec![];
|
||||
while let Some(key) = self.keys.pop_front() {
|
||||
if let Some(val) = run.get(key).await? {
|
||||
res.push((val.into(), None));
|
||||
}
|
||||
if res.len() >= limit as usize {
|
||||
return Ok(res);
|
||||
}
|
||||
}
|
||||
Ok(res)
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct MatchesThingIterator {
|
||||
hits: Option<HitsIterator>,
|
||||
}
|
||||
|
|
|
@ -1312,6 +1312,63 @@ async fn select_with_in_operator() -> Result<(), Error> {
|
|||
);
|
||||
assert_eq!(format!("{:#}", tmp), format!("{:#}", val));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn select_with_in_operator_uniq_index() -> Result<(), Error> {
|
||||
let dbs = new_ds().await?;
|
||||
let ses = Session::owner().with_ns("test").with_db("test");
|
||||
|
||||
let sql = r#"
|
||||
DEFINE INDEX apprenantUid ON apprenants FIELDS apprenantUid UNIQUE;
|
||||
CREATE apprenants:1 CONTENT { apprenantUid: "00013483-fedd-43e3-a94e-80728d896f6e" };
|
||||
SELECT apprenantUid FROM apprenants WHERE apprenantUid in [];
|
||||
SELECT apprenantUid FROM apprenants WHERE apprenantUid IN ["00013483-fedd-43e3-a94e-80728d896f6e"];
|
||||
SELECT apprenantUid FROM apprenants WHERE apprenantUid IN ["99999999-aaaa-1111-8888-abcdef012345", "00013483-fedd-43e3-a94e-80728d896f6e"];
|
||||
SELECT apprenantUid FROM apprenants WHERE apprenantUid IN ["00013483-fedd-43e3-a94e-80728d896f6e", "99999999-aaaa-1111-8888-abcdef012345"];
|
||||
SELECT apprenantUid FROM apprenants WHERE apprenantUid IN ["99999999-aaaa-1111-8888-abcdef012345", "00013483-fedd-43e3-a94e-80728d896f6e", "99999999-aaaa-1111-8888-abcdef012345"];
|
||||
SELECT apprenantUid FROM apprenants WHERE apprenantUid IN ["00013483-fedd-43e3-a94e-80728d896f6e"] EXPLAIN;
|
||||
"#;
|
||||
let mut res = dbs.execute(&sql, &ses, None).await?;
|
||||
|
||||
assert_eq!(res.len(), 8);
|
||||
skip_ok(&mut res, 2)?;
|
||||
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(r#"[]"#);
|
||||
assert_eq!(format!("{:#}", tmp), format!("{:#}", val));
|
||||
|
||||
for _ in 0..4 {
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
r#"[
|
||||
{
|
||||
apprenantUid: '00013483-fedd-43e3-a94e-80728d896f6e'
|
||||
}
|
||||
]"#,
|
||||
);
|
||||
assert_eq!(format!("{:#}", tmp), format!("{:#}", val));
|
||||
}
|
||||
|
||||
let tmp = res.remove(0).result?;
|
||||
let val = Value::parse(
|
||||
r#"[
|
||||
{
|
||||
detail: {
|
||||
plan: {
|
||||
index: 'apprenantUid',
|
||||
operator: 'union',
|
||||
value: [
|
||||
'00013483-fedd-43e3-a94e-80728d896f6e'
|
||||
]
|
||||
},
|
||||
table: 'apprenants'
|
||||
},
|
||||
operation: 'Iterate Index'
|
||||
}
|
||||
]"#,
|
||||
);
|
||||
assert_eq!(format!("{:#}", tmp), format!("{:#}", val));
|
||||
Ok(())
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue