1use super::{
10 AssignmentPlan, CommandPlan, ConflictActionPlan, MergeWhenPlan, OrderPlan, ProjectionPlan,
11 QueryPlan, RelationalPlan, ScalarExpr, ScalarFrameBound, SourcePlan,
12};
13
14pub(super) fn rewrite_query_scalars(
15 query: &mut QueryPlan,
16 rewrite: &mut dyn FnMut(&mut ScalarExpr),
17) {
18 for cte in &mut query.ctes {
19 match &mut cte.body {
20 super::CtePlanBody::Query(query) => rewrite_query_scalars(query, rewrite),
21 super::CtePlanBody::Command(command) => rewrite_command_scalars(command, rewrite),
22 }
23 }
24 match &mut query.root {
25 RelationalPlan::QueryBlock(block) => {
26 if let Some(source) = &mut block.from {
27 rewrite_source_scalars(source, rewrite);
28 }
29 rewrite_optional_scalar(&mut block.r#where, rewrite);
30 for projection in &mut block.projections {
31 rewrite_scalar(&mut projection.expr, rewrite);
32 }
33 for expression in &mut block.group_by {
34 rewrite_scalar(expression, rewrite);
35 }
36 for set in &mut block.grouping_sets {
37 for expression in set {
38 rewrite_scalar(expression, rewrite);
39 }
40 }
41 rewrite_optional_scalar(&mut block.having, rewrite);
42 rewrite_orders(&mut block.order_by, rewrite);
43 rewrite_optional_scalar(&mut block.limit, rewrite);
44 rewrite_optional_scalar(&mut block.offset, rewrite);
45 for expression in &mut block.distinct_on {
46 rewrite_scalar(expression, rewrite);
47 }
48 for subquery in &mut block.subqueries {
49 rewrite_query_scalars(subquery, rewrite);
50 }
51 }
52 RelationalPlan::SetOp {
53 left,
54 right,
55 order_by,
56 limit,
57 offset,
58 subqueries,
59 ..
60 } => {
61 rewrite_query_scalars(left, rewrite);
62 rewrite_query_scalars(right, rewrite);
63 rewrite_orders(order_by, rewrite);
64 if let Some(limit) = limit {
65 rewrite_scalar(limit, rewrite);
66 }
67 if let Some(offset) = offset {
68 rewrite_scalar(offset, rewrite);
69 }
70 for subquery in subqueries {
71 rewrite_query_scalars(subquery, rewrite);
72 }
73 }
74 RelationalPlan::Values { rows, subqueries } => {
75 for row in rows {
76 for expression in row {
77 rewrite_scalar(expression, rewrite);
78 }
79 }
80 for subquery in subqueries {
81 rewrite_query_scalars(subquery, rewrite);
82 }
83 }
84 }
85}
86
87pub(super) fn rewrite_source_scalars(
88 source: &mut SourcePlan,
89 rewrite: &mut dyn FnMut(&mut ScalarExpr),
90) {
91 match source {
92 SourcePlan::Table { .. } => {}
93 SourcePlan::Join {
94 left, right, on, ..
95 } => {
96 rewrite_source_scalars(left, rewrite);
97 rewrite_source_scalars(right, rewrite);
98 rewrite_optional_scalar(on, rewrite);
99 }
100 SourcePlan::Values { rows, .. } => {
101 for row in rows {
102 for expression in row {
103 rewrite_scalar(expression, rewrite);
104 }
105 }
106 }
107 SourcePlan::Function { args, .. } => {
108 for expression in args {
109 rewrite_scalar(expression, rewrite);
110 }
111 }
112 SourcePlan::FunctionGroup { functions, .. } => {
113 for function in functions {
114 for expression in &mut function.args {
115 rewrite_scalar(expression, rewrite);
116 }
117 }
118 }
119 SourcePlan::Subquery { body, .. } => rewrite_query_scalars(body, rewrite),
120 }
121}
122
123#[expect(
124 clippy::too_many_lines,
125 reason = "optimizer rewrite preserves exhaustive variants and fixed-point order"
126)]
127pub(super) fn rewrite_command_scalars(
128 command: &mut CommandPlan,
129 rewrite: &mut dyn FnMut(&mut ScalarExpr),
130) {
131 match command {
132 CommandPlan::Insert(plan) => {
133 for expression in plan
134 .columns
135 .iter_mut()
136 .flat_map(crate::ast::AssignmentTarget::expressions_mut)
137 {
138 rewrite_scalar(expression, rewrite);
139 }
140 for cte in &mut plan.ctes {
141 match &mut cte.body {
142 super::CtePlanBody::Query(query) => rewrite_query_scalars(query, rewrite),
143 super::CtePlanBody::Command(command) => {
144 rewrite_command_scalars(command, rewrite);
145 }
146 }
147 }
148 for row in &mut plan.rows {
149 for expression in row {
150 rewrite_scalar(expression, rewrite);
151 }
152 }
153 if let Some(source) = &mut plan.source {
154 rewrite_query_scalars(source, rewrite);
155 }
156 if let Some(conflict) = &mut plan.on_conflict {
157 for expression in &mut conflict.expressions {
158 rewrite_scalar(expression, rewrite);
159 }
160 if let Some(predicate) = &mut conflict.predicate {
161 rewrite_scalar(predicate, rewrite);
162 }
163 if let ConflictActionPlan::Update {
164 assignments,
165 predicate,
166 } = &mut conflict.action
167 {
168 rewrite_assignments(assignments, rewrite);
169 if let Some(predicate) = predicate {
170 rewrite_scalar(predicate, rewrite);
171 }
172 }
173 }
174 rewrite_projections(&mut plan.returning, rewrite);
175 for check in &mut plan.view_checks {
176 rewrite_scalar(&mut check.predicate, rewrite);
177 }
178 rewrite_subqueries(&mut plan.subqueries, rewrite);
179 }
180 CommandPlan::Update(plan) => {
181 for cte in &mut plan.ctes {
182 match &mut cte.body {
183 super::CtePlanBody::Query(query) => rewrite_query_scalars(query, rewrite),
184 super::CtePlanBody::Command(command) => {
185 rewrite_command_scalars(command, rewrite);
186 }
187 }
188 }
189 if let Some(source) = &mut plan.source {
190 rewrite_source_scalars(source, rewrite);
191 }
192 rewrite_assignments(&mut plan.assignments, rewrite);
193 rewrite_optional_scalar(&mut plan.predicate, rewrite);
194 rewrite_projections(&mut plan.returning, rewrite);
195 for check in &mut plan.view_checks {
196 rewrite_scalar(&mut check.predicate, rewrite);
197 }
198 rewrite_subqueries(&mut plan.subqueries, rewrite);
199 }
200 CommandPlan::Delete(plan) => {
201 for cte in &mut plan.ctes {
202 match &mut cte.body {
203 super::CtePlanBody::Query(query) => rewrite_query_scalars(query, rewrite),
204 super::CtePlanBody::Command(command) => {
205 rewrite_command_scalars(command, rewrite);
206 }
207 }
208 }
209 if let Some(source) = &mut plan.source {
210 rewrite_source_scalars(source, rewrite);
211 }
212 rewrite_optional_scalar(&mut plan.predicate, rewrite);
213 rewrite_projections(&mut plan.returning, rewrite);
214 rewrite_subqueries(&mut plan.subqueries, rewrite);
215 }
216 CommandPlan::Merge(plan) => {
217 for cte in &mut plan.ctes {
218 match &mut cte.body {
219 super::CtePlanBody::Query(query) => rewrite_query_scalars(query, rewrite),
220 super::CtePlanBody::Command(command) => {
221 rewrite_command_scalars(command, rewrite);
222 }
223 }
224 }
225 rewrite_source_scalars(&mut plan.source, rewrite);
226 rewrite_optional_scalar(&mut plan.target_predicate, rewrite);
227 rewrite_scalar(&mut plan.join_condition, rewrite);
228 for clause in &mut plan.when_clauses {
229 match clause {
230 MergeWhenPlan::UpdateMatched {
231 condition,
232 assignments,
233 }
234 | MergeWhenPlan::UpdateNotMatchedBySource {
235 condition,
236 assignments,
237 } => {
238 rewrite_optional_scalar(condition, rewrite);
239 rewrite_assignments(assignments, rewrite);
240 }
241 MergeWhenPlan::DeleteMatched { condition }
242 | MergeWhenPlan::DeleteNotMatchedBySource { condition }
243 | MergeWhenPlan::NothingMatched { condition }
244 | MergeWhenPlan::NothingNotMatched { condition }
245 | MergeWhenPlan::NothingNotMatchedBySource { condition } => {
246 rewrite_optional_scalar(condition, rewrite);
247 }
248 MergeWhenPlan::InsertNotMatched {
249 condition,
250 columns,
251 values,
252 } => {
253 rewrite_optional_scalar(condition, rewrite);
254 for expression in columns
255 .iter_mut()
256 .flat_map(crate::ast::AssignmentTarget::expressions_mut)
257 {
258 rewrite_scalar(expression, rewrite);
259 }
260 for value in values {
261 rewrite_scalar(value, rewrite);
262 }
263 }
264 }
265 }
266 rewrite_projections(&mut plan.returning, rewrite);
267 for check in &mut plan.view_checks {
268 rewrite_scalar(&mut check.predicate, rewrite);
269 }
270 rewrite_subqueries(&mut plan.subqueries, rewrite);
271 }
272 CommandPlan::CreateView { query, .. }
273 | CommandPlan::CreateMaterializedView { query, .. }
274 | CommandPlan::CreateTableAs { query, .. }
275 | CommandPlan::DeclareCursor { query, .. } => {
276 rewrite_query_scalars(query, rewrite);
277 }
278 CommandPlan::Explain { body, .. } | CommandPlan::Prepare { body, .. } => {
279 body.rewrite_scalar_expressions(rewrite);
280 }
281 CommandPlan::Execute { params, .. } | CommandPlan::Call { args: params, .. } => {
282 for expression in params {
283 rewrite_scalar(&mut expression.scalar, rewrite);
284 rewrite_subqueries(&mut expression.subqueries, rewrite);
285 }
286 }
287 CommandPlan::CreateTable(_)
288 | CommandPlan::CreateTableIfNotExists(_)
289 | CommandPlan::CreateIndex(_)
290 | CommandPlan::RenameIndex(_)
291 | CommandPlan::Drop(_)
292 | CommandPlan::AlterTable(_)
293 | CommandPlan::AlterForeignTable(_)
294 | CommandPlan::AlterView(_)
295 | CommandPlan::RefreshMaterializedView { .. }
296 | CommandPlan::CreateSchema { .. }
297 | CommandPlan::AlterSchemaOwner { .. }
298 | CommandPlan::Notify { .. }
299 | CommandPlan::Listen { .. }
300 | CommandPlan::Unlisten { .. }
301 | CommandPlan::SetVariable { .. }
302 | CommandPlan::ResetVariable { .. }
303 | CommandPlan::ResetAllVariables
304 | CommandPlan::SetConstraints { .. }
305 | CommandPlan::ShowVariable { .. }
306 | CommandPlan::Discard { .. }
307 | CommandPlan::Load { .. }
308 | CommandPlan::Analyze { .. }
309 | CommandPlan::Vacuum(_)
310 | CommandPlan::LockTable(_)
311 | CommandPlan::Truncate { .. }
312 | CommandPlan::Transaction(_)
313 | CommandPlan::FetchCursor(_)
314 | CommandPlan::CloseCursor { .. }
315 | CommandPlan::CreateSequence(_)
316 | CommandPlan::CreateDomain(_)
317 | CommandPlan::AlterSequence(_)
318 | CommandPlan::Deallocate { .. }
319 | CommandPlan::CreateForeignServer(_)
320 | CommandPlan::CreateForeignTable(_)
321 | CommandPlan::CreateForeignTableIfNotExists(_)
322 | CommandPlan::CreateFunction(_)
323 | CommandPlan::DropFunction(_)
324 | CommandPlan::AlterRoutine(_)
325 | CommandPlan::AlterRoutineOwner(_)
326 | CommandPlan::RenameRoutine(_)
327 | CommandPlan::GrantRoutine(_)
328 | CommandPlan::GrantTable(_)
329 | CommandPlan::GrantSequence(_)
330 | CommandPlan::GrantDatabase(_)
331 | CommandPlan::GrantSchema(_)
332 | CommandPlan::GrantRole(_)
333 | CommandPlan::CreateRole(_)
334 | CommandPlan::AlterRole(_)
335 | CommandPlan::RenameRole(_)
336 | CommandPlan::DropRole(_)
337 | CommandPlan::CreateTrigger(_)
338 | CommandPlan::DropTrigger(_)
339 | CommandPlan::CreateRule(_)
340 | CommandPlan::DropRule(_)
341 | CommandPlan::DoBlock { .. } => {}
342 }
343}
344
345pub(super) fn rewrite_assignments(
346 assignments: &mut [AssignmentPlan],
347 rewrite: &mut dyn FnMut(&mut ScalarExpr),
348) {
349 for assignment in assignments {
350 for expression in assignment.expressions_mut() {
351 rewrite_scalar(expression, rewrite);
352 }
353 }
354}
355
356pub(super) fn rewrite_projections(
357 projections: &mut [ProjectionPlan],
358 rewrite: &mut dyn FnMut(&mut ScalarExpr),
359) {
360 for projection in projections {
361 rewrite_scalar(&mut projection.expr, rewrite);
362 }
363}
364
365pub(super) fn rewrite_orders(orders: &mut [OrderPlan], rewrite: &mut dyn FnMut(&mut ScalarExpr)) {
366 for order in orders {
367 rewrite_scalar(&mut order.expr, rewrite);
368 }
369}
370
371pub(super) fn rewrite_subqueries(
372 subqueries: &mut [QueryPlan],
373 rewrite: &mut dyn FnMut(&mut ScalarExpr),
374) {
375 for subquery in subqueries {
376 rewrite_query_scalars(subquery, rewrite);
377 }
378}
379
380pub(super) fn rewrite_optional_scalar(
381 expression: &mut Option<ScalarExpr>,
382 rewrite: &mut dyn FnMut(&mut ScalarExpr),
383) {
384 if let Some(expression) = expression {
385 rewrite_scalar(expression, rewrite);
386 }
387}
388
389pub(super) fn rewrite_scalar(
390 expression: &mut ScalarExpr,
391 rewrite: &mut dyn FnMut(&mut ScalarExpr),
392) {
393 match expression {
394 ScalarExpr::Func {
395 args,
396 order_by,
397 filter,
398 ..
399 } => {
400 for argument in args {
401 rewrite_scalar(argument, rewrite);
402 }
403 for order in order_by {
404 rewrite_scalar(&mut order.expr, rewrite);
405 }
406 if let Some(filter) = filter {
407 rewrite_scalar(filter, rewrite);
408 }
409 }
410 ScalarExpr::Array(items)
411 | ScalarExpr::Row(items)
412 | ScalarExpr::And(items)
413 | ScalarExpr::Or(items) => {
414 for item in items {
415 rewrite_scalar(item, rewrite);
416 }
417 }
418 ScalarExpr::Binary { lhs, rhs, .. } => {
419 rewrite_scalar(lhs, rewrite);
420 rewrite_scalar(rhs, rewrite);
421 }
422 ScalarExpr::UnaryMinus(inner)
423 | ScalarExpr::Not(inner)
424 | ScalarExpr::IsNull { expr: inner, .. }
425 | ScalarExpr::Cast { expr: inner, .. } => rewrite_scalar(inner, rewrite),
426 ScalarExpr::Between { expr, low, high } => {
427 rewrite_scalar(expr, rewrite);
428 rewrite_scalar(low, rewrite);
429 rewrite_scalar(high, rewrite);
430 }
431 ScalarExpr::InList { expr, list, .. } => {
432 rewrite_scalar(expr, rewrite);
433 for item in list {
434 rewrite_scalar(item, rewrite);
435 }
436 }
437 ScalarExpr::WindowCall { args, spec, .. } => {
438 for argument in args {
439 rewrite_scalar(argument, rewrite);
440 }
441 for expression in &mut spec.partition_by {
442 rewrite_scalar(expression, rewrite);
443 }
444 for order in &mut spec.order_by {
445 rewrite_scalar(&mut order.expr, rewrite);
446 }
447 if let Some(frame) = &mut spec.frame {
448 rewrite_frame_bound(&mut frame.start, rewrite);
449 rewrite_frame_bound(&mut frame.end, rewrite);
450 }
451 }
452 ScalarExpr::Case {
453 base,
454 when,
455 else_branch,
456 } => {
457 if let Some(base) = base {
458 rewrite_scalar(base, rewrite);
459 }
460 for (condition, result) in when {
461 rewrite_scalar(condition, rewrite);
462 rewrite_scalar(result, rewrite);
463 }
464 if let Some(branch) = else_branch {
465 rewrite_scalar(branch, rewrite);
466 }
467 }
468 ScalarExpr::InSubquery { expr, .. } => rewrite_scalar(expr, rewrite),
469 ScalarExpr::Default
470 | ScalarExpr::Star
471 | ScalarExpr::QualifiedStar(_)
472 | ScalarExpr::Column(_)
473 | ScalarExpr::Position(_)
474 | ScalarExpr::InternalColumn(_)
475 | ScalarExpr::QualifiedColumn { .. }
476 | ScalarExpr::Literal(_)
477 | ScalarExpr::TypedLiteral { .. }
478 | ScalarExpr::Param(_)
479 | ScalarExpr::ScalarSubquery(_)
480 | ScalarExpr::Exists { .. } => {}
481 }
482 rewrite(expression);
483}
484
485pub fn rewrite_scalar_expression(
490 expression: &mut ScalarExpr,
491 rewrite: &mut dyn FnMut(&mut ScalarExpr),
492) {
493 rewrite_scalar(expression, rewrite);
494}
495
496pub(super) fn rewrite_frame_bound(
497 bound: &mut ScalarFrameBound,
498 rewrite: &mut dyn FnMut(&mut ScalarExpr),
499) {
500 match bound {
501 ScalarFrameBound::Preceding(expression) | ScalarFrameBound::Following(expression) => {
502 rewrite_scalar(expression, rewrite);
503 }
504 ScalarFrameBound::UnboundedPreceding
505 | ScalarFrameBound::UnboundedFollowing
506 | ScalarFrameBound::CurrentRow => {}
507 }
508}