use rupg_common::{Error, Result, SqlState};
use rupg_types::Value;
use crate::{AdvisoryKey, AdvisoryLock, Call, Kernel, bad_value};
#[allow(clippy::cast_possible_truncation)]
fn key(args: &[Value]) -> Result<AdvisoryKey> {
match args {
[Value::Int8(key)] => {
Ok(AdvisoryKey { high: (*key >> 32) as u32, low: *key as u32, kind: 1 })
}
[Value::Int4(key1), Value::Int4(key2)] => {
Ok(AdvisoryKey { high: key1.cast_unsigned(), low: key2.cast_unsigned(), kind: 2 })
}
_ => Err(bad_value()),
}
}
fn lock(call: &Call<'_>, args: &[Value], share: bool, session: bool) -> Result<Value> {
call.session.advisory_lock(AdvisoryLock { key: key(args)?, share, session }, true)?;
Ok(Value::Text(String::new()))
}
fn try_lock(call: &Call<'_>, args: &[Value], share: bool, session: bool) -> Result<Value> {
let lock = AdvisoryLock { key: key(args)?, share, session };
Ok(Value::Bool(call.session.advisory_lock(lock, false)?))
}
fn unlock(call: &Call<'_>, args: &[Value], share: bool) -> Result<Value> {
let lock = AdvisoryLock { key: key(args)?, share, session: true };
let released = call.session.advisory_unlock(lock)?;
if !released {
let mode = if share { "ShareLock" } else { "ExclusiveLock" };
call.session
.warn(Error::new(SqlState::WARNING, format!("you don't own a lock of type {mode}")));
}
Ok(Value::Bool(released))
}
fn unlock_all(call: &Call<'_>, _: &[Value]) -> Result<Value> {
call.session.advisory_unlock_all()?;
Ok(Value::Text(String::new()))
}
pub(crate) fn by_src(src: &str) -> Option<Kernel> {
let kernel: Kernel = match src {
"pg_advisory_lock_int8" | "pg_advisory_lock_int4" => |c, a| lock(c, a, false, true),
"pg_advisory_xact_lock_int8" | "pg_advisory_xact_lock_int4" => {
|c, a| lock(c, a, false, false)
}
"pg_advisory_lock_shared_int8" | "pg_advisory_lock_shared_int4" => {
|c, a| lock(c, a, true, true)
}
"pg_advisory_xact_lock_shared_int8" | "pg_advisory_xact_lock_shared_int4" => {
|c, a| lock(c, a, true, false)
}
"pg_try_advisory_lock_int8" | "pg_try_advisory_lock_int4" => {
|c, a| try_lock(c, a, false, true)
}
"pg_try_advisory_xact_lock_int8" | "pg_try_advisory_xact_lock_int4" => {
|c, a| try_lock(c, a, false, false)
}
"pg_try_advisory_lock_shared_int8" | "pg_try_advisory_lock_shared_int4" => {
|c, a| try_lock(c, a, true, true)
}
"pg_try_advisory_xact_lock_shared_int8" | "pg_try_advisory_xact_lock_shared_int4" => {
|c, a| try_lock(c, a, true, false)
}
"pg_advisory_unlock_int8" | "pg_advisory_unlock_int4" => |c, a| unlock(c, a, false),
"pg_advisory_unlock_shared_int8" | "pg_advisory_unlock_shared_int4" => {
|c, a| unlock(c, a, true)
}
"pg_advisory_unlock_all" => unlock_all,
_ => return None,
};
Some(kernel)
}