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];