libsql exposes a WAL checkpoint callback that is called once for each
frame and right when checkpointing is about to finish.
before this change, the result code returned by the checkpoint callback
was ignored on the 'finish' invocation, which resulted in the checkpoint
completing successfully despite the callback returning an error.
this commit propagates the callback's error code and thus prevents the
wal_checkpoint() routine from returning SQLITE_OK in cases where the
callback failed.
This fixes a missing pager that `libsql_pager_codec` expects to not be
null. All this does is add the pager when we call `sqlite3PagerWalInsert`
to the wal frame we want to insert.
Fixes#1867
We need to reset the pager in sqlite3PagerWalEndCommit() to make sure
page cache is invalidated after injecting frames to WAL to ensure
they're visible.
We have a problem with WAL API where in some scenarios, we seem to lose
WAL frames that were already applied. However, inspecting the external
WAL frame, the sync mechanics work fine and the problem is in SQLite's
in-memory state.
As it turnws out, the sqlite3PagerWalBeginCommit() function first begins
a read transaction and then upgrades it to a write transaction. However,
sqlite3PagerWalEndCommit() only ends the write transaction and therefore
leaves the pager in READER state. Let's call pager_unlock() to switch to
OPEN stte, fixing the issue of disappearing frames.
This patch adds a libsql_wal_get_frame() API to read the raw WAL frame
from a database.
You can use the API as follows (omitting error handling) to obtain all
the WAL frames in a database:
```c
static int sync_db(sqlite3 *db_primary, sqlite3 *db_backup){
unsigned int max_frame;
libsql_wal_frame_count(db_primary, &max_frame);
for(int i=1; i<=max_frame; i++){
char frame[4096+24];
libsql_wal_get_frame(db_primary, i, frame, sizeof(frame));
}
}
```
This adds a new xReadFrameRaw() function to the virtual WAL API, which
upper layers can use to fetch the full frame, including the page number,
that is useful for appending frames to a WAL.
SQLite unconditionally checkpoints when the last connection is closed to
a database. Let's add a libSQL extension API to give callers control
over that.
The module struct initializer for xPrepareSql is wrong since commit
d178de8f07 ("bugfix: reset modifications of `sqlite3_vtab` (#1027)")
because it assings the xPrepareSql as the xIntegrity hook:
```
/home/runner/work/libsql/libsql/libsql-sqlite3/src/test8.c:1364:3: warning: initialization of 'int (*)(sqlite3_vtab *, const char *, const char *, int, char **)' from incompatible pointer type 'int (*)(sqlite3_vtab_cursor *, const char *)' [-Wincompatible-pointer-types]
1364 | echoPreparedSql,
| ^~~~~~~~~~~~~~~
/home/runner/work/libsql/libsql/libsql-sqlite3/src/test8.c:1364:3: note: (near initialization for 'echoModuleV2.xIntegrity')
```
- it cah be hard in some cliens (JS for example) to distinguish between INTEGERs and FLOATs - so we always bind FLOATs instead
- this create unnecessary error: "vector index(search): third parameter (k) must be a non-negative integer"