mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-01 23:44:19 +01:00
Merge 'sqlite3: Implement sqlite3_db_filename()' from Pekka Enberg
Closes #2771
This commit is contained in:
@@ -76,6 +76,8 @@ int sqlite3_close(sqlite3 *db);
|
||||
|
||||
int sqlite3_close_v2(sqlite3 *db);
|
||||
|
||||
const char *sqlite3_db_filename(sqlite3 *db, const char *db_name);
|
||||
|
||||
int sqlite3_trace_v2(sqlite3 *_db,
|
||||
unsigned int _mask,
|
||||
void (*_callback)(unsigned int, void*, void*, void*),
|
||||
|
||||
@@ -56,6 +56,7 @@ struct sqlite3Inner {
|
||||
pub(crate) malloc_failed: bool,
|
||||
pub(crate) e_open_state: u8,
|
||||
pub(crate) p_err: *mut ffi::c_void,
|
||||
pub(crate) filename: CString,
|
||||
}
|
||||
|
||||
impl sqlite3 {
|
||||
@@ -63,6 +64,7 @@ impl sqlite3 {
|
||||
io: Arc<dyn turso_core::IO>,
|
||||
db: Arc<turso_core::Database>,
|
||||
conn: Arc<turso_core::Connection>,
|
||||
filename: CString,
|
||||
) -> Self {
|
||||
let inner = sqlite3Inner {
|
||||
_io: io,
|
||||
@@ -73,6 +75,7 @@ impl sqlite3 {
|
||||
malloc_failed: false,
|
||||
e_open_state: SQLITE_STATE_OPEN,
|
||||
p_err: std::ptr::null_mut(),
|
||||
filename,
|
||||
};
|
||||
#[allow(clippy::arc_with_non_send_sync)]
|
||||
let inner = Arc::new(Mutex::new(inner));
|
||||
@@ -132,26 +135,30 @@ pub unsafe extern "C" fn sqlite3_open(
|
||||
if db_out.is_null() {
|
||||
return SQLITE_MISUSE;
|
||||
}
|
||||
let filename = CStr::from_ptr(filename);
|
||||
let filename = match filename.to_str() {
|
||||
let filename_cstr = CStr::from_ptr(filename);
|
||||
let filename_str = match filename_cstr.to_str() {
|
||||
Ok(s) => s,
|
||||
Err(_) => return SQLITE_MISUSE,
|
||||
};
|
||||
let io: Arc<dyn turso_core::IO> = match filename {
|
||||
let io: Arc<dyn turso_core::IO> = match filename_str {
|
||||
":memory:" => Arc::new(turso_core::MemoryIO::new()),
|
||||
_ => match turso_core::PlatformIO::new() {
|
||||
Ok(io) => Arc::new(io),
|
||||
Err(_) => return SQLITE_CANTOPEN,
|
||||
},
|
||||
};
|
||||
match turso_core::Database::open_file(io.clone(), filename, false, false) {
|
||||
match turso_core::Database::open_file(io.clone(), filename_str, false, false) {
|
||||
Ok(db) => {
|
||||
let conn = db.connect().unwrap();
|
||||
*db_out = Box::leak(Box::new(sqlite3::new(io, db, conn)));
|
||||
let filename = match filename_str {
|
||||
":memory:" => CString::new("".to_string()).unwrap(),
|
||||
_ => CString::from(filename_cstr),
|
||||
};
|
||||
*db_out = Box::leak(Box::new(sqlite3::new(io, db, conn, filename)));
|
||||
SQLITE_OK
|
||||
}
|
||||
Err(e) => {
|
||||
trace!("error opening database {}: {:?}", filename, e);
|
||||
trace!("error opening database {}: {:?}", filename_str, e);
|
||||
SQLITE_CANTOPEN
|
||||
}
|
||||
}
|
||||
@@ -184,6 +191,25 @@ pub unsafe extern "C" fn sqlite3_close_v2(db: *mut sqlite3) -> ffi::c_int {
|
||||
sqlite3_close(db)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sqlite3_db_filename(
|
||||
db: *mut sqlite3,
|
||||
db_name: *const ffi::c_char,
|
||||
) -> *const ffi::c_char {
|
||||
if db.is_null() {
|
||||
return std::ptr::null();
|
||||
}
|
||||
if !db_name.is_null() {
|
||||
let name = CStr::from_ptr(db_name);
|
||||
if name.to_bytes() != b"main" {
|
||||
return std::ptr::null();
|
||||
}
|
||||
}
|
||||
let db = &*db;
|
||||
let inner = db.inner.lock().unwrap();
|
||||
inner.filename.as_ptr()
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub unsafe extern "C" fn sqlite3_trace_v2(
|
||||
_db: *mut sqlite3,
|
||||
|
||||
@@ -19,6 +19,7 @@ extern "C" {
|
||||
fn sqlite3_libversion_number() -> i32;
|
||||
fn sqlite3_close(db: *mut sqlite3) -> i32;
|
||||
fn sqlite3_open(filename: *const libc::c_char, db: *mut *mut sqlite3) -> i32;
|
||||
fn sqlite3_db_filename(db: *mut sqlite3, db_name: *const libc::c_char) -> *const libc::c_char;
|
||||
fn sqlite3_prepare_v2(
|
||||
db: *mut sqlite3,
|
||||
sql: *const libc::c_char,
|
||||
@@ -1279,4 +1280,43 @@ mod tests {
|
||||
assert_eq!(sqlite3_finalize(stmt), SQLITE_OK);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_sqlite3_db_filename() {
|
||||
const SQLITE_OK: i32 = 0;
|
||||
|
||||
unsafe {
|
||||
// Test with in-memory database
|
||||
let mut db: *mut sqlite3 = ptr::null_mut();
|
||||
assert_eq!(sqlite3_open(c":memory:".as_ptr(), &mut db), SQLITE_OK);
|
||||
let filename = sqlite3_db_filename(db, c"main".as_ptr());
|
||||
assert!(!filename.is_null());
|
||||
let filename_str = std::ffi::CStr::from_ptr(filename).to_str().unwrap();
|
||||
assert_eq!(filename_str, "");
|
||||
assert_eq!(sqlite3_close(db), SQLITE_OK);
|
||||
|
||||
// Open a file-backed database
|
||||
let temp_file = tempfile::NamedTempFile::with_suffix(".db").unwrap();
|
||||
let path = std::ffi::CString::new(temp_file.path().to_str().unwrap()).unwrap();
|
||||
let mut db = ptr::null_mut();
|
||||
assert_eq!(sqlite3_open(path.as_ptr(), &mut db), SQLITE_OK);
|
||||
|
||||
// Test with "main" database name
|
||||
let filename = sqlite3_db_filename(db, c"main".as_ptr());
|
||||
assert!(!filename.is_null());
|
||||
let filename_str = std::ffi::CStr::from_ptr(filename).to_str().unwrap();
|
||||
assert_eq!(filename_str, temp_file.path().to_str().unwrap());
|
||||
|
||||
// Test with NULL database name (defaults to main)
|
||||
let filename_default = sqlite3_db_filename(db, ptr::null());
|
||||
assert!(!filename_default.is_null());
|
||||
assert_eq!(filename, filename_default);
|
||||
|
||||
// Test with non-existent database name
|
||||
let filename = sqlite3_db_filename(db, c"temp".as_ptr());
|
||||
assert!(filename.is_null());
|
||||
|
||||
assert_eq!(sqlite3_close(db), SQLITE_OK);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user