SelectExecutor

Struct SelectExecutor 

Source
pub struct SelectExecutor<'a> {
    pub timeout_seconds: u64,
    /* private fields */
}
Expand description

Executes SELECT queries

Fields§

§timeout_seconds: u64

Timeout in seconds (defaults to MAX_QUERY_EXECUTION_SECONDS)

Implementations§

Source§

impl SelectExecutor<'_>

Source

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 statement
  • params - 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>

Source

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
Source

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

Source

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

Source

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:

  1. The main regression (100% timeout) was caused by ZERO timeout enforcement
  2. Having per-subquery timeouts still prevents infinite loops (the core issue)
  3. Most problematic queries cause recursive subquery execution, which IS caught
  4. 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

Source

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

Source

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

Source

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

Source

pub fn with_timeout(self, seconds: u64) -> Self

Override default timeout for this query (useful for testing)

Source

pub fn check_timeout(&self) -> Result<(), ExecutorError>

Check if query has exceeded timeout Call this in hot loops to prevent infinite execution

Source

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<'_>

Source

pub fn execute(&self, stmt: &SelectStmt) -> Result<Vec<Row>, ExecutorError>

Execute a SELECT statement

Source

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.

Source

pub fn execute_with_columns( &self, stmt: &SelectStmt, ) -> Result<SelectResult, ExecutorError>

Execute a SELECT statement and return both columns and rows

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> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<G1, G2> Within<G2> for G1
where G2: Contains<G1>,

Source§

fn is_within(&self, b: &G2) -> bool