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