sqlite: check sqlite3_step() and sqlite3_reset() results - #63319

Merged
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns
Aug 11, 2026
Merged

sqlite: check sqlite3_step() and sqlite3_reset() results#63319
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns

Conversation

@semimikoh

Copy link
Copy Markdown
Contributor

Summary

Per the SQLite docs, sqlite3_reset(S) may return a deferred error code
from the prior sqlite3_step(S) call. Several statement execution paths in
src/node_sqlite.cc dropped that return value, which could silently ignore
SQLite errors.

This also checks the previously ignored sqlite3_step() result in
StatementExecutionHelper::Run().

Fixes: #63311

Approach

Successful execution paths now explicitly check sqlite3_reset().

Functions with early-return or V8-exception paths keep an OnScopeLeave
reset guard so prepared statements are left reusable. The guard intentionally
drops the reset result to avoid replacing an already-pending SQLite or V8
exception.

StatementSyncIterator::Next() and StatementSyncIterator::Return() use a
direct checked reset because their control flow is linear.

$ python3 tools/cpplint.py src/node_sqlite.ccDone processing src/node_sqlite.cc
$ git diff --check -- src/node_sqlite.ccA full local build was not completed because this machine has Apple clang16.0.0, while the current tree requires a newer macOS toolchain. The buildfails in V8 because std::atomic_ref is unavailable.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/sqlite

@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. sqlite Issues and PRs related to the SQLite subsystem. labels May 15, 2026
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch 3 times, most recently from 557bcde to 4740589CompareMay 15, 2026 05:40
@codecov

codecovBot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.31%. Comparing base (e6fa5bf) to head (90fe5e2).
⚠️ Report is 38 commits behind head on main.

Files with missing linesPatch %Lines
src/node_sqlite.cc75.00%2 Missing and 7 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #63319 +/- ##
==========================================
- Coverage 90.32% 90.31% -0.01% 
==========================================
Files 759 759 Lines 248328 248352 +24 Branches 46856 46868 +12 ==========================================
- Hits 224296 224293 -3 + Misses 15466 15459 -7 - Partials 8566 8600 +34 
Files with missing linesCoverage Δ
src/node_sqlite.cc81.03% <75.00%> (-0.20%)⬇️

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@geeksilva97

Copy link
Copy Markdown
Contributor

I tried to reproduce a situation where the current code wouldn't catch the error but I couldn't. Please, get such a case into a test so it's clear which situation we must cover.

@TrevorBurnhamTrevorBurnham 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.

Reviewed the reset-error handling. The direction looks right; sqlite3_reset() returning a deferred error from the prior sqlite3_step() is real and worth surfacing. Two things I'd want addressed:

  1. In StatementSyncIterator, RESET_OR_THROW expands to a return, so the new throwing paths skip iter->done_ = true even though the statement has already been reset. A caught error then leaves the iterator resumable, and it replays the result set from the top. Details inline.

  2. No tests. get()/all() can now throw where they previously returned an already-built row/array, which is a user-visible change on a success path. Worth coverage pinning the new behavior, plus a note on whether it needs semver-major.

Things I checked that look correct: needs_reset = false is sequenced before sqlite3_reset(), so there's no double reset on the throwing path; no function can call THROW_ERR_SQLITE_ERROR twice, so the ShouldIgnoreSQLiteError() one-shot isn't consumed twice; void() threads through both macro layers; and every RESET_AND_CHECK caller keeps its OnScopeLeave safety net for the earlier failure paths.

Comment threadsrc/node_sqlite.cc Outdated
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4740589 to 4443a70CompareAugust 7, 2026 01:53
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Rebased onto main and addressed the feedback:

  • Return() now ignores the reset result (like the other OnScopeLeave guards) so it can't discard a pending exception during abrupt iterator close
  • Next()'s exhaustion path setting done_ came in via the rebase
  • Added tests for both, plus the get()/all() deferred-error case
  • Added the suggested comment in Run()

get()/all() can now throw on a previously-succeeding path — let me know if this needs notable-change.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4443a70 to ba4e195CompareAugust 7, 2026 03:47
@semimikoh

This comment was marked as outdated.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ba4e195 to ea9f2dfCompareAugust 7, 2026 03:59
@semimikoh

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ea9f2df to 52592e6CompareAugust 7, 2026 06:44
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

@trivikr CI is green now (conflicts resolved, lint fixed). Ready for another look whenever you have time.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
Comment threadsrc/node_sqlite.cc Outdated
@trivikrtrivikr removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Fixed — swapped the order so done_ is set before the checked reset, matching your suggestion.

On the test request: I don't think a failing-reset test is constructible for this specific branch. This code path is only reached after CHECK_ERROR_OR_THROW has already confirmed r == SQLITE_DONE, and in SQLite's own implementation (sqlite3VdbeReset(), vdbeapi.c):

/* If the VM did not run to completion or if it encountered an** error, then it might not have been halted properly. So halt** it now.*/if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);

sqlite3VdbeHalt() — where commits and constraint checks actually happen — only runs if the VDBE is still in VDBE_RUN_STATE. Once sqlite3_step() has returned SQLITE_DONE, the halt already happened during that step call, so a subsequent sqlite3_reset() can't trigger a new commit-time failure here. This matches @TrevorBurnham's earlier note that the equivalent SQLITE_DONE check in Get() is "effectively a no-op."

The sqlite3_reset() doc's BUSY/RETURNING example specifically requires stopping after SQLITE_ROW (VDBE still RUN_STATE) — that's the Return()/Get()/All() case, which is already covered. Happy to add the reset-fails test there if it's not covered well enough, but for this particular Next() branch I believe it's unreachable by construction.

Signed-off-by: semimikoh <ejffjeosms@gmail.com>
- StatementSyncIterator::Return() no longer throws on a deferred
reset error, matching the OnScopeLeave guards used elsewhere: it
is invoked during abrupt iterator completion (e.g. a throw inside
a for...of body), and throwing there would discard the caller's
already-pending exception.
- Add a short comment on the accepted SQLITE_ROW result in Run().
- Add tests covering get()/all() surfacing a deferred SQLite error
from reset() after already building a row/array, the iterator not
replaying results after natural exhaustion, and a pending exception
propagating correctly when the loop body throws mid-iteration.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
RESET_OR_THROW returns early on a deferred error, so the previous
ordering skipped iter->done_ = true when the reset in the natural
exhaustion path failed. The statement was reset either way, so
setting done_ first is safe and avoids leaving a caught error in a
resumable state.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
Rebasing onto main picked up "sqlite: refactor error helpers and
user function pointers", which moved SQLTagStore::All()'s reset and
bind logic into ResetAndBindStatement() and removed the local
Isolate* isolate declaration that this PR's trailing RESET_AND_CHECK
call still depends on. Re-add it.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 6f667c2 to 90fe5e2CompareAugust 9, 2026 13:01
@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 9, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 673cdef into nodejs:mainAug 11, 2026
90 of 92 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 673cdef

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.c++Issues and PRs that require attention from people who are familiar with C++.commit-queue-squashPRs the Commit Queue should land as one squashed commit.needs-ciPRs that need a full CI run.sqliteIssues and PRs related to the SQLite subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unchecked sqlite3 API calls

5 participants

@semimikoh@nodejs-github-bot@geeksilva97@trivikr@TrevorBurnham
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

sqlite: check sqlite3_step() and sqlite3_reset() results - #63319

Merged
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns
Aug 11, 2026
Merged

sqlite: check sqlite3_step() and sqlite3_reset() results#63319
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns

