sqlite3: Add libsql_wal_frame_count() API

This commit is contained in:
Pekka Enberg 2025-05-15 10:06:10 +03:00
parent 78eb901940
commit 524a523036
6 changed files with 160 additions and 0 deletions

View file

@ -486,6 +486,10 @@ impl Connection {
Ok(())
}
pub fn wal_frame_count(&self) -> Result<u64> {
self.pager.wal_frame_count()
}
pub fn cacheflush(&self) -> Result<CheckpointStatus> {
self.pager.cacheflush()
}

View file

@ -398,6 +398,15 @@ impl Pager {
dirty_pages.insert(page_id);
}
pub fn wal_frame_count(&self) -> Result<u64> {
let mut frame_count = 0;
let wal = self.wal.clone();
if let Some(wal) = &wal {
frame_count = wal.borrow().get_max_frame_in_wal();
}
Ok(frame_count)
}
pub fn cacheflush(&self) -> Result<CheckpointStatus> {
let mut checkpoint_result = CheckpointResult::default();
loop {

34
docs/manual.md Normal file
View file

@ -0,0 +1,34 @@
# Limbo Documentation
## SQLite C API
### WAL manipulation
#### `libsql_wal_frame_count`
Get the number of frames in the WAL.
**Synopsis:**
```c
int libsql_wal_frame_count(sqlite3 *db, uint32_t *p_frame_count);
```
**Description:**
The `libsql_wal_frame_count` function returns the number of frames in the WAL
in the `p_frame_count` parameter.
**Return Values:**
* `SQLITE_OK` if the number of frames in the WAL file is successfully returned.
* `SQLITE_MISUSE` if the `db` is NULL.
* SQLITE_ERROR if an error occurs while getting the number of frames in the WAL
file.
**Safety Requirements:**
* The `db` parameter must be a valid pointer to a `sqlite3` database
connection.
* The `p_frame_count` must be a valid pointer to a `u32` that will store the
* number of frames in the WAL file.

View file

@ -266,6 +266,28 @@ int sqlite3_wal_checkpoint(sqlite3 *_db, const char *_db_name);
int sqlite3_wal_checkpoint_v2(sqlite3 *db, const char *_db_name, int _mode, int *_log_size, int *_checkpoint_count);
/**
* Get the number of frames in the WAL.
*
* The `libsql_wal_frame_count` function returns the number of frames
* in the WAL in the `p_frame_count` parameter.
*
* # Returns
*
* - `SQLITE_OK` if the number of frames in the WAL file is
* successfully returned.
* - `SQLITE_MISUSE` if the `db` is `NULL`.
* - `SQLITE_ERROR` if an error occurs while getting the number of frames
* in the WAL file.
*
* # Safety
*
* - The `db` must be a valid pointer to a `sqlite3` database connection.
* - The `p_frame_count` must be a valid pointer to a `u32` that will store
* the number of frames in the WAL file.
*/
int libsql_wal_frame_count(sqlite3 *db, uint32_t *p_frame_count);
#ifdef __cplusplus
} // extern "C"
#endif // __cplusplus

View file

@ -1097,3 +1097,38 @@ pub unsafe extern "C" fn sqlite3_wal_checkpoint_v2(
}
SQLITE_OK
}
/// Get the number of frames in the WAL.
///
/// The `libsql_wal_frame_count` function returns the number of frames
/// in the WAL in the `p_frame_count` parameter.
///
/// # Returns
///
/// - `SQLITE_OK` if the number of frames in the WAL file is
/// successfully returned.
/// - `SQLITE_MISUSE` if the `db` is `NULL`.
/// - `SQLITE_ERROR` if an error occurs while getting the number of frames
/// in the WAL file.
///
/// # Safety
///
/// - The `db` must be a valid pointer to a `sqlite3` database connection.
/// - The `p_frame_count` must be a valid pointer to a `u32` that will store
/// the number of frames in the WAL file.
#[no_mangle]
pub unsafe extern "C" fn libsql_wal_frame_count(
db: *mut sqlite3,
p_frame_count: *mut u32,
) -> ffi::c_int {
if db.is_null() {
return SQLITE_MISUSE;
}
let db: &mut sqlite3 = &mut *db;
let frame_count = match db.conn.wal_frame_count() {
Ok(count) => count as u32,
Err(_) => return SQLITE_ERROR,
};
*p_frame_count = frame_count;
SQLITE_OK
}

View file

@ -1,4 +1,5 @@
#![allow(non_camel_case_types)]
#![allow(dead_code)]
use std::ptr;
@ -26,6 +27,7 @@ extern "C" {
stmt: *mut *mut sqlite3_stmt,
tail: *mut *const libc::c_char,
) -> i32;
fn sqlite3_step(stmt: *mut sqlite3_stmt) -> i32;
fn sqlite3_finalize(stmt: *mut sqlite3_stmt) -> i32;
fn sqlite3_wal_checkpoint(db: *mut sqlite3, db_name: *const libc::c_char) -> i32;
fn sqlite3_wal_checkpoint_v2(
@ -35,10 +37,13 @@ extern "C" {
log_size: *mut i32,
checkpoint_count: *mut i32,
) -> i32;
fn libsql_wal_frame_count(db: *mut sqlite3, p_frame_count: *mut u32) -> i32;
}
const SQLITE_OK: i32 = 0;
const SQLITE_CANTOPEN: i32 = 14;
const SQLITE_DONE: i32 = 101;
const SQLITE_CHECKPOINT_PASSIVE: i32 = 0;
const SQLITE_CHECKPOINT_FULL: i32 = 1;
const SQLITE_CHECKPOINT_RESTART: i32 = 2;
@ -195,4 +200,55 @@ mod tests {
assert_eq!(sqlite3_close(db), SQLITE_OK);
}
}
#[cfg(not(feature = "sqlite3"))]
mod libsql_ext {
use super::*;
#[test]
fn test_wal_frame_count() {
unsafe {
let mut db = ptr::null_mut();
assert_eq!(
sqlite3_open(b"../testing/testing.db\0".as_ptr() as *const i8, &mut db),
SQLITE_OK
);
// Ensure that WAL is initially empty.
let mut frame_count = 0;
assert_eq!(libsql_wal_frame_count(db, &mut frame_count), SQLITE_OK);
assert_eq!(frame_count, 0);
// Create a table and insert a row.
let mut stmt = ptr::null_mut();
assert_eq!(
sqlite3_prepare_v2(
db,
b"CREATE TABLE test (id INTEGER PRIMARY KEY)\0".as_ptr() as *const i8,
-1,
&mut stmt,
ptr::null_mut()
),
SQLITE_OK
);
assert_eq!(sqlite3_step(stmt), SQLITE_DONE);
assert_eq!(sqlite3_finalize(stmt), SQLITE_OK);
let mut stmt = ptr::null_mut();
assert_eq!(
sqlite3_prepare_v2(
db,
b"INSERT INTO test (id) VALUES (1)\0".as_ptr() as *const i8,
-1,
&mut stmt,
ptr::null_mut()
),
SQLITE_OK
);
assert_eq!(sqlite3_step(stmt), SQLITE_DONE);
assert_eq!(sqlite3_finalize(stmt), SQLITE_OK);
// Check that WAL has three frames.
assert_eq!(libsql_wal_frame_count(db, &mut frame_count), SQLITE_OK);
assert_eq!(frame_count, 3);
assert_eq!(sqlite3_close(db), SQLITE_OK);
}
}
}
}