feat: Use true division for the / operator in Polars SQL - #27391
Conversation
/ operator in SQL/ operator in SQL
/ operator in SQL/ operator in Polars SQL
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #27391 +/- ##
==========================================
+ Coverage 79.88% 81.46% +1.58%
==========================================
Files 1840 1840
Lines 256051 256054 +3
Branches 3180 3180
==========================================
+ Hits 204546 208595 +4049
+ Misses 50680 46634 -4046
Partials 825 825 ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
|
As a random thought, @alexander-beedie do you think maybe we should add a warning that this behaviour changed for the end user? |
SQL support is still marked as being technically "unstable" so it's not required to do so, but is probably good to note it with a |
|
@alexander-beedie Okay so I updated the documentation is |
Reclassify 873 baseline entries from sqlite/select{1,2,3}.slt that fail
only due to integer division divergence. Polars SQL deliberately uses
true (float) division for `/` (PR #27391), while SQLite truncates int/int
toward zero. These records are now marked with `skipif polars` instead of
being tracked in the expected_failures baseline.
Conversions:
- select1.slt: 168 converted (98 baseline → 95 after renumbering)
- select2.slt: 151 converted (84 baseline → 83 after renumbering)
- select3.slt: 554 converted (416 baseline → 416 after renumbering)
Baseline: 1610 entries → 733 entries
Total test records: 10091 (unchanged)
Pass rate: 92.0%
All conversions verified with cargo run -p polars-sqllogictest (exit 0,
zero unexpected FAILs/PASSes). Updated UPSTREAM documentation with new
skipif cluster counts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Vendors a curated subset of the public-domain SQLite sqllogictest corpus
(gregrahn/sqllogictest mirror, pinned commit c67f97bf3ca7e590d12e073408bcacaf2ff0f3a0,
fetched 2026-07-21) into crates/polars-sqllogictest/slt/sqlite/: select1-4.test,
evidence/{slt_lang_aggfunc,slt_lang_createview,slt_lang_dropview,in1,in2}.test, and
4 truncated random/{select,aggregates}/slt_good_{0,50}.test files (150 records each
after setup). select5.test is dropped: every one of its 732 records is a 4-to-64-way
implicit join stress test ("join-N-M"), and without join reordering polars-sql
attempts a literal N-way cross product that is combinatorially intractable past
~N=20 - bisection confirmed the harness process gets OOM-killed inside a
`join-24-4` record. A hang has no representation in the expected_failures.txt
ratchet, so the file can't be used as conformance signal; see UPSTREAM for the
full drop list (triggers, REPLACE/UPDATE, index existence-tracking cases) and
the other vendoring-time transformations (inline-comment stripping so the
sqllogictest-rs 0.29.1 parser accepts onlyif/skipif lines, hash-threshold
backfill, and reflowing one-value-per-line result blocks to one-row-per-line to
match this crate's default validator).
Shim extensions (crates/polars-sqllogictest/src/{setup,engine}.rs), minimal,
harness-only:
- untyped CREATE TABLE columns (sqlparser DataType::Unspecified) default to Int64
- CREATE INDEX / DROP INDEX are unconditional no-ops
- CREATE VIEW registers the view's SELECT as a LazyFrame via SQLContext, with
existence tracking so duplicate-create and drop-of-nonexistent-view error
correctly; DROP VIEW unregisters it
- a single "statement ok" record containing multiple setup statements (occurs
once in the corpus) now runs each statement in sequence instead of bailing
160 records get `skipif polars` (intentional divergences, each noted in
UPSTREAM): 135 for Polars' true (float) division for `/` vs SQLite/C-style
truncating int division (pre-existing decision, #27391), 17 for Postgres-aligned
native booleans vs SQLite's integer-as-boolean convention, 8 for rejecting empty
`IN ()` lists (SQL92/Postgres reject them; SQLite permits them as an extension).
Verification: `cargo run -p polars-sqllogictest --release` exits 0 with
4829 passed / 5200 expected-fail / 10029 total (48.2% pass rate); slt/polars/
alone is 96/96 (100%); slt/sqlite/ alone is 4733/9933 (47.6%). Removing one
baseline entry was spot-checked to turn the run red. cargo fmt --check clean.
Ranked triage (failure records -> Phase 3 mapping):
1484 scalar/EXISTS subquery used as a comparison operand -> 3a subqueries
1309 self-join / multi-table FROM: duplicate column names -> new (context.rs
across joined tables collide in projections/with_columns join handling,
adjacent to 3a)
878 3+ chained/mixed UNION/EXCEPT/INTERSECT in one query -> 3e set-ops
(process_except_intersect)
709 EXISTS subquery outside simple WHERE position -> 3a subqueries
655 subquery comparison operators (>, <, = ...) rejected -> 3a subqueries
(sql_expr.rs:567-577)
135 integer division semantics -> skipif (intentional)
74 SubPlan not allowed outside equality context -> 3a subqueries
25 DISTINCT inside SUM/MIN/MAX/AVG -> 3c function library
17 boolean vs 0/1 representation -> skipif (intentional)
11 TOTAL() aggregate function missing -> 3c function library
8 empty IN() list -> skipif (intentional)
8 IN-list element is an arbitrary expression, not literal -> 3e small semantics
8 unary negation of COUNT() wraps via unsigned overflow -> new (correctness bug,
not dialect-specific)
7 shim: INSERT ... SELECT not supported (VALUES only) -> harness limitation
7 IN/NOT IN with NULL: should return NULL, not false/true -> 3e small semantics
6 SQLite "NOT INDEXED" query hint (proprietary syntax) -> no fix planned
6 SQLite dynamic type-affinity edge cases (aggfunc.slt) -> not fixable (static
typing, like Postgres)
3 SUM(<literal>) doesn't multiply by row count -> new (correctness bug)
3 SUM/MIN over all-NULL or empty group returns 0, not NULL -> 3c / new
2 hex string literal (x'...') -> 3c function library
2 query expected to fail but our engine succeeds -> baseline (low value)
2 shim: bit-shift literal in INSERT VALUES unsupported -> harness limitation
1 misc one-off join constraint error -> baseline
Two items above ("self-join duplicate column names", "COUNT negation
wraparound") are not on the pre-existing Phase 3 list and are flagged here as
new, high-value findings - the duplicate-column one alone accounts for more
baseline records than any single subquery cluster.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reclassify 873 baseline entries from sqlite/select{1,2,3}.slt that fail
only due to integer division divergence. Polars SQL deliberately uses
true (float) division for `/` (PR #27391), while SQLite truncates int/int
toward zero. These records are now marked with `skipif polars` instead of
being tracked in the expected_failures baseline.
Conversions:
- select1.slt: 168 converted (98 baseline → 95 after renumbering)
- select2.slt: 151 converted (84 baseline → 83 after renumbering)
- select3.slt: 554 converted (416 baseline → 416 after renumbering)
Baseline: 1610 entries → 733 entries
Total test records: 10091 (unchanged)
Pass rate: 92.0%
All conversions verified with cargo run -p polars-sqllogictest (exit 0,
zero unexpected FAILs/PASSes). Updated UPSTREAM documentation with new
skipif cluster counts.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolves #25396.
I saw you self-assigned @alexander-beedie, but figured I would give it a stab since it's been awhile. I hope that's okay 😃!
🤖 Claude Sonnet 4.6 for navigating and explaining existing code.