Conversation

@semimikoh

Copy link
Copy Markdown
Contributor

Summary

Per the SQLite docs, sqlite3_reset(S) may return a deferred error code
from the prior sqlite3_step(S) call. Several statement execution paths in
src/node_sqlite.cc dropped that return value, which could silently ignore
SQLite errors.

This also checks the previously ignored sqlite3_step() result in
StatementExecutionHelper::Run().

Fixes: #63311

Approach

Successful execution paths now explicitly check sqlite3_reset().

Functions with early-return or V8-exception paths keep an OnScopeLeave
reset guard so prepared statements are left reusable. The guard intentionally
drops the reset result to avoid replacing an already-pending SQLite or V8
exception.

StatementSyncIterator::Next() and StatementSyncIterator::Return() use a
direct checked reset because their control flow is linear.

$ python3 tools/cpplint.py src/node_sqlite.ccDone processing src/node_sqlite.cc
$ git diff --check -- src/node_sqlite.ccA full local build was not completed because this machine has Apple clang16.0.0, while the current tree requires a newer macOS toolchain. The buildfails in V8 because std::atomic_ref is unavailable.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/sqlite

@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. sqlite Issues and PRs related to the SQLite subsystem. labels May 15, 2026
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch 3 times, most recently from 557bcde to 4740589CompareMay 15, 2026 05:40
@codecov

codecovBot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.31%. Comparing base (e6fa5bf) to head (90fe5e2).
⚠️ Report is 38 commits behind head on main.

Files with missing linesPatch %Lines
src/node_sqlite.cc75.00%2 Missing and 7 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #63319 +/- ##
==========================================
- Coverage 90.32% 90.31% -0.01% 
==========================================
Files 759 759 Lines 248328 248352 +24 Branches 46856 46868 +12 ==========================================
- Hits 224296 224293 -3 + Misses 15466 15459 -7 - Partials 8566 8600 +34 
Files with missing linesCoverage Δ
src/node_sqlite.cc81.03% <75.00%> (-0.20%)⬇️

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@geeksilva97

Copy link
Copy Markdown
Contributor

I tried to reproduce a situation where the current code wouldn't catch the error but I couldn't. Please, get such a case into a test so it's clear which situation we must cover.

@TrevorBurnhamTrevorBurnham 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.

Reviewed the reset-error handling. The direction looks right; sqlite3_reset() returning a deferred error from the prior sqlite3_step() is real and worth surfacing. Two things I'd want addressed:

  1. In StatementSyncIterator, RESET_OR_THROW expands to a return, so the new throwing paths skip iter->done_ = true even though the statement has already been reset. A caught error then leaves the iterator resumable, and it replays the result set from the top. Details inline.

  2. No tests. get()/all() can now throw where they previously returned an already-built row/array, which is a user-visible change on a success path. Worth coverage pinning the new behavior, plus a note on whether it needs semver-major.

Things I checked that look correct: needs_reset = false is sequenced before sqlite3_reset(), so there's no double reset on the throwing path; no function can call THROW_ERR_SQLITE_ERROR twice, so the ShouldIgnoreSQLiteError() one-shot isn't consumed twice; void() threads through both macro layers; and every RESET_AND_CHECK caller keeps its OnScopeLeave safety net for the earlier failure paths.

Comment threadsrc/node_sqlite.cc Outdated
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4740589 to 4443a70CompareAugust 7, 2026 01:53
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Rebased onto main and addressed the feedback:

  • Return() now ignores the reset result (like the other OnScopeLeave guards) so it can't discard a pending exception during abrupt iterator close
  • Next()'s exhaustion path setting done_ came in via the rebase
  • Added tests for both, plus the get()/all() deferred-error case
  • Added the suggested comment in Run()

get()/all() can now throw on a previously-succeeding path — let me know if this needs notable-change.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4443a70 to ba4e195CompareAugust 7, 2026 03:47
@semimikoh

This comment was marked as outdated.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ba4e195 to ea9f2dfCompareAugust 7, 2026 03:59
@semimikoh

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ea9f2df to 52592e6CompareAugust 7, 2026 06:44
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

@trivikr CI is green now (conflicts resolved, lint fixed). Ready for another look whenever you have time.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
Comment threadsrc/node_sqlite.cc Outdated
@trivikrtrivikr removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Fixed — swapped the order so done_ is set before the checked reset, matching your suggestion.

On the test request: I don't think a failing-reset test is constructible for this specific branch. This code path is only reached after CHECK_ERROR_OR_THROW has already confirmed r == SQLITE_DONE, and in SQLite's own implementation (sqlite3VdbeReset(), vdbeapi.c):

/* If the VM did not run to completion or if it encountered an** error, then it might not have been halted properly. So halt** it now.*/if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);

sqlite3VdbeHalt() — where commits and constraint checks actually happen — only runs if the VDBE is still in VDBE_RUN_STATE. Once sqlite3_step() has returned SQLITE_DONE, the halt already happened during that step call, so a subsequent sqlite3_reset() can't trigger a new commit-time failure here. This matches @TrevorBurnham's earlier note that the equivalent SQLITE_DONE check in Get() is "effectively a no-op."

The sqlite3_reset() doc's BUSY/RETURNING example specifically requires stopping after SQLITE_ROW (VDBE still RUN_STATE) — that's the Return()/Get()/All() case, which is already covered. Happy to add the reset-fails test there if it's not covered well enough, but for this particular Next() branch I believe it's unreachable by construction.

Signed-off-by: semimikoh <ejffjeosms@gmail.com>
- StatementSyncIterator::Return() no longer throws on a deferred
reset error, matching the OnScopeLeave guards used elsewhere: it
is invoked during abrupt iterator completion (e.g. a throw inside
a for...of body), and throwing there would discard the caller's
already-pending exception.
- Add a short comment on the accepted SQLITE_ROW result in Run().
- Add tests covering get()/all() surfacing a deferred SQLite error
from reset() after already building a row/array, the iterator not
replaying results after natural exhaustion, and a pending exception
propagating correctly when the loop body throws mid-iteration.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
RESET_OR_THROW returns early on a deferred error, so the previous
ordering skipped iter->done_ = true when the reset in the natural
exhaustion path failed. The statement was reset either way, so
setting done_ first is safe and avoids leaving a caught error in a
resumable state.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
Rebasing onto main picked up "sqlite: refactor error helpers and
user function pointers", which moved SQLTagStore::All()'s reset and
bind logic into ResetAndBindStatement() and removed the local
Isolate* isolate declaration that this PR's trailing RESET_AND_CHECK
call still depends on. Re-add it.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 6f667c2 to 90fe5e2CompareAugust 9, 2026 13:01
@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 9, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 673cdef into nodejs:mainAug 11, 2026
90 of 92 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 673cdef

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.c++Issues and PRs that require attention from people who are familiar with C++.commit-queue-squashPRs the Commit Queue should land as one squashed commit.needs-ciPRs that need a full CI run.sqliteIssues and PRs related to the SQLite subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unchecked sqlite3 API calls

5 participants

@semimikoh@nodejs-github-bot@geeksilva97@trivikr@TrevorBurnham
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

sqlite: check sqlite3_step() and sqlite3_reset() results - #63319

Merged
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns
Aug 11, 2026
Merged

sqlite: check sqlite3_step() and sqlite3_reset() results#63319
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns

Conversation

@semimikoh

Copy link
Copy Markdown
Contributor

Summary

