pub struct SelectExecutor<'a> {
pub timeout_seconds: u64,
/* private fields */
}Expand description
Executes SELECT queries
Fields§
§timeout_seconds: u64Timeout in seconds (defaults to MAX_QUERY_EXECUTION_SECONDS)
Implementations§
Source§impl SelectExecutor<'_>
impl SelectExecutor<'_>
Sourcepub fn execute_select_arena<'arena>(
&self,
stmt: &ArenaSelectStmt<'arena>,
params: &[SqlValue],
interner: &'arena ArenaInterner<'arena>,
) -> Result<Vec<Row>, ExecutorError>
pub fn execute_select_arena<'arena>( &self, stmt: &ArenaSelectStmt<'arena>, params: &[SqlValue], interner: &'arena ArenaInterner<'arena>, ) -> Result<Vec<Row>, ExecutorError>
Execute an arena-allocated SELECT statement with inline placeholder resolution.
This method provides zero-allocation query execution for prepared statements. Parameters are resolved inline during evaluation, avoiding AST cloning.
§Arguments
stmt- Arena-allocated SELECT statementparams- Parameter values for placeholder resolution
§Returns
Vector of result rows.
§Limitations
Currently supports simple SELECT queries without:
- JOINs (single table only)
- Subqueries
- Aggregates, GROUP BY, HAVING
- Window functions
- CTEs (WITH clause)
For unsupported features, returns an error. Fall back to standard execution.
Source§impl<'a> SelectExecutor<'a>
impl<'a> SelectExecutor<'a>
Sourcepub fn new(database: &'a Database) -> Self
pub fn new(database: &'a Database) -> Self
Create a new SELECT executor
§Performance
This constructor is optimized for OLTP workloads:
- Arena is lazily initialized (10MB allocation deferred until needed)
- Aggregate cache is lazily initialized (HashMap allocation deferred)
- Simple queries that don’t use aggregates or complex allocations skip these costs
Sourcepub fn new_with_cte(
database: &'a Database,
cte_context: &'a HashMap<String, CteResult>,
) -> Self
pub fn new_with_cte( database: &'a Database, cte_context: &'a HashMap<String, CteResult>, ) -> Self
Create a new SELECT executor with CTE context Used for INSERT … SELECT with CTEs (WITH clause on INSERT statement)
Sourcepub fn new_with_outer_context(
database: &'a Database,
outer_row: &'a Row,
outer_schema: &'a CombinedSchema,
) -> Self
pub fn new_with_outer_context( database: &'a Database, outer_row: &'a Row, outer_schema: &'a CombinedSchema, ) -> Self
Create a new SELECT executor with outer context for correlated subqueries
Sourcepub fn new_with_depth(database: &'a Database, parent_depth: usize) -> Self
pub fn new_with_depth(database: &'a Database, parent_depth: usize) -> Self
Create a new SELECT executor with explicit depth tracking Used for non-correlated subqueries to propagate depth limit enforcement
Sourcepub fn new_with_outer_context_and_depth(
database: &'a Database,
outer_row: &'a Row,
outer_schema: &'a CombinedSchema,
parent_depth: usize,
) -> Self
pub fn new_with_outer_context_and_depth( database: &'a Database, outer_row: &'a Row, outer_schema: &'a CombinedSchema, parent_depth: usize, ) -> Self
Create a new SELECT executor with outer context and explicit depth Used when creating subquery executors to track nesting depth
§Note on Timeout Inheritance
Currently subqueries get their own 60s timeout rather than sharing parent’s timeout. This means a query with N subqueries could run for up to N*60s instead of 60s total.
However, this is acceptable for the initial fix because:
- The main regression (100% timeout) was caused by ZERO timeout enforcement
- Having per-subquery timeouts still prevents infinite loops (the core issue)
- Most problematic queries cause recursive subquery execution, which IS caught
- Threading timeout through evaluators requires extensive refactoring
Future improvement: Add timeout fields to ExpressionEvaluator and pass through See: https://github.com/rjwalters/vibesql/issues/1012#subquery-timeout
Sourcepub fn new_with_procedural_context(
database: &'a Database,
procedural_context: &'a ExecutionContext,
) -> Self
pub fn new_with_procedural_context( database: &'a Database, procedural_context: &'a ExecutionContext, ) -> Self
Create a new SELECT executor with procedural context for stored procedures/functions
Sourcepub fn new_with_cte_and_depth(
database: &'a Database,
cte_context: &'a HashMap<String, CteResult>,
parent_depth: usize,
) -> Self
pub fn new_with_cte_and_depth( database: &'a Database, cte_context: &'a HashMap<String, CteResult>, parent_depth: usize, ) -> Self
Create a new SELECT executor with CTE context and depth tracking Used for non-correlated subqueries that need access to parent CTEs
Sourcepub fn new_with_outer_and_cte_and_depth(
database: &'a Database,
outer_row: &'a Row,
outer_schema: &'a CombinedSchema,
cte_context: &'a HashMap<String, CteResult>,
parent_depth: usize,
) -> Self
pub fn new_with_outer_and_cte_and_depth( database: &'a Database, outer_row: &'a Row, outer_schema: &'a CombinedSchema, cte_context: &'a HashMap<String, CteResult>, parent_depth: usize, ) -> Self
Create a new SELECT executor with outer context, CTE context, and depth tracking Used for correlated subqueries that need access to both outer row and parent CTEs
Sourcepub fn new_with_outer_rows_and_depth(
database: &'a Database,
outer_row: &'a Row,
outer_schema: &'a CombinedSchema,
outer_rows: &'a [Row],
parent_depth: usize,
) -> Self
pub fn new_with_outer_rows_and_depth( database: &'a Database, outer_row: &'a Row, outer_schema: &'a CombinedSchema, outer_rows: &'a [Row], parent_depth: usize, ) -> Self
Create a new SELECT executor with outer context, outer rows, and depth tracking Used for outer-correlated aggregates (issue #4930) where aggregates in scalar subqueries need access to ALL outer rows, not just the current one.
Sourcepub fn new_with_outer_rows_and_cte_and_depth(
database: &'a Database,
outer_row: &'a Row,
outer_schema: &'a CombinedSchema,
outer_rows: &'a [Row],
cte_context: &'a HashMap<String, CteResult>,
parent_depth: usize,
) -> Self
pub fn new_with_outer_rows_and_cte_and_depth( database: &'a Database, outer_row: &'a Row, outer_schema: &'a CombinedSchema, outer_rows: &'a [Row], cte_context: &'a HashMap<String, CteResult>, parent_depth: usize, ) -> Self
Create a new SELECT executor with outer context, outer rows, CTE, and depth tracking Used for outer-correlated aggregates (issue #4930) with CTE support
Sourcepub fn with_timeout(self, seconds: u64) -> Self
pub fn with_timeout(self, seconds: u64) -> Self
Override default timeout for this query (useful for testing)
Sourcepub fn check_timeout(&self) -> Result<(), ExecutorError>
pub fn check_timeout(&self) -> Result<(), ExecutorError>
Check if query has exceeded timeout Call this in hot loops to prevent infinite execution
Sourcepub fn reset_for_reuse(&mut self)
pub fn reset_for_reuse(&mut self)
Reset the executor for reuse between queries
This method prepares the executor for a new query execution by:
- Resetting the start time to now
- Clearing memory tracking counters
- Resetting the arena (if initialized)
- Clearing the aggregate cache (if initialized)
§Performance
Call this method to reuse an executor instead of creating a new one. This avoids the allocation overhead of creating new HashMap and arena instances.
Source§impl SelectExecutor<'_>
impl SelectExecutor<'_>
Sourcepub fn execute(&self, stmt: &SelectStmt) -> Result<Vec<Row>, ExecutorError>
pub fn execute(&self, stmt: &SelectStmt) -> Result<Vec<Row>, ExecutorError>
Execute a SELECT statement
Sourcepub fn execute_iter(
&self,
stmt: &SelectStmt,
) -> Result<impl Iterator<Item = Row>, ExecutorError>
pub fn execute_iter( &self, stmt: &SelectStmt, ) -> Result<impl Iterator<Item = Row>, ExecutorError>
Execute a SELECT statement and return an iterator over results
This enables early termination when the full result set is not needed, such as for IN subqueries where we stop after finding the first match.
§Phase 1 Implementation (Early Termination for IN subqueries)
Current implementation materializes results then returns an iterator. This still enables early termination in the consumer (e.g., eval_in_subquery) by stopping iteration when a match is found.
Future optimization: Leverage the existing RowIterator infrastructure (crate::select::iterator) for truly lazy evaluation that stops execution early, not just iteration.
Sourcepub fn execute_fast_path_with_columns(
&self,
stmt: &SelectStmt,
) -> Result<SelectResult, ExecutorError>
pub fn execute_fast_path_with_columns( &self, stmt: &SelectStmt, ) -> Result<SelectResult, ExecutorError>
Execute a SELECT statement using the fast path directly
This method is used by prepared statements with cached SimpleFastPath plans.
It bypasses the is_simple_point_query() check because the eligibility was
already determined at prepare time.
§Performance
For repeated execution of prepared statements, this saves the cost of re-checking fast path eligibility on every execution (~5-10µs per query).
Sourcepub fn derive_fast_path_column_names(
&self,
stmt: &SelectStmt,
) -> Result<Vec<String>, ExecutorError>
pub fn derive_fast_path_column_names( &self, stmt: &SelectStmt, ) -> Result<Vec<String>, ExecutorError>
Derive column names for fast path execution
For fast path queries, we derive column names directly from the SELECT list and table schema without going through the full FROM clause execution.
§Performance Note (#3780)
This method is called by Session::execute_prepared() to cache column names
in SimpleFastPathPlan. After the first execution, cached column names are
reused to avoid repeated table lookups and column name derivation.
Sourcepub fn execute_with_columns(
&self,
stmt: &SelectStmt,
) -> Result<SelectResult, ExecutorError>
pub fn execute_with_columns( &self, stmt: &SelectStmt, ) -> Result<SelectResult, ExecutorError>
Execute a SELECT statement and return both columns and rows
Sourcepub fn execute_with_simple_columns(
&self,
stmt: &SelectStmt,
) -> Result<SelectResult, ExecutorError>
pub fn execute_with_simple_columns( &self, stmt: &SelectStmt, ) -> Result<SelectResult, ExecutorError>
Execute SELECT statement and return results with simple column names
This is similar to execute_with_columns but returns column names without
table prefixes. This is used for internal purposes like view creation
where the full table.column format would cause column lookup issues.
Source§impl SelectExecutor<'_>
impl SelectExecutor<'_>
Sourcepub fn execute_streaming_aggregate(
&self,
stmt: &SelectStmt,
) -> Result<Vec<Row>, ExecutorError>
pub fn execute_streaming_aggregate( &self, stmt: &SelectStmt, ) -> Result<Vec<Row>, ExecutorError>
Execute a streaming aggregate query (#3815)
This provides ultra-fast execution for queries like:
SELECT SUM(k) FROM sbtest1 WHERE id BETWEEN ? AND ?
By accumulating aggregates inline during the PK range scan, we avoid:
- Materializing intermediate Row objects
- Going through the full pipeline infrastructure
- Multiple allocations per row
§Performance
This achieves SQLite-like performance (~4μs) compared to ~30μs for the standard aggregation path.
Source§impl SelectExecutor<'_>
impl SelectExecutor<'_>
Sourcepub fn execute_fast_path(
&self,
stmt: &SelectStmt,
) -> Result<Vec<Row>, ExecutorError>
pub fn execute_fast_path( &self, stmt: &SelectStmt, ) -> Result<Vec<Row>, ExecutorError>
Execute a query using the fast path
This bypasses the optimizer infrastructure and goes directly to table scan with optional index optimization.
§Performance Note (#3780)
This method is called by Session::execute_prepared() for queries using
SimpleFastPath cached plans. It executes the query and returns just the
rows, leaving column name resolution to the cached plan.
Auto Trait Implementations§
impl<'a> !Freeze for SelectExecutor<'a>
impl<'a> !RefUnwindSafe for SelectExecutor<'a>
impl<'a> Send for SelectExecutor<'a>
impl<'a> !Sync for SelectExecutor<'a>
impl<'a> Unpin for SelectExecutor<'a>
impl<'a> !UnwindSafe for SelectExecutor<'a>
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more