mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-10 18:54:22 +01:00
Add some utilities to constraint related structs
This commit is contained in:
@@ -433,13 +433,7 @@ pub fn open_loop(
|
||||
// Rowid equality point lookups are handled with a SeekRowid instruction which does not loop, since it is a single row lookup.
|
||||
if let Search::RowidEq { cmp_expr } = search {
|
||||
let src_reg = program.alloc_register();
|
||||
translate_expr(
|
||||
program,
|
||||
Some(tables),
|
||||
&cmp_expr.expr,
|
||||
src_reg,
|
||||
&t_ctx.resolver,
|
||||
)?;
|
||||
translate_expr(program, Some(tables), cmp_expr, src_reg, &t_ctx.resolver)?;
|
||||
program.emit_insn(Insn::SeekRowid {
|
||||
cursor_id: table_cursor_id
|
||||
.expect("Search::RowidEq requires a table cursor"),
|
||||
|
||||
@@ -50,6 +50,28 @@ pub struct Constraint {
|
||||
pub selectivity: f64,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum BinaryExprSide {
|
||||
Lhs,
|
||||
Rhs,
|
||||
}
|
||||
|
||||
impl Constraint {
|
||||
/// Get the constraining expression, e.g. '2+3' from 't.x = 2+3'
|
||||
pub fn get_constraining_expr(&self, where_clause: &[WhereTerm]) -> ast::Expr {
|
||||
let (idx, side) = self.where_clause_pos;
|
||||
let where_term = &where_clause[idx];
|
||||
let Ok(Some((lhs, _, rhs))) = as_binary_components(&where_term.expr) else {
|
||||
panic!("Expected a valid binary expression");
|
||||
};
|
||||
if side == BinaryExprSide::Lhs {
|
||||
lhs.clone()
|
||||
} else {
|
||||
rhs.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
/// A reference to a [Constraint] in a [TableConstraints].
|
||||
///
|
||||
@@ -62,7 +84,20 @@ pub struct ConstraintRef {
|
||||
/// The sort order of the constrained column in the index. Always ascending for rowid indices.
|
||||
pub sort_order: SortOrder,
|
||||
}
|
||||
#[derive(Debug, Clone)]
|
||||
|
||||
impl ConstraintRef {
|
||||
/// Convert the constraint to a column usable in a [crate::translate::plan::SeekDef::key].
|
||||
pub fn as_seek_key_column(
|
||||
&self,
|
||||
constraints: &[Constraint],
|
||||
where_clause: &[WhereTerm],
|
||||
) -> (ast::Expr, SortOrder) {
|
||||
let constraint = &constraints[self.constraint_vec_pos];
|
||||
let constraining_expr = constraint.get_constraining_expr(where_clause);
|
||||
(constraining_expr, self.sort_order)
|
||||
}
|
||||
}
|
||||
|
||||
/// A collection of [ConstraintRef]s for a given index, or if index is None, for the table's rowid index.
|
||||
/// For example, given a table `T (x,y,z)` with an index `T_I (y desc,z)`, take the following query:
|
||||
/// ```sql
|
||||
@@ -87,6 +122,7 @@ pub struct ConstraintRef {
|
||||
/// ],
|
||||
/// }
|
||||
///
|
||||
#[derive(Debug)]
|
||||
pub struct ConstraintUseCandidate {
|
||||
/// The index that may be used to satisfy the constraints. If none, the table's rowid index is used.
|
||||
pub index: Option<Arc<Index>>,
|
||||
@@ -104,16 +140,6 @@ pub struct TableConstraints {
|
||||
pub candidates: Vec<ConstraintUseCandidate>,
|
||||
}
|
||||
|
||||
/// Helper enum for [Constraint] to indicate which side of a binary comparison expression is being compared to the index column.
|
||||
/// For example, if the where clause is "WHERE x = 10" and there's an index on x,
|
||||
/// the [Constraint] for the where clause term "x = 10" will have a [BinaryExprSide::Rhs]
|
||||
/// because the right hand side expression "10" is being compared to the index column "x".
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum BinaryExprSide {
|
||||
Lhs,
|
||||
Rhs,
|
||||
}
|
||||
|
||||
/// In lieu of statistics, we estimate that an equality filter will reduce the output set to 1% of its size.
|
||||
const SELECTIVITY_EQ: f64 = 0.01;
|
||||
/// In lieu of statistics, we estimate that a range filter will reduce the output set to 40% of its size.
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
use std::{cell::RefCell, cmp::Ordering, collections::HashMap, sync::Arc};
|
||||
|
||||
use constraints::{
|
||||
constraints_from_where_clause, usable_constraints_for_join_order, BinaryExprSide, Constraint,
|
||||
ConstraintRef,
|
||||
constraints_from_where_clause, usable_constraints_for_join_order, Constraint, ConstraintRef,
|
||||
};
|
||||
use cost::Cost;
|
||||
use join::{compute_best_join_order, BestJoinOrderResult};
|
||||
@@ -12,7 +11,7 @@ use order::{compute_order_target, plan_satisfies_order_target, EliminatesSort};
|
||||
use crate::{
|
||||
parameters::PARAM_PREFIX,
|
||||
schema::{Index, IndexColumn, Schema},
|
||||
translate::{expr::as_binary_components, plan::TerminationKey},
|
||||
translate::plan::TerminationKey,
|
||||
types::SeekOp,
|
||||
Result,
|
||||
};
|
||||
@@ -311,21 +310,7 @@ fn optimize_table_access(
|
||||
[constraint_refs[0].constraint_vec_pos];
|
||||
table_references[table_number].op = match constraint.operator {
|
||||
ast::Operator::Equals => Operation::Search(Search::RowidEq {
|
||||
cmp_expr: {
|
||||
let (idx, side) = constraint.where_clause_pos;
|
||||
let Some((lhs, _, rhs)) = as_binary_components(&where_clause[idx].expr)?
|
||||
else {
|
||||
panic!("Expected a binary expression");
|
||||
};
|
||||
let where_term = WhereTerm {
|
||||
expr: match side {
|
||||
BinaryExprSide::Lhs => lhs.clone(),
|
||||
BinaryExprSide::Rhs => rhs.clone(),
|
||||
},
|
||||
from_outer_join: where_clause[idx].from_outer_join.clone(),
|
||||
};
|
||||
where_term
|
||||
},
|
||||
cmp_expr: constraint.get_constraining_expr(where_clause),
|
||||
}),
|
||||
_ => Operation::Search(Search::Seek {
|
||||
index: None,
|
||||
@@ -813,23 +798,10 @@ pub fn build_seek_def_from_constraints(
|
||||
"cannot build seek def from empty list of constraint refs"
|
||||
);
|
||||
// Extract the key values and operators
|
||||
let mut key = Vec::with_capacity(constraint_refs.len());
|
||||
|
||||
for cref in constraint_refs {
|
||||
// Extract the other expression from the binary WhereTerm (i.e. the one being compared to the index column)
|
||||
let constraint = &constraints[cref.constraint_vec_pos];
|
||||
let (where_idx, side) = constraint.where_clause_pos;
|
||||
let where_term = &where_clause[where_idx];
|
||||
let Some((lhs, _, rhs)) = as_binary_components(&where_term.expr)? else {
|
||||
panic!("Expected a binary expression");
|
||||
};
|
||||
let cmp_expr = if side == BinaryExprSide::Lhs {
|
||||
lhs.clone()
|
||||
} else {
|
||||
rhs.clone()
|
||||
};
|
||||
key.push((cmp_expr, cref.sort_order));
|
||||
}
|
||||
let key = constraint_refs
|
||||
.iter()
|
||||
.map(|cref| cref.as_seek_key_column(constraints, where_clause))
|
||||
.collect();
|
||||
|
||||
// We know all but potentially the last term is an equality, so we can use the operator of the last term
|
||||
// to form the SeekOp
|
||||
|
||||
@@ -782,7 +782,7 @@ pub struct TerminationKey {
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Search {
|
||||
/// A rowid equality point lookup. This is a special case that uses the SeekRowid bytecode instruction and does not loop.
|
||||
RowidEq { cmp_expr: WhereTerm },
|
||||
RowidEq { cmp_expr: ast::Expr },
|
||||
/// A search on a table btree (via `rowid`) or a secondary index search. Uses bytecode instructions like SeekGE, SeekGT etc.
|
||||
Seek {
|
||||
index: Option<Arc<Index>>,
|
||||
|
||||
Reference in New Issue
Block a user