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