Skip to content

Commit 54068c8

Browse files
committed
feat: parameterize EXISTS/IN subqueries with runtime index probes
1 parent 098070f commit 54068c8

File tree

24 files changed

+1328
-263
lines changed

24 files changed

+1328
-263
lines changed

src/db.rs

Lines changed: 297 additions & 57 deletions
Large diffs are not rendered by default.

src/execution/dql/index_scan.rs

Lines changed: 52 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,45 +17,58 @@ use crate::execution::{ExecArena, ExecId, ExecNode, ExecutionCaches, ExecutorNod
1717
use crate::expression::range_detacher::Range;
1818
use crate::planner::operator::table_scan::TableScanOperator;
1919
use crate::storage::{IndexIter, Iter, Transaction};
20-
use crate::types::index::IndexMetaRef;
20+
use crate::types::index::{IndexLookup, IndexMetaRef, RuntimeIndexProbe};
2121
use crate::types::serialize::TupleValueSerializableImpl;
22+
use std::array;
23+
use std::vec;
24+
25+
enum IndexLookupRanges {
26+
One(array::IntoIter<Range, 1>),
27+
Many(vec::IntoIter<Range>),
28+
}
29+
30+
impl Iterator for IndexLookupRanges {
31+
type Item = Range;
32+
33+
fn next(&mut self) -> Option<Self::Item> {
34+
match self {
35+
IndexLookupRanges::One(iter) => iter.next(),
36+
IndexLookupRanges::Many(iter) => iter.next(),
37+
}
38+
}
39+
}
2240

2341
pub(crate) struct IndexScan<'a, T: Transaction + 'a> {
2442
op: Option<TableScanOperator>,
2543
index_by: IndexMetaRef,
26-
ranges: Vec<Range>,
44+
lookup: Option<IndexLookup>,
2745
covered_deserializers: Option<Vec<TupleValueSerializableImpl>>,
2846
cover_mapping: Option<Vec<usize>>,
29-
iter: Option<IndexIter<'a, T>>,
47+
iter: Option<IndexIter<'a, T, IndexLookupRanges>>,
3048
}
3149

3250
impl<'a, T: Transaction + 'a>
3351
From<(
3452
TableScanOperator,
3553
IndexMetaRef,
36-
Range,
54+
IndexLookup,
3755
Option<Vec<TupleValueSerializableImpl>>,
3856
Option<Vec<usize>>,
3957
)> for IndexScan<'a, T>
4058
{
4159
fn from(
42-
(op, index_by, range, covered_deserializers, cover_mapping): (
60+
(op, index_by, lookup, covered_deserializers, cover_mapping): (
4361
TableScanOperator,
4462
IndexMetaRef,
45-
Range,
63+
IndexLookup,
4664
Option<Vec<TupleValueSerializableImpl>>,
4765
Option<Vec<usize>>,
4866
),
4967
) -> Self {
50-
let ranges = match range {
51-
Range::SortedRanges(ranges) => ranges,
52-
range => vec![range],
53-
};
54-
5568
IndexScan {
5669
op: Some(op),
5770
index_by,
58-
ranges,
71+
lookup: Some(lookup),
5972
covered_deserializers,
6073
cover_mapping,
6174
iter: None,
@@ -78,7 +91,7 @@ impl<'a, T: Transaction + 'a> ExecutorNode<'a, T> for IndexScan<'a, T> {
7891
type Input = (
7992
TableScanOperator,
8093
IndexMetaRef,
81-
Range,
94+
IndexLookup,
8295
Option<Vec<TupleValueSerializableImpl>>,
8396
Option<Vec<usize>>,
8497
);
@@ -98,6 +111,27 @@ impl<'a, T: Transaction + 'a> ExecutorNode<'a, T> for IndexScan<'a, T> {
98111
}
99112

100113
impl<'a, T: Transaction + 'a> IndexScan<'a, T> {
114+
fn ranges_from_lookup(lookup: IndexLookup, arena: &ExecArena<'a, T>) -> IndexLookupRanges {
115+
match lookup {
116+
IndexLookup::Static(Range::SortedRanges(ranges)) => {
117+
IndexLookupRanges::Many(ranges.into_iter())
118+
}
119+
IndexLookup::Static(range) => IndexLookupRanges::One([range].into_iter()),
120+
IndexLookup::Probe(param) => match arena.runtime_param(param) {
121+
RuntimeIndexProbe::Eq(value) => {
122+
IndexLookupRanges::One([Range::Eq(value.clone())].into_iter())
123+
}
124+
RuntimeIndexProbe::Scope { min, max } => IndexLookupRanges::One(
125+
[Range::Scope {
126+
min: min.clone(),
127+
max: max.clone(),
128+
}]
129+
.into_iter(),
130+
),
131+
},
132+
}
133+
}
134+
101135
pub(crate) fn next_tuple(&mut self, arena: &mut ExecArena<'a, T>) -> Result<(), DatabaseError> {
102136
if self.iter.is_none() {
103137
let Some(TableScanOperator {
@@ -111,13 +145,17 @@ impl<'a, T: Transaction + 'a> IndexScan<'a, T> {
111145
arena.finish();
112146
return Ok(());
113147
};
148+
let ranges = Self::ranges_from_lookup(
149+
self.lookup.take().expect("index scan lookup initialized"),
150+
arena,
151+
);
114152
self.iter = Some(arena.transaction().read_by_index(
115153
arena.table_cache(),
116154
table_name,
117155
limit,
118156
columns,
119157
self.index_by.clone(),
120-
std::mem::take(&mut self.ranges),
158+
ranges,
121159
with_pk,
122160
self.covered_deserializers.take(),
123161
self.cover_mapping.take(),

0 commit comments

Comments
 (0)