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 pub ctes: Vec<CtePlan>,
30 pub root: RelationalPlan,
31}
32
33#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
35pub struct CtePlan {
36 pub name: String,
37 pub columns: Vec<String>,
38 pub recursive: bool,
39 #[serde(default)]
40 pub materialization: uqa_sql::ast::CteMaterialization,
41 #[serde(default, skip_serializing_if = "Option::is_none")]
42 pub search: Option<CteSearchPlan>,
43 #[serde(default, skip_serializing_if = "Option::is_none")]
44 pub cycle: Option<CteCyclePlan>,
45 pub query: Box<QueryPlan>,
46}
47
48#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
50pub struct CteSearchPlan {
51 pub columns: Vec<String>,
52 pub breadth_first: bool,
53 pub sequence_column: String,
54}
55
56#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
58pub struct CteCyclePlan {
59 pub columns: Vec<String>,
60 pub mark_column: String,
61 pub mark_value: ScalarExpr,
62 pub mark_default: ScalarExpr,
63 pub path_column: String,
64}
65
66#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
69pub enum RelationalPlan {
70 QueryBlock(Box<QueryBlockPlan>),
73 SetOp {
76 kind: SetOpKind,
77 all: bool,
78 left: Box<QueryPlan>,
79 right: Box<QueryPlan>,
80 order_by: Vec<OrderPlan>,
81 limit: Option<Box<ScalarExpr>>,
82 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
83 with_ties: bool,
84 offset: Option<Box<ScalarExpr>>,
85 subqueries: Vec<QueryPlan>,
86 },
87 Values {
91 rows: Vec<Vec<ScalarExpr>>,
92 subqueries: Vec<QueryPlan>,
93 },
94}
95
96#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
99pub struct QueryBlockPlan {
100 pub projections: Vec<ProjectionPlan>,
101 pub from: Option<SourcePlan>,
102 pub r#where: Option<ScalarExpr>,
103 pub compute: ComputePlan,
104 pub group_by: Vec<ScalarExpr>,
105 pub grouping_sets: Vec<Vec<ScalarExpr>>,
106 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
107 pub group_distinct: bool,
108 pub having: Option<ScalarExpr>,
109 pub order_by: Vec<OrderPlan>,
110 pub limit: Option<ScalarExpr>,
111 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
112 pub with_ties: bool,
113 pub offset: Option<ScalarExpr>,
114 pub distinct: bool,
115 pub distinct_on: Vec<ScalarExpr>,
116 pub subqueries: Vec<QueryPlan>,
117 pub access: AccessPathPlan,
118 #[serde(default, skip_serializing_if = "Vec::is_empty")]
120 pub locking: Vec<uqa_sql::ast::LockingClause>,
121}
122
123#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
126pub enum AccessPathPlan {
127 Row,
129 OperatorTree {
131 score_limit_pushdown: bool,
134 },
135 Hybrid,
138}
139
140#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
148pub enum JoinExecutionStrategy {
149 #[default]
150 Auto,
151 Hash,
152}
153
154#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
156pub struct TableFunctionPlan {
157 pub name: String,
158 #[serde(default, skip_serializing_if = "Option::is_none")]
159 pub binding: Option<uqa_sql::ast::FunctionBinding>,
160 #[serde(default)]
161 pub output_name: String,
162 #[serde(default, skip_serializing_if = "Option::is_none")]
163 pub relation: Option<String>,
164 pub args: Vec<ScalarExpr>,
165 pub column_aliases: Vec<String>,
166 pub column_types: Vec<String>,
167}
168
169#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
171pub enum SourcePlan {
172 Table {
173 name: String,
174 #[serde(default)]
175 qualifier: String,
176 alias: Option<String>,
177 #[serde(default = "default_include_descendants")]
178 include_descendants: bool,
179 },
180 Join {
181 left: Box<SourcePlan>,
182 right: Box<SourcePlan>,
183 kind: uqa_sql::ast::JoinKind,
184 on: Option<ScalarExpr>,
185 #[serde(default, skip_serializing_if = "Option::is_none")]
186 using: Option<uqa_sql::ast::JoinUsing>,
187 #[serde(default)]
188 natural: bool,
189 #[serde(default, skip_serializing_if = "Option::is_none")]
190 alias: Option<String>,
191 #[serde(default, skip_serializing_if = "Vec::is_empty")]
192 column_aliases: Vec<String>,
193 lateral: bool,
194 #[serde(default)]
195 strategy: JoinExecutionStrategy,
196 },
197 Values {
198 rows: Vec<Vec<ScalarExpr>>,
199 alias: Option<String>,
200 column_aliases: Vec<String>,
201 #[serde(default, skip_serializing_if = "Option::is_none")]
202 internal_relation: Option<uqa_sql::ast::InternalRelationId>,
203 #[serde(default, skip_serializing_if = "Vec::is_empty")]
204 internal_column_types: Vec<Option<uqa_sql::ast::ColumnType>>,
205 },
206 Function {
207 name: String,
208 #[serde(default, skip_serializing_if = "Option::is_none")]
209 binding: Option<uqa_sql::ast::FunctionBinding>,
210 #[serde(default)]
211 output_name: String,
212 #[serde(default, skip_serializing_if = "Option::is_none")]
213 relation: Option<String>,
214 args: Vec<ScalarExpr>,
215 alias: Option<String>,
216 column_aliases: Vec<String>,
217 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
218 ordinality: bool,
219 column_types: Vec<String>,
220 },
221 FunctionGroup {
222 functions: Vec<TableFunctionPlan>,
223 alias: Option<String>,
224 column_aliases: Vec<String>,
225 #[serde(default, skip_serializing_if = "std::ops::Not::not")]
226 ordinality: bool,
227 },
228 Subquery {
229 body: Box<QueryPlan>,
230 alias: Option<String>,
231 column_aliases: Vec<String>,
232 },
233}
234
235#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
237pub enum ComputePlan {
238 Project,
239 Aggregate,
240 Window,
241}
242
243#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
244pub struct ProjectionPlan {
245 pub expr: ScalarExpr,
246 pub alias: Option<String>,
247}
248
249#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
250pub struct OrderPlan {
251 pub expr: ScalarExpr,
252 pub descending: bool,
253 pub nulls: Option<NullsOrder>,
254}
255
256#[derive(Debug, Clone)]
258pub struct ExpressionPlan {
259 pub scalar: ScalarExpr,
260 pub subqueries: Vec<QueryPlan>,
261}
262
263#[derive(Debug, Clone)]
264pub struct AssignmentPlan {
265 pub column: String,
266 pub value: ScalarExpr,
267}
268
269#[derive(Debug, Clone)]
270pub struct InsertPlan {
271 pub table: String,
272 pub target_qualifier: String,
273 pub include_descendants: bool,
274 pub columns: Vec<String>,
275 pub ctes: Vec<CtePlan>,
276 pub rows: Vec<Vec<ScalarExpr>>,
277 pub source: Option<Box<QueryPlan>>,
278 pub on_conflict: Option<ConflictPlan>,
279 pub returning: Vec<ProjectionPlan>,
280 pub returning_aliases: uqa_sql::ast::ReturningAliases,
281 pub subqueries: Vec<QueryPlan>,
282}
283
284#[derive(Debug, Clone)]
285pub struct ConflictPlan {
286 pub conflict_columns: Vec<String>,
287 pub action: ConflictActionPlan,
288}
289
290#[derive(Debug, Clone)]
291pub enum ConflictActionPlan {
292 Nothing,
293 Update {
294 assignments: Vec<AssignmentPlan>,
295 predicate: Option<ScalarExpr>,
296 },
297}
298
299#[derive(Debug, Clone)]
300pub struct UpdatePlan {
301 pub table: String,
302 pub target_qualifier: String,
303 pub include_descendants: bool,
304 pub assignments: Vec<AssignmentPlan>,
305 pub predicate: Option<ScalarExpr>,
306 pub ctes: Vec<CtePlan>,
307 pub source: Option<Box<SourcePlan>>,
308 pub returning: Vec<ProjectionPlan>,
309 pub returning_aliases: uqa_sql::ast::ReturningAliases,
310 pub subqueries: Vec<QueryPlan>,
311}
312
313#[derive(Debug, Clone)]
314pub struct DeletePlan {
315 pub table: String,
316 pub target_qualifier: String,
317 pub include_descendants: bool,
318 pub predicate: Option<ScalarExpr>,
319 pub ctes: Vec<CtePlan>,
320 pub source: Option<Box<SourcePlan>>,
321 pub returning: Vec<ProjectionPlan>,
322 pub returning_aliases: uqa_sql::ast::ReturningAliases,
323 pub subqueries: Vec<QueryPlan>,
324}
325
326#[derive(Debug, Clone)]
327pub struct MergePlan {
328 pub target: String,
329 pub target_qualifier: String,
330 pub target_alias: Option<String>,
331 pub include_descendants: bool,
332 pub source: Box<SourcePlan>,
333 pub join_condition: ScalarExpr,
334 pub when_clauses: Vec<MergeWhenPlan>,
335 pub returning: Vec<ProjectionPlan>,
336 pub returning_aliases: uqa_sql::ast::ReturningAliases,
337 pub subqueries: Vec<QueryPlan>,
338}
339
340#[derive(Debug, Clone)]
341pub enum MergeWhenPlan {
342 UpdateMatched {
343 condition: Option<ScalarExpr>,
344 assignments: Vec<AssignmentPlan>,
345 },
346 DeleteMatched {
347 condition: Option<ScalarExpr>,
348 },
349 UpdateNotMatchedBySource {
350 condition: Option<ScalarExpr>,
351 assignments: Vec<AssignmentPlan>,
352 },
353 DeleteNotMatchedBySource {
354 condition: Option<ScalarExpr>,
355 },
356 InsertNotMatched {
357 condition: Option<ScalarExpr>,
358 columns: Vec<String>,
359 values: Vec<ScalarExpr>,
360 },
361 NothingMatched {
362 condition: Option<ScalarExpr>,
363 },
364 NothingNotMatched {
365 condition: Option<ScalarExpr>,
366 },
367 NothingNotMatchedBySource {
368 condition: Option<ScalarExpr>,
369 },
370}
371
372#[derive(Debug, Clone)]
376pub enum CommandPlan {
377 CreateTable(Box<uqa_sql::ast::CreateTable>),
378 CreateIndex(uqa_sql::ast::CreateIndex),
379 Insert(Box<InsertPlan>),
380 Update(Box<UpdatePlan>),
381 Delete(Box<DeletePlan>),
382 Drop(uqa_sql::ast::DropStmt),
383 AlterTable(Box<uqa_sql::ast::AlterTableStmt>),
384 AlterViewOptions(uqa_sql::ast::AlterViewOptionsStmt),
385 CreateView {
386 name: String,
387 column_names: Vec<String>,
388 query: Box<QueryPlan>,
389 or_replace: bool,
390 persistence: uqa_sql::ast::RelationPersistence,
391 options: Vec<(String, String)>,
392 },
393 CreateMaterializedView {
394 name: String,
395 column_names: Vec<String>,
396 if_not_exists: bool,
397 with_no_data: bool,
398 options: Vec<(String, String)>,
399 query: Box<QueryPlan>,
400 },
401 RefreshMaterializedView {
402 name: String,
403 concurrently: bool,
404 with_no_data: bool,
405 },
406 CreateSchema {
407 name: String,
408 if_not_exists: bool,
409 },
410 SetVariable {
411 name: String,
412 value: String,
413 },
414 ResetVariable {
415 name: String,
416 },
417 ResetAllVariables,
418 SetConstraints {
419 constraints: Vec<uqa_sql::ast::SetConstraintName>,
420 deferred: bool,
421 },
422 ShowVariable {
423 name: String,
424 },
425 Discard {
426 target: uqa_sql::ast::DiscardTarget,
427 },
428 Load {
429 library: String,
430 },
431 Explain {
432 analyze: bool,
433 verbose: bool,
434 format: Option<String>,
435 body: Box<UnifiedPlan>,
436 },
437 Analyze {
438 table: Option<String>,
439 },
440 Vacuum(uqa_sql::ast::VacuumStmt),
441 Truncate {
442 tables: Vec<uqa_sql::ast::TruncateTarget>,
443 cascade: bool,
444 restart_identity: bool,
445 },
446 Transaction(uqa_sql::ast::TransactionStmt),
447 DeclareCursor {
448 name: String,
449 binary: bool,
450 scroll: Option<bool>,
451 hold: bool,
452 query: Box<QueryPlan>,
453 },
454 FetchCursor(uqa_sql::ast::FetchCursorStmt),
455 CloseCursor {
456 name: Option<String>,
457 },
458 CreateSequence(uqa_sql::ast::CreateSequence),
459 AlterSequence(uqa_sql::ast::AlterSequence),
460 CreateTableAs {
461 name: String,
462 if_not_exists: bool,
463 column_names: Vec<String>,
464 with_no_data: bool,
465 persistence: uqa_sql::ast::RelationPersistence,
466 on_commit: uqa_sql::ast::OnCommitAction,
467 query: Box<QueryPlan>,
468 },
469 Prepare {
470 name: String,
471 body: Box<UnifiedPlan>,
472 },
473 Execute {
474 name: String,
475 params: Vec<ExpressionPlan>,
476 },
477 Deallocate {
478 name: Option<String>,
479 },
480 CreateForeignServer(uqa_sql::ast::CreateForeignServer),
481 CreateForeignTable(uqa_sql::ast::CreateForeignTable),
482 Merge(Box<MergePlan>),
483 CreateFunction(Box<uqa_sql::ast::CreateFunction>),
484 DropFunction(uqa_sql::ast::DropFunctionStmt),
485 AlterRoutine(uqa_sql::ast::AlterRoutineStmt),
486 AlterRoutineOwner(uqa_sql::ast::AlterRoutineOwnerStmt),
487 GrantRoutine(uqa_sql::ast::GrantRoutineStmt),
488 CreateRole(uqa_sql::ast::CreateRoleStmt),
489 AlterRole(uqa_sql::ast::AlterRoleStmt),
490 DropRole(uqa_sql::ast::DropRoleStmt),
491 CreateTrigger(uqa_sql::ast::CreateTrigger),
492 DropTrigger(uqa_sql::ast::DropTrigger),
493 CreateRule(uqa_sql::ast::CreateRule),
494 DropRule(uqa_sql::ast::DropRule),
495 DoBlock {
496 language: String,
497 body: String,
498 },
499 Call {
500 name: String,
501 args: Vec<ExpressionPlan>,
502 },
503}
504
505pub trait AggregateClassifier {
509 fn is_registered_aggregate(&self, name: &str) -> bool;
510}
511
512impl<F> AggregateClassifier for F
513where
514 F: Fn(&str) -> bool,
515{
516 fn is_registered_aggregate(&self, name: &str) -> bool {
517 self(name)
518 }
519}
520
521pub(super) struct NoRegisteredAggregates;
522
523impl AggregateClassifier for NoRegisteredAggregates {
524 fn is_registered_aggregate(&self, _name: &str) -> bool {
525 false
526 }
527}