1 Commits

Author SHA1 Message Date
36478f02c4 Decode the SQ_PROTOCOLS capability negotiation (2026.08.27)
Closes the last open item from the Informix 12 field report. The driver
hardcodes several wire-framing choices that SQLI actually negotiates.
Those choices are correct on every server we've measured, but "correct
as far as we know" and "checked" are different things, and a framing
mismatch corrupts rows silently.

We were already sending SQ_PROTOCOLS with the same 8-byte client offer
IBM's JDBC driver uses, and discarding the reply. Now we decode it.

New informix_db.ServerCapabilities, reachable from any connection:

    conn.server_capabilities.four_byte_offset
    conn.server_capabilities.varchar_var_len
    conn.server_capabilities.violated_assumptions()   # [] when we agree
    conn.server_version

violated_assumptions() names each place we emit or parse a fixed wire
shape that is actually capability-gated. Non-empty at connect time logs
a warning naming the bit, so an untested server produces a diagnosable
complaint instead of quiet corruption.

Nothing branches on these bits yet — this is observation and validation
only. The hardcoded framing is correct on all three supported servers,
and rewriting working parse paths to be conditional without a server
that needs it trades certainty for risk.

The measurement, and why 12/14/15 are interchangeable:

  15.0.1.0.3       bdbe9ffe7fb7ffef ff
  14.10.FC7W1      bdbe9ffe7fb7ffef f8
  12.10.FC12W1DE   bdbe9ffe7fb7ffef f0
                   ^^^^^^^^^^^^^^^^ identical

The first 64 bits are byte-identical. Those releases don't merely behave
alike, they negotiate exactly the same capability set.

Two details worth recording. The reply is NINE bytes; JDBC's
enhancedProtocolMechanism switches on case 0..7 and drops the ninth, so
its BitSet(64) never sees it — yet that dropped byte is the only part
that differs between releases. And Cap_1 in the login response is not a
server version, it's the client's declared protocol level echoed back,
which is why JDBC tests == 316 rather than >=. The version string there
is the internal one: 12.10 reports 9.56, 14.10 reports 9.59. At the
protocol level both really are 9.x servers.

This also retires isUSVER as a red herring: it's one of six bits JDBC
pre-sets for any non-zero Cap_1, and Java's BitSet.set never clears, so
it is true on every modern server regardless of the mask.

Separately, fixed __version__. The distribution was renamed informix-db
-> informix-driver on 2026-05-08 but __init__ kept looking up the old
name. importlib.metadata needs the distribution name, not the module
name, and the miss fails silently — so every install of the renamed
package has reported "0.0.0+local". It escaped notice because a stale
informix-db distribution lingered in the dev venv and answered the
query. tests/test_package_metadata.py now pins the name against
[project].name; verified it catches the bug by reintroducing it.

247/247 integration on 15, 14.10, and 12.10. 120 unit tests.
2026-08-27 02:18:08 -06:00