# Coverage

<style>
main table, main .gd-table-scroll > table {
  table-layout: fixed; width: 100% !important; min-width: 0; font-size: 0.85rem;
}
main table th, main table td {
  overflow-wrap: anywhere; white-space: normal; vertical-align: top;
}
main table code { white-space: normal; }
main :not(pre) > code { font-size: 0.875em !important; line-height: inherit; }
main section.level2 {
  border-top: 1px solid var(--bs-border-color, #dee2e6);
  margin-top: 2.25rem; padding-top: 0.75rem;
}
main .ledger-meta {
  font-style: italic; font-size: 0.9em; color: var(--bs-secondary-color, #6c757d);
}
main .ledger-meta p { margin-bottom: 0.75rem; }
</style>

The checklist of [`characterization/areas.json`](https://github.com/AlexanderNenninger/substrait-lean/blob/main/characterization/areas.json): for each item, the facts that settle it on each engine and the strongest evidence among them, or `missing`. `python -m sverify_dev.facts --coverage <engine>` prints the same.

| Engine     | Items settled | Facts |
|------------|---------------|-------|
| DuckDB     | 68 of 69      | 101   |
| Polars     | 69 of 69      | 103   |
| DataFusion | 1 of 69       | 3     |
| Spark      | 69 of 69      | 71    |


# integers

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `overflow` | `+ - ×`, negate, `abs`, `MIN / -1` and integer `sum` past the declared width: raise, wrap or saturate, at which width. | fuzz: [duckdb-R6](duckdb-facts.md#duckdb-R6), [duckdb-decimal-arith](duckdb-facts.md#duckdb-decimal-arith), [duckdb-R1](duckdb-facts.md#duckdb-R1), [duckdb-R1-min](duckdb-facts.md#duckdb-R1-min), [duckdb-R15-int-arith](duckdb-facts.md#duckdb-R15-int-arith), [duckdb-R15-int-divide](duckdb-facts.md#duckdb-R15-int-divide), [duckdb-R15-int-modulus](duckdb-facts.md#duckdb-R15-int-modulus), [duckdb-int-pow](duckdb-facts.md#duckdb-int-pow) | probe: [polars-sum-int](polars-facts.md#polars-sum-int), [polars-decimal-arith](polars-facts.md#polars-decimal-arith), [polars-int-abs](polars-facts.md#polars-int-abs), [polars-int-arith](polars-facts.md#polars-int-arith), [polars-int-divide](polars-facts.md#polars-int-divide), [polars-int-mod-overflow](polars-facts.md#polars-int-mod-overflow) | missing | fuzz: [spark-sum-int](other-facts.md#spark-sum-int), [spark-decimal-arith](other-facts.md#spark-decimal-arith), [spark-decimal-negate](other-facts.md#spark-decimal-negate), [spark-int-abs](other-facts.md#spark-int-abs), [spark-int-arith](other-facts.md#spark-int-arith), [spark-int-divide](other-facts.md#spark-int-divide), [spark-int-modulus](other-facts.md#spark-int-modulus), [spark-int-pow](other-facts.md#spark-int-pow) |
| `division_type` | Integer `modulus` (and `divide`): truncated or floored. | fuzz: [duckdb-R15-double-modulus](duckdb-facts.md#duckdb-R15-double-modulus), [duckdb-R15-int-divide](duckdb-facts.md#duckdb-R15-int-divide), [duckdb-R15-int-modulus](duckdb-facts.md#duckdb-R15-int-modulus), [duckdb-R2](duckdb-facts.md#duckdb-R2), [duckdb-R3](duckdb-facts.md#duckdb-R3), [duckdb-int-div-domain](duckdb-facts.md#duckdb-int-div-domain) | probe: [polars-double-modulus](polars-facts.md#polars-double-modulus), [polars-double-scalar-divisor](polars-facts.md#polars-double-scalar-divisor), [polars-int-divide](polars-facts.md#polars-int-divide), [polars-int-modulus](polars-facts.md#polars-int-modulus) | missing | fuzz: [spark-double-modulus](other-facts.md#spark-double-modulus), [spark-int-divide](other-facts.md#spark-int-divide), [spark-int-modulus](other-facts.md#spark-int-modulus) |
| `on_division_by_zero` | A zero divisor of integers and of doubles: error, NULL, IEEE or a limit. | fuzz: [duckdb-R15-double-arith](duckdb-facts.md#duckdb-R15-double-arith), [duckdb-R4](duckdb-facts.md#duckdb-R4), [duckdb-R5](duckdb-facts.md#duckdb-R5), [duckdb-R15-int-divide](duckdb-facts.md#duckdb-R15-int-divide), [duckdb-R2](duckdb-facts.md#duckdb-R2), [duckdb-R3](duckdb-facts.md#duckdb-R3) | probe: [polars-double-divide](polars-facts.md#polars-double-divide), [polars-double-modulus](polars-facts.md#polars-double-modulus), [polars-int-divide](polars-facts.md#polars-int-divide), [polars-int-modulus](polars-facts.md#polars-int-modulus), [polars-int-true-divide](polars-facts.md#polars-int-true-divide) | missing | fuzz: [spark-double-divide](other-facts.md#spark-double-divide), [spark-double-modulus](other-facts.md#spark-double-modulus), [spark-int-divide](other-facts.md#spark-int-divide), [spark-int-modulus](other-facts.md#spark-int-modulus) |
| `min_mod_neg_one` | `MIN % -1`: 0 or a raise. | probe: [duckdb-R15-int-modulus](duckdb-facts.md#duckdb-R15-int-modulus) | probe: [polars-int-modulus](polars-facts.md#polars-int-modulus) | missing | probe: [spark-int-modulus](other-facts.md#spark-int-modulus) |
| `shift_range` | Shifts by a negative count or by the width or more, and bits shifted out. | probe: [duckdb-R15-shift-left](duckdb-facts.md#duckdb-R15-shift-left), [duckdb-R15-shift-right](duckdb-facts.md#duckdb-R15-shift-right) | probe: [polars-int-shift](polars-facts.md#polars-int-shift) | missing | fuzz: [spark-int-shift](other-facts.md#spark-int-shift) |


# decimals

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `decimal_rescale` | A result with more digits than its scale: how it rounds. | probe: [duckdb-decimal-arith](duckdb-facts.md#duckdb-decimal-arith) | probe: [polars-decimal-arith](polars-facts.md#polars-decimal-arith), [polars-decimal-casts](polars-facts.md#polars-decimal-casts) | missing | probe: [spark-decimal-arith](other-facts.md#spark-decimal-arith) |
| `decimal_result_type` | The precision and scale of decimal arithmetic and aggregates, and overflow past 38 digits. | probe: [duckdb-decimal-arith](duckdb-facts.md#duckdb-decimal-arith) | probe: [polars-decimal-arith](polars-facts.md#polars-decimal-arith) | missing | probe: [spark-decimal-arith](other-facts.md#spark-decimal-arith) |


# doubles

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `rounding` | Rounding of arithmetic and of `round` (to `d` digits too). | probe: [duckdb-avg-double](duckdb-facts.md#duckdb-avg-double), [duckdb-float-sum-order](duckdb-facts.md#duckdb-float-sum-order), [duckdb-stat-arg-types](duckdb-facts.md#duckdb-stat-arg-types), [duckdb-sum-double](duckdb-facts.md#duckdb-sum-double), [duckdb-R15-elementary](duckdb-facts.md#duckdb-R15-elementary), [duckdb-R15-round](duckdb-facts.md#duckdb-R15-round), [duckdb-float-ieee](duckdb-facts.md#duckdb-float-ieee), [duckdb-float-math-double](duckdb-facts.md#duckdb-float-math-double), [duckdb-round-digits-2](duckdb-facts.md#duckdb-round-digits-2), [duckdb-ulp-arith](duckdb-facts.md#duckdb-ulp-arith), [duckdb-ulp-libm](duckdb-facts.md#duckdb-ulp-libm), [duckdb-ulp-round](duckdb-facts.md#duckdb-ulp-round), [duckdb-window-sum-order](duckdb-facts.md#duckdb-window-sum-order) | probe: [polars-mean-float-streaming](polars-facts.md#polars-mean-float-streaming), [polars-sum-float-streaming](polars-facts.md#polars-sum-float-streaming), [polars-var-std-streaming](polars-facts.md#polars-var-std-streaming), [polars-double-scalar-divisor](polars-facts.md#polars-double-scalar-divisor), [polars-elem-rounding](polars-facts.md#polars-elem-rounding), [polars-fp-ieee](polars-facts.md#polars-fp-ieee), [polars-log-base](polars-facts.md#polars-log-base), [polars-round](polars-facts.md#polars-round), [polars-round-digits](polars-facts.md#polars-round-digits), [polars-scalar-divisor](polars-facts.md#polars-scalar-divisor), [polars-ulp-arith](polars-facts.md#polars-ulp-arith), [polars-ulp-libm](polars-facts.md#polars-ulp-libm), [polars-ulp-round](polars-facts.md#polars-ulp-round) | missing | fuzz: [spark-sum-double](other-facts.md#spark-sum-double), [spark-var-stddev](other-facts.md#spark-var-stddev), [spark-double-arith](other-facts.md#spark-double-arith), [spark-double-divide](other-facts.md#spark-double-divide), [spark-elem-rounding](other-facts.md#spark-elem-rounding), [spark-round](other-facts.md#spark-round) |
| `on_domain_error` | `sqrt`, logs, `asin`, `acos`, `atan2`, `power` outside their domain: NaN, NULL or a raise. | fuzz: [duckdb-R15-atan2](duckdb-facts.md#duckdb-R15-atan2), [duckdb-R15-double-arith](duckdb-facts.md#duckdb-R15-double-arith), [duckdb-R15-math-domain](duckdb-facts.md#duckdb-R15-math-domain), [duckdb-float-math-double](duckdb-facts.md#duckdb-float-math-double), [duckdb-int-div-domain](duckdb-facts.md#duckdb-int-div-domain), [duckdb-int-pow](duckdb-facts.md#duckdb-int-pow) | probe: [polars-atan2](polars-facts.md#polars-atan2), [polars-double-divide](polars-facts.md#polars-double-divide), [polars-math-domain](polars-facts.md#polars-math-domain), [polars-int-div-domain](polars-facts.md#polars-int-div-domain), [polars-int-pow-exponent](polars-facts.md#polars-int-pow-exponent) | missing | fuzz: [spark-double-divide](other-facts.md#spark-double-divide), [spark-math-domain](other-facts.md#spark-math-domain), [spark-int-divide](other-facts.md#spark-int-divide), [spark-int-pow](other-facts.md#spark-int-pow) |
| `on_log_zero` | A logarithm of zero: -inf, NaN or a raise. | probe: [duckdb-R15-math-domain](duckdb-facts.md#duckdb-R15-math-domain), [duckdb-float-math-double](duckdb-facts.md#duckdb-float-math-double) | probe: [polars-math-domain](polars-facts.md#polars-math-domain) | missing | fuzz: [spark-math-domain](other-facts.md#spark-math-domain) |
| `nan_creation` | `inf - inf`, `0 · inf`, `inf / inf`, `fmod(inf, y)`, a sum of both infinities: NaN or a raise. | fuzz: [duckdb-float-sum-order](duckdb-facts.md#duckdb-float-sum-order), [duckdb-nonfinite-aggregates](duckdb-facts.md#duckdb-nonfinite-aggregates), [duckdb-R15-double-arith](duckdb-facts.md#duckdb-R15-double-arith), [duckdb-R15-double-modulus](duckdb-facts.md#duckdb-R15-double-modulus), [duckdb-R4](duckdb-facts.md#duckdb-R4) | probe: [polars-nonfinite-aggregates](polars-facts.md#polars-nonfinite-aggregates), [polars-double-arith](polars-facts.md#polars-double-arith), [polars-double-divide](polars-facts.md#polars-double-divide), [polars-double-modulus](polars-facts.md#polars-double-modulus), [polars-double-scalar-divisor](polars-facts.md#polars-double-scalar-divisor), [polars-scalar-divisor](polars-facts.md#polars-scalar-divisor) | missing | fuzz: [spark-nonfinite-aggregates](other-facts.md#spark-nonfinite-aggregates), [spark-double-arith](other-facts.md#spark-double-arith), [spark-double-divide](other-facts.md#spark-double-divide), [spark-double-modulus](other-facts.md#spark-double-modulus) |
| `float_overflow` | A finite double operation whose result overflows: `±∞`, or a raise (#575). | probe: [duckdb-double-overflow](duckdb-facts.md#duckdb-double-overflow) | probe: [polars-nonfinite-aggregates](polars-facts.md#polars-nonfinite-aggregates), [polars-double-arith](polars-facts.md#polars-double-arith), [polars-double-divide](polars-facts.md#polars-double-divide) | missing | fuzz: [spark-nonfinite-aggregates](other-facts.md#spark-nonfinite-aggregates), [spark-double-arith](other-facts.md#spark-double-arith), [spark-double-divide](other-facts.md#spark-double-divide) |
| `nan_equality` | Is NaN equal to NaN in `=`, grouping, `DISTINCT` and joins. | probe: [duckdb-nan-equality](duckdb-facts.md#duckdb-nan-equality) | probe: [polars-nan-equality](polars-facts.md#polars-nan-equality) | missing | probe: [spark-nan-equality](other-facts.md#spark-nan-equality) |
| `nan_order` | Where NaN sorts, and how `MIN`, `MAX`, `<`, [greatest](../reference/sql.Dialect.md#sverify.sql.Dialect.greatest) treat it. | fuzz: [duckdb-arg-min-nulls](duckdb-facts.md#duckdb-arg-min-nulls), [duckdb-quantile-disc](duckdb-facts.md#duckdb-quantile-disc), [duckdb-nan-order](duckdb-facts.md#duckdb-nan-order) | probe: [polars-min-max-nan](polars-facts.md#polars-min-max-nan), [polars-nan-order](polars-facts.md#polars-nan-order) | missing | probe: [spark-nan-order](other-facts.md#spark-nan-order) |
| `nan_kind` | Does a NaN's sign (or payload) survive and show. | probe: [duckdb-float-signs](duckdb-facts.md#duckdb-float-signs), [duckdb-signbit](duckdb-facts.md#duckdb-signbit) | probe: [polars-nan-sign](polars-facts.md#polars-nan-sign) | missing | fuzz: [spark-nan-sign](other-facts.md#spark-nan-sign) |
| `zero_sign` | `-0.0` in arithmetic, comparison, sorting and grouping. | probe: [duckdb-minmax-zero-sign](duckdb-facts.md#duckdb-minmax-zero-sign), [duckdb-R14](duckdb-facts.md#duckdb-R14), [duckdb-float-signs](duckdb-facts.md#duckdb-float-signs), [duckdb-signbit](duckdb-facts.md#duckdb-signbit) | probe: [polars-min-max-zero](polars-facts.md#polars-min-max-zero), [polars-double-modulus](polars-facts.md#polars-double-modulus), [polars-zero-add](polars-facts.md#polars-zero-add), [polars-zero-order](polars-facts.md#polars-zero-order), [polars-zero-sign-streaming](polars-facts.md#polars-zero-sign-streaming) | missing | fuzz: [spark-double-modulus](other-facts.md#spark-double-modulus), [spark-zero-order](other-facts.md#spark-zero-order), [spark-zero-sign](other-facts.md#spark-zero-sign) |
| `fp32` | Single-precision arithmetic and its conversions. | probe: [duckdb-ulp-casts](duckdb-facts.md#duckdb-ulp-casts), [duckdb-R12](duckdb-facts.md#duckdb-R12), [duckdb-ulp-arith](duckdb-facts.md#duckdb-ulp-arith), [duckdb-ulp-libm](duckdb-facts.md#duckdb-ulp-libm), [duckdb-ulp-round](duckdb-facts.md#duckdb-ulp-round) | probe: [polars-cast-to-double](polars-facts.md#polars-cast-to-double), [polars-ulp-casts](polars-facts.md#polars-ulp-casts), [polars-fp32](polars-facts.md#polars-fp32), [polars-ulp-arith](polars-facts.md#polars-ulp-arith), [polars-ulp-libm](polars-facts.md#polars-ulp-libm), [polars-ulp-round](polars-facts.md#polars-ulp-round) | missing | fuzz: [spark-fp32](other-facts.md#spark-fp32) |


# strings

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `char_set` | `upper`, `lower`: Unicode or ASCII mappings. | probe: [duckdb-case-mapping](duckdb-facts.md#duckdb-case-mapping) | probe: [polars-case](polars-facts.md#polars-case), [polars-length](polars-facts.md#polars-length), [polars-reverse](polars-facts.md#polars-reverse) | missing | probe: [spark-case](other-facts.md#spark-case), [spark-string-plain](other-facts.md#spark-string-plain) |
| `case_sensitivity` | [like](../reference/sql.Dialect.md#sverify.sql.Dialect.like), `contains`, `starts_with`, `strpos`, regexes: case-sensitive or not. | probe: [duckdb-F4](duckdb-facts.md#duckdb-F4), [duckdb-string-match-case](duckdb-facts.md#duckdb-string-match-case) | probe: [polars-match-functions](polars-facts.md#polars-match-functions), [polars-regex](polars-facts.md#polars-regex) | missing | fuzz: [spark-match-functions](other-facts.md#spark-match-functions), [spark-regex](other-facts.md#spark-regex) |
| `substring_range` | [substring](../reference/sql.Dialect.md#sverify.sql.Dialect.substring) offsets and lengths outside 32 bits. | probe: [duckdb-substring-range](duckdb-facts.md#duckdb-substring-range) | probe: [polars-substring-range](polars-facts.md#polars-substring-range) | missing | fuzz: [spark-substring-range](other-facts.md#spark-substring-range) |
| `negative_start` | [substring](../reference/sql.Dialect.md#sverify.sql.Dialect.substring) with a negative or zero start; its indexing (characters or bytes, 0- or 1-based). | engine_test: [duckdb-R13](duckdb-facts.md#duckdb-R13) | probe: [polars-strpos](polars-facts.md#polars-strpos), [polars-substring](polars-facts.md#polars-substring) | missing | fuzz: [spark-strpos](other-facts.md#spark-strpos), [spark-substring](other-facts.md#spark-substring) |
| `string_positions` | What [substring](../reference/sql.Dialect.md#sverify.sql.Dialect.substring) and `strpos` positions count: characters or bytes, from 0 or 1; `strpos` without a match. | probe: [duckdb-R13](duckdb-facts.md#duckdb-R13), [duckdb-string-match-case](duckdb-facts.md#duckdb-string-match-case) | probe: [polars-strpos](polars-facts.md#polars-strpos), [polars-substring](polars-facts.md#polars-substring) | missing | fuzz: [spark-strpos](other-facts.md#spark-strpos), [spark-substring](other-facts.md#spark-substring) |
| `regex_dialect` | The regex engine and syntax, classes on non-ASCII text, a match that fails, replacement references. | probe: [duckdb-R15-regexp](duckdb-facts.md#duckdb-R15-regexp) | probe: [polars-regex](polars-facts.md#polars-regex) | missing | fuzz: [spark-regex](other-facts.md#spark-regex) |
| [digests](../reference/io.Contract.md#sverify.io.Contract.digests) | `md5`, `sha256` and other digests: present, and on which bytes. | probe: [duckdb-R15-digests](duckdb-facts.md#duckdb-R15-digests) | probe: [polars-string-functions-missing](polars-facts.md#polars-string-functions-missing) | missing | probe: [spark-digests](other-facts.md#spark-digests) |


# temporal

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `date_range` | Date and timestamp arithmetic past 0001-01-01 … 9999-12-31. | probe: [duckdb-date-range](duckdb-facts.md#duckdb-date-range) | probe: [polars-date-range](polars-facts.md#polars-date-range), [polars-month-arith](polars-facts.md#polars-month-arith) | missing | fuzz: [spark-date-range](other-facts.md#spark-date-range) |
| `time_interval_months` | `TIME ± INTERVAL` with months, and time arithmetic past midnight. | probe: [duckdb-time-plus-interval](duckdb-facts.md#duckdb-time-plus-interval) | probe: [polars-temporal-errors](polars-facts.md#polars-temporal-errors) | missing | probe: [spark-time-type](other-facts.md#spark-time-type) |
| `timestamp_precision` | The timestamp unit (s, ms, µs, ns) and its range. | engine_test: [duckdb-R10](duckdb-facts.md#duckdb-R10) | probe: [polars-timestamp-unit](polars-facts.md#polars-timestamp-unit) | missing | probe: [spark-timestamp-precision](other-facts.md#spark-timestamp-precision) |
| `time_zones` | Time zones: DST gaps and overlaps, conversions. | probe: [duckdb-time-zones](duckdb-facts.md#duckdb-time-zones) | probe: [polars-temporal-errors](polars-facts.md#polars-temporal-errors) | missing | probe: [spark-time-zones](other-facts.md#spark-time-zones) |
| `week_numbering` | Week numbers, weekdays, ISO years, [date_trunc](../reference/sql.Dialect.md#sverify.sql.Dialect.date_trunc) to a week, parts before 1970. | probe: [duckdb-yearweek](duckdb-facts.md#duckdb-yearweek) | probe: [polars-date-parts](polars-facts.md#polars-date-parts) | missing | probe: [spark-week-parts](other-facts.md#spark-week-parts) |


# casts

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| [float_to_int](../reference/sql.Dialect.md#sverify.sql.Dialect.float_to_int) | A double or decimal cast to an integer: truncate or round. | probe: [duckdb-R9](duckdb-facts.md#duckdb-R9) | probe: [polars-cast-double-to-int](polars-facts.md#polars-cast-double-to-int), [polars-decimal-casts](polars-facts.md#polars-decimal-casts) | missing | probe: [spark-cast-double-to-int](other-facts.md#spark-cast-double-to-int) |
| `cast_failure` | A cast that does not fit or parse: raise or NULL. | engine_test: [duckdb-R8](duckdb-facts.md#duckdb-R8) | probe: [polars-cast-double-to-int](polars-facts.md#polars-cast-double-to-int), [polars-cast-int](polars-facts.md#polars-cast-int), [polars-cast-string](polars-facts.md#polars-cast-string), [polars-decimal-casts](polars-facts.md#polars-decimal-casts) | missing | fuzz: [spark-cast-double-to-int](other-facts.md#spark-cast-double-to-int), [spark-cast-string](other-facts.md#spark-cast-string) |
| `cast_parsing` | Text to numbers, booleans and dates: what is accepted (spaces, signs, `nan`, `inf`, exponents). | engine_test: [duckdb-R10](duckdb-facts.md#duckdb-R10) | probe: [polars-cast-string](polars-facts.md#polars-cast-string), [polars-temporal-errors](polars-facts.md#polars-temporal-errors) | missing | fuzz: [spark-cast-string](other-facts.md#spark-cast-string) |
| `cast_formatting` | Numbers, booleans and dates to text: the format. | probe: [duckdb-printf](duckdb-facts.md#duckdb-printf) | probe: [polars-cast-string](polars-facts.md#polars-cast-string), [polars-strftime](polars-facts.md#polars-strftime) | missing | fuzz: [spark-cast-string](other-facts.md#spark-cast-string) |


# nulls

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `null_handling` | `concat` and other functions given a NULL: NULL or skip. | probe: [duckdb-null-concat](duckdb-facts.md#duckdb-null-concat) | probe: [polars-concat](polars-facts.md#polars-concat) | missing | probe: [spark-concat](other-facts.md#spark-concat) |
| `three_valued_logic` | `and`, `or`, `not` with NULLs; `bool_and`, `bool_or` over NULLs. | probe: [duckdb-kleene](duckdb-facts.md#duckdb-kleene) | probe: [polars-kleene](polars-facts.md#polars-kleene) | missing | probe: [spark-kleene](other-facts.md#spark-kleene) |
| `null_join_keys` | Do NULL keys match in joins, and how `IS NOT DISTINCT FROM` is spelled. | probe: [duckdb-null-keys](duckdb-facts.md#duckdb-null-keys), [duckdb-set-operations](duckdb-facts.md#duckdb-set-operations) | probe: [polars-null-keys](polars-facts.md#polars-null-keys), [polars-set-operations](polars-facts.md#polars-set-operations) | missing | probe: [spark-null-keys](other-facts.md#spark-null-keys), [spark-set-operations](other-facts.md#spark-set-operations) |


# nested

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `list_null_order` | A NULL element deciding `<` of lists, in comparisons and in `ORDER BY`. | engine_test: [duckdb-R11](duckdb-facts.md#duckdb-R11) | probe: [polars-list-order](polars-facts.md#polars-list-order) | missing | fuzz: [spark-list-order](other-facts.md#spark-list-order) |
| `list_indexing` | List indexing: base, negative and out-of-range indexes. | probe: [duckdb-list-index](duckdb-facts.md#duckdb-list-index) | probe: [polars-list-index](polars-facts.md#polars-list-index) | missing | fuzz: [spark-list-index](other-facts.md#spark-list-index) |
| `struct_equality` | Equality and order of structs with NULL fields. | probe: [duckdb-struct-equality](duckdb-facts.md#duckdb-struct-equality) | probe: [polars-nested-equality](polars-facts.md#polars-nested-equality) | missing | probe: [spark-nested-equality](other-facts.md#spark-nested-equality) |
| `unnest_null_empty` | UNNEST of a NULL list and of an empty one. | probe: [duckdb-unnest](duckdb-facts.md#duckdb-unnest) | probe: [polars-explode](polars-facts.md#polars-explode) | missing | probe: [spark-explode](other-facts.md#spark-explode) |


# aggregates

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `avg_int_result` | `avg` of integers: its type and how it is computed. | probe: [duckdb-R6](duckdb-facts.md#duckdb-R6), [duckdb-avg-int](duckdb-facts.md#duckdb-avg-int) | probe: [polars-avg-int](polars-facts.md#polars-avg-int) | missing | fuzz: [spark-avg-int](other-facts.md#spark-avg-int) |
| `sum_order` | The order and grouping of a double `SUM`, `AVG`. | probe: [duckdb-R7](duckdb-facts.md#duckdb-R7), [duckdb-avg-double](duckdb-facts.md#duckdb-avg-double), [duckdb-float-sum-order](duckdb-facts.md#duckdb-float-sum-order), [duckdb-kahan-sum](duckdb-facts.md#duckdb-kahan-sum), [duckdb-sum-double](duckdb-facts.md#duckdb-sum-double), [duckdb-window-sum-order](duckdb-facts.md#duckdb-window-sum-order) | probe: [polars-mean-float-streaming](polars-facts.md#polars-mean-float-streaming), [polars-sum-float-streaming](polars-facts.md#polars-sum-float-streaming) | missing | fuzz: [spark-avg-double](other-facts.md#spark-avg-double), [spark-sum-double](other-facts.md#spark-sum-double) |
| `stat_algo` | The algorithm of `VAR_*`, `STDDEV_*`, `COVAR_*`, `CORR`. | probe: [duckdb-corr](duckdb-facts.md#duckdb-corr), [duckdb-covar](duckdb-facts.md#duckdb-covar), [duckdb-stat-arg-types](duckdb-facts.md#duckdb-stat-arg-types), [duckdb-var-stddev](duckdb-facts.md#duckdb-var-stddev) | probe: [polars-corr](polars-facts.md#polars-corr), [polars-cov](polars-facts.md#polars-cov), [polars-var-std-streaming](polars-facts.md#polars-var-std-streaming) | missing | fuzz: [spark-corr](other-facts.md#spark-corr), [spark-covar](other-facts.md#spark-covar), [spark-var-stddev](other-facts.md#spark-var-stddev) |
| `stat_degenerate` | `CORR` of one pair or a constant side; a statistical aggregate of a single value. | probe: [duckdb-corr](duckdb-facts.md#duckdb-corr), [duckdb-nonfinite-aggregates](duckdb-facts.md#duckdb-nonfinite-aggregates), [duckdb-stat-arg-types](duckdb-facts.md#duckdb-stat-arg-types) | probe: [polars-corr](polars-facts.md#polars-corr), [polars-var-std-streaming](polars-facts.md#polars-var-std-streaming) | missing | fuzz: [spark-corr](other-facts.md#spark-corr), [spark-nonfinite-aggregates](other-facts.md#spark-nonfinite-aggregates), [spark-var-stddev](other-facts.md#spark-var-stddev) |
| `quantile_interp` | `QUANTILE_CONT`, `QUANTILE_DISC`, `MEDIAN`: the position and interpolation. | probe: [duckdb-quantile-cont-interpolation](duckdb-facts.md#duckdb-quantile-cont-interpolation), [duckdb-quantile-disc](duckdb-facts.md#duckdb-quantile-disc) | probe: [polars-quantile](polars-facts.md#polars-quantile) | missing | fuzz: [spark-quantile](other-facts.md#spark-quantile) |
| `tie_pick` | Which row `FIRST`, `LAST`, `ARG_MIN`, `ARG_MAX`, `any_value`, `MODE` take among ties. | probe: [duckdb-arg-min-nulls](duckdb-facts.md#duckdb-arg-min-nulls), [duckdb-mode-ties](duckdb-facts.md#duckdb-mode-ties) | probe: [polars-arg-min-max](polars-facts.md#polars-arg-min-max), [polars-first-last](polars-facts.md#polars-first-last), [polars-mode](polars-facts.md#polars-mode) | missing | probe: [spark-first-last](other-facts.md#spark-first-last) |
| `empty_group_aggregates` | Aggregates of no rows or of NULLs only (`SUM`, `COUNT`, `MIN`, `AVG`). | probe: [duckdb-avg-int](duckdb-facts.md#duckdb-avg-int), [duckdb-statistical-aggregates](duckdb-facts.md#duckdb-statistical-aggregates), [duckdb-sum-double](duckdb-facts.md#duckdb-sum-double), [duckdb-list-sum](duckdb-facts.md#duckdb-list-sum) | probe: [polars-avg-int](polars-facts.md#polars-avg-int), [polars-count-empty](polars-facts.md#polars-count-empty), [polars-mean-float-streaming](polars-facts.md#polars-mean-float-streaming), [polars-sum-float-streaming](polars-facts.md#polars-sum-float-streaming), [polars-sum-int](polars-facts.md#polars-sum-int) | missing | fuzz: [spark-avg-int](other-facts.md#spark-avg-int), [spark-sum-double](other-facts.md#spark-sum-double), [spark-sum-int](other-facts.md#spark-sum-int) |
| `nonfinite_aggregates` | Aggregates of ±inf and NaN inputs. | probe: [duckdb-R7](duckdb-facts.md#duckdb-R7), [duckdb-kahan-sum](duckdb-facts.md#duckdb-kahan-sum), [duckdb-moments](duckdb-facts.md#duckdb-moments), [duckdb-nonfinite-aggregates](duckdb-facts.md#duckdb-nonfinite-aggregates) | probe: [polars-nonfinite-aggregates](polars-facts.md#polars-nonfinite-aggregates) | missing | fuzz: [spark-nonfinite-aggregates](other-facts.md#spark-nonfinite-aggregates) |


# windows

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `ntile_spread` | How `NTILE` spreads the remainder. | probe: [duckdb-ntile](duckdb-facts.md#duckdb-ntile) | probe: [polars-rank](polars-facts.md#polars-rank) | missing | probe: [spark-rank](other-facts.md#spark-rank) |
| `default_window_frame` | The frame when none is given, with and without an order; rank functions over ties and NULLs. | probe: [duckdb-window-frame](duckdb-facts.md#duckdb-window-frame) | probe: [polars-rank](polars-facts.md#polars-rank), [polars-window-values](polars-facts.md#polars-window-values) | missing | probe: [spark-rank](other-facts.md#spark-rank), [spark-window-values](other-facts.md#spark-window-values) |


# relations

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `tie_order` | The order of ties in a sort, `STRING_AGG`, [collect](../reference/sql.Dialect.md#sverify.sql.Dialect.collect), a window: stable or not. | probe: [duckdb-mode-ties](duckdb-facts.md#duckdb-mode-ties), [duckdb-sort-ties](duckdb-facts.md#duckdb-sort-ties) | probe: [polars-first-last](polars-facts.md#polars-first-last), [polars-sort-stability-streaming](polars-facts.md#polars-sort-stability-streaming), [polars-rank](polars-facts.md#polars-rank), [polars-window-values](polars-facts.md#polars-window-values) | missing | probe: [spark-first-last](other-facts.md#spark-first-last), [spark-sort-stability](other-facts.md#spark-sort-stability), [spark-rank](other-facts.md#spark-rank), [spark-window-values](other-facts.md#spark-window-values) |
| `null_order` | Where NULLs sort by default, ascending and descending. | probe: [duckdb-F2](duckdb-facts.md#duckdb-F2), [duckdb-window-frame](duckdb-facts.md#duckdb-window-frame) | probe: [polars-null-order](polars-facts.md#polars-null-order) | missing | probe: [spark-null-order](other-facts.md#spark-null-order) |
| `clustered` | A sort that only clusters equal keys. | probe: [duckdb-clustered](duckdb-facts.md#duckdb-clustered) | probe: [polars-clustered](polars-facts.md#polars-clustered) | missing | probe: [spark-clustered](other-facts.md#spark-clustered) |
| `set_operations` | `UNION`, `INTERSECT`, `EXCEPT`, with and without `ALL`: duplicates, NULLs, order. | probe: [duckdb-set-operations](duckdb-facts.md#duckdb-set-operations) | probe: [polars-set-operations](polars-facts.md#polars-set-operations) | missing | probe: [spark-set-operations](other-facts.md#spark-set-operations) |
| `nan_zero_grouping` | Grouping, `DISTINCT` and join keys with NaN and `-0.0`: one group, and which value represents it. | probe: [duckdb-R14](duckdb-facts.md#duckdb-R14), [duckdb-nan-equality](duckdb-facts.md#duckdb-nan-equality) | probe: [polars-nan-equality](polars-facts.md#polars-nan-equality), [polars-zero-order](polars-facts.md#polars-zero-order) | missing | fuzz: [spark-nan-equality](other-facts.md#spark-nan-equality), [spark-zero-order](other-facts.md#spark-zero-order) |


# errors

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `raise_set` | Where the engine raises beyond the reference (D2): extra raises, and raises that are planning errors or panics. | probe: [duckdb-moments](duckdb-facts.md#duckdb-moments), [duckdb-decimal-arith](duckdb-facts.md#duckdb-decimal-arith), [duckdb-R15-int-modulus](duckdb-facts.md#duckdb-R15-int-modulus), [duckdb-R15-shift-left](duckdb-facts.md#duckdb-R15-shift-left), [duckdb-list-vectors](duckdb-facts.md#duckdb-list-vectors), [duckdb-printf](duckdb-facts.md#duckdb-printf), [duckdb-date-range](duckdb-facts.md#duckdb-date-range), [duckdb-ntile](duckdb-facts.md#duckdb-ntile) | probe: [polars-decimal-arith](polars-facts.md#polars-decimal-arith), [polars-list-index](polars-facts.md#polars-list-index), [polars-date-range](polars-facts.md#polars-date-range) | missing | fuzz: [spark-decimal-negate](other-facts.md#spark-decimal-negate), [spark-raise-set](other-facts.md#spark-raise-set), [spark-list-index](other-facts.md#spark-list-index), [spark-regex](other-facts.md#spark-regex), [spark-substring-range](other-facts.md#spark-substring-range), [spark-date-range](other-facts.md#spark-date-range) |


# execution

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `evaluation_order` | Short-circuit in `CASE`, `AND`, `OR`, `COALESCE`: does the engine evaluate an expression on rows a filter or a branch removes, and raise there (division by zero, a failing cast)? This can break the reference's no-error guarantee. | fuzz: [duckdb-exec-filter-pushdown](duckdb-facts.md#duckdb-exec-filter-pushdown), [duckdb-exec-short-circuit](duckdb-facts.md#duckdb-exec-short-circuit) | probe: [polars-exec-cse-hoist](polars-facts.md#polars-exec-cse-hoist), [polars-exec-predicate-pushdown](polars-facts.md#polars-exec-predicate-pushdown), [polars-exec-when-eager](polars-facts.md#polars-exec-when-eager) | missing | probe: [spark-exec-evaluation-order](other-facts.md#spark-exec-evaluation-order) |
| `settings` | Which session settings change results: DuckDB's `default_null_order`, `integer_division`, `threads`, …; Polars's `Config` and environment variables. | probe: [duckdb-exec-settings](duckdb-facts.md#duckdb-exec-settings) | engine_test: [polars-exec-engine](polars-facts.md#polars-exec-engine) | missing | fuzz: [spark-exec-parser-cache](other-facts.md#spark-exec-parser-cache), [spark-exec-settings](other-facts.md#spark-exec-settings), [spark-list-index](other-facts.md#spark-list-index), [spark-case](other-facts.md#spark-case), [spark-time-zones](other-facts.md#spark-time-zones) |
| `parallel_nondeterminism` | Results that change with the thread count or from run to run: the order of a double `SUM`, row order without `ORDER BY`, ties. | probe: [duckdb-exec-row-order](duckdb-facts.md#duckdb-exec-row-order) | probe: [polars-exec-row-order](polars-facts.md#polars-exec-row-order) | missing | fuzz: [spark-first-last](other-facts.md#spark-first-last), [spark-sum-double](other-facts.md#spark-sum-double), [spark-sum-int](other-facts.md#spark-sum-int), [spark-exec-parallel](other-facts.md#spark-exec-parallel), [spark-sort-stability](other-facts.md#spark-sort-stability), [spark-window-values](other-facts.md#spark-window-values) |
| `platform` | Results that depend on the platform: libm (`sin`, `pow`, `exp`), NaN signs, SIMD paths; probes ran on macOS arm64, CI on Linux x86_64. | probe: [duckdb-exec-platform](duckdb-facts.md#duckdb-exec-platform) | probe: [polars-exec-platform](polars-facts.md#polars-exec-platform) | missing | fuzz: [spark-elem-rounding](other-facts.md#spark-elem-rounding), [spark-nan-sign](other-facts.md#spark-nan-sign), [spark-exec-platform](other-facts.md#spark-exec-platform) |
| `size_limits` | Limits on string, blob and list lengths, decimal precision, nesting depth, and what happens past them. | engine_test: [duckdb-exec-size-limits](duckdb-facts.md#duckdb-exec-size-limits) | engine_test: [polars-exec-size-limits](polars-facts.md#polars-exec-size-limits) | missing | fuzz: [spark-exec-parser-cache](other-facts.md#spark-exec-parser-cache), [spark-exec-size-limits](other-facts.md#spark-exec-size-limits) |
| `streaming_fallback` | Operations a streaming engine cannot run itself and hands to its in-memory engine (Polars's streaming engine, which sverify targets): which, and whether results differ. | missing | engine_test: [polars-exec-streaming-fallback](polars-facts.md#polars-exec-streaming-fallback) | missing | source: [spark-exec-streaming-fallback](other-facts.md#spark-exec-streaming-fallback) |
| `try_variants` | `TRY_CAST`, `TRY(…)` and other non-raising forms: which errors become NULL and which still raise. | engine_test: [duckdb-exec-try](duckdb-facts.md#duckdb-exec-try) | engine_test: [polars-exec-strict-false](polars-facts.md#polars-exec-strict-false) | missing | fuzz: [spark-try-variants](other-facts.md#spark-try-variants) |


# frontend

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `type_names` | The engine's names of the types. | probe: [duckdb-typeof-names](duckdb-facts.md#duckdb-typeof-names), [duckdb-F4](duckdb-facts.md#duckdb-F4) | probe: [polars-type-names](polars-facts.md#polars-type-names) | missing | probe: [spark-type-names](other-facts.md#spark-type-names) |
| `implicit_casts` | Implicit casts and type promotion in arithmetic and comparisons. | engine_test: [duckdb-F1](duckdb-facts.md#duckdb-F1) | probe: [polars-fp32](polars-facts.md#polars-fp32), [polars-int-float-compare](polars-facts.md#polars-int-float-compare), [polars-implicit-casts](polars-facts.md#polars-implicit-casts), [polars-int-true-divide](polars-facts.md#polars-int-true-divide) | missing | fuzz: [spark-fp32](other-facts.md#spark-fp32), [spark-implicit-casts](other-facts.md#spark-implicit-casts) |
| `literal_types` | The types of literals. | engine_test: [duckdb-F3](duckdb-facts.md#duckdb-F3) | probe: [polars-literal-types](polars-facts.md#polars-literal-types) | engine_test: [datafusion-S4](other-facts.md#datafusion-S4) | probe: [spark-literal-types](other-facts.md#spark-literal-types) |


# io

| Item | Question | DuckDB | Polars | DataFusion | Spark |
|----|----|----|----|----|----|
| `io_formats` | File formats read and written, and their type mappings. | probe: [duckdb-IO3](duckdb-facts.md#duckdb-IO3) | probe: [polars-io](polars-facts.md#polars-io) | missing | engine_test: [spark-io](other-facts.md#spark-io) |
| `object_stores` | Object stores and their credentials. | probe: [duckdb-IO1](duckdb-facts.md#duckdb-IO1), [duckdb-IO2](duckdb-facts.md#duckdb-IO2), [duckdb-IO3](duckdb-facts.md#duckdb-IO3) | probe: [polars-io](polars-facts.md#polars-io) | missing | engine_test: [spark-io](other-facts.md#spark-io) |
| `catalogs` | Catalogs (Unity, Iceberg, …) and how the engine attaches them. | probe: [duckdb-IO1](duckdb-facts.md#duckdb-IO1), [duckdb-IO2](duckdb-facts.md#duckdb-IO2) | probe: [polars-io](polars-facts.md#polars-io) | missing | engine_test: [spark-io](other-facts.md#spark-io) |
