mod attribute;
mod error_field;
pub use attribute::*;
pub use error_field::*;
#[derive(Clone)]
pub struct Result {
result: *mut pq_sys::PGresult,
}
impl Result {
pub fn new(conn: &crate::Connection, status: crate::Status) -> Self {
let result = unsafe { pq_sys::PQmakeEmptyPGresult(conn.into(), status.into()) };
result.into()
}
pub fn status(&self) -> crate::Status {
unsafe { pq_sys::PQresultStatus(self.into()) }.into()
}
pub fn error_message(&self) -> Option<String> {
crate::ffi::to_option_string(unsafe { pq_sys::PQresultErrorMessage(self.into()) })
}
pub fn error_field(&self, field: crate::result::ErrorField) -> Option<&'static str> {
unsafe {
let ptr = pq_sys::PQresultErrorField(self.into(), field.into());
if ptr.is_null() {
return None;
}
crate::ffi::to_option_str(ptr)
}
}
pub fn ntuples(&self) -> usize {
unsafe { pq_sys::PQntuples(self.into()) as usize }
}
pub fn nfields(&self) -> usize {
unsafe { pq_sys::PQnfields(self.into()) as usize }
}
pub fn field_name(&self, number: usize) -> Option<String> {
let raw = unsafe { pq_sys::PQfname(self.into(), number as i32) };
if raw.is_null() {
None
} else {
Some(crate::ffi::to_string(raw))
}
}
pub fn field_number(&self, name: &str) -> Option<usize> {
let c_name = crate::ffi::to_cstr(name);
let number = unsafe { pq_sys::PQfnumber(self.into(), c_name.as_ptr()) };
if number == -1 {
None
} else {
Some(number as usize)
}
}
pub fn field_table(&self, column: usize) -> Option<crate::Oid> {
let oid = unsafe { pq_sys::PQftable(self.into(), column as i32) };
if oid == crate::oid::INVALID {
None
} else {
Some(oid)
}
}
pub fn field_tablecol(&self, column: usize) -> usize {
unsafe { pq_sys::PQftablecol(self.into(), column as i32) as usize }
}
pub fn field_format(&self, column: usize) -> crate::Format {
unsafe { pq_sys::PQfformat(self.into(), column as i32) }.into()
}
pub fn field_type(&self, column: usize) -> crate::Oid {
unsafe { pq_sys::PQftype(self.into(), column as i32) }
}
pub fn field_mod(&self, column: usize) -> Option<i32> {
let raw = unsafe { pq_sys::PQfmod(self.into(), column as i32) };
if raw < 0 {
None
} else {
Some(raw)
}
}
pub fn field_size(&self, column: usize) -> Option<usize> {
let raw = unsafe { pq_sys::PQfsize(self.into(), column as i32) };
if raw < 0 {
None
} else {
Some(raw as usize)
}
}
pub fn binary_tuples(&self) -> bool {
unsafe { pq_sys::PQbinaryTuples(self.into()) == 1 }
}
pub fn value(&self, row: usize, column: usize) -> Option<&[u8]> {
if self.is_null(row, column) {
None
} else {
let slice = unsafe {
let raw = pq_sys::PQgetvalue(self.into(), row as i32, column as i32) as *const u8;
let length = self.length(row, column);
std::slice::from_raw_parts(raw, length)
};
Some(slice)
}
}
pub fn is_null(&self, row: usize, column: usize) -> bool {
unsafe { pq_sys::PQgetisnull(self.into(), row as i32, column as i32) == 1 }
}
pub fn length(&self, row: usize, column: usize) -> usize {
unsafe { pq_sys::PQgetlength(self.into(), row as i32, column as i32) as usize }
}
pub fn nparams(&self) -> usize {
unsafe { pq_sys::PQnparams(self.into()) as usize }
}
pub fn param_type(&self, param: usize) -> Option<crate::Oid> {
let oid = unsafe { pq_sys::PQparamtype(self.into(), param as i32) };
if oid == crate::oid::INVALID {
None
} else {
Some(oid)
}
}
#[cfg(unix)]
pub fn print(&self, output: &dyn std::os::unix::io::AsRawFd, option: &crate::print::Options) {
let c_mode = crate::ffi::to_cstr("w");
let (_c_field_name, ptr_field_name) = crate::ffi::vec_to_nta(&option.field_name);
let c_field_sep = crate::ffi::to_cstr(&option.field_sep);
let c_table_opt = crate::ffi::to_cstr(&option.table_opt);
let c_caption = crate::ffi::to_cstr(&option.caption);
let c_option = pq_sys::_PQprintOpt {
header: option.header as i8,
align: option.align as i8,
standard: option.standard as i8,
html3: option.html3 as i8,
expanded: option.expanded as i8,
pager: option.pager as i8,
fieldSep: c_field_sep.as_ptr() as *mut i8,
tableOpt: c_table_opt.as_ptr() as *mut i8,
caption: c_caption.as_ptr() as *mut i8,
fieldName: ptr_field_name.as_ptr() as *mut *mut libc::c_char,
};
unsafe {
let stream = libc::fdopen(output.as_raw_fd(), c_mode.as_ptr());
pq_sys::PQprint(stream as *mut _, self.into(), &c_option);
}
}
pub fn cmd_status(&self) -> Option<String> {
crate::ffi::to_option_string(unsafe { pq_sys::PQcmdStatus(self.into()) })
}
pub fn cmd_tuples(&self) -> usize {
let ntuples = crate::ffi::to_string(unsafe { pq_sys::PQcmdTuples(self.into()) });
ntuples.parse().unwrap_or_default()
}
pub fn oid_value(&self) -> Option<crate::Oid> {
let oid = unsafe { pq_sys::PQoidValue(self.into()) };
if oid == crate::oid::INVALID {
None
} else {
Some(oid)
}
}
#[deprecated(
note = "This function is deprecated in favor of `libpq::Result::oid_value` and is not thread-safe."
)]
pub fn oid_status(&self) -> Option<String> {
crate::ffi::to_option_string(unsafe { pq_sys::PQoidStatus(self.into()) })
}
pub fn copy(&self, flags: i32) -> std::result::Result<Self, ()> {
let raw = unsafe { pq_sys::PQcopyResult(self.into(), flags) };
if raw.is_null() {
Err(())
} else {
Ok(raw.into())
}
}
pub fn set_attrs(
&mut self,
attributes: &[&crate::result::Attribute],
) -> std::result::Result<(), ()> {
let mut attr = attributes.iter().map(|x| x.into()).collect::<Vec<_>>();
let success = unsafe {
pq_sys::PQsetResultAttrs(self.into(), attributes.len() as i32, attr.as_mut_ptr())
};
if success == 0 {
Err(())
} else {
Ok(())
}
}
pub fn set_value(
&mut self,
tuple: usize,
field: usize,
value: Option<&str>,
) -> std::result::Result<(), ()> {
let (v, len) = if let Some(v) = value {
let cstring = std::ffi::CString::new(v).unwrap();
(cstring.into_raw(), v.len() as i32)
} else {
(std::ptr::null_mut(), -1)
};
let success =
unsafe { pq_sys::PQsetvalue(self.into(), tuple as i32, field as i32, v, len as i32) };
if success == 0 {
Err(())
} else {
Ok(())
}
}
pub unsafe fn alloc(
&mut self,
nbytes: usize,
) -> std::result::Result<*mut core::ffi::c_void, ()> {
let space = pq_sys::PQresultAlloc(self.into(), nbytes as u64);
if space.is_null() {
Err(())
} else {
Ok(space)
}
}
#[cfg(feature = "v12")]
pub fn memory_size(&self) -> u64 {
unsafe { pq_sys::PQresultMemorySize(self.into()) }
}
#[cfg(unix)]
pub fn display_tuples(
&self,
file: std::fs::File,
fill_align: bool,
field_sep: Option<&str>,
print_header: bool,
quiet: bool,
) {
use std::os::unix::io::IntoRawFd;
let c_mode = crate::ffi::to_cstr("w");
unsafe {
let fp = libc::fdopen(file.into_raw_fd(), c_mode.as_ptr());
let c_sep = field_sep.map(crate::ffi::to_cstr);
let sep = if let Some(c_sep) = c_sep {
c_sep.as_ptr()
} else {
std::ptr::null()
};
pq_sys::PQdisplayTuples(
self.into(),
fp as *mut _,
fill_align as i32,
sep,
print_header as i32,
quiet as i32,
);
}
}
}
unsafe impl Send for Result {}
unsafe impl Sync for Result {}
impl Drop for Result {
fn drop(&mut self) {
unsafe { pq_sys::PQclear(self.into()) };
}
}
#[doc(hidden)]
impl From<*mut pq_sys::PGresult> for Result {
fn from(result: *mut pq_sys::PGresult) -> Self {
Result { result }
}
}
#[doc(hidden)]
impl From<&Result> for *mut pq_sys::PGresult {
fn from(result: &Result) -> *mut pq_sys::PGresult {
result.result
}
}
#[doc(hidden)]
impl From<&mut Result> for *mut pq_sys::PGresult {
fn from(result: &mut Result) -> *mut pq_sys::PGresult {
result.result
}
}
#[doc(hidden)]
impl From<&Result> for *const pq_sys::PGresult {
fn from(result: &Result) -> *const pq_sys::PGresult {
result.result
}
}
impl std::fmt::Debug for Result {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Result")
.field("inner", &self.result)
.field("status", &self.status())
.field("error_message", &self.error_message())
.field("ntuples", &self.ntuples())
.field("nfields", &self.nfields())
.field("cmd_status", &self.cmd_status())
.field("cmd_tuples", &self.cmd_tuples())
.field("oid_value", &self.oid_value())
.field("nparams", &self.nparams())
.finish()
}
}