use super::{analyze_reusable_inputs, StatementAnalysisContext};
use crate::{plan::UnifiedPlan, ColumnType, RowSchema, SQLError, SQLParam, ScalarExpr};
#[derive(Clone, PartialEq)]
struct ParameterShape {
declared: bool,
resolved: Option<ColumnType>,
}
fn parameter_shapes(params: &[SQLParam]) -> Option<Vec<ParameterShape>> {
let schema = RowSchema::default();
params
.iter()
.enumerate()
.map(|(index, parameter)| {
Some(ParameterShape {
declared: parameter.declared_scalar_type().is_some(),
resolved: crate::scalar_type(&ScalarExpr::Param(index + 1), &schema, params)
.ok()?,
})
})
.collect()
}
#[derive(Clone)]
pub struct AnalyzedStatement {
plan: UnifiedPlan,
parameters: Vec<ParameterShape>,
}
impl AnalyzedStatement {
pub fn plan_for(&self, params: &[SQLParam]) -> Option<&UnifiedPlan> {
(parameter_shapes(params).as_ref() == Some(&self.parameters)).then_some(&self.plan)
}
}
pub fn analyze_for_statement_reuse(
context: &StatementAnalysisContext<'_>,
mut plan: UnifiedPlan,
params: &[SQLParam],
) -> Result<(UnifiedPlan, Option<AnalyzedStatement>), SQLError> {
let (_, reusable) = analyze_reusable_inputs(context, &mut plan, params)?;
let retained = reusable
.then(|| parameter_shapes(params))
.flatten()
.map(|parameters| AnalyzedStatement {
plan: plan.clone(),
parameters,
});
Ok((plan, retained))
}