Skip to main content

sqlglot_rust/ast/
types.rs

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