Per the SQLite docs, sqlite3_reset(S) may return a deferred error code
from the prior sqlite3_step(S) call. Several statement execution paths in
src/node_sqlite.cc dropped that return value, which could silently ignore
SQLite errors.

This also checks the previously ignored sqlite3_step() result in
StatementExecutionHelper::Run().

Fixes: #63311

Approach

Successful execution paths now explicitly check sqlite3_reset().

Functions with early-return or V8-exception paths keep an OnScopeLeave
reset guard so prepared statements are left reusable. The guard intentionally
drops the reset result to avoid replacing an already-pending SQLite or V8
exception.

StatementSyncIterator::Next() and StatementSyncIterator::Return() use a
direct checked reset because their control flow is linear.

$ python3 tools/cpplint.py src/node_sqlite.ccDone processing src/node_sqlite.cc
$ git diff --check -- src/node_sqlite.ccA full local build was not completed because this machine has Apple clang16.0.0, while the current tree requires a newer macOS toolchain. The buildfails in V8 because std::atomic_ref is unavailable.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/sqlite

@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. sqlite Issues and PRs related to the SQLite subsystem. labels May 15, 2026
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch 3 times, most recently from 557bcde to 4740589CompareMay 15, 2026 05:40
@codecov

codecovBot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.31%. Comparing base (e6fa5bf) to head (90fe5e2).
⚠️ Report is 38 commits behind head on main.

Files with missing linesPatch %Lines
src/node_sqlite.cc75.00%2 Missing and 7 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #63319 +/- ##
==========================================
- Coverage 90.32% 90.31% -0.01% 
==========================================
Files 759 759 Lines 248328 248352 +24 Branches 46856 46868 +12 ==========================================
- Hits 224296 224293 -3 + Misses 15466 15459 -7 - Partials 8566 8600 +34 
Files with missing linesCoverage Δ
src/node_sqlite.cc81.03% <75.00%> (-0.20%)⬇️

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@geeksilva97

Copy link
Copy Markdown
Contributor

I tried to reproduce a situation where the current code wouldn't catch the error but I couldn't. Please, get such a case into a test so it's clear which situation we must cover.

@TrevorBurnhamTrevorBurnham 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.

Reviewed the reset-error handling. The direction looks right; sqlite3_reset() returning a deferred error from the prior sqlite3_step() is real and worth surfacing. Two things I'd want addressed:

  1. In StatementSyncIterator, RESET_OR_THROW expands to a return, so the new throwing paths skip iter->done_ = true even though the statement has already been reset. A caught error then leaves the iterator resumable, and it replays the result set from the top. Details inline.

  2. No tests. get()/all() can now throw where they previously returned an already-built row/array, which is a user-visible change on a success path. Worth coverage pinning the new behavior, plus a note on whether it needs semver-major.

Things I checked that look correct: needs_reset = false is sequenced before sqlite3_reset(), so there's no double reset on the throwing path; no function can call THROW_ERR_SQLITE_ERROR twice, so the ShouldIgnoreSQLiteError() one-shot isn't consumed twice; void() threads through both macro layers; and every RESET_AND_CHECK caller keeps its OnScopeLeave safety net for the earlier failure paths.

Comment threadsrc/node_sqlite.cc Outdated
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4740589 to 4443a70CompareAugust 7, 2026 01:53
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Rebased onto main and addressed the feedback:

  • Return() now ignores the reset result (like the other OnScopeLeave guards) so it can't discard a pending exception during abrupt iterator close
  • Next()'s exhaustion path setting done_ came in via the rebase
  • Added tests for both, plus the get()/all() deferred-error case
  • Added the suggested comment in Run()

get()/all() can now throw on a previously-succeeding path — let me know if this needs notable-change.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4443a70 to ba4e195CompareAugust 7, 2026 03:47
@semimikoh

This comment was marked as outdated.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ba4e195 to ea9f2dfCompareAugust 7, 2026 03:59
@semimikoh

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ea9f2df to 52592e6CompareAugust 7, 2026 06:44
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

@trivikr CI is green now (conflicts resolved, lint fixed). Ready for another look whenever you have time.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
Comment threadsrc/node_sqlite.cc Outdated
@trivikrtrivikr removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Fixed — swapped the order so done_ is set before the checked reset, matching your suggestion.

On the test request: I don't think a failing-reset test is constructible for this specific branch. This code path is only reached after CHECK_ERROR_OR_THROW has already confirmed r == SQLITE_DONE, and in SQLite's own implementation (sqlite3VdbeReset(), vdbeapi.c):

/* If the VM did not run to completion or if it encountered an** error, then it might not have been halted properly. So halt** it now.*/if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);

sqlite3VdbeHalt() — where commits and constraint checks actually happen — only runs if the VDBE is still in VDBE_RUN_STATE. Once sqlite3_step() has returned SQLITE_DONE, the halt already happened during that step call, so a subsequent sqlite3_reset() can't trigger a new commit-time failure here. This matches @TrevorBurnham's earlier note that the equivalent SQLITE_DONE check in Get() is "effectively a no-op."

The sqlite3_reset() doc's BUSY/RETURNING example specifically requires stopping after SQLITE_ROW (VDBE still RUN_STATE) — that's the Return()/Get()/All() case, which is already covered. Happy to add the reset-fails test there if it's not covered well enough, but for this particular Next() branch I believe it's unreachable by construction.

Signed-off-by: semimikoh <ejffjeosms@gmail.com>
- StatementSyncIterator::Return() no longer throws on a deferred
reset error, matching the OnScopeLeave guards used elsewhere: it
is invoked during abrupt iterator completion (e.g. a throw inside
a for...of body), and throwing there would discard the caller's
already-pending exception.
- Add a short comment on the accepted SQLITE_ROW result in Run().
- Add tests covering get()/all() surfacing a deferred SQLite error
from reset() after already building a row/array, the iterator not
replaying results after natural exhaustion, and a pending exception
propagating correctly when the loop body throws mid-iteration.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
RESET_OR_THROW returns early on a deferred error, so the previous
ordering skipped iter->done_ = true when the reset in the natural
exhaustion path failed. The statement was reset either way, so
setting done_ first is safe and avoids leaving a caught error in a
resumable state.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
Rebasing onto main picked up "sqlite: refactor error helpers and
user function pointers", which moved SQLTagStore::All()'s reset and
bind logic into ResetAndBindStatement() and removed the local
Isolate* isolate declaration that this PR's trailing RESET_AND_CHECK
call still depends on. Re-add it.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 6f667c2 to 90fe5e2CompareAugust 9, 2026 13:01
@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 9, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 673cdef into nodejs:mainAug 11, 2026
90 of 92 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 673cdef

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.c++Issues and PRs that require attention from people who are familiar with C++.commit-queue-squashPRs the Commit Queue should land as one squashed commit.needs-ciPRs that need a full CI run.sqliteIssues and PRs related to the SQLite subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unchecked sqlite3 API calls

5 participants

@semimikoh@nodejs-github-bot@geeksilva97@trivikr@TrevorBurnham
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

sqlite: check sqlite3_step() and sqlite3_reset() results - #63319

Merged
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns
Aug 11, 2026
Merged

sqlite: check sqlite3_step() and sqlite3_reset() results#63319
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns

Conversation

@semimikoh

Copy link
Copy Markdown
Contributor

Summary

Per the SQLite docs, sqlite3_reset(S) may return a deferred error code
from the prior sqlite3_step(S) call. Several statement execution paths in
src/node_sqlite.cc dropped that return value, which could silently ignore
SQLite errors.

