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