1use super::{BindingContext, SchemaScope};
10use crate::{
11 ast::{CreateFunction, Expr, FunctionBinding, Statement},
12 plan::{ExpressionPlan, QueryPlan, UnifiedPlan},
13 routines::RoutineResolution,
14 RowSchema, SQLError, SQLParam, ScalarExpr,
15};
16use uqa_core::Value;
17
18pub struct CompositeFieldRename<'a> {
19 pub target: u32,
20 pub number: i16,
21 pub to: &'a str,
22 pub routines: &'a dyn RoutineResolution,
23 pub binding: BindingContext<'a>,
24}
25
26#[cfg(test)]
27mod tests;
28
29impl CompositeFieldRename<'_> {
30 pub fn relation_schema(&self, name: &str) -> Result<RowSchema, SQLError> {
31 let (_, qualifier) =
32 uqa_core::RelationIdentity::parse_reference(name).map_err(SQLError::Internal)?;
33 super::sources::analyze_source_plan_schema(
34 self.routines,
35 &crate::plan::SourcePlan::Table {
36 name: name.to_owned(),
37 qualifier,
38 alias: None,
39 column_aliases: Vec::new(),
40 include_descendants: true,
41 bound_columns: None,
42 },
43 &[],
44 &self.binding,
45 None,
46 )
47 }
48
49 pub fn transition_schema(&self, name: &str) -> Result<RowSchema, SQLError> {
50 let schema = self.relation_schema(name)?;
51 Ok(RowSchema::join(
52 &RowSchema::with_relation_qualifier(&schema, "old"),
53 &RowSchema::with_relation_qualifier(&schema, "new"),
54 [],
55 ))
56 }
57 fn scope(&self) -> Result<SchemaScope, SQLError> {
58 let mut scope = SchemaScope::for_analysis(&self.binding)?;
59 scope.scalar_binding = super::ScalarBindingMode::CompositeInputs;
60 scope.preserve_syntax_shape = true;
61 Ok(scope)
62 }
63
64 fn selected(&self, binding: Option<&FunctionBinding>) -> bool {
65 binding
66 .and_then(|binding| binding.composite_field.as_ref())
67 .is_some_and(|field| field.type_oid == self.target && field.number == self.number)
68 }
69
70 fn syntax_node(&self, node: &mut Expr) -> bool {
71 if let Expr::Func { binding, args, .. } = node {
72 if self.selected(binding.as_ref()) {
73 if let Some(Expr::Literal(Value::Str(name))) = args.get_mut(1) {
74 if name != self.to {
75 self.to.clone_into(name);
76 return true;
77 }
78 }
79 }
80 }
81 false
82 }
83
84 fn scalar_node(&self, node: &mut ScalarExpr) -> bool {
85 if let ScalarExpr::Func { binding, args, .. } = node {
86 if self.selected(binding.as_ref()) {
87 if let Some(ScalarExpr::Literal(Value::Str(name))) = args.get_mut(1) {
88 if name != self.to {
89 self.to.clone_into(name);
90 return true;
91 }
92 }
93 }
94 }
95 false
96 }
97
98 pub fn expression(&self, expression: &mut Expr, schema: &RowSchema) -> Result<bool, SQLError> {
99 let lowered = ExpressionPlan::lower(expression.clone());
100 let mut plan = lowered.clone();
101 self.bind_expression_plan(&mut plan, schema)?;
102 let sites = super::syntax_sites::expression_syntax_sites(&lowered, &plan)?;
103 let mut next = expression.clone();
104 crate::catalog::stored_ast::bind_stored_expression_sites(&mut next, &sites)?;
105 let mut changed = false;
106 crate::catalog::stored_ast::visit_stored_expression(&mut next, &mut |node| {
107 changed |= self.syntax_node(node);
108 Ok(())
109 })?;
110 if changed {
111 *expression = next;
112 }
113 Ok(changed)
114 }
115
116 fn bind_expression_plan(
117 &self,
118 plan: &mut ExpressionPlan,
119 schema: &RowSchema,
120 ) -> Result<(), SQLError> {
121 let mut scope = self.scope()?;
122 scope.stored_expression_outer = Some(schema.clone());
123 for query in &mut plan.subqueries {
124 scope.bind_query_routines_for_storage(self.routines, query, &[], Some(schema))?;
125 }
126 scope.bind_scalar_routines_for_storage(
127 self.routines,
128 &mut plan.scalar,
129 schema,
130 &plan.subqueries,
131 &[],
132 )
133 }
134
135 pub fn expression_plan(
136 &self,
137 plan: &mut ExpressionPlan,
138 schema: &RowSchema,
139 ) -> Result<bool, SQLError> {
140 let mut next = plan.clone();
141 self.bind_expression_plan(&mut next, schema)?;
142 let mut changed = false;
143 crate::plan::rewrite_scalar_expression(&mut next.scalar, &mut |node| {
144 changed |= self.scalar_node(node);
145 });
146 for query in &mut next.subqueries {
147 query.rewrite_scalar_expressions(&mut |node| changed |= self.scalar_node(node));
148 }
149 if changed {
150 *plan = next;
151 }
152 Ok(changed)
153 }
154
155 pub fn query(&self, query: &mut QueryPlan) -> Result<bool, SQLError> {
156 let mut next = query.clone();
157 self.scope()?
158 .bind_query_routines_for_storage(self.routines, &mut next, &[], None)?;
159 let mut changed = false;
160 next.rewrite_scalar_expressions(&mut |node| changed |= self.scalar_node(node));
161 if changed {
162 *query = next;
163 }
164 Ok(changed)
165 }
166
167 pub fn statement(
168 &self,
169 statement: &mut Statement,
170 definition: Option<&CreateFunction>,
171 outer: Option<&RowSchema>,
172 ) -> Result<bool, SQLError> {
173 let mut plan = UnifiedPlan::lower_with(statement.clone(), &|name: &str| {
174 self.routines.has_registered_aggregate_function(name)
175 });
176 super::stored_routines::mark_catalog_statement_relations_bound(&mut plan)?;
177 let params = if let Some(definition) = definition {
178 let params = self.routine_params(definition)?;
179 let scope =
180 crate::routines::body_parameters::sql_body_parameter_scope(definition, ¶ms)?;
181 super::bind_routine_parameter_references(
182 self.routines,
183 &mut plan,
184 ¶ms,
185 &self.binding,
186 &scope,
187 )?;
188 params
189 } else {
190 Vec::new()
191 };
192 let bound = super::stored_routines::bind_catalog_statement_composite_inputs(
193 &super::stored_routines::CatalogRoutineContext {
194 routines: self.routines,
195 binding: &self.binding,
196 },
197 &plan,
198 ¶ms,
199 outer,
200 )?;
201 let mut next = statement.clone();
202 crate::catalog::stored_ast::bind_stored_statement_sites(&mut next, &bound.sites)?;
203 let mut changed = false;
204 crate::catalog::stored_ast::visit_stored_statement_expressions(&mut next, &mut |node| {
205 changed |= self.syntax_node(node);
206 Ok(())
207 })?;
208 if changed {
209 *statement = next;
210 }
211 Ok(changed)
212 }
213
214 pub fn bound_plan(&self, plan: &mut UnifiedPlan) -> bool {
215 let mut changed = false;
216 plan.rewrite_scalar_expressions(&mut |node| changed |= self.scalar_node(node));
217 changed
218 }
219
220 pub fn bind_routine_plan(
221 &self,
222 plan: &mut UnifiedPlan,
223 definition: &CreateFunction,
224 ) -> Result<(), SQLError> {
225 let params = self.routine_params(definition)?;
226 let parameters =
227 crate::routines::body_parameters::sql_body_parameter_scope(definition, ¶ms)?;
228 let mut scope = self.scope()?;
229 scope.routine_parameters = Some(parameters.clone());
230 scope.bind_statement_parameters(self.routines, plan, ¶ms, Some(parameters.schema()))
231 }
232
233 fn routine_params(&self, definition: &CreateFunction) -> Result<Vec<SQLParam>, SQLError> {
234 crate::routines::body_parameters::sql_body_parameters(definition)
235 .into_iter()
236 .map(|parameter| {
237 self.routines
238 .resolve_type_name(¶meter.type_name)
239 .map(|ty| {
240 ty.map_or_else(
241 || SQLParam::scalar(Value::Null),
242 |ty| SQLParam::typed_scalar(Value::Null, ty),
243 )
244 })
245 })
246 .collect()
247 }
248}