Skip to main content

sqlglot_rust/ast/
types.rs

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