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