We are relying too much on the currently disabled `FaultyQuery` and
`FsyncNoWait` to assert the basic invariant of "the rows we have
inserted/updated/deleted in the database are still there", so adding
that as a separate `Property` here.
Closes#2610
Problem:
sim was generating compound selects like this:
- pick a random `table`
- create a random single SELECT
- create `n` random compound SELECTs (UNION ALL etc)
assign a WHERE clause that always has a condition based on `table`
This can result in e.g.
```
SELECT a FROM foo WHERE bar.x = 'baz'
```
Solution:
Don't base the WHERE clause on a table that might not be referenced
in the query.
Again, the only reason this wasn't caught before was because `FaultyQuery`
and `FsyncNoWait` are the only paths where this is actually tested with an
assertion, and those are both disabled
Closes#2588
SQLite internally implements `.clone` by doing something like piping
`.dump` into a new connection to a database attached to the file you
want. This PR implements that by adding an `ApplyWriter` that implements
`std::fmt::Write`, and refactors our current `.dump` plumbing to work
with any `Write` interface, so we can `.dump` to stdout or `.dump` to a
new connection, therefore cloning the database.
Reviewed-by: Nikita Sivukhin (@sivukhin)
Closes#2590
Add comprehensive documentation for connecting Turso databases to Claude
Code using the built-in MCP management commands.
This PR addresses the need for easier integration between Turso and
Claude Code by providing clear, step-by-step instructions for users who
want to query their databases using natural language.
Reviewed-by: Preston Thorpe <preston@turso.tech>
Closes#2606
Add comprehensive documentation for connecting Turso databases to Claude Code using the built-in MCP management commands.
The new guide includes:
- Quick 3-step setup process
- Visual command breakdown with annotations
- Multiple usage examples (local, absolute paths, project-scoped)
- MCP server management commands
- Example natural language queries users can make
This makes it much easier for developers to integrate their Turso databases with Claude Code without manually configuring JSON files or understanding the underlying MCP protocol details.
bringing #1127 back to life, except better because this doesn't add
Tokio as a dependency for extension lib just for tests.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#2418
we spend a shitload of time doing very complex selects in the simulator,
and i'm not sure there has been a lot of gain from them. using up a lot
of the runtime of a simulator run on these can mask other issues.
Reviewed-by: Preston Thorpe <preston@turso.tech>
Closes#2605
as @avinassh pointed out, if we have an error in a `writev` call, it
could go unnoticed and the checkpoint could proceed as expected after
not writing the expected total amt.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#2601
## Problem
We have been running the simulator for over a month without ever doing a
check like "did the rows we updated actually get updated" (#2602 ),
because the only properties that check those are - for whatever reason -
`FsyncNoWait` and `FaultyQuery`, and both of those have been disabled
for a long time.
Before we enable `FaultyQuery` again, let's make sure we don't have any
active bugs on `main` that don't depend on IO faults to happen. One of
these was an index-related corruption bug #2599 - already fixed - which
would've been caught by this test (or any similar assertion that just
checks what we updated in the DB, but we didn't have any)
## Solution
Add `Property::ReadYourUpdatesBack`, which essentially just does the
following:
```
UPDATE foo SET <arbitrary columns = arbitrary values> WHERE <arbitrary condition>
-- followed by
SELECT <the same columns> WHERE <the same condition>
```
And asserts that the values are the ones we just set
Reviewed-by: Pedro Muniz (@pedrocarlo)
Closes#2604
Closes#2598
Forbids using an index as the iteration cursor for an `UPDATE` statement
unless either of these is true:
1. The index is not affected by the `UPDATE` statement
2. The search condition on the index is guaranteed to return a maximum
of 1 row, so no iteration will happen
### Note
I have created a follow-up issue about handling this a bit better:
https://github.com/tursodatabase/turso/issues/2600Closes#2599
Closes#2555
## Problem
The main problem we had with the current implementation of
`init_pager()` was that the WAL header was eagerly allocated and written
to disk with a page size, and a potential already-set page size on an
initialized database was not checked. Given this scenario:
- Initialized database with e.g. page size 512 but no WAL
- Tursodb connects to DB
It would not check the database file for the page size and instead would
initialize the WAL header with the default 4096 page size, plus
initialize the `BufferPool` similarly with the wrong size, and then
panic when reading pages from the DB, expecting to read `4096` instead
of `512`, as demonstrated in the reproduction of #2555.
## Fix
1. Add `Database::read_page_size_from_db_header()` method that can be
used in the above cases
2. Initialize the WAL header lazily during the first frame append, using
the existing `WalFile::ensure_header_if_needed()` method, removing the
need to eagerly pass `page_size` when constructing the in-memory
`WalFileShared` structure.
## Reader notes
This PR follows a fairly logical commit-by-commit structure so you'll
preferably want to read it that way.
Reviewed-by: Nikita Sivukhin (@sivukhin)
Closes#2569