Rename SelectQueryType to QueryDestination

This commit is contained in:
Jussi Saurio
2025-05-25 20:31:05 +03:00
parent d893a55c55
commit 07fa3a9668
8 changed files with 62 additions and 51 deletions

View File

@@ -16,7 +16,7 @@ use super::main_loop::{
};
use super::order_by::{emit_order_by, init_order_by, SortMetadata};
use super::plan::{
JoinOrderMember, Operation, SelectPlan, SelectQueryType, TableReference, UpdatePlan,
JoinOrderMember, Operation, QueryDestination, SelectPlan, TableReference, UpdatePlan,
};
use super::schema::ParseSchema;
use super::select::emit_simple_count;
@@ -263,9 +263,9 @@ fn emit_program_for_compound_select(
let mut union_dedupe_index = if requires_union_deduplication {
let dedupe_index = get_union_dedupe_index(program, &first);
first.query_type = SelectQueryType::UnionArm {
index_cursor_id: dedupe_index.0,
dedupe_index: dedupe_index.1.clone(),
first.query_destination = QueryDestination::EphemeralIndex {
cursor_id: dedupe_index.0,
index: dedupe_index.1.clone(),
};
Some(dedupe_index)
} else {
@@ -307,9 +307,9 @@ fn emit_program_for_compound_select(
}
if requires_union_deduplication {
select.query_type = SelectQueryType::UnionArm {
index_cursor_id: union_dedupe_index.as_ref().unwrap().0,
dedupe_index: union_dedupe_index.as_ref().unwrap().1.clone(),
select.query_destination = QueryDestination::EphemeralIndex {
cursor_id: union_dedupe_index.as_ref().unwrap().0,
index: union_dedupe_index.as_ref().unwrap().1.clone(),
};
} else if let Some((dedupe_cursor_id, dedupe_index)) = union_dedupe_index.take() {
// When there are no more UNION operators left, all the deduplicated rows from the preceding union arms need to be emitted

View File

@@ -30,7 +30,7 @@ use super::{
order_by::{order_by_sorter_insert, sorter_insert},
plan::{
convert_where_to_vtab_constraint, Aggregate, GroupBy, IterationDirection, JoinOrderMember,
Operation, Search, SeekDef, SelectPlan, SelectQueryType, TableReference, WhereTerm,
Operation, QueryDestination, Search, SeekDef, SelectPlan, TableReference, WhereTerm,
},
};
@@ -466,8 +466,8 @@ pub fn open_loop(
}
Table::FromClauseSubquery(from_clause_subquery) => {
let (yield_reg, coroutine_implementation_start) =
match &from_clause_subquery.plan.query_type {
SelectQueryType::Subquery {
match &from_clause_subquery.plan.query_destination {
QueryDestination::CoroutineYield {
yield_reg,
coroutine_implementation_start,
} => (*yield_reg, *coroutine_implementation_start),

View File

@@ -309,22 +309,29 @@ pub enum Plan {
Update(UpdatePlan),
}
/// The type of the query, either top level or subquery
/// The destination of the results of a query.
/// Typically, the results of a query are returned to the caller.
/// However, there are some cases where the results are not returned to the caller,
/// but rather are yielded to a parent query via coroutine, or stored in a temp table,
/// later used by the parent query.
#[derive(Debug, Clone)]
pub enum SelectQueryType {
TopLevel,
Subquery {
/// The register that holds the program offset that handles jumping to/from the subquery.
pub enum QueryDestination {
/// The results of the query are returned to the caller.
ResultRows,
/// The results of the query are yielded to a parent query via coroutine.
CoroutineYield {
/// The register that holds the program offset that handles jumping to/from the coroutine.
yield_reg: usize,
/// The index of the first instruction in the bytecode that implements the subquery.
/// The index of the first instruction in the bytecode that implements the coroutine.
coroutine_implementation_start: BranchOffset,
},
/// One arm of a UNION query, so its results need to be fed into a temp index for deduplication.
UnionArm {
/// The cursor ID of the temp index that will be used to deduplicate the results.
index_cursor_id: CursorID,
/// The deduplication index.
dedupe_index: Arc<Index>,
/// The results of the query are stored in an ephemeral index,
/// later used by the parent query.
EphemeralIndex {
/// The cursor ID of the ephemeral index that will be used to store the results.
cursor_id: CursorID,
/// The index that will be used to store the results.
index: Arc<Index>,
},
}
@@ -438,8 +445,8 @@ pub struct SelectPlan {
pub offset: Option<isize>,
/// query contains a constant condition that is always false
pub contains_constant_false_condition: bool,
/// query type (top level or subquery)
pub query_type: SelectQueryType,
/// the destination of the resulting rows from this plan.
pub query_destination: QueryDestination,
/// whether the query is DISTINCT
pub distinctness: Distinctness,
/// values: https://sqlite.org/syntax/select-core.html
@@ -486,7 +493,10 @@ impl SelectPlan {
pub fn is_simple_count(&self) -> bool {
if !self.where_clause.is_empty()
|| self.aggregates.len() != 1
|| matches!(self.query_type, SelectQueryType::Subquery { .. })
|| matches!(
self.query_destination,
QueryDestination::CoroutineYield { .. }
)
|| self.table_references.len() != 1
|| self.result_columns.len() != 1
|| self.group_by.is_some()

View File

@@ -2,7 +2,7 @@ use super::{
expr::walk_expr,
plan::{
Aggregate, ColumnUsedMask, Distinctness, EvalAt, IterationDirection, JoinInfo,
JoinOrderMember, Operation, Plan, ResultSetColumn, SelectPlan, SelectQueryType,
JoinOrderMember, Operation, Plan, QueryDestination, ResultSetColumn, SelectPlan,
TableReference, WhereTerm,
},
select::prepare_select_plan,
@@ -298,7 +298,7 @@ fn parse_from_clause_table<'a>(
else {
crate::bail_parse_error!("Only non-compound SELECT queries are currently supported in FROM clause subqueries");
};
subplan.query_type = SelectQueryType::Subquery {
subplan.query_destination = QueryDestination::CoroutineYield {
yield_reg: usize::MAX, // will be set later in bytecode emission
coroutine_implementation_start: BranchOffset::Placeholder, // will be set later in bytecode emission
};
@@ -455,8 +455,7 @@ pub fn parse_from<'a>(
let Plan::Select(mut cte_plan) = cte_plan else {
crate::bail_parse_error!("Only SELECT queries are currently supported in CTEs");
};
// CTE can be rewritten as a subquery.
cte_plan.query_type = SelectQueryType::Subquery {
cte_plan.query_destination = QueryDestination::CoroutineYield {
yield_reg: usize::MAX, // will be set later in bytecode emission
coroutine_implementation_start: BranchOffset::Placeholder, // will be set later in bytecode emission
};

View File

@@ -10,7 +10,7 @@ use crate::{
use super::{
emitter::{LimitCtx, Resolver},
expr::translate_expr,
plan::{Distinctness, SelectPlan, SelectQueryType},
plan::{Distinctness, QueryDestination, SelectPlan},
};
/// Emits the bytecode for:
@@ -85,16 +85,16 @@ pub fn emit_result_row_and_limit(
reg_limit_offset_sum: Option<usize>,
label_on_limit_reached: Option<BranchOffset>,
) -> Result<()> {
match &plan.query_type {
SelectQueryType::TopLevel => {
match &plan.query_destination {
QueryDestination::ResultRows => {
program.emit_insn(Insn::ResultRow {
start_reg: result_columns_start_reg,
count: plan.result_columns.len(),
});
}
SelectQueryType::UnionArm {
index_cursor_id,
dedupe_index,
QueryDestination::EphemeralIndex {
cursor_id: index_cursor_id,
index: dedupe_index,
} => {
let record_reg = program.alloc_register();
program.emit_insn(Insn::MakeRecord {
@@ -111,7 +111,7 @@ pub fn emit_result_row_and_limit(
flags: IdxInsertFlags::new(),
});
}
SelectQueryType::Subquery { yield_reg, .. } => {
QueryDestination::CoroutineYield { yield_reg, .. } => {
program.emit_insn(Insn::Yield {
yield_reg: *yield_reg,
end_offset: BranchOffset::Offset(0),

View File

@@ -1,5 +1,7 @@
use super::emitter::{emit_program, TranslateCtx};
use super::plan::{select_star, Distinctness, JoinOrderMember, Operation, Search, SelectQueryType};
use super::plan::{
select_star, Distinctness, JoinOrderMember, Operation, QueryDestination, Search,
};
use super::planner::Scope;
use crate::function::{AggFunc, ExtFunc, Func};
use crate::schema::Table;
@@ -235,7 +237,7 @@ fn prepare_one_select_plan<'a>(
limit: None,
offset: None,
contains_constant_false_condition: false,
query_type: SelectQueryType::TopLevel,
query_destination: QueryDestination::ResultRows,
distinctness: Distinctness::from_ast(distinctness.as_ref()),
values: vec![],
};
@@ -549,7 +551,7 @@ fn prepare_one_select_plan<'a>(
limit: None,
offset: None,
contains_constant_false_condition: false,
query_type: SelectQueryType::TopLevel,
query_destination: QueryDestination::ResultRows,
distinctness: Distinctness::NonDistinct,
values,
};

View File

@@ -7,7 +7,7 @@ use crate::{
use super::{
emitter::{emit_query, LimitCtx, Resolver, TranslateCtx},
main_loop::LoopLabels,
plan::{SelectPlan, SelectQueryType, TableReference},
plan::{QueryDestination, SelectPlan, TableReference},
};
/// Emit the subqueries contained in the FROM clause.
@@ -51,8 +51,8 @@ pub fn emit_subquery<'a>(
) -> Result<usize> {
let yield_reg = program.alloc_register();
let coroutine_implementation_start_offset = program.allocate_label();
match &mut plan.query_type {
SelectQueryType::Subquery {
match &mut plan.query_destination {
QueryDestination::CoroutineYield {
yield_reg: y,
coroutine_implementation_start,
} => {

View File

@@ -1,6 +1,6 @@
use crate::translate::emitter::Resolver;
use crate::translate::expr::{translate_expr_no_constant_opt, NoConstantOptReason};
use crate::translate::plan::{SelectPlan, SelectQueryType};
use crate::translate::plan::{QueryDestination, SelectPlan};
use crate::vdbe::builder::ProgramBuilder;
use crate::vdbe::insn::Insn;
use crate::vdbe::BranchOffset;
@@ -16,12 +16,12 @@ pub fn emit_values(
return Ok(start_reg);
}
let reg_result_cols_start = match plan.query_type {
SelectQueryType::TopLevel => emit_toplevel_values(program, plan, resolver)?,
SelectQueryType::Subquery { yield_reg, .. } => {
let reg_result_cols_start = match plan.query_destination {
QueryDestination::ResultRows => emit_toplevel_values(program, plan, resolver)?,
QueryDestination::CoroutineYield { yield_reg, .. } => {
emit_values_in_subquery(program, plan, resolver, yield_reg)?
}
SelectQueryType::UnionArm { .. } => unreachable!(),
QueryDestination::EphemeralIndex { .. } => unreachable!(),
};
Ok(reg_result_cols_start)
}
@@ -44,20 +44,20 @@ fn emit_values_when_single_row(
NoConstantOptReason::RegisterReuse,
)?;
}
match plan.query_type {
SelectQueryType::TopLevel => {
match plan.query_destination {
QueryDestination::ResultRows => {
program.emit_insn(Insn::ResultRow {
start_reg,
count: row_len,
});
}
SelectQueryType::Subquery { yield_reg, .. } => {
QueryDestination::CoroutineYield { yield_reg, .. } => {
program.emit_insn(Insn::Yield {
yield_reg,
end_offset: BranchOffset::Offset(0),
});
}
SelectQueryType::UnionArm { .. } => unreachable!(),
QueryDestination::EphemeralIndex { .. } => unreachable!(),
}
Ok(start_reg)
}