#![deny(unsafe_op_in_unsafe_fn)]
use crate as pg_sys;
use crate::panic::{CaughtError, ErrorReport, ErrorReportLocation, ErrorReportWithLevel};
use core::ffi::CStr;
#[inline(always)]
#[track_caller]
pub unsafe fn pg_guard_ffi_boundary<T, F: FnOnce() -> T>(f: F) -> T {
unsafe { pg_guard_ffi_boundary_impl(f) }
}
#[inline(always)]
#[track_caller]
unsafe fn pg_guard_ffi_boundary_impl<T, F: FnOnce() -> T>(f: F) -> T {
super::thread_check::check_active_thread();
unsafe {
let caller_memxct = pg_sys::CurrentMemoryContext;
let prev_exception_stack = pg_sys::PG_exception_stack;
let prev_error_context_stack = pg_sys::error_context_stack;
let mut jump_buffer = std::mem::MaybeUninit::uninit();
let jump_value = crate::sigsetjmp(jump_buffer.as_mut_ptr(), 0);
if jump_value == 0 {
pg_sys::PG_exception_stack = jump_buffer.as_mut_ptr();
let result = f();
pg_sys::PG_exception_stack = prev_exception_stack;
pg_sys::error_context_stack = prev_error_context_stack;
return result;
} else {
pg_sys::CurrentMemoryContext = caller_memxct;
let errdata_ptr = pg_sys::CopyErrorData();
let errdata = errdata_ptr.as_ref().unwrap_unchecked();
let level = errdata.elevel.into();
let sqlerrcode = errdata.sqlerrcode.into();
let message = errdata
.message
.is_null()
.then(|| String::from("<null error message>"))
.unwrap_or_else(|| CStr::from_ptr(errdata.message).to_string_lossy().to_string());
let detail = errdata.detail.is_null().then(|| None).unwrap_or_else(|| {
Some(CStr::from_ptr(errdata.detail).to_string_lossy().to_string())
});
let hint = errdata.hint.is_null().then(|| None).unwrap_or_else(|| {
Some(CStr::from_ptr(errdata.hint).to_string_lossy().to_string())
});
let funcname = errdata.funcname.is_null().then(|| None).unwrap_or_else(|| {
Some(CStr::from_ptr(errdata.funcname).to_string_lossy().to_string())
});
let file =
errdata.filename.is_null().then(|| String::from("<null filename>")).unwrap_or_else(
|| CStr::from_ptr(errdata.filename).to_string_lossy().to_string(),
);
let line = errdata.lineno as _;
pg_sys::FreeErrorData(errdata_ptr);
pg_sys::PG_exception_stack = prev_exception_stack;
pg_sys::error_context_stack = prev_error_context_stack;
std::panic::panic_any(CaughtError::PostgresError(ErrorReportWithLevel {
level,
inner: ErrorReport {
sqlerrcode,
message,
detail,
hint,
location: ErrorReportLocation { file, funcname, line, col: 0, backtrace: None },
},
}))
}
}
}