From abe95cf179b6d9a2c1cd1a3fc84ab4ecc94d3e2d Mon Sep 17 00:00:00 2001 From: "Levy A." Date: Wed, 4 Dec 2024 10:25:38 -0300 Subject: [PATCH] feat: WAL mode by dafault on local databases --- .gitignore | 2 +- flake.lock | 29 ++----------- flake.nix | 17 +++++--- src/lib.rs | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 135 insertions(+), 35 deletions(-) diff --git a/.gitignore b/.gitignore index 6eeeb59..539c22c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,6 @@ /target .DS_Store -test*.db +test*.db* *.o local.db example diff --git a/flake.lock b/flake.lock index 8134dc3..ccc9bf2 100644 --- a/flake.lock +++ b/flake.lock @@ -20,11 +20,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1729413321, - "narHash": "sha256-I4tuhRpZFa6Fu6dcH9Dlo5LlH17peT79vx1y1SpeKt0=", + "lastModified": 1730785428, + "narHash": "sha256-Zwl8YgTVJTEum+L+0zVAWvXAGbWAuXHax3KzuejaDyo=", "owner": "nixos", "repo": "nixpkgs", - "rev": "1997e4aa514312c1af7e2bda7fad1644e778ff26", + "rev": "4aa36568d413aca0ea84a1684d2d46f55dbabad7", "type": "github" }, "original": { @@ -37,28 +37,7 @@ "root": { "inputs": { "flake-utils": "flake-utils", - "nixpkgs": "nixpkgs", - "rust-overlay": "rust-overlay" - } - }, - "rust-overlay": { - "inputs": { - "nixpkgs": [ - "nixpkgs" - ] - }, - "locked": { - "lastModified": 1730687492, - "narHash": "sha256-xQVadjquBA/tFxDt5A55LJ1D1AvkVWsnrKC2o+pr8F4=", - "owner": "oxalica", - "repo": "rust-overlay", - "rev": "41814763a2c597755b0755dbe3e721367a5e420f", - "type": "github" - }, - "original": { - "owner": "oxalica", - "repo": "rust-overlay", - "type": "github" + "nixpkgs": "nixpkgs" } }, "systems": { diff --git a/flake.nix b/flake.nix index 9e9a8fc..3a17bea 100644 --- a/flake.nix +++ b/flake.nix @@ -3,15 +3,11 @@ inputs = { nixpkgs.url = "github:nixos/nixpkgs?ref=nixos-unstable"; - rust-overlay = { - url = "github:oxalica/rust-overlay"; - inputs.nixpkgs.follows = "nixpkgs"; - }; flake-utils = { url = "github:numtide/flake-utils"; }; }; - outputs = { self, nixpkgs, flake-utils, rust-overlay }: + outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system: let @@ -26,7 +22,6 @@ with pkgs; mkShell { nativeBuildInputs = [ - zig pkg-config rust-bindgen cmake @@ -41,6 +36,16 @@ darwin.apple_sdk.frameworks.CoreServices ]; + CARGO_TARGET_X86_64_APPLE_DARWIN_RUSTFLAGS= lib.lists.fold (a: b: "${a} ${b}") "" [ + "-Ctarget-feature=-crt-static" + "-Clink-arg=-target" + "-Clink-arg=x86_64-apple-darwin" + ]; + CC_x86_64_apple_darwin = + "${pkgs.pkgsCross.x86_64-darwin.stdenv.cc}/bin/x86_64-apple-darwin-clang"; + CARGO_TARGET_X86_64_APPLE_DARWIN_LINKER = + "${pkgs.pkgsCross.x86_64-darwin.stdenv.cc}/bin/x86_64-apple-darwin-clang"; + CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_RUSTFLAGS="-Ctarget-feature=-crt-static"; CC_x86_64_unknown_linux_gnu = "${pkgs.pkgsCross.gnu64.stdenv.cc}/bin/x86_64-unknown-linux-gnu-gcc"; diff --git a/src/lib.rs b/src/lib.rs index a5a0c6c..8034084 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -283,7 +283,12 @@ pub extern "C" fn libsql_database_init(desc: c::libsql_database_desc_t) -> c::li _ => db, }; - RT.block_on(db.build()) + RT.block_on(async { + let db = db.build().await?; + let conn = db.connect()?; + conn.query("PRAGMA journal_mode=WAL", ()).await?; + Ok(db) + }) } (None, Some(url), Some(auth_token)) => { let db = libsql::Builder::new_remote( @@ -998,7 +1003,10 @@ const _: () = { let _: [unsafe extern "C" fn(_, _) -> _; 2] = [c::libsql_transaction_prepare, libsql_transaction_prepare]; - let _: [unsafe extern "C" fn(_) -> _; 2] = [c::libsql_statement_column_count, libsql_statement_column_count]; + let _: [unsafe extern "C" fn(_) -> _; 2] = [ + c::libsql_statement_column_count, + libsql_statement_column_count, + ]; let _: [unsafe extern "C" fn(_) -> _; 2] = [c::libsql_statement_query, libsql_statement_query]; let _: [unsafe extern "C" fn(_) -> _; 2] = [c::libsql_statement_execute, libsql_statement_execute]; @@ -1041,7 +1049,7 @@ const _: () = { #[cfg(test)] mod tests { - use crate::{libsql_database_deinit, libsql_setup}; + use crate::{libsql_database_deinit, libsql_row_empty, libsql_setup}; use super::c::*; use anyhow::Result; @@ -1181,4 +1189,112 @@ mod tests { Ok(()) } } + + #[test] + fn test_multiconnection() -> Result<()> { + unsafe { + let path = CString::new("./test2.db")?; + let key = CString::new("super_secret")?; + + let desc = libsql_database_desc_t { + path: path.as_ptr(), + encryption_key: key.as_ptr(), + ..Default::default() + }; + + let db = libsql_database_init(desc); + assert!( + db.err.is_null(), + "{:?}", + CStr::from_ptr(libsql_error_message(db.err)) + ); + + { + let conn = libsql_database_connect(db); + assert!(conn.err.is_null()); + + let sql = CString::new("create table if not exists test (i integer);")?; + let batch = libsql_connection_batch(conn, sql.as_ptr()); + assert!( + batch.err.is_null(), + "{:?}", + CStr::from_ptr(libsql_error_message(batch.err)) + ); + + // leak connection + } + + { + let conn = libsql_database_connect(db); + assert!( + conn.err.is_null(), + "{:?}", + CStr::from_ptr(libsql_error_message(conn.err)) + ); + + let sql = CString::new("insert into test values (1)")?; + let stmt = libsql_connection_prepare(conn, sql.as_ptr()); + assert!( + stmt.err.is_null(), + "{:?}", + CStr::from_ptr(libsql_error_message(stmt.err)), + ); + + let exec = libsql_statement_execute(stmt); + assert!( + exec.err.is_null(), + "{:?}", + CStr::from_ptr(libsql_error_message(stmt.err)), + ); + assert_eq!(exec.rows_changed, 1); + + libsql_connection_deinit(conn); + libsql_statement_deinit(stmt); + + // leak connection + } + + { + let conn = libsql_database_connect(db); + assert!( + conn.err.is_null(), + "{:?}", + CStr::from_ptr(libsql_error_message(conn.err)) + ); + + let sql = CString::new("select i from test")?; + let stmt = libsql_connection_prepare(conn, sql.as_ptr()); + assert!( + stmt.err.is_null(), + "{:?}", + CStr::from_ptr(libsql_error_message(stmt.err)), + ); + + let rows = libsql_statement_query(stmt); + assert!( + rows.err.is_null(), + "{:?}", + CStr::from_ptr(libsql_error_message(rows.err)), + ); + + loop { + let row = libsql_rows_next(rows); + if libsql_row_empty(row) { + break; + } + + dbg!(libsql_row_value(row, 0).ok.value.integer); + } + + libsql_connection_deinit(conn); + libsql_statement_deinit(stmt); + + // leak connection + } + + libsql_database_deinit(db); + + Ok(()) + } + } }