polars_sql/
functions.rs

1use std::ops::Sub;
2
3use polars_core::chunked_array::ops::{SortMultipleOptions, SortOptions};
4use polars_core::prelude::{
5    DataType, PolarsResult, QuantileMethod, Schema, TimeUnit, polars_bail, polars_err,
6};
7use polars_lazy::dsl::Expr;
8#[cfg(feature = "list_eval")]
9use polars_lazy::dsl::ListNameSpaceExtension;
10use polars_ops::chunked_array::UnicodeForm;
11use polars_plan::dsl::{coalesce, concat_str, len, max_horizontal, min_horizontal, when};
12use polars_plan::plans::{DynLiteralValue, LiteralValue, typed_lit};
13use polars_plan::prelude::{StrptimeOptions, col, cols, lit};
14use polars_utils::pl_str::PlSmallStr;
15use sqlparser::ast::helpers::attached_token::AttachedToken;
16use sqlparser::ast::{
17    DateTimeField, DuplicateTreatment, Expr as SQLExpr, Function as SQLFunction, FunctionArg,
18    FunctionArgExpr, FunctionArgumentClause, FunctionArgumentList, FunctionArguments, Ident,
19    OrderByExpr, Value as SQLValue, WindowSpec, WindowType,
20};
21use sqlparser::tokenizer::Span;
22
23use crate::SQLContext;
24use crate::sql_expr::{adjust_one_indexed_param, parse_extract_date_part, parse_sql_expr};
25
26pub(crate) struct SQLFunctionVisitor<'a> {
27    pub(crate) func: &'a SQLFunction,
28    pub(crate) ctx: &'a mut SQLContext,
29    pub(crate) active_schema: Option<&'a Schema>,
30}
31
32/// SQL functions that are supported by Polars
33pub(crate) enum PolarsSQLFunctions {
34    // ----
35    // Bitwise functions
36    // ----
37    /// SQL 'bit_and' function.
38    /// Returns the bitwise AND of the input expressions.
39    /// ```sql
40    /// SELECT BIT_AND(column_1, column_2) FROM df;
41    /// ```
42    BitAnd,
43    /// SQL 'bit_count' function.
44    /// Returns the number of set bits in the input expression.
45    /// ```sql
46    /// SELECT BIT_COUNT(column_1) FROM df;
47    /// ```
48    #[cfg(feature = "bitwise")]
49    BitCount,
50    /// SQL 'bit_or' function.
51    /// Returns the bitwise OR of the input expressions.
52    /// ```sql
53    /// SELECT BIT_OR(column_1, column_2) FROM df;
54    /// ```
55    BitOr,
56    /// SQL 'bit_xor' function.
57    /// Returns the bitwise XOR of the input expressions.
58    /// ```sql
59    /// SELECT BIT_XOR(column_1, column_2) FROM df;
60    /// ```
61    BitXor,
62
63    // ----
64    // Math functions
65    // ----
66    /// SQL 'abs' function
67    /// Returns the absolute value of the input expression.
68    /// ```sql
69    /// SELECT ABS(column_1) FROM df;
70    /// ```
71    Abs,
72    /// SQL 'ceil' function
73    /// Returns the nearest integer closest from zero.
74    /// ```sql
75    /// SELECT CEIL(column_1) FROM df;
76    /// ```
77    Ceil,
78    /// SQL 'div' function
79    /// Returns the integer quotient of the division.
80    /// ```sql
81    /// SELECT DIV(column_1, 2) FROM df;
82    /// ```
83    Div,
84    /// SQL 'exp' function
85    /// Computes the exponential of the given value.
86    /// ```sql
87    /// SELECT EXP(column_1) FROM df;
88    /// ```
89    Exp,
90    /// SQL 'floor' function
91    /// Returns the nearest integer away from zero.
92    ///   0.5 will be rounded
93    /// ```sql
94    /// SELECT FLOOR(column_1) FROM df;
95    /// ```
96    Floor,
97    /// SQL 'pi' function
98    /// Returns a (very good) approximation of 𝜋.
99    /// ```sql
100    /// SELECT PI() FROM df;
101    /// ```
102    Pi,
103    /// SQL 'ln' function
104    /// Computes the natural logarithm of the given value.
105    /// ```sql
106    /// SELECT LN(column_1) FROM df;
107    /// ```
108    Ln,
109    /// SQL 'log2' function
110    /// Computes the logarithm of the given value in base 2.
111    /// ```sql
112    /// SELECT LOG2(column_1) FROM df;
113    /// ```
114    Log2,
115    /// SQL 'log10' function
116    /// Computes the logarithm of the given value in base 10.
117    /// ```sql
118    /// SELECT LOG10(column_1) FROM df;
119    /// ```
120    Log10,
121    /// SQL 'log' function
122    /// Computes the `base` logarithm of the given value.
123    /// ```sql
124    /// SELECT LOG(column_1, 10) FROM df;
125    /// ```
126    Log,
127    /// SQL 'log1p' function
128    /// Computes the natural logarithm of "given value plus one".
129    /// ```sql
130    /// SELECT LOG1P(column_1) FROM df;
131    /// ```
132    Log1p,
133    /// SQL 'pow' function
134    /// Returns the value to the power of the given exponent.
135    /// ```sql
136    /// SELECT POW(column_1, 2) FROM df;
137    /// ```
138    Pow,
139    /// SQL 'mod' function
140    /// Returns the remainder of a numeric expression divided by another numeric expression.
141    /// ```sql
142    /// SELECT MOD(column_1, 2) FROM df;
143    /// ```
144    Mod,
145    /// SQL 'sqrt' function
146    /// Returns the square root (√) of a number.
147    /// ```sql
148    /// SELECT SQRT(column_1) FROM df;
149    /// ```
150    Sqrt,
151    /// SQL 'cbrt' function
152    /// Returns the cube root (∛) of a number.
153    /// ```sql
154    /// SELECT CBRT(column_1) FROM df;
155    /// ```
156    Cbrt,
157    /// SQL 'round' function
158    /// Round a number to `x` decimals (default: 0) away from zero.
159    ///   .5 is rounded away from zero.
160    /// ```sql
161    /// SELECT ROUND(column_1, 3) FROM df;
162    /// ```
163    Round,
164    /// SQL 'sign' function
165    /// Returns the sign of the argument as -1, 0, or +1.
166    /// ```sql
167    /// SELECT SIGN(column_1) FROM df;
168    /// ```
169    Sign,
170
171    // ----
172    // Trig functions
173    // ----
174    /// SQL 'cos' function
175    /// Compute the cosine sine of the input expression (in radians).
176    /// ```sql
177    /// SELECT COS(column_1) FROM df;
178    /// ```
179    Cos,
180    /// SQL 'cot' function
181    /// Compute the cotangent of the input expression (in radians).
182    /// ```sql
183    /// SELECT COT(column_1) FROM df;
184    /// ```
185    Cot,
186    /// SQL 'sin' function
187    /// Compute the sine of the input expression (in radians).
188    /// ```sql
189    /// SELECT SIN(column_1) FROM df;
190    /// ```
191    Sin,
192    /// SQL 'tan' function
193    /// Compute the tangent of the input expression (in radians).
194    /// ```sql
195    /// SELECT TAN(column_1) FROM df;
196    /// ```
197    Tan,
198    /// SQL 'cosd' function
199    /// Compute the cosine sine of the input expression (in degrees).
200    /// ```sql
201    /// SELECT COSD(column_1) FROM df;
202    /// ```
203    CosD,
204    /// SQL 'cotd' function
205    /// Compute cotangent of the input expression (in degrees).
206    /// ```sql
207    /// SELECT COTD(column_1) FROM df;
208    /// ```
209    CotD,
210    /// SQL 'sind' function
211    /// Compute the sine of the input expression (in degrees).
212    /// ```sql
213    /// SELECT SIND(column_1) FROM df;
214    /// ```
215    SinD,
216    /// SQL 'tand' function
217    /// Compute the tangent of the input expression (in degrees).
218    /// ```sql
219    /// SELECT TAND(column_1) FROM df;
220    /// ```
221    TanD,
222    /// SQL 'acos' function
223    /// Compute inverse cosine of the input expression (in radians).
224    /// ```sql
225    /// SELECT ACOS(column_1) FROM df;
226    /// ```
227    Acos,
228    /// SQL 'asin' function
229    /// Compute inverse sine of the input expression (in radians).
230    /// ```sql
231    /// SELECT ASIN(column_1) FROM df;
232    /// ```
233    Asin,
234    /// SQL 'atan' function
235    /// Compute inverse tangent of the input expression (in radians).
236    /// ```sql
237    /// SELECT ATAN(column_1) FROM df;
238    /// ```
239    Atan,
240    /// SQL 'atan2' function
241    /// Compute the inverse tangent of column_1/column_2 (in radians).
242    /// ```sql
243    /// SELECT ATAN2(column_1, column_2) FROM df;
244    /// ```
245    Atan2,
246    /// SQL 'acosd' function
247    /// Compute inverse cosine of the input expression (in degrees).
248    /// ```sql
249    /// SELECT ACOSD(column_1) FROM df;
250    /// ```
251    AcosD,
252    /// SQL 'asind' function
253    /// Compute inverse sine of the input expression (in degrees).
254    /// ```sql
255    /// SELECT ASIND(column_1) FROM df;
256    /// ```
257    AsinD,
258    /// SQL 'atand' function
259    /// Compute inverse tangent of the input expression (in degrees).
260    /// ```sql
261    /// SELECT ATAND(column_1) FROM df;
262    /// ```
263    AtanD,
264    /// SQL 'atan2d' function
265    /// Compute the inverse tangent of column_1/column_2 (in degrees).
266    /// ```sql
267    /// SELECT ATAN2D(column_1) FROM df;
268    /// ```
269    Atan2D,
270    /// SQL 'degrees' function
271    /// Convert between radians and degrees.
272    /// ```sql
273    /// SELECT DEGREES(column_1) FROM df;
274    /// ```
275    ///
276    ///
277    Degrees,
278    /// SQL 'RADIANS' function
279    /// Convert between degrees and radians.
280    /// ```sql
281    /// SELECT RADIANS(column_1) FROM df;
282    /// ```
283    Radians,
284
285    // ----
286    // Temporal functions
287    // ----
288    /// SQL 'date_part' function.
289    /// Extracts a part of a date (or datetime) such as 'year', 'month', etc.
290    /// ```sql
291    /// SELECT DATE_PART('year', column_1) FROM df;
292    /// SELECT DATE_PART('day', column_1) FROM df;
293    DatePart,
294    /// SQL 'strftime' function.
295    /// Converts a datetime to a string using a format string.
296    /// ```sql
297    /// SELECT STRFTIME(column_1, '%d-%m-%Y %H:%M') FROM df;
298    /// ```
299    Strftime,
300
301    // ----
302    // String functions
303    // ----
304    /// SQL 'bit_length' function (bytes).
305    /// ```sql
306    /// SELECT BIT_LENGTH(column_1) FROM df;
307    /// ```
308    BitLength,
309    /// SQL 'concat' function
310    /// Returns all input expressions concatenated together as a string.
311    /// ```sql
312    /// SELECT CONCAT(column_1, column_2) FROM df;
313    /// ```
314    Concat,
315    /// SQL 'concat_ws' function
316    /// Returns all input expressions concatenated together
317    /// (and interleaved with a separator) as a string.
318    /// ```sql
319    /// SELECT CONCAT_WS(':', column_1, column_2, column_3) FROM df;
320    /// ```
321    ConcatWS,
322    /// SQL 'date' function.
323    /// Converts a formatted string date to an actual Date type; ISO-8601 format is assumed
324    /// unless a strftime-compatible formatting string is provided as the second parameter.
325    /// ```sql
326    /// SELECT DATE('2021-03-15') FROM df;
327    /// SELECT DATE('2021-15-03', '%Y-d%-%m') FROM df;
328    /// SELECT DATE('2021-03', '%Y-%m') FROM df;
329    /// ```
330    Date,
331    /// SQL 'timestamp' function.
332    /// Converts a formatted string datetime to an actual Datetime type; ISO-8601 format is
333    /// assumed unless a strftime-compatible formatting string is provided as the second
334    /// parameter.
335    /// ```sql
336    /// SELECT TIMESTAMP('2021-03-15 10:30:45') FROM df;
337    /// SELECT TIMESTAMP('2021-15-03T00:01:02.333', '%Y-d%-%m %H:%M:%S') FROM df;
338    /// ```
339    Timestamp,
340    /// SQL 'ends_with' function
341    /// Returns True if the value ends with the second argument.
342    /// ```sql
343    /// SELECT ENDS_WITH(column_1, 'a') FROM df;
344    /// SELECT column_2 from df WHERE ENDS_WITH(column_1, 'a');
345    /// ```
346    EndsWith,
347    /// SQL 'initcap' function
348    /// Returns the value with the first letter capitalized.
349    /// ```sql
350    /// SELECT INITCAP(column_1) FROM df;
351    /// ```
352    #[cfg(feature = "nightly")]
353    InitCap,
354    /// SQL 'left' function
355    /// Returns the first (leftmost) `n` characters.
356    /// ```sql
357    /// SELECT LEFT(column_1, 3) FROM df;
358    /// ```
359    Left,
360    /// SQL 'length' function (characters)
361    /// Returns the character length of the string.
362    /// ```sql
363    /// SELECT LENGTH(column_1) FROM df;
364    /// ```
365    Length,
366    /// SQL 'lower' function
367    /// Returns an lowercased column.
368    /// ```sql
369    /// SELECT LOWER(column_1) FROM df;
370    /// ```
371    Lower,
372    /// SQL 'ltrim' function
373    /// Strip whitespaces from the left.
374    /// ```sql
375    /// SELECT LTRIM(column_1) FROM df;
376    /// ```
377    LTrim,
378    /// SQL 'normalize' function
379    /// Convert string to Unicode normalization form
380    /// (one of NFC, NFKC, NFD, or NFKD - unquoted).
381    /// ```sql
382    /// SELECT NORMALIZE(column_1, NFC) FROM df;
383    /// ```
384    Normalize,
385    /// SQL 'octet_length' function
386    /// Returns the length of a given string in bytes.
387    /// ```sql
388    /// SELECT OCTET_LENGTH(column_1) FROM df;
389    /// ```
390    OctetLength,
391    /// SQL 'regexp_like' function
392    /// True if `pattern` matches the value (optional: `flags`).
393    /// ```sql
394    /// SELECT REGEXP_LIKE(column_1, 'xyz', 'i') FROM df;
395    /// ```
396    RegexpLike,
397    /// SQL 'replace' function
398    /// Replace a given substring with another string.
399    /// ```sql
400    /// SELECT REPLACE(column_1, 'old', 'new') FROM df;
401    /// ```
402    Replace,
403    /// SQL 'reverse' function
404    /// Return the reversed string.
405    /// ```sql
406    /// SELECT REVERSE(column_1) FROM df;
407    /// ```
408    Reverse,
409    /// SQL 'right' function
410    /// Returns the last (rightmost) `n` characters.
411    /// ```sql
412    /// SELECT RIGHT(column_1, 3) FROM df;
413    /// ```
414    Right,
415    /// SQL 'rtrim' function
416    /// Strip whitespaces from the right.
417    /// ```sql
418    /// SELECT RTRIM(column_1) FROM df;
419    /// ```
420    RTrim,
421    /// SQL 'starts_with' function
422    /// Returns True if the value starts with the second argument.
423    /// ```sql
424    /// SELECT STARTS_WITH(column_1, 'a') FROM df;
425    /// SELECT column_2 from df WHERE STARTS_WITH(column_1, 'a');
426    /// ```
427    StartsWith,
428    /// SQL 'strpos' function
429    /// Returns the index of the given substring in the target string.
430    /// ```sql
431    /// SELECT STRPOS(column_1,'xyz') FROM df;
432    /// ```
433    StrPos,
434    /// SQL 'substr' function
435    /// Returns a portion of the data (first character = 1) in the range.
436    ///   \[start, start + length]
437    /// ```sql
438    /// SELECT SUBSTR(column_1, 3, 5) FROM df;
439    /// ```
440    Substring,
441    /// SQL 'strptime' function
442    /// Converts a string to a datetime using a format string.
443    /// ```sql
444    /// SELECT STRPTIME(column_1, '%d-%m-%Y %H:%M') FROM df;
445    /// ```
446    Strptime,
447    /// SQL 'time' function.
448    /// Converts a formatted string time to an actual Time type; ISO-8601 format is
449    /// assumed unless a strftime-compatible formatting string is provided as the second
450    /// parameter.
451    /// ```sql
452    /// SELECT TIME('10:30:45') FROM df;
453    /// SELECT TIME('20.30', '%H.%M') FROM df;
454    /// ```
455    Time,
456    /// SQL 'upper' function
457    /// Returns an uppercased column.
458    /// ```sql
459    /// SELECT UPPER(column_1) FROM df;
460    /// ```
461    Upper,
462
463    // ----
464    // Conditional functions
465    // ----
466    /// SQL 'coalesce' function
467    /// Returns the first non-null value in the provided values/columns.
468    /// ```sql
469    /// SELECT COALESCE(column_1, ...) FROM df;
470    /// ```
471    Coalesce,
472    /// SQL 'greatest' function
473    /// Returns the greatest value in the list of expressions.
474    /// ```sql
475    /// SELECT GREATEST(column_1, column_2, ...) FROM df;
476    /// ```
477    Greatest,
478    /// SQL 'if' function
479    /// Returns expr1 if the boolean condition provided as the first
480    /// parameter evaluates to true, and expr2 otherwise.
481    /// ```sql
482    /// SELECT IF(column < 0, expr1, expr2) FROM df;
483    /// ```
484    If,
485    /// SQL 'ifnull' function
486    /// If an expression value is NULL, return an alternative value.
487    /// ```sql
488    /// SELECT IFNULL(string_col, 'n/a') FROM df;
489    /// ```
490    IfNull,
491    /// SQL 'least' function
492    /// Returns the smallest value in the list of expressions.
493    /// ```sql
494    /// SELECT LEAST(column_1, column_2, ...) FROM df;
495    /// ```
496    Least,
497    /// SQL 'nullif' function
498    /// Returns NULL if two expressions are equal, otherwise returns the first.
499    /// ```sql
500    /// SELECT NULLIF(column_1, column_2) FROM df;
501    /// ```
502    NullIf,
503
504    // ----
505    // Aggregate functions
506    // ----
507    /// SQL 'avg' function
508    /// Returns the average (mean) of all the elements in the grouping.
509    /// ```sql
510    /// SELECT AVG(column_1) FROM df;
511    /// ```
512    Avg,
513    /// SQL 'count' function
514    /// Returns the amount of elements in the grouping.
515    /// ```sql
516    /// SELECT COUNT(column_1) FROM df;
517    /// SELECT COUNT(*) FROM df;
518    /// SELECT COUNT(DISTINCT column_1) FROM df;
519    /// SELECT COUNT(DISTINCT *) FROM df;
520    /// ```
521    Count,
522    /// SQL 'first' function
523    /// Returns the first element of the grouping.
524    /// ```sql
525    /// SELECT FIRST(column_1) FROM df;
526    /// ```
527    First,
528    /// SQL 'last' function
529    /// Returns the last element of the grouping.
530    /// ```sql
531    /// SELECT LAST(column_1) FROM df;
532    /// ```
533    Last,
534    /// SQL 'max' function
535    /// Returns the greatest (maximum) of all the elements in the grouping.
536    /// ```sql
537    /// SELECT MAX(column_1) FROM df;
538    /// ```
539    Max,
540    /// SQL 'median' function
541    /// Returns the median element from the grouping.
542    /// ```sql
543    /// SELECT MEDIAN(column_1) FROM df;
544    /// ```
545    Median,
546    /// SQL 'quantile_cont' function
547    /// Returns the continuous quantile element from the grouping
548    /// (interpolated value between two closest values).
549    /// ```sql
550    /// SELECT QUANTILE_CONT(column_1) FROM df;
551    /// ```
552    QuantileCont,
553    /// SQL 'quantile_disc' function
554    /// Divides the [0, 1] interval into equal-length subintervals, each corresponding to a value,
555    /// and returns the value associated with the subinterval where the quantile value falls.
556    /// ```sql
557    /// SELECT QUANTILE_DISC(column_1) FROM df;
558    /// ```
559    QuantileDisc,
560    /// SQL 'min' function
561    /// Returns the smallest (minimum) of all the elements in the grouping.
562    /// ```sql
563    /// SELECT MIN(column_1) FROM df;
564    /// ```
565    Min,
566    /// SQL 'stddev' function
567    /// Returns the standard deviation of all the elements in the grouping.
568    /// ```sql
569    /// SELECT STDDEV(column_1) FROM df;
570    /// ```
571    StdDev,
572    /// SQL 'sum' function
573    /// Returns the sum of all the elements in the grouping.
574    /// ```sql
575    /// SELECT SUM(column_1) FROM df;
576    /// ```
577    Sum,
578    /// SQL 'variance' function
579    /// Returns the variance of all the elements in the grouping.
580    /// ```sql
581    /// SELECT VARIANCE(column_1) FROM df;
582    /// ```
583    Variance,
584
585    // ----
586    // Array functions
587    // ----
588    /// SQL 'array_length' function
589    /// Returns the length of the array.
590    /// ```sql
591    /// SELECT ARRAY_LENGTH(column_1) FROM df;
592    /// ```
593    ArrayLength,
594    /// SQL 'array_lower' function
595    /// Returns the minimum value in an array; equivalent to `array_min`.
596    /// ```sql
597    /// SELECT ARRAY_LOWER(column_1) FROM df;
598    /// ```
599    ArrayMin,
600    /// SQL 'array_upper' function
601    /// Returns the maximum value in an array; equivalent to `array_max`.
602    /// ```sql
603    /// SELECT ARRAY_UPPER(column_1) FROM df;
604    /// ```
605    ArrayMax,
606    /// SQL 'array_sum' function
607    /// Returns the sum of all values in an array.
608    /// ```sql
609    /// SELECT ARRAY_SUM(column_1) FROM df;
610    /// ```
611    ArraySum,
612    /// SQL 'array_mean' function
613    /// Returns the mean of all values in an array.
614    /// ```sql
615    /// SELECT ARRAY_MEAN(column_1) FROM df;
616    /// ```
617    ArrayMean,
618    /// SQL 'array_reverse' function
619    /// Returns the array with the elements in reverse order.
620    /// ```sql
621    /// SELECT ARRAY_REVERSE(column_1) FROM df;
622    /// ```
623    ArrayReverse,
624    /// SQL 'array_unique' function
625    /// Returns the array with the unique elements.
626    /// ```sql
627    /// SELECT ARRAY_UNIQUE(column_1) FROM df;
628    /// ```
629    ArrayUnique,
630    /// SQL 'unnest' function
631    /// Unnest/explodes an array column into multiple rows.
632    /// ```sql
633    /// SELECT unnest(column_1) FROM df;
634    /// ```
635    Explode,
636    /// SQL 'array_agg' function
637    /// Concatenates the input expressions, including nulls, into an array.
638    /// ```sql
639    /// SELECT ARRAY_AGG(column_1, column_2, ...) FROM df;
640    /// ```
641    ArrayAgg,
642    /// SQL 'array_to_string' function
643    /// Takes all elements of the array and joins them into one string.
644    /// ```sql
645    /// SELECT ARRAY_TO_STRING(column_1, ',') FROM df;
646    /// SELECT ARRAY_TO_STRING(column_1, ',', 'n/a') FROM df;
647    /// ```
648    ArrayToString,
649    /// SQL 'array_get' function
650    /// Returns the value at the given index in the array.
651    /// ```sql
652    /// SELECT ARRAY_GET(column_1, 1) FROM df;
653    /// ```
654    ArrayGet,
655    /// SQL 'array_contains' function
656    /// Returns true if the array contains the value.
657    /// ```sql
658    /// SELECT ARRAY_CONTAINS(column_1, 'foo') FROM df;
659    /// ```
660    ArrayContains,
661
662    // ----
663    // Column selection
664    // ----
665    Columns,
666
667    // ----
668    // User-defined
669    // ----
670    Udf(String),
671}
672
673impl PolarsSQLFunctions {
674    pub(crate) fn keywords() -> &'static [&'static str] {
675        &[
676            "abs",
677            "acos",
678            "acosd",
679            "array_contains",
680            "array_get",
681            "array_length",
682            "array_lower",
683            "array_mean",
684            "array_reverse",
685            "array_sum",
686            "array_to_string",
687            "array_unique",
688            "array_upper",
689            "asin",
690            "asind",
691            "atan",
692            "atan2",
693            "atan2d",
694            "atand",
695            "avg",
696            "bit_and",
697            "bit_count",
698            "bit_length",
699            "bit_or",
700            "bit_xor",
701            "cbrt",
702            "ceil",
703            "ceiling",
704            "char_length",
705            "character_length",
706            "coalesce",
707            "columns",
708            "concat",
709            "concat_ws",
710            "cos",
711            "cosd",
712            "cot",
713            "cotd",
714            "count",
715            "date",
716            "date_part",
717            "degrees",
718            "ends_with",
719            "exp",
720            "first",
721            "floor",
722            "greatest",
723            "if",
724            "ifnull",
725            "initcap",
726            "last",
727            "least",
728            "left",
729            "length",
730            "ln",
731            "log",
732            "log10",
733            "log1p",
734            "log2",
735            "lower",
736            "ltrim",
737            "max",
738            "median",
739            "quantile_disc",
740            "min",
741            "mod",
742            "nullif",
743            "octet_length",
744            "pi",
745            "pow",
746            "power",
747            "quantile_cont",
748            "quantile_disc",
749            "radians",
750            "regexp_like",
751            "replace",
752            "reverse",
753            "right",
754            "round",
755            "rtrim",
756            "sign",
757            "sin",
758            "sind",
759            "sqrt",
760            "starts_with",
761            "stddev",
762            "stddev_samp",
763            "stdev",
764            "stdev_samp",
765            "strftime",
766            "strpos",
767            "strptime",
768            "substr",
769            "sum",
770            "tan",
771            "tand",
772            "unnest",
773            "upper",
774            "var",
775            "var_samp",
776            "variance",
777        ]
778    }
779}
780
781impl PolarsSQLFunctions {
782    fn try_from_sql(function: &'_ SQLFunction, ctx: &'_ SQLContext) -> PolarsResult<Self> {
783        let function_name = function.name.0[0].value.to_lowercase();
784        Ok(match function_name.as_str() {
785            // ----
786            // Bitwise functions
787            // ----
788            "bit_and" | "bitand" => Self::BitAnd,
789            #[cfg(feature = "bitwise")]
790            "bit_count" | "bitcount" => Self::BitCount,
791            "bit_or" | "bitor" => Self::BitOr,
792            "bit_xor" | "bitxor" | "xor" => Self::BitXor,
793
794            // ----
795            // Math functions
796            // ----
797            "abs" => Self::Abs,
798            "cbrt" => Self::Cbrt,
799            "ceil" | "ceiling" => Self::Ceil,
800            "div" => Self::Div,
801            "exp" => Self::Exp,
802            "floor" => Self::Floor,
803            "ln" => Self::Ln,
804            "log" => Self::Log,
805            "log10" => Self::Log10,
806            "log1p" => Self::Log1p,
807            "log2" => Self::Log2,
808            "mod" => Self::Mod,
809            "pi" => Self::Pi,
810            "pow" | "power" => Self::Pow,
811            "round" => Self::Round,
812            "sign" => Self::Sign,
813            "sqrt" => Self::Sqrt,
814
815            // ----
816            // Trig functions
817            // ----
818            "cos" => Self::Cos,
819            "cot" => Self::Cot,
820            "sin" => Self::Sin,
821            "tan" => Self::Tan,
822            "cosd" => Self::CosD,
823            "cotd" => Self::CotD,
824            "sind" => Self::SinD,
825            "tand" => Self::TanD,
826            "acos" => Self::Acos,
827            "asin" => Self::Asin,
828            "atan" => Self::Atan,
829            "atan2" => Self::Atan2,
830            "acosd" => Self::AcosD,
831            "asind" => Self::AsinD,
832            "atand" => Self::AtanD,
833            "atan2d" => Self::Atan2D,
834            "degrees" => Self::Degrees,
835            "radians" => Self::Radians,
836
837            // ----
838            // Conditional functions
839            // ----
840            "coalesce" => Self::Coalesce,
841            "greatest" => Self::Greatest,
842            "if" => Self::If,
843            "ifnull" => Self::IfNull,
844            "least" => Self::Least,
845            "nullif" => Self::NullIf,
846
847            // ----
848            // Date functions
849            // ----
850            "date_part" => Self::DatePart,
851            "strftime" => Self::Strftime,
852
853            // ----
854            // String functions
855            // ----
856            "bit_length" => Self::BitLength,
857            "concat" => Self::Concat,
858            "concat_ws" => Self::ConcatWS,
859            "date" => Self::Date,
860            "timestamp" | "datetime" => Self::Timestamp,
861            "ends_with" => Self::EndsWith,
862            #[cfg(feature = "nightly")]
863            "initcap" => Self::InitCap,
864            "length" | "char_length" | "character_length" => Self::Length,
865            "left" => Self::Left,
866            "lower" => Self::Lower,
867            "ltrim" => Self::LTrim,
868            "normalize" => Self::Normalize,
869            "octet_length" => Self::OctetLength,
870            "strpos" => Self::StrPos,
871            "regexp_like" => Self::RegexpLike,
872            "replace" => Self::Replace,
873            "reverse" => Self::Reverse,
874            "right" => Self::Right,
875            "rtrim" => Self::RTrim,
876            "starts_with" => Self::StartsWith,
877            "strptime" => Self::Strptime,
878            "substr" => Self::Substring,
879            "time" => Self::Time,
880            "upper" => Self::Upper,
881
882            // ----
883            // Aggregate functions
884            // ----
885            "avg" => Self::Avg,
886            "count" => Self::Count,
887            "first" => Self::First,
888            "last" => Self::Last,
889            "max" => Self::Max,
890            "median" => Self::Median,
891            "quantile_cont" => Self::QuantileCont,
892            "quantile_disc" => Self::QuantileDisc,
893            "min" => Self::Min,
894            "stdev" | "stddev" | "stdev_samp" | "stddev_samp" => Self::StdDev,
895            "sum" => Self::Sum,
896            "var" | "variance" | "var_samp" => Self::Variance,
897
898            // ----
899            // Array functions
900            // ----
901            "array_agg" => Self::ArrayAgg,
902            "array_contains" => Self::ArrayContains,
903            "array_get" => Self::ArrayGet,
904            "array_length" => Self::ArrayLength,
905            "array_lower" => Self::ArrayMin,
906            "array_mean" => Self::ArrayMean,
907            "array_reverse" => Self::ArrayReverse,
908            "array_sum" => Self::ArraySum,
909            "array_to_string" => Self::ArrayToString,
910            "array_unique" => Self::ArrayUnique,
911            "array_upper" => Self::ArrayMax,
912            "unnest" => Self::Explode,
913
914            // ----
915            // Column selection
916            // ----
917            "columns" => Self::Columns,
918
919            other => {
920                if ctx.function_registry.contains(other) {
921                    Self::Udf(other.to_string())
922                } else {
923                    polars_bail!(SQLInterface: "unsupported function '{}'", other);
924                }
925            },
926        })
927    }
928}
929
930impl SQLFunctionVisitor<'_> {
931    pub(crate) fn visit_function(&mut self) -> PolarsResult<Expr> {
932        use PolarsSQLFunctions::*;
933        let function_name = PolarsSQLFunctions::try_from_sql(self.func, self.ctx)?;
934        let function = self.func;
935
936        // TODO: implement the following functions where possible
937        if !function.within_group.is_empty() {
938            polars_bail!(SQLInterface: "'WITHIN GROUP' is not currently supported")
939        }
940        if function.filter.is_some() {
941            polars_bail!(SQLInterface: "'FILTER' is not currently supported")
942        }
943        if function.null_treatment.is_some() {
944            polars_bail!(SQLInterface: "'IGNORE|RESPECT NULLS' is not currently supported")
945        }
946
947        match function_name {
948            // ----
949            // Bitwise functions
950            // ----
951            BitAnd => self.visit_binary::<Expr>(Expr::and),
952            #[cfg(feature = "bitwise")]
953            BitCount => self.visit_unary(Expr::bitwise_count_ones),
954            BitOr => self.visit_binary::<Expr>(Expr::or),
955            BitXor => self.visit_binary::<Expr>(Expr::xor),
956
957            // ----
958            // Math functions
959            // ----
960            Abs => self.visit_unary(Expr::abs),
961            Cbrt => self.visit_unary(Expr::cbrt),
962            Ceil => self.visit_unary(Expr::ceil),
963            Div => self.visit_binary(|e, d| e.floor_div(d).cast(DataType::Int64)),
964            Exp => self.visit_unary(Expr::exp),
965            Floor => self.visit_unary(Expr::floor),
966            Ln => self.visit_unary(|e| e.log(std::f64::consts::E)),
967            Log => self.visit_binary(Expr::log),
968            Log10 => self.visit_unary(|e| e.log(10.0)),
969            Log1p => self.visit_unary(Expr::log1p),
970            Log2 => self.visit_unary(|e| e.log(2.0)),
971            Pi => self.visit_nullary(Expr::pi),
972            Mod => self.visit_binary(|e1, e2| e1 % e2),
973            Pow => self.visit_binary::<Expr>(Expr::pow),
974            Round => {
975                let args = extract_args(function)?;
976                match args.len() {
977                    1 => self.visit_unary(|e| e.round(0)),
978                    2 => self.try_visit_binary(|e, decimals| {
979                        Ok(e.round(match decimals {
980                            Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n))) => {
981                                if n >= 0 { n as u32 } else {
982                                    polars_bail!(SQLInterface: "ROUND does not currently support negative decimals value ({})", args[1])
983                                }
984                            },
985                            _ => polars_bail!(SQLSyntax: "invalid value for ROUND decimals ({})", args[1]),
986                        }))
987                    }),
988                    _ => polars_bail!(SQLSyntax: "ROUND expects 1-2 arguments (found {})", args.len()),
989                }
990            },
991            Sign => self.visit_unary(Expr::sign),
992            Sqrt => self.visit_unary(Expr::sqrt),
993
994            // ----
995            // Trig functions
996            // ----
997            Acos => self.visit_unary(Expr::arccos),
998            AcosD => self.visit_unary(|e| e.arccos().degrees()),
999            Asin => self.visit_unary(Expr::arcsin),
1000            AsinD => self.visit_unary(|e| e.arcsin().degrees()),
1001            Atan => self.visit_unary(Expr::arctan),
1002            Atan2 => self.visit_binary(Expr::arctan2),
1003            Atan2D => self.visit_binary(|e, s| e.arctan2(s).degrees()),
1004            AtanD => self.visit_unary(|e| e.arctan().degrees()),
1005            Cos => self.visit_unary(Expr::cos),
1006            CosD => self.visit_unary(|e| e.radians().cos()),
1007            Cot => self.visit_unary(Expr::cot),
1008            CotD => self.visit_unary(|e| e.radians().cot()),
1009            Degrees => self.visit_unary(Expr::degrees),
1010            Radians => self.visit_unary(Expr::radians),
1011            Sin => self.visit_unary(Expr::sin),
1012            SinD => self.visit_unary(|e| e.radians().sin()),
1013            Tan => self.visit_unary(Expr::tan),
1014            TanD => self.visit_unary(|e| e.radians().tan()),
1015
1016            // ----
1017            // Conditional functions
1018            // ----
1019            Coalesce => self.visit_variadic(coalesce),
1020            Greatest => self.visit_variadic(|exprs: &[Expr]| max_horizontal(exprs).unwrap()),
1021            If => {
1022                let args = extract_args(function)?;
1023                match args.len() {
1024                    3 => self.try_visit_ternary(|cond: Expr, expr1: Expr, expr2: Expr| {
1025                        Ok(when(cond).then(expr1).otherwise(expr2))
1026                    }),
1027                    _ => {
1028                        polars_bail!(SQLSyntax: "IF expects 3 arguments (found {})", args.len()
1029                        )
1030                    },
1031                }
1032            },
1033            IfNull => {
1034                let args = extract_args(function)?;
1035                match args.len() {
1036                    2 => self.visit_variadic(coalesce),
1037                    _ => {
1038                        polars_bail!(SQLSyntax: "IFNULL expects 2 arguments (found {})", args.len())
1039                    },
1040                }
1041            },
1042            Least => self.visit_variadic(|exprs: &[Expr]| min_horizontal(exprs).unwrap()),
1043            NullIf => {
1044                let args = extract_args(function)?;
1045                match args.len() {
1046                    2 => self.visit_binary(|l: Expr, r: Expr| {
1047                        when(l.clone().eq(r))
1048                            .then(lit(LiteralValue::untyped_null()))
1049                            .otherwise(l)
1050                    }),
1051                    _ => {
1052                        polars_bail!(SQLSyntax: "NULLIF expects 2 arguments (found {})", args.len())
1053                    },
1054                }
1055            },
1056
1057            // ----
1058            // Date functions
1059            // ----
1060            DatePart => self.try_visit_binary(|part, e| {
1061                match part {
1062                    Expr::Literal(p) if p.extract_str().is_some() => {
1063                        let p = p.extract_str().unwrap();
1064                        // note: 'DATE_PART' and 'EXTRACT' are minor syntactic
1065                        // variations on otherwise identical functionality
1066                        parse_extract_date_part(
1067                            e,
1068                            &DateTimeField::Custom(Ident {
1069                                value: p.to_string(),
1070                                quote_style: None,
1071                                span: Span::empty(),
1072                            }),
1073                        )
1074                    },
1075                    _ => {
1076                        polars_bail!(SQLSyntax: "invalid 'part' for EXTRACT/DATE_PART ({})", part);
1077                    },
1078                }
1079            }),
1080            Strftime => {
1081                let args = extract_args(function)?;
1082                match args.len() {
1083                    2 => self.visit_binary(|e, fmt: String| e.dt().strftime(fmt.as_str())),
1084                    _ => {
1085                        polars_bail!(SQLSyntax: "STRFTIME expects 2 arguments (found {})", args.len())
1086                    },
1087                }
1088            },
1089
1090            // ----
1091            // String functions
1092            // ----
1093            BitLength => self.visit_unary(|e| e.str().len_bytes() * lit(8)),
1094            Concat => {
1095                let args = extract_args(function)?;
1096                if args.is_empty() {
1097                    polars_bail!(SQLSyntax: "CONCAT expects at least 1 argument (found 0)");
1098                } else {
1099                    self.visit_variadic(|exprs: &[Expr]| concat_str(exprs, "", true))
1100                }
1101            },
1102            ConcatWS => {
1103                let args = extract_args(function)?;
1104                if args.len() < 2 {
1105                    polars_bail!(SQLSyntax: "CONCAT_WS expects at least 2 arguments (found {})", args.len());
1106                } else {
1107                    self.try_visit_variadic(|exprs: &[Expr]| {
1108                        match &exprs[0] {
1109                            Expr::Literal(lv) if lv.extract_str().is_some() => Ok(concat_str(&exprs[1..], lv.extract_str().unwrap(), true)),
1110                            _ => polars_bail!(SQLSyntax: "CONCAT_WS 'separator' must be a literal string (found {:?})", exprs[0]),
1111                        }
1112                    })
1113                }
1114            },
1115            Date => {
1116                let args = extract_args(function)?;
1117                match args.len() {
1118                    1 => self.visit_unary(|e| e.str().to_date(StrptimeOptions::default())),
1119                    2 => self.visit_binary(|e, fmt| e.str().to_date(fmt)),
1120                    _ => {
1121                        polars_bail!(SQLSyntax: "DATE expects 1-2 arguments (found {})", args.len())
1122                    },
1123                }
1124            },
1125            EndsWith => self.visit_binary(|e, s| e.str().ends_with(s)),
1126            #[cfg(feature = "nightly")]
1127            InitCap => self.visit_unary(|e| e.str().to_titlecase()),
1128            Left => self.try_visit_binary(|e, length| {
1129                Ok(match length {
1130                    Expr::Literal(lv) if lv.is_null() => lit(lv),
1131                    Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(0))) => lit(""),
1132                    Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n))) => {
1133                        let len = if n > 0 {
1134                            lit(n)
1135                        } else {
1136                            (e.clone().str().len_chars() + lit(n)).clip_min(lit(0))
1137                        };
1138                        e.str().slice(lit(0), len)
1139                    },
1140                    Expr::Literal(v) => {
1141                        polars_bail!(SQLSyntax: "invalid 'n_chars' for LEFT ({:?})", v)
1142                    },
1143                    _ => when(length.clone().gt_eq(lit(0)))
1144                        .then(e.clone().str().slice(lit(0), length.clone().abs()))
1145                        .otherwise(e.clone().str().slice(
1146                            lit(0),
1147                            (e.clone().str().len_chars() + length.clone()).clip_min(lit(0)),
1148                        )),
1149                })
1150            }),
1151            Length => self.visit_unary(|e| e.str().len_chars()),
1152            Lower => self.visit_unary(|e| e.str().to_lowercase()),
1153            LTrim => {
1154                let args = extract_args(function)?;
1155                match args.len() {
1156                    1 => self.visit_unary(|e| {
1157                        e.str().strip_chars_start(lit(LiteralValue::untyped_null()))
1158                    }),
1159                    2 => self.visit_binary(|e, s| e.str().strip_chars_start(s)),
1160                    _ => {
1161                        polars_bail!(SQLSyntax: "LTRIM expects 1-2 arguments (found {})", args.len())
1162                    },
1163                }
1164            },
1165            Normalize => {
1166                let args = extract_args(function)?;
1167                match args.len() {
1168                    1 => self.visit_unary(|e| e.str().normalize(UnicodeForm::NFC)),
1169                    2 => {
1170                        let form = if let FunctionArgExpr::Expr(SQLExpr::Identifier(Ident {
1171                            value: s,
1172                            quote_style: None,
1173                            span: _,
1174                        })) = args[1]
1175                        {
1176                            match s.to_uppercase().as_str() {
1177                                "NFC" => UnicodeForm::NFC,
1178                                "NFD" => UnicodeForm::NFD,
1179                                "NFKC" => UnicodeForm::NFKC,
1180                                "NFKD" => UnicodeForm::NFKD,
1181                                _ => {
1182                                    polars_bail!(SQLSyntax: "invalid 'form' for NORMALIZE (found {})", s)
1183                                },
1184                            }
1185                        } else {
1186                            polars_bail!(SQLSyntax: "invalid 'form' for NORMALIZE (found {})", args[1])
1187                        };
1188                        self.try_visit_binary(|e, _form: Expr| Ok(e.str().normalize(form.clone())))
1189                    },
1190                    _ => {
1191                        polars_bail!(SQLSyntax: "NORMALIZE expects 1-2 arguments (found {})", args.len())
1192                    },
1193                }
1194            },
1195            OctetLength => self.visit_unary(|e| e.str().len_bytes()),
1196            StrPos => {
1197                // // note: SQL is 1-indexed; returns zero if no match found
1198                self.visit_binary(|expr, substring| {
1199                    (expr.str().find(substring, true) + typed_lit(1u32)).fill_null(typed_lit(0u32))
1200                })
1201            },
1202            RegexpLike => {
1203                let args = extract_args(function)?;
1204                match args.len() {
1205                    2 => self.visit_binary(|e, s| e.str().contains(s, true)),
1206                    3 => self.try_visit_ternary(|e, pat, flags| {
1207                        Ok(e.str().contains(
1208                            match (pat, flags) {
1209                                (Expr::Literal(s_lv), Expr::Literal(f_lv)) if s_lv.extract_str().is_some() && f_lv.extract_str().is_some() => {
1210                                    let s = s_lv.extract_str().unwrap();
1211                                    let f = f_lv.extract_str().unwrap();
1212                                    if f.is_empty() {
1213                                        polars_bail!(SQLSyntax: "invalid/empty 'flags' for REGEXP_LIKE ({})", args[2]);
1214                                    };
1215                                    lit(format!("(?{}){}", f, s))
1216                                },
1217                                _ => {
1218                                    polars_bail!(SQLSyntax: "invalid arguments for REGEXP_LIKE ({}, {})", args[1], args[2]);
1219                                },
1220                            },
1221                            true))
1222                    }),
1223                    _ => polars_bail!(SQLSyntax: "REGEXP_LIKE expects 2-3 arguments (found {})",args.len()),
1224                }
1225            },
1226            Replace => {
1227                let args = extract_args(function)?;
1228                match args.len() {
1229                    3 => self
1230                        .try_visit_ternary(|e, old, new| Ok(e.str().replace_all(old, new, true))),
1231                    _ => {
1232                        polars_bail!(SQLSyntax: "REPLACE expects 3 arguments (found {})", args.len())
1233                    },
1234                }
1235            },
1236            Reverse => self.visit_unary(|e| e.str().reverse()),
1237            Right => self.try_visit_binary(|e, length| {
1238                Ok(match length {
1239                    Expr::Literal(lv) if lv.is_null() => lit(lv),
1240                    Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(0))) => typed_lit(""),
1241                    Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n))) => {
1242                        let n: i64 = n.try_into().unwrap();
1243                        let offset = if n < 0 {
1244                            lit(n.abs())
1245                        } else {
1246                            e.clone().str().len_chars().cast(DataType::Int32) - lit(n)
1247                        };
1248                        e.str().slice(offset, lit(LiteralValue::untyped_null()))
1249                    },
1250                    Expr::Literal(v) => {
1251                        polars_bail!(SQLSyntax: "invalid 'n_chars' for RIGHT ({:?})", v)
1252                    },
1253                    _ => when(length.clone().lt(lit(0)))
1254                        .then(
1255                            e.clone()
1256                                .str()
1257                                .slice(length.clone().abs(), lit(LiteralValue::untyped_null())),
1258                        )
1259                        .otherwise(e.clone().str().slice(
1260                            e.clone().str().len_chars().cast(DataType::Int32) - length.clone(),
1261                            lit(LiteralValue::untyped_null()),
1262                        )),
1263                })
1264            }),
1265            RTrim => {
1266                let args = extract_args(function)?;
1267                match args.len() {
1268                    1 => self.visit_unary(|e| {
1269                        e.str().strip_chars_end(lit(LiteralValue::untyped_null()))
1270                    }),
1271                    2 => self.visit_binary(|e, s| e.str().strip_chars_end(s)),
1272                    _ => {
1273                        polars_bail!(SQLSyntax: "RTRIM expects 1-2 arguments (found {})", args.len())
1274                    },
1275                }
1276            },
1277            StartsWith => self.visit_binary(|e, s| e.str().starts_with(s)),
1278            Strptime => {
1279                let args = extract_args(function)?;
1280                match args.len() {
1281                    2 => self.visit_binary(|e, fmt: String| {
1282                        e.str().strptime(
1283                            DataType::Datetime(TimeUnit::Microseconds, None),
1284                            StrptimeOptions {
1285                                format: Some(fmt.into()),
1286                                ..Default::default()
1287                            },
1288                            lit("latest"),
1289                        )
1290                    }),
1291                    _ => {
1292                        polars_bail!(SQLSyntax: "STRPTIME expects 2 arguments (found {})", args.len())
1293                    },
1294                }
1295            },
1296            Time => {
1297                let args = extract_args(function)?;
1298                match args.len() {
1299                    1 => self.visit_unary(|e| e.str().to_time(StrptimeOptions::default())),
1300                    2 => self.visit_binary(|e, fmt| e.str().to_time(fmt)),
1301                    _ => {
1302                        polars_bail!(SQLSyntax: "TIME expects 1-2 arguments (found {})", args.len())
1303                    },
1304                }
1305            },
1306            Timestamp => {
1307                let args = extract_args(function)?;
1308                match args.len() {
1309                    1 => self.visit_unary(|e| {
1310                        e.str()
1311                            .to_datetime(None, None, StrptimeOptions::default(), lit("latest"))
1312                    }),
1313                    2 => self
1314                        .visit_binary(|e, fmt| e.str().to_datetime(None, None, fmt, lit("latest"))),
1315                    _ => {
1316                        polars_bail!(SQLSyntax: "DATETIME expects 1-2 arguments (found {})", args.len())
1317                    },
1318                }
1319            },
1320            Substring => {
1321                let args = extract_args(function)?;
1322                match args.len() {
1323                    // note: SQL is 1-indexed, hence the need for adjustments
1324                    2 => self.try_visit_binary(|e, start| {
1325                        Ok(match start {
1326                            Expr::Literal(lv) if lv.is_null() => lit(lv),
1327                            Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n))) if n <= 0 => e,
1328                            Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n))) => e.str().slice(lit(n - 1), lit(LiteralValue::untyped_null())),
1329                            Expr::Literal(_) => polars_bail!(SQLSyntax: "invalid 'start' for SUBSTR ({})", args[1]),
1330                            _ => start.clone() + lit(1),
1331                        })
1332                    }),
1333                    3 => self.try_visit_ternary(|e: Expr, start: Expr, length: Expr| {
1334                        Ok(match (start.clone(), length.clone()) {
1335                            (Expr::Literal(lv), _) | (_, Expr::Literal(lv)) if lv.is_null() => lit(lv),
1336                            (_, Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n)))) if n < 0 => {
1337                                polars_bail!(SQLSyntax: "SUBSTR does not support negative length ({})", args[2])
1338                            },
1339                            (Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n))), _) if n > 0 => e.str().slice(lit(n - 1), length.clone()),
1340                            (Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n))), _) => {
1341                                e.str().slice(lit(0), (length.clone() + lit(n - 1)).clip_min(lit(0)))
1342                            },
1343                            (Expr::Literal(_), _) => polars_bail!(SQLSyntax: "invalid 'start' for SUBSTR ({})", args[1]),
1344                            (_, Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Float(_)))) => {
1345                                polars_bail!(SQLSyntax: "invalid 'length' for SUBSTR ({})", args[1])
1346                            },
1347                            _ => {
1348                                let adjusted_start = start.clone() - lit(1);
1349                                when(adjusted_start.clone().lt(lit(0)))
1350                                    .then(e.clone().str().slice(lit(0), (length.clone() + adjusted_start.clone()).clip_min(lit(0))))
1351                                    .otherwise(e.clone().str().slice(adjusted_start.clone(), length.clone()))
1352                            }
1353                        })
1354                    }),
1355                    _ => polars_bail!(SQLSyntax: "SUBSTR expects 2-3 arguments (found {})", args.len()),
1356                }
1357            },
1358            Upper => self.visit_unary(|e| e.str().to_uppercase()),
1359
1360            // ----
1361            // Aggregate functions
1362            // ----
1363            Avg => self.visit_unary(Expr::mean),
1364            Count => self.visit_count(),
1365            First => self.visit_unary(Expr::first),
1366            Last => self.visit_unary(Expr::last),
1367            Max => self.visit_unary_with_opt_cumulative(Expr::max, Expr::cum_max),
1368            Median => self.visit_unary(Expr::median),
1369            QuantileCont => {
1370                let args = extract_args(function)?;
1371                match args.len() {
1372                    2 => self.try_visit_binary(|e, q| {
1373                        let value = match q {
1374                            Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Float(f))) => {
1375                                if (0.0..=1.0).contains(&f) {
1376                                    Expr::from(f)
1377                                } else {
1378                                    polars_bail!(SQLSyntax: "QUANTILE_CONT value must be between 0 and 1 ({})", args[1])
1379                                }
1380                            },
1381                            Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n))) => {
1382                                if (0..=1).contains(&n) {
1383                                    Expr::from(n as f64)
1384                                } else {
1385                                    polars_bail!(SQLSyntax: "QUANTILE_CONT value must be between 0 and 1 ({})", args[1])
1386                                }
1387                            },
1388                            _ => polars_bail!(SQLSyntax: "invalid value for QUANTILE_CONT ({})", args[1])
1389                        };
1390                        Ok(e.quantile(value, QuantileMethod::Linear))
1391                    }),
1392                    _ => polars_bail!(SQLSyntax: "QUANTILE_CONT expects 2 arguments (found {})", args.len()),
1393                }
1394            },
1395            QuantileDisc => {
1396                let args = extract_args(function)?;
1397                match args.len() {
1398                    2 => self.try_visit_binary(|e, q| {
1399                        let value = match q {
1400                            Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Float(f))) => {
1401                                if (0.0..=1.0).contains(&f) {
1402                                    Expr::from(f)
1403                                } else {
1404                                    polars_bail!(SQLSyntax: "QUANTILE_DISC value must be between 0 and 1 ({})", args[1])
1405                                }
1406                            },
1407                            Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n))) => {
1408                                if (0..=1).contains(&n) {
1409                                    Expr::from(n as f64)
1410                                } else {
1411                                    polars_bail!(SQLSyntax: "QUANTILE_DISC value must be between 0 and 1 ({})", args[1])
1412                                }
1413                            },
1414                            _ => polars_bail!(SQLSyntax: "invalid value for QUANTILE_DISC ({})", args[1])
1415                        };
1416                        Ok(e.quantile(value, QuantileMethod::Equiprobable))
1417                    }),
1418                    _ => polars_bail!(SQLSyntax: "QUANTILE_DISC expects 2 arguments (found {})", args.len()),
1419                }
1420            },
1421            Min => self.visit_unary_with_opt_cumulative(Expr::min, Expr::cum_min),
1422            StdDev => self.visit_unary(|e| e.std(1)),
1423            Sum => self.visit_unary_with_opt_cumulative(Expr::sum, Expr::cum_sum),
1424            Variance => self.visit_unary(|e| e.var(1)),
1425
1426            // ----
1427            // Array functions
1428            // ----
1429            ArrayAgg => self.visit_arr_agg(),
1430            ArrayContains => self.visit_binary::<Expr>(|e, s| e.list().contains(s)),
1431            ArrayGet => {
1432                // note: SQL is 1-indexed, not 0-indexed
1433                self.visit_binary(|e, idx: Expr| {
1434                    let idx = adjust_one_indexed_param(idx, true);
1435                    e.list().get(idx, true)
1436                })
1437            },
1438            ArrayLength => self.visit_unary(|e| e.list().len()),
1439            ArrayMax => self.visit_unary(|e| e.list().max()),
1440            ArrayMean => self.visit_unary(|e| e.list().mean()),
1441            ArrayMin => self.visit_unary(|e| e.list().min()),
1442            ArrayReverse => self.visit_unary(|e| e.list().reverse()),
1443            ArraySum => self.visit_unary(|e| e.list().sum()),
1444            ArrayToString => self.visit_arr_to_string(),
1445            ArrayUnique => self.visit_unary(|e| e.list().unique()),
1446            Explode => self.visit_unary(|e| e.explode()),
1447
1448            // ----
1449            // Column selection
1450            // ----
1451            Columns => {
1452                let active_schema = self.active_schema;
1453                self.try_visit_unary(|e: Expr| match e {
1454                    Expr::Literal(lv) if lv.extract_str().is_some() => {
1455                        let pat = lv.extract_str().unwrap();
1456                        if pat == "*" {
1457                            polars_bail!(
1458                                SQLSyntax: "COLUMNS('*') is not a valid regex; \
1459                                did you mean COLUMNS(*)?"
1460                            )
1461                        };
1462                        let pat = match pat {
1463                            _ if pat.starts_with('^') && pat.ends_with('$') => pat.to_string(),
1464                            _ if pat.starts_with('^') => format!("{}.*$", pat),
1465                            _ if pat.ends_with('$') => format!("^.*{}", pat),
1466                            _ => format!("^.*{}.*$", pat),
1467                        };
1468                        if let Some(active_schema) = &active_schema {
1469                            let rx = polars_utils::regex_cache::compile_regex(&pat).unwrap();
1470                            let col_names = active_schema
1471                                .iter_names()
1472                                .filter(|name| rx.is_match(name))
1473                                .cloned()
1474                                .collect::<Vec<_>>();
1475
1476                            Ok(if col_names.len() == 1 {
1477                                col(col_names.into_iter().next().unwrap())
1478                            } else {
1479                                cols(col_names)
1480                            })
1481                        } else {
1482                            Ok(col(pat.as_str()))
1483                        }
1484                    },
1485                    Expr::Wildcard => Ok(col("*")),
1486                    _ => polars_bail!(SQLSyntax: "COLUMNS expects a regex; found {:?}", e),
1487                })
1488            },
1489
1490            // ----
1491            // User-defined
1492            // ----
1493            Udf(func_name) => self.visit_udf(&func_name),
1494        }
1495    }
1496
1497    fn visit_udf(&mut self, func_name: &str) -> PolarsResult<Expr> {
1498        let args = extract_args(self.func)?
1499            .into_iter()
1500            .map(|arg| {
1501                if let FunctionArgExpr::Expr(e) = arg {
1502                    parse_sql_expr(e, self.ctx, self.active_schema)
1503                } else {
1504                    polars_bail!(SQLInterface: "only expressions are supported in UDFs")
1505                }
1506            })
1507            .collect::<PolarsResult<Vec<_>>>()?;
1508
1509        self.ctx
1510            .function_registry
1511            .get_udf(func_name)?
1512            .ok_or_else(|| polars_err!(SQLInterface: "UDF {} not found", func_name))?
1513            .call(args)
1514    }
1515
1516    /// Window specs without partition bys are essentially cumulative functions
1517    /// e.g. SUM(a) OVER (ORDER BY b DESC) -> CUMSUM(a, false)
1518    fn apply_cumulative_window(
1519        &mut self,
1520        f: impl Fn(Expr) -> Expr,
1521        cumulative_f: impl Fn(Expr, bool) -> Expr,
1522        WindowSpec {
1523            partition_by,
1524            order_by,
1525            ..
1526        }: &WindowSpec,
1527    ) -> PolarsResult<Expr> {
1528        if !order_by.is_empty() && partition_by.is_empty() {
1529            let (order_by, desc): (Vec<Expr>, Vec<bool>) = order_by
1530                .iter()
1531                .map(|o| {
1532                    let expr = parse_sql_expr(&o.expr, self.ctx, self.active_schema)?;
1533                    Ok(match o.asc {
1534                        Some(b) => (expr, !b),
1535                        None => (expr, false),
1536                    })
1537                })
1538                .collect::<PolarsResult<Vec<_>>>()?
1539                .into_iter()
1540                .unzip();
1541            self.visit_unary_no_window(|e| {
1542                cumulative_f(
1543                    e.sort_by(
1544                        &order_by,
1545                        SortMultipleOptions::default().with_order_descending_multi(desc.clone()),
1546                    ),
1547                    false,
1548                )
1549            })
1550        } else {
1551            self.visit_unary(f)
1552        }
1553    }
1554
1555    fn visit_unary(&mut self, f: impl Fn(Expr) -> Expr) -> PolarsResult<Expr> {
1556        self.try_visit_unary(|e| Ok(f(e)))
1557    }
1558
1559    fn try_visit_unary(&mut self, f: impl Fn(Expr) -> PolarsResult<Expr>) -> PolarsResult<Expr> {
1560        let args = extract_args(self.func)?;
1561        match args.as_slice() {
1562            [FunctionArgExpr::Expr(sql_expr)] => {
1563                f(parse_sql_expr(sql_expr, self.ctx, self.active_schema)?)
1564            },
1565            [FunctionArgExpr::Wildcard] => f(parse_sql_expr(
1566                &SQLExpr::Wildcard(AttachedToken::empty()),
1567                self.ctx,
1568                self.active_schema,
1569            )?),
1570            _ => self.not_supported_error(),
1571        }
1572        .and_then(|e| self.apply_window_spec(e, &self.func.over))
1573    }
1574
1575    /// Some functions have cumulative equivalents that can be applied to window specs
1576    /// e.g. SUM(a) OVER (ORDER BY b DESC) -> CUMSUM(a, false)
1577    /// visit_unary_with_cumulative_window will take in a function & a cumulative function
1578    /// if there is a cumulative window spec, it will apply the cumulative function,
1579    /// otherwise it will apply the function
1580    fn visit_unary_with_opt_cumulative(
1581        &mut self,
1582        f: impl Fn(Expr) -> Expr,
1583        cumulative_f: impl Fn(Expr, bool) -> Expr,
1584    ) -> PolarsResult<Expr> {
1585        match self.func.over.as_ref() {
1586            Some(WindowType::WindowSpec(spec)) => {
1587                self.apply_cumulative_window(f, cumulative_f, spec)
1588            },
1589            Some(WindowType::NamedWindow(named_window)) => polars_bail!(
1590                SQLInterface: "Named windows are not currently supported; found {:?}",
1591                named_window
1592            ),
1593            _ => self.visit_unary(f),
1594        }
1595    }
1596
1597    fn visit_unary_no_window(&mut self, f: impl Fn(Expr) -> Expr) -> PolarsResult<Expr> {
1598        let args = extract_args(self.func)?;
1599        match args.as_slice() {
1600            [FunctionArgExpr::Expr(sql_expr)] => {
1601                let expr = parse_sql_expr(sql_expr, self.ctx, self.active_schema)?;
1602                // apply the function on the inner expr -- e.g. SUM(a) -> SUM
1603                Ok(f(expr))
1604            },
1605            _ => self.not_supported_error(),
1606        }
1607    }
1608
1609    fn visit_binary<Arg: FromSQLExpr>(
1610        &mut self,
1611        f: impl Fn(Expr, Arg) -> Expr,
1612    ) -> PolarsResult<Expr> {
1613        self.try_visit_binary(|e, a| Ok(f(e, a)))
1614    }
1615
1616    fn try_visit_binary<Arg: FromSQLExpr>(
1617        &mut self,
1618        f: impl Fn(Expr, Arg) -> PolarsResult<Expr>,
1619    ) -> PolarsResult<Expr> {
1620        let args = extract_args(self.func)?;
1621        match args.as_slice() {
1622            [
1623                FunctionArgExpr::Expr(sql_expr1),
1624                FunctionArgExpr::Expr(sql_expr2),
1625            ] => {
1626                let expr1 = parse_sql_expr(sql_expr1, self.ctx, self.active_schema)?;
1627                let expr2 = Arg::from_sql_expr(sql_expr2, self.ctx)?;
1628                f(expr1, expr2)
1629            },
1630            _ => self.not_supported_error(),
1631        }
1632    }
1633
1634    fn visit_variadic(&mut self, f: impl Fn(&[Expr]) -> Expr) -> PolarsResult<Expr> {
1635        self.try_visit_variadic(|e| Ok(f(e)))
1636    }
1637
1638    fn try_visit_variadic(
1639        &mut self,
1640        f: impl Fn(&[Expr]) -> PolarsResult<Expr>,
1641    ) -> PolarsResult<Expr> {
1642        let args = extract_args(self.func)?;
1643        let mut expr_args = vec![];
1644        for arg in args {
1645            if let FunctionArgExpr::Expr(sql_expr) = arg {
1646                expr_args.push(parse_sql_expr(sql_expr, self.ctx, self.active_schema)?);
1647            } else {
1648                return self.not_supported_error();
1649            };
1650        }
1651        f(&expr_args)
1652    }
1653
1654    fn try_visit_ternary<Arg: FromSQLExpr>(
1655        &mut self,
1656        f: impl Fn(Expr, Arg, Arg) -> PolarsResult<Expr>,
1657    ) -> PolarsResult<Expr> {
1658        let args = extract_args(self.func)?;
1659        match args.as_slice() {
1660            [
1661                FunctionArgExpr::Expr(sql_expr1),
1662                FunctionArgExpr::Expr(sql_expr2),
1663                FunctionArgExpr::Expr(sql_expr3),
1664            ] => {
1665                let expr1 = parse_sql_expr(sql_expr1, self.ctx, self.active_schema)?;
1666                let expr2 = Arg::from_sql_expr(sql_expr2, self.ctx)?;
1667                let expr3 = Arg::from_sql_expr(sql_expr3, self.ctx)?;
1668                f(expr1, expr2, expr3)
1669            },
1670            _ => self.not_supported_error(),
1671        }
1672    }
1673
1674    fn visit_nullary(&self, f: impl Fn() -> Expr) -> PolarsResult<Expr> {
1675        let args = extract_args(self.func)?;
1676        if !args.is_empty() {
1677            return self.not_supported_error();
1678        }
1679        Ok(f())
1680    }
1681
1682    fn visit_arr_agg(&mut self) -> PolarsResult<Expr> {
1683        let (args, is_distinct, clauses) = extract_args_and_clauses(self.func)?;
1684        match args.as_slice() {
1685            [FunctionArgExpr::Expr(sql_expr)] => {
1686                let mut base = parse_sql_expr(sql_expr, self.ctx, self.active_schema)?;
1687                if is_distinct {
1688                    base = base.unique_stable();
1689                }
1690                for clause in clauses {
1691                    match clause {
1692                        FunctionArgumentClause::OrderBy(order_exprs) => {
1693                            base = self.apply_order_by(base, order_exprs.as_slice())?;
1694                        },
1695                        FunctionArgumentClause::Limit(limit_expr) => {
1696                            let limit = parse_sql_expr(&limit_expr, self.ctx, self.active_schema)?;
1697                            match limit {
1698                                Expr::Literal(LiteralValue::Dyn(DynLiteralValue::Int(n)))
1699                                    if n >= 0 =>
1700                                {
1701                                    base = base.head(Some(n as usize))
1702                                },
1703                                _ => {
1704                                    polars_bail!(SQLSyntax: "LIMIT in ARRAY_AGG must be a positive integer")
1705                                },
1706                            };
1707                        },
1708                        _ => {},
1709                    }
1710                }
1711                Ok(base.implode())
1712            },
1713            _ => {
1714                polars_bail!(SQLSyntax: "ARRAY_AGG must have exactly one argument; found {}", args.len())
1715            },
1716        }
1717    }
1718
1719    fn visit_arr_to_string(&mut self) -> PolarsResult<Expr> {
1720        let args = extract_args(self.func)?;
1721        match args.len() {
1722            2 => self.try_visit_binary(|e, sep| {
1723                Ok(e.cast(DataType::List(Box::from(DataType::String)))
1724                    .list()
1725                    .join(sep, true))
1726            }),
1727            #[cfg(feature = "list_eval")]
1728            3 => self.try_visit_ternary(|e, sep, null_value| match null_value {
1729                Expr::Literal(lv) if lv.extract_str().is_some() => {
1730                    Ok(if lv.extract_str().unwrap().is_empty() {
1731                        e.cast(DataType::List(Box::from(DataType::String)))
1732                            .list()
1733                            .join(sep, true)
1734                    } else {
1735                        e.cast(DataType::List(Box::from(DataType::String)))
1736                            .list()
1737                            .eval(col("").fill_null(lit(lv.extract_str().unwrap())), false)
1738                            .list()
1739                            .join(sep, false)
1740                    })
1741                },
1742                _ => {
1743                    polars_bail!(SQLSyntax: "invalid null value for ARRAY_TO_STRING ({})", args[2])
1744                },
1745            }),
1746            _ => {
1747                polars_bail!(SQLSyntax: "ARRAY_TO_STRING expects 2-3 arguments (found {})", args.len())
1748            },
1749        }
1750    }
1751
1752    fn visit_count(&mut self) -> PolarsResult<Expr> {
1753        let (args, is_distinct) = extract_args_distinct(self.func)?;
1754        match (is_distinct, args.as_slice()) {
1755            // count(*), count()
1756            (false, [FunctionArgExpr::Wildcard] | []) => Ok(len()),
1757            // count(column_name)
1758            (false, [FunctionArgExpr::Expr(sql_expr)]) => {
1759                let expr = parse_sql_expr(sql_expr, self.ctx, self.active_schema)?;
1760                let expr = self.apply_window_spec(expr, &self.func.over)?;
1761                Ok(expr.count())
1762            },
1763            // count(distinct column_name)
1764            (true, [FunctionArgExpr::Expr(sql_expr)]) => {
1765                let expr = parse_sql_expr(sql_expr, self.ctx, self.active_schema)?;
1766                let expr = self.apply_window_spec(expr, &self.func.over)?;
1767                Ok(expr.clone().n_unique().sub(expr.null_count().gt(lit(0))))
1768            },
1769            _ => self.not_supported_error(),
1770        }
1771    }
1772
1773    fn apply_order_by(&mut self, expr: Expr, order_by: &[OrderByExpr]) -> PolarsResult<Expr> {
1774        let mut by = Vec::with_capacity(order_by.len());
1775        let mut descending = Vec::with_capacity(order_by.len());
1776        let mut nulls_last = Vec::with_capacity(order_by.len());
1777
1778        for ob in order_by {
1779            // note: if not specified 'NULLS FIRST' is default for DESC, 'NULLS LAST' otherwise
1780            // https://www.postgresql.org/docs/current/queries-order.html
1781            let desc_order = !ob.asc.unwrap_or(true);
1782            by.push(parse_sql_expr(&ob.expr, self.ctx, self.active_schema)?);
1783            nulls_last.push(!ob.nulls_first.unwrap_or(desc_order));
1784            descending.push(desc_order);
1785        }
1786        Ok(expr.sort_by(
1787            by,
1788            SortMultipleOptions::default()
1789                .with_order_descending_multi(descending)
1790                .with_nulls_last_multi(nulls_last)
1791                .with_maintain_order(true),
1792        ))
1793    }
1794
1795    fn apply_window_spec(
1796        &mut self,
1797        expr: Expr,
1798        window_type: &Option<WindowType>,
1799    ) -> PolarsResult<Expr> {
1800        Ok(match &window_type {
1801            Some(WindowType::WindowSpec(window_spec)) => {
1802                if window_spec.partition_by.is_empty() {
1803                    let exprs = window_spec
1804                        .order_by
1805                        .iter()
1806                        .map(|o| {
1807                            let e = parse_sql_expr(&o.expr, self.ctx, self.active_schema)?;
1808                            Ok(o.asc.map_or(e.clone(), |b| {
1809                                e.sort(SortOptions::default().with_order_descending(!b))
1810                            }))
1811                        })
1812                        .collect::<PolarsResult<Vec<_>>>()?;
1813                    expr.over(exprs)
1814                } else {
1815                    // Process for simple window specification, partition by first
1816                    let partition_by = window_spec
1817                        .partition_by
1818                        .iter()
1819                        .map(|p| parse_sql_expr(p, self.ctx, self.active_schema))
1820                        .collect::<PolarsResult<Vec<_>>>()?;
1821                    expr.over(partition_by)
1822                }
1823            },
1824            Some(WindowType::NamedWindow(named_window)) => polars_bail!(
1825                SQLInterface: "Named windows are not currently supported; found {:?}",
1826                named_window
1827            ),
1828            None => expr,
1829        })
1830    }
1831
1832    fn not_supported_error(&self) -> PolarsResult<Expr> {
1833        polars_bail!(
1834            SQLInterface:
1835            "no function matches the given name and arguments: `{}`",
1836            self.func.to_string()
1837        );
1838    }
1839}
1840
1841fn extract_args(func: &SQLFunction) -> PolarsResult<Vec<&FunctionArgExpr>> {
1842    let (args, _, _) = _extract_func_args(func, false, false)?;
1843    Ok(args)
1844}
1845
1846fn extract_args_distinct(func: &SQLFunction) -> PolarsResult<(Vec<&FunctionArgExpr>, bool)> {
1847    let (args, is_distinct, _) = _extract_func_args(func, true, false)?;
1848    Ok((args, is_distinct))
1849}
1850
1851fn extract_args_and_clauses(
1852    func: &SQLFunction,
1853) -> PolarsResult<(Vec<&FunctionArgExpr>, bool, Vec<FunctionArgumentClause>)> {
1854    _extract_func_args(func, true, true)
1855}
1856
1857fn _extract_func_args(
1858    func: &SQLFunction,
1859    get_distinct: bool,
1860    get_clauses: bool,
1861) -> PolarsResult<(Vec<&FunctionArgExpr>, bool, Vec<FunctionArgumentClause>)> {
1862    match &func.args {
1863        FunctionArguments::List(FunctionArgumentList {
1864            args,
1865            duplicate_treatment,
1866            clauses,
1867        }) => {
1868            let is_distinct = matches!(duplicate_treatment, Some(DuplicateTreatment::Distinct));
1869            if !(get_clauses || get_distinct) && is_distinct {
1870                polars_bail!(SQLSyntax: "unexpected use of DISTINCT found in '{}'", func.name)
1871            } else if !get_clauses && !clauses.is_empty() {
1872                polars_bail!(SQLSyntax: "unexpected clause found in '{}' ({})", func.name, clauses[0])
1873            } else {
1874                let unpacked_args = args
1875                    .iter()
1876                    .map(|arg| match arg {
1877                        FunctionArg::Named { arg, .. } => arg,
1878                        FunctionArg::ExprNamed { arg, .. } => arg,
1879                        FunctionArg::Unnamed(arg) => arg,
1880                    })
1881                    .collect();
1882                Ok((unpacked_args, is_distinct, clauses.clone()))
1883            }
1884        },
1885        FunctionArguments::Subquery { .. } => {
1886            Err(polars_err!(SQLInterface: "subquery not expected in {}", func.name))
1887        },
1888        FunctionArguments::None => Ok((vec![], false, vec![])),
1889    }
1890}
1891
1892pub(crate) trait FromSQLExpr {
1893    fn from_sql_expr(expr: &SQLExpr, ctx: &mut SQLContext) -> PolarsResult<Self>
1894    where
1895        Self: Sized;
1896}
1897
1898impl FromSQLExpr for f64 {
1899    fn from_sql_expr(expr: &SQLExpr, _ctx: &mut SQLContext) -> PolarsResult<Self>
1900    where
1901        Self: Sized,
1902    {
1903        match expr {
1904            SQLExpr::Value(v) => match v {
1905                SQLValue::Number(s, _) => s
1906                    .parse()
1907                    .map_err(|_| polars_err!(SQLInterface: "cannot parse literal {:?}", s)),
1908                _ => polars_bail!(SQLInterface: "cannot parse literal {:?}", v),
1909            },
1910            _ => polars_bail!(SQLInterface: "cannot parse literal {:?}", expr),
1911        }
1912    }
1913}
1914
1915impl FromSQLExpr for bool {
1916    fn from_sql_expr(expr: &SQLExpr, _ctx: &mut SQLContext) -> PolarsResult<Self>
1917    where
1918        Self: Sized,
1919    {
1920        match expr {
1921            SQLExpr::Value(v) => match v {
1922                SQLValue::Boolean(v) => Ok(*v),
1923                _ => polars_bail!(SQLInterface: "cannot parse boolean {:?}", v),
1924            },
1925            _ => polars_bail!(SQLInterface: "cannot parse boolean {:?}", expr),
1926        }
1927    }
1928}
1929
1930impl FromSQLExpr for String {
1931    fn from_sql_expr(expr: &SQLExpr, _: &mut SQLContext) -> PolarsResult<Self>
1932    where
1933        Self: Sized,
1934    {
1935        match expr {
1936            SQLExpr::Value(v) => match v {
1937                SQLValue::SingleQuotedString(s) => Ok(s.clone()),
1938                _ => polars_bail!(SQLInterface: "cannot parse literal {:?}", v),
1939            },
1940            _ => polars_bail!(SQLInterface: "cannot parse literal {:?}", expr),
1941        }
1942    }
1943}
1944
1945impl FromSQLExpr for StrptimeOptions {
1946    fn from_sql_expr(expr: &SQLExpr, _: &mut SQLContext) -> PolarsResult<Self>
1947    where
1948        Self: Sized,
1949    {
1950        match expr {
1951            SQLExpr::Value(v) => match v {
1952                SQLValue::SingleQuotedString(s) => Ok(StrptimeOptions {
1953                    format: Some(PlSmallStr::from_str(s)),
1954                    ..StrptimeOptions::default()
1955                }),
1956                _ => polars_bail!(SQLInterface: "cannot parse literal {:?}", v),
1957            },
1958            _ => polars_bail!(SQLInterface: "cannot parse literal {:?}", expr),
1959        }
1960    }
1961}
1962
1963impl FromSQLExpr for Expr {
1964    fn from_sql_expr(expr: &SQLExpr, ctx: &mut SQLContext) -> PolarsResult<Self>
1965    where
1966        Self: Sized,
1967    {
1968        parse_sql_expr(expr, ctx, None)
1969    }
1970}