uqa_sql/binding/statements/
procedural.rs1use super::{AnalyzedResult, BindingContext, StatementAnalysisContext};
10use crate::{
11 catalog::resolution::EffectiveSearchPath,
12 plan::{CommandPlan, UnifiedPlan},
13 prepared::dependencies::{PreparedAnalysisDependencies, PreparedDependencySnapshot},
14 routines::{declaration::RoutineTypeCatalog, resolution::RoutineOverloadContext},
15 SQLError, SQLParam,
16};
17
18#[derive(Debug)]
19pub struct ProceduralPlanAnalysis {
20 pub composite_inputs: crate::prepared::composites::CompositeInputs,
21 pub result: AnalyzedResult,
22 pub dependencies: PreparedAnalysisDependencies,
23 pub effective_search_path: Option<EffectiveSearchPath>,
24 pub dependency_snapshot: Option<PreparedDependencySnapshot>,
25}
26
27impl ProceduralPlanAnalysis {
28 pub fn prepared_definition(
30 &self,
31 plan: &UnifiedPlan,
32 params: &[SQLParam],
33 ) -> Result<crate::prepared::definition::PreparedDefinition, SQLError> {
34 let parameter_types = (1..=params.len())
35 .map(|index| {
36 crate::type_resolution::scalar_type(
37 &crate::ScalarExpr::Param(index),
38 &crate::RowSchema::new(Vec::new()),
39 params,
40 )
41 })
42 .collect::<Result<Vec<_>, _>>()?;
43 let result_schema = match &self.result {
44 AnalyzedResult::Command => None,
45 AnalyzedResult::Schema(schema) => Some(schema.clone()),
46 AnalyzedResult::Rows(types) => Some(crate::RowSchema::with_types(
47 vec![String::new(); types.len()],
48 types.clone(),
49 )),
50 };
51 Ok(crate::prepared::definition::PreparedDefinition {
52 composite_inputs: self.composite_inputs.clone(),
53 logical_plan: plan.clone(),
54 parameter_types,
55 result_schema,
56 effective_search_path: self.effective_search_path.clone(),
57 dependencies: self.dependencies.clone(),
58 dependency_snapshot: self.dependency_snapshot.clone(),
59 })
60 }
61}
62
63pub fn analyze_procedural_plan(
66 context: &StatementAnalysisContext<'_>,
67 overloads: &RoutineOverloadContext<'_>,
68 types: &dyn RoutineTypeCatalog,
69 plan: &mut UnifiedPlan,
70 params: &[SQLParam],
71) -> Result<ProceduralPlanAnalysis, SQLError> {
72 let mut analyzed = None;
73 context.scopes.with_scope(&mut |scope| {
74 let binding = scope.binding_context()?;
75 let (result, dependencies) =
76 analyze_inputs(context, overloads, types, plan, params, &binding)?;
77 crate::routines::compilation::bind_analyzed_sql_body_types(types, plan)?;
78 super::super::composite_inputs::retain_composite_inputs(
79 context.routines,
80 plan,
81 params,
82 &binding,
83 )?;
84 let composite_inputs =
85 crate::prepared::composites::CompositeInputs::capture(plan, context.routines)?;
86 let effective_search_path = binding.catalog.effective_search_path(&binding.resolution)?;
87 let dependency_snapshot = binding
88 .catalog
89 .prepared_dependency_snapshot(&dependencies)?;
90 analyzed = Some(ProceduralPlanAnalysis {
91 composite_inputs,
92 result,
93 dependencies,
94 effective_search_path,
95 dependency_snapshot,
96 });
97 Ok(())
98 })?;
99 analyzed.ok_or_else(|| SQLError::Internal("procedural analysis scope did not run".into()))
100}
101
102fn analyze_inputs(
103 context: &StatementAnalysisContext<'_>,
104 overloads: &RoutineOverloadContext<'_>,
105 types: &dyn RoutineTypeCatalog,
106 plan: &mut UnifiedPlan,
107 params: &[SQLParam],
108 binding: &BindingContext<'_>,
109) -> Result<(AnalyzedResult, PreparedAnalysisDependencies), SQLError> {
110 if let UnifiedPlan::Command(command) = plan {
111 match command.as_mut() {
112 CommandPlan::Call { .. } => {
113 return crate::binding::preparation::prepare_procedure_call(
114 context, overloads, types, plan, params, binding,
115 );
116 }
117 CommandPlan::Explain { body, .. } => {
118 let (_, dependencies) =
119 analyze_inputs(context, overloads, types, body, params, binding)?;
120 return Ok((AnalyzedResult::Command, dependencies));
121 }
122 _ => {}
123 }
124 }
125 let dependencies = crate::binding::preparation::read_procedural_inputs(
126 context.routines,
127 plan,
128 params,
129 binding,
130 context.aliases,
131 )?;
132 let result = super::analyze_bound_result(context.routines, plan, params, binding)?;
133 Ok((result, dependencies))
134}