Skip to content

feat(db): add IBM Db2 LUW provider (#786) - #787

Open
nycjay wants to merge 1 commit into
libredb:mainfrom
nycjay:feat/786-db2-luw-provider
Open

feat(db): add IBM Db2 LUW provider (#786)#787
nycjay wants to merge 1 commit into
libredb:mainfrom
nycjay:feat/786-db2-luw-provider

Conversation

@nycjay

@nycjay nycjay commented Sep 11, 2026

Copy link
Copy Markdown

Description

Adds IBM Db2 LUW as a database provider (type-id db2), over the DRDA protocol with the native ibm_db driver. It extends SQLBaseProvider and overrides only prepareQuery(), because Db2's SQL is Oracle-shaped (double-quoted identifiers, FETCH FIRST / OFFSET ... FETCH NEXT paging).

Type of Change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • Documentation update
  • Code refactoring
  • Performance improvement
  • Test addition or update

Related Issue

Closes #786

Changes Made

  • Provider (src/lib/db/providers/sql/db2.ts). Identifier escaping is inherited from SQLBaseProvider unchanged; prepareQuery() is the only dialect override. Schema reads the SYSCAT.* catalog views scoped to CURRENT SCHEMA.
  • Native driver, not REST. ibm_db (pinned 4.0.1, in trustedDependencies), added to serverExternalPackages in next.config.ts so Turbopack doesn't bundle the addon. Chosen over the Db2 REST /execsql path because REST is deployed separately from the engine and is commonly disabled, while ibm_db connects straight to the engine and works air-gapped. The tradeoff is a native addon with an install-time driver download.
  • Per-table maintenance. analyze runs RUNSTATS, optimize runs REORG, both through SYSPROC.ADMIN_CMD. Db2 has no whole-database form, so there is no global maintenance card.
  • Bound parameters. query(sql, params) forwards the values array to the driver so inline row edit (UPDATE ... WHERE pk) works. A no-params call uses the two-arg driver form, because ibm_db reads a function in the params slot as the callback and an empty array against a marker-less statement raises CLI0100E.
  • Migration generator. A Db2 branch emits SET DATA TYPE, plus a commented REORG advisory for the alters Db2 documents as leaving a table REORG-pending (drop column, retype, nullability change). It emits guidance rather than running a REORG, which can be slow and lock-heavy on a large table.
  • Registration surfaces. types, factory, ui-config, icon, connection-string parser (db2://), positional placeholder (?), export, showcase, query generators.
  • Docs, tests, fixtures. docs/providers/db2.md, tests/integration/db/db2-provider.test.ts (100% line coverage of db2.ts), a db2 service in database-compose.yml, and the external-engine count copy across READMEs, docs, deploy listings, charts and operator.

Deliberate follow-ups, not gaps: supportsExplain: false (Db2 EXPLAIN populates explain tables rather than returning a single-statement plan, same as MSSQL #126), supportsTransactions: false (no held-session transaction wired, so the toolbar and SANDBOX stay hidden), monitoring panels return neutral empties instead of fabricated zeros, and columnTypes is omitted because the high-level query() exposes no declared type.

Testing

  • I have tested this locally
  • I have added/updated tests
  • All existing tests pass

Verified end-to-end against a live Db2 v11.5.9.0 server, driving the app with Playwright and the API: connect and schema tree (columns, PK/nullable, FKs, indexes, untrimmed names); paging (FETCH FIRST, then OFFSET ... FETCH NEXT, an already-bounded query left alone); CRUD with read-your-writes; value fidelity (BIGINT → lossless string, BLOB → Buffer, CLOB/DECFLOAT/XML, CHAR(n) space-padded as expected); error paths (SQL0204N, SQL0104N throw rather than returning zero rows); per-table RUNSTATS/REORG plus rejection of a global or unsupported op; capability-gated UI (no Explain button or tab, no transaction toolbar/SANDBOX, Create Table present, inline-edit present); and an inline row edit persisting through UPDATE ... WHERE pk. ibm_db loads under both Bun and Node.

Two commands I could not run locally (per the "CI is the merge gate" note in CONTRIBUTING):

  • bun run test:coverage / bun run coverage:check — the test:coverage:core step runs bash tests/run-core.sh, whose line 41 uses mapfile (a bash 4+ builtin), and this machine has only macOS /bin/bash 3.2. The Db2 suites pass under bun run test and db2.ts is at 100% line coverage from the integration test, but CI needs to confirm the gate.
  • bun run chart:check — no Helm locally. The chart and operator count copy was edited by hand to match README.md.

Test Environment

  • LibreDB Studio Version: main
  • Browser: Chromium (Playwright)
  • OS: macOS
  • Node.js/Bun Version: Bun 1.4.0 / Node v26.8.2
  • Database Type: IBM Db2 LUW 11.5.9.0

Screenshots (if applicable)

Checklist

  • My code follows the project's code style guidelines
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have updated the documentation accordingly
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes
  • The required CI test job passes the 100% line-coverage gate (bun run test:coverage and bun run coverage:check)
  • If I changed src/lib/db/providers/, I updated the matching docs/providers/ documentation and tests/integration/db/ tests in the same PR (provider triad)
  • Any dependent changes have been merged and published

Additional Notes

This PR adds a runtime dependency (ibm_db), unlike the recent HTTP-only providers. Rationale is under Changes Made.

Connect to Db2 LUW over DRDA with the native ibm_db driver. The provider
extends SQLBaseProvider and overrides only prepareQuery(): Db2's SQL is
Oracle-shaped (double-quoted identifiers, FETCH FIRST / OFFSET ... FETCH
NEXT paging), so identifier escaping is inherited unchanged. Schema reads
the SYSCAT.* catalog views scoped to CURRENT SCHEMA. Per-table maintenance
maps analyze to RUNSTATS and optimize to REORG through SYSPROC.ADMIN_CMD;
Db2 has no whole-database form, so there is no global maintenance card.

Bound ? parameters are forwarded to the driver so inline row edit works
(UPDATE ... WHERE pk); verified end-to-end against Db2 v11.5.9.0.

Capabilities are conservative and honest: supportsExplain false (Db2
EXPLAIN populates explain tables rather than returning a single-statement
plan, same as MSSQL libredb#126), supportsTransactions false (no held-session
transaction wired, so the toolbar and SANDBOX stay hidden), and monitoring
panels return neutral empties instead of fabricated zeros. All documented
as intentional follow-ups.

Includes the provider triad (db2.ts, docs/providers/db2.md, and the
integration test at 100% line coverage), the registration surfaces, a db2
service in database-compose.yml, and the external-engine count copy.

Closes libredb#786
@socket-security

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Addednpm/​ibm_db@​4.0.18910010088100

View full report

@cevheri cevheri added the loop:needs-moderator-action Flagged by the maintainer loop: suspicious content or a decision only a human can make label Sep 11, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

loop:needs-moderator-action Flagged by the maintainer loop: suspicious content or a decision only a human can make

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[FEATURE] Add IBM Db2 LUW provider

2 participants