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