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