| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent adbaf7a commit c757e3e
2 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -941,6 +941,19 @@ bool DatabaseSync::Open() { | |||
| 941 | 941 | return false; | |
| 942 | 942 | } | |
| 943 | 943 | ||
| 944 | + // sqlite3_open_v2() assigns a database handle even when it fails. Such a | ||
| 945 | + // handle is in a "sick" state and may only be used to retrieve the error | ||
| 946 | + // and must then be released with sqlite3_close(). Close and reset the | ||
| 947 | + // handle on any failure below so that a failed open() does not leave the | ||
| 948 | + // database in an open state. | ||
| 949 | + bool opened = false; | ||
| 950 | + auto reset_connection_on_failure = OnScopeLeave([&]() { | ||
| 951 | + if (!opened && connection_ != nullptr) { | ||
| 952 | + sqlite3_close_v2(connection_); | ||
| 953 | + connection_ = nullptr; | ||
| 954 | + } | ||
| 955 | + }); | ||
| 956 | + | ||
| 944 | 957 | // TODO(cjihrig): Support additional flags. | |
| 945 | 958 | int default_flags = SQLITE_OPEN_URI; | |
| 946 | 959 | int flags = open_config_.get_read_only() | |
@@ -1003,6 +1016,7 @@ bool DatabaseSync::Open() { | |||
| 1003 | 1016 | env()->isolate(), this, load_extension_ret, SQLITE_OK, false); | |
| 1004 | 1017 | } | |
| 1005 | 1018 | ||
| 1019 | + opened = true; | ||
| 1006 | 1020 | return true; | |
| 1007 | 1021 | } | |
| 1008 | 1022 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -2,7 +2,7 @@ | |||
| 2 | 2 | const { skipIfSQLiteMissing } = require('../common'); | |
| 3 | 3 | skipIfSQLiteMissing(); | |
| 4 | 4 | const tmpdir = require('../common/tmpdir'); | |
| 5 | - const { existsSync } = require('node:fs'); | ||
| 5 | + const { existsSync, mkdirSync } = require('node:fs'); | ||
| 6 | 6 | const { join } = require('node:path'); | |
| 7 | 7 | const { DatabaseSync, StatementSync } = require('node:sqlite'); | |
| 8 | 8 | const { suite, test } = require('node:test'); | |
@@ -308,6 +308,42 @@ suite('DatabaseSync.prototype.open()', () => { | |||
| 308 | 308 | }); | |
| 309 | 309 | t.assert.strictEqual(db.isOpen, true); | |
| 310 | 310 | }); | |
| 311 | + | ||
| 312 | + test('does not leave the database open after a failed open', (t) => { | ||
| 313 | + // Regression test for https://github.com/nodejs/node/issues/63831 | ||
| 314 | + const dbDir = join(tmpdir.path, `database-dir-${cnt++}`); | ||
| 315 | + const dbPath = join(dbDir, 'failed-open.db'); | ||
| 316 | + using db = new DatabaseSync(dbPath, { open: false }); | ||
| 317 | + | ||
| 318 | + // The directory does not exist, so opening the database fails. | ||
| 319 | + t.assert.throws(() => { | ||
| 320 | + db.open(); | ||
| 321 | + }, { | ||
| 322 | + code: 'ERR_SQLITE_ERROR', | ||
| 323 | + message: /unable to open database file/, | ||
| 324 | + }); | ||
| 325 | + t.assert.strictEqual(db.isOpen, false); | ||
| 326 | + | ||
| 327 | + // The connection must not be usable after a failed open. | ||
| 328 | + t.assert.throws(() => { | ||
| 329 | + db.exec('SELECT 1'); | ||
| 330 | + }, { | ||
| 331 | + code: 'ERR_INVALID_STATE', | ||
| 332 | + message: /database is not open/, | ||
| 333 | + }); | ||
| 334 | + t.assert.throws(() => { | ||
| 335 | + db.function('fn', () => {}); | ||
| 336 | + }, { | ||
| 337 | + code: 'ERR_INVALID_STATE', | ||
| 338 | + message: /database is not open/, | ||
| 339 | + }); | ||
| 340 | + | ||
| 341 | + // The database can be opened once the underlying problem is resolved. | ||
| 342 | + mkdirSync(dbDir); | ||
| 343 | + t.assert.strictEqual(db.open(), undefined); | ||
| 344 | + t.assert.strictEqual(db.isOpen, true); | ||
| 345 | + db.exec('CREATE TABLE foo (id INTEGER PRIMARY KEY)'); | ||
| 346 | + }); | ||
| 311 | 347 | }); | |
| 312 | 348 | ||
| 313 | 349 | suite('DatabaseSync.prototype.close()', () => { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments