Skip to main content

qusql_parse/
function_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    Expression, Identifier, OptSpanned, Span, Spanned,
15    expression::{PRIORITY_MAX, parse_expression_outer, parse_expression_unreserved},
16    keywords::Keyword,
17    lexer::Token,
18    parser::{ParseError, Parser},
19    select::OrderFlag,
20};
21use alloc::{boxed::Box, vec::Vec};
22
23/// Function to execute
24#[derive(Debug, Clone, PartialEq, Eq)]
25pub enum Function<'a> {
26    Abs,
27    Acos,
28    AddDate,
29    AddMonths,
30    AddTime,
31    Ascii,
32    Asin,
33    Atan,
34    Atan2,
35    Bin,
36    BitLength,
37    Ceil,
38    Char,
39    CharacterLength,
40    Chr,
41    Concat,
42    ConcatWs,
43    Conv,
44    ConvertTz,
45    Cos,
46    Cot,
47    Crc32,
48    Crc32c,
49    CurrentCatalog,
50    CurrentRole,
51    CurrentUser,
52    CurDate,
53    CurrentTimestamp,
54    CurTime,
55    SessionUser,
56    Date,
57    DateDiff,
58    DateFormat,
59    DateSub,
60    Datetime,
61    DayName,
62    DayOfMonth,
63    DayOfWeek,
64    DayOfYear,
65    Degrees,
66    Elt,
67    Exists,
68    Exp,
69    ExportSet,
70    ExtractValue,
71    Field,
72    FindInSet,
73    Floor,
74    Format,
75    FromBase64,
76    FromDays,
77    FromUnixTime,
78    Greatest,
79    Hex,
80    Hour,
81    If,
82    IfNull,
83    Insert,
84    InStr,
85    JsonArray,
86    JsonArrayAgg,
87    JsonArrayAppend,
88    JsonArrayInsert,
89    JsonArrayIntersect,
90    JsonCompact,
91    JsonContains,
92    JsonContainsPath,
93    JsonDepth,
94    JsonDetailed,
95    JsonEquals,
96    JsonExists,
97    JsonExtract,
98    JsonInsert,
99    JsonKeys,
100    JsonLength,
101    JsonLoose,
102    JsonMerge,
103    JsonMergePath,
104    JsonMergePerserve,
105    JsonNormalize,
106    JsonObject,
107    JsonObjectAgg,
108    JsonObjectFilterKeys,
109    JsonObjectToArray,
110    JsonOverlaps,
111    JsonPretty,
112    JsonQuery,
113    JsonQuote,
114    JsonRemove,
115    JsonReplace,
116    JsonSchemaValid,
117    JsonSearch,
118    JsonSet,
119    JsonTable,
120    JsonType,
121    JsonUnquote,
122    JsonValid,
123    JsonValue,
124    Lag,
125    LastDay,
126    Avg,
127    Count,
128    LCase,
129    Lead,
130    Least,
131    Left,
132    Length,
133    LengthB,
134    Ln,
135    LoadFile,
136    Locate,
137    Log,
138    Log10,
139    Log2,
140    Lower,
141    LPad,
142    LTrim,
143    MakeDate,
144    MakeSet,
145    MakeTime,
146    Max,
147    MicroSecond,
148    Mid,
149    Min,
150    Minute,
151    Mod,
152    Month,
153    MonthName,
154    NaturalSortkey,
155    Now,
156    NullIf,
157    NVL2,
158    Oct,
159    OctetLength,
160    Ord,
161    PeriodAdd,
162    PeriodDiff,
163    Pi,
164    Position,
165    Pow,
166    Quarter,
167    Quote,
168    Radians,
169    Rand,
170    Repeat,
171    Replace,
172    Reverse,
173    Right,
174    Round,
175    RPad,
176    RTrim,
177    Second,
178    SecToTime,
179    SFormat,
180    Sign,
181    Sin,
182    Sleep,
183    SoundEx,
184    Space,
185    Sqrt,
186    StartsWith,
187    StrCmp,
188    Strftime,
189    StrToDate,
190    SubStr,
191    SubStringIndex,
192    SubTime,
193    Sum,
194    SysDate,
195    Tan,
196    Time,
197    TimeDiff,
198    TimeFormat,
199    Timestamp,
200    TimeToSec,
201    ToBase64,
202    ToChar,
203    ToDays,
204    ToSeconds,
205    Truncate,
206    UCase,
207    UncompressedLength,
208    UnHex,
209    UnixTimestamp,
210    Unknown,
211    UpdateXml,
212    Upper,
213    UtcDate,
214    UtcTime,
215    UtcTimeStamp,
216    Value,
217    Week,
218    Weekday,
219    WeekOfYear,
220    Year,
221    YearWeek,
222    // MySQL 8.4 explicit functions
223    AesDecrypt,
224    AesEncrypt,
225    AnyValue,
226    Benchmark,
227    BinToUuid,
228    BitCount,
229    Charset,
230    Coercibility,
231    Collation,
232    Compress,
233    ConnectionId,
234    DatabaseFunc,
235    FirstValue,
236    FormatBytes,
237    FormatPicoTime,
238    FoundRows,
239    GetFormat,
240    GetLock,
241    Grouping,
242    IcuVersion,
243    Inet6Aton,
244    Inet6Ntoa,
245    InetAton,
246    InetNtoa,
247    IsFreeLock,
248    IsIPv4,
249    IsIPv4Compat,
250    IsIPv4Mapped,
251    IsIPv6,
252    IsUsedLock,
253    IsUuid,
254    LastInsertId,
255    LastValue,
256    Md5,
257    NameConst,
258    NthValue,
259    Ntile,
260    PsCurrentThreadId,
261    PsThreadId,
262    RandomBytes,
263    RegexpInstr,
264    RegexpLike,
265    RegexpReplace,
266    RegexpSubstr,
267    ReleaseAllLocks,
268    ReleaseLock,
269    RolesGraphml,
270    RowCount,
271    RowNumber,
272    SchemaFunc,
273    SessionUserFunc,
274    Sha,
275    Sha1,
276    Sha2,
277    StatementDigest,
278    StatementDigestText,
279    SystemUser,
280    Uncompress,
281    UserFunc,
282    Uuid,
283    UuidShort,
284    UuidToBin,
285    ValidatePasswordStrength,
286    Version,
287    WeightString,
288    ArrayAgg,
289    BitAnd,
290    BitOr,
291    BitXor,
292    BoolAnd,
293    BoolOr,
294    Corr,
295    CovarPop,
296    CovarSamp,
297    CumeDist,
298    DenseRank,
299    JsonAgg,
300    JsonbAgg,
301    JsonbObjectAgg,
302    PercentRank,
303    PercentileCont,
304    PercentileDisc,
305    Rank,
306    RegrAvgx,
307    RegrAvgy,
308    RegrCount,
309    RegrIntercept,
310    RegrR2,
311    RegrSlope,
312    RegrSxx,
313    RegrSxy,
314    RegrSyy,
315    Mode,
316    Std,
317    Stddev,
318    StddevPop,
319    StddevSamp,
320    StringAgg,
321    Variance,
322    VarPop,
323    VarSamp,
324    Xmlagg,
325    Other(Vec<Identifier<'a>>),
326}
327
328/// Function call expression,
329#[derive(Debug, Clone)]
330pub struct FunctionCallExpression<'a> {
331    pub function: Function<'a>,
332    pub args: Vec<Expression<'a>>,
333    pub function_span: Span,
334}
335
336impl Spanned for FunctionCallExpression<'_> {
337    fn span(&self) -> Span {
338        self.function_span.join_span(&self.args)
339    }
340}
341
342/// CHAR(N,... [USING charset_name]) expression
343#[derive(Debug, Clone)]
344pub struct CharFunctionExpression<'a> {
345    /// Span of "CHAR"
346    pub char_span: Span,
347    /// Arguments to CHAR()
348    pub args: Vec<Expression<'a>>,
349    /// Optional USING charset_name clause
350    pub using_charset: Option<(Span, Identifier<'a>)>,
351}
352
353impl<'a> Spanned for CharFunctionExpression<'a> {
354    fn span(&self) -> Span {
355        self.char_span
356            .join_span(&self.args)
357            .join_span(&self.using_charset)
358    }
359}
360
361/// Window frame mode: ROWS, RANGE, or GROUPS
362#[derive(Debug, Clone)]
363pub enum WindowFrameMode {
364    Rows(Span),
365    Range(Span),
366    Groups(Span),
367}
368
369impl Spanned for WindowFrameMode {
370    fn span(&self) -> Span {
371        match self {
372            WindowFrameMode::Rows(s) | WindowFrameMode::Range(s) | WindowFrameMode::Groups(s) => {
373                s.clone()
374            }
375        }
376    }
377}
378
379/// One bound in a window frame clause
380#[derive(Debug, Clone)]
381pub enum WindowFrameBound<'a> {
382    /// UNBOUNDED PRECEDING
383    UnboundedPreceding(Span),
384    /// <expr> PRECEDING
385    Preceding(Expression<'a>, Span),
386    /// CURRENT ROW
387    CurrentRow(Span),
388    /// <expr> FOLLOWING
389    Following(Expression<'a>, Span),
390    /// UNBOUNDED FOLLOWING
391    UnboundedFollowing(Span),
392}
393
394impl<'a> Spanned for WindowFrameBound<'a> {
395    fn span(&self) -> Span {
396        match self {
397            WindowFrameBound::UnboundedPreceding(s) => s.clone(),
398            WindowFrameBound::Preceding(e, s) => e.span().join_span(s),
399            WindowFrameBound::CurrentRow(s) => s.clone(),
400            WindowFrameBound::Following(e, s) => e.span().join_span(s),
401            WindowFrameBound::UnboundedFollowing(s) => s.clone(),
402        }
403    }
404}
405
406/// Window frame clause: ROWS/RANGE/GROUPS { frame_start | BETWEEN frame_start AND frame_end }
407#[derive(Debug, Clone)]
408pub struct WindowFrame<'a> {
409    /// ROWS, RANGE, or GROUPS
410    pub mode: WindowFrameMode,
411    /// The start bound (or sole bound when no BETWEEN)
412    pub start: WindowFrameBound<'a>,
413    /// When BETWEEN was used: span covering "BETWEEN ... AND" and the end bound
414    pub between: Option<(Span, WindowFrameBound<'a>)>,
415}
416
417impl<'a> Spanned for WindowFrame<'a> {
418    fn span(&self) -> Span {
419        let s = self.mode.span().join_span(&self.start);
420        if let Some((and_span, end)) = &self.between {
421            s.join_span(and_span).join_span(end)
422        } else {
423            s
424        }
425    }
426}
427
428/// When part of CASE
429#[derive(Debug, Clone)]
430pub struct WindowSpec<'a> {
431    /// Span of "PARTITION BY" and list of partition expressions, if specified
432    pub partition_by: Option<(Span, Vec<Expression<'a>>)>,
433    /// Span of "ORDER BY" and list of order expression and directions, if specified
434    pub order_by: Option<(Span, Vec<(Expression<'a>, OrderFlag)>)>,
435    /// Window frame clause (ROWS/RANGE BETWEEN ... AND ...), if specified
436    pub frame: Option<WindowFrame<'a>>,
437}
438
439impl<'a> Spanned for WindowSpec<'a> {
440    fn span(&self) -> Span {
441        self.partition_by
442            .opt_join_span(&self.order_by)
443            .opt_join_span(&self.frame)
444            .expect("Either partition_by, order_by, or frame must be specified")
445    }
446}
447
448#[derive(Debug, Clone)]
449pub struct WindowClause<'a> {
450    pub over_span: Span,
451    pub window_spec: WindowSpec<'a>,
452}
453
454impl Spanned for WindowClause<'_> {
455    fn span(&self) -> Span {
456        self.over_span.join_span(&self.window_spec)
457    }
458}
459
460/// A window function call expression
461#[derive(Debug, Clone)]
462pub struct WindowFunctionCallExpression<'a> {
463    pub function: Function<'a>,
464    pub args: Vec<Expression<'a>>,
465    pub function_span: Span,
466    pub over: WindowClause<'a>,
467}
468
469impl Spanned for WindowFunctionCallExpression<'_> {
470    fn span(&self) -> Span {
471        self.function_span
472            .join_span(&self.args)
473            .join_span(&self.over)
474    }
475}
476
477#[derive(Debug, Clone)]
478pub struct AggregateFunctionCallExpression<'a> {
479    pub function: Function<'a>,
480    pub args: Vec<Expression<'a>>,
481    pub function_span: Span,
482    pub distinct_span: Option<Span>,
483    pub within_group: Option<(Span, Vec<(Expression<'a>, OrderFlag)>)>,
484    pub filter: Option<(Span, Expression<'a>)>,
485    pub over: Option<WindowClause<'a>>,
486}
487
488impl Spanned for AggregateFunctionCallExpression<'_> {
489    fn span(&self) -> Span {
490        self.function_span
491            .join_span(&self.args)
492            .join_span(&self.distinct_span)
493            .join_span(&self.within_group)
494            .join_span(&self.filter)
495            .join_span(&self.over)
496    }
497}
498
499pub(crate) fn is_aggregate_function_ident(keyword: &Keyword) -> bool {
500    matches!(
501        keyword,
502        Keyword::COUNT
503            | Keyword::AVG
504            | Keyword::SUM
505            | Keyword::MIN
506            | Keyword::MAX
507            | Keyword::JSON_ARRAYAGG
508            | Keyword::JSON_OBJECTAGG
509            | Keyword::ARRAY_AGG
510            | Keyword::BIT_AND
511            | Keyword::BIT_OR
512            | Keyword::BIT_XOR
513            | Keyword::BOOL_AND
514            | Keyword::BOOL_OR
515            | Keyword::CORR
516            | Keyword::COVAR_POP
517            | Keyword::COVAR_SAMP
518            | Keyword::CUME_DIST
519            | Keyword::DENSE_RANK
520            | Keyword::EVERY
521            | Keyword::JSON_AGG
522            | Keyword::JSONB_AGG
523            | Keyword::JSONB_OBJECT_AGG
524            | Keyword::PERCENT_RANK
525            | Keyword::PERCENTILE_CONT
526            | Keyword::PERCENTILE_DISC
527            | Keyword::RANK
528            | Keyword::REGR_AVGX
529            | Keyword::REGR_AVGY
530            | Keyword::REGR_COUNT
531            | Keyword::REGR_INTERCEPT
532            | Keyword::REGR_R2
533            | Keyword::REGR_SLOPE
534            | Keyword::REGR_SXX
535            | Keyword::REGR_SXY
536            | Keyword::REGR_SYY
537            | Keyword::STD
538            | Keyword::STDDEV
539            | Keyword::STDDEV_POP
540            | Keyword::STDDEV_SAMP
541            | Keyword::STRING_AGG
542            | Keyword::VARIANCE
543            | Keyword::VAR_POP
544            | Keyword::VAR_SAMP
545            | Keyword::XMLAGG
546            | Keyword::MODE
547    )
548}
549
550fn parse_window_frame_bound<'a>(
551    parser: &mut Parser<'a, '_>,
552) -> Result<WindowFrameBound<'a>, ParseError> {
553    match &parser.token {
554        Token::Ident(_, Keyword::UNBOUNDED) => {
555            let kw_span = parser.consume_keyword(Keyword::UNBOUNDED)?;
556            if let Some(span) = parser.skip_keyword(Keyword::PRECEDING) {
557                Ok(WindowFrameBound::UnboundedPreceding(
558                    kw_span.join_span(&span),
559                ))
560            } else {
561                Ok(WindowFrameBound::UnboundedFollowing(
562                    parser
563                        .consume_keyword(Keyword::FOLLOWING)?
564                        .join_span(&kw_span),
565                ))
566            }
567        }
568        Token::Ident(_, Keyword::CURRENT) => {
569            let current_row_span = parser.consume_keywords(&[Keyword::CURRENT, Keyword::ROW])?;
570            Ok(WindowFrameBound::CurrentRow(current_row_span))
571        }
572        _ => {
573            let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
574            if let Some(s) = parser.skip_keyword(Keyword::PRECEDING) {
575                Ok(WindowFrameBound::Preceding(expr, s))
576            } else {
577                let s = parser.consume_keyword(Keyword::FOLLOWING)?;
578                Ok(WindowFrameBound::Following(expr, s))
579            }
580        }
581    }
582}
583
584fn parse_window_frame<'a>(
585    parser: &mut Parser<'a, '_>,
586    mode: WindowFrameMode,
587) -> Result<WindowFrame<'a>, ParseError> {
588    if let Some(between_span) = parser.skip_keyword(Keyword::BETWEEN) {
589        let start = parse_window_frame_bound(parser)?;
590        let and_span = parser.consume_keyword(Keyword::AND)?;
591        let end = parse_window_frame_bound(parser)?;
592        Ok(WindowFrame {
593            mode,
594            start,
595            between: Some((between_span.join_span(&and_span), end)),
596        })
597    } else {
598        let start = parse_window_frame_bound(parser)?;
599        Ok(WindowFrame {
600            mode,
601            start,
602            between: None,
603        })
604    }
605}
606
607fn parse_over_clause<'a>(
608    parser: &mut Parser<'a, '_>,
609) -> Result<Option<WindowClause<'a>>, ParseError> {
610    let Some(over_span) = parser.skip_keyword(Keyword::OVER) else {
611        return Ok(None);
612    };
613
614    parser.consume_token(Token::LParen)?;
615
616    let partition_by = if let Some(partition_span) = parser.skip_keyword(Keyword::PARTITION) {
617        let partition_by_span = partition_span.join_span(&parser.consume_keyword(Keyword::BY)?);
618        let mut partition_exprs = Vec::new();
619        loop {
620            partition_exprs.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
621            if parser.skip_token(Token::Comma).is_none() {
622                break;
623            }
624        }
625        Some((partition_by_span, partition_exprs))
626    } else {
627        None
628    };
629
630    let order_by = if let Some(span) = parser.skip_keyword(Keyword::ORDER) {
631        let order_span = span.join_span(&parser.consume_keyword(Keyword::BY)?);
632        let mut order = Vec::new();
633        loop {
634            let e = parse_expression_unreserved(parser, PRIORITY_MAX)?;
635            let f = match &parser.token {
636                Token::Ident(_, Keyword::ASC) => OrderFlag::Asc(parser.consume()),
637                Token::Ident(_, Keyword::DESC) => OrderFlag::Desc(parser.consume()),
638                _ => OrderFlag::None,
639            };
640            order.push((e, f));
641            if parser.skip_token(Token::Comma).is_none() {
642                break;
643            }
644        }
645        Some((order_span, order))
646    } else {
647        None
648    };
649
650    // Window frame clause: ROWS/RANGE { frame_start | BETWEEN frame_start AND frame_end }
651    let frame = if let Some(s) = parser.skip_keyword(Keyword::ROWS) {
652        Some(parse_window_frame(parser, WindowFrameMode::Rows(s))?)
653    } else if let Some(s) = parser.skip_keyword(Keyword::RANGE) {
654        Some(parse_window_frame(parser, WindowFrameMode::Range(s))?)
655    } else {
656        None
657    };
658
659    parser.consume_token(Token::RParen)?;
660
661    Ok(Some(WindowClause {
662        over_span,
663        window_spec: WindowSpec {
664            partition_by,
665            order_by,
666            frame,
667        },
668    }))
669}
670
671pub(crate) fn parse_aggregate_function<'a>(
672    parser: &mut Parser<'a, '_>,
673    t: Token<'a>,
674    span: Span,
675) -> Result<Expression<'a>, ParseError> {
676    parser.consume_token(Token::LParen)?;
677    let func = match &t {
678        Token::Ident(_, Keyword::COUNT) => Function::Count,
679        Token::Ident(_, Keyword::AVG) => Function::Avg,
680        Token::Ident(_, Keyword::SUM) => Function::Sum,
681        Token::Ident(_, Keyword::MIN) => Function::Min,
682        Token::Ident(_, Keyword::MAX) => Function::Max,
683        Token::Ident(_, Keyword::JSON_ARRAYAGG) => Function::JsonArrayAgg,
684        Token::Ident(_, Keyword::JSON_OBJECTAGG) => Function::JsonObjectAgg,
685        Token::Ident(_, Keyword::ARRAY_AGG) => Function::ArrayAgg,
686        Token::Ident(_, Keyword::BIT_AND) => Function::BitAnd,
687        Token::Ident(_, Keyword::BIT_OR) => Function::BitOr,
688        Token::Ident(_, Keyword::BIT_XOR) => Function::BitXor,
689        Token::Ident(_, Keyword::BOOL_AND) => Function::BoolAnd,
690        Token::Ident(_, Keyword::BOOL_OR) => Function::BoolOr,
691        Token::Ident(_, Keyword::CORR) => Function::Corr,
692        Token::Ident(_, Keyword::COVAR_POP) => Function::CovarPop,
693        Token::Ident(_, Keyword::COVAR_SAMP) => Function::CovarSamp,
694        Token::Ident(_, Keyword::CUME_DIST) => Function::CumeDist,
695        Token::Ident(_, Keyword::DENSE_RANK) => Function::DenseRank,
696        Token::Ident(_, Keyword::EVERY) => Function::BoolAnd,
697        Token::Ident(_, Keyword::JSON_AGG) => Function::JsonAgg,
698        Token::Ident(_, Keyword::JSONB_AGG) => Function::JsonbAgg,
699        Token::Ident(_, Keyword::JSONB_OBJECT_AGG) => Function::JsonbObjectAgg,
700        Token::Ident(_, Keyword::PERCENT_RANK) => Function::PercentRank,
701        Token::Ident(_, Keyword::PERCENTILE_CONT) => Function::PercentileCont,
702        Token::Ident(_, Keyword::PERCENTILE_DISC) => Function::PercentileDisc,
703        Token::Ident(_, Keyword::RANK) => Function::Rank,
704        Token::Ident(_, Keyword::REGR_AVGX) => Function::RegrAvgx,
705        Token::Ident(_, Keyword::REGR_AVGY) => Function::RegrAvgy,
706        Token::Ident(_, Keyword::REGR_COUNT) => Function::RegrCount,
707        Token::Ident(_, Keyword::REGR_INTERCEPT) => Function::RegrIntercept,
708        Token::Ident(_, Keyword::REGR_R2) => Function::RegrR2,
709        Token::Ident(_, Keyword::REGR_SLOPE) => Function::RegrSlope,
710        Token::Ident(_, Keyword::REGR_SXX) => Function::RegrSxx,
711        Token::Ident(_, Keyword::REGR_SXY) => Function::RegrSxy,
712        Token::Ident(_, Keyword::REGR_SYY) => Function::RegrSyy,
713        Token::Ident(_, Keyword::STD) => Function::Std,
714        Token::Ident(_, Keyword::STDDEV) => Function::Stddev,
715        Token::Ident(_, Keyword::STDDEV_POP) => Function::StddevPop,
716        Token::Ident(_, Keyword::STDDEV_SAMP) => Function::StddevSamp,
717        Token::Ident(_, Keyword::STRING_AGG) => Function::StringAgg,
718        Token::Ident(_, Keyword::VARIANCE) => Function::Variance,
719        Token::Ident(_, Keyword::VAR_POP) => Function::VarPop,
720        Token::Ident(_, Keyword::VAR_SAMP) => Function::VarSamp,
721        Token::Ident(_, Keyword::XMLAGG) => Function::Xmlagg,
722        Token::Ident(_, Keyword::MODE) => Function::Mode,
723        _ => {
724            parser.err("Unknown aggregate function", &span);
725            Function::Unknown
726        }
727    };
728
729    let distinct_span = parser.skip_keyword(Keyword::DISTINCT);
730    let mut args = Vec::new();
731    if !matches!(parser.token, Token::RParen) {
732        loop {
733            parser.recovered(
734                "')' or ','",
735                &|t| matches!(t, Token::RParen | Token::Comma),
736                |parser| {
737                    args.push(parse_expression_outer(parser)?);
738                    Ok(())
739                },
740            )?;
741            if parser.skip_token(Token::Comma).is_none() {
742                break;
743            }
744        }
745    }
746    parser.consume_token(Token::RParen)?;
747
748    let within_group = if let Some(within_span) = parser.skip_keyword(Keyword::WITHIN) {
749        let within_group_span = within_span.join_span(&parser.consume_keyword(Keyword::GROUP)?);
750        parser.consume_token(Token::LParen)?;
751        let order_span = parser.consume_keyword(Keyword::ORDER)?;
752        let order_by_span = order_span.join_span(&parser.consume_keyword(Keyword::BY)?);
753        let mut order = Vec::new();
754        loop {
755            let e = parse_expression_unreserved(parser, PRIORITY_MAX)?;
756            let f = match &parser.token {
757                Token::Ident(_, Keyword::ASC) => OrderFlag::Asc(parser.consume()),
758                Token::Ident(_, Keyword::DESC) => OrderFlag::Desc(parser.consume()),
759                _ => OrderFlag::None,
760            };
761            order.push((e, f));
762            if parser.skip_token(Token::Comma).is_none() {
763                break;
764            }
765        }
766        parser.consume_token(Token::RParen)?;
767        Some((within_group_span.join_span(&order_by_span), order))
768    } else {
769        None
770    };
771
772    let filter = if let Some(filter_span) = parser.skip_keyword(Keyword::FILTER) {
773        parser.postgres_only(&filter_span);
774        parser.consume_token(Token::LParen)?;
775        parser.consume_keyword(Keyword::WHERE)?;
776        let condition = parse_expression_unreserved(parser, PRIORITY_MAX)?;
777        parser.consume_token(Token::RParen)?;
778        Some((filter_span, condition))
779    } else {
780        None
781    };
782
783    let over = parse_over_clause(parser)?;
784
785    Ok(Expression::AggregateFunction(Box::new(
786        AggregateFunctionCallExpression {
787            function: func,
788            args,
789            function_span: span,
790            distinct_span,
791            within_group,
792            filter,
793            over,
794        },
795    )))
796}
797
798pub(crate) fn parse_function<'a>(
799    parser: &mut Parser<'a, '_>,
800    t: Token<'a>,
801    span: Span,
802) -> Result<Expression<'a>, ParseError> {
803    parser.consume_token(Token::LParen)?;
804
805    let func = match &t {
806        // https://mariadb.com/kb/en/string-functions/
807        Token::Ident(_, Keyword::ASCII) => Function::Ascii,
808        Token::Ident(_, Keyword::BIN) => Function::Bin,
809        Token::Ident(_, Keyword::BIT_LENGTH) => Function::BitLength,
810        Token::Ident(_, Keyword::CHAR_LENGTH) => Function::CharacterLength,
811        Token::Ident(_, Keyword::CHARACTER_LENGTH) => Function::CharacterLength,
812        Token::Ident(_, Keyword::CHR) => Function::Chr,
813        Token::Ident(_, Keyword::CONCAT) => Function::Concat,
814        Token::Ident(_, Keyword::CONCAT_WS) => Function::ConcatWs,
815        Token::Ident(_, Keyword::ELT) => Function::Elt,
816        Token::Ident(_, Keyword::EXPORT_SET) => Function::ExportSet,
817        Token::Ident(_, Keyword::EXTRACTVALUE) => Function::ExtractValue,
818        Token::Ident(_, Keyword::FIELD) => Function::Field,
819        Token::Ident(_, Keyword::FIND_IN_SET) => Function::FindInSet,
820        Token::Ident(_, Keyword::FORMAT) => Function::Format,
821        Token::Ident(_, Keyword::FROM_BASE64) => Function::FromBase64,
822        Token::Ident(_, Keyword::HEX) => Function::Hex,
823        Token::Ident(_, Keyword::INSERT) => Function::Insert,
824        Token::Ident(_, Keyword::INSTR) => Function::InStr,
825        Token::Ident(_, Keyword::LCASE) => Function::LCase,
826        Token::Ident(_, Keyword::LEFT) => Function::Left,
827        Token::Ident(_, Keyword::LENGTH) => Function::Length,
828        Token::Ident(_, Keyword::LENGTHB) => Function::LengthB,
829        Token::Ident(_, Keyword::LOAD_FILE) => Function::LoadFile,
830        Token::Ident(_, Keyword::LOCATE) => Function::Locate,
831        Token::Ident(_, Keyword::LOWER) => Function::Lower,
832        Token::Ident(_, Keyword::LPAD) => Function::LPad,
833        Token::Ident(_, Keyword::LTRIM) => Function::LTrim,
834        Token::Ident(_, Keyword::MAKE_SET) => Function::MakeSet,
835        Token::Ident(_, Keyword::MID) => Function::Mid,
836        Token::Ident(_, Keyword::NATURAL_SORT_KEY) => Function::NaturalSortkey,
837        Token::Ident(_, Keyword::OCTET_LENGTH) => Function::OctetLength,
838        Token::Ident(_, Keyword::ORD) => Function::Ord,
839        Token::Ident(_, Keyword::POSITION) => Function::Position,
840        Token::Ident(_, Keyword::QUOTE) => Function::Quote,
841        Token::Ident(_, Keyword::REPEAT) => Function::Repeat,
842        Token::Ident(_, Keyword::REPLACE) => Function::Replace,
843        Token::Ident(_, Keyword::REVERSE) => Function::Reverse,
844        Token::Ident(_, Keyword::RIGHT) => Function::Right,
845        Token::Ident(_, Keyword::RPAD) => Function::RPad,
846        Token::Ident(_, Keyword::RTRIM) => Function::RTrim,
847        Token::Ident(_, Keyword::SOUNDEX) => Function::SoundEx,
848        Token::Ident(_, Keyword::SLEEP) => Function::Sleep,
849        Token::Ident(_, Keyword::SPACE) => Function::Space,
850        Token::Ident(_, Keyword::STRCMP) => Function::StrCmp,
851        Token::Ident(_, Keyword::SUBSTR) => Function::SubStr,
852        Token::Ident(_, Keyword::SUBSTRING) => Function::SubStr,
853        Token::Ident(_, Keyword::SUBSTRING_INDEX) => Function::SubStringIndex,
854        Token::Ident(_, Keyword::TO_BASE64) => Function::ToBase64,
855        Token::Ident(_, Keyword::TO_CHAR) => Function::ToChar,
856        Token::Ident(_, Keyword::UCASE) => Function::UCase,
857        Token::Ident(_, Keyword::UNCOMPRESSED_LENGTH) => Function::UncompressedLength,
858        Token::Ident(_, Keyword::UNHEX) => Function::UnHex,
859        Token::Ident(_, Keyword::UPDATEXML) => Function::UpdateXml,
860        Token::Ident(_, Keyword::UPPER) => Function::Upper,
861        Token::Ident(_, Keyword::SFORMAT) => Function::SFormat,
862
863        // TODO uncat
864        Token::Ident(_, Keyword::EXISTS) => Function::Exists,
865        Token::Ident(_, Keyword::COUNT) => Function::Count,
866        Token::Ident(_, Keyword::AVG) => Function::Avg,
867        Token::Ident(_, Keyword::MIN) => Function::Min,
868        Token::Ident(_, Keyword::MAX) => Function::Max,
869        Token::Ident(_, Keyword::SUM) => Function::Sum,
870        Token::Ident(_, Keyword::VALUE) => Function::Value,
871        Token::Ident(_, Keyword::VALUES) => Function::Value,
872        Token::Ident(_, Keyword::LEAD) => Function::Lead,
873        Token::Ident(_, Keyword::LAG) => Function::Lag,
874        Token::Ident(_, Keyword::STARTS_WITH) => Function::StartsWith,
875
876        //https://mariadb.com/kb/en/control-flow-functions/
877        Token::Ident(_, Keyword::IFNULL) => Function::IfNull,
878        Token::Ident(_, Keyword::NULLIF) => Function::NullIf,
879        Token::Ident(_, Keyword::NVL) => Function::IfNull,
880        Token::Ident(_, Keyword::NVL2) => Function::NVL2,
881        Token::Ident(_, Keyword::IF) => Function::If,
882
883        //https://mariadb.com/kb/en/numeric-functions/
884        Token::Ident(_, Keyword::ABS) => Function::Abs,
885        Token::Ident(_, Keyword::ACOS) => Function::Acos,
886        Token::Ident(_, Keyword::ASIN) => Function::Asin,
887        Token::Ident(_, Keyword::ATAN) => Function::Atan,
888        Token::Ident(_, Keyword::ATAN2) => Function::Atan2,
889        Token::Ident(_, Keyword::CEIL | Keyword::CEILING) => Function::Ceil,
890        Token::Ident(_, Keyword::CONV) => Function::Conv,
891        Token::Ident(_, Keyword::COS) => Function::Cos,
892        Token::Ident(_, Keyword::COT) => Function::Cot,
893        Token::Ident(_, Keyword::CRC32) => Function::Crc32,
894        Token::Ident(_, Keyword::DEGREES) => Function::Degrees,
895        Token::Ident(_, Keyword::EXP) => Function::Exp,
896        Token::Ident(_, Keyword::FLOOR) => Function::Floor,
897        Token::Ident(_, Keyword::GREATEST) => Function::Greatest,
898        Token::Ident(_, Keyword::LN) => Function::Ln,
899        Token::Ident(_, Keyword::LOG) => Function::Log,
900        Token::Ident(_, Keyword::LOG10) => Function::Log10,
901        Token::Ident(_, Keyword::LOG2) => Function::Log2,
902        Token::Ident(_, Keyword::MOD) => Function::Mod,
903        Token::Ident(_, Keyword::OCT) => Function::Oct,
904        Token::Ident(_, Keyword::PI) => Function::Pi,
905        Token::Ident(_, Keyword::POW | Keyword::POWER) => Function::Pow,
906        Token::Ident(_, Keyword::RADIANS) => Function::Radians,
907        Token::Ident(_, Keyword::RAND) => Function::Rand,
908        Token::Ident(_, Keyword::ROUND) => Function::Round,
909        Token::Ident(_, Keyword::SIGN) => Function::Sign,
910        Token::Ident(_, Keyword::SIN) => Function::Sin,
911        Token::Ident(_, Keyword::SQRT) => Function::Sqrt,
912        Token::Ident(_, Keyword::TAN) => Function::Tan,
913        Token::Ident(_, Keyword::TRUNCATE) => Function::Truncate,
914        Token::Ident(_, Keyword::CRC32C) => Function::Crc32c,
915        Token::Ident(_, Keyword::LEAST) => Function::Least,
916
917        // https://mariadb.com/kb/en/date-time-functions/
918        Token::Ident(_, Keyword::ADDDATE) => Function::AddDate,
919        Token::Ident(_, Keyword::ADDTIME) => Function::AddTime,
920        Token::Ident(_, Keyword::CONVERT_TZ) => Function::ConvertTz,
921        Token::Ident(_, Keyword::CURDATE) => Function::CurDate,
922        Token::Ident(_, Keyword::CURRENT_DATE) => Function::CurDate,
923        Token::Ident(_, Keyword::CURRENT_TIME) => Function::CurTime,
924        Token::Ident(_, Keyword::CURTIME) => Function::CurTime,
925        Token::Ident(_, Keyword::DATE) => Function::Date,
926        Token::Ident(_, Keyword::HOUR) => Function::Hour,
927        Token::Ident(_, Keyword::DATEDIFF) => Function::DateDiff,
928        Token::Ident(_, Keyword::DATE_ADD) => Function::AddDate,
929        Token::Ident(_, Keyword::DATE_FORMAT) => Function::DateFormat,
930        Token::Ident(_, Keyword::DATE_SUB) => Function::DateSub,
931        Token::Ident(_, Keyword::DAY | Keyword::DAYOFMONTH) => Function::DayOfMonth,
932        Token::Ident(_, Keyword::DAYNAME) => Function::DayName,
933        Token::Ident(_, Keyword::DAYOFWEEK) => Function::DayOfWeek,
934        Token::Ident(_, Keyword::DAYOFYEAR) => Function::DayOfYear,
935        Token::Ident(_, Keyword::FROM_DAYS) => Function::FromDays,
936        Token::Ident(_, Keyword::CURRENT_TIMESTAMP) => Function::CurrentTimestamp,
937        Token::Ident(_, Keyword::LOCALTIME | Keyword::LOCALTIMESTAMP | Keyword::NOW) => {
938            Function::Now
939        }
940        Token::Ident(_, Keyword::MAKEDATE) => Function::MakeDate,
941        Token::Ident(_, Keyword::MAKETIME) => Function::MakeTime,
942        Token::Ident(_, Keyword::MICROSECOND) => Function::MicroSecond,
943        Token::Ident(_, Keyword::MINUTE) => Function::Minute,
944        Token::Ident(_, Keyword::MONTH) => Function::Month,
945        Token::Ident(_, Keyword::MONTHNAME) => Function::MonthName,
946        Token::Ident(_, Keyword::PERIOD_ADD) => Function::PeriodAdd,
947        Token::Ident(_, Keyword::PERIOD_DIFF) => Function::PeriodDiff,
948        Token::Ident(_, Keyword::QUARTER) => Function::Quarter,
949        Token::Ident(_, Keyword::SECOND) => Function::Second,
950        Token::Ident(_, Keyword::SEC_TO_TIME) => Function::SecToTime,
951        Token::Ident(_, Keyword::STR_TO_DATE) => Function::StrToDate,
952        Token::Ident(_, Keyword::SUBDATE) => Function::DateSub,
953        Token::Ident(_, Keyword::SUBTIME) => Function::SubTime,
954        Token::Ident(_, Keyword::TIME) => Function::Time,
955        Token::Ident(_, Keyword::LAST_DAY) => Function::LastDay,
956        Token::Ident(_, Keyword::TIMEDIFF) => Function::TimeDiff,
957        Token::Ident(_, Keyword::TIMESTAMP) => Function::Timestamp,
958        Token::Ident(_, Keyword::TIME_FORMAT) => Function::TimeFormat,
959        Token::Ident(_, Keyword::TIME_TO_SEC) => Function::TimeToSec,
960        Token::Ident(_, Keyword::TO_DAYS) => Function::ToDays,
961        Token::Ident(_, Keyword::TO_SECONDS) => Function::ToSeconds,
962        Token::Ident(_, Keyword::UNIX_TIMESTAMP) => Function::UnixTimestamp,
963        Token::Ident(_, Keyword::UTC_DATE) => Function::UtcDate,
964        Token::Ident(_, Keyword::UTC_TIME) => Function::UtcTime,
965        Token::Ident(_, Keyword::UTC_TIMESTAMP) => Function::UtcTimeStamp,
966        Token::Ident(_, Keyword::WEEK) => Function::Week,
967        Token::Ident(_, Keyword::WEEKDAY) => Function::Weekday,
968        Token::Ident(_, Keyword::WEEKOFYEAR) => Function::WeekOfYear,
969        Token::Ident(_, Keyword::ADD_MONTHS) => Function::AddMonths,
970        Token::Ident(_, Keyword::FROM_UNIXTIME) => Function::FromUnixTime,
971        Token::Ident(_, Keyword::YEAR) => Function::Year,
972        Token::Ident(_, Keyword::YEARWEEK) => Function::YearWeek,
973        Token::Ident(_, Keyword::SYSDATE) => Function::SysDate,
974
975        // https://mariadb.com/kb/en/json-functions/
976        Token::Ident(_, Keyword::JSON_ARRAY) => Function::JsonArray,
977        Token::Ident(_, Keyword::JSON_ARRAYAGG) => Function::JsonArrayAgg,
978        Token::Ident(_, Keyword::JSON_ARRAY_APPEND) => Function::JsonArrayAppend,
979        Token::Ident(_, Keyword::JSON_ARRAY_INSERT) => Function::JsonArrayInsert,
980        Token::Ident(_, Keyword::JSON_ARRAY_INTERSECT) => Function::JsonArrayIntersect,
981        Token::Ident(_, Keyword::JSON_COMPACT) => Function::JsonCompact,
982        Token::Ident(_, Keyword::JSON_CONTAINS) => Function::JsonContains,
983        Token::Ident(_, Keyword::JSON_CONTAINS_PATH) => Function::JsonContainsPath,
984        Token::Ident(_, Keyword::JSON_DEPTH) => Function::JsonDepth,
985        Token::Ident(_, Keyword::JSON_DETAILED) => Function::JsonDetailed,
986        Token::Ident(_, Keyword::JSON_EQUALS) => Function::JsonEquals,
987        Token::Ident(_, Keyword::JSON_EXISTS) => Function::JsonExists,
988        Token::Ident(_, Keyword::JSON_EXTRACT) => Function::JsonExtract,
989        Token::Ident(_, Keyword::JSON_INSERT) => Function::JsonInsert,
990        Token::Ident(_, Keyword::JSON_KEYS) => Function::JsonKeys,
991        Token::Ident(_, Keyword::JSON_LENGTH) => Function::JsonLength,
992        Token::Ident(_, Keyword::JSON_LOOSE) => Function::JsonLoose,
993        Token::Ident(_, Keyword::JSON_MERGE) => Function::JsonMerge,
994        Token::Ident(_, Keyword::JSON_MERGE_PATCH) => Function::JsonMergePath,
995        Token::Ident(_, Keyword::JSON_MERGE_PRESERVE) => Function::JsonMergePerserve,
996        Token::Ident(_, Keyword::JSON_NORMALIZE) => Function::JsonNormalize,
997        Token::Ident(_, Keyword::JSON_OBJECT) => Function::JsonObject,
998        Token::Ident(_, Keyword::JSON_OBJECT_FILTER_KEYS) => Function::JsonObjectFilterKeys,
999        Token::Ident(_, Keyword::JSON_OBJECT_TO_ARRAY) => Function::JsonObjectToArray,
1000        Token::Ident(_, Keyword::JSON_OBJECTAGG) => Function::JsonObjectAgg,
1001        Token::Ident(_, Keyword::JSON_OVERLAPS) => Function::JsonOverlaps,
1002        Token::Ident(_, Keyword::JSON_PRETTY) => Function::JsonPretty,
1003        Token::Ident(_, Keyword::JSON_QUERY) => Function::JsonQuery,
1004        Token::Ident(_, Keyword::JSON_QUOTE) => Function::JsonQuote,
1005        Token::Ident(_, Keyword::JSON_REMOVE) => Function::JsonRemove,
1006        Token::Ident(_, Keyword::JSON_REPLACE) => Function::JsonReplace,
1007        Token::Ident(_, Keyword::JSON_SCHEMA_VALID) => Function::JsonSchemaValid,
1008        Token::Ident(_, Keyword::JSON_SEARCH) => Function::JsonSearch,
1009        Token::Ident(_, Keyword::JSON_SET) => Function::JsonSet,
1010        Token::Ident(_, Keyword::JSON_TABLE) => Function::JsonTable,
1011        Token::Ident(_, Keyword::JSON_TYPE) => Function::JsonType,
1012        Token::Ident(_, Keyword::JSON_UNQUOTE) => Function::JsonUnquote,
1013        Token::Ident(_, Keyword::JSON_VALID) => Function::JsonValid,
1014        Token::Ident(_, Keyword::JSON_VALUE) => Function::JsonValue,
1015
1016        // Sqlite
1017        Token::Ident(_, Keyword::STRFTIME) => Function::Strftime,
1018        Token::Ident(_, Keyword::DATETIME) => Function::Datetime,
1019
1020        // MySQL 8.4 encryption / compression
1021        Token::Ident(_, Keyword::AES_DECRYPT) => Function::AesDecrypt,
1022        Token::Ident(_, Keyword::AES_ENCRYPT) => Function::AesEncrypt,
1023        Token::Ident(_, Keyword::COMPRESS) => Function::Compress,
1024        Token::Ident(_, Keyword::MD5) => Function::Md5,
1025        Token::Ident(_, Keyword::RANDOM_BYTES) => Function::RandomBytes,
1026        Token::Ident(_, Keyword::SHA) => Function::Sha,
1027        Token::Ident(_, Keyword::SHA1) => Function::Sha1,
1028        Token::Ident(_, Keyword::SHA2) => Function::Sha2,
1029        Token::Ident(_, Keyword::STATEMENT_DIGEST) => Function::StatementDigest,
1030        Token::Ident(_, Keyword::STATEMENT_DIGEST_TEXT) => Function::StatementDigestText,
1031        Token::Ident(_, Keyword::UNCOMPRESS) => Function::Uncompress,
1032        Token::Ident(_, Keyword::VALIDATE_PASSWORD_STRENGTH) => Function::ValidatePasswordStrength,
1033
1034        // MySQL 8.4 locking
1035        Token::Ident(_, Keyword::GET_LOCK) => Function::GetLock,
1036        Token::Ident(_, Keyword::IS_FREE_LOCK) => Function::IsFreeLock,
1037        Token::Ident(_, Keyword::IS_USED_LOCK) => Function::IsUsedLock,
1038        Token::Ident(_, Keyword::RELEASE_ALL_LOCKS) => Function::ReleaseAllLocks,
1039        Token::Ident(_, Keyword::RELEASE_LOCK) => Function::ReleaseLock,
1040
1041        // MySQL 8.4 information
1042        Token::Ident(_, Keyword::BENCHMARK) => Function::Benchmark,
1043        Token::Ident(_, Keyword::CHARSET) => Function::Charset,
1044        Token::Ident(_, Keyword::COERCIBILITY) => Function::Coercibility,
1045        Token::Ident(_, Keyword::COLLATION) => Function::Collation,
1046        Token::Ident(_, Keyword::CONNECTION_ID) => Function::ConnectionId,
1047        Token::Ident(_, Keyword::CURRENT_ROLE) => Function::CurrentRole,
1048        Token::Ident(_, Keyword::CURRENT_USER) => Function::CurrentUser,
1049        Token::Ident(_, Keyword::DATABASE) => Function::DatabaseFunc,
1050        Token::Ident(_, Keyword::FOUND_ROWS) => Function::FoundRows,
1051        Token::Ident(_, Keyword::ICU_VERSION) => Function::IcuVersion,
1052        Token::Ident(_, Keyword::LAST_INSERT_ID) => Function::LastInsertId,
1053        Token::Ident(_, Keyword::ROLES_GRAPHML) => Function::RolesGraphml,
1054        Token::Ident(_, Keyword::ROW_COUNT) => Function::RowCount,
1055        Token::Ident(_, Keyword::SCHEMA) => Function::SchemaFunc,
1056        Token::Ident(_, Keyword::SESSION_USER) => Function::SessionUserFunc,
1057        Token::Ident(_, Keyword::SYSTEM_USER) => Function::SystemUser,
1058        Token::Ident(_, Keyword::USER) => Function::UserFunc,
1059        Token::Ident(_, Keyword::VERSION) => Function::Version,
1060
1061        // MySQL 8.4 regexp
1062        Token::Ident(_, Keyword::REGEXP_INSTR) => Function::RegexpInstr,
1063        Token::Ident(_, Keyword::REGEXP_LIKE) => Function::RegexpLike,
1064        Token::Ident(_, Keyword::REGEXP_REPLACE) => Function::RegexpReplace,
1065        Token::Ident(_, Keyword::REGEXP_SUBSTR) => Function::RegexpSubstr,
1066        Token::Ident(_, Keyword::WEIGHT_STRING) => Function::WeightString,
1067
1068        // MySQL 8.4 datetime
1069        Token::Ident(_, Keyword::GET_FORMAT) => Function::GetFormat,
1070
1071        // MySQL 8.4 window / analytics
1072        Token::Ident(_, Keyword::FIRST_VALUE) => Function::FirstValue,
1073        Token::Ident(_, Keyword::LAST_VALUE) => Function::LastValue,
1074        Token::Ident(_, Keyword::NTH_VALUE) => Function::NthValue,
1075        Token::Ident(_, Keyword::NTILE) => Function::Ntile,
1076        Token::Ident(_, Keyword::ROW_NUMBER) => Function::RowNumber,
1077
1078        // MySQL 8.4 performance schema
1079        Token::Ident(_, Keyword::FORMAT_BYTES) => Function::FormatBytes,
1080        Token::Ident(_, Keyword::FORMAT_PICO_TIME) => Function::FormatPicoTime,
1081        Token::Ident(_, Keyword::PS_CURRENT_THREAD_ID) => Function::PsCurrentThreadId,
1082        Token::Ident(_, Keyword::PS_THREAD_ID) => Function::PsThreadId,
1083
1084        // MySQL 8.4 miscellaneous
1085        Token::Ident(_, Keyword::ANY_VALUE) => Function::AnyValue,
1086        Token::Ident(_, Keyword::BIN_TO_UUID) => Function::BinToUuid,
1087        Token::Ident(_, Keyword::BIT_COUNT) => Function::BitCount,
1088        Token::Ident(_, Keyword::GROUPING) => Function::Grouping,
1089        Token::Ident(_, Keyword::INET6_ATON) => Function::Inet6Aton,
1090        Token::Ident(_, Keyword::INET6_NTOA) => Function::Inet6Ntoa,
1091        Token::Ident(_, Keyword::INET_ATON) => Function::InetAton,
1092        Token::Ident(_, Keyword::INET_NTOA) => Function::InetNtoa,
1093        Token::Ident(_, Keyword::IS_IPV4) => Function::IsIPv4,
1094        Token::Ident(_, Keyword::IS_IPV4_COMPAT) => Function::IsIPv4Compat,
1095        Token::Ident(_, Keyword::IS_IPV4_MAPPED) => Function::IsIPv4Mapped,
1096        Token::Ident(_, Keyword::IS_IPV6) => Function::IsIPv6,
1097        Token::Ident(_, Keyword::IS_UUID) => Function::IsUuid,
1098        Token::Ident(_, Keyword::NAME_CONST) => Function::NameConst,
1099        Token::Ident(_, Keyword::UUID) => Function::Uuid,
1100        Token::Ident(_, Keyword::UUID_SHORT) => Function::UuidShort,
1101        Token::Ident(_, Keyword::UUID_TO_BIN) => Function::UuidToBin,
1102
1103        Token::Ident(v, k) if !k.restricted(parser.reserved()) => {
1104            Function::Other(alloc::vec![Identifier {
1105                value: v,
1106                span: span.clone()
1107            }])
1108        }
1109        _ => {
1110            parser.err("Unknown function", &span);
1111            Function::Unknown
1112        }
1113    };
1114
1115    let mut args = Vec::new();
1116
1117    // SQL-standard SUBSTRING(str FROM pos [FOR len]) — PostgreSQL and ANSI SQL.
1118    if matches!(func, Function::SubStr) && !matches!(parser.token, Token::RParen) {
1119        let expr = parse_expression_outer(parser)?;
1120        if let Some(_from) = parser.skip_keyword(Keyword::FROM) {
1121            let pos = parse_expression_outer(parser)?;
1122            args.push(expr);
1123            args.push(pos);
1124            if parser.skip_keyword(Keyword::FOR).is_some() {
1125                args.push(parse_expression_outer(parser)?);
1126            }
1127            parser.consume_token(Token::RParen)?;
1128            return Ok(Expression::Function(Box::new(FunctionCallExpression {
1129                function: func,
1130                args,
1131                function_span: span,
1132            })));
1133        } else {
1134            // Comma-style: push first arg and continue normally
1135            args.push(expr);
1136            while parser.skip_token(Token::Comma).is_some() {
1137                parser.recovered(
1138                    "')' or ','",
1139                    &|t| matches!(t, Token::RParen | Token::Comma),
1140                    |parser| {
1141                        args.push(parse_expression_outer(parser)?);
1142                        Ok(())
1143                    },
1144                )?;
1145            }
1146            parser.consume_token(Token::RParen)?;
1147            if let Some(over) = parse_over_clause(parser)? {
1148                return Ok(Expression::WindowFunction(Box::new(
1149                    WindowFunctionCallExpression {
1150                        function: func,
1151                        args,
1152                        function_span: span,
1153                        over,
1154                    },
1155                )));
1156            }
1157            return Ok(Expression::Function(Box::new(FunctionCallExpression {
1158                function: func,
1159                args,
1160                function_span: span,
1161            })));
1162        }
1163    }
1164
1165    if !matches!(parser.token, Token::RParen) {
1166        loop {
1167            parser.recovered(
1168                "')' or ','",
1169                &|t| matches!(t, Token::RParen | Token::Comma),
1170                |parser| {
1171                    args.push(parse_expression_outer(parser)?);
1172                    Ok(())
1173                },
1174            )?;
1175            if parser.skip_token(Token::Comma).is_none() {
1176                break;
1177            }
1178        }
1179    }
1180    parser.consume_token(Token::RParen)?;
1181
1182    if let Some(over) = parse_over_clause(parser)? {
1183        Ok(Expression::WindowFunction(Box::new(
1184            WindowFunctionCallExpression {
1185                function: func,
1186                args,
1187                function_span: span,
1188                over,
1189            },
1190        )))
1191    } else {
1192        Ok(Expression::Function(Box::new(FunctionCallExpression {
1193            function: func,
1194            args,
1195            function_span: span,
1196        })))
1197    }
1198}
1199
1200/// Parse the argument list and optional OVER clause for a schema-qualified function call.
1201/// The caller has already resolved `func = Function::Other(qualified_parts)` and
1202/// computed `function_span` covering the full qualified name.
1203pub(crate) fn parse_char_function<'a>(
1204    parser: &mut Parser<'a, '_>,
1205    char_span: Span,
1206) -> Result<Expression<'a>, ParseError> {
1207    parser.consume_token(Token::LParen)?;
1208    let mut args = Vec::new();
1209    if !matches!(parser.token, Token::RParen) {
1210        loop {
1211            parser.recovered(
1212                "')' or ','",
1213                &|t| {
1214                    matches!(
1215                        t,
1216                        Token::RParen | Token::Comma | Token::Ident(_, Keyword::USING)
1217                    )
1218                },
1219                |parser| {
1220                    args.push(parse_expression_outer(parser)?);
1221                    Ok(())
1222                },
1223            )?;
1224            if parser.skip_token(Token::Comma).is_none() {
1225                break;
1226            }
1227        }
1228    }
1229    // Optional USING charset_name
1230    let using_charset = if let Some(using_span) = parser.skip_keyword(Keyword::USING) {
1231        let charset = parser.consume_plain_identifier_unreserved()?;
1232        Some((using_span, charset))
1233    } else {
1234        None
1235    };
1236    parser.consume_token(Token::RParen)?;
1237    Ok(Expression::Char(Box::new(CharFunctionExpression {
1238        char_span,
1239        args,
1240        using_charset,
1241    })))
1242}
1243
1244pub(crate) fn parse_function_call<'a>(
1245    parser: &mut Parser<'a, '_>,
1246    func: Function<'a>,
1247    function_span: Span,
1248) -> Result<Expression<'a>, ParseError> {
1249    parser.consume_token(Token::LParen)?;
1250    let mut args = Vec::new();
1251    if !matches!(parser.token, Token::RParen) {
1252        loop {
1253            parser.recovered(
1254                "')' or ','",
1255                &|t| matches!(t, Token::RParen | Token::Comma),
1256                |parser| {
1257                    args.push(parse_expression_outer(parser)?);
1258                    Ok(())
1259                },
1260            )?;
1261            if parser.skip_token(Token::Comma).is_none() {
1262                break;
1263            }
1264        }
1265    }
1266    parser.consume_token(Token::RParen)?;
1267    if let Some(over) = parse_over_clause(parser)? {
1268        Ok(Expression::WindowFunction(Box::new(
1269            WindowFunctionCallExpression {
1270                function: func,
1271                args,
1272                function_span,
1273                over,
1274            },
1275        )))
1276    } else {
1277        Ok(Expression::Function(Box::new(FunctionCallExpression {
1278            function: func,
1279            args,
1280            function_span,
1281        })))
1282    }
1283}
1284
1285#[cfg(test)]
1286mod tests {
1287    use core::ops::Deref;
1288
1289    use alloc::string::{String, ToString};
1290
1291    use crate::{
1292        Function, FunctionCallExpression, ParseOptions, SQLDialect,
1293        expression::{Expression, PRIORITY_MAX},
1294        issue::Issues,
1295        parser::Parser,
1296    };
1297
1298    use super::parse_expression_unreserved;
1299
1300    fn test_expr(src: &'static str, f: impl FnOnce(&Expression<'_>) -> Result<(), String>) {
1301        let mut issues = Issues::new(src);
1302        let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
1303        let mut parser = Parser::new(src, &mut issues, &options);
1304        let res = parse_expression_unreserved(&mut parser, PRIORITY_MAX)
1305            .expect("Expression in test expr");
1306        if let Err(e) = f(&res) {
1307            panic!("Error parsing {}: {}\nGot {:#?}", src, e, res);
1308        }
1309    }
1310
1311    #[test]
1312    fn mariadb_datetime_functions() {
1313        fn test_func(src: &'static str, f: Function, cnt: usize) {
1314            let mut issues = Issues::new(src);
1315            let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
1316            let mut parser = Parser::new(src, &mut issues, &options);
1317            let res = match parse_expression_unreserved(&mut parser, PRIORITY_MAX) {
1318                Ok(res) => res,
1319                Err(e) => panic!("Unable to parse {}: {:?}", src, e),
1320            };
1321            let Expression::Function(r) = res else {
1322                panic!("Should be parsed as function {}", src);
1323            };
1324            let FunctionCallExpression {
1325                function: pf, args, ..
1326            } = r.deref();
1327            assert_eq!(pf, &f, "Failure en expr {}", src);
1328            assert_eq!(args.len(), cnt, "Failure en expr {}", src);
1329        }
1330        test_func("ADD_MONTHS('2012-01-31', 2)", Function::AddMonths, 2);
1331        test_func(
1332            "ADDTIME('2007-12-31 23:59:59.999999', '1 1:1:1.000002')",
1333            Function::AddTime,
1334            2,
1335        );
1336        test_func(
1337            "DATE_ADD('2008-01-02', INTERVAL 31 DAY)",
1338            Function::AddDate,
1339            2,
1340        );
1341        test_func(
1342            "ADDDATE('2008-01-02', INTERVAL 31 DAY)",
1343            Function::AddDate,
1344            2,
1345        );
1346        test_func("ADDDATE('2008-01-02', 31)", Function::AddDate, 2);
1347        test_func(
1348            "CONVERT_TZ('2016-01-01 12:00:00','+00:00','+10:00')",
1349            Function::ConvertTz,
1350            3,
1351        );
1352        test_func("CURDATE()", Function::CurDate, 0);
1353        test_func("CURRENT_DATE", Function::CurDate, 0);
1354        test_func("CURRENT_DATE()", Function::CurDate, 0);
1355        test_func("CURRENT_TIME", Function::CurTime, 0);
1356        test_func("CURRENT_TIME()", Function::CurTime, 0);
1357        test_func("CURTIME()", Function::CurTime, 0);
1358        test_func("CURTIME(2)", Function::CurTime, 1);
1359        test_func("CURRENT_DATE", Function::CurDate, 0);
1360        test_func("CURRENT_DATE()", Function::CurDate, 0);
1361        test_func("CURDATE()", Function::CurDate, 0);
1362        test_func("CURRENT_TIMESTAMP", Function::CurrentTimestamp, 0);
1363        test_func("CURRENT_TIMESTAMP()", Function::CurrentTimestamp, 0);
1364        test_func("CURRENT_TIMESTAMP(10)", Function::CurrentTimestamp, 1);
1365        test_func("LOCALTIME", Function::Now, 0);
1366        test_func("LOCALTIME()", Function::Now, 0);
1367        test_func("LOCALTIME(10)", Function::Now, 1);
1368        test_func("LOCALTIMESTAMP", Function::Now, 0);
1369        test_func("LOCALTIMESTAMP()", Function::Now, 0);
1370        test_func("LOCALTIMESTAMP(10)", Function::Now, 1);
1371        test_func("DATE('2013-07-18 12:21:32')", Function::Date, 1);
1372        test_func(
1373            "DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y')",
1374            Function::DateFormat,
1375            2,
1376        );
1377        test_func(
1378            "DATE_SUB('1998-01-02', INTERVAL 31 DAY)",
1379            Function::DateSub,
1380            2,
1381        );
1382        test_func("DAY('2007-02-03')", Function::DayOfMonth, 1);
1383        test_func("DAYOFMONTH('2007-02-03')", Function::DayOfMonth, 1);
1384        test_func(
1385            "DATEDIFF('2007-12-31 23:59:59','2007-12-30')",
1386            Function::DateDiff,
1387            2,
1388        );
1389        test_func("DAYNAME('2007-02-03')", Function::DayName, 1);
1390        test_func("DAYOFYEAR('2018-02-16')", Function::DayOfYear, 1);
1391        test_func("DAYOFWEEK('2007-02-03')", Function::DayOfWeek, 1);
1392        test_expr("EXTRACT(YEAR_MONTH FROM '2009-07-02 01:02:03')", |e| {
1393            let Expression::Extract { .. } = e else {
1394                return Err("Wrong type".to_string());
1395            };
1396            Ok(())
1397        });
1398        //test_func("FORMAT_PICO_TIME(4321123443212345) AS h", Function::DayOfWeek, 1);
1399        test_func("FROM_DAYS(730669)", Function::FromDays, 1);
1400        test_func("FROM_UNIXTIME(1196440219)", Function::FromUnixTime, 1);
1401        test_func(
1402            "FROM_UNIXTIME(UNIX_TIMESTAMP(), '%Y %D %M %h:%i:%s %x')",
1403            Function::FromUnixTime,
1404            2,
1405        );
1406        //test_func("GET_FORMAT(DATE, 'EUR')", Function::GetFormat, 2);
1407        test_func("HOUR('10:05:03')", Function::Hour, 1);
1408        test_func("LAST_DAY('2004-01-01 01:01:01')", Function::LastDay, 1);
1409        test_func("MAKEDATE(2011,31)", Function::MakeDate, 2);
1410        test_func("MAKETIME(-13,57,33)", Function::MakeTime, 3);
1411        test_func("MICROSECOND('12:00:00.123456')", Function::MicroSecond, 1);
1412        test_func("MINUTE('2013-08-03 11:04:03')", Function::Minute, 1);
1413        test_func("MONTH('2019-01-03')", Function::Month, 1);
1414        test_func("MONTHNAME('2019-02-03')", Function::MonthName, 1);
1415        test_func("PERIOD_ADD(200801,2)", Function::PeriodAdd, 2);
1416        test_func("PERIOD_DIFF(200802,200703)", Function::PeriodDiff, 2);
1417        test_func("QUARTER('2008-04-01')", Function::Quarter, 1);
1418        test_func("SEC_TO_TIME(12414)", Function::SecToTime, 1);
1419        test_func("SECOND('10:05:03')", Function::Second, 1);
1420        test_func(
1421            "STR_TO_DATE('Wednesday, June 2, 2014', '%W, %M %e, %Y')",
1422            Function::StrToDate,
1423            2,
1424        );
1425        test_func(
1426            "DATE_SUB('2008-01-02', INTERVAL 31 DAY)",
1427            Function::DateSub,
1428            2,
1429        );
1430        test_func("SUBDATE('2008-01-02 12:00:00', 31)", Function::DateSub, 2);
1431        test_func(
1432            "SUBDATE('2008-01-02', INTERVAL 31 DAY)",
1433            Function::DateSub,
1434            2,
1435        );
1436        test_func(
1437            "SUBTIME('2007-12-31 23:59:59.999999','1 1:1:1.000002')",
1438            Function::SubTime,
1439            2,
1440        );
1441        test_func("SYSDATE()", Function::SysDate, 0);
1442        test_func("SYSDATE(4)", Function::SysDate, 1);
1443        test_func("TIME('2003-12-31 01:02:03')", Function::Time, 1);
1444        test_func(
1445            "TIME_FORMAT('100:00:00', '%H %k %h %I %l')",
1446            Function::TimeFormat,
1447            2,
1448        );
1449        test_func("TIME_TO_SEC('22:23:00')", Function::TimeToSec, 1);
1450        test_func(
1451            "TIMEDIFF('2008-12-31 23:59:59.000001', '2008-12-30 01:01:01.000002')",
1452            Function::TimeDiff,
1453            2,
1454        );
1455        test_func("TIMESTAMP('2003-12-31')", Function::Timestamp, 1);
1456        test_func(
1457            "TIMESTAMP('2003-12-31 12:00:00','6:30:00')",
1458            Function::Timestamp,
1459            2,
1460        );
1461        test_expr("TIMESTAMPADD(MINUTE,1,'2003-01-02')", |e| {
1462            let Expression::TimestampAdd { .. } = e else {
1463                return Err("Wrong type".to_string());
1464            };
1465            Ok(())
1466        });
1467        test_expr("TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01');", |e| {
1468            let Expression::TimestampDiff { .. } = e else {
1469                return Err("Wrong type".to_string());
1470            };
1471            Ok(())
1472        });
1473        test_func("TO_DAYS('2007-10-07')", Function::ToDays, 1);
1474        test_func("UNIX_TIMESTAMP()", Function::UnixTimestamp, 0);
1475        test_func(
1476            "UNIX_TIMESTAMP('2007-11-30 10:30:19')",
1477            Function::UnixTimestamp,
1478            1,
1479        );
1480        test_func("UTC_DATE", Function::UtcDate, 0);
1481        test_func("UTC_DATE()", Function::UtcDate, 0);
1482        test_func("UTC_TIME", Function::UtcTime, 0);
1483        test_func("UTC_TIME()", Function::UtcTime, 0);
1484        test_func("UTC_TIME(5)", Function::UtcTime, 1);
1485        test_func("UTC_TIMESTAMP", Function::UtcTimeStamp, 0);
1486        test_func("UTC_TIMESTAMP()", Function::UtcTimeStamp, 0);
1487        test_func("UTC_TIMESTAMP(4)", Function::UtcTimeStamp, 1);
1488        test_func("WEEK('2008-02-20')", Function::Week, 1);
1489        test_func("WEEK('2008-02-20',0)", Function::Week, 2);
1490        test_func("WEEKDAY('2008-02-03 22:23:00')", Function::Weekday, 1);
1491        test_func("WEEKOFYEAR('2008-02-20')", Function::WeekOfYear, 1);
1492        test_func("YEAR('1987-01-01')", Function::Year, 1);
1493        test_func("YEARWEEK('1987-01-01')", Function::YearWeek, 1);
1494        test_func("YEARWEEK('1987-01-01',0)", Function::YearWeek, 2);
1495    }
1496}