This also checks the previously ignored sqlite3_step() result in
StatementExecutionHelper::Run().

Fixes: #63311

Approach

Successful execution paths now explicitly check sqlite3_reset().

Functions with early-return or V8-exception paths keep an OnScopeLeave
reset guard so prepared statements are left reusable. The guard intentionally
drops the reset result to avoid replacing an already-pending SQLite or V8
exception.

StatementSyncIterator::Next() and StatementSyncIterator::Return() use a
direct checked reset because their control flow is linear.

$ python3 tools/cpplint.py src/node_sqlite.ccDone processing src/node_sqlite.cc
$ git diff --check -- src/node_sqlite.ccA full local build was not completed because this machine has Apple clang16.0.0, while the current tree requires a newer macOS toolchain. The buildfails in V8 because std::atomic_ref is unavailable.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/sqlite

@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. sqlite Issues and PRs related to the SQLite subsystem. labels May 15, 2026
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch 3 times, most recently from 557bcde to 4740589CompareMay 15, 2026 05:40
@codecov

codecovBot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.31%. Comparing base (e6fa5bf) to head (90fe5e2).
⚠️ Report is 38 commits behind head on main.

Files with missing linesPatch %Lines
src/node_sqlite.cc75.00%2 Missing and 7 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #63319 +/- ##
==========================================
- Coverage 90.32% 90.31% -0.01% 
==========================================
Files 759 759 Lines 248328 248352 +24 Branches 46856 46868 +12 ==========================================
- Hits 224296 224293 -3 + Misses 15466 15459 -7 - Partials 8566 8600 +34 
Files with missing linesCoverage Δ
src/node_sqlite.cc81.03% <75.00%> (-0.20%)⬇️

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@geeksilva97

Copy link
Copy Markdown
Contributor

I tried to reproduce a situation where the current code wouldn't catch the error but I couldn't. Please, get such a case into a test so it's clear which situation we must cover.

@TrevorBurnhamTrevorBurnham 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.

Reviewed the reset-error handling. The direction looks right; sqlite3_reset() returning a deferred error from the prior sqlite3_step() is real and worth surfacing. Two things I'd want addressed:

  1. In StatementSyncIterator, RESET_OR_THROW expands to a return, so the new throwing paths skip iter->done_ = true even though the statement has already been reset. A caught error then leaves the iterator resumable, and it replays the result set from the top. Details inline.

  2. No tests. get()/all() can now throw where they previously returned an already-built row/array, which is a user-visible change on a success path. Worth coverage pinning the new behavior, plus a note on whether it needs semver-major.

Things I checked that look correct: needs_reset = false is sequenced before sqlite3_reset(), so there's no double reset on the throwing path; no function can call THROW_ERR_SQLITE_ERROR twice, so the ShouldIgnoreSQLiteError() one-shot isn't consumed twice; void() threads through both macro layers; and every RESET_AND_CHECK caller keeps its OnScopeLeave safety net for the earlier failure paths.

Comment threadsrc/node_sqlite.cc Outdated
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4740589 to 4443a70CompareAugust 7, 2026 01:53
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Rebased onto main and addressed the feedback:

  • Return() now ignores the reset result (like the other OnScopeLeave guards) so it can't discard a pending exception during abrupt iterator close
  • Next()'s exhaustion path setting done_ came in via the rebase
  • Added tests for both, plus the get()/all() deferred-error case
  • Added the suggested comment in Run()

get()/all() can now throw on a previously-succeeding path — let me know if this needs notable-change.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4443a70 to ba4e195CompareAugust 7, 2026 03:47
@semimikoh

This comment was marked as outdated.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ba4e195 to ea9f2dfCompareAugust 7, 2026 03:59
@semimikoh

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ea9f2df to 52592e6CompareAugust 7, 2026 06:44
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

@trivikr CI is green now (conflicts resolved, lint fixed). Ready for another look whenever you have time.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
Comment threadsrc/node_sqlite.cc Outdated
@trivikrtrivikr removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Fixed — swapped the order so done_ is set before the checked reset, matching your suggestion.

On the test request: I don't think a failing-reset test is constructible for this specific branch. This code path is only reached after CHECK_ERROR_OR_THROW has already confirmed r == SQLITE_DONE, and in SQLite's own implementation (sqlite3VdbeReset(), vdbeapi.c):

/* If the VM did not run to completion or if it encountered an** error, then it might not have been halted properly. So halt** it now.*/if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);

sqlite3VdbeHalt() — where commits and constraint checks actually happen — only runs if the VDBE is still in VDBE_RUN_STATE. Once sqlite3_step() has returned SQLITE_DONE, the halt already happened during that step call, so a subsequent sqlite3_reset() can't trigger a new commit-time failure here. This matches @TrevorBurnham's earlier note that the equivalent SQLITE_DONE check in Get() is "effectively a no-op."

The sqlite3_reset() doc's BUSY/RETURNING example specifically requires stopping after SQLITE_ROW (VDBE still RUN_STATE) — that's the Return()/Get()/All() case, which is already covered. Happy to add the reset-fails test there if it's not covered well enough, but for this particular Next() branch I believe it's unreachable by construction.

Signed-off-by: semimikoh <ejffjeosms@gmail.com>
- StatementSyncIterator::Return() no longer throws on a deferred
reset error, matching the OnScopeLeave guards used elsewhere: it
is invoked during abrupt iterator completion (e.g. a throw inside
a for...of body), and throwing there would discard the caller's
already-pending exception.
- Add a short comment on the accepted SQLITE_ROW result in Run().
- Add tests covering get()/all() surfacing a deferred SQLite error
from reset() after already building a row/array, the iterator not
replaying results after natural exhaustion, and a pending exception
propagating correctly when the loop body throws mid-iteration.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
RESET_OR_THROW returns early on a deferred error, so the previous
ordering skipped iter->done_ = true when the reset in the natural
exhaustion path failed. The statement was reset either way, so
setting done_ first is safe and avoids leaving a caught error in a
resumable state.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
Rebasing onto main picked up "sqlite: refactor error helpers and
user function pointers", which moved SQLTagStore::All()'s reset and
bind logic into ResetAndBindStatement() and removed the local
Isolate* isolate declaration that this PR's trailing RESET_AND_CHECK
call still depends on. Re-add it.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 6f667c2 to 90fe5e2CompareAugust 9, 2026 13:01
@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 9, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 673cdef into nodejs:mainAug 11, 2026
90 of 92 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 673cdef

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.c++Issues and PRs that require attention from people who are familiar with C++.commit-queue-squashPRs the Commit Queue should land as one squashed commit.needs-ciPRs that need a full CI run.sqliteIssues and PRs related to the SQLite subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unchecked sqlite3 API calls

5 participants

@semimikoh@nodejs-github-bot@geeksilva97@trivikr@TrevorBurnham
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

sqlite: check sqlite3_step() and sqlite3_reset() results - #63319

Merged
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns
Aug 11, 2026
Merged

sqlite: check sqlite3_step() and sqlite3_reset() results#63319
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns

Conversation

@semimikoh

Copy link
Copy Markdown
Contributor

Summary

Per the SQLite docs, sqlite3_reset(S) may return a deferred error code
from the prior sqlite3_step(S) call. Several statement execution paths in
src/node_sqlite.cc dropped that return value, which could silently ignore
SQLite errors.

This also checks the previously ignored sqlite3_step() result in
StatementExecutionHelper::Run().

Fixes: #63311

Approach

Successful execution paths now explicitly check sqlite3_reset().

