Skip to content

The SQLI wire protocol

SQLI is Informix’s wire protocol — the same protocol IBM’s CSDK and JDBC driver speak. It’s a binary, length-prefixed PDU stream over a single TCP connection.

This page is a short tour. The byte-level reference (with hex annotations) lives in docs/PROTOCOL_NOTES.md in the repo.

Every PDU starts with a 1-byte tag and (mostly) ends with a 2-byte EOT marker. Common tags:

TagHexDirectionPurpose
SQ_INFO0x01→SInitial capability/identity exchange
SQ_VERSION0x14S→Server version response
SQ_PASSWD0x18→SAuthentication
SQ_DBOPEN0x24→SOpen database
SQ_PREPARE0x02→SPrepare statement
SQ_DESCRIBE0x08→SDescribe column structure
SQ_OPEN0x06→SOpen cursor
SQ_FETCH0x04→SFetch rows
SQ_TUPLE0x09S→One row of data
SQ_ID0x37S→SQLCODE / status code
SQ_FILE0x62bothSmart-LOB transfer
SQ_EOT0x0cbothEnd-of-transmission

The trailing 00 0c (length=0, tag=0x0c) marks the end of every multi-PDU response.

Annotated output from docs/CAPTURES/01-connect-only.socat.log:

> OUT 01 c3 01 3c 00 00 00 64 00 65 00 00 00 3d 00 06 ; SQ_INFO
49 45 45 45 4d 00 00 6c 73 71 6c 65 78 65 63 00 ; "IEEEM..lsqlexec"
00 00 00 00 00 00 06 39 2e 32 38 30 00 00 0c 52 ; ".......9.280...R"
44 53 23 52 30 30 30 30 30 30 00 00 05 73 71 6c ; "DS#R000000...sql"
69 00 00 00 01 3c 00 00 00 00 00 00 00 00 00 01 ; "i....<.........."
...
< IN 01 14 02 3c 10 00 00 64 00 65 00 00 00 3d 00 06 ; SQ_VERSION
49 45 45 45 49 00 00 6c 73 72 76 69 6e 66 78 00 ; "IEEEI..lsrvinfx."
00 00 00 00 00 00 2f 49 42 4d 20 49 6e 66 6f 72 ; "....../IBM Infor"
6d 69 78 20 44 79 6e 61 6d 69 63 20 53 65 72 76 ; "mix Dynamic Serv"
65 72 20 56 65 72 73 69 6f 6e 20 31 35 2e 30 2e ; "er Version 15.0."

The payload of SQ_INFO is a sequence of length-prefixed strings: byte-order marker (IEEEM = big-endian), client app name (sqlexec), client version (9.280), build ID, protocol token (sqli), feature flags. The server’s SQ_VERSION response mirrors this with the server’s own identification.

The full lifecycle for SELECT id FROM users WHERE id = ?:

→ SQ_PREPARE "SELECT id FROM users WHERE id = ?"
← SQ_ID (statement ID, parameter shape, ...)
→ SQ_DESCRIBE
← SQ_DESC (column descriptors: "id" SMALLINT)
→ SQ_OPEN (parameter values: 42)
← SQ_ID (cursor ID)
→ SQ_FETCH
← SQ_TUPLE (id=42)
← SQ_TUPLE (or SQ_DONE)
→ SQ_CLOSE (release cursor)
← SQ_ID

For pipelined executemany, the driver sends SQ_OPEN+SQ_FETCH (or SQ_BIND+SQ_EXEC) for all N rows back-to-back without waiting for responses, then drains all responses at the end. This is what gives the 1.6× win over IfxPy on bulk inserts — see Bulk inserts.

SQ_FILE (0x62) is a self-contained PDU type that carries chunks of BLOB/CLOB data. It’s used by Informix’s lotofile and filetoblob server functions. The driver intercepts these PDUs at the wire level and reassembles them client-side — no SQ_FPROUTINE / SQ_LODATA machinery needed.

This was the architectural pivot in Phase 10/11 that made smart-LOBs work end-to-end in pure Python. Reading and writing GB-sized BLOBs goes through the same socket as any other query.