postgres_extension/utils/
elog.rs

1#![macro_use]
2#![allow(non_snake_case)]
3
4use libc::*;
5use std::ffi::CString;
6use crate::setjmp::*;
7
8#[repr(C)]
9pub struct ErrorContextCallback {
10    previous: *mut ErrorContextCallback,
11    callback: extern fn(arg: *mut c_void),
12    arg: *mut c_void,
13}
14
15#[macro_export]
16macro_rules! elog {
17    ($elevel:expr, $fmt:expr, $($args:tt)*) => {
18        postgres_extension::utils::elog::elog_internal(
19            file!(), line!(), $elevel, &format!($fmt, $($args)*));
20    };
21}
22
23extern {
24    fn elog_start(filename : *const c_char, lineno : c_int, funcname : *const c_char ) -> ();
25    fn elog_finish(elevel : c_int, fmt : *const c_char, ...) -> ();
26    pub fn pg_re_throw() -> ();
27}
28
29pub static mut POSTGRES_THREW_EXCEPTION: bool = false;
30
31pub const DEBUG5  : i32 = 10;
32pub const DEBUG4  : i32 = 11;
33pub const DEBUG3  : i32 = 12;
34pub const DEBUG2  : i32 = 13;
35pub const DEBUG1  : i32 = 14;
36pub const LOG     : i32 = 15;
37pub const INFO    : i32 = 17;
38pub const NOTICE  : i32 = 18;
39pub const WARNING : i32 = 19;
40pub const ERROR   : i32 = 20;
41pub const FATAL   : i32 = 21;
42pub const PANIC   : i32 = 22;
43pub fn elog_internal(filename: &str, lineno: u32, elevel: i32, fmt: &str) -> () {
44    let cfilename = CString::new(filename).unwrap().as_ptr();
45    let clineno = lineno as c_int;
46    /* rust doesn't have a macro to provide the current function name */
47    let cfuncname = std::ptr::null::<c_char>();
48    let celevel = elevel as c_int;
49    let cfmt = CString::new(fmt).unwrap();
50
51    unsafe {
52        elog_start(cfilename, clineno, cfuncname);
53        elog_finish(celevel, cfmt.as_ptr());
54    }
55}
56
57extern "C" {
58    #[allow(dead_code)]
59    pub static mut PG_exception_stack: *mut sigjmp_buf;
60    pub static mut error_context_stack: *mut ErrorContextCallback;
61}
62
63pub struct PgError;
64
65#[macro_export]
66macro_rules! longjmp_panic {
67    ($e:expr) => {
68        let retval;
69        unsafe {
70            use postgres_extension::utils::elog
71                ::{PG_exception_stack,
72                   error_context_stack,
73                   PgError};
74            use postgres_extension::setjmp::{sigsetjmp,sigjmp_buf};
75            let save_exception_stack: *mut sigjmp_buf = PG_exception_stack;
76            let save_context_stack: *mut ErrorContextCallback = error_context_stack;
77            let mut local_sigjmp_buf: sigjmp_buf = std::mem::uninitialized();
78            if sigsetjmp(&mut local_sigjmp_buf, 0) == 0 {
79                PG_exception_stack = &mut local_sigjmp_buf;
80                retval = $e;
81            } else {
82                PG_exception_stack = save_exception_stack;
83                error_context_stack = save_context_stack;
84                POSTGRES_THREW_EXCEPTION = true;
85                panic!(PgError);
86            }
87            PG_exception_stack = save_exception_stack;
88            error_context_stack = save_context_stack;
89        }
90        retval
91    }
92}