mirror of
https://github.com/launchbadge/sqlx.git
synced 2025-10-03 07:45:30 +00:00
parent
5790ffc8d3
commit
2d65c5de80
@ -3,9 +3,12 @@ use std::ptr;
|
|||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
use crate::error::Error;
|
use crate::error::Error;
|
||||||
use libsqlite3_sys::{sqlite3, sqlite3_close, sqlite3_exec, sqlite3_last_insert_rowid, SQLITE_OK};
|
use libsqlite3_sys::{
|
||||||
|
sqlite3, sqlite3_close, sqlite3_exec, sqlite3_last_insert_rowid, SQLITE_LOCKED_SHAREDCACHE,
|
||||||
|
SQLITE_OK,
|
||||||
|
};
|
||||||
|
|
||||||
use crate::sqlite::SqliteError;
|
use crate::sqlite::{statement::unlock_notify, SqliteError};
|
||||||
|
|
||||||
/// Managed handle to the raw SQLite3 database handle.
|
/// Managed handle to the raw SQLite3 database handle.
|
||||||
/// The database handle will be closed when this is dropped and no `ConnectionHandleRef`s exist.
|
/// The database handle will be closed when this is dropped and no `ConnectionHandleRef`s exist.
|
||||||
@ -61,21 +64,23 @@ impl ConnectionHandle {
|
|||||||
|
|
||||||
// SAFETY: we have exclusive access to the database handle
|
// SAFETY: we have exclusive access to the database handle
|
||||||
unsafe {
|
unsafe {
|
||||||
let status = sqlite3_exec(
|
loop {
|
||||||
self.as_ptr(),
|
let status = sqlite3_exec(
|
||||||
query.as_ptr(),
|
self.as_ptr(),
|
||||||
// callback if we wanted result rows
|
query.as_ptr(),
|
||||||
None,
|
// callback if we wanted result rows
|
||||||
// callback data
|
None,
|
||||||
ptr::null_mut(),
|
// callback data
|
||||||
// out-pointer for the error message, we just use `SqliteError::new()`
|
ptr::null_mut(),
|
||||||
ptr::null_mut(),
|
// out-pointer for the error message, we just use `SqliteError::new()`
|
||||||
);
|
ptr::null_mut(),
|
||||||
|
);
|
||||||
|
|
||||||
if status == SQLITE_OK {
|
match status {
|
||||||
Ok(())
|
SQLITE_OK => return Ok(()),
|
||||||
} else {
|
SQLITE_LOCKED_SHAREDCACHE => unlock_notify::wait(self.as_ptr())?,
|
||||||
Err(SqliteError::new(self.as_ptr()).into())
|
_ => return Err(SqliteError::new(self.as_ptr()).into()),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,6 @@ use std::ptr;
|
|||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
use std::slice::from_raw_parts;
|
use std::slice::from_raw_parts;
|
||||||
use std::str::{from_utf8, from_utf8_unchecked};
|
use std::str::{from_utf8, from_utf8_unchecked};
|
||||||
use std::sync::{Condvar, Mutex};
|
|
||||||
|
|
||||||
use libsqlite3_sys::{
|
use libsqlite3_sys::{
|
||||||
sqlite3, sqlite3_bind_blob64, sqlite3_bind_double, sqlite3_bind_int, sqlite3_bind_int64,
|
sqlite3, sqlite3_bind_blob64, sqlite3_bind_double, sqlite3_bind_int, sqlite3_bind_int64,
|
||||||
@ -17,14 +16,16 @@ use libsqlite3_sys::{
|
|||||||
sqlite3_column_name, sqlite3_column_origin_name, sqlite3_column_table_name,
|
sqlite3_column_name, sqlite3_column_origin_name, sqlite3_column_table_name,
|
||||||
sqlite3_column_type, sqlite3_column_value, sqlite3_db_handle, sqlite3_finalize, sqlite3_reset,
|
sqlite3_column_type, sqlite3_column_value, sqlite3_db_handle, sqlite3_finalize, sqlite3_reset,
|
||||||
sqlite3_sql, sqlite3_step, sqlite3_stmt, sqlite3_stmt_readonly, sqlite3_table_column_metadata,
|
sqlite3_sql, sqlite3_step, sqlite3_stmt, sqlite3_stmt_readonly, sqlite3_table_column_metadata,
|
||||||
sqlite3_unlock_notify, sqlite3_value, SQLITE_DONE, SQLITE_LOCKED_SHAREDCACHE, SQLITE_MISUSE,
|
sqlite3_value, SQLITE_DONE, SQLITE_LOCKED_SHAREDCACHE, SQLITE_MISUSE, SQLITE_OK, SQLITE_ROW,
|
||||||
SQLITE_OK, SQLITE_ROW, SQLITE_TRANSIENT, SQLITE_UTF8,
|
SQLITE_TRANSIENT, SQLITE_UTF8,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::error::{BoxDynError, Error};
|
use crate::error::{BoxDynError, Error};
|
||||||
use crate::sqlite::type_info::DataType;
|
use crate::sqlite::type_info::DataType;
|
||||||
use crate::sqlite::{SqliteError, SqliteTypeInfo};
|
use crate::sqlite::{SqliteError, SqliteTypeInfo};
|
||||||
|
|
||||||
|
use super::unlock_notify;
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub(crate) struct StatementHandle(NonNull<sqlite3_stmt>);
|
pub(crate) struct StatementHandle(NonNull<sqlite3_stmt>);
|
||||||
|
|
||||||
@ -314,7 +315,7 @@ impl StatementHandle {
|
|||||||
SQLITE_LOCKED_SHAREDCACHE => {
|
SQLITE_LOCKED_SHAREDCACHE => {
|
||||||
// The shared cache is locked by another connection. Wait for unlock
|
// The shared cache is locked by another connection. Wait for unlock
|
||||||
// notification and try again.
|
// notification and try again.
|
||||||
wait_for_unlock_notify(self.db_handle())?;
|
unlock_notify::wait(self.db_handle())?;
|
||||||
// Need to reset the handle after the unlock
|
// Need to reset the handle after the unlock
|
||||||
// (https://www.sqlite.org/unlock_notify.html)
|
// (https://www.sqlite.org/unlock_notify.html)
|
||||||
sqlite3_reset(self.0.as_ptr());
|
sqlite3_reset(self.0.as_ptr());
|
||||||
@ -344,55 +345,3 @@ impl Drop for StatementHandle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn wait_for_unlock_notify(conn: *mut sqlite3) -> Result<(), SqliteError> {
|
|
||||||
let notify = Notify::new();
|
|
||||||
|
|
||||||
if sqlite3_unlock_notify(
|
|
||||||
conn,
|
|
||||||
Some(unlock_notify_cb),
|
|
||||||
¬ify as *const Notify as *mut Notify as *mut _,
|
|
||||||
) != SQLITE_OK
|
|
||||||
{
|
|
||||||
return Err(SqliteError::new(conn));
|
|
||||||
}
|
|
||||||
|
|
||||||
notify.wait();
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
unsafe extern "C" fn unlock_notify_cb(ptr: *mut *mut c_void, len: c_int) {
|
|
||||||
let ptr = ptr as *mut &Notify;
|
|
||||||
let slice = from_raw_parts(ptr, len as usize);
|
|
||||||
|
|
||||||
for notify in slice {
|
|
||||||
notify.fire();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Notify {
|
|
||||||
mutex: Mutex<bool>,
|
|
||||||
condvar: Condvar,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Notify {
|
|
||||||
fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
mutex: Mutex::new(false),
|
|
||||||
condvar: Condvar::new(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn wait(&self) {
|
|
||||||
let _ = self
|
|
||||||
.condvar
|
|
||||||
.wait_while(self.mutex.lock().unwrap(), |fired| !*fired)
|
|
||||||
.unwrap();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fire(&self) {
|
|
||||||
*self.mutex.lock().unwrap() = true;
|
|
||||||
self.condvar.notify_one();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -9,6 +9,7 @@ use std::borrow::Cow;
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
mod handle;
|
mod handle;
|
||||||
|
pub(super) mod unlock_notify;
|
||||||
mod r#virtual;
|
mod r#virtual;
|
||||||
|
|
||||||
pub(crate) use handle::StatementHandle;
|
pub(crate) use handle::StatementHandle;
|
||||||
|
61
sqlx-core/src/sqlite/statement/unlock_notify.rs
Normal file
61
sqlx-core/src/sqlite/statement/unlock_notify.rs
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
use std::ffi::c_void;
|
||||||
|
use std::os::raw::c_int;
|
||||||
|
use std::slice;
|
||||||
|
use std::sync::{Condvar, Mutex};
|
||||||
|
|
||||||
|
use libsqlite3_sys::{sqlite3, sqlite3_unlock_notify, SQLITE_OK};
|
||||||
|
|
||||||
|
use crate::sqlite::SqliteError;
|
||||||
|
|
||||||
|
// Wait for unlock notification (https://www.sqlite.org/unlock_notify.html)
|
||||||
|
pub unsafe fn wait(conn: *mut sqlite3) -> Result<(), SqliteError> {
|
||||||
|
let notify = Notify::new();
|
||||||
|
|
||||||
|
if sqlite3_unlock_notify(
|
||||||
|
conn,
|
||||||
|
Some(unlock_notify_cb),
|
||||||
|
¬ify as *const Notify as *mut Notify as *mut _,
|
||||||
|
) != SQLITE_OK
|
||||||
|
{
|
||||||
|
return Err(SqliteError::new(conn));
|
||||||
|
}
|
||||||
|
|
||||||
|
notify.wait();
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
unsafe extern "C" fn unlock_notify_cb(ptr: *mut *mut c_void, len: c_int) {
|
||||||
|
let ptr = ptr as *mut &Notify;
|
||||||
|
let slice = slice::from_raw_parts(ptr, len as usize);
|
||||||
|
|
||||||
|
for notify in slice {
|
||||||
|
notify.fire();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Notify {
|
||||||
|
mutex: Mutex<bool>,
|
||||||
|
condvar: Condvar,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Notify {
|
||||||
|
fn new() -> Self {
|
||||||
|
Self {
|
||||||
|
mutex: Mutex::new(false),
|
||||||
|
condvar: Condvar::new(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn wait(&self) {
|
||||||
|
let _ = self
|
||||||
|
.condvar
|
||||||
|
.wait_while(self.mutex.lock().unwrap(), |fired| !*fired)
|
||||||
|
.unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fire(&self) {
|
||||||
|
*self.mutex.lock().unwrap() = true;
|
||||||
|
self.condvar.notify_one();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user