uqa_sql/binding/
statements.rs1use super::BindingContext;
10use crate::{
11 plan::{CommandPlan, UnifiedPlan},
12 routines::RoutineResolution,
13 RowSchema, SQLError, SQLParam, ScalarExpr,
14};
15use uqa_core::Value;
16
17pub trait StatementBindingScope {
19 fn binding_context(&self) -> Result<BindingContext<'_>, SQLError>;
20}
21pub type StatementAnalysisOperation<'a> =
22 &'a mut dyn FnMut(&dyn StatementBindingScope) -> Result<(), SQLError>;
23
24pub trait StatementAnalysisScopes {
26 fn with_scope(&self, analyze: StatementAnalysisOperation<'_>) -> Result<(), SQLError>;
27}
28pub struct StatementAnalysisContext<'a> {
29 pub scopes: &'a dyn StatementAnalysisScopes,
30 pub routines: &'a dyn RoutineResolution,
31}
32
33pub fn analyze_executable_plan(
34 context: &StatementAnalysisContext<'_>,
35 plan: &UnifiedPlan,
36 params: &[SQLParam],
37) -> Result<(), SQLError> {
38 context.scopes.with_scope(&mut |scope| {
39 match plan {
40 UnifiedPlan::Query(query) => {
41 super::analyze_query_plan_schema(
42 context.routines,
43 query,
44 params,
45 &scope.binding_context()?,
46 None,
47 )?;
48 }
49 UnifiedPlan::Command(command) => match command.as_ref() {
50 CommandPlan::Explain { body, .. } => {
51 analyze_executable_plan(context, body, params)?;
52 }
53 CommandPlan::CreateTableAs { query, .. }
54 | CommandPlan::CreateMaterializedView { query, .. }
55 | CommandPlan::DeclareCursor { query, .. } => {
56 super::analyze_query_plan_schema(
57 context.routines,
58 query,
59 params,
60 &scope.binding_context()?,
61 None,
62 )?;
63 }
64 _ => {
65 if command.mutation_target().is_some() {
66 analyze_command_parameters(context.routines, command, params, scope)?;
67 }
68 super::analyze_prepared_command_schema(
69 context.routines,
70 command,
71 params,
72 &scope.binding_context()?,
73 )?;
74 }
75 },
76 }
77 Ok(())
78 })
79}
80
81pub fn analyze_command_parameters(
82 routines: &dyn RoutineResolution,
83 command: &CommandPlan,
84 params: &[SQLParam],
85 scope: &dyn StatementBindingScope,
86) -> Result<(), SQLError> {
87 let schema = RowSchema::default();
88 let declared = (1..=params.len())
89 .map(|index| match ¶ms[index - 1] {
90 SQLParam::Scalar(Value::Str(_) | Value::Null) => Ok(None),
91 _ => crate::scalar_type(&ScalarExpr::Param(index), &schema, params),
92 })
93 .collect::<Result<Vec<_>, _>>()?;
94 super::infer_prepared_parameter_types(
95 routines,
96 &UnifiedPlan::Command(Box::new(command.clone())),
97 &declared,
98 &scope.binding_context()?,
99 )?;
100 Ok(())
101}
102
103#[cfg(test)]
104mod tests;