uqa_sql/plpgsql/
parameters.rs1use super::{
10 binding::{bind_statement, ResolvedVariable, VariableResolver},
11 variable_conflicts::{statement_variable_names, VariableSiteResolver},
12 VariableConflict,
13};
14use crate::{
15 ast::{Expr, Statement},
16 SQLError, SQLParam,
17};
18
19#[derive(Debug, Clone)]
20pub enum PLpgSQLVariableReference {
21 Name(String),
22 Qualified { qualifier: String, column: String },
23 Parameter(usize),
24}
25impl PLpgSQLVariableReference {
26 pub fn read(&self, resolver: &mut dyn VariableResolver) -> Result<SQLParam, SQLError> {
27 let value = match self {
28 Self::Name(name) => resolver.resolve_name(name),
29 Self::Qualified { qualifier, column } => resolver.resolve_qualified(qualifier, column),
30 Self::Parameter(index) => resolver.resolve_param(*index),
31 }?
32 .ok_or_else(|| {
33 SQLError::Internal("prepared PL/pgSQL variable no longer resolves".into())
34 })?;
35 Ok(parameter(value, resolver))
36 }
37}
38fn parameter(value: ResolvedVariable, resolver: &dyn VariableResolver) -> SQLParam {
39 match value
40 .declared_type
41 .as_deref()
42 .and_then(|name| resolver.parameter_type(name))
43 {
44 Some(ty) => SQLParam::typed_scalar(value.value, ty),
45 None => SQLParam::scalar(value.value),
46 }
47}
48
49pub struct PLpgSQLVariableBindings {
50 pub statement: Statement,
51 pub references: Vec<PLpgSQLVariableReference>,
52 pub parameters: Vec<SQLParam>,
53}
54
55pub fn parameterize_statement_variables(
58 statement: &Statement,
59 resolver: &mut dyn VariableResolver,
60 conflict: VariableConflict,
61 resolve_sites: VariableSiteResolver<'_>,
62) -> Result<PLpgSQLVariableBindings, SQLError> {
63 let keep = statement_variable_names(statement, resolver, conflict, resolve_sites)?;
64 let mut binding = VariableBindings {
65 inner: resolver,
66 keep: &keep,
67 next_name: 0,
68 references: Vec::new(),
69 parameters: Vec::new(),
70 };
71 let statement = bind_statement(statement, &mut binding)?;
72 Ok(PLpgSQLVariableBindings {
73 statement,
74 references: binding.references,
75 parameters: binding.parameters,
76 })
77}
78struct VariableBindings<'a> {
79 inner: &'a mut dyn VariableResolver,
80 keep: &'a [bool],
81 next_name: usize,
82 references: Vec<PLpgSQLVariableReference>,
83 parameters: Vec<SQLParam>,
84}
85impl VariableBindings<'_> {
86 fn mark(
87 &mut self,
88 reference: PLpgSQLVariableReference,
89 value: Option<ResolvedVariable>,
90 named: bool,
91 ) -> Option<Expr> {
92 let value = value?;
93 if named {
94 let site = self.next_name;
95 self.next_name += 1;
96 if self.keep.get(site).copied().unwrap_or(false) {
97 return None;
98 }
99 }
100 self.references.push(reference);
101 self.parameters.push(parameter(value, self.inner));
102 Some(Expr::Param(self.references.len()))
103 }
104}
105impl VariableResolver for VariableBindings<'_> {
106 fn resolve_name(&mut self, name: &str) -> Result<Option<ResolvedVariable>, SQLError> {
107 self.inner.resolve_name(name)
108 }
109 fn resolve_qualified(
110 &mut self,
111 qualifier: &str,
112 column: &str,
113 ) -> Result<Option<ResolvedVariable>, SQLError> {
114 self.inner.resolve_qualified(qualifier, column)
115 }
116 fn resolve_param(&mut self, index: usize) -> Result<Option<ResolvedVariable>, SQLError> {
117 self.inner.resolve_param(index)
118 }
119 fn rewrite_name(&mut self, name: &str) -> Result<Option<Expr>, SQLError> {
120 let value = self.inner.resolve_name(name)?;
121 Ok(self.mark(
122 PLpgSQLVariableReference::Name(name.to_string()),
123 value,
124 true,
125 ))
126 }
127 fn rewrite_qualified(
128 &mut self,
129 qualifier: &str,
130 column: &str,
131 ) -> Result<Option<Expr>, SQLError> {
132 let value = self.inner.resolve_qualified(qualifier, column)?;
133 Ok(self.mark(
134 PLpgSQLVariableReference::Qualified {
135 qualifier: qualifier.to_string(),
136 column: column.to_string(),
137 },
138 value,
139 true,
140 ))
141 }
142 fn rewrite_param(&mut self, index: usize) -> Result<Option<Expr>, SQLError> {
143 let value = self.inner.resolve_param(index)?;
144 Ok(self.mark(PLpgSQLVariableReference::Parameter(index), value, false))
145 }
146}
147
148#[cfg(test)]
149mod tests;