#![allow(non_snake_case, non_camel_case_types, non_upper_case_globals, unused)]
use core::fmt;
use std::ffi::{CStr, CString};
use std::os::raw::{c_int, c_long, c_short, c_uint, c_ulong, c_ushort, c_void};
const DT_TYPES: u16 = 1022;
const DT_NOTYPE: u16 = 0;
const DT_SMALLINT: u16 = 500;
const DT_INT: u16 = 496;
const DT_FLOAT: u16 = 482;
const DT_DOUBLE: u16 = 480;
const DT_STRING: u16 = 460;
const DT_FIXCHAR: u16 = 452;
const DT_VARCHAR: u16 = 448;
const DT_LONGVARCHAR: u16 = 456;
const DT_BINARY: u16 = 524;
const DT_LONGBINARY: u16 = 528;
const DT_TINYINT: u16 = 604;
const DT_BIGINT: u16 = 608;
const DT_UNSINT: u16 = 612;
const DT_UNSSMALLINT: u16 = 616;
const DT_UNSBIGINT: u16 = 620;
const DT_BIT: u16 = 624;
const DT_NSTRING: u16 = 628;
const DT_NFIXCHAR: u16 = 632;
const DT_NVARCHAR: u16 = 636;
const DT_LONGNVARCHAR: u16 = 640;
const EXTFN_V0_API: u32 = 0;
const EXTFN_V2_API: u32 = 2;
const EXTFN_V3_API: u32 = 3;
const EXTFN_V4_API: u32 = 4;
pub const EXTFN_API_VERSION: u32 = 2;
const EXTFN_CONNECTION_HANDLE_ARG_NUM: a_sql_uint32 = !0;
const EXTFN_RESULT_SET_ARG_NUM: a_sql_uint32 = !0;
pub type a_sql_int32 = c_int;
pub type a_sql_uint32 = c_uint;
pub type a_sql_int64 = c_long;
pub type a_sql_uint64 = c_ulong;
type a_sql_data_type = c_ushort;
#[repr(u16)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum SqlDataTypeKind {
Unknown = DT_NOTYPE,
FixedChar = DT_FIXCHAR,
VarChar = DT_VARCHAR,
LongVarChar = DT_LONGVARCHAR,
NFixedChar = DT_NFIXCHAR,
NVarChar = DT_NVARCHAR,
LongNVarChar = DT_LONGNVARCHAR,
Binary = DT_BINARY,
LongBinary = DT_LONGBINARY,
U8 = DT_TINYINT,
I16 = DT_SMALLINT,
U16 = DT_UNSSMALLINT,
I32 = DT_INT,
U32 = DT_UNSINT,
I64 = DT_BIGINT,
U64 = DT_UNSBIGINT,
F32 = DT_FLOAT,
F64 = DT_DOUBLE,
}
#[repr(C)]
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Default)]
pub struct SqlDataType(::std::os::raw::c_ushort);
bitflags::bitflags! {
pub struct SqlDataTypeFlags: u16 {
const NULLS_ALLOWED = 1;
const PROCEDURE_OUT = 32768;
const PROCEDURE_IN = 16384;
const UPDATABLE = 8192;
const DESCRIBE_INPUT = 4096;
const AUTO_INCREMENT = 2048;
const KEY_COLUMN = 1024;
const HIDDEN_COLUMN = 512;
const HAS_USERTYPE_INFO = 256;
}
}
impl SqlDataType {
pub fn new(kind: SqlDataTypeKind) -> Self {
SqlDataType(kind as u16)
}
pub fn flags(self) -> SqlDataTypeFlags {
unsafe { SqlDataTypeFlags::from_bits_unchecked(self.0) }
}
pub fn kind(self) -> SqlDataTypeKind {
match self.0 & DT_TYPES {
DT_FIXCHAR => SqlDataTypeKind::FixedChar,
DT_VARCHAR => SqlDataTypeKind::VarChar,
DT_LONGVARCHAR => SqlDataTypeKind::LongVarChar,
DT_NFIXCHAR => SqlDataTypeKind::NFixedChar,
DT_NVARCHAR => SqlDataTypeKind::NVarChar,
DT_LONGNVARCHAR => SqlDataTypeKind::LongNVarChar,
DT_BINARY => SqlDataTypeKind::Binary,
DT_LONGBINARY => SqlDataTypeKind::LongBinary,
DT_TINYINT => SqlDataTypeKind::U8,
DT_SMALLINT => SqlDataTypeKind::I16,
DT_UNSSMALLINT => SqlDataTypeKind::I16,
DT_INT => SqlDataTypeKind::I32,
DT_UNSINT => SqlDataTypeKind::U32,
DT_BIGINT => SqlDataTypeKind::I64,
DT_UNSBIGINT => SqlDataTypeKind::U64,
DT_FLOAT => SqlDataTypeKind::F32,
DT_DOUBLE => SqlDataTypeKind::F64,
DT_NOTYPE | _ => SqlDataTypeKind::Unknown,
}
}
}
pub type RawSqlFnArguments = c_void;
#[repr(C)]
#[derive(Copy, Clone, Debug)]
pub struct ExtFnValue {
data: *mut c_void,
piece_len: a_sql_uint32,
len: a_sql_uint32,
data_type: SqlDataType,
}
#[derive(Debug, Clone)]
pub enum Error {
NullValue,
InvalidSqlDataType(SqlDataTypeKind),
UndecodableString,
InvalidArgumentIndex,
SetValue,
}
impl ExtFnValue {
pub fn as_str(&self) -> Result<&str, Error> {
if self.len == 0 {
return Err(Error::NullValue);
}
use SqlDataTypeKind::*;
match self.data_type.kind() {
FixedChar | VarChar | LongVarChar => {
let c_str = unsafe { CStr::from_ptr(self.data as *mut std::os::raw::c_char) };
c_str.to_str().map_err(|_| Error::UndecodableString)
}
NFixedChar | NVarChar | LongNVarChar => {
let data = self.data as *const u8;
unsafe {
let slice = std::slice::from_raw_parts(data, self.piece_len as usize);
Ok(std::str::from_utf8_unchecked(slice))
}
}
k @ _ => Err(Error::InvalidSqlDataType(k)),
}
}
pub fn as_u32(&self) -> Result<u32, Error> {
if self.len == 0 {
return Err(Error::NullValue);
}
match self.data_type.kind() {
SqlDataTypeKind::U32 => unsafe { Ok(*(self.data as *const u32)) },
k @ _ => Err(Error::InvalidSqlDataType(k)),
}
}
pub fn as_u64(&self) -> Result<u64, Error> {
if self.len == 0 {
return Err(Error::NullValue);
}
match self.data_type.kind() {
SqlDataTypeKind::U64 => unsafe { Ok(*(self.data as *const u64)) },
k @ _ => Err(Error::InvalidSqlDataType(k)),
}
}
}
impl Into<ExtFnValue> for &u64 {
fn into(self) -> ExtFnValue {
ExtFnValue {
data: self as *const u64 as *mut c_void,
piece_len: std::mem::size_of::<u64>() as a_sql_uint32,
len: std::mem::size_of::<u64>() as a_sql_uint32,
data_type: SqlDataType::new(SqlDataTypeKind::U64),
}
}
}
impl Into<ExtFnValue> for &str {
fn into(self) -> ExtFnValue {
unsafe {
let c = CStr::from_bytes_with_nul_unchecked(self.as_bytes());
ExtFnValue {
data: c.as_ptr() as *mut c_void,
piece_len: self.len() as a_sql_uint32,
len: self.len() as a_sql_uint32,
data_type: SqlDataType::new(SqlDataTypeKind::VarChar),
}
}
}
}
impl Default for ExtFnValue {
fn default() -> Self {
Self {
data: std::ptr::null_mut(),
piece_len: 0,
len: 0,
data_type: SqlDataType(0),
}
}
}
pub struct ExtFnApi {
extapi: *mut RawExtApi,
arg_handle: *mut RawSqlFnArguments,
}
impl ExtFnApi {
pub fn from_raw(extapi: *mut RawExtApi, arg_handle: *mut RawSqlFnArguments) -> Self {
Self { extapi, arg_handle }
}
pub fn get_connection(&self) -> Result<*mut c_void, Error> {
let mut value = ExtFnValue::default();
let ret = unsafe {
((*self.extapi).get_value)(self.arg_handle, EXTFN_CONNECTION_HANDLE_ARG_NUM, &mut value)
};
match ret {
0 => Err(Error::InvalidArgumentIndex),
_ => Ok(value.data),
}
}
pub fn arg(&self, idx: u32) -> Result<ExtFnValue, Error> {
let mut value = ExtFnValue::default();
let ret = unsafe { ((*self.extapi).get_value)(self.arg_handle, idx + 1, &mut value) };
match ret {
0 => Err(Error::InvalidArgumentIndex),
_ => Ok(value),
}
}
pub fn return_value<R: Into<ExtFnValue>>(&self, idx: u32, to_return: R) -> Result<(), Error> {
unsafe {
let mut retval = to_return.into();
match ((*self.extapi).set_value)(self.arg_handle, idx, &mut retval, 0) {
0 => Err(Error::SetValue),
_ => Ok(()),
}
}
}
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct RawExtApi {
get_value: unsafe extern "system" fn(
arg_handle: *mut RawSqlFnArguments,
arg_num: a_sql_uint32,
value: *mut ExtFnValue,
) -> c_short,
get_piece: unsafe extern "system" fn(
arg_handle: *mut RawSqlFnArguments,
arg_num: a_sql_uint32,
value: *mut ExtFnValue,
offset: a_sql_uint32,
) -> c_short,
set_value: unsafe extern "system" fn(
arg_handle: *mut RawSqlFnArguments,
arg_num: a_sql_uint32,
value: *mut ExtFnValue,
append: c_short,
) -> c_short,
set_cancel:
unsafe extern "system" fn(arg_handle: *mut RawSqlFnArguments, cancel_handle: *mut c_void),
}