December 7, 2024·4 min read·engineeringsqlitefloating-pointcorrectness

SQLite fixes a large-number conversion error on x86

SQLite 3.47.2 corrects decimal text conversion near an unsigned integer boundary. The defect can double a value, which is different from ordinary floating-point precision loss.

A large integer losing a few low-order digits when converted to floating point is an expected limitation of representation. A value becoming roughly twice as large is a different failure. SQLite 3.47.2 fixes that second problem for a narrow family of decimal inputs on x64 and i386 hardware.

The December 7 release identifies values whose first sixteen significant digits are 1844674407370955 as the relevant family. More precisely, it gives a bounded interval of significands that can fail with any decimal exponent. The regression began in 3.47.0, so the patch concerns the conversion implementation introduced in that release.

I value SQLite's predictable handling of stored data, and numeric conversion belongs to that expectation. An application does not need an elaborate schema to encounter this bug. The original report demonstrates it with a single numeric literal selected by a single SQL statement.

The smallest reproduction has no table

The reported example selects 18446744073709551488. The expected result is a floating-point value near 1.84467440737096e+19. An affected build instead reports a result near 3.68934881474191e+19. The discrepancy is therefore about magnitude, rather than a disagreement in the last displayed decimal place.

SELECT 18446744073709551488;

The statement needs no table, index, or stored record. That makes it useful for understanding where the failure occurs. SQLite must interpret the decimal token and choose its numeric representation before a query can return it. A bad conversion at that point can affect the selected value even though there is no database content to repair.

The report includes neighboring inputs that convert normally. That detail explains why testing an arbitrary large number would not necessarily expose the problem. The failure belongs to a small interval near a conversion boundary, rather than every number too large for SQLite's signed integer representation.

Changing the decimal exponent also preserves the relevant pattern. The release note describes the interval using significands and an arbitrary exponent for that reason. Restricting the explanation to one nineteen-digit integer would make the affected class appear narrower than the documented conversion defect.

A round trip crosses a machine boundary

The fix's check-in explanation identifies a failing round trip from uint64_t to double and back to uint64_t for values close to the unsigned maximum on x64. The converter relied on that round trip in a region where it did not preserve the required result.

This is a useful mechanism to distinguish from ordinary decimal formatting. Formatting determines how a numeric value appears as text. Here, converting the input text produces the wrong floating-point value before a display format can help. Printing more digits would expose a more detailed version of the wrong magnitude.

It is also different from expecting arbitrary integers to remain exact in a floating-point representation. The report accepts that a large integer can lose precision. Its complaint is that the result is nowhere near the representable value expected for the original number. That is why treating the output as normal rounding would miss the regression.

The 3.47.0 release had removed reliance on long double and adopted Dekker's algorithm where extended precision was needed. The October release notes explain that hardware support and compiler toolchain difficulties motivated that change. December's correction repairs a specific consequence of the new conversion work. It does not establish that every operation using floating point is defective.

Architecture changes what a reproduction proves

The forum discussion quickly establishes that the problem is architecture-dependent. A participant could not reproduce it on an M1 MacBook Pro, while Richard Hipp reported observing it on x86 across Linux, macOS, and Windows. The release's final scope names x64 and i386 hardware.

That distribution is useful because it separates operating-system packaging from the numeric mechanism. Different operating systems can exhibit the same conversion problem on the relevant hardware, while another architecture running SQLite may return the expected result. A successful reproduction or a passing check needs that context to be interpretable.

I find the small SQL example helpful precisely because it makes that comparison possible without a dataset. The relevant variables include the SQLite build and architecture. There is no reason to infer from one unaffected machine that an affected deployment cannot have the problem.

A converter fix and historical values are separate concerns

Installing the corrected engine changes how it handles the affected conversion. The release does not say that updating the library rewrites values an application might already have derived and stored. If a wrong result became ordinary application data, the library cannot infer the intended original input simply from that stored result.

That is a practical implication of the failure mechanism, rather than a claim that a particular database has been damaged. The original reproduction selects a literal and stores nothing. An application's exposure depends on whether its inputs include the documented numeric family and what it does with the resulting value.

The precision discussion should remain equally narrow. Version 3.47.2 corrects a magnitude error in decimal conversion. It does not promise exact representation for every large integer or decimal fraction. Those are different requirements, and the report's expected result already acknowledges floating-point rounding.

The patch therefore restores the converter's handling of the identified interval on the affected hardware. The primary sources give a minimal query, the problematic numeric pattern, and an implementation-level explanation. Together they make this maintenance change understandable without turning a specific regression into a general claim about all SQLite arithmetic.