Functions with early-return or V8-exception paths keep an OnScopeLeave
reset guard so prepared statements are left reusable. The guard intentionally
drops the reset result to avoid replacing an already-pending SQLite or V8
exception.

StatementSyncIterator::Next() and StatementSyncIterator::Return() use a
direct checked reset because their control flow is linear.

$ python3 tools/cpplint.py src/node_sqlite.ccDone processing src/node_sqlite.cc
$ git diff --check -- src/node_sqlite.ccA full local build was not completed because this machine has Apple clang16.0.0, while the current tree requires a newer macOS toolchain. The buildfails in V8 because std::atomic_ref is unavailable.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/sqlite

@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. sqlite Issues and PRs related to the SQLite subsystem. labels May 15, 2026
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch 3 times, most recently from 557bcde to 4740589CompareMay 15, 2026 05:40
@codecov

codecovBot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.31%. Comparing base (e6fa5bf) to head (90fe5e2).
⚠️ Report is 38 commits behind head on main.

Files with missing linesPatch %Lines
src/node_sqlite.cc75.00%2 Missing and 7 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #63319 +/- ##
==========================================
- Coverage 90.32% 90.31% -0.01% 
==========================================
Files 759 759 Lines 248328 248352 +24 Branches 46856 46868 +12 ==========================================
- Hits 224296 224293 -3 + Misses 15466 15459 -7 - Partials 8566 8600 +34 
Files with missing linesCoverage Δ
src/node_sqlite.cc81.03% <75.00%> (-0.20%)⬇️

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@geeksilva97

Copy link
Copy Markdown
Contributor

I tried to reproduce a situation where the current code wouldn't catch the error but I couldn't. Please, get such a case into a test so it's clear which situation we must cover.

@TrevorBurnhamTrevorBurnham 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.

Reviewed the reset-error handling. The direction looks right; sqlite3_reset() returning a deferred error from the prior sqlite3_step() is real and worth surfacing. Two things I'd want addressed:

  1. In StatementSyncIterator, RESET_OR_THROW expands to a return, so the new throwing paths skip iter->done_ = true even though the statement has already been reset. A caught error then leaves the iterator resumable, and it replays the result set from the top. Details inline.

  2. No tests. get()/all() can now throw where they previously returned an already-built row/array, which is a user-visible change on a success path. Worth coverage pinning the new behavior, plus a note on whether it needs semver-major.

Things I checked that look correct: needs_reset = false is sequenced before sqlite3_reset(), so there's no double reset on the throwing path; no function can call THROW_ERR_SQLITE_ERROR twice, so the ShouldIgnoreSQLiteError() one-shot isn't consumed twice; void() threads through both macro layers; and every RESET_AND_CHECK caller keeps its OnScopeLeave safety net for the earlier failure paths.

Comment threadsrc/node_sqlite.cc Outdated
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4740589 to 4443a70CompareAugust 7, 2026 01:53
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Rebased onto main and addressed the feedback:

  • Return() now ignores the reset result (like the other OnScopeLeave guards) so it can't discard a pending exception during abrupt iterator close
  • Next()'s exhaustion path setting done_ came in via the rebase
  • Added tests for both, plus the get()/all() deferred-error case
  • Added the suggested comment in Run()

get()/all() can now throw on a previously-succeeding path — let me know if this needs notable-change.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4443a70 to ba4e195CompareAugust 7, 2026 03:47
@semimikoh

This comment was marked as outdated.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ba4e195 to ea9f2dfCompareAugust 7, 2026 03:59
@semimikoh

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ea9f2df to 52592e6CompareAugust 7, 2026 06:44
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

@trivikr CI is green now (conflicts resolved, lint fixed). Ready for another look whenever you have time.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
Comment threadsrc/node_sqlite.cc Outdated
@trivikrtrivikr removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Fixed — swapped the order so done_ is set before the checked reset, matching your suggestion.

On the test request: I don't think a failing-reset test is constructible for this specific branch. This code path is only reached after CHECK_ERROR_OR_THROW has already confirmed r == SQLITE_DONE, and in SQLite's own implementation (sqlite3VdbeReset(), vdbeapi.c):

/* If the VM did not run to completion or if it encountered an** error, then it might not have been halted properly. So halt** it now.*/if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);

sqlite3VdbeHalt() — where commits and constraint checks actually happen — only runs if the VDBE is still in VDBE_RUN_STATE. Once sqlite3_step() has returned SQLITE_DONE, the halt already happened during that step call, so a subsequent sqlite3_reset() can't trigger a new commit-time failure here. This matches @TrevorBurnham's earlier note that the equivalent SQLITE_DONE check in Get() is "effectively a no-op."

The sqlite3_reset() doc's BUSY/RETURNING example specifically requires stopping after SQLITE_ROW (VDBE still RUN_STATE) — that's the Return()/Get()/All() case, which is already covered. Happy to add the reset-fails test there if it's not covered well enough, but for this particular Next() branch I believe it's unreachable by construction.

Signed-off-by: semimikoh <ejffjeosms@gmail.com>
- StatementSyncIterator::Return() no longer throws on a deferred
reset error, matching the OnScopeLeave guards used elsewhere: it
is invoked during abrupt iterator completion (e.g. a throw inside
a for...of body), and throwing there would discard the caller's
already-pending exception.
- Add a short comment on the accepted SQLITE_ROW result in Run().
- Add tests covering get()/all() surfacing a deferred SQLite error
from reset() after already building a row/array, the iterator not
replaying results after natural exhaustion, and a pending exception
propagating correctly when the loop body throws mid-iteration.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
RESET_OR_THROW returns early on a deferred error, so the previous
ordering skipped iter->done_ = true when the reset in the natural
exhaustion path failed. The statement was reset either way, so
setting done_ first is safe and avoids leaving a caught error in a
resumable state.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
Rebasing onto main picked up "sqlite: refactor error helpers and
user function pointers", which moved SQLTagStore::All()'s reset and
bind logic into ResetAndBindStatement() and removed the local
Isolate* isolate declaration that this PR's trailing RESET_AND_CHECK
call still depends on. Re-add it.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 6f667c2 to 90fe5e2CompareAugust 9, 2026 13:01
@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 9, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 673cdef into nodejs:mainAug 11, 2026
90 of 92 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 673cdef

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.c++Issues and PRs that require attention from people who are familiar with C++.commit-queue-squashPRs the Commit Queue should land as one squashed commit.needs-ciPRs that need a full CI run.sqliteIssues and PRs related to the SQLite subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unchecked sqlite3 API calls

5 participants

@semimikoh@nodejs-github-bot@geeksilva97@trivikr@TrevorBurnham
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

sqlite: check sqlite3_step() and sqlite3_reset() results - #63319

Merged
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns
Aug 11, 2026
Merged

sqlite: check sqlite3_step() and sqlite3_reset() results#63319
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns

Conversation

@semimikoh

Copy link
Copy Markdown
Contributor

Summary

Per the SQLite docs, sqlite3_reset(S) may return a deferred error code
from the prior sqlite3_step(S) call. Several statement execution paths in
src/node_sqlite.cc dropped that return value, which could silently ignore
SQLite errors.

This also checks the previously ignored sqlite3_step() result in
StatementExecutionHelper::Run().

Fixes: #63311

Approach

Successful execution paths now explicitly check sqlite3_reset().

Functions with early-return or V8-exception paths keep an OnScopeLeave
reset guard so prepared statements are left reusable. The guard intentionally
drops the reset result to avoid replacing an already-pending SQLite or V8
exception.

