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    Acosd,
29    Acosh,
30    AddDate,
31    AddMonths,
32    AddTime,
33    Area,
34    Abbrev,
35    Ascii,
36    Btrim,
37    Asin,
38    Asind,
39    Asinh,
40    Atan,
41    Atan2,
42    Atan2d,
43    Atand,
44    Atanh,
45    Bin,
46    BitLength,
47    Broadcast,
48    Casefold,
49    Cbrt,
50    Ceil,
51    Center,
52    Char,
53    CharacterLength,
54    Chr,
55    Concat,
56    ConcatWs,
57    Conv,
58    ConvertTz,
59    Cos,
60    Cosd,
61    Cosh,
62    Cot,
63    Cotd,
64    Crc32,
65    Crc32c,
66    CurrentCatalog,
67    CurrentRole,
68    CurrentUser,
69    CurDate,
70    CurrentTimestamp,
71    CurTime,
72    SessionUser,
73    Date,
74    DateDiff,
75    DateFormat,
76    DateSub,
77    Datetime,
78    DayName,
79    DayOfMonth,
80    DayOfWeek,
81    DayOfYear,
82    Degrees,
83    Diagonal,
84    Diameter,
85    Elt,
86    Exists,
87    Erf,
88    Erfc,
89    Exp,
90    EnumFirst,
91    EnumLast,
92    EnumRange,
93    ExportSet,
94    ExtractValue,
95    Family,
96    Field,
97    Factorial,
98    FindInSet,
99    Floor,
100    Format,
101    FromBase64,
102    FromDays,
103    FromUnixTime,
104    Gamma,
105    Gcd,
106    Greatest,
107    Hex,
108    Height,
109    Host,
110    Hour,
111    If,
112    IfNull,
113    Initcap,
114    Insert,
115    InStr,
116    JsonArray,
117    JsonArrayAgg,
118    JsonArrayAppend,
119    JsonArrayInsert,
120    JsonArrayIntersect,
121    JsonCompact,
122    JsonContains,
123    JsonContainsPath,
124    JsonDepth,
125    JsonDetailed,
126    JsonEquals,
127    JsonExists,
128    JsonExtract,
129    JsonInsert,
130    JsonKeys,
131    JsonLength,
132    JsonLoose,
133    JsonMerge,
134    JsonMergePath,
135    JsonMergePerserve,
136    JsonNormalize,
137    JsonObject,
138    JsonObjectAgg,
139    JsonObjectFilterKeys,
140    JsonObjectToArray,
141    JsonOverlaps,
142    JsonPretty,
143    JsonQuery,
144    JsonQuote,
145    JsonRemove,
146    JsonReplace,
147    JsonSchemaValid,
148    JsonSearch,
149    JsonSet,
150    JsonTable,
151    JsonType,
152    JsonUnquote,
153    JsonValid,
154    JsonValue,
155    Lag,
156    LastDay,
157    Avg,
158    Count,
159    LCase,
160    Lead,
161    Lcm,
162    Least,
163    Left,
164    Length,
165    LengthB,
166    Lgamma,
167    Ln,
168    LoadFile,
169    Locate,
170    Log,
171    Log10,
172    Log2,
173    Lower,
174    LPad,
175    LTrim,
176    MakeDate,
177    MakeSet,
178    MakeTime,
179    Max,
180    MicroSecond,
181    Mid,
182    Min,
183    Minute,
184    MinScale,
185    Mod,
186    Month,
187    MonthName,
188    Normalize,
189    NaturalSortkey,
190    Now,
191    NullIf,
192    NVL2,
193    Npoints,
194    Oct,
195    OctetLength,
196    Ord,
197    ParseIdent,
198    Pclose,
199    PeriodAdd,
200    PeriodDiff,
201    PgClientEncoding,
202    Pi,
203    Popen,
204    Position,
205    Pow,
206    Quarter,
207    Quote,
208    QuoteIdent,
209    QuoteLiteral,
210    QuoteNullable,
211    Radians,
212    Radius,
213    Rand,
214    RandomNormal,
215    Repeat,
216    Replace,
217    Reverse,
218    Right,
219    Round,
220    RPad,
221    RTrim,
222    Scale,
223    Second,
224    SecToTime,
225    SFormat,
226    SetBit,
227    SetSeed,
228    Sign,
229    Sin,
230    Sind,
231    Sinh,
232    Sleep,
233    Slope,
234    SoundEx,
235    Space,
236    SplitPart,
237    Sqrt,
238    StartsWith,
239    StrCmp,
240    Strpos,
241    Strftime,
242    StrToDate,
243    SubStr,
244    SubStringIndex,
245    SubTime,
246    Sum,
247    SysDate,
248    Tan,
249    Tand,
250    Tanh,
251    Time,
252    TimeDiff,
253    TimeFormat,
254    Timestamp,
255    TimeToSec,
256    ToAscii,
257    ToBase64,
258    ToBin,
259    ToChar,
260    ToDate,
261    ToDays,
262    ToHex,
263    ToNumber,
264    ToOct,
265    ToSeconds,
266    ToTimestamp,
267    Translate,
268    TrimScale,
269    Truncate,
270    UCase,
271    UncompressedLength,
272    UnHex,
273    UnixTimestamp,
274    Unknown,
275    UpdateXml,
276    Upper,
277    UnicodeAssigned,
278    Unistr,
279    UtcDate,
280    UtcTime,
281    UtcTimeStamp,
282    Value,
283    Week,
284    Weekday,
285    WeekOfYear,
286    Width,
287    WidthBucket,
288    Year,
289    YearWeek,
290    // MySQL 8.4 explicit functions
291    AesDecrypt,
292    AesEncrypt,
293    AnyValue,
294    Benchmark,
295    BinToUuid,
296    BitCount,
297    Charset,
298    Coercibility,
299    Collation,
300    Compress,
301    ConnectionId,
302    DatabaseFunc,
303    FirstValue,
304    FormatBytes,
305    FormatPicoTime,
306    FoundRows,
307    GetBit,
308    GetFormat,
309    GetLock,
310    Grouping,
311    IcuVersion,
312    Inet6Aton,
313    Inet6Ntoa,
314    InetAton,
315    InetNtoa,
316    IsFreeLock,
317    IsIPv4,
318    IsIPv4Compat,
319    IsIPv4Mapped,
320    IsIPv6,
321    InetMerge,
322    InetSameFamily,
323    Macaddr8Set7bit,
324    MaskLen,
325    NetMask,
326    Network,
327    SetMaskLen,
328    IsUsedLock,
329    IsUuid,
330    LastInsertId,
331    LastValue,
332    Md5,
333    NameConst,
334    NthValue,
335    Ntile,
336    PsCurrentThreadId,
337    PsThreadId,
338    RandomBytes,
339    RegexpCount,
340    RegexpInstr,
341    RegexpLike,
342    RegexpMatch,
343    RegexpMatches,
344    RegexpReplace,
345    RegexpSplitToArray,
346    RegexpSplitToTable,
347    RegexpSubstr,
348    ReleaseAllLocks,
349    ReleaseLock,
350    RolesGraphml,
351    RowCount,
352    RowNumber,
353    SchemaFunc,
354    SessionUserFunc,
355    Sha,
356    Sha1,
357    Sha2,
358    StatementDigest,
359    StatementDigestText,
360    SystemUser,
361    Uncompress,
362    UserFunc,
363    Uuid,
364    UuidShort,
365    UuidToBin,
366    ValidatePasswordStrength,
367    Version,
368    WeightString,
369    // PostgreSQL system functions
370    InetServerAddr,
371    InetServerPort,
372    HostMask,
373    PgPostmasterStartTime,
374    PostgisFullVersion,
375    // PostgreSQL system information functions (9.27)
376    ColDescription,
377    CurrentDatabase,
378    CurrentQuery,
379    CurrentSchemas,
380    FormatType,
381    HasAnyColumnPrivilege,
382    HasColumnPrivilege,
383    HasDatabasePrivilege,
384    HasForeignDataWrapperPrivilege,
385    HasFunctionPrivilege,
386    HasLanguagePrivilege,
387    HasLargeobjectPrivilege,
388    HasParameterPrivilege,
389    HasSchemaPrivilege,
390    HasSequencePrivilege,
391    HasServerPrivilege,
392    HasTablePrivilege,
393    HasTablespacePrivilege,
394    HasTypePrivilege,
395    IcuUnicodeVersion,
396    InetClientAddr,
397    InetClientPort,
398    Makeaclitem,
399    MxidAge,
400    ObjDescription,
401    PgAvailableWalSummaries,
402    PgBackendPid,
403    PgBlockingPids,
404    PgCharToEncoding,
405    PgCollationIsVisible,
406    PgConfLoadTime,
407    PgControlCheckpoint,
408    PgControlInit,
409    PgControlRecovery,
410    PgControlSystem,
411    PgConversionIsVisible,
412    PgCurrentLogfile,
413    PgCurrentSnapshot,
414    PgCurrentXactId,
415    PgCurrentXactIdIfAssigned,
416    PgDescribeObject,
417    PgEncodingToChar,
418    PgFunctionIsVisible,
419    PgGetAcl,
420    PgGetConstraintdef,
421    PgGetExpr,
422    PgGetFunctiondef,
423    PgGetFunctionArguments,
424    PgGetFunctionIdentityArguments,
425    PgGetFunctionResult,
426    PgGetIndexdef,
427    PgGetObjectAddress,
428    PgGetPartitionConstraintdef,
429    PgGetPartkeydef,
430    PgGetRuledef,
431    PgGetSerialSequence,
432    PgGetStatisticsobjdef,
433    PgGetTriggerdef,
434    PgGetUserbyid,
435    PgGetViewdef,
436    PgGetWalSummarizerState,
437    PgHasRole,
438    PgIndexColumnHasProperty,
439    PgIndexHasProperty,
440    PgIndexamHasProperty,
441    PgInputErrorInfo,
442    PgInputIsValid,
443    PgIsOtherTempSchema,
444    PgJitAvailable,
445    PgLastCommittedXact,
446    PgListeningChannels,
447    PgMyTempSchema,
448    PgNotificationQueueUsage,
449    PgOpclassIsVisible,
450    PgOperatorIsVisible,
451    PgOpfamilyIsVisible,
452    PgSafeSnapshotBlockingPids,
453    PgSettingsGetFlags,
454    PgSnapshotXip,
455    PgSnapshotXmax,
456    PgSnapshotXmin,
457    PgStatisticsObjIsVisible,
458    PgTableIsVisible,
459    PgTablespaceLocation,
460    PgTriggerDepth,
461    PgTsConfigIsVisible,
462    PgTsDictIsVisible,
463    PgTsParserIsVisible,
464    PgTsTemplateIsVisible,
465    PgTypeIsVisible,
466    PgTypeof,
467    PgVisibleInSnapshot,
468    PgXactCommitTimestamp,
469    PgXactStatus,
470    RowSecurityActive,
471    ShobjDescription,
472    ToRegclass,
473    ToRegcollation,
474    ToRegnamespace,
475    ToRegoper,
476    ToRegoperator,
477    ToRegproc,
478    ToRegprocedure,
479    ToRegrole,
480    ToRegtype,
481    ToRegtypemod,
482    UnicodeVersion,
483    ArrayAgg,
484    BitAnd,
485    BitOr,
486    BitXor,
487    BoolAnd,
488    BoolOr,
489    Corr,
490    CovarPop,
491    CovarSamp,
492    CumeDist,
493    DenseRank,
494    JsonAgg,
495    JsonbAgg,
496    JsonbObjectAgg,
497    JsonbSet,
498    JsonBuildObject,
499    PercentRank,
500    PercentileCont,
501    PercentileDisc,
502    Rank,
503    RegrAvgx,
504    RegrAvgy,
505    RegrCount,
506    RegrIntercept,
507    RegrR2,
508    RegrSlope,
509    RegrSxx,
510    RegrSxy,
511    RegrSyy,
512    Mode,
513    Std,
514    Stddev,
515    StddevPop,
516    StddevSamp,
517    StringAgg,
518    StringToArray,
519    StringToTable,
520    Variance,
521    VarPop,
522    VarSamp,
523    Xmlagg,
524    Coalesce,
525    // PostgreSQL geometric functions (non-PostGIS)
526    BoundBox,
527    Isclosed,
528    IsOpen,
529    // PostGIS / geometry functions
530    Box2D,
531    Box3D,
532    GeometryType,
533    StAddMeasure,
534    StAddPoint,
535    StAffine,
536    StArea,
537    StAsBinary,
538    StAsEwkb,
539    StAsEwkt,
540    StAsGeoJson,
541    StAsGml,
542    StAsHexEwkb,
543    StAsKml,
544    StAsSvg,
545    StAsText,
546    StAzimuth,
547    StBoundary,
548    StBuffer,
549    StBuildArea,
550    StCentroid,
551    StClosestPoint,
552    StCollect,
553    StCollectionExtract,
554    StContains,
555    StContainsProperly,
556    StConvexHull,
557    StCoordDim,
558    StCoveredBy,
559    StCovers,
560    StCrosses,
561    StCurveToLine,
562    StDFullyWithin,
563    StDifference,
564    StDimension,
565    StDisjoint,
566    StDistance,
567    StDistanceSphere,
568    StDistanceSpheroidal,
569    StDWithin,
570    StEndPoint,
571    StEnvelope,
572    StEquals,
573    StExteriorRing,
574    StForce2D,
575    StForce3D,
576    StForce3DM,
577    StForce3DZ,
578    StForce4D,
579    StForceCollection,
580    StForceRHR,
581    StGeoHash,
582    StGeomCollFromText,
583    StGeomFromEwkb,
584    StGeomFromEwkt,
585    StGeomFromGeoJson,
586    StGeomFromGml,
587    StGeomFromKml,
588    StGeomFromText,
589    StGeomFromWkb,
590    StGeometryFromText,
591    StGeometryN,
592    StGeometryType,
593    StGmlToSQL,
594    StHasArc,
595    StHausdorffDistance,
596    StInteriorRingN,
597    StIntersection,
598    StIntersects,
599    StIsClosed,
600    StIsEmpty,
601    StIsRing,
602    StIsSimple,
603    StIsValid,
604    StIsValidReason,
605    StLength,
606    StLength2D,
607    StLength3D,
608    StLineCrossingDirection,
609    StLineFromMultiPoint,
610    StLineFromText,
611    StLineFromWkb,
612    StLineMerge,
613    StLinestringFromWkb,
614    StLineToCurve,
615    StLineInterpolatePoint,
616    StLineLocatePoint,
617    StLineSubstring,
618    StLongestLine,
619    StM,
620    StMakeEnvelope,
621    StMakeLine,
622    StMakePoint,
623    StMakePointM,
624    StMakePolygon,
625    StMaxDistance,
626    StMemSize,
627    StMinimumBoundingCircle,
628    StMulti,
629    StNDims,
630    StNPoints,
631    StNRings,
632    StNumGeometries,
633    StNumInteriorRing,
634    StNumInteriorRings,
635    StNumPoints,
636    StOrderingEquals,
637    StOverlaps,
638    StPerimeter,
639    StPerimeter2D,
640    StPerimeter3D,
641    StPoint,
642    StPointFromText,
643    StPointFromWkb,
644    StPointN,
645    StPointOnSurface,
646    StPointInsideCircle,
647    StPolygon,
648    StPolygonFromText,
649    StPolygonize,
650    StRelate,
651    StRemovePoint,
652    StReverse,
653    StRotate,
654    StRotateX,
655    StRotateY,
656    StRotateZ,
657    StScale,
658    StSegmentize,
659    StSetPoint,
660    StSetSrid,
661    StShiftLongitude,
662    StShortestLine,
663    StSimplify,
664    StSimplifyPreserveTopology,
665    StSnapToGrid,
666    StSRID,
667    StStartPoint,
668    StSummary,
669    StSymDifference,
670    StTouches,
671    StTransform,
672    StTranslate,
673    StTransScale,
674    StUnion,
675    StWithin,
676    StWkbToSQL,
677    StWktToSQL,
678    StX,
679    StXMax,
680    StXMin,
681    StY,
682    StYMax,
683    StYMin,
684    StZ,
685    StZMax,
686    StZMin,
687    StZmflag,
688    // PostGIS additional functions
689    StMakeValid,
690    StIsValidDetail,
691    StDump,
692    StDumpPoints,
693    StDumpRings,
694    StDumpSegments,
695    StSnap,
696    StNode,
697    StSplit,
698    StSharedPaths,
699    StExpand,
700    StEstimatedExtent,
701    StFlipCoordinates,
702    StForceCw,
703    StForceCcw,
704    StForcePolygonCw,
705    StForcePolygonCcw,
706    StConcaveHull,
707    StVoronoiPolygons,
708    StVoronoiLines,
709    StDelaunayTriangles,
710    StSubdivide,
711    StGeneratePoints,
712    StBoundingDiagonal,
713    StMaximumInscribedCircle,
714    StChaikinSmoothing,
715    StFrechetDistance,
716    StProject,
717    StLocateAlong,
718    StLocateBetween,
719    StInterpolatePoint,
720    StMakeBox2D,
721    St3DMakeBox,
722    St3DDistance,
723    St3DMaxDistance,
724    St3DIntersects,
725    StExtent,
726    St3DExtent,
727    // PostgreSQL UUID functions
728    GenRandomUuid,
729    UuidExtractTimestamp,
730    UuidExtractVersion,
731    Uuidv4,
732    Uuidv7,
733    // PostgreSQL XML functions
734    CursorToXml,
735    CursorToXmlschema,
736    DatabaseToXml,
737    DatabaseToXmlAndXmlschema,
738    DatabaseToXmlschema,
739    QueryToXml,
740    QueryToXmlAndXmlschema,
741    QueryToXmlschema,
742    SchemaToXml,
743    SchemaToXmlAndXmlschema,
744    SchemaToXmlschema,
745    TableToXml,
746    TableToXmlAndXmlschema,
747    TableToXmlschema,
748    XmlComment,
749    XmlConcat,
750    XmlIsWellFormed,
751    XmlIsWellFormedContent,
752    XmlIsWellFormedDocument,
753    XmlText,
754    Xpath,
755    XpathExists,
756    // PostgreSQL JSON functions
757    ArrayToJson,
758    JsonArrayElements,
759    JsonArrayElementsText,
760    JsonArrayLength,
761    JsonBuildArray,
762    JsonEach,
763    JsonEachText,
764    JsonExtractPath,
765    JsonExtractPathText,
766    JsonObjectKeys,
767    JsonPopulateRecord,
768    JsonPopulateRecordset,
769    JsonScalar,
770    JsonSerialize,
771    JsonStripNulls,
772    JsonToRecord,
773    JsonToRecordset,
774    JsonTypeof,
775    JsonbArrayElements,
776    JsonbArrayElementsText,
777    JsonbArrayLength,
778    JsonbBuildArray,
779    JsonbBuildObject,
780    JsonbEach,
781    JsonbEachText,
782    JsonbExtractPath,
783    JsonbExtractPathText,
784    JsonbInsert,
785    JsonbObject,
786    JsonbObjectKeys,
787    JsonbPathExists,
788    JsonbPathExistsTz,
789    JsonbPathMatch,
790    JsonbPathMatchTz,
791    JsonbPathQuery,
792    JsonbPathQueryArray,
793    JsonbPathQueryArrayTz,
794    JsonbPathQueryFirst,
795    JsonbPathQueryFirstTz,
796    JsonbPathQueryTz,
797    JsonbPopulateRecord,
798    JsonbPopulateRecordValid,
799    JsonbPopulateRecordset,
800    JsonbPretty,
801    JsonbSetLax,
802    JsonbStripNulls,
803    JsonbToRecord,
804    JsonbToRecordset,
805    JsonbTypeof,
806    RowToJson,
807    ToJson,
808    ToJsonb,
809    // PostgreSQL sequence functions
810    Currval,
811    Lastval,
812    Nextval,
813    Setval,
814    // PostgreSQL array functions
815    ArrayAppend,
816    ArrayCat,
817    ArrayDims,
818    ArrayFill,
819    ArrayLength,
820    ArrayLower,
821    ArrayNdims,
822    ArrayPosition,
823    ArrayPositions,
824    ArrayPrepend,
825    ArrayRemove,
826    ArrayReplace,
827    ArrayReverse,
828    ArraySample,
829    ArrayShuffle,
830    ArraySort,
831    ArrayToString,
832    ArrayUpper,
833    Cardinality,
834    TrimArray,
835    // PostgreSQL text search functions
836    ArrayToTsvector,
837    GetCurrentTsConfig,
838    JsonToTsvector,
839    JsonbToTsvector,
840    Numnode,
841    PhraseToTsquery,
842    PlainToTsquery,
843    Querytree,
844    Setweight,
845    Strip,
846    ToTsquery,
847    ToTsvector,
848    TsDebug,
849    TsDelete,
850    TsFilter,
851    TsHeadline,
852    TsLexize,
853    TsParse,
854    TsRank,
855    TsRankCd,
856    TsRewrite,
857    TsStat,
858    TsTokenType,
859    TsqueryPhrase,
860    TsvectorToArray,
861    Unnest,
862    WebsearchToTsquery,
863    Other(Vec<Identifier<'a>>),
864}
865
866/// Function call expression,
867#[derive(Debug, Clone)]
868pub struct FunctionCallExpression<'a> {
869    pub function: Function<'a>,
870    pub args: Vec<Expression<'a>>,
871    pub function_span: Span,
872}
873
874impl Spanned for FunctionCallExpression<'_> {
875    fn span(&self) -> Span {
876        self.function_span.join_span(&self.args)
877    }
878}
879
880/// CHAR(N,... [USING charset_name]) expression
881#[derive(Debug, Clone)]
882pub struct CharFunctionExpression<'a> {
883    /// Span of "CHAR"
884    pub char_span: Span,
885    /// Arguments to CHAR()
886    pub args: Vec<Expression<'a>>,
887    /// Optional USING charset_name clause
888    pub using_charset: Option<(Span, Identifier<'a>)>,
889}
890
891impl<'a> Spanned for CharFunctionExpression<'a> {
892    fn span(&self) -> Span {
893        self.char_span
894            .join_span(&self.args)
895            .join_span(&self.using_charset)
896    }
897}
898
899/// Window frame mode: ROWS, RANGE, or GROUPS
900#[derive(Debug, Clone)]
901pub enum WindowFrameMode {
902    Rows(Span),
903    Range(Span),
904    Groups(Span),
905}
906
907impl Spanned for WindowFrameMode {
908    fn span(&self) -> Span {
909        match self {
910            WindowFrameMode::Rows(s) | WindowFrameMode::Range(s) | WindowFrameMode::Groups(s) => {
911                s.clone()
912            }
913        }
914    }
915}
916
917/// One bound in a window frame clause
918#[derive(Debug, Clone)]
919pub enum WindowFrameBound<'a> {
920    /// UNBOUNDED PRECEDING
921    UnboundedPreceding(Span),
922    /// <expr> PRECEDING
923    Preceding(Expression<'a>, Span),
924    /// CURRENT ROW
925    CurrentRow(Span),
926    /// <expr> FOLLOWING
927    Following(Expression<'a>, Span),
928    /// UNBOUNDED FOLLOWING
929    UnboundedFollowing(Span),
930}
931
932impl<'a> Spanned for WindowFrameBound<'a> {
933    fn span(&self) -> Span {
934        match self {
935            WindowFrameBound::UnboundedPreceding(s) => s.clone(),
936            WindowFrameBound::Preceding(e, s) => e.span().join_span(s),
937            WindowFrameBound::CurrentRow(s) => s.clone(),
938            WindowFrameBound::Following(e, s) => e.span().join_span(s),
939            WindowFrameBound::UnboundedFollowing(s) => s.clone(),
940        }
941    }
942}
943
944/// Window frame clause: ROWS/RANGE/GROUPS { frame_start | BETWEEN frame_start AND frame_end }
945#[derive(Debug, Clone)]
946pub struct WindowFrame<'a> {
947    /// ROWS, RANGE, or GROUPS
948    pub mode: WindowFrameMode,
949    /// The start bound (or sole bound when no BETWEEN)
950    pub start: WindowFrameBound<'a>,
951    /// When BETWEEN was used: span covering "BETWEEN ... AND" and the end bound
952    pub between: Option<(Span, WindowFrameBound<'a>)>,
953}
954
955impl<'a> Spanned for WindowFrame<'a> {
956    fn span(&self) -> Span {
957        let s = self.mode.span().join_span(&self.start);
958        if let Some((and_span, end)) = &self.between {
959            s.join_span(and_span).join_span(end)
960        } else {
961            s
962        }
963    }
964}
965
966/// When part of CASE
967#[derive(Debug, Clone)]
968pub struct WindowSpec<'a> {
969    /// Span of the opening parenthesis — used as fallback when the spec is empty
970    pub lparen_span: Span,
971    /// Span of "PARTITION BY" and list of partition expressions, if specified
972    pub partition_by: Option<(Span, Vec<Expression<'a>>)>,
973    /// Span of "ORDER BY" and list of order expression and directions, if specified
974    pub order_by: Option<(Span, Vec<(Expression<'a>, OrderFlag)>)>,
975    /// Window frame clause (ROWS/RANGE BETWEEN ... AND ...), if specified
976    pub frame: Option<WindowFrame<'a>>,
977}
978
979impl<'a> Spanned for WindowSpec<'a> {
980    fn span(&self) -> Span {
981        self.partition_by
982            .opt_join_span(&self.order_by)
983            .opt_join_span(&self.frame)
984            .unwrap_or(self.lparen_span.clone())
985    }
986}
987
988#[derive(Debug, Clone)]
989pub struct WindowClause<'a> {
990    pub over_span: Span,
991    pub window_spec: WindowSpec<'a>,
992}
993
994impl Spanned for WindowClause<'_> {
995    fn span(&self) -> Span {
996        self.over_span.join_span(&self.window_spec)
997    }
998}
999
1000/// A window function call expression
1001#[derive(Debug, Clone)]
1002pub struct WindowFunctionCallExpression<'a> {
1003    pub function: Function<'a>,
1004    pub args: Vec<Expression<'a>>,
1005    pub function_span: Span,
1006    pub over: WindowClause<'a>,
1007}
1008
1009impl Spanned for WindowFunctionCallExpression<'_> {
1010    fn span(&self) -> Span {
1011        self.function_span
1012            .join_span(&self.args)
1013            .join_span(&self.over)
1014    }
1015}
1016
1017#[derive(Debug, Clone)]
1018pub struct AggregateFunctionCallExpression<'a> {
1019    pub function: Function<'a>,
1020    pub args: Vec<Expression<'a>>,
1021    pub function_span: Span,
1022    pub distinct_span: Option<Span>,
1023    pub within_group: Option<(Span, Vec<(Expression<'a>, OrderFlag)>)>,
1024    pub filter: Option<(Span, Expression<'a>)>,
1025    pub over: Option<WindowClause<'a>>,
1026}
1027
1028impl Spanned for AggregateFunctionCallExpression<'_> {
1029    fn span(&self) -> Span {
1030        self.function_span
1031            .join_span(&self.args)
1032            .join_span(&self.distinct_span)
1033            .join_span(&self.within_group)
1034            .join_span(&self.filter)
1035            .join_span(&self.over)
1036    }
1037}
1038
1039pub(crate) fn is_aggregate_function_ident(keyword: &Keyword) -> bool {
1040    matches!(
1041        keyword,
1042        Keyword::COUNT
1043            | Keyword::AVG
1044            | Keyword::SUM
1045            | Keyword::MIN
1046            | Keyword::MAX
1047            | Keyword::JSON_ARRAYAGG
1048            | Keyword::JSON_OBJECTAGG
1049            | Keyword::ARRAY_AGG
1050            | Keyword::BIT_AND
1051            | Keyword::BIT_OR
1052            | Keyword::BIT_XOR
1053            | Keyword::BOOL_AND
1054            | Keyword::BOOL_OR
1055            | Keyword::CORR
1056            | Keyword::COVAR_POP
1057            | Keyword::COVAR_SAMP
1058            | Keyword::CUME_DIST
1059            | Keyword::DENSE_RANK
1060            | Keyword::EVERY
1061            | Keyword::JSON_AGG
1062            | Keyword::JSONB_AGG
1063            | Keyword::JSONB_OBJECT_AGG
1064            | Keyword::PERCENT_RANK
1065            | Keyword::PERCENTILE_CONT
1066            | Keyword::PERCENTILE_DISC
1067            | Keyword::RANK
1068            | Keyword::REGR_AVGX
1069            | Keyword::REGR_AVGY
1070            | Keyword::REGR_COUNT
1071            | Keyword::REGR_INTERCEPT
1072            | Keyword::REGR_R2
1073            | Keyword::REGR_SLOPE
1074            | Keyword::REGR_SXX
1075            | Keyword::REGR_SXY
1076            | Keyword::REGR_SYY
1077            | Keyword::STD
1078            | Keyword::STDDEV
1079            | Keyword::STDDEV_POP
1080            | Keyword::STDDEV_SAMP
1081            | Keyword::STRING_AGG
1082            | Keyword::VARIANCE
1083            | Keyword::VAR_POP
1084            | Keyword::VAR_SAMP
1085            | Keyword::XMLAGG
1086            | Keyword::MODE
1087    )
1088}
1089
1090fn parse_window_frame_bound<'a>(
1091    parser: &mut Parser<'a, '_>,
1092) -> Result<WindowFrameBound<'a>, ParseError> {
1093    match &parser.token {
1094        Token::Ident(_, Keyword::UNBOUNDED) => {
1095            let kw_span = parser.consume_keyword(Keyword::UNBOUNDED)?;
1096            if let Some(span) = parser.skip_keyword(Keyword::PRECEDING) {
1097                Ok(WindowFrameBound::UnboundedPreceding(
1098                    kw_span.join_span(&span),
1099                ))
1100            } else {
1101                Ok(WindowFrameBound::UnboundedFollowing(
1102                    parser
1103                        .consume_keyword(Keyword::FOLLOWING)?
1104                        .join_span(&kw_span),
1105                ))
1106            }
1107        }
1108        Token::Ident(_, Keyword::CURRENT) => {
1109            let current_row_span = parser.consume_keywords(&[Keyword::CURRENT, Keyword::ROW])?;
1110            Ok(WindowFrameBound::CurrentRow(current_row_span))
1111        }
1112        _ => {
1113            let expr = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1114            if let Some(s) = parser.skip_keyword(Keyword::PRECEDING) {
1115                Ok(WindowFrameBound::Preceding(expr, s))
1116            } else {
1117                let s = parser.consume_keyword(Keyword::FOLLOWING)?;
1118                Ok(WindowFrameBound::Following(expr, s))
1119            }
1120        }
1121    }
1122}
1123
1124fn parse_window_frame<'a>(
1125    parser: &mut Parser<'a, '_>,
1126    mode: WindowFrameMode,
1127) -> Result<WindowFrame<'a>, ParseError> {
1128    if let Some(between_span) = parser.skip_keyword(Keyword::BETWEEN) {
1129        let start = parse_window_frame_bound(parser)?;
1130        let and_span = parser.consume_keyword(Keyword::AND)?;
1131        let end = parse_window_frame_bound(parser)?;
1132        Ok(WindowFrame {
1133            mode,
1134            start,
1135            between: Some((between_span.join_span(&and_span), end)),
1136        })
1137    } else {
1138        let start = parse_window_frame_bound(parser)?;
1139        Ok(WindowFrame {
1140            mode,
1141            start,
1142            between: None,
1143        })
1144    }
1145}
1146
1147fn parse_over_clause<'a>(
1148    parser: &mut Parser<'a, '_>,
1149) -> Result<Option<WindowClause<'a>>, ParseError> {
1150    let Some(over_span) = parser.skip_keyword(Keyword::OVER) else {
1151        return Ok(None);
1152    };
1153
1154    let lparen_span = parser.consume_token(Token::LParen)?;
1155
1156    let partition_by = if let Some(partition_span) = parser.skip_keyword(Keyword::PARTITION) {
1157        let partition_by_span = partition_span.join_span(&parser.consume_keyword(Keyword::BY)?);
1158        let mut partition_exprs = Vec::new();
1159        loop {
1160            partition_exprs.push(parse_expression_unreserved(parser, PRIORITY_MAX)?);
1161            if parser.skip_token(Token::Comma).is_none() {
1162                break;
1163            }
1164        }
1165        Some((partition_by_span, partition_exprs))
1166    } else {
1167        None
1168    };
1169
1170    let order_by = if let Some(span) = parser.skip_keyword(Keyword::ORDER) {
1171        let order_span = span.join_span(&parser.consume_keyword(Keyword::BY)?);
1172        let mut order = Vec::new();
1173        loop {
1174            let e = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1175            let f = match &parser.token {
1176                Token::Ident(_, Keyword::ASC) => OrderFlag::Asc(parser.consume()),
1177                Token::Ident(_, Keyword::DESC) => OrderFlag::Desc(parser.consume()),
1178                _ => OrderFlag::None,
1179            };
1180            order.push((e, f));
1181            if parser.skip_token(Token::Comma).is_none() {
1182                break;
1183            }
1184        }
1185        Some((order_span, order))
1186    } else {
1187        None
1188    };
1189
1190    // Window frame clause: ROWS/RANGE { frame_start | BETWEEN frame_start AND frame_end }
1191    let frame = if let Some(s) = parser.skip_keyword(Keyword::ROWS) {
1192        Some(parse_window_frame(parser, WindowFrameMode::Rows(s))?)
1193    } else if let Some(s) = parser.skip_keyword(Keyword::RANGE) {
1194        Some(parse_window_frame(parser, WindowFrameMode::Range(s))?)
1195    } else {
1196        None
1197    };
1198
1199    parser.consume_token(Token::RParen)?;
1200
1201    Ok(Some(WindowClause {
1202        over_span,
1203        window_spec: WindowSpec {
1204            lparen_span,
1205            partition_by,
1206            order_by,
1207            frame,
1208        },
1209    }))
1210}
1211
1212pub(crate) fn parse_aggregate_function<'a>(
1213    parser: &mut Parser<'a, '_>,
1214    t: Token<'a>,
1215    span: Span,
1216) -> Result<Expression<'a>, ParseError> {
1217    parser.consume_token(Token::LParen)?;
1218    let func = match &t {
1219        Token::Ident(_, Keyword::COUNT) => Function::Count,
1220        Token::Ident(_, Keyword::AVG) => Function::Avg,
1221        Token::Ident(_, Keyword::SUM) => Function::Sum,
1222        Token::Ident(_, Keyword::MIN) => Function::Min,
1223        Token::Ident(_, Keyword::MAX) => Function::Max,
1224        Token::Ident(_, Keyword::JSON_ARRAYAGG) => Function::JsonArrayAgg,
1225        Token::Ident(_, Keyword::JSON_OBJECTAGG) => Function::JsonObjectAgg,
1226        Token::Ident(_, Keyword::ARRAY_AGG) => Function::ArrayAgg,
1227        Token::Ident(_, Keyword::BIT_AND) => Function::BitAnd,
1228        Token::Ident(_, Keyword::BIT_OR) => Function::BitOr,
1229        Token::Ident(_, Keyword::BIT_XOR) => Function::BitXor,
1230        Token::Ident(_, Keyword::BOOL_AND) => Function::BoolAnd,
1231        Token::Ident(_, Keyword::BOOL_OR) => Function::BoolOr,
1232        Token::Ident(_, Keyword::CORR) => Function::Corr,
1233        Token::Ident(_, Keyword::COVAR_POP) => Function::CovarPop,
1234        Token::Ident(_, Keyword::COVAR_SAMP) => Function::CovarSamp,
1235        Token::Ident(_, Keyword::CUME_DIST) => Function::CumeDist,
1236        Token::Ident(_, Keyword::DENSE_RANK) => Function::DenseRank,
1237        Token::Ident(_, Keyword::EVERY) => Function::BoolAnd,
1238        Token::Ident(_, Keyword::JSON_AGG) => Function::JsonAgg,
1239        Token::Ident(_, Keyword::JSONB_AGG) => Function::JsonbAgg,
1240        Token::Ident(_, Keyword::JSONB_OBJECT_AGG) => Function::JsonbObjectAgg,
1241        Token::Ident(_, Keyword::JSONB_SET) => Function::JsonbSet,
1242        Token::Ident(_, Keyword::PERCENT_RANK) => Function::PercentRank,
1243        Token::Ident(_, Keyword::PERCENTILE_CONT) => Function::PercentileCont,
1244        Token::Ident(_, Keyword::PERCENTILE_DISC) => Function::PercentileDisc,
1245        Token::Ident(_, Keyword::RANK) => Function::Rank,
1246        Token::Ident(_, Keyword::REGR_AVGX) => Function::RegrAvgx,
1247        Token::Ident(_, Keyword::REGR_AVGY) => Function::RegrAvgy,
1248        Token::Ident(_, Keyword::REGR_COUNT) => Function::RegrCount,
1249        Token::Ident(_, Keyword::REGR_INTERCEPT) => Function::RegrIntercept,
1250        Token::Ident(_, Keyword::REGR_R2) => Function::RegrR2,
1251        Token::Ident(_, Keyword::REGR_SLOPE) => Function::RegrSlope,
1252        Token::Ident(_, Keyword::REGR_SXX) => Function::RegrSxx,
1253        Token::Ident(_, Keyword::REGR_SXY) => Function::RegrSxy,
1254        Token::Ident(_, Keyword::REGR_SYY) => Function::RegrSyy,
1255        Token::Ident(_, Keyword::STD) => Function::Std,
1256        Token::Ident(_, Keyword::STDDEV) => Function::Stddev,
1257        Token::Ident(_, Keyword::STDDEV_POP) => Function::StddevPop,
1258        Token::Ident(_, Keyword::STDDEV_SAMP) => Function::StddevSamp,
1259        Token::Ident(_, Keyword::STRING_AGG) => Function::StringAgg,
1260        Token::Ident(_, Keyword::VARIANCE) => Function::Variance,
1261        Token::Ident(_, Keyword::VAR_POP) => Function::VarPop,
1262        Token::Ident(_, Keyword::VAR_SAMP) => Function::VarSamp,
1263        Token::Ident(_, Keyword::XMLAGG) => Function::Xmlagg,
1264        Token::Ident(_, Keyword::MODE) => Function::Mode,
1265        _ => {
1266            parser.err("Unknown aggregate function", &span);
1267            Function::Unknown
1268        }
1269    };
1270
1271    let distinct_span = parser.skip_keyword(Keyword::DISTINCT);
1272    let mut args = Vec::new();
1273    if !matches!(parser.token, Token::RParen) {
1274        loop {
1275            parser.recovered(
1276                "')' or ','",
1277                &|t| matches!(t, Token::RParen | Token::Comma),
1278                |parser| {
1279                    args.push(parse_expression_outer(parser)?);
1280                    Ok(())
1281                },
1282            )?;
1283            if parser.skip_token(Token::Comma).is_none() {
1284                break;
1285            }
1286        }
1287    }
1288    parser.consume_token(Token::RParen)?;
1289
1290    let within_group = if let Some(within_span) = parser.skip_keyword(Keyword::WITHIN) {
1291        let within_group_span = within_span.join_span(&parser.consume_keyword(Keyword::GROUP)?);
1292        parser.consume_token(Token::LParen)?;
1293        let order_span = parser.consume_keyword(Keyword::ORDER)?;
1294        let order_by_span = order_span.join_span(&parser.consume_keyword(Keyword::BY)?);
1295        let mut order = Vec::new();
1296        loop {
1297            let e = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1298            let f = match &parser.token {
1299                Token::Ident(_, Keyword::ASC) => OrderFlag::Asc(parser.consume()),
1300                Token::Ident(_, Keyword::DESC) => OrderFlag::Desc(parser.consume()),
1301                _ => OrderFlag::None,
1302            };
1303            order.push((e, f));
1304            if parser.skip_token(Token::Comma).is_none() {
1305                break;
1306            }
1307        }
1308        parser.consume_token(Token::RParen)?;
1309        Some((within_group_span.join_span(&order_by_span), order))
1310    } else {
1311        None
1312    };
1313
1314    let filter = if let Some(filter_span) = parser.skip_keyword(Keyword::FILTER) {
1315        parser.postgres_only(&filter_span);
1316        parser.consume_token(Token::LParen)?;
1317        parser.consume_keyword(Keyword::WHERE)?;
1318        let condition = parse_expression_unreserved(parser, PRIORITY_MAX)?;
1319        parser.consume_token(Token::RParen)?;
1320        Some((filter_span, condition))
1321    } else {
1322        None
1323    };
1324
1325    let over = parse_over_clause(parser)?;
1326
1327    Ok(Expression::AggregateFunction(Box::new(
1328        AggregateFunctionCallExpression {
1329            function: func,
1330            args,
1331            function_span: span,
1332            distinct_span,
1333            within_group,
1334            filter,
1335            over,
1336        },
1337    )))
1338}
1339
1340pub(crate) fn parse_function<'a>(
1341    parser: &mut Parser<'a, '_>,
1342    t: Token<'a>,
1343    span: Span,
1344) -> Result<Expression<'a>, ParseError> {
1345    parser.consume_token(Token::LParen)?;
1346
1347    let func = match &t {
1348        // https://mariadb.com/kb/en/string-functions/
1349        Token::Ident(_, Keyword::ASCII) => Function::Ascii,
1350        Token::Ident(_, Keyword::BIN) => Function::Bin,
1351        Token::Ident(_, Keyword::BIT_LENGTH) => Function::BitLength,
1352        Token::Ident(_, Keyword::CHAR_LENGTH) => Function::CharacterLength,
1353        Token::Ident(_, Keyword::CHARACTER_LENGTH) => Function::CharacterLength,
1354        Token::Ident(_, Keyword::CHR) => Function::Chr,
1355        Token::Ident(_, Keyword::CONCAT) => Function::Concat,
1356        Token::Ident(_, Keyword::CONCAT_WS) => Function::ConcatWs,
1357        Token::Ident(_, Keyword::ELT) => Function::Elt,
1358        Token::Ident(_, Keyword::EXPORT_SET) => Function::ExportSet,
1359        Token::Ident(_, Keyword::EXTRACTVALUE) => Function::ExtractValue,
1360        Token::Ident(_, Keyword::FIELD) => Function::Field,
1361        Token::Ident(_, Keyword::FIND_IN_SET) => Function::FindInSet,
1362        Token::Ident(_, Keyword::FORMAT) => Function::Format,
1363        Token::Ident(_, Keyword::FROM_BASE64) => Function::FromBase64,
1364        Token::Ident(_, Keyword::HEX) => Function::Hex,
1365        Token::Ident(_, Keyword::INSERT) => Function::Insert,
1366        Token::Ident(_, Keyword::INSTR) => Function::InStr,
1367        Token::Ident(_, Keyword::LCASE) => Function::LCase,
1368        Token::Ident(_, Keyword::LEFT) => Function::Left,
1369        Token::Ident(_, Keyword::LENGTH) => Function::Length,
1370        Token::Ident(_, Keyword::LENGTHB) => Function::LengthB,
1371        Token::Ident(_, Keyword::LOAD_FILE) => Function::LoadFile,
1372        Token::Ident(_, Keyword::LOCATE) => Function::Locate,
1373        Token::Ident(_, Keyword::LOWER) => Function::Lower,
1374        Token::Ident(_, Keyword::LPAD) => Function::LPad,
1375        Token::Ident(_, Keyword::LTRIM) => Function::LTrim,
1376        Token::Ident(_, Keyword::MAKE_SET) => Function::MakeSet,
1377        Token::Ident(_, Keyword::MID) => Function::Mid,
1378        Token::Ident(_, Keyword::NATURAL_SORT_KEY) => Function::NaturalSortkey,
1379        Token::Ident(_, Keyword::OCTET_LENGTH) => Function::OctetLength,
1380        Token::Ident(_, Keyword::ORD) => Function::Ord,
1381        Token::Ident(_, Keyword::POSITION) => Function::Position,
1382        Token::Ident(_, Keyword::QUOTE) => Function::Quote,
1383        Token::Ident(_, Keyword::REPEAT) => Function::Repeat,
1384        Token::Ident(_, Keyword::REPLACE) => Function::Replace,
1385        Token::Ident(_, Keyword::REVERSE) => Function::Reverse,
1386        Token::Ident(_, Keyword::RIGHT) => Function::Right,
1387        Token::Ident(_, Keyword::RPAD) => Function::RPad,
1388        Token::Ident(_, Keyword::RTRIM) => Function::RTrim,
1389        Token::Ident(_, Keyword::SOUNDEX) => Function::SoundEx,
1390        Token::Ident(_, Keyword::SLEEP) => Function::Sleep,
1391        Token::Ident(_, Keyword::SPACE) => Function::Space,
1392        Token::Ident(_, Keyword::STRCMP) => Function::StrCmp,
1393        Token::Ident(_, Keyword::SUBSTR) => Function::SubStr,
1394        Token::Ident(_, Keyword::SUBSTRING) => Function::SubStr,
1395        Token::Ident(_, Keyword::SUBSTRING_INDEX) => Function::SubStringIndex,
1396        Token::Ident(_, Keyword::TO_BASE64) => Function::ToBase64,
1397        Token::Ident(_, Keyword::TO_CHAR) => Function::ToChar,
1398        Token::Ident(_, Keyword::TO_DATE) => Function::ToDate,
1399        Token::Ident(_, Keyword::TO_NUMBER) => Function::ToNumber,
1400        Token::Ident(_, Keyword::TO_TIMESTAMP) => Function::ToTimestamp,
1401        Token::Ident(_, Keyword::UCASE) => Function::UCase,
1402        Token::Ident(_, Keyword::UNCOMPRESSED_LENGTH) => Function::UncompressedLength,
1403        Token::Ident(_, Keyword::UNHEX) => Function::UnHex,
1404        Token::Ident(_, Keyword::UPDATEXML) => Function::UpdateXml,
1405        Token::Ident(_, Keyword::UPPER) => Function::Upper,
1406        Token::Ident(_, Keyword::SFORMAT) => Function::SFormat,
1407
1408        // PostgreSQL string functions
1409        Token::Ident(_, Keyword::BTRIM) if parser.options.dialect.is_postgresql() => {
1410            Function::Btrim
1411        }
1412        Token::Ident(_, Keyword::CASEFOLD) if parser.options.dialect.is_postgresql() => {
1413            Function::Casefold
1414        }
1415        Token::Ident(_, Keyword::INITCAP) if parser.options.dialect.is_postgresql() => {
1416            Function::Initcap
1417        }
1418        Token::Ident(_, Keyword::NORMALIZE) if parser.options.dialect.is_postgresql() => {
1419            Function::Normalize
1420        }
1421        Token::Ident(_, Keyword::PARSE_IDENT) if parser.options.dialect.is_postgresql() => {
1422            Function::ParseIdent
1423        }
1424        Token::Ident(_, Keyword::PG_CLIENT_ENCODING) if parser.options.dialect.is_postgresql() => {
1425            Function::PgClientEncoding
1426        }
1427        Token::Ident(_, Keyword::QUOTE_IDENT) if parser.options.dialect.is_postgresql() => {
1428            Function::QuoteIdent
1429        }
1430        Token::Ident(_, Keyword::QUOTE_LITERAL) if parser.options.dialect.is_postgresql() => {
1431            Function::QuoteLiteral
1432        }
1433        Token::Ident(_, Keyword::QUOTE_NULLABLE) if parser.options.dialect.is_postgresql() => {
1434            Function::QuoteNullable
1435        }
1436        Token::Ident(_, Keyword::SPLIT_PART) if parser.options.dialect.is_postgresql() => {
1437            Function::SplitPart
1438        }
1439        Token::Ident(_, Keyword::STRING_TO_ARRAY) if parser.options.dialect.is_postgresql() => {
1440            Function::StringToArray
1441        }
1442        Token::Ident(_, Keyword::STRING_TO_TABLE) if parser.options.dialect.is_postgresql() => {
1443            Function::StringToTable
1444        }
1445        Token::Ident(_, Keyword::STRPOS) if parser.options.dialect.is_postgresql() => {
1446            Function::Strpos
1447        }
1448        Token::Ident(_, Keyword::TO_ASCII) if parser.options.dialect.is_postgresql() => {
1449            Function::ToAscii
1450        }
1451        Token::Ident(_, Keyword::TO_BIN) if parser.options.dialect.is_postgresql() => {
1452            Function::ToBin
1453        }
1454        Token::Ident(_, Keyword::TO_HEX) if parser.options.dialect.is_postgresql() => {
1455            Function::ToHex
1456        }
1457        Token::Ident(_, Keyword::TO_OCT) if parser.options.dialect.is_postgresql() => {
1458            Function::ToOct
1459        }
1460        Token::Ident(_, Keyword::TRANSLATE) if parser.options.dialect.is_postgresql() => {
1461            Function::Translate
1462        }
1463        Token::Ident(_, Keyword::UNICODE_ASSIGNED) if parser.options.dialect.is_postgresql() => {
1464            Function::UnicodeAssigned
1465        }
1466        Token::Ident(_, Keyword::UNISTR) if parser.options.dialect.is_postgresql() => {
1467            Function::Unistr
1468        }
1469
1470        // TODO uncat
1471        Token::Ident(_, Keyword::EXISTS) => Function::Exists,
1472        Token::Ident(_, Keyword::COUNT) => Function::Count,
1473        Token::Ident(_, Keyword::AVG) => Function::Avg,
1474        Token::Ident(_, Keyword::MIN) => Function::Min,
1475        Token::Ident(_, Keyword::MAX) => Function::Max,
1476        Token::Ident(_, Keyword::SUM) => Function::Sum,
1477        Token::Ident(_, Keyword::VALUE) => Function::Value,
1478        Token::Ident(_, Keyword::VALUES) => Function::Value,
1479        Token::Ident(_, Keyword::LEAD) => Function::Lead,
1480        Token::Ident(_, Keyword::LAG) => Function::Lag,
1481        Token::Ident(_, Keyword::STARTS_WITH) => Function::StartsWith,
1482
1483        //https://mariadb.com/kb/en/control-flow-functions/
1484        Token::Ident(_, Keyword::IFNULL) => Function::IfNull,
1485        Token::Ident(_, Keyword::NULLIF) => Function::NullIf,
1486        Token::Ident(_, Keyword::NVL) => Function::IfNull,
1487        Token::Ident(_, Keyword::NVL2) => Function::NVL2,
1488        Token::Ident(_, Keyword::IF) => Function::If,
1489        Token::Ident(_, Keyword::COALESCE) => Function::Coalesce,
1490
1491        //https://mariadb.com/kb/en/numeric-functions/
1492        Token::Ident(_, Keyword::ABS) => Function::Abs,
1493        Token::Ident(_, Keyword::ACOS) => Function::Acos,
1494        Token::Ident(_, Keyword::ACOSD) => Function::Acosd,
1495        Token::Ident(_, Keyword::ACOSH) => Function::Acosh,
1496        Token::Ident(_, Keyword::ASIN) => Function::Asin,
1497        Token::Ident(_, Keyword::ASIND) => Function::Asind,
1498        Token::Ident(_, Keyword::ASINH) => Function::Asinh,
1499        Token::Ident(_, Keyword::ATAN) => Function::Atan,
1500        Token::Ident(_, Keyword::ATAN2) => Function::Atan2,
1501        Token::Ident(_, Keyword::ATAN2D) => Function::Atan2d,
1502        Token::Ident(_, Keyword::ATAND) => Function::Atand,
1503        Token::Ident(_, Keyword::ATANH) => Function::Atanh,
1504        Token::Ident(_, Keyword::CBRT) => Function::Cbrt,
1505        Token::Ident(_, Keyword::CEIL | Keyword::CEILING) => Function::Ceil,
1506        Token::Ident(_, Keyword::CONV) => Function::Conv,
1507        Token::Ident(_, Keyword::COS) => Function::Cos,
1508        Token::Ident(_, Keyword::COSD) => Function::Cosd,
1509        Token::Ident(_, Keyword::COSH) => Function::Cosh,
1510        Token::Ident(_, Keyword::COT) => Function::Cot,
1511        Token::Ident(_, Keyword::COTD) => Function::Cotd,
1512        Token::Ident(_, Keyword::CRC32) => Function::Crc32,
1513        Token::Ident(_, Keyword::DEGREES) => Function::Degrees,
1514        Token::Ident(_, Keyword::ERF) => Function::Erf,
1515        Token::Ident(_, Keyword::ERFC) => Function::Erfc,
1516        Token::Ident(_, Keyword::EXP) => Function::Exp,
1517        Token::Ident(_, Keyword::FACTORIAL) => Function::Factorial,
1518        Token::Ident(_, Keyword::FLOOR) => Function::Floor,
1519        Token::Ident(_, Keyword::GAMMA) => Function::Gamma,
1520        Token::Ident(_, Keyword::GCD) => Function::Gcd,
1521        Token::Ident(_, Keyword::GREATEST) => Function::Greatest,
1522        Token::Ident(_, Keyword::LCM) => Function::Lcm,
1523        Token::Ident(_, Keyword::LGAMMA) => Function::Lgamma,
1524        Token::Ident(_, Keyword::LN) => Function::Ln,
1525        Token::Ident(_, Keyword::LOG) => Function::Log,
1526        Token::Ident(_, Keyword::LOG10) => Function::Log10,
1527        Token::Ident(_, Keyword::LOG2) => Function::Log2,
1528        Token::Ident(_, Keyword::MIN_SCALE) => Function::MinScale,
1529        Token::Ident(_, Keyword::MOD) => Function::Mod,
1530        Token::Ident(_, Keyword::OCT) => Function::Oct,
1531        Token::Ident(_, Keyword::PI) => Function::Pi,
1532        Token::Ident(_, Keyword::POW | Keyword::POWER) => Function::Pow,
1533        Token::Ident(_, Keyword::RADIANS) => Function::Radians,
1534        Token::Ident(_, Keyword::RAND) => Function::Rand,
1535        Token::Ident(_, Keyword::RANDOM_NORMAL) => Function::RandomNormal,
1536        Token::Ident(_, Keyword::ROUND) => Function::Round,
1537        Token::Ident(_, Keyword::SCALE) => Function::Scale,
1538        Token::Ident(_, Keyword::SET_BIT) => Function::SetBit,
1539        Token::Ident(_, Keyword::SETSEED) => Function::SetSeed,
1540        Token::Ident(_, Keyword::SIGN) => Function::Sign,
1541        Token::Ident(_, Keyword::SIN) => Function::Sin,
1542        Token::Ident(_, Keyword::SIND) => Function::Sind,
1543        Token::Ident(_, Keyword::SINH) => Function::Sinh,
1544        Token::Ident(_, Keyword::SQRT) => Function::Sqrt,
1545        Token::Ident(_, Keyword::TAN) => Function::Tan,
1546        Token::Ident(_, Keyword::TAND) => Function::Tand,
1547        Token::Ident(_, Keyword::TANH) => Function::Tanh,
1548        Token::Ident(_, Keyword::TRIM_SCALE) => Function::TrimScale,
1549        Token::Ident(_, Keyword::TRUNCATE) => Function::Truncate,
1550        Token::Ident(_, Keyword::WIDTH_BUCKET) => Function::WidthBucket,
1551        Token::Ident(_, Keyword::CRC32C) => Function::Crc32c,
1552        Token::Ident(_, Keyword::LEAST) => Function::Least,
1553
1554        // https://mariadb.com/kb/en/date-time-functions/
1555        Token::Ident(_, Keyword::ADDDATE) => Function::AddDate,
1556        Token::Ident(_, Keyword::ADDTIME) => Function::AddTime,
1557        Token::Ident(_, Keyword::CONVERT_TZ) => Function::ConvertTz,
1558        Token::Ident(_, Keyword::CURDATE) => Function::CurDate,
1559        Token::Ident(_, Keyword::CURRENT_DATE) => Function::CurDate,
1560        Token::Ident(_, Keyword::CURRENT_TIME) => Function::CurTime,
1561        Token::Ident(_, Keyword::CURTIME) => Function::CurTime,
1562        Token::Ident(_, Keyword::DATE) => Function::Date,
1563        Token::Ident(_, Keyword::HOUR) => Function::Hour,
1564        Token::Ident(_, Keyword::DATEDIFF) => Function::DateDiff,
1565        Token::Ident(_, Keyword::DATE_ADD) => Function::AddDate,
1566        Token::Ident(_, Keyword::DATE_FORMAT) => Function::DateFormat,
1567        Token::Ident(_, Keyword::DATE_SUB) => Function::DateSub,
1568        Token::Ident(_, Keyword::DAY | Keyword::DAYOFMONTH) => Function::DayOfMonth,
1569        Token::Ident(_, Keyword::DAYNAME) => Function::DayName,
1570        Token::Ident(_, Keyword::DAYOFWEEK) => Function::DayOfWeek,
1571        Token::Ident(_, Keyword::DAYOFYEAR) => Function::DayOfYear,
1572        Token::Ident(_, Keyword::FROM_DAYS) => Function::FromDays,
1573        Token::Ident(_, Keyword::CURRENT_TIMESTAMP) => Function::CurrentTimestamp,
1574        Token::Ident(_, Keyword::LOCALTIME | Keyword::LOCALTIMESTAMP | Keyword::NOW) => {
1575            Function::Now
1576        }
1577        Token::Ident(_, Keyword::MAKEDATE) => Function::MakeDate,
1578        Token::Ident(_, Keyword::MAKETIME) => Function::MakeTime,
1579        Token::Ident(_, Keyword::MICROSECOND) => Function::MicroSecond,
1580        Token::Ident(_, Keyword::MINUTE) => Function::Minute,
1581        Token::Ident(_, Keyword::MONTH) => Function::Month,
1582        Token::Ident(_, Keyword::MONTHNAME) => Function::MonthName,
1583        Token::Ident(_, Keyword::PERIOD_ADD) => Function::PeriodAdd,
1584        Token::Ident(_, Keyword::PERIOD_DIFF) => Function::PeriodDiff,
1585        Token::Ident(_, Keyword::QUARTER) => Function::Quarter,
1586        Token::Ident(_, Keyword::SECOND) => Function::Second,
1587        Token::Ident(_, Keyword::SEC_TO_TIME) => Function::SecToTime,
1588        Token::Ident(_, Keyword::STR_TO_DATE) => Function::StrToDate,
1589        Token::Ident(_, Keyword::SUBDATE) => Function::DateSub,
1590        Token::Ident(_, Keyword::SUBTIME) => Function::SubTime,
1591        Token::Ident(_, Keyword::TIME) => Function::Time,
1592        Token::Ident(_, Keyword::LAST_DAY) => Function::LastDay,
1593        Token::Ident(_, Keyword::TIMEDIFF) => Function::TimeDiff,
1594        Token::Ident(_, Keyword::TIMESTAMP) => Function::Timestamp,
1595        Token::Ident(_, Keyword::TIME_FORMAT) => Function::TimeFormat,
1596        Token::Ident(_, Keyword::TIME_TO_SEC) => Function::TimeToSec,
1597        Token::Ident(_, Keyword::TO_DAYS) => Function::ToDays,
1598        Token::Ident(_, Keyword::TO_SECONDS) => Function::ToSeconds,
1599        Token::Ident(_, Keyword::UNIX_TIMESTAMP) => Function::UnixTimestamp,
1600        Token::Ident(_, Keyword::UTC_DATE) => Function::UtcDate,
1601        Token::Ident(_, Keyword::UTC_TIME) => Function::UtcTime,
1602        Token::Ident(_, Keyword::UTC_TIMESTAMP) => Function::UtcTimeStamp,
1603        Token::Ident(_, Keyword::WEEK) => Function::Week,
1604        Token::Ident(_, Keyword::WEEKDAY) => Function::Weekday,
1605        Token::Ident(_, Keyword::WEEKOFYEAR) => Function::WeekOfYear,
1606        Token::Ident(_, Keyword::ADD_MONTHS) => Function::AddMonths,
1607        Token::Ident(_, Keyword::FROM_UNIXTIME) => Function::FromUnixTime,
1608        Token::Ident(_, Keyword::YEAR) => Function::Year,
1609        Token::Ident(_, Keyword::YEARWEEK) => Function::YearWeek,
1610        Token::Ident(_, Keyword::SYSDATE) => Function::SysDate,
1611
1612        // https://mariadb.com/kb/en/json-functions/
1613        Token::Ident(_, Keyword::JSON_ARRAY) => Function::JsonArray,
1614        Token::Ident(_, Keyword::JSON_ARRAYAGG) => Function::JsonArrayAgg,
1615        Token::Ident(_, Keyword::JSON_ARRAY_APPEND) => Function::JsonArrayAppend,
1616        Token::Ident(_, Keyword::JSON_ARRAY_INSERT) => Function::JsonArrayInsert,
1617        Token::Ident(_, Keyword::JSON_ARRAY_INTERSECT) => Function::JsonArrayIntersect,
1618        Token::Ident(_, Keyword::JSON_COMPACT) => Function::JsonCompact,
1619        Token::Ident(_, Keyword::JSON_CONTAINS) => Function::JsonContains,
1620        Token::Ident(_, Keyword::JSON_CONTAINS_PATH) => Function::JsonContainsPath,
1621        Token::Ident(_, Keyword::JSON_DEPTH) => Function::JsonDepth,
1622        Token::Ident(_, Keyword::JSON_DETAILED) => Function::JsonDetailed,
1623        Token::Ident(_, Keyword::JSON_EQUALS) => Function::JsonEquals,
1624        Token::Ident(_, Keyword::JSON_EXISTS) => Function::JsonExists,
1625        Token::Ident(_, Keyword::JSON_EXTRACT) => Function::JsonExtract,
1626        Token::Ident(_, Keyword::JSON_INSERT) => Function::JsonInsert,
1627        Token::Ident(_, Keyword::JSON_KEYS) => Function::JsonKeys,
1628        Token::Ident(_, Keyword::JSON_LENGTH) => Function::JsonLength,
1629        Token::Ident(_, Keyword::JSON_LOOSE) => Function::JsonLoose,
1630        Token::Ident(_, Keyword::JSON_MERGE) => Function::JsonMerge,
1631        Token::Ident(_, Keyword::JSON_MERGE_PATCH) => Function::JsonMergePath,
1632        Token::Ident(_, Keyword::JSON_MERGE_PRESERVE) => Function::JsonMergePerserve,
1633        Token::Ident(_, Keyword::JSON_NORMALIZE) => Function::JsonNormalize,
1634        Token::Ident(_, Keyword::JSON_OBJECT) => Function::JsonObject,
1635        Token::Ident(_, Keyword::JSON_OBJECT_FILTER_KEYS) => Function::JsonObjectFilterKeys,
1636        Token::Ident(_, Keyword::JSON_OBJECT_TO_ARRAY) => Function::JsonObjectToArray,
1637        Token::Ident(_, Keyword::JSON_OBJECTAGG) => Function::JsonObjectAgg,
1638        Token::Ident(_, Keyword::JSON_OVERLAPS) => Function::JsonOverlaps,
1639        Token::Ident(_, Keyword::JSON_PRETTY) => Function::JsonPretty,
1640        Token::Ident(_, Keyword::JSON_QUERY) => Function::JsonQuery,
1641        Token::Ident(_, Keyword::JSON_QUOTE) => Function::JsonQuote,
1642        Token::Ident(_, Keyword::JSON_REMOVE) => Function::JsonRemove,
1643        Token::Ident(_, Keyword::JSON_REPLACE) => Function::JsonReplace,
1644        Token::Ident(_, Keyword::JSON_SCHEMA_VALID) => Function::JsonSchemaValid,
1645        Token::Ident(_, Keyword::JSON_SEARCH) => Function::JsonSearch,
1646        Token::Ident(_, Keyword::JSON_SET) => Function::JsonSet,
1647        Token::Ident(_, Keyword::JSON_TABLE) => Function::JsonTable,
1648        Token::Ident(_, Keyword::JSON_TYPE) => Function::JsonType,
1649        Token::Ident(_, Keyword::JSON_UNQUOTE) => Function::JsonUnquote,
1650        Token::Ident(_, Keyword::JSON_VALID) => Function::JsonValid,
1651        Token::Ident(_, Keyword::JSON_VALUE) => Function::JsonValue,
1652
1653        // Sqlite
1654        Token::Ident(_, Keyword::STRFTIME) if parser.options.dialect.is_sqlite() => {
1655            Function::Strftime
1656        }
1657        Token::Ident(_, Keyword::DATETIME) if parser.options.dialect.is_sqlite() => {
1658            Function::Datetime
1659        }
1660
1661        // MySQL 8.4 encryption / compression
1662        Token::Ident(_, Keyword::AES_DECRYPT) if parser.options.dialect.is_maria() => {
1663            Function::AesDecrypt
1664        }
1665        Token::Ident(_, Keyword::AES_ENCRYPT) if parser.options.dialect.is_maria() => {
1666            Function::AesEncrypt
1667        }
1668        Token::Ident(_, Keyword::COMPRESS) if parser.options.dialect.is_maria() => {
1669            Function::Compress
1670        }
1671        Token::Ident(_, Keyword::MD5) if parser.options.dialect.is_maria() => Function::Md5,
1672        Token::Ident(_, Keyword::RANDOM_BYTES) if parser.options.dialect.is_maria() => {
1673            Function::RandomBytes
1674        }
1675        Token::Ident(_, Keyword::SHA) if parser.options.dialect.is_maria() => Function::Sha,
1676        Token::Ident(_, Keyword::SHA1) if parser.options.dialect.is_maria() => Function::Sha1,
1677        Token::Ident(_, Keyword::SHA2) if parser.options.dialect.is_maria() => Function::Sha2,
1678        Token::Ident(_, Keyword::STATEMENT_DIGEST) if parser.options.dialect.is_maria() => {
1679            Function::StatementDigest
1680        }
1681        Token::Ident(_, Keyword::STATEMENT_DIGEST_TEXT) if parser.options.dialect.is_maria() => {
1682            Function::StatementDigestText
1683        }
1684        Token::Ident(_, Keyword::UNCOMPRESS) if parser.options.dialect.is_maria() => {
1685            Function::Uncompress
1686        }
1687        Token::Ident(_, Keyword::VALIDATE_PASSWORD_STRENGTH)
1688            if parser.options.dialect.is_maria() =>
1689        {
1690            Function::ValidatePasswordStrength
1691        }
1692
1693        // MySQL 8.4 locking
1694        Token::Ident(_, Keyword::GET_LOCK) if parser.options.dialect.is_maria() => {
1695            Function::GetLock
1696        }
1697        Token::Ident(_, Keyword::IS_FREE_LOCK) if parser.options.dialect.is_maria() => {
1698            Function::IsFreeLock
1699        }
1700        Token::Ident(_, Keyword::IS_USED_LOCK) if parser.options.dialect.is_maria() => {
1701            Function::IsUsedLock
1702        }
1703        Token::Ident(_, Keyword::RELEASE_ALL_LOCKS) if parser.options.dialect.is_maria() => {
1704            Function::ReleaseAllLocks
1705        }
1706        Token::Ident(_, Keyword::RELEASE_LOCK) if parser.options.dialect.is_maria() => {
1707            Function::ReleaseLock
1708        }
1709
1710        // MySQL 8.4 information
1711        Token::Ident(_, Keyword::BENCHMARK) if parser.options.dialect.is_maria() => {
1712            Function::Benchmark
1713        }
1714        Token::Ident(_, Keyword::CHARSET) if parser.options.dialect.is_maria() => Function::Charset,
1715        Token::Ident(_, Keyword::COERCIBILITY) if parser.options.dialect.is_maria() => {
1716            Function::Coercibility
1717        }
1718        Token::Ident(_, Keyword::COLLATION) if parser.options.dialect.is_maria() => {
1719            Function::Collation
1720        }
1721        Token::Ident(_, Keyword::CONNECTION_ID) if parser.options.dialect.is_maria() => {
1722            Function::ConnectionId
1723        }
1724        Token::Ident(_, Keyword::CURRENT_ROLE) => Function::CurrentRole,
1725        Token::Ident(_, Keyword::CURRENT_USER) => Function::CurrentUser,
1726        Token::Ident(_, Keyword::DATABASE) if parser.options.dialect.is_maria() => {
1727            Function::DatabaseFunc
1728        }
1729        Token::Ident(_, Keyword::FOUND_ROWS) if parser.options.dialect.is_maria() => {
1730            Function::FoundRows
1731        }
1732        Token::Ident(_, Keyword::ICU_VERSION) if parser.options.dialect.is_maria() => {
1733            Function::IcuVersion
1734        }
1735        Token::Ident(_, Keyword::LAST_INSERT_ID) if parser.options.dialect.is_maria() => {
1736            Function::LastInsertId
1737        }
1738        Token::Ident(_, Keyword::ROLES_GRAPHML) if parser.options.dialect.is_maria() => {
1739            Function::RolesGraphml
1740        }
1741        Token::Ident(_, Keyword::ROW_COUNT) if parser.options.dialect.is_maria() => {
1742            Function::RowCount
1743        }
1744        Token::Ident(_, Keyword::SCHEMA) if parser.options.dialect.is_maria() => {
1745            Function::SchemaFunc
1746        }
1747        Token::Ident(_, Keyword::SESSION_USER) => Function::SessionUserFunc,
1748        Token::Ident(_, Keyword::SYSTEM_USER) if parser.options.dialect.is_maria() => {
1749            Function::SystemUser
1750        }
1751        Token::Ident(_, Keyword::USER) if parser.options.dialect.is_maria() => Function::UserFunc,
1752        Token::Ident(_, Keyword::VERSION) => Function::Version,
1753        // PostgreSQL system functions
1754        Token::Ident(_, Keyword::INET_SERVER_ADDR) if parser.options.dialect.is_postgresql() => {
1755            Function::InetServerAddr
1756        }
1757        Token::Ident(_, Keyword::INET_SERVER_PORT) if parser.options.dialect.is_postgresql() => {
1758            Function::InetServerPort
1759        }
1760        Token::Ident(_, Keyword::JSON_BUILD_OBJECT) if parser.options.dialect.is_postgresql() => {
1761            Function::JsonBuildObject
1762        }
1763        Token::Ident(_, Keyword::JSONB_SET) if parser.options.dialect.is_postgresql() => {
1764            Function::JsonbSet
1765        }
1766        Token::Ident(_, Keyword::PG_POSTMASTER_START_TIME)
1767            if parser.options.dialect.is_postgresql() =>
1768        {
1769            Function::PgPostmasterStartTime
1770        }
1771        Token::Ident(_, Keyword::POSTGIS_FULL_VERSION) if parser.options.dialect.is_postgis() => {
1772            Function::PostgisFullVersion
1773        }
1774        // PostgreSQL system information functions (9.27)
1775        Token::Ident(_, Keyword::COL_DESCRIPTION) if parser.options.dialect.is_postgresql() => {
1776            Function::ColDescription
1777        }
1778        Token::Ident(_, Keyword::CURRENT_DATABASE) if parser.options.dialect.is_postgresql() => {
1779            Function::CurrentDatabase
1780        }
1781        Token::Ident(_, Keyword::CURRENT_QUERY) if parser.options.dialect.is_postgresql() => {
1782            Function::CurrentQuery
1783        }
1784        Token::Ident(_, Keyword::CURRENT_SCHEMAS) if parser.options.dialect.is_postgresql() => {
1785            Function::CurrentSchemas
1786        }
1787        Token::Ident(_, Keyword::FORMAT_TYPE) if parser.options.dialect.is_postgresql() => {
1788            Function::FormatType
1789        }
1790        Token::Ident(_, Keyword::HAS_ANY_COLUMN_PRIVILEGE)
1791            if parser.options.dialect.is_postgresql() =>
1792        {
1793            Function::HasAnyColumnPrivilege
1794        }
1795        Token::Ident(_, Keyword::HAS_COLUMN_PRIVILEGE)
1796            if parser.options.dialect.is_postgresql() =>
1797        {
1798            Function::HasColumnPrivilege
1799        }
1800        Token::Ident(_, Keyword::HAS_DATABASE_PRIVILEGE)
1801            if parser.options.dialect.is_postgresql() =>
1802        {
1803            Function::HasDatabasePrivilege
1804        }
1805        Token::Ident(_, Keyword::HAS_FOREIGN_DATA_WRAPPER_PRIVILEGE)
1806            if parser.options.dialect.is_postgresql() =>
1807        {
1808            Function::HasForeignDataWrapperPrivilege
1809        }
1810        Token::Ident(_, Keyword::HAS_FUNCTION_PRIVILEGE)
1811            if parser.options.dialect.is_postgresql() =>
1812        {
1813            Function::HasFunctionPrivilege
1814        }
1815        Token::Ident(_, Keyword::HAS_LANGUAGE_PRIVILEGE)
1816            if parser.options.dialect.is_postgresql() =>
1817        {
1818            Function::HasLanguagePrivilege
1819        }
1820        Token::Ident(_, Keyword::HAS_LARGEOBJECT_PRIVILEGE)
1821            if parser.options.dialect.is_postgresql() =>
1822        {
1823            Function::HasLargeobjectPrivilege
1824        }
1825        Token::Ident(_, Keyword::HAS_PARAMETER_PRIVILEGE)
1826            if parser.options.dialect.is_postgresql() =>
1827        {
1828            Function::HasParameterPrivilege
1829        }
1830        Token::Ident(_, Keyword::HAS_SCHEMA_PRIVILEGE)
1831            if parser.options.dialect.is_postgresql() =>
1832        {
1833            Function::HasSchemaPrivilege
1834        }
1835        Token::Ident(_, Keyword::HAS_SEQUENCE_PRIVILEGE)
1836            if parser.options.dialect.is_postgresql() =>
1837        {
1838            Function::HasSequencePrivilege
1839        }
1840        Token::Ident(_, Keyword::HAS_SERVER_PRIVILEGE)
1841            if parser.options.dialect.is_postgresql() =>
1842        {
1843            Function::HasServerPrivilege
1844        }
1845        Token::Ident(_, Keyword::HAS_TABLE_PRIVILEGE) if parser.options.dialect.is_postgresql() => {
1846            Function::HasTablePrivilege
1847        }
1848        Token::Ident(_, Keyword::HAS_TABLESPACE_PRIVILEGE)
1849            if parser.options.dialect.is_postgresql() =>
1850        {
1851            Function::HasTablespacePrivilege
1852        }
1853        Token::Ident(_, Keyword::HAS_TYPE_PRIVILEGE) if parser.options.dialect.is_postgresql() => {
1854            Function::HasTypePrivilege
1855        }
1856        Token::Ident(_, Keyword::ICU_UNICODE_VERSION) if parser.options.dialect.is_postgresql() => {
1857            Function::IcuUnicodeVersion
1858        }
1859        Token::Ident(_, Keyword::INET_CLIENT_ADDR) if parser.options.dialect.is_postgresql() => {
1860            Function::InetClientAddr
1861        }
1862        Token::Ident(_, Keyword::INET_CLIENT_PORT) if parser.options.dialect.is_postgresql() => {
1863            Function::InetClientPort
1864        }
1865        Token::Ident(_, Keyword::MAKEACLITEM) if parser.options.dialect.is_postgresql() => {
1866            Function::Makeaclitem
1867        }
1868        Token::Ident(_, Keyword::MXID_AGE) if parser.options.dialect.is_postgresql() => {
1869            Function::MxidAge
1870        }
1871        Token::Ident(_, Keyword::OBJ_DESCRIPTION) if parser.options.dialect.is_postgresql() => {
1872            Function::ObjDescription
1873        }
1874        Token::Ident(_, Keyword::PG_AVAILABLE_WAL_SUMMARIES)
1875            if parser.options.dialect.is_postgresql() =>
1876        {
1877            Function::PgAvailableWalSummaries
1878        }
1879        Token::Ident(_, Keyword::PG_BACKEND_PID) if parser.options.dialect.is_postgresql() => {
1880            Function::PgBackendPid
1881        }
1882        Token::Ident(_, Keyword::PG_BLOCKING_PIDS) if parser.options.dialect.is_postgresql() => {
1883            Function::PgBlockingPids
1884        }
1885        Token::Ident(_, Keyword::PG_CHAR_TO_ENCODING) if parser.options.dialect.is_postgresql() => {
1886            Function::PgCharToEncoding
1887        }
1888        Token::Ident(_, Keyword::PG_COLLATION_IS_VISIBLE)
1889            if parser.options.dialect.is_postgresql() =>
1890        {
1891            Function::PgCollationIsVisible
1892        }
1893        Token::Ident(_, Keyword::PG_CONF_LOAD_TIME) if parser.options.dialect.is_postgresql() => {
1894            Function::PgConfLoadTime
1895        }
1896        Token::Ident(_, Keyword::PG_CONTROL_CHECKPOINT)
1897            if parser.options.dialect.is_postgresql() =>
1898        {
1899            Function::PgControlCheckpoint
1900        }
1901        Token::Ident(_, Keyword::PG_CONTROL_INIT) if parser.options.dialect.is_postgresql() => {
1902            Function::PgControlInit
1903        }
1904        Token::Ident(_, Keyword::PG_CONTROL_RECOVERY) if parser.options.dialect.is_postgresql() => {
1905            Function::PgControlRecovery
1906        }
1907        Token::Ident(_, Keyword::PG_CONTROL_SYSTEM) if parser.options.dialect.is_postgresql() => {
1908            Function::PgControlSystem
1909        }
1910        Token::Ident(_, Keyword::PG_CONVERSION_IS_VISIBLE)
1911            if parser.options.dialect.is_postgresql() =>
1912        {
1913            Function::PgConversionIsVisible
1914        }
1915        Token::Ident(_, Keyword::PG_CURRENT_LOGFILE) if parser.options.dialect.is_postgresql() => {
1916            Function::PgCurrentLogfile
1917        }
1918        Token::Ident(_, Keyword::PG_CURRENT_SNAPSHOT) if parser.options.dialect.is_postgresql() => {
1919            Function::PgCurrentSnapshot
1920        }
1921        Token::Ident(_, Keyword::PG_CURRENT_XACT_ID) if parser.options.dialect.is_postgresql() => {
1922            Function::PgCurrentXactId
1923        }
1924        Token::Ident(_, Keyword::PG_CURRENT_XACT_ID_IF_ASSIGNED)
1925            if parser.options.dialect.is_postgresql() =>
1926        {
1927            Function::PgCurrentXactIdIfAssigned
1928        }
1929        Token::Ident(_, Keyword::PG_DESCRIBE_OBJECT) if parser.options.dialect.is_postgresql() => {
1930            Function::PgDescribeObject
1931        }
1932        Token::Ident(_, Keyword::PG_ENCODING_TO_CHAR) if parser.options.dialect.is_postgresql() => {
1933            Function::PgEncodingToChar
1934        }
1935        Token::Ident(_, Keyword::PG_FUNCTION_IS_VISIBLE)
1936            if parser.options.dialect.is_postgresql() =>
1937        {
1938            Function::PgFunctionIsVisible
1939        }
1940        Token::Ident(_, Keyword::PG_GET_ACL) if parser.options.dialect.is_postgresql() => {
1941            Function::PgGetAcl
1942        }
1943        Token::Ident(_, Keyword::PG_GET_CONSTRAINTDEF)
1944            if parser.options.dialect.is_postgresql() =>
1945        {
1946            Function::PgGetConstraintdef
1947        }
1948        Token::Ident(_, Keyword::PG_GET_EXPR) if parser.options.dialect.is_postgresql() => {
1949            Function::PgGetExpr
1950        }
1951        Token::Ident(_, Keyword::PG_GET_FUNCTIONDEF) if parser.options.dialect.is_postgresql() => {
1952            Function::PgGetFunctiondef
1953        }
1954        Token::Ident(_, Keyword::PG_GET_FUNCTION_ARGUMENTS)
1955            if parser.options.dialect.is_postgresql() =>
1956        {
1957            Function::PgGetFunctionArguments
1958        }
1959        Token::Ident(_, Keyword::PG_GET_FUNCTION_IDENTITY_ARGUMENTS)
1960            if parser.options.dialect.is_postgresql() =>
1961        {
1962            Function::PgGetFunctionIdentityArguments
1963        }
1964        Token::Ident(_, Keyword::PG_GET_FUNCTION_RESULT)
1965            if parser.options.dialect.is_postgresql() =>
1966        {
1967            Function::PgGetFunctionResult
1968        }
1969        Token::Ident(_, Keyword::PG_GET_INDEXDEF) if parser.options.dialect.is_postgresql() => {
1970            Function::PgGetIndexdef
1971        }
1972        Token::Ident(_, Keyword::PG_GET_OBJECT_ADDRESS)
1973            if parser.options.dialect.is_postgresql() =>
1974        {
1975            Function::PgGetObjectAddress
1976        }
1977        Token::Ident(_, Keyword::PG_GET_PARTITION_CONSTRAINTDEF)
1978            if parser.options.dialect.is_postgresql() =>
1979        {
1980            Function::PgGetPartitionConstraintdef
1981        }
1982        Token::Ident(_, Keyword::PG_GET_PARTKEYDEF) if parser.options.dialect.is_postgresql() => {
1983            Function::PgGetPartkeydef
1984        }
1985        Token::Ident(_, Keyword::PG_GET_RULEDEF) if parser.options.dialect.is_postgresql() => {
1986            Function::PgGetRuledef
1987        }
1988        Token::Ident(_, Keyword::PG_GET_SERIAL_SEQUENCE)
1989            if parser.options.dialect.is_postgresql() =>
1990        {
1991            Function::PgGetSerialSequence
1992        }
1993        Token::Ident(_, Keyword::PG_GET_STATISTICSOBJDEF)
1994            if parser.options.dialect.is_postgresql() =>
1995        {
1996            Function::PgGetStatisticsobjdef
1997        }
1998        Token::Ident(_, Keyword::PG_GET_TRIGGERDEF) if parser.options.dialect.is_postgresql() => {
1999            Function::PgGetTriggerdef
2000        }
2001        Token::Ident(_, Keyword::PG_GET_USERBYID) if parser.options.dialect.is_postgresql() => {
2002            Function::PgGetUserbyid
2003        }
2004        Token::Ident(_, Keyword::PG_GET_VIEWDEF) if parser.options.dialect.is_postgresql() => {
2005            Function::PgGetViewdef
2006        }
2007        Token::Ident(_, Keyword::PG_GET_WAL_SUMMARIZER_STATE)
2008            if parser.options.dialect.is_postgresql() =>
2009        {
2010            Function::PgGetWalSummarizerState
2011        }
2012        Token::Ident(_, Keyword::PG_HAS_ROLE) if parser.options.dialect.is_postgresql() => {
2013            Function::PgHasRole
2014        }
2015        Token::Ident(_, Keyword::PG_INDEX_COLUMN_HAS_PROPERTY)
2016            if parser.options.dialect.is_postgresql() =>
2017        {
2018            Function::PgIndexColumnHasProperty
2019        }
2020        Token::Ident(_, Keyword::PG_INDEX_HAS_PROPERTY)
2021            if parser.options.dialect.is_postgresql() =>
2022        {
2023            Function::PgIndexHasProperty
2024        }
2025        Token::Ident(_, Keyword::PG_INDEXAM_HAS_PROPERTY)
2026            if parser.options.dialect.is_postgresql() =>
2027        {
2028            Function::PgIndexamHasProperty
2029        }
2030        Token::Ident(_, Keyword::PG_INPUT_ERROR_INFO) if parser.options.dialect.is_postgresql() => {
2031            Function::PgInputErrorInfo
2032        }
2033        Token::Ident(_, Keyword::PG_INPUT_IS_VALID) if parser.options.dialect.is_postgresql() => {
2034            Function::PgInputIsValid
2035        }
2036        Token::Ident(_, Keyword::PG_IS_OTHER_TEMP_SCHEMA)
2037            if parser.options.dialect.is_postgresql() =>
2038        {
2039            Function::PgIsOtherTempSchema
2040        }
2041        Token::Ident(_, Keyword::PG_JIT_AVAILABLE) if parser.options.dialect.is_postgresql() => {
2042            Function::PgJitAvailable
2043        }
2044        Token::Ident(_, Keyword::PG_LAST_COMMITTED_XACT)
2045            if parser.options.dialect.is_postgresql() =>
2046        {
2047            Function::PgLastCommittedXact
2048        }
2049        Token::Ident(_, Keyword::PG_LISTENING_CHANNELS)
2050            if parser.options.dialect.is_postgresql() =>
2051        {
2052            Function::PgListeningChannels
2053        }
2054        Token::Ident(_, Keyword::PG_MY_TEMP_SCHEMA) if parser.options.dialect.is_postgresql() => {
2055            Function::PgMyTempSchema
2056        }
2057        Token::Ident(_, Keyword::PG_NOTIFICATION_QUEUE_USAGE)
2058            if parser.options.dialect.is_postgresql() =>
2059        {
2060            Function::PgNotificationQueueUsage
2061        }
2062        Token::Ident(_, Keyword::PG_OPCLASS_IS_VISIBLE)
2063            if parser.options.dialect.is_postgresql() =>
2064        {
2065            Function::PgOpclassIsVisible
2066        }
2067        Token::Ident(_, Keyword::PG_OPERATOR_IS_VISIBLE)
2068            if parser.options.dialect.is_postgresql() =>
2069        {
2070            Function::PgOperatorIsVisible
2071        }
2072        Token::Ident(_, Keyword::PG_OPFAMILY_IS_VISIBLE)
2073            if parser.options.dialect.is_postgresql() =>
2074        {
2075            Function::PgOpfamilyIsVisible
2076        }
2077        Token::Ident(_, Keyword::PG_SAFE_SNAPSHOT_BLOCKING_PIDS)
2078            if parser.options.dialect.is_postgresql() =>
2079        {
2080            Function::PgSafeSnapshotBlockingPids
2081        }
2082        Token::Ident(_, Keyword::PG_SETTINGS_GET_FLAGS)
2083            if parser.options.dialect.is_postgresql() =>
2084        {
2085            Function::PgSettingsGetFlags
2086        }
2087        Token::Ident(_, Keyword::PG_SNAPSHOT_XIP) if parser.options.dialect.is_postgresql() => {
2088            Function::PgSnapshotXip
2089        }
2090        Token::Ident(_, Keyword::PG_SNAPSHOT_XMAX) if parser.options.dialect.is_postgresql() => {
2091            Function::PgSnapshotXmax
2092        }
2093        Token::Ident(_, Keyword::PG_SNAPSHOT_XMIN) if parser.options.dialect.is_postgresql() => {
2094            Function::PgSnapshotXmin
2095        }
2096        Token::Ident(_, Keyword::PG_STATISTICS_OBJ_IS_VISIBLE)
2097            if parser.options.dialect.is_postgresql() =>
2098        {
2099            Function::PgStatisticsObjIsVisible
2100        }
2101        Token::Ident(_, Keyword::PG_TABLE_IS_VISIBLE) if parser.options.dialect.is_postgresql() => {
2102            Function::PgTableIsVisible
2103        }
2104        Token::Ident(_, Keyword::PG_TABLESPACE_LOCATION)
2105            if parser.options.dialect.is_postgresql() =>
2106        {
2107            Function::PgTablespaceLocation
2108        }
2109        Token::Ident(_, Keyword::PG_TRIGGER_DEPTH) if parser.options.dialect.is_postgresql() => {
2110            Function::PgTriggerDepth
2111        }
2112        Token::Ident(_, Keyword::PG_TS_CONFIG_IS_VISIBLE)
2113            if parser.options.dialect.is_postgresql() =>
2114        {
2115            Function::PgTsConfigIsVisible
2116        }
2117        Token::Ident(_, Keyword::PG_TS_DICT_IS_VISIBLE)
2118            if parser.options.dialect.is_postgresql() =>
2119        {
2120            Function::PgTsDictIsVisible
2121        }
2122        Token::Ident(_, Keyword::PG_TS_PARSER_IS_VISIBLE)
2123            if parser.options.dialect.is_postgresql() =>
2124        {
2125            Function::PgTsParserIsVisible
2126        }
2127        Token::Ident(_, Keyword::PG_TS_TEMPLATE_IS_VISIBLE)
2128            if parser.options.dialect.is_postgresql() =>
2129        {
2130            Function::PgTsTemplateIsVisible
2131        }
2132        Token::Ident(_, Keyword::PG_TYPE_IS_VISIBLE) if parser.options.dialect.is_postgresql() => {
2133            Function::PgTypeIsVisible
2134        }
2135        Token::Ident(_, Keyword::PG_TYPEOF) if parser.options.dialect.is_postgresql() => {
2136            Function::PgTypeof
2137        }
2138        Token::Ident(_, Keyword::PG_VISIBLE_IN_SNAPSHOT)
2139            if parser.options.dialect.is_postgresql() =>
2140        {
2141            Function::PgVisibleInSnapshot
2142        }
2143        Token::Ident(_, Keyword::PG_XACT_COMMIT_TIMESTAMP)
2144            if parser.options.dialect.is_postgresql() =>
2145        {
2146            Function::PgXactCommitTimestamp
2147        }
2148        Token::Ident(_, Keyword::PG_XACT_STATUS) if parser.options.dialect.is_postgresql() => {
2149            Function::PgXactStatus
2150        }
2151        Token::Ident(_, Keyword::ROW_SECURITY_ACTIVE) if parser.options.dialect.is_postgresql() => {
2152            Function::RowSecurityActive
2153        }
2154        Token::Ident(_, Keyword::SHOBJ_DESCRIPTION) if parser.options.dialect.is_postgresql() => {
2155            Function::ShobjDescription
2156        }
2157        Token::Ident(_, Keyword::TO_REGCLASS) if parser.options.dialect.is_postgresql() => {
2158            Function::ToRegclass
2159        }
2160        Token::Ident(_, Keyword::TO_REGCOLLATION) if parser.options.dialect.is_postgresql() => {
2161            Function::ToRegcollation
2162        }
2163        Token::Ident(_, Keyword::TO_REGNAMESPACE) if parser.options.dialect.is_postgresql() => {
2164            Function::ToRegnamespace
2165        }
2166        Token::Ident(_, Keyword::TO_REGOPER) if parser.options.dialect.is_postgresql() => {
2167            Function::ToRegoper
2168        }
2169        Token::Ident(_, Keyword::TO_REGOPERATOR) if parser.options.dialect.is_postgresql() => {
2170            Function::ToRegoperator
2171        }
2172        Token::Ident(_, Keyword::TO_REGPROC) if parser.options.dialect.is_postgresql() => {
2173            Function::ToRegproc
2174        }
2175        Token::Ident(_, Keyword::TO_REGPROCEDURE) if parser.options.dialect.is_postgresql() => {
2176            Function::ToRegprocedure
2177        }
2178        Token::Ident(_, Keyword::TO_REGROLE) if parser.options.dialect.is_postgresql() => {
2179            Function::ToRegrole
2180        }
2181        Token::Ident(_, Keyword::TO_REGTYPE) if parser.options.dialect.is_postgresql() => {
2182            Function::ToRegtype
2183        }
2184        Token::Ident(_, Keyword::TO_REGTYPEMOD) if parser.options.dialect.is_postgresql() => {
2185            Function::ToRegtypemod
2186        }
2187        Token::Ident(_, Keyword::UNICODE_VERSION) if parser.options.dialect.is_postgresql() => {
2188            Function::UnicodeVersion
2189        }
2190
2191        // PostgreSQL network address functions
2192        Token::Ident(_, Keyword::ABBREV) if parser.options.dialect.is_postgresql() => {
2193            Function::Abbrev
2194        }
2195        Token::Ident(_, Keyword::BROADCAST) if parser.options.dialect.is_postgresql() => {
2196            Function::Broadcast
2197        }
2198        Token::Ident(_, Keyword::FAMILY) if parser.options.dialect.is_postgresql() => {
2199            Function::Family
2200        }
2201        Token::Ident(_, Keyword::HOST) if parser.options.dialect.is_postgresql() => Function::Host,
2202        Token::Ident(_, Keyword::HOSTMASK) if parser.options.dialect.is_postgresql() => {
2203            Function::HostMask
2204        }
2205        Token::Ident(_, Keyword::INET_MERGE) if parser.options.dialect.is_postgresql() => {
2206            Function::InetMerge
2207        }
2208        Token::Ident(_, Keyword::INET_SAME_FAMILY) if parser.options.dialect.is_postgresql() => {
2209            Function::InetSameFamily
2210        }
2211        Token::Ident(_, Keyword::MACADDR8_SET7BIT) if parser.options.dialect.is_postgresql() => {
2212            Function::Macaddr8Set7bit
2213        }
2214        Token::Ident(_, Keyword::MASKLEN) if parser.options.dialect.is_postgresql() => {
2215            Function::MaskLen
2216        }
2217        Token::Ident(_, Keyword::NETMASK) if parser.options.dialect.is_postgresql() => {
2218            Function::NetMask
2219        }
2220        Token::Ident(_, Keyword::NETWORK) if parser.options.dialect.is_postgresql() => {
2221            Function::Network
2222        }
2223        Token::Ident(_, Keyword::SET_MASKLEN) if parser.options.dialect.is_postgresql() => {
2224            Function::SetMaskLen
2225        }
2226
2227        // PostgreSQL UUID functions
2228        Token::Ident(_, Keyword::GEN_RANDOM_UUID) if parser.options.dialect.is_postgresql() => {
2229            Function::GenRandomUuid
2230        }
2231        Token::Ident(_, Keyword::UUID_EXTRACT_TIMESTAMP)
2232            if parser.options.dialect.is_postgresql() =>
2233        {
2234            Function::UuidExtractTimestamp
2235        }
2236        Token::Ident(_, Keyword::UUID_EXTRACT_VERSION)
2237            if parser.options.dialect.is_postgresql() =>
2238        {
2239            Function::UuidExtractVersion
2240        }
2241        Token::Ident(_, Keyword::UUIDV4) if parser.options.dialect.is_postgresql() => {
2242            Function::Uuidv4
2243        }
2244        Token::Ident(_, Keyword::UUIDV7) if parser.options.dialect.is_postgresql() => {
2245            Function::Uuidv7
2246        }
2247
2248        // PostgreSQL XML functions
2249        Token::Ident(_, Keyword::CURSOR_TO_XML) if parser.options.dialect.is_postgresql() => {
2250            Function::CursorToXml
2251        }
2252        Token::Ident(_, Keyword::CURSOR_TO_XMLSCHEMA) if parser.options.dialect.is_postgresql() => {
2253            Function::CursorToXmlschema
2254        }
2255        Token::Ident(_, Keyword::DATABASE_TO_XML) if parser.options.dialect.is_postgresql() => {
2256            Function::DatabaseToXml
2257        }
2258        Token::Ident(_, Keyword::DATABASE_TO_XML_AND_XMLSCHEMA)
2259            if parser.options.dialect.is_postgresql() =>
2260        {
2261            Function::DatabaseToXmlAndXmlschema
2262        }
2263        Token::Ident(_, Keyword::DATABASE_TO_XMLSCHEMA)
2264            if parser.options.dialect.is_postgresql() =>
2265        {
2266            Function::DatabaseToXmlschema
2267        }
2268        Token::Ident(_, Keyword::QUERY_TO_XML) if parser.options.dialect.is_postgresql() => {
2269            Function::QueryToXml
2270        }
2271        Token::Ident(_, Keyword::QUERY_TO_XML_AND_XMLSCHEMA)
2272            if parser.options.dialect.is_postgresql() =>
2273        {
2274            Function::QueryToXmlAndXmlschema
2275        }
2276        Token::Ident(_, Keyword::QUERY_TO_XMLSCHEMA) if parser.options.dialect.is_postgresql() => {
2277            Function::QueryToXmlschema
2278        }
2279        Token::Ident(_, Keyword::SCHEMA_TO_XML) if parser.options.dialect.is_postgresql() => {
2280            Function::SchemaToXml
2281        }
2282        Token::Ident(_, Keyword::SCHEMA_TO_XML_AND_XMLSCHEMA)
2283            if parser.options.dialect.is_postgresql() =>
2284        {
2285            Function::SchemaToXmlAndXmlschema
2286        }
2287        Token::Ident(_, Keyword::SCHEMA_TO_XMLSCHEMA) if parser.options.dialect.is_postgresql() => {
2288            Function::SchemaToXmlschema
2289        }
2290        Token::Ident(_, Keyword::TABLE_TO_XML) if parser.options.dialect.is_postgresql() => {
2291            Function::TableToXml
2292        }
2293        Token::Ident(_, Keyword::TABLE_TO_XML_AND_XMLSCHEMA)
2294            if parser.options.dialect.is_postgresql() =>
2295        {
2296            Function::TableToXmlAndXmlschema
2297        }
2298        Token::Ident(_, Keyword::TABLE_TO_XMLSCHEMA) if parser.options.dialect.is_postgresql() => {
2299            Function::TableToXmlschema
2300        }
2301        Token::Ident(_, Keyword::XML_IS_WELL_FORMED) if parser.options.dialect.is_postgresql() => {
2302            Function::XmlIsWellFormed
2303        }
2304        Token::Ident(_, Keyword::XML_IS_WELL_FORMED_CONTENT)
2305            if parser.options.dialect.is_postgresql() =>
2306        {
2307            Function::XmlIsWellFormedContent
2308        }
2309        Token::Ident(_, Keyword::XML_IS_WELL_FORMED_DOCUMENT)
2310            if parser.options.dialect.is_postgresql() =>
2311        {
2312            Function::XmlIsWellFormedDocument
2313        }
2314        Token::Ident(_, Keyword::XMLCOMMENT) if parser.options.dialect.is_postgresql() => {
2315            Function::XmlComment
2316        }
2317        Token::Ident(_, Keyword::XMLCONCAT) if parser.options.dialect.is_postgresql() => {
2318            Function::XmlConcat
2319        }
2320        Token::Ident(_, Keyword::XMLTEXT) if parser.options.dialect.is_postgresql() => {
2321            Function::XmlText
2322        }
2323        Token::Ident(_, Keyword::XPATH) if parser.options.dialect.is_postgresql() => {
2324            Function::Xpath
2325        }
2326        Token::Ident(_, Keyword::XPATH_EXISTS) if parser.options.dialect.is_postgresql() => {
2327            Function::XpathExists
2328        }
2329
2330        // PostgreSQL JSON functions
2331        Token::Ident(_, Keyword::ARRAY_TO_JSON) if parser.options.dialect.is_postgresql() => {
2332            Function::ArrayToJson
2333        }
2334        Token::Ident(_, Keyword::JSON_ARRAY_ELEMENTS) if parser.options.dialect.is_postgresql() => {
2335            Function::JsonArrayElements
2336        }
2337        Token::Ident(_, Keyword::JSON_ARRAY_ELEMENTS_TEXT)
2338            if parser.options.dialect.is_postgresql() =>
2339        {
2340            Function::JsonArrayElementsText
2341        }
2342        Token::Ident(_, Keyword::JSON_ARRAY_LENGTH) if parser.options.dialect.is_postgresql() => {
2343            Function::JsonArrayLength
2344        }
2345        Token::Ident(_, Keyword::JSON_BUILD_ARRAY) if parser.options.dialect.is_postgresql() => {
2346            Function::JsonBuildArray
2347        }
2348        Token::Ident(_, Keyword::JSON_EACH) if parser.options.dialect.is_postgresql() => {
2349            Function::JsonEach
2350        }
2351        Token::Ident(_, Keyword::JSON_EACH_TEXT) if parser.options.dialect.is_postgresql() => {
2352            Function::JsonEachText
2353        }
2354        Token::Ident(_, Keyword::JSON_EXTRACT_PATH) if parser.options.dialect.is_postgresql() => {
2355            Function::JsonExtractPath
2356        }
2357        Token::Ident(_, Keyword::JSON_EXTRACT_PATH_TEXT)
2358            if parser.options.dialect.is_postgresql() =>
2359        {
2360            Function::JsonExtractPathText
2361        }
2362        Token::Ident(_, Keyword::JSON_OBJECT_KEYS) if parser.options.dialect.is_postgresql() => {
2363            Function::JsonObjectKeys
2364        }
2365        Token::Ident(_, Keyword::JSON_POPULATE_RECORD)
2366            if parser.options.dialect.is_postgresql() =>
2367        {
2368            Function::JsonPopulateRecord
2369        }
2370        Token::Ident(_, Keyword::JSON_POPULATE_RECORDSET)
2371            if parser.options.dialect.is_postgresql() =>
2372        {
2373            Function::JsonPopulateRecordset
2374        }
2375        Token::Ident(_, Keyword::JSON_SCALAR) if parser.options.dialect.is_postgresql() => {
2376            Function::JsonScalar
2377        }
2378        Token::Ident(_, Keyword::JSON_SERIALIZE) if parser.options.dialect.is_postgresql() => {
2379            Function::JsonSerialize
2380        }
2381        Token::Ident(_, Keyword::JSON_STRIP_NULLS) if parser.options.dialect.is_postgresql() => {
2382            Function::JsonStripNulls
2383        }
2384        Token::Ident(_, Keyword::JSON_TO_RECORD) if parser.options.dialect.is_postgresql() => {
2385            Function::JsonToRecord
2386        }
2387        Token::Ident(_, Keyword::JSON_TO_RECORDSET) if parser.options.dialect.is_postgresql() => {
2388            Function::JsonToRecordset
2389        }
2390        Token::Ident(_, Keyword::JSON_TYPEOF) if parser.options.dialect.is_postgresql() => {
2391            Function::JsonTypeof
2392        }
2393        Token::Ident(_, Keyword::JSONB_ARRAY_ELEMENTS)
2394            if parser.options.dialect.is_postgresql() =>
2395        {
2396            Function::JsonbArrayElements
2397        }
2398        Token::Ident(_, Keyword::JSONB_ARRAY_ELEMENTS_TEXT)
2399            if parser.options.dialect.is_postgresql() =>
2400        {
2401            Function::JsonbArrayElementsText
2402        }
2403        Token::Ident(_, Keyword::JSONB_ARRAY_LENGTH) if parser.options.dialect.is_postgresql() => {
2404            Function::JsonbArrayLength
2405        }
2406        Token::Ident(_, Keyword::JSONB_BUILD_ARRAY) if parser.options.dialect.is_postgresql() => {
2407            Function::JsonbBuildArray
2408        }
2409        Token::Ident(_, Keyword::JSONB_BUILD_OBJECT) if parser.options.dialect.is_postgresql() => {
2410            Function::JsonbBuildObject
2411        }
2412        Token::Ident(_, Keyword::JSONB_EACH) if parser.options.dialect.is_postgresql() => {
2413            Function::JsonbEach
2414        }
2415        Token::Ident(_, Keyword::JSONB_EACH_TEXT) if parser.options.dialect.is_postgresql() => {
2416            Function::JsonbEachText
2417        }
2418        Token::Ident(_, Keyword::JSONB_EXTRACT_PATH) if parser.options.dialect.is_postgresql() => {
2419            Function::JsonbExtractPath
2420        }
2421        Token::Ident(_, Keyword::JSONB_EXTRACT_PATH_TEXT)
2422            if parser.options.dialect.is_postgresql() =>
2423        {
2424            Function::JsonbExtractPathText
2425        }
2426        Token::Ident(_, Keyword::JSONB_INSERT) if parser.options.dialect.is_postgresql() => {
2427            Function::JsonbInsert
2428        }
2429        Token::Ident(_, Keyword::JSONB_OBJECT) if parser.options.dialect.is_postgresql() => {
2430            Function::JsonbObject
2431        }
2432        Token::Ident(_, Keyword::JSONB_OBJECT_KEYS) if parser.options.dialect.is_postgresql() => {
2433            Function::JsonbObjectKeys
2434        }
2435        Token::Ident(_, Keyword::JSONB_PATH_EXISTS) if parser.options.dialect.is_postgresql() => {
2436            Function::JsonbPathExists
2437        }
2438        Token::Ident(_, Keyword::JSONB_PATH_EXISTS_TZ)
2439            if parser.options.dialect.is_postgresql() =>
2440        {
2441            Function::JsonbPathExistsTz
2442        }
2443        Token::Ident(_, Keyword::JSONB_PATH_MATCH) if parser.options.dialect.is_postgresql() => {
2444            Function::JsonbPathMatch
2445        }
2446        Token::Ident(_, Keyword::JSONB_PATH_MATCH_TZ) if parser.options.dialect.is_postgresql() => {
2447            Function::JsonbPathMatchTz
2448        }
2449        Token::Ident(_, Keyword::JSONB_PATH_QUERY) if parser.options.dialect.is_postgresql() => {
2450            Function::JsonbPathQuery
2451        }
2452        Token::Ident(_, Keyword::JSONB_PATH_QUERY_ARRAY)
2453            if parser.options.dialect.is_postgresql() =>
2454        {
2455            Function::JsonbPathQueryArray
2456        }
2457        Token::Ident(_, Keyword::JSONB_PATH_QUERY_ARRAY_TZ)
2458            if parser.options.dialect.is_postgresql() =>
2459        {
2460            Function::JsonbPathQueryArrayTz
2461        }
2462        Token::Ident(_, Keyword::JSONB_PATH_QUERY_FIRST)
2463            if parser.options.dialect.is_postgresql() =>
2464        {
2465            Function::JsonbPathQueryFirst
2466        }
2467        Token::Ident(_, Keyword::JSONB_PATH_QUERY_FIRST_TZ)
2468            if parser.options.dialect.is_postgresql() =>
2469        {
2470            Function::JsonbPathQueryFirstTz
2471        }
2472        Token::Ident(_, Keyword::JSONB_PATH_QUERY_TZ) if parser.options.dialect.is_postgresql() => {
2473            Function::JsonbPathQueryTz
2474        }
2475        Token::Ident(_, Keyword::JSONB_POPULATE_RECORD)
2476            if parser.options.dialect.is_postgresql() =>
2477        {
2478            Function::JsonbPopulateRecord
2479        }
2480        Token::Ident(_, Keyword::JSONB_POPULATE_RECORD_VALID)
2481            if parser.options.dialect.is_postgresql() =>
2482        {
2483            Function::JsonbPopulateRecordValid
2484        }
2485        Token::Ident(_, Keyword::JSONB_POPULATE_RECORDSET)
2486            if parser.options.dialect.is_postgresql() =>
2487        {
2488            Function::JsonbPopulateRecordset
2489        }
2490        Token::Ident(_, Keyword::JSONB_PRETTY) if parser.options.dialect.is_postgresql() => {
2491            Function::JsonbPretty
2492        }
2493        Token::Ident(_, Keyword::JSONB_SET_LAX) if parser.options.dialect.is_postgresql() => {
2494            Function::JsonbSetLax
2495        }
2496        Token::Ident(_, Keyword::JSONB_STRIP_NULLS) if parser.options.dialect.is_postgresql() => {
2497            Function::JsonbStripNulls
2498        }
2499        Token::Ident(_, Keyword::JSONB_TO_RECORD) if parser.options.dialect.is_postgresql() => {
2500            Function::JsonbToRecord
2501        }
2502        Token::Ident(_, Keyword::JSONB_TO_RECORDSET) if parser.options.dialect.is_postgresql() => {
2503            Function::JsonbToRecordset
2504        }
2505        Token::Ident(_, Keyword::JSONB_TYPEOF) if parser.options.dialect.is_postgresql() => {
2506            Function::JsonbTypeof
2507        }
2508        Token::Ident(_, Keyword::ROW_TO_JSON) if parser.options.dialect.is_postgresql() => {
2509            Function::RowToJson
2510        }
2511        Token::Ident(_, Keyword::TO_JSON) if parser.options.dialect.is_postgresql() => {
2512            Function::ToJson
2513        }
2514        Token::Ident(_, Keyword::TO_JSONB) if parser.options.dialect.is_postgresql() => {
2515            Function::ToJsonb
2516        }
2517
2518        // PostgreSQL sequence functions
2519        Token::Ident(_, Keyword::CURRVAL) if parser.options.dialect.is_postgresql() => {
2520            Function::Currval
2521        }
2522        Token::Ident(_, Keyword::LASTVAL) if parser.options.dialect.is_postgresql() => {
2523            Function::Lastval
2524        }
2525        Token::Ident(_, Keyword::NEXTVAL) if parser.options.dialect.is_postgresql() => {
2526            Function::Nextval
2527        }
2528        Token::Ident(_, Keyword::SETVAL) if parser.options.dialect.is_postgresql() => {
2529            Function::Setval
2530        }
2531
2532        // PostgreSQL array functions
2533        Token::Ident(_, Keyword::ARRAY_APPEND) if parser.options.dialect.is_postgresql() => {
2534            Function::ArrayAppend
2535        }
2536        Token::Ident(_, Keyword::ARRAY_CAT) if parser.options.dialect.is_postgresql() => {
2537            Function::ArrayCat
2538        }
2539        Token::Ident(_, Keyword::ARRAY_DIMS) if parser.options.dialect.is_postgresql() => {
2540            Function::ArrayDims
2541        }
2542        Token::Ident(_, Keyword::ARRAY_FILL) if parser.options.dialect.is_postgresql() => {
2543            Function::ArrayFill
2544        }
2545        Token::Ident(_, Keyword::ARRAY_LENGTH) if parser.options.dialect.is_postgresql() => {
2546            Function::ArrayLength
2547        }
2548        Token::Ident(_, Keyword::ARRAY_LOWER) if parser.options.dialect.is_postgresql() => {
2549            Function::ArrayLower
2550        }
2551        Token::Ident(_, Keyword::ARRAY_NDIMS) if parser.options.dialect.is_postgresql() => {
2552            Function::ArrayNdims
2553        }
2554        Token::Ident(_, Keyword::ARRAY_POSITION) if parser.options.dialect.is_postgresql() => {
2555            Function::ArrayPosition
2556        }
2557        Token::Ident(_, Keyword::ARRAY_POSITIONS) if parser.options.dialect.is_postgresql() => {
2558            Function::ArrayPositions
2559        }
2560        Token::Ident(_, Keyword::ARRAY_PREPEND) if parser.options.dialect.is_postgresql() => {
2561            Function::ArrayPrepend
2562        }
2563        Token::Ident(_, Keyword::ARRAY_REMOVE) if parser.options.dialect.is_postgresql() => {
2564            Function::ArrayRemove
2565        }
2566        Token::Ident(_, Keyword::ARRAY_REPLACE) if parser.options.dialect.is_postgresql() => {
2567            Function::ArrayReplace
2568        }
2569        Token::Ident(_, Keyword::ARRAY_REVERSE) if parser.options.dialect.is_postgresql() => {
2570            Function::ArrayReverse
2571        }
2572        Token::Ident(_, Keyword::ARRAY_SAMPLE) if parser.options.dialect.is_postgresql() => {
2573            Function::ArraySample
2574        }
2575        Token::Ident(_, Keyword::ARRAY_SHUFFLE) if parser.options.dialect.is_postgresql() => {
2576            Function::ArrayShuffle
2577        }
2578        Token::Ident(_, Keyword::ARRAY_SORT) if parser.options.dialect.is_postgresql() => {
2579            Function::ArraySort
2580        }
2581        Token::Ident(_, Keyword::ARRAY_TO_STRING) if parser.options.dialect.is_postgresql() => {
2582            Function::ArrayToString
2583        }
2584        Token::Ident(_, Keyword::ARRAY_UPPER) if parser.options.dialect.is_postgresql() => {
2585            Function::ArrayUpper
2586        }
2587        Token::Ident(_, Keyword::CARDINALITY) if parser.options.dialect.is_postgresql() => {
2588            Function::Cardinality
2589        }
2590        Token::Ident(_, Keyword::TRIM_ARRAY) if parser.options.dialect.is_postgresql() => {
2591            Function::TrimArray
2592        }
2593
2594        // PostgreSQL text search functions
2595        Token::Ident(_, Keyword::ARRAY_TO_TSVECTOR) if parser.options.dialect.is_postgresql() => {
2596            Function::ArrayToTsvector
2597        }
2598        Token::Ident(_, Keyword::GET_CURRENT_TS_CONFIG)
2599            if parser.options.dialect.is_postgresql() =>
2600        {
2601            Function::GetCurrentTsConfig
2602        }
2603        Token::Ident(_, Keyword::JSON_TO_TSVECTOR) if parser.options.dialect.is_postgresql() => {
2604            Function::JsonToTsvector
2605        }
2606        Token::Ident(_, Keyword::JSONB_TO_TSVECTOR) if parser.options.dialect.is_postgresql() => {
2607            Function::JsonbToTsvector
2608        }
2609        Token::Ident(_, Keyword::NUMNODE) if parser.options.dialect.is_postgresql() => {
2610            Function::Numnode
2611        }
2612        Token::Ident(_, Keyword::PHRASETO_TSQUERY) if parser.options.dialect.is_postgresql() => {
2613            Function::PhraseToTsquery
2614        }
2615        Token::Ident(_, Keyword::PLAINTO_TSQUERY) if parser.options.dialect.is_postgresql() => {
2616            Function::PlainToTsquery
2617        }
2618        Token::Ident(_, Keyword::QUERYTREE) if parser.options.dialect.is_postgresql() => {
2619            Function::Querytree
2620        }
2621        Token::Ident(_, Keyword::SETWEIGHT) if parser.options.dialect.is_postgresql() => {
2622            Function::Setweight
2623        }
2624        Token::Ident(_, Keyword::STRIP) if parser.options.dialect.is_postgresql() => {
2625            Function::Strip
2626        }
2627        Token::Ident(_, Keyword::TO_TSQUERY) if parser.options.dialect.is_postgresql() => {
2628            Function::ToTsquery
2629        }
2630        Token::Ident(_, Keyword::TO_TSVECTOR) if parser.options.dialect.is_postgresql() => {
2631            Function::ToTsvector
2632        }
2633        Token::Ident(_, Keyword::TS_DEBUG) if parser.options.dialect.is_postgresql() => {
2634            Function::TsDebug
2635        }
2636        Token::Ident(_, Keyword::TS_DELETE) if parser.options.dialect.is_postgresql() => {
2637            Function::TsDelete
2638        }
2639        Token::Ident(_, Keyword::TS_FILTER) if parser.options.dialect.is_postgresql() => {
2640            Function::TsFilter
2641        }
2642        Token::Ident(_, Keyword::TS_HEADLINE) if parser.options.dialect.is_postgresql() => {
2643            Function::TsHeadline
2644        }
2645        Token::Ident(_, Keyword::TS_LEXIZE) if parser.options.dialect.is_postgresql() => {
2646            Function::TsLexize
2647        }
2648        Token::Ident(_, Keyword::TS_PARSE) if parser.options.dialect.is_postgresql() => {
2649            Function::TsParse
2650        }
2651        Token::Ident(_, Keyword::TS_RANK) if parser.options.dialect.is_postgresql() => {
2652            Function::TsRank
2653        }
2654        Token::Ident(_, Keyword::TS_RANK_CD) if parser.options.dialect.is_postgresql() => {
2655            Function::TsRankCd
2656        }
2657        Token::Ident(_, Keyword::TS_REWRITE) if parser.options.dialect.is_postgresql() => {
2658            Function::TsRewrite
2659        }
2660        Token::Ident(_, Keyword::TS_STAT) if parser.options.dialect.is_postgresql() => {
2661            Function::TsStat
2662        }
2663        Token::Ident(_, Keyword::TS_TOKEN_TYPE) if parser.options.dialect.is_postgresql() => {
2664            Function::TsTokenType
2665        }
2666        Token::Ident(_, Keyword::TSQUERY_PHRASE) if parser.options.dialect.is_postgresql() => {
2667            Function::TsqueryPhrase
2668        }
2669        Token::Ident(_, Keyword::TSVECTOR_TO_ARRAY) if parser.options.dialect.is_postgresql() => {
2670            Function::TsvectorToArray
2671        }
2672        Token::Ident(_, Keyword::UNNEST) if parser.options.dialect.is_postgresql() => {
2673            Function::Unnest
2674        }
2675        Token::Ident(_, Keyword::WEBSEARCH_TO_TSQUERY)
2676            if parser.options.dialect.is_postgresql() =>
2677        {
2678            Function::WebsearchToTsquery
2679        }
2680
2681        // MySQL 8.4 regexp
2682        Token::Ident(_, Keyword::REGEXP_COUNT) if parser.options.dialect.is_maria() => {
2683            Function::RegexpCount
2684        }
2685        Token::Ident(_, Keyword::REGEXP_INSTR) if parser.options.dialect.is_maria() => {
2686            Function::RegexpInstr
2687        }
2688        Token::Ident(_, Keyword::REGEXP_LIKE) if parser.options.dialect.is_maria() => {
2689            Function::RegexpLike
2690        }
2691        Token::Ident(_, Keyword::REGEXP_MATCH) if parser.options.dialect.is_postgresql() => {
2692            Function::RegexpMatch
2693        }
2694        Token::Ident(_, Keyword::REGEXP_MATCHES) if parser.options.dialect.is_postgresql() => {
2695            Function::RegexpMatches
2696        }
2697        Token::Ident(_, Keyword::REGEXP_REPLACE) => Function::RegexpReplace,
2698        Token::Ident(_, Keyword::REGEXP_SPLIT_TO_ARRAY)
2699            if parser.options.dialect.is_postgresql() =>
2700        {
2701            Function::RegexpSplitToArray
2702        }
2703        Token::Ident(_, Keyword::REGEXP_SPLIT_TO_TABLE)
2704            if parser.options.dialect.is_postgresql() =>
2705        {
2706            Function::RegexpSplitToTable
2707        }
2708        Token::Ident(_, Keyword::REGEXP_SUBSTR) if parser.options.dialect.is_maria() => {
2709            Function::RegexpSubstr
2710        }
2711        Token::Ident(_, Keyword::WEIGHT_STRING) if parser.options.dialect.is_maria() => {
2712            Function::WeightString
2713        }
2714
2715        // MySQL 8.4 datetime
2716        Token::Ident(_, Keyword::GET_BIT) if parser.options.dialect.is_maria() => Function::GetBit,
2717        Token::Ident(_, Keyword::GET_FORMAT) if parser.options.dialect.is_maria() => {
2718            Function::GetFormat
2719        }
2720
2721        // MySQL 8.4 window / analytics
2722        Token::Ident(_, Keyword::FIRST_VALUE) if parser.options.dialect.is_maria() => {
2723            Function::FirstValue
2724        }
2725        Token::Ident(_, Keyword::LAST_VALUE) if parser.options.dialect.is_maria() => {
2726            Function::LastValue
2727        }
2728        Token::Ident(_, Keyword::NTH_VALUE) if parser.options.dialect.is_maria() => {
2729            Function::NthValue
2730        }
2731        Token::Ident(_, Keyword::NTILE) if parser.options.dialect.is_maria() => Function::Ntile,
2732        Token::Ident(_, Keyword::ROW_NUMBER) => Function::RowNumber,
2733
2734        // MySQL 8.4 performance schema
2735        Token::Ident(_, Keyword::FORMAT_BYTES) if parser.options.dialect.is_maria() => {
2736            Function::FormatBytes
2737        }
2738        Token::Ident(_, Keyword::FORMAT_PICO_TIME) if parser.options.dialect.is_maria() => {
2739            Function::FormatPicoTime
2740        }
2741        Token::Ident(_, Keyword::PS_CURRENT_THREAD_ID) if parser.options.dialect.is_maria() => {
2742            Function::PsCurrentThreadId
2743        }
2744        Token::Ident(_, Keyword::PS_THREAD_ID) if parser.options.dialect.is_maria() => {
2745            Function::PsThreadId
2746        }
2747
2748        // MySQL 8.4 miscellaneous
2749        Token::Ident(_, Keyword::ANY_VALUE) if parser.options.dialect.is_maria() => {
2750            Function::AnyValue
2751        }
2752        Token::Ident(_, Keyword::BIN_TO_UUID) if parser.options.dialect.is_maria() => {
2753            Function::BinToUuid
2754        }
2755        Token::Ident(_, Keyword::BIT_COUNT) if parser.options.dialect.is_maria() => {
2756            Function::BitCount
2757        }
2758        Token::Ident(_, Keyword::GROUPING) => Function::Grouping,
2759        Token::Ident(_, Keyword::INET6_ATON) if parser.options.dialect.is_maria() => {
2760            Function::Inet6Aton
2761        }
2762        Token::Ident(_, Keyword::INET6_NTOA) if parser.options.dialect.is_maria() => {
2763            Function::Inet6Ntoa
2764        }
2765        Token::Ident(_, Keyword::INET_ATON) if parser.options.dialect.is_maria() => {
2766            Function::InetAton
2767        }
2768        Token::Ident(_, Keyword::INET_NTOA) if parser.options.dialect.is_maria() => {
2769            Function::InetNtoa
2770        }
2771        Token::Ident(_, Keyword::IS_IPV4) if parser.options.dialect.is_maria() => Function::IsIPv4,
2772        Token::Ident(_, Keyword::IS_IPV4_COMPAT) if parser.options.dialect.is_maria() => {
2773            Function::IsIPv4Compat
2774        }
2775        Token::Ident(_, Keyword::IS_IPV4_MAPPED) if parser.options.dialect.is_maria() => {
2776            Function::IsIPv4Mapped
2777        }
2778        Token::Ident(_, Keyword::IS_IPV6) if parser.options.dialect.is_maria() => Function::IsIPv6,
2779        Token::Ident(_, Keyword::IS_UUID) if parser.options.dialect.is_maria() => Function::IsUuid,
2780        Token::Ident(_, Keyword::NAME_CONST) if parser.options.dialect.is_maria() => {
2781            Function::NameConst
2782        }
2783        Token::Ident(_, Keyword::UUID) => Function::Uuid,
2784        Token::Ident(_, Keyword::UUID_SHORT) if parser.options.dialect.is_maria() => {
2785            Function::UuidShort
2786        }
2787        Token::Ident(_, Keyword::UUID_TO_BIN) if parser.options.dialect.is_maria() => {
2788            Function::UuidToBin
2789        }
2790
2791        // PostgreSQL geometric functions (non-PostGIS) - Table 9.37
2792        Token::Ident(_, Keyword::AREA) if parser.options.dialect.is_postgresql() => Function::Area,
2793        Token::Ident(_, Keyword::BOUND_BOX) if parser.options.dialect.is_postgresql() => {
2794            Function::BoundBox
2795        }
2796        Token::Ident(_, Keyword::CENTER) if parser.options.dialect.is_postgresql() => {
2797            Function::Center
2798        }
2799        Token::Ident(_, Keyword::DIAGONAL) if parser.options.dialect.is_postgresql() => {
2800            Function::Diagonal
2801        }
2802        Token::Ident(_, Keyword::DIAMETER) if parser.options.dialect.is_postgresql() => {
2803            Function::Diameter
2804        }
2805        Token::Ident(_, Keyword::HEIGHT) if parser.options.dialect.is_postgresql() => {
2806            Function::Height
2807        }
2808        Token::Ident(_, Keyword::ISCLOSED) if parser.options.dialect.is_postgresql() => {
2809            Function::Isclosed
2810        }
2811        Token::Ident(_, Keyword::ISOPEN) if parser.options.dialect.is_postgresql() => {
2812            Function::IsOpen
2813        }
2814        Token::Ident(_, Keyword::NPOINTS) if parser.options.dialect.is_postgresql() => {
2815            Function::Npoints
2816        }
2817        Token::Ident(_, Keyword::PCLOSE) if parser.options.dialect.is_postgresql() => {
2818            Function::Pclose
2819        }
2820        Token::Ident(_, Keyword::POPEN) if parser.options.dialect.is_postgresql() => {
2821            Function::Popen
2822        }
2823        Token::Ident(_, Keyword::RADIUS) if parser.options.dialect.is_postgresql() => {
2824            Function::Radius
2825        }
2826        Token::Ident(_, Keyword::SLOPE) if parser.options.dialect.is_postgresql() => {
2827            Function::Slope
2828        }
2829        Token::Ident(_, Keyword::WIDTH) if parser.options.dialect.is_postgresql() => {
2830            Function::Width
2831        }
2832
2833        // PostgreSQL enum support functions
2834        Token::Ident(_, Keyword::ENUM_FIRST) if parser.options.dialect.is_postgresql() => {
2835            Function::EnumFirst
2836        }
2837        Token::Ident(_, Keyword::ENUM_LAST) if parser.options.dialect.is_postgresql() => {
2838            Function::EnumLast
2839        }
2840        Token::Ident(_, Keyword::ENUM_RANGE) if parser.options.dialect.is_postgresql() => {
2841            Function::EnumRange
2842        }
2843
2844        // PostGIS / geometry functions
2845        Token::Ident(_, Keyword::BOX2D) if parser.options.dialect.is_postgis() => Function::Box2D,
2846        Token::Ident(_, Keyword::BOX3D) if parser.options.dialect.is_postgis() => Function::Box3D,
2847        Token::Ident(_, Keyword::GEOMETRYTYPE) if parser.options.dialect.is_postgis() => {
2848            Function::GeometryType
2849        }
2850        Token::Ident(_, Keyword::ST_ADDMEASURE) if parser.options.dialect.is_postgis() => {
2851            Function::StAddMeasure
2852        }
2853        Token::Ident(_, Keyword::ST_ADDPOINT) if parser.options.dialect.is_postgis() => {
2854            Function::StAddPoint
2855        }
2856        Token::Ident(_, Keyword::ST_AFFINE) if parser.options.dialect.is_postgis() => {
2857            Function::StAffine
2858        }
2859        Token::Ident(_, Keyword::ST_AREA) if parser.options.dialect.is_postgis() => {
2860            Function::StArea
2861        }
2862        Token::Ident(_, Keyword::ST_ASBINARY) if parser.options.dialect.is_postgis() => {
2863            Function::StAsBinary
2864        }
2865        Token::Ident(_, Keyword::ST_ASEWKB) if parser.options.dialect.is_postgis() => {
2866            Function::StAsEwkb
2867        }
2868        Token::Ident(_, Keyword::ST_ASEWKT) if parser.options.dialect.is_postgis() => {
2869            Function::StAsEwkt
2870        }
2871        Token::Ident(_, Keyword::ST_ASGEOJSON) if parser.options.dialect.is_postgis() => {
2872            Function::StAsGeoJson
2873        }
2874        Token::Ident(_, Keyword::ST_ASGML) if parser.options.dialect.is_postgis() => {
2875            Function::StAsGml
2876        }
2877        Token::Ident(_, Keyword::ST_ASHEXEWKB) if parser.options.dialect.is_postgis() => {
2878            Function::StAsHexEwkb
2879        }
2880        Token::Ident(_, Keyword::ST_ASKML) if parser.options.dialect.is_postgis() => {
2881            Function::StAsKml
2882        }
2883        Token::Ident(_, Keyword::ST_ASSVG) if parser.options.dialect.is_postgis() => {
2884            Function::StAsSvg
2885        }
2886        Token::Ident(_, Keyword::ST_ASTEXT) if parser.options.dialect.is_postgis() => {
2887            Function::StAsText
2888        }
2889        Token::Ident(_, Keyword::ST_AZIMUTH) if parser.options.dialect.is_postgis() => {
2890            Function::StAzimuth
2891        }
2892        Token::Ident(_, Keyword::ST_BOUNDARY) if parser.options.dialect.is_postgis() => {
2893            Function::StBoundary
2894        }
2895        Token::Ident(_, Keyword::ST_BUFFER) if parser.options.dialect.is_postgis() => {
2896            Function::StBuffer
2897        }
2898        Token::Ident(_, Keyword::ST_BUILDAREA) if parser.options.dialect.is_postgis() => {
2899            Function::StBuildArea
2900        }
2901        Token::Ident(_, Keyword::ST_CENTROID) if parser.options.dialect.is_postgis() => {
2902            Function::StCentroid
2903        }
2904        Token::Ident(_, Keyword::ST_CLOSESTPOINT) if parser.options.dialect.is_postgis() => {
2905            Function::StClosestPoint
2906        }
2907        Token::Ident(_, Keyword::ST_COLLECT) if parser.options.dialect.is_postgis() => {
2908            Function::StCollect
2909        }
2910        Token::Ident(_, Keyword::ST_COLLECTIONEXTRACT) if parser.options.dialect.is_postgis() => {
2911            Function::StCollectionExtract
2912        }
2913        Token::Ident(_, Keyword::ST_CONTAINS) if parser.options.dialect.is_postgis() => {
2914            Function::StContains
2915        }
2916        Token::Ident(_, Keyword::ST_CONTAINSPROPERLY) if parser.options.dialect.is_postgis() => {
2917            Function::StContainsProperly
2918        }
2919        Token::Ident(_, Keyword::ST_CONVEXHULL) if parser.options.dialect.is_postgis() => {
2920            Function::StConvexHull
2921        }
2922        Token::Ident(_, Keyword::ST_COORDDIM) if parser.options.dialect.is_postgis() => {
2923            Function::StCoordDim
2924        }
2925        Token::Ident(_, Keyword::ST_COVEREDBY) if parser.options.dialect.is_postgis() => {
2926            Function::StCoveredBy
2927        }
2928        Token::Ident(_, Keyword::ST_COVERS) if parser.options.dialect.is_postgis() => {
2929            Function::StCovers
2930        }
2931        Token::Ident(_, Keyword::ST_CROSSES) if parser.options.dialect.is_postgis() => {
2932            Function::StCrosses
2933        }
2934        Token::Ident(_, Keyword::ST_CURVETOLINE) if parser.options.dialect.is_postgis() => {
2935            Function::StCurveToLine
2936        }
2937        Token::Ident(_, Keyword::ST_DFULLWITHIN) if parser.options.dialect.is_postgis() => {
2938            Function::StDFullyWithin
2939        }
2940        Token::Ident(_, Keyword::ST_DIFFERENCE) if parser.options.dialect.is_postgis() => {
2941            Function::StDifference
2942        }
2943        Token::Ident(_, Keyword::ST_DIMENSION) if parser.options.dialect.is_postgis() => {
2944            Function::StDimension
2945        }
2946        Token::Ident(_, Keyword::ST_DISJOINT) if parser.options.dialect.is_postgis() => {
2947            Function::StDisjoint
2948        }
2949        Token::Ident(_, Keyword::ST_DISTANCE) if parser.options.dialect.is_postgis() => {
2950            Function::StDistance
2951        }
2952        Token::Ident(_, Keyword::ST_DISTANCE_SPHERE) if parser.options.dialect.is_postgis() => {
2953            Function::StDistanceSphere
2954        }
2955        Token::Ident(_, Keyword::ST_DISTANCE_SPHEROID) if parser.options.dialect.is_postgis() => {
2956            Function::StDistanceSpheroidal
2957        }
2958        Token::Ident(_, Keyword::ST_DWITHIN) if parser.options.dialect.is_postgis() => {
2959            Function::StDWithin
2960        }
2961        Token::Ident(_, Keyword::ST_ENDPOINT) if parser.options.dialect.is_postgis() => {
2962            Function::StEndPoint
2963        }
2964        Token::Ident(_, Keyword::ST_ENVELOPE) if parser.options.dialect.is_postgis() => {
2965            Function::StEnvelope
2966        }
2967        Token::Ident(_, Keyword::ST_EQUALS) if parser.options.dialect.is_postgis() => {
2968            Function::StEquals
2969        }
2970        Token::Ident(_, Keyword::ST_EXTERIORRING) if parser.options.dialect.is_postgis() => {
2971            Function::StExteriorRing
2972        }
2973        Token::Ident(_, Keyword::ST_FORCE_2D) if parser.options.dialect.is_postgis() => {
2974            Function::StForce2D
2975        }
2976        Token::Ident(_, Keyword::ST_FORCE_3D) if parser.options.dialect.is_postgis() => {
2977            Function::StForce3D
2978        }
2979        Token::Ident(_, Keyword::ST_FORCE_3DM) if parser.options.dialect.is_postgis() => {
2980            Function::StForce3DM
2981        }
2982        Token::Ident(_, Keyword::ST_FORCE_3DZ) if parser.options.dialect.is_postgis() => {
2983            Function::StForce3DZ
2984        }
2985        Token::Ident(_, Keyword::ST_FORCE_4D) if parser.options.dialect.is_postgis() => {
2986            Function::StForce4D
2987        }
2988        Token::Ident(_, Keyword::ST_FORCE_COLLECTION) if parser.options.dialect.is_postgis() => {
2989            Function::StForceCollection
2990        }
2991        Token::Ident(_, Keyword::ST_FORCERHR) if parser.options.dialect.is_postgis() => {
2992            Function::StForceRHR
2993        }
2994        Token::Ident(_, Keyword::ST_GEOHASH) if parser.options.dialect.is_postgis() => {
2995            Function::StGeoHash
2996        }
2997        Token::Ident(_, Keyword::ST_GEOMCOLLFROMTEXT) if parser.options.dialect.is_postgis() => {
2998            Function::StGeomCollFromText
2999        }
3000        Token::Ident(_, Keyword::ST_GEOMFROMEWKB) if parser.options.dialect.is_postgis() => {
3001            Function::StGeomFromEwkb
3002        }
3003        Token::Ident(_, Keyword::ST_GEOMFROMEWKT) if parser.options.dialect.is_postgis() => {
3004            Function::StGeomFromEwkt
3005        }
3006        Token::Ident(_, Keyword::ST_GEOMFROMGEOJSON) if parser.options.dialect.is_postgis() => {
3007            Function::StGeomFromGeoJson
3008        }
3009        Token::Ident(_, Keyword::ST_GEOMFROMGML) if parser.options.dialect.is_postgis() => {
3010            Function::StGeomFromGml
3011        }
3012        Token::Ident(_, Keyword::ST_GEOMFROMKML) if parser.options.dialect.is_postgis() => {
3013            Function::StGeomFromKml
3014        }
3015        Token::Ident(_, Keyword::ST_GEOMFROMTEXT) if parser.options.dialect.is_postgis() => {
3016            Function::StGeomFromText
3017        }
3018        Token::Ident(_, Keyword::ST_GEOMFROMWKB) if parser.options.dialect.is_postgis() => {
3019            Function::StGeomFromWkb
3020        }
3021        Token::Ident(_, Keyword::ST_GEOMETRYFROMTEXT) if parser.options.dialect.is_postgis() => {
3022            Function::StGeometryFromText
3023        }
3024        Token::Ident(_, Keyword::ST_GEOMETRYN) if parser.options.dialect.is_postgis() => {
3025            Function::StGeometryN
3026        }
3027        Token::Ident(_, Keyword::ST_GEOMETRYTYPE) if parser.options.dialect.is_postgis() => {
3028            Function::StGeometryType
3029        }
3030        Token::Ident(_, Keyword::ST_GMLTOSQL) if parser.options.dialect.is_postgis() => {
3031            Function::StGmlToSQL
3032        }
3033        Token::Ident(_, Keyword::ST_HASARC) if parser.options.dialect.is_postgis() => {
3034            Function::StHasArc
3035        }
3036        Token::Ident(_, Keyword::ST_HAUSDORFFDISTANCE) if parser.options.dialect.is_postgis() => {
3037            Function::StHausdorffDistance
3038        }
3039        Token::Ident(_, Keyword::ST_INTERIORRINGN) if parser.options.dialect.is_postgis() => {
3040            Function::StInteriorRingN
3041        }
3042        Token::Ident(_, Keyword::ST_INTERSECTION) if parser.options.dialect.is_postgis() => {
3043            Function::StIntersection
3044        }
3045        Token::Ident(_, Keyword::ST_INTERSECTS) if parser.options.dialect.is_postgis() => {
3046            Function::StIntersects
3047        }
3048        Token::Ident(_, Keyword::ST_ISCLOSED) if parser.options.dialect.is_postgis() => {
3049            Function::StIsClosed
3050        }
3051        Token::Ident(_, Keyword::ST_ISEMPTY) if parser.options.dialect.is_postgis() => {
3052            Function::StIsEmpty
3053        }
3054        Token::Ident(_, Keyword::ST_ISRING) if parser.options.dialect.is_postgis() => {
3055            Function::StIsRing
3056        }
3057        Token::Ident(_, Keyword::ST_ISSIMPLE) if parser.options.dialect.is_postgis() => {
3058            Function::StIsSimple
3059        }
3060        Token::Ident(_, Keyword::ST_ISVALID) if parser.options.dialect.is_postgis() => {
3061            Function::StIsValid
3062        }
3063        Token::Ident(_, Keyword::ST_ISVALIDREASON) if parser.options.dialect.is_postgis() => {
3064            Function::StIsValidReason
3065        }
3066        Token::Ident(_, Keyword::ST_LENGTH) if parser.options.dialect.is_postgis() => {
3067            Function::StLength
3068        }
3069        Token::Ident(_, Keyword::ST_LENGTH2D) if parser.options.dialect.is_postgis() => {
3070            Function::StLength2D
3071        }
3072        Token::Ident(_, Keyword::ST_LENGTH3D) if parser.options.dialect.is_postgis() => {
3073            Function::StLength3D
3074        }
3075        Token::Ident(_, Keyword::ST_LINECROSSINGDIRECTION)
3076            if parser.options.dialect.is_postgis() =>
3077        {
3078            Function::StLineCrossingDirection
3079        }
3080        Token::Ident(_, Keyword::ST_LINEFROMMULTIPOINT) if parser.options.dialect.is_postgis() => {
3081            Function::StLineFromMultiPoint
3082        }
3083        Token::Ident(_, Keyword::ST_LINEFROMTEXT) if parser.options.dialect.is_postgis() => {
3084            Function::StLineFromText
3085        }
3086        Token::Ident(_, Keyword::ST_LINEFROMWKB) if parser.options.dialect.is_postgis() => {
3087            Function::StLineFromWkb
3088        }
3089        Token::Ident(_, Keyword::ST_LINEMERGE) if parser.options.dialect.is_postgis() => {
3090            Function::StLineMerge
3091        }
3092        Token::Ident(_, Keyword::ST_LINESTRINGFROMWKB) if parser.options.dialect.is_postgis() => {
3093            Function::StLinestringFromWkb
3094        }
3095        Token::Ident(_, Keyword::ST_LINETOCURVE) if parser.options.dialect.is_postgis() => {
3096            Function::StLineToCurve
3097        }
3098        Token::Ident(_, Keyword::ST_LINE_INTERPOLATE_POINT)
3099            if parser.options.dialect.is_postgis() =>
3100        {
3101            Function::StLineInterpolatePoint
3102        }
3103        Token::Ident(_, Keyword::ST_LINE_LOCATE_POINT) if parser.options.dialect.is_postgis() => {
3104            Function::StLineLocatePoint
3105        }
3106        Token::Ident(_, Keyword::ST_LINE_SUBSTRING) if parser.options.dialect.is_postgis() => {
3107            Function::StLineSubstring
3108        }
3109        Token::Ident(_, Keyword::ST_LONGESTLINE) if parser.options.dialect.is_postgis() => {
3110            Function::StLongestLine
3111        }
3112        Token::Ident(_, Keyword::ST_M) if parser.options.dialect.is_postgis() => Function::StM,
3113        Token::Ident(_, Keyword::ST_MAKEENVELOPE) if parser.options.dialect.is_postgis() => {
3114            Function::StMakeEnvelope
3115        }
3116        Token::Ident(_, Keyword::ST_MAKELINE) if parser.options.dialect.is_postgis() => {
3117            Function::StMakeLine
3118        }
3119        Token::Ident(_, Keyword::ST_MAKEPOINT) if parser.options.dialect.is_postgis() => {
3120            Function::StMakePoint
3121        }
3122        Token::Ident(_, Keyword::ST_MAKEPOINTM) if parser.options.dialect.is_postgis() => {
3123            Function::StMakePointM
3124        }
3125        Token::Ident(_, Keyword::ST_MAKEPOLYGON) if parser.options.dialect.is_postgis() => {
3126            Function::StMakePolygon
3127        }
3128        Token::Ident(_, Keyword::ST_MAXDISTANCE) if parser.options.dialect.is_postgis() => {
3129            Function::StMaxDistance
3130        }
3131        Token::Ident(_, Keyword::ST_MEM_SIZE) if parser.options.dialect.is_postgis() => {
3132            Function::StMemSize
3133        }
3134        Token::Ident(_, Keyword::ST_MINIMUMBOUNDINGCIRCLE)
3135            if parser.options.dialect.is_postgis() =>
3136        {
3137            Function::StMinimumBoundingCircle
3138        }
3139        Token::Ident(_, Keyword::ST_MULTI) if parser.options.dialect.is_postgis() => {
3140            Function::StMulti
3141        }
3142        Token::Ident(_, Keyword::ST_NDIMS) if parser.options.dialect.is_postgis() => {
3143            Function::StNDims
3144        }
3145        Token::Ident(_, Keyword::ST_NPOINTS) if parser.options.dialect.is_postgis() => {
3146            Function::StNPoints
3147        }
3148        Token::Ident(_, Keyword::ST_NRINGS) if parser.options.dialect.is_postgis() => {
3149            Function::StNRings
3150        }
3151        Token::Ident(_, Keyword::ST_NUMGEOMETRIES) if parser.options.dialect.is_postgis() => {
3152            Function::StNumGeometries
3153        }
3154        Token::Ident(_, Keyword::ST_NUMINTERIORRING) if parser.options.dialect.is_postgis() => {
3155            Function::StNumInteriorRing
3156        }
3157        Token::Ident(_, Keyword::ST_NUMINTERIORRINGS) if parser.options.dialect.is_postgis() => {
3158            Function::StNumInteriorRings
3159        }
3160        Token::Ident(_, Keyword::ST_NUMPOINTS) if parser.options.dialect.is_postgis() => {
3161            Function::StNumPoints
3162        }
3163        Token::Ident(_, Keyword::ST_ORDERINGEQUALS) if parser.options.dialect.is_postgis() => {
3164            Function::StOrderingEquals
3165        }
3166        Token::Ident(_, Keyword::ST_OVERLAPS) if parser.options.dialect.is_postgis() => {
3167            Function::StOverlaps
3168        }
3169        Token::Ident(_, Keyword::ST_PERIMETER) if parser.options.dialect.is_postgis() => {
3170            Function::StPerimeter
3171        }
3172        Token::Ident(_, Keyword::ST_PERIMETER2D) if parser.options.dialect.is_postgis() => {
3173            Function::StPerimeter2D
3174        }
3175        Token::Ident(_, Keyword::ST_PERIMETER3D) if parser.options.dialect.is_postgis() => {
3176            Function::StPerimeter3D
3177        }
3178        Token::Ident(_, Keyword::ST_POINT) if parser.options.dialect.is_postgis() => {
3179            Function::StPoint
3180        }
3181        Token::Ident(_, Keyword::ST_POINTFROMTEXT) if parser.options.dialect.is_postgis() => {
3182            Function::StPointFromText
3183        }
3184        Token::Ident(_, Keyword::ST_POINTFROMWKB) if parser.options.dialect.is_postgis() => {
3185            Function::StPointFromWkb
3186        }
3187        Token::Ident(_, Keyword::ST_POINTN) if parser.options.dialect.is_postgis() => {
3188            Function::StPointN
3189        }
3190        Token::Ident(_, Keyword::ST_POINTONSURFACE) if parser.options.dialect.is_postgis() => {
3191            Function::StPointOnSurface
3192        }
3193        Token::Ident(_, Keyword::ST_POINT_INSIDE_CIRCLE) if parser.options.dialect.is_postgis() => {
3194            Function::StPointInsideCircle
3195        }
3196        Token::Ident(_, Keyword::ST_POLYGON) if parser.options.dialect.is_postgis() => {
3197            Function::StPolygon
3198        }
3199        Token::Ident(_, Keyword::ST_POLYGONFROMTEXT) if parser.options.dialect.is_postgis() => {
3200            Function::StPolygonFromText
3201        }
3202        Token::Ident(_, Keyword::ST_POLYGONIZE) if parser.options.dialect.is_postgis() => {
3203            Function::StPolygonize
3204        }
3205        Token::Ident(_, Keyword::ST_RELATE) if parser.options.dialect.is_postgis() => {
3206            Function::StRelate
3207        }
3208        Token::Ident(_, Keyword::ST_REMOVEPOINT) if parser.options.dialect.is_postgis() => {
3209            Function::StRemovePoint
3210        }
3211        Token::Ident(_, Keyword::ST_REVERSE) if parser.options.dialect.is_postgis() => {
3212            Function::StReverse
3213        }
3214        Token::Ident(_, Keyword::ST_ROTATE) if parser.options.dialect.is_postgis() => {
3215            Function::StRotate
3216        }
3217        Token::Ident(_, Keyword::ST_ROTATEX) if parser.options.dialect.is_postgis() => {
3218            Function::StRotateX
3219        }
3220        Token::Ident(_, Keyword::ST_ROTATEY) if parser.options.dialect.is_postgis() => {
3221            Function::StRotateY
3222        }
3223        Token::Ident(_, Keyword::ST_ROTATEZ) if parser.options.dialect.is_postgis() => {
3224            Function::StRotateZ
3225        }
3226        Token::Ident(_, Keyword::ST_SCALE) if parser.options.dialect.is_postgis() => {
3227            Function::StScale
3228        }
3229        Token::Ident(_, Keyword::ST_SEGMENTIZE) if parser.options.dialect.is_postgis() => {
3230            Function::StSegmentize
3231        }
3232        Token::Ident(_, Keyword::ST_SETPOINT) if parser.options.dialect.is_postgis() => {
3233            Function::StSetPoint
3234        }
3235        Token::Ident(_, Keyword::ST_SETSRID) if parser.options.dialect.is_postgis() => {
3236            Function::StSetSrid
3237        }
3238        Token::Ident(_, Keyword::ST_SHIFT_LONGITUDE) if parser.options.dialect.is_postgis() => {
3239            Function::StShiftLongitude
3240        }
3241        Token::Ident(_, Keyword::ST_SHORTESTLINE) if parser.options.dialect.is_postgis() => {
3242            Function::StShortestLine
3243        }
3244        Token::Ident(_, Keyword::ST_SIMPLIFY) if parser.options.dialect.is_postgis() => {
3245            Function::StSimplify
3246        }
3247        Token::Ident(_, Keyword::ST_SIMPLIFYPRESERVETOPOLOGY)
3248            if parser.options.dialect.is_postgis() =>
3249        {
3250            Function::StSimplifyPreserveTopology
3251        }
3252        Token::Ident(_, Keyword::ST_SNAPTOGRID) if parser.options.dialect.is_postgis() => {
3253            Function::StSnapToGrid
3254        }
3255        Token::Ident(_, Keyword::ST_SRID) if parser.options.dialect.is_postgis() => {
3256            Function::StSRID
3257        }
3258        Token::Ident(_, Keyword::ST_STARTPOINT) if parser.options.dialect.is_postgis() => {
3259            Function::StStartPoint
3260        }
3261        Token::Ident(_, Keyword::ST_SUMMARY) if parser.options.dialect.is_postgis() => {
3262            Function::StSummary
3263        }
3264        Token::Ident(_, Keyword::ST_SYMDIFFERENCE) if parser.options.dialect.is_postgis() => {
3265            Function::StSymDifference
3266        }
3267        Token::Ident(_, Keyword::ST_TOUCHES) if parser.options.dialect.is_postgis() => {
3268            Function::StTouches
3269        }
3270        Token::Ident(_, Keyword::ST_TRANSFORM) if parser.options.dialect.is_postgis() => {
3271            Function::StTransform
3272        }
3273        Token::Ident(_, Keyword::ST_TRANSLATE) if parser.options.dialect.is_postgis() => {
3274            Function::StTranslate
3275        }
3276        Token::Ident(_, Keyword::ST_TRANSSCALE) if parser.options.dialect.is_postgis() => {
3277            Function::StTransScale
3278        }
3279        Token::Ident(_, Keyword::ST_UNION) if parser.options.dialect.is_postgis() => {
3280            Function::StUnion
3281        }
3282        Token::Ident(_, Keyword::ST_WITHIN) if parser.options.dialect.is_postgis() => {
3283            Function::StWithin
3284        }
3285        Token::Ident(_, Keyword::ST_WKBTOSQL) if parser.options.dialect.is_postgis() => {
3286            Function::StWkbToSQL
3287        }
3288        Token::Ident(_, Keyword::ST_WKTTOSQL) if parser.options.dialect.is_postgis() => {
3289            Function::StWktToSQL
3290        }
3291        Token::Ident(_, Keyword::ST_X) if parser.options.dialect.is_postgis() => Function::StX,
3292        Token::Ident(_, Keyword::ST_XMAX) if parser.options.dialect.is_postgis() => {
3293            Function::StXMax
3294        }
3295        Token::Ident(_, Keyword::ST_XMIN) if parser.options.dialect.is_postgis() => {
3296            Function::StXMin
3297        }
3298        Token::Ident(_, Keyword::ST_Y) if parser.options.dialect.is_postgis() => Function::StY,
3299        Token::Ident(_, Keyword::ST_YMAX) if parser.options.dialect.is_postgis() => {
3300            Function::StYMax
3301        }
3302        Token::Ident(_, Keyword::ST_YMIN) if parser.options.dialect.is_postgis() => {
3303            Function::StYMin
3304        }
3305        Token::Ident(_, Keyword::ST_Z) if parser.options.dialect.is_postgis() => Function::StZ,
3306        Token::Ident(_, Keyword::ST_ZMAX) if parser.options.dialect.is_postgis() => {
3307            Function::StZMax
3308        }
3309        Token::Ident(_, Keyword::ST_ZMIN) if parser.options.dialect.is_postgis() => {
3310            Function::StZMin
3311        }
3312        Token::Ident(_, Keyword::ST_ZMFLAG) if parser.options.dialect.is_postgis() => {
3313            Function::StZmflag
3314        }
3315        Token::Ident(_, Keyword::ST_3DDISTANCE) if parser.options.dialect.is_postgis() => {
3316            Function::St3DDistance
3317        }
3318        Token::Ident(_, Keyword::ST_3DMAXDISTANCE) if parser.options.dialect.is_postgis() => {
3319            Function::St3DMaxDistance
3320        }
3321        Token::Ident(_, Keyword::ST_3DINTERSECTS) if parser.options.dialect.is_postgis() => {
3322            Function::St3DIntersects
3323        }
3324        Token::Ident(_, Keyword::ST_MAKEVALID) if parser.options.dialect.is_postgis() => {
3325            Function::StMakeValid
3326        }
3327        Token::Ident(_, Keyword::ST_ISVALIDDETAIL) if parser.options.dialect.is_postgis() => {
3328            Function::StIsValidDetail
3329        }
3330        Token::Ident(_, Keyword::ST_DUMP) if parser.options.dialect.is_postgis() => {
3331            Function::StDump
3332        }
3333        Token::Ident(_, Keyword::ST_DUMPPOINTS) if parser.options.dialect.is_postgis() => {
3334            Function::StDumpPoints
3335        }
3336        Token::Ident(_, Keyword::ST_DUMPRINGS) if parser.options.dialect.is_postgis() => {
3337            Function::StDumpRings
3338        }
3339        Token::Ident(_, Keyword::ST_DUMPSEGMENTS) if parser.options.dialect.is_postgis() => {
3340            Function::StDumpSegments
3341        }
3342        Token::Ident(_, Keyword::ST_SNAP) if parser.options.dialect.is_postgis() => {
3343            Function::StSnap
3344        }
3345        Token::Ident(_, Keyword::ST_NODE) if parser.options.dialect.is_postgis() => {
3346            Function::StNode
3347        }
3348        Token::Ident(_, Keyword::ST_SPLIT) if parser.options.dialect.is_postgis() => {
3349            Function::StSplit
3350        }
3351        Token::Ident(_, Keyword::ST_SHAREDPATHS) if parser.options.dialect.is_postgis() => {
3352            Function::StSharedPaths
3353        }
3354        Token::Ident(_, Keyword::ST_EXPAND) if parser.options.dialect.is_postgis() => {
3355            Function::StExpand
3356        }
3357        Token::Ident(_, Keyword::ST_ESTIMATEDEXTENT) if parser.options.dialect.is_postgis() => {
3358            Function::StEstimatedExtent
3359        }
3360        Token::Ident(_, Keyword::ST_FLIPCOORDINATES) if parser.options.dialect.is_postgis() => {
3361            Function::StFlipCoordinates
3362        }
3363        Token::Ident(_, Keyword::ST_FORCECW) if parser.options.dialect.is_postgis() => {
3364            Function::StForceCw
3365        }
3366        Token::Ident(_, Keyword::ST_FORCECCW) if parser.options.dialect.is_postgis() => {
3367            Function::StForceCcw
3368        }
3369        Token::Ident(_, Keyword::ST_FORCEPOLYGONCW) if parser.options.dialect.is_postgis() => {
3370            Function::StForcePolygonCw
3371        }
3372        Token::Ident(_, Keyword::ST_FORCEPOLYGONCCW) if parser.options.dialect.is_postgis() => {
3373            Function::StForcePolygonCcw
3374        }
3375        Token::Ident(_, Keyword::ST_CONCAVEHULL) if parser.options.dialect.is_postgis() => {
3376            Function::StConcaveHull
3377        }
3378        Token::Ident(_, Keyword::ST_VORONOIPOLYGONS) if parser.options.dialect.is_postgis() => {
3379            Function::StVoronoiPolygons
3380        }
3381        Token::Ident(_, Keyword::ST_VORONOILINES) if parser.options.dialect.is_postgis() => {
3382            Function::StVoronoiLines
3383        }
3384        Token::Ident(_, Keyword::ST_DELAUNAYTRIANGLES) if parser.options.dialect.is_postgis() => {
3385            Function::StDelaunayTriangles
3386        }
3387        Token::Ident(_, Keyword::ST_SUBDIVIDE) if parser.options.dialect.is_postgis() => {
3388            Function::StSubdivide
3389        }
3390        Token::Ident(_, Keyword::ST_GENERATEPOINTS) if parser.options.dialect.is_postgis() => {
3391            Function::StGeneratePoints
3392        }
3393        Token::Ident(_, Keyword::ST_BOUNDINGDIAGONAL) if parser.options.dialect.is_postgis() => {
3394            Function::StBoundingDiagonal
3395        }
3396        Token::Ident(_, Keyword::ST_MAXIMUMINSCRIBEDCIRCLE)
3397            if parser.options.dialect.is_postgis() =>
3398        {
3399            Function::StMaximumInscribedCircle
3400        }
3401        Token::Ident(_, Keyword::ST_CHAIKINSMOOTHING) if parser.options.dialect.is_postgis() => {
3402            Function::StChaikinSmoothing
3403        }
3404        Token::Ident(_, Keyword::ST_FRECHETDISTANCE) if parser.options.dialect.is_postgis() => {
3405            Function::StFrechetDistance
3406        }
3407        Token::Ident(_, Keyword::ST_PROJECT) if parser.options.dialect.is_postgis() => {
3408            Function::StProject
3409        }
3410        Token::Ident(_, Keyword::ST_LOCATEALONG) if parser.options.dialect.is_postgis() => {
3411            Function::StLocateAlong
3412        }
3413        Token::Ident(_, Keyword::ST_LOCATEBETWEEN) if parser.options.dialect.is_postgis() => {
3414            Function::StLocateBetween
3415        }
3416        Token::Ident(_, Keyword::ST_INTERPOLATEPOINT) if parser.options.dialect.is_postgis() => {
3417            Function::StInterpolatePoint
3418        }
3419        Token::Ident(_, Keyword::ST_MAKEBOX2D) if parser.options.dialect.is_postgis() => {
3420            Function::StMakeBox2D
3421        }
3422        Token::Ident(_, Keyword::ST_3DMAKEBOX) if parser.options.dialect.is_postgis() => {
3423            Function::St3DMakeBox
3424        }
3425        Token::Ident(_, Keyword::ST_EXTENT) if parser.options.dialect.is_postgis() => {
3426            Function::StExtent
3427        }
3428        Token::Ident(_, Keyword::ST_3DEXTENT) if parser.options.dialect.is_postgis() => {
3429            Function::St3DExtent
3430        }
3431
3432        Token::Ident(v, k) if !k.restricted(parser.reserved()) => {
3433            Function::Other(alloc::vec![Identifier {
3434                value: v,
3435                span: span.clone()
3436            }])
3437        }
3438        _ => {
3439            parser.err("Unknown function", &span);
3440            Function::Unknown
3441        }
3442    };
3443
3444    let mut args = Vec::new();
3445
3446    // SQL-standard SUBSTRING(str FROM pos [FOR len]) — PostgreSQL and ANSI SQL.
3447    if matches!(func, Function::SubStr) && !matches!(parser.token, Token::RParen) {
3448        let expr = parse_expression_outer(parser)?;
3449        if let Some(_from) = parser.skip_keyword(Keyword::FROM) {
3450            let pos = parse_expression_outer(parser)?;
3451            args.push(expr);
3452            args.push(pos);
3453            if parser.skip_keyword(Keyword::FOR).is_some() {
3454                args.push(parse_expression_outer(parser)?);
3455            }
3456            parser.consume_token(Token::RParen)?;
3457            return Ok(Expression::Function(Box::new(FunctionCallExpression {
3458                function: func,
3459                args,
3460                function_span: span,
3461            })));
3462        } else {
3463            // Comma-style: push first arg and continue normally
3464            args.push(expr);
3465            while parser.skip_token(Token::Comma).is_some() {
3466                parser.recovered(
3467                    "')' or ','",
3468                    &|t| matches!(t, Token::RParen | Token::Comma),
3469                    |parser| {
3470                        args.push(parse_expression_outer(parser)?);
3471                        Ok(())
3472                    },
3473                )?;
3474            }
3475            parser.consume_token(Token::RParen)?;
3476            if let Some(over) = parse_over_clause(parser)? {
3477                return Ok(Expression::WindowFunction(Box::new(
3478                    WindowFunctionCallExpression {
3479                        function: func,
3480                        args,
3481                        function_span: span,
3482                        over,
3483                    },
3484                )));
3485            }
3486            return Ok(Expression::Function(Box::new(FunctionCallExpression {
3487                function: func,
3488                args,
3489                function_span: span,
3490            })));
3491        }
3492    }
3493
3494    if !matches!(parser.token, Token::RParen) {
3495        loop {
3496            parser.recovered(
3497                "')' or ','",
3498                &|t| matches!(t, Token::RParen | Token::Comma),
3499                |parser| {
3500                    args.push(parse_expression_outer(parser)?);
3501                    Ok(())
3502                },
3503            )?;
3504            if parser.skip_token(Token::Comma).is_none() {
3505                break;
3506            }
3507        }
3508    }
3509    parser.consume_token(Token::RParen)?;
3510
3511    if let Some(over) = parse_over_clause(parser)? {
3512        Ok(Expression::WindowFunction(Box::new(
3513            WindowFunctionCallExpression {
3514                function: func,
3515                args,
3516                function_span: span,
3517                over,
3518            },
3519        )))
3520    } else {
3521        Ok(Expression::Function(Box::new(FunctionCallExpression {
3522            function: func,
3523            args,
3524            function_span: span,
3525        })))
3526    }
3527}
3528
3529/// Parse the argument list and optional OVER clause for a schema-qualified function call.
3530/// The caller has already resolved `func = Function::Other(qualified_parts)` and
3531/// computed `function_span` covering the full qualified name.
3532pub(crate) fn parse_char_function<'a>(
3533    parser: &mut Parser<'a, '_>,
3534    char_span: Span,
3535) -> Result<Expression<'a>, ParseError> {
3536    parser.consume_token(Token::LParen)?;
3537    let mut args = Vec::new();
3538    if !matches!(parser.token, Token::RParen) {
3539        loop {
3540            parser.recovered(
3541                "')' or ','",
3542                &|t| {
3543                    matches!(
3544                        t,
3545                        Token::RParen | Token::Comma | Token::Ident(_, Keyword::USING)
3546                    )
3547                },
3548                |parser| {
3549                    args.push(parse_expression_outer(parser)?);
3550                    Ok(())
3551                },
3552            )?;
3553            if parser.skip_token(Token::Comma).is_none() {
3554                break;
3555            }
3556        }
3557    }
3558    // Optional USING charset_name
3559    let using_charset = if let Some(using_span) = parser.skip_keyword(Keyword::USING) {
3560        let charset = parser.consume_plain_identifier_unreserved()?;
3561        Some((using_span, charset))
3562    } else {
3563        None
3564    };
3565    parser.consume_token(Token::RParen)?;
3566    Ok(Expression::Char(Box::new(CharFunctionExpression {
3567        char_span,
3568        args,
3569        using_charset,
3570    })))
3571}
3572
3573pub(crate) fn parse_function_call<'a>(
3574    parser: &mut Parser<'a, '_>,
3575    func: Function<'a>,
3576    function_span: Span,
3577) -> Result<Expression<'a>, ParseError> {
3578    parser.consume_token(Token::LParen)?;
3579    let mut args = Vec::new();
3580    if !matches!(parser.token, Token::RParen) {
3581        loop {
3582            parser.recovered(
3583                "')' or ','",
3584                &|t| matches!(t, Token::RParen | Token::Comma),
3585                |parser| {
3586                    args.push(parse_expression_outer(parser)?);
3587                    Ok(())
3588                },
3589            )?;
3590            if parser.skip_token(Token::Comma).is_none() {
3591                break;
3592            }
3593        }
3594    }
3595    parser.consume_token(Token::RParen)?;
3596    if let Some(over) = parse_over_clause(parser)? {
3597        Ok(Expression::WindowFunction(Box::new(
3598            WindowFunctionCallExpression {
3599                function: func,
3600                args,
3601                function_span,
3602                over,
3603            },
3604        )))
3605    } else {
3606        Ok(Expression::Function(Box::new(FunctionCallExpression {
3607            function: func,
3608            args,
3609            function_span,
3610        })))
3611    }
3612}
3613
3614#[cfg(test)]
3615mod tests {
3616    use core::ops::Deref;
3617
3618    use alloc::string::{String, ToString};
3619
3620    use crate::{
3621        Function, FunctionCallExpression, ParseOptions, SQLDialect,
3622        expression::{Expression, PRIORITY_MAX},
3623        issue::Issues,
3624        parser::Parser,
3625    };
3626
3627    use super::parse_expression_unreserved;
3628
3629    fn test_expr(src: &'static str, f: impl FnOnce(&Expression<'_>) -> Result<(), String>) {
3630        let mut issues = Issues::new(src);
3631        let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
3632        let mut parser = Parser::new(src, &mut issues, &options);
3633        let res = parse_expression_unreserved(&mut parser, PRIORITY_MAX)
3634            .expect("Expression in test expr");
3635        if let Err(e) = f(&res) {
3636            panic!("Error parsing {}: {}\nGot {:#?}", src, e, res);
3637        }
3638    }
3639
3640    #[test]
3641    fn mariadb_datetime_functions() {
3642        fn test_func(src: &'static str, f: Function, cnt: usize) {
3643            let mut issues = Issues::new(src);
3644            let options = ParseOptions::new().dialect(SQLDialect::MariaDB);
3645            let mut parser = Parser::new(src, &mut issues, &options);
3646            let res = match parse_expression_unreserved(&mut parser, PRIORITY_MAX) {
3647                Ok(res) => res,
3648                Err(e) => panic!("Unable to parse {}: {:?}", src, e),
3649            };
3650            let Expression::Function(r) = res else {
3651                panic!("Should be parsed as function {}", src);
3652            };
3653            let FunctionCallExpression {
3654                function: pf, args, ..
3655            } = r.deref();
3656            assert_eq!(pf, &f, "Failure en expr {}", src);
3657            assert_eq!(args.len(), cnt, "Failure en expr {}", src);
3658        }
3659        test_func("ADD_MONTHS('2012-01-31', 2)", Function::AddMonths, 2);
3660        test_func(
3661            "ADDTIME('2007-12-31 23:59:59.999999', '1 1:1:1.000002')",
3662            Function::AddTime,
3663            2,
3664        );
3665        test_func(
3666            "DATE_ADD('2008-01-02', INTERVAL 31 DAY)",
3667            Function::AddDate,
3668            2,
3669        );
3670        test_func(
3671            "ADDDATE('2008-01-02', INTERVAL 31 DAY)",
3672            Function::AddDate,
3673            2,
3674        );
3675        test_func("ADDDATE('2008-01-02', 31)", Function::AddDate, 2);
3676        test_func(
3677            "CONVERT_TZ('2016-01-01 12:00:00','+00:00','+10:00')",
3678            Function::ConvertTz,
3679            3,
3680        );
3681        test_func("CURDATE()", Function::CurDate, 0);
3682        test_func("CURRENT_DATE", Function::CurDate, 0);
3683        test_func("CURRENT_DATE()", Function::CurDate, 0);
3684        test_func("CURRENT_TIME", Function::CurTime, 0);
3685        test_func("CURRENT_TIME()", Function::CurTime, 0);
3686        test_func("CURTIME()", Function::CurTime, 0);
3687        test_func("CURTIME(2)", Function::CurTime, 1);
3688        test_func("CURRENT_DATE", Function::CurDate, 0);
3689        test_func("CURRENT_DATE()", Function::CurDate, 0);
3690        test_func("CURDATE()", Function::CurDate, 0);
3691        test_func("CURRENT_TIMESTAMP", Function::CurrentTimestamp, 0);
3692        test_func("CURRENT_TIMESTAMP()", Function::CurrentTimestamp, 0);
3693        test_func("CURRENT_TIMESTAMP(10)", Function::CurrentTimestamp, 1);
3694        test_func("LOCALTIME", Function::Now, 0);
3695        test_func("LOCALTIME()", Function::Now, 0);
3696        test_func("LOCALTIME(10)", Function::Now, 1);
3697        test_func("LOCALTIMESTAMP", Function::Now, 0);
3698        test_func("LOCALTIMESTAMP()", Function::Now, 0);
3699        test_func("LOCALTIMESTAMP(10)", Function::Now, 1);
3700        test_func("DATE('2013-07-18 12:21:32')", Function::Date, 1);
3701        test_func(
3702            "DATE_FORMAT('2009-10-04 22:23:00', '%W %M %Y')",
3703            Function::DateFormat,
3704            2,
3705        );
3706        test_func(
3707            "DATE_SUB('1998-01-02', INTERVAL 31 DAY)",
3708            Function::DateSub,
3709            2,
3710        );
3711        test_func("DAY('2007-02-03')", Function::DayOfMonth, 1);
3712        test_func("DAYOFMONTH('2007-02-03')", Function::DayOfMonth, 1);
3713        test_func(
3714            "DATEDIFF('2007-12-31 23:59:59','2007-12-30')",
3715            Function::DateDiff,
3716            2,
3717        );
3718        test_func("DAYNAME('2007-02-03')", Function::DayName, 1);
3719        test_func("DAYOFYEAR('2018-02-16')", Function::DayOfYear, 1);
3720        test_func("DAYOFWEEK('2007-02-03')", Function::DayOfWeek, 1);
3721        test_expr("EXTRACT(YEAR_MONTH FROM '2009-07-02 01:02:03')", |e| {
3722            let Expression::Extract { .. } = e else {
3723                return Err("Wrong type".to_string());
3724            };
3725            Ok(())
3726        });
3727        //test_func("FORMAT_PICO_TIME(4321123443212345) AS h", Function::DayOfWeek, 1);
3728        test_func("FROM_DAYS(730669)", Function::FromDays, 1);
3729        test_func("FROM_UNIXTIME(1196440219)", Function::FromUnixTime, 1);
3730        test_func(
3731            "FROM_UNIXTIME(UNIX_TIMESTAMP(), '%Y %D %M %h:%i:%s %x')",
3732            Function::FromUnixTime,
3733            2,
3734        );
3735        //test_func("GET_FORMAT(DATE, 'EUR')", Function::GetFormat, 2);
3736        test_func("HOUR('10:05:03')", Function::Hour, 1);
3737        test_func("LAST_DAY('2004-01-01 01:01:01')", Function::LastDay, 1);
3738        test_func("MAKEDATE(2011,31)", Function::MakeDate, 2);
3739        test_func("MAKETIME(-13,57,33)", Function::MakeTime, 3);
3740        test_func("MICROSECOND('12:00:00.123456')", Function::MicroSecond, 1);
3741        test_func("MINUTE('2013-08-03 11:04:03')", Function::Minute, 1);
3742        test_func("MONTH('2019-01-03')", Function::Month, 1);
3743        test_func("MONTHNAME('2019-02-03')", Function::MonthName, 1);
3744        test_func("PERIOD_ADD(200801,2)", Function::PeriodAdd, 2);
3745        test_func("PERIOD_DIFF(200802,200703)", Function::PeriodDiff, 2);
3746        test_func("QUARTER('2008-04-01')", Function::Quarter, 1);
3747        test_func("SEC_TO_TIME(12414)", Function::SecToTime, 1);
3748        test_func("SECOND('10:05:03')", Function::Second, 1);
3749        test_func(
3750            "STR_TO_DATE('Wednesday, June 2, 2014', '%W, %M %e, %Y')",
3751            Function::StrToDate,
3752            2,
3753        );
3754        test_func(
3755            "DATE_SUB('2008-01-02', INTERVAL 31 DAY)",
3756            Function::DateSub,
3757            2,
3758        );
3759        test_func("SUBDATE('2008-01-02 12:00:00', 31)", Function::DateSub, 2);
3760        test_func(
3761            "SUBDATE('2008-01-02', INTERVAL 31 DAY)",
3762            Function::DateSub,
3763            2,
3764        );
3765        test_func(
3766            "SUBTIME('2007-12-31 23:59:59.999999','1 1:1:1.000002')",
3767            Function::SubTime,
3768            2,
3769        );
3770        test_func("SYSDATE()", Function::SysDate, 0);
3771        test_func("SYSDATE(4)", Function::SysDate, 1);
3772        test_func("TIME('2003-12-31 01:02:03')", Function::Time, 1);
3773        test_func(
3774            "TIME_FORMAT('100:00:00', '%H %k %h %I %l')",
3775            Function::TimeFormat,
3776            2,
3777        );
3778        test_func("TIME_TO_SEC('22:23:00')", Function::TimeToSec, 1);
3779        test_func(
3780            "TIMEDIFF('2008-12-31 23:59:59.000001', '2008-12-30 01:01:01.000002')",
3781            Function::TimeDiff,
3782            2,
3783        );
3784        test_func("TIMESTAMP('2003-12-31')", Function::Timestamp, 1);
3785        test_func(
3786            "TIMESTAMP('2003-12-31 12:00:00','6:30:00')",
3787            Function::Timestamp,
3788            2,
3789        );
3790        test_expr("TIMESTAMPADD(MINUTE,1,'2003-01-02')", |e| {
3791            let Expression::TimestampAdd { .. } = e else {
3792                return Err("Wrong type".to_string());
3793            };
3794            Ok(())
3795        });
3796        test_expr("TIMESTAMPDIFF(MONTH,'2003-02-01','2003-05-01');", |e| {
3797            let Expression::TimestampDiff { .. } = e else {
3798                return Err("Wrong type".to_string());
3799            };
3800            Ok(())
3801        });
3802        test_func("TO_DAYS('2007-10-07')", Function::ToDays, 1);
3803        test_func("UNIX_TIMESTAMP()", Function::UnixTimestamp, 0);
3804        test_func(
3805            "UNIX_TIMESTAMP('2007-11-30 10:30:19')",
3806            Function::UnixTimestamp,
3807            1,
3808        );
3809        test_func("UTC_DATE", Function::UtcDate, 0);
3810        test_func("UTC_DATE()", Function::UtcDate, 0);
3811        test_func("UTC_TIME", Function::UtcTime, 0);
3812        test_func("UTC_TIME()", Function::UtcTime, 0);
3813        test_func("UTC_TIME(5)", Function::UtcTime, 1);
3814        test_func("UTC_TIMESTAMP", Function::UtcTimeStamp, 0);
3815        test_func("UTC_TIMESTAMP()", Function::UtcTimeStamp, 0);
3816        test_func("UTC_TIMESTAMP(4)", Function::UtcTimeStamp, 1);
3817        test_func("WEEK('2008-02-20')", Function::Week, 1);
3818        test_func("WEEK('2008-02-20',0)", Function::Week, 2);
3819        test_func("WEEKDAY('2008-02-03 22:23:00')", Function::Weekday, 1);
3820        test_func("WEEKOFYEAR('2008-02-20')", Function::WeekOfYear, 1);
3821        test_func("YEAR('1987-01-01')", Function::Year, 1);
3822        test_func("YEARWEEK('1987-01-01')", Function::YearWeek, 1);
3823        test_func("YEARWEEK('1987-01-01',0)", Function::YearWeek, 2);
3824    }
3825}