deleteResolvedReferences bound every id into a single unbounded `IN (...)`, so a list longer than SQLITE_MAX_VARIABLE_NUMBER (32766 on the bundled node:sqlite) threw "too many SQL variables" — the one IN-list in queries.ts that #540 missed. It's reachable only through the exported QueryBuilder (library use): the internal resolution path uses deleteSpecificResolvedReferences, which binds per-row and is immune, so the CLI/MCP indexing pipeline was never affected. Wrap it in the same SQLITE_PARAM_CHUNK_SIZE loop every sibling query uses, and add a regression test (33k ids, past the real 32766 ceiling) that throws without the fix. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
f83a1ecc8e
commit
30dc303f4c
@@ -97,6 +97,50 @@ describe('getNodesByIds (batch lookup)', () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe('deleteResolvedReferences (chunking)', () => {
|
||||
let dir: string;
|
||||
let db: DatabaseConnection;
|
||||
let q: QueryBuilder;
|
||||
|
||||
beforeEach(() => {
|
||||
dir = fs.mkdtempSync(path.join(os.tmpdir(), 'db-perf-delref-'));
|
||||
db = DatabaseConnection.initialize(path.join(dir, 'test.db'));
|
||||
q = new QueryBuilder(db.getDb());
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
db.close();
|
||||
if (fs.existsSync(dir)) fs.rmSync(dir, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
it('deletes unresolved refs for more ids than the SQLite parameter limit (#1001)', () => {
|
||||
// Regression: this method bound every id as one parameter in a single
|
||||
// IN (...), so passing more ids than SQLITE_MAX_VARIABLE_NUMBER (32766 on
|
||||
// the bundled node:sqlite) threw "too many SQL variables". Use 33000 to
|
||||
// clear that ceiling. from_node_id has a FK to nodes, so insert nodes first.
|
||||
const nodes = Array.from({ length: 33000 }, (_, i) => makeNode(`n${i}`));
|
||||
q.insertNodes(nodes);
|
||||
q.insertUnresolvedRefsBatch(
|
||||
nodes.map((n) => ({
|
||||
fromNodeId: n.id,
|
||||
referenceName: 'someName',
|
||||
referenceKind: 'calls',
|
||||
line: 1,
|
||||
column: 0,
|
||||
}))
|
||||
);
|
||||
expect(q.getUnresolvedReferencesCount()).toBe(33000);
|
||||
|
||||
const ids = nodes.map((n) => n.id);
|
||||
expect(() => q.deleteResolvedReferences(ids)).not.toThrow();
|
||||
expect(q.getUnresolvedReferencesCount()).toBe(0);
|
||||
});
|
||||
|
||||
it('handles an empty input array', () => {
|
||||
expect(() => q.deleteResolvedReferences([])).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('insertNode cache invalidation', () => {
|
||||
let dir: string;
|
||||
let db: DatabaseConnection;
|
||||
|
||||
Reference in New Issue
Block a user