Skip to content

Commit 808e62f

Browse files
committed
chore(driver-sql): changeset, and the #25019 pin's note on the refused connection's siblings
Claude-Session: https://claude.ai/code/session_01WQM1Hwm3eDA8xPhFuZGmZ6 Co-authored-by: Claude <noreply@anthropic.com>
1 parent a7c62f7 commit 808e62f

2 files changed

Lines changed: 18 additions & 3 deletions

File tree

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
---
2+
'@objectstack/driver-sql': patch
3+
---
4+
5+
fix(driver-sql): a SQLite `connect()` that refuses its file closes the connection it opened before it rejects
6+
7+
Clause-②: no (resource release only: no response, status, error, outcome or export moves)
8+
Metadata-protocol: none
9+
10+
- **What it was.** `SqlDriver.connect()` refuses a declared SQLite file its first statement cannot use (`SqliteDatabaseFileError`: `SQLITE_CANTOPEN`, `SQLITE_NOTADB`, `SQLITE_CORRUPT`). The file was opened to give that answer, and the pool kept the better-sqlite3 connection after the rejection. For a damaged file whose header says WAL, SQLite kept its `-shm` and an empty `-wal` beside the file until something called `disconnect()`. A datasource left unconnected on the degraded path is never disconnected, so it kept them for the life of the process.
11+
- **What changed.** When a SQLite `connect()` rejects, it destroys its pool and puts a fresh, empty one in its place, then rethrows the same error: same class, code, message and `cause`. Nothing is left open, and the `-shm` / `-wal` siblings are gone when the rejection arrives. A later `connect()` on the same instance opens the file again: it gives the same refusal while the file is bad, and connects once the file is repaired. A release that itself fails is logged at `warn`, and the original refusal is still the error thrown.
12+
- **Unchanged.** Which files are refused, the codes and the messages. Server dialects (`pg`, `mysql`) are untouched: their `connect()` rejects only when no connection could be made, so there is nothing to release. `SqliteWasmDriver` and the local mode of `TursoDriver` inherit the release through `super.connect()`.
13+
- **What to do.** Nothing.

‎packages/drivers/driver-sql/src/sql-driver-25019-sqlite-damaged-file-and-dangling-link.test.ts‎

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,11 @@ async function seedDatabase(filename: string): Promise<void> {
8989

9090
/**
9191
* The refused file holds the bytes it was found with, and nothing is left
92-
* beside it. The header still says WAL (this driver's journal mode), so SQLite
93-
* keeps its `-shm` and an empty `-wal` while the refused connection is open:
94-
* no `.corrupt-*` sibling then, and nothing at all once it is closed.
92+
* beside it: no `.corrupt-*` sibling, and nothing at all after `disconnect()`.
93+
* The header still says WAL (this driver's journal mode); the `-shm` and empty
94+
* `-wal` SQLite keeps while a connection is open are gone already when
95+
* `connect()` rejects, because the refusal closes its connection (#25084,
96+
* pinned in `sql-driver-25084-sqlite-refused-connect-release.test.ts`).
9597
*/
9698
async function expectLeftAsItWas(driver: SqlDriver, filename: string, before: Buffer): Promise<void> {
9799
expect(readdirSync(dir).filter((name) => name.includes('.corrupt-'))).toEqual([]);

0 commit comments

Comments
 (0)