Skip to main content

sqlglot_rust/generator/
sql_generator.rs

1use crate::ast::*;
2
3/// SQL code generator that converts an AST into a SQL string.
4///
5/// Supports all statement and expression types defined in the AST,
6/// including CTEs, subqueries, UNION/INTERSECT/EXCEPT, CAST, window
7/// functions, EXISTS, EXTRACT, INTERVAL, and more.
8pub struct Generator {
9    output: String,
10    /// When true, emit formatted SQL with indentation and newlines.
11    pretty: bool,
12    indent: usize,
13}
14
15impl Generator {
16    #[must_use]
17    pub fn new() -> Self {
18        Self {
19            output: String::new(),
20            pretty: false,
21            indent: 0,
22        }
23    }
24
25    /// Create a generator that produces formatted SQL.
26    #[must_use]
27    pub fn pretty() -> Self {
28        Self {
29            output: String::new(),
30            pretty: true,
31            indent: 0,
32        }
33    }
34
35    /// Generate SQL from a statement.
36    #[must_use]
37    pub fn generate(&mut self, statement: &Statement) -> String {
38        self.output.clear();
39        self.gen_statement(statement);
40        self.output.clone()
41    }
42
43    /// Generate SQL for an expression (static helper for `Expr::sql()`).
44    #[must_use]
45    pub fn expr_to_sql(expr: &Expr) -> String {
46        let mut g = Self::new();
47        g.gen_expr(expr);
48        g.output
49    }
50
51    fn write(&mut self, s: &str) {
52        self.output.push_str(s);
53    }
54
55    /// Emit a newline followed by current indentation (pretty mode only).
56    fn newline(&mut self) {
57        if self.pretty {
58            self.output.push('\n');
59            for _ in 0..self.indent {
60                self.output.push_str("  ");
61            }
62        }
63    }
64
65    /// In pretty mode: newline + indent. In compact mode: a single space.
66    fn sep(&mut self) {
67        if self.pretty {
68            self.newline();
69        } else {
70            self.output.push(' ');
71        }
72    }
73
74    fn indent_up(&mut self) {
75        self.indent += 1;
76    }
77
78    fn indent_down(&mut self) {
79        self.indent = self.indent.saturating_sub(1);
80    }
81
82    fn write_keyword(&mut self, s: &str) {
83        self.write(s);
84    }
85
86    /// Write an identifier with the given quoting style.
87    fn write_quoted(&mut self, name: &str, style: QuoteStyle) {
88        match style {
89            QuoteStyle::None => self.write(name),
90            QuoteStyle::DoubleQuote => {
91                self.write("\"");
92                self.write(&name.replace('"', "\"\""));
93                self.write("\"");
94            }
95            QuoteStyle::Backtick => {
96                self.write("`");
97                self.write(&name.replace('`', "``"));
98                self.write("`");
99            }
100            QuoteStyle::Bracket => {
101                self.write("[");
102                self.write(&name.replace(']', "]]"));
103                self.write("]");
104            }
105        }
106    }
107
108    // ══════════════════════════════════════════════════════════════
109    // Statements
110    // ══════════════════════════════════════════════════════════════
111
112    fn gen_statement(&mut self, statement: &Statement) {
113        match statement {
114            Statement::Select(s) => self.gen_select(s),
115            Statement::Insert(s) => self.gen_insert(s),
116            Statement::Update(s) => self.gen_update(s),
117            Statement::Delete(s) => self.gen_delete(s),
118            Statement::CreateTable(s) => self.gen_create_table(s),
119            Statement::DropTable(s) => self.gen_drop_table(s),
120            Statement::SetOperation(s) => self.gen_set_operation(s),
121            Statement::AlterTable(s) => self.gen_alter_table(s),
122            Statement::CreateView(s) => self.gen_create_view(s),
123            Statement::DropView(s) => self.gen_drop_view(s),
124            Statement::Truncate(s) => self.gen_truncate(s),
125            Statement::Transaction(s) => self.gen_transaction(s),
126            Statement::Explain(s) => self.gen_explain(s),
127            Statement::Use(s) => self.gen_use(s),
128            Statement::Expression(e) => self.gen_expr(e),
129        }
130    }
131
132    // ── SELECT ──────────────────────────────────────────────────
133
134    fn gen_select(&mut self, sel: &SelectStatement) {
135        // CTEs
136        if !sel.ctes.is_empty() {
137            self.gen_ctes(&sel.ctes);
138            self.sep();
139        }
140
141        self.write_keyword("SELECT");
142        if sel.distinct {
143            self.write(" ");
144            self.write_keyword("DISTINCT");
145        }
146        if let Some(top) = &sel.top {
147            self.write(" ");
148            self.write_keyword("TOP ");
149            self.gen_expr(top);
150        }
151
152        // columns
153        if self.pretty {
154            self.indent_up();
155            for (i, item) in sel.columns.iter().enumerate() {
156                self.newline();
157                self.gen_select_item(item);
158                if i < sel.columns.len() - 1 {
159                    self.write(",");
160                }
161            }
162            self.indent_down();
163        } else {
164            self.write(" ");
165            for (i, item) in sel.columns.iter().enumerate() {
166                if i > 0 {
167                    self.write(", ");
168                }
169                self.gen_select_item(item);
170            }
171        }
172
173        if let Some(from) = &sel.from {
174            self.sep();
175            self.write_keyword("FROM");
176            if self.pretty {
177                self.indent_up();
178                self.newline();
179                self.gen_table_source(&from.source);
180                self.indent_down();
181            } else {
182                self.write(" ");
183                self.gen_table_source(&from.source);
184            }
185        }
186
187        for join in &sel.joins {
188            self.gen_join(join);
189        }
190
191        if let Some(wh) = &sel.where_clause {
192            self.sep();
193            self.write_keyword("WHERE");
194            if self.pretty {
195                self.indent_up();
196                self.newline();
197                self.gen_expr(wh);
198                self.indent_down();
199            } else {
200                self.write(" ");
201                self.gen_expr(wh);
202            }
203        }
204
205        if !sel.group_by.is_empty() {
206            self.sep();
207            self.write_keyword("GROUP BY");
208            if self.pretty {
209                self.indent_up();
210                self.newline();
211                self.gen_expr_list(&sel.group_by);
212                self.indent_down();
213            } else {
214                self.write(" ");
215                self.gen_expr_list(&sel.group_by);
216            }
217        }
218
219        if let Some(having) = &sel.having {
220            self.sep();
221            self.write_keyword("HAVING");
222            if self.pretty {
223                self.indent_up();
224                self.newline();
225                self.gen_expr(having);
226                self.indent_down();
227            } else {
228                self.write(" ");
229                self.gen_expr(having);
230            }
231        }
232
233        if let Some(qualify) = &sel.qualify {
234            self.sep();
235            self.write_keyword("QUALIFY");
236            if self.pretty {
237                self.indent_up();
238                self.newline();
239                self.gen_expr(qualify);
240                self.indent_down();
241            } else {
242                self.write(" ");
243                self.gen_expr(qualify);
244            }
245        }
246
247        if !sel.window_definitions.is_empty() {
248            self.sep();
249            self.write_keyword("WINDOW ");
250            for (i, wd) in sel.window_definitions.iter().enumerate() {
251                if i > 0 {
252                    self.write(", ");
253                }
254                self.write(&wd.name);
255                self.write(" AS (");
256                self.gen_window_spec(&wd.spec);
257                self.write(")");
258            }
259        }
260
261        self.gen_order_by(&sel.order_by);
262
263        if let Some(limit) = &sel.limit {
264            self.sep();
265            self.write_keyword("LIMIT ");
266            self.gen_expr(limit);
267        }
268
269        if let Some(offset) = &sel.offset {
270            self.sep();
271            self.write_keyword("OFFSET ");
272            self.gen_expr(offset);
273        }
274
275        if let Some(fetch) = &sel.fetch_first {
276            self.sep();
277            self.write_keyword("FETCH FIRST ");
278            self.gen_expr(fetch);
279            self.write(" ");
280            self.write_keyword("ROWS ONLY");
281        }
282    }
283
284    fn gen_ctes(&mut self, ctes: &[Cte]) {
285        self.write_keyword("WITH ");
286        if ctes.iter().any(|c| c.recursive) {
287            self.write_keyword("RECURSIVE ");
288        }
289        for (i, cte) in ctes.iter().enumerate() {
290            if i > 0 {
291                self.write(",");
292                self.sep();
293            }
294            self.write(&cte.name);
295            if !cte.columns.is_empty() {
296                self.write("(");
297                self.write(&cte.columns.join(", "));
298                self.write(")");
299            }
300            self.write(" ");
301            self.write_keyword("AS ");
302            if let Some(true) = cte.materialized {
303                self.write_keyword("MATERIALIZED ");
304            } else if let Some(false) = cte.materialized {
305                self.write_keyword("NOT MATERIALIZED ");
306            }
307            self.write("(");
308            if self.pretty {
309                self.indent_up();
310                self.newline();
311                self.gen_statement(&cte.query);
312                self.indent_down();
313                self.newline();
314            } else {
315                self.gen_statement(&cte.query);
316            }
317            self.write(")");
318        }
319    }
320
321    fn gen_select_item(&mut self, item: &SelectItem) {
322        match item {
323            SelectItem::Wildcard => self.write("*"),
324            SelectItem::QualifiedWildcard { table } => {
325                self.write(table);
326                self.write(".*");
327            }
328            SelectItem::Expr { expr, alias } => {
329                self.gen_expr(expr);
330                if let Some(alias) = alias {
331                    self.write(" ");
332                    self.write_keyword("AS ");
333                    self.write(alias);
334                }
335            }
336        }
337    }
338
339    fn gen_table_source(&mut self, source: &TableSource) {
340        match source {
341            TableSource::Table(table_ref) => self.gen_table_ref(table_ref),
342            TableSource::Subquery { query, alias } => {
343                self.write("(");
344                self.gen_statement(query);
345                self.write(")");
346                if let Some(alias) = alias {
347                    self.write(" ");
348                    self.write_keyword("AS ");
349                    self.write(alias);
350                }
351            }
352            TableSource::TableFunction { name, args, alias } => {
353                self.write(name);
354                self.write("(");
355                self.gen_expr_list(args);
356                self.write(")");
357                if let Some(alias) = alias {
358                    self.write(" ");
359                    self.write_keyword("AS ");
360                    self.write(alias);
361                }
362            }
363            TableSource::Lateral { source } => {
364                self.write_keyword("LATERAL ");
365                self.gen_table_source(source);
366            }
367            TableSource::Unnest {
368                expr,
369                alias,
370                with_offset,
371            } => {
372                self.write_keyword("UNNEST(");
373                self.gen_expr(expr);
374                self.write(")");
375                if let Some(alias) = alias {
376                    self.write(" ");
377                    self.write_keyword("AS ");
378                    self.write(alias);
379                }
380                if *with_offset {
381                    self.write(" ");
382                    self.write_keyword("WITH OFFSET");
383                }
384            }
385        }
386    }
387
388    fn gen_table_ref(&mut self, table: &TableRef) {
389        if let Some(catalog) = &table.catalog {
390            self.write(catalog);
391            self.write(".");
392        }
393        if let Some(schema) = &table.schema {
394            self.write(schema);
395            self.write(".");
396        }
397        self.write_quoted(&table.name, table.name_quote_style);
398        if let Some(alias) = &table.alias {
399            self.write(" ");
400            self.write_keyword("AS ");
401            self.write(alias);
402        }
403    }
404
405    fn gen_join(&mut self, join: &JoinClause) {
406        let join_kw = match join.join_type {
407            JoinType::Inner => "INNER JOIN",
408            JoinType::Left => "LEFT JOIN",
409            JoinType::Right => "RIGHT JOIN",
410            JoinType::Full => "FULL JOIN",
411            JoinType::Cross => "CROSS JOIN",
412            JoinType::Natural => "NATURAL JOIN",
413            JoinType::Lateral => "LATERAL JOIN",
414        };
415        self.sep();
416        self.write_keyword(join_kw);
417        if self.pretty {
418            self.indent_up();
419            self.newline();
420            self.gen_table_source(&join.table);
421        } else {
422            self.write(" ");
423            self.gen_table_source(&join.table);
424        }
425        if let Some(on) = &join.on {
426            if self.pretty {
427                self.newline();
428            } else {
429                self.write(" ");
430            }
431            self.write_keyword("ON ");
432            self.gen_expr(on);
433        }
434        if !join.using.is_empty() {
435            if self.pretty {
436                self.newline();
437            } else {
438                self.write(" ");
439            }
440            self.write_keyword("USING (");
441            self.write(&join.using.join(", "));
442            self.write(")");
443        }
444        if self.pretty {
445            self.indent_down();
446        }
447    }
448
449    fn gen_order_by(&mut self, items: &[OrderByItem]) {
450        if items.is_empty() {
451            return;
452        }
453        self.sep();
454        self.write_keyword("ORDER BY");
455        if self.pretty {
456            self.indent_up();
457            self.newline();
458        } else {
459            self.write(" ");
460        }
461        for (i, item) in items.iter().enumerate() {
462            if i > 0 {
463                self.write(", ");
464            }
465            self.gen_expr(&item.expr);
466            if !item.ascending {
467                self.write(" ");
468                self.write_keyword("DESC");
469            }
470            if let Some(nulls_first) = item.nulls_first {
471                if nulls_first {
472                    self.write(" ");
473                    self.write_keyword("NULLS FIRST");
474                } else {
475                    self.write(" ");
476                    self.write_keyword("NULLS LAST");
477                }
478            }
479        }
480        if self.pretty {
481            self.indent_down();
482        }
483    }
484
485    // ── Set operations ──────────────────────────────────────────
486
487    fn gen_set_operation(&mut self, sop: &SetOperationStatement) {
488        self.gen_statement(&sop.left);
489        let op_kw = match sop.op {
490            SetOperationType::Union => "UNION",
491            SetOperationType::Intersect => "INTERSECT",
492            SetOperationType::Except => "EXCEPT",
493        };
494        self.sep();
495        self.write_keyword(op_kw);
496        if sop.all {
497            self.write(" ");
498            self.write_keyword("ALL");
499        }
500        self.sep();
501        self.gen_statement(&sop.right);
502
503        self.gen_order_by(&sop.order_by);
504
505        if let Some(limit) = &sop.limit {
506            self.sep();
507            self.write_keyword("LIMIT ");
508            self.gen_expr(limit);
509        }
510        if let Some(offset) = &sop.offset {
511            self.sep();
512            self.write_keyword("OFFSET ");
513            self.gen_expr(offset);
514        }
515    }
516
517    // ── INSERT ──────────────────────────────────────────────────
518
519    fn gen_insert(&mut self, ins: &InsertStatement) {
520        self.write_keyword("INSERT INTO ");
521        self.gen_table_ref(&ins.table);
522
523        if !ins.columns.is_empty() {
524            self.write(" (");
525            self.write(&ins.columns.join(", "));
526            self.write(")");
527        }
528
529        match &ins.source {
530            InsertSource::Values(rows) => {
531                self.sep();
532                self.write_keyword("VALUES");
533                if self.pretty {
534                    self.indent_up();
535                    for (i, row) in rows.iter().enumerate() {
536                        self.newline();
537                        self.write("(");
538                        self.gen_expr_list(row);
539                        self.write(")");
540                        if i < rows.len() - 1 {
541                            self.write(",");
542                        }
543                    }
544                    self.indent_down();
545                } else {
546                    self.write(" ");
547                    for (i, row) in rows.iter().enumerate() {
548                        if i > 0 {
549                            self.write(", ");
550                        }
551                        self.write("(");
552                        self.gen_expr_list(row);
553                        self.write(")");
554                    }
555                }
556            }
557            InsertSource::Query(query) => {
558                self.sep();
559                self.gen_statement(query);
560            }
561            InsertSource::Default => {
562                self.sep();
563                self.write_keyword("DEFAULT VALUES");
564            }
565        }
566
567        if let Some(on_conflict) = &ins.on_conflict {
568            self.sep();
569            self.write_keyword("ON CONFLICT");
570            if !on_conflict.columns.is_empty() {
571                self.write(" (");
572                self.write(&on_conflict.columns.join(", "));
573                self.write(")");
574            }
575            match &on_conflict.action {
576                ConflictAction::DoNothing => {
577                    self.write(" ");
578                    self.write_keyword("DO NOTHING");
579                }
580                ConflictAction::DoUpdate(assignments) => {
581                    self.write(" ");
582                    self.write_keyword("DO UPDATE SET ");
583                    for (i, (col, val)) in assignments.iter().enumerate() {
584                        if i > 0 {
585                            self.write(", ");
586                        }
587                        self.write(col);
588                        self.write(" = ");
589                        self.gen_expr(val);
590                    }
591                }
592            }
593        }
594
595        if !ins.returning.is_empty() {
596            self.sep();
597            self.write_keyword("RETURNING ");
598            for (i, item) in ins.returning.iter().enumerate() {
599                if i > 0 {
600                    self.write(", ");
601                }
602                self.gen_select_item(item);
603            }
604        }
605    }
606
607    // ── UPDATE ──────────────────────────────────────────────────
608
609    fn gen_update(&mut self, upd: &UpdateStatement) {
610        self.write_keyword("UPDATE ");
611        self.gen_table_ref(&upd.table);
612        self.sep();
613        self.write_keyword("SET");
614
615        if self.pretty {
616            self.indent_up();
617            for (i, (col, val)) in upd.assignments.iter().enumerate() {
618                self.newline();
619                self.write(col);
620                self.write(" = ");
621                self.gen_expr(val);
622                if i < upd.assignments.len() - 1 {
623                    self.write(",");
624                }
625            }
626            self.indent_down();
627        } else {
628            self.write(" ");
629            for (i, (col, val)) in upd.assignments.iter().enumerate() {
630                if i > 0 {
631                    self.write(", ");
632                }
633                self.write(col);
634                self.write(" = ");
635                self.gen_expr(val);
636            }
637        }
638
639        if let Some(from) = &upd.from {
640            self.sep();
641            self.write_keyword("FROM ");
642            self.gen_table_source(&from.source);
643        }
644
645        if let Some(wh) = &upd.where_clause {
646            self.sep();
647            self.write_keyword("WHERE");
648            if self.pretty {
649                self.indent_up();
650                self.newline();
651                self.gen_expr(wh);
652                self.indent_down();
653            } else {
654                self.write(" ");
655                self.gen_expr(wh);
656            }
657        }
658
659        if !upd.returning.is_empty() {
660            self.sep();
661            self.write_keyword("RETURNING ");
662            for (i, item) in upd.returning.iter().enumerate() {
663                if i > 0 {
664                    self.write(", ");
665                }
666                self.gen_select_item(item);
667            }
668        }
669    }
670
671    // ── DELETE ──────────────────────────────────────────────────
672
673    fn gen_delete(&mut self, del: &DeleteStatement) {
674        self.write_keyword("DELETE FROM ");
675        self.gen_table_ref(&del.table);
676
677        if let Some(using) = &del.using {
678            self.sep();
679            self.write_keyword("USING ");
680            self.gen_table_source(&using.source);
681        }
682
683        if let Some(wh) = &del.where_clause {
684            self.sep();
685            self.write_keyword("WHERE");
686            if self.pretty {
687                self.indent_up();
688                self.newline();
689                self.gen_expr(wh);
690                self.indent_down();
691            } else {
692                self.write(" ");
693                self.gen_expr(wh);
694            }
695        }
696
697        if !del.returning.is_empty() {
698            self.sep();
699            self.write_keyword("RETURNING ");
700            for (i, item) in del.returning.iter().enumerate() {
701                if i > 0 {
702                    self.write(", ");
703                }
704                self.gen_select_item(item);
705            }
706        }
707    }
708
709    // ── CREATE TABLE ────────────────────────────────────────────
710
711    fn gen_create_table(&mut self, ct: &CreateTableStatement) {
712        self.write_keyword("CREATE ");
713        if ct.temporary {
714            self.write_keyword("TEMPORARY ");
715        }
716        self.write_keyword("TABLE ");
717        if ct.if_not_exists {
718            self.write_keyword("IF NOT EXISTS ");
719        }
720        self.gen_table_ref(&ct.table);
721
722        if let Some(as_select) = &ct.as_select {
723            self.write(" ");
724            self.write_keyword("AS ");
725            self.gen_statement(as_select);
726            return;
727        }
728
729        self.write(" (");
730
731        if self.pretty {
732            self.indent_up();
733            for (i, col) in ct.columns.iter().enumerate() {
734                self.newline();
735                self.gen_column_def(col);
736                if i < ct.columns.len() - 1 || !ct.constraints.is_empty() {
737                    self.write(",");
738                }
739            }
740            for (i, constraint) in ct.constraints.iter().enumerate() {
741                self.newline();
742                self.gen_table_constraint(constraint);
743                if i < ct.constraints.len() - 1 {
744                    self.write(",");
745                }
746            }
747            self.indent_down();
748            self.newline();
749        } else {
750            for (i, col) in ct.columns.iter().enumerate() {
751                if i > 0 {
752                    self.write(", ");
753                }
754                self.gen_column_def(col);
755            }
756            for (i, constraint) in ct.constraints.iter().enumerate() {
757                if i + ct.columns.len() > 0 {
758                    self.write(", ");
759                }
760                self.gen_table_constraint(constraint);
761            }
762        }
763
764        self.write(")");
765    }
766
767    fn gen_column_def(&mut self, col: &ColumnDef) {
768        self.write(&col.name);
769        self.write(" ");
770        self.gen_data_type(&col.data_type);
771
772        if col.primary_key {
773            self.write(" ");
774            self.write_keyword("PRIMARY KEY");
775        }
776        if col.unique {
777            self.write(" ");
778            self.write_keyword("UNIQUE");
779        }
780        if col.auto_increment {
781            self.write(" ");
782            self.write_keyword("AUTOINCREMENT");
783        }
784
785        match col.nullable {
786            Some(false) => {
787                self.write(" ");
788                self.write_keyword("NOT NULL");
789            }
790            Some(true) => {
791                self.write(" ");
792                self.write_keyword("NULL");
793            }
794            None => {}
795        }
796
797        if let Some(default) = &col.default {
798            self.write(" ");
799            self.write_keyword("DEFAULT ");
800            self.gen_expr(default);
801        }
802
803        if let Some(collation) = &col.collation {
804            self.write(" ");
805            self.write_keyword("COLLATE ");
806            self.write(collation);
807        }
808
809        if let Some(comment) = &col.comment {
810            self.write(" ");
811            self.write_keyword("COMMENT '");
812            self.write(&comment.replace('\'', "''"));
813            self.write("'");
814        }
815    }
816
817    fn gen_table_constraint(&mut self, constraint: &TableConstraint) {
818        match constraint {
819            TableConstraint::PrimaryKey { name, columns } => {
820                if let Some(name) = name {
821                    self.write_keyword("CONSTRAINT ");
822                    self.write(name);
823                    self.write(" ");
824                }
825                self.write_keyword("PRIMARY KEY (");
826                self.write(&columns.join(", "));
827                self.write(")");
828            }
829            TableConstraint::Unique { name, columns } => {
830                if let Some(name) = name {
831                    self.write_keyword("CONSTRAINT ");
832                    self.write(name);
833                    self.write(" ");
834                }
835                self.write_keyword("UNIQUE (");
836                self.write(&columns.join(", "));
837                self.write(")");
838            }
839            TableConstraint::ForeignKey {
840                name,
841                columns,
842                ref_table,
843                ref_columns,
844                on_delete,
845                on_update,
846            } => {
847                if let Some(name) = name {
848                    self.write_keyword("CONSTRAINT ");
849                    self.write(name);
850                    self.write(" ");
851                }
852                self.write_keyword("FOREIGN KEY (");
853                self.write(&columns.join(", "));
854                self.write(") ");
855                self.write_keyword("REFERENCES ");
856                self.gen_table_ref(ref_table);
857                self.write(" (");
858                self.write(&ref_columns.join(", "));
859                self.write(")");
860                if let Some(action) = on_delete {
861                    self.write(" ");
862                    self.write_keyword("ON DELETE ");
863                    self.gen_referential_action(action);
864                }
865                if let Some(action) = on_update {
866                    self.write(" ");
867                    self.write_keyword("ON UPDATE ");
868                    self.gen_referential_action(action);
869                }
870            }
871            TableConstraint::Check { name, expr } => {
872                if let Some(name) = name {
873                    self.write_keyword("CONSTRAINT ");
874                    self.write(name);
875                    self.write(" ");
876                }
877                self.write_keyword("CHECK (");
878                self.gen_expr(expr);
879                self.write(")");
880            }
881        }
882    }
883
884    fn gen_referential_action(&mut self, action: &ReferentialAction) {
885        match action {
886            ReferentialAction::Cascade => self.write_keyword("CASCADE"),
887            ReferentialAction::Restrict => self.write_keyword("RESTRICT"),
888            ReferentialAction::NoAction => self.write_keyword("NO ACTION"),
889            ReferentialAction::SetNull => self.write_keyword("SET NULL"),
890            ReferentialAction::SetDefault => self.write_keyword("SET DEFAULT"),
891        }
892    }
893
894    // ── DROP TABLE ──────────────────────────────────────────────
895
896    fn gen_drop_table(&mut self, dt: &DropTableStatement) {
897        self.write_keyword("DROP TABLE ");
898        if dt.if_exists {
899            self.write_keyword("IF EXISTS ");
900        }
901        self.gen_table_ref(&dt.table);
902        if dt.cascade {
903            self.write(" ");
904            self.write_keyword("CASCADE");
905        }
906    }
907
908    // ── ALTER TABLE ─────────────────────────────────────────────
909
910    fn gen_alter_table(&mut self, alt: &AlterTableStatement) {
911        self.write_keyword("ALTER TABLE ");
912        self.gen_table_ref(&alt.table);
913
914        for (i, action) in alt.actions.iter().enumerate() {
915            if i > 0 {
916                self.write(",");
917            }
918            self.write(" ");
919            match action {
920                AlterTableAction::AddColumn(col) => {
921                    self.write_keyword("ADD COLUMN ");
922                    self.gen_column_def(col);
923                }
924                AlterTableAction::DropColumn { name, if_exists } => {
925                    self.write_keyword("DROP COLUMN ");
926                    if *if_exists {
927                        self.write_keyword("IF EXISTS ");
928                    }
929                    self.write(name);
930                }
931                AlterTableAction::RenameColumn { old_name, new_name } => {
932                    self.write_keyword("RENAME COLUMN ");
933                    self.write(old_name);
934                    self.write(" ");
935                    self.write_keyword("TO ");
936                    self.write(new_name);
937                }
938                AlterTableAction::AlterColumnType { name, data_type } => {
939                    self.write_keyword("ALTER COLUMN ");
940                    self.write(name);
941                    self.write(" ");
942                    self.write_keyword("TYPE ");
943                    self.gen_data_type(data_type);
944                }
945                AlterTableAction::AddConstraint(constraint) => {
946                    self.write_keyword("ADD ");
947                    self.gen_table_constraint(constraint);
948                }
949                AlterTableAction::DropConstraint { name } => {
950                    self.write_keyword("DROP CONSTRAINT ");
951                    self.write(name);
952                }
953                AlterTableAction::RenameTable { new_name } => {
954                    self.write_keyword("RENAME TO ");
955                    self.write(new_name);
956                }
957            }
958        }
959    }
960
961    // ── CREATE / DROP VIEW ──────────────────────────────────────
962
963    fn gen_create_view(&mut self, cv: &CreateViewStatement) {
964        self.write_keyword("CREATE ");
965        if cv.or_replace {
966            self.write_keyword("OR REPLACE ");
967        }
968        if cv.materialized {
969            self.write_keyword("MATERIALIZED ");
970        }
971        self.write_keyword("VIEW ");
972        if cv.if_not_exists {
973            self.write_keyword("IF NOT EXISTS ");
974        }
975        self.gen_table_ref(&cv.name);
976
977        if !cv.columns.is_empty() {
978            self.write(" (");
979            self.write(&cv.columns.join(", "));
980            self.write(")");
981        }
982
983        self.write(" ");
984        self.write_keyword("AS ");
985        self.gen_statement(&cv.query);
986    }
987
988    fn gen_drop_view(&mut self, dv: &DropViewStatement) {
989        self.write_keyword("DROP ");
990        if dv.materialized {
991            self.write_keyword("MATERIALIZED ");
992        }
993        self.write_keyword("VIEW ");
994        if dv.if_exists {
995            self.write_keyword("IF EXISTS ");
996        }
997        self.gen_table_ref(&dv.name);
998    }
999
1000    // ── TRUNCATE ────────────────────────────────────────────────
1001
1002    fn gen_truncate(&mut self, t: &TruncateStatement) {
1003        self.write_keyword("TRUNCATE TABLE ");
1004        self.gen_table_ref(&t.table);
1005    }
1006
1007    // ── Transaction ─────────────────────────────────────────────
1008
1009    fn gen_transaction(&mut self, t: &TransactionStatement) {
1010        match t {
1011            TransactionStatement::Begin => self.write_keyword("BEGIN"),
1012            TransactionStatement::Commit => self.write_keyword("COMMIT"),
1013            TransactionStatement::Rollback => self.write_keyword("ROLLBACK"),
1014            TransactionStatement::Savepoint(name) => {
1015                self.write_keyword("SAVEPOINT ");
1016                self.write(name);
1017            }
1018            TransactionStatement::ReleaseSavepoint(name) => {
1019                self.write_keyword("RELEASE SAVEPOINT ");
1020                self.write(name);
1021            }
1022            TransactionStatement::RollbackTo(name) => {
1023                self.write_keyword("ROLLBACK TO SAVEPOINT ");
1024                self.write(name);
1025            }
1026        }
1027    }
1028
1029    // ── EXPLAIN ─────────────────────────────────────────────────
1030
1031    fn gen_explain(&mut self, e: &ExplainStatement) {
1032        self.write_keyword("EXPLAIN ");
1033        if e.analyze {
1034            self.write_keyword("ANALYZE ");
1035        }
1036        self.gen_statement(&e.statement);
1037    }
1038
1039    // ── USE ─────────────────────────────────────────────────────
1040
1041    fn gen_use(&mut self, u: &UseStatement) {
1042        self.write_keyword("USE ");
1043        self.write(&u.name);
1044    }
1045
1046    // ══════════════════════════════════════════════════════════════
1047    // Data types
1048    // ══════════════════════════════════════════════════════════════
1049
1050    fn gen_data_type(&mut self, dt: &DataType) {
1051        match dt {
1052            DataType::TinyInt => self.write("TINYINT"),
1053            DataType::SmallInt => self.write("SMALLINT"),
1054            DataType::Int => self.write("INT"),
1055            DataType::BigInt => self.write("BIGINT"),
1056            DataType::Float => self.write("FLOAT"),
1057            DataType::Double => self.write("DOUBLE"),
1058            DataType::Real => self.write("REAL"),
1059            DataType::Decimal { precision, scale } | DataType::Numeric { precision, scale } => {
1060                self.write(if matches!(dt, DataType::Numeric { .. }) {
1061                    "NUMERIC"
1062                } else {
1063                    "DECIMAL"
1064                });
1065                if let Some(p) = precision {
1066                    self.write(&format!("({p}"));
1067                    if let Some(s) = scale {
1068                        self.write(&format!(", {s}"));
1069                    }
1070                    self.write(")");
1071                }
1072            }
1073            DataType::Varchar(len) => {
1074                self.write("VARCHAR");
1075                if let Some(n) = len {
1076                    self.write(&format!("({n})"));
1077                }
1078            }
1079            DataType::Char(len) => {
1080                self.write("CHAR");
1081                if let Some(n) = len {
1082                    self.write(&format!("({n})"));
1083                }
1084            }
1085            DataType::Text => self.write("TEXT"),
1086            DataType::String => self.write("STRING"),
1087            DataType::Binary(len) => {
1088                self.write("BINARY");
1089                if let Some(n) = len {
1090                    self.write(&format!("({n})"));
1091                }
1092            }
1093            DataType::Varbinary(len) => {
1094                self.write("VARBINARY");
1095                if let Some(n) = len {
1096                    self.write(&format!("({n})"));
1097                }
1098            }
1099            DataType::Boolean => self.write("BOOLEAN"),
1100            DataType::Date => self.write("DATE"),
1101            DataType::Time { precision } => {
1102                self.write("TIME");
1103                if let Some(p) = precision {
1104                    self.write(&format!("({p})"));
1105                }
1106            }
1107            DataType::Timestamp { precision, with_tz } => {
1108                self.write("TIMESTAMP");
1109                if let Some(p) = precision {
1110                    self.write(&format!("({p})"));
1111                }
1112                if *with_tz {
1113                    self.write(" WITH TIME ZONE");
1114                }
1115            }
1116            DataType::Interval => self.write("INTERVAL"),
1117            DataType::DateTime => self.write("DATETIME"),
1118            DataType::Blob => self.write("BLOB"),
1119            DataType::Bytea => self.write("BYTEA"),
1120            DataType::Bytes => self.write("BYTES"),
1121            DataType::Json => self.write("JSON"),
1122            DataType::Jsonb => self.write("JSONB"),
1123            DataType::Uuid => self.write("UUID"),
1124            DataType::Array(inner) => {
1125                self.write("ARRAY");
1126                if let Some(inner) = inner {
1127                    self.write("<");
1128                    self.gen_data_type(inner);
1129                    self.write(">");
1130                }
1131            }
1132            DataType::Map { key, value } => {
1133                self.write("MAP<");
1134                self.gen_data_type(key);
1135                self.write(", ");
1136                self.gen_data_type(value);
1137                self.write(">");
1138            }
1139            DataType::Struct(fields) => {
1140                self.write("STRUCT<");
1141                for (i, (name, dt)) in fields.iter().enumerate() {
1142                    if i > 0 {
1143                        self.write(", ");
1144                    }
1145                    self.write(name);
1146                    self.write(" ");
1147                    self.gen_data_type(dt);
1148                }
1149                self.write(">");
1150            }
1151            DataType::Tuple(types) => {
1152                self.write("TUPLE(");
1153                for (i, dt) in types.iter().enumerate() {
1154                    if i > 0 {
1155                        self.write(", ");
1156                    }
1157                    self.gen_data_type(dt);
1158                }
1159                self.write(")");
1160            }
1161            DataType::Null => self.write("NULL"),
1162            DataType::Variant => self.write("VARIANT"),
1163            DataType::Object => self.write("OBJECT"),
1164            DataType::Xml => self.write("XML"),
1165            DataType::Inet => self.write("INET"),
1166            DataType::Cidr => self.write("CIDR"),
1167            DataType::Macaddr => self.write("MACADDR"),
1168            DataType::Bit(len) => {
1169                self.write("BIT");
1170                if let Some(n) = len {
1171                    self.write(&format!("({n})"));
1172                }
1173            }
1174            DataType::Money => self.write("MONEY"),
1175            DataType::Serial => self.write("SERIAL"),
1176            DataType::BigSerial => self.write("BIGSERIAL"),
1177            DataType::SmallSerial => self.write("SMALLSERIAL"),
1178            DataType::Regclass => self.write("REGCLASS"),
1179            DataType::Regtype => self.write("REGTYPE"),
1180            DataType::Hstore => self.write("HSTORE"),
1181            DataType::Geography => self.write("GEOGRAPHY"),
1182            DataType::Geometry => self.write("GEOMETRY"),
1183            DataType::Super => self.write("SUPER"),
1184            DataType::Unknown(name) => self.write(name),
1185        }
1186    }
1187
1188    // ══════════════════════════════════════════════════════════════
1189    // Expressions
1190    // ══════════════════════════════════════════════════════════════
1191
1192    fn binary_op_str(op: &BinaryOperator) -> &'static str {
1193        match op {
1194            BinaryOperator::Plus => " + ",
1195            BinaryOperator::Minus => " - ",
1196            BinaryOperator::Multiply => " * ",
1197            BinaryOperator::Divide => " / ",
1198            BinaryOperator::Modulo => " % ",
1199            BinaryOperator::Eq => " = ",
1200            BinaryOperator::Neq => " <> ",
1201            BinaryOperator::Lt => " < ",
1202            BinaryOperator::Gt => " > ",
1203            BinaryOperator::LtEq => " <= ",
1204            BinaryOperator::GtEq => " >= ",
1205            BinaryOperator::And => " AND ",
1206            BinaryOperator::Or => " OR ",
1207            BinaryOperator::Xor => " XOR ",
1208            BinaryOperator::Concat => " || ",
1209            BinaryOperator::BitwiseAnd => " & ",
1210            BinaryOperator::BitwiseOr => " | ",
1211            BinaryOperator::BitwiseXor => " ^ ",
1212            BinaryOperator::ShiftLeft => " << ",
1213            BinaryOperator::ShiftRight => " >> ",
1214            BinaryOperator::Arrow => " -> ",
1215            BinaryOperator::DoubleArrow => " ->> ",
1216        }
1217    }
1218
1219    fn gen_expr_list(&mut self, exprs: &[Expr]) {
1220        for (i, expr) in exprs.iter().enumerate() {
1221            if i > 0 {
1222                self.write(", ");
1223            }
1224            self.gen_expr(expr);
1225        }
1226    }
1227
1228    fn gen_expr(&mut self, expr: &Expr) {
1229        match expr {
1230            Expr::Column {
1231                table,
1232                name,
1233                quote_style,
1234                table_quote_style,
1235            } => {
1236                if let Some(t) = table {
1237                    self.write_quoted(t, *table_quote_style);
1238                    self.write(".");
1239                }
1240                self.write_quoted(name, *quote_style);
1241            }
1242            Expr::Number(n) => self.write(n),
1243            Expr::StringLiteral(s) => {
1244                self.write("'");
1245                self.write(&s.replace('\'', "''"));
1246                self.write("'");
1247            }
1248            Expr::Boolean(b) => self.write(if *b { "TRUE" } else { "FALSE" }),
1249            Expr::Null => self.write("NULL"),
1250            Expr::Default => self.write_keyword("DEFAULT"),
1251            Expr::Wildcard | Expr::Star => self.write("*"),
1252
1253            Expr::BinaryOp { left, op, right } => {
1254                self.gen_expr(left);
1255                self.write(Self::binary_op_str(op));
1256                self.gen_expr(right);
1257            }
1258            Expr::AnyOp { expr, op, right } => {
1259                self.gen_expr(expr);
1260                self.write(Self::binary_op_str(op));
1261                self.write_keyword("ANY");
1262                self.write("(");
1263                if let Expr::Subquery(query) = right.as_ref() {
1264                    self.gen_statement(query);
1265                } else {
1266                    self.gen_expr(right);
1267                }
1268                self.write(")");
1269            }
1270            Expr::AllOp { expr, op, right } => {
1271                self.gen_expr(expr);
1272                self.write(Self::binary_op_str(op));
1273                self.write_keyword("ALL");
1274                self.write("(");
1275                if let Expr::Subquery(query) = right.as_ref() {
1276                    self.gen_statement(query);
1277                } else {
1278                    self.gen_expr(right);
1279                }
1280                self.write(")");
1281            }
1282            Expr::UnaryOp { op, expr } => {
1283                let op_str = match op {
1284                    UnaryOperator::Not => "NOT ",
1285                    UnaryOperator::Minus => "-",
1286                    UnaryOperator::Plus => "+",
1287                    UnaryOperator::BitwiseNot => "~",
1288                };
1289                self.write(op_str);
1290                self.gen_expr(expr);
1291            }
1292            Expr::Function {
1293                name,
1294                args,
1295                distinct,
1296                filter,
1297                over,
1298            } => {
1299                self.write(name);
1300                self.write("(");
1301                if *distinct {
1302                    self.write_keyword("DISTINCT ");
1303                }
1304                self.gen_expr_list(args);
1305                self.write(")");
1306
1307                if let Some(filter_expr) = filter {
1308                    self.write(" ");
1309                    self.write_keyword("FILTER (WHERE ");
1310                    self.gen_expr(filter_expr);
1311                    self.write(")");
1312                }
1313                if let Some(spec) = over {
1314                    self.write(" ");
1315                    self.write_keyword("OVER ");
1316                    if let Some(wref) = &spec.window_ref {
1317                        if spec.partition_by.is_empty()
1318                            && spec.order_by.is_empty()
1319                            && spec.frame.is_none()
1320                        {
1321                            self.write(wref);
1322                        } else {
1323                            self.write("(");
1324                            self.gen_window_spec(spec);
1325                            self.write(")");
1326                        }
1327                    } else {
1328                        self.write("(");
1329                        self.gen_window_spec(spec);
1330                        self.write(")");
1331                    }
1332                }
1333            }
1334            Expr::Between {
1335                expr,
1336                low,
1337                high,
1338                negated,
1339            } => {
1340                self.gen_expr(expr);
1341                if *negated {
1342                    self.write(" ");
1343                    self.write_keyword("NOT");
1344                }
1345                self.write(" ");
1346                self.write_keyword("BETWEEN ");
1347                self.gen_expr(low);
1348                self.write(" ");
1349                self.write_keyword("AND ");
1350                self.gen_expr(high);
1351            }
1352            Expr::InList {
1353                expr,
1354                list,
1355                negated,
1356            } => {
1357                self.gen_expr(expr);
1358                if *negated {
1359                    self.write(" ");
1360                    self.write_keyword("NOT");
1361                }
1362                self.write(" ");
1363                self.write_keyword("IN (");
1364                self.gen_expr_list(list);
1365                self.write(")");
1366            }
1367            Expr::InSubquery {
1368                expr,
1369                subquery,
1370                negated,
1371            } => {
1372                self.gen_expr(expr);
1373                if *negated {
1374                    self.write(" ");
1375                    self.write_keyword("NOT");
1376                }
1377                self.write(" ");
1378                self.write_keyword("IN (");
1379                self.gen_statement(subquery);
1380                self.write(")");
1381            }
1382            Expr::IsNull { expr, negated } => {
1383                self.gen_expr(expr);
1384                if *negated {
1385                    self.write(" ");
1386                    self.write_keyword("IS NOT NULL");
1387                } else {
1388                    self.write(" ");
1389                    self.write_keyword("IS NULL");
1390                }
1391            }
1392            Expr::IsBool {
1393                expr,
1394                value,
1395                negated,
1396            } => {
1397                self.gen_expr(expr);
1398                self.write(" ");
1399                match (negated, value) {
1400                    (false, true) => self.write_keyword("IS TRUE"),
1401                    (false, false) => self.write_keyword("IS FALSE"),
1402                    (true, true) => self.write_keyword("IS NOT TRUE"),
1403                    (true, false) => self.write_keyword("IS NOT FALSE"),
1404                }
1405            }
1406            Expr::Like {
1407                expr,
1408                pattern,
1409                negated,
1410                escape,
1411            } => {
1412                self.gen_expr(expr);
1413                if *negated {
1414                    self.write(" ");
1415                    self.write_keyword("NOT");
1416                }
1417                self.write(" ");
1418                self.write_keyword("LIKE ");
1419                self.gen_expr(pattern);
1420                if let Some(esc) = escape {
1421                    self.write(" ");
1422                    self.write_keyword("ESCAPE ");
1423                    self.gen_expr(esc);
1424                }
1425            }
1426            Expr::ILike {
1427                expr,
1428                pattern,
1429                negated,
1430                escape,
1431            } => {
1432                self.gen_expr(expr);
1433                if *negated {
1434                    self.write(" ");
1435                    self.write_keyword("NOT");
1436                }
1437                self.write(" ");
1438                self.write_keyword("ILIKE ");
1439                self.gen_expr(pattern);
1440                if let Some(esc) = escape {
1441                    self.write(" ");
1442                    self.write_keyword("ESCAPE ");
1443                    self.gen_expr(esc);
1444                }
1445            }
1446            Expr::Case {
1447                operand,
1448                when_clauses,
1449                else_clause,
1450            } => {
1451                self.write_keyword("CASE");
1452                if let Some(op) = operand {
1453                    self.write(" ");
1454                    self.gen_expr(op);
1455                }
1456                for (cond, result) in when_clauses {
1457                    self.write(" ");
1458                    self.write_keyword("WHEN ");
1459                    self.gen_expr(cond);
1460                    self.write(" ");
1461                    self.write_keyword("THEN ");
1462                    self.gen_expr(result);
1463                }
1464                if let Some(el) = else_clause {
1465                    self.write(" ");
1466                    self.write_keyword("ELSE ");
1467                    self.gen_expr(el);
1468                }
1469                self.write(" ");
1470                self.write_keyword("END");
1471            }
1472            Expr::Nested(inner) => {
1473                self.write("(");
1474                self.gen_expr(inner);
1475                self.write(")");
1476            }
1477            Expr::Subquery(query) => {
1478                self.write("(");
1479                self.gen_statement(query);
1480                self.write(")");
1481            }
1482            Expr::Exists { subquery, negated } => {
1483                if *negated {
1484                    self.write_keyword("NOT ");
1485                }
1486                self.write_keyword("EXISTS (");
1487                self.gen_statement(subquery);
1488                self.write(")");
1489            }
1490            Expr::Cast { expr, data_type } => {
1491                self.write_keyword("CAST(");
1492                self.gen_expr(expr);
1493                self.write(" ");
1494                self.write_keyword("AS ");
1495                self.gen_data_type(data_type);
1496                self.write(")");
1497            }
1498            Expr::TryCast { expr, data_type } => {
1499                self.write_keyword("TRY_CAST(");
1500                self.gen_expr(expr);
1501                self.write(" ");
1502                self.write_keyword("AS ");
1503                self.gen_data_type(data_type);
1504                self.write(")");
1505            }
1506            Expr::Extract { field, expr } => {
1507                self.write_keyword("EXTRACT(");
1508                self.gen_datetime_field(field);
1509                self.write(" ");
1510                self.write_keyword("FROM ");
1511                self.gen_expr(expr);
1512                self.write(")");
1513            }
1514            Expr::Interval { value, unit } => {
1515                self.write_keyword("INTERVAL ");
1516                self.gen_expr(value);
1517                if let Some(unit) = unit {
1518                    self.write(" ");
1519                    self.gen_datetime_field(unit);
1520                }
1521            }
1522            Expr::ArrayLiteral(items) => {
1523                self.write_keyword("ARRAY[");
1524                self.gen_expr_list(items);
1525                self.write("]");
1526            }
1527            Expr::Tuple(items) => {
1528                self.write("(");
1529                self.gen_expr_list(items);
1530                self.write(")");
1531            }
1532            Expr::Coalesce(items) => {
1533                self.write_keyword("COALESCE(");
1534                self.gen_expr_list(items);
1535                self.write(")");
1536            }
1537            Expr::If {
1538                condition,
1539                true_val,
1540                false_val,
1541            } => {
1542                self.write_keyword("IF(");
1543                self.gen_expr(condition);
1544                self.write(", ");
1545                self.gen_expr(true_val);
1546                if let Some(fv) = false_val {
1547                    self.write(", ");
1548                    self.gen_expr(fv);
1549                }
1550                self.write(")");
1551            }
1552            Expr::NullIf { expr, r#else } => {
1553                self.write_keyword("NULLIF(");
1554                self.gen_expr(expr);
1555                self.write(", ");
1556                self.gen_expr(r#else);
1557                self.write(")");
1558            }
1559            Expr::Collate { expr, collation } => {
1560                self.gen_expr(expr);
1561                self.write(" ");
1562                self.write_keyword("COLLATE ");
1563                self.write(collation);
1564            }
1565            Expr::Parameter(p) => self.write(p),
1566            Expr::TypeExpr(dt) => self.gen_data_type(dt),
1567            Expr::QualifiedWildcard { table } => {
1568                self.write(table);
1569                self.write(".*");
1570            }
1571            Expr::Alias { expr, name } => {
1572                self.gen_expr(expr);
1573                self.write(" ");
1574                self.write_keyword("AS ");
1575                self.write(name);
1576            }
1577            Expr::ArrayIndex { expr, index } => {
1578                self.gen_expr(expr);
1579                self.write("[");
1580                self.gen_expr(index);
1581                self.write("]");
1582            }
1583            Expr::JsonAccess {
1584                expr,
1585                path,
1586                as_text,
1587            } => {
1588                self.gen_expr(expr);
1589                if *as_text {
1590                    self.write("->>");
1591                } else {
1592                    self.write("->");
1593                }
1594                self.gen_expr(path);
1595            }
1596            Expr::Lambda { params, body } => {
1597                if params.len() == 1 {
1598                    self.write(&params[0]);
1599                } else {
1600                    self.write("(");
1601                    self.write(&params.join(", "));
1602                    self.write(")");
1603                }
1604                self.write(" -> ");
1605                self.gen_expr(body);
1606            }
1607        }
1608    }
1609
1610    fn gen_window_spec(&mut self, spec: &WindowSpec) {
1611        if let Some(wref) = &spec.window_ref {
1612            self.write(wref);
1613            if !spec.partition_by.is_empty() || !spec.order_by.is_empty() || spec.frame.is_some() {
1614                self.write(" ");
1615            }
1616        }
1617        if !spec.partition_by.is_empty() {
1618            self.write_keyword("PARTITION BY ");
1619            self.gen_expr_list(&spec.partition_by);
1620        }
1621        if !spec.order_by.is_empty() {
1622            if !spec.partition_by.is_empty() {
1623                self.write(" ");
1624            }
1625            self.write_keyword("ORDER BY ");
1626            for (i, item) in spec.order_by.iter().enumerate() {
1627                if i > 0 {
1628                    self.write(", ");
1629                }
1630                self.gen_expr(&item.expr);
1631                if !item.ascending {
1632                    self.write(" ");
1633                    self.write_keyword("DESC");
1634                }
1635                if let Some(nulls_first) = item.nulls_first {
1636                    if nulls_first {
1637                        self.write(" ");
1638                        self.write_keyword("NULLS FIRST");
1639                    } else {
1640                        self.write(" ");
1641                        self.write_keyword("NULLS LAST");
1642                    }
1643                }
1644            }
1645        }
1646        if let Some(frame) = &spec.frame {
1647            self.write(" ");
1648            self.gen_window_frame(frame);
1649        }
1650    }
1651
1652    fn gen_window_frame(&mut self, frame: &WindowFrame) {
1653        match frame.kind {
1654            WindowFrameKind::Rows => self.write_keyword("ROWS "),
1655            WindowFrameKind::Range => self.write_keyword("RANGE "),
1656            WindowFrameKind::Groups => self.write_keyword("GROUPS "),
1657        }
1658        if let Some(end) = &frame.end {
1659            self.write_keyword("BETWEEN ");
1660            self.gen_window_frame_bound(&frame.start);
1661            self.write(" ");
1662            self.write_keyword("AND ");
1663            self.gen_window_frame_bound(end);
1664        } else {
1665            self.gen_window_frame_bound(&frame.start);
1666        }
1667    }
1668
1669    fn gen_window_frame_bound(&mut self, bound: &WindowFrameBound) {
1670        match bound {
1671            WindowFrameBound::CurrentRow => self.write_keyword("CURRENT ROW"),
1672            WindowFrameBound::Preceding(None) => self.write_keyword("UNBOUNDED PRECEDING"),
1673            WindowFrameBound::Preceding(Some(n)) => {
1674                self.gen_expr(n);
1675                self.write(" ");
1676                self.write_keyword("PRECEDING");
1677            }
1678            WindowFrameBound::Following(None) => self.write_keyword("UNBOUNDED FOLLOWING"),
1679            WindowFrameBound::Following(Some(n)) => {
1680                self.gen_expr(n);
1681                self.write(" ");
1682                self.write_keyword("FOLLOWING");
1683            }
1684        }
1685    }
1686
1687    fn gen_datetime_field(&mut self, field: &DateTimeField) {
1688        let name = match field {
1689            DateTimeField::Year => "YEAR",
1690            DateTimeField::Quarter => "QUARTER",
1691            DateTimeField::Month => "MONTH",
1692            DateTimeField::Week => "WEEK",
1693            DateTimeField::Day => "DAY",
1694            DateTimeField::DayOfWeek => "DOW",
1695            DateTimeField::DayOfYear => "DOY",
1696            DateTimeField::Hour => "HOUR",
1697            DateTimeField::Minute => "MINUTE",
1698            DateTimeField::Second => "SECOND",
1699            DateTimeField::Millisecond => "MILLISECOND",
1700            DateTimeField::Microsecond => "MICROSECOND",
1701            DateTimeField::Nanosecond => "NANOSECOND",
1702            DateTimeField::Epoch => "EPOCH",
1703            DateTimeField::Timezone => "TIMEZONE",
1704            DateTimeField::TimezoneHour => "TIMEZONE_HOUR",
1705            DateTimeField::TimezoneMinute => "TIMEZONE_MINUTE",
1706        };
1707        self.write(name);
1708    }
1709}
1710
1711impl Default for Generator {
1712    fn default() -> Self {
1713        Self::new()
1714    }
1715}
1716
1717#[cfg(test)]
1718mod tests {
1719    use super::*;
1720    use crate::parser::Parser;
1721
1722    fn roundtrip(sql: &str) -> String {
1723        let stmt = Parser::new(sql).unwrap().parse_statement().unwrap();
1724        let mut g = Generator::new();
1725        g.generate(&stmt)
1726    }
1727
1728    #[test]
1729    fn test_select_roundtrip() {
1730        assert_eq!(roundtrip("SELECT a, b FROM t"), "SELECT a, b FROM t");
1731    }
1732
1733    #[test]
1734    fn test_select_where() {
1735        assert_eq!(
1736            roundtrip("SELECT x FROM t WHERE x > 10"),
1737            "SELECT x FROM t WHERE x > 10"
1738        );
1739    }
1740
1741    #[test]
1742    fn test_select_wildcard() {
1743        assert_eq!(roundtrip("SELECT * FROM users"), "SELECT * FROM users");
1744    }
1745
1746    #[test]
1747    fn test_insert_values() {
1748        assert_eq!(
1749            roundtrip("INSERT INTO t (a, b) VALUES (1, 'hello')"),
1750            "INSERT INTO t (a, b) VALUES (1, 'hello')"
1751        );
1752    }
1753
1754    #[test]
1755    fn test_delete() {
1756        assert_eq!(
1757            roundtrip("DELETE FROM users WHERE id = 1"),
1758            "DELETE FROM users WHERE id = 1"
1759        );
1760    }
1761
1762    #[test]
1763    fn test_join() {
1764        assert_eq!(
1765            roundtrip("SELECT a.id, b.name FROM a INNER JOIN b ON a.id = b.a_id"),
1766            "SELECT a.id, b.name FROM a INNER JOIN b ON a.id = b.a_id"
1767        );
1768    }
1769
1770    #[test]
1771    fn test_create_table() {
1772        assert_eq!(
1773            roundtrip("CREATE TABLE users (id INT NOT NULL, name VARCHAR(255), email TEXT)"),
1774            "CREATE TABLE users (id INT NOT NULL, name VARCHAR(255), email TEXT)"
1775        );
1776    }
1777
1778    #[test]
1779    fn test_cte_roundtrip() {
1780        let sql = "WITH cte AS (SELECT 1 AS x) SELECT x FROM cte";
1781        assert_eq!(
1782            roundtrip(sql),
1783            "WITH cte AS (SELECT 1 AS x) SELECT x FROM cte"
1784        );
1785    }
1786
1787    #[test]
1788    fn test_union_roundtrip() {
1789        let sql = "SELECT 1 UNION ALL SELECT 2";
1790        assert_eq!(roundtrip(sql), "SELECT 1 UNION ALL SELECT 2");
1791    }
1792
1793    #[test]
1794    fn test_cast_roundtrip() {
1795        assert_eq!(
1796            roundtrip("SELECT CAST(x AS INT) FROM t"),
1797            "SELECT CAST(x AS INT) FROM t"
1798        );
1799    }
1800
1801    #[test]
1802    fn test_exists_roundtrip() {
1803        assert_eq!(
1804            roundtrip("SELECT * FROM t WHERE EXISTS (SELECT 1 FROM t2)"),
1805            "SELECT * FROM t WHERE EXISTS (SELECT 1 FROM t2)"
1806        );
1807    }
1808
1809    #[test]
1810    fn test_extract_roundtrip() {
1811        assert_eq!(
1812            roundtrip("SELECT EXTRACT(YEAR FROM created_at) FROM t"),
1813            "SELECT EXTRACT(YEAR FROM created_at) FROM t"
1814        );
1815    }
1816
1817    #[test]
1818    fn test_window_function_roundtrip() {
1819        assert_eq!(
1820            roundtrip("SELECT ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) FROM emp"),
1821            "SELECT ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) FROM emp"
1822        );
1823    }
1824
1825    #[test]
1826    fn test_subquery_from_roundtrip() {
1827        assert_eq!(
1828            roundtrip("SELECT * FROM (SELECT 1 AS x) AS sub"),
1829            "SELECT * FROM (SELECT 1 AS x) AS sub"
1830        );
1831    }
1832
1833    #[test]
1834    fn test_in_subquery_roundtrip() {
1835        assert_eq!(
1836            roundtrip("SELECT * FROM t WHERE id IN (SELECT id FROM t2)"),
1837            "SELECT * FROM t WHERE id IN (SELECT id FROM t2)"
1838        );
1839    }
1840
1841    // ═══════════════════════════════════════════════════════════════
1842    // Pretty-print tests
1843    // ═══════════════════════════════════════════════════════════════
1844
1845    fn pretty_print(sql: &str) -> String {
1846        let stmt = Parser::new(sql).unwrap().parse_statement().unwrap();
1847        let mut g = Generator::pretty();
1848        g.generate(&stmt)
1849    }
1850
1851    #[test]
1852    fn test_pretty_simple_select() {
1853        assert_eq!(
1854            pretty_print("SELECT a, b, c FROM t"),
1855            "SELECT\n  a,\n  b,\n  c\nFROM\n  t"
1856        );
1857    }
1858
1859    #[test]
1860    fn test_pretty_select_where() {
1861        assert_eq!(
1862            pretty_print("SELECT a FROM t WHERE a > 1"),
1863            "SELECT\n  a\nFROM\n  t\nWHERE\n  a > 1"
1864        );
1865    }
1866
1867    #[test]
1868    fn test_pretty_select_group_by_having() {
1869        assert_eq!(
1870            pretty_print("SELECT a, COUNT(*) FROM t GROUP BY a HAVING COUNT(*) > 1"),
1871            "SELECT\n  a,\n  COUNT(*)\nFROM\n  t\nGROUP BY\n  a\nHAVING\n  COUNT(*) > 1"
1872        );
1873    }
1874
1875    #[test]
1876    fn test_pretty_select_order_by_limit() {
1877        assert_eq!(
1878            pretty_print("SELECT a FROM t ORDER BY a DESC LIMIT 10"),
1879            "SELECT\n  a\nFROM\n  t\nORDER BY\n  a DESC\nLIMIT 10"
1880        );
1881    }
1882
1883    #[test]
1884    fn test_pretty_join() {
1885        assert_eq!(
1886            pretty_print("SELECT a.id, b.name FROM a INNER JOIN b ON a.id = b.a_id"),
1887            "SELECT\n  a.id,\n  b.name\nFROM\n  a\nINNER JOIN\n  b\n  ON a.id = b.a_id"
1888        );
1889    }
1890
1891    #[test]
1892    fn test_pretty_cte() {
1893        assert_eq!(
1894            pretty_print("WITH cte AS (SELECT 1 AS x) SELECT x FROM cte"),
1895            "WITH cte AS (\n  SELECT\n    1 AS x\n)\nSELECT\n  x\nFROM\n  cte"
1896        );
1897    }
1898
1899    #[test]
1900    fn test_pretty_union() {
1901        assert_eq!(
1902            pretty_print("SELECT 1 UNION ALL SELECT 2"),
1903            "SELECT\n  1\nUNION ALL\nSELECT\n  2"
1904        );
1905    }
1906
1907    #[test]
1908    fn test_pretty_insert() {
1909        assert_eq!(
1910            pretty_print("INSERT INTO t (a, b) VALUES (1, 'hello'), (2, 'world')"),
1911            "INSERT INTO t (a, b)\nVALUES\n  (1, 'hello'),\n  (2, 'world')"
1912        );
1913    }
1914
1915    #[test]
1916    fn test_pretty_update() {
1917        assert_eq!(
1918            pretty_print("UPDATE t SET a = 1, b = 2 WHERE c = 3"),
1919            "UPDATE t\nSET\n  a = 1,\n  b = 2\nWHERE\n  c = 3"
1920        );
1921    }
1922
1923    #[test]
1924    fn test_pretty_delete() {
1925        assert_eq!(
1926            pretty_print("DELETE FROM t WHERE id = 1"),
1927            "DELETE FROM t\nWHERE\n  id = 1"
1928        );
1929    }
1930
1931    #[test]
1932    fn test_pretty_create_table() {
1933        assert_eq!(
1934            pretty_print("CREATE TABLE t (id INT NOT NULL, name VARCHAR(255), email TEXT)"),
1935            "CREATE TABLE t (\n  id INT NOT NULL,\n  name VARCHAR(255),\n  email TEXT\n)"
1936        );
1937    }
1938
1939    #[test]
1940    fn test_pretty_complex_query() {
1941        let sql = "SELECT a, SUM(b) FROM t1 INNER JOIN t2 ON t1.id = t2.id WHERE t1.x > 1 GROUP BY a HAVING SUM(b) > 10 ORDER BY a LIMIT 100";
1942        let expected = "SELECT\n  a,\n  SUM(b)\nFROM\n  t1\nINNER JOIN\n  t2\n  ON t1.id = t2.id\nWHERE\n  t1.x > 1\nGROUP BY\n  a\nHAVING\n  SUM(b) > 10\nORDER BY\n  a\nLIMIT 100";
1943        assert_eq!(pretty_print(sql), expected);
1944    }
1945
1946    #[test]
1947    fn test_pretty_select_distinct() {
1948        assert_eq!(
1949            pretty_print("SELECT DISTINCT a, b FROM t"),
1950            "SELECT DISTINCT\n  a,\n  b\nFROM\n  t"
1951        );
1952    }
1953}