Skip to main content

qusql_parse/
expression.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License at
4//
5// http://www.apache.org/licenses/LICENSE-2.0
6//
7// Unless required by applicable law or agreed to in writing, software
8// distributed under the License is distributed on an "AS IS" BASIS,
9// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10// See the License for the specific language governing permissions and
11// limitations under the License.
12
13use crate::{
14    DataType, Identifier, QualifiedName, SString, Span, Spanned, Statement,
15    data_type::{DataTypeContext, parse_data_type},
16    function_expression::{
17        AggregateFunctionCallExpression, CharFunctionExpression, Function, FunctionCallExpression,
18        WindowFunctionCallExpression, is_aggregate_function_ident, parse_aggregate_function,
19        parse_char_function, parse_function, parse_function_call,
20    },
21    keywords::{Keyword, Restrict},
22    lexer::Token,
23    operator::parse_operator_name,
24    parser::{ParseError, Parser},
25    span::OptSpanned,
26    statement::parse_compound_query,
27};
28use alloc::string::ToString;
29use alloc::vec;
30use alloc::{boxed::Box, vec::Vec};
31
32/// Function to execute
33#[derive(Debug, Clone)]
34pub enum Variable<'a> {
35    TimeZone,
36    Other(&'a str),
37}
38
39/// Binary operator to apply
40#[derive(Debug, Clone)]
41pub enum BinaryOperator<'a> {
42    Or(Span),
43    Xor(Span),
44    And(Span),
45    Eq(Span),
46    NullSafeEq(Span),
47    GtEq(Span),
48    Gt(Span),
49    LtEq(Span),
50    Lt(Span),
51    Neq(Span),
52    ShiftLeft(Span),
53    ShiftRight(Span),
54    BitAnd(Span),
55    BitOr(Span),
56    BitXor(Span),
57    Add(Span),
58    Subtract(Span),
59    Divide(Span),
60    Div(Span),
61    Mod(Span),
62    Mult(Span),
63    Like(Span),
64    NotLike(Span),
65    Regexp(Span),
66    NotRegexp(Span),
67    Rlike(Span),
68    NotRlike(Span),
69    Collate(Span),
70    JsonExtract(Span),
71    JsonExtractUnquote(Span),
72    Assignment(Span),
73    // PostgreSQL-specific binary operators
74    /// @>
75    Contains(Span),
76    /// <@
77    ContainedBy(Span),
78    /// @@ (full-text / jsonpath match)
79    JsonPathMatch(Span),
80    /// @?
81    JsonPathExists(Span),
82    /// ? (jsonb key exists)
83    JsonbKeyExists(Span),
84    /// ?|
85    JsonbAnyKeyExists(Span),
86    /// ?&
87    JsonbAllKeyExists(Span),
88    /// #>
89    JsonGetPath(Span),
90    /// #>>
91    JsonGetPathText(Span),
92    /// #-
93    JsonDeletePath(Span),
94    /// ~ (regex match)
95    RegexMatch(Span),
96    /// ~* (case-insensitive regex match)
97    RegexIMatch(Span),
98    /// !~ (regex not match)
99    NotRegexMatch(Span),
100    /// !~* (case-insensitive regex not match)
101    NotRegexIMatch(Span),
102    /// User-defined / unrecognised PostgreSQL operator
103    User(&'a str, Span),
104    /// PostgreSQL OPERATOR(schema.op) expression
105    Operator(QualifiedName<'a>, Span),
106}
107
108impl<'a> Spanned for BinaryOperator<'a> {
109    fn span(&self) -> Span {
110        match self {
111            BinaryOperator::Or(s)
112            | BinaryOperator::Xor(s)
113            | BinaryOperator::And(s)
114            | BinaryOperator::Eq(s)
115            | BinaryOperator::NullSafeEq(s)
116            | BinaryOperator::GtEq(s)
117            | BinaryOperator::Gt(s)
118            | BinaryOperator::LtEq(s)
119            | BinaryOperator::Lt(s)
120            | BinaryOperator::Neq(s)
121            | BinaryOperator::ShiftLeft(s)
122            | BinaryOperator::ShiftRight(s)
123            | BinaryOperator::BitAnd(s)
124            | BinaryOperator::BitOr(s)
125            | BinaryOperator::BitXor(s)
126            | BinaryOperator::Add(s)
127            | BinaryOperator::Subtract(s)
128            | BinaryOperator::Divide(s)
129            | BinaryOperator::Div(s)
130            | BinaryOperator::Mod(s)
131            | BinaryOperator::Mult(s)
132            | BinaryOperator::Like(s)
133            | BinaryOperator::NotLike(s)
134            | BinaryOperator::Regexp(s)
135            | BinaryOperator::NotRegexp(s)
136            | BinaryOperator::Rlike(s)
137            | BinaryOperator::NotRlike(s)
138            | BinaryOperator::Collate(s)
139            | BinaryOperator::JsonExtract(s)
140            | BinaryOperator::JsonExtractUnquote(s)
141            | BinaryOperator::Assignment(s)
142            | BinaryOperator::Contains(s)
143            | BinaryOperator::ContainedBy(s)
144            | BinaryOperator::JsonPathMatch(s)
145            | BinaryOperator::JsonPathExists(s)
146            | BinaryOperator::JsonbKeyExists(s)
147            | BinaryOperator::JsonbAnyKeyExists(s)
148            | BinaryOperator::JsonbAllKeyExists(s)
149            | BinaryOperator::JsonGetPath(s)
150            | BinaryOperator::JsonGetPathText(s)
151            | BinaryOperator::JsonDeletePath(s)
152            | BinaryOperator::RegexMatch(s)
153            | BinaryOperator::RegexIMatch(s)
154            | BinaryOperator::NotRegexMatch(s)
155            | BinaryOperator::NotRegexIMatch(s) => s.clone(),
156            BinaryOperator::User(_, s) => s.clone(),
157            BinaryOperator::Operator(_, s) => s.clone(),
158        }
159    }
160}
161
162/// Mode for MATCH ... AGAINST
163#[derive(Debug, Clone)]
164pub enum MatchMode {
165    InBoolean(Span),
166    InNaturalLanguage(Span),
167    InNaturalLanguageWithQueryExpansion(Span),
168    WithQueryExpansion(Span),
169}
170
171impl Spanned for MatchMode {
172    fn span(&self) -> Span {
173        match self {
174            MatchMode::InBoolean(s) => s.clone(),
175            MatchMode::InNaturalLanguage(s) => s.clone(),
176            MatchMode::InNaturalLanguageWithQueryExpansion(s) => s.clone(),
177            MatchMode::WithQueryExpansion(s) => s.clone(),
178        }
179    }
180}
181
182/// Type of is expression
183#[derive(Debug, Clone)]
184pub enum Is<'a> {
185    Null,
186    NotNull,
187    True,
188    NotTrue,
189    False,
190    NotFalse,
191    Unknown,
192    NotUnknown,
193    DistinctFrom(Expression<'a>),
194    NotDistinctFrom(Expression<'a>),
195}
196
197/// Unary operator to apply
198#[derive(Debug, Clone)]
199pub enum UnaryOperator {
200    Binary(Span),
201    LogicalNot(Span),
202    Minus(Span),
203    Not(Span),
204}
205
206impl Spanned for UnaryOperator {
207    fn span(&self) -> Span {
208        match self {
209            UnaryOperator::Binary(s)
210            | UnaryOperator::LogicalNot(s)
211            | UnaryOperator::Minus(s)
212            | UnaryOperator::Not(s) => s.clone(),
213        }
214    }
215}
216
217/// Part of a full identifier
218#[derive(Debug, Clone)]
219pub enum IdentifierPart<'a> {
220    Name(Identifier<'a>),
221    Star(Span),
222}
223
224impl<'a> Spanned for IdentifierPart<'a> {
225    fn span(&self) -> Span {
226        match &self {
227            IdentifierPart::Name(v) => v.span(),
228            IdentifierPart::Star(v) => v.span(),
229        }
230    }
231}
232
233/// When part of CASE
234#[derive(Debug, Clone)]
235pub struct When<'a> {
236    /// Span of WHEN
237    pub when_span: Span,
238    /// When to return then
239    pub when: Expression<'a>,
240    /// Span of THEN
241    pub then_span: Span,
242    /// What to return when when applyes
243    pub then: Expression<'a>,
244}
245
246impl<'a> Spanned for When<'a> {
247    fn span(&self) -> Span {
248        self.when_span
249            .join_span(&self.when)
250            .join_span(&self.then_span)
251            .join_span(&self.then)
252    }
253}
254
255/// Units of time
256#[derive(Debug, Clone, PartialEq, Eq)]
257pub enum TimeUnit {
258    /// Microseconds
259    Microsecond,
260    /// Seconds
261    Second,
262    /// Minutes
263    Minute,
264    /// Hours
265    Hour,
266    /// Days
267    Day,
268    /// Weeks
269    Week,
270    /// Months
271    Month,
272    /// Quarters
273    Quarter,
274    /// Years
275    Year,
276    /// Seconds.Microseconds
277    SecondMicrosecond,
278    /// Minutes.Seconds.Microseconds
279    MinuteMicrosecond,
280    /// Minutes.Seconds
281    MinuteSecond,
282    /// Hours.Minutes.Seconds.Microseconds
283    HourMicrosecond,
284    /// Hours.Minutes.Seconds
285    HourSecond,
286    /// Hours.Minutes
287    HourMinute,
288    /// Days Hours.Minutes.Seconds.Microseconds
289    DayMicrosecond,
290    /// Days Hours.Minutes.Seconds
291    DaySecond,
292    /// Days Hours.Minutes
293    DayMinute,
294    /// Days Hours
295    DayHour,
296    /// Years-Months
297    YearMonth,
298}
299
300fn parse_time_unit(t: &Token<'_>) -> Option<TimeUnit> {
301    match t {
302        Token::Ident(_, Keyword::MICROSECOND) => Some(TimeUnit::Microsecond),
303        Token::Ident(_, Keyword::SECOND) => Some(TimeUnit::Second),
304        Token::Ident(_, Keyword::MINUTE) => Some(TimeUnit::Minute),
305        Token::Ident(_, Keyword::HOUR) => Some(TimeUnit::Hour),
306        Token::Ident(_, Keyword::DAY) => Some(TimeUnit::Day),
307        Token::Ident(_, Keyword::WEEK) => Some(TimeUnit::Week),
308        Token::Ident(_, Keyword::MONTH) => Some(TimeUnit::Month),
309        Token::Ident(_, Keyword::QUARTER) => Some(TimeUnit::Quarter),
310        Token::Ident(_, Keyword::YEAR) => Some(TimeUnit::Year),
311        Token::Ident(_, Keyword::SECOND_MICROSECOND) => Some(TimeUnit::SecondMicrosecond),
312        Token::Ident(_, Keyword::MINUTE_MICROSECOND) => Some(TimeUnit::MinuteMicrosecond),
313        Token::Ident(_, Keyword::MINUTE_SECOND) => Some(TimeUnit::MinuteSecond),
314        Token::Ident(_, Keyword::HOUR_MICROSECOND) => Some(TimeUnit::HourMicrosecond),
315        Token::Ident(_, Keyword::HOUR_SECOND) => Some(TimeUnit::HourSecond),
316        Token::Ident(_, Keyword::HOUR_MINUTE) => Some(TimeUnit::HourMinute),
317        Token::Ident(_, Keyword::DAY_MICROSECOND) => Some(TimeUnit::DayMicrosecond),
318        Token::Ident(_, Keyword::DAY_SECOND) => Some(TimeUnit::DaySecond),
319        Token::Ident(_, Keyword::DAY_MINUTE) => Some(TimeUnit::DayMinute),
320        Token::Ident(_, Keyword::DAY_HOUR) => Some(TimeUnit::DayHour),
321        Token::Ident(_, Keyword::YEAR_MONTH) => Some(TimeUnit::YearMonth),
322        _ => None,
323    }
324}
325
326/// Expression with binary operator
327#[derive(Debug, Clone)]
328pub struct BinaryExpression<'a> {
329    pub op: BinaryOperator<'a>,
330    pub lhs: Expression<'a>,
331    pub rhs: Expression<'a>,
332}
333
334impl Spanned for BinaryExpression<'_> {
335    fn span(&self) -> Span {
336        self.op.span().join_span(&self.lhs).join_span(&self.rhs)
337    }
338}
339
340/// Expression with a unary (prefix) operator
341#[derive(Debug, Clone)]
342pub struct UnaryExpression<'a> {
343    pub op: UnaryOperator,
344    pub operand: Expression<'a>,
345}
346
347impl Spanned for UnaryExpression<'_> {
348    fn span(&self) -> Span {
349        self.op.span().join_span(&self.operand)
350    }
351}
352/// Time Interval
353#[derive(Debug, Clone)]
354pub struct IntervalExpression {
355    /// Span of "INTERVAL"
356    pub interval_span: Span,
357    /// Time internal
358    pub time_interval: (Vec<i64>, Span),
359    /// Unit of the time interval
360    pub time_unit: (TimeUnit, Span),
361}
362
363impl Spanned for IntervalExpression {
364    fn span(&self) -> Span {
365        self.interval_span
366            .join_span(&self.time_interval.1)
367            .join_span(&self.time_unit.1)
368    }
369}
370
371/// Extract expression
372#[derive(Debug, Clone)]
373pub struct ExtractExpression<'a> {
374    /// Span of "EXTRACT"
375    pub extract_span: Span,
376    /// Unit of the time interval
377    pub time_unit: (TimeUnit, Span),
378    /// Span of "FROM"
379    pub from_span: Span,
380    /// Date expression
381    pub date: Expression<'a>,
382}
383
384impl Spanned for ExtractExpression<'_> {
385    fn span(&self) -> Span {
386        self.extract_span
387            .join_span(&self.time_unit.1)
388            .join_span(&self.from_span)
389            .join_span(&self.date)
390    }
391}
392
393/// Direction for TRIM()
394#[derive(Debug, Clone)]
395pub enum TrimDirection {
396    Both(Span),
397    Leading(Span),
398    Trailing(Span),
399}
400
401impl Spanned for TrimDirection {
402    fn span(&self) -> Span {
403        match self {
404            TrimDirection::Both(s) | TrimDirection::Leading(s) | TrimDirection::Trailing(s) => {
405                s.clone()
406            }
407        }
408    }
409}
410
411/// TRIM([{BOTH|LEADING|TRAILING} [remstr] FROM] str) expression
412#[derive(Debug, Clone)]
413pub struct TrimExpression<'a> {
414    /// Span of "TRIM"
415    pub trim_span: Span,
416    /// Optional BOTH / LEADING / TRAILING direction
417    pub direction: Option<TrimDirection>,
418    /// Optional removal string (remstr)
419    pub what: Option<Expression<'a>>,
420    /// Span of "FROM" when present
421    pub from_span: Option<Span>,
422    /// The string to trim
423    pub value: Expression<'a>,
424}
425
426impl Spanned for TrimExpression<'_> {
427    fn span(&self) -> Span {
428        self.trim_span
429            .join_span(&self.direction)
430            .join_span(&self.what)
431            .join_span(&self.from_span)
432            .join_span(&self.value)
433    }
434}
435
436/// In expression
437#[derive(Debug, Clone)]
438pub struct InExpression<'a> {
439    /// Left hand side expression
440    pub lhs: Expression<'a>,
441    /// Right hand side expression
442    pub rhs: Vec<Expression<'a>>,
443    /// Span of "IN" or "NOT IN"
444    pub in_span: Span,
445    /// True if not in
446    pub not_in: bool,
447}
448
449impl Spanned for InExpression<'_> {
450    fn span(&self) -> Span {
451        self.in_span.join_span(&self.lhs).join_span(&self.rhs)
452    }
453}
454
455/// Between expression (expr BETWEEN low AND high)
456#[derive(Debug, Clone)]
457pub struct BetweenExpression<'a> {
458    /// The value being tested
459    pub lhs: Expression<'a>,
460    /// Lower bound
461    pub low: Expression<'a>,
462    /// Upper bound
463    pub high: Expression<'a>,
464    /// Span covering "BETWEEN ... AND"
465    pub between_span: Span,
466    /// True if NOT BETWEEN
467    pub not_between: bool,
468}
469
470impl Spanned for BetweenExpression<'_> {
471    fn span(&self) -> Span {
472        self.between_span
473            .join_span(&self.lhs)
474            .join_span(&self.low)
475            .join_span(&self.high)
476    }
477}
478
479/// Member of expression
480#[derive(Debug, Clone)]
481pub struct MemberOfExpression<'a> {
482    /// Left hand side expression
483    pub lhs: Expression<'a>,
484    /// Right hand side expression
485    pub rhs: Expression<'a>,
486    /// Span of "MEMBER OF"
487    pub member_of_span: Span,
488}
489
490impl Spanned for MemberOfExpression<'_> {
491    fn span(&self) -> Span {
492        self.member_of_span
493            .join_span(&self.lhs)
494            .join_span(&self.rhs)
495    }
496}
497
498/// Case expression
499#[derive(Debug, Clone)]
500pub struct CaseExpression<'a> {
501    /// Span of "CASE"
502    pub case_span: Span,
503    /// Optional value to switch over
504    pub value: Option<Expression<'a>>,
505    /// When parts
506    pub whens: Vec<When<'a>>,
507    /// Span of "ELSE" and else value if specified
508    pub else_: Option<(Span, Expression<'a>)>,
509    /// Span of "END"
510    pub end_span: Span,
511}
512
513impl Spanned for CaseExpression<'_> {
514    fn span(&self) -> Span {
515        self.case_span
516            .join_span(&self.value)
517            .join_span(&self.whens)
518            .join_span(&self.else_)
519            .join_span(&self.end_span)
520    }
521}
522
523/// Cast expression
524#[derive(Debug, Clone)]
525pub struct CastExpression<'a> {
526    /// Span of "CAST"
527    pub cast_span: Span,
528    /// Value to cast
529    pub expr: Expression<'a>,
530    /// Span of "AS"
531    pub as_span: Span,
532    /// Type to cast to
533    pub type_: DataType<'a>,
534}
535
536impl Spanned for CastExpression<'_> {
537    fn span(&self) -> Span {
538        self.cast_span
539            .join_span(&self.expr)
540            .join_span(&self.as_span)
541            .join_span(&self.type_)
542    }
543}
544
545/// Convert expression (CONVERT(expr, type) or CONVERT(expr USING charset))
546#[derive(Debug, Clone)]
547pub struct ConvertExpression<'a> {
548    /// Span of "CONVERT"
549    pub convert_span: Span,
550    /// Value to convert
551    pub expr: Expression<'a>,
552    /// Type to convert to (for CONVERT(expr, type))
553    pub type_: Option<DataType<'a>>,
554    /// Charset (for CONVERT(expr USING charset))
555    pub using_charset: Option<(Span, Identifier<'a>)>,
556}
557
558impl Spanned for ConvertExpression<'_> {
559    fn span(&self) -> Span {
560        self.convert_span
561            .join_span(&self.expr)
562            .join_span(&self.type_)
563            .join_span(&self.using_charset)
564    }
565}
566
567/// PostgreSQL-style typecast expression (expr::type)
568#[derive(Debug, Clone)]
569pub struct TypeCastExpression<'a> {
570    /// The expression being cast
571    pub expr: Expression<'a>,
572    /// Span of "::"
573    pub doublecolon_span: Span,
574    /// Type to cast to
575    pub type_: DataType<'a>,
576}
577
578impl Spanned for TypeCastExpression<'_> {
579    fn span(&self) -> Span {
580        self.expr
581            .span()
582            .join_span(&self.doublecolon_span)
583            .join_span(&self.type_)
584    }
585}
586
587/// PostgreSQL ARRAY[...] literal expression
588#[derive(Debug, Clone)]
589pub struct ArrayExpression<'a> {
590    /// Span of the "ARRAY" keyword
591    pub array_span: Span,
592    /// Span of the bracket region "[...]"
593    pub bracket_span: Span,
594    /// The element expressions
595    pub elements: Vec<Expression<'a>>,
596}
597
598impl Spanned for ArrayExpression<'_> {
599    fn span(&self) -> Span {
600        self.array_span.join_span(&self.bracket_span)
601    }
602}
603
604/// Array subscript or slice expression: expr[idx] or expr[lower:upper]
605#[derive(Debug, Clone)]
606pub struct ArraySubscriptExpression<'a> {
607    /// The array expression being subscripted
608    pub expr: Expression<'a>,
609    /// Span of the "[...]" bracket region
610    pub bracket_span: Span,
611    /// The lower bound / index
612    pub lower: Expression<'a>,
613    /// The upper bound for slice notation (expr[lower:upper])
614    pub upper: Option<Expression<'a>>,
615}
616
617impl Spanned for ArraySubscriptExpression<'_> {
618    fn span(&self) -> Span {
619        self.expr.span().join_span(&self.bracket_span)
620    }
621}
622
623/// PostgreSQL composite type field access: (expr).field
624#[derive(Debug, Clone)]
625pub struct FieldAccessExpression<'a> {
626    /// The expression whose field is accessed
627    pub expr: Expression<'a>,
628    /// Span of the "."
629    pub dot_span: Span,
630    /// The field name
631    pub field: Identifier<'a>,
632}
633
634impl Spanned for FieldAccessExpression<'_> {
635    fn span(&self) -> Span {
636        self.expr
637            .span()
638            .join_span(&self.dot_span)
639            .join_span(&self.field)
640    }
641}
642
643/// Group contat expression
644#[derive(Debug, Clone)]
645pub struct GroupConcatExpression<'a> {
646    /// Span of "GROUP_CONCAT"
647    pub group_concat_span: Span,
648    /// Span of "DISTINCT" if specified
649    pub distinct_span: Option<Span>,
650    /// Expression to count
651    pub expr: Expression<'a>,
652}
653
654impl Spanned for GroupConcatExpression<'_> {
655    fn span(&self) -> Span {
656        self.group_concat_span
657            .join_span(&self.distinct_span)
658            .join_span(&self.expr)
659    }
660}
661
662/// Variable expression
663#[derive(Debug, Clone)]
664pub struct VariableExpression<'a> {
665    /// Span of "@@GLOBAL"
666    pub global: Option<Span>,
667    /// Span of "@@SESSION"
668    pub session: Option<Span>,
669    /// Span of '.'
670    pub dot: Option<Span>,
671    /// variable
672    pub variable: Variable<'a>,
673    // Span of variable
674    pub variable_span: Span,
675}
676
677impl Spanned for VariableExpression<'_> {
678    fn span(&self) -> Span {
679        self.variable_span
680            .join_span(&self.global)
681            .join_span(&self.session)
682            .join_span(&self.dot)
683    }
684}
685
686/// User variable expression (@variable_name)
687#[derive(Debug, Clone)]
688pub struct UserVariableExpression<'a> {
689    /// The variable name
690    pub name: Identifier<'a>,
691    /// Span of '@'
692    pub at_span: Span,
693}
694
695impl Spanned for UserVariableExpression<'_> {
696    fn span(&self) -> Span {
697        self.at_span.join_span(&self.name)
698    }
699}
700
701/// Timestampadd call
702#[derive(Debug, Clone)]
703pub struct TimestampAddExpression<'a> {
704    /// Span of "TIMESTAMPADD"
705    pub timestamp_add_span: Span,
706    /// Unit of the interval
707    pub unit: (TimeUnit, Span),
708    /// Interval expression
709    pub interval: Expression<'a>,
710    /// Datetime expression
711    pub datetime: Expression<'a>,
712}
713
714impl Spanned for TimestampAddExpression<'_> {
715    fn span(&self) -> Span {
716        self.timestamp_add_span
717            .join_span(&self.unit.1)
718            .join_span(&self.interval)
719            .join_span(&self.datetime)
720    }
721}
722
723/// Timestampdiff call
724#[derive(Debug, Clone)]
725pub struct TimestampDiffExpression<'a> {
726    /// Span of "TIMESTAMPDIFF"
727    pub timestamp_diff_span: Span,
728    /// Unit of the interval
729    pub unit: (TimeUnit, Span),
730    /// First expression
731    pub e1: Expression<'a>,
732    /// Second expression
733    pub e2: Expression<'a>,
734}
735
736impl Spanned for TimestampDiffExpression<'_> {
737    fn span(&self) -> Span {
738        self.timestamp_diff_span
739            .join_span(&self.unit.1)
740            .join_span(&self.e1)
741            .join_span(&self.e2)
742    }
743}
744
745/// Full-text MATCH ... AGAINST expression
746#[derive(Debug, Clone)]
747pub struct MatchAgainstExpression<'a> {
748    /// Span of "MATCH"
749    pub match_span: Span,
750    /// Columns to match against
751    pub columns: Vec<Expression<'a>>,
752    /// Span of "AGAINST"
753    pub against_span: Span,
754    /// Expression to match against
755    pub expr: Expression<'a>,
756    /// Match mode
757    pub mode: Option<MatchMode>,
758}
759
760impl Spanned for MatchAgainstExpression<'_> {
761    fn span(&self) -> Span {
762        self.match_span
763            .join_span(&self.columns)
764            .join_span(&self.against_span)
765            .join_span(&self.expr)
766            .join_span(&self.mode)
767    }
768}
769
770/// Is expression
771#[derive(Debug, Clone)]
772pub struct IsExpression<'a> {
773    /// Left hand side expression
774    pub lhs: Expression<'a>,
775    /// Type of is expression
776    pub is: Is<'a>,
777    /// Span of "IS" and "NOT"
778    pub is_span: Span,
779}
780
781impl<'a> Spanned for IsExpression<'a> {
782    fn span(&self) -> Span {
783        match &self.is {
784            Is::DistinctFrom(rhs) | Is::NotDistinctFrom(rhs) => {
785                self.lhs.span().join_span(&self.is_span).join_span(rhs)
786            }
787            _ => self.lhs.span().join_span(&self.is_span),
788        }
789    }
790}
791
792/// Literal NULL expression
793#[derive(Debug, Clone)]
794pub struct NullExpression {
795    /// Span of "NULL"
796    pub span: Span,
797}
798
799impl Spanned for NullExpression {
800    fn span(&self) -> Span {
801        self.span.clone()
802    }
803}
804
805/// Literal DEFAULT expression
806#[derive(Debug, Clone)]
807pub struct DefaultExpression {
808    /// Span of "DEFAULT"
809    pub span: Span,
810}
811
812impl Spanned for DefaultExpression {
813    fn span(&self) -> Span {
814        self.span.clone()
815    }
816}
817
818/// Literal bool expression "TRUE" or "FALSE"
819#[derive(Debug, Clone)]
820pub struct BoolExpression {
821    /// The boolean value
822    pub value: bool,
823    /// Span of "TRUE" or "FALSE"
824    pub span: Span,
825}
826
827impl Spanned for BoolExpression {
828    fn span(&self) -> Span {
829        self.span.clone()
830    }
831}
832
833/// Literal integer expression
834#[derive(Debug, Clone)]
835pub struct IntegerExpression {
836    /// The integer value
837    pub value: u64,
838    /// Span of the integer
839    pub span: Span,
840}
841
842impl Spanned for IntegerExpression {
843    fn span(&self) -> Span {
844        self.span.clone()
845    }
846}
847
848/// Literal _LIST_ expression
849#[derive(Debug, Clone)]
850pub struct ListHackExpression {
851    /// The index of the list
852    pub index: usize,
853    /// Span of the list
854    pub span: Span,
855}
856
857impl Spanned for ListHackExpression {
858    fn span(&self) -> Span {
859        self.span.clone()
860    }
861}
862
863/// Literal floating point expression
864#[derive(Debug, Clone)]
865pub struct FloatExpression {
866    /// The floating point value
867    pub value: f64,
868    /// Span of the floating point
869    pub span: Span,
870}
871
872impl Spanned for FloatExpression {
873    fn span(&self) -> Span {
874        self.span.clone()
875    }
876}
877
878/// Input argument to query, the first argument is the occurrence number of the argument
879#[derive(Debug, Clone)]
880pub struct ArgExpression {
881    /// The occurrence number of the argument
882    pub index: usize,
883    /// Span of the argument
884    pub span: Span,
885}
886
887impl Spanned for ArgExpression {
888    fn span(&self) -> Span {
889        self.span.clone()
890    }
891}
892
893/// Invalid expression, returned on recovery of a parse error
894#[derive(Debug, Clone)]
895pub struct InvalidExpression {
896    /// Span of the invalid expression
897    pub span: Span,
898}
899
900impl Spanned for InvalidExpression {
901    fn span(&self) -> Span {
902        self.span.clone()
903    }
904}
905
906/// Identifier pointing to column
907#[derive(Debug, Clone)]
908pub struct IdentifierExpression<'a> {
909    /// The identifier  parts, for example in "a.b.*" the parts are "a", "b" and "*"
910    pub parts: Vec<IdentifierPart<'a>>,
911}
912
913impl<'a> Spanned for IdentifierExpression<'a> {
914    fn span(&self) -> Span {
915        self.parts.opt_span().expect("Span of identifier parts")
916    }
917}
918
919/// Subquery expression
920#[derive(Debug, Clone)]
921pub struct SubqueryExpression<'a> {
922    /// The subquery
923    pub expression: Statement<'a>,
924}
925
926impl Spanned for SubqueryExpression<'_> {
927    fn span(&self) -> Span {
928        self.expression.span()
929    }
930}
931
932/// Exists expression
933#[derive(Debug, Clone)]
934pub struct ExistsExpression<'a> {
935    /// Span of "EXISTS"
936    pub exists_span: Span,
937    /// The subquery
938    pub subquery: Statement<'a>,
939}
940
941impl Spanned for ExistsExpression<'_> {
942    fn span(&self) -> Span {
943        self.exists_span.join_span(&self.subquery)
944    }
945}
946
947/// Which row quantifier keyword was used
948#[derive(Debug, Clone, PartialEq, Eq)]
949pub enum Quantifier {
950    /// ANY(subquery_or_array)
951    Any(Span),
952    /// SOME(subquery_or_array) — synonym for ANY in PostgreSQL
953    Some(Span),
954    /// ALL(subquery_or_array)
955    All(Span),
956}
957
958impl Spanned for Quantifier {
959    fn span(&self) -> Span {
960        match self {
961            Quantifier::Any(s) | Quantifier::Some(s) | Quantifier::All(s) => s.clone(),
962        }
963    }
964}
965
966/// PostgreSQL ANY / SOME / ALL quantifier expression.
967///
968/// Appears as the right-hand operand of a comparison:
969/// `expr op ANY (subquery_or_array)`
970#[derive(Debug, Clone)]
971pub struct QuantifierExpression<'a> {
972    /// Which quantifier keyword was written
973    pub quantifier: Quantifier,
974    /// The operand — either a subquery expression or an array expression
975    pub operand: Expression<'a>,
976}
977
978impl Spanned for QuantifierExpression<'_> {
979    fn span(&self) -> Span {
980        self.quantifier.join_span(&self.operand)
981    }
982}
983
984/// Representation of an expression
985#[derive(Debug, Clone)]
986pub enum Expression<'a> {
987    /// Expression with binary operator
988    Binary(Box<BinaryExpression<'a>>),
989    /// Expression with a unary (prefix) operator
990    Unary(Box<UnaryExpression<'a>>),
991    /// Subquery expression
992    Subquery(Box<SubqueryExpression<'a>>),
993    /// Literal NULL expression
994    Null(Box<NullExpression>),
995    /// Literal DEFAULT expression
996    Default(Box<DefaultExpression>),
997    /// Literal bool expression "TRUE" or "FALSE"
998    Bool(Box<BoolExpression>),
999    /// Literal string expression, the SString contains the represented string
1000    /// with escaping removed
1001    String(Box<SString<'a>>),
1002    /// Literal integer expression
1003    Integer(Box<IntegerExpression>),
1004    /// Literal _LIST_
1005    ListHack(Box<ListHackExpression>),
1006    /// Literal floating point expression
1007    Float(Box<FloatExpression>),
1008    /// Function call expression,
1009    Function(Box<FunctionCallExpression<'a>>),
1010    /// A window function call expression
1011    WindowFunction(Box<WindowFunctionCallExpression<'a>>),
1012    /// Aggregate function call expression with optional DISTINCT/FILTER/OVER
1013    AggregateFunction(Box<AggregateFunctionCallExpression<'a>>),
1014    /// Identifier pointing to column
1015    Identifier(Box<IdentifierExpression<'a>>),
1016    /// Time Interval
1017    Interval(Box<IntervalExpression>),
1018    /// Input argument to query, the first argument is the occurrence number of the argument
1019    Arg(Box<ArgExpression>),
1020    /// Exists expression
1021    Exists(Box<ExistsExpression<'a>>),
1022    /// Extract expression
1023    Extract(Box<ExtractExpression<'a>>),
1024    /// Trim expression
1025    Trim(Box<TrimExpression<'a>>),
1026    /// In expression
1027    In(Box<InExpression<'a>>),
1028    /// Between expression
1029    Between(Box<BetweenExpression<'a>>),
1030    /// Member of expression
1031    MemberOf(Box<MemberOfExpression<'a>>),
1032    /// Is expression
1033    Is(Box<IsExpression<'a>>),
1034    /// Invalid expression, returned on recovery of a parse error
1035    Invalid(Box<InvalidExpression>),
1036    /// Case expression
1037    Case(Box<CaseExpression<'a>>),
1038    /// Cast expression
1039    Cast(Box<CastExpression<'a>>),
1040    /// Convert expression (CONVERT(expr, type) or CONVERT(expr USING charset))
1041    Convert(Box<ConvertExpression<'a>>),
1042    /// Group contat expression
1043    GroupConcat(Box<GroupConcatExpression<'a>>),
1044    /// Variable expression
1045    Variable(Box<VariableExpression<'a>>),
1046    /// User variable expression (@variable_name)
1047    UserVariable(Box<UserVariableExpression<'a>>),
1048    /// Timestampadd call
1049    TimestampAdd(Box<TimestampAddExpression<'a>>),
1050    /// Timestampdiff call
1051    TimestampDiff(Box<TimestampDiffExpression<'a>>),
1052    /// PostgreSQL-style typecast expression (expr::type)
1053    TypeCast(Box<TypeCastExpression<'a>>),
1054    /// Full-text MATCH ... AGAINST expression
1055    MatchAgainst(Box<MatchAgainstExpression<'a>>),
1056    /// PostgreSQL ARRAY[...] literal expression
1057    Array(Box<ArrayExpression<'a>>),
1058    /// Array subscript / slice expression: expr[idx] or expr[lower:upper]
1059    ArraySubscript(Box<ArraySubscriptExpression<'a>>),
1060    /// PostgreSQL ANY / SOME / ALL quantifier: ANY(subquery_or_array)
1061    Quantifier(Box<QuantifierExpression<'a>>),
1062    /// PostgreSQL composite type field access: (expr).field
1063    FieldAccess(Box<FieldAccessExpression<'a>>),
1064    /// CHAR(N,... [USING charset_name]) expression
1065    Char(Box<CharFunctionExpression<'a>>),
1066}
1067
1068impl<'a> Spanned for Expression<'a> {
1069    fn span(&self) -> Span {
1070        match &self {
1071            Expression::Binary(e) => e.span(),
1072            Expression::Unary(e) => e.span(),
1073            Expression::Subquery(v) => v.span(),
1074            Expression::Null(v) => v.span(),
1075            Expression::Default(v) => v.span(),
1076            Expression::Bool(v) => v.span(),
1077            Expression::String(v) => v.span(),
1078            Expression::Integer(v) => v.span(),
1079            Expression::Float(v) => v.span(),
1080            Expression::ListHack(v) => v.span(),
1081            Expression::Function(e) => e.span(),
1082            Expression::AggregateFunction(e) => e.span(),
1083            Expression::Identifier(e) => e.span(),
1084            Expression::Arg(v) => v.span(),
1085            Expression::Exists(v) => v.span(),
1086            Expression::In(e) => e.span(),
1087            Expression::Between(e) => e.span(),
1088            Expression::MemberOf(e) => e.span(),
1089            Expression::Is(e) => e.span(),
1090            Expression::Invalid(s) => s.span(),
1091            Expression::Case(e) => e.span(),
1092            Expression::Cast(e) => e.span(),
1093            Expression::Convert(e) => e.span(),
1094            Expression::TypeCast(e) => e.span(),
1095            Expression::GroupConcat(e) => e.span(),
1096            Expression::Variable(e) => e.span(),
1097            Expression::UserVariable(e) => e.span(),
1098            Expression::WindowFunction(e) => e.span(),
1099            Expression::Interval(e) => e.span(),
1100            Expression::Extract(e) => e.span(),
1101            Expression::Trim(e) => e.span(),
1102            Expression::TimestampAdd(e) => e.span(),
1103            Expression::TimestampDiff(e) => e.span(),
1104            Expression::MatchAgainst(e) => e.span(),
1105            Expression::Array(e) => e.span(),
1106            Expression::ArraySubscript(e) => e.span(),
1107            Expression::Quantifier(e) => e.span(),
1108            Expression::FieldAccess(e) => e.span(),
1109            Expression::Char(e) => e.span(),
1110        }
1111    }
1112}
1113
1114// Operator parsing priority table.
1115// Lower number = tighter binding (reduced later, applied first).
1116// An operator is only parsed when its priority < max_priority passed to the parser.
1117pub(crate) const PRIORITY_TYPECAST: usize = 10; // ::
1118pub(crate) const PRIORITY_JSON_EXTRACT: usize = 30; // -> ->>
1119pub(crate) const PRIORITY_BITXOR: usize = 50; // ^ (XOR bitwise)
1120pub(crate) const PRIORITY_MULT: usize = 60; // * / % DIV MOD
1121pub(crate) const PRIORITY_ADD: usize = 70; // + -
1122pub(crate) const PRIORITY_PG_CUSTOM: usize = 75; // PostgreSQL custom / user-defined operators
1123pub(crate) const PRIORITY_SHIFT: usize = 80; // << >>
1124pub(crate) const PRIORITY_BITAND: usize = 90; // &
1125pub(crate) const PRIORITY_BITOR: usize = 100; // |
1126pub(crate) const PRIORITY_CMP: usize = 110; // = != < > <= >= IS IN LIKE BETWEEN SIMILAR TO ...
1127pub(crate) const PRIORITY_AND: usize = 140; // AND  (tighter than OR)
1128pub(crate) const PRIORITY_XOR: usize = 150; // XOR (keyword logical XOR)
1129pub(crate) const PRIORITY_OR: usize = 160; // OR   (loosest binary operator)
1130pub(crate) const PRIORITY_ASSIGN: usize = 200; // :=
1131
1132/// Parse all operators (no restriction).
1133pub(crate) const PRIORITY_MAX: usize = usize::MAX;
1134
1135trait Priority {
1136    fn priority(&self) -> usize;
1137}
1138
1139impl<'a> Priority for BinaryOperator<'a> {
1140    fn priority(&self) -> usize {
1141        match self {
1142            BinaryOperator::Assignment(_) => PRIORITY_ASSIGN,
1143            BinaryOperator::Or(_) => PRIORITY_OR,
1144            BinaryOperator::Xor(_) => PRIORITY_XOR,
1145            BinaryOperator::And(_) => PRIORITY_AND,
1146            BinaryOperator::Eq(_) => PRIORITY_CMP,
1147            BinaryOperator::NullSafeEq(_) => PRIORITY_CMP,
1148            BinaryOperator::GtEq(_) => PRIORITY_CMP,
1149            BinaryOperator::Gt(_) => PRIORITY_CMP,
1150            BinaryOperator::LtEq(_) => PRIORITY_CMP,
1151            BinaryOperator::Lt(_) => PRIORITY_CMP,
1152            BinaryOperator::Neq(_) => PRIORITY_CMP,
1153            BinaryOperator::Like(_) => PRIORITY_CMP,
1154            BinaryOperator::NotLike(_) => PRIORITY_CMP,
1155            BinaryOperator::Regexp(_) => PRIORITY_CMP,
1156            BinaryOperator::NotRegexp(_) => PRIORITY_CMP,
1157            BinaryOperator::Rlike(_) => PRIORITY_CMP,
1158            BinaryOperator::NotRlike(_) => PRIORITY_CMP,
1159            BinaryOperator::ShiftLeft(_) => PRIORITY_SHIFT,
1160            BinaryOperator::ShiftRight(_) => PRIORITY_SHIFT,
1161            BinaryOperator::BitAnd(_) => PRIORITY_BITAND,
1162            BinaryOperator::BitOr(_) => PRIORITY_BITOR,
1163            BinaryOperator::BitXor(_) => PRIORITY_BITXOR,
1164            BinaryOperator::Add(_) => PRIORITY_ADD,
1165            BinaryOperator::Subtract(_) => PRIORITY_ADD,
1166            BinaryOperator::Divide(_) => PRIORITY_MULT,
1167            BinaryOperator::Div(_) => PRIORITY_MULT,
1168            BinaryOperator::Mod(_) => PRIORITY_MULT,
1169            BinaryOperator::Mult(_) => PRIORITY_MULT,
1170            BinaryOperator::Collate(_) => 20,
1171            BinaryOperator::JsonExtract(_) => PRIORITY_JSON_EXTRACT,
1172            BinaryOperator::JsonExtractUnquote(_) => PRIORITY_JSON_EXTRACT,
1173            BinaryOperator::Contains(_)
1174            | BinaryOperator::ContainedBy(_)
1175            | BinaryOperator::JsonPathMatch(_)
1176            | BinaryOperator::JsonPathExists(_)
1177            | BinaryOperator::JsonbKeyExists(_)
1178            | BinaryOperator::JsonbAnyKeyExists(_)
1179            | BinaryOperator::JsonbAllKeyExists(_)
1180            | BinaryOperator::JsonGetPath(_)
1181            | BinaryOperator::JsonGetPathText(_)
1182            | BinaryOperator::JsonDeletePath(_)
1183            | BinaryOperator::RegexMatch(_)
1184            | BinaryOperator::RegexIMatch(_)
1185            | BinaryOperator::NotRegexMatch(_)
1186            | BinaryOperator::NotRegexIMatch(_)
1187            | BinaryOperator::User(_, _)
1188            | BinaryOperator::Operator(_, _) => PRIORITY_PG_CUSTOM,
1189        }
1190    }
1191}
1192
1193impl Priority for UnaryOperator {
1194    fn priority(&self) -> usize {
1195        match self {
1196            UnaryOperator::Binary(_) => 20,
1197            UnaryOperator::LogicalNot(_) => 30,
1198            UnaryOperator::Minus(_) => 40,
1199            UnaryOperator::Not(_) => 130,
1200        }
1201    }
1202}
1203
1204#[derive(Debug)]
1205enum ReduceMember<'a> {
1206    Expression(Expression<'a>),
1207    Binary(BinaryOperator<'a>),
1208    Unary(UnaryOperator),
1209}
1210
1211struct Reducer<'a> {
1212    stack: Vec<ReduceMember<'a>>,
1213}
1214
1215impl<'a> Reducer<'a> {
1216    fn reduce(&mut self, priority: usize) -> Result<(), &'static str> {
1217        let mut e = match self.stack.pop() {
1218            Some(ReduceMember::Expression(e)) => e,
1219            _ => {
1220                return Err("Expected expression before here");
1221            }
1222        };
1223        loop {
1224            let v = self.stack.pop();
1225            match v {
1226                None => break,
1227                Some(ReduceMember::Expression(_)) => return Err("ICE Reduce stack error 1"),
1228                Some(ReduceMember::Unary(op)) if op.priority() > priority => {
1229                    self.stack.push(ReduceMember::Unary(op));
1230                    break;
1231                }
1232                Some(ReduceMember::Binary(op)) if op.priority() > priority => {
1233                    self.stack.push(ReduceMember::Binary(op));
1234                    break;
1235                }
1236                Some(ReduceMember::Unary(op)) => {
1237                    e = Expression::Unary(Box::new(UnaryExpression { op, operand: e }));
1238                }
1239                Some(ReduceMember::Binary(op)) => {
1240                    let lhs = match self.stack.pop() {
1241                        Some(ReduceMember::Expression(e)) => e,
1242                        _ => return Err("ICE Reduce stack error 2"),
1243                    };
1244                    e = Expression::Binary(Box::new(BinaryExpression { op, lhs, rhs: e }));
1245                }
1246            }
1247        }
1248        self.stack.push(ReduceMember::Expression(e));
1249        Ok(())
1250    }
1251
1252    fn shift_binop(&mut self, op: BinaryOperator<'a>) -> Result<(), &'static str> {
1253        self.reduce(op.priority())?;
1254        self.stack.push(ReduceMember::Binary(op));
1255        Ok(())
1256    }
1257
1258    fn shift_unary(&mut self, op: UnaryOperator) -> Result<(), &'static str> {
1259        if matches!(self.stack.last(), Some(ReduceMember::Expression(_))) {
1260            return Err("Unary operator cannot come before expression");
1261        }
1262        self.stack.push(ReduceMember::Unary(op));
1263        Ok(())
1264    }
1265
1266    fn shift_expr(&mut self, e: Expression<'a>) -> Result<(), &'static str> {
1267        if matches!(self.stack.last(), Some(ReduceMember::Expression(_))) {
1268            //panic!();
1269            return Err("Expression should not follow expression");
1270        }
1271        self.stack.push(ReduceMember::Expression(e));
1272        Ok(())
1273    }
1274}
1275
1276/// Parse a single element inside an ARRAY[...] literal.
1277/// If the current token is `[`, parses a nested sub-array `[elem, ...]` recursively.
1278/// Otherwise delegates to `parse_expression_unreserved`.
1279fn parse_array_element<'a>(parser: &mut Parser<'a, '_>) -> Result<Expression<'a>, ParseError> {
1280    if matches!(parser.token, Token::LBracket) {
1281        let lbracket = parser.consume_token(Token::LBracket)?;
1282        let mut elements = Vec::new();
1283        if !matches!(parser.token, Token::RBracket) {
1284            loop {
1285                parser.recovered(
1286                    "']' or ','",
1287                    &|t| matches!(t, Token::RBracket | Token::Comma),
1288                    |parser| {
1289                        elements.push(parse_array_element(parser)?);
1290                        Ok(())
1291                    },
1292                )?;
1293                if parser.skip_token(Token::Comma).is_none() {
1294                    break;
1295                }
1296            }
1297        }
1298        let rbracket = parser.consume_token(Token::RBracket)?;
1299        let bracket_span = lbracket.join_span(&rbracket);
1300        Ok(Expression::Array(Box::new(ArrayExpression {
1301            array_span: bracket_span.clone(),
1302            bracket_span,
1303            elements,
1304        })))
1305    } else {
1306        parse_expression_unreserved(parser, PRIORITY_MAX)
1307    }
1308}
1309
1310pub(crate) fn parse_expression_restricted<'a>(
1311    parser: &mut Parser<'a, '_>,
1312    max_priority: usize,
1313    restrict: Restrict,
1314) -> Result<Expression<'a>, ParseError> {
1315    let mut r = Reducer { stack: Vec::new() };
1316    loop {
1317        if matches!(r.stack.last(), Some(ReduceMember::Expression(_)))
1318            && matches!(
1319                parser.token,
1320                Token::Ident(
1321                    _,
1322                    Keyword::NULLS
1323                        | Keyword::FIRST
1324                        | Keyword::LAST
1325                        | Keyword::ROW
1326                        | Keyword::ROWS
1327                        | Keyword::RANGE
1328                        | Keyword::ONLY
1329                        | Keyword::FILTER
1330                        | Keyword::PRECEDING
1331                        | Keyword::FOLLOWING
1332                )
1333            )
1334        {
1335            break;
1336        }
1337        // `NOT NULL` is a column constraint, not an expression operator
1338        // (e.g. `DEFAULT (foo())::TEXT NOT NULL`).  Break before consuming
1339        // the NOT so the caller can handle NOT NULL as a constraint.
1340        if matches!(r.stack.last(), Some(ReduceMember::Expression(_)))
1341            && matches!(parser.token, Token::Ident(_, Keyword::NOT))
1342            && matches!(parser.peek(), Token::Ident(_, Keyword::NULL))
1343        {
1344            break;
1345        }
1346        let e = match parser.token.clone() {
1347            Token::ColonEq if PRIORITY_ASSIGN < max_priority => {
1348                r.shift_binop(BinaryOperator::Assignment(parser.consume()))
1349            }
1350            Token::Ident(_, Keyword::OR) | Token::DoublePipe if PRIORITY_OR < max_priority => {
1351                r.shift_binop(BinaryOperator::Or(parser.consume()))
1352            }
1353            Token::Ident(_, Keyword::XOR) if PRIORITY_XOR < max_priority => {
1354                r.shift_binop(BinaryOperator::Xor(parser.consume()))
1355            }
1356            Token::Ident(_, Keyword::AND) | Token::DoubleAmpersand
1357                if PRIORITY_AND < max_priority =>
1358            {
1359                r.shift_binop(BinaryOperator::And(parser.consume()))
1360            }
1361            Token::Eq if PRIORITY_CMP < max_priority => {
1362                r.shift_binop(BinaryOperator::Eq(parser.consume()))
1363            }
1364            Token::Spaceship if PRIORITY_CMP < max_priority => {
1365                r.shift_binop(BinaryOperator::NullSafeEq(parser.consume()))
1366            }
1367            Token::GtEq if PRIORITY_CMP < max_priority => {
1368                r.shift_binop(BinaryOperator::GtEq(parser.consume()))
1369            }
1370            Token::Gt if PRIORITY_CMP < max_priority => {
1371                r.shift_binop(BinaryOperator::Gt(parser.consume()))
1372            }
1373            Token::LtEq if PRIORITY_CMP < max_priority => {
1374                r.shift_binop(BinaryOperator::LtEq(parser.consume()))
1375            }
1376            Token::Lt if PRIORITY_CMP < max_priority => {
1377                r.shift_binop(BinaryOperator::Lt(parser.consume()))
1378            }
1379            Token::Neq if PRIORITY_CMP < max_priority => {
1380                r.shift_binop(BinaryOperator::Neq(parser.consume()))
1381            }
1382            Token::ShiftLeft if PRIORITY_SHIFT < max_priority => {
1383                r.shift_binop(BinaryOperator::ShiftLeft(parser.consume()))
1384            }
1385            Token::ShiftRight if PRIORITY_SHIFT < max_priority => {
1386                r.shift_binop(BinaryOperator::ShiftRight(parser.consume()))
1387            }
1388            Token::Ampersand => r.shift_binop(BinaryOperator::BitAnd(parser.consume())),
1389            Token::Pipe if PRIORITY_BITOR < max_priority => {
1390                r.shift_binop(BinaryOperator::BitOr(parser.consume()))
1391            }
1392            Token::Ident(_, Keyword::BINARY) if PRIORITY_JSON_EXTRACT < max_priority => {
1393                r.shift_unary(UnaryOperator::Binary(parser.consume()))
1394            }
1395            Token::Ident(_, Keyword::COLLATE)
1396                if 20 < max_priority
1397                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1398            {
1399                // COLLATE is a binary operator: expr COLLATE collation_name
1400                let collate_span = parser.consume_keyword(Keyword::COLLATE)?;
1401                let collation = parser.consume_plain_identifier_unreserved()?;
1402                if let Err(e) = r.shift_binop(BinaryOperator::Collate(collate_span)) {
1403                    parser.err_here(e)?;
1404                }
1405                r.shift_expr(Expression::Identifier(Box::new(IdentifierExpression {
1406                    parts: vec![IdentifierPart::Name(collation)],
1407                })))
1408            }
1409            Token::ExclamationMark if PRIORITY_JSON_EXTRACT < max_priority => {
1410                r.shift_unary(UnaryOperator::LogicalNot(parser.consume()))
1411            }
1412            Token::Minus if !matches!(r.stack.last(), Some(ReduceMember::Expression(_))) => {
1413                r.shift_unary(UnaryOperator::Minus(parser.consume()))
1414            }
1415            Token::Minus
1416                if PRIORITY_ADD < max_priority
1417                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1418            {
1419                r.shift_binop(BinaryOperator::Subtract(parser.consume()))
1420            }
1421            Token::Ident(_, Keyword::IN) if PRIORITY_CMP < max_priority => {
1422                if let Err(e) = r.reduce(PRIORITY_CMP) {
1423                    parser.err_here(e)?;
1424                }
1425                let lhs = match r.stack.pop() {
1426                    Some(ReduceMember::Expression(e)) => e,
1427                    _ => parser.err_here("Expected expression before here 3")?,
1428                };
1429                let op = parser.consume_keyword(Keyword::IN)?;
1430                parser.consume_token(Token::LParen)?;
1431                let mut rhs = Vec::new();
1432                loop {
1433                    parser.recovered(
1434                        "')' or ','",
1435                        &|t| matches!(t, Token::RParen | Token::Comma),
1436                        |parser| {
1437                            rhs.push(parse_expression_paren(parser)?);
1438                            Ok(())
1439                        },
1440                    )?;
1441                    if parser.skip_token(Token::Comma).is_none() {
1442                        break;
1443                    }
1444                }
1445                parser.consume_token(Token::RParen)?;
1446                r.shift_expr(Expression::In(Box::new(InExpression {
1447                    lhs,
1448                    rhs,
1449                    in_span: op,
1450                    not_in: false,
1451                })))
1452            }
1453            Token::Ident(_, Keyword::IS) if PRIORITY_CMP < max_priority => {
1454                if let Err(e) = r.reduce(PRIORITY_CMP) {
1455                    parser.err_here(e)?;
1456                }
1457                let lhs = match r.stack.pop() {
1458                    Some(ReduceMember::Expression(e)) => e,
1459                    _ => parser.err_here("Expected expression before here 4")?,
1460                };
1461                let op = parser.consume_keyword(Keyword::IS)?;
1462                let (is, op) = match &parser.token {
1463                    Token::Ident(_, Keyword::NOT) => {
1464                        parser.consume();
1465                        match &parser.token {
1466                            Token::Ident(_, Keyword::TRUE) => {
1467                                (Is::NotTrue, parser.consume().join_span(&op))
1468                            }
1469                            Token::Ident(_, Keyword::FALSE) => {
1470                                (Is::NotFalse, parser.consume().join_span(&op))
1471                            }
1472                            Token::Ident(_, Keyword::NULL) => {
1473                                (Is::NotNull, parser.consume().join_span(&op))
1474                            }
1475                            Token::Ident(_, Keyword::UNKNOWN) => {
1476                                (Is::NotUnknown, parser.consume().join_span(&op))
1477                            }
1478                            Token::Ident(_, Keyword::DISTINCT) => {
1479                                let op_span = parser
1480                                    .consume_keywords(&[Keyword::DISTINCT, Keyword::FROM])?
1481                                    .join_span(&op);
1482                                parser.postgres_only(&op_span);
1483                                let rhs = parse_expression_unreserved(parser, PRIORITY_AND)?;
1484                                (Is::NotDistinctFrom(rhs), op_span)
1485                            }
1486                            _ => parser.expected_failure(
1487                                "'TRUE', 'FALSE', 'UNKNOWN', 'NULL' or 'DISTINCT'",
1488                            )?,
1489                        }
1490                    }
1491                    Token::Ident(_, Keyword::TRUE) => (Is::True, parser.consume().join_span(&op)),
1492                    Token::Ident(_, Keyword::FALSE) => (Is::False, parser.consume().join_span(&op)),
1493                    Token::Ident(_, Keyword::NULL) => (Is::Null, parser.consume().join_span(&op)),
1494                    Token::Ident(_, Keyword::DISTINCT) => {
1495                        let op_span = parser
1496                            .consume_keywords(&[Keyword::DISTINCT, Keyword::FROM])?
1497                            .join_span(&op);
1498                        parser.postgres_only(&op_span);
1499                        let rhs = parse_expression_unreserved(parser, PRIORITY_AND)?;
1500                        (Is::DistinctFrom(rhs), op_span)
1501                    }
1502                    Token::Ident(_, Keyword::UNKNOWN) => {
1503                        (Is::Unknown, parser.consume().join_span(&op))
1504                    }
1505                    _ => parser.expected_failure(
1506                        "'NOT', 'TRUE', 'FALSE', 'UNKNOWN', 'NULL' or 'DISTINCT'",
1507                    )?,
1508                };
1509                r.shift_expr(Expression::Is(Box::new(IsExpression {
1510                    lhs,
1511                    is,
1512                    is_span: op,
1513                })))
1514            }
1515            Token::DoubleColon
1516                if parser.options.dialect.is_postgresql()
1517                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1518            {
1519                // PostgreSQL typecast operator: expr::type
1520                // Reduce with very high priority (binds tighter than most operators)
1521                if let Err(e) = r.reduce(PRIORITY_TYPECAST) {
1522                    parser.err_here(e)?;
1523                }
1524                let expr = match r.stack.pop() {
1525                    Some(ReduceMember::Expression(e)) => e,
1526                    _ => parser.err_here("Expected expression before '::'")?,
1527                };
1528                let doublecolon_span = parser.consume_token(Token::DoubleColon)?;
1529                let type_ = parse_data_type(parser, DataTypeContext::TypeRef)?;
1530                r.shift_expr(Expression::TypeCast(Box::new(TypeCastExpression {
1531                    expr,
1532                    doublecolon_span,
1533                    type_,
1534                })))
1535            }
1536            Token::LBracket
1537                if parser.options.dialect.is_postgresql()
1538                    && PRIORITY_TYPECAST < max_priority
1539                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1540            {
1541                // Array subscript / slice: expr[idx] or expr[lower:upper]
1542                if let Err(e) = r.reduce(PRIORITY_TYPECAST) {
1543                    parser.err_here(e)?;
1544                }
1545                let expr = match r.stack.pop() {
1546                    Some(ReduceMember::Expression(e)) => e,
1547                    _ => parser.err_here("Expected expression before '['")?,
1548                };
1549                let lbracket = parser.consume_token(Token::LBracket)?;
1550                let lower = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1551                let upper = if parser.skip_token(Token::Colon).is_some() {
1552                    Some(parse_expression_unreserved(parser, PRIORITY_MAX)?)
1553                } else {
1554                    None
1555                };
1556                let rbracket = parser.consume_token(Token::RBracket)?;
1557                let bracket_span = lbracket.join_span(&rbracket);
1558                r.shift_expr(Expression::ArraySubscript(Box::new(
1559                    ArraySubscriptExpression {
1560                        expr,
1561                        bracket_span,
1562                        lower,
1563                        upper,
1564                    },
1565                )))
1566            }
1567            Token::Period
1568                if parser.options.dialect.is_postgresql()
1569                    && PRIORITY_TYPECAST < max_priority
1570                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1571            {
1572                // PostgreSQL composite type field access: (expr).field
1573                if let Err(e) = r.reduce(PRIORITY_TYPECAST) {
1574                    parser.err_here(e)?;
1575                }
1576                let expr = match r.stack.pop() {
1577                    Some(ReduceMember::Expression(e)) => e,
1578                    _ => parser.err_here("Expected expression before '.'")?,
1579                };
1580                let dot_span = parser.consume_token(Token::Period)?;
1581                let field = parser.consume_plain_identifier_unreserved()?;
1582                r.shift_expr(Expression::FieldAccess(Box::new(FieldAccessExpression {
1583                    expr,
1584                    dot_span,
1585                    field,
1586                })))
1587            }
1588            Token::Ident(_, Keyword::NOT)
1589                if !matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1590            {
1591                r.shift_unary(UnaryOperator::Not(parser.consume()))
1592            }
1593            Token::Ident(_, Keyword::NOT)
1594                if PRIORITY_CMP < max_priority
1595                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1596            {
1597                if let Err(e) = r.reduce(PRIORITY_CMP) {
1598                    parser.err_here(e)?;
1599                }
1600                let lhs = match r.stack.pop() {
1601                    Some(ReduceMember::Expression(e)) => e,
1602                    _ => parser.err_here("Expected expression before here 2")?,
1603                };
1604                let op = parser.consume_keyword(Keyword::NOT)?;
1605                match &parser.token {
1606                    Token::Ident(_, Keyword::IN) => {
1607                        let op = parser.consume_keyword(Keyword::IN)?.join_span(&op);
1608                        parser.consume_token(Token::LParen)?;
1609                        let mut rhs = Vec::new();
1610                        loop {
1611                            parser.recovered(
1612                                "')' or ','",
1613                                &|t| matches!(t, Token::RParen | Token::Comma),
1614                                |parser| {
1615                                    rhs.push(parse_expression_paren(parser)?);
1616                                    Ok(())
1617                                },
1618                            )?;
1619                            if parser.skip_token(Token::Comma).is_none() {
1620                                break;
1621                            }
1622                        }
1623                        parser.consume_token(Token::RParen)?;
1624                        r.shift_expr(Expression::In(Box::new(InExpression {
1625                            lhs,
1626                            rhs,
1627                            in_span: op,
1628                            not_in: true,
1629                        })))
1630                    }
1631                    Token::Ident(_, Keyword::LIKE) => {
1632                        r.stack.push(ReduceMember::Expression(lhs));
1633                        r.shift_binop(BinaryOperator::NotLike(parser.consume().join_span(&op)))
1634                    }
1635                    Token::Ident(_, Keyword::REGEXP) if parser.options.dialect.is_maria() => {
1636                        r.stack.push(ReduceMember::Expression(lhs));
1637                        r.shift_binop(BinaryOperator::NotRegexp(parser.consume().join_span(&op)))
1638                    }
1639                    Token::Ident(_, Keyword::RLIKE) if parser.options.dialect.is_maria() => {
1640                        r.stack.push(ReduceMember::Expression(lhs));
1641                        r.shift_binop(BinaryOperator::NotRlike(parser.consume().join_span(&op)))
1642                    }
1643                    Token::Ident(_, Keyword::BETWEEN) => {
1644                        let between_span = parser.consume_keyword(Keyword::BETWEEN)?.join_span(&op);
1645                        let low = parse_expression_unreserved(parser, PRIORITY_AND)?;
1646                        let and_span = parser.consume_keyword(Keyword::AND)?;
1647                        let high = parse_expression_unreserved(parser, PRIORITY_AND)?;
1648                        r.shift_expr(Expression::Between(Box::new(BetweenExpression {
1649                            lhs,
1650                            low,
1651                            high,
1652                            between_span: between_span.join_span(&and_span),
1653                            not_between: true,
1654                        })))
1655                    }
1656                    _ => parser.expected_failure("'IN', 'LIKE', 'REGEXP', 'RLIKE' or 'BETWEEN'")?,
1657                }
1658            }
1659            Token::Ident(_, Keyword::BETWEEN)
1660                if PRIORITY_CMP < max_priority
1661                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1662            {
1663                if let Err(e) = r.reduce(PRIORITY_CMP) {
1664                    parser.err_here(e)?;
1665                }
1666                let lhs = match r.stack.pop() {
1667                    Some(ReduceMember::Expression(e)) => e,
1668                    _ => parser.err_here("Expected expression before BETWEEN")?,
1669                };
1670                let between_span = parser.consume_keyword(Keyword::BETWEEN)?;
1671                let low = parse_expression_unreserved(parser, PRIORITY_AND)?;
1672                let and_span = parser.consume_keyword(Keyword::AND)?;
1673                let high = parse_expression_unreserved(parser, PRIORITY_AND)?;
1674                r.shift_expr(Expression::Between(Box::new(BetweenExpression {
1675                    lhs,
1676                    low,
1677                    high,
1678                    between_span: between_span.join_span(&and_span),
1679                    not_between: false,
1680                })))
1681            }
1682            Token::Ident(_, Keyword::LIKE) if PRIORITY_CMP < max_priority => {
1683                r.shift_binop(BinaryOperator::Like(parser.consume()))
1684            }
1685            Token::Ident(_, Keyword::SIMILAR)
1686                if PRIORITY_CMP < max_priority
1687                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1688            {
1689                // SIMILAR TO expr (PostgreSQL)
1690                if let Err(e) = r.reduce(PRIORITY_CMP) {
1691                    parser.err_here(e)?;
1692                }
1693                let lhs = match r.stack.pop() {
1694                    Some(ReduceMember::Expression(e)) => e,
1695                    _ => parser.err_here("Expected expression before SIMILAR")?,
1696                };
1697                let op_span = parser.consume_keywords(&[Keyword::SIMILAR, Keyword::TO])?;
1698                parser.postgres_only(&op_span);
1699                r.stack.push(ReduceMember::Expression(lhs));
1700                r.shift_binop(BinaryOperator::Like(op_span))
1701            }
1702            Token::Ident(_, Keyword::REGEXP)
1703                if PRIORITY_CMP < max_priority && parser.options.dialect.is_maria() =>
1704            {
1705                r.shift_binop(BinaryOperator::Regexp(parser.consume()))
1706            }
1707            Token::Ident(_, Keyword::RLIKE)
1708                if PRIORITY_CMP < max_priority && parser.options.dialect.is_maria() =>
1709            {
1710                r.shift_binop(BinaryOperator::Rlike(parser.consume()))
1711            }
1712            Token::RArrowJson if PRIORITY_JSON_EXTRACT < max_priority => {
1713                r.shift_binop(BinaryOperator::JsonExtract(parser.consume()))
1714            }
1715            Token::RDoubleArrowJson if PRIORITY_JSON_EXTRACT < max_priority => {
1716                r.shift_binop(BinaryOperator::JsonExtractUnquote(parser.consume()))
1717            }
1718            // PostgreSQL built-in operator tokens
1719            Token::Contains if PRIORITY_PG_CUSTOM < max_priority => {
1720                r.shift_binop(BinaryOperator::Contains(parser.consume()))
1721            }
1722            Token::ContainedBy if PRIORITY_PG_CUSTOM < max_priority => {
1723                r.shift_binop(BinaryOperator::ContainedBy(parser.consume()))
1724            }
1725            Token::AtQuestion if PRIORITY_PG_CUSTOM < max_priority => {
1726                r.shift_binop(BinaryOperator::JsonPathExists(parser.consume()))
1727            }
1728            Token::QuestionPipe if PRIORITY_PG_CUSTOM < max_priority => {
1729                r.shift_binop(BinaryOperator::JsonbAnyKeyExists(parser.consume()))
1730            }
1731            Token::QuestionAmpersand if PRIORITY_PG_CUSTOM < max_priority => {
1732                r.shift_binop(BinaryOperator::JsonbAllKeyExists(parser.consume()))
1733            }
1734            Token::HashArrow if PRIORITY_PG_CUSTOM < max_priority => {
1735                r.shift_binop(BinaryOperator::JsonGetPath(parser.consume()))
1736            }
1737            Token::HashDoubleArrow if PRIORITY_PG_CUSTOM < max_priority => {
1738                r.shift_binop(BinaryOperator::JsonGetPathText(parser.consume()))
1739            }
1740            Token::HashMinus if PRIORITY_PG_CUSTOM < max_priority => {
1741                r.shift_binop(BinaryOperator::JsonDeletePath(parser.consume()))
1742            }
1743            Token::TildeStar if PRIORITY_PG_CUSTOM < max_priority => {
1744                r.shift_binop(BinaryOperator::RegexIMatch(parser.consume()))
1745            }
1746            Token::NotTilde if PRIORITY_PG_CUSTOM < max_priority => {
1747                r.shift_binop(BinaryOperator::NotRegexMatch(parser.consume()))
1748            }
1749            Token::NotTildeStar if PRIORITY_PG_CUSTOM < max_priority => {
1750                r.shift_binop(BinaryOperator::NotRegexIMatch(parser.consume()))
1751            }
1752            Token::LikeTilde if PRIORITY_CMP < max_priority => {
1753                r.shift_binop(BinaryOperator::Like(parser.consume()))
1754            }
1755            Token::NotLikeTilde if PRIORITY_CMP < max_priority => {
1756                r.shift_binop(BinaryOperator::NotLike(parser.consume()))
1757            }
1758            // @@ as binary (full-text / jsonpath match)
1759            Token::AtAt
1760                if PRIORITY_PG_CUSTOM < max_priority
1761                    && parser.options.dialect.is_postgresql()
1762                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1763            {
1764                r.shift_binop(BinaryOperator::JsonPathMatch(parser.consume()))
1765            }
1766            // ~ as binary regex match (only when expression already on left)
1767            Token::Tilde
1768                if PRIORITY_PG_CUSTOM < max_priority
1769                    && parser.options.dialect.is_postgresql()
1770                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1771            {
1772                r.shift_binop(BinaryOperator::RegexMatch(parser.consume()))
1773            }
1774            // ? as jsonb key-exists binary operator (PG, non-argument mode)
1775            Token::QuestionMark
1776                if PRIORITY_PG_CUSTOM < max_priority
1777                    && parser.options.dialect.is_postgresql()
1778                    && !matches!(parser.options.arguments, crate::SQLArguments::QuestionMark)
1779                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1780            {
1781                r.shift_binop(BinaryOperator::JsonbKeyExists(parser.consume()))
1782            }
1783            // Remaining user-defined PostgreSQL operators
1784            Token::PostgresOperator(op)
1785                if PRIORITY_PG_CUSTOM < max_priority
1786                    && parser.options.dialect.is_postgresql()
1787                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1788            {
1789                r.shift_binop(BinaryOperator::User(op, parser.consume()))
1790            }
1791            Token::Ident(_, Keyword::OPERATOR)
1792                if PRIORITY_PG_CUSTOM < max_priority
1793                    && parser.options.dialect.is_postgresql()
1794                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1795            {
1796                let operator_span = parser.consume_keyword(Keyword::OPERATOR)?;
1797                parser.consume_token(Token::LParen)?;
1798                let op_name = parse_operator_name(parser)?;
1799                let rparen_span = parser.consume_token(Token::RParen)?;
1800                let full_span = operator_span.join_span(&rparen_span);
1801                r.shift_binop(BinaryOperator::Operator(op_name, full_span))
1802            }
1803            Token::Ident(_, Keyword::MEMBER)
1804                if PRIORITY_CMP < max_priority
1805                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1806            {
1807                if let Err(e) = r.reduce(PRIORITY_CMP) {
1808                    parser.err_here(e)?;
1809                }
1810                let lhs = match r.stack.pop() {
1811                    Some(ReduceMember::Expression(e)) => e,
1812                    _ => parser.err_here("Expected expression before here")?,
1813                };
1814                let member_span = parser.consume_keyword(Keyword::MEMBER)?;
1815                let of_span = parser.consume_keyword(Keyword::OF)?;
1816                parser.consume_token(Token::LParen)?;
1817                let rhs = parse_expression_paren(parser)?;
1818                parser.consume_token(Token::RParen)?;
1819                r.shift_expr(Expression::MemberOf(Box::new(MemberOfExpression {
1820                    lhs,
1821                    rhs,
1822                    member_of_span: member_span.join_span(&of_span),
1823                })))
1824            }
1825            Token::Ident(_, Keyword::INTERVAL) => {
1826                let interval_span = parser.consume();
1827                let time_interval = match parser.token {
1828                    Token::String(..) => {
1829                        let v = parser.consume_string()?;
1830                        let mut r = Vec::new();
1831                        for part in v.split([':', '!', ',', '.', '-', ' ']) {
1832                            let Ok(v) = part.parse() else {
1833                                parser.err("Expected . separated integers in a string", &v);
1834                                continue;
1835                            };
1836                            r.push(v);
1837                        }
1838                        (r, v.span())
1839                    }
1840                    Token::Integer(_) => {
1841                        let (v, s) = parser.consume_int()?;
1842                        (vec![v], s)
1843                    }
1844                    _ => parser.err_here("Expected integer or string")?,
1845                };
1846                let Some(u) = parse_time_unit(&parser.token) else {
1847                    parser.err_here("Expected time unit")?
1848                };
1849                let time_unit = (u, parser.consume());
1850                let e = Expression::Interval(Box::new(IntervalExpression {
1851                    interval_span,
1852                    time_interval,
1853                    time_unit,
1854                }));
1855                r.shift_expr(e)
1856            }
1857            Token::Ident(_, Keyword::TIMESTAMPADD) => {
1858                let timestamp_add_span = parser.consume();
1859                parser.consume_token(Token::LParen)?;
1860                let parts = parser.recovered("')'", &|t| matches!(t, Token::RParen), |parser| {
1861                    let Some(u) = parse_time_unit(&parser.token) else {
1862                        parser.err_here("Expected time unit")?
1863                    };
1864                    let unit = (u, parser.consume());
1865                    parser.consume_token(Token::Comma)?;
1866                    let interval = parse_expression_outer(parser)?;
1867                    parser.consume_token(Token::Comma)?;
1868                    let datetime = parse_expression_outer(parser)?;
1869                    Ok(Some((unit, interval, datetime)))
1870                })?;
1871                parser.consume_token(Token::RParen)?;
1872                if let Some((unit, interval, datetime)) = parts {
1873                    r.shift_expr(Expression::TimestampAdd(Box::new(TimestampAddExpression {
1874                        timestamp_add_span,
1875                        unit,
1876                        interval,
1877                        datetime,
1878                    })))
1879                } else {
1880                    r.shift_expr(Expression::Invalid(Box::new(InvalidExpression {
1881                        span: timestamp_add_span,
1882                    })))
1883                }
1884            }
1885            Token::Ident(_, Keyword::TIMESTAMPDIFF) => {
1886                let timestamp_diff_span = parser.consume();
1887                parser.consume_token(Token::LParen)?;
1888                let parts = parser.recovered("')'", &|t| matches!(t, Token::RParen), |parser| {
1889                    let Some(u) = parse_time_unit(&parser.token) else {
1890                        parser.err_here("Expected time unit")?
1891                    };
1892                    let unit = (u, parser.consume());
1893                    parser.consume_token(Token::Comma)?;
1894                    let e1 = parse_expression_outer(parser)?;
1895                    parser.consume_token(Token::Comma)?;
1896                    let e2 = parse_expression_outer(parser)?;
1897                    Ok(Some((unit, e1, e2)))
1898                })?;
1899                parser.consume_token(Token::RParen)?;
1900                if let Some((unit, e1, e2)) = parts {
1901                    r.shift_expr(Expression::TimestampDiff(Box::new(
1902                        TimestampDiffExpression {
1903                            timestamp_diff_span,
1904                            unit,
1905                            e1,
1906                            e2,
1907                        },
1908                    )))
1909                } else {
1910                    r.shift_expr(Expression::Invalid(Box::new(InvalidExpression {
1911                        span: timestamp_diff_span,
1912                    })))
1913                }
1914            }
1915            Token::Plus if PRIORITY_ADD < max_priority => {
1916                r.shift_binop(BinaryOperator::Add(parser.consume()))
1917            }
1918            Token::Div if PRIORITY_MULT < max_priority => {
1919                r.shift_binop(BinaryOperator::Divide(parser.consume()))
1920            }
1921            Token::Ident(_, Keyword::DIV) if PRIORITY_MULT < max_priority => {
1922                r.shift_binop(BinaryOperator::Div(parser.consume()))
1923            }
1924            Token::Minus if PRIORITY_ADD < max_priority => {
1925                r.shift_binop(BinaryOperator::Subtract(parser.consume()))
1926            }
1927            Token::Ident(_, Keyword::LIKE) if PRIORITY_CMP < max_priority => {
1928                r.shift_binop(BinaryOperator::Like(parser.consume()))
1929            }
1930            Token::Mul if !matches!(r.stack.last(), Some(ReduceMember::Expression(_))) => r
1931                .shift_expr(Expression::Identifier(Box::new(IdentifierExpression {
1932                    parts: vec![IdentifierPart::Star(parser.consume_token(Token::Mul)?)],
1933                }))),
1934            Token::Mul
1935                if PRIORITY_MULT < max_priority
1936                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1937            {
1938                r.shift_binop(BinaryOperator::Mult(parser.consume()))
1939            }
1940            Token::Mod if PRIORITY_MULT < max_priority => {
1941                r.shift_binop(BinaryOperator::Mod(parser.consume()))
1942            }
1943            Token::Ident(_, Keyword::MOD)
1944                if PRIORITY_MULT < max_priority
1945                    && matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
1946            {
1947                r.shift_binop(BinaryOperator::Mod(parser.consume()))
1948            }
1949            Token::Ident(_, Keyword::TRUE) => {
1950                r.shift_expr(Expression::Bool(Box::new(BoolExpression {
1951                    value: true,
1952                    span: parser.consume_keyword(Keyword::TRUE)?,
1953                })))
1954            }
1955            Token::Ident(_, Keyword::FALSE) => {
1956                r.shift_expr(Expression::Bool(Box::new(BoolExpression {
1957                    value: false,
1958                    span: parser.consume_keyword(Keyword::FALSE)?,
1959                })))
1960            }
1961            Token::Ident(_, Keyword::NULL) => {
1962                r.shift_expr(Expression::Null(Box::new(NullExpression {
1963                    span: parser.consume_keyword(Keyword::NULL)?,
1964                })))
1965            }
1966            Token::Ident(_, Keyword::_LIST_) if parser.options.list_hack => {
1967                let arg = parser.arg;
1968                parser.arg += 1;
1969                r.shift_expr(Expression::ListHack(Box::new(ListHackExpression {
1970                    index: arg,
1971                    span: parser.consume_keyword(Keyword::_LIST_)?,
1972                })))
1973            }
1974            Token::String(..) => {
1975                r.shift_expr(Expression::String(Box::new(parser.consume_string()?)))
1976            }
1977            Token::Integer(_) => {
1978                let (value, span) = parser.consume_int()?;
1979                r.shift_expr(Expression::Integer(Box::new(IntegerExpression {
1980                    value,
1981                    span,
1982                })))
1983            }
1984            Token::Float(_) => {
1985                let (value, span) = parser.consume_float()?;
1986                r.shift_expr(Expression::Float(Box::new(FloatExpression { value, span })))
1987            }
1988            Token::Ident(_, Keyword::CAST) => {
1989                let cast_span = parser.consume_keyword(Keyword::CAST)?;
1990                parser.consume_token(Token::LParen)?;
1991                let cast = parser.recovered("')'", &|t| matches!(t, Token::RParen), |parser| {
1992                    let expr = parse_expression_outer(parser)?;
1993                    let as_span = parser.consume_keyword(Keyword::AS)?;
1994                    let type_ = parse_data_type(parser, DataTypeContext::TypeRef)?;
1995                    Ok(Some((expr, as_span, type_)))
1996                })?;
1997                parser.consume_token(Token::RParen)?;
1998                if let Some((expr, as_span, type_)) = cast {
1999                    r.shift_expr(Expression::Cast(Box::new(CastExpression {
2000                        cast_span,
2001                        expr,
2002                        as_span,
2003                        type_,
2004                    })))
2005                } else {
2006                    r.shift_expr(Expression::Invalid(Box::new(InvalidExpression {
2007                        span: cast_span,
2008                    })))
2009                }
2010            }
2011            Token::Ident(_, Keyword::CONVERT) => {
2012                let convert_span = parser.consume_keyword(Keyword::CONVERT)?;
2013                parser.consume_token(Token::LParen)?;
2014                let convert =
2015                    parser.recovered("')'", &|t| matches!(t, Token::RParen), |parser| {
2016                        let expr = parse_expression_outer(parser)?;
2017                        // Check if it's CONVERT(expr, type) or CONVERT(expr USING charset)
2018                        if parser.skip_keyword(Keyword::USING).is_some() {
2019                            // CONVERT(expr USING charset)
2020                            let charset = parser.consume_plain_identifier_unreserved()?;
2021                            Ok(Some((expr, None, Some(charset))))
2022                        } else {
2023                            // CONVERT(expr, type)
2024                            parser.consume_token(Token::Comma)?;
2025                            let type_ = parse_data_type(parser, DataTypeContext::TypeRef)?;
2026                            Ok(Some((expr, Some(type_), None)))
2027                        }
2028                    })?;
2029                parser.consume_token(Token::RParen)?;
2030                if let Some((expr, type_, charset)) = convert {
2031                    r.shift_expr(Expression::Convert(Box::new(ConvertExpression {
2032                        convert_span,
2033                        expr,
2034                        type_,
2035                        using_charset: charset.map(|c| (c.span(), c)),
2036                    })))
2037                } else {
2038                    r.shift_expr(Expression::Invalid(Box::new(InvalidExpression {
2039                        span: convert_span,
2040                    })))
2041                }
2042            }
2043            Token::Ident(_, Keyword::GROUP_CONCAT) => {
2044                let group_concat_span: core::ops::Range<usize> =
2045                    parser.consume_keyword(Keyword::GROUP_CONCAT)?;
2046                parser.consume_token(Token::LParen)?;
2047                let distinct_span: Option<core::ops::Range<usize>> =
2048                    parser.skip_keyword(Keyword::DISTINCT);
2049                let expr = parser.recovered("')'", &|t| matches!(t, Token::RParen), |parser| {
2050                    let expr = parse_expression_outer(parser)?;
2051                    Ok(Some(expr))
2052                })?;
2053                // TODO
2054                // [ORDER BY {unsigned_integer | col_name | expr}
2055                //     [ASC | DESC] [,col_name ...]]
2056                // [SEPARATOR str_val]
2057                // [LIMIT {[offset,] row_count | row_count OFFSET offset}])
2058                parser.consume_token(Token::RParen)?;
2059                if let Some(expr) = expr {
2060                    r.shift_expr(Expression::GroupConcat(Box::new(GroupConcatExpression {
2061                        group_concat_span,
2062                        distinct_span,
2063                        expr,
2064                    })))
2065                } else {
2066                    r.shift_expr(Expression::Invalid(Box::new(InvalidExpression {
2067                        span: group_concat_span,
2068                    })))
2069                }
2070            }
2071            Token::Ident(_, Keyword::TRIM) if matches!(parser.peek(), Token::LParen) => {
2072                let trim_span = parser.consume_keyword(Keyword::TRIM)?;
2073                parser.consume_token(Token::LParen)?;
2074                let parts = parser.recovered("')'", &|t| matches!(t, Token::RParen), |parser| {
2075                    // Optional BOTH / LEADING / TRAILING
2076                    let direction = match &parser.token {
2077                        Token::Ident(_, Keyword::BOTH) => {
2078                            Some(TrimDirection::Both(parser.consume()))
2079                        }
2080                        Token::Ident(_, Keyword::LEADING) => {
2081                            Some(TrimDirection::Leading(parser.consume()))
2082                        }
2083                        Token::Ident(_, Keyword::TRAILING) => {
2084                            Some(TrimDirection::Trailing(parser.consume()))
2085                        }
2086                        _ => None,
2087                    };
2088
2089                    let (what, from_span, value) = if direction.is_some() {
2090                        // After direction: optionally [remstr] FROM value
2091                        if let Some(from_s) = parser.skip_keyword(Keyword::FROM) {
2092                            // No remstr: TRIM(BOTH FROM str)
2093                            let value = parse_expression_outer(parser)?;
2094                            (None, Some(from_s), value)
2095                        } else {
2096                            // Has remstr: TRIM(BOTH remstr FROM str)
2097                            let what = parse_expression_outer(parser)?;
2098                            let from_s = parser.consume_keyword(Keyword::FROM)?;
2099                            let value = parse_expression_outer(parser)?;
2100                            (Some(what), Some(from_s), value)
2101                        }
2102                    } else {
2103                        // No direction: TRIM(str) or TRIM(remstr FROM str)
2104                        let first = parse_expression_outer(parser)?;
2105                        if let Some(from_s) = parser.skip_keyword(Keyword::FROM) {
2106                            // first is remstr
2107                            let value = parse_expression_outer(parser)?;
2108                            (Some(first), Some(from_s), value)
2109                        } else {
2110                            // first is the value itself
2111                            (None, None, first)
2112                        }
2113                    };
2114                    Ok(Some((direction, what, from_span, value)))
2115                })?;
2116                parser.consume_token(Token::RParen)?;
2117                if let Some((direction, what, from_span, value)) = parts {
2118                    r.shift_expr(Expression::Trim(Box::new(TrimExpression {
2119                        trim_span,
2120                        direction,
2121                        what,
2122                        from_span,
2123                        value,
2124                    })))
2125                } else {
2126                    r.shift_expr(Expression::Invalid(Box::new(InvalidExpression {
2127                        span: trim_span,
2128                    })))
2129                }
2130            }
2131            Token::Ident(_, Keyword::EXTRACT) => {
2132                let extract_span = parser.consume_keyword(Keyword::EXTRACT)?;
2133                parser.consume_token(Token::LParen)?;
2134                let parts = parser.recovered("')'", &|t| matches!(t, Token::RParen), |parser| {
2135                    let Some(u) = parse_time_unit(&parser.token) else {
2136                        parser.err_here("Expected time unit")?
2137                    };
2138                    let time_unit = (u, parser.consume());
2139                    let from_span = parser.consume_keyword(Keyword::FROM)?;
2140                    let date = parse_expression_outer(parser)?;
2141                    Ok(Some((time_unit, from_span, date)))
2142                })?;
2143                parser.consume_token(Token::RParen)?;
2144                if let Some((time_unit, from_span, date)) = parts {
2145                    r.shift_expr(Expression::Extract(Box::new(ExtractExpression {
2146                        extract_span,
2147                        time_unit,
2148                        from_span,
2149                        date,
2150                    })))
2151                } else {
2152                    r.shift_expr(Expression::Invalid(Box::new(InvalidExpression {
2153                        span: extract_span,
2154                    })))
2155                }
2156            }
2157            Token::Ident(_, Keyword::MATCH) => {
2158                let match_span = parser.consume_keyword(Keyword::MATCH)?;
2159                parser.consume_token(Token::LParen)?;
2160                let mut cols = Vec::new();
2161                loop {
2162                    parser.recovered(
2163                        "')' or ','",
2164                        &|t| matches!(t, Token::RParen | Token::Comma),
2165                        |parser| {
2166                            cols.push(parse_expression_paren(parser)?);
2167                            Ok(())
2168                        },
2169                    )?;
2170                    if parser.skip_token(Token::Comma).is_none() {
2171                        break;
2172                    }
2173                }
2174                parser.consume_token(Token::RParen)?;
2175                let against_span = parser.consume_keyword(Keyword::AGAINST)?;
2176                parser.consume_token(Token::LParen)?;
2177
2178                // Parse the search expression but don't treat `IN`/`WITH` as binary
2179                // operators here — they are MATCH modes and may appear inside the
2180                // AGAINST(...) parentheses (MySQL allows both inside and outside).
2181                // PRIORITY_CMP stops before IN/WITH so they remain available as MATCH mode keywords
2182                let expr = parse_expression_unreserved(parser, PRIORITY_CMP)?;
2183
2184                // optional mode that may appear inside the AGAINST(...) parentheses
2185                let mut mode: Option<MatchMode> = None;
2186                if parser.skip_keyword(Keyword::IN).is_some() {
2187                    if let Some(boolean_span) = parser.skip_keyword(Keyword::BOOLEAN) {
2188                        let mode_span = parser.consume_keyword(Keyword::MODE)?;
2189                        mode = Some(MatchMode::InBoolean(boolean_span.join_span(&mode_span)));
2190                    } else if let Some(natural_span) = parser.skip_keyword(Keyword::NATURAL) {
2191                        // optional LANGUAGE after NATURAL
2192                        let _language_span = parser.skip_keyword(Keyword::LANGUAGE);
2193                        let mode_span = parser.consume_keyword(Keyword::MODE)?;
2194                        let natural_total = natural_span.join_span(&mode_span);
2195                        // optional WITH QUERY EXPANSION following NATURAL MODE inside parens
2196                        if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
2197                            let expansion_total = with_span.join_span(
2198                                &parser.consume_keywords(&[Keyword::QUERY, Keyword::EXPANSION])?,
2199                            );
2200                            mode = Some(MatchMode::InNaturalLanguageWithQueryExpansion(
2201                                natural_total.join_span(&expansion_total),
2202                            ));
2203                        } else {
2204                            mode = Some(MatchMode::InNaturalLanguage(natural_total));
2205                        }
2206                    }
2207                } else if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
2208                    mode = Some(MatchMode::WithQueryExpansion(with_span.join_span(
2209                        &parser.consume_keywords(&[Keyword::QUERY, Keyword::EXPANSION])?,
2210                    )));
2211                }
2212
2213                parser.consume_token(Token::RParen)?;
2214
2215                // If no mode was found inside the parens, allow it after the closing
2216                // parenthesis as well (some dialects/placeholders may put it there).
2217                if mode.is_none() {
2218                    if parser.skip_keyword(Keyword::IN).is_some() {
2219                        if let Some(boolean_span) = parser.skip_keyword(Keyword::BOOLEAN) {
2220                            let mode_span = parser.consume_keyword(Keyword::MODE)?;
2221                            mode = Some(MatchMode::InBoolean(boolean_span.join_span(&mode_span)));
2222                        } else if let Some(natural_span) = parser.skip_keyword(Keyword::NATURAL) {
2223                            let _language_span = parser.skip_keyword(Keyword::LANGUAGE);
2224                            let mode_span = parser.consume_keyword(Keyword::MODE)?;
2225                            let natural_total = natural_span.join_span(&mode_span);
2226                            // optional WITH QUERY EXPANSION following NATURAL MODE after paren
2227                            if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
2228                                let expansion_total = with_span.join_span(
2229                                    &parser
2230                                        .consume_keywords(&[Keyword::QUERY, Keyword::EXPANSION])?,
2231                                );
2232                                mode = Some(MatchMode::InNaturalLanguageWithQueryExpansion(
2233                                    natural_total.join_span(&expansion_total),
2234                                ));
2235                            } else {
2236                                mode = Some(MatchMode::InNaturalLanguage(natural_total));
2237                            }
2238                        }
2239                    } else if let Some(with_span) = parser.skip_keyword(Keyword::WITH) {
2240                        mode = Some(MatchMode::WithQueryExpansion(with_span.join_span(
2241                            &parser.consume_keywords(&[Keyword::QUERY, Keyword::EXPANSION])?,
2242                        )));
2243                    }
2244                }
2245
2246                r.shift_expr(Expression::MatchAgainst(Box::new(MatchAgainstExpression {
2247                    match_span,
2248                    columns: cols,
2249                    against_span,
2250                    expr,
2251                    mode,
2252                })))
2253            }
2254            Token::Ident(_, Keyword::LEFT) if matches!(parser.peek(), Token::LParen) => {
2255                let i = parser.token.clone();
2256                let s = parser.span.clone();
2257                parser.consume();
2258                r.shift_expr(parse_function(parser, i, s)?)
2259            }
2260            Token::Ident(_, Keyword::CHAR) if matches!(parser.peek(), Token::LParen) => {
2261                let s = parser.span.clone();
2262                parser.consume();
2263                r.shift_expr(parse_char_function(parser, s)?)
2264            }
2265            Token::Ident(_, keyword)
2266                if matches!(parser.peek(), Token::LParen)
2267                    && is_aggregate_function_ident(&keyword) =>
2268            {
2269                let i = parser.token.clone();
2270                let s = parser.span.clone();
2271                parser.consume();
2272                r.shift_expr(parse_aggregate_function(parser, i, s)?)
2273            }
2274            // Handle charset-prefixed strings like _utf8mb4 'abc' or _binary 'data'
2275            Token::Ident(charset, _)
2276                if charset.starts_with('_') && matches!(parser.peek(), Token::String(..)) =>
2277            {
2278                // Consume the charset prefix
2279                parser.consume();
2280                // Parse the string literal
2281                r.shift_expr(Expression::String(Box::new(parser.consume_string()?)))
2282            }
2283            // PostgreSQL ARRAY[...] literal
2284            Token::Ident(_, Keyword::ARRAY) if matches!(parser.peek(), Token::LBracket) => {
2285                let array_span = parser.consume_keyword(Keyword::ARRAY)?;
2286                parser.postgres_only(&array_span);
2287                let lbracket = parser.consume_token(Token::LBracket)?;
2288                let mut elements = Vec::new();
2289                if !matches!(parser.token, Token::RBracket) {
2290                    loop {
2291                        parser.recovered(
2292                            "']' or ','",
2293                            &|t| matches!(t, Token::RBracket | Token::Comma),
2294                            |parser| {
2295                                elements.push(parse_array_element(parser)?);
2296                                Ok(())
2297                            },
2298                        )?;
2299                        if parser.skip_token(Token::Comma).is_none() {
2300                            break;
2301                        }
2302                    }
2303                }
2304                let rbracket = parser.consume_token(Token::RBracket)?;
2305                let bracket_span = lbracket.join_span(&rbracket);
2306                r.shift_expr(Expression::Array(Box::new(ArrayExpression {
2307                    array_span,
2308                    bracket_span,
2309                    elements,
2310                })))
2311            }
2312            Token::Ident(_, k)
2313                if (k.expr_ident() || !k.restricted(restrict))
2314                    && !matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
2315            {
2316                let i = parser.token.clone();
2317                let s = parser.span.clone();
2318                parser.consume();
2319                if matches!(parser.token, Token::LParen) {
2320                    r.shift_expr(parse_function(parser, i, s)?)
2321                } else {
2322                    let f = match i {
2323                        Token::Ident(_, Keyword::CURRENT_TIMESTAMP) => {
2324                            Some(Function::CurrentTimestamp)
2325                        }
2326                        Token::Ident(_, Keyword::LOCALTIME | Keyword::LOCALTIMESTAMP) => {
2327                            Some(Function::Now)
2328                        }
2329                        Token::Ident(_, Keyword::UTC_TIMESTAMP) => Some(Function::UtcTimeStamp),
2330                        Token::Ident(_, Keyword::UTC_DATE) => Some(Function::UtcDate),
2331                        Token::Ident(_, Keyword::UTC_TIME) => Some(Function::UtcTime),
2332                        Token::Ident(_, Keyword::CURRENT_DATE) => Some(Function::CurDate),
2333                        Token::Ident(_, Keyword::CURRENT_TIME) => Some(Function::CurTime),
2334                        Token::Ident(_, Keyword::CURRENT_USER) => Some(Function::CurrentUser),
2335                        Token::Ident(_, Keyword::CURRENT_ROLE) => Some(Function::CurrentRole),
2336                        Token::Ident(_, Keyword::CURRENT_CATALOG) => Some(Function::CurrentCatalog),
2337                        Token::Ident(_, Keyword::SESSION_USER) => Some(Function::SessionUser),
2338                        Token::Ident(_, Keyword::USER)
2339                            if parser.options.dialect.is_postgresql() =>
2340                        {
2341                            Some(Function::CurrentUser)
2342                        }
2343                        _ => None,
2344                    };
2345                    if let Some(f) = f {
2346                        r.shift_expr(Expression::Function(Box::new(FunctionCallExpression {
2347                            function: f,
2348                            args: Vec::new(),
2349                            function_span: s,
2350                        })))
2351                    } else {
2352                        let mut parts = vec![IdentifierPart::Name(
2353                            parser.token_to_plain_identifier(&i, s)?,
2354                        )];
2355                        // Save the last identifier token so we can call parse_function if
2356                        // the chain is followed by `(` (schema-qualified function call).
2357                        let mut last_ident_tok: Option<(Token<'a>, Span)> = None;
2358                        loop {
2359                            if parser.skip_token(Token::Period).is_none() {
2360                                break;
2361                            }
2362                            match &parser.token {
2363                                Token::Mul => {
2364                                    last_ident_tok = None;
2365                                    parts.push(IdentifierPart::Star(
2366                                        parser.consume_token(Token::Mul)?,
2367                                    ));
2368                                }
2369                                Token::Ident(_, _) => {
2370                                    let fn_tok = parser.token.clone();
2371                                    let fn_span = parser.span.clone();
2372                                    last_ident_tok = Some((fn_tok, fn_span));
2373                                    parts.push(IdentifierPart::Name(
2374                                        parser.consume_plain_identifier_unreserved()?,
2375                                    ));
2376                                }
2377                                _ => parser.expected_failure("Identifier or '*'")?,
2378                            }
2379                        }
2380                        // Schema-qualified function call: schema.func(args)
2381                        if matches!(parser.token, Token::LParen) {
2382                            if let Some((fn_tok, fn_span)) = last_ident_tok {
2383                                // All parts form the qualified name; last part is function name
2384                                let mut all_idents: Vec<Identifier<'a>> = parts[..parts.len() - 1]
2385                                    .iter()
2386                                    .filter_map(|p| match p {
2387                                        IdentifierPart::Name(id) => Some(id.clone()),
2388                                        _ => None,
2389                                    })
2390                                    .collect();
2391                                let fn_ident = Identifier {
2392                                    value: match &fn_tok {
2393                                        Token::Ident(v, _) => v,
2394                                        _ => "",
2395                                    },
2396                                    span: fn_span.clone(),
2397                                };
2398                                all_idents.push(fn_ident);
2399                                // function_span covers from first qualifier to function name
2400                                let function_span = if all_idents.len() > 1 {
2401                                    all_idents[0].span.join_span(&fn_span)
2402                                } else {
2403                                    fn_span
2404                                };
2405                                r.shift_expr(parse_function_call(
2406                                    parser,
2407                                    Function::Other(all_idents),
2408                                    function_span,
2409                                )?)
2410                            } else {
2411                                r.shift_expr(Expression::Identifier(Box::new(
2412                                    IdentifierExpression { parts },
2413                                )))
2414                            }
2415                        } else {
2416                            r.shift_expr(Expression::Identifier(Box::new(IdentifierExpression {
2417                                parts,
2418                            })))
2419                        }
2420                    }
2421                }
2422            }
2423            Token::QuestionMark
2424                if matches!(parser.options.arguments, crate::SQLArguments::QuestionMark) =>
2425            {
2426                let arg = parser.arg;
2427                parser.arg += 1;
2428                r.shift_expr(Expression::Arg(Box::new(ArgExpression {
2429                    index: arg,
2430                    span: parser.consume_token(Token::QuestionMark)?,
2431                })))
2432            }
2433            Token::PercentS if matches!(parser.options.arguments, crate::SQLArguments::Percent) => {
2434                let arg = parser.arg;
2435                parser.arg += 1;
2436                r.shift_expr(Expression::Arg(Box::new(ArgExpression {
2437                    index: arg,
2438                    span: parser.consume_token(Token::PercentS)?,
2439                })))
2440            }
2441            Token::DollarArg(arg)
2442                if matches!(parser.options.arguments, crate::SQLArguments::Dollar) =>
2443            {
2444                r.shift_expr(Expression::Arg(Box::new(ArgExpression {
2445                    index: arg - 1,
2446                    span: parser.consume(),
2447                })))
2448            }
2449            Token::LParen => {
2450                parser.consume_token(Token::LParen)?;
2451                let ans = parse_expression_paren(parser)?;
2452                parser.consume_token(Token::RParen)?;
2453                r.shift_expr(ans)
2454            }
2455            Token::Ident(_, Keyword::EXISTS) => {
2456                let exists_span = parser.consume_keyword(Keyword::EXISTS)?;
2457                parser.consume_token(Token::LParen)?;
2458                let subquery = parse_compound_query(parser)?;
2459                parser.consume_token(Token::RParen)?;
2460                let ans = Expression::Exists(Box::new(ExistsExpression {
2461                    exists_span,
2462                    subquery,
2463                }));
2464                r.shift_expr(ans)
2465            }
2466            Token::Ident(_, Keyword::ANY | Keyword::SOME | Keyword::ALL)
2467                if parser.options.dialect.is_postgresql()
2468                    && !matches!(r.stack.last(), Some(ReduceMember::Expression(_))) =>
2469            {
2470                let quantifier = match &parser.token {
2471                    Token::Ident(_, Keyword::ANY) => {
2472                        Quantifier::Any(parser.consume_keyword(Keyword::ANY)?)
2473                    }
2474                    Token::Ident(_, Keyword::SOME) => {
2475                        Quantifier::Some(parser.consume_keyword(Keyword::SOME)?)
2476                    }
2477                    _ => Quantifier::All(parser.consume_keyword(Keyword::ALL)?),
2478                };
2479                parser.consume_token(Token::LParen)?;
2480                let operand = parse_expression_paren(parser)?;
2481                parser.consume_token(Token::RParen)?;
2482                r.shift_expr(Expression::Quantifier(Box::new(QuantifierExpression {
2483                    quantifier,
2484                    operand,
2485                })))
2486            }
2487            Token::Ident(_, Keyword::CASE) => {
2488                let case_span = parser.consume_keyword(Keyword::CASE)?;
2489                let value = if !matches!(parser.token, Token::Ident(_, Keyword::WHEN)) {
2490                    Some(parse_expression_unreserved(parser, PRIORITY_MAX)?)
2491                } else {
2492                    None
2493                };
2494                let mut whens = Vec::new();
2495                let mut else_ = None;
2496                parser.recovered(
2497                    "'END'",
2498                    &|t| matches!(t, Token::Ident(_, Keyword::END)),
2499                    |parser| {
2500                        loop {
2501                            let when_span = parser.consume_keyword(Keyword::WHEN)?;
2502                            let when = parse_expression_unreserved(parser, PRIORITY_MAX)?;
2503                            let then_span = parser.consume_keyword(Keyword::THEN)?;
2504                            let then = parse_expression_unreserved(parser, PRIORITY_MAX)?;
2505                            whens.push(When {
2506                                when_span,
2507                                when,
2508                                then_span,
2509                                then,
2510                            });
2511                            if !matches!(parser.token, Token::Ident(_, Keyword::WHEN)) {
2512                                break;
2513                            }
2514                        }
2515                        if let Some(span) = parser.skip_keyword(Keyword::ELSE) {
2516                            else_ = Some((span, parse_expression_unreserved(parser, PRIORITY_MAX)?))
2517                        };
2518                        Ok(())
2519                    },
2520                )?;
2521                let end_span = parser.consume_keyword(Keyword::END)?;
2522                r.shift_expr(Expression::Case(Box::new(CaseExpression {
2523                    case_span,
2524                    value,
2525                    whens,
2526                    else_,
2527                    end_span,
2528                })))
2529            }
2530            Token::AtAtGlobal | Token::AtAtSession => {
2531                let global = parser.skip_token(Token::AtAtGlobal);
2532                let session = if global.is_none() {
2533                    Some(parser.consume_token(Token::AtAtSession)?)
2534                } else {
2535                    None
2536                };
2537                let dot = Some(parser.consume_token(Token::Period)?);
2538                let variable = match &parser.token {
2539                    Token::Ident(_, Keyword::TIME_ZONE) => Variable::TimeZone,
2540                    Token::Ident(t, _) => Variable::Other(t),
2541                    _ => parser.expected_failure("Identifier")?,
2542                };
2543                let variable_span = parser.consume();
2544                r.shift_expr(Expression::Variable(Box::new(VariableExpression {
2545                    global,
2546                    session,
2547                    dot,
2548                    variable,
2549                    variable_span,
2550                })))
2551            }
2552            Token::At => {
2553                // User variable: @variable_name
2554                let at_span = parser.consume_token(Token::At)?;
2555                let name = parser.consume_plain_identifier_unreserved()?;
2556                r.shift_expr(Expression::UserVariable(Box::new(UserVariableExpression {
2557                    name,
2558                    at_span,
2559                })))
2560            }
2561            _ => break,
2562        };
2563        if let Err(e) = e {
2564            parser.err_here(e.to_string())?;
2565        }
2566    }
2567    if r.reduce(99999).is_err() {
2568        parser.err_here("Expected expression")
2569    } else if r.stack.len() != 1 {
2570        parser.ice(file!(), line!())
2571    } else if let Some(ReduceMember::Expression(e)) = r.stack.pop() {
2572        Ok(e)
2573    } else {
2574        parser.ice(file!(), line!())
2575    }
2576}
2577
2578pub(crate) fn parse_expression_unreserved<'a>(
2579    parser: &mut Parser<'a, '_>,
2580    max_priority: usize,
2581) -> Result<Expression<'a>, ParseError> {
2582    parse_expression_restricted(parser, max_priority, parser.reserved())
2583}
2584
2585/// Parse an expression that may be DEFAULT (for INSERT VALUES, INSERT SET, UPDATE SET contexts)
2586pub(crate) fn parse_expression_or_default<'a>(
2587    parser: &mut Parser<'a, '_>,
2588    max_priority: usize,
2589) -> Result<Expression<'a>, ParseError> {
2590    if matches!(parser.token, Token::Ident(_, Keyword::DEFAULT)) {
2591        Ok(Expression::Default(Box::new(DefaultExpression {
2592            span: parser.consume_keyword(Keyword::DEFAULT)?,
2593        })))
2594    } else {
2595        parse_expression_unreserved(parser, max_priority)
2596    }
2597}
2598
2599pub(crate) fn parse_expression_outer<'a>(
2600    parser: &mut Parser<'a, '_>,
2601) -> Result<Expression<'a>, ParseError> {
2602    if matches!(parser.token, Token::Ident(_, Keyword::SELECT)) {
2603        Ok(Expression::Subquery(Box::new(SubqueryExpression {
2604            expression: parse_compound_query(parser)?,
2605        })))
2606    } else {
2607        parse_expression_unreserved(parser, PRIORITY_MAX)
2608    }
2609}
2610
2611pub(crate) fn parse_expression_paren<'a>(
2612    parser: &mut Parser<'a, '_>,
2613) -> Result<Expression<'a>, ParseError> {
2614    if matches!(parser.token, Token::Ident(_, Keyword::SELECT)) {
2615        Ok(Expression::Subquery(Box::new(SubqueryExpression {
2616            expression: parse_compound_query(parser)?,
2617        })))
2618    } else {
2619        parse_expression_unreserved(parser, PRIORITY_MAX)
2620    }
2621}
2622
2623#[cfg(test)]
2624mod tests {
2625    use core::ops::Deref;
2626
2627    use alloc::{
2628        format,
2629        string::{String, ToString},
2630    };
2631
2632    use crate::{
2633        BinaryExpression, ParseOptions, SQLDialect,
2634        expression::{BinaryOperator, Expression, PRIORITY_MAX, Quantifier},
2635        issue::Issues,
2636        parser::Parser,
2637    };
2638
2639    use super::{IdentifierPart, parse_expression_unreserved};
2640
2641    fn test_ident<'a>(e: &Expression<'a>, v: &str) -> Result<(), String> {
2642        let v = match e {
2643            Expression::Identifier(a) => match a.parts.as_slice() {
2644                [IdentifierPart::Name(vv)] => vv.deref() == v,
2645                _ => false,
2646            },
2647            _ => false,
2648        };
2649        if !v {
2650            Err(format!("Expected identifier {} found {:?}", v, e))
2651        } else {
2652            Ok(())
2653        }
2654    }
2655
2656    fn test_expr(src: &'static str, f: impl FnOnce(&Expression<'_>) -> Result<(), String>) {
2657        let mut issues = Issues::new(src);
2658        let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
2659        let mut parser = Parser::new(src, &mut issues, &options);
2660        let res = parse_expression_unreserved(&mut parser, PRIORITY_MAX)
2661            .expect("Expression in test expr");
2662        if let Err(e) = f(&res) {
2663            panic!("Error parsing {}: {}\nGot {:#?}", src, e, res);
2664        }
2665    }
2666
2667    #[test]
2668    fn expressions() {
2669        test_expr("`a` + `b` * `c` + `d`", |e| {
2670            match e {
2671                Expression::Binary(b) => {
2672                    let BinaryExpression {
2673                        op: BinaryOperator::Add(_),
2674                        lhs,
2675                        rhs,
2676                        ..
2677                    } = b.as_ref()
2678                    else {
2679                        return Err("Expected outer +".to_string());
2680                    };
2681                    match lhs {
2682                        Expression::Binary(b) => {
2683                            let BinaryExpression {
2684                                op: BinaryOperator::Add(_),
2685                                lhs,
2686                                rhs,
2687                                ..
2688                            } = b.as_ref()
2689                            else {
2690                                return Err("Expected inner +".to_string());
2691                            };
2692                            test_ident(lhs, "a")?;
2693                            match rhs {
2694                                Expression::Binary(b) => {
2695                                    let BinaryExpression {
2696                                        op: BinaryOperator::Mult(_),
2697                                        lhs,
2698                                        rhs,
2699                                        ..
2700                                    } = b.as_ref()
2701                                    else {
2702                                        return Err("Expected *".to_string());
2703                                    };
2704                                    test_ident(lhs, "b")?;
2705                                    test_ident(rhs, "c")?;
2706                                }
2707                                _ => return Err("Lhs.Rhs".to_string()),
2708                            }
2709                        }
2710                        _ => return Err("Lhs".to_string()),
2711                    }
2712                    test_ident(rhs, "d")?;
2713                }
2714                _ => return Err("Outer".to_string()),
2715            }
2716            Ok(())
2717        });
2718    }
2719
2720    fn test_expr_pg(src: &'static str, f: impl FnOnce(&Expression<'_>) -> Result<(), String>) {
2721        let mut issues = Issues::new(src);
2722        let options = ParseOptions::new().dialect(SQLDialect::PostgreSQL);
2723        let mut parser = Parser::new(src, &mut issues, &options);
2724        let res = parse_expression_unreserved(&mut parser, PRIORITY_MAX)
2725            .expect("Expression in test_expr_pg");
2726        if let Err(e) = f(&res) {
2727            panic!("Error parsing {}: {}\nGot {:#?}", src, e, res);
2728        }
2729    }
2730
2731    #[test]
2732    fn quantifier_any() {
2733        test_expr_pg(
2734            "salary > ANY (SELECT max_salary FROM departments)",
2735            |e| match e {
2736                Expression::Binary(b) => match &b.rhs {
2737                    Expression::Quantifier(q) => {
2738                        assert!(matches!(q.quantifier, Quantifier::Any(_)));
2739                        Ok(())
2740                    }
2741                    _ => Err(format!("Expected Quantifier RHS, got {:?}", b.rhs)),
2742                },
2743                _ => Err(format!("Expected Binary expression, got {:?}", e)),
2744            },
2745        );
2746    }
2747
2748    #[test]
2749    fn quantifier_some() {
2750        test_expr_pg("x = SOME (ARRAY[1, 2, 3])", |e| match e {
2751            Expression::Binary(b) => match &b.rhs {
2752                Expression::Quantifier(q) => {
2753                    assert!(matches!(q.quantifier, Quantifier::Some(_)));
2754                    Ok(())
2755                }
2756                _ => Err(format!("Expected Quantifier RHS, got {:?}", b.rhs)),
2757            },
2758            _ => Err(format!("Expected Binary expression, got {:?}", e)),
2759        });
2760    }
2761
2762    #[test]
2763    fn quantifier_all() {
2764        test_expr_pg("price <= ALL (SELECT price FROM products)", |e| match e {
2765            Expression::Binary(b) => match &b.rhs {
2766                Expression::Quantifier(q) => {
2767                    assert!(matches!(q.quantifier, Quantifier::All(_)));
2768                    Ok(())
2769                }
2770                _ => Err(format!("Expected Quantifier RHS, got {:?}", b.rhs)),
2771            },
2772            _ => Err(format!("Expected Binary expression, got {:?}", e)),
2773        });
2774    }
2775}