StatementSyncIterator::Next() and StatementSyncIterator::Return() use a
direct checked reset because their control flow is linear.

$ python3 tools/cpplint.py src/node_sqlite.ccDone processing src/node_sqlite.cc
$ git diff --check -- src/node_sqlite.ccA full local build was not completed because this machine has Apple clang16.0.0, while the current tree requires a newer macOS toolchain. The buildfails in V8 because std::atomic_ref is unavailable.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/sqlite

@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. sqlite Issues and PRs related to the SQLite subsystem. labels May 15, 2026
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch 3 times, most recently from 557bcde to 4740589CompareMay 15, 2026 05:40
@codecov

codecovBot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.31%. Comparing base (e6fa5bf) to head (90fe5e2).
⚠️ Report is 38 commits behind head on main.

Files with missing linesPatch %Lines
src/node_sqlite.cc75.00%2 Missing and 7 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #63319 +/- ##
==========================================
- Coverage 90.32% 90.31% -0.01% 
==========================================
Files 759 759 Lines 248328 248352 +24 Branches 46856 46868 +12 ==========================================
- Hits 224296 224293 -3 + Misses 15466 15459 -7 - Partials 8566 8600 +34 
Files with missing linesCoverage Δ
src/node_sqlite.cc81.03% <75.00%> (-0.20%)⬇️

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@geeksilva97

Copy link
Copy Markdown
Contributor

I tried to reproduce a situation where the current code wouldn't catch the error but I couldn't. Please, get such a case into a test so it's clear which situation we must cover.

@TrevorBurnhamTrevorBurnham 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.

Reviewed the reset-error handling. The direction looks right; sqlite3_reset() returning a deferred error from the prior sqlite3_step() is real and worth surfacing. Two things I'd want addressed:

  1. In StatementSyncIterator, RESET_OR_THROW expands to a return, so the new throwing paths skip iter->done_ = true even though the statement has already been reset. A caught error then leaves the iterator resumable, and it replays the result set from the top. Details inline.

  2. No tests. get()/all() can now throw where they previously returned an already-built row/array, which is a user-visible change on a success path. Worth coverage pinning the new behavior, plus a note on whether it needs semver-major.

Things I checked that look correct: needs_reset = false is sequenced before sqlite3_reset(), so there's no double reset on the throwing path; no function can call THROW_ERR_SQLITE_ERROR twice, so the ShouldIgnoreSQLiteError() one-shot isn't consumed twice; void() threads through both macro layers; and every RESET_AND_CHECK caller keeps its OnScopeLeave safety net for the earlier failure paths.

Comment threadsrc/node_sqlite.cc Outdated
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4740589 to 4443a70CompareAugust 7, 2026 01:53
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Rebased onto main and addressed the feedback:

  • Return() now ignores the reset result (like the other OnScopeLeave guards) so it can't discard a pending exception during abrupt iterator close
  • Next()'s exhaustion path setting done_ came in via the rebase
  • Added tests for both, plus the get()/all() deferred-error case
  • Added the suggested comment in Run()

get()/all() can now throw on a previously-succeeding path — let me know if this needs notable-change.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4443a70 to ba4e195CompareAugust 7, 2026 03:47
@semimikoh

This comment was marked as outdated.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ba4e195 to ea9f2dfCompareAugust 7, 2026 03:59
@semimikoh

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ea9f2df to 52592e6CompareAugust 7, 2026 06:44
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

@trivikr CI is green now (conflicts resolved, lint fixed). Ready for another look whenever you have time.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
Comment threadsrc/node_sqlite.cc Outdated
@trivikrtrivikr removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Fixed — swapped the order so done_ is set before the checked reset, matching your suggestion.

On the test request: I don't think a failing-reset test is constructible for this specific branch. This code path is only reached after CHECK_ERROR_OR_THROW has already confirmed r == SQLITE_DONE, and in SQLite's own implementation (sqlite3VdbeReset(), vdbeapi.c):

/* If the VM did not run to completion or if it encountered an** error, then it might not have been halted properly. So halt** it now.*/if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);

sqlite3VdbeHalt() — where commits and constraint checks actually happen — only runs if the VDBE is still in VDBE_RUN_STATE. Once sqlite3_step() has returned SQLITE_DONE, the halt already happened during that step call, so a subsequent sqlite3_reset() can't trigger a new commit-time failure here. This matches @TrevorBurnham's earlier note that the equivalent SQLITE_DONE check in Get() is "effectively a no-op."

The sqlite3_reset() doc's BUSY/RETURNING example specifically requires stopping after SQLITE_ROW (VDBE still RUN_STATE) — that's the Return()/Get()/All() case, which is already covered. Happy to add the reset-fails test there if it's not covered well enough, but for this particular Next() branch I believe it's unreachable by construction.

Signed-off-by: semimikoh <ejffjeosms@gmail.com>
- StatementSyncIterator::Return() no longer throws on a deferred
reset error, matching the OnScopeLeave guards used elsewhere: it
is invoked during abrupt iterator completion (e.g. a throw inside
a for...of body), and throwing there would discard the caller's
already-pending exception.
- Add a short comment on the accepted SQLITE_ROW result in Run().
- Add tests covering get()/all() surfacing a deferred SQLite error
from reset() after already building a row/array, the iterator not
replaying results after natural exhaustion, and a pending exception
propagating correctly when the loop body throws mid-iteration.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
RESET_OR_THROW returns early on a deferred error, so the previous
ordering skipped iter->done_ = true when the reset in the natural
exhaustion path failed. The statement was reset either way, so
setting done_ first is safe and avoids leaving a caught error in a
resumable state.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
Rebasing onto main picked up "sqlite: refactor error helpers and
user function pointers", which moved SQLTagStore::All()'s reset and
bind logic into ResetAndBindStatement() and removed the local
Isolate* isolate declaration that this PR's trailing RESET_AND_CHECK
call still depends on. Re-add it.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 6f667c2 to 90fe5e2CompareAugust 9, 2026 13:01
@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 9, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 673cdef into nodejs:mainAug 11, 2026
90 of 92 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 673cdef

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.c++Issues and PRs that require attention from people who are familiar with C++.commit-queue-squashPRs the Commit Queue should land as one squashed commit.needs-ciPRs that need a full CI run.sqliteIssues and PRs related to the SQLite subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unchecked sqlite3 API calls

5 participants

@semimikoh@nodejs-github-bot@geeksilva97@trivikr@TrevorBurnham
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

sqlite: check sqlite3_step() and sqlite3_reset() results - #63319

Merged
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns
Aug 11, 2026
Merged

sqlite: check sqlite3_step() and sqlite3_reset() results#63319
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns

Conversation

@semimikoh

Copy link
Copy Markdown
Contributor

Summary

Per the SQLite docs, sqlite3_reset(S) may return a deferred error code
from the prior sqlite3_step(S) call. Several statement execution paths in
src/node_sqlite.cc dropped that return value, which could silently ignore
SQLite errors.

This also checks the previously ignored sqlite3_step() result in
StatementExecutionHelper::Run().

Fixes: #63311

Approach

Successful execution paths now explicitly check sqlite3_reset().

Functions with early-return or V8-exception paths keep an OnScopeLeave
reset guard so prepared statements are left reusable. The guard intentionally
drops the reset result to avoid replacing an already-pending SQLite or V8
exception.

StatementSyncIterator::Next() and StatementSyncIterator::Return() use a
direct checked reset because their control flow is linear.

