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