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