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