Ryan Malloy ddac40ff0b Phase 2 foundations: _types.py, converters.py, post-login protocol notes
Decoded the post-login execution flow from docs/CAPTURES/02-select-1.socat.log:

SQ_PREPARE format (validated against both observed PREPAREs):
  [short SQ_PREPARE=2]
  [short flags=0]
  [int sqlLen]            ← SQL byte count, NOT including nul
  [bytes sql]
  [byte 0]                ← nul terminator
  [short 0x0016]          ← observed 22; cursor options? statement type?
  [short 0x0031]          ← observed 49; identical across both PREPAREs
  [short SQ_EOT=12]

SQ_TUPLE format (definitive):
  [short SQ_TUPLE=14]
  [int 0]                  ← flags / reserved
  [short payloadLen]
  [bytes payload]          ← column values back-to-back, per type encoding

SQ_DONE format (partial — see PROTOCOL_NOTES.md §6e for what's known)

JDBC's full prepare/fetch/release sequence (PREPARE → DESCRIBE → ID(3
=cursor name) → ID(9=NFETCH) → TUPLE → DONE → ID(10=close) →
ID(11=release)) documented in §6c. The action codes inside SQ_ID
roughly map to other SQ_* tag values from IfxMessageTypes.

For Python MVP we'll likely try SQ_COMMAND=1 (execute-immediate)
first — it might let us skip the cursor lifecycle for parameterless
queries.

New modules:

src/informix_db/_types.py — IfxType IntEnum ported from
  com.informix.lang.IfxTypes. All IDS internal type codes (CHAR=0,
  SMALLINT=1, INT=2, ..., BOOLEAN=45, BIGINT=52, BIGSERIAL=53, CLOB=101,
  BLOB=102) plus the high-bit flags (NOTNULLABLE=0x100 etc) and helpers
  base_type() / is_nullable() to strip and inspect the flag byte.

src/informix_db/converters.py — wire-bytes → Python decoders for the
  Phase-2 MVP type set: SMALLINT, INT, BIGINT, SMFLOAT, FLOAT, CHAR,
  VARCHAR, NCHAR, NVCHAR, LVARCHAR, BOOL, DATE. Plus FIXED_WIDTHS table
  for the row decoder. ENCODERS dict declared empty (Phase 4 fills it
  in for parameter binding).

DATE handling uses Informix epoch (1899-12-31, day 0); 4-byte BE int
day count → datetime.date. Smoke-tested decoders all return correct
Python values.

Cursor / _resultset implementation NOT in this commit — they need
deeper SQ_DESCRIBE byte-layout analysis and the SQ_ID sub-action
vocabulary characterization. Both are bounded-but-substantial Phase 2
tasks deferred to a fresh session.

40 unit tests still passing, ruff clean.
2026-05-02 20:24:25 -06:00
..