Skip to main content

inillucent_sql/
function.rs

1//! The built-in function registry: names, arities, and identities.
2//!
3//! Invariant: a function is recognised here or it does not exist. The binder
4//! resolves a name to one of these identities and refuses everything else with
5//! "no such function", so an unknown name fails at prepare time rather than
6//! part-way through a scan, and the VM never dispatches on a string.
7//!
8//! Arity is checked here too, because SQLite reports "wrong number of arguments
9//! to function abs()" from prepare rather than from execution.
10
11/// The names that exist in inillucent but need a component this build has not
12/// got.
13///
14/// **`embed` is the whole list, and it is here rather than in the registry
15/// because the registry is where it is absent** (task-1979, section 8.1, gap
16/// 12). `inillucent-search` registers `embed` only when the `embed` feature is
17/// compiled in, so on a build without it the name reaches the binder's
18/// "no such function" path and answered exit 1 - which says the caller
19/// misspelled something. The statement is spelled correctly and this build has
20/// not got the function, which is exactly what exit 3 means.
21///
22/// A build that *does* have `embed` never reaches here, because the registry
23/// resolves the name before the refusal is built. A machine that has the
24/// function and not the model is a third thing again and keeps its own status:
25/// `inillucent-search`'s `no_model` answers `invalid_state` and names
26/// `inillucent setup-embeddings`, because the component is installable and
27/// exit 3 would say the opposite.
28const NEEDS_A_COMPONENT: &[(&[u8], &str)] = &[(
29    b"embed",
30    "embed(TEXT): this build has no embedding support compiled in",
31)];
32
33/// Returns what a name needs, when the name is one this build left out.
34///
35/// @param name - the folded function name that did not resolve
36pub fn needs_a_component(name: &[u8]) -> Option<&'static str> {
37    NEEDS_A_COMPONENT
38        .iter()
39        .find(|(known, _)| *known == name)
40        .map(|(_, said)| *said)
41}
42
43/// A scalar built-in.
44#[derive(Clone, Copy, Debug, PartialEq, Eq)]
45pub enum ScalarFunc {
46    /// `abs(x)`
47    Abs,
48    /// `char(...)`
49    Char,
50    /// `coalesce(...)`
51    Coalesce,
52    /// `concat(...)`
53    Concat,
54    /// `concat_ws(sep, ...)`
55    ConcatWs,
56    /// `glob(pattern, text)`
57    Glob,
58    /// `hex(x)`
59    Hex,
60    /// `ifnull(a, b)`
61    IfNull,
62    /// `iif(a, b, c)`
63    Iif,
64    /// `instr(haystack, needle)`
65    Instr,
66    /// `length(x)`
67    Length,
68    /// `like(pattern, text[, escape])`
69    Like,
70    /// `likelihood(x, y)`, `likely(x)` and `unlikely(x)`, which are no-ops.
71    Likelihood,
72    /// `lower(x)`
73    Lower,
74    /// `ltrim(x[, chars])`
75    LTrim,
76    /// `max(a, b, ...)`, the scalar form.
77    Max,
78    /// `min(a, b, ...)`, the scalar form.
79    Min,
80    /// `nullif(a, b)`
81    NullIf,
82    /// `quote(x)`
83    Quote,
84    /// `replace(text, from, to)`
85    Replace,
86    /// `round(x[, digits])`
87    Round,
88    /// `rtrim(x[, chars])`
89    RTrim,
90    /// `sign(x)`
91    Sign,
92    /// `substr(x, start[, length])`
93    Substr,
94    /// `trim(x[, chars])`
95    Trim,
96    /// `typeof(x)`
97    TypeOf,
98    /// `unhex(x[, chars])`
99    Unhex,
100    /// `unicode(x)`
101    Unicode,
102    /// `upper(x)`
103    Upper,
104    /// `zeroblob(n)`
105    ZeroBlob,
106    /// `printf(format, ...)` and `format(format, ...)`
107    Printf,
108    /// `octet_length(x)`
109    OctetLength,
110    /// `random()`
111    Random,
112    /// `randomblob(n)`
113    RandomBlob,
114    /// `changes()`
115    Changes,
116    /// `total_changes()`
117    TotalChanges,
118    /// `last_insert_rowid()`
119    LastInsertRowid,
120    /// `sqlite_source_id()`
121    SourceId,
122    /// `fts5_source_id()`
123    Fts5SourceId,
124    /// `sqlite_version()`
125    Version,
126    /// `vector_distance_cos(a, b)`, the cosine distance between two vectors.
127    ///
128    /// **Not a SQLite function, and the first one this engine adds.** pgvector
129    /// spells it `a <=> b`; the whole point of Phase 2's Part 7 is that a
130    /// vector is a value a `SELECT` can order by, and an operator that is sugar
131    /// for a function needs the function to exist first. A vector is a blob of
132    /// little-endian `f32`, which is what `inillucent_search` already stores and
133    /// what `vector_distance_l2` and `vector_dot` read too.
134    VectorDistanceCos,
135    /// `vector_distance_l2(a, b)`, the Euclidean distance between two vectors.
136    VectorDistanceL2,
137    /// `vector_dot(a, b)`, the dot product of two vectors.
138    ///
139    /// Negated relative to pgvector's `<#>`, which answers the *negative* inner
140    /// product so that a smaller number is a better match. This answers the dot
141    /// product itself, because a function named `dot` that returned its negative
142    /// would be a trap; the ordering sugar negates where it needs to.
143    VectorDot,
144    /// `l1_distance(a, b)`, the taxicab distance, spelled `a <+> b`.
145    VectorDistanceL1,
146    /// `hamming_distance(a, b)`, how many components differ.
147    ///
148    /// pgvector defines it over its `bit` type and spells it `a <~> b`. Here a
149    /// bit vector is the blob `binary_quantize` produces, and the distance is
150    /// the population count of the two blobs' exclusive-or - which is the same
151    /// number, computed the same way, over the representation this engine has.
152    VectorDistanceHamming,
153    /// `jaccard_distance(a, b)`, one minus the overlap, spelled `a <%> b`.
154    VectorDistanceJaccard,
155    /// `vector_dims(a)`, how many components a vector has.
156    VectorDims,
157    /// `vector_norm(a)`, its Euclidean length.
158    VectorNorm,
159    /// `l2_normalize(a)`, the same direction with length one.
160    VectorNormalize,
161    /// `binary_quantize(a)`, one bit per component: set when it is positive.
162    VectorQuantize,
163    /// `subvector(a, start, count)`, a slice, counted from one.
164    VectorSlice,
165    /// `vector_add(a, b)`, component by component.
166    ///
167    /// **A function rather than `+`, and that is a compatibility choice rather
168    /// than a shortcut.** pgvector can overload `+` because a `vector` is a
169    /// distinct type in PostgreSQL; here a vector is a blob, and SQLite says
170    /// that a blob in arithmetic is zero. Overloading the operator for every
171    /// blob would change the answer to `x'00' + x'00'` from `0` to a blob,
172    /// which is a difference every application that adds two blobs would see.
173    ///
174    /// **The operators were given back, on the one condition that keeps
175    /// both answers.** `a + b` binds to this function when a side reads a
176    /// column *declared* `VECTOR(n)` - which is the same thing PostgreSQL is
177    /// using, a declared type - and stays SQLite's arithmetic otherwise. So
178    /// `x'00' + x'00'` is still `0` and `v + v` over a vector column is a
179    /// vector.
180    VectorAdd,
181    /// `vector_sub(a, b)`, component by component.
182    VectorSubtract,
183    /// `vector_mul(a, b)`, component by component.
184    VectorMultiply,
185    /// `vector_concat(a, b)`, one vector after the other.
186    VectorConcat,
187    /// `geopoly_area(P)`, the signed area a polygon encloses.
188    ///
189    /// **The `geopoly` surface is thirteen functions and one aggregate**, and
190    /// they are listed here individually rather than folded into one
191    /// `Geopoly(kind)` variant because arity checking reads this enum: they
192    /// take one, two, three, four, seven and any number of arguments, and a
193    /// single variant could not say so.
194    GeopolyArea,
195    /// `geopoly_blob(P)`, the stored form of a polygon.
196    GeopolyBlob,
197    /// `geopoly_json(P)`, the GeoJSON form.
198    GeopolyJson,
199    /// `geopoly_svg(P, ...)`, an SVG `<polyline>` with the extra arguments
200    /// written into the tag.
201    GeopolySvg,
202    /// `geopoly_within(P1, P2)`, whether the second is inside the first.
203    GeopolyWithin,
204    /// `geopoly_contains_point(P, X, Y)`, where a point sits.
205    GeopolyContainsPoint,
206    /// `geopoly_overlap(P1, P2)`, how two polygons meet.
207    GeopolyOverlap,
208    /// `geopoly_debug(X)`, which answers nothing.
209    ///
210    /// It switches on the reference's own tracing, which only exists in a build
211    /// made with `GEOPOLY_ENABLE_DEBUG`; in every other build it reads its
212    /// argument and returns nothing at all. That is what this does, and it is
213    /// registered because a name the reference resolves and this engine does
214    /// not is a difference an application can see.
215    GeopolyDebug,
216    /// `geopoly_bbox(P)`, the bounding box as a four-sided polygon.
217    GeopolyBbox,
218    /// `geopoly_xform(P, A, B, C, D, E, F)`, an affine transform.
219    GeopolyXform,
220    /// `geopoly_regular(X, Y, R, N)`, a regular polygon.
221    GeopolyRegular,
222    /// `geopoly_ccw(P)`, the same ring wound counter-clockwise.
223    GeopolyCcw,
224    /// `unknown(...)`, which answers NULL to anything.
225    ///
226    /// SQLite registers it, lists it in `function_list`, and returns NULL from
227    /// it whatever it is given. It is here because a name the reference resolves
228    /// and this engine does not is a difference an application can see.
229    Unknown,
230    /// `subtype(x)`, the tag a function attached to its answer.
231    Subtype,
232    /// `unistr(x)`, which expands `\uXXXX` and `\UXXXXXXXX` escapes.
233    Unistr,
234    /// `unistr_quote(x)`, `quote()` with the control characters escaped.
235    UnistrQuote,
236    /// `sqlite_compileoption_used(name)`
237    CompileOptionUsed,
238    /// `sqlite_compileoption_get(n)`
239    CompileOptionGet,
240    /// `sqlite_log(code, message)`, which writes to the log and answers NULL.
241    Log,
242    /// `load_extension(path[, entry])`
243    LoadExtension,
244    /// `regexp(pattern, subject)`, which is what `X REGEXP Y` calls.
245    Regexp,
246    /// `sqlar_compress(X)`, a blob compressed if that makes it smaller.
247    ///
248    /// **The archive format's own rule, and it is why this is not just a
249    /// compressor.** A row of a `.sqlar` table holds either a zlib stream or
250    /// the raw bytes, and which one is decided by whichever is shorter; the
251    /// stored `sz` column is what tells the two apart on the way back. So a
252    /// value that does not compress is stored as it stands, and a value that is
253    /// not a blob at all is returned unchanged, type and all.
254    SqlarCompress,
255    /// `sqlar_uncompress(Z, SZ)`, the inverse.
256    ///
257    /// `SZ` is the size the row claims the content is. When it equals the
258    /// blob's own length the blob *is* the content and is returned unchanged,
259    /// which is how the format says "this one was stored raw".
260    SqlarUncompress,
261    /// `sqlite_offset(X)`, where in the file the row holding X is.
262    ///
263    /// **The page, not the record, and that is the whole of the difference.**
264    /// SQLite reports the byte offset of the *record* a value would be read
265    /// from, because a row there is one contiguous run of bytes. A leaf here is
266    /// PAX: each column is its own run, so one row occupies several places on
267    /// its page and there is no single offset for it. What is reported is the
268    /// offset of the page, which is where the value is genuinely read from.
269    ///
270    /// Folded to its answer by the physical pass, like `rtreecheck`, because it
271    /// is a question about a *tree* rather than about a value.
272    Offset,
273    /// `rtreedepth(X)`, the depth stored at the front of an R-Tree node.
274    RTreeDepth,
275    /// `rtreenode(D, X)`, an R-Tree node rendered as a readable list.
276    RTreeNode,
277    /// `rtreecheck(T)`, an integrity check over one R-Tree table.
278    ///
279    /// **Answered where the table is reachable, which is not here.** A scalar
280    /// is handed values and nothing else; this one is about a *table*, so the
281    /// physical pass folds it to its answer while it still has the catalog,
282    /// and what reaches the evaluator is already the text. Running once per
283    /// preparation rather than once per row is also what it means: the
284    /// argument is a table name, so the answer cannot vary down a column.
285    RTreeCheck,
286}
287
288/// An aggregate built-in.
289#[derive(Clone, Copy, Debug, PartialEq, Eq)]
290pub enum AggregateFunc {
291    /// `count(x)` and `count(*)`
292    Count,
293    /// `sum(x)`
294    Sum,
295    /// `total(x)`
296    Total,
297    /// `avg(x)`
298    Avg,
299    /// `min(x)`
300    Min,
301    /// `max(x)`
302    Max,
303    /// `group_concat(x[, sep])` and `string_agg(x, sep)`
304    GroupConcat,
305    /// `json_group_array(x)`
306    JsonGroupArray,
307    /// `jsonb_group_array(x)`
308    JsonbGroupArray,
309    /// `json_group_object(label, x)`
310    JsonGroupObject,
311    /// `jsonb_group_object(label, x)`
312    JsonbGroupObject,
313    /// `median(x)`, which is `percentile_cont(x, 0.5)` under a shorter name.
314    Median,
315    /// `geopoly_group_bbox(P)`, the box that holds every polygon in the group.
316    GeopolyGroupBbox,
317    /// `sum(v)` and `total(v)` over a vector column, component by component.
318    ///
319    /// Not a name a caller writes: the binder picks it when `sum`'s argument
320    /// reads a vector, because that is where the argument's type is known.
321    VectorSum,
322    /// `avg(v)` over a vector column, component by component.
323    VectorAvg,
324    /// `percentile(x, p)`, where `p` runs 0 to 100.
325    Percentile,
326    /// `percentile_cont(x, f)`, where `f` runs 0 to 1 and the answer is
327    /// interpolated between the two rows it falls between.
328    PercentileCont,
329    /// `percentile_disc(x, f)`, which answers one of the rows rather than a
330    /// value between two of them.
331    PercentileDisc,
332    /// An aggregate an application registered, named beside the call.
333    ///
334    /// The name is not in here because this enum is `Copy` and travels through
335    /// the program's operands; it rides in `AggregateCall` instead.
336    External,
337}
338
339/// What a registered function promises about itself.
340///
341/// It lives here, below `inillucent-ext`, because two different layers have to
342/// read the same promise: `inillucent_ext::registry::Registry` records it when
343/// an application registers a function, and the binder enforces it when a
344/// schema names one. `inillucent-ext` re-exports this type, so a registrant
345/// writes `inillucent_ext::registry::FunctionFlags` exactly as before.
346#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
347pub struct FunctionFlags {
348    /// The function may only be called from top-level SQL, never from a
349    /// schema: not from a `DEFAULT`, a `CHECK`, a generated column, an index
350    /// expression, a partial-index predicate, a view or a trigger.
351    ///
352    /// [`FunctionFlags::external`] sets this, because the safe assumption about
353    /// code somebody else wrote is that it does something. **It is not what the
354    /// `Default` derive gives**, which is every flag false: a registrant who
355    /// writes `..FunctionFlags::default()` gets a function a schema may name.
356    /// That is the hole `embed` was registered through (task-1969, 7.4), and
357    /// `inillucent_ext::registry::UserFunction::external` is the constructor to
358    /// reach for instead.
359    pub direct_only: bool,
360    /// The function does nothing an ordinary expression could not: no side
361    /// effects, no file access, no dependence on anything but its arguments.
362    pub innocuous: bool,
363    /// The function returns the same answer for the same arguments within one
364    /// statement, so the planner may call it once.
365    pub deterministic: bool,
366}
367
368impl FunctionFlags {
369    /// Returns the flags a built-in carries: safe for a schema to call.
370    pub fn builtin() -> FunctionFlags {
371        FunctionFlags {
372            direct_only: false,
373            innocuous: true,
374            deterministic: true,
375        }
376    }
377
378    /// Returns the flags anything registered from outside carries by default.
379    pub fn external() -> FunctionFlags {
380        FunctionFlags {
381            direct_only: true,
382            innocuous: false,
383            deterministic: false,
384        }
385    }
386}
387
388/// Which context a name is being resolved from.
389#[derive(Clone, Copy, Debug, PartialEq, Eq)]
390pub enum CallSite {
391    /// The statement an application submitted.
392    Statement,
393    /// A `DEFAULT`, `CHECK`, generated column, index expression, partial-index
394    /// predicate, view or trigger stored in the schema.
395    Schema,
396}
397
398/// Returns why a schema may not call this function, or nothing when it may.
399///
400/// **One rule, read by two layers (task-1972).** `Registry::authorize_function`
401/// wraps the answer in a `DbError` for an application that asks the registry
402/// directly, and the binder wraps it in a `ParseError` for the statement it is
403/// compiling. Writing the rule twice is how the two would eventually disagree,
404/// and the half nobody exercised would be the permissive one.
405///
406/// The rule reads the same way SQLite's does: a direct-only function is never
407/// callable from a schema; anything else is callable from a schema only when
408/// the connection trusts the schema or the function is innocuous.
409///
410/// @param flags - what the function promises about itself
411/// @param site - where the call was written
412/// @param trusted_schema - whether the connection trusts the schema it read
413pub fn schema_refusal(
414    flags: FunctionFlags,
415    site: CallSite,
416    trusted_schema: bool,
417) -> Option<&'static str> {
418    if site == CallSite::Statement {
419        return None;
420    }
421    if flags.direct_only {
422        return Some("may only be used from top-level SQL");
423    }
424    if trusted_schema || flags.innocuous {
425        return None;
426    }
427    Some("is not allowed in a schema")
428}
429
430/// A function an application registered, as the binder needs to see it.
431///
432/// Only what resolution needs: a name, how many arguments it takes, whether it
433/// reduces a group, and what it promises about itself. What it *does* is the
434/// machine's business.
435///
436/// **The flags are here because the binder is where the promise is kept
437/// (task-1972).** `Registry::authorize_function` had no caller, so
438/// `direct_only`, `innocuous` and `PRAGMA trusted_schema` were a policy with a
439/// passing unit test and no effect on the engine: a `CHECK`, an index
440/// expression or a generated column could name any registered function whatever
441/// its flags. `inillucent-sql` sits below `inillucent-ext` and cannot reach the
442/// registry, so what the registry knows travels down here with the name.
443#[derive(Clone, Debug, PartialEq, Eq)]
444pub struct ExternalFunction {
445    /// The folded name.
446    pub name: Vec<u8>,
447    /// How many arguments it takes, or -1 for any number.
448    pub arity: i32,
449    /// Whether it reduces a group rather than a row.
450    pub aggregate: bool,
451    /// What it promises about itself, which decides whether a schema may name
452    /// it.
453    pub flags: FunctionFlags,
454}
455
456impl ExternalFunction {
457    /// Returns whether this registration answers a call with this many
458    /// arguments.
459    pub fn accepts(&self, argc: usize) -> bool {
460        self.arity < 0 || self.arity as usize == argc
461    }
462}
463
464/// Returns the registration that answers a call, preferring an exact arity.
465///
466/// SQLite resolves the same way: a function registered for exactly this many
467/// arguments wins over one registered for any number, so an application can
468/// define both a fast two-argument form and a general one.
469pub fn lookup_external<'a>(
470    functions: &'a [ExternalFunction],
471    name: &[u8],
472    argc: usize,
473) -> Option<&'a ExternalFunction> {
474    let folded = name.to_ascii_lowercase();
475    functions
476        .iter()
477        .find(|function| function.name == folded && function.arity as usize == argc)
478        .or_else(|| {
479            functions
480                .iter()
481                .find(|function| function.name == folded && function.arity < 0)
482        })
483}
484
485/// A date or time built-in.
486#[derive(Clone, Copy, Debug, PartialEq, Eq)]
487pub enum TimeFunc {
488    /// `date(...)`
489    Date,
490    /// `time(...)`
491    Time,
492    /// `datetime(...)`
493    DateTime,
494    /// `julianday(...)`
495    JulianDay,
496    /// `unixepoch(...)`
497    UnixEpoch,
498    /// `strftime(format, ...)`
499    StrfTime,
500    /// `timediff(a, b)`
501    TimeDiff,
502}
503
504/// Returns the date or time function a folded name spells.
505pub fn lookup_time(folded: &[u8]) -> Option<TimeFunc> {
506    let func = match folded {
507        b"date" => TimeFunc::Date,
508        b"time" => TimeFunc::Time,
509        b"datetime" => TimeFunc::DateTime,
510        b"julianday" => TimeFunc::JulianDay,
511        b"unixepoch" => TimeFunc::UnixEpoch,
512        b"strftime" => TimeFunc::StrfTime,
513        b"timediff" => TimeFunc::TimeDiff,
514        _ => return None,
515    };
516    Some(func)
517}
518
519/// A math built-in.
520///
521/// They are their own enum rather than more `ScalarFunc` variants because they
522/// are a compile-time option in SQLite (`SQLITE_ENABLE_MATH_FUNCTIONS`) and
523/// share one rule the others do not: an argument outside the domain is NULL
524/// rather than an error or a NaN.
525#[derive(Clone, Copy, Debug, PartialEq, Eq)]
526pub enum MathFunc {
527    /// `acos(x)`
528    Acos,
529    /// `acosh(x)`
530    Acosh,
531    /// `asin(x)`
532    Asin,
533    /// `asinh(x)`
534    Asinh,
535    /// `atan(x)`
536    Atan,
537    /// `atan2(y, x)`
538    Atan2,
539    /// `atanh(x)`
540    Atanh,
541    /// `ceil(x)` and `ceiling(x)`
542    Ceil,
543    /// `cos(x)`
544    Cos,
545    /// `cosh(x)`
546    Cosh,
547    /// `degrees(x)`
548    Degrees,
549    /// `exp(x)`
550    Exp,
551    /// `floor(x)`
552    Floor,
553    /// `ln(x)`
554    Ln,
555    /// `log(x)` base 10, or `log(b, x)` base b.
556    Log,
557    /// `log10(x)`
558    Log10,
559    /// `log2(x)`
560    Log2,
561    /// `mod(x, y)`
562    Mod,
563    /// `pi()`
564    Pi,
565    /// `pow(x, y)` and `power(x, y)`
566    Pow,
567    /// `radians(x)`
568    Radians,
569    /// `sin(x)`
570    Sin,
571    /// `sinh(x)`
572    Sinh,
573    /// `sqrt(x)`
574    Sqrt,
575    /// `tan(x)`
576    Tan,
577    /// `tanh(x)`
578    Tanh,
579    /// `trunc(x)`
580    Trunc,
581}
582
583impl MathFunc {
584    /// Returns how many arguments the function takes, as `(least, most)`.
585    pub fn arity(self) -> (usize, usize) {
586        match self {
587            MathFunc::Pi => (0, 0),
588            MathFunc::Atan2 | MathFunc::Mod | MathFunc::Pow => (2, 2),
589            MathFunc::Log => (1, 2),
590            _ => (1, 1),
591        }
592    }
593}
594
595/// Returns the math function a folded name spells.
596pub fn lookup_math(folded: &[u8]) -> Option<MathFunc> {
597    let func = match folded {
598        b"acos" => MathFunc::Acos,
599        b"acosh" => MathFunc::Acosh,
600        b"asin" => MathFunc::Asin,
601        b"asinh" => MathFunc::Asinh,
602        b"atan" => MathFunc::Atan,
603        b"atan2" => MathFunc::Atan2,
604        b"atanh" => MathFunc::Atanh,
605        b"ceil" | b"ceiling" => MathFunc::Ceil,
606        b"cos" => MathFunc::Cos,
607        b"cosh" => MathFunc::Cosh,
608        b"degrees" => MathFunc::Degrees,
609        b"exp" => MathFunc::Exp,
610        b"floor" => MathFunc::Floor,
611        b"ln" => MathFunc::Ln,
612        b"log" => MathFunc::Log,
613        b"log10" => MathFunc::Log10,
614        b"log2" => MathFunc::Log2,
615        b"mod" => MathFunc::Mod,
616        b"pi" => MathFunc::Pi,
617        b"pow" | b"power" => MathFunc::Pow,
618        b"radians" => MathFunc::Radians,
619        b"sin" => MathFunc::Sin,
620        b"sinh" => MathFunc::Sinh,
621        b"sqrt" => MathFunc::Sqrt,
622        b"tan" => MathFunc::Tan,
623        b"tanh" => MathFunc::Tanh,
624        b"trunc" => MathFunc::Trunc,
625        _ => return None,
626    };
627    Some(func)
628}
629
630/// A window function that is not an aggregate.
631///
632/// The aggregates are the same functions in a different frame, so they are not
633/// listed again here: `sum(x) OVER (...)` is `AggregateFunc::Sum` with a frame,
634/// and giving it a second spelling would mean two implementations of `sum`.
635#[derive(Clone, Copy, Debug, PartialEq, Eq)]
636pub enum WindowFunc {
637    /// `row_number()`
638    RowNumber,
639    /// `rank()`
640    Rank,
641    /// `dense_rank()`
642    DenseRank,
643    /// `percent_rank()`
644    PercentRank,
645    /// `cume_dist()`
646    CumeDist,
647    /// `ntile(n)`
648    Ntile,
649    /// `lag(x[, offset[, default]])`
650    Lag,
651    /// `lead(x[, offset[, default]])`
652    Lead,
653    /// `first_value(x)`
654    FirstValue,
655    /// `last_value(x)`
656    LastValue,
657    /// `nth_value(x, n)`
658    NthValue,
659}
660
661impl WindowFunc {
662    /// Returns how many arguments the function takes, as `(least, most)`.
663    pub fn arity(self) -> (usize, usize) {
664        match self {
665            WindowFunc::RowNumber
666            | WindowFunc::Rank
667            | WindowFunc::DenseRank
668            | WindowFunc::PercentRank
669            | WindowFunc::CumeDist => (0, 0),
670            WindowFunc::Ntile | WindowFunc::FirstValue | WindowFunc::LastValue => (1, 1),
671            WindowFunc::NthValue => (2, 2),
672            WindowFunc::Lag | WindowFunc::Lead => (1, 3),
673        }
674    }
675}
676
677/// Returns the window function a folded name spells.
678pub fn lookup_window(folded: &[u8]) -> Option<WindowFunc> {
679    let func = match folded {
680        b"row_number" => WindowFunc::RowNumber,
681        b"rank" => WindowFunc::Rank,
682        b"dense_rank" => WindowFunc::DenseRank,
683        b"percent_rank" => WindowFunc::PercentRank,
684        b"cume_dist" => WindowFunc::CumeDist,
685        b"ntile" => WindowFunc::Ntile,
686        b"lag" => WindowFunc::Lag,
687        b"lead" => WindowFunc::Lead,
688        b"first_value" => WindowFunc::FirstValue,
689        b"last_value" => WindowFunc::LastValue,
690        b"nth_value" => WindowFunc::NthValue,
691        _ => return None,
692    };
693    Some(func)
694}
695
696/// A JSON built-in.
697///
698/// They are their own enum for the same reason the math functions are: they
699/// share a rule none of the others has. Every one of them can fail - a document
700/// that will not parse is an error and not a NULL - and every one of them cares
701/// whether its arguments are already JSON, which is a property of the value
702/// rather than of the expression. Folding them into `ScalarFunc` would push
703/// both facts onto eighty functions that have neither.
704///
705/// The `b` spellings return the binary format rather than text. They are
706/// separate identities rather than a flag because `json_extract` and
707/// `jsonb_extract` differ in more than their output: the text form answers a
708/// SQL value for a leaf and the binary form answers a document.
709#[derive(Clone, Copy, Debug, PartialEq, Eq)]
710pub enum JsonFunc {
711    /// `json(X)`
712    Json,
713    /// `jsonb(X)`
714    Jsonb,
715    /// `json_array(...)`
716    Array,
717    /// `jsonb_array(...)`
718    ArrayB,
719    /// `json_array_length(X[, P])`
720    ArrayLength,
721    /// `json_error_position(X)`
722    ErrorPosition,
723    /// `json_extract(X, P, ...)`
724    Extract,
725    /// `jsonb_extract(X, P, ...)`
726    ExtractB,
727    /// The `->` operator.
728    Arrow,
729    /// The `->>` operator.
730    ArrowShift,
731    /// `json_insert(X, P, V, ...)`
732    Insert,
733    /// `jsonb_insert(X, P, V, ...)`
734    InsertB,
735    /// `json_object(...)`
736    Object,
737    /// `jsonb_object(...)`
738    ObjectB,
739    /// `json_patch(T, P)`
740    Patch,
741    /// `jsonb_patch(T, P)`
742    PatchB,
743    /// `json_pretty(X[, indent])`
744    Pretty,
745    /// `json_remove(X, P, ...)`
746    Remove,
747    /// `jsonb_remove(X, P, ...)`
748    RemoveB,
749    /// `json_replace(X, P, V, ...)`
750    Replace,
751    /// `jsonb_replace(X, P, V, ...)`
752    ReplaceB,
753    /// `json_set(X, P, V, ...)`
754    Set,
755    /// `jsonb_set(X, P, V, ...)`
756    SetB,
757    /// `json_type(X[, P])`
758    Type,
759    /// `json_valid(X[, flags])`
760    Valid,
761    /// `json_quote(X)`
762    Quote,
763    /// `json_array_insert(X, P, V, ...)`
764    ArrayInsert,
765    /// `jsonb_array_insert(X, P, V, ...)`
766    ArrayInsertB,
767}
768
769impl JsonFunc {
770    /// Returns how many arguments the function takes, as `(least, most)`.
771    ///
772    /// `usize::MAX` as the upper bound means "any number", which the editing
773    /// functions further restrict to an odd count in
774    /// [`JsonFunc::arity_ok`] - a rule a pair of bounds cannot express.
775    pub fn arity(self) -> (usize, usize) {
776        match self {
777            JsonFunc::Json | JsonFunc::Jsonb | JsonFunc::ErrorPosition | JsonFunc::Quote => (1, 1),
778            JsonFunc::Array | JsonFunc::ArrayB | JsonFunc::Object | JsonFunc::ObjectB => {
779                (0, usize::MAX)
780            }
781            JsonFunc::ArrayLength | JsonFunc::Type | JsonFunc::Valid | JsonFunc::Pretty => (1, 2),
782            JsonFunc::Patch | JsonFunc::PatchB | JsonFunc::Arrow | JsonFunc::ArrowShift => (2, 2),
783            JsonFunc::Extract | JsonFunc::ExtractB | JsonFunc::Remove | JsonFunc::RemoveB => {
784                (2, usize::MAX)
785            }
786            JsonFunc::Insert
787            | JsonFunc::InsertB
788            | JsonFunc::Replace
789            | JsonFunc::ReplaceB
790            | JsonFunc::Set
791            | JsonFunc::SetB
792            | JsonFunc::ArrayInsert
793            | JsonFunc::ArrayInsertB => (3, usize::MAX),
794        }
795    }
796
797    /// Returns whether an argument count is legal for this function.
798    pub fn arity_ok(self, count: usize) -> bool {
799        let (least, most) = self.arity();
800        if count < least || count > most {
801            return false;
802        }
803        match self {
804            // A path and a value go together, so the count past the document
805            // has to be even and the whole count therefore odd.
806            JsonFunc::Insert
807            | JsonFunc::InsertB
808            | JsonFunc::Replace
809            | JsonFunc::ReplaceB
810            | JsonFunc::Set
811            | JsonFunc::SetB
812            | JsonFunc::ArrayInsert
813            | JsonFunc::ArrayInsertB => count % 2 == 1,
814            JsonFunc::Object | JsonFunc::ObjectB => count.is_multiple_of(2),
815            _ => true,
816        }
817    }
818
819    /// Returns whether the function answers the binary format.
820    pub fn is_binary(self) -> bool {
821        matches!(
822            self,
823            JsonFunc::Jsonb
824                | JsonFunc::ArrayB
825                | JsonFunc::ExtractB
826                | JsonFunc::InsertB
827                | JsonFunc::ObjectB
828                | JsonFunc::PatchB
829                | JsonFunc::RemoveB
830                | JsonFunc::ReplaceB
831                | JsonFunc::SetB
832        )
833    }
834
835    /// Returns whether this function's first argument names a document to be
836    /// read, rather than a value to be embedded or quoted.
837    ///
838    /// The distinction an executor's document-cache optimisation needs: it
839    /// may only substitute a pre-parsed JSONB blob for the first argument
840    /// when that argument *is* the document a call reads, such as `X` in
841    /// `json_extract(X, P)`. `json_array`, `json_object` and `json_quote`
842    /// take that same position as a **value** - one that merely happens to
843    /// look like JSON is still meant to be embedded or quoted as a string,
844    /// per the subtype rule this module's own doc comment states. Handing
845    /// them a blob instead answered "JSON cannot hold BLOB values" for a
846    /// perfectly ordinary unmarked string, which is what
847    /// `json_array('[1]')` did before this existed. `Valid` reads its
848    /// argument as a document too, but is excluded by its caller for the
849    /// unrelated reason that substituting a re-encoded blob changes what its
850    /// flags answer about the original text.
851    pub fn first_argument_is_a_document(self) -> bool {
852        !matches!(
853            self,
854            JsonFunc::Array
855                | JsonFunc::ArrayB
856                | JsonFunc::Object
857                | JsonFunc::ObjectB
858                | JsonFunc::Quote
859        )
860    }
861}
862
863/// Returns the JSON function a folded name spells.
864pub fn lookup_json(folded: &[u8]) -> Option<JsonFunc> {
865    let func = match folded {
866        b"json" => JsonFunc::Json,
867        b"jsonb" => JsonFunc::Jsonb,
868        b"json_array" => JsonFunc::Array,
869        b"jsonb_array" => JsonFunc::ArrayB,
870        b"json_array_length" => JsonFunc::ArrayLength,
871        b"json_error_position" => JsonFunc::ErrorPosition,
872        b"json_extract" => JsonFunc::Extract,
873        // **The operators are function names too.** SQLite registers `->` and
874        // `->>` as ordinary two-argument functions, so `"->"(a, b)` binds and
875        // `pragma_function_list` reports them. The parser lowered the operators
876        // here already; only the spellings were missing, which made this engine
877        // report two fewer functions than it has and refuse a call SQLite
878        // answers.
879        b"->" => JsonFunc::Arrow,
880        b"->>" => JsonFunc::ArrowShift,
881        b"jsonb_extract" => JsonFunc::ExtractB,
882        b"json_array_insert" => JsonFunc::ArrayInsert,
883        b"jsonb_array_insert" => JsonFunc::ArrayInsertB,
884        b"json_insert" => JsonFunc::Insert,
885        b"jsonb_insert" => JsonFunc::InsertB,
886        b"json_object" => JsonFunc::Object,
887        b"jsonb_object" => JsonFunc::ObjectB,
888        b"json_patch" => JsonFunc::Patch,
889        b"jsonb_patch" => JsonFunc::PatchB,
890        b"json_pretty" => JsonFunc::Pretty,
891        b"json_remove" => JsonFunc::Remove,
892        b"jsonb_remove" => JsonFunc::RemoveB,
893        b"json_replace" => JsonFunc::Replace,
894        b"jsonb_replace" => JsonFunc::ReplaceB,
895        b"json_set" => JsonFunc::Set,
896        b"jsonb_set" => JsonFunc::SetB,
897        b"json_type" => JsonFunc::Type,
898        b"json_valid" => JsonFunc::Valid,
899        b"json_quote" => JsonFunc::Quote,
900        _ => return None,
901    };
902    Some(func)
903}
904
905/// Returns the scalar function a folded name spells.
906pub fn lookup_scalar(folded: &[u8]) -> Option<ScalarFunc> {
907    let func = match folded {
908        b"abs" => ScalarFunc::Abs,
909        b"char" => ScalarFunc::Char,
910        b"coalesce" => ScalarFunc::Coalesce,
911        b"concat" => ScalarFunc::Concat,
912        b"concat_ws" => ScalarFunc::ConcatWs,
913        b"glob" => ScalarFunc::Glob,
914        b"hex" => ScalarFunc::Hex,
915        b"ifnull" => ScalarFunc::IfNull,
916        b"iif" | b"if" => ScalarFunc::Iif,
917        b"instr" => ScalarFunc::Instr,
918        b"length" => ScalarFunc::Length,
919        b"like" => ScalarFunc::Like,
920        b"likelihood" | b"likely" | b"unlikely" => ScalarFunc::Likelihood,
921        b"lower" => ScalarFunc::Lower,
922        b"ltrim" => ScalarFunc::LTrim,
923        b"max" => ScalarFunc::Max,
924        b"min" => ScalarFunc::Min,
925        b"nullif" => ScalarFunc::NullIf,
926        b"quote" => ScalarFunc::Quote,
927        b"replace" => ScalarFunc::Replace,
928        b"round" => ScalarFunc::Round,
929        b"rtrim" => ScalarFunc::RTrim,
930        b"sign" => ScalarFunc::Sign,
931        b"substr" | b"substring" => ScalarFunc::Substr,
932        b"printf" | b"format" => ScalarFunc::Printf,
933        b"octet_length" => ScalarFunc::OctetLength,
934        b"random" => ScalarFunc::Random,
935        b"randomblob" => ScalarFunc::RandomBlob,
936        b"changes" => ScalarFunc::Changes,
937        b"total_changes" => ScalarFunc::TotalChanges,
938        b"last_insert_rowid" => ScalarFunc::LastInsertRowid,
939        b"sqlite_source_id" => ScalarFunc::SourceId,
940        b"fts5_source_id" => ScalarFunc::Fts5SourceId,
941        b"trim" => ScalarFunc::Trim,
942        b"typeof" => ScalarFunc::TypeOf,
943        b"unhex" => ScalarFunc::Unhex,
944        b"unicode" => ScalarFunc::Unicode,
945        b"upper" => ScalarFunc::Upper,
946        b"zeroblob" => ScalarFunc::ZeroBlob,
947        b"sqlite_version" => ScalarFunc::Version,
948        b"vector_distance_cos" | b"cosine_distance" => ScalarFunc::VectorDistanceCos,
949        b"vector_distance_l2" | b"l2_distance" => ScalarFunc::VectorDistanceL2,
950        b"vector_dot" | b"inner_product" => ScalarFunc::VectorDot,
951        // **Both spellings of each distance.** `l1_distance` is pgvector's name
952        // and `vector_distance_l1` is this engine's own, and the family reads
953        // as a family only if every member answers to both - `cos` and `l2`
954        // already did, and `l1` answered to one of the two.
955        b"l1_distance" | b"vector_distance_l1" => ScalarFunc::VectorDistanceL1,
956        b"hamming_distance" | b"vector_distance_hamming" => ScalarFunc::VectorDistanceHamming,
957        b"jaccard_distance" | b"vector_distance_jaccard" => ScalarFunc::VectorDistanceJaccard,
958        b"vector_dims" => ScalarFunc::VectorDims,
959        b"vector_norm" => ScalarFunc::VectorNorm,
960        b"l2_normalize" => ScalarFunc::VectorNormalize,
961        b"binary_quantize" => ScalarFunc::VectorQuantize,
962        b"subvector" => ScalarFunc::VectorSlice,
963        b"vector_add" => ScalarFunc::VectorAdd,
964        b"vector_sub" => ScalarFunc::VectorSubtract,
965        b"vector_mul" => ScalarFunc::VectorMultiply,
966        b"vector_concat" => ScalarFunc::VectorConcat,
967        b"geopoly_area" => ScalarFunc::GeopolyArea,
968        b"geopoly_blob" => ScalarFunc::GeopolyBlob,
969        b"geopoly_json" => ScalarFunc::GeopolyJson,
970        b"geopoly_svg" => ScalarFunc::GeopolySvg,
971        b"geopoly_within" => ScalarFunc::GeopolyWithin,
972        b"geopoly_contains_point" => ScalarFunc::GeopolyContainsPoint,
973        b"geopoly_overlap" => ScalarFunc::GeopolyOverlap,
974        b"geopoly_debug" => ScalarFunc::GeopolyDebug,
975        b"geopoly_bbox" => ScalarFunc::GeopolyBbox,
976        b"geopoly_xform" => ScalarFunc::GeopolyXform,
977        b"geopoly_regular" => ScalarFunc::GeopolyRegular,
978        b"geopoly_ccw" => ScalarFunc::GeopolyCcw,
979        b"unknown" => ScalarFunc::Unknown,
980        b"subtype" => ScalarFunc::Subtype,
981        b"unistr" => ScalarFunc::Unistr,
982        b"unistr_quote" => ScalarFunc::UnistrQuote,
983        b"sqlite_compileoption_used" => ScalarFunc::CompileOptionUsed,
984        b"sqlite_compileoption_get" => ScalarFunc::CompileOptionGet,
985        b"sqlite_log" => ScalarFunc::Log,
986        b"load_extension" => ScalarFunc::LoadExtension,
987        b"regexp" => ScalarFunc::Regexp,
988        b"sqlite_offset" => ScalarFunc::Offset,
989        b"sqlar_compress" => ScalarFunc::SqlarCompress,
990        b"sqlar_uncompress" => ScalarFunc::SqlarUncompress,
991        b"rtreedepth" => ScalarFunc::RTreeDepth,
992        b"rtreenode" => ScalarFunc::RTreeNode,
993        b"rtreecheck" => ScalarFunc::RTreeCheck,
994        _ => return None,
995    };
996    Some(func)
997}
998
999/// Returns the aggregate a folded name spells.
1000///
1001/// `min` and `max` are both: one argument makes them aggregates and two or more
1002/// make them scalars, which is why the binder asks about the argument count
1003/// before it decides.
1004pub fn lookup_aggregate(folded: &[u8]) -> Option<AggregateFunc> {
1005    let func = match folded {
1006        b"count" => AggregateFunc::Count,
1007        b"sum" => AggregateFunc::Sum,
1008        b"total" => AggregateFunc::Total,
1009        b"avg" => AggregateFunc::Avg,
1010        b"group_concat" | b"string_agg" => AggregateFunc::GroupConcat,
1011        b"json_group_array" => AggregateFunc::JsonGroupArray,
1012        b"jsonb_group_array" => AggregateFunc::JsonbGroupArray,
1013        b"json_group_object" => AggregateFunc::JsonGroupObject,
1014        b"geopoly_group_bbox" => AggregateFunc::GeopolyGroupBbox,
1015        b"median" => AggregateFunc::Median,
1016        b"percentile" => AggregateFunc::Percentile,
1017        b"percentile_cont" => AggregateFunc::PercentileCont,
1018        b"percentile_disc" => AggregateFunc::PercentileDisc,
1019        b"jsonb_group_object" => AggregateFunc::JsonbGroupObject,
1020        _ => return None,
1021    };
1022    Some(func)
1023}
1024
1025/// Returns whether an argument count is legal for a scalar function.
1026pub fn scalar_arity_ok(func: ScalarFunc, count: usize) -> bool {
1027    match func {
1028        ScalarFunc::Abs
1029        | ScalarFunc::Hex
1030        | ScalarFunc::Length
1031        | ScalarFunc::Lower
1032        | ScalarFunc::Quote
1033        | ScalarFunc::Sign
1034        | ScalarFunc::TypeOf
1035        | ScalarFunc::Unicode
1036        | ScalarFunc::Upper
1037        | ScalarFunc::ZeroBlob => count == 1,
1038        ScalarFunc::IfNull | ScalarFunc::NullIf | ScalarFunc::Glob => count == 2,
1039        ScalarFunc::VectorDistanceCos
1040        | ScalarFunc::VectorDistanceL2
1041        | ScalarFunc::VectorDot
1042        | ScalarFunc::VectorDistanceL1
1043        | ScalarFunc::VectorDistanceHamming
1044        | ScalarFunc::VectorDistanceJaccard
1045        | ScalarFunc::VectorAdd
1046        | ScalarFunc::VectorSubtract
1047        | ScalarFunc::VectorMultiply
1048        | ScalarFunc::VectorConcat => count == 2,
1049        ScalarFunc::VectorDims
1050        | ScalarFunc::VectorNorm
1051        | ScalarFunc::VectorNormalize
1052        | ScalarFunc::VectorQuantize => count == 1,
1053        ScalarFunc::VectorSlice => count == 3,
1054        ScalarFunc::RTreeDepth | ScalarFunc::Offset | ScalarFunc::SqlarCompress => count == 1,
1055        ScalarFunc::SqlarUncompress => count == 2,
1056        ScalarFunc::RTreeNode => count == 2,
1057        // One argument is the table and two is a schema and a table, which is
1058        // the same pair `rtreecheck` takes in the reference.
1059        ScalarFunc::RTreeCheck => count == 1 || count == 2,
1060        ScalarFunc::GeopolyArea
1061        | ScalarFunc::GeopolyBlob
1062        | ScalarFunc::GeopolyJson
1063        | ScalarFunc::GeopolyDebug
1064        | ScalarFunc::GeopolyBbox
1065        | ScalarFunc::GeopolyCcw => count == 1,
1066        ScalarFunc::GeopolyWithin | ScalarFunc::GeopolyOverlap => count == 2,
1067        ScalarFunc::GeopolyContainsPoint => count == 3,
1068        ScalarFunc::GeopolyRegular => count == 4,
1069        ScalarFunc::GeopolyXform => count == 7,
1070        ScalarFunc::GeopolySvg => count >= 1,
1071        ScalarFunc::Replace => count == 3,
1072        // `iif` is `CASE` written as a call: pairs of a test and a value, with
1073        // an optional final answer. Two arguments is the shortest legal form
1074        // and there is no upper bound, which is why it is not `count == 3`.
1075        ScalarFunc::Iif => count >= 2,
1076        ScalarFunc::Unknown => true,
1077        ScalarFunc::Subtype
1078        | ScalarFunc::Unistr
1079        | ScalarFunc::UnistrQuote
1080        | ScalarFunc::CompileOptionUsed
1081        | ScalarFunc::CompileOptionGet => count == 1,
1082        ScalarFunc::Log | ScalarFunc::Regexp => count == 2,
1083        ScalarFunc::LoadExtension => count == 1 || count == 2,
1084        ScalarFunc::Instr => count == 2,
1085        ScalarFunc::Like => count == 2 || count == 3,
1086        ScalarFunc::Likelihood => count == 1 || count == 2,
1087        ScalarFunc::LTrim | ScalarFunc::RTrim | ScalarFunc::Trim | ScalarFunc::Unhex => {
1088            count == 1 || count == 2
1089        }
1090        ScalarFunc::Round => count == 1 || count == 2,
1091        ScalarFunc::Substr => count == 2 || count == 3,
1092        ScalarFunc::Coalesce | ScalarFunc::Max | ScalarFunc::Min => count >= 2,
1093        // `char()` with no arguments is the empty string in SQLite, not a
1094        // parse error (task-1979, F16). `concat()` keeps its floor of one,
1095        // which is the reference's own rule for that name.
1096        ScalarFunc::Char => true,
1097        ScalarFunc::Concat => count >= 1,
1098        ScalarFunc::ConcatWs => count >= 2,
1099        ScalarFunc::Version => count == 0,
1100        ScalarFunc::Printf => count >= 1,
1101        ScalarFunc::OctetLength | ScalarFunc::RandomBlob => count == 1,
1102        ScalarFunc::Random
1103        | ScalarFunc::Changes
1104        | ScalarFunc::TotalChanges
1105        | ScalarFunc::LastInsertRowid
1106        | ScalarFunc::SourceId
1107        | ScalarFunc::Fts5SourceId => count == 0,
1108    }
1109}
1110
1111/// Returns whether an argument count is legal for an aggregate.
1112pub fn aggregate_arity_ok(func: AggregateFunc, count: usize, star: bool) -> bool {
1113    match func {
1114        AggregateFunc::Count => star || count == 1,
1115        AggregateFunc::Sum | AggregateFunc::Total | AggregateFunc::Avg => !star && count == 1,
1116        AggregateFunc::Min | AggregateFunc::Max => !star && count == 1,
1117        AggregateFunc::GroupConcat => !star && (count == 1 || count == 2),
1118        AggregateFunc::JsonGroupArray | AggregateFunc::JsonbGroupArray => !star && count == 1,
1119        AggregateFunc::JsonGroupObject | AggregateFunc::JsonbGroupObject => !star && count == 2,
1120        AggregateFunc::Median
1121        | AggregateFunc::GeopolyGroupBbox
1122        | AggregateFunc::VectorSum
1123        | AggregateFunc::VectorAvg => !star && count == 1,
1124        AggregateFunc::Percentile
1125        | AggregateFunc::PercentileCont
1126        | AggregateFunc::PercentileDisc => !star && count == 2,
1127        // An application's aggregate declared its own arity, and the binder
1128        // checked it against the registration before getting here.
1129        AggregateFunc::External => !star,
1130    }
1131}
1132
1133/// Returns whether a folded name may be an aggregate at this argument count.
1134///
1135/// `min(x)` is the aggregate and `min(x, y)` is the scalar; asking the question
1136/// this way keeps the rule in one place instead of in both lookups.
1137pub fn is_aggregate_call(folded: &[u8], count: usize, star: bool) -> bool {
1138    if folded == b"min" || folded == b"max" {
1139        return !star && count == 1;
1140    }
1141    lookup_aggregate(folded).is_some()
1142}
1143
1144/// Returns the aggregate a `min`/`max` call resolves to at one argument.
1145pub fn minmax_aggregate(folded: &[u8]) -> Option<AggregateFunc> {
1146    match folded {
1147        b"min" => Some(AggregateFunc::Min),
1148        b"max" => Some(AggregateFunc::Max),
1149        _ => None,
1150    }
1151}
1152
1153#[cfg(test)]
1154mod tests {
1155    use super::*;
1156
1157    /// Names are matched folded, and an unknown name is not a function.
1158    #[test]
1159    fn lookup_matches_folded_names() {
1160        assert_eq!(lookup_scalar(b"abs"), Some(ScalarFunc::Abs));
1161        assert_eq!(lookup_scalar(b"substring"), Some(ScalarFunc::Substr));
1162        assert_eq!(lookup_scalar(b"nope"), None);
1163        assert_eq!(lookup_aggregate(b"count"), Some(AggregateFunc::Count));
1164        assert_eq!(
1165            lookup_aggregate(b"string_agg"),
1166            Some(AggregateFunc::GroupConcat)
1167        );
1168    }
1169
1170    /// `min` and `max` change identity with their argument count, which is the
1171    /// one place SQLite overloads a name across the scalar/aggregate boundary.
1172    #[test]
1173    fn min_and_max_are_aggregates_only_at_one_argument() {
1174        assert!(is_aggregate_call(b"min", 1, false));
1175        assert!(!is_aggregate_call(b"min", 2, false));
1176        assert!(!is_aggregate_call(b"min", 0, true));
1177        assert_eq!(minmax_aggregate(b"max"), Some(AggregateFunc::Max));
1178    }
1179
1180    /// Arity is checked at bind time, so a wrong count is a prepare failure.
1181    #[test]
1182    fn arity_is_checked_per_function() {
1183        assert!(scalar_arity_ok(ScalarFunc::Abs, 1));
1184        assert!(!scalar_arity_ok(ScalarFunc::Abs, 2));
1185        assert!(scalar_arity_ok(ScalarFunc::Substr, 2));
1186        assert!(scalar_arity_ok(ScalarFunc::Substr, 3));
1187        assert!(!scalar_arity_ok(ScalarFunc::Substr, 4));
1188        assert!(scalar_arity_ok(ScalarFunc::Coalesce, 5));
1189        assert!(!scalar_arity_ok(ScalarFunc::Coalesce, 1));
1190        assert!(aggregate_arity_ok(AggregateFunc::Count, 0, true));
1191        assert!(!aggregate_arity_ok(AggregateFunc::Sum, 0, true));
1192    }
1193}
1194
1195/// One row of `PRAGMA function_list`.
1196#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1197pub struct FunctionEntry {
1198    /// The name as it is written.
1199    pub name: &'static str,
1200    /// `s` for a scalar, `w` for a window function, `a` for an aggregate.
1201    pub kind: &'static str,
1202    /// How many arguments, or -1 for any number.
1203    pub arity: i64,
1204    /// The flag word the C surface reports.
1205    ///
1206    /// 2048 is `SQLITE_INNOCUOUS` and 524288 is `SQLITE_DETERMINISTIC`, which
1207    /// is what a built-in carries: it does nothing an expression could not, and
1208    /// it answers the same thing twice.
1209    pub flags: i64,
1210}
1211
1212/// The bit `function_list` sets for a function a schema may safely call.
1213///
1214/// Named rather than written twice because `inillucent-engine`'s
1215/// `function_list` reports the connection's registered functions beside these
1216/// built-ins, and it has to describe them in the same column with the same
1217/// meaning. A registered function that promised `innocuous` and was reported
1218/// with a bit nothing else uses would be a register that under-describes, which
1219/// is the defect this whole list was extended to fix.
1220pub const INNOCUOUS_FLAG: i64 = 2048;
1221
1222/// The bit `function_list` sets for a function that answers the same twice.
1223pub const DETERMINISTIC_FLAG: i64 = 524288;
1224
1225/// The flags every built-in carries: innocuous and deterministic.
1226const BUILTIN_FLAGS: i64 = INNOCUOUS_FLAG | DETERMINISTIC_FLAG;
1227
1228/// The flags a built-in that is not deterministic carries.
1229const VOLATILE_FLAGS: i64 = INNOCUOUS_FLAG;
1230
1231/// Returns every built-in this build has, in the order `function_list` reports.
1232///
1233/// The list is written out rather than derived from the lookup tables because
1234/// the arity is per *overload*: `substr` is here twice, at two and at three
1235/// arguments, which is what SQLite reports and what an application checking
1236/// whether a call will bind needs to see.
1237///
1238/// **It must name everything the binder will resolve, and a completeness check
1239/// found that it did not.** The register answered 161 names where SQLite answers 218, and
1240/// the functionality behind most of the difference was present and
1241/// byte-identical - `current_date`, `regexp`, `unistr`, `median`, `bm25`,
1242/// `matchinfo` and the rest all answered when called. A caller that
1243/// introspects the register to decide what it may use was told less than the
1244/// truth, with no error, which is the one *silent* difference this project has
1245/// had. The additions below were each verified against the engine before being
1246/// listed: a name here that the binder refuses would be the same defect
1247/// pointing the other way.
1248pub fn every_function() -> Vec<FunctionEntry> {
1249    let mut out = Vec::new();
1250    let mut scalar = |name: &'static str, arity: i64| {
1251        out.push(FunctionEntry {
1252            name,
1253            kind: "s",
1254            arity,
1255            flags: BUILTIN_FLAGS,
1256        });
1257    };
1258    for (name, arity) in SCALARS {
1259        scalar(name, *arity);
1260    }
1261    for (name, arity) in VOLATILE {
1262        out.push(FunctionEntry {
1263            name,
1264            kind: "s",
1265            arity: *arity,
1266            flags: VOLATILE_FLAGS,
1267        });
1268    }
1269    for (name, arity) in AGGREGATES {
1270        out.push(FunctionEntry {
1271            name,
1272            kind: "a",
1273            arity: *arity,
1274            flags: BUILTIN_FLAGS,
1275        });
1276    }
1277    for (name, arity) in WINDOWS {
1278        out.push(FunctionEntry {
1279            name,
1280            kind: "w",
1281            arity: *arity,
1282            flags: BUILTIN_FLAGS,
1283        });
1284    }
1285    out.sort_by(|left, right| left.name.cmp(right.name).then(left.arity.cmp(&right.arity)));
1286    out
1287}
1288
1289/// The deterministic scalars, with one row per overload.
1290///
1291/// **`narg` is SQLite's own encoding, not "how many arguments".** A negative
1292/// number means variadic *and carries a minimum*: `coalesce` reads -4 and
1293/// `concat` -3 in the reference's register, not -1. A
1294/// register-completeness check compares this column because it is the one an
1295/// application reads to decide whether a call will bind, and it found seven
1296/// entries here that disagreed with the reference while answering identically.
1297const SCALARS: &[(&str, i64)] = &[
1298    ("abs", 1),
1299    ("acos", 1),
1300    ("acosh", 1),
1301    ("asin", 1),
1302    ("asinh", 1),
1303    ("atan", 1),
1304    ("atan2", 2),
1305    ("atanh", 1),
1306    ("ceil", 1),
1307    ("ceiling", 1),
1308    ("char", -1),
1309    ("coalesce", -4),
1310    ("concat", -3),
1311    ("concat_ws", -4),
1312    ("cos", 1),
1313    ("cosh", 1),
1314    ("date", -1),
1315    ("datetime", -1),
1316    ("degrees", 1),
1317    ("exp", 1),
1318    ("floor", 1),
1319    ("format", -1),
1320    ("glob", 2),
1321    ("hex", 1),
1322    ("ifnull", 2),
1323    ("iif", -4),
1324    ("instr", 2),
1325    ("json", 1),
1326    ("json_array", -1),
1327    ("json_array_length", 1),
1328    ("json_array_length", 2),
1329    ("json_error_position", 1),
1330    ("json_extract", -1),
1331    ("json_insert", -1),
1332    ("json_object", -1),
1333    ("json_patch", 2),
1334    ("json_pretty", 1),
1335    ("json_pretty", 2),
1336    ("json_quote", 1),
1337    ("json_remove", -1),
1338    ("json_replace", -1),
1339    ("json_set", -1),
1340    ("json_type", 1),
1341    ("json_type", 2),
1342    ("json_valid", 1),
1343    ("json_valid", 2),
1344    ("jsonb", 1),
1345    ("jsonb_array", -1),
1346    ("jsonb_extract", -1),
1347    ("jsonb_insert", -1),
1348    ("jsonb_object", -1),
1349    ("jsonb_patch", 2),
1350    ("jsonb_remove", -1),
1351    ("jsonb_replace", -1),
1352    ("jsonb_set", -1),
1353    ("julianday", -1),
1354    ("length", 1),
1355    ("like", 2),
1356    ("like", 3),
1357    ("likelihood", 2),
1358    ("likely", 1),
1359    ("ln", 1),
1360    ("log", 1),
1361    ("log", 2),
1362    ("log10", 1),
1363    ("log2", 1),
1364    ("lower", 1),
1365    ("ltrim", 1),
1366    ("ltrim", 2),
1367    ("max", -3),
1368    ("min", -3),
1369    ("mod", 2),
1370    ("nullif", 2),
1371    ("octet_length", 1),
1372    ("pi", 0),
1373    ("pow", 2),
1374    ("power", 2),
1375    ("printf", -1),
1376    ("quote", 1),
1377    ("radians", 1),
1378    ("replace", 3),
1379    ("round", 1),
1380    ("round", 2),
1381    ("rtrim", 1),
1382    ("rtrim", 2),
1383    ("sign", 1),
1384    ("sin", 1),
1385    ("sinh", 1),
1386    ("fts5_source_id", 0),
1387    ("optimize", 1),
1388    ("sqlite_source_id", 0),
1389    ("sqlite_version", 0),
1390    ("sqrt", 1),
1391    ("strftime", -1),
1392    ("substr", 2),
1393    ("substr", 3),
1394    ("substring", 2),
1395    ("substring", 3),
1396    ("tan", 1),
1397    ("tanh", 1),
1398    ("time", -1),
1399    ("timediff", 2),
1400    ("trim", 1),
1401    ("trim", 2),
1402    ("trunc", 1),
1403    ("typeof", 1),
1404    ("unhex", 1),
1405    ("unhex", 2),
1406    ("unicode", 1),
1407    ("unixepoch", -1),
1408    ("unlikely", 1),
1409    ("upper", 1),
1410    ("binary_quantize", 1),
1411    ("rtreecheck", -1),
1412    ("sqlar_compress", 1),
1413    ("sqlar_uncompress", 2),
1414    ("sqlite_offset", 1),
1415    ("rtreedepth", 1),
1416    ("rtreenode", 2),
1417    ("geopoly_area", 1),
1418    ("geopoly_bbox", 1),
1419    ("geopoly_blob", 1),
1420    ("geopoly_ccw", 1),
1421    ("geopoly_contains_point", 3),
1422    ("geopoly_debug", 1),
1423    ("geopoly_group_bbox", 1),
1424    ("geopoly_json", 1),
1425    ("geopoly_overlap", 2),
1426    ("geopoly_regular", 4),
1427    ("geopoly_svg", -1),
1428    ("geopoly_within", 2),
1429    ("geopoly_xform", 7),
1430    ("cosine_distance", 2),
1431    ("hamming_distance", 2),
1432    ("inner_product", 2),
1433    ("jaccard_distance", 2),
1434    ("l1_distance", 2),
1435    ("l2_distance", 2),
1436    ("l2_normalize", 1),
1437    ("subvector", 3),
1438    ("vector_add", 2),
1439    ("vector_concat", 2),
1440    ("vector_dims", 1),
1441    ("vector_distance_cos", 2),
1442    ("vector_distance_l2", 2),
1443    ("vector_dot", 2),
1444    ("vector_mul", 2),
1445    ("vector_norm", 1),
1446    ("vector_sub", 2),
1447    ("zeroblob", 1),
1448    // Present and answering, and missing from this list until now.
1449    // Each was checked against the shell before it was added.
1450    ("->", 2),
1451    ("->>", 2),
1452    ("bm25", -1),
1453    ("highlight", -1),
1454    ("if", -4),
1455    ("json_array_insert", -1),
1456    ("jsonb_array_insert", -1),
1457    ("match", 2),
1458    ("matchinfo", 1),
1459    ("matchinfo", 2),
1460    ("offsets", 1),
1461    ("regexp", 2),
1462    ("snippet", -1),
1463    ("sqlite_compileoption_get", 1),
1464    ("sqlite_compileoption_used", 1),
1465    ("subtype", 1),
1466    ("unistr", 1),
1467    ("unistr_quote", 1),
1468    ("unknown", -1),
1469];
1470
1471/// The scalars whose answer depends on something other than their arguments.
1472const VOLATILE: &[(&str, i64)] = &[
1473    ("changes", 0),
1474    // The three date keywords are functions in SQLite's register and answer
1475    // like functions here; they read the clock, so they are not deterministic.
1476    ("current_date", 0),
1477    ("current_time", 0),
1478    ("current_timestamp", 0),
1479    ("last_insert_rowid", 0),
1480    ("load_extension", 1),
1481    ("load_extension", 2),
1482    ("random", 0),
1483    ("randomblob", 1),
1484    ("sqlite_log", 2),
1485    ("total_changes", 0),
1486];
1487
1488/// The aggregates, with one row per overload.
1489const AGGREGATES: &[(&str, i64)] = &[
1490    ("avg", 1),
1491    ("count", 0),
1492    ("count", 1),
1493    ("group_concat", 1),
1494    ("group_concat", 2),
1495    ("json_group_array", 1),
1496    ("json_group_object", 2),
1497    ("jsonb_group_array", 1),
1498    ("jsonb_group_object", 2),
1499    ("max", 1),
1500    ("min", 1),
1501    ("string_agg", 2),
1502    ("sum", 1),
1503    ("total", 1),
1504];
1505
1506/// The window functions that are not aggregates.
1507const WINDOWS: &[(&str, i64)] = &[
1508    ("cume_dist", 0),
1509    ("dense_rank", 0),
1510    ("first_value", 1),
1511    ("lag", 1),
1512    ("lag", 2),
1513    ("lag", 3),
1514    ("last_value", 1),
1515    ("lead", 1),
1516    ("lead", 2),
1517    ("lead", 3),
1518    ("nth_value", 2),
1519    ("ntile", 1),
1520    ("percent_rank", 0),
1521    ("rank", 0),
1522    ("row_number", 0),
1523    // The percentile family, which SQLite reports as window functions and which
1524    // this engine answers as both aggregates and window functions.
1525    ("median", 1),
1526    ("percentile", 2),
1527    ("percentile_cont", 2),
1528    ("percentile_disc", 2),
1529];