1use super::{
8 active_unconditional_instead_rule, add_check_option, automatic_view_layer,
9 duplicate_assignment, insert_conflict_subquery_ids, insert_input_width,
10 instead_of_trigger_definition, not_automatically_updatable, preserve_view_rule_returning,
11 record_view_rule_relation, returning_subquery_ids, rewrite_correlated_dml_context,
12 rewrite_existing_view_checks, rewrite_returning, rewrite_target_expression,
13 validate_direct_view_rule_path, validate_insert_expressions, validate_insert_targets,
14 validate_mapped_columns, validate_public_insert_contract, validate_public_view_targets,
15 view_updatability, writable_column, BTreeSet, ConflictActionPlan, CorrelatedDmlContext,
16 ExpressionScope, InsertPlan, SQLError, TriggerEvent, ViewRewriteContext, ViewRuleInsertPlan,
17};
18
19#[expect(
20 clippy::too_many_lines,
21 reason = "preserves view qualifier and row identity"
22)]
23pub fn rewrite_insert_to_base(
24 services: ViewRewriteContext<'_>,
25 statement: &InsertPlan,
26 params: &[crate::SQLParam],
27 inherited_ctes: Option<&super::CteScope>,
28) -> Result<InsertPlan, SQLError> {
29 validate_public_view_targets(
30 services,
31 &statement.table,
32 statement
33 .columns
34 .iter()
35 .map(|target| target.column.as_str()),
36 )?;
37 validate_public_insert_contract(services, statement)?;
38 let Some(initial_layer) = automatic_view_layer(services, &statement.table)? else {
39 return Err(not_automatically_updatable(&statement.table, "INSERT"));
40 };
41 validate_insert_targets(&initial_layer, statement)?;
42 validate_direct_view_rule_path(
43 services,
44 &initial_layer.canonical_name,
45 crate::ast::RuleEvent::Insert,
46 "INSERT",
47 )?;
48 if !view_updatability(services, &statement.table)?
49 .automatic
50 .insertable
51 {
52 return Err(not_automatically_updatable(&statement.table, "INSERT"));
53 }
54 let mut plan = statement.clone();
55 let next_privilege_subject =
56 crate::semantics::view_privileges::ensure_insert(services.authorization, &plan)?;
57 plan.target_privilege_subject = Some(next_privilege_subject);
58 let mut implicit_width = if statement.columns.is_empty() {
59 Some(insert_input_width(
60 services,
61 statement,
62 params,
63 inherited_ctes,
64 )?)
65 } else {
66 None
67 };
68 let mut cascaded = false;
69 let mut visited = BTreeSet::new();
70 let mut rewrite_suppressed = false;
71 loop {
72 let Some(layer) = automatic_view_layer(services, &plan.table)? else {
73 if active_unconditional_instead_rule(
74 services,
75 &plan.table,
76 crate::ast::RuleEvent::Insert,
77 )? {
78 break;
79 }
80 return Err(not_automatically_updatable(&plan.table, "INSERT"));
81 };
82 if !visited.insert(layer.canonical_name.clone()) {
83 return Err(SQLError::Internal(format!(
84 "cycle while rewriting automatically updatable view `{}`",
85 layer.canonical_name
86 )));
87 }
88 if !rewrite_suppressed {
89 validate_direct_view_rule_path(
90 services,
91 &layer.canonical_name,
92 crate::ast::RuleEvent::Insert,
93 "INSERT",
94 )?;
95 }
96 if !rewrite_suppressed
97 && visited.len() > 1
98 && instead_of_trigger_definition(services, &layer.canonical_name, TriggerEvent::Insert)?
99 {
100 return Err(not_automatically_updatable(&layer.canonical_name, "INSERT"));
101 }
102 let has_view_rules = if rewrite_suppressed {
103 false
104 } else {
105 record_view_rule_relation(
106 services,
107 &mut plan.view_rule_relations,
108 &layer,
109 crate::ast::RuleEvent::Insert,
110 )?
111 };
112 let layer_suppresses = has_view_rules
113 && super::context::relation_suppresses_original_query(
114 services,
115 &layer.canonical_name,
116 crate::ast::RuleEvent::Insert,
117 )?;
118 if visited.len() > 1 && !rewrite_suppressed && !layer_suppresses {
119 let next_privilege_subject =
120 crate::semantics::view_privileges::ensure_insert(services.authorization, &plan)?;
121 plan.target_privilege_subject = Some(next_privilege_subject);
122 }
123 if has_view_rules
124 && super::context::relation_has_returning_provider(
125 services,
126 &layer.canonical_name,
127 crate::ast::RuleEvent::Insert,
128 )?
129 {
130 preserve_view_rule_returning(
131 &mut plan.view_rule_returning,
132 &layer.canonical_name,
133 &plan.target_qualifier,
134 &plan.returning,
135 &plan.returning_aliases,
136 &plan.subqueries,
137 );
138 }
139 let target_qualifier = plan.target_qualifier.clone();
140 if visited.len() == 1 {
141 validate_insert_expressions(services, &plan, &layer, params, inherited_ctes)?;
142 }
143 let conflict_subquery_ids = insert_conflict_subquery_ids(&plan);
144 rewrite_correlated_dml_context(
145 CorrelatedDmlContext {
146 inherited_ctes,
147 services,
148 layer: &layer,
149 target_qualifier: &plan.target_qualifier,
150 source: None,
151 returning_aliases: None,
152 include_excluded: true,
153 ctes: &plan.ctes,
154 ids: &conflict_subquery_ids,
155 params,
156 },
157 &mut plan.subqueries,
158 )?;
159 let returning_subquery_ids = returning_subquery_ids(&plan.returning);
160 rewrite_correlated_dml_context(
161 CorrelatedDmlContext {
162 inherited_ctes,
163 services,
164 layer: &layer,
165 target_qualifier: &plan.target_qualifier,
166 source: None,
167 returning_aliases: Some(&plan.returning_aliases),
168 include_excluded: false,
169 ctes: &plan.ctes,
170 ids: &returning_subquery_ids,
171 params,
172 },
173 &mut plan.subqueries,
174 )?;
175 let supplied_columns = if let Some(width) = implicit_width.take() {
176 layer
177 .columns
178 .iter()
179 .take(width)
180 .map(|column| column.name.clone().into())
181 .collect::<Vec<_>>()
182 } else {
183 plan.columns.clone()
184 };
185 let columns = if rewrite_suppressed || layer_suppresses {
186 supplied_columns.clone()
187 } else {
188 supplied_columns
189 .clone()
190 .into_iter()
191 .map(|mut target| {
192 target.column = writable_column(&layer, &target.column, "INSERT")?;
193 Ok::<_, SQLError>(target)
194 })
195 .collect::<Result<Vec<_>, _>>()?
196 };
197 if has_view_rules {
198 plan.view_rule_insert_plans.push(ViewRuleInsertPlan {
199 relation: layer.canonical_name.clone(),
200 supplied_columns: supplied_columns
201 .into_iter()
202 .map(|target| target.column)
203 .collect(),
204 input_columns: Vec::new(),
205 });
206 }
207 validate_mapped_columns(&columns, duplicate_assignment)?;
208 if let Some(conflict) = &mut plan.on_conflict {
209 for predicate in conflict
210 .expressions
211 .iter_mut()
212 .chain(conflict.predicate.iter_mut().map(Box::as_mut))
213 {
214 rewrite_target_expression(
215 services,
216 predicate,
217 &layer,
218 ExpressionScope {
219 target_qualifier: &target_qualifier,
220 returning_aliases: None,
221 source: None,
222 include_excluded: false,
223 },
224 &mut plan.subqueries,
225 )?;
226 }
227 conflict.conflict_columns = conflict
228 .conflict_columns
229 .iter()
230 .map(|column| writable_column(&layer, column, "INSERT"))
231 .collect::<Result<Vec<_>, _>>()?;
232 if let ConflictActionPlan::Update {
233 assignments,
234 predicate,
235 } = &mut conflict.action
236 {
237 let scope = ExpressionScope {
238 target_qualifier: &target_qualifier,
239 returning_aliases: None,
240 source: None,
241 include_excluded: true,
242 };
243 for assignment in assignments.iter_mut() {
244 assignment.target.column =
245 writable_column(&layer, &assignment.target.column, "UPDATE")?;
246 for expression in assignment.expressions_mut() {
247 rewrite_target_expression(
248 services,
249 expression,
250 &layer,
251 scope,
252 &mut plan.subqueries,
253 )?;
254 }
255 }
256 let mapped = assignments
257 .iter()
258 .map(|assignment| assignment.target.clone())
259 .collect::<Vec<_>>();
260 validate_mapped_columns(&mapped, duplicate_assignment)?;
261 if let Some(predicate) = predicate {
262 rewrite_target_expression(
263 services,
264 predicate,
265 &layer,
266 scope,
267 &mut plan.subqueries,
268 )?;
269 }
270 }
271 }
272 rewrite_existing_view_checks(
273 services,
274 &mut plan.view_checks,
275 &layer,
276 &target_qualifier,
277 &mut plan.subqueries,
278 )?;
279 let (returning, _) = rewrite_returning(
280 services,
281 plan.returning,
282 &layer,
283 &target_qualifier,
284 &plan.returning_aliases,
285 None,
286 &mut plan.subqueries,
287 )?;
288 plan.returning = returning;
289 add_check_option(
290 services,
291 &mut plan.view_checks,
292 &layer,
293 &target_qualifier,
294 &mut cascaded,
295 &mut plan.subqueries,
296 )?;
297 plan.columns = columns;
298 plan.table = layer.source_name;
299 plan.include_descendants = true;
300 rewrite_suppressed |= layer_suppresses;
301 if !super::context::target_is_view(services, &plan.table)? {
302 break;
303 }
304 }
305 for insert_plan in &mut plan.view_rule_insert_plans {
306 insert_plan.input_columns = plan
307 .columns
308 .iter()
309 .map(|target| target.column.clone())
310 .collect();
311 }
312 Ok(plan)
313}