| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 83169e5 commit 5e387ce
3 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -662,6 +662,10 @@ console.log(query.get()); | |||
| 662 | 662 | ||
| 663 | 663 | <!-- YAML | |
| 664 | 664 | added: v22.5.0 | |
| 665 | + changes: | ||
| 666 | + - version: REPLACEME | ||
| 667 | + pr-url: https://github.com/nodejs/node/pull/65157 | ||
| 668 | + description: Throw `ERR_INVALID_ARG_VALUE` if `sql` contains no statements. | ||
| 665 | 669 | --> | |
| 666 | 670 | ||
| 667 | 671 | * `sql` {string} A SQL string to compile to a prepared statement. | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -1581,6 +1581,16 @@ void DatabaseSync::Prepare(const FunctionCallbackInfo<Value>& args) { | |||
| 1581 | 1581 | int r = sqlite3_prepare_v2(db->connection_, *sql, -1, &s, nullptr); | |
| 1582 | 1582 | ||
| 1583 | 1583 | CHECK_ERROR_OR_THROW(env->isolate(), db, r, SQLITE_OK, void()); | |
| 1584 | + | ||
| 1585 | + // sqlite3_prepare_v2() reports success without producing a statement when | ||
| 1586 | + // the input holds no SQL, such as a comment. Such a statement can never be | ||
| 1587 | + // stepped, and tracking it would leave a dangling pointer in statements_ | ||
| 1588 | + // because its destructor treats a null statement as already finalized. | ||
| 1589 | + if (s == nullptr) { | ||
| 1590 | + THROW_ERR_INVALID_ARG_VALUE(env, "The SQL query contains no statements."); | ||
| 1591 | + return; | ||
| 1592 | + } | ||
| 1593 | + | ||
| 1584 | 1594 | BaseObjectPtr<StatementSync> stmt = | |
| 1585 | 1595 | StatementSync::Create(env, BaseObjectPtr<DatabaseSync>(db), s); | |
| 1586 | 1596 | db->statements_.insert(stmt.get()); | |
@@ -3659,9 +3669,8 @@ BaseObjectPtr<StatementSync> SQLTagStore::PrepareStatement( | |||
| 3659 | 3669 | return BaseObjectPtr<StatementSync>(); | |
| 3660 | 3670 | } | |
| 3661 | 3671 | ||
| 3662 | - // sqlite3_prepare_v2() reports success without producing a statement when | ||
| 3663 | - // the input holds no SQL, such as a comment. Such a statement cannot be | ||
| 3664 | - // bound or executed, so reject it instead of caching it. | ||
| 3672 | + // As in DatabaseSync::Prepare(), reject input that holds no SQL rather | ||
| 3673 | + // than caching a statement that can never be bound or stepped. | ||
| 3665 | 3674 | if (s == nullptr) { | |
| 3666 | 3675 | THROW_ERR_INVALID_ARG_VALUE(env, "The SQL query contains no statements."); | |
| 3667 | 3676 | return BaseObjectPtr<StatementSync>(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -397,6 +397,32 @@ suite('DatabaseSync.prototype.prepare()', () => { | |||
| 397 | 397 | message: /The "sql" argument must be a string/, | |
| 398 | 398 | }); | |
| 399 | 399 | }); | |
| 400 | + | ||
| 401 | + test('throws if sql contains no statements', (t) => { | ||
| 402 | + using db = new DatabaseSync(nextDb()); | ||
| 403 | + | ||
| 404 | + for (const sql of ['', ' ', ';', '-- comment', '/* comment */']) { | ||
| 405 | + t.assert.throws(() => { | ||
| 406 | + db.prepare(sql); | ||
| 407 | + }, { | ||
| 408 | + code: 'ERR_INVALID_ARG_VALUE', | ||
| 409 | + message: /contains no statements/, | ||
| 410 | + }); | ||
| 411 | + } | ||
| 412 | + }); | ||
| 413 | + | ||
| 414 | + test('prepares statements that contain comments', (t) => { | ||
| 415 | + using db = new DatabaseSync(nextDb()); | ||
| 416 | + const queries = [ | ||
| 417 | + '-- lead\nSELECT 1 AS v', | ||
| 418 | + 'SELECT 1 AS v -- trail', | ||
| 419 | + 'SELECT /* mid */ 1 AS v', | ||
| 420 | + ]; | ||
| 421 | + | ||
| 422 | + for (const sql of queries) { | ||
| 423 | + t.assert.strictEqual(db.prepare(sql).get().v, 1); | ||
| 424 | + } | ||
| 425 | + }); | ||
| 400 | 426 | }); | |
| 401 | 427 | ||
| 402 | 428 | suite('DatabaseSync.prototype.exec()', () => { | |
| Back | FazBrowse Home | New Git URL |
0 commit comments