diff --git a/README.md b/README.md index f6e5edc..07a1f44 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ cur.write_blob_column( ) ``` -Both work end-to-end in pure Python via the `lotofile` / `filetoblob` server functions intercepted at the `SQ_FILE` (98) wire-protocol level — no native machinery anywhere in the thread of execution. See [`docs/DECISION_LOG.md`](docs/DECISION_LOG.md) §10–11 for the architecture pivot that made this possible. +Both work end-to-end in pure Python via the `lotofile` / `filetoblob` server functions intercepted at the `SQ_FILE` (98) wire-protocol level — no native machinery anywhere in the thread of execution. See [`docs/DECISION_LOG.md`](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/docs/DECISION_LOG.md) §10–11 for the architecture pivot that made this possible. ## Direct stored-procedure invocation (fast-path) @@ -149,7 +149,7 @@ The fast-path RPC (`SQ_FPROUTINE` / `SQ_EXFPROUTINE`) bypasses PREPARE → EXECU Tested against IBM Informix Dynamic Server **15.0.1.0.3DE** (the official `icr.io/informix/informix-developer-database` Docker image). The wire protocol is stable across modern Informix versions; should work against 12.10+ unmodified. -For features that need server-side configuration (smart-LOBs, logged transactions), see [`docs/DECISION_LOG.md`](docs/DECISION_LOG.md): +For features that need server-side configuration (smart-LOBs, logged transactions), see [`docs/DECISION_LOG.md`](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/docs/DECISION_LOG.md): - Phase 7 — logged-DB transactions - Phase 8 — BYTE/TEXT (needs blobspace) - Phase 10/11 — BLOB/CLOB (needs sbspace + `SBSPACENAME` config + level-0 archive) @@ -168,7 +168,7 @@ Single-connection benchmarks against the dev container on loopback: | Pool acquire + query + release | 295 µs | ~3.4K queries/sec | | Cold connect (login handshake) | 11 ms | ~90 connections/sec | -**Performance gotcha**: `executemany(...)` under `autocommit=True` is **53× slower** than the same call inside a single transaction (server flushes the transaction log per row). For bulk loads, `autocommit=False` (default) + `conn.commit()` at the end. See [`docs/USAGE.md`](docs/USAGE.md) for the full performance tips section. +**Performance gotcha**: `executemany(...)` under `autocommit=True` is **53× slower** than the same call inside a single transaction (server flushes the transaction log per row). For bulk loads, `autocommit=False` (default) + `conn.commit()` at the end. See [`docs/USAGE.md`](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/docs/USAGE.md) for the full performance tips section. ### Compared to IfxPy (the C-bound PyPI driver) @@ -204,7 +204,7 @@ Head-to-head benchmarks against [IfxPy](https://pypi.org/project/IfxPy/) on iden These results are reproducible from `tests/benchmarks/compare/` — the Dockerfile, bench script, and README walk through every step. -Full methodology, IQR caveats, install gauntlet, and reproduction in [`tests/benchmarks/compare/README.md`](tests/benchmarks/compare/README.md). +Full methodology, IQR caveats, install gauntlet, and reproduction in [`tests/benchmarks/compare/README.md`](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/tests/benchmarks/compare/README.md). A note on IfxPy's install gauntlet: getting it to run on a modern system requires Python ≤ 3.11, setuptools <58, permissive CFLAGS, manual download of a 92 MB ODBC tarball, four `LD_LIBRARY_PATH` directories, and `libcrypt.so.1` (deprecated 2018, missing on Arch / Fedora 35+ / RHEL 9). `informix-db`'s install: `pip install informix-db`. @@ -217,7 +217,7 @@ A note on IfxPy's install gauntlet: getting it to run on a modern system require ## Development -The full test + lint workflow is in the [Makefile](Makefile). Quick summary: +The full test + lint workflow is in the [Makefile](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/Makefile). Quick summary: ```bash make test # 77 unit tests (no Docker) @@ -226,22 +226,22 @@ make bench # benchmark suite make lint # ruff ``` -For the smart-LOB tests specifically, the dev container needs additional one-time setup (blobspace + sbspace + level-0 archive). See [`docs/DECISION_LOG.md`](docs/DECISION_LOG.md) §10 for the `onspaces` / `onmode` / `ontape` commands. +For the smart-LOB tests specifically, the dev container needs additional one-time setup (blobspace + sbspace + level-0 archive). See [`docs/DECISION_LOG.md`](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/docs/DECISION_LOG.md) §10 for the `onspaces` / `onmode` / `ontape` commands. ## Documentation -- [**`docs/USAGE.md`**](docs/USAGE.md) — practical recipes: connections, parameter binding, type mapping, transactions, performance tips, scrollable cursors, BLOBs, async, TLS, locale/Unicode, error handling, known limitations -- [`tests/benchmarks/README.md`](tests/benchmarks/README.md) — performance baselines, headline numbers, how to run regressions +- [**`docs/USAGE.md`**](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/docs/USAGE.md) — practical recipes: connections, parameter binding, type mapping, transactions, performance tips, scrollable cursors, BLOBs, async, TLS, locale/Unicode, error handling, known limitations +- [`tests/benchmarks/README.md`](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/tests/benchmarks/README.md) — performance baselines, headline numbers, how to run regressions - `CHANGELOG.md` — phase-by-phase release notes ## Project history & design rationale This driver was built incrementally across 30 phases, each with a focused scope and decision log. The reasoning trail lives in: -- [`docs/PROTOCOL_NOTES.md`](docs/PROTOCOL_NOTES.md) — byte-level SQLI wire-format reference -- [`docs/JDBC_NOTES.md`](docs/JDBC_NOTES.md) — index into the decompiled IBM JDBC driver, used as a clean-room reference -- [`docs/DECISION_LOG.md`](docs/DECISION_LOG.md) — phase-by-phase architectural decisions, with the *why* preserved -- [`docs/CAPTURES/`](docs/CAPTURES/) — annotated socat hex-dump captures +- [`docs/PROTOCOL_NOTES.md`](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/docs/PROTOCOL_NOTES.md) — byte-level SQLI wire-format reference +- [`docs/JDBC_NOTES.md`](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/docs/JDBC_NOTES.md) — index into the decompiled IBM JDBC driver, used as a clean-room reference +- [`docs/DECISION_LOG.md`](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/docs/DECISION_LOG.md) — phase-by-phase architectural decisions, with the *why* preserved +- [`docs/CAPTURES/`](https://git.supported.systems/warehack.ing/informix-db/src/branch/main/docs/CAPTURES/) — annotated socat hex-dump captures Notable architectural pivots documented in the decision log: - **Phase 10/11** (smart-LOB read/write): used `lotofile`/`filetoblob` SQL functions + `SQ_FILE` protocol intercept instead of the heavier `SQ_FPROUTINE` + `SQ_LODATA` stack — ~3x smaller than originally projected diff --git a/pyproject.toml b/pyproject.toml index 53f556d..5484503 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [project] name = "informix-db" -version = "2026.05.05.12" +version = "2026.05.08" description = "Pure-Python driver for IBM Informix IDS — speaks the SQLI wire protocol over raw sockets. No CSDK, no JVM, no native libraries." readme = "README.md" license = { text = "MIT" } @@ -27,9 +27,11 @@ classifiers = [ dependencies = [] [project.urls] -Homepage = "https://github.com/rsp2k/informix-db" -Documentation = "https://github.com/rsp2k/informix-db/tree/main/docs" -Issues = "https://github.com/rsp2k/informix-db/issues" +Homepage = "https://informix-db.warehack.ing" +Documentation = "https://informix-db.warehack.ing" +Source = "https://git.supported.systems/warehack.ing/informix-db" +Issues = "https://git.supported.systems/warehack.ing/informix-db/issues" +Changelog = "https://git.supported.systems/warehack.ing/informix-db/src/branch/main/CHANGELOG.md" [project.optional-dependencies] dev = [ @@ -49,13 +51,15 @@ packages = ["src/informix_db"] # (the wheel doesn't ship these by default, but the sdist would). # See ~/.claude/rules/python.md for the full pre-publish PII audit playbook. exclude = [ - "CLAUDE.md", # operator-private context + "CLAUDE.md", # operator-private context ".env", ".env.local", ".env.*", - ".mcp.json", # may contain local filesystem paths - "build/", # decompiled JDBC, downloaded JARs + ".mcp.json", # may contain local filesystem paths + "build/", # decompiled JDBC, downloaded JARs "audits/", - "docs/CAPTURES/", # spike artifacts; tests can re-capture against the dev container - "tests/reference/", # Java reference client — spike infra + "docs/**", # protocol notes / decision log / captures — go to GitHub for the depth + "docs-site/**", # Astro/Starlight site sources — published at informix-db.warehack.ing + "tests/reference/**", # Java reference client — spike infra + "tests/benchmarks/.results/**", # pytest-benchmark cache (gitignored, but still ships unless excluded) ".pytest_cache/", ".ruff_cache/", ".mypy_cache/", "dist/", "*.egg-info/", ] diff --git a/tests/benchmarks/baseline.json b/tests/benchmarks/baseline.json index 0a46c11..babc93e 100644 --- a/tests/benchmarks/baseline.json +++ b/tests/benchmarks/baseline.json @@ -1,6 +1,6 @@ { "machine_info": { - "node": "rpm-bullet", + "node": "PLACEHOLDER", "processor": "", "machine": "x86_64", "python_compiler": "Clang 22.1.1 ",