use super::{materialize_plan_ctes, materialize_plan_ctes_with_filters, CteExecutionContext};
use crate::query::CteScope;
use std::collections::{BTreeMap, BTreeSet};
use uqa_sql::{
plan::CtePlan,
semantics::{cte_strategy::order_statement_ctes, order_cte_plans},
SQLError, SQLParam, ScalarExpr,
};
pub fn materialize_statement_ctes<'a, S: Clone>(
context: CteExecutionContext<'_, S>,
ctes: &'a [CtePlan],
scheduled: Vec<&'a CtePlan>,
primary_references: impl FnOnce() -> BTreeSet<String>,
params: &[SQLParam],
scope: &mut CteScope<S>,
output_filters: &BTreeMap<String, (String, ScalarExpr)>,
) -> Result<(), SQLError> {
if !scheduled.iter().any(|cte| cte.body.modifies_data()) {
return materialize_plan_ctes_with_filters(
context,
scheduled,
params,
scope,
output_filters,
);
}
let order = order_statement_ctes(ctes, order_cte_plans(scheduled)?, &primary_references());
let commands = match scope.statement_commands() {
Some(commands) => std::sync::Arc::clone(commands),
None => {
let commands = std::sync::Arc::default();
scope.set_statement_commands(std::sync::Arc::clone(&commands));
commands
}
};
commands.begin_data_modifying_with(order.postponed.into_iter().cloned().collect());
materialize_plan_ctes_with_filters(context, order.primary, params, scope, output_filters)
}
pub fn materialize_command_ctes<S: Clone>(
context: CteExecutionContext<'_, S>,
ctes: &[CtePlan],
primary_references: impl FnOnce() -> BTreeSet<String>,
params: &[SQLParam],
scope: &mut CteScope<S>,
) -> Result<(), SQLError> {
materialize_statement_ctes(
context,
ctes,
ctes.iter().collect(),
primary_references,
params,
scope,
&BTreeMap::new(),
)
}
pub fn finish_statement_ctes<S: Clone>(
context: CteExecutionContext<'_, S>,
params: &[SQLParam],
scope: &mut CteScope<S>,
) -> Result<(), SQLError> {
let Some(commands) = scope.statement_commands().cloned() else {
return Ok(());
};
let postponed = commands.take_postponed();
materialize_plan_ctes(context, &postponed, params, scope)
}