use core::sync::atomic::{AtomicU32, Ordering};
use drizzle_core::error::Result;
pub fn sync_savepoint<R>(
depth: &AtomicU32,
mut execute_raw: impl FnMut(&str) -> Result<()>,
body: impl FnOnce() -> Result<R>,
) -> Result<R> {
let level = depth.load(Ordering::Relaxed);
let sp = format!("drizzle_sp_{level}");
depth.store(level + 1, Ordering::Relaxed);
execute_raw(&format!("SAVEPOINT {sp}"))?;
let outcome = std::panic::catch_unwind(std::panic::AssertUnwindSafe(body));
depth.store(level, Ordering::Relaxed);
match outcome {
Ok(Ok(value)) => {
execute_raw(&format!("RELEASE SAVEPOINT {sp}"))?;
Ok(value)
}
Ok(Err(e)) => {
let _ = execute_raw(&format!("ROLLBACK TO SAVEPOINT {sp}"));
let _ = execute_raw(&format!("RELEASE SAVEPOINT {sp}"));
Err(e)
}
Err(panic_payload) => {
let _ = execute_raw(&format!("ROLLBACK TO SAVEPOINT {sp}"));
let _ = execute_raw(&format!("RELEASE SAVEPOINT {sp}"));
std::panic::resume_unwind(panic_payload);
}
}
}
pub async fn async_savepoint<R, Exec, ExecFut, BodyFut>(
depth: &AtomicU32,
mut execute_raw: Exec,
body: BodyFut,
) -> Result<R>
where
Exec: FnMut(String) -> ExecFut,
ExecFut: core::future::Future<Output = Result<()>>,
BodyFut: core::future::Future<Output = Result<R>>,
{
let level = depth.load(Ordering::Relaxed);
let sp = format!("drizzle_sp_{level}");
depth.store(level + 1, Ordering::Relaxed);
execute_raw(format!("SAVEPOINT {sp}")).await?;
let outcome = body.await;
depth.store(level, Ordering::Relaxed);
match outcome {
Ok(value) => {
execute_raw(format!("RELEASE SAVEPOINT {sp}")).await?;
Ok(value)
}
Err(e) => {
let _ = execute_raw(format!("ROLLBACK TO SAVEPOINT {sp}")).await;
let _ = execute_raw(format!("RELEASE SAVEPOINT {sp}")).await;
Err(e)
}
}
}