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