Features
Oninit® MySQL-2-Informix — Features
The proxy's job is to make Informix look like MySQL on the wire, without losing fidelity at the type or catalog layer. The feature set below is what makes that round-trip work for real applications.
Wire-protocol coverage
| Feature | Status |
|---|---|
| MySQL 4.1 handshake (capability flags, plugin name, salt) | Implemented; matches the negotiation existing clients in the wild rely on. |
| Server greeting and OK / ERR / EOF packets | Implemented. |
| Query, field-definition, and result-row packets (text protocol) | Implemented; binary-safe length-encoded strings, embedded NUL preserved. |
| COM_INIT_DB (USE database) | Reconnects the Informix backend session to the named database. |
| COM_PING, COM_QUIT, COM_FIELD_LIST | Implemented. |
| Per-connection threading | One pthread per accepted client; each holds its own Informix backend session. |
Catalog translation
MySQL catalog statements are rewritten as Informix system-catalog SELECTs and the result reshaped to look like the MySQL output that client tooling and ORMs expect.
| MySQL statement | Informix catalog tables consulted |
|---|---|
| SHOW DATABASES | sysmaster:sysdatabases |
| SHOW [FULL] TABLES [FROM db] [LIKE pat] | systables |
| SHOW CREATE TABLE <name> | syscolumns, systables, sysindexes, sysconstraints, sysxtdtypes |
| SHOW INDEX FROM <table> | sysindexes, syscolumns, systables, sysconstraints |
| SHOW GRANTS [FOR user] | systabauth, systables |
| SHOW TRIGGERS [FROM db] | systriggers, systables |
| SHOW CREATE VIEW <name> | sysviews, systables |
| SHOW CREATE TRIGGER <name> | systriggers, systrigbody |
Built-in responses (no Informix round-trip)
| MySQL statement | Response |
|---|---|
| SELECT 1 | Single-row literal. |
| SELECT VERSION() / SHOW VERSION | Oninit MySQL-2-Informix version string. |
| SELECT USER() | The current session user. |
| SELECT DATABASE() | The currently-active database. |
DDL rewriting
CREATE TABLE is intercepted, parsed column by column, and each MySQL type is rewritten to its Informix equivalent before the statement is forwarded. The complete mapping table is on the Type Mapping page. The reverse mapping is applied by SHOW CREATE TABLE so the output reads MySQL-shaped — an ORM that introspected the schema for code generation, or a developer running SHOW CREATE TABLE from mysql(1), sees the same column declarations they wrote.
MySQL-only attributes are stripped at translation time: UNSIGNED, AUTO_INCREMENT, ZEROFILL, ENGINE=..., DEFAULT CHARSET=..., COLLATE=..., and backtick-quoted identifiers. AUTO_INCREMENT=N seed values are translated into the Informix SERIAL(N) / BIGSERIAL(N) seed clause so the next-id semantics match. MySQL's b'01010' bit-literal syntax is rewritten to its decimal-integer equivalent in a pre-pass so it can survive into BIT(N)-mapped Informix columns transparently.
Database management
| MySQL statement | Action |
|---|---|
| CREATE DATABASE <name> [WITH BUFFERED LOG] | Forwarded to Informix. |
| DROP DATABASE [IF EXISTS] <name> | Forwarded to Informix. |
| USE <database> / COM_INIT_DB | Reconnects the Informix backend session to the specified database. |
INSERT into BYTE / TEXT columns (m2is)
Informix rejects inline-literal INSERTs into BYTE and TEXT columns (Error 274). MySQL clients almost always emit exactly that shape — an ORM batching binary payloads sends INSERT INTO t VALUES (1, 'data') with the bytes inline. The SQLI-protocol backend bridges the gap by detecting the shape and rewriting it to a bound INSERT on the wire:
| Step | What happens |
|---|---|
| 1. Parse the VALUES clause | Per-position literal kinds extracted: number, string, hex literal, NULL. |
| 2. Look up the table's column types | A per-connection schema cache (populated lazily from the syscolumns catalog) reports which slots are BYTE / TEXT. |
| 3. Rewrite the SQL | Each blob-column literal is replaced with a single ? placeholder; non-blob literals stay inline as-is. |
| 4. Emit the bound wire form | SQ_PREPARE + SQ_NDESCRIBE + SQ_BIND (mixed types) + SQ_BBIND + SQ_BLOB stream + SQ_EXECUTE. The SQ_BLOB stream carries the actual blob bytes. |
| 5. Invalidate on shape change | DROP TABLE, ALTER TABLE, RENAME TABLE, and TRUNCATE drop the cached entry so the next INSERT re-reads the catalog. |
The translation is invisible to the MySQL client: it sees a normal INSERT round-trip with the affected-row count. Coverage extends to column-list INSERTs (INSERT INTO t (id, payload) VALUES (1, 'x')), multi-row VALUES (INSERT INTO t VALUES (1, 'a'), (2, 'b') — split into N single-row INSERTs since Informix doesn't accept multi-row natively), NULL into a blob column, and mixed NULL+non-NULL across rows of the same statement. The ESQL/CSDK backend doesn't have an equivalent path — the CSDK returns Error 274 for the same SQL.
Other DML
UPDATE, DELETE, generic SELECT, and other DDL not covered above are forwarded to Informix verbatim. SELECT results come back through a cursor; DML returns an OK packet with affected-row count.
Pure-C, dependency-light by design
- Single binary per backend; no external runtime deps beyond libc, pthreads, and (for the ESQL backend) the Informix CSDK.
- The SQLI-protocol backend has no CSDK dependency on the deployment host; the codec, transport, login, tuple decoder, bind encoder, and blob streamer are pure C.
- The license-key code is intentionally pure C with its own SHA-256 and HMAC-SHA256 — no OpenSSL, no GnuTLS.
- Validated against IBM Informix Dynamic Server for every classification, translation, and INSERT-routing behaviour described above.