use crate::client::Client;
use crate::constants;
use crate::db_type::DB_TYPE_BLOB;
use crate::db_type::DB_TYPE_CLOB;
use crate::db_type::DB_TYPE_LONG;
use crate::db_type::DB_TYPE_LONG_NVARCHAR;
use crate::db_type::DB_TYPE_LONG_RAW;
use crate::db_type::DB_TYPE_NCLOB;
use crate::db_type::DbType;
use crate::error::Error;
use crate::response::Response;
use crate::write_buffer::WriteBuffer;
#[derive(Clone, Debug)]
pub struct Metadata {
name: String,
db_type: &'static DbType,
null_by_describe: bool,
nullable: bool,
precision: u8,
scale: i8,
max_size: u32,
is_array: bool,
}
impl Metadata {
fn new(
db_type: &'static DbType,
max_size: usize,
is_array: bool,
) -> Metadata {
let actual_max_size: u32 = if max_size == 0 {
db_type.default_size
} else {
max_size.try_into().unwrap()
};
Metadata {
name: String::new(),
db_type,
nullable: false,
null_by_describe: false,
precision: 0,
scale: 0,
max_size: actual_max_size,
is_array,
}
}
pub(crate) fn define_metadata(&self) -> Metadata {
match *self.db_type {
DB_TYPE_BLOB => Metadata::new(&DB_TYPE_LONG_RAW, 0, false),
DB_TYPE_CLOB => Metadata::new(&DB_TYPE_LONG, 0, false),
DB_TYPE_NCLOB => Metadata::new(&DB_TYPE_LONG_NVARCHAR, 0, false),
_ => self.clone(),
}
}
pub(crate) fn from_response(
resp: &mut Response,
client: &Client,
) -> Result<Metadata, Error> {
let ora_type_num: u16 = resp.read_u8()?.into();
resp.read_u8()?; let precision = resp.read_u8()?;
let scale = resp.read_i8()?;
let buffer_size = resp.read_ub4()?;
resp.read_ub4()?; resp.read_ub8()?; resp.read_bytes_with_double_length()?; resp.read_ub2()?; resp.read_ub2()?; let csfrm = resp.read_u8()?;
let db_type = DbType::from_ora_type_and_csfrm(ora_type_num, csfrm);
let mut max_size = resp.read_ub4()?;
if ora_type_num == constants::ORA_TYPE_NUM_RAW {
max_size = buffer_size;
}
if client.supports_ttc_field_version(constants::TTC_FIELD_VERSION_12_2)
{
resp.read_ub4()?; }
let nulls_allowed = resp.read_u8()?;
resp.read_u8()?; let name = resp.read_str_with_double_length()?;
let _obj_schema = resp.read_str_with_double_length()?;
let _obj_name = resp.read_str_with_double_length()?;
resp.read_ub2()?; let _uds_flags = resp.read_ub4()?;
if client.supports_ttc_field_version(constants::TTC_FIELD_VERSION_23_1)
{
let _domain_schema = resp.read_str_with_double_length()?;
let _domain_name = resp.read_str_with_double_length()?;
}
if client.supports_ttc_field_version(
constants::TTC_FIELD_VERSION_23_1_EXT_3,
) {
let num_annotations = resp.read_ub4()?;
if num_annotations > 0 {
todo!();
}
}
if client.supports_ttc_field_version(constants::TTC_FIELD_VERSION_23_4)
{
let _vector_dimensions = resp.read_ub4()?;
let _vector_format = resp.read_u8()?;
let _vector_flags = resp.read_u8()?;
}
let null_by_describe = match db_type.ora_type_num {
constants::ORA_TYPE_NUM_LONG
| constants::ORA_TYPE_NUM_LONG_RAW
| constants::ORA_TYPE_NUM_UROWID => false,
_ => buffer_size == 0,
};
Ok(Metadata {
name,
db_type,
nullable: (nulls_allowed != 0),
precision,
scale,
null_by_describe,
max_size,
is_array: false,
})
}
pub(crate) fn is_null_by_describe(&self) -> bool {
self.null_by_describe
}
pub(crate) fn new_scalar(
db_type: &'static DbType,
max_size: usize,
) -> Metadata {
Metadata::new(db_type, max_size, false)
}
pub(crate) fn requires_define(&self) -> bool {
matches!(
self.db_type.ora_type_num,
constants::ORA_TYPE_NUM_BLOB
| constants::ORA_TYPE_NUM_CLOB
| constants::ORA_TYPE_NUM_JSON
| constants::ORA_TYPE_NUM_VECTOR
)
}
pub(crate) fn set_is_array(&mut self, is_array: bool) {
self.is_array = is_array;
}
pub(crate) fn write_to_buf(&self, buf: &mut WriteBuffer, client: &Client) {
let mut cont_flag: u64 = 0;
let mut lob_prefetch_length: u32 = 0;
match self.db_type.ora_type_num {
constants::ORA_TYPE_NUM_BLOB | constants::ORA_TYPE_NUM_CLOB => {
cont_flag = 0x2000000; }
constants::ORA_TYPE_NUM_JSON | constants::ORA_TYPE_NUM_VECTOR => {
cont_flag = 0x2000000; lob_prefetch_length = self.buffer_size();
}
_ => {}
};
buf.write_u8(self.db_type.ora_type_num.try_into().unwrap());
buf.write_u8(constants::TTC_BIND_FLAG_USE_INDICATORS);
buf.write_u8(0); buf.write_u8(0); buf.write_ub4(self.buffer_size());
buf.write_ub4(0); buf.write_ub8(cont_flag);
buf.write_ub4(0); buf.write_ub2(0); if self.db_type.csfrm != 0 {
buf.write_ub2(constants::CHARSET_ID_UTF8);
} else {
buf.write_ub2(0);
}
buf.write_u8(self.db_type.csfrm);
buf.write_ub4(lob_prefetch_length);
if client.supports_ttc_field_version(constants::TTC_FIELD_VERSION_12_2)
{
buf.write_ub4(0); }
}
pub fn buffer_size(&self) -> u32 {
let buffer_size_factor: u32 =
self.db_type.buffer_size_factor.try_into().unwrap();
if self.db_type.default_size == 0 {
buffer_size_factor
} else {
self.max_size * buffer_size_factor
}
}
pub fn db_type(&self) -> &'static DbType {
self.db_type
}
pub fn is_array(&self) -> bool {
self.is_array
}
pub fn max_size(&self) -> u32 {
self.max_size
}
pub fn name(&self) -> &str {
&self.name
}
pub fn nullable(&self) -> bool {
self.nullable
}
pub fn precision(&self) -> u8 {
self.precision
}
pub fn scale(&self) -> i8 {
self.scale
}
}