1use super::model::NoRegisteredAggregates;
10use super::query::{lower_assignments, lower_ctes, lower_merge_when};
11use super::rewrite::{rewrite_command_scalars, rewrite_query_scalars};
12use super::scalar::lower_scalar_expression;
13use super::{
14 AggregateClassifier, CommandPlan, ConflictActionPlan, ConflictPlan, DeletePlan, ExpressionPlan,
15 InsertPlan, MergePlan, ProjectionPlan, QueryPlan, RelationalPlan, ScalarExpr, SourcePlan,
16 Statement, UnifiedPlan, UpdatePlan,
17};
18
19impl UnifiedPlan {
20 #[must_use]
22 pub fn lower(statement: Statement) -> Self {
23 Self::lower_with(statement, &NoRegisteredAggregates)
24 }
25
26 #[must_use]
28 #[expect(
29 clippy::too_many_lines,
30 reason = "plan lowering preserves exhaustive variants and structural identities"
31 )]
32 pub fn lower_with(statement: Statement, aggregates: &dyn AggregateClassifier) -> Self {
33 match statement {
34 Statement::Select(query) => {
35 Self::Query(Box::new(QueryPlan::lower_with(*query, aggregates)))
36 }
37 Statement::Values { rows } => {
38 let mut subqueries = Vec::new();
39 let rows = rows
40 .into_iter()
41 .map(|row| {
42 row.into_iter()
43 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries))
44 .collect()
45 })
46 .collect();
47 Self::Query(Box::new(QueryPlan {
48 relations_bound: false,
49 ctes: Vec::new(),
50 root: RelationalPlan::Values { rows, subqueries },
51 }))
52 }
53 Statement::CreateTable(value) => {
54 Self::Command(Box::new(CommandPlan::CreateTable(Box::new(value))))
55 }
56 Statement::CreateTableIfNotExists(value) => {
57 Self::Command(Box::new(CommandPlan::CreateTableIfNotExists(value)))
58 }
59 Statement::CreateIndex(value) => {
60 Self::Command(Box::new(CommandPlan::CreateIndex(value)))
61 }
62 Statement::Insert(statement) => {
63 let ctes = lower_ctes(&statement.with, aggregates);
64 let source = statement
65 .select_source
66 .map(|query| Box::new(QueryPlan::lower_with(*query, aggregates)));
67 let mut subqueries = Vec::new();
68 let rows = statement
69 .rows
70 .into_iter()
71 .map(|row| {
72 row.into_iter()
73 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries))
74 .collect()
75 })
76 .collect();
77 let on_conflict = statement.on_conflict.map(|conflict| {
78 let action = match conflict.action {
79 crate::ast::OnConflictAction::Nothing => ConflictActionPlan::Nothing,
80 crate::ast::OnConflictAction::Update {
81 assignments,
82 r#where,
83 } => ConflictActionPlan::Update {
84 assignments: lower_assignments(
85 assignments,
86 aggregates,
87 &mut subqueries,
88 ),
89 predicate: r#where.map(|expr| {
90 Box::new(lower_scalar_expression(
91 *expr,
92 aggregates,
93 &mut subqueries,
94 ))
95 }),
96 },
97 };
98 ConflictPlan {
99 predicate: conflict.predicate.map(|expr| {
100 Box::new(lower_scalar_expression(*expr, aggregates, &mut subqueries))
101 }),
102 constraint: conflict.constraint,
103 conflict_columns: conflict.conflict_columns,
104 expressions: conflict
105 .expressions
106 .into_iter()
107 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries))
108 .collect(),
109 action,
110 }
111 });
112 let returning = statement
113 .returning
114 .into_iter()
115 .map(|projection| {
116 ProjectionPlan::lower_with(projection, aggregates, &mut subqueries)
117 })
118 .collect();
119 Self::Command(Box::new(CommandPlan::Insert(Box::new(InsertPlan {
120 table: statement.table,
121 target_relation_bound: statement.target_relation_bound,
122 relations_bound: false,
123 statement_privilege_subject: None,
124 target_privilege_subject: None,
125 target_qualifier: statement.target_qualifier,
126 include_descendants: statement.include_descendants,
127 columns: statement.columns,
128 ctes,
129 rows,
130 source,
131 on_conflict,
132 returning,
133 returning_aliases: statement.returning_aliases,
134 subqueries,
135 view_checks: Vec::new(),
136 view_rule_relations: Vec::new(),
137 view_rule_insert_plans: Vec::new(),
138 view_rule_returning: None,
139 }))))
140 }
141 Statement::Update(statement) => {
142 let ctes = lower_ctes(&statement.with, aggregates);
143 let mut subqueries = Vec::new();
144 let source = statement
145 .from
146 .map(|from| SourcePlan::lower_with(from, aggregates, &mut subqueries));
147 let assignments =
148 lower_assignments(statement.assignments, aggregates, &mut subqueries);
149 let predicate = statement
150 .r#where
151 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries));
152 let returning = statement
153 .returning
154 .into_iter()
155 .map(|projection| {
156 ProjectionPlan::lower_with(projection, aggregates, &mut subqueries)
157 })
158 .collect();
159 Self::Command(Box::new(CommandPlan::Update(Box::new(UpdatePlan {
160 table: statement.table,
161 target_relation_bound: statement.target_relation_bound,
162 relations_bound: false,
163 statement_privilege_subject: None,
164 target_privilege_subject: None,
165 target_qualifier: statement.target_qualifier,
166 include_descendants: statement.include_descendants,
167 assignments,
168 predicate,
169 ctes,
170 source: source.map(Box::new),
171 returning,
172 returning_aliases: statement.returning_aliases,
173 subqueries,
174 view_checks: Vec::new(),
175 view_rule_relations: Vec::new(),
176 view_rule_update_plans: Vec::new(),
177 view_rule_returning: None,
178 }))))
179 }
180 Statement::Delete(statement) => {
181 let ctes = lower_ctes(&statement.with, aggregates);
182 let mut subqueries = Vec::new();
183 let source = statement
184 .using
185 .map(|from| SourcePlan::lower_with(from, aggregates, &mut subqueries));
186 let predicate = statement
187 .r#where
188 .map(|expr| lower_scalar_expression(expr, aggregates, &mut subqueries));
189 let returning = statement
190 .returning
191 .into_iter()
192 .map(|projection| {
193 ProjectionPlan::lower_with(projection, aggregates, &mut subqueries)
194 })
195 .collect();
196 Self::Command(Box::new(CommandPlan::Delete(Box::new(DeletePlan {
197 table: statement.table,
198 target_relation_bound: statement.target_relation_bound,
199 relations_bound: false,
200 statement_privilege_subject: None,
201 target_privilege_subject: None,
202 target_qualifier: statement.target_qualifier,
203 include_descendants: statement.include_descendants,
204 predicate,
205 ctes,
206 source: source.map(Box::new),
207 returning,
208 returning_aliases: statement.returning_aliases,
209 subqueries,
210 view_rule_relations: Vec::new(),
211 view_rule_returning: None,
212 }))))
213 }
214 Statement::Drop(value) => Self::Command(Box::new(CommandPlan::Drop(value))),
215 Statement::AlterTable(value) => {
216 Self::Command(Box::new(CommandPlan::AlterTable(Box::new(value))))
217 }
218 Statement::AlterForeignTable(value) => {
219 Self::Command(Box::new(CommandPlan::AlterForeignTable(value)))
220 }
221 Statement::AlterView(value) => Self::Command(Box::new(CommandPlan::AlterView(value))),
222 Statement::CreateView {
223 name,
224 column_names,
225 body,
226 or_replace,
227 persistence,
228 options,
229 } => {
230 let query = Box::new(QueryPlan::lower_with(*body, aggregates));
231 Self::Command(Box::new(CommandPlan::CreateView {
232 name,
233 column_names,
234 query,
235 or_replace,
236 persistence,
237 options,
238 }))
239 }
240 Statement::CreateMaterializedView {
241 name,
242 column_names,
243 if_not_exists,
244 with_no_data,
245 options,
246 body,
247 } => Self::Command(Box::new(CommandPlan::CreateMaterializedView {
248 name,
249 column_names,
250 if_not_exists,
251 with_no_data,
252 options,
253 query: Box::new(QueryPlan::lower_with(*body, aggregates)),
254 })),
255 Statement::RefreshMaterializedView {
256 name,
257 concurrently,
258 with_no_data,
259 } => Self::Command(Box::new(CommandPlan::RefreshMaterializedView {
260 name,
261 concurrently,
262 with_no_data,
263 })),
264 Statement::CreateSchema {
265 name,
266 if_not_exists,
267 authorization,
268 } => Self::Command(Box::new(CommandPlan::CreateSchema {
269 name,
270 if_not_exists,
271 authorization,
272 })),
273 Statement::AlterSchemaOwner { name, new_owner } => {
274 Self::Command(Box::new(CommandPlan::AlterSchemaOwner { name, new_owner }))
275 }
276 Statement::Notify { channel, payload } => {
277 Self::Command(Box::new(CommandPlan::Notify { channel, payload }))
278 }
279 Statement::Listen { channel } => {
280 Self::Command(Box::new(CommandPlan::Listen { channel }))
281 }
282 Statement::Unlisten { channel } => {
283 Self::Command(Box::new(CommandPlan::Unlisten { channel }))
284 }
285 Statement::SetVariable {
286 name,
287 value,
288 local,
289 is_default,
290 } => Self::Command(Box::new(CommandPlan::SetVariable {
291 name,
292 value,
293 local,
294 is_default,
295 })),
296 Statement::ResetVariable { name } => {
297 Self::Command(Box::new(CommandPlan::ResetVariable { name }))
298 }
299 Statement::ResetAllVariables => Self::Command(Box::new(CommandPlan::ResetAllVariables)),
300 Statement::SetConstraints {
301 constraints,
302 deferred,
303 } => Self::Command(Box::new(CommandPlan::SetConstraints {
304 constraints,
305 deferred,
306 })),
307 Statement::ShowVariable { name } => {
308 Self::Command(Box::new(CommandPlan::ShowVariable { name }))
309 }
310 Statement::Discard { target } => {
311 Self::Command(Box::new(CommandPlan::Discard { target }))
312 }
313 Statement::Load { library } => Self::Command(Box::new(CommandPlan::Load { library })),
314 Statement::Explain {
315 analyze,
316 verbose,
317 format,
318 body,
319 } => Self::Command(Box::new(CommandPlan::Explain {
320 analyze,
321 verbose,
322 format,
323 body: Box::new(Self::lower_with(*body, aggregates)),
324 })),
325 Statement::Analyze { table } => Self::Command(Box::new(CommandPlan::Analyze { table })),
326 Statement::Vacuum(vacuum) => Self::Command(Box::new(CommandPlan::Vacuum(vacuum))),
327 Statement::Truncate {
328 tables,
329 cascade,
330 restart_identity,
331 } => Self::Command(Box::new(CommandPlan::Truncate {
332 tables,
333 cascade,
334 restart_identity,
335 })),
336 Statement::Transaction(value) => {
337 Self::Command(Box::new(CommandPlan::Transaction(value)))
338 }
339 Statement::DeclareCursor(cursor) => {
340 Self::Command(Box::new(CommandPlan::DeclareCursor {
341 name: cursor.name,
342 binary: cursor.binary,
343 scroll: cursor.scroll,
344 hold: cursor.hold,
345 query: Box::new(QueryPlan::lower_with(*cursor.query, aggregates)),
346 }))
347 }
348 Statement::FetchCursor(cursor) => {
349 Self::Command(Box::new(CommandPlan::FetchCursor(cursor)))
350 }
351 Statement::CloseCursor { name } => {
352 Self::Command(Box::new(CommandPlan::CloseCursor { name }))
353 }
354 Statement::CreateSequence(value) => {
355 Self::Command(Box::new(CommandPlan::CreateSequence(value)))
356 }
357 Statement::CreateDomain(value) => {
358 Self::Command(Box::new(CommandPlan::CreateDomain(value)))
359 }
360 Statement::AlterSequence(value) => {
361 Self::Command(Box::new(CommandPlan::AlterSequence(value)))
362 }
363 Statement::CreateTableAs {
364 name,
365 if_not_exists,
366 column_names,
367 with_no_data,
368 persistence,
369 on_commit,
370 body,
371 } => Self::Command(Box::new(CommandPlan::CreateTableAs {
372 name,
373 if_not_exists,
374 column_names,
375 with_no_data,
376 persistence,
377 on_commit,
378 query: Box::new(QueryPlan::lower_with(*body, aggregates)),
379 })),
380 Statement::Prepare {
381 name,
382 parameter_types,
383 body,
384 } => {
385 let body = Box::new(Self::lower_with(*body, aggregates));
386 Self::Command(Box::new(CommandPlan::Prepare {
387 name,
388 parameter_types,
389 body,
390 }))
391 }
392 Statement::Execute { name, params } => Self::Command(Box::new(CommandPlan::Execute {
393 name,
394 params: params
395 .into_iter()
396 .map(|expr| ExpressionPlan::lower_with(expr, aggregates))
397 .collect(),
398 })),
399 Statement::Deallocate { name } => {
400 Self::Command(Box::new(CommandPlan::Deallocate { name }))
401 }
402 Statement::CreateForeignServer(value) => {
403 Self::Command(Box::new(CommandPlan::CreateForeignServer(value)))
404 }
405 Statement::CreateForeignTable(value) => {
406 Self::Command(Box::new(CommandPlan::CreateForeignTable(value)))
407 }
408 Statement::CreateForeignTableIfNotExists(value) => {
409 Self::Command(Box::new(CommandPlan::CreateForeignTableIfNotExists(value)))
410 }
411 Statement::Merge(statement) => {
412 let mut subqueries = Vec::new();
413 let source = SourcePlan::lower_with(statement.source, aggregates, &mut subqueries);
414 let join_condition =
415 lower_scalar_expression(statement.join_condition, aggregates, &mut subqueries);
416 let when_clauses = statement
417 .when_clauses
418 .into_iter()
419 .map(|clause| lower_merge_when(clause, aggregates, &mut subqueries))
420 .collect();
421 let returning = statement
422 .returning
423 .into_iter()
424 .map(|projection| {
425 ProjectionPlan::lower_with(projection, aggregates, &mut subqueries)
426 })
427 .collect();
428 Self::Command(Box::new(CommandPlan::Merge(Box::new(MergePlan {
429 ctes: lower_ctes(&statement.with, aggregates),
430 target: statement.target,
431 statement_privilege_subject: None,
432 target_privilege_subject: None,
433 target_qualifier: statement.target_qualifier,
434 target_alias: statement.target_alias,
435 include_descendants: statement.include_descendants,
436 target_predicate: None,
437 source: Box::new(source),
438 join_condition,
439 when_clauses,
440 returning,
441 returning_aliases: statement.returning_aliases,
442 subqueries,
443 view_checks: Vec::new(),
444 }))))
445 }
446 Statement::CreateFunction(value) => {
447 Self::Command(Box::new(CommandPlan::CreateFunction(value)))
448 }
449 Statement::DropFunction(value) => {
450 Self::Command(Box::new(CommandPlan::DropFunction(value)))
451 }
452 Statement::AlterRoutine(value) => {
453 Self::Command(Box::new(CommandPlan::AlterRoutine(value)))
454 }
455 Statement::AlterRoutineOwner(value) => {
456 Self::Command(Box::new(CommandPlan::AlterRoutineOwner(value)))
457 }
458 Statement::RenameRoutine(value) => {
459 Self::Command(Box::new(CommandPlan::RenameRoutine(value)))
460 }
461 Statement::GrantRoutine(value) => {
462 Self::Command(Box::new(CommandPlan::GrantRoutine(value)))
463 }
464 Statement::GrantTable(value) => Self::Command(Box::new(CommandPlan::GrantTable(value))),
465 Statement::GrantSequence(value) => {
466 Self::Command(Box::new(CommandPlan::GrantSequence(value)))
467 }
468 Statement::GrantDatabase(value) => {
469 Self::Command(Box::new(CommandPlan::GrantDatabase(value)))
470 }
471 Statement::GrantSchema(value) => {
472 Self::Command(Box::new(CommandPlan::GrantSchema(value)))
473 }
474 Statement::GrantRole(value) => Self::Command(Box::new(CommandPlan::GrantRole(value))),
475 Statement::CreateRole(value) => Self::Command(Box::new(CommandPlan::CreateRole(value))),
476 Statement::AlterRole(value) => Self::Command(Box::new(CommandPlan::AlterRole(value))),
477 Statement::DropRole(value) => Self::Command(Box::new(CommandPlan::DropRole(value))),
478 Statement::CreateTrigger(value) => {
479 Self::Command(Box::new(CommandPlan::CreateTrigger(value)))
480 }
481 Statement::DropTrigger(value) => {
482 Self::Command(Box::new(CommandPlan::DropTrigger(value)))
483 }
484 Statement::CreateRule(value) => Self::Command(Box::new(CommandPlan::CreateRule(value))),
485 Statement::DropRule(value) => Self::Command(Box::new(CommandPlan::DropRule(value))),
486 Statement::DoBlock { language, body } => {
487 Self::Command(Box::new(CommandPlan::DoBlock { language, body }))
488 }
489 Statement::Call { name, args } => Self::Command(Box::new(CommandPlan::Call {
490 name,
491 args: args
492 .into_iter()
493 .map(|expr| ExpressionPlan::lower_with(expr, aggregates))
494 .collect(),
495 })),
496 }
497 }
498
499 #[must_use]
500 pub fn name(&self) -> &'static str {
501 match self {
502 Self::Query(_) => "Query",
503 Self::Command(command) => command.name(),
504 }
505 }
506
507 pub fn rewrite_scalar_expressions(&mut self, rewrite: &mut dyn FnMut(&mut ScalarExpr)) {
513 match self {
514 Self::Query(query) => rewrite_query_scalars(query, rewrite),
515 Self::Command(command) => rewrite_command_scalars(command, rewrite),
516 }
517 }
518}
519
520impl CommandPlan {
521 #[must_use]
522 pub fn name(&self) -> &'static str {
523 match self {
524 Self::CreateTable(_) => "CreateTable",
525 Self::CreateTableIfNotExists(_) => "CreateTableIfNotExists",
526 Self::CreateIndex(_) => "CreateIndex",
527 Self::Insert(_) => "Insert",
528 Self::Update(_) => "Update",
529 Self::Delete(_) => "Delete",
530 Self::Drop(_) => "Drop",
531 Self::AlterTable(_) => "AlterTable",
532 Self::AlterView(_) => "AlterView",
533 Self::CreateView { .. } => "CreateView",
534 Self::CreateMaterializedView { .. } => "CreateMaterializedView",
535 Self::RefreshMaterializedView { .. } => "RefreshMaterializedView",
536 Self::CreateSchema { .. } => "CreateSchema",
537 Self::AlterSchemaOwner { .. } => "AlterSchemaOwner",
538 Self::Notify { .. } => "Notify",
539 Self::Listen { .. } => "Listen",
540 Self::Unlisten { .. } => "Unlisten",
541 Self::SetVariable { .. } => "SetVariable",
542 Self::ResetVariable { .. } => "ResetVariable",
543 Self::ResetAllVariables => "ResetAllVariables",
544 Self::SetConstraints { .. } => "SetConstraints",
545 Self::ShowVariable { .. } => "ShowVariable",
546 Self::Discard { .. } => "Discard",
547 Self::Load { .. } => "Load",
548 Self::Explain { .. } => "Explain",
549 Self::Analyze { .. } => "Analyze",
550 Self::Vacuum(_) => "Vacuum",
551 Self::Truncate { .. } => "Truncate",
552 Self::Transaction(_) => "Transaction",
553 Self::DeclareCursor { .. } => "DeclareCursor",
554 Self::FetchCursor(_) => "FetchCursor",
555 Self::CloseCursor { .. } => "CloseCursor",
556 Self::CreateSequence(_) => "CreateSequence",
557 Self::CreateDomain(_) => "CreateDomain",
558 Self::AlterSequence(_) => "AlterSequence",
559 Self::CreateTableAs { .. } => "CreateTableAs",
560 Self::Prepare { .. } => "Prepare",
561 Self::Execute { .. } => "Execute",
562 Self::Deallocate { .. } => "Deallocate",
563 Self::CreateForeignServer(_) => "CreateForeignServer",
564 Self::CreateForeignTable(_) => "CreateForeignTable",
565 Self::CreateForeignTableIfNotExists(_) => "CreateForeignTableIfNotExists",
566 Self::AlterForeignTable(_) => "AlterForeignTable",
567 Self::Merge(_) => "Merge",
568 Self::CreateFunction(_) => "CreateFunction",
569 Self::DropFunction(_) => "DropFunction",
570 Self::AlterRoutine(_) => "AlterRoutine",
571 Self::AlterRoutineOwner(_) => "AlterRoutineOwner",
572 Self::RenameRoutine(_) => "RenameRoutine",
573 Self::GrantRoutine(_) => "GrantRoutine",
574 Self::GrantTable(_) => "GrantTable",
575 Self::GrantSequence(_) => "GrantSequence",
576 Self::GrantDatabase(_) => "GrantDatabase",
577 Self::GrantSchema(_) => "GrantSchema",
578 Self::GrantRole(_) => "GrantRole",
579 Self::CreateRole(_) => "CreateRole",
580 Self::AlterRole(_) => "AlterRole",
581 Self::DropRole(_) => "DropRole",
582 Self::CreateTrigger(_) => "CreateTrigger",
583 Self::DropTrigger(_) => "DropTrigger",
584 Self::CreateRule(_) => "CreateRule",
585 Self::DropRule(_) => "DropRule",
586 Self::DoBlock { .. } => "DoBlock",
587 Self::Call { .. } => "Call",
588 }
589 }
590}