oracle/
sql_value.rs

1// Rust-oracle - Rust binding for Oracle database
2//
3// URL: https://github.com/kubo/rust-oracle
4//
5//-----------------------------------------------------------------------------
6// Copyright (c) 2017-2025 Kubo Takehiro <kubo@jiubao.org>. All rights reserved.
7// This program is free software: you can modify it and/or redistribute it
8// under the terms of:
9//
10// (i)  the Universal Permissive License v 1.0 or at your option, any
11//      later version (http://oss.oracle.com/licenses/upl); and/or
12//
13// (ii) the Apache License v 2.0. (http://www.apache.org/licenses/LICENSE-2.0)
14//-----------------------------------------------------------------------------
15
16use crate::chkerr;
17use crate::connection::Conn;
18use crate::sql_type::vector::VecFmt;
19use crate::sql_type::vector::VecRef;
20use crate::sql_type::vector::Vector;
21use crate::sql_type::Bfile;
22use crate::sql_type::Blob;
23use crate::sql_type::Clob;
24use crate::sql_type::Collection;
25use crate::sql_type::FromSql;
26use crate::sql_type::InnerValue;
27use crate::sql_type::IntervalDS;
28use crate::sql_type::IntervalYM;
29use crate::sql_type::NativeType;
30use crate::sql_type::Nclob;
31use crate::sql_type::Object;
32use crate::sql_type::ObjectType;
33use crate::sql_type::OracleType;
34use crate::sql_type::RefCursor;
35use crate::sql_type::Timestamp;
36use crate::sql_type::ToSql;
37use crate::statement::LobBindType;
38use crate::statement::QueryParams;
39use crate::to_rust_slice;
40use crate::to_rust_str;
41use crate::util::check_number_format;
42use crate::util::parse_str_into_raw;
43use crate::util::set_hex_string;
44use crate::AssertSend;
45use crate::Context;
46use crate::DpiObject;
47use crate::DpiStmt;
48use crate::DpiVar;
49use crate::Error;
50use crate::ErrorKind;
51use crate::Result;
52use odpic_sys::dpi_impl::DPI_MAX_BASIC_BUFFER_SIZE;
53use odpic_sys::*;
54use std::borrow::Cow;
55use std::convert::TryInto;
56use std::fmt;
57use std::mem::MaybeUninit;
58use std::os::raw::c_char;
59use std::ptr;
60use std::rc::Rc;
61use std::slice;
62use std::str;
63use std::sync::atomic::{AtomicU32, Ordering};
64use std::sync::Arc;
65
66macro_rules! flt_to_int {
67    ($expr:expr, $src_type:ident, $dest_type:ident) => {{
68        let src_val = $expr;
69        if $dest_type::MIN as $src_type <= src_val && src_val <= $dest_type::MAX as $src_type {
70            Ok(src_val as $dest_type)
71        } else {
72            Err(Error::out_of_range(format!(
73                "{} overflow: {}",
74                stringify!($dest_type),
75                src_val.to_string(),
76            )))
77        }
78    }};
79}
80
81macro_rules! define_fn_to_int {
82    ($(#[$attr:meta])* : $func_name:ident, $type:ident) => {
83        $(#[$attr])*
84        pub (crate)fn $func_name(&self) -> Result<$type> {
85            match self.native_type {
86                NativeType::Int64 =>
87                    Ok(self.get_i64_unchecked()?.try_into()?),
88                NativeType::UInt64 =>
89                    Ok(self.get_u64_unchecked()?.try_into()?),
90                NativeType::Float =>
91                    flt_to_int!(self.get_f32_unchecked()?, f32, $type),
92                NativeType::Double =>
93                    flt_to_int!(self.get_f64_unchecked()?, f64, $type),
94                NativeType::Char => Ok(self.get_cow_str_unchecked()?.parse()?),
95                NativeType::Number => Ok(self.get_str_unchecked()?.parse()?),
96                NativeType::Clob => Ok(self.get_clob_as_string_unchecked()?.parse()?),
97                _ =>
98                    self.invalid_conversion_to_rust_type(stringify!($type))
99            }
100        }
101    }
102}
103
104macro_rules! define_fn_set_int {
105    ($(#[$attr:meta])* : $func_name:ident, $type:ident) => {
106        $(#[$attr])*
107        pub(crate) fn $func_name(&mut self, val: &$type) -> Result<()> {
108            match self.native_type {
109                NativeType::Int64 =>
110                    self.set_i64_unchecked(*val as i64),
111                NativeType::UInt64 =>
112                    self.set_u64_unchecked(*val as u64),
113                NativeType::Float =>
114                    self.set_f32_unchecked(*val as f32),
115                NativeType::Double =>
116                    self.set_f64_unchecked(*val as f64),
117                NativeType::Char |
118                NativeType::Number => {
119                    let s = val.to_string();
120                    self.set_string_unchecked(&s)
121                },
122                _ =>
123                    self.invalid_conversion_from_rust_type(stringify!($type))
124            }
125        }
126    }
127}
128
129pub enum BufferRowIndex {
130    Shared(Arc<AtomicU32>),
131    Owned(u32),
132}
133
134enum DpiData<'a> {
135    Data(&'a mut dpiData),
136    Var(Rc<DpiVar>), // Rc is incremented only when <Row as RowValue>::get() is called.
137    Null,
138}
139
140unsafe impl Send for DpiData<'_> {}
141
142/// A type containing an Oracle value
143///
144/// When this is a column value in a select statement, the Oracle type is
145/// determined by the column type.
146///
147/// When this is a bind value in a SQL statement, the Oracle type is determined
148/// by [`ToSql::oratype`].
149pub struct SqlValue<'a> {
150    conn: Conn,
151    data: DpiData<'a>,
152    native_type: NativeType,
153    oratype: Option<OracleType>,
154    pub(crate) array_size: u32,
155    pub(crate) buffer_row_index: BufferRowIndex,
156    keep_bytes: Vec<u8>,
157    keep_dpiobj: DpiObject,
158    pub(crate) lob_bind_type: LobBindType,
159    pub(crate) query_params: QueryParams,
160    vector_format: VecFmt,
161}
162
163impl SqlValue<'_> {
164    fn new(
165        conn: Conn,
166        lob_bind_type: LobBindType,
167        query_params: QueryParams,
168        array_size: u32,
169    ) -> SqlValue<'static> {
170        SqlValue {
171            conn,
172            data: DpiData::Null,
173            native_type: NativeType::Int64,
174            oratype: None,
175            array_size,
176            buffer_row_index: BufferRowIndex::Owned(0),
177            keep_bytes: Vec::new(),
178            keep_dpiobj: DpiObject::null(),
179            lob_bind_type,
180            query_params,
181            vector_format: VecFmt::Flexible,
182        }
183    }
184
185    pub(crate) fn for_bind(
186        conn: Conn,
187        query_params: QueryParams,
188        array_size: u32,
189    ) -> SqlValue<'static> {
190        SqlValue::new(conn, LobBindType::Locator, query_params, array_size)
191    }
192
193    pub(crate) fn for_column(
194        conn: Conn,
195        query_params: QueryParams,
196        shared_buffer_row_index: Arc<AtomicU32>,
197        oratype: &OracleType,
198        stmt_handle: *mut dpiStmt,
199        pos: u32,
200    ) -> Result<SqlValue<'static>> {
201        let array_size = query_params.fetch_array_size;
202        let mut val = SqlValue::new(conn, query_params.lob_bind_type, query_params, array_size);
203        let oratype_i64 = OracleType::Int64;
204        let oratype = match oratype {
205            // When the column type is number whose prec is less than 18
206            // and the scale is zero, define it as int64.
207            OracleType::Number(prec, 0) if 0 < *prec && *prec < DPI_MAX_INT64_PRECISION as u8 => {
208                &oratype_i64
209            }
210            _ => oratype,
211        };
212        val.buffer_row_index = BufferRowIndex::Shared(shared_buffer_row_index);
213        val.init_handle(oratype)?;
214        chkerr!(val.ctxt(), dpiStmt_define(stmt_handle, pos, val.handle()?));
215        Ok(val)
216    }
217
218    // for object type
219    pub(crate) fn from_oratype<'a>(
220        conn: Conn,
221        oratype: &OracleType,
222        data: &'a mut dpiData,
223    ) -> Result<SqlValue<'a>> {
224        let param = oratype.var_create_param()?;
225        Ok(SqlValue {
226            conn,
227            data: DpiData::Data(data),
228            native_type: param.native_type,
229            oratype: Some(oratype.clone()),
230            array_size: 0,
231            buffer_row_index: BufferRowIndex::Owned(0),
232            keep_bytes: Vec::new(),
233            keep_dpiobj: DpiObject::null(),
234            lob_bind_type: LobBindType::Locator,
235            query_params: QueryParams::new(),
236            vector_format: param.vector_format,
237        })
238    }
239
240    pub(crate) fn ctxt(&self) -> &Context {
241        self.conn.ctxt()
242    }
243
244    fn handle_is_reusable(&self, oratype: &OracleType) -> Result<bool> {
245        match self.data {
246            DpiData::Var(_) => (),
247            _ => return Ok(false),
248        };
249        let current_oratype = match self.oratype {
250            Some(ref oratype) => oratype,
251            None => return Ok(false),
252        };
253        let current = current_oratype.var_create_param()?;
254        let new = oratype.var_create_param()?;
255        if current.oracle_type_num != new.oracle_type_num {
256            return Ok(false);
257        }
258        match current.oracle_type_num {
259            DPI_ORACLE_TYPE_VARCHAR
260            | DPI_ORACLE_TYPE_NVARCHAR
261            | DPI_ORACLE_TYPE_CHAR
262            | DPI_ORACLE_TYPE_NCHAR
263            | DPI_ORACLE_TYPE_RAW => Ok(current.size >= new.size),
264            DPI_ORACLE_TYPE_OBJECT => Ok(current.native_type == new.native_type),
265            _ => Ok(true),
266        }
267    }
268
269    pub(crate) fn init_handle(&mut self, oratype: &OracleType) -> Result<bool> {
270        if self.handle_is_reusable(oratype)? {
271            return Ok(false);
272        }
273        self.data = DpiData::Null;
274        let param = match self.lob_bind_type {
275            LobBindType::Bytes => match oratype {
276                OracleType::CLOB => &OracleType::Long,
277                OracleType::NCLOB => {
278                    // When the size is larger than DPI_MAX_BASIC_BUFFER_SIZE, ODPI-C uses
279                    // a dynamic buffer instead of a fixed-size buffer.
280                    &OracleType::NVarchar2(DPI_MAX_BASIC_BUFFER_SIZE + 1)
281                }
282                OracleType::BLOB => &OracleType::LongRaw,
283                OracleType::BFILE => &OracleType::LongRaw,
284                _ => oratype,
285            },
286            LobBindType::Locator => oratype,
287        }
288        .var_create_param()?;
289        let mut handle = ptr::null_mut();
290        let mut data = ptr::null_mut();
291        let native_type_num = param.native_type.to_native_type_num();
292        let object_type_handle = param.native_type.to_object_type_handle();
293        chkerr!(
294            self.ctxt(),
295            dpiConn_newVar(
296                self.conn.handle.raw(),
297                param.oracle_type_num,
298                native_type_num,
299                self.array_size,
300                param.size,
301                param.size_is_byte,
302                0,
303                object_type_handle,
304                &mut handle,
305                &mut data,
306            )
307        );
308        self.data = DpiData::Var(Rc::new(DpiVar::new(handle, data)));
309        self.native_type = param.native_type;
310        self.oratype = Some(oratype.clone());
311        if native_type_num == DPI_NATIVE_TYPE_STMT {
312            for i in 0..self.array_size {
313                let handle = unsafe { dpiData_getStmt(data.offset(i as isize)) };
314                if let Some(prefetch_rows) = self.query_params.prefetch_rows {
315                    chkerr!(self.ctxt(), dpiStmt_setPrefetchRows(handle, prefetch_rows));
316                }
317            }
318        }
319        Ok(true)
320    }
321
322    pub(crate) fn fix_internal_data(&mut self) -> Result<()> {
323        let handle = self.handle()?;
324        let mut num = 0;
325        let mut data = ptr::null_mut();
326        chkerr!(
327            self.ctxt(),
328            dpiVar_getReturnedData(handle, 0, &mut num, &mut data)
329        );
330        if num != 0 {
331            self.array_size = num;
332            self.data = DpiData::Var(Rc::new(DpiVar::with_add_ref(handle, data)));
333        }
334        Ok(())
335    }
336
337    fn buffer_row_index(&self) -> u32 {
338        match self.buffer_row_index {
339            BufferRowIndex::Shared(ref idx) => idx.load(Ordering::Relaxed),
340            BufferRowIndex::Owned(idx) => idx,
341        }
342    }
343
344    pub(crate) fn handle(&self) -> Result<*mut dpiVar> {
345        if let DpiData::Var(var) = &self.data {
346            Ok(var.raw)
347        } else {
348            Err(Error::internal_error("dpVar handle isn't initialized"))
349        }
350    }
351
352    pub(crate) fn data(&self) -> Result<&mut dpiData> {
353        unsafe {
354            Ok(&mut *match self.data {
355                DpiData::Data(ref data) => *data as *const dpiData as *mut dpiData,
356                DpiData::Var(ref var) => var.data,
357                DpiData::Null => {
358                    return Err(Error::internal_error("dpData isn't initialized"));
359                }
360            }
361            .offset(self.buffer_row_index() as isize))
362        }
363    }
364
365    pub(crate) fn native_type_num(&self) -> dpiNativeTypeNum {
366        self.native_type.to_native_type_num()
367    }
368
369    /// Gets the Oracle value. It internally does the followings:
370    ///
371    /// 1. Checks whether the conversion from the Oracle type to the target rust type
372    ///    is allowed. It returns `Err(Error::InvalidTypeConversion(...))` when it
373    ///    isn't allowed.
374    /// 2. Checks whether the Oracle value is null. When it is null and the return
375    ///    type is `Option<FromSql>`, it returns `Ok(None)`. When it is null and it
376    ///    isn't `Option<FromSql>`, it returns `Err(Error::NullValue)`.
377    /// 3. Converts the Oracle value to the rust value. The data type is converted
378    ///    implicitly if required. For example string is converted to i64 by
379    ///    [`str::parse`] if `get::<i64>()` is called for `VARCHAR2` columns.
380    ///    If the conversion fails, various errors are returned.
381    pub fn get<T>(&self) -> Result<T>
382    where
383        T: FromSql,
384    {
385        <T>::from_sql(self)
386    }
387
388    /// Sets a rust value to the Oracle value. It internally does the followings:
389    ///
390    /// 1. Checks whether the conversion from the rust type to the target Oracle type
391    ///    is allowed. It returns `Err(Error::InvalidTypeConversion(...))` when it
392    ///    isn't allowed.
393    /// 2. When the argument type is `None::<ToSql>`, null is set.
394    /// 3. Otherwise, converts the rust value to the Oracle value. The data type
395    ///    is converted implicitly if required. For example i64 is converted to
396    ///    string by `to_string()` if `set(100i64)` is called for `VARCHAR2` columns.
397    ///    When the argument is `None::<ToSql>`
398    ///    If the conversion fails, various errors are returned.
399    pub fn set(&mut self, val: &dyn ToSql) -> Result<()> {
400        val.to_sql(self)
401    }
402
403    fn invalid_conversion_to_rust_type<T>(&self, to_type: &str) -> Result<T> {
404        Err(match self.oratype {
405            Some(ref oratype) => Error::invalid_type_conversion(oratype.to_string(), to_type),
406            None => Error::uninitialized_bind_value(),
407        })
408    }
409
410    fn invalid_conversion_from_rust_type<T>(&self, from_type: &str) -> Result<T> {
411        Err(match self.oratype {
412            Some(ref oratype) => Error::invalid_type_conversion(from_type, oratype.to_string()),
413            None => Error::uninitialized_bind_value(),
414        })
415    }
416
417    fn lob_locator_is_not_set<T>(&self, to_type: &str) -> Result<T> {
418        match self.oratype {
419            Some(_) => Err(Error::invalid_operation(format!(
420                "use StatementBuilder.lob_locator() instead to fetch LOB data as {}",
421                to_type
422            ))),
423            None => Err(Error::uninitialized_bind_value()),
424        }
425    }
426
427    fn check_not_null(&self) -> Result<()> {
428        if self.is_null()? {
429            Err(Error::null_value())
430        } else {
431            Ok(())
432        }
433    }
434
435    /// Returns `Ok(true)` when the SQL value is null. `Ok(false)` when it isn't null.
436    pub fn is_null(&self) -> Result<bool> {
437        Ok(self.data()?.isNull != 0)
438    }
439
440    /// Sets null to the SQL value.
441    pub fn set_null(&mut self) -> Result<()> {
442        self.data()?.isNull = 1;
443        Ok(())
444    }
445
446    /// Gets the Oracle type of the SQL value.
447    pub fn oracle_type(&self) -> Result<&OracleType> {
448        match self.oratype {
449            Some(ref oratype) => Ok(oratype),
450            None => Err(Error::uninitialized_bind_value()),
451        }
452    }
453
454    /// Returns the raw SQL data inside of internal array fetch buffer
455    ///
456    /// This is intended to be used inside of [`FromSql::from_sql()`]
457    ///
458    /// See [`InnerValue`] documentation.
459    pub fn as_inner_value(&self) -> Result<InnerValue> {
460        let data = self.data()?;
461        if data.isNull != 0 {
462            return Err(Error::null_value());
463        }
464        Ok(unsafe {
465            match self.native_type {
466                NativeType::Int64 => InnerValue::Int64(data.value.asInt64),
467                NativeType::UInt64 => InnerValue::UInt64(data.value.asUint64),
468                NativeType::Float => InnerValue::Float(data.value.asFloat),
469                NativeType::Double => InnerValue::Double(data.value.asDouble),
470                NativeType::Char => InnerValue::Char(to_rust_slice(
471                    data.value.asBytes.ptr,
472                    data.value.asBytes.length,
473                )),
474                NativeType::Number => InnerValue::Number(str::from_utf8_unchecked(to_rust_slice(
475                    data.value.asBytes.ptr,
476                    data.value.asBytes.length,
477                ))),
478                NativeType::Raw => InnerValue::Raw(to_rust_slice(
479                    data.value.asBytes.ptr,
480                    data.value.asBytes.length,
481                )),
482                NativeType::Timestamp => InnerValue::Timestamp(&data.value.asTimestamp),
483                NativeType::IntervalDS => InnerValue::IntervalDS(&data.value.asIntervalDS),
484                NativeType::IntervalYM => InnerValue::IntervalYM(&data.value.asIntervalYM),
485                NativeType::Clob => InnerValue::Clob(data.value.asLOB),
486                NativeType::Blob => InnerValue::Blob(data.value.asLOB),
487                NativeType::Object(_) => InnerValue::Object(data.value.asObject),
488                NativeType::Boolean => InnerValue::Boolean(data.value.asBoolean != 0),
489                NativeType::Rowid => InnerValue::Rowid(data.value.asRowid),
490                NativeType::Stmt => InnerValue::Stmt(data.value.asStmt),
491                NativeType::Vector => InnerValue::Vector(data.value.asVector),
492            }
493        })
494    }
495
496    //
497    // get_TYPE_unchecked methods
498    //
499
500    /// Gets the SQL value as i64. The native_type must be
501    /// NativeType::Int64. Otherwise, this returns unexpected value.
502    fn get_i64_unchecked(&self) -> Result<i64> {
503        self.check_not_null()?;
504        unsafe { Ok(dpiData_getInt64(self.data()?)) }
505    }
506
507    /// Gets the SQL value as u64. The native_type must be
508    /// NativeType::UInt64. Otherwise, this returns unexpected value.
509    fn get_u64_unchecked(&self) -> Result<u64> {
510        self.check_not_null()?;
511        unsafe { Ok(dpiData_getUint64(self.data()?)) }
512    }
513
514    /// Gets the SQL value as f32. The native_type must be
515    /// NativeType::Float. Otherwise, this returns unexpected value.
516    fn get_f32_unchecked(&self) -> Result<f32> {
517        self.check_not_null()?;
518        unsafe { Ok(dpiData_getFloat(self.data()?)) }
519    }
520
521    /// Gets the SQL value as f64. The native_type must be
522    /// NativeType::Double. Otherwise, this returns unexpected value.
523    fn get_f64_unchecked(&self) -> Result<f64> {
524        self.check_not_null()?;
525        unsafe { Ok(dpiData_getDouble(self.data()?)) }
526    }
527
528    /// Gets the SQL value as utf8 string. The native_type must be
529    /// NativeType::Char or NativeType::Number. Otherwise, this may cause access
530    /// violation.
531    fn get_cow_str_unchecked(&self) -> Result<Cow<str>> {
532        self.check_not_null()?;
533        unsafe {
534            let bytes = dpiData_getBytes(self.data()?);
535            let s = slice::from_raw_parts((*bytes).ptr as *mut u8, (*bytes).length as usize);
536            Ok(String::from_utf8_lossy(s))
537        }
538    }
539
540    /// Gets the SQL value as utf8 string. The native_type must be
541    /// NativeType::Char or NativeType::Number. Otherwise, this may cause access
542    /// violation.
543    /// Unlike get_cow_str_unchecked() this doesn't check whether the byte sequence
544    /// is a valid UTF-8.
545    fn get_str_unchecked(&self) -> Result<&str> {
546        self.check_not_null()?;
547        unsafe {
548            let bytes = dpiData_getBytes(self.data()?);
549            let s = slice::from_raw_parts((*bytes).ptr as *mut u8, (*bytes).length as usize);
550            Ok(str::from_utf8_unchecked(s))
551        }
552    }
553
554    /// Gets the SQL value as Vec<u8>. The native_type must be
555    /// NativeType::Raw. Otherwise, this may cause access violation.
556    fn get_raw_unchecked(&self) -> Result<Vec<u8>> {
557        self.check_not_null()?;
558        unsafe {
559            let bytes = dpiData_getBytes(self.data()?);
560            let mut vec = Vec::with_capacity((*bytes).length as usize);
561            vec.extend_from_slice(to_rust_slice((*bytes).ptr, (*bytes).length));
562            Ok(vec)
563        }
564    }
565
566    /// Gets the SQL value as hexadecimal string. The native_type must be
567    /// NativeType::Raw. Otherwise, this may cause access violation.
568    fn get_raw_as_hex_string_unchecked(&self) -> Result<String> {
569        self.check_not_null()?;
570        unsafe {
571            let bytes = dpiData_getBytes(self.data()?);
572            let mut str = String::with_capacity(((*bytes).length * 2) as usize);
573            set_hex_string(&mut str, to_rust_slice((*bytes).ptr, (*bytes).length));
574            Ok(str)
575        }
576    }
577
578    /// Gets the SQL value as Timestamp. The native_type must be
579    /// NativeType::Timestamp. Otherwise, this returns unexpected value.
580    fn get_timestamp_unchecked(&self) -> Result<Timestamp> {
581        self.check_not_null()?;
582        unsafe {
583            let ts = dpiData_getTimestamp(self.data()?);
584            Ok(Timestamp::from_dpi_timestamp(&*ts, self.oracle_type()?))
585        }
586    }
587
588    /// Gets the SQL value as IntervalDS. The native_type must be
589    /// NativeType::IntervalDS. Otherwise, this returns unexpected value.
590    fn get_interval_ds_unchecked(&self) -> Result<IntervalDS> {
591        self.check_not_null()?;
592        unsafe {
593            let it = dpiData_getIntervalDS(self.data()?);
594            IntervalDS::from_dpi_interval_ds(&*it, self.oracle_type()?)
595        }
596    }
597
598    /// Gets the SQL value as IntervalYM. The native_type must be
599    /// NativeType::IntervalYM. Otherwise, this returns unexpected value.
600    fn get_interval_ym_unchecked(&self) -> Result<IntervalYM> {
601        self.check_not_null()?;
602        unsafe {
603            let it = dpiData_getIntervalYM(self.data()?);
604            IntervalYM::from_dpi_interval_ym(&*it, self.oracle_type()?)
605        }
606    }
607
608    fn get_clob_as_string_unchecked(&self) -> Result<String> {
609        self.check_not_null()?;
610        const READ_CHAR_SIZE: u64 = 8192;
611        let lob = unsafe { dpiData_getLOB(self.data()?) };
612        let mut total_char_size = 0;
613        let mut total_byte_size = 0;
614        let mut bufsiz = 0;
615        unsafe {
616            dpiLob_getSize(lob, &mut total_char_size);
617            dpiLob_getBufferSize(lob, total_char_size, &mut total_byte_size);
618            dpiLob_getBufferSize(lob, READ_CHAR_SIZE, &mut bufsiz);
619        }
620        let mut result = String::with_capacity(total_byte_size as usize);
621        let mut buf = vec![0u8; bufsiz as usize];
622        let bufptr = buf.as_mut_ptr() as *mut c_char;
623
624        let mut offset = 1;
625        while offset <= total_char_size {
626            let mut read_len = bufsiz;
627            chkerr!(
628                self.ctxt(),
629                dpiLob_readBytes(lob, offset, READ_CHAR_SIZE, bufptr, &mut read_len)
630            );
631            result.push_str(str::from_utf8(&buf[..(read_len as usize)])?);
632            offset += READ_CHAR_SIZE;
633        }
634        Ok(result)
635    }
636
637    fn get_blob_unchecked(&self) -> Result<Vec<u8>> {
638        self.check_not_null()?;
639        let lob = unsafe { dpiData_getLOB(self.data()?) };
640        let mut total_size = 0;
641        unsafe {
642            dpiLob_getSize(lob, &mut total_size);
643        }
644        let mut result: Vec<u8> = Vec::with_capacity(total_size as usize);
645        let mut read_len = total_size;
646        chkerr!(
647            self.ctxt(),
648            dpiLob_readBytes(
649                lob,
650                1,
651                total_size,
652                result.as_mut_ptr() as *mut c_char,
653                &mut read_len
654            )
655        );
656        unsafe {
657            result.set_len(read_len as usize);
658        }
659        Ok(result)
660    }
661
662    fn get_blob_as_hex_string_unchecked(&self) -> Result<String> {
663        self.check_not_null()?;
664        const READ_SIZE: u64 = 8192;
665        let lob = unsafe { dpiData_getLOB(self.data()?) };
666        let mut total_size = 0;
667        unsafe {
668            dpiLob_getSize(lob, &mut total_size);
669        }
670        let mut result = String::with_capacity((total_size * 2) as usize);
671        let mut buf = vec![0u8; READ_SIZE as usize];
672        let bufptr = buf.as_mut_ptr() as *mut c_char;
673
674        let mut offset = 1;
675        while offset <= total_size {
676            let mut read_len = READ_SIZE;
677            chkerr!(
678                self.ctxt(),
679                dpiLob_readBytes(lob, offset, READ_SIZE, bufptr, &mut read_len)
680            );
681            set_hex_string(&mut result, &buf[..(read_len as usize)]);
682            offset += READ_SIZE;
683        }
684        Ok(result)
685    }
686
687    fn get_collection_unchecked(&self, objtype: &ObjectType) -> Result<Collection> {
688        self.check_not_null()?;
689        let dpiobj = unsafe { dpiData_getObject(self.data()?) };
690        chkerr!(self.ctxt(), dpiObject_addRef(dpiobj));
691        Ok(Collection::new(
692            self.conn.clone(),
693            DpiObject::new(dpiobj),
694            objtype.clone(),
695        ))
696    }
697
698    fn get_object_unchecked(&self, objtype: &ObjectType) -> Result<Object> {
699        self.check_not_null()?;
700        let dpiobj = unsafe { dpiData_getObject(self.data()?) };
701        chkerr!(self.ctxt(), dpiObject_addRef(dpiobj));
702        Ok(Object::new(
703            self.conn.clone(),
704            DpiObject::new(dpiobj),
705            objtype.clone(),
706        ))
707    }
708
709    /// Gets the SQL value as bool. The native_type must be
710    /// NativeType::Boolean. Otherwise, this returns unexpected value.
711    fn get_bool_unchecked(&self) -> Result<bool> {
712        self.check_not_null()?;
713        unsafe { Ok(dpiData_getBool(self.data()?) != 0) }
714    }
715
716    fn get_rowid_as_string_unchecked(&self) -> Result<String> {
717        self.check_not_null()?;
718        let mut ptr = ptr::null();
719        let mut len = 0;
720        chkerr!(
721            self.ctxt(),
722            dpiRowid_getStringValue(self.data()?.value.asRowid, &mut ptr, &mut len)
723        );
724        Ok(to_rust_str(ptr, len))
725    }
726
727    fn get_lob_unchecked(&self) -> Result<*mut dpiLob> {
728        self.check_not_null()?;
729        unsafe { Ok(dpiData_getLOB(self.data()?)) }
730    }
731
732    fn get_stmt_unchecked(&self) -> Result<*mut dpiStmt> {
733        self.check_not_null()?;
734        unsafe { Ok(dpiData_getStmt(self.data()?)) }
735    }
736
737    /// # Safety
738    ///
739    /// The actual lifetime of VecRef isn't 'static.
740    /// It is same with that of DpiVar.
741    unsafe fn get_vec_ref_unchecked(&self) -> Result<VecRef<'static>> {
742        self.check_not_null()?;
743        let mut info = MaybeUninit::uninit();
744        chkerr!(
745            self.ctxt(),
746            dpiVector_getValue(self.data()?.value.asVector, info.as_mut_ptr())
747        );
748        VecRef::from_dpi(info.assume_init())
749    }
750
751    //
752    // set_TYPE_unchecked methods
753    //
754
755    /// Sets i64 to the SQL value. The native_type must be
756    /// NativeType::Int64. Otherwise, this may cause access violation.
757    fn set_i64_unchecked(&mut self, val: i64) -> Result<()> {
758        unsafe { dpiData_setInt64(self.data()?, val) }
759        Ok(())
760    }
761
762    /// Sets u64 to the SQL value. The native_type must be
763    /// NativeType::UInt64. Otherwise, this may cause access violation.
764    fn set_u64_unchecked(&mut self, val: u64) -> Result<()> {
765        unsafe { dpiData_setUint64(self.data()?, val) }
766        Ok(())
767    }
768
769    /// Sets f32 to the SQL value. The native_type must be
770    /// NativeType::Float. Otherwise, this may cause access violation.
771    fn set_f32_unchecked(&mut self, val: f32) -> Result<()> {
772        unsafe { dpiData_setFloat(self.data()?, val) }
773        Ok(())
774    }
775
776    /// Sets f64 to the SQL value. The native_type must be
777    /// NativeType::Double. Otherwise, this may cause access violation.
778    fn set_f64_unchecked(&mut self, val: f64) -> Result<()> {
779        unsafe { dpiData_setDouble(self.data()?, val) }
780        Ok(())
781    }
782
783    fn set_bytes_unchecked(&mut self, val: &[u8]) -> Result<()> {
784        match &self.data {
785            DpiData::Data(_) => {
786                self.keep_bytes = Vec::with_capacity(val.len());
787                self.keep_bytes.extend_from_slice(val);
788                unsafe {
789                    dpiData_setBytes(
790                        self.data()?,
791                        self.keep_bytes.as_mut_ptr() as *mut c_char,
792                        val.len() as u32,
793                    );
794                }
795                Ok(())
796            }
797            DpiData::Var(var) => {
798                chkerr!(
799                    self.ctxt(),
800                    dpiVar_setFromBytes(
801                        var.raw,
802                        self.buffer_row_index(),
803                        val.as_ptr() as *const c_char,
804                        val.len() as u32
805                    )
806                );
807                Ok(())
808            }
809            DpiData::Null => Err(Error::internal_error("dpiData isn't initialized")),
810        }
811    }
812
813    /// Sets utf8 string to the SQL value. The native_type must be
814    /// NativeType::Char or NativeType::Number. Otherwise, this may cause access
815    /// violation.
816    fn set_string_unchecked(&mut self, val: &str) -> Result<()> {
817        self.set_bytes_unchecked(val.as_bytes())
818    }
819
820    /// Sets &[u8] to the SQL value. The native_type must be
821    /// NativeType::Raw. Otherwise, this may cause access violation.
822    fn set_raw_unchecked(&mut self, val: &[u8]) -> Result<()> {
823        self.set_bytes_unchecked(val)
824    }
825
826    /// Sets Timestamp to the SQL value. The native_type must be
827    /// NativeType::Timestamp. Otherwise, this may cause access violation.
828    fn set_timestamp_unchecked(&mut self, val: &Timestamp) -> Result<()> {
829        let data = self.data()?;
830        data.isNull = 0;
831        data.value.asTimestamp = val.ts;
832        Ok(())
833    }
834
835    /// Sets IntervalDS to the SQL value. The native_type must be
836    /// NativeType::IntervalDS. Otherwise, this may cause access violation.
837    fn set_interval_ds_unchecked(&mut self, val: &IntervalDS) -> Result<()> {
838        let data = self.data()?;
839        data.isNull = 0;
840        data.value.asIntervalDS = val.intvl;
841        Ok(())
842    }
843
844    /// Sets IntervalYM to the SQL value. The native_type must be
845    /// NativeType::IntervalYM. Otherwise, this may cause access violation.
846    fn set_interval_ym_unchecked(&mut self, val: &IntervalYM) -> Result<()> {
847        let data = self.data()?;
848        data.isNull = 0;
849        data.value.asIntervalYM = val.intvl;
850        Ok(())
851    }
852
853    fn set_string_to_clob_unchecked(&mut self, val: &str) -> Result<()> {
854        let ptr = val.as_ptr() as *const c_char;
855        let len = val.len() as u64;
856        let lob = unsafe { dpiData_getLOB(self.data()?) };
857        chkerr!(self.ctxt(), dpiLob_trim(lob, 0));
858        chkerr!(self.ctxt(), dpiLob_writeBytes(lob, 1, ptr, len));
859        self.data()?.isNull = 0;
860        Ok(())
861    }
862
863    fn set_raw_to_blob_unchecked(&mut self, val: &[u8]) -> Result<()> {
864        let ptr = val.as_ptr() as *const c_char;
865        let len = val.len() as u64;
866        let lob = unsafe { dpiData_getLOB(self.data()?) };
867        chkerr!(self.ctxt(), dpiLob_trim(lob, 0));
868        chkerr!(self.ctxt(), dpiLob_writeBytes(lob, 1, ptr, len));
869        self.data()?.isNull = 0;
870        Ok(())
871    }
872
873    fn set_object_unchecked(&mut self, obj: &DpiObject) -> Result<()> {
874        match self.data {
875            DpiData::Data(_) => {
876                unsafe { dpiData_setObject(self.data()?, obj.raw) }
877                self.keep_dpiobj = obj.clone();
878                Ok(())
879            }
880            DpiData::Var(ref var) => {
881                chkerr!(
882                    self.ctxt(),
883                    dpiVar_setFromObject(var.raw, self.buffer_row_index(), obj.raw)
884                );
885                Ok(())
886            }
887            DpiData::Null => Err(Error::internal_error("dpiData isn't initialized")),
888        }
889    }
890
891    /// Sets bool to the SQL value. The native_type must be
892    /// NativeType::Boolean. Otherwise, this may cause access violation.
893    fn set_bool_unchecked(&mut self, val: bool) -> Result<()> {
894        unsafe { dpiData_setBool(self.data()?, i32::from(val)) }
895        Ok(())
896    }
897
898    fn set_lob_unchecked(&mut self, lob: *mut dpiLob) -> Result<()> {
899        chkerr!(
900            self.ctxt(),
901            dpiVar_setFromLob(self.handle()?, self.buffer_row_index(), lob)
902        );
903        Ok(())
904    }
905
906    fn set_vec_ref_unchecked(&mut self, vec: &VecRef) -> Result<()> {
907        let data = self.data()?;
908        let mut vec = vec.to_dpi()?;
909        chkerr!(
910            self.ctxt(),
911            dpiVector_setValue(data.value.asVector, &mut vec)
912        );
913        data.isNull = 0;
914        Ok(())
915    }
916
917    pub(crate) fn clone_except_fetch_array_buffer(&self) -> Result<SqlValue<'static>> {
918        if let DpiData::Var(ref var) = self.data {
919            Ok(SqlValue {
920                conn: self.conn.clone(),
921                data: DpiData::Var(var.clone()),
922                native_type: self.native_type.clone(),
923                oratype: self.oratype.clone(),
924                array_size: self.array_size,
925                buffer_row_index: BufferRowIndex::Owned(self.buffer_row_index()),
926                keep_bytes: Vec::new(),
927                keep_dpiobj: DpiObject::null(),
928                lob_bind_type: self.lob_bind_type,
929                query_params: self.query_params.clone(),
930                vector_format: self.vector_format,
931            })
932        } else {
933            Err(Error::internal_error("dpVar handle isn't initialized"))
934        }
935    }
936
937    pub(crate) fn fetch_array_buffer_shared_count(&self) -> Result<usize> {
938        if let DpiData::Var(ref var) = self.data {
939            Ok(Rc::strong_count(var))
940        } else {
941            Err(Error::internal_error("dpData isn't initialized"))
942        }
943    }
944
945    //
946    // as_TYPE methods
947    //
948
949    define_fn_to_int!(
950        /// Gets the SQL value as i8. The Oracle type must be
951        /// numeric or string (excluding LOB) types.
952        : to_i8, i8);
953    define_fn_to_int!(
954        /// Gets the SQL value as i16. The Oracle type must be
955        /// numeric or string (excluding LOB) types.
956        : to_i16, i16);
957    define_fn_to_int!(
958        /// Gets the SQL value as i32. The Oracle type must be
959        /// numeric or string (excluding LOB) types.
960        : to_i32, i32);
961    define_fn_to_int!(
962        /// Gets the SQL value as isize. The Oracle type must be
963        /// numeric or string (excluding LOB) types.
964        : to_isize, isize);
965
966    /// Gets the SQL value as i64. The Oracle type must be
967    /// numeric or string (excluding LOB) types.
968    pub(crate) fn to_i64(&self) -> Result<i64> {
969        match self.native_type {
970            NativeType::Int64 => self.get_i64_unchecked(),
971            NativeType::UInt64 => Ok(self.get_u64_unchecked()?.try_into()?),
972            NativeType::Float => flt_to_int!(self.get_f32_unchecked()?, f32, i64),
973            NativeType::Double => flt_to_int!(self.get_f64_unchecked()?, f64, i64),
974            NativeType::Char => Ok(self.get_cow_str_unchecked()?.parse()?),
975            NativeType::Number => Ok(self.get_str_unchecked()?.parse()?),
976            NativeType::Clob => Ok(self.get_clob_as_string_unchecked()?.parse()?),
977            _ => self.invalid_conversion_to_rust_type("i64"),
978        }
979    }
980
981    define_fn_to_int!(
982        /// Gets the SQL value as u8. The Oracle type must be
983        /// numeric or string (excluding LOB) types.
984        : to_u8, u8);
985    define_fn_to_int!(
986        /// Gets the SQL value as u16. The Oracle type must be
987        /// numeric or string (excluding LOB) types.
988        : to_u16, u16);
989    define_fn_to_int!(
990        /// Gets the SQL value as u32. The Oracle type must be
991        /// numeric or string (excluding LOB) types.
992        : to_u32, u32);
993    define_fn_to_int!(
994        /// Gets the SQL value as usize. The Oracle type must be
995        /// numeric or string (excluding LOB) types.
996        : to_usize, usize);
997
998    /// Gets the SQL value as u64. The Oracle type must be
999    /// numeric or string (excluding LOB) types.
1000    pub(crate) fn to_u64(&self) -> Result<u64> {
1001        match self.native_type {
1002            NativeType::Int64 => Ok(self.get_i64_unchecked()?.try_into()?),
1003            NativeType::UInt64 => self.get_u64_unchecked(),
1004            NativeType::Float => flt_to_int!(self.get_f32_unchecked()?, f32, u64),
1005            NativeType::Double => flt_to_int!(self.get_f64_unchecked()?, f64, u64),
1006            NativeType::Char => Ok(self.get_cow_str_unchecked()?.parse()?),
1007            NativeType::Number => Ok(self.get_str_unchecked()?.parse()?),
1008            NativeType::Clob => Ok(self.get_clob_as_string_unchecked()?.parse()?),
1009            _ => self.invalid_conversion_to_rust_type("u64"),
1010        }
1011    }
1012
1013    /// Gets the SQL value as f32. The Oracle type must be
1014    /// numeric or string (excluding LOB) types.
1015    pub(crate) fn to_f32(&self) -> Result<f32> {
1016        match self.native_type {
1017            NativeType::Int64 => Ok(self.get_i64_unchecked()? as f32),
1018            NativeType::UInt64 => Ok(self.get_u64_unchecked()? as f32),
1019            NativeType::Float => self.get_f32_unchecked(),
1020            NativeType::Double => Ok(self.get_f64_unchecked()? as f32),
1021            NativeType::Char => Ok(self.get_cow_str_unchecked()?.parse()?),
1022            NativeType::Number => Ok(self.get_str_unchecked()?.parse()?),
1023            NativeType::Clob => Ok(self.get_clob_as_string_unchecked()?.parse()?),
1024            _ => self.invalid_conversion_to_rust_type("f32"),
1025        }
1026    }
1027
1028    /// Gets the SQL value as f64. The Oracle type must be
1029    /// numeric or string (excluding LOB) types.
1030    pub(crate) fn to_f64(&self) -> Result<f64> {
1031        match self.native_type {
1032            NativeType::Int64 => Ok(self.get_i64_unchecked()? as f64),
1033            NativeType::UInt64 => Ok(self.get_u64_unchecked()? as f64),
1034            NativeType::Float => Ok(self.get_f32_unchecked()? as f64),
1035            NativeType::Double => self.get_f64_unchecked(),
1036            NativeType::Char => Ok(self.get_cow_str_unchecked()?.parse()?),
1037            NativeType::Number => Ok(self.get_str_unchecked()?.parse()?),
1038            NativeType::Clob => Ok(self.get_clob_as_string_unchecked()?.parse()?),
1039            _ => self.invalid_conversion_to_rust_type("f64"),
1040        }
1041    }
1042
1043    /// Gets the SQL value as string. ...
1044    pub(crate) fn to_string(&self) -> Result<String> {
1045        match self.native_type {
1046            NativeType::Int64 => Ok(self.get_i64_unchecked()?.to_string()),
1047            NativeType::UInt64 => Ok(self.get_u64_unchecked()?.to_string()),
1048            NativeType::Float => Ok(self.get_f32_unchecked()?.to_string()),
1049            NativeType::Double => Ok(self.get_f64_unchecked()?.to_string()),
1050            NativeType::Char => Ok(self.get_cow_str_unchecked()?.into()),
1051            NativeType::Number => Ok(self.get_str_unchecked()?.into()),
1052            NativeType::Raw => self.get_raw_as_hex_string_unchecked(),
1053            NativeType::Timestamp => Ok(self.get_timestamp_unchecked()?.to_string()),
1054            NativeType::IntervalDS => Ok(self.get_interval_ds_unchecked()?.to_string()),
1055            NativeType::IntervalYM => Ok(self.get_interval_ym_unchecked()?.to_string()),
1056            NativeType::Clob => self.get_clob_as_string_unchecked(),
1057            NativeType::Blob => self.get_blob_as_hex_string_unchecked(),
1058            NativeType::Object(ref objtype) => {
1059                if objtype.is_collection() {
1060                    Ok(self.get_collection_unchecked(objtype)?.to_string())
1061                } else {
1062                    Ok(self.get_object_unchecked(objtype)?.to_string())
1063                }
1064            }
1065            NativeType::Boolean => Ok(if self.get_bool_unchecked()? {
1066                "TRUE".into()
1067            } else {
1068                "FALSE".into()
1069            }),
1070            NativeType::Rowid => self.get_rowid_as_string_unchecked(),
1071            NativeType::Stmt => self.invalid_conversion_to_rust_type("string"),
1072            NativeType::Vector => Ok(match unsafe { self.get_vec_ref_unchecked()? } {
1073                VecRef::Float32(slice) => format!("{:?}", slice),
1074                VecRef::Float64(slice) => format!("{:?}", slice),
1075                VecRef::Int8(slice) => format!("{:?}", slice),
1076                VecRef::Binary(slice) => format!("{:?}", slice),
1077            }),
1078        }
1079    }
1080
1081    /// Gets the SQL value as Vec\<u8>. ...
1082    pub(crate) fn to_bytes(&self) -> Result<Vec<u8>> {
1083        match self.native_type {
1084            NativeType::Raw => self.get_raw_unchecked(),
1085            NativeType::Blob => self.get_blob_unchecked(),
1086            NativeType::Char => Ok(parse_str_into_raw(&self.get_cow_str_unchecked()?)?),
1087            NativeType::Clob => Ok(parse_str_into_raw(&self.get_clob_as_string_unchecked()?)?),
1088            NativeType::Vector
1089                if self.vector_format == VecFmt::Binary
1090                    || self.vector_format == VecFmt::Flexible =>
1091            unsafe {
1092                let vec_ref = self.get_vec_ref_unchecked()?;
1093                match vec_ref {
1094                    VecRef::Binary(slice) => Ok(slice.to_vec()),
1095                    _ => Err(Error::invalid_type_conversion(
1096                        vec_ref.oracle_type().to_string(),
1097                        "Vec<u8>",
1098                    )),
1099                }
1100            },
1101            _ => self.invalid_conversion_to_rust_type("raw"),
1102        }
1103    }
1104
1105    pub(crate) fn to_f32_vec(&self) -> Result<Vec<f32>> {
1106        match self.native_type {
1107            NativeType::Vector
1108                if self.vector_format == VecFmt::Float32
1109                    || self.vector_format == VecFmt::Flexible =>
1110            unsafe {
1111                let vec_ref = self.get_vec_ref_unchecked()?;
1112                match vec_ref {
1113                    VecRef::Float32(slice) => Ok(slice.to_vec()),
1114                    _ => Err(Error::invalid_type_conversion(
1115                        vec_ref.oracle_type().to_string(),
1116                        "Vec<f32>",
1117                    )),
1118                }
1119            },
1120            _ => self.invalid_conversion_to_rust_type("Vec<f32>"),
1121        }
1122    }
1123
1124    pub(crate) fn to_f64_vec(&self) -> Result<Vec<f64>> {
1125        match self.native_type {
1126            NativeType::Vector
1127                if self.vector_format == VecFmt::Float64
1128                    || self.vector_format == VecFmt::Flexible =>
1129            unsafe {
1130                let vec_ref = self.get_vec_ref_unchecked()?;
1131                match vec_ref {
1132                    VecRef::Float64(slice) => Ok(slice.to_vec()),
1133                    _ => Err(Error::invalid_type_conversion(
1134                        vec_ref.oracle_type().to_string(),
1135                        "Vec<f64>",
1136                    )),
1137                }
1138            },
1139            _ => self.invalid_conversion_to_rust_type("Vec<f64>"),
1140        }
1141    }
1142
1143    pub(crate) fn to_i8_vec(&self) -> Result<Vec<i8>> {
1144        match self.native_type {
1145            NativeType::Vector
1146                if self.vector_format == VecFmt::Int8 || self.vector_format == VecFmt::Flexible =>
1147            unsafe {
1148                let vec_ref = self.get_vec_ref_unchecked()?;
1149                match vec_ref {
1150                    VecRef::Int8(slice) => Ok(slice.to_vec()),
1151                    _ => Err(Error::invalid_type_conversion(
1152                        vec_ref.oracle_type().to_string(),
1153                        "Vec<i8>",
1154                    )),
1155                }
1156            },
1157            _ => self.invalid_conversion_to_rust_type("Vec<i8>"),
1158        }
1159    }
1160
1161    /// Gets the SQL value as Timestamp. The Oracle type must be
1162    /// `DATE`, `TIMESTAMP`, or `TIMESTAMP WITH TIME ZONE`.
1163    pub(crate) fn to_timestamp(&self) -> Result<Timestamp> {
1164        match self.native_type {
1165            NativeType::Timestamp => self.get_timestamp_unchecked(),
1166            NativeType::Char => Ok(self.get_cow_str_unchecked()?.parse()?),
1167            NativeType::Clob => Ok(self.get_clob_as_string_unchecked()?.parse()?),
1168            _ => self.invalid_conversion_to_rust_type("Timestamp"),
1169        }
1170    }
1171
1172    /// Gets the SQL value as IntervalDS. The Oracle type must be
1173    /// `INTERVAL DAY TO SECOND`.
1174    pub(crate) fn to_interval_ds(&self) -> Result<IntervalDS> {
1175        match self.native_type {
1176            NativeType::IntervalDS => self.get_interval_ds_unchecked(),
1177            NativeType::Char => Ok(self.get_cow_str_unchecked()?.parse()?),
1178            NativeType::Clob => Ok(self.get_clob_as_string_unchecked()?.parse()?),
1179            _ => self.invalid_conversion_to_rust_type("IntervalDS"),
1180        }
1181    }
1182
1183    /// Gets the SQL value as IntervalYM. The Oracle type must be
1184    /// `INTERVAL YEAR TO MONTH`.
1185    pub(crate) fn to_interval_ym(&self) -> Result<IntervalYM> {
1186        match self.native_type {
1187            NativeType::IntervalYM => self.get_interval_ym_unchecked(),
1188            NativeType::Char => Ok(self.get_cow_str_unchecked()?.parse()?),
1189            NativeType::Clob => Ok(self.get_clob_as_string_unchecked()?.parse()?),
1190            _ => self.invalid_conversion_to_rust_type("IntervalYM"),
1191        }
1192    }
1193
1194    pub(crate) fn to_collection(&self) -> Result<Collection> {
1195        match self.native_type {
1196            NativeType::Object(ref objtype) => {
1197                if objtype.is_collection() {
1198                    self.get_collection_unchecked(objtype)
1199                } else {
1200                    self.invalid_conversion_to_rust_type("Collection")
1201                }
1202            }
1203            _ => self.invalid_conversion_to_rust_type("Collection"),
1204        }
1205    }
1206
1207    pub(crate) fn to_object(&self) -> Result<Object> {
1208        match self.native_type {
1209            NativeType::Object(ref objtype) => {
1210                if !objtype.is_collection() {
1211                    self.get_object_unchecked(objtype)
1212                } else {
1213                    self.invalid_conversion_to_rust_type("Object")
1214                }
1215            }
1216            _ => self.invalid_conversion_to_rust_type("Object"),
1217        }
1218    }
1219
1220    /// Gets the SQL value as bool. The Oracle type must be
1221    /// `BOOLEAN`(PL/SQL only).
1222    pub(crate) fn to_bool(&self) -> Result<bool> {
1223        match self.native_type {
1224            NativeType::Boolean => self.get_bool_unchecked(),
1225            _ => self.invalid_conversion_to_rust_type("bool"),
1226        }
1227    }
1228
1229    pub(crate) fn to_bfile(&self) -> Result<Bfile> {
1230        if self.oratype == Some(OracleType::BFILE) {
1231            match self.native_type {
1232                NativeType::Blob => return Bfile::from_raw(self.ctxt(), self.get_lob_unchecked()?),
1233                NativeType::Raw => return self.lob_locator_is_not_set("Bfile"),
1234                _ => (),
1235            }
1236        }
1237        self.invalid_conversion_to_rust_type("Bfile")
1238    }
1239
1240    pub(crate) fn to_blob(&self) -> Result<Blob> {
1241        if self.oratype == Some(OracleType::BLOB) {
1242            match self.native_type {
1243                NativeType::Blob => return Blob::from_raw(self.ctxt(), self.get_lob_unchecked()?),
1244                NativeType::Raw => return self.lob_locator_is_not_set("Blob"),
1245                _ => (),
1246            }
1247        }
1248        self.invalid_conversion_to_rust_type("Blob")
1249    }
1250
1251    pub(crate) fn to_clob(&self) -> Result<Clob> {
1252        if self.oratype == Some(OracleType::CLOB) {
1253            match self.native_type {
1254                NativeType::Clob => return Clob::from_raw(self.ctxt(), self.get_lob_unchecked()?),
1255                NativeType::Raw => return self.lob_locator_is_not_set("Clob"),
1256                _ => (),
1257            }
1258        }
1259        self.invalid_conversion_to_rust_type("Clob")
1260    }
1261
1262    pub(crate) fn to_nclob(&self) -> Result<Nclob> {
1263        if self.oratype == Some(OracleType::NCLOB) {
1264            match self.native_type {
1265                NativeType::Clob => return Nclob::from_raw(self.ctxt(), self.get_lob_unchecked()?),
1266                NativeType::Raw => return self.lob_locator_is_not_set("Nclob"),
1267                _ => (),
1268            }
1269        }
1270        self.invalid_conversion_to_rust_type("Nclob")
1271    }
1272
1273    pub(crate) fn to_ref_cursor(&self) -> Result<RefCursor> {
1274        match self.native_type {
1275            NativeType::Stmt => Ok(RefCursor::from_handle(
1276                self.conn.clone(),
1277                DpiStmt::with_add_ref(self.get_stmt_unchecked()?),
1278                self.query_params.clone(),
1279            )?),
1280            _ => self.invalid_conversion_to_rust_type("RefCursor"),
1281        }
1282    }
1283
1284    pub(crate) fn to_vector(&self) -> Result<Vector> {
1285        let var = if let DpiData::Var(var) = &self.data {
1286            var.clone()
1287        } else {
1288            return Err(Error::internal_error("dpVar handle isn't initialized"));
1289        };
1290        match self.native_type {
1291            NativeType::Vector => unsafe {
1292                let vec_ref = self.get_vec_ref_unchecked()?;
1293                Vector::new(vec_ref, var)
1294            },
1295            _ => self.invalid_conversion_to_rust_type("Vector"),
1296        }
1297    }
1298
1299    //
1300    // set_TYPE methods
1301    //
1302
1303    define_fn_set_int!(
1304        /// Sets i8 to the SQL value. The Oracle type must be
1305        /// numeric or string (excluding LOB) types.
1306        : set_i8, i8);
1307    define_fn_set_int!(
1308        /// Sets i16 to the SQL value. The Oracle type must be
1309        /// numeric or string (excluding LOB) types.
1310        : set_i16, i16);
1311    define_fn_set_int!(
1312        /// Sets i32 to the SQL value. The Oracle type must be
1313        /// numeric or string (excluding LOB) types.
1314        : set_i32, i32);
1315    define_fn_set_int!(
1316        /// Sets i64 to the SQL value. The Oracle type must be
1317        /// numeric or string (excluding LOB) types.
1318        : set_i64, i64);
1319    define_fn_set_int!(
1320        /// Sets isize to the SQL value. The Oracle type must be
1321        /// numeric or string (excluding LOB) types.
1322        : set_isize, isize);
1323    define_fn_set_int!(
1324        /// Sets u8 to the SQL value. The Oracle type must be
1325        /// numeric or string (excluding LOB) types.
1326        : set_u8, u8);
1327    define_fn_set_int!(
1328        /// Sets u16 to the SQL value. The Oracle type must be
1329        /// numeric or string (excluding LOB) types.
1330        : set_u16, u16);
1331    define_fn_set_int!(
1332        /// Sets u32 to the SQL value. The Oracle type must be
1333        /// numeric or string (excluding LOB) types.
1334        : set_u32, u32);
1335    define_fn_set_int!(
1336        /// Sets u64 to the SQL value. The Oracle type must be
1337        /// numeric or string (excluding LOB) types.
1338        : set_u64, u64);
1339    define_fn_set_int!(
1340        /// Sets usize to the SQL value. The Oracle type must be
1341        /// numeric or string (excluding LOB) types.
1342        : set_usize, usize);
1343    define_fn_set_int!(
1344        /// Sets f32 to the SQL value. The Oracle type must be
1345        /// numeric or string (excluding LOB) types.
1346        : set_f32, f32);
1347    define_fn_set_int!(
1348        /// Sets f64 to the SQL value. The Oracle type must be
1349        /// numeric or string (excluding LOB) types.
1350        : set_f64, f64);
1351
1352    /// Sets &str to the SQL value. ...
1353    pub(crate) fn set_string(&mut self, val: &str) -> Result<()> {
1354        match self.native_type {
1355            NativeType::Int64 => self.set_i64_unchecked(val.parse()?),
1356            NativeType::UInt64 => self.set_u64_unchecked(val.parse()?),
1357            NativeType::Float => self.set_f32_unchecked(val.parse()?),
1358            NativeType::Double => self.set_f64_unchecked(val.parse()?),
1359            NativeType::Char => self.set_string_unchecked(val),
1360            NativeType::Number => {
1361                check_number_format(val)?;
1362                self.set_string_unchecked(val)
1363            }
1364            NativeType::Raw => self.set_raw_unchecked(&parse_str_into_raw(val)?),
1365            NativeType::Timestamp => self.set_timestamp_unchecked(&val.parse()?),
1366            NativeType::IntervalDS => self.set_interval_ds_unchecked(&val.parse()?),
1367            NativeType::IntervalYM => self.set_interval_ym_unchecked(&val.parse()?),
1368            NativeType::Clob => self.set_string_to_clob_unchecked(val),
1369            NativeType::Blob => self.set_raw_to_blob_unchecked(&parse_str_into_raw(val)?),
1370            _ => self.invalid_conversion_from_rust_type("&str"),
1371        }
1372    }
1373
1374    /// Sets &[u8] to the SQL value. ...
1375    pub(crate) fn set_bytes(&mut self, val: &[u8]) -> Result<()> {
1376        match self.native_type {
1377            NativeType::Raw => self.set_raw_unchecked(val),
1378            NativeType::Blob => self.set_raw_to_blob_unchecked(val),
1379            _ => self.invalid_conversion_from_rust_type("&[u8]"),
1380        }
1381    }
1382
1383    /// Sets Timestamp to the SQL value. The Oracle type must be
1384    /// `DATE`, `TIMESTAMP`, or `TIMESTAMP WITH TIME ZONE`.
1385    pub(crate) fn set_timestamp(&mut self, val: &Timestamp) -> Result<()> {
1386        match self.native_type {
1387            NativeType::Timestamp => self.set_timestamp_unchecked(val),
1388            _ => self.invalid_conversion_from_rust_type("Timestamp"),
1389        }
1390    }
1391
1392    /// Sets IntervalDS to the SQL value. The Oracle type must be
1393    /// `INTERVAL DAY TO SECOND`.
1394    pub(crate) fn set_interval_ds(&mut self, val: &IntervalDS) -> Result<()> {
1395        match self.native_type {
1396            NativeType::IntervalDS => self.set_interval_ds_unchecked(val),
1397            _ => self.invalid_conversion_from_rust_type("IntervalDS"),
1398        }
1399    }
1400
1401    /// Sets IntervalYM to the SQL value. The Oracle type must be
1402    /// `INTERVAL YEAR TO MONTH`.
1403    pub(crate) fn set_interval_ym(&mut self, val: &IntervalYM) -> Result<()> {
1404        match self.native_type {
1405            NativeType::IntervalYM => self.set_interval_ym_unchecked(val),
1406            _ => self.invalid_conversion_from_rust_type("IntervalYM"),
1407        }
1408    }
1409
1410    /// Sets Object to the Sql Value
1411    pub(crate) fn set_object(&mut self, val: &Object) -> Result<()> {
1412        match self.native_type {
1413            NativeType::Object(_) => self.set_object_unchecked(&val.handle),
1414            _ => self.invalid_conversion_from_rust_type("Object"),
1415        }
1416    }
1417
1418    /// Sets Collection to the Sql Value
1419    pub(crate) fn set_collection(&mut self, val: &Collection) -> Result<()> {
1420        match self.native_type {
1421            NativeType::Object(_) => self.set_object_unchecked(&val.handle),
1422            _ => self.invalid_conversion_from_rust_type("Collection"),
1423        }
1424    }
1425
1426    /// Sets boolean to the SQL value. The Oracle type must be
1427    /// `BOOLEAN`(PL/SQL only).
1428    pub(crate) fn set_bool(&mut self, val: &bool) -> Result<()> {
1429        match self.native_type {
1430            NativeType::Boolean => self.set_bool_unchecked(*val),
1431            _ => self.invalid_conversion_from_rust_type("bool"),
1432        }
1433    }
1434
1435    pub(crate) fn set_bfile(&mut self, val: &Bfile) -> Result<()> {
1436        if self.oratype == Some(OracleType::BFILE) {
1437            match self.native_type {
1438                NativeType::Blob => return self.set_lob_unchecked(val.lob.handle),
1439                NativeType::Raw => return self.lob_locator_is_not_set("Bfile"),
1440                _ => (),
1441            }
1442        }
1443        self.invalid_conversion_from_rust_type("Bfile")
1444    }
1445
1446    pub(crate) fn set_blob(&mut self, val: &Blob) -> Result<()> {
1447        if self.oratype == Some(OracleType::BLOB) {
1448            match self.native_type {
1449                NativeType::Blob => return self.set_lob_unchecked(val.lob.handle),
1450                NativeType::Raw => return self.lob_locator_is_not_set("Blob"),
1451                _ => (),
1452            }
1453        }
1454        self.invalid_conversion_from_rust_type("Blob")
1455    }
1456
1457    pub(crate) fn set_clob(&mut self, val: &Clob) -> Result<()> {
1458        if self.oratype == Some(OracleType::CLOB) {
1459            match self.native_type {
1460                NativeType::Clob => return self.set_lob_unchecked(val.lob.handle),
1461                NativeType::Raw => return self.lob_locator_is_not_set("Clob"),
1462                _ => (),
1463            }
1464        }
1465        self.invalid_conversion_from_rust_type("Clob")
1466    }
1467
1468    pub(crate) fn set_nclob(&mut self, val: &Nclob) -> Result<()> {
1469        if self.oratype == Some(OracleType::NCLOB) {
1470            match self.native_type {
1471                NativeType::Clob => return self.set_lob_unchecked(val.lob.handle),
1472                NativeType::Raw => return self.lob_locator_is_not_set("Nclob"),
1473                _ => (),
1474            }
1475        }
1476        self.invalid_conversion_from_rust_type("Nclob")
1477    }
1478
1479    pub(crate) fn set_vec_ref(&mut self, val: &VecRef, typename: &str) -> Result<()> {
1480        match self.native_type {
1481            NativeType::Vector => self.set_vec_ref_unchecked(val),
1482            _ => self.invalid_conversion_from_rust_type(typename),
1483        }
1484    }
1485
1486    pub(crate) fn clone_with_narrow_lifetime(&self) -> Result<SqlValue> {
1487        Ok(SqlValue {
1488            conn: self.conn.clone(),
1489            data: DpiData::Data(self.data()?),
1490            native_type: self.native_type.clone(),
1491            oratype: self.oratype.clone(),
1492            array_size: self.array_size,
1493            buffer_row_index: BufferRowIndex::Owned(0),
1494            keep_bytes: Vec::new(),
1495            keep_dpiobj: DpiObject::null(),
1496            lob_bind_type: self.lob_bind_type,
1497            query_params: self.query_params.clone(),
1498            vector_format: self.vector_format,
1499        })
1500    }
1501}
1502
1503impl AssertSend for SqlValue<'_> {}
1504
1505impl fmt::Display for SqlValue<'_> {
1506    /// Formats any SQL value to string using the given formatter.
1507    /// Note that both a null value and a string `NULL` are formatted
1508    /// as `NULL`.
1509    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1510        if self.oratype.is_some() {
1511            match self.to_string() {
1512                Ok(s) => write!(f, "{}", s),
1513                Err(err) if err.kind() == ErrorKind::NullValue => write!(f, "NULL"),
1514                Err(err) => write!(f, "{}", err),
1515            }
1516        } else {
1517            write!(f, "uninitialized SQL value")
1518        }
1519    }
1520}
1521
1522impl fmt::Debug for SqlValue<'_> {
1523    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1524        if let Some(ref oratype) = self.oratype {
1525            write!(f, "SqlValue {{ val: ")?;
1526            match self.to_string() {
1527                Ok(s) => match self.native_type {
1528                    NativeType::Char | NativeType::Raw | NativeType::Clob | NativeType::Blob => {
1529                        write!(f, "{:?}", s)
1530                    }
1531                    _ => write!(f, "{}", s),
1532                },
1533                Err(err) if err.kind() == ErrorKind::NullValue => write!(f, "NULL"),
1534                Err(err) => write!(f, "{}", err),
1535            }?;
1536            write!(
1537                f,
1538                ", type: {}, idx/size: {}/{})",
1539                oratype,
1540                self.buffer_row_index(),
1541                self.array_size
1542            )
1543        } else {
1544            write!(f, "SqlValue {{ uninitialized }}")
1545        }
1546    }
1547}