mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-05 01:04:22 +01:00
Merge 'Don't do any I/O if top level operator is Nothing' from Jussi Saurio
Small tweak Before: ``` limbo> explain select * from users where 0; addr opcode p1 p2 p3 p4 p5 comment ---- ----------------- ---- ---- ---- ------------- -- ------- 0 Init 0 21 0 0 Start at 21 1 OpenReadAsync 0 2 0 0 table=users, root=2 2 OpenReadAwait 0 0 0 0 3 RewindAsync 0 0 0 0 4 RewindAwait 0 20 0 0 Rewind table users 5 Integer 0 1 0 0 r[1]=0 6 IfNot 1 18 1 0 if !r[1] goto 18 7 RowId 0 2 0 0 r[2]=users.rowid 8 Column 0 1 3 0 r[3]=users.first_name 9 Column 0 2 4 0 r[4]=users.last_name 10 Column 0 3 5 0 r[5]=users.email 11 Column 0 4 6 0 r[6]=users.phone_number 12 Column 0 5 7 0 r[7]=users.address 13 Column 0 6 8 0 r[8]=users.city 14 Column 0 7 9 0 r[9]=users.state 15 Column 0 8 10 0 r[10]=users.zipcode 16 Column 0 9 11 0 r[11]=users.age 17 ResultRow 2 10 0 0 output=r[2..11] 18 NextAsync 0 0 0 0 19 NextAwait 0 4 0 0 20 Halt 0 0 0 0 21 Transaction 0 0 0 0 22 Goto 0 1 0 0 ``` After: ``` limbo> explain select * from users where 0; addr opcode p1 p2 p3 p4 p5 comment ---- ----------------- ---- ---- ---- ------------- -- ------- 0 Init 0 2 0 0 Start at 2 1 Halt 0 0 0 0 2 Transaction 0 0 0 0 3 Goto 0 1 0 0 ``` Closes #306
This commit is contained in:
@@ -16,7 +16,14 @@ pub fn optimize_plan(mut select_plan: Plan) -> Result<Plan> {
|
||||
&mut select_plan.root_operator,
|
||||
&select_plan.referenced_tables,
|
||||
)?;
|
||||
eliminate_constants(&mut select_plan.root_operator)?;
|
||||
if eliminate_constants(&mut select_plan.root_operator)?
|
||||
== ConstantConditionEliminationResult::ImpossibleCondition
|
||||
{
|
||||
return Ok(Plan {
|
||||
root_operator: Operator::Nothing,
|
||||
referenced_tables: vec![],
|
||||
});
|
||||
}
|
||||
use_indexes(
|
||||
&mut select_plan.root_operator,
|
||||
&select_plan.referenced_tables,
|
||||
@@ -116,9 +123,15 @@ fn use_indexes(
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
enum ConstantConditionEliminationResult {
|
||||
Continue,
|
||||
ImpossibleCondition,
|
||||
}
|
||||
|
||||
// removes predicates that are always true
|
||||
// returns false if there is an impossible predicate that is always false
|
||||
fn eliminate_constants(operator: &mut Operator) -> Result<bool> {
|
||||
// returns a ConstantEliminationResult indicating whether any predicates are always false
|
||||
fn eliminate_constants(operator: &mut Operator) -> Result<ConstantConditionEliminationResult> {
|
||||
match operator {
|
||||
Operator::Filter {
|
||||
source, predicates, ..
|
||||
@@ -129,7 +142,7 @@ fn eliminate_constants(operator: &mut Operator) -> Result<bool> {
|
||||
if predicate.is_always_true()? {
|
||||
predicates.remove(i);
|
||||
} else if predicate.is_always_false()? {
|
||||
return Ok(false);
|
||||
return Ok(ConstantConditionEliminationResult::ImpossibleCondition);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
@@ -142,7 +155,7 @@ fn eliminate_constants(operator: &mut Operator) -> Result<bool> {
|
||||
eliminate_constants(source)?;
|
||||
}
|
||||
|
||||
return Ok(true);
|
||||
return Ok(ConstantConditionEliminationResult::Continue);
|
||||
}
|
||||
Operator::Join {
|
||||
left,
|
||||
@@ -151,15 +164,19 @@ fn eliminate_constants(operator: &mut Operator) -> Result<bool> {
|
||||
outer,
|
||||
..
|
||||
} => {
|
||||
if !eliminate_constants(left)? {
|
||||
return Ok(false);
|
||||
if eliminate_constants(left)? == ConstantConditionEliminationResult::ImpossibleCondition
|
||||
{
|
||||
return Ok(ConstantConditionEliminationResult::ImpossibleCondition);
|
||||
}
|
||||
if !eliminate_constants(right)? && !*outer {
|
||||
return Ok(false);
|
||||
if eliminate_constants(right)?
|
||||
== ConstantConditionEliminationResult::ImpossibleCondition
|
||||
&& !*outer
|
||||
{
|
||||
return Ok(ConstantConditionEliminationResult::ImpossibleCondition);
|
||||
}
|
||||
|
||||
if predicates.is_none() {
|
||||
return Ok(true);
|
||||
return Ok(ConstantConditionEliminationResult::Continue);
|
||||
}
|
||||
|
||||
let predicates = predicates.as_mut().unwrap();
|
||||
@@ -170,20 +187,22 @@ fn eliminate_constants(operator: &mut Operator) -> Result<bool> {
|
||||
if predicate.is_always_true()? {
|
||||
predicates.remove(i);
|
||||
} else if predicate.is_always_false()? && !*outer {
|
||||
return Ok(false);
|
||||
return Ok(ConstantConditionEliminationResult::ImpossibleCondition);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(true);
|
||||
return Ok(ConstantConditionEliminationResult::Continue);
|
||||
}
|
||||
Operator::Aggregate { source, .. } => {
|
||||
let ok = eliminate_constants(source)?;
|
||||
if !ok {
|
||||
if eliminate_constants(source)?
|
||||
== ConstantConditionEliminationResult::ImpossibleCondition
|
||||
{
|
||||
*source = Box::new(Operator::Nothing);
|
||||
}
|
||||
return Ok(ok);
|
||||
// Aggregation operator can return a row even if the source is empty e.g. count(1) from users where 0
|
||||
return Ok(ConstantConditionEliminationResult::Continue);
|
||||
}
|
||||
Operator::SeekRowid {
|
||||
rowid_predicate,
|
||||
@@ -197,7 +216,7 @@ fn eliminate_constants(operator: &mut Operator) -> Result<bool> {
|
||||
if predicate.is_always_true()? {
|
||||
predicates.remove(i);
|
||||
} else if predicate.is_always_false()? {
|
||||
return Ok(false);
|
||||
return Ok(ConstantConditionEliminationResult::ImpossibleCondition);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
@@ -205,31 +224,38 @@ fn eliminate_constants(operator: &mut Operator) -> Result<bool> {
|
||||
}
|
||||
|
||||
if rowid_predicate.is_always_false()? {
|
||||
return Ok(false);
|
||||
return Ok(ConstantConditionEliminationResult::ImpossibleCondition);
|
||||
}
|
||||
|
||||
return Ok(true);
|
||||
return Ok(ConstantConditionEliminationResult::Continue);
|
||||
}
|
||||
Operator::Limit { source, .. } => {
|
||||
let ok = eliminate_constants(source)?;
|
||||
if !ok {
|
||||
let constant_elimination_result = eliminate_constants(source)?;
|
||||
if constant_elimination_result
|
||||
== ConstantConditionEliminationResult::ImpossibleCondition
|
||||
{
|
||||
*operator = Operator::Nothing;
|
||||
}
|
||||
return Ok(ok);
|
||||
return Ok(constant_elimination_result);
|
||||
}
|
||||
Operator::Order { source, .. } => {
|
||||
let ok = eliminate_constants(source)?;
|
||||
if !ok {
|
||||
if eliminate_constants(source)?
|
||||
== ConstantConditionEliminationResult::ImpossibleCondition
|
||||
{
|
||||
*operator = Operator::Nothing;
|
||||
return Ok(ConstantConditionEliminationResult::ImpossibleCondition);
|
||||
}
|
||||
return Ok(true);
|
||||
return Ok(ConstantConditionEliminationResult::Continue);
|
||||
}
|
||||
Operator::Projection { source, .. } => {
|
||||
let ok = eliminate_constants(source)?;
|
||||
if !ok {
|
||||
if eliminate_constants(source)?
|
||||
== ConstantConditionEliminationResult::ImpossibleCondition
|
||||
{
|
||||
*operator = Operator::Nothing;
|
||||
return Ok(ConstantConditionEliminationResult::ImpossibleCondition);
|
||||
}
|
||||
return Ok(ok);
|
||||
|
||||
return Ok(ConstantConditionEliminationResult::Continue);
|
||||
}
|
||||
Operator::Scan { predicates, .. } => {
|
||||
if let Some(ps) = predicates {
|
||||
@@ -239,7 +265,7 @@ fn eliminate_constants(operator: &mut Operator) -> Result<bool> {
|
||||
if predicate.is_always_true()? {
|
||||
ps.remove(i);
|
||||
} else if predicate.is_always_false()? {
|
||||
return Ok(false);
|
||||
return Ok(ConstantConditionEliminationResult::ImpossibleCondition);
|
||||
} else {
|
||||
i += 1;
|
||||
}
|
||||
@@ -249,9 +275,9 @@ fn eliminate_constants(operator: &mut Operator) -> Result<bool> {
|
||||
*predicates = None;
|
||||
}
|
||||
}
|
||||
return Ok(true);
|
||||
return Ok(ConstantConditionEliminationResult::Continue);
|
||||
}
|
||||
Operator::Nothing => return Ok(true),
|
||||
Operator::Nothing => return Ok(ConstantConditionEliminationResult::Continue),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ use sqlite3_parser::ast;
|
||||
|
||||
use crate::{function::AggFunc, schema::BTreeTable, util::normalize_ident, Result};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Plan {
|
||||
pub root_operator: Operator,
|
||||
pub referenced_tables: Vec<(Rc<BTreeTable>, String)>,
|
||||
|
||||
Reference in New Issue
Block a user