`TransitionResult::Continue` is an internal implementation detail that
tells an invocation of `StateMachine::step()` to continue looping, but
it is of no use to upstream callers.
For this reason, just return an IOResult from StateMachine::step() which
simplifies the result handling.
Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>
Closes#3248
TransitionResult is an internal implementation detail that tells
an invocation of StateMachine::step() to continue looping, but it
is of no use to other callers.
For this reason, just return an IOResult from StateMachine::step()
which simplifies the result handling.
This PR does not implement MVCC checkpoint yet, just adds a lock for it.
MVCC checkpoints are always TRUNCATE, plus they block all other
transactions. This guarantees that never need to let transactions read
from the SQLite WAL.
In MVCC, the checkpoint procedure is roughly as follows:
- Take the blocking_checkpoint_lock
- Write everything in the logical log to the pager, and from there
commit to the SQLite WAL.
- Immediately TRUNCATE checkpoint the WAL into the database file.
- Release the blocking_checkpoint_lock.
Reviewed-by: Pere Diaz Bou <pere-altea@homail.com>
Closes#3244
This PR adds support for partial indexes, e.g. `CREATE INDEX` with a
provided predicate
```sql
CREATE UNIQUE INDEX idx_expensive ON products(sku) where price > 100;
```
The PR does not yet implement support for using the partial indexes in
the optimizer.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#3228
- Made the code around snapshot isolation more ergonomic with each
connections having its own transaction state. Also when shadowing, we
pass a ShadowTablesMut object that dynamically uses the committed tables
or the connection tables depending on the transaction state.
- added begin concurrent transaction before every property when mvcc is
enabled (this is just so we can have some mvcc code be tested using the
simulator under Begin Concurrent, I have not yet implemented the logic
to have concurrent transactions in the simulator)
- some small enhancements to shrinking
TODOs
- have proper logic to have concurrent transactions without WriteWrite
conflicts. This means when generating the plans we need to make sure
that we do not generate rows that will conflict with rows in other
transactions. This is slightly more powerful than what we do in the
fuzzer, as we just have `WriteWriteConflict` as an acceptable error
there. By baking this `NoConflict` approach to the simulator, we can
continuously test the what does not trigger a WriteWriteConflict and
snapshot isolation.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#3226
MVCC checkpoints are always TRUNCATE, plus they block all other transactions.
This guarantees that never need to let transactions read from the SQLite WAL.
In MVCC, the checkpoint procedure is roughly as follows:
- Take the blocking_checkpoint_lock
- Write everything in the logical log to the pager, and from there commit to the SQLite WAL.
- Immediately TRUNCATE checkpoint the WAL into the database file.
- Release the blocking_checkpoint_lock.
Add a `Once` object to uphold this property. We cannot use the OnceLock
to dictate this, because if we set the OnceLock before actually calling
the callback, there is a moment in time where we will have an incorrect
transient state. This change ensures we atomically call the callback and
then set the OnceLock
Should fix#3217Closes#3217Closes#3237
UNION queries, while useful on their own, are a cornerstone of recursive
CTEs.
This PR implements:
* the merge operator, required to merge both sides of a union query.
* the circuitry necessary to issue the Merge operator.
* extraction of tables mentioned in union and CTE expressions, so we can
correctly populate tables that contain them.
Closes#3234
We currently don't handle non equality, but end up just returning a
bogus result. Let's parse error.
Reviewed-by: Jussi Saurio <jussi.saurio@gmail.com>
Closes#3232
This solves an issue where an INSERT statement conflicts with
multiple indices. In that case, sqlite iterates the linked list
`pTab->pIndex` in order and handles the first conflict encountered.
The newest parsed index is always added to the head of the list.
To be compatible with this behavior, we also need to put the most
recently parsed index definition first in our indexes list for a given
table.
This PR improves sync and database bindings for browser
List of changes:
- For node and browser database now run on main thread and only IO work
offloaded to the worker (web worker in browser)
- Simple locks are implemented for database access externally in order
to guard access to the same connection (when request is executed async -
main thread can try to start another request concurrently)
- parking_lot in the Wal replaced by spin-wait (by invoking
`parking_lot.try_read/try_write`) for WASM target because browser can't
park main thread
- js sync reworked in order to support few engine options
(`longPollTimeoutMs`) and introduce external locking which properly
guards concurrent access of sync methods
Closes#3218
The Merge operator is a stateless operator that merges two deltas.
There are two modes: Distinct, where we merge together values that
are the same, and All, where we preserve all values. We use the rowid of
the hashable row to guarantee that: In Distinct mode, the rowid is set
to 0 in both sides. If they values are the same, they will hash to the
same thing. For All, the rowids are different.
The merge operator is used for the UNION statement, which is a
cornerstone of Recursive CTEs.
The population code extracts table information from the select statement
so it can populate the materialized view. But the code, as written
today, is naive. It doesn't capture table information correctly if there
is more than one select statement (such in the case of a union query).