The SQLite command line has facilities to ingest things like csv, and
other formats. But here we are, in 2025, and I asked Claude if Turso's
CLI should, in the same vein, have a native MCP server.
Claude told me: "You're absolutely right!" "That's a great insight!"
"That's a fantastic idea!" and then proceeded to help me with the
boilerplate for this beautiful server.
Rust has a crate, mcp_server, that implements an mcp_server trait.
However, that depends on Tokio, and I think that would bloat our binary
too much.
I have also considered implementing an MCP server that operates on a
directory and allows to list many SQLite files, but figured that would
be a good job for a more advanced and specialized server, not for the
one that comes by default with the CLI. Let's go for simple.
Closes#2148
Currently we are using `find_cell` which does a binary search on every
insert, even if the cursor is already in the correct place.
1. Remove `find_cell` and use `seek` when inserting instead of
`move_to`.
2. After removing `find_cell`, we now need to be more mindful of when we
do actually require a seek before insertion. This is signified by the
addition of `InsertFlags::REQUIRE_SEEK`. Previously some inserts worked
by accident because we always happened to be on the correct page --
`find_cell()´ only binary searches a single page.
3. After removing `find_cell` we also need to call `next()` after
`Insn::NewRowid`, because `NewRowid` positions us at the old maximum
rowid, and we need to be positioned after it.
4. After removing `find_cell` we also need to leave the cursor
positioned correctly during seeks where we don't find a match.
5. Allow overwrite of an index interior cell, which Closes#1975.
Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>
Closes#1988
Another fix extracted from running simulations on the #1988 branch.
## What
When interior cell replacement happens as described in #2108, we use the
`cursor.prev()` method to locate the largest key in the left subtree.
There was an error during backwards traversal in the `get_prev_record()`
method where the parent's cell index was set as `i32::MAX` but not
properly set to `cell_count + 1` (indicating that rightmost pointer has
been visited).
This meant that if the child page we took the replacement cell from
underflowed and needed balancing, the parent page would now have
`i32::MAX` as its cell index and crash at the point where we determine
based on the parent page which page is going to undergo balancing.
## Fix
This PR fixes the issue by setting the cell index of the parent properly
when visiting the rightmost child. This way the balance procedure will
correctly detect that the rightmost child page is going to undergo
balancing.
### Trivia
The reason `i32::MAX` is used is that the cell count of the page is not
necessarily known at the time it is pushed to the stack.
Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>
Closes#2163
Another fix extracted from running simulations on the #1988 branch.
When interior cell replacement happens as described in #2108,
we use the `cursor.prev()` method to locate the largest key in the
left subtree.
There was an error during backwards traversal in the `get_prev_record()`
method where the parent's cell index was set as `i32::MAX` but not properly
set to `cell_count + 1` (indicating that rightmost pointer has been visited).
The reason `i32::MAX` is used is that the cell count of the page is not
necessarily known at the time it is pushed to the stack.
This PR fixes the issue by setting the cell index of the parent properly
when visiting the rightmost child.
Fixes#2153.
Not so sure if SQLite doesn't rollback in more cases, we should
definitively check this out.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#2154
pread and pwrite is usually less instructions then seek and read. Also
added possibility for io to retry if AGAIN error happens. And made write
to wait for Event::writable
Reviewed-by: Preston Thorpe (@PThorpe92)
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#2010
Closes#91
Replaces #1771 since the previous PR went stale and had too many
conflicts.
The maximum size of the in-memory buffer is determined by the settings
that configure the page-cache size.
In scope:
- Spill the in-memory buffer to a temporary file on disk if its size
exceeds the threshold
- When iterating over the sorter, the next record is picked using heap
populated from sorted chunk files
- Flushing the in-memory buffer and reading from chunk files occur
asynchronously.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#2128
Span creation in debug mode is very slow and impacts our ability to run
the Simulator faster.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#2146
If we use `Assumption` here, the simulator just goes to the next
property instead of halting here.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#2147