$ python3 tools/cpplint.py src/node_sqlite.ccDone processing src/node_sqlite.cc
$ git diff --check -- src/node_sqlite.ccA full local build was not completed because this machine has Apple clang16.0.0, while the current tree requires a newer macOS toolchain. The buildfails in V8 because std::atomic_ref is unavailable.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/sqlite

@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. sqlite Issues and PRs related to the SQLite subsystem. labels May 15, 2026
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch 3 times, most recently from 557bcde to 4740589CompareMay 15, 2026 05:40
@codecov

codecovBot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.31%. Comparing base (e6fa5bf) to head (90fe5e2).
⚠️ Report is 38 commits behind head on main.

Files with missing linesPatch %Lines
src/node_sqlite.cc75.00%2 Missing and 7 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #63319 +/- ##
==========================================
- Coverage 90.32% 90.31% -0.01% 
==========================================
Files 759 759 Lines 248328 248352 +24 Branches 46856 46868 +12 ==========================================
- Hits 224296 224293 -3 + Misses 15466 15459 -7 - Partials 8566 8600 +34 
Files with missing linesCoverage Δ
src/node_sqlite.cc81.03% <75.00%> (-0.20%)⬇️

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@geeksilva97

Copy link
Copy Markdown
Contributor

I tried to reproduce a situation where the current code wouldn't catch the error but I couldn't. Please, get such a case into a test so it's clear which situation we must cover.

@TrevorBurnhamTrevorBurnham 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.

Reviewed the reset-error handling. The direction looks right; sqlite3_reset() returning a deferred error from the prior sqlite3_step() is real and worth surfacing. Two things I'd want addressed:

  1. In StatementSyncIterator, RESET_OR_THROW expands to a return, so the new throwing paths skip iter->done_ = true even though the statement has already been reset. A caught error then leaves the iterator resumable, and it replays the result set from the top. Details inline.

  2. No tests. get()/all() can now throw where they previously returned an already-built row/array, which is a user-visible change on a success path. Worth coverage pinning the new behavior, plus a note on whether it needs semver-major.

Things I checked that look correct: needs_reset = false is sequenced before sqlite3_reset(), so there's no double reset on the throwing path; no function can call THROW_ERR_SQLITE_ERROR twice, so the ShouldIgnoreSQLiteError() one-shot isn't consumed twice; void() threads through both macro layers; and every RESET_AND_CHECK caller keeps its OnScopeLeave safety net for the earlier failure paths.

Comment threadsrc/node_sqlite.cc Outdated
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4740589 to 4443a70CompareAugust 7, 2026 01:53
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Rebased onto main and addressed the feedback:

  • Return() now ignores the reset result (like the other OnScopeLeave guards) so it can't discard a pending exception during abrupt iterator close
  • Next()'s exhaustion path setting done_ came in via the rebase
  • Added tests for both, plus the get()/all() deferred-error case
  • Added the suggested comment in Run()

get()/all() can now throw on a previously-succeeding path — let me know if this needs notable-change.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4443a70 to ba4e195CompareAugust 7, 2026 03:47
@semimikoh

This comment was marked as outdated.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ba4e195 to ea9f2dfCompareAugust 7, 2026 03:59
@semimikoh

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ea9f2df to 52592e6CompareAugust 7, 2026 06:44
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

@trivikr CI is green now (conflicts resolved, lint fixed). Ready for another look whenever you have time.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
Comment threadsrc/node_sqlite.cc Outdated
@trivikrtrivikr removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Fixed — swapped the order so done_ is set before the checked reset, matching your suggestion.

On the test request: I don't think a failing-reset test is constructible for this specific branch. This code path is only reached after CHECK_ERROR_OR_THROW has already confirmed r == SQLITE_DONE, and in SQLite's own implementation (sqlite3VdbeReset(), vdbeapi.c):

/* If the VM did not run to completion or if it encountered an** error, then it might not have been halted properly. So halt** it now.*/if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);

sqlite3VdbeHalt() — where commits and constraint checks actually happen — only runs if the VDBE is still in VDBE_RUN_STATE. Once sqlite3_step() has returned SQLITE_DONE, the halt already happened during that step call, so a subsequent sqlite3_reset() can't trigger a new commit-time failure here. This matches @TrevorBurnham's earlier note that the equivalent SQLITE_DONE check in Get() is "effectively a no-op."

The sqlite3_reset() doc's BUSY/RETURNING example specifically requires stopping after SQLITE_ROW (VDBE still RUN_STATE) — that's the Return()/Get()/All() case, which is already covered. Happy to add the reset-fails test there if it's not covered well enough, but for this particular Next() branch I believe it's unreachable by construction.

Signed-off-by: semimikoh <ejffjeosms@gmail.com>
- StatementSyncIterator::Return() no longer throws on a deferred
reset error, matching the OnScopeLeave guards used elsewhere: it
is invoked during abrupt iterator completion (e.g. a throw inside
a for...of body), and throwing there would discard the caller's
already-pending exception.
- Add a short comment on the accepted SQLITE_ROW result in Run().
- Add tests covering get()/all() surfacing a deferred SQLite error
from reset() after already building a row/array, the iterator not
replaying results after natural exhaustion, and a pending exception
propagating correctly when the loop body throws mid-iteration.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
RESET_OR_THROW returns early on a deferred error, so the previous
ordering skipped iter->done_ = true when the reset in the natural
exhaustion path failed. The statement was reset either way, so
setting done_ first is safe and avoids leaving a caught error in a
resumable state.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
Rebasing onto main picked up "sqlite: refactor error helpers and
user function pointers", which moved SQLTagStore::All()'s reset and
bind logic into ResetAndBindStatement() and removed the local
Isolate* isolate declaration that this PR's trailing RESET_AND_CHECK
call still depends on. Re-add it.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 6f667c2 to 90fe5e2CompareAugust 9, 2026 13:01
@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 9, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 673cdef into nodejs:mainAug 11, 2026
90 of 92 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 673cdef

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.c++Issues and PRs that require attention from people who are familiar with C++.commit-queue-squashPRs the Commit Queue should land as one squashed commit.needs-ciPRs that need a full CI run.sqliteIssues and PRs related to the SQLite subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unchecked sqlite3 API calls

5 participants

@semimikoh@nodejs-github-bot@geeksilva97@trivikr@TrevorBurnham
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

sqlite: check sqlite3_step() and sqlite3_reset() results - #63319

Merged
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns
Aug 11, 2026
Merged

sqlite: check sqlite3_step() and sqlite3_reset() results#63319
nodejs-github-bot merged 4 commits into
nodejs:mainfrom
semimikoh:sqlite/check-step-reset-returns

Conversation

@semimikoh

Copy link
Copy Markdown
Contributor

Summary

Per the SQLite docs, sqlite3_reset(S) may return a deferred error code
from the prior sqlite3_step(S) call. Several statement execution paths in
src/node_sqlite.cc dropped that return value, which could silently ignore
SQLite errors.

This also checks the previously ignored sqlite3_step() result in
StatementExecutionHelper::Run().

Fixes: #63311

Approach

Successful execution paths now explicitly check sqlite3_reset().

Functions with early-return or V8-exception paths keep an OnScopeLeave
reset guard so prepared statements are left reusable. The guard intentionally
drops the reset result to avoid replacing an already-pending SQLite or V8
exception.

StatementSyncIterator::Next() and StatementSyncIterator::Return() use a
direct checked reset because their control flow is linear.

