Skip to content

[pull] main from tursodatabase:main #104

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 6 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,18 @@ exclude = [
]

[workspace.package]
version = "0.9.6"
version = "0.9.7"
authors = ["the libSQL authors"]
edition = "2021"
license = "MIT"
repository = "https://github.com/tursodatabase/libsql"

[workspace.dependencies]
libsql-ffi = { path = "libsql-ffi", version = "0.9.6" }
libsql-sys = { path = "libsql-sys", version = "0.9.6", default-features = false }
libsql-hrana = { path = "libsql-hrana", version = "0.9.6" }
libsql_replication = { path = "libsql-replication", version = "0.9.6" }
rusqlite = { package = "libsql-rusqlite", path = "vendored/rusqlite", version = "0.9.6", default-features = false, features = [
libsql-ffi = { path = "libsql-ffi", version = "0.9.7" }
libsql-sys = { path = "libsql-sys", version = "0.9.7", default-features = false }
libsql-hrana = { path = "libsql-hrana", version = "0.9.7" }
libsql_replication = { path = "libsql-replication", version = "0.9.7" }
rusqlite = { package = "libsql-rusqlite", path = "vendored/rusqlite", version = "0.9.7", default-features = false, features = [
"libsql-experimental",
"column_decltype",
"load_extension",
Expand Down
2 changes: 1 addition & 1 deletion libsql-ffi/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,4 +48,4 @@ sqlean-extensions = [
"sqlean-extension-text",
]
libsql-disable-checkpoint-downgrade = []
libsql-checkpoint-callback-on-any-frame-written = []
libsql-checkpoint-only-full= []
4 changes: 2 additions & 2 deletions libsql-ffi/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,8 +276,8 @@ pub fn build_bundled(out_dir: &str, out_path: &Path) {
if cfg!(feature = "libsql-disable-checkpoint-downgrade") {
cfg.flag("-DLIBSQL_DISABLE_CHECKPOINT_DOWNGRADE=1");
}
if cfg!(feature = "libsql-checkpoint-callback-on-any-frame-written") {
cfg.flag("-DLIBSQL_CHECKPOINT_CALLBACK_ON_ANY_FRAME_WRITTEN=1");
if cfg!(feature = "libsql-checkpoint-only-full") {
cfg.flag("-DLIBSQL_CHECKPOINT_ONLY_FULL=1");
}

if cfg!(feature = "bundled-sqlcipher") {
Expand Down
19 changes: 14 additions & 5 deletions libsql-ffi/bundled/bindings/bindgen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ extern "C" {
) -> ::std::os::raw::c_int;
}

pub const __GNUC_VA_LIST: i32 = 1;
pub const SQLITE_VERSION: &[u8; 7] = b"3.45.1\0";
pub const SQLITE_VERSION_NUMBER: i32 = 3045001;
pub const SQLITE_SOURCE_ID: &[u8; 85] =
Expand Down Expand Up @@ -501,8 +502,8 @@ pub const FTS5_TOKENIZE_DOCUMENT: i32 = 4;
pub const FTS5_TOKENIZE_AUX: i32 = 8;
pub const FTS5_TOKEN_COLOCATED: i32 = 1;
pub const WAL_SAVEPOINT_NDATA: i32 = 4;
pub type __gnuc_va_list = __builtin_va_list;
pub type va_list = __builtin_va_list;
pub type __gnuc_va_list = __builtin_va_list;
extern "C" {
pub static sqlite3_version: [::std::os::raw::c_char; 0usize];
}
Expand Down Expand Up @@ -939,7 +940,7 @@ extern "C" {
extern "C" {
pub fn sqlite3_vmprintf(
arg1: *const ::std::os::raw::c_char,
arg2: va_list,
arg2: *mut __va_list_tag,
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
Expand All @@ -955,7 +956,7 @@ extern "C" {
arg1: ::std::os::raw::c_int,
arg2: *mut ::std::os::raw::c_char,
arg3: *const ::std::os::raw::c_char,
arg4: va_list,
arg4: *mut __va_list_tag,
) -> *mut ::std::os::raw::c_char;
}
extern "C" {
Expand Down Expand Up @@ -2505,7 +2506,7 @@ extern "C" {
pub fn sqlite3_str_vappendf(
arg1: *mut sqlite3_str,
zFormat: *const ::std::os::raw::c_char,
arg2: va_list,
arg2: *mut __va_list_tag,
);
}
extern "C" {
Expand Down Expand Up @@ -3573,4 +3574,12 @@ extern "C" {
extern "C" {
pub static sqlite3_wal_manager: libsql_wal_manager;
}
pub type __builtin_va_list = *mut ::std::os::raw::c_char;
pub type __builtin_va_list = [__va_list_tag; 1usize];
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct __va_list_tag {
pub gp_offset: ::std::os::raw::c_uint,
pub fp_offset: ::std::os::raw::c_uint,
pub overflow_arg_area: *mut ::std::os::raw::c_void,
pub reg_save_area: *mut ::std::os::raw::c_void,
}
17 changes: 9 additions & 8 deletions libsql-ffi/bundled/src/sqlite3.c
Original file line number Diff line number Diff line change
Expand Up @@ -67613,6 +67613,15 @@ static int walCheckpoint(
}
}


#ifdef LIBSQL_CHECKPOINT_ONLY_FULL
// in case of LIBSQL_CHECKPOINT_ONLY_FULL option we want to either checkpoint whole WAL or quickly abort the checkpoint
if( mxSafeFrame!=walIndexHdr(pWal)->mxFrame ){
rc = SQLITE_BUSY;
goto walcheckpoint_out;
}
#endif

/* Allocate the iterator */
if( pInfo->nBackfill<mxSafeFrame ){
rc = walIteratorRevInit(pWal, pInfo->nBackfill, &pIter, mxSafeFrame, xCb == NULL);
Expand Down Expand Up @@ -67677,18 +67686,10 @@ static int walCheckpoint(

/* If work was actually accomplished... */
if( rc==SQLITE_OK ){
#ifdef LIBSQL_CHECKPOINT_CALLBACK_ON_ANY_FRAME_WRITTEN
if (xCb) {
rc = (xCb)(pCbData, mxSafeFrame, NULL, 0, 0, 0);
}
#endif

if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
#ifndef LIBSQL_CHECKPOINT_CALLBACK_ON_ANY_FRAME_WRITTEN
if (xCb) {
rc = (xCb)(pCbData, mxSafeFrame, NULL, 0, 0, 0);
}
#endif
if( rc==SQLITE_OK ){
i64 szDb = pWal->hdr.nPage*(i64)szPage;
testcase( IS_BIG_INT(szDb) );
Expand Down
4 changes: 2 additions & 2 deletions libsql-server/tests/standalone/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,15 +99,15 @@ fn basic_metrics() {

let snapshot = snapshot_metrics();
snapshot.assert_counter("libsql_server_libsql_execute_program", 3);
snapshot.assert_counter("libsql_server_user_http_response", 3);
snapshot.assert_counter("libsql_server_user_http_response", 4);

for (key, (_, _, val)) in snapshot.snapshot() {
if key.kind() == metrics_util::MetricKind::Counter
&& key.key().name() == "libsql_client_version"
{
let label = key.key().labels().next().unwrap();
assert!(label.value().starts_with("libsql-remote-"));
assert_eq!(val, &metrics_util::debugging::DebugValue::Counter(3));
assert_eq!(val, &metrics_util::debugging::DebugValue::Counter(4));
}
}

Expand Down
17 changes: 9 additions & 8 deletions libsql-sqlite3/src/wal.c
Original file line number Diff line number Diff line change
Expand Up @@ -2066,6 +2066,15 @@ static int walCheckpoint(
}
}


#ifdef LIBSQL_CHECKPOINT_ONLY_FULL
// in case of LIBSQL_CHECKPOINT_ONLY_FULL option we want to either checkpoint whole WAL or quickly abort the checkpoint
if( mxSafeFrame!=walIndexHdr(pWal)->mxFrame ){
rc = SQLITE_BUSY;
goto walcheckpoint_out;
}
#endif

/* Allocate the iterator */
if( pInfo->nBackfill<mxSafeFrame ){
rc = walIteratorRevInit(pWal, pInfo->nBackfill, &pIter, mxSafeFrame, xCb == NULL);
Expand Down Expand Up @@ -2130,18 +2139,10 @@ static int walCheckpoint(

/* If work was actually accomplished... */
if( rc==SQLITE_OK ){
#ifdef LIBSQL_CHECKPOINT_CALLBACK_ON_ANY_FRAME_WRITTEN
if (xCb) {
rc = (xCb)(pCbData, mxSafeFrame, NULL, 0, 0, 0);
}
#endif

if( mxSafeFrame==walIndexHdr(pWal)->mxFrame ){
#ifndef LIBSQL_CHECKPOINT_CALLBACK_ON_ANY_FRAME_WRITTEN
if (xCb) {
rc = (xCb)(pCbData, mxSafeFrame, NULL, 0, 0, 0);
}
#endif
if( rc==SQLITE_OK ){
i64 szDb = pWal->hdr.nPage*(i64)szPage;
testcase( IS_BIG_INT(szDb) );
Expand Down
4 changes: 2 additions & 2 deletions libsql/src/hrana/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ where
)
}

pub fn prepare(&self, sql: &str) -> crate::Result<Statement<T>> {
pub async fn prepare(&self, sql: &str) -> crate::Result<Statement<T>> {
let stream = self.current_stream().clone();
Statement::new(stream, sql.to_string(), true)
Statement::new(stream, sql.to_string(), true).await
}
}

Expand Down
15 changes: 12 additions & 3 deletions libsql/src/hrana/hyper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ impl Conn for HttpConnection<HttpSender> {

async fn prepare(&self, sql: &str) -> crate::Result<Statement> {
let stream = self.current_stream().clone();
let stmt = crate::hrana::Statement::new(stream, sql.to_string(), true)?;
let stmt = crate::hrana::Statement::new(stream, sql.to_string(), true).await?;
Ok(Statement {
inner: Box::new(stmt),
})
Expand Down Expand Up @@ -241,7 +241,16 @@ impl crate::statement::Stmt for crate::hrana::Statement<HttpSender> {
// 2. Even if we do execute query, Hrana doesn't return all info that Column exposes.
// 3. Even if we would like to return some of the column info ie. column [ValueType], this information is not
// present in Hrana [Col] but rather inferred from the row cell type.
vec![]
self.cols
.iter()
.map(|name| crate::Column {
name,
origin_name: None,
table_name: None,
database_name: None,
decl_type: None,
})
.collect()
}
}

Expand Down Expand Up @@ -350,7 +359,7 @@ impl Conn for HranaStream<HttpSender> {
}

async fn prepare(&self, sql: &str) -> crate::Result<Statement> {
let stmt = crate::hrana::Statement::new(self.clone(), sql.to_string(), true)?;
let stmt = crate::hrana::Statement::new(self.clone(), sql.to_string(), true).await?;
Ok(Statement {
inner: Box::new(stmt),
})
Expand Down
12 changes: 11 additions & 1 deletion libsql/src/hrana/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -119,13 +119,22 @@ where
stream: HranaStream<T>,
close_stream: bool,
inner: Stmt,
cols: Vec<String>,
}

impl<T> Statement<T>
where
T: HttpSend + Send + Sync + 'static,
{
pub(crate) fn new(stream: HranaStream<T>, sql: String, want_rows: bool) -> crate::Result<Self> {
pub(crate) async fn new(
stream: HranaStream<T>,
sql: String,
want_rows: bool,
) -> crate::Result<Self> {
let desc = stream.describe(&sql).await?;

let cols: Vec<_> = desc.cols.into_iter().map(|col| col.name).collect();

// in SQLite when a multiple statements are glued together into one string, only the first one is
// executed and then a handle to continue execution is returned. However Hrana API doesn't allow
// passing multi-statement strings, so we just pick first one.
Expand All @@ -147,6 +156,7 @@ where
stream,
close_stream,
inner,
cols,
})
}
}
Expand Down
25 changes: 18 additions & 7 deletions libsql/src/replication/connection.rs
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
// TODO(lucio): Move this to `remote/mod.rs`

use std::time::Duration;
use std::str::FromStr;
use std::sync::Arc;
use std::sync::atomic::AtomicU64;
use libsql_replication::rpc::proxy::{
describe_result, query_result::RowResult, Cond, DescribeResult, ExecuteResults, NotCond,
OkCond, Positional, Query, ResultRows, State as RemoteState, Step,
};
use parking_lot::Mutex;
use std::str::FromStr;
use std::sync::atomic::AtomicU64;
use std::sync::Arc;
use std::time::Duration;

use crate::parser;
use crate::parser::StmtKind;
Expand Down Expand Up @@ -168,7 +168,11 @@ impl From<RemoteState> for State {
}

impl RemoteConnection {
pub(crate) fn new(local: LibsqlConnection, writer: Option<Writer>, max_write_replication_index: Arc<AtomicU64>) -> Self {
pub(crate) fn new(
local: LibsqlConnection,
writer: Option<Writer>,
max_write_replication_index: Arc<AtomicU64>,
) -> Self {
let state = Arc::new(Mutex::new(Inner::default()));
Self {
local,
Expand All @@ -180,9 +184,16 @@ impl RemoteConnection {

fn update_max_write_replication_index(&self, index: Option<u64>) {
if let Some(index) = index {
let mut current = self.max_write_replication_index.load(std::sync::atomic::Ordering::SeqCst);
let mut current = self
.max_write_replication_index
.load(std::sync::atomic::Ordering::SeqCst);
while index > current {
match self.max_write_replication_index.compare_exchange(current, index, std::sync::atomic::Ordering::SeqCst, std::sync::atomic::Ordering::SeqCst) {
match self.max_write_replication_index.compare_exchange(
current,
index,
std::sync::atomic::Ordering::SeqCst,
std::sync::atomic::Ordering::SeqCst,
) {
Ok(_) => break,
Err(new_current) => current = new_current,
}
Expand Down
2 changes: 1 addition & 1 deletion libsql/src/sync/connection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ impl Conn for SyncedConnection {
})
} else {
let stmt = Statement {
inner: Box::new(self.remote.prepare(sql)?),
inner: Box::new(self.remote.prepare(sql).await?),
};

if self.read_your_writes {
Expand Down
Loading