Repository navigation
perf: cache column names per statement for object rows - #53
Merged
Merged
Conversation
Contributor
Author
|
Verify Signed Commit Authors fails on Generated by Claude Code |
There was a problem hiding this comment.
🟡 Changes recommended
Cached keys may become stale if SQLite reprepares during a later step in all() or explainQueryPlan().
1 open issue
What changed in this PR
This PR caches statement column names and reuses RowBuilder for object-row construction, reducing repeated V8 string creation.
Changes:
- Adds per-statement column-key caching with schema invalidation.
- Routes object-row APIs through
RowBuilderon supported Node versions. - Adds schema-change regression tests.
| File | Summary |
|---|---|
test/23.statement.iterate.js |
Tests schema changes during iteration. |
test/22.statement.all.js |
Tests schema changes for all(). |
test/21.statement.get.js |
Tests schema changes for get(). |
src/util/row-builder.cpp |
Builds rows using cached keys. |
src/util/column-keys.cpp |
Implements cached column-name handles. |
src/objects/statement.hpp |
Adds statement cache and row-builder state. |
src/objects/statement.cpp |
Integrates cached row construction. |
src/objects/statement-iterator.cpp |
Uses the statement row-conversion path. |
src/better_sqlite3.cpp |
Includes the new utility. |
Review effort: Lite
get() and iterate() internalized every column name again for each row, and all() did so once per call. Statements now keep the names as persistent handles and refresh them only when SQLite re-prepares the statement (SQLITE_STMTSTATUS_REPREPARE) or the column count changes, which is the only time names can change, e.g. a schema change behind SELECT *.
arv
force-pushed
the
arv/cache-column-keys
branch
from
October 19, 2026 12:15
61c1840 to
3fa671b
Compare
This was referenced Oct 19, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

get()anditerate()internalized every column name again for each row, andall()did so once per call. Statements now keep the names asv8::Global<v8::Name>handles (src/util/column-keys.cpp) and refresh them only when SQLite re-prepares the statement (SQLITE_STMTSTATUS_REPREPARE) or the column count changes. That is the only time names can change, e.g. a schema change behindSELECT *.get(),iterate(),all()andexplainQueryPlannow all build object rows throughRowBuilder. Guarded byNODE_MODULE_VERSION >= 127(needsv8::LocalVector); older Node keeps the existing path.First of two stacked PRs; #54 builds rows from a cached
v8::DictionaryTemplateon top of this.Benchmark
Node 22.22.0, 2000-row tables with 4 and 10 columns. Runs alternate between builds; each figure is the median of 25 rounds, in µs.
all()iterate()get()×2000all()iterate()get()×2000prepare().get()Tests
get/all/iterate. Each runs the statement, thenALTER TABLE … RENAME COLUMNandADD COLUMN, and asserts the rows pick up the new names.🤖 Generated with Claude Code
https://claude.ai/code/session_01WCP5vbpvciRmgWBx2b1zKb