1use itertools::Itertools;
13use mz_sql_parser::ast::display::{AstDisplay, escape_single_quote_string};
14use mz_sql_parser::ast::*;
15use pretty::{Doc, RcDoc};
16
17use crate::util::{
18 bracket, bracket_doc, comma_separate, comma_separated, intersperse_line_nest, nest,
19 nest_comma_separate, nest_title, title_comma_separate,
20};
21use crate::{Pretty, TAB};
22
23impl Pretty {
24 pub(crate) fn doc_display<'a, T: AstDisplay>(&self, v: &T, _debug: &str) -> RcDoc<'a, ()> {
26 #[cfg(test)]
27 eprintln!(
28 "UNKNOWN PRETTY TYPE in {}: {}, {}",
29 _debug,
30 std::any::type_name::<T>(),
31 v.to_ast_string_simple()
32 );
33 self.doc_display_pass(v)
34 }
35
36 fn doc_display_pass<'a, T: AstDisplay>(&self, v: &T) -> RcDoc<'a, ()> {
38 RcDoc::text(v.to_ast_string(self.config.format_mode))
39 }
40
41 pub(crate) fn doc_create_source<'a, T: AstInfo>(
42 &'a self,
43 v: &'a CreateSourceStatement<T>,
44 ) -> RcDoc<'a> {
45 let mut docs = Vec::new();
46 let title = format!(
47 "CREATE SOURCE{}",
48 if v.if_not_exists {
49 " IF NOT EXISTS"
50 } else {
51 ""
52 }
53 );
54 let mut doc = self.doc_display_pass(&v.name);
55 let mut names = Vec::new();
56 names.extend(v.col_names.iter().map(|name| self.doc_display_pass(name)));
57 names.extend(v.key_constraint.iter().map(|kc| self.doc_display_pass(kc)));
58 if !names.is_empty() {
59 doc = nest(doc, bracket("(", comma_separated(names), ")"));
60 }
61 docs.push(nest_title(title, doc));
62 if let Some(cluster) = &v.in_cluster {
63 docs.push(nest_title("IN CLUSTER", self.doc_display_pass(cluster)));
64 }
65 docs.push(nest_title("FROM", self.doc_display_pass(&v.connection)));
66 if let Some(format) = &v.format {
67 docs.push(self.doc_format_specifier(format));
68 }
69 if !v.include_metadata.is_empty() {
70 docs.push(nest_title(
71 "INCLUDE",
72 comma_separate(|im| self.doc_display_pass(im), &v.include_metadata),
73 ));
74 }
75 if let Some(envelope) = &v.envelope {
76 docs.push(nest_title("ENVELOPE", self.doc_display_pass(envelope)));
77 }
78 if let Some(references) = &v.external_references {
79 docs.push(self.doc_external_references(references));
80 }
81 if let Some(progress) = &v.progress_subsource {
82 docs.push(nest_title(
83 "EXPOSE PROGRESS AS",
84 self.doc_display_pass(progress),
85 ));
86 }
87 if !v.with_options.is_empty() {
88 docs.push(bracket(
89 "WITH (",
90 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
91 ")",
92 ));
93 }
94 RcDoc::intersperse(docs, Doc::line()).group()
95 }
96
97 pub(crate) fn doc_create_webhook_source<'a, T: AstInfo>(
98 &'a self,
99 v: &'a CreateWebhookSourceStatement<T>,
100 ) -> RcDoc<'a> {
101 let mut docs = Vec::new();
102
103 let mut title = "CREATE ".to_string();
104 if v.is_table {
105 title.push_str("TABLE");
106 } else {
107 title.push_str("SOURCE");
108 }
109 if v.if_not_exists {
110 title.push_str(" IF NOT EXISTS");
111 }
112 docs.push(nest_title(title, self.doc_display_pass(&v.name)));
113
114 if !v.is_table {
116 if let Some(cluster) = &v.in_cluster {
117 docs.push(nest_title("IN CLUSTER", self.doc_display_pass(cluster)));
118 }
119 }
120
121 docs.push(RcDoc::text("FROM WEBHOOK"));
122 docs.push(nest_title(
123 "BODY FORMAT",
124 self.doc_display_pass(&v.body_format),
125 ));
126
127 if !v.include_headers.mappings.is_empty() || v.include_headers.column.is_some() {
128 let mut header_docs = Vec::new();
129
130 for mapping in &v.include_headers.mappings {
132 header_docs.push(self.doc_display_pass(mapping));
133 }
134
135 if let Some(filters) = &v.include_headers.column {
137 if filters.is_empty() {
138 header_docs.push(RcDoc::text("INCLUDE HEADERS"));
139 } else {
140 header_docs.push(bracket(
141 "INCLUDE HEADERS (",
142 comma_separate(|f| self.doc_display_pass(f), filters),
143 ")",
144 ));
145 }
146 }
147
148 if !header_docs.is_empty() {
149 docs.extend(header_docs);
150 }
151 }
152
153 if let Some(check) = &v.validate_using {
154 docs.push(self.doc_webhook_check(check));
155 }
156
157 RcDoc::intersperse(docs, Doc::line()).group()
158 }
159
160 fn doc_webhook_check<'a, T: AstInfo>(
161 &'a self,
162 v: &'a CreateWebhookSourceCheck<T>,
163 ) -> RcDoc<'a> {
164 let mut inner = Vec::new();
165
166 if let Some(options) = &v.options {
167 let mut with_items = Vec::new();
168
169 for header in &options.headers {
170 with_items.push(self.doc_display_pass(header));
171 }
172 for body in &options.bodies {
173 with_items.push(self.doc_display_pass(body));
174 }
175 for secret in &options.secrets {
176 with_items.push(self.doc_display_pass(secret));
177 }
178
179 if !with_items.is_empty() {
180 inner.push(bracket("WITH (", comma_separated(with_items), ")"));
181 inner.push(RcDoc::line());
182 }
183 }
184
185 inner.push(self.doc_display_pass(&v.using));
186
187 bracket_doc(
188 RcDoc::text("CHECK ("),
189 RcDoc::concat(inner),
190 RcDoc::text(")"),
191 RcDoc::line(),
192 )
193 }
194
195 pub(crate) fn doc_create_table<'a, T: AstInfo>(
196 &'a self,
197 v: &'a CreateTableStatement<T>,
198 ) -> RcDoc<'a> {
199 let mut docs = Vec::new();
200
201 let mut title = "CREATE ".to_string();
203 if v.temporary {
204 title.push_str("TEMPORARY ");
205 }
206 title.push_str("TABLE");
207 if v.if_not_exists {
208 title.push_str(" IF NOT EXISTS");
209 }
210
211 let mut col_items = Vec::new();
213 col_items.extend(v.columns.iter().map(|c| self.doc_display_pass(c)));
214 col_items.extend(v.constraints.iter().map(|c| self.doc_display_pass(c)));
215
216 let table_def = nest(
217 self.doc_display_pass(&v.name),
218 bracket("(", comma_separated(col_items), ")"),
219 );
220 docs.push(nest_title(title, table_def));
221
222 if !v.with_options.is_empty() {
224 docs.push(bracket(
225 "WITH (",
226 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
227 ")",
228 ));
229 }
230
231 RcDoc::intersperse(docs, Doc::line()).group()
232 }
233
234 pub(crate) fn doc_create_table_from_source<'a, T: AstInfo>(
235 &'a self,
236 v: &'a CreateTableFromSourceStatement<T>,
237 ) -> RcDoc<'a> {
238 let mut docs = Vec::new();
239
240 let mut title = "CREATE TABLE".to_string();
242 if v.if_not_exists {
243 title.push_str(" IF NOT EXISTS");
244 }
245
246 let mut table_def = self.doc_display_pass(&v.name);
247
248 let has_columns_or_constraints = match &v.columns {
249 TableFromSourceColumns::NotSpecified => false,
250 _ => true,
251 } || !v.constraints.is_empty();
252
253 if has_columns_or_constraints {
254 let mut items = Vec::new();
255
256 match &v.columns {
257 TableFromSourceColumns::NotSpecified => {}
258 TableFromSourceColumns::Named(cols) => {
259 items.extend(cols.iter().map(|c| self.doc_display_pass(c)));
260 }
261 TableFromSourceColumns::Defined(cols) => {
262 items.extend(cols.iter().map(|c| self.doc_display_pass(c)));
263 }
264 }
265
266 items.extend(v.constraints.iter().map(|c| self.doc_display_pass(c)));
267
268 if !items.is_empty() {
269 table_def = nest(table_def, bracket("(", comma_separated(items), ")"));
270 }
271 }
272
273 docs.push(nest_title(title, table_def));
274
275 let mut from_source = nest_title("FROM SOURCE", self.doc_display_pass(&v.source));
277 if let Some(reference) = &v.external_reference {
278 from_source = nest(
279 from_source,
280 bracket("(REFERENCE = ", self.doc_display_pass(reference), ")"),
281 );
282 }
283 docs.push(from_source);
284
285 if let Some(format) = &v.format {
286 docs.push(self.doc_format_specifier(format));
287 }
288
289 if !v.include_metadata.is_empty() {
290 docs.push(nest_title(
291 "INCLUDE",
292 comma_separate(|im| self.doc_display_pass(im), &v.include_metadata),
293 ));
294 }
295
296 if let Some(envelope) = &v.envelope {
297 docs.push(nest_title("ENVELOPE", self.doc_display_pass(envelope)));
298 }
299
300 if !v.with_options.is_empty() {
301 docs.push(bracket(
302 "WITH (",
303 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
304 ")",
305 ));
306 }
307
308 RcDoc::intersperse(docs, Doc::line()).group()
309 }
310
311 pub(crate) fn doc_create_connection<'a, T: AstInfo>(
312 &'a self,
313 v: &'a CreateConnectionStatement<T>,
314 ) -> RcDoc<'a> {
315 let mut docs = Vec::new();
316
317 let mut title = "CREATE CONNECTION".to_string();
318 if v.if_not_exists {
319 title.push_str(" IF NOT EXISTS");
320 }
321 docs.push(nest_title(title, self.doc_display_pass(&v.name)));
322
323 let connection_with_values = nest(
324 RcDoc::concat([
325 RcDoc::text("TO "),
326 self.doc_display_pass(&v.connection_type),
327 ]),
328 bracket(
329 "(",
330 comma_separate(|val| self.doc_display_pass(val), &v.values),
331 ")",
332 ),
333 );
334 docs.push(connection_with_values);
335
336 if !v.with_options.is_empty() {
337 docs.push(bracket(
338 "WITH (",
339 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
340 ")",
341 ));
342 }
343
344 RcDoc::intersperse(docs, Doc::line()).group()
345 }
346
347 pub(crate) fn doc_create_sink<'a, T: AstInfo>(
348 &'a self,
349 v: &'a CreateSinkStatement<T>,
350 ) -> RcDoc<'a> {
351 let mut docs = Vec::new();
352
353 let mut title = "CREATE SINK".to_string();
355 if v.if_not_exists {
356 title.push_str(" IF NOT EXISTS");
357 }
358
359 if let Some(name) = &v.name {
360 docs.push(nest_title(title, self.doc_display_pass(name)));
361 } else {
362 docs.push(RcDoc::text(title));
363 }
364
365 if let Some(cluster) = &v.in_cluster {
366 docs.push(nest_title("IN CLUSTER", self.doc_display_pass(cluster)));
367 }
368
369 docs.push(nest_title("FROM", self.doc_display_pass(&v.from)));
370 docs.push(nest_title("INTO", self.doc_display_pass(&v.connection)));
371
372 if let Some(format) = &v.format {
373 docs.push(self.doc_format_specifier(format));
374 }
375
376 if let Some(envelope) = &v.envelope {
377 docs.push(nest_title("ENVELOPE", self.doc_display_pass(envelope)));
378 }
379
380 if let Some(mode) = &v.mode {
381 docs.push(nest_title("MODE", self.doc_display_pass(mode)));
382 }
383
384 if !v.with_options.is_empty() {
385 docs.push(bracket(
386 "WITH (",
387 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
388 ")",
389 ));
390 }
391
392 RcDoc::intersperse(docs, Doc::line()).group()
393 }
394
395 pub(crate) fn doc_create_subsource<'a, T: AstInfo>(
396 &'a self,
397 v: &'a CreateSubsourceStatement<T>,
398 ) -> RcDoc<'a> {
399 let mut docs = Vec::new();
400
401 let mut title = "CREATE SUBSOURCE".to_string();
403 if v.if_not_exists {
404 title.push_str(" IF NOT EXISTS");
405 }
406
407 let mut col_items = Vec::new();
409 col_items.extend(v.columns.iter().map(|c| self.doc_display_pass(c)));
410 col_items.extend(v.constraints.iter().map(|c| self.doc_display_pass(c)));
411
412 let table_def = nest(
413 self.doc_display_pass(&v.name),
414 bracket("(", comma_separated(col_items), ")"),
415 );
416 docs.push(nest_title(title, table_def));
417
418 if let Some(of_source) = &v.of_source {
420 docs.push(nest_title("OF SOURCE", self.doc_display_pass(of_source)));
421 }
422
423 if !v.with_options.is_empty() {
425 docs.push(bracket(
426 "WITH (",
427 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
428 ")",
429 ));
430 }
431
432 RcDoc::intersperse(docs, Doc::line()).group()
433 }
434
435 pub(crate) fn doc_create_cluster<'a, T: AstInfo>(
436 &'a self,
437 v: &'a CreateClusterStatement<T>,
438 ) -> RcDoc<'a> {
439 let mut docs = Vec::new();
440
441 docs.push(nest_title("CREATE CLUSTER", self.doc_display_pass(&v.name)));
443
444 if !v.options.is_empty() {
446 docs.push(bracket(
447 "(",
448 comma_separate(|o| self.doc_display_pass(o), &v.options),
449 ")",
450 ));
451 }
452
453 if !v.features.is_empty() {
455 docs.push(bracket(
456 "FEATURES (",
457 comma_separate(|f| self.doc_display_pass(f), &v.features),
458 ")",
459 ));
460 }
461
462 RcDoc::intersperse(docs, Doc::line()).group()
463 }
464
465 pub(crate) fn doc_create_cluster_replica<'a, T: AstInfo>(
466 &'a self,
467 v: &'a CreateClusterReplicaStatement<T>,
468 ) -> RcDoc<'a> {
469 let mut docs = Vec::new();
470
471 let replica_name = RcDoc::concat([
473 self.doc_display_pass(&v.of_cluster),
474 RcDoc::text("."),
475 self.doc_display_pass(&v.definition.name),
476 ]);
477 docs.push(nest_title("CREATE CLUSTER REPLICA", replica_name));
478
479 docs.push(bracket(
481 "(",
482 comma_separate(|o| self.doc_display_pass(o), &v.definition.options),
483 ")",
484 ));
485
486 RcDoc::intersperse(docs, Doc::line()).group()
487 }
488
489 pub(crate) fn doc_create_network_policy<'a, T: AstInfo>(
490 &'a self,
491 v: &'a CreateNetworkPolicyStatement<T>,
492 ) -> RcDoc<'a> {
493 let docs = vec![
494 nest_title("CREATE NETWORK POLICY", self.doc_display_pass(&v.name)),
496 bracket(
498 "(",
499 comma_separate(|o| self.doc_display_pass(o), &v.options),
500 ")",
501 ),
502 ];
503
504 RcDoc::intersperse(docs, Doc::line()).group()
505 }
506
507 pub(crate) fn doc_create_index<'a, T: AstInfo>(
508 &'a self,
509 v: &'a CreateIndexStatement<T>,
510 ) -> RcDoc<'a> {
511 let mut docs = Vec::new();
512
513 let mut title = "CREATE".to_string();
515 if v.key_parts.is_none() {
516 title.push_str(" DEFAULT");
517 }
518 title.push_str(" INDEX");
519 if v.if_not_exists {
520 title.push_str(" IF NOT EXISTS");
521 }
522
523 if let Some(name) = &v.name {
524 docs.push(nest_title(title, self.doc_display_pass(name)));
525 } else {
526 docs.push(RcDoc::text(title));
527 }
528
529 if let Some(cluster) = &v.in_cluster {
531 docs.push(nest_title("IN CLUSTER", self.doc_display_pass(cluster)));
532 }
533
534 let on_clause = if let Some(key_parts) = &v.key_parts {
536 nest(
537 self.doc_display_pass(&v.on_name),
538 bracket(
539 "(",
540 comma_separate(|k| self.doc_display_pass(k), key_parts),
541 ")",
542 ),
543 )
544 } else {
545 self.doc_display_pass(&v.on_name)
546 };
547 docs.push(nest_title("ON", on_clause));
548
549 if !v.with_options.is_empty() {
551 docs.push(bracket(
552 "WITH (",
553 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
554 ")",
555 ));
556 }
557
558 RcDoc::intersperse(docs, Doc::line()).group()
559 }
560
561 fn doc_format_specifier<T: AstInfo>(&self, v: &FormatSpecifier<T>) -> RcDoc<'_> {
562 match v {
563 FormatSpecifier::Bare(format) => nest_title("FORMAT", self.doc_display_pass(format)),
564 FormatSpecifier::KeyValue { key, value } => {
565 let docs = vec![
566 nest_title("KEY FORMAT", self.doc_display_pass(key)),
567 nest_title("VALUE FORMAT", self.doc_display_pass(value)),
568 ];
569 RcDoc::intersperse(docs, Doc::line()).group()
570 }
571 }
572 }
573
574 fn doc_external_references<'a>(&'a self, v: &'a ExternalReferences) -> RcDoc<'a> {
575 match v {
576 ExternalReferences::SubsetTables(subsources) => bracket(
577 "FOR TABLES (",
578 comma_separate(|s| self.doc_display_pass(s), subsources),
579 ")",
580 ),
581 ExternalReferences::SubsetSchemas(schemas) => bracket(
582 "FOR SCHEMAS (",
583 comma_separate(|s| self.doc_display_pass(s), schemas),
584 ")",
585 ),
586 ExternalReferences::All => RcDoc::text("FOR ALL TABLES"),
587 }
588 }
589
590 pub(crate) fn doc_copy<'a, T: AstInfo>(&'a self, v: &'a CopyStatement<T>) -> RcDoc<'a> {
591 let relation = match &v.relation {
592 CopyRelation::Named { name, columns } => {
593 let mut relation = self.doc_display_pass(name);
594 if !columns.is_empty() {
595 relation = bracket_doc(
596 nest(relation, RcDoc::text("(")),
597 comma_separate(|c| self.doc_display_pass(c), columns),
598 RcDoc::text(")"),
599 RcDoc::line_(),
600 );
601 }
602 RcDoc::concat([RcDoc::text("COPY "), relation])
603 }
604 CopyRelation::Select(query) => bracket("COPY (", self.doc_select_statement(query), ")"),
605 CopyRelation::Subscribe(query) => bracket("COPY (", self.doc_subscribe(query), ")"),
606 };
607 let mut docs = vec![
608 relation,
609 RcDoc::concat([
610 self.doc_display_pass(&v.direction),
611 RcDoc::text(" "),
612 self.doc_display_pass(&v.target),
613 ]),
614 ];
615 if !v.options.is_empty() {
616 docs.push(bracket(
617 "WITH (",
618 comma_separate(|o| self.doc_display_pass(o), &v.options),
619 ")",
620 ));
621 }
622 RcDoc::intersperse(docs, Doc::line()).group()
623 }
624
625 pub(crate) fn doc_subscribe<'a, T: AstInfo>(
626 &'a self,
627 v: &'a SubscribeStatement<T>,
628 ) -> RcDoc<'a> {
629 let doc = match &v.relation {
630 SubscribeRelation::Name(name) => nest_title("SUBSCRIBE", self.doc_display_pass(name)),
631 SubscribeRelation::Query(query) => bracket("SUBSCRIBE (", self.doc_query(query), ")"),
632 };
633 let mut docs = vec![doc];
634 if !v.options.is_empty() {
635 docs.push(bracket(
636 "WITH (",
637 comma_separate(|o| self.doc_display_pass(o), &v.options),
638 ")",
639 ));
640 }
641 if let Some(as_of) = &v.as_of {
642 docs.push(self.doc_as_of(as_of));
643 }
644 if let Some(up_to) = &v.up_to {
645 docs.push(nest_title("UP TO", self.doc_expr(up_to)));
646 }
647 match &v.output {
648 SubscribeOutput::Diffs => {}
649 SubscribeOutput::WithinTimestampOrderBy { order_by } => {
650 docs.push(nest_title(
651 "WITHIN TIMESTAMP ORDER BY ",
652 comma_separate(|o| self.doc_order_by_expr(o), order_by),
653 ));
654 }
655 SubscribeOutput::EnvelopeUpsert { key_columns } => {
656 docs.push(bracket(
657 "ENVELOPE UPSERT (KEY (",
658 comma_separate(|kc| self.doc_display_pass(kc), key_columns),
659 "))",
660 ));
661 }
662 SubscribeOutput::EnvelopeDebezium { key_columns } => {
663 docs.push(bracket(
664 "ENVELOPE DEBEZIUM (KEY (",
665 comma_separate(|kc| self.doc_display_pass(kc), key_columns),
666 "))",
667 ));
668 }
669 }
670 RcDoc::intersperse(docs, Doc::line()).group()
671 }
672
673 fn doc_as_of<'a, T: AstInfo>(&'a self, v: &'a AsOf<T>) -> RcDoc<'a> {
674 let (title, expr) = match v {
675 AsOf::At(expr) => ("AS OF", expr),
676 AsOf::AtLeast(expr) => ("AS OF AT LEAST", expr),
677 };
678 nest_title(title, self.doc_expr(expr))
679 }
680
681 pub(crate) fn doc_create_view<'a, T: AstInfo>(
682 &'a self,
683 v: &'a CreateViewStatement<T>,
684 ) -> RcDoc<'a> {
685 let mut docs = vec![];
686 docs.push(RcDoc::text(format!(
687 "CREATE{}{} VIEW{}",
688 if v.if_exists == IfExistsBehavior::Replace {
689 " OR REPLACE"
690 } else {
691 ""
692 },
693 if v.temporary { " TEMPORARY" } else { "" },
694 if v.if_exists == IfExistsBehavior::Skip {
695 " IF NOT EXISTS"
696 } else {
697 ""
698 },
699 )));
700 docs.push(self.doc_view_definition(&v.definition));
701 intersperse_line_nest(docs)
702 }
703
704 pub(crate) fn doc_create_materialized_view<'a, T: AstInfo>(
705 &'a self,
706 v: &'a CreateMaterializedViewStatement<T>,
707 ) -> RcDoc<'a> {
708 let mut docs = vec![];
709 docs.push(RcDoc::text(format!(
710 "CREATE{}{} MATERIALIZED VIEW{} {}",
711 if v.if_exists == IfExistsBehavior::Replace {
712 " OR REPLACE"
713 } else {
714 ""
715 },
716 if v.replacement_for.is_some() {
717 " REPLACEMENT"
718 } else {
719 ""
720 },
721 if v.if_exists == IfExistsBehavior::Skip {
722 " IF NOT EXISTS"
723 } else {
724 ""
725 },
726 v.name,
727 )));
728 if !v.columns.is_empty() {
729 docs.push(bracket(
730 "(",
731 comma_separate(|c| self.doc_display_pass(c), &v.columns),
732 ")",
733 ));
734 }
735 if let Some(target) = &v.replacement_for {
736 docs.push(RcDoc::text(format!(
737 "FOR {}",
738 target.to_ast_string_simple()
739 )));
740 }
741 match (&v.in_cluster, &v.in_cluster_replica) {
742 (Some(cluster), Some(replica)) => {
743 docs.push(RcDoc::text(format!(
744 "IN CLUSTER {} REPLICA {}",
745 cluster.to_ast_string_simple(),
746 replica.to_ast_string_simple(),
747 )));
748 }
749 (Some(cluster), None) => {
750 docs.push(RcDoc::text(format!(
751 "IN CLUSTER {}",
752 cluster.to_ast_string_simple(),
753 )));
754 }
755 (None, Some(replica)) => {
756 docs.push(RcDoc::text(format!(
757 "IN REPLICA {}",
758 replica.to_ast_string_simple(),
759 )));
760 }
761 (None, None) => {}
762 }
763 if !v.with_options.is_empty() {
764 docs.push(bracket(
765 "WITH (",
766 comma_separate(|wo| self.doc_display_pass(wo), &v.with_options),
767 ")",
768 ));
769 }
770 docs.push(nest_title("AS", self.doc_query(&v.query)));
771 if let Some(time) = &v.as_of {
774 docs.push(RcDoc::text(format!("AS OF {time}")));
775 }
776 intersperse_line_nest(docs)
777 }
778
779 pub(crate) fn doc_create_role<'a>(&'a self, v: &'a CreateRoleStatement) -> RcDoc<'a> {
780 let mut docs = vec![RcDoc::text(format!(
781 "CREATE ROLE {}",
782 v.name.to_ast_string_simple()
783 ))];
784 for option in &v.options {
785 docs.push(self.doc_role_attribute(option));
786 }
787 intersperse_line_nest(docs)
788 }
789
790 pub(crate) fn doc_alter_role<'a, T: AstInfo>(
791 &'a self,
792 v: &'a AlterRoleStatement<T>,
793 ) -> RcDoc<'a> {
794 let mut docs = vec![RcDoc::text(format!(
795 "ALTER ROLE {}",
796 v.name.to_ast_string_simple()
797 ))];
798 match &v.option {
799 AlterRoleOption::Attributes(attrs) => {
800 for attr in attrs {
801 docs.push(self.doc_role_attribute(attr));
802 }
803 }
804 AlterRoleOption::Variable(var) => docs.push(self.doc_display_pass(var)),
807 }
808 intersperse_line_nest(docs)
809 }
810
811 fn doc_role_attribute<'a>(&'a self, attr: &'a RoleAttribute) -> RcDoc<'a> {
815 match attr {
816 RoleAttribute::Password(Some(password)) => RcDoc::text(format!(
817 "PASSWORD '{}'",
818 escape_single_quote_string(password)
819 )),
820 RoleAttribute::Password(None) => RcDoc::text("PASSWORD NULL"),
821 other => self.doc_display_pass(other),
822 }
823 }
824
825 fn doc_view_definition<'a, T: AstInfo>(&'a self, v: &'a ViewDefinition<T>) -> RcDoc<'a> {
826 let mut docs = vec![RcDoc::text(v.name.to_string())];
827 if !v.columns.is_empty() {
828 docs.push(bracket(
829 "(",
830 comma_separate(|c| self.doc_display_pass(c), &v.columns),
831 ")",
832 ));
833 }
834 docs.push(nest_title("AS", self.doc_query(&v.query)));
835 RcDoc::intersperse(docs, Doc::line()).group()
836 }
837
838 pub(crate) fn doc_insert<'a, T: AstInfo>(&'a self, v: &'a InsertStatement<T>) -> RcDoc<'a> {
839 let mut first = vec![RcDoc::text(format!(
840 "INSERT INTO {}",
841 v.table_name.to_ast_string_simple()
842 ))];
843 if !v.columns.is_empty() {
844 first.push(bracket(
845 "(",
846 comma_separate(|c| self.doc_display_pass(c), &v.columns),
847 ")",
848 ));
849 }
850 let sources = match &v.source {
851 InsertSource::Query(query) => self.doc_query(query),
852 InsertSource::DefaultValues => self.doc_display(&v.source, "insert source"),
853 };
854 let mut doc = intersperse_line_nest([intersperse_line_nest(first), sources]);
855 if !v.returning.is_empty() {
856 doc = nest(
857 doc,
858 nest_title(
859 "RETURNING",
860 comma_separate(|r| self.doc_display_pass(r), &v.returning),
861 ),
862 )
863 }
864 doc
865 }
866
867 pub(crate) fn doc_select_statement<'a, T: AstInfo>(
868 &'a self,
869 v: &'a SelectStatement<T>,
870 ) -> RcDoc<'a> {
871 let mut doc = self.doc_query(&v.query);
872 if let Some(as_of) = &v.as_of {
873 doc = intersperse_line_nest([doc, self.doc_as_of(as_of)]);
874 }
875 doc.group()
876 }
877
878 fn doc_order_by<'a, T: AstInfo>(&'a self, v: &'a [OrderByExpr<T>]) -> RcDoc<'a> {
879 title_comma_separate("ORDER BY", |o| self.doc_order_by_expr(o), v)
880 }
881
882 fn doc_order_by_expr<'a, T: AstInfo>(&'a self, v: &'a OrderByExpr<T>) -> RcDoc<'a> {
883 let doc = self.doc_expr(&v.expr);
884 let doc = match v.asc {
885 Some(true) => nest(doc, RcDoc::text("ASC")),
886 Some(false) => nest(doc, RcDoc::text("DESC")),
887 None => doc,
888 };
889 match v.nulls_last {
890 Some(true) => nest(doc, RcDoc::text("NULLS LAST")),
891 Some(false) => nest(doc, RcDoc::text("NULLS FIRST")),
892 None => doc,
893 }
894 }
895
896 fn doc_query<'a, T: AstInfo>(&'a self, v: &'a Query<T>) -> RcDoc<'a> {
897 let mut docs = vec![];
898 if !v.ctes.is_empty() {
899 match &v.ctes {
900 CteBlock::Simple(ctes) => {
901 docs.push(title_comma_separate("WITH", |cte| self.doc_cte(cte), ctes))
902 }
903 CteBlock::MutuallyRecursive(mutrec) => {
904 let mut doc = RcDoc::text("WITH MUTUALLY RECURSIVE");
905 if !mutrec.options.is_empty() {
906 doc = nest(
907 doc,
908 bracket(
909 "(",
910 comma_separate(|o| self.doc_display_pass(o), &mutrec.options),
911 ")",
912 ),
913 );
914 }
915 docs.push(nest(
916 doc,
917 comma_separate(|c| self.doc_mutually_recursive(c), &mutrec.ctes),
918 ));
919 }
920 }
921 }
922 docs.push(self.doc_set_expr(&v.body));
923 if !v.order_by.is_empty() {
924 docs.push(self.doc_order_by(&v.order_by));
925 }
926
927 let offset = if let Some(offset) = &v.offset {
928 vec![RcDoc::concat([nest_title("OFFSET", self.doc_expr(offset))])]
929 } else {
930 vec![]
931 };
932
933 if let Some(limit) = &v.limit {
934 if limit.with_ties {
935 docs.extend(offset);
936 docs.push(RcDoc::concat([
937 RcDoc::text("FETCH FIRST "),
938 self.doc_expr(&limit.quantity),
939 RcDoc::text(" ROWS WITH TIES"),
940 ]));
941 } else {
942 docs.push(nest_title("LIMIT", self.doc_expr(&limit.quantity)));
943 docs.extend(offset);
944 }
945 } else {
946 docs.extend(offset);
947 }
948
949 RcDoc::intersperse(docs, Doc::line()).group()
950 }
951
952 fn doc_cte<'a, T: AstInfo>(&'a self, v: &'a Cte<T>) -> RcDoc<'a> {
953 RcDoc::concat([
954 RcDoc::text(format!("{} AS", v.alias)),
955 RcDoc::line(),
956 bracket("(", self.doc_query(&v.query), ")"),
957 ])
958 }
959
960 fn doc_mutually_recursive<'a, T: AstInfo>(&'a self, v: &'a CteMutRec<T>) -> RcDoc<'a> {
961 let mut docs = Vec::new();
962 if !v.columns.is_empty() {
963 docs.push(bracket(
964 "(",
965 comma_separate(|c| self.doc_display_pass(c), &v.columns),
966 ")",
967 ));
968 }
969 docs.push(bracket("AS (", self.doc_query(&v.query), ")"));
970 nest(
971 self.doc_display_pass(&v.name),
972 RcDoc::intersperse(docs, Doc::line()).group(),
973 )
974 }
975
976 fn doc_set_expr<'a, T: AstInfo>(&'a self, v: &'a SetExpr<T>) -> RcDoc<'a> {
977 match v {
978 SetExpr::Select(v) => self.doc_select(v),
979 SetExpr::Query(v) => bracket("(", self.doc_query(v), ")"),
980 SetExpr::SetOperation {
981 op,
982 all,
983 left,
984 right,
985 } => {
986 let all_str = if *all { " ALL" } else { "" };
987 RcDoc::concat([
988 self.doc_set_expr(left),
989 RcDoc::line(),
990 RcDoc::concat([
991 RcDoc::text(format!("{}{}", op, all_str)),
992 RcDoc::line(),
993 self.doc_set_expr(right),
994 ])
995 .nest(TAB)
996 .group(),
997 ])
998 }
999 SetExpr::Values(v) => self.doc_values(v),
1000 SetExpr::Show(v) => self.doc_display(v, "SHOW"),
1001 SetExpr::Table(v) => nest(RcDoc::text("TABLE"), self.doc_display_pass(v)),
1002 }
1003 .group()
1004 }
1005
1006 fn doc_values<'a, T: AstInfo>(&'a self, v: &'a Values<T>) -> RcDoc<'a> {
1007 let rows =
1008 v.0.iter()
1009 .map(|row| bracket("(", comma_separate(|v| self.doc_expr(v), row), ")"));
1010 RcDoc::concat([RcDoc::text("VALUES"), RcDoc::line(), comma_separated(rows)])
1011 .nest(TAB)
1012 .group()
1013 }
1014
1015 fn doc_table_with_joins<'a, T: AstInfo>(&'a self, v: &'a TableWithJoins<T>) -> RcDoc<'a> {
1016 let mut docs = vec![self.doc_table_factor(&v.relation)];
1017 for j in &v.joins {
1018 docs.push(self.doc_join(j));
1019 }
1020 intersperse_line_nest(docs)
1021 }
1022
1023 fn doc_join<'a, T: AstInfo>(&'a self, v: &'a Join<T>) -> RcDoc<'a> {
1024 let (constraint, name) = match &v.join_operator {
1025 JoinOperator::Inner(constraint) => (constraint, "JOIN"),
1026 JoinOperator::FullOuter(constraint) => (constraint, "FULL JOIN"),
1027 JoinOperator::LeftOuter(constraint) => (constraint, "LEFT JOIN"),
1028 JoinOperator::RightOuter(constraint) => (constraint, "RIGHT JOIN"),
1029 JoinOperator::CrossJoin => return self.doc_display(v, "join operator"),
1030 };
1031 let constraint = match constraint {
1032 JoinConstraint::On(expr) => nest_title("ON", self.doc_expr(expr)),
1033 JoinConstraint::Using { columns, alias } => {
1034 let mut doc = bracket(
1035 "USING(",
1036 comma_separate(|c| self.doc_display_pass(c), columns),
1037 ")",
1038 );
1039 if let Some(alias) = alias {
1040 doc = nest(doc, nest_title("AS", self.doc_display_pass(alias)));
1041 }
1042 doc
1043 }
1044 JoinConstraint::Natural => return self.doc_display(v, "join constraint"),
1045 };
1046 intersperse_line_nest([
1047 RcDoc::text(name),
1048 self.doc_table_factor(&v.relation),
1049 constraint,
1050 ])
1051 }
1052
1053 fn doc_table_factor<'a, T: AstInfo>(&'a self, v: &'a TableFactor<T>) -> RcDoc<'a> {
1054 match v {
1055 TableFactor::Derived {
1056 lateral,
1057 subquery,
1058 alias,
1059 } => {
1060 let prefix = if *lateral { "LATERAL (" } else { "(" };
1061 let mut docs = vec![bracket(prefix, self.doc_query(subquery), ")")];
1062 if let Some(alias) = alias {
1063 docs.push(RcDoc::text(format!("AS {}", alias)));
1064 }
1065 intersperse_line_nest(docs)
1066 }
1067 TableFactor::NestedJoin { join, alias } => {
1068 let mut doc = bracket("(", self.doc_table_with_joins(join), ")");
1069 if let Some(alias) = alias {
1070 doc = nest(doc, RcDoc::text(format!("AS {}", alias)));
1071 }
1072 doc
1073 }
1074 TableFactor::Table { name, alias } => {
1075 let mut doc = self.doc_display_pass(name);
1076 if let Some(alias) = alias {
1077 doc = nest(doc, RcDoc::text(format!("AS {}", alias)));
1078 }
1079 doc
1080 }
1081 _ => self.doc_display(v, "table factor variant"),
1082 }
1083 }
1084
1085 fn doc_distinct<'a, T: AstInfo>(&'a self, v: &'a Distinct<T>) -> RcDoc<'a> {
1086 match v {
1087 Distinct::EntireRow => RcDoc::text("DISTINCT"),
1088 Distinct::On(cols) => bracket(
1089 "DISTINCT ON (",
1090 comma_separate(|c| self.doc_expr(c), cols),
1091 ")",
1092 ),
1093 }
1094 }
1095
1096 fn doc_select<'a, T: AstInfo>(&'a self, v: &'a Select<T>) -> RcDoc<'a> {
1097 let mut docs = vec![];
1098 let mut select = RcDoc::text("SELECT");
1099 if let Some(distinct) = &v.distinct {
1100 select = nest(select, self.doc_distinct(distinct));
1101 }
1102 docs.push(nest_comma_separate(
1103 select,
1104 |s| self.doc_select_item(s),
1105 &v.projection,
1106 ));
1107 if !v.from.is_empty() {
1108 docs.push(title_comma_separate(
1109 "FROM",
1110 |t| self.doc_table_with_joins(t),
1111 &v.from,
1112 ));
1113 }
1114 if let Some(selection) = &v.selection {
1115 docs.push(nest_title("WHERE", self.doc_expr(selection)));
1116 }
1117 if !v.group_by.is_empty() {
1118 docs.push(title_comma_separate(
1119 "GROUP BY",
1120 |e| self.doc_expr(e),
1121 &v.group_by,
1122 ));
1123 }
1124 if let Some(having) = &v.having {
1125 docs.push(nest_title("HAVING", self.doc_expr(having)));
1126 }
1127 if let Some(qualify) = &v.qualify {
1128 docs.push(nest_title("QUALIFY", self.doc_expr(qualify)));
1129 }
1130 if !v.options.is_empty() {
1131 docs.push(bracket(
1132 "OPTIONS (",
1133 comma_separate(|o| self.doc_display_pass(o), &v.options),
1134 ")",
1135 ));
1136 }
1137 RcDoc::intersperse(docs, Doc::line()).group()
1138 }
1139
1140 fn doc_select_item<'a, T: AstInfo>(&'a self, v: &'a SelectItem<T>) -> RcDoc<'a> {
1141 match v {
1142 SelectItem::Expr { expr, alias } => {
1143 let mut doc = self.doc_expr(expr);
1144 if let Some(alias) = alias {
1145 doc = nest(
1146 doc,
1147 RcDoc::concat([RcDoc::text("AS "), self.doc_display_pass(alias)]),
1148 );
1149 }
1150 doc
1151 }
1152 SelectItem::Wildcard => self.doc_display_pass(v),
1153 }
1154 }
1155
1156 pub fn doc_expr<'a, T: AstInfo>(&'a self, v: &'a Expr<T>) -> RcDoc<'a> {
1157 match v {
1158 Expr::Op { op, expr1, expr2 } => {
1159 if let Some(expr2) = expr2 {
1160 RcDoc::concat([
1161 self.doc_expr(expr1),
1162 RcDoc::line(),
1163 RcDoc::text(format!("{} ", op)),
1164 self.doc_expr(expr2).nest(TAB),
1165 ])
1166 } else {
1167 RcDoc::concat([RcDoc::text(format!("{} ", op)), self.doc_expr(expr1)])
1168 }
1169 }
1170 Expr::Case {
1171 operand,
1172 conditions,
1173 results,
1174 else_result,
1175 } => {
1176 let mut docs = Vec::new();
1177 if let Some(operand) = operand {
1178 docs.push(self.doc_expr(operand));
1179 }
1180 for (c, r) in conditions.iter().zip_eq(results) {
1181 let when = nest_title("WHEN", self.doc_expr(c));
1182 let then = nest_title("THEN", self.doc_expr(r));
1183 docs.push(nest(when, then));
1184 }
1185 if let Some(else_result) = else_result {
1186 docs.push(nest_title("ELSE", self.doc_expr(else_result)));
1187 }
1188 let doc = intersperse_line_nest(docs);
1189 bracket_doc(RcDoc::text("CASE"), doc, RcDoc::text("END"), RcDoc::line())
1190 }
1191 Expr::Cast { expr, data_type } => {
1192 let doc = self.doc_expr(expr);
1193 RcDoc::concat([
1194 doc,
1195 RcDoc::text(format!("::{}", data_type.to_ast_string_simple())),
1196 ])
1197 }
1198 Expr::Nested(ast) => bracket("(", self.doc_expr(ast), ")"),
1199 Expr::Function(fun) => self.doc_function(fun),
1200 Expr::Subquery(ast) => bracket("(", self.doc_query(ast), ")"),
1201 Expr::Identifier(_)
1202 | Expr::Value(_)
1203 | Expr::QualifiedWildcard(_)
1204 | Expr::WildcardAccess(_)
1205 | Expr::FieldAccess { .. } => self.doc_display_pass(v),
1206 Expr::And { left, right } => bracket_doc(
1207 self.doc_expr(left),
1208 RcDoc::text("AND"),
1209 self.doc_expr(right),
1210 RcDoc::line(),
1211 ),
1212 Expr::Or { left, right } => bracket_doc(
1213 self.doc_expr(left),
1214 RcDoc::text("OR"),
1215 self.doc_expr(right),
1216 RcDoc::line(),
1217 ),
1218 Expr::Exists(s) => bracket("EXISTS (", self.doc_query(s), ")"),
1219 Expr::IsExpr {
1220 expr,
1221 negated,
1222 construct,
1223 } => bracket_doc(
1224 self.doc_expr(expr),
1225 RcDoc::text(if *negated { "IS NOT" } else { "IS" }),
1226 self.doc_display_pass(construct),
1227 RcDoc::line(),
1228 ),
1229 Expr::Not { expr } => {
1230 RcDoc::concat([RcDoc::text("NOT"), RcDoc::line(), self.doc_expr(expr)])
1231 }
1232 Expr::Between {
1233 expr,
1234 negated,
1235 low,
1236 high,
1237 } => RcDoc::intersperse(
1238 [
1239 self.doc_expr(expr),
1240 RcDoc::text(if *negated { "NOT BETWEEN" } else { "BETWEEN" }),
1241 RcDoc::intersperse(
1242 [self.doc_expr(low), RcDoc::text("AND"), self.doc_expr(high)],
1243 RcDoc::line(),
1244 )
1245 .group(),
1246 ],
1247 RcDoc::line(),
1248 ),
1249 Expr::InSubquery {
1250 expr,
1251 subquery,
1252 negated,
1253 } => RcDoc::intersperse(
1254 [
1255 self.doc_expr(expr),
1256 RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }),
1257 self.doc_query(subquery),
1258 RcDoc::text(")"),
1259 ],
1260 RcDoc::line(),
1261 ),
1262 Expr::InList {
1263 expr,
1264 list,
1265 negated,
1266 } => RcDoc::intersperse(
1267 [
1268 self.doc_expr(expr),
1269 RcDoc::text(if *negated { "NOT IN (" } else { "IN (" }),
1270 comma_separate(|e| self.doc_expr(e), list),
1271 RcDoc::text(")"),
1272 ],
1273 RcDoc::line(),
1274 ),
1275 Expr::Row { exprs } => {
1276 bracket("ROW(", comma_separate(|e| self.doc_expr(e), exprs), ")")
1277 }
1278 Expr::NullIf { l_expr, r_expr } => bracket(
1279 "NULLIF (",
1280 comma_separate(|e| self.doc_expr(e), [&**l_expr, &**r_expr]),
1281 ")",
1282 ),
1283 Expr::HomogenizingFunction { function, exprs } => bracket(
1284 format!("{function}("),
1285 comma_separate(|e| self.doc_expr(e), exprs),
1286 ")",
1287 ),
1288 Expr::ArraySubquery(s) => bracket("ARRAY(", self.doc_query(s), ")"),
1289 Expr::ListSubquery(s) => bracket("LIST(", self.doc_query(s), ")"),
1290 Expr::Array(exprs) => {
1291 bracket("ARRAY[", comma_separate(|e| self.doc_expr(e), exprs), "]")
1292 }
1293 Expr::List(exprs) => bracket("LIST[", comma_separate(|e| self.doc_expr(e), exprs), "]"),
1294 _ => self.doc_display(v, "expr variant"),
1295 }
1296 .group()
1297 }
1298
1299 fn doc_function<'a, T: AstInfo>(&'a self, v: &'a Function<T>) -> RcDoc<'a> {
1300 match &v.args {
1301 FunctionArgs::Star => self.doc_display_pass(v),
1302 FunctionArgs::Args { args, order_by } => {
1303 if args.is_empty() {
1304 return self.doc_display_pass(v);
1306 }
1307 if v.filter.is_some() || v.over.is_some() || !order_by.is_empty() {
1308 return self.doc_display(v, "function filter or over or order by");
1309 }
1310 let special = match v.name.to_ast_string_stable().as_str() {
1311 r#""extract""# if v.args.len() == Some(2) => true,
1312 r#""position""# if v.args.len() == Some(2) => true,
1313 _ => false,
1314 };
1315 if special {
1316 return self.doc_display(v, "special function");
1317 }
1318 let name = format!(
1319 "{}({}",
1320 v.name.to_ast_string_simple(),
1321 if v.distinct { "DISTINCT " } else { "" }
1322 );
1323 bracket(name, comma_separate(|e| self.doc_expr(e), args), ")")
1324 }
1325 }
1326 }
1327}