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