Skip to main content

sqlglot_rust/ast/
types.rs

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