Skip to content

(MOT-4216) fix(database): resolve omitted db to the sole/primary pool - #585

Merged
andersonleal merged 4 commits into
mainfrom
fix/database-optional-db
Jul 24, 2026
Merged

(MOT-4216) fix(database): resolve omitted db to the sole/primary pool#585
andersonleal merged 4 commits into
mainfrom
fix/database-optional-db

Conversation

@andersonleal

@andersonleal andersonleal commented Jul 24, 2026

Copy link
Copy Markdown
Collaborator

Why

Every sub-agent session in the rctest orchestration runs (reactor, finalizer, repair, orchestrator — rctest5-K7mQ most recently) burned its first database::* call on serialization error: missing field 'db'. LLM callers routinely omit db; a hard serde failure there is a wasted round-trip in every live session.

What

  • db is now optional on query, execute, executeBatch, transaction, prepareStatement, beginTransaction (documented in the function schema, so callers see it's optional).
  • Resolution (AppState::resolve_db): explicit name → unchanged (unknown names still get UNKNOWN_DB); omitted → the sole configured pool, else primary when several exist, else the new MISSING_DB error which enumerates the available names — same self-correction pattern as MOT-4208's UNKNOWN_DB.

Tests

  • omitted db on a sole pool executes against it
  • omitted db among many pools prefers primary
  • omitted db with no unambiguous default → MISSING_DB with sorted available list
  • function schema no longer marks db required
  • MISSING_DB wire-envelope serialization

222 database tests pass; clippy clean.

Closes MOT-4216.

Summary by CodeRabbit

  • New Features

    • Database selection is now optional for queries, executions, prepared statements, batches, and transactions.
    • Requests automatically use the sole configured database or the primary database when available.
    • Clear errors now identify available databases when selection is ambiguous.
  • Bug Fixes

    • Prevented transaction-control SQL from running through pooled operations.
    • Automatically rolls back leaked transactions before reusing connections.

Every sub-agent in the rctest orchestration runs burned its first
database call on `serialization error: missing field `db`` — a wasted
error round-trip per session, four per run.

`db` is now optional on query/execute/executeBatch/transaction/
prepareStatement/beginTransaction. Explicit names behave exactly as
before (unknown ones still get UNKNOWN_DB); an omitted `db` resolves to
the sole configured pool, then to `primary` when several exist, and only
errors — the new MISSING_DB, which enumerates the available names so a
caller can self-correct from one failure — when neither rule
disambiguates.
@vercel

vercel Bot commented Jul 24, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
workers Ready Ready Preview, Comment Jul 24, 2026 1:18pm
workers-tech-spec Ready Ready Preview, Comment Jul 24, 2026 1:18pm

Request Review

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@andersonleal, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 45 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 2259b9a1-31f6-47cc-8313-9756b06b8bfa

📥 Commits

Reviewing files that changed from the base of the PR and between 1bb75f3 and 8635b59.

📒 Files selected for processing (2)
  • database/src/handlers/query.rs
  • database/src/pool/sqlite.rs
📝 Walkthrough

Walkthrough

Handlers now accept omitted database names, resolve configured defaults, reject transaction-control SQL on pooled operations, and roll back leaked SQLite transactions before connection reuse. Error serialization and tests cover missing-database reporting and the updated behavior.

Changes

Database routing and transaction safety

Layer / File(s) Summary
Database resolution contract
database/src/error.rs, database/src/handlers/mod.rs
Adds the MISSING_DB error and resolves optional database names to a sole pool, primary, or an available-database error.
Handler database routing
database/src/handlers/{begin_transaction,execute,execute_batch,prepare,query,transaction}.rs
Makes request database fields optional and routes pool selection, transaction registration, and logging through the resolved database name.
Transaction-control SQL guard
database/src/handlers/{mod,execute,prepare,query}.rs
Rejects transaction-control SQL in pooled handlers and tests rejection across whitespace and comment variations.
SQLite connection cleanup
database/src/pool/sqlite.rs
Rolls back leaked open transactions during acquisition and verifies safe connection reuse.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant Handler
  participant AppState
  participant SQLitePool
  Client->>Handler: Submit request with optional db and SQL
  Handler->>AppState: resolve_db(optional db)
  AppState-->>Handler: Resolved database or MISSING_DB
  Handler->>Handler: reject_tx_control_sql(SQL)
  Handler->>SQLitePool: Acquire resolved database connection
  SQLitePool-->>Handler: Clean connection
  Handler-->>Client: Execute result or validation error
Loading

Suggested reviewers: sergiofilhowz

Poem

A rabbit hops through pools so bright,
Finds primary by morning light.
Leaked transactions roll away,
Guarded SQL knows what not to say.
“MISSING_DB” leaves clues in tow—
Clean paths make the carrots grow! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: omitted db values are resolved to the sole pool or primary pool.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/database-optional-db

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

skill-check — worker

0 verified, 48 skipped (no docs/).

Layer Result
structure
vale
ai
render

Four for four. Nicely done.

…elf-heal leaked transactions

rctest5 postmortem, attempt 3: an agent ran execute("BEGIN") expecting a
session. Each call draws a fresh pooled connection, so the BEGIN/COMMIT
pair never met — worse, the BEGIN's connection went back to the pool
still inside an open transaction, and every later caller unlucky enough
to draw it failed `cannot start a transaction within a transaction`.
Three writer agents starved on one poisoned connection; 7 of 15 rows
landed.

Two layers:
* execute/query/prepareStatement now reject transaction-control SQL
  (BEGIN/COMMIT/ROLLBACK/SAVEPOINT, comment/whitespace-prefixed forms
  included, via the existing tx_sql_guard) with INVALID_PARAM naming the
  real transactional surfaces (beginTransaction/transactionExecute/
  commitTransaction, executeBatch). query is included because sqlite
  happily starts a transaction from query("BEGIN") and returns no rows.
* SqlitePool::acquire rolls back any leaked open transaction before
  handing the connection out — a regression anywhere upstream degrades
  to one warning line instead of a permanently poisoned pool.
@andersonleal

Copy link
Copy Markdown
Collaborator Author

Second commit (1eaf7fd9): reject transaction-control SQL on pooled surfaces + self-heal leaked transactions.

Live-run postmortem (rctest5, attempt 3): an agent ran execute("BEGIN") expecting a session. Each call draws a fresh pooled connection, so BEGIN/COMMIT never pair up — worse, the BEGIN's connection returned to the pool still inside an open transaction, and every later caller that drew it failed cannot start a transaction within a transaction. Three writer agents starved on one poisoned connection (7 of 15 rows landed).

  • execute / query / prepareStatement now reject BEGIN/COMMIT/ROLLBACK/SAVEPOINT (comment/whitespace-prefixed forms included, via the existing tx_sql_guard) with INVALID_PARAM naming the real transactional surfaces. query is included because sqlite happily starts a transaction from query("BEGIN") and returns zero rows.
  • SqlitePool::acquire rolls back any leaked open transaction before handing the connection out — a regression anywhere upstream degrades to one warning line instead of a permanently poisoned pool. Regression test drives the exact leak (max=1 pool, BEGIN, drop, re-acquire).

225 tests pass; clippy clean.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
database/src/handlers/query.rs (1)

225-234: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Replicate db-not-required schema assertion across sibling request types.

Only QueryReq gets a schema regression test confirming db isn't required. ExecuteReq, PrepareReq, TxReq, BeginTxReq, and ExecuteBatchReq all made the same field change but have no equivalent test, so a future accidental regression (e.g., dropping #[serde(default)]) on any of them wouldn't be caught.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@database/src/handlers/query.rs` around lines 225 - 234, Add equivalent schema
regression tests for ExecuteReq, PrepareReq, TxReq, BeginTxReq, and
ExecuteBatchReq, alongside request_schema_marks_db_optional. Each test should
serialize its request schema, assert db is absent from required, and retain the
existing expectation that sql is required where applicable, matching the
QueryReq test pattern.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@database/src/pool/sqlite.rs`:
- Around line 91-96: The connection-acquisition path must not return a
connection when the ROLLBACK issued after detecting an open transaction fails.
Update the handling around conn.execute_batch("ROLLBACK") to propagate the
rollback error and discard or invalidate the affected pooled connection before
returning, while preserving normal reuse when rollback succeeds.

---

Nitpick comments:
In `@database/src/handlers/query.rs`:
- Around line 225-234: Add equivalent schema regression tests for ExecuteReq,
PrepareReq, TxReq, BeginTxReq, and ExecuteBatchReq, alongside
request_schema_marks_db_optional. Each test should serialize its request schema,
assert db is absent from required, and retain the existing expectation that sql
is required where applicable, matching the QueryReq test pattern.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 1257c698-1524-46c6-9dcb-cb1598c83976

📥 Commits

Reviewing files that changed from the base of the PR and between 0e4432c and 1bb75f3.

📒 Files selected for processing (9)
  • database/src/error.rs
  • database/src/handlers/begin_transaction.rs
  • database/src/handlers/execute.rs
  • database/src/handlers/execute_batch.rs
  • database/src/handlers/mod.rs
  • database/src/handlers/prepare.rs
  • database/src/handlers/query.rs
  • database/src/handlers/transaction.rs
  • database/src/pool/sqlite.rs

Comment thread database/src/pool/sqlite.rs Outdated
…aked transaction won't roll back

CodeRabbit: discarding the ROLLBACK error still handed out a connection
possibly inside a transaction — recreating the pool poisoning the check
exists to prevent. A failed or ineffective rollback now fails the
acquire with a distinct stuck-transaction DriverError instead; the
connection returns to the pool and the rollback is retried on its next
checkout, so a transient failure self-heals rather than poisoning
forever, and callers see the real cause instead of `cannot start a
transaction within a transaction`.
@andersonleal
andersonleal merged commit 0c512bf into main Jul 24, 2026
17 checks passed
@andersonleal
andersonleal deleted the fix/database-optional-db branch July 24, 2026 13:24
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