1use super::{NullsOrder, ScalarExpr, SetOpKind};
10
11const fn default_include_descendants() -> bool {
12 true
13}
14
15#[derive(Debug, Clone)]
21pub enum UnifiedPlan {
22 Query(Box<QueryPlan>),
23 Command(Box<CommandPlan>),
24}
25
26#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
28pub struct QueryPlan {
29 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
31 pub relations_bound: bool,
32 pub ctes: Vec<CtePlan>,
33 pub root: RelationalPlan,
34}
35
36#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
38pub struct CtePlan {
39 pub name: String,
40 pub columns: Vec<String>,
41 pub recursive: bool,
42 #[serde(default)]
43 pub materialization: uqa_sql::ast::CteMaterialization,
44 #[serde(default, skip_serializing_if = "Option::is_none")]
45 pub search: Option<CteSearchPlan>,
46 #[serde(default, skip_serializing_if = "Option::is_none")]
47 pub cycle: Option<CteCyclePlan>,
48 pub query: Box<QueryPlan>,
49}
50
51#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
53pub struct CteSearchPlan {
54 pub columns: Vec<String>,
55 pub breadth_first: bool,
56 pub sequence_column: String,
57}
58
59#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
61pub struct CteCyclePlan {
62 pub columns: Vec<String>,
63 pub mark_column: String,
64 pub mark_value: ScalarExpr,
65 pub mark_default: ScalarExpr,
66 pub path_column: String,
67}
68
69#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
72pub enum RelationalPlan {
73 QueryBlock(Box<QueryBlockPlan>),
76 SetOp {
79 kind: SetOpKind,
80 all: bool,
81 left: Box<QueryPlan>,
82 right: Box<QueryPlan>,
83 order_by: Vec<OrderPlan>,
84 limit: Option<Box<ScalarExpr>>,
85 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
86 with_ties: bool,
87 offset: Option<Box<ScalarExpr>>,
88 subqueries: Vec<QueryPlan>,
89 },
90 Values {
94 rows: Vec<Vec<ScalarExpr>>,
95 subqueries: Vec<QueryPlan>,
96 },
97}
98
99#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
102pub struct QueryBlockPlan {
103 pub projections: Vec<ProjectionPlan>,
104 pub from: Option<SourcePlan>,
105 pub r#where: Option<ScalarExpr>,
106 pub compute: ComputePlan,
107 pub group_by: Vec<ScalarExpr>,
108 pub grouping_sets: Vec<Vec<ScalarExpr>>,
109 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
110 pub group_distinct: bool,
111 pub having: Option<ScalarExpr>,
112 pub order_by: Vec<OrderPlan>,
113 pub limit: Option<ScalarExpr>,
114 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
115 pub with_ties: bool,
116 pub offset: Option<ScalarExpr>,
117 pub distinct: bool,
118 pub distinct_on: Vec<ScalarExpr>,
119 pub subqueries: Vec<QueryPlan>,
120 pub access: AccessPathPlan,
121 #[serde(default, skip_serializing_if = "Vec::is_empty")]
123 pub locking: Vec<uqa_sql::ast::LockingClause>,
124}
125
126#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
129pub enum AccessPathPlan {
130 Row,
132 OperatorTree {
134 score_limit_pushdown: bool,
137 },
138 Hybrid,
141}
142
143#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
151pub enum JoinExecutionStrategy {
152 #[default]
153 Auto,
154 Hash,
155}
156
157#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
159pub struct TableFunctionPlan {
160 pub name: String,
161 #[serde(default, skip_serializing_if = "Option::is_none")]
162 pub binding: Option<uqa_sql::ast::FunctionBinding>,
163 #[serde(default)]
164 pub output_name: String,
165 #[serde(default, skip_serializing_if = "Option::is_none")]
166 pub relations: Option<uqa_sql::ast::OperatorJoinRelations>,
167 pub args: Vec<ScalarExpr>,
168 pub column_aliases: Vec<String>,
169 pub column_types: Vec<String>,
170}
171
172#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
174pub enum SourcePlan {
175 Table {
176 name: String,
177 #[serde(default)]
178 qualifier: String,
179 alias: Option<String>,
180 #[serde(default, skip_serializing_if = "Vec::is_empty")]
181 column_aliases: Vec<String>,
182 #[serde(default = "default_include_descendants")]
183 include_descendants: bool,
184 },
185 Join {
186 left: Box<SourcePlan>,
187 right: Box<SourcePlan>,
188 kind: uqa_sql::ast::JoinKind,
189 on: Option<ScalarExpr>,
190 #[serde(default, skip_serializing_if = "Option::is_none")]
191 using: Option<uqa_sql::ast::JoinUsing>,
192 #[serde(default)]
193 natural: bool,
194 #[serde(default, skip_serializing_if = "Option::is_none")]
195 alias: Option<String>,
196 #[serde(default, skip_serializing_if = "Vec::is_empty")]
197 column_aliases: Vec<String>,
198 lateral: bool,
199 #[serde(default)]
200 strategy: JoinExecutionStrategy,
201 },
202 Values {
203 rows: Vec<Vec<ScalarExpr>>,
204 alias: Option<String>,
205 column_aliases: Vec<String>,
206 #[serde(default, skip_serializing_if = "Option::is_none")]
207 internal_relation: Option<uqa_sql::ast::InternalRelationId>,
208 #[serde(default, skip_serializing_if = "Vec::is_empty")]
209 internal_column_types: Vec<Option<uqa_sql::ast::ColumnType>>,
210 },
211 Function {
212 name: String,
213 #[serde(default, skip_serializing_if = "Option::is_none")]
214 binding: Option<uqa_sql::ast::FunctionBinding>,
215 #[serde(default)]
216 output_name: String,
217 #[serde(default, skip_serializing_if = "Option::is_none")]
218 relations: Option<uqa_sql::ast::OperatorJoinRelations>,
219 args: Vec<ScalarExpr>,
220 alias: Option<String>,
221 column_aliases: Vec<String>,
222 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
223 ordinality: bool,
224 column_types: Vec<String>,
225 },
226 FunctionGroup {
227 functions: Vec<TableFunctionPlan>,
228 alias: Option<String>,
229 column_aliases: Vec<String>,
230 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
231 ordinality: bool,
232 },
233 Subquery {
234 body: Box<QueryPlan>,
235 alias: Option<String>,
236 column_aliases: Vec<String>,
237 },
238}
239
240#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
242pub enum ComputePlan {
243 Project,
244 Aggregate,
245 Window,
246}
247
248#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
249pub struct ProjectionPlan {
250 pub expr: ScalarExpr,
251 pub alias: Option<String>,
252}
253
254#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
255pub struct OrderPlan {
256 pub expr: ScalarExpr,
257 pub descending: bool,
258 pub nulls: Option<NullsOrder>,
259}
260
261#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
263pub struct ExpressionPlan {
264 pub scalar: ScalarExpr,
265 pub subqueries: Vec<QueryPlan>,
266}
267
268#[derive(Debug, Clone)]
269pub struct AssignmentPlan {
270 pub column: String,
271 pub value: ScalarExpr,
272}
273
274#[derive(Debug, Clone)]
275pub struct ViewCheckPlan {
276 pub view: String,
277 pub predicate: ScalarExpr,
278}
279
280#[derive(Debug, Clone)]
281pub struct ViewRuleReturningPlan {
282 pub relation: String,
283 pub target_qualifier: String,
284 pub returning: Vec<ProjectionPlan>,
285 pub aliases: uqa_sql::ast::ReturningAliases,
286 pub subqueries: Vec<QueryPlan>,
287}
288
289#[derive(Debug, Clone)]
290pub struct ViewRuleInsertPlan {
291 pub relation: String,
292 pub supplied_columns: Vec<String>,
293 pub input_columns: Vec<String>,
294}
295
296#[derive(Debug, Clone)]
297pub struct ViewRuleUpdatePlan {
298 pub relation: String,
299 pub assigned_columns: Vec<String>,
300 pub input_columns: Vec<String>,
301}
302
303#[derive(Debug, Clone)]
304pub struct InsertPlan {
305 pub table: String,
306 pub target_relation_bound: bool,
307 pub relations_bound: bool,
309 pub statement_privilege_subject: Option<String>,
311 pub target_privilege_subject: Option<String>,
313 pub target_qualifier: String,
314 pub include_descendants: bool,
315 pub columns: Vec<String>,
316 pub ctes: Vec<CtePlan>,
317 pub rows: Vec<Vec<ScalarExpr>>,
318 pub source: Option<Box<QueryPlan>>,
319 pub on_conflict: Option<ConflictPlan>,
320 pub returning: Vec<ProjectionPlan>,
321 pub returning_aliases: uqa_sql::ast::ReturningAliases,
322 pub subqueries: Vec<QueryPlan>,
323 pub view_checks: Vec<ViewCheckPlan>,
324 pub view_rule_relations: Vec<String>,
325 pub view_rule_insert_plans: Vec<ViewRuleInsertPlan>,
326 pub view_rule_returning: Option<ViewRuleReturningPlan>,
327}
328
329#[derive(Debug, Clone)]
330pub struct ConflictPlan {
331 pub predicate: Option<Box<ScalarExpr>>,
332 pub constraint: Option<String>,
333 pub conflict_columns: Vec<String>,
334 pub expressions: Vec<ScalarExpr>,
335 pub action: ConflictActionPlan,
336}
337
338#[derive(Debug, Clone)]
339pub enum ConflictActionPlan {
340 Nothing,
341 Update {
342 assignments: Vec<AssignmentPlan>,
343 predicate: Option<Box<ScalarExpr>>,
344 },
345}
346
347#[derive(Debug, Clone)]
348pub struct UpdatePlan {
349 pub table: String,
350 pub target_relation_bound: bool,
351 pub relations_bound: bool,
353 pub statement_privilege_subject: Option<String>,
355 pub target_privilege_subject: Option<String>,
357 pub target_qualifier: String,
358 pub include_descendants: bool,
359 pub assignments: Vec<AssignmentPlan>,
360 pub predicate: Option<ScalarExpr>,
361 pub ctes: Vec<CtePlan>,
362 pub source: Option<Box<SourcePlan>>,
363 pub returning: Vec<ProjectionPlan>,
364 pub returning_aliases: uqa_sql::ast::ReturningAliases,
365 pub subqueries: Vec<QueryPlan>,
366 pub view_checks: Vec<ViewCheckPlan>,
367 pub view_rule_relations: Vec<String>,
368 pub view_rule_update_plans: Vec<ViewRuleUpdatePlan>,
369 pub view_rule_returning: Option<ViewRuleReturningPlan>,
370}
371
372#[derive(Debug, Clone)]
373pub struct DeletePlan {
374 pub table: String,
375 pub target_relation_bound: bool,
376 pub relations_bound: bool,
378 pub statement_privilege_subject: Option<String>,
380 pub target_privilege_subject: Option<String>,
382 pub target_qualifier: String,
383 pub include_descendants: bool,
384 pub predicate: Option<ScalarExpr>,
385 pub ctes: Vec<CtePlan>,
386 pub source: Option<Box<SourcePlan>>,
387 pub returning: Vec<ProjectionPlan>,
388 pub returning_aliases: uqa_sql::ast::ReturningAliases,
389 pub subqueries: Vec<QueryPlan>,
390 pub view_rule_relations: Vec<String>,
391 pub view_rule_returning: Option<ViewRuleReturningPlan>,
392}
393
394#[derive(Debug, Clone)]
395pub struct MergePlan {
396 pub target: String,
397 pub statement_privilege_subject: Option<String>,
399 pub target_privilege_subject: Option<String>,
401 pub target_qualifier: String,
402 pub target_alias: Option<String>,
403 pub include_descendants: bool,
404 pub target_predicate: Option<ScalarExpr>,
405 pub source: Box<SourcePlan>,
406 pub join_condition: ScalarExpr,
407 pub when_clauses: Vec<MergeWhenPlan>,
408 pub returning: Vec<ProjectionPlan>,
409 pub returning_aliases: uqa_sql::ast::ReturningAliases,
410 pub subqueries: Vec<QueryPlan>,
411 pub view_checks: Vec<ViewCheckPlan>,
412}
413
414#[derive(Debug, Clone)]
415pub enum MergeWhenPlan {
416 UpdateMatched {
417 condition: Option<ScalarExpr>,
418 assignments: Vec<AssignmentPlan>,
419 },
420 DeleteMatched {
421 condition: Option<ScalarExpr>,
422 },
423 UpdateNotMatchedBySource {
424 condition: Option<ScalarExpr>,
425 assignments: Vec<AssignmentPlan>,
426 },
427 DeleteNotMatchedBySource {
428 condition: Option<ScalarExpr>,
429 },
430 InsertNotMatched {
431 condition: Option<ScalarExpr>,
432 columns: Vec<String>,
433 values: Vec<ScalarExpr>,
434 },
435 NothingMatched {
436 condition: Option<ScalarExpr>,
437 },
438 NothingNotMatched {
439 condition: Option<ScalarExpr>,
440 },
441 NothingNotMatchedBySource {
442 condition: Option<ScalarExpr>,
443 },
444}
445
446#[derive(Debug, Clone)]
450pub enum CommandPlan {
451 CreateTable(Box<uqa_sql::ast::CreateTable>),
452 CreateTableIfNotExists(uqa_sql::ast::DeferredCreateTable),
453 CreateIndex(uqa_sql::ast::CreateIndex),
454 Insert(Box<InsertPlan>),
455 Update(Box<UpdatePlan>),
456 Delete(Box<DeletePlan>),
457 Drop(uqa_sql::ast::DropStmt),
458 AlterTable(Box<uqa_sql::ast::AlterTableStmt>),
459 AlterView(uqa_sql::ast::AlterViewStmt),
460 CreateView {
461 name: String,
462 column_names: Vec<String>,
463 query: Box<QueryPlan>,
464 or_replace: bool,
465 persistence: uqa_sql::ast::RelationPersistence,
466 options: Vec<(String, String)>,
467 },
468 CreateMaterializedView {
469 name: String,
470 column_names: Vec<String>,
471 if_not_exists: bool,
472 with_no_data: bool,
473 options: Vec<(String, String)>,
474 query: Box<QueryPlan>,
475 },
476 RefreshMaterializedView {
477 name: String,
478 concurrently: bool,
479 with_no_data: bool,
480 },
481 CreateSchema {
482 name: String,
483 if_not_exists: bool,
484 },
485 Notify {
486 channel: String,
487 payload: String,
488 },
489 Listen {
490 channel: String,
491 },
492 Unlisten {
493 channel: Option<String>,
494 },
495 SetVariable {
496 name: String,
497 value: String,
498 },
499 ResetVariable {
500 name: String,
501 },
502 ResetAllVariables,
503 SetConstraints {
504 constraints: Vec<uqa_sql::ast::SetConstraintName>,
505 deferred: bool,
506 },
507 ShowVariable {
508 name: String,
509 },
510 Discard {
511 target: uqa_sql::ast::DiscardTarget,
512 },
513 Load {
514 library: String,
515 },
516 Explain {
517 analyze: bool,
518 verbose: bool,
519 format: Option<String>,
520 body: Box<UnifiedPlan>,
521 },
522 Analyze {
523 table: Option<String>,
524 },
525 Vacuum(uqa_sql::ast::VacuumStmt),
526 Truncate {
527 tables: Vec<uqa_sql::ast::TruncateTarget>,
528 cascade: bool,
529 restart_identity: bool,
530 },
531 Transaction(uqa_sql::ast::TransactionStmt),
532 DeclareCursor {
533 name: String,
534 binary: bool,
535 scroll: Option<bool>,
536 hold: bool,
537 query: Box<QueryPlan>,
538 },
539 FetchCursor(uqa_sql::ast::FetchCursorStmt),
540 CloseCursor {
541 name: Option<String>,
542 },
543 CreateSequence(uqa_sql::ast::CreateSequence),
544 AlterSequence(uqa_sql::ast::AlterSequence),
545 CreateTableAs {
546 name: String,
547 if_not_exists: bool,
548 column_names: Vec<String>,
549 with_no_data: bool,
550 persistence: uqa_sql::ast::RelationPersistence,
551 on_commit: uqa_sql::ast::OnCommitAction,
552 query: Box<QueryPlan>,
553 },
554 Prepare {
555 name: String,
556 body: Box<UnifiedPlan>,
557 },
558 Execute {
559 name: String,
560 params: Vec<ExpressionPlan>,
561 },
562 Deallocate {
563 name: Option<String>,
564 },
565 CreateForeignServer(uqa_sql::ast::CreateForeignServer),
566 CreateForeignTable(uqa_sql::ast::CreateForeignTable),
567 CreateForeignTableIfNotExists(uqa_sql::ast::DeferredCreateForeignTable),
568 AlterForeignTable(uqa_sql::ast::AlterForeignTableStmt),
569 Merge(Box<MergePlan>),
570 CreateFunction(Box<uqa_sql::ast::CreateFunction>),
571 DropFunction(uqa_sql::ast::DropFunctionStmt),
572 AlterRoutine(uqa_sql::ast::AlterRoutineStmt),
573 AlterRoutineOwner(uqa_sql::ast::AlterRoutineOwnerStmt),
574 RenameRoutine(uqa_sql::ast::RenameRoutineStmt),
575 GrantRoutine(uqa_sql::ast::GrantRoutineStmt),
576 GrantTable(uqa_sql::ast::GrantTableStmt),
577 GrantSequence(uqa_sql::ast::GrantSequenceStmt),
578 GrantDatabase(uqa_sql::ast::GrantDatabaseStmt),
579 GrantSchema(uqa_sql::ast::GrantSchemaStmt),
580 GrantRole(uqa_sql::ast::GrantRoleStmt),
581 CreateRole(uqa_sql::ast::CreateRoleStmt),
582 AlterRole(uqa_sql::ast::AlterRoleStmt),
583 DropRole(uqa_sql::ast::DropRoleStmt),
584 CreateTrigger(uqa_sql::ast::CreateTrigger),
585 DropTrigger(uqa_sql::ast::DropTrigger),
586 CreateRule(uqa_sql::ast::CreateRule),
587 DropRule(uqa_sql::ast::DropRule),
588 DoBlock {
589 language: String,
590 body: String,
591 },
592 Call {
593 name: String,
594 args: Vec<ExpressionPlan>,
595 },
596}
597
598pub trait AggregateClassifier {
602 fn is_registered_aggregate(&self, name: &str) -> bool;
603}
604
605impl<F> AggregateClassifier for F
606where
607 F: Fn(&str) -> bool,
608{
609 fn is_registered_aggregate(&self, name: &str) -> bool {
610 self(name)
611 }
612}
613
614pub(super) struct NoRegisteredAggregates;
615
616impl AggregateClassifier for NoRegisteredAggregates {
617 fn is_registered_aggregate(&self, _name: &str) -> bool {
618 false
619 }
620}