Skip to content

fix(core): batch SqliteVecIndex.delete under SQLite expression-depth limit - #1857

Closed
MbappeWU wants to merge 1 commit into
basicmachines-co:mainfrom
MbappeWU:fix/1850-sqlite-vec-delete-batch
Closed

MbappeWU wants to merge 1 commit into
basicmachines-co:mainfrom
MbappeWU:fix/1850-sqlite-vec-delete-batch

Conversation

@MbappeWU

Copy link
Copy Markdown
Contributor

Fixes #1850.

Summary

SQLiteVecIndex.delete() built one UPDATE … WHERE project_id AND (p0 OR p1 OR …) statement with a 4-term AND predicate per pending chunk. SQLite's SQLITE_MAX_EXPR_DEPTH (1000) fails above ~995 deletions.

This batches the OR-chain work (_DELETE_BATCH_SIZE = 200), keeps the pending-row match semantics, and deletes embeddings/chunks from the collected rowids afterward.

Tests

  • pytest tests/repository/test_sqlite_vector_search_repository.py::test_sqlite_vec_delete_batches_above_expression_depth_limit tests/repository/test_sqlite_vector_search_repository.py::test_sqlite_vec_delete_requires_pending_source_generation -q → 2 passed (includes a new 1200-row regression)

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 24, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ⚠️ Failed 2026-10-24T19:23:31.396045Z
We couldn’t complete this review. Comment @codex review to try again.
3be6c4a PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

… limit

A single UPDATE with one 4-term AND predicate per pending chunk exceeds
SQLITE_MAX_EXPR_DEPTH above ~995 deletions. Delete in batches of 200 and
keep the pending-row match semantics. Add a 1200-row regression test.

Signed-off-by: MbappeWU <MbappeWU@users.noreply.github.com>
@MbappeWU
MbappeWU force-pushed the fix/1850-sqlite-vec-delete-batch branch from 3be6c4a to b18b506 Compare October 24, 2026 19:23
@MbappeWU MbappeWU changed the title fix(search): batch SqliteVecIndex.delete under SQLite expression-depth limit fix(core): batch SqliteVecIndex.delete under SQLite expression-depth limit Oct 24, 2026
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

1 similar comment
@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@MbappeWU

Copy link
Copy Markdown
Contributor Author

I have read the CLA Document and I hereby sign the CLA

@MbappeWU

Copy link
Copy Markdown
Contributor Author

@CLAassistant check

@phernandez

Copy link
Copy Markdown
Member

Thanks, @MbappeWU, for identifying the SQLite expression-depth failure and contributing the batching fix and regression test!

We cherry-picked your commit into #1865, preserving your authorship and sign-off, and added real SQLite integration coverage for large deletes, generation guards, and project isolation. Closing this PR in favor of #1865, which is approved and passing CI. Thank you for the contribution!

@phernandez phernandez closed this Oct 25, 2026
phernandez added a commit that referenced this pull request Oct 25, 2026
…1865)

## Why

Two reported SQLite failures block reindexing or startup: deleting a
large chunk manifest exceeds SQLite's expression-depth limit (#1850),
and an interrupted script-ngram migration leaves a scratch table that
prevents the next startup (#1853). Both reproduce on current main with
the contributor's regression tests.

Fixes #1850. Fixes #1853.

## What Changed

- Cherry-pick @MbappeWU's fixes from #1857 and #1859, retaining
authorship and sign-offs.
- Batch pending-vector deletion predicates and row-id deletes in groups
of 200.
- Drop a leftover `search_index_rebuilt` scratch table before rebuilding
the intact source index.
- Add real SQLite integration tests covering a 1,201-record delete,
protected generations/project partitions, repeated deletion, and
upgrade/downgrade retries with empty or populated scratch tables.

## Implementation Details

Deletion retains the existing project, key, source-hash and
pending-status guards in one transaction. Batching limits expression
depth and bound parameters without changing the concurrency protocol.

The migration rebuilds from `search_index`; the scratch table has no
authoritative state. Integration tests commit the interrupted state
before opening a new transaction and verify preserved full-text matches
afterward. They use Alembic's real Operations context and sqlite-vec
without application mocks. Contributor workflow-evidence notes are
omitted from the final diff.

## Testing

- Before fixes: the two new contributor regressions fail on main with
`Expression tree is too large` and `table search_index_rebuilt already
exists`.
- `uv run pytest
tests/repository/test_sqlite_vector_search_repository.py
tests/test_script_ngram_search_migration.py
test-int/test_sqlite_index_recovery.py -q -o addopts= --tb=short`: 46
passed.
- `just fast-check`: lint, format and full typecheck passed.
- `just doctor`: sandboxed write, index and search passed.
- `git diff --check`: passed.

## Risks / Follow-ups

Changes are SQLite-specific; PostgreSQL production paths are unchanged.
The recovery assumes the original FTS table remains intact, matching the
reported interrupted upgrade. #1861's watcher lifecycle changes are
reviewed separately.

---------

Signed-off-by: MbappeWU <MbappeWU@users.noreply.github.com>
Signed-off-by: phernandez <paul@basicmachines.co>
Co-authored-by: MbappeWU <MbappeWU@users.noreply.github.com>
@MbappeWU

Copy link
Copy Markdown
Contributor Author

Thanks @phernandez — glad to see this landed via #1865. Appreciate the cherry-pick and authorship credit.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] SqliteVecIndex.delete() builds one OR chain and fails above 995 deletions

3 participants