Skip to content

feat: opt-in IBM DB2 support behind the db2 build tag#140

Open
afalahi wants to merge 4 commits into
mainfrom
ali/db2-support
Open

feat: opt-in IBM DB2 support behind the db2 build tag#140
afalahi wants to merge 4 commits into
mainfrom
ali/db2-support

Conversation

@afalahi

@afalahi afalahi commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Description

  • Bug fix
  • New feature

Adds IBM DB2 as a supported engine, fully isolated behind a db2 Go build tag.

DB2 is unlike every other engine here: no pure-Go driver exists (the only two DRDA-in-Go attempts are abandoned), so the only viable driver is IBM's github.com/ibmdb/go_ibm_db — cgo, linking IBM's native ODBC/CLI driver ("clidriver"). Left unguarded, that import breaks default builds, cross-compilation, and the goreleaser release pipeline. This PR quarantines it so the cost is paid only by builds that opt in.

Default build: zero behavior change

  • make build, go test, lint, and the release pipeline stay pure Go — no IBM software, no CGO flags, no env vars, CGO_ENABLED=0 cross-compilation intact.
  • A default binary given a db2:// DSN fails fast with: baton-sql: DB2 support not compiled into this binary; rebuild with -tags db2 (see docs/db2.md).
  • DSN parsing/conversion lives in an untagged file, so it is compiled and unit-tested in every build.

What -tags db2 adds

  • pkg/database/db2: driver registration (tagged), stub Connect (!db2), URL→native DSN conversion.
  • Hardened DSN handling: credentials containing DB2 metacharacters are ODBC brace-quoted (a ; in a password would otherwise silently truncate it or inject connection keywords), URL query params are forwarded as connection keywords, and params colliding with URL-derived keywords are rejected.
  • Explicit DB2 cases for parameter placeholders and timestamp parsing in pkg/bsql.

