Skip to main content

sqlglot_rust/ast/
types.rs

1use serde::{Deserialize, Serialize};
2
3// ═══════════════════════════════════════════════════════════════════════
4// Comment types
5// ═══════════════════════════════════════════════════════════════════════
6
7/// The type of a SQL comment.
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
9pub enum CommentType {
10    /// Single-line comment starting with `--`
11    Line,
12    /// Block comment delimited by `/* ... */`
13    Block,
14    /// MySQL-style hash comment starting with `#`
15    Hash,
16}
17
18// ═══════════════════════════════════════════════════════════════════════
19// Identifier quoting style
20// ═══════════════════════════════════════════════════════════════════════
21
22/// How an identifier (column, table, alias) was quoted in the source SQL.
23///
24/// Used to preserve and transform quoting across dialects (e.g. backtick
25/// for MySQL/BigQuery → double-quote for PostgreSQL → bracket for T-SQL).
26#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize, Default)]
27pub enum QuoteStyle {
28    /// Bare / unquoted identifier
29    #[default]
30    None,
31    /// `"identifier"` — ANSI SQL, PostgreSQL, Oracle, Snowflake, etc.
32    DoubleQuote,
33    /// `` `identifier` `` — MySQL, BigQuery, Hive, Spark, etc.
34    Backtick,
35    /// `[identifier]` — T-SQL / SQL Server
36    Bracket,
37}
38
39impl QuoteStyle {
40    /// Returns the canonical quoting style for the given dialect.
41    #[must_use]
42    pub fn for_dialect(dialect: crate::dialects::Dialect) -> Self {
43        use crate::dialects::Dialect;
44        match dialect {
45            Dialect::Tsql | Dialect::Fabric => QuoteStyle::Bracket,
46            Dialect::Mysql
47            | Dialect::BigQuery
48            | Dialect::Hive
49            | Dialect::Spark
50            | Dialect::Databricks
51            | Dialect::Doris
52            | Dialect::SingleStore
53            | Dialect::StarRocks => QuoteStyle::Backtick,
54            // ANSI, Postgres, Oracle, Snowflake, Presto, Trino, etc.
55            _ => QuoteStyle::DoubleQuote,
56        }
57    }
58
59    /// Returns `true` when the identifier carries explicit quoting.
60    #[must_use]
61    pub fn is_quoted(self) -> bool {
62        !matches!(self, QuoteStyle::None)
63    }
64}
65
66// ═══════════════════════════════════════════════════════════════════════
67// Top-level statement types
68// ═══════════════════════════════════════════════════════════════════════
69
70/// A fully parsed SQL statement.
71///
72/// Corresponds to the top-level node in sqlglot's expression tree.
73#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
74pub enum Statement {
75    Select(SelectStatement),
76    Insert(InsertStatement),
77    Update(UpdateStatement),
78    Delete(DeleteStatement),
79    CreateTable(CreateTableStatement),
80    DropTable(DropTableStatement),
81    /// UNION / INTERSECT / EXCEPT between queries
82    SetOperation(SetOperationStatement),
83    /// ALTER TABLE ...
84    AlterTable(AlterTableStatement),
85    /// CREATE VIEW ...
86    CreateView(CreateViewStatement),
87    /// DROP VIEW ...
88    DropView(DropViewStatement),
89    /// TRUNCATE TABLE ...
90    Truncate(TruncateStatement),
91    /// BEGIN / COMMIT / ROLLBACK
92    Transaction(TransactionStatement),
93    /// EXPLAIN <statement>
94    Explain(ExplainStatement),
95    /// USE database
96    Use(UseStatement),
97    /// MERGE INTO ... USING ... WHEN MATCHED / WHEN NOT MATCHED
98    Merge(MergeStatement),
99    /// Raw / passthrough expression (for expressions that don't fit a specific statement type)
100    Expression(Expr),
101    /// Catch-all for statements that the parser accepts for round-tripping
102    /// but does not model in detail (e.g. `SET extra_float_digits = 0`,
103    /// `SHOW VARIABLES LIKE 'innodb%'`, `GO`, `DECLARE @x INT = 1`,
104    /// `COMMENT ON COLUMN t.c IS 'x'`, `CREATE OPERATOR FAMILY …`,
105    /// vendor-specific `ALTER TABLE … COMPACT 'major'`).
106    ///
107    /// The verb (`kind`) preserves the original keyword(s) so the generator
108    /// can emit a literal round-trip; `body` is the raw rest of the
109    /// statement up to the terminating semicolon/EOF.
110    Command(CommandStatement),
111}
112
113// ═══════════════════════════════════════════════════════════════════════
114// SELECT
115// ═══════════════════════════════════════════════════════════════════════
116
117/// A SELECT statement, including CTEs.
118///
119/// Aligned with sqlglot's `Select` expression which wraps `With`, `From`,
120/// `Where`, `Group`, `Having`, `Order`, `Limit`, `Offset`, `Window`.
121#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
122pub struct SelectStatement {
123    /// Comments attached to this statement.
124    #[serde(default, skip_serializing_if = "Vec::is_empty")]
125    pub comments: Vec<String>,
126    /// Common Table Expressions (WITH clause)
127    pub ctes: Vec<Cte>,
128    pub distinct: bool,
129    /// TOP N (TSQL-style)
130    pub top: Option<Box<Expr>>,
131    pub columns: Vec<SelectItem>,
132    pub from: Option<FromClause>,
133    pub joins: Vec<JoinClause>,
134    pub where_clause: Option<Expr>,
135    pub group_by: Vec<Expr>,
136    pub having: Option<Expr>,
137    pub order_by: Vec<OrderByItem>,
138    pub limit: Option<Expr>,
139    pub offset: Option<Expr>,
140    /// Oracle-style FETCH FIRST n ROWS ONLY
141    pub fetch_first: Option<Expr>,
142    /// QUALIFY clause (BigQuery, Snowflake)
143    pub qualify: Option<Expr>,
144    /// Named WINDOW definitions
145    pub window_definitions: Vec<WindowDefinition>,
146}
147
148/// A Common Table Expression: `name [(col1, col2)] AS [NOT] MATERIALIZED (query)`
149#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
150pub struct Cte {
151    pub name: String,
152    #[serde(default)]
153    pub name_quote_style: QuoteStyle,
154    pub columns: Vec<String>,
155    pub query: Box<Statement>,
156    pub materialized: Option<bool>,
157    pub recursive: bool,
158}
159
160/// Named WINDOW definition: `window_name AS (window_spec)`
161#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
162pub struct WindowDefinition {
163    pub name: String,
164    pub spec: WindowSpec,
165}
166
167// ═══════════════════════════════════════════════════════════════════════
168// Set operations (UNION, INTERSECT, EXCEPT)
169// ═══════════════════════════════════════════════════════════════════════
170
171/// UNION / INTERSECT / EXCEPT between two or more queries.
172#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
173pub struct SetOperationStatement {
174    /// Comments attached to this statement.
175    #[serde(default, skip_serializing_if = "Vec::is_empty")]
176    pub comments: Vec<String>,
177    pub op: SetOperationType,
178    pub all: bool,
179    pub left: Box<Statement>,
180    pub right: Box<Statement>,
181    pub order_by: Vec<OrderByItem>,
182    pub limit: Option<Expr>,
183    pub offset: Option<Expr>,
184}
185
186#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
187pub enum SetOperationType {
188    Union,
189    Intersect,
190    Except,
191}
192
193// ═══════════════════════════════════════════════════════════════════════
194// SELECT items and FROM
195// ═══════════════════════════════════════════════════════════════════════
196
197/// An item in a SELECT list.
198#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
199pub enum SelectItem {
200    /// `*`
201    Wildcard,
202    /// `table.*`
203    QualifiedWildcard { table: String },
204    /// An expression with optional alias: `expr AS alias`
205    Expr {
206        expr: Expr,
207        alias: Option<String>,
208        #[serde(default)]
209        alias_quote_style: QuoteStyle,
210    },
211}
212
213/// A FROM clause, now supporting subqueries and multiple tables.
214#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
215pub struct FromClause {
216    pub source: TableSource,
217}
218
219/// A table source can be a table reference, subquery, or table function.
220#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
221pub enum TableSource {
222    Table(TableRef),
223    Subquery {
224        query: Box<Statement>,
225        alias: Option<String>,
226        #[serde(default)]
227        alias_quote_style: QuoteStyle,
228    },
229    TableFunction {
230        name: String,
231        args: Vec<Expr>,
232        alias: Option<String>,
233        #[serde(default)]
234        alias_quote_style: QuoteStyle,
235    },
236    /// LATERAL subquery or function
237    Lateral {
238        source: Box<TableSource>,
239    },
240    /// UNNEST(array_expr)
241    Unnest {
242        expr: Box<Expr>,
243        alias: Option<String>,
244        #[serde(default)]
245        alias_quote_style: QuoteStyle,
246        with_offset: bool,
247    },
248    /// PIVOT (aggregate FOR column IN (values))
249    Pivot {
250        source: Box<TableSource>,
251        aggregate: Box<Expr>,
252        for_column: String,
253        in_values: Vec<PivotValue>,
254        alias: Option<String>,
255        #[serde(default)]
256        alias_quote_style: QuoteStyle,
257    },
258    /// UNPIVOT (value_column FOR name_column IN (columns))
259    Unpivot {
260        source: Box<TableSource>,
261        value_column: String,
262        for_column: String,
263        in_columns: Vec<PivotValue>,
264        alias: Option<String>,
265        #[serde(default)]
266        alias_quote_style: QuoteStyle,
267    },
268}
269
270/// A value/column in a PIVOT IN list, optionally aliased.
271#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
272pub struct PivotValue {
273    pub value: Expr,
274    pub alias: Option<String>,
275    #[serde(default)]
276    pub alias_quote_style: QuoteStyle,
277}
278
279/// A reference to a table.
280#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
281pub struct TableRef {
282    pub catalog: Option<String>,
283    pub schema: Option<String>,
284    pub name: String,
285    pub alias: Option<String>,
286    /// How the table name was quoted in the source SQL.
287    #[serde(default)]
288    pub name_quote_style: QuoteStyle,
289    /// How the alias was quoted in the source SQL.
290    #[serde(default)]
291    pub alias_quote_style: QuoteStyle,
292}
293
294/// A JOIN clause.
295#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
296pub struct JoinClause {
297    pub join_type: JoinType,
298    pub table: TableSource,
299    pub on: Option<Expr>,
300    pub using: Vec<String>,
301}
302
303/// The type of JOIN.
304#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
305pub enum JoinType {
306    Inner,
307    Left,
308    Right,
309    Full,
310    Cross,
311    /// NATURAL JOIN
312    Natural,
313    /// LATERAL JOIN
314    Lateral,
315}
316
317/// An ORDER BY item.
318#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
319pub struct OrderByItem {
320    pub expr: Expr,
321    pub ascending: bool,
322    /// NULLS FIRST / NULLS LAST
323    pub nulls_first: Option<bool>,
324}
325
326// ═══════════════════════════════════════════════════════════════════════
327// Expressions (the core of the AST)
328// ═══════════════════════════════════════════════════════════════════════
329
330/// An expression in SQL.
331///
332/// This enum is aligned with sqlglot's Expression class hierarchy.
333/// Key additions over the basic implementation:
334/// - Subquery, Exists, Cast, Extract, Window functions
335/// - TypedString, Interval, Array/Struct constructors
336/// - Postgres-style casting (`::`)
337#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
338pub enum Expr {
339    /// A column reference, possibly qualified: `[catalog.][schema.]table.column`
340    Column {
341        table: Option<String>,
342        name: String,
343        /// How the column name was quoted in the source SQL.
344        #[serde(default)]
345        quote_style: QuoteStyle,
346        /// How the table qualifier was quoted, if present.
347        #[serde(default)]
348        table_quote_style: QuoteStyle,
349    },
350    /// A numeric literal.
351    Number(String),
352    /// A string literal.
353    StringLiteral(String),
354    /// A national character string literal: `N'...'`.
355    NationalStringLiteral(String),
356    /// A boolean literal.
357    Boolean(bool),
358    /// NULL literal.
359    Null,
360    /// A binary operation: `left op right`
361    BinaryOp {
362        left: Box<Expr>,
363        op: BinaryOperator,
364        right: Box<Expr>,
365    },
366    /// A unary operation: `op expr`
367    UnaryOp { op: UnaryOperator, expr: Box<Expr> },
368    /// A function call: `name(args...)` with optional DISTINCT, ORDER BY, etc.
369    Function {
370        name: String,
371        args: Vec<Expr>,
372        distinct: bool,
373        /// FILTER (WHERE expr) clause on aggregate
374        filter: Option<Box<Expr>>,
375        /// OVER window specification for window functions
376        over: Option<WindowSpec>,
377        /// Inline ORDER BY inside the argument list, or a trailing
378        /// WITHIN GROUP (ORDER BY …) clause. Both surface forms are
379        /// stored here; the generator picks the right emission based
380        /// on `within_group`.
381        #[serde(default, skip_serializing_if = "Vec::is_empty")]
382        order_by: Vec<OrderByItem>,
383        /// True iff the ORDER BY originally came from a trailing
384        /// `WITHIN GROUP (ORDER BY …)` clause rather than an inline
385        /// `ORDER BY` inside the argument list.
386        #[serde(default, skip_serializing_if = "std::ops::Not::not")]
387        within_group: bool,
388    },
389    /// `expr BETWEEN low AND high`
390    Between {
391        expr: Box<Expr>,
392        low: Box<Expr>,
393        high: Box<Expr>,
394        negated: bool,
395    },
396    /// `expr IN (list...)` or `expr IN (subquery)`
397    InList {
398        expr: Box<Expr>,
399        list: Vec<Expr>,
400        negated: bool,
401    },
402    /// `expr IN (SELECT ...)`
403    InSubquery {
404        expr: Box<Expr>,
405        subquery: Box<Statement>,
406        negated: bool,
407    },
408    /// `expr op ANY(subexpr)` — PostgreSQL array/subquery comparison
409    AnyOp {
410        expr: Box<Expr>,
411        op: BinaryOperator,
412        right: Box<Expr>,
413    },
414    /// `expr op ALL(subexpr)` — PostgreSQL array/subquery comparison
415    AllOp {
416        expr: Box<Expr>,
417        op: BinaryOperator,
418        right: Box<Expr>,
419    },
420    /// `expr IS [NOT] NULL`
421    IsNull { expr: Box<Expr>, negated: bool },
422    /// `expr IS [NOT] TRUE` / `expr IS [NOT] FALSE`
423    IsBool {
424        expr: Box<Expr>,
425        value: bool,
426        negated: bool,
427    },
428    /// `expr [NOT] LIKE pattern [ESCAPE escape_char]`
429    Like {
430        expr: Box<Expr>,
431        pattern: Box<Expr>,
432        negated: bool,
433        escape: Option<Box<Expr>>,
434    },
435    /// `expr [NOT] ILIKE pattern [ESCAPE escape_char]` (case-insensitive LIKE)
436    ILike {
437        expr: Box<Expr>,
438        pattern: Box<Expr>,
439        negated: bool,
440        escape: Option<Box<Expr>>,
441    },
442    /// `expr [NOT] SIMILAR TO pattern [ESCAPE escape_char]`
443    SimilarTo {
444        expr: Box<Expr>,
445        pattern: Box<Expr>,
446        negated: bool,
447        escape: Option<Box<Expr>>,
448    },
449    /// `CASE [operand] WHEN ... THEN ... ELSE ... END`
450    Case {
451        operand: Option<Box<Expr>>,
452        when_clauses: Vec<(Expr, Expr)>,
453        else_clause: Option<Box<Expr>>,
454    },
455    /// A parenthesized sub-expression.
456    Nested(Box<Expr>),
457    /// A wildcard `*` used in contexts like `COUNT(*)`.
458    Wildcard,
459    /// A scalar subquery: `(SELECT ...)`
460    Subquery(Box<Statement>),
461    /// `EXISTS (SELECT ...)`
462    Exists {
463        subquery: Box<Statement>,
464        negated: bool,
465    },
466    /// `CAST(expr AS type)` or `expr::type` (PostgreSQL)
467    Cast {
468        expr: Box<Expr>,
469        data_type: DataType,
470    },
471    /// `TRY_CAST(expr AS type)`
472    TryCast {
473        expr: Box<Expr>,
474        data_type: DataType,
475    },
476    /// `EXTRACT(field FROM expr)`
477    Extract {
478        field: DateTimeField,
479        expr: Box<Expr>,
480    },
481    /// `INTERVAL 'value' unit`
482    Interval {
483        value: Box<Expr>,
484        unit: Option<DateTimeField>,
485    },
486    /// Array literal: `ARRAY[1, 2, 3]` or `[1, 2, 3]`
487    ArrayLiteral(Vec<Expr>),
488    /// Struct literal / row constructor: `(1, 'a', true)`
489    Tuple(Vec<Expr>),
490    /// `COALESCE(a, b, c)`
491    Coalesce(Vec<Expr>),
492    /// `IF(condition, true_val, false_val)` (MySQL, BigQuery)
493    If {
494        condition: Box<Expr>,
495        true_val: Box<Expr>,
496        false_val: Option<Box<Expr>>,
497    },
498    /// `NULLIF(a, b)`
499    NullIf { expr: Box<Expr>, r#else: Box<Expr> },
500    /// `expr COLLATE collation`
501    Collate { expr: Box<Expr>, collation: String },
502    /// Parameter / placeholder: `$1`, `?`, `:name`
503    Parameter(String),
504    /// A type expression used in DDL contexts or CAST
505    TypeExpr(DataType),
506    /// `table.*` in expression context
507    QualifiedWildcard { table: String },
508    /// Star expression `*`
509    Star,
510    /// Alias expression: `expr AS name`
511    Alias { expr: Box<Expr>, name: String },
512    /// Array access: `expr[index]`
513    ArrayIndex { expr: Box<Expr>, index: Box<Expr> },
514    /// JSON access: `expr->key` or `expr->>key`
515    JsonAccess {
516        expr: Box<Expr>,
517        path: Box<Expr>,
518        /// false = ->, true = ->>
519        as_text: bool,
520    },
521    /// Lambda expression: `x -> x + 1`
522    Lambda {
523        params: Vec<String>,
524        body: Box<Expr>,
525    },
526    /// `DEFAULT` keyword in INSERT/UPDATE contexts
527    Default,
528    /// `CUBE(a, b, ...)` in GROUP BY clause
529    Cube { exprs: Vec<Expr> },
530    /// `ROLLUP(a, b, ...)` in GROUP BY clause
531    Rollup { exprs: Vec<Expr> },
532    /// `GROUPING SETS ((a, b), (c), ...)` in GROUP BY clause
533    GroupingSets { sets: Vec<Expr> },
534    /// A typed function expression with semantic awareness.
535    /// Enables per-function, per-dialect code generation and transpilation.
536    TypedFunction {
537        func: TypedFunction,
538        /// FILTER (WHERE expr) clause on aggregate
539        filter: Option<Box<Expr>>,
540        /// OVER window specification for window functions
541        over: Option<WindowSpec>,
542    },
543    /// An expression with attached SQL comments.
544    /// Wraps an inner expression so that comments survive transformations.
545    Commented {
546        expr: Box<Expr>,
547        comments: Vec<String>,
548    },
549}
550
551// ═══════════════════════════════════════════════════════════════════════
552// Window specification
553// ═══════════════════════════════════════════════════════════════════════
554
555/// Window specification for window functions: OVER (PARTITION BY ... ORDER BY ... frame)
556#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
557pub struct WindowSpec {
558    /// Reference to a named window
559    pub window_ref: Option<String>,
560    pub partition_by: Vec<Expr>,
561    pub order_by: Vec<OrderByItem>,
562    pub frame: Option<WindowFrame>,
563}
564
565#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
566pub struct WindowFrame {
567    pub kind: WindowFrameKind,
568    pub start: WindowFrameBound,
569    pub end: Option<WindowFrameBound>,
570}
571
572#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
573pub enum WindowFrameKind {
574    Rows,
575    Range,
576    Groups,
577}
578
579#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
580pub enum WindowFrameBound {
581    CurrentRow,
582    Preceding(Option<Box<Expr>>), // None = UNBOUNDED PRECEDING
583    Following(Option<Box<Expr>>), // None = UNBOUNDED FOLLOWING
584}
585
586// ═══════════════════════════════════════════════════════════════════════
587// Date/time fields (for EXTRACT, INTERVAL)
588// ═══════════════════════════════════════════════════════════════════════
589
590#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
591pub enum DateTimeField {
592    Year,
593    Quarter,
594    Month,
595    Week,
596    Day,
597    DayOfWeek,
598    DayOfYear,
599    Hour,
600    Minute,
601    Second,
602    Millisecond,
603    Microsecond,
604    Nanosecond,
605    Epoch,
606    Timezone,
607    TimezoneHour,
608    TimezoneMinute,
609}
610
611// ═══════════════════════════════════════════════════════════════════════
612// Trim type
613// ═══════════════════════════════════════════════════════════════════════
614
615/// The type of TRIM operation.
616#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
617pub enum TrimType {
618    Leading,
619    Trailing,
620    Both,
621}
622
623// ═══════════════════════════════════════════════════════════════════════
624// Typed function expressions
625// ═══════════════════════════════════════════════════════════════════════
626
627/// Typed function variants enabling per-function transpilation rules,
628/// function signature validation, and dialect-specific code generation.
629///
630/// Each variant carries semantically typed arguments rather than a generic
631/// `Vec<Expr>`, allowing the generator to emit dialect-specific SQL.
632#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
633pub enum TypedFunction {
634    // ── Date/Time ──────────────────────────────────────────────────────
635    /// `DATE_ADD(expr, interval)` — add an interval to a date/timestamp
636    DateAdd {
637        expr: Box<Expr>,
638        interval: Box<Expr>,
639        unit: Option<DateTimeField>,
640    },
641    /// `DATE_DIFF(start, end)` — difference between two dates
642    DateDiff {
643        start: Box<Expr>,
644        end: Box<Expr>,
645        unit: Option<DateTimeField>,
646    },
647    /// `DATE_TRUNC(unit, expr)` — truncate to the given precision
648    DateTrunc {
649        unit: DateTimeField,
650        expr: Box<Expr>,
651    },
652    /// `DATE_SUB(expr, interval)` — subtract an interval from a date
653    DateSub {
654        expr: Box<Expr>,
655        interval: Box<Expr>,
656        unit: Option<DateTimeField>,
657    },
658    /// `CURRENT_DATE`
659    CurrentDate,
660    /// `CURRENT_TIME` — returns the current time of day (ANSI / PostgreSQL).
661    CurrentTime,
662    /// `CURRENT_TIMESTAMP` / `NOW()` / `GETDATE()`
663    CurrentTimestamp,
664    /// `STR_TO_TIME(expr, format)` / `TO_TIMESTAMP` / `PARSE_DATETIME`
665    StrToTime { expr: Box<Expr>, format: Box<Expr> },
666    /// `TIME_TO_STR(expr, format)` / `DATE_FORMAT` / `FORMAT_DATETIME`
667    TimeToStr { expr: Box<Expr>, format: Box<Expr> },
668    /// `TS_OR_DS_TO_DATE(expr)` — convert timestamp or date-string to date
669    TsOrDsToDate { expr: Box<Expr> },
670    /// `YEAR(expr)` — extract year from a date/timestamp
671    Year { expr: Box<Expr> },
672    /// `MONTH(expr)` — extract month from a date/timestamp
673    Month { expr: Box<Expr> },
674    /// `DAY(expr)` — extract day from a date/timestamp
675    Day { expr: Box<Expr> },
676
677    // ── String ─────────────────────────────────────────────────────────
678    /// `TRIM([LEADING|TRAILING|BOTH] [chars FROM] expr)`
679    Trim {
680        expr: Box<Expr>,
681        trim_type: TrimType,
682        trim_chars: Option<Box<Expr>>,
683    },
684    /// `SUBSTRING(expr, start [, length])` / `SUBSTR`
685    Substring {
686        expr: Box<Expr>,
687        start: Box<Expr>,
688        length: Option<Box<Expr>>,
689    },
690    /// `UPPER(expr)` / `UCASE`
691    Upper { expr: Box<Expr> },
692    /// `LOWER(expr)` / `LCASE`
693    Lower { expr: Box<Expr> },
694    /// `REGEXP_LIKE(expr, pattern [, flags])` / `~` (Postgres)
695    RegexpLike {
696        expr: Box<Expr>,
697        pattern: Box<Expr>,
698        flags: Option<Box<Expr>>,
699    },
700    /// `REGEXP_EXTRACT(expr, pattern [, group_index])`
701    RegexpExtract {
702        expr: Box<Expr>,
703        pattern: Box<Expr>,
704        group_index: Option<Box<Expr>>,
705    },
706    /// `REGEXP_REPLACE(expr, pattern, replacement [, flags])`
707    RegexpReplace {
708        expr: Box<Expr>,
709        pattern: Box<Expr>,
710        replacement: Box<Expr>,
711        flags: Option<Box<Expr>>,
712    },
713    /// `CONCAT_WS(separator, expr, ...)`
714    ConcatWs {
715        separator: Box<Expr>,
716        exprs: Vec<Expr>,
717    },
718    /// `SPLIT(expr, delimiter)` / `STRING_SPLIT`
719    Split {
720        expr: Box<Expr>,
721        delimiter: Box<Expr>,
722    },
723    /// `INITCAP(expr)` — capitalize first letter of each word
724    Initcap { expr: Box<Expr> },
725    /// `LENGTH(expr)` / `LEN`
726    Length { expr: Box<Expr> },
727    /// `REPLACE(expr, from, to)`
728    Replace {
729        expr: Box<Expr>,
730        from: Box<Expr>,
731        to: Box<Expr>,
732    },
733    /// `REVERSE(expr)`
734    Reverse { expr: Box<Expr> },
735    /// `LEFT(expr, n)`
736    Left { expr: Box<Expr>, n: Box<Expr> },
737    /// `RIGHT(expr, n)`
738    Right { expr: Box<Expr>, n: Box<Expr> },
739    /// `LPAD(expr, length [, pad])`
740    Lpad {
741        expr: Box<Expr>,
742        length: Box<Expr>,
743        pad: Option<Box<Expr>>,
744    },
745    /// `RPAD(expr, length [, pad])`
746    Rpad {
747        expr: Box<Expr>,
748        length: Box<Expr>,
749        pad: Option<Box<Expr>>,
750    },
751
752    // ── Aggregate ──────────────────────────────────────────────────────
753    /// `COUNT(expr)` or `COUNT(DISTINCT expr)` or `COUNT(*)`
754    Count { expr: Box<Expr>, distinct: bool },
755    /// `SUM([DISTINCT] expr)`
756    Sum { expr: Box<Expr>, distinct: bool },
757    /// `AVG([DISTINCT] expr)`
758    Avg { expr: Box<Expr>, distinct: bool },
759    /// `MIN(expr)`
760    Min { expr: Box<Expr> },
761    /// `MAX(expr)`
762    Max { expr: Box<Expr> },
763    /// `ARRAY_AGG([DISTINCT] expr)` / `LIST` / `COLLECT_LIST`
764    ArrayAgg { expr: Box<Expr>, distinct: bool },
765    /// `APPROX_DISTINCT(expr)` / `APPROX_COUNT_DISTINCT`
766    ApproxDistinct { expr: Box<Expr> },
767    /// `VARIANCE(expr)` / `VAR_SAMP`
768    Variance { expr: Box<Expr> },
769    /// `STDDEV(expr)` / `STDDEV_SAMP`
770    Stddev { expr: Box<Expr> },
771    /// `GROUP_CONCAT([DISTINCT] expr [, ...] [ORDER BY ...] [SEPARATOR sep])` (MySQL)
772    /// / `STRING_AGG(expr, sep [ORDER BY ...])` (Postgres/BigQuery/TSQL)
773    /// / `LISTAGG(expr, sep [WITHIN GROUP (ORDER BY ...)])` (Oracle/Redshift/Snowflake)
774    /// / `GROUP_CONCAT(expr, sep)` (SQLite)
775    GroupConcat {
776        /// The expression(s) being concatenated. MySQL allows multiple positional
777        /// args which are implicitly concatenated; most other dialects accept one.
778        exprs: Vec<Expr>,
779        /// Optional separator. When absent, dialect default applies (`,` for MySQL).
780        separator: Option<Box<Expr>>,
781        /// Optional ORDER BY clause for the aggregate input.
782        order_by: Vec<OrderByItem>,
783        /// DISTINCT modifier on input rows.
784        distinct: bool,
785    },
786
787    // ── Array ──────────────────────────────────────────────────────────
788    /// `ARRAY_CONCAT(arr1, arr2)` / `ARRAY_CAT`
789    ArrayConcat { arrays: Vec<Expr> },
790    /// `ARRAY_CONTAINS(array, element)` / `ARRAY_POSITION`
791    ArrayContains {
792        array: Box<Expr>,
793        element: Box<Expr>,
794    },
795    /// `ARRAY_SIZE(expr)` / `ARRAY_LENGTH` / `CARDINALITY`
796    ArraySize { expr: Box<Expr> },
797    /// `EXPLODE(expr)` — Hive/Spark array expansion
798    Explode { expr: Box<Expr> },
799    /// `GENERATE_SERIES(start, stop [, step])`
800    GenerateSeries {
801        start: Box<Expr>,
802        stop: Box<Expr>,
803        step: Option<Box<Expr>>,
804    },
805    /// `FLATTEN(expr)` — flatten nested arrays
806    Flatten { expr: Box<Expr> },
807
808    // ── JSON ───────────────────────────────────────────────────────────
809    /// `JSON_EXTRACT(expr, path)` / `JSON_VALUE` / `->` (Postgres)
810    JSONExtract { expr: Box<Expr>, path: Box<Expr> },
811    /// `JSON_EXTRACT_SCALAR(expr, path)` / `->>`
812    JSONExtractScalar { expr: Box<Expr>, path: Box<Expr> },
813    /// `PARSE_JSON(expr)` / `JSON_PARSE`
814    ParseJSON { expr: Box<Expr> },
815    /// `JSON_FORMAT(expr)` / `TO_JSON`
816    JSONFormat { expr: Box<Expr> },
817
818    // ── Window ─────────────────────────────────────────────────────────
819    /// `ROW_NUMBER()`
820    RowNumber,
821    /// `RANK()`
822    Rank,
823    /// `DENSE_RANK()`
824    DenseRank,
825    /// `NTILE(n)`
826    NTile { n: Box<Expr> },
827    /// `LEAD(expr [, offset [, default]])`
828    Lead {
829        expr: Box<Expr>,
830        offset: Option<Box<Expr>>,
831        default: Option<Box<Expr>>,
832    },
833    /// `LAG(expr [, offset [, default]])`
834    Lag {
835        expr: Box<Expr>,
836        offset: Option<Box<Expr>>,
837        default: Option<Box<Expr>>,
838    },
839    /// `FIRST_VALUE(expr)`
840    FirstValue { expr: Box<Expr> },
841    /// `LAST_VALUE(expr)`
842    LastValue { expr: Box<Expr> },
843
844    // ── Math ───────────────────────────────────────────────────────────
845    /// `ABS(expr)`
846    Abs { expr: Box<Expr> },
847    /// `CEIL(expr)` / `CEILING`
848    Ceil { expr: Box<Expr> },
849    /// `FLOOR(expr)`
850    Floor { expr: Box<Expr> },
851    /// `ROUND(expr [, decimals])`
852    Round {
853        expr: Box<Expr>,
854        decimals: Option<Box<Expr>>,
855    },
856    /// `LOG(expr [, base])` — semantics vary by dialect
857    Log {
858        expr: Box<Expr>,
859        base: Option<Box<Expr>>,
860    },
861    /// `LN(expr)` — natural logarithm
862    Ln { expr: Box<Expr> },
863    /// `POW(base, exponent)` / `POWER`
864    Pow {
865        base: Box<Expr>,
866        exponent: Box<Expr>,
867    },
868    /// `SQRT(expr)`
869    Sqrt { expr: Box<Expr> },
870    /// `GREATEST(expr, ...)`
871    Greatest { exprs: Vec<Expr> },
872    /// `LEAST(expr, ...)`
873    Least { exprs: Vec<Expr> },
874    /// `MOD(a, b)` — modulo function
875    Mod { left: Box<Expr>, right: Box<Expr> },
876
877    // ── Conversion ─────────────────────────────────────────────────────
878    /// `HEX(expr)` / `TO_HEX`
879    Hex { expr: Box<Expr> },
880    /// `UNHEX(expr)` / `FROM_HEX`
881    Unhex { expr: Box<Expr> },
882    /// `MD5(expr)`
883    Md5 { expr: Box<Expr> },
884    /// `SHA(expr)` / `SHA1`
885    Sha { expr: Box<Expr> },
886    /// `SHA2(expr, bit_length)` — SHA-256/SHA-512
887    Sha2 {
888        expr: Box<Expr>,
889        bit_length: Box<Expr>,
890    },
891}
892
893impl TypedFunction {
894    /// Walk child expressions, calling `visitor` on each.
895    pub fn walk_children<F>(&self, visitor: &mut F)
896    where
897        F: FnMut(&Expr) -> bool,
898    {
899        match self {
900            // Date/Time
901            TypedFunction::DateAdd { expr, interval, .. }
902            | TypedFunction::DateSub { expr, interval, .. } => {
903                expr.walk(visitor);
904                interval.walk(visitor);
905            }
906            TypedFunction::DateDiff { start, end, .. } => {
907                start.walk(visitor);
908                end.walk(visitor);
909            }
910            TypedFunction::DateTrunc { expr, .. } => expr.walk(visitor),
911            TypedFunction::CurrentDate
912            | TypedFunction::CurrentTime
913            | TypedFunction::CurrentTimestamp => {}
914            TypedFunction::StrToTime { expr, format }
915            | TypedFunction::TimeToStr { expr, format } => {
916                expr.walk(visitor);
917                format.walk(visitor);
918            }
919            TypedFunction::TsOrDsToDate { expr }
920            | TypedFunction::Year { expr }
921            | TypedFunction::Month { expr }
922            | TypedFunction::Day { expr } => expr.walk(visitor),
923
924            // String
925            TypedFunction::Trim {
926                expr, trim_chars, ..
927            } => {
928                expr.walk(visitor);
929                if let Some(c) = trim_chars {
930                    c.walk(visitor);
931                }
932            }
933            TypedFunction::Substring {
934                expr,
935                start,
936                length,
937            } => {
938                expr.walk(visitor);
939                start.walk(visitor);
940                if let Some(l) = length {
941                    l.walk(visitor);
942                }
943            }
944            TypedFunction::Upper { expr }
945            | TypedFunction::Lower { expr }
946            | TypedFunction::Initcap { expr }
947            | TypedFunction::Length { expr }
948            | TypedFunction::Reverse { expr } => expr.walk(visitor),
949            TypedFunction::RegexpLike {
950                expr,
951                pattern,
952                flags,
953            } => {
954                expr.walk(visitor);
955                pattern.walk(visitor);
956                if let Some(f) = flags {
957                    f.walk(visitor);
958                }
959            }
960            TypedFunction::RegexpExtract {
961                expr,
962                pattern,
963                group_index,
964            } => {
965                expr.walk(visitor);
966                pattern.walk(visitor);
967                if let Some(g) = group_index {
968                    g.walk(visitor);
969                }
970            }
971            TypedFunction::RegexpReplace {
972                expr,
973                pattern,
974                replacement,
975                flags,
976            } => {
977                expr.walk(visitor);
978                pattern.walk(visitor);
979                replacement.walk(visitor);
980                if let Some(f) = flags {
981                    f.walk(visitor);
982                }
983            }
984            TypedFunction::ConcatWs { separator, exprs } => {
985                separator.walk(visitor);
986                for e in exprs {
987                    e.walk(visitor);
988                }
989            }
990            TypedFunction::Split { expr, delimiter } => {
991                expr.walk(visitor);
992                delimiter.walk(visitor);
993            }
994            TypedFunction::Replace { expr, from, to } => {
995                expr.walk(visitor);
996                from.walk(visitor);
997                to.walk(visitor);
998            }
999            TypedFunction::Left { expr, n } | TypedFunction::Right { expr, n } => {
1000                expr.walk(visitor);
1001                n.walk(visitor);
1002            }
1003            TypedFunction::Lpad { expr, length, pad }
1004            | TypedFunction::Rpad { expr, length, pad } => {
1005                expr.walk(visitor);
1006                length.walk(visitor);
1007                if let Some(p) = pad {
1008                    p.walk(visitor);
1009                }
1010            }
1011
1012            // Aggregate
1013            TypedFunction::Count { expr, .. }
1014            | TypedFunction::Sum { expr, .. }
1015            | TypedFunction::Avg { expr, .. }
1016            | TypedFunction::Min { expr }
1017            | TypedFunction::Max { expr }
1018            | TypedFunction::ArrayAgg { expr, .. }
1019            | TypedFunction::ApproxDistinct { expr }
1020            | TypedFunction::Variance { expr }
1021            | TypedFunction::Stddev { expr } => expr.walk(visitor),
1022            TypedFunction::GroupConcat {
1023                exprs,
1024                separator,
1025                order_by,
1026                ..
1027            } => {
1028                for e in exprs {
1029                    e.walk(visitor);
1030                }
1031                if let Some(s) = separator {
1032                    s.walk(visitor);
1033                }
1034                for o in order_by {
1035                    o.expr.walk(visitor);
1036                }
1037            }
1038
1039            // Array
1040            TypedFunction::ArrayConcat { arrays } => {
1041                for a in arrays {
1042                    a.walk(visitor);
1043                }
1044            }
1045            TypedFunction::ArrayContains { array, element } => {
1046                array.walk(visitor);
1047                element.walk(visitor);
1048            }
1049            TypedFunction::ArraySize { expr }
1050            | TypedFunction::Explode { expr }
1051            | TypedFunction::Flatten { expr } => expr.walk(visitor),
1052            TypedFunction::GenerateSeries { start, stop, step } => {
1053                start.walk(visitor);
1054                stop.walk(visitor);
1055                if let Some(s) = step {
1056                    s.walk(visitor);
1057                }
1058            }
1059
1060            // JSON
1061            TypedFunction::JSONExtract { expr, path }
1062            | TypedFunction::JSONExtractScalar { expr, path } => {
1063                expr.walk(visitor);
1064                path.walk(visitor);
1065            }
1066            TypedFunction::ParseJSON { expr } | TypedFunction::JSONFormat { expr } => {
1067                expr.walk(visitor)
1068            }
1069
1070            // Window
1071            TypedFunction::RowNumber | TypedFunction::Rank | TypedFunction::DenseRank => {}
1072            TypedFunction::NTile { n } => n.walk(visitor),
1073            TypedFunction::Lead {
1074                expr,
1075                offset,
1076                default,
1077            }
1078            | TypedFunction::Lag {
1079                expr,
1080                offset,
1081                default,
1082            } => {
1083                expr.walk(visitor);
1084                if let Some(o) = offset {
1085                    o.walk(visitor);
1086                }
1087                if let Some(d) = default {
1088                    d.walk(visitor);
1089                }
1090            }
1091            TypedFunction::FirstValue { expr } | TypedFunction::LastValue { expr } => {
1092                expr.walk(visitor)
1093            }
1094
1095            // Math
1096            TypedFunction::Abs { expr }
1097            | TypedFunction::Ceil { expr }
1098            | TypedFunction::Floor { expr }
1099            | TypedFunction::Ln { expr }
1100            | TypedFunction::Sqrt { expr } => expr.walk(visitor),
1101            TypedFunction::Round { expr, decimals } => {
1102                expr.walk(visitor);
1103                if let Some(d) = decimals {
1104                    d.walk(visitor);
1105                }
1106            }
1107            TypedFunction::Log { expr, base } => {
1108                expr.walk(visitor);
1109                if let Some(b) = base {
1110                    b.walk(visitor);
1111                }
1112            }
1113            TypedFunction::Pow { base, exponent } => {
1114                base.walk(visitor);
1115                exponent.walk(visitor);
1116            }
1117            TypedFunction::Greatest { exprs } | TypedFunction::Least { exprs } => {
1118                for e in exprs {
1119                    e.walk(visitor);
1120                }
1121            }
1122            TypedFunction::Mod { left, right } => {
1123                left.walk(visitor);
1124                right.walk(visitor);
1125            }
1126
1127            // Conversion
1128            TypedFunction::Hex { expr }
1129            | TypedFunction::Unhex { expr }
1130            | TypedFunction::Md5 { expr }
1131            | TypedFunction::Sha { expr } => expr.walk(visitor),
1132            TypedFunction::Sha2 { expr, bit_length } => {
1133                expr.walk(visitor);
1134                bit_length.walk(visitor);
1135            }
1136        }
1137    }
1138
1139    /// Transform child expressions, returning a new `TypedFunction`.
1140    #[must_use]
1141    pub fn transform_children<F>(self, func: &F) -> TypedFunction
1142    where
1143        F: Fn(Expr) -> Expr,
1144    {
1145        match self {
1146            // Date/Time
1147            TypedFunction::DateAdd {
1148                expr,
1149                interval,
1150                unit,
1151            } => TypedFunction::DateAdd {
1152                expr: Box::new(expr.transform(func)),
1153                interval: Box::new(interval.transform(func)),
1154                unit,
1155            },
1156            TypedFunction::DateDiff { start, end, unit } => TypedFunction::DateDiff {
1157                start: Box::new(start.transform(func)),
1158                end: Box::new(end.transform(func)),
1159                unit,
1160            },
1161            TypedFunction::DateTrunc { unit, expr } => TypedFunction::DateTrunc {
1162                unit,
1163                expr: Box::new(expr.transform(func)),
1164            },
1165            TypedFunction::DateSub {
1166                expr,
1167                interval,
1168                unit,
1169            } => TypedFunction::DateSub {
1170                expr: Box::new(expr.transform(func)),
1171                interval: Box::new(interval.transform(func)),
1172                unit,
1173            },
1174            TypedFunction::CurrentDate => TypedFunction::CurrentDate,
1175            TypedFunction::CurrentTime => TypedFunction::CurrentTime,
1176            TypedFunction::CurrentTimestamp => TypedFunction::CurrentTimestamp,
1177            TypedFunction::StrToTime { expr, format } => TypedFunction::StrToTime {
1178                expr: Box::new(expr.transform(func)),
1179                format: Box::new(format.transform(func)),
1180            },
1181            TypedFunction::TimeToStr { expr, format } => TypedFunction::TimeToStr {
1182                expr: Box::new(expr.transform(func)),
1183                format: Box::new(format.transform(func)),
1184            },
1185            TypedFunction::TsOrDsToDate { expr } => TypedFunction::TsOrDsToDate {
1186                expr: Box::new(expr.transform(func)),
1187            },
1188            TypedFunction::Year { expr } => TypedFunction::Year {
1189                expr: Box::new(expr.transform(func)),
1190            },
1191            TypedFunction::Month { expr } => TypedFunction::Month {
1192                expr: Box::new(expr.transform(func)),
1193            },
1194            TypedFunction::Day { expr } => TypedFunction::Day {
1195                expr: Box::new(expr.transform(func)),
1196            },
1197
1198            // String
1199            TypedFunction::Trim {
1200                expr,
1201                trim_type,
1202                trim_chars,
1203            } => TypedFunction::Trim {
1204                expr: Box::new(expr.transform(func)),
1205                trim_type,
1206                trim_chars: trim_chars.map(|c| Box::new(c.transform(func))),
1207            },
1208            TypedFunction::Substring {
1209                expr,
1210                start,
1211                length,
1212            } => TypedFunction::Substring {
1213                expr: Box::new(expr.transform(func)),
1214                start: Box::new(start.transform(func)),
1215                length: length.map(|l| Box::new(l.transform(func))),
1216            },
1217            TypedFunction::Upper { expr } => TypedFunction::Upper {
1218                expr: Box::new(expr.transform(func)),
1219            },
1220            TypedFunction::Lower { expr } => TypedFunction::Lower {
1221                expr: Box::new(expr.transform(func)),
1222            },
1223            TypedFunction::RegexpLike {
1224                expr,
1225                pattern,
1226                flags,
1227            } => TypedFunction::RegexpLike {
1228                expr: Box::new(expr.transform(func)),
1229                pattern: Box::new(pattern.transform(func)),
1230                flags: flags.map(|f| Box::new(f.transform(func))),
1231            },
1232            TypedFunction::RegexpExtract {
1233                expr,
1234                pattern,
1235                group_index,
1236            } => TypedFunction::RegexpExtract {
1237                expr: Box::new(expr.transform(func)),
1238                pattern: Box::new(pattern.transform(func)),
1239                group_index: group_index.map(|g| Box::new(g.transform(func))),
1240            },
1241            TypedFunction::RegexpReplace {
1242                expr,
1243                pattern,
1244                replacement,
1245                flags,
1246            } => TypedFunction::RegexpReplace {
1247                expr: Box::new(expr.transform(func)),
1248                pattern: Box::new(pattern.transform(func)),
1249                replacement: Box::new(replacement.transform(func)),
1250                flags: flags.map(|f| Box::new(f.transform(func))),
1251            },
1252            TypedFunction::ConcatWs { separator, exprs } => TypedFunction::ConcatWs {
1253                separator: Box::new(separator.transform(func)),
1254                exprs: exprs.into_iter().map(|e| e.transform(func)).collect(),
1255            },
1256            TypedFunction::Split { expr, delimiter } => TypedFunction::Split {
1257                expr: Box::new(expr.transform(func)),
1258                delimiter: Box::new(delimiter.transform(func)),
1259            },
1260            TypedFunction::Initcap { expr } => TypedFunction::Initcap {
1261                expr: Box::new(expr.transform(func)),
1262            },
1263            TypedFunction::Length { expr } => TypedFunction::Length {
1264                expr: Box::new(expr.transform(func)),
1265            },
1266            TypedFunction::Replace { expr, from, to } => TypedFunction::Replace {
1267                expr: Box::new(expr.transform(func)),
1268                from: Box::new(from.transform(func)),
1269                to: Box::new(to.transform(func)),
1270            },
1271            TypedFunction::Reverse { expr } => TypedFunction::Reverse {
1272                expr: Box::new(expr.transform(func)),
1273            },
1274            TypedFunction::Left { expr, n } => TypedFunction::Left {
1275                expr: Box::new(expr.transform(func)),
1276                n: Box::new(n.transform(func)),
1277            },
1278            TypedFunction::Right { expr, n } => TypedFunction::Right {
1279                expr: Box::new(expr.transform(func)),
1280                n: Box::new(n.transform(func)),
1281            },
1282            TypedFunction::Lpad { expr, length, pad } => TypedFunction::Lpad {
1283                expr: Box::new(expr.transform(func)),
1284                length: Box::new(length.transform(func)),
1285                pad: pad.map(|p| Box::new(p.transform(func))),
1286            },
1287            TypedFunction::Rpad { expr, length, pad } => TypedFunction::Rpad {
1288                expr: Box::new(expr.transform(func)),
1289                length: Box::new(length.transform(func)),
1290                pad: pad.map(|p| Box::new(p.transform(func))),
1291            },
1292
1293            // Aggregate
1294            TypedFunction::Count { expr, distinct } => TypedFunction::Count {
1295                expr: Box::new(expr.transform(func)),
1296                distinct,
1297            },
1298            TypedFunction::Sum { expr, distinct } => TypedFunction::Sum {
1299                expr: Box::new(expr.transform(func)),
1300                distinct,
1301            },
1302            TypedFunction::Avg { expr, distinct } => TypedFunction::Avg {
1303                expr: Box::new(expr.transform(func)),
1304                distinct,
1305            },
1306            TypedFunction::Min { expr } => TypedFunction::Min {
1307                expr: Box::new(expr.transform(func)),
1308            },
1309            TypedFunction::Max { expr } => TypedFunction::Max {
1310                expr: Box::new(expr.transform(func)),
1311            },
1312            TypedFunction::ArrayAgg { expr, distinct } => TypedFunction::ArrayAgg {
1313                expr: Box::new(expr.transform(func)),
1314                distinct,
1315            },
1316            TypedFunction::ApproxDistinct { expr } => TypedFunction::ApproxDistinct {
1317                expr: Box::new(expr.transform(func)),
1318            },
1319            TypedFunction::Variance { expr } => TypedFunction::Variance {
1320                expr: Box::new(expr.transform(func)),
1321            },
1322            TypedFunction::Stddev { expr } => TypedFunction::Stddev {
1323                expr: Box::new(expr.transform(func)),
1324            },
1325            TypedFunction::GroupConcat {
1326                exprs,
1327                separator,
1328                order_by,
1329                distinct,
1330            } => TypedFunction::GroupConcat {
1331                exprs: exprs.into_iter().map(|e| e.transform(func)).collect(),
1332                separator: separator.map(|s| Box::new(s.transform(func))),
1333                order_by: order_by
1334                    .into_iter()
1335                    .map(|o| OrderByItem {
1336                        expr: o.expr.transform(func),
1337                        ascending: o.ascending,
1338                        nulls_first: o.nulls_first,
1339                    })
1340                    .collect(),
1341                distinct,
1342            },
1343
1344            // Array
1345            TypedFunction::ArrayConcat { arrays } => TypedFunction::ArrayConcat {
1346                arrays: arrays.into_iter().map(|a| a.transform(func)).collect(),
1347            },
1348            TypedFunction::ArrayContains { array, element } => TypedFunction::ArrayContains {
1349                array: Box::new(array.transform(func)),
1350                element: Box::new(element.transform(func)),
1351            },
1352            TypedFunction::ArraySize { expr } => TypedFunction::ArraySize {
1353                expr: Box::new(expr.transform(func)),
1354            },
1355            TypedFunction::Explode { expr } => TypedFunction::Explode {
1356                expr: Box::new(expr.transform(func)),
1357            },
1358            TypedFunction::GenerateSeries { start, stop, step } => TypedFunction::GenerateSeries {
1359                start: Box::new(start.transform(func)),
1360                stop: Box::new(stop.transform(func)),
1361                step: step.map(|s| Box::new(s.transform(func))),
1362            },
1363            TypedFunction::Flatten { expr } => TypedFunction::Flatten {
1364                expr: Box::new(expr.transform(func)),
1365            },
1366
1367            // JSON
1368            TypedFunction::JSONExtract { expr, path } => TypedFunction::JSONExtract {
1369                expr: Box::new(expr.transform(func)),
1370                path: Box::new(path.transform(func)),
1371            },
1372            TypedFunction::JSONExtractScalar { expr, path } => TypedFunction::JSONExtractScalar {
1373                expr: Box::new(expr.transform(func)),
1374                path: Box::new(path.transform(func)),
1375            },
1376            TypedFunction::ParseJSON { expr } => TypedFunction::ParseJSON {
1377                expr: Box::new(expr.transform(func)),
1378            },
1379            TypedFunction::JSONFormat { expr } => TypedFunction::JSONFormat {
1380                expr: Box::new(expr.transform(func)),
1381            },
1382
1383            // Window
1384            TypedFunction::RowNumber => TypedFunction::RowNumber,
1385            TypedFunction::Rank => TypedFunction::Rank,
1386            TypedFunction::DenseRank => TypedFunction::DenseRank,
1387            TypedFunction::NTile { n } => TypedFunction::NTile {
1388                n: Box::new(n.transform(func)),
1389            },
1390            TypedFunction::Lead {
1391                expr,
1392                offset,
1393                default,
1394            } => TypedFunction::Lead {
1395                expr: Box::new(expr.transform(func)),
1396                offset: offset.map(|o| Box::new(o.transform(func))),
1397                default: default.map(|d| Box::new(d.transform(func))),
1398            },
1399            TypedFunction::Lag {
1400                expr,
1401                offset,
1402                default,
1403            } => TypedFunction::Lag {
1404                expr: Box::new(expr.transform(func)),
1405                offset: offset.map(|o| Box::new(o.transform(func))),
1406                default: default.map(|d| Box::new(d.transform(func))),
1407            },
1408            TypedFunction::FirstValue { expr } => TypedFunction::FirstValue {
1409                expr: Box::new(expr.transform(func)),
1410            },
1411            TypedFunction::LastValue { expr } => TypedFunction::LastValue {
1412                expr: Box::new(expr.transform(func)),
1413            },
1414
1415            // Math
1416            TypedFunction::Abs { expr } => TypedFunction::Abs {
1417                expr: Box::new(expr.transform(func)),
1418            },
1419            TypedFunction::Ceil { expr } => TypedFunction::Ceil {
1420                expr: Box::new(expr.transform(func)),
1421            },
1422            TypedFunction::Floor { expr } => TypedFunction::Floor {
1423                expr: Box::new(expr.transform(func)),
1424            },
1425            TypedFunction::Round { expr, decimals } => TypedFunction::Round {
1426                expr: Box::new(expr.transform(func)),
1427                decimals: decimals.map(|d| Box::new(d.transform(func))),
1428            },
1429            TypedFunction::Log { expr, base } => TypedFunction::Log {
1430                expr: Box::new(expr.transform(func)),
1431                base: base.map(|b| Box::new(b.transform(func))),
1432            },
1433            TypedFunction::Ln { expr } => TypedFunction::Ln {
1434                expr: Box::new(expr.transform(func)),
1435            },
1436            TypedFunction::Pow { base, exponent } => TypedFunction::Pow {
1437                base: Box::new(base.transform(func)),
1438                exponent: Box::new(exponent.transform(func)),
1439            },
1440            TypedFunction::Sqrt { expr } => TypedFunction::Sqrt {
1441                expr: Box::new(expr.transform(func)),
1442            },
1443            TypedFunction::Greatest { exprs } => TypedFunction::Greatest {
1444                exprs: exprs.into_iter().map(|e| e.transform(func)).collect(),
1445            },
1446            TypedFunction::Least { exprs } => TypedFunction::Least {
1447                exprs: exprs.into_iter().map(|e| e.transform(func)).collect(),
1448            },
1449            TypedFunction::Mod { left, right } => TypedFunction::Mod {
1450                left: Box::new(left.transform(func)),
1451                right: Box::new(right.transform(func)),
1452            },
1453
1454            // Conversion
1455            TypedFunction::Hex { expr } => TypedFunction::Hex {
1456                expr: Box::new(expr.transform(func)),
1457            },
1458            TypedFunction::Unhex { expr } => TypedFunction::Unhex {
1459                expr: Box::new(expr.transform(func)),
1460            },
1461            TypedFunction::Md5 { expr } => TypedFunction::Md5 {
1462                expr: Box::new(expr.transform(func)),
1463            },
1464            TypedFunction::Sha { expr } => TypedFunction::Sha {
1465                expr: Box::new(expr.transform(func)),
1466            },
1467            TypedFunction::Sha2 { expr, bit_length } => TypedFunction::Sha2 {
1468                expr: Box::new(expr.transform(func)),
1469                bit_length: Box::new(bit_length.transform(func)),
1470            },
1471        }
1472    }
1473}
1474
1475// ═══════════════════════════════════════════════════════════════════════
1476// Operators
1477// ═══════════════════════════════════════════════════════════════════════
1478
1479/// Binary operators.
1480#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1481pub enum BinaryOperator {
1482    Plus,
1483    Minus,
1484    Multiply,
1485    Divide,
1486    Modulo,
1487    Eq,
1488    Neq,
1489    Lt,
1490    Gt,
1491    LtEq,
1492    GtEq,
1493    And,
1494    Or,
1495    Xor,
1496    Concat,
1497    BitwiseAnd,
1498    BitwiseOr,
1499    BitwiseXor,
1500    ShiftLeft,
1501    ShiftRight,
1502    /// `->` JSON access operator
1503    Arrow,
1504    /// `->>` JSON text access
1505    DoubleArrow,
1506    /// `@>` PostgreSQL "contains" (arrays / jsonb / range)
1507    AtArrow,
1508    /// `<@` PostgreSQL "is contained by"
1509    ArrowAt,
1510}
1511
1512/// Unary operators.
1513#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1514pub enum UnaryOperator {
1515    Not,
1516    Minus,
1517    Plus,
1518    BitwiseNot,
1519}
1520
1521// ═══════════════════════════════════════════════════════════════════════
1522// DML statements
1523// ═══════════════════════════════════════════════════════════════════════
1524
1525/// An INSERT statement, now supporting INSERT ... SELECT and ON CONFLICT.
1526#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1527pub struct InsertStatement {
1528    /// Comments attached to this statement.
1529    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1530    pub comments: Vec<String>,
1531    pub table: TableRef,
1532    pub columns: Vec<String>,
1533    pub source: InsertSource,
1534    /// ON CONFLICT / ON DUPLICATE KEY
1535    pub on_conflict: Option<OnConflict>,
1536    /// RETURNING clause
1537    pub returning: Vec<SelectItem>,
1538}
1539
1540#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1541pub enum InsertSource {
1542    Values(Vec<Vec<Expr>>),
1543    Query(Box<Statement>),
1544    Default,
1545}
1546
1547#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1548pub struct OnConflict {
1549    pub columns: Vec<String>,
1550    pub action: ConflictAction,
1551}
1552
1553#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1554pub enum ConflictAction {
1555    DoNothing,
1556    DoUpdate(Vec<(String, Expr)>),
1557}
1558
1559/// An UPDATE statement.
1560#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1561pub struct UpdateStatement {
1562    /// Comments attached to this statement.
1563    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1564    pub comments: Vec<String>,
1565    pub table: TableRef,
1566    pub assignments: Vec<(String, Expr)>,
1567    pub from: Option<FromClause>,
1568    pub where_clause: Option<Expr>,
1569    pub returning: Vec<SelectItem>,
1570}
1571
1572/// A DELETE statement.
1573#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1574pub struct DeleteStatement {
1575    /// Comments attached to this statement.
1576    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1577    pub comments: Vec<String>,
1578    pub table: TableRef,
1579    pub using: Option<FromClause>,
1580    pub where_clause: Option<Expr>,
1581    pub returning: Vec<SelectItem>,
1582}
1583
1584// ═══════════════════════════════════════════════════════════════════════
1585// MERGE statement
1586// ═══════════════════════════════════════════════════════════════════════
1587
1588/// A MERGE (UPSERT) statement.
1589///
1590/// MERGE INTO target USING source ON condition
1591///   WHEN MATCHED THEN UPDATE SET ...
1592///   WHEN NOT MATCHED THEN INSERT ...
1593#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1594pub struct MergeStatement {
1595    /// Comments attached to this statement.
1596    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1597    pub comments: Vec<String>,
1598    pub target: TableRef,
1599    pub source: TableSource,
1600    pub on: Expr,
1601    pub clauses: Vec<MergeClause>,
1602    /// OUTPUT clause (T-SQL extension)
1603    pub output: Vec<SelectItem>,
1604}
1605
1606/// A single WHEN MATCHED / WHEN NOT MATCHED clause in a MERGE statement.
1607#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1608pub struct MergeClause {
1609    pub kind: MergeClauseKind,
1610    /// Optional additional condition: WHEN MATCHED AND <condition>
1611    pub condition: Option<Expr>,
1612    pub action: MergeAction,
1613}
1614
1615/// The kind of WHEN clause in a MERGE statement.
1616#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1617pub enum MergeClauseKind {
1618    /// WHEN MATCHED
1619    Matched,
1620    /// WHEN NOT MATCHED (BY TARGET) — standard SQL and most dialects
1621    NotMatched,
1622    /// WHEN NOT MATCHED BY SOURCE — T-SQL extension
1623    NotMatchedBySource,
1624}
1625
1626/// The action to take in a MERGE WHEN clause.
1627#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1628pub enum MergeAction {
1629    /// UPDATE SET col = val, ...
1630    Update(Vec<(String, Expr)>),
1631    /// INSERT (columns) VALUES (values)
1632    Insert {
1633        columns: Vec<String>,
1634        values: Vec<Expr>,
1635    },
1636    /// INSERT ROW (BigQuery)
1637    InsertRow,
1638    /// DELETE
1639    Delete,
1640}
1641
1642// ═══════════════════════════════════════════════════════════════════════
1643// DDL statements
1644// ═══════════════════════════════════════════════════════════════════════
1645
1646/// A CREATE TABLE statement.
1647#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1648pub struct CreateTableStatement {
1649    /// Comments attached to this statement.
1650    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1651    pub comments: Vec<String>,
1652    pub if_not_exists: bool,
1653    pub temporary: bool,
1654    pub table: TableRef,
1655    pub columns: Vec<ColumnDef>,
1656    pub constraints: Vec<TableConstraint>,
1657    /// CREATE TABLE ... AS SELECT ...
1658    pub as_select: Option<Box<Statement>>,
1659}
1660
1661/// Table-level constraints.
1662#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1663pub enum TableConstraint {
1664    PrimaryKey {
1665        name: Option<String>,
1666        columns: Vec<String>,
1667    },
1668    Unique {
1669        name: Option<String>,
1670        columns: Vec<String>,
1671    },
1672    ForeignKey {
1673        name: Option<String>,
1674        columns: Vec<String>,
1675        ref_table: TableRef,
1676        ref_columns: Vec<String>,
1677        on_delete: Option<ReferentialAction>,
1678        on_update: Option<ReferentialAction>,
1679    },
1680    Check {
1681        name: Option<String>,
1682        expr: Expr,
1683    },
1684}
1685
1686#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1687pub enum ReferentialAction {
1688    Cascade,
1689    Restrict,
1690    NoAction,
1691    SetNull,
1692    SetDefault,
1693}
1694
1695/// A column definition in CREATE TABLE.
1696#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1697pub struct ColumnDef {
1698    pub name: String,
1699    pub data_type: DataType,
1700    pub nullable: Option<bool>,
1701    pub default: Option<Expr>,
1702    pub primary_key: bool,
1703    pub unique: bool,
1704    pub auto_increment: bool,
1705    pub collation: Option<String>,
1706    pub comment: Option<String>,
1707}
1708
1709/// ALTER TABLE statement.
1710#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1711pub struct AlterTableStatement {
1712    /// Comments attached to this statement.
1713    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1714    pub comments: Vec<String>,
1715    pub table: TableRef,
1716    pub actions: Vec<AlterTableAction>,
1717}
1718
1719#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1720pub enum AlterTableAction {
1721    AddColumn(ColumnDef),
1722    DropColumn { name: String, if_exists: bool },
1723    RenameColumn { old_name: String, new_name: String },
1724    AlterColumnType { name: String, data_type: DataType },
1725    AddConstraint(TableConstraint),
1726    DropConstraint { name: String },
1727    RenameTable { new_name: String },
1728}
1729
1730/// CREATE VIEW statement.
1731#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1732pub struct CreateViewStatement {
1733    /// Comments attached to this statement.
1734    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1735    pub comments: Vec<String>,
1736    pub name: TableRef,
1737    pub columns: Vec<String>,
1738    pub query: Box<Statement>,
1739    pub or_replace: bool,
1740    pub materialized: bool,
1741    pub if_not_exists: bool,
1742}
1743
1744/// DROP VIEW statement.
1745#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1746pub struct DropViewStatement {
1747    /// Comments attached to this statement.
1748    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1749    pub comments: Vec<String>,
1750    pub name: TableRef,
1751    pub if_exists: bool,
1752    pub materialized: bool,
1753}
1754
1755/// TRUNCATE TABLE statement.
1756#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1757pub struct TruncateStatement {
1758    /// Comments attached to this statement.
1759    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1760    pub comments: Vec<String>,
1761    pub table: TableRef,
1762}
1763
1764/// Transaction control statements.
1765#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1766pub enum TransactionStatement {
1767    Begin,
1768    Commit,
1769    Rollback,
1770    Savepoint(String),
1771    ReleaseSavepoint(String),
1772    RollbackTo(String),
1773}
1774
1775/// EXPLAIN statement.
1776#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1777pub struct ExplainStatement {
1778    /// Comments attached to this statement.
1779    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1780    pub comments: Vec<String>,
1781    pub analyze: bool,
1782    pub statement: Box<Statement>,
1783}
1784
1785/// USE database statement.
1786#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1787pub struct UseStatement {
1788    /// Comments attached to this statement.
1789    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1790    pub comments: Vec<String>,
1791    pub name: String,
1792}
1793
1794/// A raw-tail statement preserved verbatim for round-tripping.
1795///
1796/// Used for statements the parser accepts but does not model in detail —
1797/// `SET`, `SHOW`, `GO`, `DECLARE`, `COMMENT ON …`, `ANALYZE`, `DESCRIBE`,
1798/// `LOAD`, `EXPLAIN (FORMAT …)`, vendor-specific `ALTER TABLE` tails,
1799/// `CREATE OPERATOR/AGGREGATE/SEQUENCE/…`, etc. The verb sequence is
1800/// preserved in `kind` and the remainder of the statement (up to the next
1801/// `;` or EOF) is captured in `body` exactly as it appeared in the input.
1802#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1803pub struct CommandStatement {
1804    /// Comments attached to this statement.
1805    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1806    pub comments: Vec<String>,
1807    /// Leading verb(s), uppercased — e.g. "SET", "SHOW", "GO",
1808    /// "DECLARE", "COMMENT ON", "ANALYZE", "DESCRIBE", "LOAD",
1809    /// "CREATE OPERATOR", "ALTER TABLE", "REM".
1810    pub kind: String,
1811    /// Raw tail of the statement (everything after `kind`), reproduced
1812    /// verbatim so round-tripping preserves the original wording.
1813    pub body: String,
1814}
1815
1816/// A DROP TABLE statement.
1817#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
1818pub struct DropTableStatement {
1819    /// Comments attached to this statement.
1820    #[serde(default, skip_serializing_if = "Vec::is_empty")]
1821    pub comments: Vec<String>,
1822    pub if_exists: bool,
1823    pub table: TableRef,
1824    pub cascade: bool,
1825}
1826
1827// ═══════════════════════════════════════════════════════════════════════
1828// Data types
1829// ═══════════════════════════════════════════════════════════════════════
1830
1831/// SQL data types. Significantly expanded to match sqlglot's DataType.Type enum.
1832#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
1833pub enum DataType {
1834    // Numeric
1835    TinyInt,
1836    SmallInt,
1837    Int,
1838    BigInt,
1839    Float,
1840    Double,
1841    Decimal {
1842        precision: Option<u32>,
1843        scale: Option<u32>,
1844    },
1845    Numeric {
1846        precision: Option<u32>,
1847        scale: Option<u32>,
1848    },
1849    Real,
1850
1851    // String
1852    Varchar(Option<u32>),
1853    Char(Option<u32>),
1854    Text,
1855    String,
1856    Binary(Option<u32>),
1857    Varbinary(Option<u32>),
1858
1859    // Boolean
1860    Boolean,
1861
1862    // Date/Time
1863    Date,
1864    Time {
1865        precision: Option<u32>,
1866    },
1867    Timestamp {
1868        precision: Option<u32>,
1869        with_tz: bool,
1870    },
1871    Interval,
1872    DateTime,
1873
1874    // Binary
1875    Blob,
1876    Bytea,
1877    Bytes,
1878
1879    // JSON
1880    Json,
1881    Jsonb,
1882
1883    // UUID
1884    Uuid,
1885
1886    // Complex types
1887    Array(Option<Box<DataType>>),
1888    Map {
1889        key: Box<DataType>,
1890        value: Box<DataType>,
1891    },
1892    Struct(Vec<(String, DataType)>),
1893    Tuple(Vec<DataType>),
1894
1895    // Special
1896    Null,
1897    Unknown(String),
1898    Variant,
1899    Object,
1900    Xml,
1901    Inet,
1902    Cidr,
1903    Macaddr,
1904    Bit(Option<u32>),
1905    Money,
1906    Serial,
1907    BigSerial,
1908    SmallSerial,
1909    Regclass,
1910    Regtype,
1911    Hstore,
1912    Geography,
1913    Geometry,
1914    Super,
1915}
1916
1917// ═══════════════════════════════════════════════════════════════════════
1918// Expression tree traversal helpers
1919// ═══════════════════════════════════════════════════════════════════════
1920
1921impl Expr {
1922    /// Recursively walk this expression tree, calling `visitor` on each node.
1923    /// If `visitor` returns `false`, children of that node are not visited.
1924    pub fn walk<F>(&self, visitor: &mut F)
1925    where
1926        F: FnMut(&Expr) -> bool,
1927    {
1928        if !visitor(self) {
1929            return;
1930        }
1931        match self {
1932            Expr::BinaryOp { left, right, .. } => {
1933                left.walk(visitor);
1934                right.walk(visitor);
1935            }
1936            Expr::UnaryOp { expr, .. } => expr.walk(visitor),
1937            Expr::Function { args, filter, .. } => {
1938                for arg in args {
1939                    arg.walk(visitor);
1940                }
1941                if let Some(f) = filter {
1942                    f.walk(visitor);
1943                }
1944            }
1945            Expr::Between {
1946                expr, low, high, ..
1947            } => {
1948                expr.walk(visitor);
1949                low.walk(visitor);
1950                high.walk(visitor);
1951            }
1952            Expr::InList { expr, list, .. } => {
1953                expr.walk(visitor);
1954                for item in list {
1955                    item.walk(visitor);
1956                }
1957            }
1958            Expr::InSubquery { expr, .. } => {
1959                expr.walk(visitor);
1960            }
1961            Expr::IsNull { expr, .. } => expr.walk(visitor),
1962            Expr::IsBool { expr, .. } => expr.walk(visitor),
1963            Expr::AnyOp { expr, right, .. } | Expr::AllOp { expr, right, .. } => {
1964                expr.walk(visitor);
1965                right.walk(visitor);
1966            }
1967            Expr::Like { expr, pattern, .. }
1968            | Expr::ILike { expr, pattern, .. }
1969            | Expr::SimilarTo { expr, pattern, .. } => {
1970                expr.walk(visitor);
1971                pattern.walk(visitor);
1972            }
1973            Expr::Case {
1974                operand,
1975                when_clauses,
1976                else_clause,
1977            } => {
1978                if let Some(op) = operand {
1979                    op.walk(visitor);
1980                }
1981                for (cond, result) in when_clauses {
1982                    cond.walk(visitor);
1983                    result.walk(visitor);
1984                }
1985                if let Some(el) = else_clause {
1986                    el.walk(visitor);
1987                }
1988            }
1989            Expr::Nested(inner) => inner.walk(visitor),
1990            Expr::Cast { expr, .. } | Expr::TryCast { expr, .. } => expr.walk(visitor),
1991            Expr::Extract { expr, .. } => expr.walk(visitor),
1992            Expr::Interval { value, .. } => value.walk(visitor),
1993            Expr::ArrayLiteral(items) | Expr::Tuple(items) | Expr::Coalesce(items) => {
1994                for item in items {
1995                    item.walk(visitor);
1996                }
1997            }
1998            Expr::If {
1999                condition,
2000                true_val,
2001                false_val,
2002            } => {
2003                condition.walk(visitor);
2004                true_val.walk(visitor);
2005                if let Some(fv) = false_val {
2006                    fv.walk(visitor);
2007                }
2008            }
2009            Expr::NullIf { expr, r#else } => {
2010                expr.walk(visitor);
2011                r#else.walk(visitor);
2012            }
2013            Expr::Collate { expr, .. } => expr.walk(visitor),
2014            Expr::Alias { expr, .. } => expr.walk(visitor),
2015            Expr::ArrayIndex { expr, index } => {
2016                expr.walk(visitor);
2017                index.walk(visitor);
2018            }
2019            Expr::JsonAccess { expr, path, .. } => {
2020                expr.walk(visitor);
2021                path.walk(visitor);
2022            }
2023            Expr::Lambda { body, .. } => body.walk(visitor),
2024            Expr::TypedFunction { func, filter, .. } => {
2025                func.walk_children(visitor);
2026                if let Some(f) = filter {
2027                    f.walk(visitor);
2028                }
2029            }
2030            Expr::Cube { exprs } | Expr::Rollup { exprs } => {
2031                for item in exprs {
2032                    item.walk(visitor);
2033                }
2034            }
2035            Expr::GroupingSets { sets } => {
2036                for item in sets {
2037                    item.walk(visitor);
2038                }
2039            }
2040            Expr::Commented { expr, .. } => expr.walk(visitor),
2041            // Leaf nodes
2042            Expr::Column { .. }
2043            | Expr::Number(_)
2044            | Expr::StringLiteral(_)
2045            | Expr::NationalStringLiteral(_)
2046            | Expr::Boolean(_)
2047            | Expr::Null
2048            | Expr::Wildcard
2049            | Expr::Star
2050            | Expr::Parameter(_)
2051            | Expr::TypeExpr(_)
2052            | Expr::QualifiedWildcard { .. }
2053            | Expr::Default
2054            | Expr::Subquery(_)
2055            | Expr::Exists { .. } => {}
2056        }
2057    }
2058
2059    /// Find the first expression matching the predicate.
2060    #[must_use]
2061    pub fn find<F>(&self, predicate: &F) -> Option<&Expr>
2062    where
2063        F: Fn(&Expr) -> bool,
2064    {
2065        let mut result = None;
2066        self.walk(&mut |expr| {
2067            if result.is_some() {
2068                return false;
2069            }
2070            if predicate(expr) {
2071                result = Some(expr as *const Expr);
2072                false
2073            } else {
2074                true
2075            }
2076        });
2077        // SAFETY: the pointer is valid as long as self is alive
2078        result.map(|p| unsafe { &*p })
2079    }
2080
2081    /// Find all expressions matching the predicate.
2082    #[must_use]
2083    pub fn find_all<F>(&self, predicate: &F) -> Vec<&Expr>
2084    where
2085        F: Fn(&Expr) -> bool,
2086    {
2087        let mut results: Vec<*const Expr> = Vec::new();
2088        self.walk(&mut |expr| {
2089            if predicate(expr) {
2090                results.push(expr as *const Expr);
2091            }
2092            true
2093        });
2094        results.into_iter().map(|p| unsafe { &*p }).collect()
2095    }
2096
2097    /// Transform this expression tree by applying a function to each node.
2098    /// The function can return a new expression to replace the current one.
2099    #[must_use]
2100    pub fn transform<F>(self, func: &F) -> Expr
2101    where
2102        F: Fn(Expr) -> Expr,
2103    {
2104        let transformed = match self {
2105            Expr::BinaryOp { left, op, right } => Expr::BinaryOp {
2106                left: Box::new(left.transform(func)),
2107                op,
2108                right: Box::new(right.transform(func)),
2109            },
2110            Expr::UnaryOp { op, expr } => Expr::UnaryOp {
2111                op,
2112                expr: Box::new(expr.transform(func)),
2113            },
2114            Expr::Function {
2115                name,
2116                args,
2117                distinct,
2118                filter,
2119                over,
2120                order_by,
2121                within_group,
2122            } => Expr::Function {
2123                name,
2124                args: args.into_iter().map(|a| a.transform(func)).collect(),
2125                distinct,
2126                filter: filter.map(|f| Box::new(f.transform(func))),
2127                over,
2128                order_by,
2129                within_group,
2130            },
2131            Expr::Nested(inner) => Expr::Nested(Box::new(inner.transform(func))),
2132            Expr::Cast { expr, data_type } => Expr::Cast {
2133                expr: Box::new(expr.transform(func)),
2134                data_type,
2135            },
2136            Expr::Between {
2137                expr,
2138                low,
2139                high,
2140                negated,
2141            } => Expr::Between {
2142                expr: Box::new(expr.transform(func)),
2143                low: Box::new(low.transform(func)),
2144                high: Box::new(high.transform(func)),
2145                negated,
2146            },
2147            Expr::Case {
2148                operand,
2149                when_clauses,
2150                else_clause,
2151            } => Expr::Case {
2152                operand: operand.map(|o| Box::new(o.transform(func))),
2153                when_clauses: when_clauses
2154                    .into_iter()
2155                    .map(|(c, r)| (c.transform(func), r.transform(func)))
2156                    .collect(),
2157                else_clause: else_clause.map(|e| Box::new(e.transform(func))),
2158            },
2159            Expr::IsBool {
2160                expr,
2161                value,
2162                negated,
2163            } => Expr::IsBool {
2164                expr: Box::new(expr.transform(func)),
2165                value,
2166                negated,
2167            },
2168            Expr::AnyOp { expr, op, right } => Expr::AnyOp {
2169                expr: Box::new(expr.transform(func)),
2170                op,
2171                right: Box::new(right.transform(func)),
2172            },
2173            Expr::AllOp { expr, op, right } => Expr::AllOp {
2174                expr: Box::new(expr.transform(func)),
2175                op,
2176                right: Box::new(right.transform(func)),
2177            },
2178            Expr::TypedFunction {
2179                func: tf,
2180                filter,
2181                over,
2182            } => Expr::TypedFunction {
2183                func: tf.transform_children(func),
2184                filter: filter.map(|f| Box::new(f.transform(func))),
2185                over,
2186            },
2187            Expr::InList {
2188                expr,
2189                list,
2190                negated,
2191            } => Expr::InList {
2192                expr: Box::new(expr.transform(func)),
2193                list: list.into_iter().map(|e| e.transform(func)).collect(),
2194                negated,
2195            },
2196            Expr::InSubquery {
2197                expr,
2198                subquery,
2199                negated,
2200            } => Expr::InSubquery {
2201                expr: Box::new(expr.transform(func)),
2202                subquery, // Statement — not transformable via Expr func
2203                negated,
2204            },
2205            Expr::IsNull { expr, negated } => Expr::IsNull {
2206                expr: Box::new(expr.transform(func)),
2207                negated,
2208            },
2209            Expr::Like {
2210                expr,
2211                pattern,
2212                negated,
2213                escape,
2214            } => Expr::Like {
2215                expr: Box::new(expr.transform(func)),
2216                pattern: Box::new(pattern.transform(func)),
2217                negated,
2218                escape: escape.map(|e| Box::new(e.transform(func))),
2219            },
2220            Expr::ILike {
2221                expr,
2222                pattern,
2223                negated,
2224                escape,
2225            } => Expr::ILike {
2226                expr: Box::new(expr.transform(func)),
2227                pattern: Box::new(pattern.transform(func)),
2228                negated,
2229                escape: escape.map(|e| Box::new(e.transform(func))),
2230            },
2231            Expr::TryCast { expr, data_type } => Expr::TryCast {
2232                expr: Box::new(expr.transform(func)),
2233                data_type,
2234            },
2235            Expr::Extract { field, expr } => Expr::Extract {
2236                field,
2237                expr: Box::new(expr.transform(func)),
2238            },
2239            Expr::Interval { value, unit } => Expr::Interval {
2240                value: Box::new(value.transform(func)),
2241                unit,
2242            },
2243            Expr::ArrayLiteral(elems) => {
2244                Expr::ArrayLiteral(elems.into_iter().map(|e| e.transform(func)).collect())
2245            }
2246            Expr::Tuple(elems) => {
2247                Expr::Tuple(elems.into_iter().map(|e| e.transform(func)).collect())
2248            }
2249            Expr::Coalesce(elems) => {
2250                Expr::Coalesce(elems.into_iter().map(|e| e.transform(func)).collect())
2251            }
2252            Expr::If {
2253                condition,
2254                true_val,
2255                false_val,
2256            } => Expr::If {
2257                condition: Box::new(condition.transform(func)),
2258                true_val: Box::new(true_val.transform(func)),
2259                false_val: false_val.map(|f| Box::new(f.transform(func))),
2260            },
2261            Expr::NullIf { expr, r#else } => Expr::NullIf {
2262                expr: Box::new(expr.transform(func)),
2263                r#else: Box::new(r#else.transform(func)),
2264            },
2265            Expr::Collate { expr, collation } => Expr::Collate {
2266                expr: Box::new(expr.transform(func)),
2267                collation,
2268            },
2269            Expr::Alias { expr, name } => Expr::Alias {
2270                expr: Box::new(expr.transform(func)),
2271                name,
2272            },
2273            Expr::ArrayIndex { expr, index } => Expr::ArrayIndex {
2274                expr: Box::new(expr.transform(func)),
2275                index: Box::new(index.transform(func)),
2276            },
2277            Expr::JsonAccess {
2278                expr,
2279                path,
2280                as_text,
2281            } => Expr::JsonAccess {
2282                expr: Box::new(expr.transform(func)),
2283                path: Box::new(path.transform(func)),
2284                as_text,
2285            },
2286            Expr::Lambda { params, body } => Expr::Lambda {
2287                params,
2288                body: Box::new(body.transform(func)),
2289            },
2290            Expr::Cube { exprs } => Expr::Cube {
2291                exprs: exprs.into_iter().map(|e| e.transform(func)).collect(),
2292            },
2293            Expr::Rollup { exprs } => Expr::Rollup {
2294                exprs: exprs.into_iter().map(|e| e.transform(func)).collect(),
2295            },
2296            Expr::GroupingSets { sets } => Expr::GroupingSets {
2297                sets: sets.into_iter().map(|e| e.transform(func)).collect(),
2298            },
2299            Expr::Commented { expr, comments } => Expr::Commented {
2300                expr: Box::new(expr.transform(func)),
2301                comments,
2302            },
2303            other => other,
2304        };
2305        func(transformed)
2306    }
2307
2308    /// Check whether this expression is a column reference.
2309    #[must_use]
2310    pub fn is_column(&self) -> bool {
2311        matches!(self, Expr::Column { .. })
2312    }
2313
2314    /// Check whether this expression is a literal value (number, string, bool, null).
2315    #[must_use]
2316    pub fn is_literal(&self) -> bool {
2317        matches!(
2318            self,
2319            Expr::Number(_)
2320                | Expr::StringLiteral(_)
2321                | Expr::NationalStringLiteral(_)
2322                | Expr::Boolean(_)
2323                | Expr::Null
2324        )
2325    }
2326
2327    /// Get the SQL representation of this expression for display purposes.
2328    /// For full generation, use the Generator.
2329    #[must_use]
2330    pub fn sql(&self) -> String {
2331        use crate::generator::Generator;
2332        Generator::expr_to_sql(self)
2333    }
2334}
2335
2336/// Helper: collect all column references from an expression.
2337#[must_use]
2338pub fn find_columns(expr: &Expr) -> Vec<&Expr> {
2339    expr.find_all(&|e| matches!(e, Expr::Column { .. }))
2340}
2341
2342/// Helper: collect all table references from a statement.
2343#[must_use]
2344pub fn find_tables(statement: &Statement) -> Vec<&TableRef> {
2345    match statement {
2346        Statement::Select(sel) => {
2347            let mut tables = Vec::new();
2348            if let Some(from) = &sel.from {
2349                collect_table_refs_from_source(&from.source, &mut tables);
2350            }
2351            for join in &sel.joins {
2352                collect_table_refs_from_source(&join.table, &mut tables);
2353            }
2354            tables
2355        }
2356        Statement::Insert(ins) => vec![&ins.table],
2357        Statement::Update(upd) => vec![&upd.table],
2358        Statement::Delete(del) => vec![&del.table],
2359        Statement::CreateTable(ct) => vec![&ct.table],
2360        Statement::DropTable(dt) => vec![&dt.table],
2361        _ => vec![],
2362    }
2363}
2364
2365fn collect_table_refs_from_source<'a>(source: &'a TableSource, tables: &mut Vec<&'a TableRef>) {
2366    match source {
2367        TableSource::Table(table_ref) => tables.push(table_ref),
2368        TableSource::Subquery { .. } => {}
2369        TableSource::TableFunction { .. } => {}
2370        TableSource::Lateral { source } => collect_table_refs_from_source(source, tables),
2371        TableSource::Pivot { source, .. } | TableSource::Unpivot { source, .. } => {
2372            collect_table_refs_from_source(source, tables);
2373        }
2374        TableSource::Unnest { .. } => {}
2375    }
2376}