$ python3 tools/cpplint.py src/node_sqlite.ccDone processing src/node_sqlite.cc
$ git diff --check -- src/node_sqlite.ccA full local build was not completed because this machine has Apple clang16.0.0, while the current tree requires a newer macOS toolchain. The buildfails in V8 because std::atomic_ref is unavailable.

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/sqlite

@nodejs-github-botnodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. sqlite Issues and PRs related to the SQLite subsystem. labels May 15, 2026
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch 3 times, most recently from 557bcde to 4740589CompareMay 15, 2026 05:40
@codecov

codecovBot commented May 15, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 75.00000% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 90.31%. Comparing base (e6fa5bf) to head (90fe5e2).
⚠️ Report is 38 commits behind head on main.

Files with missing linesPatch %Lines
src/node_sqlite.cc75.00%2 Missing and 7 partials ⚠️
Additional details and impacted files
@@ Coverage Diff @@## main #63319 +/- ##
==========================================
- Coverage 90.32% 90.31% -0.01% 
==========================================
Files 759 759 Lines 248328 248352 +24 Branches 46856 46868 +12 ==========================================
- Hits 224296 224293 -3 + Misses 15466 15459 -7 - Partials 8566 8600 +34 
Files with missing linesCoverage Δ
src/node_sqlite.cc81.03% <75.00%> (-0.20%)⬇️

... and 45 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@geeksilva97

Copy link
Copy Markdown
Contributor

I tried to reproduce a situation where the current code wouldn't catch the error but I couldn't. Please, get such a case into a test so it's clear which situation we must cover.

@TrevorBurnhamTrevorBurnham 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.

Reviewed the reset-error handling. The direction looks right; sqlite3_reset() returning a deferred error from the prior sqlite3_step() is real and worth surfacing. Two things I'd want addressed:

  1. In StatementSyncIterator, RESET_OR_THROW expands to a return, so the new throwing paths skip iter->done_ = true even though the statement has already been reset. A caught error then leaves the iterator resumable, and it replays the result set from the top. Details inline.

  2. No tests. get()/all() can now throw where they previously returned an already-built row/array, which is a user-visible change on a success path. Worth coverage pinning the new behavior, plus a note on whether it needs semver-major.

Things I checked that look correct: needs_reset = false is sequenced before sqlite3_reset(), so there's no double reset on the throwing path; no function can call THROW_ERR_SQLITE_ERROR twice, so the ShouldIgnoreSQLiteError() one-shot isn't consumed twice; void() threads through both macro layers; and every RESET_AND_CHECK caller keeps its OnScopeLeave safety net for the earlier failure paths.

Comment threadsrc/node_sqlite.cc Outdated
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
Comment threadsrc/node_sqlite.cc
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4740589 to 4443a70CompareAugust 7, 2026 01:53
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Rebased onto main and addressed the feedback:

  • Return() now ignores the reset result (like the other OnScopeLeave guards) so it can't discard a pending exception during abrupt iterator close
  • Next()'s exhaustion path setting done_ came in via the rebase
  • Added tests for both, plus the get()/all() deferred-error case
  • Added the suggested comment in Run()

get()/all() can now throw on a previously-succeeding path — let me know if this needs notable-change.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 4443a70 to ba4e195CompareAugust 7, 2026 03:47
@semimikoh

This comment was marked as outdated.

@trivikr

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ba4e195 to ea9f2dfCompareAugust 7, 2026 03:59
@semimikoh

This comment was marked as outdated.

@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from ea9f2df to 52592e6CompareAugust 7, 2026 06:44
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

@trivikr CI is green now (conflicts resolved, lint fixed). Ready for another look whenever you have time.

@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
Comment threadsrc/node_sqlite.cc Outdated
@trivikrtrivikr removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 7, 2026
@semimikoh

Copy link
Copy Markdown
ContributorAuthor

Fixed — swapped the order so done_ is set before the checked reset, matching your suggestion.

On the test request: I don't think a failing-reset test is constructible for this specific branch. This code path is only reached after CHECK_ERROR_OR_THROW has already confirmed r == SQLITE_DONE, and in SQLite's own implementation (sqlite3VdbeReset(), vdbeapi.c):

/* If the VM did not run to completion or if it encountered an** error, then it might not have been halted properly. So halt** it now.*/if( p->eVdbeState==VDBE_RUN_STATE ) sqlite3VdbeHalt(p);

sqlite3VdbeHalt() — where commits and constraint checks actually happen — only runs if the VDBE is still in VDBE_RUN_STATE. Once sqlite3_step() has returned SQLITE_DONE, the halt already happened during that step call, so a subsequent sqlite3_reset() can't trigger a new commit-time failure here. This matches @TrevorBurnham's earlier note that the equivalent SQLITE_DONE check in Get() is "effectively a no-op."

The sqlite3_reset() doc's BUSY/RETURNING example specifically requires stopping after SQLITE_ROW (VDBE still RUN_STATE) — that's the Return()/Get()/All() case, which is already covered. Happy to add the reset-fails test there if it's not covered well enough, but for this particular Next() branch I believe it's unreachable by construction.

Signed-off-by: semimikoh <ejffjeosms@gmail.com>
- StatementSyncIterator::Return() no longer throws on a deferred
reset error, matching the OnScopeLeave guards used elsewhere: it
is invoked during abrupt iterator completion (e.g. a throw inside
a for...of body), and throwing there would discard the caller's
already-pending exception.
- Add a short comment on the accepted SQLITE_ROW result in Run().
- Add tests covering get()/all() surfacing a deferred SQLite error
from reset() after already building a row/array, the iterator not
replaying results after natural exhaustion, and a pending exception
propagating correctly when the loop body throws mid-iteration.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
RESET_OR_THROW returns early on a deferred error, so the previous
ordering skipped iter->done_ = true when the reset in the natural
exhaustion path failed. The statement was reset either way, so
setting done_ first is safe and avoids leaving a caught error in a
resumable state.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
Rebasing onto main picked up "sqlite: refactor error helpers and
user function pointers", which moved SQLTagStore::All()'s reset and
bind logic into ResetAndBindStatement() and removed the local
Isolate* isolate declaration that this PR's trailing RESET_AND_CHECK
call still depends on. Re-add it.
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
@semimikoh
semimikohforce-pushed the sqlite/check-step-reset-returns branch from 6f667c2 to 90fe5e2CompareAugust 9, 2026 13:01
@trivikrtrivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@trivikrtrivikr added the author ready PRs with CI started, the required approvals, and no outstanding review comments. label Aug 9, 2026
@github-actionsgithub-actionsBot removed the request-ci Add this label to start a Jenkins CI on a PR. label Aug 9, 2026
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

@trivikrtrivikr added commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue PRs queued for automated landing through the Commit Queue. labels Aug 11, 2026
@nodejs-github-bot
nodejs-github-bot merged commit 673cdef into nodejs:mainAug 11, 2026
90 of 92 checks passed
@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Landed in 673cdef

@nodejs-github-botnodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
Signed-off-by: semimikoh <ejffjeosms@gmail.com>
PR-URL: #63319Fixes: #63311
Reviewed-By: Trivikram Kamat <trivikr.dev@gmail.com>
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

author readyPRs with CI started, the required approvals, and no outstanding review comments.c++Issues and PRs that require attention from people who are familiar with C++.commit-queue-squashPRs the Commit Queue should land as one squashed commit.needs-ciPRs that need a full CI run.sqliteIssues and PRs related to the SQLite subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unchecked sqlite3 API calls

5 participants

@semimikoh@nodejs-github-bot@geeksilva97@trivikr@TrevorBurnham