Skip to main content

radixdb_sql/ast/
expression.rs

1// Copyright 2026 RadixDB Contributors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use super::*;
16
17// ============================================================================
18// Core Traits
19// ============================================================================
20
21/// Node trait - base for all AST nodes
22pub trait Node: fmt::Display + fmt::Debug {
23    /// Returns the literal string of the first token
24    fn token_literal(&self) -> &str;
25    /// Returns the position of the node in source code
26    fn position(&self) -> Position;
27}
28
29// ============================================================================
30// Expressions
31// ============================================================================
32
33/// Expression enum representing all expression types
34#[derive(Debug, Clone, PartialEq)]
35pub enum Expression {
36    /// Identifier (column name, table name)
37    Identifier(Identifier),
38    /// Qualified identifier (table.column)
39    QualifiedIdentifier(QualifiedIdentifier),
40    /// Integer literal
41    IntegerLiteral(IntegerLiteral),
42    /// Float literal
43    FloatLiteral(FloatLiteral),
44    /// String literal
45    StringLiteral(StringLiteral),
46    /// Boolean literal (TRUE/FALSE)
47    BooleanLiteral(BooleanLiteral),
48    /// NULL literal
49    NullLiteral(NullLiteral),
50    /// INTERVAL literal
51    IntervalLiteral(IntervalLiteral),
52    /// Executor-bound typed value. Never produced by the SQL parser; this
53    /// preserves exact subquery/runtime identity during internal rewriting.
54    BoundValue(Box<Value>),
55    /// Parameter ($1, ?)
56    Parameter(Parameter),
57    /// Prefix expression (-x, NOT x)
58    Prefix(PrefixExpression),
59    /// Infix expression (a + b, a = b)
60    Infix(InfixExpression),
61    /// List of expressions (for IN clause) - Boxed to reduce enum size
62    List(Box<ListExpression>),
63    /// DISTINCT expression
64    Distinct(DistinctExpression),
65    /// EXISTS subquery
66    Exists(ExistsExpression),
67    /// ALL/ANY/SOME subquery comparison (e.g., x > ALL (SELECT ...))
68    AllAny(AllAnyExpression),
69    /// IN expression
70    In(InExpression),
71    /// Pre-computed IN expression with HashSet (for semi-join optimization)
72    /// Uses Arc for cheap cloning in parallel execution
73    InHashSet(InHashSetExpression),
74    /// BETWEEN expression
75    Between(BetweenExpression),
76    /// LIKE expression (with optional ESCAPE clause)
77    Like(LikeExpression),
78    /// Scalar subquery
79    ScalarSubquery(ScalarSubquery),
80    /// Expression list (for IN values) - Boxed to reduce enum size
81    ExpressionList(Box<ExpressionList>),
82    /// CASE expression - Boxed to reduce enum size
83    Case(Box<CaseExpression>),
84    /// CAST expression
85    Cast(CastExpression),
86    /// Function call - Boxed to reduce enum size (has 2 Vecs)
87    FunctionCall(Box<FunctionCall>),
88    /// Aliased expression (expr AS alias)
89    Aliased(AliasedExpression),
90    /// Window expression - Boxed to reduce enum size (has 2 Vecs)
91    Window(Box<WindowExpression>),
92    /// Simple table source - Boxed to reduce enum size
93    TableSource(Box<SimpleTableSource>),
94    /// Join table source
95    JoinSource(Box<JoinTableSource>),
96    /// Subquery table source - Boxed to reduce enum size (216 bytes unboxed)
97    SubquerySource(Box<SubqueryTableSource>),
98    /// VALUES table source - Boxed to reduce enum size (256 bytes unboxed)
99    ValuesSource(Box<ValuesTableSource>),
100    /// CTE reference - Boxed to reduce enum size (336 bytes unboxed)
101    CteReference(Box<CteReference>),
102    /// Function table source (table-valued function in FROM clause) - Boxed to reduce enum size
103    FunctionTableSource(Box<FunctionTableSource>),
104    /// Star (*) for SELECT *
105    Star(StarExpression),
106    /// Qualified star (table.*) for SELECT table.*
107    QualifiedStar(QualifiedStarExpression),
108    /// DEFAULT keyword (for INSERT VALUES)
109    Default(DefaultExpression),
110}
111
112impl fmt::Display for Expression {
113    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114        match self {
115            Expression::Identifier(e) => write!(f, "{}", e),
116            Expression::QualifiedIdentifier(e) => write!(f, "{}", e),
117            Expression::IntegerLiteral(e) => write!(f, "{}", e),
118            Expression::FloatLiteral(e) => write!(f, "{}", e),
119            Expression::StringLiteral(e) => write!(f, "{}", e),
120            Expression::BooleanLiteral(e) => write!(f, "{}", e),
121            Expression::NullLiteral(e) => write!(f, "{}", e),
122            Expression::IntervalLiteral(e) => write!(f, "{}", e),
123            Expression::BoundValue(value) => write!(f, "<bound:{}>", value.data_type()),
124            Expression::Parameter(e) => write!(f, "{}", e),
125            Expression::Prefix(e) => write!(f, "{}", e),
126            Expression::Infix(e) => write!(f, "{}", e),
127            Expression::List(e) => write!(f, "{}", e),
128            Expression::Distinct(e) => write!(f, "{}", e),
129            Expression::Exists(e) => write!(f, "{}", e),
130            Expression::AllAny(e) => write!(f, "{}", e),
131            Expression::In(e) => write!(f, "{}", e),
132            Expression::InHashSet(e) => write!(f, "{}", e),
133            Expression::Between(e) => write!(f, "{}", e),
134            Expression::Like(e) => write!(f, "{}", e),
135            Expression::ScalarSubquery(e) => write!(f, "{}", e),
136            Expression::ExpressionList(e) => write!(f, "{}", e),
137            Expression::Case(e) => write!(f, "{}", e),
138            Expression::Cast(e) => write!(f, "{}", e),
139            Expression::FunctionCall(e) => write!(f, "{}", e),
140            Expression::Aliased(e) => write!(f, "{}", e),
141            Expression::Window(e) => write!(f, "{}", e),
142            Expression::TableSource(e) => write!(f, "{}", e),
143            Expression::JoinSource(e) => write!(f, "{}", e),
144            Expression::SubquerySource(e) => write!(f, "{}", e),
145            Expression::ValuesSource(e) => write!(f, "{}", e),
146            Expression::CteReference(e) => write!(f, "{}", e),
147            Expression::FunctionTableSource(e) => write!(f, "{}", e),
148            Expression::Star(e) => write!(f, "{}", e),
149            Expression::QualifiedStar(e) => write!(f, "{}", e),
150            Expression::Default(e) => write!(f, "{}", e),
151        }
152    }
153}
154
155impl Expression {
156    /// Get the position of this expression
157    pub fn position(&self) -> Position {
158        match self {
159            Expression::Identifier(e) => e.token.position,
160            Expression::QualifiedIdentifier(e) => e.token.position,
161            Expression::IntegerLiteral(e) => e.token.position,
162            Expression::FloatLiteral(e) => e.token.position,
163            Expression::StringLiteral(e) => e.token.position,
164            Expression::BooleanLiteral(e) => e.token.position,
165            Expression::NullLiteral(e) => e.token.position,
166            Expression::IntervalLiteral(e) => e.token.position,
167            Expression::BoundValue(_) => Position::default(),
168            Expression::Parameter(e) => e.token.position,
169            Expression::Prefix(e) => e.token.position,
170            Expression::Infix(e) => e.token.position,
171            Expression::List(e) => e.token.position,
172            Expression::Distinct(e) => e.token.position,
173            Expression::Exists(e) => e.token.position,
174            Expression::AllAny(e) => e.token.position,
175            Expression::In(e) => e.token.position,
176            Expression::InHashSet(e) => e.token.position,
177            Expression::Between(e) => e.token.position,
178            Expression::Like(e) => e.token.position,
179            Expression::ScalarSubquery(e) => e.token.position,
180            Expression::ExpressionList(e) => e.token.position,
181            Expression::Case(e) => e.token.position,
182            Expression::Cast(e) => e.token.position,
183            Expression::FunctionCall(e) => e.token.position,
184            Expression::Aliased(e) => e.token.position,
185            Expression::Window(e) => e.token.position,
186            Expression::TableSource(e) => e.token.position,
187            Expression::JoinSource(e) => e.token.position,
188            Expression::SubquerySource(e) => e.token.position,
189            Expression::ValuesSource(e) => e.token.position,
190            Expression::CteReference(e) => e.token.position,
191            Expression::FunctionTableSource(e) => e.token.position,
192            Expression::Star(e) => e.token.position,
193            Expression::QualifiedStar(e) => e.token.position,
194            Expression::Default(e) => e.token.position,
195        }
196    }
197}
198
199// ============================================================================
200// Expression Types
201// ============================================================================
202
203/// Identifier (column name, table name, etc.)
204#[derive(Debug, Clone, PartialEq)]
205pub struct Identifier {
206    pub token: Token,
207    #[doc(hidden)]
208    pub value: SmartString,
209    /// Pre-computed lowercase value for fast case-insensitive lookups
210    #[doc(hidden)]
211    pub value_lower: SmartString,
212}
213
214impl Identifier {
215    /// Create a new identifier with pre-computed lowercase value.
216    /// Keywords are uppercased by the lexer for parsing; when used as identifiers
217    /// (column names, aliases, table names), fold to lowercase like PostgreSQL.
218    #[inline]
219    pub fn new(token: Token, value: impl Into<SmartString>) -> Self {
220        let value = value.into();
221        if token.token_type == TokenType::Keyword {
222            // Keywords are uppercased by the lexer; fold to lowercase like PostgreSQL.
223            // value and value_lower are identical, so avoid double lowercasing.
224            let lowered = value.to_lowercase();
225            Self {
226                token,
227                value_lower: lowered.clone(),
228                value: lowered,
229            }
230        } else {
231            let value_lower = value.to_lowercase();
232            Self {
233                token,
234                value,
235                value_lower,
236            }
237        }
238    }
239
240    #[inline]
241    pub fn value(&self) -> &str {
242        &self.value
243    }
244
245    #[inline]
246    pub fn value_lower(&self) -> &str {
247        &self.value_lower
248    }
249}
250
251impl fmt::Display for Identifier {
252    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
253        if self.token.quoted {
254            write!(f, "\"{}\"", self.value.replace('"', "\"\""))
255        } else {
256            write!(f, "{}", self.value)
257        }
258    }
259}
260
261/// Qualified identifier or an unresolved multi-part identifier path.
262///
263/// Two-component identifiers keep the historic `qualifier.name` shape. For
264/// longer paths, `intermediate` owns every component between the root
265/// qualifier and terminal name. The parser preserves each component as an
266/// `Identifier`, including its source token and position; schema meaning is
267/// deliberately assigned later by the binder.
268#[derive(Debug, Clone, PartialEq)]
269pub struct QualifiedIdentifier {
270    pub token: Token,
271    pub qualifier: Box<Identifier>,
272    /// Allocated only for paths longer than `qualifier.name`, keeping the
273    /// common two-component AST node compact.
274    pub intermediate: Option<Box<Vec<Identifier>>>,
275    pub name: Box<Identifier>,
276}
277
278impl QualifiedIdentifier {
279    #[inline]
280    pub fn component_count(&self) -> usize {
281        self.intermediate.as_ref().map_or(0, |items| items.len()) + 2
282    }
283
284    #[inline]
285    pub fn is_multi_part_path(&self) -> bool {
286        self.intermediate
287            .as_ref()
288            .is_some_and(|items| !items.is_empty())
289    }
290
291    pub fn components(&self) -> impl Iterator<Item = &Identifier> {
292        std::iter::once(self.qualifier.as_ref())
293            .chain(
294                self.intermediate
295                    .as_deref()
296                    .into_iter()
297                    .flat_map(|items| items.iter()),
298            )
299            .chain(std::iter::once(self.name.as_ref()))
300    }
301}
302
303impl fmt::Display for QualifiedIdentifier {
304    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
305        write!(f, "{}", self.qualifier)?;
306        if let Some(intermediate) = &self.intermediate {
307            for component in intermediate.iter() {
308                write!(f, ".{component}")?;
309            }
310        }
311        write!(f, ".{}", self.name)
312    }
313}
314
315/// Integer literal
316#[derive(Debug, Clone, PartialEq)]
317pub struct IntegerLiteral {
318    pub token: Token,
319    pub value: i64,
320}
321
322impl fmt::Display for IntegerLiteral {
323    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
324        write!(f, "{}", self.value)
325    }
326}
327
328/// Float literal
329#[derive(Debug, Clone, PartialEq)]
330pub struct FloatLiteral {
331    pub token: Token,
332    pub value: f64,
333}
334
335impl fmt::Display for FloatLiteral {
336    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
337        let rendered = self.value.to_string();
338        if self.value.is_finite()
339            && !rendered.contains('.')
340            && !rendered.contains('e')
341            && !rendered.contains('E')
342        {
343            write!(f, "{}.0", rendered)
344        } else {
345            write!(f, "{}", rendered)
346        }
347    }
348}
349
350/// String literal
351#[derive(Debug, Clone, PartialEq)]
352pub struct StringLiteral {
353    pub token: Token,
354    pub value: SmartString,
355    /// Optional type hint (DATE, TIME, JSON, etc.)
356    pub type_hint: Option<SmartString>,
357}
358
359impl fmt::Display for StringLiteral {
360    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
361        if let Some(type_hint) = &self.type_hint {
362            write!(
363                f,
364                "{} '{}'",
365                type_hint.to_uppercase(),
366                self.value.replace('\'', "''")
367            )
368        } else {
369            write!(f, "'{}'", self.value.replace('\'', "''"))
370        }
371    }
372}
373
374/// Boolean literal
375#[derive(Debug, Clone, PartialEq)]
376pub struct BooleanLiteral {
377    pub token: Token,
378    pub value: bool,
379}
380
381impl fmt::Display for BooleanLiteral {
382    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
383        write!(f, "{}", if self.value { "TRUE" } else { "FALSE" })
384    }
385}
386
387/// NULL literal
388#[derive(Debug, Clone, PartialEq)]
389pub struct NullLiteral {
390    pub token: Token,
391}
392
393impl fmt::Display for NullLiteral {
394    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
395        write!(f, "NULL")
396    }
397}
398
399/// INTERVAL literal
400#[derive(Debug, Clone, PartialEq)]
401pub struct IntervalLiteral {
402    pub token: Token,
403    pub value: SmartString,
404    pub quantity: i64,
405    pub unit: SmartString,
406}
407
408impl fmt::Display for IntervalLiteral {
409    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
410        write!(f, "INTERVAL '{}'", self.value)
411    }
412}
413
414/// Parameter ($1, ?)
415#[derive(Debug, Clone, PartialEq)]
416pub struct Parameter {
417    pub token: Token,
418    pub name: SmartString,
419    pub index: usize,
420    /// Optional record field selected from a named procedural parameter, for
421    /// example `:NEW.id`. The SQL parser preserves it as a parameter leaf;
422    /// only the stored-program binder resolves the record contract.
423    pub field: Option<Box<Identifier>>,
424}
425
426impl fmt::Display for Parameter {
427    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
428        if self.name.is_empty() {
429            write!(f, "?")
430        } else if let Some(field) = &self.field {
431            write!(f, "{}.{}", self.name, field)
432        } else {
433            write!(f, "{}", self.name)
434        }
435    }
436}
437
438/// Infix operator type (pre-computed at parse time for zero-allocation evaluation)
439/// This is a key optimization: instead of string comparison for every row,
440/// we match on a small enum which is faster and allocation-free.
441#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
442pub enum InfixOperator {
443    // Comparison operators
444    Equal,        // =
445    NotEqual,     // <> or !=
446    LessThan,     // <
447    LessEqual,    // <=
448    GreaterThan,  // >
449    GreaterEqual, // >=
450
451    // Logical operators
452    And,
453    Or,
454    Xor,
455
456    // Arithmetic operators
457    Add,      // +
458    Subtract, // -
459    Multiply, // *
460    Divide,   // /
461    Modulo,   // % or MOD
462
463    // String operators
464    Concat, // ||
465
466    // Pattern matching
467    Like,
468    ILike,
469    NotLike,
470    NotILike,
471    Glob,
472    NotGlob,
473    Regexp,
474    NotRegexp,
475
476    // Null check
477    Is,                // IS (NULL)
478    IsNot,             // IS NOT (NULL)
479    IsDistinctFrom,    // IS DISTINCT FROM (NULL-safe not equal)
480    IsNotDistinctFrom, // IS NOT DISTINCT FROM (NULL-safe equal)
481
482    // Array index
483    Index, // []
484
485    // JSON operators
486    JsonAccess,     // -> (returns JSON)
487    JsonAccessText, // ->> (returns TEXT)
488
489    // Vector distance operator
490    VectorDistance, // <=>
491
492    // Bitwise operators
493    BitwiseAnd, // &
494    BitwiseOr,  // |
495    BitwiseXor, // ^
496    LeftShift,  // <<
497    RightShift, // >>
498
499    // Unknown/other (fallback for rare operators)
500    Other,
501}
502
503impl InfixOperator {
504    /// Parse operator string to enum (called once at parse time)
505    #[inline]
506    #[allow(clippy::should_implement_trait)]
507    pub fn from_str(s: &str) -> Self {
508        match s.to_uppercase().as_str() {
509            "=" => InfixOperator::Equal,
510            "<>" | "!=" => InfixOperator::NotEqual,
511            "<" => InfixOperator::LessThan,
512            "<=" => InfixOperator::LessEqual,
513            ">" => InfixOperator::GreaterThan,
514            ">=" => InfixOperator::GreaterEqual,
515            "AND" => InfixOperator::And,
516            "OR" => InfixOperator::Or,
517            "XOR" => InfixOperator::Xor,
518            "+" => InfixOperator::Add,
519            "-" => InfixOperator::Subtract,
520            "*" => InfixOperator::Multiply,
521            "/" => InfixOperator::Divide,
522            "%" | "MOD" => InfixOperator::Modulo,
523            "||" => InfixOperator::Concat,
524            "LIKE" => InfixOperator::Like,
525            "ILIKE" => InfixOperator::ILike,
526            "NOT LIKE" => InfixOperator::NotLike,
527            "NOT ILIKE" => InfixOperator::NotILike,
528            "GLOB" => InfixOperator::Glob,
529            "NOT GLOB" => InfixOperator::NotGlob,
530            "REGEXP" | "RLIKE" => InfixOperator::Regexp,
531            "NOT REGEXP" | "NOT RLIKE" => InfixOperator::NotRegexp,
532            "IS" => InfixOperator::Is,
533            "IS NOT" => InfixOperator::IsNot,
534            "IS DISTINCT FROM" => InfixOperator::IsDistinctFrom,
535            "IS NOT DISTINCT FROM" => InfixOperator::IsNotDistinctFrom,
536            "[]" => InfixOperator::Index,
537            "->" => InfixOperator::JsonAccess,
538            "->>" => InfixOperator::JsonAccessText,
539            "<=>" => InfixOperator::VectorDistance,
540            "&" => InfixOperator::BitwiseAnd,
541            "|" => InfixOperator::BitwiseOr,
542            "^" => InfixOperator::BitwiseXor,
543            "<<" => InfixOperator::LeftShift,
544            ">>" => InfixOperator::RightShift,
545            _ => InfixOperator::Other,
546        }
547    }
548}
549
550/// Prefix operator type (pre-computed at parse time)
551#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
552pub enum PrefixOperator {
553    Negate,     // -
554    Not,        // NOT
555    Plus,       // + (unary plus, no-op)
556    BitwiseNot, // ~ (bitwise NOT)
557    Other,
558}
559
560impl PrefixOperator {
561    /// Parse operator string to enum (called once at parse time)
562    #[inline]
563    #[allow(clippy::should_implement_trait)]
564    pub fn from_str(s: &str) -> Self {
565        match s.to_uppercase().as_str() {
566            "-" => PrefixOperator::Negate,
567            "NOT" => PrefixOperator::Not,
568            "+" => PrefixOperator::Plus,
569            "~" => PrefixOperator::BitwiseNot,
570            _ => PrefixOperator::Other,
571        }
572    }
573}
574
575/// Star expression (*)
576#[derive(Debug, Clone, PartialEq)]
577pub struct StarExpression {
578    pub token: Token,
579}
580
581impl fmt::Display for StarExpression {
582    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
583        write!(f, "*")
584    }
585}
586
587/// Qualified star expression (table.*)
588#[derive(Debug, Clone, PartialEq)]
589pub struct QualifiedStarExpression {
590    pub token: Token,
591    pub qualifier: SmartString,
592}
593
594impl fmt::Display for QualifiedStarExpression {
595    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
596        write!(f, "{}.*", self.qualifier)
597    }
598}
599
600/// DEFAULT keyword expression (for INSERT VALUES)
601#[derive(Debug, Clone, PartialEq)]
602pub struct DefaultExpression {
603    pub token: Token,
604}
605
606impl fmt::Display for DefaultExpression {
607    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
608        write!(f, "DEFAULT")
609    }
610}
611
612/// Prefix expression (-x, NOT x)
613#[derive(Debug, Clone, PartialEq)]
614pub struct PrefixExpression {
615    pub token: Token,
616    #[doc(hidden)]
617    pub operator: SmartString,
618    /// Pre-computed operator type for fast evaluation (no string comparison)
619    #[doc(hidden)]
620    pub op_type: PrefixOperator,
621    pub right: Box<Expression>,
622}
623
624impl PrefixExpression {
625    /// Create a new prefix expression with auto-computed op_type
626    #[inline]
627    pub fn new(token: Token, operator: impl Into<SmartString>, right: Box<Expression>) -> Self {
628        let operator = operator.into();
629        let op_type = PrefixOperator::from_str(&operator);
630        Self {
631            token,
632            operator,
633            op_type,
634            right,
635        }
636    }
637
638    #[inline]
639    pub fn operator(&self) -> &str {
640        &self.operator
641    }
642
643    #[inline]
644    pub fn op_type(&self) -> PrefixOperator {
645        self.op_type
646    }
647}
648
649impl fmt::Display for PrefixExpression {
650    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
651        if self.operator == "-" || self.operator == "+" {
652            write!(f, "({}{})", self.operator, self.right)
653        } else {
654            write!(f, "({} {})", self.operator, self.right)
655        }
656    }
657}
658
659/// Infix expression (a + b, a = b)
660#[derive(Debug, Clone, PartialEq)]
661pub struct InfixExpression {
662    pub token: Token,
663    pub left: Box<Expression>,
664    #[doc(hidden)]
665    pub operator: SmartString,
666    /// Pre-computed operator type for fast evaluation (no string comparison)
667    #[doc(hidden)]
668    pub op_type: InfixOperator,
669    pub right: Box<Expression>,
670}
671
672impl InfixExpression {
673    /// Create a new infix expression with auto-computed op_type
674    #[inline]
675    pub fn new(
676        token: Token,
677        left: Box<Expression>,
678        operator: impl Into<SmartString>,
679        right: Box<Expression>,
680    ) -> Self {
681        let operator = operator.into();
682        let op_type = InfixOperator::from_str(&operator);
683        Self {
684            token,
685            left,
686            operator,
687            op_type,
688            right,
689        }
690    }
691
692    #[inline]
693    pub fn operator(&self) -> &str {
694        &self.operator
695    }
696
697    #[inline]
698    pub fn op_type(&self) -> InfixOperator {
699        self.op_type
700    }
701}
702
703impl fmt::Display for InfixExpression {
704    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
705        write!(f, "({} {} {})", self.left, self.operator, self.right)
706    }
707}
708
709/// List expression (for IN clause values)
710#[derive(Debug, Clone, PartialEq)]
711pub struct ListExpression {
712    pub token: Token,
713    pub elements: Vec<Expression>,
714}
715
716impl fmt::Display for ListExpression {
717    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
718        let elements: Vec<String> = self.elements.iter().map(|e| e.to_string()).collect();
719        write!(f, "({})", elements.join(", "))
720    }
721}
722
723/// DISTINCT expression
724#[derive(Debug, Clone, PartialEq)]
725pub struct DistinctExpression {
726    pub token: Token,
727    pub expr: Box<Expression>,
728}
729
730impl fmt::Display for DistinctExpression {
731    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
732        write!(f, "DISTINCT {}", self.expr)
733    }
734}
735
736/// EXISTS expression
737#[derive(Debug, Clone, PartialEq)]
738pub struct ExistsExpression {
739    pub token: Token,
740    pub subquery: Box<SelectStatement>,
741}
742
743impl fmt::Display for ExistsExpression {
744    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
745        write!(f, "EXISTS ({})", self.subquery)
746    }
747}
748
749/// ALL/ANY comparison type
750#[derive(Debug, Clone, Copy, PartialEq, Eq)]
751pub enum AllAnyType {
752    All,
753    Any,
754}
755
756impl fmt::Display for AllAnyType {
757    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
758        match self {
759            AllAnyType::All => write!(f, "ALL"),
760            AllAnyType::Any => write!(f, "ANY"),
761        }
762    }
763}
764
765/// ALL/ANY/SOME subquery expression (e.g., x > ALL (SELECT ...))
766#[derive(Debug, Clone, PartialEq)]
767pub struct AllAnyExpression {
768    pub token: Token,
769    pub left: Box<Expression>,
770    pub operator: SmartString,
771    pub all_any_type: AllAnyType,
772    pub subquery: Box<SelectStatement>,
773}
774
775impl fmt::Display for AllAnyExpression {
776    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
777        write!(
778            f,
779            "{} {} {} ({})",
780            self.left, self.operator, self.all_any_type, self.subquery
781        )
782    }
783}
784
785/// IN expression
786#[derive(Debug, Clone, PartialEq)]
787pub struct InExpression {
788    pub token: Token,
789    pub left: Box<Expression>,
790    pub right: Box<Expression>,
791    pub not: bool,
792}
793
794impl fmt::Display for InExpression {
795    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
796        if self.not {
797            write!(f, "{} NOT IN {}", self.left, self.right)
798        } else {
799            write!(f, "{} IN {}", self.left, self.right)
800        }
801    }
802}
803
804/// Pre-computed IN expression with HashSet for O(1) lookup
805///
806/// This is used by the semi-join optimization to avoid rebuilding
807/// the HashSet on every row during parallel filtering.
808/// Arc enables cheap cloning when the expression is cloned for parallel execution.
809#[derive(Debug, Clone)]
810pub struct InHashSetExpression {
811    pub token: Token,
812    /// The column/expression to check
813    pub column: Box<Expression>,
814    /// Pre-computed ValueSet for O(1) lookup - Arc for cheap parallel cloning
815    pub values: CompactArc<ValueSet>,
816    /// Whether this is NOT IN
817    pub not: bool,
818}
819
820impl PartialEq for InHashSetExpression {
821    fn eq(&self, other: &Self) -> bool {
822        // Compare by CompactArc pointer for efficiency (same HashSet = same CompactArc)
823        self.not == other.not
824            && CompactArc::ptr_eq(&self.values, &other.values)
825            && self.column == other.column
826    }
827}
828
829impl fmt::Display for InHashSetExpression {
830    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
831        if self.not {
832            write!(f, "{} NOT IN (<{} values>)", self.column, self.values.len())
833        } else {
834            write!(f, "{} IN (<{} values>)", self.column, self.values.len())
835        }
836    }
837}
838
839/// BETWEEN expression
840#[derive(Debug, Clone, PartialEq)]
841pub struct BetweenExpression {
842    pub token: Token,
843    pub expr: Box<Expression>,
844    pub lower: Box<Expression>,
845    pub upper: Box<Expression>,
846    pub not: bool,
847}
848
849impl fmt::Display for BetweenExpression {
850    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
851        if self.not {
852            write!(
853                f,
854                "{} NOT BETWEEN {} AND {}",
855                self.expr, self.lower, self.upper
856            )
857        } else {
858            write!(f, "{} BETWEEN {} AND {}", self.expr, self.lower, self.upper)
859        }
860    }
861}
862
863/// LIKE expression with optional ESCAPE clause
864#[derive(Debug, Clone, PartialEq)]
865pub struct LikeExpression {
866    pub token: Token,
867    pub left: Box<Expression>,
868    pub pattern: Box<Expression>,
869    /// The operator: LIKE, ILIKE, NOT LIKE, NOT ILIKE, GLOB, NOT GLOB, REGEXP, RLIKE, NOT REGEXP, NOT RLIKE
870    pub operator: SmartString,
871    /// Optional escape character
872    pub escape: Option<Box<Expression>>,
873}
874
875impl fmt::Display for LikeExpression {
876    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
877        write!(f, "{} {} {}", self.left, self.operator, self.pattern)?;
878        if let Some(ref escape) = self.escape {
879            write!(f, " ESCAPE {}", escape)?;
880        }
881        Ok(())
882    }
883}
884
885/// Scalar subquery
886#[derive(Debug, Clone, PartialEq)]
887pub struct ScalarSubquery {
888    pub token: Token,
889    pub subquery: Box<SelectStatement>,
890}
891
892impl fmt::Display for ScalarSubquery {
893    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
894        write!(f, "({})", self.subquery)
895    }
896}
897
898/// Expression list (for IN values)
899#[derive(Debug, Clone, PartialEq)]
900pub struct ExpressionList {
901    pub token: Token,
902    pub expressions: Vec<Expression>,
903}
904
905impl fmt::Display for ExpressionList {
906    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
907        let exprs: Vec<String> = self.expressions.iter().map(|e| e.to_string()).collect();
908        write!(f, "({})", exprs.join(", "))
909    }
910}
911
912/// CASE expression
913#[derive(Debug, Clone, PartialEq)]
914pub struct CaseExpression {
915    pub token: Token,
916    pub value: Option<Box<Expression>>,
917    pub when_clauses: Vec<WhenClause>,
918    pub else_value: Option<Box<Expression>>,
919}
920
921impl fmt::Display for CaseExpression {
922    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
923        let mut result = String::from("CASE");
924        if let Some(ref val) = self.value {
925            result.push_str(&format!(" {}", val));
926        }
927        for when in &self.when_clauses {
928            result.push_str(&format!(" {}", when));
929        }
930        if let Some(ref else_val) = self.else_value {
931            result.push_str(&format!(" ELSE {}", else_val));
932        }
933        result.push_str(" END");
934        write!(f, "{}", result)
935    }
936}
937
938/// WHEN clause in CASE expression
939#[derive(Debug, Clone, PartialEq)]
940pub struct WhenClause {
941    pub token: Token,
942    pub condition: Expression,
943    pub then_result: Expression,
944}
945
946impl fmt::Display for WhenClause {
947    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
948        write!(f, "WHEN {} THEN {}", self.condition, self.then_result)
949    }
950}
951
952/// CAST expression
953#[derive(Debug, Clone, PartialEq)]
954pub struct CastExpression {
955    pub token: Token,
956    pub expr: Box<Expression>,
957    pub type_name: SmartString,
958}
959
960impl fmt::Display for CastExpression {
961    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
962        write!(f, "CAST({} AS {})", self.expr, self.type_name)
963    }
964}
965
966/// Function call
967#[derive(Debug, Clone, PartialEq)]
968pub struct FunctionCall {
969    pub token: Token,
970    pub function: SmartString,
971    pub arguments: Vec<Expression>,
972    pub is_distinct: bool,
973    pub order_by: Vec<OrderByExpression>,
974    /// FILTER clause for aggregate functions (e.g., COUNT(*) FILTER (WHERE condition))
975    pub filter: Option<Box<Expression>>,
976}
977
978impl fmt::Display for FunctionCall {
979    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
980        let mut args = String::new();
981        if self.is_distinct && !self.arguments.is_empty() {
982            args.push_str("DISTINCT ");
983            args.push_str(&self.arguments[0].to_string());
984            for arg in &self.arguments[1..] {
985                args.push_str(", ");
986                args.push_str(&arg.to_string());
987            }
988        } else {
989            let arg_strs: Vec<String> = self
990                .arguments
991                .iter()
992                .map(|a| {
993                    if matches!(a, Expression::Star(_)) {
994                        "*".to_string()
995                    } else {
996                        a.to_string()
997                    }
998                })
999                .collect();
1000            args = arg_strs.join(", ");
1001        }
1002        if !self.order_by.is_empty() {
1003            args.push_str(" ORDER BY ");
1004            let order_strs: Vec<String> = self.order_by.iter().map(|o| o.to_string()).collect();
1005            args.push_str(&order_strs.join(", "));
1006        }
1007        write!(f, "{}({})", self.function, args)?;
1008        if let Some(filter) = &self.filter {
1009            write!(f, " FILTER (WHERE {})", filter)?;
1010        }
1011        Ok(())
1012    }
1013}
1014
1015/// Aliased expression (expr AS alias)
1016#[derive(Debug, Clone, PartialEq)]
1017pub struct AliasedExpression {
1018    pub token: Token,
1019    pub expression: Box<Expression>,
1020    pub alias: Identifier,
1021}
1022
1023impl fmt::Display for AliasedExpression {
1024    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1025        write!(f, "{} AS {}", self.expression, self.alias)
1026    }
1027}
1028
1029/// Window expression
1030#[derive(Debug, Clone, PartialEq)]
1031pub struct WindowExpression {
1032    pub token: Token,
1033    pub function: Box<FunctionCall>,
1034    /// Named window reference (e.g., OVER w)
1035    pub window_ref: Option<SmartString>,
1036    pub partition_by: Vec<Expression>,
1037    pub order_by: Vec<OrderByExpression>,
1038    pub frame: Option<WindowFrame>,
1039}
1040
1041impl fmt::Display for WindowExpression {
1042    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1043        let mut result = self.function.to_string();
1044        if let Some(ref win_ref) = self.window_ref {
1045            result.push_str(" OVER ");
1046            result.push_str(win_ref);
1047        } else {
1048            result.push_str(" OVER (");
1049            if !self.partition_by.is_empty() {
1050                result.push_str("PARTITION BY ");
1051                let parts: Vec<String> = self.partition_by.iter().map(|e| e.to_string()).collect();
1052                result.push_str(&parts.join(", "));
1053            }
1054            if !self.order_by.is_empty() {
1055                if !self.partition_by.is_empty() {
1056                    result.push(' ');
1057                }
1058                result.push_str("ORDER BY ");
1059                let orders: Vec<String> = self.order_by.iter().map(|o| o.to_string()).collect();
1060                result.push_str(&orders.join(", "));
1061            }
1062            if let Some(ref frame) = self.frame {
1063                result.push(' ');
1064                result.push_str(&frame.to_string());
1065            }
1066            result.push(')');
1067        }
1068        write!(f, "{}", result)
1069    }
1070}
1071
1072/// Window frame specification
1073#[derive(Debug, Clone, PartialEq)]
1074pub struct WindowFrame {
1075    pub unit: WindowFrameUnit,
1076    pub start: WindowFrameBound,
1077    pub end: Option<WindowFrameBound>,
1078}
1079
1080impl fmt::Display for WindowFrame {
1081    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1082        let unit = match self.unit {
1083            WindowFrameUnit::Rows => "ROWS",
1084            WindowFrameUnit::Range => "RANGE",
1085        };
1086        if let Some(ref end) = self.end {
1087            write!(f, "{} BETWEEN {} AND {}", unit, self.start, end)
1088        } else {
1089            write!(f, "{} {}", unit, self.start)
1090        }
1091    }
1092}
1093
1094/// Window frame unit
1095#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1096pub enum WindowFrameUnit {
1097    Rows,
1098    Range,
1099}
1100
1101/// Window frame bound
1102#[derive(Debug, Clone, PartialEq)]
1103pub enum WindowFrameBound {
1104    CurrentRow,
1105    UnboundedPreceding,
1106    UnboundedFollowing,
1107    Preceding(Box<Expression>),
1108    Following(Box<Expression>),
1109}
1110
1111impl fmt::Display for WindowFrameBound {
1112    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1113        match self {
1114            WindowFrameBound::CurrentRow => write!(f, "CURRENT ROW"),
1115            WindowFrameBound::UnboundedPreceding => write!(f, "UNBOUNDED PRECEDING"),
1116            WindowFrameBound::UnboundedFollowing => write!(f, "UNBOUNDED FOLLOWING"),
1117            WindowFrameBound::Preceding(e) => write!(f, "{} PRECEDING", e),
1118            WindowFrameBound::Following(e) => write!(f, "{} FOLLOWING", e),
1119        }
1120    }
1121}
1122
1123/// Named window definition (WINDOW w AS (...))
1124#[derive(Debug, Clone, PartialEq)]
1125pub struct WindowDefinition {
1126    pub name: SmartString,
1127    pub partition_by: Vec<Expression>,
1128    pub order_by: Vec<OrderByExpression>,
1129    pub frame: Option<WindowFrame>,
1130}
1131
1132impl fmt::Display for WindowDefinition {
1133    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1134        let mut result = format!("{} AS (", self.name);
1135        if !self.partition_by.is_empty() {
1136            result.push_str("PARTITION BY ");
1137            let parts: Vec<String> = self.partition_by.iter().map(|e| e.to_string()).collect();
1138            result.push_str(&parts.join(", "));
1139        }
1140        if !self.order_by.is_empty() {
1141            if !self.partition_by.is_empty() {
1142                result.push(' ');
1143            }
1144            result.push_str("ORDER BY ");
1145            let orders: Vec<String> = self.order_by.iter().map(|o| o.to_string()).collect();
1146            result.push_str(&orders.join(", "));
1147        }
1148        if let Some(ref frame) = self.frame {
1149            result.push(' ');
1150            result.push_str(&frame.to_string());
1151        }
1152        result.push(')');
1153        write!(f, "{}", result)
1154    }
1155}