Query planner to support mixed number types on range queries (#4747)
This commit is contained in:
parent
0fe9807096
commit
3d505697de
4 changed files with 863 additions and 70 deletions
|
@ -12,9 +12,10 @@ use crate::idx::ft::{FtIndex, MatchRef};
|
|||
use crate::idx::planner::checker::{HnswConditionChecker, MTreeConditionChecker};
|
||||
use crate::idx::planner::iterators::{
|
||||
IndexEqualThingIterator, IndexJoinThingIterator, IndexRangeThingIterator,
|
||||
IndexUnionThingIterator, IteratorRecord, IteratorRef, KnnIterator, KnnIteratorResult,
|
||||
MatchesThingIterator, MultipleIterators, ThingIterator, UniqueEqualThingIterator,
|
||||
UniqueJoinThingIterator, UniqueRangeThingIterator, UniqueUnionThingIterator,
|
||||
IndexUnionThingIterator, IteratorRange, IteratorRecord, IteratorRef, KnnIterator,
|
||||
KnnIteratorResult, MatchesThingIterator, MultipleIterators, ThingIterator,
|
||||
UniqueEqualThingIterator, UniqueJoinThingIterator, UniqueRangeThingIterator,
|
||||
UniqueUnionThingIterator, ValueType,
|
||||
};
|
||||
use crate::idx::planner::knn::{KnnBruteForceResult, KnnPriorityList};
|
||||
use crate::idx::planner::plan::IndexOperator::Matches;
|
||||
|
@ -391,7 +392,7 @@ impl QueryExecutor {
|
|||
Ok(match io.op() {
|
||||
IndexOperator::Equality(value) | IndexOperator::Exactness(value) => {
|
||||
if let Value::Number(n) = value.as_ref() {
|
||||
let values = Self::get_number_variants(n);
|
||||
let values = Self::get_equal_number_variants(n);
|
||||
if values.len() == 1 {
|
||||
Some(Self::new_index_equal_iterator(irf, opt, &ix, &values[0])?)
|
||||
} else {
|
||||
|
@ -444,47 +445,224 @@ impl QueryExecutor {
|
|||
Ok(ThingIterator::Multiples(Box::new(MultipleIterators::new(iterators))))
|
||||
}
|
||||
|
||||
/// This function takes a reference to a `Number` enum and returns a vector of `Value` enum.
|
||||
/// The `Number` enum can be either an `Int`, `Float`, or `Decimal`.
|
||||
/// The function first initializes an empty vector with a capacity of 3 to store the converted values.
|
||||
/// It then matches on the input number and performs the appropriate conversions.
|
||||
/// For `Int`, it pushes the original `Int` value, the equivalent `Float` value, and if possible, the equivalent `Decimal` value.
|
||||
/// For `Float`, it pushes the original `Float` value, the truncated `Int` value if it is a whole number, and if possible, the equivalent `Decimal` value.
|
||||
/// For `Decimal`, it pushes the equivalent `Int` value if it is representable as an `i64`, and the equivalent `Float` value if it is representable as an `f64`.
|
||||
/// Finally, it returns the vector of converted values.
|
||||
fn get_number_variants(n: &Number) -> Vec<Value> {
|
||||
let mut values = Vec::with_capacity(3);
|
||||
/// This function takes a reference to a `Number` enum and a conversion function `float_to_int`.
|
||||
/// It returns a tuple containing the variants of the `Number` as `Option<i64>`, `Option<f64>`, and `Option<Decimal>`.
|
||||
///
|
||||
/// The `Number` enum can be one of the following:
|
||||
/// - `Int(i64)`: Integer value.
|
||||
/// - `Float(f64)`: Floating point value.
|
||||
/// - `Decimal(Decimal)`: Decimal value.
|
||||
///
|
||||
/// The function performs the following conversions based on the type of the `Number`:
|
||||
/// - For `Int`, it returns the original `Int` value as `Option<i64>`, the equivalent `Float` value as `Option<f64>`, and the equivalent `Decimal` value as `Option<Decimal>`.
|
||||
/// - For `Float`, it uses the provided `float_to_int` function to convert the `Float` to `Option<i64>`, returns the original `Float` value as `Option<f64>`, and the equivalent `Decimal` value as `Option<Decimal>`.
|
||||
/// - For `Decimal`, it converts the `Decimal` to `Option<i64>` (if representable as `i64`), returns the equivalent `Float` value as `Option<f64>` (if representable as `f64`), and the original `Decimal` value as `Option<Decimal>`.
|
||||
///
|
||||
/// # Parameters
|
||||
/// - `n`: A reference to a `Number` enum.
|
||||
/// - `float_to_int`: A function that converts a reference to `f64` to `Option<i64>`.
|
||||
///
|
||||
/// # Returns
|
||||
/// A tuple of `(Option<i64>, Option<f64>, Option<Decimal>)` representing the converted variants of the input `Number`.
|
||||
fn get_number_variants<F>(
|
||||
n: &Number,
|
||||
float_to_int: F,
|
||||
) -> (Option<i64>, Option<f64>, Option<Decimal>)
|
||||
where
|
||||
F: Fn(&f64) -> Option<i64>,
|
||||
{
|
||||
let oi;
|
||||
let of;
|
||||
let od;
|
||||
match n {
|
||||
Number::Int(i) => {
|
||||
values.push(Number::Int(*i).into());
|
||||
values.push(Number::Float(*i as f64).into());
|
||||
if let Some(d) = Decimal::from_i64(*i) {
|
||||
values.push(Number::Decimal(d.normalize()).into());
|
||||
}
|
||||
oi = Some(*i);
|
||||
of = Some(*i as f64);
|
||||
od = Decimal::from_i64(*i);
|
||||
}
|
||||
Number::Float(f) => {
|
||||
values.push(Number::Float(*f).into());
|
||||
if f.trunc().eq(f) {
|
||||
values.push(Number::Int(*f as i64).into());
|
||||
}
|
||||
if let Some(d) = Decimal::from_f64(*f) {
|
||||
values.push(Number::Decimal(d.normalize()).into());
|
||||
}
|
||||
oi = float_to_int(f);
|
||||
of = Some(*f);
|
||||
od = Decimal::from_f64(*f);
|
||||
}
|
||||
Number::Decimal(d) => {
|
||||
values.push(Number::Decimal(d.normalize()).into());
|
||||
if let Some(i) = d.to_i64() {
|
||||
values.push(Number::Int(i).into());
|
||||
}
|
||||
if let Some(f) = d.to_f64() {
|
||||
values.push(Number::Float(f).into());
|
||||
}
|
||||
oi = d.to_i64();
|
||||
of = d.to_f64();
|
||||
od = Some(*d);
|
||||
}
|
||||
};
|
||||
println!("VALUES: {:?}", values);
|
||||
(oi, of, od)
|
||||
}
|
||||
fn get_equal_number_variants(n: &Number) -> Vec<Value> {
|
||||
let (oi, of, od) = Self::get_number_variants(n, |f| {
|
||||
if f.trunc().eq(f) {
|
||||
f.to_i64()
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let mut values = Vec::with_capacity(3);
|
||||
if let Some(i) = oi {
|
||||
values.push(Number::Int(i).into());
|
||||
}
|
||||
if let Some(f) = of {
|
||||
values.push(Number::Float(f).into());
|
||||
}
|
||||
if let Some(d) = od {
|
||||
values.push(Number::Decimal(d).into());
|
||||
}
|
||||
values
|
||||
}
|
||||
|
||||
fn get_range_number_from_variants(n: &Number) -> (Option<i64>, Option<f64>, Option<Decimal>) {
|
||||
Self::get_number_variants(n, |f| f.floor().to_i64())
|
||||
}
|
||||
|
||||
fn get_range_number_to_variants(n: &Number) -> (Option<i64>, Option<f64>, Option<Decimal>) {
|
||||
Self::get_number_variants(n, |f| f.ceil().to_i64())
|
||||
}
|
||||
|
||||
fn get_from_range_number_variants<'a>(from: &Number, from_inc: bool) -> Vec<IteratorRange<'a>> {
|
||||
let (from_i, from_f, from_d) = Self::get_range_number_from_variants(from);
|
||||
let mut vec = Vec::with_capacity(3);
|
||||
if let Some(from) = from_i {
|
||||
vec.push(IteratorRange::new(
|
||||
ValueType::NumberInt,
|
||||
RangeValue {
|
||||
value: Number::Int(from).into(),
|
||||
inclusive: from_inc,
|
||||
},
|
||||
RangeValue {
|
||||
value: Value::None,
|
||||
inclusive: false,
|
||||
},
|
||||
));
|
||||
}
|
||||
if let Some(from) = from_f {
|
||||
vec.push(IteratorRange::new(
|
||||
ValueType::NumberFloat,
|
||||
RangeValue {
|
||||
value: Number::Float(from).into(),
|
||||
inclusive: from_inc,
|
||||
},
|
||||
RangeValue {
|
||||
value: Value::None,
|
||||
inclusive: false,
|
||||
},
|
||||
));
|
||||
}
|
||||
if let Some(from) = from_d {
|
||||
vec.push(IteratorRange::new(
|
||||
ValueType::NumberDecimal,
|
||||
RangeValue {
|
||||
value: Number::Decimal(from).into(),
|
||||
inclusive: from_inc,
|
||||
},
|
||||
RangeValue {
|
||||
value: Value::None,
|
||||
inclusive: false,
|
||||
},
|
||||
));
|
||||
}
|
||||
vec
|
||||
}
|
||||
|
||||
fn get_to_range_number_variants<'a>(to: &Number, to_inc: bool) -> Vec<IteratorRange<'a>> {
|
||||
let (from_i, from_f, from_d) = Self::get_range_number_to_variants(to);
|
||||
let mut vec = Vec::with_capacity(3);
|
||||
if let Some(to) = from_i {
|
||||
vec.push(IteratorRange::new(
|
||||
ValueType::NumberInt,
|
||||
RangeValue {
|
||||
value: Value::None,
|
||||
inclusive: false,
|
||||
},
|
||||
RangeValue {
|
||||
value: Number::Int(to).into(),
|
||||
inclusive: to_inc,
|
||||
},
|
||||
));
|
||||
}
|
||||
if let Some(to) = from_f {
|
||||
vec.push(IteratorRange::new(
|
||||
ValueType::NumberFloat,
|
||||
RangeValue {
|
||||
value: Value::None,
|
||||
inclusive: false,
|
||||
},
|
||||
RangeValue {
|
||||
value: Number::Float(to).into(),
|
||||
inclusive: to_inc,
|
||||
},
|
||||
));
|
||||
}
|
||||
if let Some(to) = from_d {
|
||||
vec.push(IteratorRange::new(
|
||||
ValueType::NumberDecimal,
|
||||
RangeValue {
|
||||
value: Value::None,
|
||||
inclusive: false,
|
||||
},
|
||||
RangeValue {
|
||||
value: Number::Decimal(to).into(),
|
||||
inclusive: to_inc,
|
||||
},
|
||||
));
|
||||
}
|
||||
vec
|
||||
}
|
||||
|
||||
fn get_ranges_number_variants<'a>(
|
||||
from: &Number,
|
||||
from_inc: bool,
|
||||
to: &Number,
|
||||
to_inc: bool,
|
||||
) -> Vec<IteratorRange<'a>> {
|
||||
let (from_i, from_f, from_d) = Self::get_range_number_from_variants(from);
|
||||
let (to_i, to_f, to_d) = Self::get_range_number_to_variants(to);
|
||||
let mut vec = Vec::with_capacity(3);
|
||||
if let (Some(from), Some(to)) = (from_i, to_i) {
|
||||
vec.push(IteratorRange::new(
|
||||
ValueType::NumberInt,
|
||||
RangeValue {
|
||||
value: Number::Int(from).into(),
|
||||
inclusive: from_inc,
|
||||
},
|
||||
RangeValue {
|
||||
value: Number::Int(to).into(),
|
||||
inclusive: to_inc,
|
||||
},
|
||||
));
|
||||
}
|
||||
if let (Some(from), Some(to)) = (from_f, to_f) {
|
||||
vec.push(IteratorRange::new(
|
||||
ValueType::NumberFloat,
|
||||
RangeValue {
|
||||
value: Number::Float(from).into(),
|
||||
inclusive: from_inc,
|
||||
},
|
||||
RangeValue {
|
||||
value: Number::Float(to).into(),
|
||||
inclusive: to_inc,
|
||||
},
|
||||
));
|
||||
}
|
||||
if let (Some(from), Some(to)) = (from_d, to_d) {
|
||||
vec.push(IteratorRange::new(
|
||||
ValueType::NumberDecimal,
|
||||
RangeValue {
|
||||
value: Number::Decimal(from).into(),
|
||||
inclusive: from_inc,
|
||||
},
|
||||
RangeValue {
|
||||
value: Number::Decimal(to).into(),
|
||||
inclusive: to_inc,
|
||||
},
|
||||
));
|
||||
}
|
||||
vec
|
||||
}
|
||||
|
||||
fn new_range_iterator(
|
||||
&self,
|
||||
opt: &Options,
|
||||
|
@ -495,26 +673,44 @@ impl QueryExecutor {
|
|||
if let Some(ix) = self.get_index_def(ir) {
|
||||
match ix.index {
|
||||
Index::Idx => {
|
||||
return Ok(Some(ThingIterator::IndexRange(IndexRangeThingIterator::new(
|
||||
let ranges = Self::get_ranges_variants(from, to);
|
||||
if let Some(ranges) = ranges {
|
||||
if ranges.len() == 1 {
|
||||
return Ok(Some(Self::new_index_range_iterator(
|
||||
ir, opt, ix, &ranges[0],
|
||||
)?));
|
||||
} else {
|
||||
return Ok(Some(Self::new_multiple_index_range_iterator(
|
||||
ir, opt, ix, &ranges,
|
||||
)?));
|
||||
}
|
||||
}
|
||||
return Ok(Some(Self::new_index_range_iterator(
|
||||
ir,
|
||||
opt.ns()?,
|
||||
opt.db()?,
|
||||
&ix.what,
|
||||
&ix.name,
|
||||
from,
|
||||
to,
|
||||
))))
|
||||
opt,
|
||||
ix,
|
||||
&IteratorRange::new_ref(ValueType::None, from, to),
|
||||
)?));
|
||||
}
|
||||
Index::Uniq => {
|
||||
return Ok(Some(ThingIterator::UniqueRange(UniqueRangeThingIterator::new(
|
||||
let ranges = Self::get_ranges_variants(from, to);
|
||||
if let Some(ranges) = ranges {
|
||||
if ranges.len() == 1 {
|
||||
return Ok(Some(Self::new_unique_range_iterator(
|
||||
ir, opt, ix, &ranges[0],
|
||||
)?));
|
||||
} else {
|
||||
return Ok(Some(Self::new_multiple_unique_range_iterator(
|
||||
ir, opt, ix, &ranges,
|
||||
)?));
|
||||
}
|
||||
}
|
||||
return Ok(Some(Self::new_unique_range_iterator(
|
||||
ir,
|
||||
opt.ns()?,
|
||||
opt.db()?,
|
||||
&ix.what,
|
||||
&ix.name,
|
||||
from,
|
||||
to,
|
||||
))))
|
||||
opt,
|
||||
ix,
|
||||
&IteratorRange::new_ref(ValueType::None, from, to),
|
||||
)?));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
@ -522,6 +718,82 @@ impl QueryExecutor {
|
|||
Ok(None)
|
||||
}
|
||||
|
||||
fn get_ranges_variants<'a>(
|
||||
from: &'a RangeValue,
|
||||
to: &'a RangeValue,
|
||||
) -> Option<Vec<IteratorRange<'a>>> {
|
||||
match (&from.value, &to.value) {
|
||||
(Value::Number(from_n), Value::Number(to_n)) => {
|
||||
Some(Self::get_ranges_number_variants(from_n, from.inclusive, to_n, to.inclusive))
|
||||
}
|
||||
(Value::Number(from_n), Value::None) => {
|
||||
Some(Self::get_from_range_number_variants(from_n, from.inclusive))
|
||||
}
|
||||
(Value::None, Value::Number(to_n)) => {
|
||||
Some(Self::get_to_range_number_variants(to_n, to.inclusive))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn new_index_range_iterator(
|
||||
ir: IndexRef,
|
||||
opt: &Options,
|
||||
ix: &DefineIndexStatement,
|
||||
range: &IteratorRange,
|
||||
) -> Result<ThingIterator, Error> {
|
||||
Ok(ThingIterator::IndexRange(IndexRangeThingIterator::new(
|
||||
ir,
|
||||
opt.ns()?,
|
||||
opt.db()?,
|
||||
&ix.what,
|
||||
&ix.name,
|
||||
range,
|
||||
)))
|
||||
}
|
||||
|
||||
fn new_unique_range_iterator(
|
||||
ir: IndexRef,
|
||||
opt: &Options,
|
||||
ix: &DefineIndexStatement,
|
||||
range: &IteratorRange<'_>,
|
||||
) -> Result<ThingIterator, Error> {
|
||||
Ok(ThingIterator::UniqueRange(UniqueRangeThingIterator::new(
|
||||
ir,
|
||||
opt.ns()?,
|
||||
opt.db()?,
|
||||
&ix.what,
|
||||
&ix.name,
|
||||
range,
|
||||
)))
|
||||
}
|
||||
|
||||
fn new_multiple_index_range_iterator(
|
||||
ir: IndexRef,
|
||||
opt: &Options,
|
||||
ix: &DefineIndexStatement,
|
||||
ranges: &[IteratorRange],
|
||||
) -> Result<ThingIterator, Error> {
|
||||
let mut iterators = VecDeque::with_capacity(ranges.len());
|
||||
for range in ranges {
|
||||
iterators.push_back(Self::new_index_range_iterator(ir, opt, ix, range)?);
|
||||
}
|
||||
Ok(ThingIterator::Multiples(Box::new(MultipleIterators::new(iterators))))
|
||||
}
|
||||
|
||||
fn new_multiple_unique_range_iterator(
|
||||
ir: IndexRef,
|
||||
opt: &Options,
|
||||
ix: &DefineIndexStatement,
|
||||
ranges: &[IteratorRange<'_>],
|
||||
) -> Result<ThingIterator, Error> {
|
||||
let mut iterators = VecDeque::with_capacity(ranges.len());
|
||||
for range in ranges {
|
||||
iterators.push_back(Self::new_unique_range_iterator(ir, opt, ix, range)?);
|
||||
}
|
||||
Ok(ThingIterator::Multiples(Box::new(MultipleIterators::new(iterators))))
|
||||
}
|
||||
|
||||
async fn new_unique_index_iterator(
|
||||
&self,
|
||||
opt: &Options,
|
||||
|
@ -532,7 +804,7 @@ impl QueryExecutor {
|
|||
Ok(match io.op() {
|
||||
IndexOperator::Equality(value) | IndexOperator::Exactness(value) => {
|
||||
if let Value::Number(n) = value.as_ref() {
|
||||
let values = Self::get_number_variants(n);
|
||||
let values = Self::get_equal_number_variants(n);
|
||||
if values.len() == 1 {
|
||||
Some(Self::new_unique_equal_iterator(irf, opt, ix, &values[0])?)
|
||||
} else {
|
||||
|
|
|
@ -9,8 +9,10 @@ use crate::key::index::Index;
|
|||
use crate::kvs::Key;
|
||||
use crate::kvs::Transaction;
|
||||
use crate::sql::statements::DefineIndexStatement;
|
||||
use crate::sql::{Array, Ident, Thing, Value};
|
||||
use crate::sql::{Array, Ident, Number, Thing, Value};
|
||||
use radix_trie::Trie;
|
||||
use rust_decimal::Decimal;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::VecDeque;
|
||||
use std::sync::Arc;
|
||||
|
||||
|
@ -247,6 +249,96 @@ impl RangeScan {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) struct IteratorRange<'a> {
|
||||
value_type: ValueType,
|
||||
from: Cow<'a, RangeValue>,
|
||||
to: Cow<'a, RangeValue>,
|
||||
}
|
||||
|
||||
impl<'a> IteratorRange<'a> {
|
||||
pub(super) fn new(t: ValueType, from: RangeValue, to: RangeValue) -> Self {
|
||||
IteratorRange {
|
||||
value_type: t,
|
||||
from: Cow::Owned(from),
|
||||
to: Cow::Owned(to),
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn new_ref(t: ValueType, from: &'a RangeValue, to: &'a RangeValue) -> Self {
|
||||
IteratorRange {
|
||||
value_type: t,
|
||||
from: Cow::Borrowed(from),
|
||||
to: Cow::Borrowed(to),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When we know the type of the range values, we have the opportunity
|
||||
// to restrict the key range to the exact prefixes according to the type.
|
||||
#[derive(Copy, Clone)]
|
||||
pub(super) enum ValueType {
|
||||
None,
|
||||
NumberInt,
|
||||
NumberFloat,
|
||||
NumberDecimal,
|
||||
}
|
||||
|
||||
impl ValueType {
|
||||
fn prefix_beg(&self, ns: &str, db: &str, ix_what: &Ident, ix_name: &Ident) -> Vec<u8> {
|
||||
match self {
|
||||
Self::None => Index::prefix_beg(ns, db, ix_what, ix_name),
|
||||
Self::NumberInt => Index::prefix_ids_beg(
|
||||
ns,
|
||||
db,
|
||||
ix_what,
|
||||
ix_name,
|
||||
&Array(vec![Value::Number(Number::Int(i64::MIN))]),
|
||||
),
|
||||
Self::NumberFloat => Index::prefix_ids_beg(
|
||||
ns,
|
||||
db,
|
||||
ix_what,
|
||||
ix_name,
|
||||
&Array(vec![Value::Number(Number::Float(f64::MIN))]),
|
||||
),
|
||||
Self::NumberDecimal => Index::prefix_ids_beg(
|
||||
ns,
|
||||
db,
|
||||
ix_what,
|
||||
ix_name,
|
||||
&Array(vec![Value::Number(Number::Decimal(Decimal::MIN))]),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
fn prefix_end(&self, ns: &str, db: &str, ix_what: &Ident, ix_name: &Ident) -> Vec<u8> {
|
||||
match self {
|
||||
Self::None => Index::prefix_end(ns, db, ix_what, ix_name),
|
||||
Self::NumberInt => Index::prefix_ids_end(
|
||||
ns,
|
||||
db,
|
||||
ix_what,
|
||||
ix_name,
|
||||
&Array(vec![Value::Number(Number::Int(i64::MAX))]),
|
||||
),
|
||||
Self::NumberFloat => Index::prefix_ids_end(
|
||||
ns,
|
||||
db,
|
||||
ix_what,
|
||||
ix_name,
|
||||
&Array(vec![Value::Number(Number::Float(f64::MAX))]),
|
||||
),
|
||||
Self::NumberDecimal => Index::prefix_ids_end(
|
||||
ns,
|
||||
db,
|
||||
ix_what,
|
||||
ix_name,
|
||||
&Array(vec![Value::Number(Number::Decimal(Decimal::MAX))]),
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct IndexRangeThingIterator {
|
||||
irf: IteratorRef,
|
||||
r: RangeScan,
|
||||
|
@ -259,14 +351,13 @@ impl IndexRangeThingIterator {
|
|||
db: &str,
|
||||
ix_what: &Ident,
|
||||
ix_name: &Ident,
|
||||
from: &RangeValue,
|
||||
to: &RangeValue,
|
||||
range: &IteratorRange<'_>,
|
||||
) -> Self {
|
||||
let beg = Self::compute_beg(ns, db, ix_what, ix_name, from);
|
||||
let end = Self::compute_end(ns, db, ix_what, ix_name, to);
|
||||
let beg = Self::compute_beg(ns, db, ix_what, ix_name, &range.from, range.value_type);
|
||||
let end = Self::compute_end(ns, db, ix_what, ix_name, &range.to, range.value_type);
|
||||
Self {
|
||||
irf,
|
||||
r: RangeScan::new(beg, from.inclusive, end, to.inclusive),
|
||||
r: RangeScan::new(beg, range.from.inclusive, end, range.to.inclusive),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -281,7 +372,12 @@ impl IndexRangeThingIterator {
|
|||
value: Value::None,
|
||||
inclusive: true,
|
||||
};
|
||||
Self::new(irf, ns, db, ix_what, ix_name, &full_range, &full_range)
|
||||
let range = IteratorRange {
|
||||
value_type: ValueType::None,
|
||||
from: Cow::Borrowed(&full_range),
|
||||
to: Cow::Borrowed(&full_range),
|
||||
};
|
||||
Self::new(irf, ns, db, ix_what, ix_name, &range)
|
||||
}
|
||||
|
||||
fn compute_beg(
|
||||
|
@ -290,9 +386,10 @@ impl IndexRangeThingIterator {
|
|||
ix_what: &Ident,
|
||||
ix_name: &Ident,
|
||||
from: &RangeValue,
|
||||
value_type: ValueType,
|
||||
) -> Vec<u8> {
|
||||
if from.value == Value::None {
|
||||
return Index::prefix_beg(ns, db, ix_what, ix_name);
|
||||
return value_type.prefix_beg(ns, db, ix_what, ix_name);
|
||||
}
|
||||
let fd = Array::from(from.value.to_owned());
|
||||
if from.inclusive {
|
||||
|
@ -308,9 +405,10 @@ impl IndexRangeThingIterator {
|
|||
ix_what: &Ident,
|
||||
ix_name: &Ident,
|
||||
to: &RangeValue,
|
||||
value_type: ValueType,
|
||||
) -> Vec<u8> {
|
||||
if to.value == Value::None {
|
||||
return Index::prefix_end(ns, db, ix_what, ix_name);
|
||||
return value_type.prefix_end(ns, db, ix_what, ix_name);
|
||||
}
|
||||
let fd = Array::from(to.value.to_owned());
|
||||
if to.inclusive {
|
||||
|
@ -571,14 +669,13 @@ impl UniqueRangeThingIterator {
|
|||
db: &str,
|
||||
ix_what: &Ident,
|
||||
ix_name: &Ident,
|
||||
from: &RangeValue,
|
||||
to: &RangeValue,
|
||||
range: &IteratorRange<'_>,
|
||||
) -> Self {
|
||||
let beg = Self::compute_beg(ns, db, ix_what, ix_name, from);
|
||||
let end = Self::compute_end(ns, db, ix_what, ix_name, to);
|
||||
let beg = Self::compute_beg(ns, db, ix_what, ix_name, &range.from, range.value_type);
|
||||
let end = Self::compute_end(ns, db, ix_what, ix_name, &range.to, range.value_type);
|
||||
Self {
|
||||
irf,
|
||||
r: RangeScan::new(beg, from.inclusive, end, to.inclusive),
|
||||
r: RangeScan::new(beg, range.from.inclusive, end, range.to.inclusive),
|
||||
done: false,
|
||||
}
|
||||
}
|
||||
|
@ -589,11 +686,16 @@ impl UniqueRangeThingIterator {
|
|||
db: &str,
|
||||
ix: &DefineIndexStatement,
|
||||
) -> Self {
|
||||
let full_range = RangeValue {
|
||||
let value = RangeValue {
|
||||
value: Value::None,
|
||||
inclusive: true,
|
||||
};
|
||||
Self::new(irf, ns, db, &ix.what, &ix.name, &full_range, &full_range)
|
||||
let range = IteratorRange {
|
||||
value_type: ValueType::None,
|
||||
from: Cow::Borrowed(&value),
|
||||
to: Cow::Borrowed(&value),
|
||||
};
|
||||
Self::new(irf, ns, db, &ix.what, &ix.name, &range)
|
||||
}
|
||||
|
||||
fn compute_beg(
|
||||
|
@ -602,9 +704,10 @@ impl UniqueRangeThingIterator {
|
|||
ix_what: &Ident,
|
||||
ix_name: &Ident,
|
||||
from: &RangeValue,
|
||||
value_type: ValueType,
|
||||
) -> Vec<u8> {
|
||||
if from.value == Value::None {
|
||||
return Index::prefix_beg(ns, db, ix_what, ix_name);
|
||||
return value_type.prefix_beg(ns, db, ix_what, ix_name);
|
||||
}
|
||||
Index::new(ns, db, ix_what, ix_name, &Array::from(from.value.to_owned()), None)
|
||||
.encode()
|
||||
|
@ -617,9 +720,10 @@ impl UniqueRangeThingIterator {
|
|||
ix_what: &Ident,
|
||||
ix_name: &Ident,
|
||||
to: &RangeValue,
|
||||
value_type: ValueType,
|
||||
) -> Vec<u8> {
|
||||
if to.value == Value::None {
|
||||
return Index::prefix_end(ns, db, ix_what, ix_name);
|
||||
return value_type.prefix_end(ns, db, ix_what, ix_name);
|
||||
}
|
||||
Index::new(ns, db, ix_what, ix_name, &Array::from(to.value.to_owned()), None)
|
||||
.encode()
|
||||
|
|
|
@ -298,7 +298,7 @@ impl IndexOption {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Eq, PartialEq, Hash)]
|
||||
#[derive(Debug, Clone, Default, Eq, PartialEq, Hash)]
|
||||
pub(super) struct RangeValue {
|
||||
pub(super) value: Value,
|
||||
pub(super) inclusive: bool,
|
||||
|
|
|
@ -797,6 +797,423 @@ async fn define_statement_unique_index_numbers() -> Result<(), Error> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn check_range(t: &mut Test, result: &str, explain: &str) -> Result<(), Error> {
|
||||
for _ in 0..2 {
|
||||
t.expect_val(result)?;
|
||||
}
|
||||
t.expect_val(explain)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn define_statement_mixed_numbers_range(unique: bool) -> Result<(), Error> {
|
||||
let sql = format!(
|
||||
"
|
||||
DEFINE INDEX index ON TABLE test COLUMNS number {};
|
||||
CREATE test:int0 SET number = 0;
|
||||
CREATE test:float0 SET number = 0.5;
|
||||
CREATE test:int1 SET number = 1;
|
||||
CREATE test:float1 SET number = 1.5;
|
||||
CREATE test:int2 SET number = 2;
|
||||
SELECT * FROM test WITH NOINDEX WHERE number > 0 AND number < 2 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0 AND number < 2 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0 AND number < 2 ORDER BY id EXPLAIN;
|
||||
SELECT * FROM test WITH NOINDEX WHERE number > 0.1 AND number < 2 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0.1 AND number < 2 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0.1 AND number < 2 ORDER BY id EXPLAIN;
|
||||
SELECT * FROM test WITH NOINDEX WHERE number > 0.1 AND number < 1.5 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0.1 AND number < 1.5 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0.1 AND number < 1.5 ORDER BY id EXPLAIN;
|
||||
SELECT * FROM test WITH NOINDEX WHERE number > 0 AND number < 1.5 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0 AND number < 1.5 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0 AND number < 1.5 ORDER BY id EXPLAIN;
|
||||
SELECT * FROM test WITH NOINDEX WHERE number > 0.1 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0.1 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0.1 ORDER BY id EXPLAIN;
|
||||
SELECT * FROM test WITH NOINDEX WHERE number > 0 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0 ORDER BY id;
|
||||
SELECT * FROM test WHERE number > 0 ORDER BY id EXPLAIN;
|
||||
SELECT * FROM test WITH NOINDEX WHERE number < 2 ORDER BY id;
|
||||
SELECT * FROM test WHERE number < 2 ORDER BY id;
|
||||
SELECT * FROM test WHERE number < 2 ORDER BY id EXPLAIN;
|
||||
SELECT * FROM test WITH NOINDEX WHERE number < 1.9 ORDER BY id;
|
||||
SELECT * FROM test WHERE number < 1.9 ORDER BY id;
|
||||
SELECT * FROM test WHERE number < 1.9 ORDER BY id EXPLAIN;
|
||||
",
|
||||
if unique {
|
||||
"UNIQUE"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
);
|
||||
let mut t = Test::new(&sql).await?;
|
||||
t.expect_size(30)?;
|
||||
t.skip_ok(6)?;
|
||||
// number > 0 AND number < 2
|
||||
check_range(
|
||||
&mut t,
|
||||
"[
|
||||
{
|
||||
id: test:float0,
|
||||
number: 0.5f
|
||||
},
|
||||
{
|
||||
id: test:float1,
|
||||
number: 1.5f
|
||||
},
|
||||
{
|
||||
id: test:int1,
|
||||
number: 1
|
||||
}
|
||||
]",
|
||||
"[
|
||||
{
|
||||
detail: {
|
||||
plan: {
|
||||
from: {
|
||||
inclusive: false,
|
||||
value: 0
|
||||
},
|
||||
index: 'index',
|
||||
to: {
|
||||
inclusive: false,
|
||||
value: 2
|
||||
}
|
||||
},
|
||||
table: 'test'
|
||||
},
|
||||
operation: 'Iterate Index'
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
type: 'Memory'
|
||||
},
|
||||
operation: 'Collector'
|
||||
}
|
||||
]",
|
||||
)?;
|
||||
// number > 0.1 AND number < 2
|
||||
check_range(
|
||||
&mut t,
|
||||
"[
|
||||
{
|
||||
id: test:float0,
|
||||
number: 0.5f
|
||||
},
|
||||
{
|
||||
id: test:float1,
|
||||
number: 1.5f
|
||||
},
|
||||
{
|
||||
id: test:int1,
|
||||
number: 1
|
||||
}
|
||||
]",
|
||||
"[
|
||||
{
|
||||
detail: {
|
||||
plan: {
|
||||
from: {
|
||||
inclusive: false,
|
||||
value: 0.1f
|
||||
},
|
||||
index: 'index',
|
||||
to: {
|
||||
inclusive: false,
|
||||
value: 2
|
||||
}
|
||||
},
|
||||
table: 'test'
|
||||
},
|
||||
operation: 'Iterate Index'
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
type: 'Memory'
|
||||
},
|
||||
operation: 'Collector'
|
||||
}
|
||||
]",
|
||||
)?;
|
||||
// number > 0.1 AND number < 1.5
|
||||
check_range(
|
||||
&mut t,
|
||||
"[
|
||||
{
|
||||
id: test:float0,
|
||||
number: 0.5f
|
||||
},
|
||||
{
|
||||
id: test:int1,
|
||||
number: 1
|
||||
}
|
||||
]",
|
||||
"[
|
||||
{
|
||||
detail: {
|
||||
plan: {
|
||||
from: {
|
||||
inclusive: false,
|
||||
value: 0.1f
|
||||
},
|
||||
index: 'index',
|
||||
to: {
|
||||
inclusive: false,
|
||||
value: 1.5f
|
||||
}
|
||||
},
|
||||
table: 'test'
|
||||
},
|
||||
operation: 'Iterate Index'
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
type: 'Memory'
|
||||
},
|
||||
operation: 'Collector'
|
||||
}
|
||||
]",
|
||||
)?;
|
||||
// number > 0 AND number < 1.5
|
||||
check_range(
|
||||
&mut t,
|
||||
"[
|
||||
{
|
||||
id: test:float0,
|
||||
number: 0.5f
|
||||
},
|
||||
{
|
||||
id: test:int1,
|
||||
number: 1
|
||||
}
|
||||
]",
|
||||
"[
|
||||
{
|
||||
detail: {
|
||||
plan: {
|
||||
from: {
|
||||
inclusive: false,
|
||||
value: 0
|
||||
},
|
||||
index: 'index',
|
||||
to: {
|
||||
inclusive: false,
|
||||
value: 1.5f
|
||||
}
|
||||
},
|
||||
table: 'test'
|
||||
},
|
||||
operation: 'Iterate Index'
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
type: 'Memory'
|
||||
},
|
||||
operation: 'Collector'
|
||||
}
|
||||
]",
|
||||
)?;
|
||||
// number > 0.1
|
||||
check_range(
|
||||
&mut t,
|
||||
"[
|
||||
{
|
||||
id: test:float0,
|
||||
number: 0.5f
|
||||
},
|
||||
{
|
||||
id: test:float1,
|
||||
number: 1.5f
|
||||
},
|
||||
{
|
||||
id: test:int1,
|
||||
number: 1
|
||||
},
|
||||
{
|
||||
id: test:int2,
|
||||
number: 2
|
||||
}
|
||||
]",
|
||||
"[
|
||||
{
|
||||
detail: {
|
||||
plan: {
|
||||
from: {
|
||||
inclusive: false,
|
||||
value: 0.1f
|
||||
},
|
||||
index: 'index',
|
||||
to: {
|
||||
inclusive: false,
|
||||
value: NONE
|
||||
}
|
||||
},
|
||||
table: 'test'
|
||||
},
|
||||
operation: 'Iterate Index'
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
type: 'Memory'
|
||||
},
|
||||
operation: 'Collector'
|
||||
}
|
||||
]",
|
||||
)?;
|
||||
// number > 0
|
||||
check_range(
|
||||
&mut t,
|
||||
"[
|
||||
{
|
||||
id: test:float0,
|
||||
number: 0.5f
|
||||
},
|
||||
{
|
||||
id: test:float1,
|
||||
number: 1.5f
|
||||
},
|
||||
{
|
||||
id: test:int1,
|
||||
number: 1
|
||||
},
|
||||
{
|
||||
id: test:int2,
|
||||
number: 2
|
||||
}
|
||||
]",
|
||||
"[
|
||||
{
|
||||
detail: {
|
||||
plan: {
|
||||
from: {
|
||||
inclusive: false,
|
||||
value: 0
|
||||
},
|
||||
index: 'index',
|
||||
to: {
|
||||
inclusive: false,
|
||||
value: NONE
|
||||
}
|
||||
},
|
||||
table: 'test'
|
||||
},
|
||||
operation: 'Iterate Index'
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
type: 'Memory'
|
||||
},
|
||||
operation: 'Collector'
|
||||
}
|
||||
]",
|
||||
)?;
|
||||
// number < 2
|
||||
check_range(
|
||||
&mut t,
|
||||
"[
|
||||
{
|
||||
id: test:float0,
|
||||
number: 0.5f
|
||||
},
|
||||
{
|
||||
id: test:float1,
|
||||
number: 1.5f
|
||||
},
|
||||
{
|
||||
id: test:int0,
|
||||
number: 0
|
||||
},
|
||||
{
|
||||
id: test:int1,
|
||||
number: 1
|
||||
}
|
||||
]",
|
||||
"[
|
||||
{
|
||||
detail: {
|
||||
plan: {
|
||||
from: {
|
||||
inclusive: false,
|
||||
value: NONE
|
||||
},
|
||||
index: 'index',
|
||||
to: {
|
||||
inclusive: false,
|
||||
value: 2
|
||||
}
|
||||
},
|
||||
table: 'test'
|
||||
},
|
||||
operation: 'Iterate Index'
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
type: 'Memory'
|
||||
},
|
||||
operation: 'Collector'
|
||||
}
|
||||
]",
|
||||
)?;
|
||||
// number < 1.9
|
||||
check_range(
|
||||
&mut t,
|
||||
"[
|
||||
{
|
||||
id: test:float0,
|
||||
number: 0.5f
|
||||
},
|
||||
{
|
||||
id: test:float1,
|
||||
number: 1.5f
|
||||
},
|
||||
{
|
||||
id: test:int0,
|
||||
number: 0
|
||||
},
|
||||
{
|
||||
id: test:int1,
|
||||
number: 1
|
||||
}
|
||||
]",
|
||||
"[
|
||||
{
|
||||
detail: {
|
||||
plan: {
|
||||
from: {
|
||||
inclusive: false,
|
||||
value: NONE
|
||||
},
|
||||
index: 'index',
|
||||
to: {
|
||||
inclusive: false,
|
||||
value: 1.9f
|
||||
}
|
||||
},
|
||||
table: 'test'
|
||||
},
|
||||
operation: 'Iterate Index'
|
||||
},
|
||||
{
|
||||
detail: {
|
||||
type: 'Memory'
|
||||
},
|
||||
operation: 'Collector'
|
||||
}
|
||||
]",
|
||||
)?;
|
||||
//
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn define_statement_index_mixed_numbers_range() -> Result<(), Error> {
|
||||
define_statement_mixed_numbers_range(false).await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn define_statement_unique_mixed_numbers_range() -> Result<(), Error> {
|
||||
define_statement_mixed_numbers_range(true).await
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn define_statement_index_concurrently() -> Result<(), Error> {
|
||||
let sql = "
|
||||
|
|
Loading…
Reference in a new issue