use std::collections::HashMap;
use vibesql_ast::SelectStmt;
use vibesql_storage::Row;
use super::builder::SelectExecutor;
use crate::errors::ExecutorError;
pub(crate) mod analysis;
mod helpers;
mod index_lookup;
mod pk_lookup;
mod range_scan;
mod streaming_agg;
pub use analysis::{is_simple_point_query, is_streaming_aggregate_query};
impl SelectExecutor<'_> {
pub fn execute_fast_path(&self, stmt: &SelectStmt) -> Result<Vec<Row>, ExecutorError> {
let (table_name, alias) = match &stmt.from {
Some(vibesql_ast::FromClause::Table { name, alias, .. }) => {
(name.as_str(), alias.as_ref())
}
_ => unreachable!("Fast path requires simple table FROM clause"),
};
let resolved_where = if stmt.where_clause.is_some()
&& crate::select::order::select_list_has_aliases(&stmt.select_list)
{
stmt.where_clause.as_ref().map(|where_expr| {
if let Some(table_schema) = self.database.catalog.get_table(table_name) {
let effective_name = alias.map(|a| a.as_str()).unwrap_or(table_name);
let schema = crate::schema::CombinedSchema::from_table(
effective_name.to_string(),
table_schema.clone(),
);
crate::select::order::resolve_where_aliases_with_schema(
where_expr,
&stmt.select_list,
&schema,
)
} else {
crate::select::order::resolve_where_aliases(where_expr, &stmt.select_list)
}
})
} else {
stmt.where_clause.clone()
};
if let Some(result) = self.try_pk_lookup_fast(table_name, alias, stmt)? {
return Ok(result);
}
if let Some(result) = self.try_pk_prefix_with_limit_fast(table_name, alias, stmt)? {
return Ok(result);
}
if let Some(result) =
self.try_secondary_index_prefix_with_limit_fast(table_name, alias, stmt)?
{
return Ok(result);
}
if let Some(result) = self.try_secondary_index_lookup_fast(table_name, alias, stmt)? {
return Ok(result);
}
if let Some(result) = self.try_covering_index_scan_fast(table_name, alias, stmt)? {
return Ok(result);
}
if let Some(result) = self.try_pk_range_scan_with_early_projection(table_name, stmt)? {
return Ok(result);
}
let limit = crate::select::helpers::evaluate_limit(&stmt.limit, self.database)?;
let from_result = crate::select::scan::execute_from_clause(
stmt.from.as_ref().unwrap(),
&HashMap::new(), self.database,
resolved_where.as_ref(),
stmt.order_by.as_deref(),
limit, None, None, |_| unreachable!("Fast path doesn't support subqueries"),
)?;
let schema = from_result.schema.clone();
let where_filtered = from_result.where_filtered;
let sorted_by = from_result.sorted_by.clone();
let rows = from_result.into_rows();
let filtered_rows = match (&resolved_where, where_filtered) {
(Some(where_expr), false) => self.apply_where_filter_fast(where_expr, rows, &schema)?,
_ => rows,
};
let sorted_rows = if let Some(order_by) = &stmt.order_by {
if analysis::needs_sorting(order_by, &sorted_by) {
self.apply_order_by_fast(order_by, filtered_rows, &schema)?
} else {
filtered_rows
}
} else {
filtered_rows
};
let projected_rows = self.apply_projection_fast(&stmt.select_list, sorted_rows, &schema)?;
let offset = crate::select::helpers::evaluate_offset(&stmt.offset, self.database)?;
let final_rows = crate::select::helpers::apply_limit_offset(projected_rows, limit, offset);
Ok(final_rows)
}
}