Skip to content

v0.2.1

Choose a tag to compare

@github-actions github-actions released this 16 Aug 07:11
· 58 commits to main since this release
eb49c0d

v0.2.1

One fix, and it is silent data corruption. Upgrade from v0.2.0 if you query
the warehouse over HiveServer2.

The bug

A HiveServer2 result column was typed from its first non-null value only,
and the conversion to INT was unchecked. One small number at the top of a
column therefore fixed it at INT, and every later value too wide for int32
was truncated on the way to the client:

[[1], [5000000000]]
  inferred type: INT_TYPE
  packed as INT32: [1 705032704]     <- 5000000000 delivered as 705032704

No error, no warning, nothing a client could inspect to know it happened. The
number simply arrived wrong.

Both witnessed clients sit on that path. databricks-sql-connector and
dbt-databricks read results through it, so a dbt model over a column with an
id, a timestamp in milliseconds, or any value above 2,147,483,647 could have
been reading corrupted numbers since v0.2.0.

What let it hide is an asymmetry: a type mismatch in a column, say
[[1], ["abc"]], already failed loudly by name. A range overflow passed
quietly. Loud on the wrong shape, silent on the wrong value.

The fix

Inferred columns — the whole column is read now, and INT widens to
BIGINT the moment one value needs 64 bits, including when the wide value
sits behind a null. Other type mixes are deliberately unchanged: the packer
already refuses those by name, and a loud failure beats a wrong number.

Engine-declared columns — inference alone was not enough. When the engine
supplies a schema the table is built from that hint and inference never runs,
so a declared INT holding an oversize value would still have truncated. That
conversion now refuses the value instead. Refusing is the honest answer:
the declared width belongs to the engine, not to us to widen after the fact.

Why it is only int32

The other two narrowing conversions in that file are a column position and a
column count, both bounded by the number of columns. The value path had
exactly one, and it is fixed.

Verification

Nine tests, three of which fail against v0.2.0's code and pass against this
one — two on the inferred path, including a wide value hidden behind a null,
and one on the engine-declared path:

--- FAIL: TestWideValueDoesNotTruncateAfterASmallFirstRow
--- FAIL: TestNullsDoNotHideAWideValue
--- FAIL: TestEngineDeclaredIntRefusesAnOversizeValue

A test that passes against the broken code would not have been evidence of
anything, so that is checked rather than assumed.

Upgrading

docker pull ghcr.io/calvinchengx/databricks-emulator:0.2.1

Nothing else changed. If you have results computed against 0.2.0 that included
values above 2,147,483,647, treat them as suspect and recompute.