use std::ffi::{CString,CStr};
use crate::utils::memutils::MemoryContext;
use libc::*;
pub type SPIPlanPtr = *mut _SPI_plan;
pub type HeapTuple = *mut HeapTupleData;
pub type TupleDesc = *mut TupleDescData;
pub type SubTransactionId = u32;
#[repr(C)]
pub struct TupleDescData { pub natts: c_int, _private: [u8; 0] }
#[repr(C)]
pub struct HeapTupleData { _private: [u8; 0] }
#[repr(C)]
pub struct _SPI_plan { _private: [u8; 0] }
#[repr(C)]
pub struct slist_node { _private: [u8; 0] }
#[repr(C)]
pub struct SPITupleTable
{
tuptabcxt: MemoryContext,
alloced: u64,
free: u64,
pub tupdesc: TupleDesc,
pub vals: *mut HeapTuple,
next: *mut slist_node,
subid: SubTransactionId,
}
pub const SPI_ERROR_CONNECT: i32 = -1;
pub const SPI_ERROR_COPY: i32 = -2;
pub const SPI_ERROR_OPUNKNOWN: i32 = -3;
pub const SPI_ERROR_UNCONNECTED: i32 = -4;
pub const SPI_ERROR_CURSOR: i32 = -5;
pub const SPI_ERROR_ARGUMENT: i32 = -6;
pub const SPI_ERROR_PARAM: i32 = -7;
pub const SPI_ERROR_TRANSACTION: i32 = -8;
pub const SPI_ERROR_NOATTRIBUTE: i32 = -9;
pub const SPI_ERROR_NOOUTFUNC: i32 = -10;
pub const SPI_ERROR_TYPUNKNOWN: i32 = -11;
pub const SPI_ERROR_REL_DUPLICATE: i32 = -12;
pub const SPI_ERROR_REL_NOT_FOUND: i32 = -13;
pub const SPI_OK_CONNECT: i32 = 1;
pub const SPI_OK_FINISH: i32 = 2;
pub const SPI_OK_FETCH: i32 = 3;
pub const SPI_OK_UTILITY: i32 = 4;
pub const SPI_OK_SELECT: i32 = 5;
pub const SPI_OK_SELINTO: i32 = 6;
pub const SPI_OK_INSERT: i32 = 7;
pub const SPI_OK_DELETE: i32 = 8;
pub const SPI_OK_UPDATE: i32 = 9;
pub const SPI_OK_CURSOR: i32 = 10;
pub const SPI_OK_INSERT_RETURNING: i32 = 11;
pub const SPI_OK_DELETE_RETURNING: i32 = 12;
pub const SPI_OK_UPDATE_RETURNING: i32 = 13;
pub const SPI_OK_REWRITTEN: i32 = 14;
pub const SPI_OK_REL_REGISTER: i32 = 15;
pub const SPI_OK_REL_UNREGISTER: i32 = 16;
pub const SPI_OK_TD_REGISTER: i32 = 17;
pub const SPI_OPT_NONATOMIC: i32 = (1 << 0);
pub mod c {
use libc::*;
use super::*;
extern {
pub static SPI_processed: u64;
pub static SPI_tuptable: *mut SPITupleTable;
pub static SPI_result: c_int;
pub fn SPI_connect() -> c_int;
pub fn SPI_connect_ext(options: c_int) -> c_int;
pub fn SPI_finish() -> c_int;
pub fn SPI_execute(src: *const c_char, read_only: bool,
tcount: c_long) -> c_int;
pub fn SPI_exec(src: *const c_char, tcount: c_long) -> c_int;
pub fn SPI_getvalue(tuple: HeapTuple, tupdesc: TupleDesc,
fnumber: c_int) -> *const c_char;
pub fn SPI_freetuptable(tuptable: *mut SPITupleTable);
}
}
pub struct SPIConnection;
pub struct SPIResult<'a> {
pub status: i32,
processed: u64,
tuptable: &'a mut SPITupleTable,
}
impl SPIConnection {
pub fn execute(&self, query: &str, readonly: bool) -> Result<SPIResult,i32> {
let query_cstring = CString::new(query).unwrap();
let query_ptr = query_cstring.as_ptr();
unsafe {
let status = c::SPI_execute(query_ptr, readonly, 0);
if status >= 0 {
return Ok(SPIResult {
status: status,
processed: c::SPI_processed,
tuptable: &mut *c::SPI_tuptable,
})
} else {
return Err(status);
}
}
}
}
impl Drop for SPIConnection {
fn drop(&mut self) {
unsafe {
c::SPI_finish();
}
}
}
impl<'a> SPIResult<'a> {
pub fn tuples(&self) -> &'a [&HeapTupleData] {
unsafe {
let vals: *const &HeapTupleData = (*self.tuptable).vals
as *const &HeapTupleData;
return std::slice::from_raw_parts(vals, self.processed as usize);
}
}
pub fn tupdesc(&self) -> &'a TupleDescData {
unsafe {
return &*(*self.tuptable).tupdesc;
}
}
}
impl<'a> Drop for SPIResult<'a> {
fn drop(&mut self) {
unsafe {
c::SPI_freetuptable(self.tuptable);
}
}
}
pub fn spi_connect() -> SPIConnection {
unsafe {
c::SPI_connect();
}
return SPIConnection {};
}
pub fn spi_getvalue(tuple: &HeapTupleData,
tupdesc: &TupleDescData,
attno: c_int) -> String {
unsafe {
let tuple_ptr: HeapTuple = tuple as *const HeapTupleData
as *mut HeapTupleData;
let tupdesc_ptr: TupleDesc = tupdesc as *const TupleDescData
as *mut TupleDescData;
let val_ptr = c::SPI_getvalue(tuple_ptr, tupdesc_ptr, attno);
let val_str = CStr::from_ptr(val_ptr).to_str().unwrap();
return CString::new(val_str).unwrap().into_string().unwrap();
};
}