use uqa_execution::operator_tree::{OperatorOutput, OperatorTreeDriver};
use uqa_execution::parallel::ParallelExecutor;
use uqa_execution::ScalarExpr;
use uqa_operators::OperatorTree;
use uqa_planner::retrieval_planning::{
estimate_cross_relation_operator_join, estimate_operator_tree_access, query_optimizer,
};
use uqa_sql::ast::OperatorJoinRelations;
use uqa_sql::SQLParam;
use crate::{Engine, ScoredEntry};
use uqa_sql::SQLError;
pub use uqa_execution::operator_tree::binding::lower_where;
type DriverResult<T> = Result<T, SQLError>;
fn operator_execution_error(operator: &str, error: impl std::fmt::Display) -> SQLError {
SQLError::Internal(format!("execute {operator}: {error}"))
}
pub struct EngineDriver<'a> {
pub engine: &'a Engine,
pub table: &'a str,
pub params: &'a [SQLParam],
pub parallel: ParallelExecutor,
}
impl<'a> EngineDriver<'a> {
#[must_use]
pub fn new(engine: &'a Engine, table: &'a str, params: &'a [SQLParam]) -> Self {
Self {
engine,
table,
params,
parallel: ParallelExecutor::default(),
}
}
#[must_use]
pub fn with_parallel(mut self, parallel: ParallelExecutor) -> Self {
self.parallel = parallel;
self
}
}
impl OperatorTreeDriver for EngineDriver<'_> {
type Error = SQLError;
fn execute_node(&self, tree: &OperatorTree) -> DriverResult<OperatorOutput> {
execution::execute_public_physical_node(self, tree)
}
}
pub fn optimised_tree_for(
engine: &Engine,
table: &str,
where_expr: &ScalarExpr,
params: &[SQLParam],
) -> DriverResult<Option<OperatorTree>> {
let Some(tree) = engine.retrieval_binding().lower_where(where_expr, params)? else {
return Ok(None);
};
Ok(Some(query_optimizer(engine, table, &tree)?.optimize(tree)))
}
pub(crate) fn estimate_local_access(
engine: &Engine,
table: &str,
where_expr: &ScalarExpr,
params: &[SQLParam],
) -> DriverResult<Option<uqa_planner::LocalAccessEstimate>> {
let Some(tree) = engine.retrieval_binding().lower_where(where_expr, params)? else {
return Ok(None);
};
estimate_operator_tree_access(engine, table, tree, true).map(Some)
}
mod execution;
pub(crate) use execution::execute_scored_tree;
pub use execution::run_optimised;
use uqa_execution::operator_tree::driver::posting::posting_list_to_scored;
pub(crate) fn estimate_operator_join_table_function(
engine: &Engine,
name: &str,
relations: Option<&OperatorJoinRelations>,
args: &[ScalarExpr],
params: &[SQLParam],
) -> DriverResult<uqa_planner::LocalAccessEstimate> {
let (relations, tree) = engine
.retrieval_binding()
.lower_join(name, relations, args, params)?;
estimate_cross_relation_operator_join(engine, &relations, tree)
}