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
|
// Everything ok
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
} else {
|
||||||
|
return Err(Error::QueryNotExecutedDetail {
|
||||||
|
message: "No Iterator has been found.".to_string(),
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error::QueryNotExecutedDetail {
|
Err(Error::QueryNotExecutedDetail {
|
||||||
|
|
|
@ -10,6 +10,7 @@ use crate::idx::ft::{FtIndex, MatchRef};
|
||||||
use crate::idx::planner::iterators::{
|
use crate::idx::planner::iterators::{
|
||||||
DocIdsIterator, IndexEqualThingIterator, IndexRangeThingIterator, IndexUnionThingIterator,
|
DocIdsIterator, IndexEqualThingIterator, IndexRangeThingIterator, IndexUnionThingIterator,
|
||||||
MatchesThingIterator, ThingIterator, UniqueEqualThingIterator, UniqueRangeThingIterator,
|
MatchesThingIterator, ThingIterator, UniqueEqualThingIterator, UniqueRangeThingIterator,
|
||||||
|
UniqueUnionThingIterator,
|
||||||
};
|
};
|
||||||
use crate::idx::planner::knn::KnnPriorityList;
|
use crate::idx::planner::knn::KnnPriorityList;
|
||||||
use crate::idx::planner::plan::IndexOperator::Matches;
|
use crate::idx::planner::plan::IndexOperator::Matches;
|
||||||
|
@ -338,6 +339,9 @@ impl QueryExecutor {
|
||||||
IndexOperator::Equality(value) => {
|
IndexOperator::Equality(value) => {
|
||||||
Some(ThingIterator::UniqueEqual(UniqueEqualThingIterator::new(opt, ix, value)))
|
Some(ThingIterator::UniqueEqual(UniqueEqualThingIterator::new(opt, ix, value)))
|
||||||
}
|
}
|
||||||
|
IndexOperator::Union(value) => {
|
||||||
|
Some(ThingIterator::UniqueUnion(UniqueUnionThingIterator::new(opt, ix, value)))
|
||||||
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ pub(crate) enum ThingIterator {
|
||||||
IndexUnion(IndexUnionThingIterator),
|
IndexUnion(IndexUnionThingIterator),
|
||||||
UniqueEqual(UniqueEqualThingIterator),
|
UniqueEqual(UniqueEqualThingIterator),
|
||||||
UniqueRange(UniqueRangeThingIterator),
|
UniqueRange(UniqueRangeThingIterator),
|
||||||
|
UniqueUnion(UniqueUnionThingIterator),
|
||||||
Matches(MatchesThingIterator),
|
Matches(MatchesThingIterator),
|
||||||
Knn(DocIdsIterator),
|
Knn(DocIdsIterator),
|
||||||
}
|
}
|
||||||
|
@ -34,6 +35,7 @@ impl ThingIterator {
|
||||||
ThingIterator::IndexRange(i) => i.next_batch(tx, size).await,
|
ThingIterator::IndexRange(i) => i.next_batch(tx, size).await,
|
||||||
ThingIterator::UniqueRange(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::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::Matches(i) => i.next_batch(tx, size).await,
|
||||||
ThingIterator::Knn(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 {
|
pub(crate) struct MatchesThingIterator {
|
||||||
hits: Option<HitsIterator>,
|
hits: Option<HitsIterator>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1312,6 +1312,63 @@ async fn select_with_in_operator() -> Result<(), Error> {
|
||||||
);
|
);
|
||||||
assert_eq!(format!("{:#}", tmp), format!("{:#}", val));
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue