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