Conversation
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
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
…#786) Answers the review ask to check the admin/monitoring capabilities. Every MON_GET_* / SYSIBMADM.* read is permission-gated and wrapped so a restricted account degrades to an empty panel instead of an error; a monitoring-authorized account (verified on Db2 v11.5.9.0) gets real figures. - getTableStats: real per-table rows from SYSCAT.TABLES — row count (CARD) and the RUNSTATS timestamp (STATS_TIME -> lastAnalyze), so the age of the count is visible. CARD = -1 / STATS_TIME NULL maps to "no stats" (0 rows, no lastAnalyze), never a literal -1. Size deferred (per-object only). - getActiveSessions: live connections from MON_GET_CONNECTION. - getSlowQueries: costliest cached statements from MON_GET_PKG_CACHE_STMT, filtered to rows that actually carry timings (NUM_EXEC_WITH_METRICS > 0). When the database's mon_req_metrics is off there are none, so the panel shows a Db2-specific empty state naming the exact enablement command rather than the Postgres pg_stat_statements wording (slowQueriesEmptyState label). - getStorageStats: per-tablespace sizing from MON_GET_TABLESPACE. - getIndexStats: per-index rows from SYSCAT.INDEXES/INDEXCOLUSE with scan counts LEFT JOINed (RTRIM) from MON_GET_INDEX. - getPerformanceMetrics/getHealth: cache hit ratio from SYSIBMADM.BP_HITRATIO (works regardless of mon_obj_metrics, unlike MON_GET_BUFFERPOOL) and deadlocks from MON_GET_DATABASE. - getOverview: uptime (computed IN the database to avoid a timezone-driven negative), database size (+ databaseSizeBytes so fleet-health totals it), table/index counts, active connections, and maxConnections (maxappls). Hardening: - validate() rejects ';' in host/database/user/password: the DRDA attribute list has no escaping for its delimiter, so a value with ';' misparses (a password fails auth) or injects an attribute (PWD=x;SECURITY=NONE connected in testing). Pasted connection strings remain the user's own responsibility. - prepareQuery: pin the trailing-semicolon and trailing-line-comment cases (the clause splices before the trivia, never inside a comment). Tests updated to 100% line coverage of db2.ts; docs/providers/db2.md rewritten to describe each surface, its source, and its honest limits (per-object size, slow-query timings needing mon_req_metrics, the data/index Storage Breakdown that ADMIN_GET_TAB_INFO makes too slow to fill).
af19bea to
173c834
Compare
Brings in the object model (libredb#811, libredb#820, libredb#831). Conflicts resolved in database-compose.yml (both services kept), src/lib/db/factory.ts (main's comment, db2 kept in the type list), bun.lock (regenerated by bun install) and the operator bundle CSV (taken from main, regenerated in a later commit). This commit does not typecheck on its own: Db2Provider still implements the removed getSchema() instead of the object methods. The next commit converts it.
- engine-support: the DatabaseType arm parser read ids as [a-z]+, so "db2" failed its own arm-count check. Ids may now carry a digit after the first letter. - README_ur.md arrived on main after this branch; it gets the Db2 row and count so readme:check passes. - AWS listing: the engines marker is 17. Azure: the 100-character summary no longer names Db2 (103 characters); the short description still does. - query-generators tests: generateTableQuery and generateSelectQuery take a path since libredb#811. - package.json: the trustedDependencies note named "these three" and now lists four, with the reason ibm_db runs an install script. - operator bundle regenerated with make -C operator bundle.
) getSchema() was removed by libredb#811, so Db2Provider now implements the object surface instead, measured against icr.io/db2_community/db2:12.1.0.0 with a new fixture in docker/db2-init (mounted at /var/custom in database-compose). - One container level, the schema, from SYSCAT.SCHEMATA. Every schema is listed except SYS%, NULLID and SQLJ; owner type cannot separate them because an implicitly created user schema is owned by SYSIBM too. - Nine kinds: table, view, materialized query table, alias, sequence, module, procedure, function, trigger. A routine is addressed by SPECIFICNAME, so overloads stay distinct. A trigger nests under its table only when both share a schema. - describeObjects reads a whole relation kind in four round trips, with the caller's bound sent as FETCH FIRST limit + 1. - readObjectSource returns the stored CREATE text from SYSCAT.VIEWS, ROUTINES and TRIGGERS; an external or sourced routine has NULL text and gets a refusal part that says so. - Column types carry length, precision and scale, which schema diff and the migration generator need. - The foreign key join now matches the referenced key on its table too. A constraint name is unique per table, not per schema, so the previous join could pair one foreign key with every same-named key in the schema. - No kind is editable. docs/providers/db2.md records what was measured about CREATE OR REPLACE. The provider moves to sql/db2/index.ts, with the catalog statements and row mapping in sql/db2/objects.ts, both at 100% line coverage.
RUNSTATS and REORG run as CALL SYSPROC.ADMIN_CMD('...'), so the table name
sits inside a SQL string literal. It was escaped only as a delimited
identifier, so a name containing ' ended the literal early. Measured on Db2
12.1 with a table named O'Brien: the old form answered SQL0010N, and with the
quote doubled both operations succeed.
|
Thanks @nycjay. The object browser was rebuilt in #811, #820 and #831, so I converted this branch rather than ask you to chase a moving interface. Main is merged in, the provider now implements the object surface (schemas, nine kinds, definition text), and CI is green. I also fixed a foreign key join that matched constraint names per schema instead of per table, and quote escaping in the ADMIN_CMD maintenance target. Two distribution problems remain, and neither shows up in this PR's CI:
The second is a Dockerfile fix. The first needs a supported arm64 path for the driver, so I am putting this PR on hold until we find one. |
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
|
I am thinking about it: we can generate a new tag image without ARM |
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
Related Issue
Closes #786
Changes Made
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
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):
Test Environment
Screenshots (if applicable)
Checklist
bun run test:coverageandbun run coverage:check)src/lib/db/providers/, I updated the matchingdocs/providers/documentation andtests/integration/db/tests in the same PR (provider triad)Additional Notes
This PR adds a runtime dependency (ibm_db), unlike the recent HTTP-only providers. Rationale is under Changes Made.