uqa_sql/binding/statements/
cache.rs1use super::{analyze_reusable_inputs, StatementAnalysisContext};
10use crate::{plan::UnifiedPlan, ColumnType, RowSchema, SQLError, SQLParam, ScalarExpr};
11
12#[derive(Clone, PartialEq)]
13struct ParameterShape {
14 declared: bool,
15 resolved: Option<ColumnType>,
16}
17
18fn parameter_shapes(params: &[SQLParam]) -> Option<Vec<ParameterShape>> {
19 let schema = RowSchema::default();
20 params
21 .iter()
22 .enumerate()
23 .map(|(index, parameter)| {
24 Some(ParameterShape {
25 declared: parameter.declared_scalar_type().is_some(),
26 resolved: crate::scalar_type(&ScalarExpr::Param(index + 1), &schema, params)
27 .ok()?,
28 })
29 })
30 .collect()
31}
32
33#[derive(Clone)]
35pub struct AnalyzedStatement {
36 plan: UnifiedPlan,
37 parameters: Vec<ParameterShape>,
38}
39
40impl AnalyzedStatement {
41 pub fn plan_for(&self, params: &[SQLParam]) -> Option<&UnifiedPlan> {
42 (parameter_shapes(params).as_ref() == Some(&self.parameters)).then_some(&self.plan)
43 }
44}
45
46pub fn analyze_for_statement_reuse(
48 context: &StatementAnalysisContext<'_>,
49 mut plan: UnifiedPlan,
50 params: &[SQLParam],
51) -> Result<(UnifiedPlan, Option<AnalyzedStatement>), SQLError> {
52 let (_, reusable) = analyze_reusable_inputs(context, &mut plan, params)?;
53 let retained = reusable
54 .then(|| parameter_shapes(params))
55 .flatten()
56 .map(|parameters| AnalyzedStatement {
57 plan: plan.clone(),
58 parameters,
59 });
60 Ok((plan, retained))
61}