Skip to main content

sqlglot_rust/ast/
types.rs

1use serde::{Deserialize, Serialize};
2
3// ═══════════════════════════════════════════════════════════════════════
4// Identifier quoting style
5// ═══════════════════════════════════════════════════════════════════════
6
7/// How an identifier (column, table, alias) was quoted in the source SQL.
8///
9/// Used to preserve and transform quoting across dialects (e.g. backtick
10/// for MySQL/BigQuery → double-quote for PostgreSQL → bracket for T-SQL).
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
12pub enum QuoteStyle {
13    /// Bare / unquoted identifier
14    #[default]
15    None,
16    /// `"identifier"` — ANSI SQL, PostgreSQL, Oracle, Snowflake, etc.
17    DoubleQuote,
18    /// `` `identifier` `` — MySQL, BigQuery, Hive, Spark, etc.
19    Backtick,
20    /// `[identifier]` — T-SQL / SQL Server
21    Bracket,
22}
23
24impl QuoteStyle {
25    /// Returns the canonical quoting style for the given dialect.
26    #[must_use]
27    pub fn for_dialect(dialect: crate::dialects::Dialect) -> Self {
28        use crate::dialects::Dialect;
29        match dialect {
30            Dialect::Tsql | Dialect::Fabric => QuoteStyle::Bracket,
31            Dialect::Mysql | Dialect::BigQuery | Dialect::Hive | Dialect::Spark
32            | Dialect::Databricks | Dialect::Doris | Dialect::SingleStore
33            | Dialect::StarRocks => QuoteStyle::Backtick,
34            // ANSI, Postgres, Oracle, Snowflake, Presto, Trino, etc.
35            _ => QuoteStyle::DoubleQuote,
36        }
37    }
38
39    /// Returns `true` when the identifier carries explicit quoting.
40    #[must_use]
41    pub fn is_quoted(self) -> bool {
42        !matches!(self, QuoteStyle::None)
43    }
44}
45
46// ═══════════════════════════════════════════════════════════════════════
47// Top-level statement types
48// ═══════════════════════════════════════════════════════════════════════
49
50/// A fully parsed SQL statement.
51///
52/// Corresponds to the top-level node in sqlglot's expression tree.
53#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
54pub enum Statement {
55    Select(SelectStatement),
56    Insert(InsertStatement),
57    Update(UpdateStatement),
58    Delete(DeleteStatement),
59    CreateTable(CreateTableStatement),
60    DropTable(DropTableStatement),
61    /// UNION / INTERSECT / EXCEPT between queries
62    SetOperation(SetOperationStatement),
63    /// ALTER TABLE ...
64    AlterTable(AlterTableStatement),
65    /// CREATE VIEW ...
66    CreateView(CreateViewStatement),
67    /// DROP VIEW ...
68    DropView(DropViewStatement),
69    /// TRUNCATE TABLE ...
70    Truncate(TruncateStatement),
71    /// BEGIN / COMMIT / ROLLBACK
72    Transaction(TransactionStatement),
73    /// EXPLAIN <statement>
74    Explain(ExplainStatement),
75    /// USE database
76    Use(UseStatement),
77    /// Raw / passthrough expression (for expressions that don't fit a specific statement type)
78    Expression(Expr),
79}
80
81// ═══════════════════════════════════════════════════════════════════════
82// SELECT
83// ═══════════════════════════════════════════════════════════════════════
84
85/// A SELECT statement, including CTEs.
86///
87/// Aligned with sqlglot's `Select` expression which wraps `With`, `From`,
88/// `Where`, `Group`, `Having`, `Order`, `Limit`, `Offset`, `Window`.
89#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
90pub struct SelectStatement {
91    /// Common Table Expressions (WITH clause)
92    pub ctes: Vec<Cte>,
93    pub distinct: bool,
94    /// TOP N (TSQL-style)
95    pub top: Option<Box<Expr>>,
96    pub columns: Vec<SelectItem>,
97    pub from: Option<FromClause>,
98    pub joins: Vec<JoinClause>,
99    pub where_clause: Option<Expr>,
100    pub group_by: Vec<Expr>,
101    pub having: Option<Expr>,
102    pub order_by: Vec<OrderByItem>,
103    pub limit: Option<Expr>,
104    pub offset: Option<Expr>,
105    /// Oracle-style FETCH FIRST n ROWS ONLY
106    pub fetch_first: Option<Expr>,
107    /// QUALIFY clause (BigQuery, Snowflake)
108    pub qualify: Option<Expr>,
109    /// Named WINDOW definitions
110    pub window_definitions: Vec<WindowDefinition>,
111}
112
113/// A Common Table Expression: `name [(col1, col2)] AS [NOT] MATERIALIZED (query)`
114#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
115pub struct Cte {
116    pub name: String,
117    pub columns: Vec<String>,
118    pub query: Box<Statement>,
119    pub materialized: Option<bool>,
120    pub recursive: bool,
121}
122
123/// Named WINDOW definition: `window_name AS (window_spec)`
124#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
125pub struct WindowDefinition {
126    pub name: String,
127    pub spec: WindowSpec,
128}
129
130// ═══════════════════════════════════════════════════════════════════════
131// Set operations (UNION, INTERSECT, EXCEPT)
132// ═══════════════════════════════════════════════════════════════════════
133
134/// UNION / INTERSECT / EXCEPT between two or more queries.
135#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
136pub struct SetOperationStatement {
137    pub op: SetOperationType,
138    pub all: bool,
139    pub left: Box<Statement>,
140    pub right: Box<Statement>,
141    pub order_by: Vec<OrderByItem>,
142    pub limit: Option<Expr>,
143    pub offset: Option<Expr>,
144}
145
146#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
147pub enum SetOperationType {
148    Union,
149    Intersect,
150    Except,
151}
152
153// ═══════════════════════════════════════════════════════════════════════
154// SELECT items and FROM
155// ═══════════════════════════════════════════════════════════════════════
156
157/// An item in a SELECT list.
158#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
159pub enum SelectItem {
160    /// `*`
161    Wildcard,
162    /// `table.*`
163    QualifiedWildcard { table: String },
164    /// An expression with optional alias: `expr AS alias`
165    Expr { expr: Expr, alias: Option<String> },
166}
167
168/// A FROM clause, now supporting subqueries and multiple tables.
169#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
170pub struct FromClause {
171    pub source: TableSource,
172}
173
174/// A table source can be a table reference, subquery, or table function.
175#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
176pub enum TableSource {
177    Table(TableRef),
178    Subquery {
179        query: Box<Statement>,
180        alias: Option<String>,
181    },
182    TableFunction {
183        name: String,
184        args: Vec<Expr>,
185        alias: Option<String>,
186    },
187    /// LATERAL subquery or function
188    Lateral {
189        source: Box<TableSource>,
190    },
191    /// UNNEST(array_expr)
192    Unnest {
193        expr: Box<Expr>,
194        alias: Option<String>,
195        with_offset: bool,
196    },
197}
198
199/// A reference to a table.
200#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
201pub struct TableRef {
202    pub catalog: Option<String>,
203    pub schema: Option<String>,
204    pub name: String,
205    pub alias: Option<String>,
206    /// How the table name was quoted in the source SQL.
207    #[serde(default)]
208    pub name_quote_style: QuoteStyle,
209}
210
211/// A JOIN clause.
212#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
213pub struct JoinClause {
214    pub join_type: JoinType,
215    pub table: TableSource,
216    pub on: Option<Expr>,
217    pub using: Vec<String>,
218}
219
220/// The type of JOIN.
221#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
222pub enum JoinType {
223    Inner,
224    Left,
225    Right,
226    Full,
227    Cross,
228    /// NATURAL JOIN
229    Natural,
230    /// LATERAL JOIN
231    Lateral,
232}
233
234/// An ORDER BY item.
235#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
236pub struct OrderByItem {
237    pub expr: Expr,
238    pub ascending: bool,
239    /// NULLS FIRST / NULLS LAST
240    pub nulls_first: Option<bool>,
241}
242
243// ═══════════════════════════════════════════════════════════════════════
244// Expressions (the core of the AST)
245// ═══════════════════════════════════════════════════════════════════════
246
247/// An expression in SQL.
248///
249/// This enum is aligned with sqlglot's Expression class hierarchy.
250/// Key additions over the basic implementation:
251/// - Subquery, Exists, Cast, Extract, Window functions
252/// - TypedString, Interval, Array/Struct constructors
253/// - Postgres-style casting (`::`)
254#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
255pub enum Expr {
256    /// A column reference, possibly qualified: `[catalog.][schema.]table.column`
257    Column {
258        table: Option<String>,
259        name: String,
260        /// How the column name was quoted in the source SQL.
261        #[serde(default)]
262        quote_style: QuoteStyle,
263        /// How the table qualifier was quoted, if present.
264        #[serde(default)]
265        table_quote_style: QuoteStyle,
266    },
267    /// A numeric literal.
268    Number(String),
269    /// A string literal.
270    StringLiteral(String),
271    /// A boolean literal.
272    Boolean(bool),
273    /// NULL literal.
274    Null,
275    /// A binary operation: `left op right`
276    BinaryOp {
277        left: Box<Expr>,
278        op: BinaryOperator,
279        right: Box<Expr>,
280    },
281    /// A unary operation: `op expr`
282    UnaryOp {
283        op: UnaryOperator,
284        expr: Box<Expr>,
285    },
286    /// A function call: `name(args...)` with optional DISTINCT, ORDER BY, etc.
287    Function {
288        name: String,
289        args: Vec<Expr>,
290        distinct: bool,
291        /// FILTER (WHERE expr) clause on aggregate
292        filter: Option<Box<Expr>>,
293        /// OVER window specification for window functions
294        over: Option<WindowSpec>,
295    },
296    /// `expr BETWEEN low AND high`
297    Between {
298        expr: Box<Expr>,
299        low: Box<Expr>,
300        high: Box<Expr>,
301        negated: bool,
302    },
303    /// `expr IN (list...)` or `expr IN (subquery)`
304    InList {
305        expr: Box<Expr>,
306        list: Vec<Expr>,
307        negated: bool,
308    },
309    /// `expr IN (SELECT ...)`
310    InSubquery {
311        expr: Box<Expr>,
312        subquery: Box<Statement>,
313        negated: bool,
314    },
315    /// `expr op ANY(subexpr)` — PostgreSQL array/subquery comparison
316    AnyOp {
317        expr: Box<Expr>,
318        op: BinaryOperator,
319        right: Box<Expr>,
320    },
321    /// `expr op ALL(subexpr)` — PostgreSQL array/subquery comparison
322    AllOp {
323        expr: Box<Expr>,
324        op: BinaryOperator,
325        right: Box<Expr>,
326    },
327    /// `expr IS [NOT] NULL`
328    IsNull {
329        expr: Box<Expr>,
330        negated: bool,
331    },
332    /// `expr IS [NOT] TRUE` / `expr IS [NOT] FALSE`
333    IsBool {
334        expr: Box<Expr>,
335        value: bool,
336        negated: bool,
337    },
338    /// `expr [NOT] LIKE pattern [ESCAPE escape_char]`
339    Like {
340        expr: Box<Expr>,
341        pattern: Box<Expr>,
342        negated: bool,
343        escape: Option<Box<Expr>>,
344    },
345    /// `expr [NOT] ILIKE pattern [ESCAPE escape_char]` (case-insensitive LIKE)
346    ILike {
347        expr: Box<Expr>,
348        pattern: Box<Expr>,
349        negated: bool,
350        escape: Option<Box<Expr>>,
351    },
352    /// `CASE [operand] WHEN ... THEN ... ELSE ... END`
353    Case {
354        operand: Option<Box<Expr>>,
355        when_clauses: Vec<(Expr, Expr)>,
356        else_clause: Option<Box<Expr>>,
357    },
358    /// A parenthesized sub-expression.
359    Nested(Box<Expr>),
360    /// A wildcard `*` used in contexts like `COUNT(*)`.
361    Wildcard,
362    /// A scalar subquery: `(SELECT ...)`
363    Subquery(Box<Statement>),
364    /// `EXISTS (SELECT ...)`
365    Exists {
366        subquery: Box<Statement>,
367        negated: bool,
368    },
369    /// `CAST(expr AS type)` or `expr::type` (PostgreSQL)
370    Cast {
371        expr: Box<Expr>,
372        data_type: DataType,
373    },
374    /// `TRY_CAST(expr AS type)`
375    TryCast {
376        expr: Box<Expr>,
377        data_type: DataType,
378    },
379    /// `EXTRACT(field FROM expr)`
380    Extract {
381        field: DateTimeField,
382        expr: Box<Expr>,
383    },
384    /// `INTERVAL 'value' unit`
385    Interval {
386        value: Box<Expr>,
387        unit: Option<DateTimeField>,
388    },
389    /// Array literal: `ARRAY[1, 2, 3]` or `[1, 2, 3]`
390    ArrayLiteral(Vec<Expr>),
391    /// Struct literal / row constructor: `(1, 'a', true)`
392    Tuple(Vec<Expr>),
393    /// `COALESCE(a, b, c)`
394    Coalesce(Vec<Expr>),
395    /// `IF(condition, true_val, false_val)` (MySQL, BigQuery)
396    If {
397        condition: Box<Expr>,
398        true_val: Box<Expr>,
399        false_val: Option<Box<Expr>>,
400    },
401    /// `NULLIF(a, b)`
402    NullIf {
403        expr: Box<Expr>,
404        r#else: Box<Expr>,
405    },
406    /// `expr COLLATE collation`
407    Collate {
408        expr: Box<Expr>,
409        collation: String,
410    },
411    /// Parameter / placeholder: `$1`, `?`, `:name`
412    Parameter(String),
413    /// A type expression used in DDL contexts or CAST
414    TypeExpr(DataType),
415    /// `table.*` in expression context
416    QualifiedWildcard { table: String },
417    /// Star expression `*`
418    Star,
419    /// Alias expression: `expr AS name`
420    Alias {
421        expr: Box<Expr>,
422        name: String,
423    },
424    /// Array access: `expr[index]`
425    ArrayIndex {
426        expr: Box<Expr>,
427        index: Box<Expr>,
428    },
429    /// JSON access: `expr->key` or `expr->>key`
430    JsonAccess {
431        expr: Box<Expr>,
432        path: Box<Expr>,
433        /// false = ->, true = ->>
434        as_text: bool,
435    },
436    /// Lambda expression: `x -> x + 1`
437    Lambda {
438        params: Vec<String>,
439        body: Box<Expr>,
440    },
441    /// `DEFAULT` keyword in INSERT/UPDATE contexts
442    Default,
443}
444
445// ═══════════════════════════════════════════════════════════════════════
446// Window specification
447// ═══════════════════════════════════════════════════════════════════════
448
449/// Window specification for window functions: OVER (PARTITION BY ... ORDER BY ... frame)
450#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
451pub struct WindowSpec {
452    /// Reference to a named window
453    pub window_ref: Option<String>,
454    pub partition_by: Vec<Expr>,
455    pub order_by: Vec<OrderByItem>,
456    pub frame: Option<WindowFrame>,
457}
458
459#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
460pub struct WindowFrame {
461    pub kind: WindowFrameKind,
462    pub start: WindowFrameBound,
463    pub end: Option<WindowFrameBound>,
464}
465
466#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
467pub enum WindowFrameKind {
468    Rows,
469    Range,
470    Groups,
471}
472
473#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
474pub enum WindowFrameBound {
475    CurrentRow,
476    Preceding(Option<Box<Expr>>),  // None = UNBOUNDED PRECEDING
477    Following(Option<Box<Expr>>),  // None = UNBOUNDED FOLLOWING
478}
479
480// ═══════════════════════════════════════════════════════════════════════
481// Date/time fields (for EXTRACT, INTERVAL)
482// ═══════════════════════════════════════════════════════════════════════
483
484#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
485pub enum DateTimeField {
486    Year,
487    Quarter,
488    Month,
489    Week,
490    Day,
491    DayOfWeek,
492    DayOfYear,
493    Hour,
494    Minute,
495    Second,
496    Millisecond,
497    Microsecond,
498    Nanosecond,
499    Epoch,
500    Timezone,
501    TimezoneHour,
502    TimezoneMinute,
503}
504
505// ═══════════════════════════════════════════════════════════════════════
506// Operators
507// ═══════════════════════════════════════════════════════════════════════
508
509/// Binary operators.
510#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
511pub enum BinaryOperator {
512    Plus,
513    Minus,
514    Multiply,
515    Divide,
516    Modulo,
517    Eq,
518    Neq,
519    Lt,
520    Gt,
521    LtEq,
522    GtEq,
523    And,
524    Or,
525    Xor,
526    Concat,
527    BitwiseAnd,
528    BitwiseOr,
529    BitwiseXor,
530    ShiftLeft,
531    ShiftRight,
532    /// `->` JSON access operator
533    Arrow,
534    /// `->>` JSON text access
535    DoubleArrow,
536}
537
538/// Unary operators.
539#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
540pub enum UnaryOperator {
541    Not,
542    Minus,
543    Plus,
544    BitwiseNot,
545}
546
547// ═══════════════════════════════════════════════════════════════════════
548// DML statements
549// ═══════════════════════════════════════════════════════════════════════
550
551/// An INSERT statement, now supporting INSERT ... SELECT and ON CONFLICT.
552#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
553pub struct InsertStatement {
554    pub table: TableRef,
555    pub columns: Vec<String>,
556    pub source: InsertSource,
557    /// ON CONFLICT / ON DUPLICATE KEY
558    pub on_conflict: Option<OnConflict>,
559    /// RETURNING clause
560    pub returning: Vec<SelectItem>,
561}
562
563#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
564pub enum InsertSource {
565    Values(Vec<Vec<Expr>>),
566    Query(Box<Statement>),
567    Default,
568}
569
570#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
571pub struct OnConflict {
572    pub columns: Vec<String>,
573    pub action: ConflictAction,
574}
575
576#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
577pub enum ConflictAction {
578    DoNothing,
579    DoUpdate(Vec<(String, Expr)>),
580}
581
582/// An UPDATE statement.
583#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
584pub struct UpdateStatement {
585    pub table: TableRef,
586    pub assignments: Vec<(String, Expr)>,
587    pub from: Option<FromClause>,
588    pub where_clause: Option<Expr>,
589    pub returning: Vec<SelectItem>,
590}
591
592/// A DELETE statement.
593#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
594pub struct DeleteStatement {
595    pub table: TableRef,
596    pub using: Option<FromClause>,
597    pub where_clause: Option<Expr>,
598    pub returning: Vec<SelectItem>,
599}
600
601// ═══════════════════════════════════════════════════════════════════════
602// DDL statements
603// ═══════════════════════════════════════════════════════════════════════
604
605/// A CREATE TABLE statement.
606#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
607pub struct CreateTableStatement {
608    pub if_not_exists: bool,
609    pub temporary: bool,
610    pub table: TableRef,
611    pub columns: Vec<ColumnDef>,
612    pub constraints: Vec<TableConstraint>,
613    /// CREATE TABLE ... AS SELECT ...
614    pub as_select: Option<Box<Statement>>,
615}
616
617/// Table-level constraints.
618#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
619pub enum TableConstraint {
620    PrimaryKey {
621        name: Option<String>,
622        columns: Vec<String>,
623    },
624    Unique {
625        name: Option<String>,
626        columns: Vec<String>,
627    },
628    ForeignKey {
629        name: Option<String>,
630        columns: Vec<String>,
631        ref_table: TableRef,
632        ref_columns: Vec<String>,
633        on_delete: Option<ReferentialAction>,
634        on_update: Option<ReferentialAction>,
635    },
636    Check {
637        name: Option<String>,
638        expr: Expr,
639    },
640}
641
642#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
643pub enum ReferentialAction {
644    Cascade,
645    Restrict,
646    NoAction,
647    SetNull,
648    SetDefault,
649}
650
651/// A column definition in CREATE TABLE.
652#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
653pub struct ColumnDef {
654    pub name: String,
655    pub data_type: DataType,
656    pub nullable: Option<bool>,
657    pub default: Option<Expr>,
658    pub primary_key: bool,
659    pub unique: bool,
660    pub auto_increment: bool,
661    pub collation: Option<String>,
662    pub comment: Option<String>,
663}
664
665/// ALTER TABLE statement.
666#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
667pub struct AlterTableStatement {
668    pub table: TableRef,
669    pub actions: Vec<AlterTableAction>,
670}
671
672#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
673pub enum AlterTableAction {
674    AddColumn(ColumnDef),
675    DropColumn { name: String, if_exists: bool },
676    RenameColumn { old_name: String, new_name: String },
677    AlterColumnType { name: String, data_type: DataType },
678    AddConstraint(TableConstraint),
679    DropConstraint { name: String },
680    RenameTable { new_name: String },
681}
682
683/// CREATE VIEW statement.
684#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
685pub struct CreateViewStatement {
686    pub name: TableRef,
687    pub columns: Vec<String>,
688    pub query: Box<Statement>,
689    pub or_replace: bool,
690    pub materialized: bool,
691    pub if_not_exists: bool,
692}
693
694/// DROP VIEW statement.
695#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
696pub struct DropViewStatement {
697    pub name: TableRef,
698    pub if_exists: bool,
699    pub materialized: bool,
700}
701
702/// TRUNCATE TABLE statement.
703#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
704pub struct TruncateStatement {
705    pub table: TableRef,
706}
707
708/// Transaction control statements.
709#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
710pub enum TransactionStatement {
711    Begin,
712    Commit,
713    Rollback,
714    Savepoint(String),
715    ReleaseSavepoint(String),
716    RollbackTo(String),
717}
718
719/// EXPLAIN statement.
720#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
721pub struct ExplainStatement {
722    pub analyze: bool,
723    pub statement: Box<Statement>,
724}
725
726/// USE database statement.
727#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
728pub struct UseStatement {
729    pub name: String,
730}
731
732/// A DROP TABLE statement.
733#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
734pub struct DropTableStatement {
735    pub if_exists: bool,
736    pub table: TableRef,
737    pub cascade: bool,
738}
739
740// ═══════════════════════════════════════════════════════════════════════
741// Data types
742// ═══════════════════════════════════════════════════════════════════════
743
744/// SQL data types. Significantly expanded to match sqlglot's DataType.Type enum.
745#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
746pub enum DataType {
747    // Numeric
748    TinyInt,
749    SmallInt,
750    Int,
751    BigInt,
752    Float,
753    Double,
754    Decimal { precision: Option<u32>, scale: Option<u32> },
755    Numeric { precision: Option<u32>, scale: Option<u32> },
756    Real,
757
758    // String
759    Varchar(Option<u32>),
760    Char(Option<u32>),
761    Text,
762    String,
763    Binary(Option<u32>),
764    Varbinary(Option<u32>),
765
766    // Boolean
767    Boolean,
768
769    // Date/Time
770    Date,
771    Time { precision: Option<u32> },
772    Timestamp { precision: Option<u32>, with_tz: bool },
773    Interval,
774    DateTime,
775
776    // Binary
777    Blob,
778    Bytea,
779    Bytes,
780
781    // JSON
782    Json,
783    Jsonb,
784
785    // UUID
786    Uuid,
787
788    // Complex types
789    Array(Option<Box<DataType>>),
790    Map { key: Box<DataType>, value: Box<DataType> },
791    Struct(Vec<(String, DataType)>),
792    Tuple(Vec<DataType>),
793
794    // Special
795    Null,
796    Unknown(String),
797    Variant,
798    Object,
799    Xml,
800    Inet,
801    Cidr,
802    Macaddr,
803    Bit(Option<u32>),
804    Money,
805    Serial,
806    BigSerial,
807    SmallSerial,
808    Regclass,
809    Regtype,
810    Hstore,
811    Geography,
812    Geometry,
813    Super,
814}
815
816// ═══════════════════════════════════════════════════════════════════════
817// Expression tree traversal helpers
818// ═══════════════════════════════════════════════════════════════════════
819
820impl Expr {
821    /// Recursively walk this expression tree, calling `visitor` on each node.
822    /// If `visitor` returns `false`, children of that node are not visited.
823    pub fn walk<F>(&self, visitor: &mut F)
824    where
825        F: FnMut(&Expr) -> bool,
826    {
827        if !visitor(self) {
828            return;
829        }
830        match self {
831            Expr::BinaryOp { left, right, .. } => {
832                left.walk(visitor);
833                right.walk(visitor);
834            }
835            Expr::UnaryOp { expr, .. } => expr.walk(visitor),
836            Expr::Function { args, filter, .. } => {
837                for arg in args {
838                    arg.walk(visitor);
839                }
840                if let Some(f) = filter {
841                    f.walk(visitor);
842                }
843            }
844            Expr::Between { expr, low, high, .. } => {
845                expr.walk(visitor);
846                low.walk(visitor);
847                high.walk(visitor);
848            }
849            Expr::InList { expr, list, .. } => {
850                expr.walk(visitor);
851                for item in list {
852                    item.walk(visitor);
853                }
854            }
855            Expr::InSubquery { expr, .. } => {
856                expr.walk(visitor);
857            }
858            Expr::IsNull { expr, .. } => expr.walk(visitor),
859            Expr::IsBool { expr, .. } => expr.walk(visitor),
860            Expr::AnyOp { expr, right, .. } | Expr::AllOp { expr, right, .. } => {
861                expr.walk(visitor);
862                right.walk(visitor);
863            }
864            Expr::Like { expr, pattern, .. } | Expr::ILike { expr, pattern, .. } => {
865                expr.walk(visitor);
866                pattern.walk(visitor);
867            }
868            Expr::Case {
869                operand,
870                when_clauses,
871                else_clause,
872            } => {
873                if let Some(op) = operand {
874                    op.walk(visitor);
875                }
876                for (cond, result) in when_clauses {
877                    cond.walk(visitor);
878                    result.walk(visitor);
879                }
880                if let Some(el) = else_clause {
881                    el.walk(visitor);
882                }
883            }
884            Expr::Nested(inner) => inner.walk(visitor),
885            Expr::Cast { expr, .. } | Expr::TryCast { expr, .. } => expr.walk(visitor),
886            Expr::Extract { expr, .. } => expr.walk(visitor),
887            Expr::Interval { value, .. } => value.walk(visitor),
888            Expr::ArrayLiteral(items) | Expr::Tuple(items) | Expr::Coalesce(items) => {
889                for item in items {
890                    item.walk(visitor);
891                }
892            }
893            Expr::If { condition, true_val, false_val } => {
894                condition.walk(visitor);
895                true_val.walk(visitor);
896                if let Some(fv) = false_val {
897                    fv.walk(visitor);
898                }
899            }
900            Expr::NullIf { expr, r#else } => {
901                expr.walk(visitor);
902                r#else.walk(visitor);
903            }
904            Expr::Collate { expr, .. } => expr.walk(visitor),
905            Expr::Alias { expr, .. } => expr.walk(visitor),
906            Expr::ArrayIndex { expr, index } => {
907                expr.walk(visitor);
908                index.walk(visitor);
909            }
910            Expr::JsonAccess { expr, path, .. } => {
911                expr.walk(visitor);
912                path.walk(visitor);
913            }
914            Expr::Lambda { body, .. } => body.walk(visitor),
915            // Leaf nodes
916            Expr::Column { .. }
917            | Expr::Number(_)
918            | Expr::StringLiteral(_)
919            | Expr::Boolean(_)
920            | Expr::Null
921            | Expr::Wildcard
922            | Expr::Star
923            | Expr::Parameter(_)
924            | Expr::TypeExpr(_)
925            | Expr::QualifiedWildcard { .. }
926            | Expr::Default
927            | Expr::Subquery(_)
928            | Expr::Exists { .. } => {}
929        }
930    }
931
932    /// Find the first expression matching the predicate.
933    #[must_use]
934    pub fn find<F>(&self, predicate: &F) -> Option<&Expr>
935    where
936        F: Fn(&Expr) -> bool,
937    {
938        let mut result = None;
939        self.walk(&mut |expr| {
940            if result.is_some() {
941                return false;
942            }
943            if predicate(expr) {
944                result = Some(expr as *const Expr);
945                false
946            } else {
947                true
948            }
949        });
950        // SAFETY: the pointer is valid as long as self is alive
951        result.map(|p| unsafe { &*p })
952    }
953
954    /// Find all expressions matching the predicate.
955    #[must_use]
956    pub fn find_all<F>(&self, predicate: &F) -> Vec<&Expr>
957    where
958        F: Fn(&Expr) -> bool,
959    {
960        let mut results: Vec<*const Expr> = Vec::new();
961        self.walk(&mut |expr| {
962            if predicate(expr) {
963                results.push(expr as *const Expr);
964            }
965            true
966        });
967        results.into_iter().map(|p| unsafe { &*p }).collect()
968    }
969
970    /// Transform this expression tree by applying a function to each node.
971    /// The function can return a new expression to replace the current one.
972    #[must_use]
973    pub fn transform<F>(self, func: &F) -> Expr
974    where
975        F: Fn(Expr) -> Expr,
976    {
977        let transformed = match self {
978            Expr::BinaryOp { left, op, right } => Expr::BinaryOp {
979                left: Box::new(left.transform(func)),
980                op,
981                right: Box::new(right.transform(func)),
982            },
983            Expr::UnaryOp { op, expr } => Expr::UnaryOp {
984                op,
985                expr: Box::new(expr.transform(func)),
986            },
987            Expr::Function { name, args, distinct, filter, over } => Expr::Function {
988                name,
989                args: args.into_iter().map(|a| a.transform(func)).collect(),
990                distinct,
991                filter: filter.map(|f| Box::new(f.transform(func))),
992                over,
993            },
994            Expr::Nested(inner) => Expr::Nested(Box::new(inner.transform(func))),
995            Expr::Cast { expr, data_type } => Expr::Cast {
996                expr: Box::new(expr.transform(func)),
997                data_type,
998            },
999            Expr::Between { expr, low, high, negated } => Expr::Between {
1000                expr: Box::new(expr.transform(func)),
1001                low: Box::new(low.transform(func)),
1002                high: Box::new(high.transform(func)),
1003                negated,
1004            },
1005            Expr::Case { operand, when_clauses, else_clause } => Expr::Case {
1006                operand: operand.map(|o| Box::new(o.transform(func))),
1007                when_clauses: when_clauses
1008                    .into_iter()
1009                    .map(|(c, r)| (c.transform(func), r.transform(func)))
1010                    .collect(),
1011                else_clause: else_clause.map(|e| Box::new(e.transform(func))),
1012            },
1013            Expr::IsBool { expr, value, negated } => Expr::IsBool {
1014                expr: Box::new(expr.transform(func)),
1015                value,
1016                negated,
1017            },
1018            Expr::AnyOp { expr, op, right } => Expr::AnyOp {
1019                expr: Box::new(expr.transform(func)),
1020                op,
1021                right: Box::new(right.transform(func)),
1022            },
1023            Expr::AllOp { expr, op, right } => Expr::AllOp {
1024                expr: Box::new(expr.transform(func)),
1025                op,
1026                right: Box::new(right.transform(func)),
1027            },
1028            other => other,
1029        };
1030        func(transformed)
1031    }
1032
1033    /// Check whether this expression is a column reference.
1034    #[must_use]
1035    pub fn is_column(&self) -> bool {
1036        matches!(self, Expr::Column { .. })
1037    }
1038
1039    /// Check whether this expression is a literal value (number, string, bool, null).
1040    #[must_use]
1041    pub fn is_literal(&self) -> bool {
1042        matches!(
1043            self,
1044            Expr::Number(_) | Expr::StringLiteral(_) | Expr::Boolean(_) | Expr::Null
1045        )
1046    }
1047
1048    /// Get the SQL representation of this expression for display purposes.
1049    /// For full generation, use the Generator.
1050    #[must_use]
1051    pub fn sql(&self) -> String {
1052        use crate::generator::Generator;
1053        Generator::expr_to_sql(self)
1054    }
1055}
1056
1057/// Helper: collect all column references from an expression.
1058#[must_use]
1059pub fn find_columns(expr: &Expr) -> Vec<&Expr> {
1060    expr.find_all(&|e| matches!(e, Expr::Column { .. }))
1061}
1062
1063/// Helper: collect all table references from a statement.
1064#[must_use]
1065pub fn find_tables(statement: &Statement) -> Vec<&TableRef> {
1066    match statement {
1067        Statement::Select(sel) => {
1068            let mut tables = Vec::new();
1069            if let Some(from) = &sel.from {
1070                collect_table_refs_from_source(&from.source, &mut tables);
1071            }
1072            for join in &sel.joins {
1073                collect_table_refs_from_source(&join.table, &mut tables);
1074            }
1075            tables
1076        }
1077        Statement::Insert(ins) => vec![&ins.table],
1078        Statement::Update(upd) => vec![&upd.table],
1079        Statement::Delete(del) => vec![&del.table],
1080        Statement::CreateTable(ct) => vec![&ct.table],
1081        Statement::DropTable(dt) => vec![&dt.table],
1082        _ => vec![],
1083    }
1084}
1085
1086fn collect_table_refs_from_source<'a>(source: &'a TableSource, tables: &mut Vec<&'a TableRef>) {
1087    match source {
1088        TableSource::Table(table_ref) => tables.push(table_ref),
1089        TableSource::Subquery { .. } => {}
1090        TableSource::TableFunction { .. } => {}
1091        TableSource::Lateral { source } => collect_table_refs_from_source(source, tables),
1092        TableSource::Unnest { .. } => {}
1093    }
1094}