rudb_functions/signature.rs
1//! What a function call resolves to.
2//!
3//! This is the smallest thing the binder cannot be written without: given a name and the types of
4//! the arguments, which function is that and what does it return. It is not the function library.
5//! There is no implementation attached to any of these yet, no volatility, no statistics and no
6//! vectorized kernel, and all of that is what this crate grows into.
7//!
8//! The set here is what M0 reaches, which is the operators the transformer emits plus the five
9//! aggregates a first query needs. A name that is not in it produces DuckDB's own error text rather
10//! than a Rust panic or a silent pass through, because a function that binds and then does nothing
11//! is a wrong answer and a function that does not bind is a message.
12//!
13//! Overload resolution here is by shape rather than by an exact signature match. `+` does not have
14//! one entry per pair of numeric types, it has one entry that says both arguments promote and the
15//! result is what they promote to. DuckDB's own table is closer to the former and it needs to be,
16//! because it carries an implementation per pair. Ours does not carry one yet, and inventing 169
17//! rows before there is a kernel behind any of them would be inventing the wrong 169 rows.
18
19use rudb_common::{Error, LogicalType, MAX_DECIMAL_WIDTH, Result};
20
21/// Whether a name is a scalar function or an aggregate.
22///
23/// The binder needs to ask before it knows which slot the call goes in, since an aggregate is only
24/// legal in an aggregate list and the error for one in the wrong place should say so.
25#[derive(Debug, Clone, Copy, PartialEq, Eq)]
26pub enum FunctionKind {
27 /// One row in, one row out.
28 Scalar,
29 /// Many rows in, one row out.
30 Aggregate,
31}
32
33/// A resolved call.
34///
35/// `arguments` is what the arguments have to be cast to and not what they were, so the binder can
36/// insert the casts without redoing the resolution. It is the same length as what was passed in.
37#[derive(Debug, Clone, PartialEq, Eq)]
38pub struct Resolved {
39 /// The function's own name, which is what the plan records.
40 pub name: &'static str,
41 /// Scalar or aggregate.
42 pub kind: FunctionKind,
43 /// What each argument has to be cast to.
44 pub arguments: Vec<LogicalType>,
45 /// What the call produces.
46 pub returns: LogicalType,
47}
48
49/// How the argument types decide the return type.
50#[derive(Debug, Clone, Copy, PartialEq, Eq)]
51enum Shape {
52 /// Every argument promotes to one type and the result is that type. `*` and `min`.
53 Promoted,
54 /// Two arguments, and a decimal product is as wide as both operands together. `*`.
55 Multiplied,
56 /// Every argument promotes to one type, and a decimal promotion becomes a double instead. `//`.
57 ///
58 /// `//` is integer division only when there are integers on both sides of it. Upstream answers
59 /// `7.5 // 2.5` with the DOUBLE 3.0 and `7.9 // 1.0` with 7.9, so it does not truncate what it
60 /// divides once a side is not an integer, and it is `/` under another spelling there. The one
61 /// thing it does not do is go to a double the way `/` does whatever it was given, since
62 /// `7 // 2` is 3 and an INTEGER on both engines, so it cannot share `/`'s shape. A FLOAT stays
63 /// a FLOAT, which was measured, so this is a rule about decimals rather than about width.
64 Divided,
65 /// Slash promotes integers and decimals to double but preserves two floats as float.
66 Slashed,
67 /// Every argument promotes and a decimal result gains a digit for the carry. `+` and `-`.
68 ///
69 /// Adding two `DECIMAL(18,0)` produces nineteen digits, so a rule that gives the sum eighteen
70 /// of them is a rule that raises an overflow on the largest inputs it accepts. Only a decimal
71 /// moves: an integer result is the promoted type, since promotion already went to a type that
72 /// holds both, and the unary forms of the two operators do not widen because negating a number
73 /// cannot carry.
74 PromotedWithCarry,
75 /// Every argument promotes to one type and the result is fixed. `=` over anything is boolean.
76 PromotedTo(Fixed),
77 /// Every argument is cast to one fixed type and the result is another. `||` over strings.
78 FixedTo(Fixed, Fixed),
79 /// Every argument has to be that type already and the result is fixed. `lower`, `length`,
80 /// `LIKE`, `chr`.
81 ///
82 /// The difference from [`Shape::FixedTo`] is the word already. DuckDB refuses `lower(123)`,
83 /// `length(DATE '2020-01-01')` and `123 LIKE '1%'` with a binder error naming the overloads it
84 /// does have, and it refuses a BLOB as well, so the rule is VARCHAR rather than anything a cast
85 /// can reach. `||` is the one string function that really does take anything, since `1 || 'a'`
86 /// is `1a` upstream, and it keeps [`Shape::FixedTo`] for that reason.
87 ///
88 /// The argument type is part of the shape because the same rule holds away from strings.
89 /// `chr(col0 INTEGER)` is the only overload upstream has and it refuses `chr(65.9)` and
90 /// `chr(65::BIGINT)` rather than narrowing either of them.
91 Exact(Fixed, Fixed),
92 /// Every argument has to reach that type by widening and the result is fixed. `to_days`.
93 ///
94 /// Between [`Shape::Exact`] and [`Shape::FixedTo`], and it is where the interval constructors
95 /// sit. `to_hours(25)` is an INTEGER reaching a BIGINT and upstream answers it, `to_seconds(1.5)`
96 /// is a DECIMAL reaching a DOUBLE and upstream answers that too, and `to_days(1.7)` is a
97 /// DECIMAL that would have to lose its fraction to reach an INTEGER, which upstream refuses with
98 /// a binder error naming both overloads. So the question is whether promotion gets there and not
99 /// whether the type is already right, and not whether a cast exists, since a cast exists for
100 /// every one of the three.
101 Widened(Fixed, Fixed),
102 /// Every argument widens to the one type they all reach, no narrower than a floor, and the
103 /// result is fixed. `age(x, y)`.
104 ///
105 /// The difference from [`Shape::Widened`] is which way the arguments are allowed to pull. There
106 /// the floor is the answer and an argument wider than it is refused, which is right for a name
107 /// whose one overload reads a fixed type. Here the arguments meet each other first, so
108 /// `age(DATE, DATE)` reads two timestamps because the floor says so and `age(now(), now())`
109 /// reads two zoned ones because the arguments say so. Upstream has a row per combination and
110 /// this is the one rule they follow.
111 WidenedTogether(Fixed, Fixed),
112 /// The arguments are whatever they are and the result is fixed. `count(x)` over anything.
113 AnyTo(Fixed),
114 /// The first `n` arguments are cast to one fixed type, the rest are left alone, and the result
115 /// is fixed. `date_part('minute', x)` reads a part of whatever `x` is, and
116 /// `regexp_extract(s, p, 2)` takes two strings and then a number that has to stay one.
117 LeadingFixedTo(usize, Fixed, Fixed),
118 /// The first argument is cast to one fixed type, the rest are left alone, and the result is the
119 /// last argument's own type. `date_trunc('month', x)` gives back whatever kind of date `x` was.
120 LeadingFixedToLast(Fixed),
121 /// Every argument promotes and an integer result widens to the accumulator. `sum`.
122 Accumulated,
123 /// The first argument is a string or a list and the result is one piece of it. `array_extract`.
124 ///
125 /// The index is a BIGINT and nothing is cast to one, which is upstream's rule rather than an
126 /// omission here: `[1, 2, 3][1.5]` is a binder error there listing the four overloads, so a
127 /// decimal index is refused and not rounded. The bounds of a slice are the other way round,
128 /// which is why that is a shape of its own and not this one with a longer arity.
129 Extracted,
130 /// The first argument is a string or a list, the rest are the bounds, and the result is the first
131 /// argument's own type. `array_slice`.
132 Sliced,
133 /// The first `n` arguments have to be strings already, the rest are indexes, and the result is
134 /// fixed. `substring(s, a, b)` and `overlay(s, r, a, b)`.
135 ///
136 /// An index is a BIGINT and nothing is cast to one, which is the same rule
137 /// [`Shape::Extracted`] follows and is upstream's: `substring('abcdef', 2.5, 3)` is a binder
138 /// error there listing the two overloads rather than a substring from the second character.
139 TextThenIndex(usize, Fixed),
140 /// Every argument promotes, and the result is the first argument's own type. `nullif`.
141 ///
142 /// The promotion is for the comparison and not for the answer, which is what makes this its own
143 /// shape: `typeof(nullif(1, 2.5))` is INTEGER upstream and the comparison behind it is still
144 /// `1 = 2.5`, so the two arguments have to meet somewhere and the answer has to come back from
145 /// where it started. Comparing at the first argument's type instead would round the second one
146 /// and answer `nullif(2, 2.5)` with null.
147 PromotedToFirst,
148 /// One string naming a setting, and the result is whatever type that setting holds.
149 ///
150 /// `current_setting` and nothing else. It is a shape rather than a fixed pair because the pin
151 /// declares the return as `ANY` and then works it out from the name that was passed, which is
152 /// why `typeof(current_setting('threads'))` is BIGINT there and
153 /// `typeof(current_setting('memory_limit'))` is VARCHAR. Both come from one overload.
154 ///
155 /// Resolving this is an error and that is the point of it. The binder folds the call to the
156 /// setting's value before it asks this table anything, so the only way a call arrives here is
157 /// the way the fold cannot happen, which is an argument that is not a constant, and that is the
158 /// case the pin refuses in the same words.
159 Setting,
160 /// No arguments at all and a fixed result. `now()` and `current_schema()`.
161 ///
162 /// The session context functions, which are the ones whose answer comes from the connection
163 /// rather than from anything written in the query. The binder folds every one of them into a
164 /// constant before this table is asked, the same way it folds `typeof`, so what these rows are
165 /// for is the two questions the fold does not answer: which names exist, which is what
166 /// `duckdb_functions()` reports, and what `now(1)` says, which is the arity error rather than a
167 /// missing function.
168 Constant(Fixed),
169}
170
171/// The return types a signature can name outright.
172///
173/// A small enum rather than a `LogicalType` so that the table stays a `const` and there is no
174/// allocation behind a lookup that happens once per expression in every query.
175#[derive(Debug, Clone, Copy, PartialEq, Eq)]
176enum Fixed {
177 Boolean,
178 Integer,
179 BigInt,
180 Double,
181 Varchar,
182 Date,
183 Time,
184 TimeTz,
185 Timestamp,
186 TimestampTz,
187 Interval,
188}
189
190impl Fixed {
191 fn ty(self) -> LogicalType {
192 match self {
193 Self::Boolean => LogicalType::Boolean,
194 Self::Integer => LogicalType::Integer,
195 Self::BigInt => LogicalType::BigInt,
196 Self::Double => LogicalType::Double,
197 Self::Varchar => LogicalType::Varchar,
198 Self::Date => LogicalType::Date,
199 Self::Time => LogicalType::Time,
200 Self::TimeTz => LogicalType::TimeTz,
201 Self::Timestamp => LogicalType::Timestamp,
202 Self::TimestampTz => LogicalType::TimestampTz,
203 Self::Interval => LogicalType::Interval,
204 }
205 }
206}
207
208/// How many arguments a function takes.
209///
210/// A range rather than a count because `-` is both the negation and the subtraction, and one name
211/// with two arities is much less trouble than two names that the transformer would have to tell
212/// apart before the binder ever sees the call.
213///
214/// `OneOf` is the range with a hole in it. `make_date` takes one argument or three and not two, and
215/// a range that accepted two would bind a call DuckDB refuses and then have nothing to compute.
216#[derive(Debug, Clone, Copy, PartialEq, Eq)]
217enum Arity {
218 Exactly(usize),
219 Between(usize, Option<usize>),
220 OneOf(&'static [usize]),
221}
222
223impl Arity {
224 const fn exactly(count: usize) -> Self {
225 Self::Exactly(count)
226 }
227
228 const fn between(least: usize, most: usize) -> Self {
229 Self::Between(least, Some(most))
230 }
231
232 const fn at_least(least: usize) -> Self {
233 Self::Between(least, None)
234 }
235
236 const fn one_of(counts: &'static [usize]) -> Self {
237 Self::OneOf(counts)
238 }
239
240 fn accepts(self, count: usize) -> bool {
241 match self {
242 Self::Exactly(wanted) => count == wanted,
243 Self::Between(least, most) => count >= least && most.is_none_or(|most| count <= most),
244 Self::OneOf(counts) => counts.contains(&count),
245 }
246 }
247
248 /// Every count this accepts, with an open end stopped one past where it starts, for the tests
249 /// that hold each row of the table to its own shape at each count it claims to take.
250 #[cfg(test)]
251 fn counts(self) -> Vec<usize> {
252 match self {
253 Self::Exactly(count) => vec![count],
254 Self::Between(least, most) => (least..=most.unwrap_or(least + 1)).collect(),
255 Self::OneOf(counts) => counts.to_vec(),
256 }
257 }
258
259 #[cfg(test)]
260 fn least(self) -> usize {
261 match self {
262 Self::Exactly(count) | Self::Between(count, _) => count,
263 Self::OneOf(counts) => counts.iter().copied().min().unwrap_or(0),
264 }
265 }
266}
267
268struct Entry {
269 name: &'static str,
270 kind: FunctionKind,
271 arity: Arity,
272 shape: Shape,
273 /// Whether every argument has to be a number, which is the only argument constraint M0 needs.
274 numeric_only: bool,
275}
276
277/// The whole table.
278///
279/// One row per name. There are no overloads by argument type in here yet, because every name below
280/// has exactly one shape, and a second row for a name would need a rule for which one wins that is
281/// worth writing when there is a name that needs it.
282const TABLE: &[Entry] = &[
283 // Arithmetic. The result is what the operands promote to, so `INTEGER + BIGINT` is a `BIGINT`
284 // and the executor never has to widen mid expression. `+` and `-` take one argument as well as
285 // two, because the unary forms are the same function and DuckDB names them the same way, and
286 // they are the two that carry: a sum of two decimals needs a digit the operands do not have.
287 number("+", Arity::between(1, 2), Shape::PromotedWithCarry),
288 number("-", Arity::between(1, 2), Shape::PromotedWithCarry),
289 number("*", Arity::exactly(2), Shape::Multiplied),
290 number("%", Arity::exactly(2), Shape::Promoted),
291 // `/` is the exception and it is DuckDB's exception too: `7 / 2` is 3.5 and not 3, so the
292 // result is a double whatever went in, and `//` is the operator that keeps the integer.
293 number("/", Arity::exactly(2), Shape::Slashed),
294 number("//", Arity::exactly(2), Shape::Divided),
295 number("abs", Arity::exactly(1), Shape::Promoted),
296 // Strings.
297 // `||` is the one that takes anything and turns it into a string, which is why it is a
298 // `FixedTo` and everything under it is a `Text`. `1 || 'a'` is `1a` upstream.
299 Entry {
300 name: "||",
301 kind: FunctionKind::Scalar,
302 arity: Arity::exactly(2),
303 shape: Shape::FixedTo(Fixed::Varchar, Fixed::Varchar),
304 numeric_only: false,
305 },
306 text("lower", Arity::exactly(1), Fixed::Varchar),
307 text("upper", Arity::exactly(1), Fixed::Varchar),
308 text("length", Arity::exactly(1), Fixed::BigInt),
309 // `strlen` is bytes where `length` is characters, and it is a separate row rather than an alias
310 // for that reason. `strlen('héllo')` is 6 upstream and `length('héllo')` is 5. It is here
311 // because DuckDB's own ClickBench entry writes `AVG(STRLEN(URL))` in query 28, so a rudb
312 // that has only `length` cannot run that board at all without the SQL being changed, and the
313 // whole point of the comparison is that it is not changed.
314 text("strlen", Arity::exactly(1), Fixed::BigInt),
315 // The four SQL string functions that have a grammar rule of their own, plus the aliases upstream
316 // answers the same call with. Each alias is a row rather than a pointer at one, because the
317 // column a query gets back is named after the name that was written: `substr('abcdef', 2)` comes
318 // back as `substr('abcdef', 2)` upstream and not as a substring of anything.
319 Entry {
320 name: "substring",
321 kind: FunctionKind::Scalar,
322 arity: Arity::one_of(&[2, 3]),
323 shape: Shape::TextThenIndex(1, Fixed::Varchar),
324 numeric_only: false,
325 },
326 Entry {
327 name: "substr",
328 kind: FunctionKind::Scalar,
329 arity: Arity::one_of(&[2, 3]),
330 shape: Shape::TextThenIndex(1, Fixed::Varchar),
331 numeric_only: false,
332 },
333 Entry {
334 name: "overlay",
335 kind: FunctionKind::Scalar,
336 arity: Arity::one_of(&[3, 4]),
337 shape: Shape::TextThenIndex(2, Fixed::Varchar),
338 numeric_only: false,
339 },
340 // `left` and `right` count characters and clamp, and a negative count is a count from the other
341 // end rather than an error, so `left('abc', -1)` is `ab`. Both are declared
342 // `(VARCHAR, BIGINT)` upstream and neither casts its count, which is what
343 // [`Shape::TextThenIndex`] already says.
344 Entry {
345 name: "left",
346 kind: FunctionKind::Scalar,
347 arity: Arity::exactly(2),
348 shape: Shape::TextThenIndex(1, Fixed::Varchar),
349 numeric_only: false,
350 },
351 Entry {
352 name: "right",
353 kind: FunctionKind::Scalar,
354 arity: Arity::exactly(2),
355 shape: Shape::TextThenIndex(1, Fixed::Varchar),
356 numeric_only: false,
357 },
358 text("replace", Arity::exactly(3), Fixed::Varchar),
359 // `chr` is a code point and not a byte, so `chr(233)` is one character and not two bytes of
360 // something else. Its one overload upstream takes an INTEGER and it narrows nothing to reach
361 // it: `chr(65::BIGINT)` and `chr(65.9)` are both binder errors there.
362 Entry {
363 name: "chr",
364 kind: FunctionKind::Scalar,
365 arity: Arity::exactly(1),
366 shape: Shape::Exact(Fixed::Integer, Fixed::Varchar),
367 numeric_only: false,
368 },
369 // `concat` takes anything, joins it and drops the nulls instead of propagating them, so
370 // `concat('a', 1, NULL)` is `a1`. That last part is what makes it a third exception to the null
371 // in null out rule, next to `coalesce` and `nullif`, and it is the only one of the three that is
372 // an ordinary function rather than sugar for something else.
373 Entry {
374 name: "concat",
375 kind: FunctionKind::Scalar,
376 arity: Arity::at_least(1),
377 shape: Shape::FixedTo(Fixed::Varchar, Fixed::Varchar),
378 numeric_only: false,
379 },
380 text("position", Arity::exactly(2), Fixed::BigInt),
381 text("strpos", Arity::exactly(2), Fixed::BigInt),
382 text("instr", Arity::exactly(2), Fixed::BigInt),
383 text("trim", Arity::between(1, 2), Fixed::Varchar),
384 text("ltrim", Arity::between(1, 2), Fixed::Varchar),
385 text("rtrim", Arity::between(1, 2), Fixed::Varchar),
386 // Pattern matching. The transformer emits the operator spellings, so those are the names, and
387 // `LIKE` is one of them rather than a keyword the binder has to know about separately.
388 text("~~", Arity::exactly(2), Fixed::Boolean),
389 text("!~~", Arity::exactly(2), Fixed::Boolean),
390 text("~~*", Arity::exactly(2), Fixed::Boolean),
391 text("!~~*", Arity::exactly(2), Fixed::Boolean),
392 // Logic. `AND` and `OR` are conjunctions in the plan rather than calls, so only `NOT` is here.
393 Entry {
394 name: "not",
395 kind: FunctionKind::Scalar,
396 arity: Arity::exactly(1),
397 shape: Shape::FixedTo(Fixed::Boolean, Fixed::Boolean),
398 numeric_only: false,
399 },
400 // `coalesce` promotes across every argument, which is exactly what `Shape::Promoted` says, and
401 // it is the one scalar here that takes a variable number of them.
402 Entry {
403 name: "coalesce",
404 kind: FunctionKind::Scalar,
405 arity: Arity::at_least(1),
406 shape: Shape::Promoted,
407 numeric_only: false,
408 },
409 // `nullif(a, b)` is a macro upstream, `CASE WHEN a = b THEN NULL ELSE a END`, and it is a
410 // function here because the column it produces is named after the call rather than after the
411 // expansion. What that costs is the message for the wrong number of arguments: upstream's is a
412 // binder error about a macro listing `"nullif"(a, b)` under `Candidate macros:`, and the one
413 // below is the ordinary sentence about a function. Both refuse, and the reachable spelling of the
414 // mistake is the quoted `"nullif"(1)`, since the grammar has NULLIF with exactly two arguments
415 // and refuses any other count before the binder sees it.
416 Entry {
417 name: "nullif",
418 kind: FunctionKind::Scalar,
419 arity: Arity::exactly(2),
420 shape: Shape::PromotedToFirst,
421 numeric_only: false,
422 },
423 // Dates and times. `EXTRACT(minute FROM x)` is spelled `date_part('minute', x)` by the time it
424 // gets here, because that is what DuckDB's own parser does with it, so there is one entry for
425 // the two spellings. The part is a string and the thing it is a part of is left alone, which is
426 // what the two leading shapes are for: there is nothing to promote a timestamp towards.
427 // The answer is a double here and a bigint by the time the binder is finished with it, for
428 // every part but the two that carry a fraction. See `narrowed_part` in `rudb-bind`, which is
429 // where the value of the first argument gets to decide the type of the call.
430 Entry {
431 name: "date_part",
432 kind: FunctionKind::Scalar,
433 arity: Arity::exactly(2),
434 shape: Shape::LeadingFixedTo(1, Fixed::Varchar, Fixed::Double),
435 numeric_only: false,
436 },
437 Entry {
438 name: "date_trunc",
439 kind: FunctionKind::Scalar,
440 arity: Arity::exactly(2),
441 shape: Shape::LeadingFixedToLast(Fixed::Varchar),
442 numeric_only: false,
443 },
444 // The gap between two moments counted in calendar fields. Upstream has a one argument form as
445 // well, which measures from today, and it is not here because there is no clock in the engine
446 // yet and a function that invents one would be worse than a function that is missing.
447 //
448 // Widening rather than casting is the whole overload: a DATE widens to a TIMESTAMP and upstream
449 // accepts `age(DATE, DATE)`, while a TIME and an INTERVAL do not widen anywhere and upstream
450 // refuses both of those with a binder error rather than reading them as moments.
451 Entry {
452 name: "age",
453 kind: FunctionKind::Scalar,
454 arity: Arity::one_of(&[1, 2]),
455 shape: Shape::WidenedTogether(Fixed::Timestamp, Fixed::Interval),
456 numeric_only: false,
457 },
458 // The two that turn a number into a date and a timestamp, which is how every ClickBench entry
459 // on the board reads that data: the Parquet stores four of its columns as integers and every
460 // query in the set treats them as dates and times. DuckDB's own entry wraps them in exactly
461 // these two calls, so these are what let that entry run here unmodified.
462 //
463 // One argument is days since the epoch and three are a year, a month and a day. Upstream reads
464 // the single one as an INTEGER and the triple as three BIGINTs, and both are INTEGER here,
465 // because the column this is called on is an INTEGER and a widening pass over a hundred million
466 // values to reach a function that immediately narrows again is a pass nobody asked for. The
467 // difference shows on a year that does not fit in an INTEGER, where upstream converts and then
468 // complains about the destination and this complains about the cast.
469 Entry {
470 name: "make_date",
471 kind: FunctionKind::Scalar,
472 arity: Arity::one_of(&[1, 3]),
473 shape: Shape::FixedTo(Fixed::Integer, Fixed::Date),
474 numeric_only: true,
475 },
476 // Milliseconds since the epoch. Upstream also has seven overloads that read a date or a time
477 // and give the milliseconds back, which this table has no way to say yet because it is one row
478 // per name and those pick by argument type. `epoch_ms` of a timestamp is the missing half.
479 Entry {
480 name: "epoch_ms",
481 kind: FunctionKind::Scalar,
482 arity: Arity::exactly(1),
483 shape: Shape::FixedTo(Fixed::BigInt, Fixed::Timestamp),
484 numeric_only: true,
485 },
486 // The thirteen ways to build an interval out of a count of one unit, which is what
487 // `INTERVAL 1 DAY` is once the transformer has rewritten it, and `to_days(1)` written out by
488 // hand is the same call. Eleven of them count whole units and the two that can carry a fraction
489 // take a DOUBLE, so `INTERVAL 2.7 SECOND` is two and seven tenths of a second while
490 // `INTERVAL 1.5 DAY` is one day.
491 //
492 // Upstream declares the eight that land in months or days twice, once over an INTEGER and once
493 // over a BIGINT, and only the first is here, for the reason the head of this table gives: one
494 // row per name, and a second row needs a rule for which one wins. The rewrite always casts to
495 // the width the row below wants, so the literal is unaffected and what is missing is a
496 // handwritten `to_days(3::BIGINT)`, which is refused here and answered there. The three that
497 // land in microseconds have the BIGINT overload and no INTEGER one, so those rows are exact.
498 built("to_years", Fixed::Integer),
499 built("to_months", Fixed::Integer),
500 built("to_quarters", Fixed::Integer),
501 built("to_decades", Fixed::Integer),
502 built("to_centuries", Fixed::Integer),
503 built("to_millennia", Fixed::Integer),
504 built("to_days", Fixed::Integer),
505 built("to_weeks", Fixed::Integer),
506 built("to_hours", Fixed::BigInt),
507 built("to_minutes", Fixed::BigInt),
508 built("to_microseconds", Fixed::BigInt),
509 built("to_seconds", Fixed::Double),
510 built("to_milliseconds", Fixed::Double),
511 // `trunc` is here because the interval rewrite writes it, and it is an ordinary function anybody
512 // can write as well. Upstream has twenty six overloads and every one of them gives back the type
513 // it was handed, which is what `Shape::Promoted` says over one argument. The exception is the
514 // decimal, where upstream drops the scale and gives `DECIMAL(2,0)` for `trunc(1.7)` and this
515 // keeps `DECIMAL(2,1)` holding 1.0, since no shape in this table drops a scale.
516 number("trunc", Arity::exactly(1), Shape::Promoted),
517 // Regular expressions. The pattern is a string like the text is, so three of the four are the
518 // plain string shape. `regexp_extract` is not, because its third argument is the group number
519 // and casting that to a string and reading it back would be a way to accept `'two'`.
520 text("regexp_replace", Arity::between(3, 4), Fixed::Varchar),
521 text("regexp_matches", Arity::between(2, 3), Fixed::Boolean),
522 text("regexp_full_match", Arity::between(2, 3), Fixed::Boolean),
523 Entry {
524 name: "regexp_extract",
525 kind: FunctionKind::Scalar,
526 arity: Arity::between(2, 4),
527 shape: Shape::LeadingFixedTo(2, Fixed::Varchar, Fixed::Varchar),
528 numeric_only: false,
529 },
530 // Subscripting. A bracket is one of these two calls by the time the transformer is done with it,
531 // `x[2]` being `array_extract(x, 2)` and `x[1:2]` being `array_slice(x, 1, 2)`, which is what
532 // DuckDB's own transformer writes as well. Both take a string or a list and give back a piece of
533 // the same thing, so neither one can name its return type here: it is read off the argument.
534 Entry {
535 name: "array_extract",
536 kind: FunctionKind::Scalar,
537 arity: Arity::exactly(2),
538 shape: Shape::Extracted,
539 numeric_only: false,
540 },
541 // Three arguments is a range and four is a range with a step. There is no two argument form,
542 // which is why a slice cannot share the row above: `array_slice([1, 2, 3], 1)` is an arity error
543 // upstream rather than the whole list from the first element on.
544 Entry {
545 name: "array_slice",
546 kind: FunctionKind::Scalar,
547 arity: Arity::between(3, 4),
548 shape: Shape::Sliced,
549 numeric_only: false,
550 },
551 // The type of an expression, as a string. Nothing is cast and nothing runs: the binder folds
552 // this to the name of the type it just decided, so the argument is only ever looked at and the
553 // executor never sees the call.
554 Entry {
555 name: "typeof",
556 kind: FunctionKind::Scalar,
557 arity: Arity::exactly(1),
558 shape: Shape::AnyTo(Fixed::Varchar),
559 numeric_only: false,
560 },
561 // The value of a setting, as a value rather than as a row of `duckdb_settings()`. This is the
562 // second function the binder folds and it folds for the same reason `typeof` does: the answer
563 // is settled once the name is known and nothing about it changes per row. Upstream folds it too
564 // and an `EXPLAIN` of a query that calls it shows the literal, which is what makes an `ANY`
565 // return type resolve to something a plan can carry.
566 Entry {
567 name: "current_setting",
568 kind: FunctionKind::Scalar,
569 arity: Arity::exactly(1),
570 shape: Shape::Setting,
571 numeric_only: false,
572 },
573 // Session context. Fourteen names for eight answers, which is the SQL standard's spellings and
574 // Postgres's spellings and DuckDB's own sitting on top of each other. The binder folds every one
575 // of them, so these rows exist to be listed by `duckdb_settings()`'s neighbour
576 // `duckdb_functions()` and to give `now(1)` the arity error the pin gives it.
577 //
578 // Four of these are macro rows upstream rather than scalar rows, which is `current_user`,
579 // `session_user`, `user` and `current_catalog`, and this table has no macros so they are scalars
580 // here. The difference shows up in the `function_type` column of `duckdb_functions()` and
581 // nowhere else, since the parenthesized call binds on both engines and answers the same.
582 session("now", Fixed::TimestampTz),
583 session("get_current_timestamp", Fixed::TimestampTz),
584 session("transaction_timestamp", Fixed::TimestampTz),
585 session("current_localtimestamp", Fixed::Timestamp),
586 session("get_current_time", Fixed::TimeTz),
587 session("current_localtime", Fixed::Time),
588 session("current_date", Fixed::Date),
589 session("today", Fixed::Date),
590 session("current_schema", Fixed::Varchar),
591 session("current_database", Fixed::Varchar),
592 session("current_catalog", Fixed::Varchar),
593 session("current_user", Fixed::Varchar),
594 session("session_user", Fixed::Varchar),
595 session("user", Fixed::Varchar),
596 // Aggregates.
597 aggregate("count_star", Arity::exactly(0), Shape::AnyTo(Fixed::BigInt), false),
598 aggregate("count", Arity::exactly(1), Shape::AnyTo(Fixed::BigInt), false),
599 aggregate("sum", Arity::exactly(1), Shape::Accumulated, true),
600 aggregate("avg", Arity::exactly(1), Shape::PromotedTo(Fixed::Double), true),
601 aggregate("min", Arity::exactly(1), Shape::Promoted, false),
602 aggregate("max", Arity::exactly(1), Shape::Promoted, false),
603];
604
605/// A scalar that takes numbers.
606const fn number(name: &'static str, arity: Arity, shape: Shape) -> Entry {
607 Entry { name, kind: FunctionKind::Scalar, arity, shape, numeric_only: true }
608}
609
610/// A scalar that takes strings and returns `returns`.
611const fn text(name: &'static str, arity: Arity, returns: Fixed) -> Entry {
612 Entry {
613 name,
614 kind: FunctionKind::Scalar,
615 arity,
616 shape: Shape::Exact(Fixed::Varchar, returns),
617 numeric_only: false,
618 }
619}
620
621/// An interval constructor, which takes one count of one unit and gives back an interval.
622const fn built(name: &'static str, count: Fixed) -> Entry {
623 Entry {
624 name,
625 kind: FunctionKind::Scalar,
626 arity: Arity::exactly(1),
627 shape: Shape::Widened(count, Fixed::Interval),
628 numeric_only: false,
629 }
630}
631
632/// A session context function, which takes nothing and answers about the connection.
633const fn session(name: &'static str, returns: Fixed) -> Entry {
634 Entry {
635 name,
636 kind: FunctionKind::Scalar,
637 arity: Arity::exactly(0),
638 shape: Shape::Constant(returns),
639 numeric_only: false,
640 }
641}
642
643const fn aggregate(name: &'static str, arity: Arity, shape: Shape, numeric_only: bool) -> Entry {
644 Entry { name, kind: FunctionKind::Aggregate, arity, shape, numeric_only }
645}
646
647/// Whether a name is a function at all, and which kind.
648///
649/// The binder asks this before it knows what to do with a call, since `count(x)` in a projection
650/// has to become an error naming the aggregate rather than a lookup failure naming the name.
651#[must_use]
652pub fn kind_of(name: &str) -> Option<FunctionKind> {
653 find(name).map(|entry| entry.kind)
654}
655
656/// What `date_part` answers with when the specifier is known at binding time.
657///
658/// `epoch` counts seconds and `julian` counts days, and both of them carry a fraction, so those two
659/// are doubles and every other part is a whole number. A specifier that names no part at all is a
660/// double as well, since the call is going to fail anyway and the sentence about it belongs to the
661/// one place that knows every spelling.
662///
663/// This is the only place a call's type comes from the value of an argument rather than the type of
664/// one, and it is upstream's rule rather than an optimization: the declared overload there is a
665/// double and the binder narrows it, which is why `date_part(p, ts)` over a column of specifiers is
666/// a double even when every row of it says `year`.
667#[must_use]
668pub fn part_type(spelling: &str) -> LogicalType {
669 let fraction = ["epoch", "julian", "jd"];
670 if fraction.iter().any(|name| name.eq_ignore_ascii_case(spelling)) {
671 LogicalType::Double
672 } else {
673 LogicalType::BigInt
674 }
675}
676
677/// Resolves a call.
678///
679/// # Errors
680///
681/// If there is no function of that name, if the argument count is wrong, if an argument is not a
682/// number where the function needs one, or if the arguments have no type in common. The messages
683/// are DuckDB's, since a great deal of code in the wild asserts on them.
684pub fn resolve(name: &str, arguments: &[LogicalType]) -> Result<Resolved> {
685 let entry = find(name).ok_or_else(|| {
686 Error::catalog(format!("Scalar Function with name {name} does not exist!"))
687 })?;
688 if !entry.arity.accepts(arguments.len()) {
689 return Err(no_match(entry.name, arguments));
690 }
691 if let Some((cast_to, returns)) = temporal(entry.name, arguments) {
692 return Ok(Resolved { name: entry.name, kind: entry.kind, arguments: cast_to, returns });
693 }
694 if entry.numeric_only {
695 for ty in arguments {
696 // A null literal has no type yet and every function accepts one, since the alternative
697 // is that `sum(NULL)` fails to bind rather than returning null.
698 if !ty.is_numeric() && *ty != LogicalType::Null {
699 return Err(Error::binder(format!(
700 "No function matches the given name and argument types '{name}({ty})'. You might need to add explicit type casts."
701 )));
702 }
703 }
704 }
705 let (cast_to, returns) = match entry.shape {
706 Shape::Promoted => {
707 let common = promote_all(name, arguments)?;
708 (vec![common.clone(); arguments.len()], common)
709 }
710 Shape::Multiplied => {
711 let common = promote_all(name, arguments)?;
712 match product(arguments)? {
713 // Each side keeps its own scale and takes the answer's width, so the two runs are
714 // the same physical type and the unscaled values multiply into the answer with no
715 // rescaling anywhere. That is what the decimal loop in rudb-kernels expects.
716 Some(LogicalType::Decimal { width, scale }) => {
717 let cast_to = arguments
718 .iter()
719 .map(|ty| match ty.decimal_shape() {
720 Some((_, held)) => LogicalType::Decimal { width, scale: held },
721 None => ty.clone(),
722 })
723 .collect();
724 (cast_to, LogicalType::Decimal { width, scale })
725 }
726 _ => (vec![common.clone(); arguments.len()], common),
727 }
728 }
729 Shape::Divided => {
730 let common = promote_all(name, arguments)?;
731 // The cast goes with the answer rather than being left where promotion put it, because
732 // a decimal run divided as a decimal and then widened to a double is not the same
733 // number as the same pair of values divided as doubles.
734 let returns = match common {
735 LogicalType::Decimal { .. } => LogicalType::Double,
736 other => other,
737 };
738 (vec![returns.clone(); arguments.len()], returns)
739 }
740 Shape::Slashed => {
741 let common = promote_all(name, arguments)?;
742 let returns =
743 if common == LogicalType::Float { LogicalType::Float } else { LogicalType::Double };
744 (vec![returns.clone(); arguments.len()], returns)
745 }
746 Shape::PromotedWithCarry => {
747 let common = promote_all(name, arguments)?;
748 // One argument is a negation or a unary plus, and neither one can carry. Negating the
749 // smallest value of a type is the exception and it is not a signature's to take, since
750 // the type of the answer depends on the value: the constant folder widens that one
751 // value by a step, per #264, and the signature says the same thing here as upstream's
752 // does.
753 let returns = if arguments.len() > 1 { carrying(common) } else { common };
754 (vec![returns.clone(); arguments.len()], returns)
755 }
756 Shape::PromotedTo(fixed) => {
757 let common = promote_all(name, arguments)?;
758 (vec![common; arguments.len()], fixed.ty())
759 }
760 Shape::FixedTo(argument, result) => (vec![argument.ty(); arguments.len()], result.ty()),
761 Shape::Exact(argument, result) => {
762 let wanted = argument.ty();
763 for ty in arguments {
764 // An untyped null is accepted the way it is everywhere else here. DuckDB answers
765 // `length(NULL)` with NULL rather than refusing it, because a null has no type to
766 // pick an overload with and every overload would return null anyway.
767 if *ty != wanted && *ty != LogicalType::Null {
768 return Err(no_match(entry.name, arguments));
769 }
770 }
771 (vec![wanted; arguments.len()], result.ty())
772 }
773 Shape::Widened(argument, result) => {
774 let wanted = argument.ty();
775 for ty in arguments {
776 // A null is accepted here for the reason it is accepted above, and it is the only
777 // type that does not have to promote anywhere, since it has nothing to promote.
778 if *ty != LogicalType::Null && ty.promote(&wanted).as_ref() != Some(&wanted) {
779 return Err(no_match(entry.name, arguments));
780 }
781 }
782 (vec![wanted; arguments.len()], result.ty())
783 }
784 Shape::WidenedTogether(floor, result) => {
785 // A null has nothing to pull with, so it is left out of the meeting and then cast to
786 // whatever the rest of them settled on, which is the floor when they were all nulls.
787 let mut wanted = floor.ty();
788 for ty in arguments {
789 if *ty == LogicalType::Null {
790 continue;
791 }
792 match ty.promote(&wanted) {
793 Some(met) => wanted = met,
794 None => return Err(no_match(entry.name, arguments)),
795 }
796 }
797 (vec![wanted.clone(); arguments.len()], result.ty())
798 }
799 Shape::AnyTo(result) => (arguments.to_vec(), result.ty()),
800 Shape::LeadingFixedTo(count, first, result) => {
801 (leading(count, first, arguments), result.ty())
802 }
803 Shape::LeadingFixedToLast(first) => {
804 // A null literal has no type and DuckDB refuses `date_trunc('month', NULL)` outright,
805 // because it cannot tell the date overload from the interval one. Refusing needs a
806 // table with both overloads in it to refuse from, which this is not yet, so the answer
807 // is the widest of the candidates rather than a message about a choice nobody made.
808 let last = match arguments.last() {
809 Some(LogicalType::Null) | None => LogicalType::Timestamp,
810 Some(ty) => ty.clone(),
811 };
812 (leading(1, first, arguments), last)
813 }
814 Shape::Accumulated => {
815 let common = promote_all(name, arguments)?;
816 let returns = accumulator(&common);
817 (vec![common; arguments.len()], returns)
818 }
819 Shape::Extracted => {
820 let target = &arguments[0];
821 let index = &arguments[1];
822 let Some(element) = element_of(target) else {
823 return Err(no_match(entry.name, arguments));
824 };
825 if !index.is_integer() && *index != LogicalType::Null {
826 return Err(no_match(entry.name, arguments));
827 }
828 (vec![target.clone(), LogicalType::BigInt], element)
829 }
830 Shape::Sliced => {
831 let target = &arguments[0];
832 if element_of(target).is_none() {
833 // Upstream's own sentence, shouted, and it is the same sentence whichever of the two
834 // spellings the call was written with.
835 return Err(Error::binder("ARRAY_SLICE can only operate on LISTs and VARCHARs"));
836 }
837 // A step is declared BIGINT and so it is not cast to one either, while the two bounds
838 // are declared ANY and are: `array_slice([1, 2, 3], 1.5, 2)` is `[2]` upstream, rounded,
839 // and `array_slice([1, 2, 3], 1, 2, 1.5)` is a binder error.
840 if let Some(step) = arguments.get(3) {
841 if !step.is_integer() && *step != LogicalType::Null {
842 return Err(no_match(entry.name, arguments));
843 }
844 }
845 let mut cast_to = vec![LogicalType::BigInt; arguments.len()];
846 cast_to[0] = target.clone();
847 (cast_to, target.clone())
848 }
849 Shape::TextThenIndex(count, result) => {
850 let (text, indexes) = arguments.split_at(count.min(arguments.len()));
851 for ty in text {
852 if *ty != LogicalType::Varchar && *ty != LogicalType::Null {
853 return Err(no_match(entry.name, arguments));
854 }
855 }
856 for ty in indexes {
857 if !ty.is_integer() && *ty != LogicalType::Null {
858 return Err(no_match(entry.name, arguments));
859 }
860 }
861 let mut cast_to = vec![LogicalType::BigInt; arguments.len()];
862 for slot in &mut cast_to[..text.len()] {
863 *slot = LogicalType::Varchar;
864 }
865 (cast_to, result.ty())
866 }
867 Shape::PromotedToFirst => {
868 let common = promote_all(name, arguments)?;
869 // An untyped null keeps nothing to hand back, so it takes the promoted type the way
870 // every other shape here does. Upstream says NULL for `typeof(nullif(NULL, NULL))`
871 // because it has a type for a null literal and this engine does not, which is #244.
872 let first = &arguments[0];
873 let returns = if *first == LogicalType::Null { common.clone() } else { first.clone() };
874 (vec![common; arguments.len()], returns)
875 }
876 // Reaching here means the binder could not fold the call, and the only reason it cannot is
877 // an argument that is not a constant. The pin says exactly this and names the parameter.
878 Shape::Setting => {
879 return Err(Error::binder(format!(
880 "The \"setting_name\" argument in function \"{}\" must be a constant expression",
881 entry.name
882 )));
883 }
884 // The arity check above already refused every call but the one with no arguments, so there
885 // is nothing to cast and nothing left to decide.
886 Shape::Constant(fixed) => (Vec::new(), fixed.ty()),
887 };
888 Ok(Resolved { name: entry.name, kind: entry.kind, arguments: cast_to, returns })
889}
890
891/// What the arithmetic operators return when a date, a time, a timestamp or an interval is one of
892/// the arguments.
893///
894/// The one place in this file where the argument types pick the overload rather than the name
895/// picking one shape. The table above says a name has exactly one shape and that a second row for
896/// a name needs a rule for which one wins, and this is the rule: a date, a time, a timestamp or an
897/// interval next to one of those, or next to a number, is temporal arithmetic, and everything else
898/// is the numeric row. The answer is the types to cast the arguments to and the type that comes
899/// back.
900///
901/// A date plus an interval is a timestamp and not a date, because the interval carries a time of
902/// day. A time plus an interval is a time, since the months and the days have nowhere to go and it
903/// wraps at midnight. Taking a date off an interval is not a thing on either engine, so only the
904/// commuted addition is here.
905///
906/// Two intervals add and subtract field by field, and a number scales one, in either order for the
907/// multiplication and with the interval on the left for the division.
908///
909/// The multiplication has two overloads of its own and the difference between them shows. A whole
910/// number goes in as a `BIGINT` and multiplies the three fields as they are, and everything else
911/// goes in as a `DOUBLE` and moves what is left over on a field down to the next one. `HUGEINT` and
912/// `UBIGINT` take the double as well, since neither of them fits a `BIGINT` to begin with. Dividing
913/// has only the double, which is why an integer count divided into an interval reports its division
914/// by zero as `0.0`.
915///
916/// A plain number next to a date is a count of days and the answer stays a date, which is the one
917/// shape here that does not become a timestamp. The count is an `INTEGER` and nothing wider, so a
918/// `BIGINT` next to a date has no overload to reach at all, and taking a date off a number is not a
919/// thing. One date taken off another is a count of days as a `BIGINT` and one timestamp taken off
920/// another is an interval, and a date on either side of that subtraction becomes a timestamp first.
921/// A date plus a time is the timestamp they name together, in either order, and taking a time off a
922/// date is refused upstream.
923///
924/// An untyped null next to a date is the count of days and next to a timestamp is the interval,
925/// which is measured rather than picked: `typeof(DATE '2020-01-01' + NULL)` is `DATE` and
926/// `typeof(TIMESTAMP '2020-01-01' - NULL)` is `TIMESTAMP`. A null next to a time or next to an
927/// interval is ambiguous upstream and refused, which we refuse too, with the wrong sentence for now
928/// because the sentence for an ambiguous call is #395.
929fn temporal(name: &str, arguments: &[LogicalType]) -> Option<(Vec<LogicalType>, LogicalType)> {
930 use LogicalType::{
931 BigInt, Date, Double, HugeInt, Integer, Interval, Null, SmallInt, Time, TimeTz, Timestamp,
932 TimestampTz, TinyInt, UBigInt, UHugeInt, USmallInt, UTinyInt,
933 };
934 let kept = |returns| Some((arguments.to_vec(), returns));
935 // A null literal has no type yet, so it counts as the number and the cast to a double is what
936 // turns the whole call into a null.
937 let number = |ty: &LogicalType| ty.is_numeric() || *ty == Null;
938 let counted = |ty: &LogicalType| ty.is_integer() && !matches!(ty, HugeInt | UHugeInt | UBigInt);
939 // The days a date moves by are an `INTEGER`, so this is the set of types that widen into one.
940 let days =
941 |ty: &LogicalType| matches!(ty, TinyInt | SmallInt | Integer | UTinyInt | USmallInt | Null);
942 match (name, arguments) {
943 ("-", [Interval]) => kept(Interval),
944 ("+" | "-", [Date | Timestamp, Interval]) | ("+", [Interval, Date | Timestamp]) => {
945 kept(Timestamp)
946 }
947 ("+" | "-", [Time, Interval]) | ("+", [Interval, Time]) => kept(Time),
948 ("+" | "-", [Interval, Interval]) => kept(Interval),
949 ("-", [Date, Date]) => kept(BigInt),
950 ("-", [Timestamp, Timestamp]) => kept(Interval),
951 ("-", [Date, Timestamp] | [Timestamp, Date]) => {
952 Some((vec![Timestamp, Timestamp], Interval))
953 }
954 ("+", [Date, Time] | [Time, Date]) => kept(Timestamp),
955 // A zoned value keeps its zone through all of this, which is upstream's answer for every one
956 // of these rather than something read off the unzoned rows above. The mixed subtraction is
957 // the one that has a cast in it: a plain timestamp or a date next to a zoned one becomes
958 // zoned first, and then the two of them are two of the same kind.
959 ("+" | "-", [TimestampTz, Interval]) | ("+", [Interval, TimestampTz]) => kept(TimestampTz),
960 ("+" | "-", [TimeTz, Interval]) | ("+", [Interval, TimeTz]) => kept(TimeTz),
961 ("-", [TimestampTz, TimestampTz]) => kept(Interval),
962 ("-", [TimestampTz, Timestamp | Date] | [Timestamp | Date, TimestampTz]) => {
963 Some((vec![TimestampTz, TimestampTz], Interval))
964 }
965 ("+", [Date, TimeTz] | [TimeTz, Date]) => kept(TimestampTz),
966 ("+" | "-", [TimestampTz, Null]) | ("+", [Null, TimestampTz]) => kept(TimestampTz),
967 ("+" | "-", [Date, count]) if days(count) => Some((vec![Date, Integer], Date)),
968 ("+", [count, Date]) if days(count) => Some((vec![Integer, Date], Date)),
969 ("+" | "-", [Timestamp, Null]) | ("+", [Null, Timestamp]) => kept(Timestamp),
970 ("*", [Interval, count]) if counted(count) => Some((vec![Interval, BigInt], Interval)),
971 ("*", [count, Interval]) if counted(count) => Some((vec![BigInt, Interval], Interval)),
972 ("*" | "/", [Interval, scale]) if number(scale) => Some((vec![Interval, Double], Interval)),
973 ("*", [scale, Interval]) if number(scale) => Some((vec![Double, Interval], Interval)),
974 _ => None,
975 }
976}
977
978/// The error for a call that names a real function and does not fit any of its overloads.
979///
980/// The sentence is DuckDB's, and so is the block under it when there is one. A message that says a
981/// call does not match without saying what would match is a message that sends somebody to the
982/// documentation, and the whole argument for copying the reference's errors is that a program
983/// written against one engine should not have to be debugged differently against the other.
984///
985/// The trailing newline is the reference's too. Its message ends after the last candidate with a
986/// line break, which is visible as the second blank line before the shell prints the offending SQL.
987fn no_match(name: &str, arguments: &[LogicalType]) -> Error {
988 let types = arguments.iter().map(ToString::to_string).collect::<Vec<_>>().join(", ");
989 let mut message = format!(
990 "No function matches the given name and argument types '{name}({types})'. You might need to add explicit type casts."
991 );
992 if let Some((_, overloads)) = CANDIDATES.iter().find(|(entry, _)| *entry == name) {
993 message.push_str("\n\tCandidate functions:");
994 for overload in *overloads {
995 message.push_str("\n\t");
996 message.push_str(overload);
997 }
998 message.push('\n');
999 }
1000 Error::binder(message)
1001}
1002
1003/// What the reference prints under `Candidate functions:`, per function, byte for byte.
1004///
1005/// Copied off the pinned binary rather than generated from [`TABLE`], because it is not derivable
1006/// from what rudb has. The parameters are called `col0` and `col1` for some functions and `string`,
1007/// `regex` and a quoted `"options"` for others, an operator is quoted where a plain name is not, and
1008/// `length` lists three overloads of which rudb has one. That last one is the argument for copying
1009/// rather than deriving: the list is what DuckDB accepts, rudb is meant to accept the same, and a
1010/// list that shrank to what is built today would have to be edited every time a gap closes.
1011///
1012/// A name missing from here gets the sentence with no block under it, which is what every function
1013/// outside the string family does today.
1014const CANDIDATES: &[(&str, &[&str])] = &[
1015 // The session context functions, which all print the same way because they all take nothing.
1016 // The four spelled as macros upstream are not here on purpose: the pin answers those with
1017 // "Macro current_user() does not support the supplied arguments" and a `Candidate macros:` block
1018 // under it, and rudb has no macros to say that about, so a block naming candidate functions
1019 // would be a second thing wrong rather than the sentence with nothing under it.
1020 ("now", &["now() -> TIMESTAMP WITH TIME ZONE"]),
1021 ("get_current_timestamp", &["get_current_timestamp() -> TIMESTAMP WITH TIME ZONE"]),
1022 ("transaction_timestamp", &["transaction_timestamp() -> TIMESTAMP WITH TIME ZONE"]),
1023 ("current_localtimestamp", &["current_localtimestamp() -> TIMESTAMP"]),
1024 ("get_current_time", &["get_current_time() -> TIME WITH TIME ZONE"]),
1025 ("current_localtime", &["current_localtime() -> TIME"]),
1026 ("current_date", &["current_date() -> DATE"]),
1027 ("today", &["today() -> DATE"]),
1028 ("current_schema", &["current_schema() -> VARCHAR"]),
1029 ("current_database", &["current_database() -> VARCHAR"]),
1030 ("lower", &["lower(col0 VARCHAR) -> VARCHAR"]),
1031 ("upper", &["upper(col0 VARCHAR) -> VARCHAR"]),
1032 (
1033 "length",
1034 &[
1035 "length(col0 VARCHAR) -> BIGINT",
1036 "length(col0 BIT) -> BIGINT",
1037 "length(col0 ANY[]) -> BIGINT",
1038 ],
1039 ),
1040 ("strlen", &["strlen(col0 VARCHAR) -> BIGINT"]),
1041 ("chr", &["chr(col0 INTEGER) -> VARCHAR"]),
1042 ("left", &["\"left\"(col0 VARCHAR, col1 BIGINT) -> VARCHAR"]),
1043 ("right", &["\"right\"(col0 VARCHAR, col1 BIGINT) -> VARCHAR"]),
1044 ("replace", &["\"replace\"(col0 VARCHAR, col1 VARCHAR, col2 VARCHAR) -> VARCHAR"]),
1045 // The one overload upstream prints with a repeated parameter in it, which is how it writes a
1046 // variadic. Reachable with no arguments at all, since the grammar has nothing to say about the
1047 // count of an ordinary call.
1048 ("concat", &["concat(col0 ANY, [ANY...]) -> ANY"]),
1049 (
1050 "substring",
1051 &[
1052 "\"substring\"(col0 VARCHAR, col1 BIGINT, col2 BIGINT) -> VARCHAR",
1053 "\"substring\"(col0 VARCHAR, col1 BIGINT) -> VARCHAR",
1054 ],
1055 ),
1056 (
1057 "substr",
1058 &[
1059 "substr(col0 VARCHAR, col1 BIGINT, col2 BIGINT) -> VARCHAR",
1060 "substr(col0 VARCHAR, col1 BIGINT) -> VARCHAR",
1061 ],
1062 ),
1063 (
1064 "overlay",
1065 &[
1066 "\"overlay\"(col0 VARCHAR, col1 VARCHAR, col2 BIGINT) -> VARCHAR",
1067 "\"overlay\"(col0 VARCHAR, col1 VARCHAR, col2 BIGINT, col3 BIGINT) -> VARCHAR",
1068 ],
1069 ),
1070 ("position", &["\"position\"(col0 VARCHAR, col1 VARCHAR) -> BIGINT"]),
1071 ("strpos", &["strpos(col0 VARCHAR, col1 VARCHAR) -> BIGINT"]),
1072 ("instr", &["instr(col0 VARCHAR, col1 VARCHAR) -> BIGINT"]),
1073 (
1074 "trim",
1075 &["\"trim\"(col0 VARCHAR) -> VARCHAR", "\"trim\"(col0 VARCHAR, col1 VARCHAR) -> VARCHAR"],
1076 ),
1077 ("ltrim", &["ltrim(col0 VARCHAR) -> VARCHAR", "ltrim(col0 VARCHAR, col1 VARCHAR) -> VARCHAR"]),
1078 ("rtrim", &["rtrim(col0 VARCHAR) -> VARCHAR", "rtrim(col0 VARCHAR, col1 VARCHAR) -> VARCHAR"]),
1079 ("~~", &["\"~~\"(col0 VARCHAR, col1 VARCHAR) -> BOOLEAN"]),
1080 ("!~~", &["\"!~~\"(col0 VARCHAR, col1 VARCHAR) -> BOOLEAN"]),
1081 ("~~*", &["\"~~*\"(col0 VARCHAR, col1 VARCHAR) -> BOOLEAN"]),
1082 ("!~~*", &["\"!~~*\"(col0 VARCHAR, col1 VARCHAR) -> BOOLEAN"]),
1083 (
1084 "regexp_replace",
1085 &[
1086 "regexp_replace(string VARCHAR, regex VARCHAR, replacement VARCHAR) -> VARCHAR",
1087 "regexp_replace(string VARCHAR, regex VARCHAR, replacement VARCHAR, \"options\" VARCHAR) -> VARCHAR",
1088 ],
1089 ),
1090 (
1091 "regexp_matches",
1092 &[
1093 "regexp_matches(string VARCHAR, regex VARCHAR) -> BOOLEAN",
1094 "regexp_matches(string VARCHAR, regex VARCHAR, \"options\" VARCHAR) -> BOOLEAN",
1095 ],
1096 ),
1097 (
1098 "regexp_full_match",
1099 &[
1100 "regexp_full_match(string VARCHAR, regex VARCHAR) -> BOOLEAN",
1101 "regexp_full_match(string VARCHAR, regex VARCHAR, \"options\" VARCHAR) -> BOOLEAN",
1102 ],
1103 ),
1104 // Both overloads of each interval constructor, including the BIGINT one this engine does not
1105 // have a row for, because the list is what DuckDB accepts and somebody reading it is being told
1106 // what to write rather than what is built here.
1107 ("to_years", &["to_years(col0 INTEGER) -> INTERVAL", "to_years(col0 BIGINT) -> INTERVAL"]),
1108 ("to_months", &["to_months(col0 INTEGER) -> INTERVAL", "to_months(col0 BIGINT) -> INTERVAL"]),
1109 (
1110 "to_quarters",
1111 &["to_quarters(col0 INTEGER) -> INTERVAL", "to_quarters(col0 BIGINT) -> INTERVAL"],
1112 ),
1113 (
1114 "to_decades",
1115 &["to_decades(col0 INTEGER) -> INTERVAL", "to_decades(col0 BIGINT) -> INTERVAL"],
1116 ),
1117 (
1118 "to_centuries",
1119 &["to_centuries(col0 INTEGER) -> INTERVAL", "to_centuries(col0 BIGINT) -> INTERVAL"],
1120 ),
1121 (
1122 "to_millennia",
1123 &["to_millennia(col0 INTEGER) -> INTERVAL", "to_millennia(col0 BIGINT) -> INTERVAL"],
1124 ),
1125 ("to_days", &["to_days(col0 INTEGER) -> INTERVAL", "to_days(col0 BIGINT) -> INTERVAL"]),
1126 ("to_weeks", &["to_weeks(col0 INTEGER) -> INTERVAL", "to_weeks(col0 BIGINT) -> INTERVAL"]),
1127 // The five that have one overload each, which is why they are not in the pattern above. The
1128 // three that land in microseconds are declared over a BIGINT and never over an INTEGER, since
1129 // an hour of INTEGER hours does not fit the field anyway.
1130 ("to_hours", &["to_hours(col0 BIGINT) -> INTERVAL"]),
1131 ("to_minutes", &["to_minutes(col0 BIGINT) -> INTERVAL"]),
1132 ("to_microseconds", &["to_microseconds(col0 BIGINT) -> INTERVAL"]),
1133 ("to_seconds", &["to_seconds(col0 DOUBLE) -> INTERVAL"]),
1134 ("to_milliseconds", &["to_milliseconds(col0 DOUBLE) -> INTERVAL"]),
1135 // Four overloads of which this engine has two. The STRUCT one is `x.y`, which the transformer
1136 // writes as `struct_extract`, and a TUPLE is the positional half of the same idea.
1137 (
1138 "array_extract",
1139 &[
1140 "array_extract(\"array\" T[], \"index\" BIGINT) -> T",
1141 "array_extract(col0 VARCHAR, col1 BIGINT) -> VARCHAR",
1142 "array_extract(\"struct\" STRUCT, \"key\" VARCHAR) -> ANY",
1143 "array_extract(\"tuple\" TUPLE, \"index\" BIGINT) -> ANY",
1144 ],
1145 ),
1146 (
1147 "array_slice",
1148 &[
1149 "array_slice(col0 ANY, col1 ANY, col2 ANY) -> ANY",
1150 "array_slice(col0 ANY, col1 ANY, col2 ANY, col3 BIGINT) -> ANY",
1151 ],
1152 ),
1153 ("typeof", &["typeof(col0 ANY) -> VARCHAR"]),
1154 ("current_setting", &["current_setting(setting_name VARCHAR) -> ANY"]),
1155];
1156
1157/// What one element of a subscripted value is, or `None` for a value that cannot be subscripted.
1158///
1159/// A string is subscripted by character and a character is a string, so `'abcdef'[2]` is a VARCHAR
1160/// and not a type of its own. An untyped null takes the VARCHAR overload, which was measured:
1161/// `typeof(array_extract(NULL, 1))` is VARCHAR on the pinned binary while
1162/// `typeof(array_slice(NULL, 1, 2))` is NULL, so the null goes here and the slice keeps the type it
1163/// was handed.
1164///
1165/// A STRUCT is subscripted by name rather than by position and is not one of these. `x.y` is
1166/// `struct_extract(x, 'y')` by the time it leaves the transformer, which is a function this table
1167/// does not have yet, so that call fails with the name of the function it is missing.
1168fn element_of(ty: &LogicalType) -> Option<LogicalType> {
1169 match ty {
1170 LogicalType::Varchar | LogicalType::Null => Some(LogicalType::Varchar),
1171 LogicalType::List(element) | LogicalType::Array(element, _) => Some((**element).clone()),
1172 _ => None,
1173 }
1174}
1175
1176/// The cast list for a shape that fixes the leading arguments and leaves the others as they are.
1177fn leading(count: usize, first: Fixed, arguments: &[LogicalType]) -> Vec<LogicalType> {
1178 let mut cast_to = arguments.to_vec();
1179 for head in cast_to.iter_mut().take(count) {
1180 *head = first.ty();
1181 }
1182 cast_to
1183}
1184
1185/// The type of a decimal product, or `None` when no decimal is involved and promotion decides.
1186///
1187/// A product of `DECIMAL(a,b)` and `DECIMAL(c,d)` needs `a + c` digits with `b + d` after the
1188/// point, because the largest pair of inputs multiplies to exactly that, and an integer counts as
1189/// the decimal that holds it. The rest is where upstream stops widening, and both of the places it
1190/// stops were read off `v2.0.0-dev84237` across a grid of seventy two pairs rather than reasoned
1191/// about:
1192///
1193/// A product of two operands that each fit in sixty four bits is kept there when it can be. So
1194/// `DECIMAL(10,0) * DECIMAL(10,0)` is `DECIMAL(18,0)` rather than `DECIMAL(20,0)`, which is a type
1195/// that cannot hold every product of its own inputs and raises an overflow on the ones it cannot,
1196/// and `DECIMAL(18,17) * DECIMAL(10,0)` is `DECIMAL(18,17)`. It is kept there only while a digit is
1197/// left in front of the point, which is why `DECIMAL(10,9) * DECIMAL(10,9)` is `DECIMAL(20,18)` and
1198/// not `DECIMAL(18,18)`: at eighteen decimal places there is no room for the integer part, so the
1199/// answer moves to the wider representation instead.
1200///
1201/// Past that, the width stops at the widest decimal there is and the scale does not, because a
1202/// scale that had to shrink would be an answer with digits missing from the end of it rather than a
1203/// narrower one. A scale of more than thirty eight is refused at bind time with upstream's own
1204/// sentence, since there is no type to put the answer in.
1205fn product(arguments: &[LogicalType]) -> Result<Option<LogicalType>> {
1206 let mut decimals = false;
1207 let (mut width, mut scale, mut widest) = (0u8, 0u8, 0u8);
1208 for ty in arguments {
1209 decimals |= matches!(ty, LogicalType::Decimal { .. });
1210 let Some((one, held)) = ty.decimal_shape() else { return Ok(None) };
1211 width = width.saturating_add(one);
1212 scale = scale.saturating_add(held);
1213 widest = widest.max(one);
1214 }
1215 if !decimals {
1216 return Ok(None);
1217 }
1218 if scale > MAX_DECIMAL_WIDTH {
1219 return Err(Error::out_of_range(format!(
1220 "Needed scale {scale} to accurately represent the multiplication result, but this is out of range of the DECIMAL type. Max scale is {MAX_DECIMAL_WIDTH}; could not perform an accurate multiplication. Either add a cast to DOUBLE, or add an explicit cast to a decimal with a lower scale."
1221 )));
1222 }
1223 if widest <= WIDEST_SIXTY_FOUR_BIT
1224 && width > WIDEST_SIXTY_FOUR_BIT
1225 && scale < WIDEST_SIXTY_FOUR_BIT
1226 {
1227 width = WIDEST_SIXTY_FOUR_BIT;
1228 }
1229 Ok(Some(LogicalType::Decimal { width: width.min(MAX_DECIMAL_WIDTH), scale }))
1230}
1231
1232/// The widest decimal that is still eight bytes a value, which is where a product stops widening.
1233const WIDEST_SIXTY_FOUR_BIT: u8 = 18;
1234
1235/// The type an addition or a subtraction produces from what its operands promote to.
1236///
1237/// A decimal gains the one digit an addition can carry into and everything else is unchanged. At
1238/// the maximum width there is nowhere left to widen into, so the type stays where it is and the
1239/// overflow is raised on the row that overflows rather than on every query that could.
1240///
1241/// Measured on `v2.0.0-dev84237`, which is where each of these numbers comes from:
1242/// `DECIMAL(18,0) + DECIMAL(18,0)` is `DECIMAL(19,0)`, `DECIMAL(38,0) + DECIMAL(38,0)` is
1243/// `DECIMAL(38,0)`, `2.0 + 1::INTEGER` is `DECIMAL(12,1)` and `DECIMAL(18,0) - DECIMAL(4,2)` is
1244/// `DECIMAL(21,2)`. A modulo, a negation and `abs` do not widen and keep [`Shape::Promoted`] for
1245/// that reason, and a product widens by a rule of its own, which is [`product`].
1246fn carrying(common: LogicalType) -> LogicalType {
1247 match common {
1248 LogicalType::Decimal { width, scale } if width < MAX_DECIMAL_WIDTH => {
1249 LogicalType::Decimal { width: width + 1, scale }
1250 }
1251 other => other,
1252 }
1253}
1254
1255/// What a sum of this type accumulates into.
1256///
1257/// Summing a column of `INTEGER` overflows an `INTEGER` after 2^31 of them and there is no useful
1258/// error to raise at that point, so the accumulator is the widest integer there is and the answer
1259/// is right. A float sums into a double for the same reason and a double stays a double, since
1260/// there is nothing wider to go to.
1261fn accumulator(ty: &LogicalType) -> LogicalType {
1262 if ty.is_integer() {
1263 LogicalType::HugeInt
1264 } else if *ty == LogicalType::Float {
1265 LogicalType::Double
1266 } else {
1267 ty.clone()
1268 }
1269}
1270
1271fn promote_all(name: &str, arguments: &[LogicalType]) -> Result<LogicalType> {
1272 // Only reachable for a signature whose arity allows no arguments and whose shape promotes,
1273 // which is a combination the table does not contain and which the test below holds it to.
1274 let mut common = match arguments.first() {
1275 Some(first) => first.clone(),
1276 None => {
1277 return Err(Error::internal(format!("{name} promotes over no arguments")));
1278 }
1279 };
1280 for ty in &arguments[1..] {
1281 common = common.promote(ty).ok_or_else(|| {
1282 Error::binder(format!(
1283 "No function matches the given name and argument types '{name}({})'. You might need to add explicit type casts.",
1284 arguments.iter().map(ToString::to_string).collect::<Vec<_>>().join(", ")
1285 ))
1286 })?;
1287 }
1288 // Every argument was a null literal, which has no type. Untyped null is not a type an executor
1289 // can hold a vector of, so it becomes an integer, which is what DuckDB does with `SELECT NULL`.
1290 if common == LogicalType::Null {
1291 common = LogicalType::Integer;
1292 }
1293 Ok(common)
1294}
1295
1296fn find(name: &str) -> Option<&'static Entry> {
1297 let name = canonical(name);
1298 TABLE.iter().find(|entry| entry.name.eq_ignore_ascii_case(name))
1299}
1300
1301/// One overload of one function, as `duckdb_functions()` reports it.
1302///
1303/// An overload here is a name and an argument count, because that is what an entry in this crate's
1304/// table has one of each. Upstream has an overload per pair of argument types instead and so reports
1305/// 44 rows for `+`, and `types` is where the difference shows up. See [`function_rows`].
1306#[derive(Debug, Clone, PartialEq, Eq)]
1307pub struct FunctionRow {
1308 /// The name as it was written, which is the alias for an alias.
1309 pub name: &'static str,
1310 /// Scalar or aggregate.
1311 pub kind: FunctionKind,
1312 /// The name this one resolves to, and `None` for a name that is its own.
1313 pub alias_of: Option<&'static str>,
1314 /// One per argument, in order.
1315 pub types: Vec<&'static str>,
1316 /// What the call produces.
1317 pub returns: &'static str,
1318 /// The type of the trailing variadic argument, for the names that take one.
1319 pub varargs: Option<&'static str>,
1320}
1321
1322/// Every name in the table and every argument count it takes, for `duckdb_functions()`.
1323///
1324/// The types here are declared types and not resolved ones, which is the whole difference between
1325/// this table and upstream's. The table in this module resolves by shape: `+` is one entry saying
1326/// both arguments promote and the result is what they promote to, where upstream carries an entry
1327/// per pair of numeric types because it carries an implementation per pair. So upstream reports 44
1328/// rows for `+` naming concrete types and this reports two, one per arity, with the type variable.
1329///
1330/// `T` is upstream's own spelling for an argument whose type the call decides, which it uses for
1331/// `list_extract` and `lag` and the rest of the generic functions, and it means the same thing here:
1332/// every argument spelled `T` in one row is the same type as every other. `ANY` is the weaker one
1333/// and means the argument is not constrained and not tied to the others, which is what `count(x)`
1334/// takes. A return of `ANY` means the type is decided by the arguments in a way a name cannot say,
1335/// which is where `sum` is, since it promotes and then widens an integer to the accumulator.
1336///
1337/// Rows come out in the order the table is written in, which is by family. The caller sorts.
1338///
1339/// [`resolve`]: crate::signature::resolve
1340#[must_use]
1341pub fn function_rows() -> Vec<FunctionRow> {
1342 let mut rows = Vec::new();
1343 for entry in TABLE {
1344 for count in entry.arity.every_count() {
1345 let (types, returns) = entry.shape.declared(count);
1346 rows.push(FunctionRow {
1347 name: entry.name,
1348 kind: entry.kind,
1349 alias_of: None,
1350 types,
1351 returns,
1352 varargs: entry.arity.open().then(|| entry.shape.declared(1).0[0]),
1353 });
1354 }
1355 }
1356 // An alias is a row of its own with the same shape, because a client reading this table to find
1357 // out whether `len` works wants a row for `len`. Upstream does the same and fills `alias_of`
1358 // with the name it resolves to, which is how this crate's list was read off in the first place.
1359 for (alias, real) in ALIASES {
1360 let mut aliased: Vec<FunctionRow> = rows
1361 .iter()
1362 .filter(|row| row.name == *real)
1363 .map(|row| FunctionRow { name: alias, alias_of: Some(real), ..row.clone() })
1364 .collect();
1365 rows.append(&mut aliased);
1366 }
1367 rows
1368}
1369
1370impl Arity {
1371 /// Every argument count this accepts, with an open end reported as its shortest form.
1372 ///
1373 /// An open end is `concat` and friends, which take any number, and the row for one says so in
1374 /// `varargs` rather than by having a row per count up to some number nobody picked.
1375 fn every_count(self) -> Vec<usize> {
1376 match self {
1377 Self::Exactly(count) => vec![count],
1378 Self::Between(least, Some(most)) => (least..=most).collect(),
1379 Self::Between(least, None) => vec![least],
1380 Self::OneOf(counts) => counts.to_vec(),
1381 }
1382 }
1383
1384 /// Whether the count has no upper end.
1385 const fn open(self) -> bool {
1386 matches!(self, Self::Between(_, None))
1387 }
1388}
1389
1390impl Fixed {
1391 /// The name this type goes by in a catalog table, which is the name a cast spells.
1392 const fn name(self) -> &'static str {
1393 match self {
1394 Self::Boolean => "BOOLEAN",
1395 Self::Integer => "INTEGER",
1396 Self::BigInt => "BIGINT",
1397 Self::Double => "DOUBLE",
1398 Self::Varchar => "VARCHAR",
1399 Self::Date => "DATE",
1400 Self::Time => "TIME",
1401 Self::TimeTz => "TIME WITH TIME ZONE",
1402 Self::Timestamp => "TIMESTAMP",
1403 Self::TimestampTz => "TIMESTAMP WITH TIME ZONE",
1404 Self::Interval => "INTERVAL",
1405 }
1406 }
1407}
1408
1409/// The type variable, for an argument whose type the call decides and that every other argument
1410/// spelled the same way has to agree with.
1411const SAME: &str = "T";
1412
1413/// An argument that is not constrained and is not tied to the others, or a result that the
1414/// arguments decide in a way no name can say.
1415const ANY: &str = "ANY";
1416
1417impl Shape {
1418 /// What the arguments and the result are declared to be, at this argument count.
1419 ///
1420 /// Not what a call resolves to. A shape that promotes says `T` here and works out the real type
1421 /// in [`resolve`] from what was passed, and a shape that widens a decimal says `ANY` for the
1422 /// result because the width is not in the name.
1423 fn declared(self, count: usize) -> (Vec<&'static str>, &'static str) {
1424 let all = |name: &'static str| vec![name; count];
1425 let leading = |taken: usize, first: &'static str, rest: &'static str| {
1426 (0..count).map(|at| if at < taken { first } else { rest }).collect::<Vec<_>>()
1427 };
1428 match self {
1429 // Promoting says `T` and the result is that same `T`, exactly.
1430 Self::Promoted | Self::PromotedToFirst => (all(SAME), SAME),
1431 // Promoting and then moving: a decimal product is as wide as both operands, a decimal
1432 // quotient is a double, a decimal sum gains a carry digit and an integer sum widens to
1433 // the accumulator. The arguments still meet at one type and the result is no longer it.
1434 Self::Multiplied
1435 | Self::Divided
1436 | Self::Slashed
1437 | Self::PromotedWithCarry
1438 | Self::Accumulated => (all(SAME), ANY),
1439 Self::PromotedTo(fixed) => (all(SAME), fixed.name()),
1440 // The floor is what a shape that widens is declared as, which is the overload upstream
1441 // lists first and the one a call with nothing to say about its arguments lands on.
1442 Self::FixedTo(from, to)
1443 | Self::Exact(from, to)
1444 | Self::Widened(from, to)
1445 | Self::WidenedTogether(from, to) => (all(from.name()), to.name()),
1446 Self::AnyTo(fixed) => (all(ANY), fixed.name()),
1447 Self::LeadingFixedTo(taken, first, to) => {
1448 (leading(taken, first.name(), ANY), to.name())
1449 }
1450 Self::LeadingFixedToLast(first) => (leading(1, first.name(), SAME), SAME),
1451 // A subscript takes a string or a list and a whole number, and the whole number is not
1452 // cast to one, which is why it is spelled out rather than left as `ANY`.
1453 Self::Extracted => (leading(1, SAME, "BIGINT"), ANY),
1454 Self::Sliced => (leading(1, SAME, "BIGINT"), SAME),
1455 Self::TextThenIndex(taken, to) => {
1456 (leading(taken, Fixed::Varchar.name(), "BIGINT"), to.name())
1457 }
1458 // One overload with an `ANY` return, which is the pin's row for it. The name decides
1459 // the type and a name is not something a signature can hold.
1460 Self::Setting => (all(Fixed::Varchar.name()), ANY),
1461 // No arguments, so `all` is empty whatever it is handed and only the result is named.
1462 Self::Constant(fixed) => (Vec::new(), fixed.name()),
1463 }
1464 }
1465}
1466
1467/// The name a function is in [`TABLE`] under, which is its own name unless it is an alias.
1468///
1469/// Aliases are resolved here rather than by a second row in the table, so that [`Resolved::name`]
1470/// is always the canonical name and the plan, the executor and every kernel below it see one name
1471/// per function. A kernel that had to know `len` is `length` would be a kernel with a second place
1472/// for the two to drift apart.
1473///
1474/// The list is DuckDB's, read off `duckdb_functions()` where `alias_of` is set, and it is only ever
1475/// as long as the table it points into. There is no point aliasing a name onto a function this
1476/// engine does not have yet, because the error would move from a missing function to a missing
1477/// function under a different name.
1478fn canonical(name: &str) -> &str {
1479 ALIASES
1480 .iter()
1481 .find(|(alias, _)| alias.eq_ignore_ascii_case(name))
1482 .map_or(name, |(_, real)| *real)
1483}
1484
1485/// Every other name DuckDB accepts for a function already in [`TABLE`].
1486///
1487/// `strlen` is deliberately not here. Upstream counts bytes with it and characters with `length`,
1488/// so it is a different function and it has a row of its own.
1489/// The three subscript spellings point the way the transformer writes them rather than the way
1490/// `duckdb_functions()` has them. Upstream is `array_slice` aliased onto `list_slice`, and
1491/// `array_extract` and `list_extract` are two functions there rather than one, differing in the
1492/// overloads they carry for a STRUCT and a TUPLE. Neither of those is here, so they are one function
1493/// here, and the name it is under is the one a bracket produces, which is what keeps the message a
1494/// bracket produces word for word the reference's.
1495///
1496/// What that costs is the same thing every row below costs: the message names the canonical spelling
1497/// and not the written one, so `list_slice(1, 2, 3)` says `array_slice` here where upstream says
1498/// `list_slice`, exactly as `len(1)` says `length`.
1499const ALIASES: &[(&str, &str)] = &[
1500 ("len", "length"),
1501 ("char_length", "length"),
1502 ("character_length", "length"),
1503 ("lcase", "lower"),
1504 ("ucase", "upper"),
1505 ("mean", "avg"),
1506 ("list_extract", "array_extract"),
1507 ("list_element", "array_extract"),
1508 ("list_slice", "array_slice"),
1509];
1510
1511#[cfg(test)]
1512mod tests {
1513 use super::*;
1514
1515 #[test]
1516 fn arithmetic_returns_what_its_operands_promote_to() {
1517 let resolved = resolve("+", &[LogicalType::Integer, LogicalType::BigInt])
1518 .expect("an integer and a bigint add");
1519 assert_eq!(resolved.returns, LogicalType::BigInt);
1520 assert_eq!(resolved.arguments, vec![LogicalType::BigInt, LogicalType::BigInt]);
1521 }
1522
1523 /// Every decimal sum in here was read off `v2.0.0-dev84237` with `typeof`, per #243.
1524 ///
1525 /// The last one is the case the rule exists for. Two `DECIMAL(18,0)` hold numbers that add to
1526 /// nineteen digits, and a result type of eighteen means the largest pair of inputs the operator
1527 /// accepts is a pair it cannot answer.
1528 #[test]
1529 fn a_decimal_sum_is_a_digit_wider_than_what_its_operands_promote_to() {
1530 let decimal = |width, scale| LogicalType::Decimal { width, scale };
1531 let sum = |left: LogicalType, right: LogicalType| {
1532 resolve("+", &[left, right]).expect("adds").returns
1533 };
1534 assert_eq!(sum(decimal(18, 0), decimal(18, 0)), decimal(19, 0));
1535 assert_eq!(sum(decimal(2, 1), LogicalType::Integer), decimal(12, 1));
1536 assert_eq!(sum(decimal(18, 0), decimal(4, 2)), decimal(21, 2));
1537 assert_eq!(sum(decimal(4, 2), LogicalType::BigInt), decimal(22, 2));
1538 assert_eq!(sum(decimal(4, 2), LogicalType::UBigInt), decimal(23, 2));
1539 assert_eq!(sum(decimal(4, 2), LogicalType::HugeInt), decimal(38, 2));
1540 // Both sides are cast to the answer's type, because the kernel underneath adds two runs of
1541 // the same width and the carry digit can move the answer into a wider one.
1542 let resolved = resolve("-", &[decimal(18, 0), decimal(18, 0)]).expect("subtracts");
1543 assert_eq!(resolved.arguments, vec![decimal(19, 0), decimal(19, 0)]);
1544 }
1545
1546 /// At the maximum width there is nowhere to carry into, so the type stops and the row raises.
1547 #[test]
1548 fn a_decimal_sum_at_the_widest_decimal_stays_there() {
1549 let widest = LogicalType::Decimal { width: MAX_DECIMAL_WIDTH, scale: 0 };
1550 let resolved = resolve("+", &[widest.clone(), widest.clone()]).expect("adds");
1551 assert_eq!(resolved.returns, widest);
1552 }
1553
1554 /// Negation cannot carry, and neither can anything that is not an addition.
1555 ///
1556 /// `-1.50` is a `DECIMAL(4,2)` upstream and so is `abs(-1.50)`, and `5.50 % 3` is a
1557 /// `DECIMAL(12,2)`, which is the promotion with no digit added to it.
1558 #[test]
1559 fn nothing_but_a_two_sided_addition_gains_a_digit() {
1560 let decimal = |width, scale| LogicalType::Decimal { width, scale };
1561 assert_eq!(resolve("-", &[decimal(4, 2)]).expect("negates").returns, decimal(4, 2));
1562 assert_eq!(resolve("+", &[decimal(4, 2)]).expect("is unary plus").returns, decimal(4, 2));
1563 assert_eq!(resolve("abs", &[decimal(4, 2)]).expect("has a size").returns, decimal(4, 2));
1564 assert_eq!(
1565 resolve("%", &[decimal(4, 2), LogicalType::Integer]).expect("divides").returns,
1566 decimal(12, 2)
1567 );
1568 }
1569
1570 /// Every product in here was read off `v2.0.0-dev84237` with `typeof`, per #243.
1571 ///
1572 /// The first three are the plain rule, the next two are the pair that stays in sixty four bits
1573 /// and the pair that does not because it has no digit left in front of the point, and the last
1574 /// is the width running into the widest decimal there is while the scale does not move.
1575 #[test]
1576 fn a_decimal_product_is_as_wide_as_both_of_its_operands_together() {
1577 let decimal = |width, scale| LogicalType::Decimal { width, scale };
1578 let times = |left: LogicalType, right: LogicalType| {
1579 resolve("*", &[left, right]).expect("multiplies").returns
1580 };
1581 assert_eq!(times(decimal(4, 2), decimal(4, 2)), decimal(8, 4));
1582 assert_eq!(times(decimal(4, 2), LogicalType::BigInt), decimal(23, 2));
1583 assert_eq!(times(decimal(18, 3), LogicalType::Integer), decimal(18, 3));
1584 assert_eq!(times(decimal(12, 6), decimal(12, 6)), decimal(18, 12));
1585 assert_eq!(times(decimal(10, 9), decimal(10, 9)), decimal(20, 18));
1586 assert_eq!(times(decimal(18, 17), decimal(18, 17)), decimal(36, 34));
1587 assert_eq!(times(decimal(20, 10), decimal(20, 10)), decimal(38, 20));
1588 // Nothing that is not a decimal goes near any of this.
1589 assert_eq!(times(LogicalType::Integer, LogicalType::Integer), LogicalType::Integer);
1590 }
1591
1592 /// Each side takes the answer's width and keeps its own scale, which is what the kernel needs.
1593 ///
1594 /// The unscaled values then multiply into the answer with nothing rescaled on either side of
1595 /// the operator, which a cast of both sides to the answer's scale would not give.
1596 #[test]
1597 fn a_decimal_product_casts_its_operands_to_the_width_of_the_answer() {
1598 let decimal = |width, scale| LogicalType::Decimal { width, scale };
1599 let resolved = resolve("*", &[decimal(4, 2), LogicalType::BigInt]).expect("multiplies");
1600 assert_eq!(resolved.arguments, vec![decimal(23, 2), decimal(23, 0)]);
1601 }
1602
1603 /// There is no type to put the answer in, so it is refused at bind time rather than truncated.
1604 #[test]
1605 fn a_product_that_needs_more_than_thirty_eight_decimal_places_is_refused() {
1606 let wide = LogicalType::Decimal { width: 30, scale: 30 };
1607 let error = resolve("*", &[wide.clone(), wide]).expect_err("has nowhere to put the scale");
1608 assert!(error.to_string().contains("Max scale is 38"), "{error}");
1609 }
1610
1611 /// The one arithmetic result that is not the promotion, and it is DuckDB's rule rather than an
1612 /// invention: `7 / 2` is 3.5 and `7 // 2` is 3.
1613 #[test]
1614 fn division_gives_a_double_and_integer_division_does_not() {
1615 let divide = resolve("/", &[LogicalType::Integer, LogicalType::Integer]).expect("divides");
1616 assert_eq!(divide.returns, LogicalType::Double);
1617 let integer =
1618 resolve("//", &[LogicalType::Integer, LogicalType::Integer]).expect("divides");
1619 assert_eq!(integer.returns, LogicalType::Integer);
1620 }
1621
1622 /// `//` is integer division only when there are integers on both sides of it, which was
1623 /// measured: `7.5 // 2.5` is the DOUBLE 3.0 upstream and `7.5 // 2` is 3.75, so it neither
1624 /// stays a decimal nor truncates what it divided.
1625 #[test]
1626 fn integer_division_of_anything_but_integers_is_ordinary_division() {
1627 let decimal = LogicalType::Decimal { width: 4, scale: 2 };
1628 let divides = |left: LogicalType, right: LogicalType| {
1629 let resolved = resolve("//", &[left, right]).expect("divides");
1630 (resolved.arguments, resolved.returns)
1631 };
1632 let double = || (vec![LogicalType::Double; 2], LogicalType::Double);
1633 assert_eq!(divides(decimal.clone(), decimal.clone()), double());
1634 assert_eq!(divides(decimal.clone(), LogicalType::Integer), double());
1635 assert_eq!(divides(LogicalType::Integer, decimal), double());
1636 assert_eq!(divides(LogicalType::Double, LogicalType::Double), double());
1637 // A float stays a float, so this is a rule about decimals rather than about width.
1638 assert_eq!(
1639 divides(LogicalType::Float, LogicalType::Float),
1640 (vec![LogicalType::Float; 2], LogicalType::Float)
1641 );
1642 assert_eq!(
1643 divides(LogicalType::Integer, LogicalType::BigInt),
1644 (vec![LogicalType::BigInt; 2], LogicalType::BigInt)
1645 );
1646 assert_eq!(
1647 divides(LogicalType::HugeInt, LogicalType::HugeInt),
1648 (vec![LogicalType::HugeInt; 2], LogicalType::HugeInt)
1649 );
1650 }
1651
1652 /// An alias has to come back under the real name, because the name on [`Resolved`] is what the
1653 /// plan interns and what every kernel below it matches on. SQL is case insensitive here, so the
1654 /// shouted spelling has to land in the same place.
1655 #[test]
1656 fn an_alias_resolves_to_the_function_it_is_an_alias_of() {
1657 for (alias, real) in ALIASES {
1658 assert_eq!(canonical(alias), *real);
1659 assert_eq!(canonical(&alias.to_uppercase()), *real);
1660 }
1661 let resolved = resolve("LEN", &[LogicalType::Varchar]).expect("len resolves");
1662 assert_eq!(resolved.name, "length");
1663 assert_eq!(resolved.returns, LogicalType::BigInt);
1664 }
1665
1666 /// Every alias has to point at a row that exists, or the error a caller gets moves from a
1667 /// missing function to a missing function under another name, which is worse.
1668 #[test]
1669 fn every_alias_points_at_a_real_function() {
1670 for (alias, real) in ALIASES {
1671 assert!(
1672 TABLE.iter().any(|entry| entry.name == *real),
1673 "{alias} points at {real}, which is not in the table"
1674 );
1675 }
1676 }
1677
1678 /// DuckDB refuses a string function anything that is not already a string, and the whole point
1679 /// of refusing is the message, so the message is what this checks.
1680 #[test]
1681 fn a_string_function_refuses_a_type_that_is_not_a_string() {
1682 let error = resolve("lower", &[LogicalType::Date]).expect_err("lower takes strings");
1683 assert_eq!(
1684 error.to_string(),
1685 "Binder Error: No function matches the given name and argument types 'lower(DATE)'. \
1686 You might need to add explicit type casts.\n\tCandidate functions:\n\tlower(col0 \
1687 VARCHAR) -> VARCHAR\n"
1688 );
1689 for name in ["upper", "length", "strlen"] {
1690 assert!(resolve(name, &[LogicalType::Integer]).is_err(), "{name} took an integer");
1691 }
1692 for name in ["~~", "!~~", "~~*", "!~~*"] {
1693 let types = [LogicalType::Integer, LogicalType::Varchar];
1694 assert!(resolve(name, &types).is_err(), "{name} took an integer");
1695 }
1696 }
1697
1698 /// The wrong answer this shape was added for. `length([1,2,3])` used to cast the list to a
1699 /// string and count the nine characters of `[1, 2, 3]`, where DuckDB counts three elements.
1700 /// rudb has no list type in the executor yet, so refusing is the honest end of it for now.
1701 #[test]
1702 fn length_of_something_that_is_not_a_string_is_refused_rather_than_stringified() {
1703 let error = resolve("length", &[LogicalType::Blob]).expect_err("length takes strings");
1704 assert!(error.to_string().contains("length(col0 ANY[]) -> BIGINT"), "{error}");
1705 }
1706
1707 /// `||` is the exception and it has to stay one. `1 || 'a'` is `1a` upstream.
1708 #[test]
1709 fn concatenation_still_takes_anything_and_makes_a_string_of_it() {
1710 let resolved = resolve("||", &[LogicalType::Integer, LogicalType::Varchar])
1711 .expect("concatenation takes anything");
1712 assert_eq!(resolved.returns, LogicalType::Varchar);
1713 assert_eq!(resolved.arguments, vec![LogicalType::Varchar, LogicalType::Varchar]);
1714 }
1715
1716 /// A null literal has no type to pick an overload with, and DuckDB answers `length(NULL)` with
1717 /// NULL rather than refusing it.
1718 #[test]
1719 fn a_string_function_takes_an_untyped_null() {
1720 let resolved = resolve("length", &[LogicalType::Null]).expect("length of a null");
1721 assert_eq!(resolved.returns, LogicalType::BigInt);
1722 assert_eq!(resolved.arguments, vec![LogicalType::Varchar]);
1723 }
1724
1725 /// A candidate block for a name nothing resolves to would be a message about a function that
1726 /// does not exist, which is worse than no block at all.
1727 #[test]
1728 fn every_name_with_candidates_is_a_function_this_engine_has() {
1729 for (name, overloads) in CANDIDATES {
1730 assert!(TABLE.iter().any(|entry| entry.name == *name), "{name} has no entry");
1731 assert!(!overloads.is_empty(), "{name} has an empty candidate list");
1732 }
1733 }
1734
1735 /// `strlen` counts bytes and `length` counts characters, so it is a function and not an alias.
1736 /// This is the test that stops someone folding it into [`ALIASES`] to save a row.
1737 #[test]
1738 fn strlen_is_its_own_function_and_not_an_alias_of_length() {
1739 assert!(!ALIASES.iter().any(|(alias, _)| *alias == "strlen"));
1740 let resolved = resolve("strlen", &[LogicalType::Varchar]).expect("strlen resolves");
1741 assert_eq!(resolved.name, "strlen");
1742 assert_eq!(resolved.returns, LogicalType::BigInt);
1743 }
1744
1745 #[test]
1746 fn a_sum_accumulates_wider_than_it_reads() {
1747 assert_eq!(
1748 resolve("sum", &[LogicalType::Integer]).expect("sums").returns,
1749 LogicalType::HugeInt
1750 );
1751 assert_eq!(
1752 resolve("sum", &[LogicalType::Double]).expect("sums").returns,
1753 LogicalType::Double
1754 );
1755 assert_eq!(
1756 resolve("sum", &[LogicalType::Float]).expect("sums").returns,
1757 LogicalType::Double
1758 );
1759 }
1760
1761 #[test]
1762 fn count_takes_anything_and_returns_a_bigint() {
1763 let counted = resolve("count", &[LogicalType::Varchar]).expect("counts strings");
1764 assert_eq!(counted.returns, LogicalType::BigInt);
1765 assert_eq!(counted.arguments, vec![LogicalType::Varchar], "count does not cast its input");
1766 assert_eq!(resolve("count_star", &[]).expect("counts rows").returns, LogicalType::BigInt);
1767 }
1768
1769 /// `date_part` says double whatever it reads and `date_trunc` hands back the type it was given,
1770 /// which is two answers that one shape cannot give and is why there are two new ones. A double
1771 /// rather than a bigint because that is upstream's declared overload, and the narrowing to a
1772 /// bigint happens in the binder, where the specifier can be looked at.
1773 #[test]
1774 fn a_date_function_fixes_the_part_and_leaves_the_date_alone() {
1775 let part = resolve("date_part", &[LogicalType::Varchar, LogicalType::Timestamp])
1776 .expect("a part of a timestamp");
1777 assert_eq!(part.returns, LogicalType::Double);
1778 assert_eq!(part.arguments, vec![LogicalType::Varchar, LogicalType::Timestamp]);
1779 let truncated = resolve("date_trunc", &[LogicalType::Varchar, LogicalType::Date])
1780 .expect("a truncated date");
1781 assert_eq!(truncated.returns, LogicalType::Date);
1782 assert_eq!(truncated.arguments, vec![LogicalType::Varchar, LogicalType::Date]);
1783 }
1784
1785 /// The two constructors, and the arity with a hole in it. Two arguments is not a `make_date`
1786 /// upstream has and it is not one here either.
1787 #[test]
1788 fn a_date_is_made_from_one_number_or_from_three_and_never_from_two() {
1789 let day = resolve("make_date", &[LogicalType::Integer]).expect("days since the epoch");
1790 assert_eq!(day.returns, LogicalType::Date);
1791 assert_eq!(day.arguments, vec![LogicalType::Integer]);
1792 let civil =
1793 resolve("make_date", &vec![LogicalType::BigInt; 3]).expect("a year, a month and a day");
1794 assert_eq!(civil.returns, LogicalType::Date);
1795 assert_eq!(civil.arguments, vec![LogicalType::Integer; 3]);
1796 let error = resolve("make_date", &vec![LogicalType::Integer; 2]).unwrap_err();
1797 assert_eq!(
1798 error.message(),
1799 "No function matches the given name and argument types 'make_date(INTEGER, INTEGER)'. You might need to add explicit type casts."
1800 );
1801 }
1802
1803 #[test]
1804 fn milliseconds_since_the_epoch_are_a_timestamp() {
1805 let stamp = resolve("epoch_ms", &[LogicalType::Integer]).expect("a timestamp");
1806 assert_eq!(stamp.returns, LogicalType::Timestamp);
1807 assert_eq!(stamp.arguments, vec![LogicalType::BigInt], "the argument widens to read it");
1808 let error = resolve("epoch_ms", &[LogicalType::Varchar]).unwrap_err();
1809 assert!(error.message().contains("'epoch_ms(VARCHAR)'"), "{error}");
1810 }
1811
1812 /// The part is cast rather than checked, so a part that arrives as something other than a
1813 /// string is a string by the time the kernel sees it.
1814 #[test]
1815 fn the_part_of_a_date_function_is_cast_to_a_string() {
1816 let resolved = resolve("date_part", &[LogicalType::Integer, LogicalType::Date])
1817 .expect("the part is cast rather than refused");
1818 assert_eq!(resolved.arguments, vec![LogicalType::Varchar, LogicalType::Date]);
1819 }
1820
1821 /// The group number of an extraction has to arrive as a number, since the kernel tells the
1822 /// option string from the group by the type rather than by the position.
1823 #[test]
1824 fn an_extraction_casts_the_text_and_the_pattern_and_leaves_the_group_alone() {
1825 let resolved = resolve(
1826 "regexp_extract",
1827 &[LogicalType::Varchar, LogicalType::Varchar, LogicalType::Integer],
1828 )
1829 .expect("an extraction");
1830 assert_eq!(resolved.returns, LogicalType::Varchar);
1831 assert_eq!(
1832 resolved.arguments,
1833 vec![LogicalType::Varchar, LogicalType::Varchar, LogicalType::Integer]
1834 );
1835 let matched = resolve("regexp_matches", &[LogicalType::Varchar, LogicalType::Varchar])
1836 .expect("a match");
1837 assert_eq!(matched.returns, LogicalType::Boolean);
1838 }
1839
1840 #[test]
1841 fn a_name_that_is_not_a_function_says_so_the_way_duckdb_does() {
1842 let error = resolve("nope", &[]).expect_err("there is no function called nope");
1843 assert_eq!(
1844 error.to_string(),
1845 "Catalog Error: Scalar Function with name nope does not exist!"
1846 );
1847 }
1848
1849 #[test]
1850 fn the_wrong_number_of_arguments_is_caught() {
1851 let error = resolve("abs", &[LogicalType::Integer, LogicalType::Integer])
1852 .expect_err("abs takes one");
1853 assert!(error.message().contains("No function matches"), "{error}");
1854 }
1855
1856 #[test]
1857 fn arithmetic_on_a_string_is_refused() {
1858 let error =
1859 resolve("*", &[LogicalType::Varchar, LogicalType::Integer]).expect_err("no multiply");
1860 assert!(error.message().contains("No function matches"), "{error}");
1861 }
1862
1863 #[test]
1864 fn a_call_over_nothing_but_nulls_lands_on_a_type_an_executor_can_hold() {
1865 let resolved =
1866 resolve("+", &[LogicalType::Null, LogicalType::Null]).expect("null plus null");
1867 assert_eq!(resolved.returns, LogicalType::Integer);
1868 }
1869
1870 /// `nullif` compares at one type and answers at another, both read off the pinned binary with
1871 /// `typeof`. Per #306.
1872 #[test]
1873 fn nullif_answers_the_first_argument_and_compares_at_the_promotion() {
1874 let resolved =
1875 resolve("nullif", &[LogicalType::Integer, LogicalType::Decimal { width: 2, scale: 1 }])
1876 .expect("an integer and a decimal compare");
1877 assert_eq!(resolved.returns, LogicalType::Integer);
1878 let wide = LogicalType::Decimal { width: 11, scale: 1 };
1879 assert_eq!(resolved.arguments, vec![wide.clone(), wide]);
1880 let resolved = resolve("nullif", &[LogicalType::BigInt, LogicalType::SmallInt])
1881 .expect("two integers compare");
1882 assert_eq!(resolved.returns, LogicalType::BigInt);
1883 let resolved =
1884 resolve("nullif", &[LogicalType::Null, LogicalType::Null]).expect("two nulls compare");
1885 assert_eq!(resolved.returns, LogicalType::Integer, "there is nothing else to hand back");
1886 let error = resolve("nullif", &[LogicalType::Varchar, LogicalType::Integer])
1887 .expect_err("a string and a number have nothing in common here");
1888 assert!(error.message().contains("No function matches"), "{error}");
1889 }
1890
1891 #[test]
1892 fn an_aggregate_is_known_to_be_one() {
1893 assert_eq!(kind_of("sum"), Some(FunctionKind::Aggregate));
1894 assert_eq!(kind_of("SUM"), Some(FunctionKind::Aggregate), "names are case insensitive");
1895 assert_eq!(kind_of("abs"), Some(FunctionKind::Scalar));
1896 assert_eq!(kind_of("nope"), None);
1897 }
1898
1899 /// Two rows for one name would need a rule for which one wins, and there is no such rule yet,
1900 /// so the table having none is worth asserting rather than remembering.
1901 #[test]
1902 fn no_name_appears_twice() {
1903 let mut names: Vec<&str> = TABLE.iter().map(|entry| entry.name).collect();
1904 let count = names.len();
1905 names.sort_unstable();
1906 names.dedup();
1907 assert_eq!(names.len(), count, "a name is in the table twice");
1908 }
1909
1910 #[test]
1911 fn every_entry_resolves_at_every_count_it_accepts() {
1912 for entry in TABLE {
1913 // The one row that is meant not to resolve, because the binder answers the call before
1914 // it gets here and the only way here is the case upstream refuses. It has a test of its
1915 // own below rather than an exception with nothing behind it.
1916 if entry.shape == Shape::Setting {
1917 continue;
1918 }
1919 for count in entry.arity.counts() {
1920 // A shape that names the type it wants is asked for it, since `chr` wants an
1921 // INTEGER and refuses a string the way upstream does.
1922 let ty = match (entry.numeric_only, entry.shape) {
1923 (
1924 _,
1925 Shape::Exact(argument, _)
1926 | Shape::Widened(argument, _)
1927 | Shape::WidenedTogether(argument, _),
1928 ) => argument.ty(),
1929 (true, _) => LogicalType::Integer,
1930 (false, _) => LogicalType::Varchar,
1931 };
1932 let mut arguments = vec![ty; count];
1933 // A subscript and a substring are the shapes whose arguments are not all alike. The
1934 // leading ones are the string or the list and everything after them is a whole
1935 // number, so a row of strings is not a call either one accepts and not a call worth
1936 // asserting it accepts.
1937 let leading = match entry.shape {
1938 Shape::Extracted | Shape::Sliced => 1,
1939 Shape::TextThenIndex(leading, _) => leading,
1940 _ => count,
1941 };
1942 for bound in arguments.iter_mut().skip(leading) {
1943 *bound = LogicalType::BigInt;
1944 }
1945 resolve(entry.name, &arguments).unwrap_or_else(|error| {
1946 panic!("{} does not resolve at {count} arguments: {error}", entry.name)
1947 });
1948 }
1949 }
1950 }
1951
1952 /// The three answers the pin gives a call to `current_setting`, read off `v2.0.0-dev84237`.
1953 ///
1954 /// The right number of arguments and a name the binder could not fold is the constant
1955 /// expression sentence, and a wrong number is the ordinary arity error with the one overload
1956 /// listed under it. The folded case is not here because it never reaches this table.
1957 #[test]
1958 fn a_setting_read_from_a_column_is_refused_in_the_pins_words() {
1959 let error = resolve("current_setting", &[LogicalType::Varchar]).expect_err("is refused");
1960 assert_eq!(
1961 error.to_string(),
1962 "Binder Error: The \"setting_name\" argument in function \"current_setting\" must be a constant expression"
1963 );
1964 let none = resolve("current_setting", &[]).expect_err("takes one argument");
1965 assert_eq!(
1966 none.to_string(),
1967 "Binder Error: No function matches the given name and argument types 'current_setting()'. \
1968 You might need to add explicit type casts.\n\tCandidate functions:\n\tcurrent_setting(setting_name VARCHAR) -> ANY\n"
1969 );
1970 }
1971
1972 /// One row with an `ANY` return, which is what the pin's `duckdb_functions()` says about it.
1973 #[test]
1974 fn a_setting_is_declared_over_a_string_and_returns_anything() {
1975 let row = function_rows()
1976 .into_iter()
1977 .find(|row| row.name == "current_setting")
1978 .expect("a row for it");
1979 assert_eq!(row.types, ["VARCHAR"]);
1980 assert_eq!(row.returns, "ANY");
1981 assert_eq!(row.varargs, None);
1982 }
1983
1984 /// A signature that promotes over its arguments and accepts none of them would reach the
1985 /// internal error in `promote_all`, which is a message no user should ever see.
1986 #[test]
1987 fn nothing_that_promotes_accepts_no_arguments() {
1988 for entry in TABLE {
1989 let promotes =
1990 matches!(entry.shape, Shape::Promoted | Shape::PromotedTo(_) | Shape::Accumulated);
1991 assert!(
1992 !(promotes && entry.arity.least() == 0),
1993 "{} promotes over its arguments and takes none",
1994 entry.name
1995 );
1996 }
1997 }
1998
1999 /// `-` is the negation and the subtraction under one name, which is the reason arity is a
2000 /// range, so it is worth holding to.
2001 #[test]
2002 fn minus_is_both_the_negation_and_the_subtraction() {
2003 assert_eq!(
2004 resolve("-", &[LogicalType::Integer]).expect("negates").returns,
2005 LogicalType::Integer
2006 );
2007 assert_eq!(
2008 resolve("-", &[LogicalType::Integer, LogicalType::BigInt]).expect("subtracts").returns,
2009 LogicalType::BigInt
2010 );
2011 assert!(
2012 resolve("-", &vec![LogicalType::Integer; 3]).is_err(),
2013 "three is not an arity minus has"
2014 );
2015 }
2016}