Build & distribution

  • make build-db2 — CGO flags scoped inline to that one command (never exported), -tags db2.
  • Binaries are relocatable: they resolve the clidriver next to the executable first ($ORIGIN/clidriver/lib on Linux, @executable_path on macOS with the load command rewritten to @rpath), falling back to the build-time DB2HOME. No LD_LIBRARY_PATH/DYLD_LIBRARY_PATH at run time in either layout.
  • make package-db2 — self-contained ~55 MB tarball (binary + clidriver + IBM's license/ directory, which the redistribution terms require shipping). Customers untar and run; no installation, no root, no env vars.
  • docs/db2.md — setup, troubleshooting, Docker example, and redistribution-licensing notes (including the GSKit TLS and Db2 Connect caveats).

Verification

  • Default build with all DB2 env vars scrubbed; CGO_ENABLED=0; GOOS=linux cross-compile; full test suite; golangci-lint (no new findings); go vet -tags db2.
  • Relocatable lookup proven strictly on both platforms: macOS with the fallback rpath stripped from the binary, Linux running the bundle from an arbitrary path in a bare debian:bookworm-slim container with the fallback pointed at a nonexistent directory.
  • That Linux run surfaced the clidriver's one OS-level dependency, libxml2 — documented and added to the Docker example (it is preinstalled on full server distros, absent in slim images).

Notes for reviewers

  • Most of the diff is vendor/github.com/ibmdb + vendor/github.com/ibmruntimes; the reviewable surface is pkg/database/db2, small switch additions in pkg/database/database.go and pkg/bsql, the Makefile targets, and docs.
  • Platform limits are IBM's, not ours: no Linux ARM64 clidriver, glibc only (no Alpine/musl).
  • The DB2 variant cannot ride the standard goreleaser release (cgo); it ships as the package-db2 bundle or a Docker image until releng wants to own a DB2 artifact.

Useful links:

afalahi added 4 commits July 9, 2026 06:55
The go_ibm_db driver is cgo and links IBM's native CLI driver, so it is
excluded from default builds: make build stays pure Go (CGO_ENABLED=0,
cross-compilable, no clidriver needed) and a db2:// DSN on a default
binary returns a clear rebuild hint. make build-db2 scopes the CGO flags
to that one invocation and bakes the library path into the binary
(rpath on Linux, install_name_tool on macOS) so no LD_LIBRARY_PATH or
DYLD_LIBRARY_PATH is needed at run time.

URL-form DSNs brace-quote credentials containing DSN metacharacters and
forward query parameters as DB2 connection keywords, rejecting
collisions with URL-derived keywords.
The db2 binary now resolves the clidriver relative to itself first
($ORIGIN/clidriver/lib on Linux, @executable_path on macOS) before
falling back to the build-time DB2HOME, so make package-db2 can ship a
single archive (binary + clidriver + IBM license files) that customers
untar and run anywhere with no installation or environment variables.
Verified end-to-end on macOS and on linux/amd64 in a bare
debian:bookworm-slim container; the clidriver's one OS dependency,
libxml2, is documented and added to the Docker example.
@afalahi afalahi requested a review from a team July 9, 2026 14:26
Comment thread pkg/database/db2/dsn.go
// Build DB2 DSN format
// HOSTNAME=SERVER_NAME;PORT=DB_PORT;DATABASE=DATABASE_NAME;UID=USER_ID;PWD=PASSWORD
var dsnParts []string
dsnParts = append(dsnParts, fmt.Sprintf("HOSTNAME=%s", hostname))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Suggestion: hostname is the only URL-derived value not passed through quoteDB2Value, unlike UID/PWD/DATABASE and query keywords. Go's url.Parse permits ; in the host (a sub-delim), so a configured DSN like db2://h;SECURITY=NONE@host/db would splice an extra HOSTNAME=h;SECURITY=NONE keyword pair into the DB2 connection string, bypassing the reserved-keyword rejection the rest of the code enforces. Low exploitability since the DSN comes from operator config, but for consistency run hostname through quoteDB2Value (or reject ;{= in it). (medium confidence)

@linear-code

linear-code Bot commented Jul 9, 2026

Copy link
Copy Markdown

CXP-750

@github-actions

github-actions Bot commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Connector PR Review: feat: opt-in IBM DB2 support behind the db2 build tag

Blocking Issues: 0 | Suggestions: 1 | Threads Resolved: 0
Criteria: Criteria status: loaded .claude/skills/ci-review.md from trusted base c68e5c138d45.
Review mode: full
View review run

Review Summary

Scanned the full PR diff for security and correctness. This adds opt-in IBM DB2 support gated behind the db2 build tag: a cgo Connect (//go:build db2) plus a //go:build !db2 stub that returns a clear rebuild error, a build-tag-free DSN converter with table-driven tests, DB2 wired into the engine enum / placeholder / time-parse switches, Makefile build-db2/package-db2 targets, docs, and the vendored go_ibm_db driver. Build-tag isolation is correct (default builds need no IBM software), go.mod/go.sum/vendor/modules.txt are consistent with the vendored code, and the DSN converter carefully quotes UID/PWD/DATABASE and rejects reserved/duplicate query keywords. One non-blocking hardening gap: the hostname alone skips that quoting. No blocking issues found.

Security Issues

None found.

Correctness Issues

None found.

Suggestions

  • pkg/database/db2/dsn.go:75hostname is not run through quoteDB2Value like the other URL-derived values, allowing a semicolon-bearing configured host to splice extra DB2 connection keywords into the DSN.
Prompt for AI agents
Verify each finding against the current code and only fix it if needed.

## Suggestions

In `pkg/database/db2/dsn.go`:
- Around line 51-75: The `hostname` value from `parsedURL.Hostname()` is interpolated
  directly into the DSN as `HOSTNAME=%s` without going through `quoteDB2Value`, unlike
  UID/PWD/DATABASE and the forwarded query keywords. Go's url.Parse permits a semicolon in
  the host, so a DSN such as `db2://h;SECURITY=NONE@host/db` would inject an extra
  `HOSTNAME=h;SECURITY=NONE` keyword pair into the semicolon-delimited DB2 connection
  string, bypassing the reserved-keyword rejection enforced elsewhere. Fix by passing
  hostname through `quoteDB2Value` (handling the returned error) before building the
  HOSTNAME part, or reject hostnames that contain semicolons, braces, equals signs, or spaces.

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No blocking issues found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant