use chrono::{DateTime, Datelike, Duration, TimeZone, Timelike, Utc};
use error::{Error, ErrorKind, Result};
use hex_slice::AsHex;
use objecttype::ObjectType;
use odpi::enums::ODPIOracleTypeNum;
use odpi::structs::{ODPIData, ODPIDataBuffer, ODPIDataTypeInfo};
use odpi::{enums, externs, opaque};
use std::convert::TryFrom;
use std::slice;
use util::ODPIStr;
#[derive(Default, Getters, Setters)]
pub struct YearsMonths {
#[get = "pub"]
#[set = "pub"]
years: i32,
#[get = "pub"]
#[set = "pub"]
months: i32,
}
#[derive(Debug)]
pub struct Data {
inner: *mut ODPIData,
}
impl Data {
#[doc(hidden)]
pub fn new(is_null: bool, val: ODPIDataBuffer) -> Self {
let mut odpi_data = ODPIData {
is_null: if is_null { 1 } else { 0 },
value: val,
};
Self {
inner: &mut odpi_data,
}
}
#[doc(hidden)]
pub fn inner(&self) -> *mut ODPIData {
self.inner
}
pub fn null(&self) -> bool {
unsafe { (*self.inner).is_null == 1 }
}
pub fn get_bytes(&self) -> Vec<u8> {
unsafe {
let bytes = (*self.inner).value.as_bytes;
let slice = slice::from_raw_parts(bytes.ptr as *mut u8, bytes.length as usize);
slice.into()
}
}
pub fn get_boolean(&self) -> bool {
unsafe { (*self.inner).value.as_boolean == 1 }
}
pub fn set_boolean(&self, val: bool) {
unsafe { (*self.inner).value.as_boolean = if val { 1 } else { 0 } }
}
pub fn get_double(&self) -> f64 {
unsafe { externs::dpiData_getDouble(self.inner) }
}
pub fn set_double(&self, val: f64) {
unsafe { (*self.inner).value.as_double = val }
}
pub fn get_duration(&self) -> Duration {
let odpi_int_ds = unsafe { (*self.inner).value.as_interval_ds };
let mut dur = Duration::days(i64::from(odpi_int_ds.days));
dur = dur + Duration::hours(i64::from(odpi_int_ds.hours));
dur = dur + Duration::minutes(i64::from(odpi_int_ds.minutes));
dur = dur + Duration::seconds(i64::from(odpi_int_ds.seconds));
dur = dur + Duration::nanoseconds(i64::from(odpi_int_ds.fseconds));
dur
}
pub fn set_duration(&self, val: Duration) -> Result<()> {
let mut odpi_int_ds = unsafe { (*self.inner).value.as_interval_ds };
odpi_int_ds.days = TryFrom::try_from(val.num_days())?;
odpi_int_ds.hours = TryFrom::try_from(val.num_hours())?;
odpi_int_ds.minutes = TryFrom::try_from(val.num_minutes())?;
odpi_int_ds.seconds = TryFrom::try_from(val.num_seconds())?;
odpi_int_ds.fseconds = if let Some(ns) = val.num_nanoseconds() {
TryFrom::try_from(ns)?
} else {
0
};
Ok(())
}
pub fn get_float(&self) -> f32 {
unsafe { (*self.inner).value.as_float }
}
pub fn set_float(&self, val: f32) {
unsafe { (*self.inner).value.as_float = val }
}
pub fn get_int64(&self) -> i64 {
unsafe { (*self.inner).value.as_int_64 }
}
pub fn set_int64(&self, val: i64) {
unsafe { (*self.inner).value.as_int_64 = val }
}
pub fn get_lob(&self) -> *mut opaque::ODPILob {
unsafe { (*self.inner).value.as_lob }
}
pub fn set_lob(&self, val: *mut opaque::ODPILob) {
unsafe { (*self.inner).value.as_lob = val }
}
pub fn get_object(&self) -> *mut opaque::ODPIObject {
unsafe { (*self.inner).value.as_object }
}
pub fn set_object(&self, val: *mut opaque::ODPIObject) {
unsafe { (*self.inner).value.as_object = val }
}
pub fn get_stmt(&self) -> *mut opaque::ODPIStmt {
unsafe { (*self.inner).value.as_stmt }
}
pub fn set_stmt(&self, val: *mut opaque::ODPIStmt) {
unsafe { (*self.inner).value.as_stmt = val }
}
pub fn get_string(&self) -> String {
unsafe {
let odpi_bytes = (*self.inner).value.as_bytes;
let odpi_s = ODPIStr::new(odpi_bytes.ptr, odpi_bytes.length);
odpi_s.into()
}
}
pub fn set_string(&self, val: &str) -> Result<()> {
let val_s: ODPIStr = TryFrom::try_from(val)?;
let mut bytes = unsafe { (*self.inner).value.as_bytes };
bytes.ptr = val_s.ptr() as *mut i8;
bytes.length = val_s.len();
Ok(())
}
pub fn get_uint64(&self) -> u64 {
unsafe { (*self.inner).value.as_uint_64 }
}
pub fn set_uint64(&self, val: u64) {
unsafe { (*self.inner).value.as_uint_64 = val }
}
pub fn get_utc(&self) -> DateTime<Utc> {
let odpi_ts = unsafe { (*self.inner).value.as_timestamp };
let year = i32::from(odpi_ts.year);
let month = u32::from(odpi_ts.month);
let day = u32::from(odpi_ts.day);
let hour = u32::from(odpi_ts.hour);
let minute = u32::from(odpi_ts.minute);
let second = u32::from(odpi_ts.second);
Utc.ymd(year, month, day)
.and_hms_nano(hour, minute, second, odpi_ts.fsecond)
}
pub fn set_utc(&self, val: DateTime<Utc>) -> Result<()> {
let mut odpi_ts = unsafe { (*self.inner).value.as_timestamp };
odpi_ts.year = TryFrom::try_from(val.year())?;
odpi_ts.month = TryFrom::try_from(val.month())?;
odpi_ts.day = TryFrom::try_from(val.day())?;
odpi_ts.hour = TryFrom::try_from(val.hour())?;
odpi_ts.minute = TryFrom::try_from(val.minute())?;
odpi_ts.second = TryFrom::try_from(val.second())?;
Ok(())
}
pub fn get_years_months(&self) -> YearsMonths {
let odpi_int_ym = unsafe { (*self.inner).value.as_interval_ym };
let mut ym: YearsMonths = Default::default();
ym.set_years(odpi_int_ym.years);
ym.set_months(odpi_int_ym.months);
ym
}
pub fn set_years_months(&self, val: &YearsMonths) {
let mut odpi_int_ym = unsafe { (*self.inner).value.as_interval_ym };
odpi_int_ym.years = *val.years();
odpi_int_ym.months = *val.months();
}
pub fn to_string(&self, type_info: &TypeInfo) -> Result<String> {
let as_str = if self.null() {
"(null)".to_string()
} else {
let oracle_type = type_info.oracle_type_num();
let _native_type = type_info.default_native_type_num();
match oracle_type {
ODPIOracleTypeNum::Char | ODPIOracleTypeNum::Varchar => self.get_string(),
ODPIOracleTypeNum::Date => self.get_utc().to_rfc3339(),
ODPIOracleTypeNum::Number => self.get_double().to_string(),
ODPIOracleTypeNum::Raw => format!("{:x}", self.get_bytes().as_hex()),
_ => return Err(ErrorKind::Length.into()),
}
};
Ok(as_str)
}
pub fn len(&self, type_info: &TypeInfo) -> Result<usize> {
let as_str = self.to_string(type_info)?;
let len = as_str.len();
Ok(len)
}
}
impl TryFrom<*mut ODPIData> for Data {
type Error = Error;
fn try_from(inner: *mut ODPIData) -> Result<Self> {
if inner.is_null() {
Err(ErrorKind::NullPtr.into())
} else {
Ok(Self { inner })
}
}
}
#[derive(Clone, Debug, Default)]
pub struct TypeInfo {
inner: ODPIDataTypeInfo,
}
impl TypeInfo {
pub fn new(inner: ODPIDataTypeInfo) -> Self {
Self { inner }
}
pub fn oracle_type_num(&self) -> enums::ODPIOracleTypeNum {
self.inner.oracle_type_num
}
pub fn default_native_type_num(&self) -> enums::ODPINativeTypeNum {
self.inner.default_native_type_num
}
pub fn db_size_in_bytes(&self) -> u32 {
self.inner.db_size_in_bytes
}
pub fn client_size_in_bytes(&self) -> u32 {
self.inner.client_size_in_bytes
}
pub fn size_in_chars(&self) -> u32 {
self.inner.size_in_chars
}
pub fn precision(&self) -> i16 {
self.inner.precision
}
pub fn scale(&self) -> i8 {
self.inner.scale
}
pub fn object_type(&self) -> Option<ObjectType> {
if self.inner.object_type.is_null() {
None
} else {
Some(self.inner.object_type.into())
}
}
}
impl From<ODPIDataTypeInfo> for TypeInfo {
fn from(inner: ODPIDataTypeInfo) -> Self {
Self { inner }
}
}