Skip to main content

sqlx_core_oldapi/odbc/
value.rs

1use crate::error::Error;
2use crate::odbc::{Odbc, OdbcBatch, OdbcTypeInfo};
3use crate::type_info::TypeInfo;
4use crate::value::{Value, ValueRef};
5use odbc_api::buffers::{AnyColumnBufferSlice, BufferDesc, NullableSlice};
6use odbc_api::handles::CDataMut;
7use odbc_api::parameter::CElement;
8use odbc_api::{DataType, Nullable};
9use std::borrow::Cow;
10use std::sync::Arc;
11
12/// Enum containing owned column data for all supported ODBC types
13#[derive(Debug, Clone)]
14pub enum OdbcValueVec {
15    // Integer types
16    TinyInt(Vec<i8>),
17    SmallInt(Vec<i16>),
18    Integer(Vec<i32>),
19    BigInt(Vec<i64>),
20
21    // Floating point types
22    Real(Vec<f32>),
23    Double(Vec<f64>),
24
25    // Bit type
26    Bit(Vec<bool>),
27
28    // Text types (inherently nullable in ODBC)
29    Text(Vec<String>),
30
31    // Binary types (inherently nullable in ODBC)
32    Binary(Vec<Vec<u8>>),
33
34    // Date/Time types
35    Date(Vec<odbc_api::sys::Date>),
36    Time(Vec<odbc_api::sys::Time>),
37    Timestamp(Vec<odbc_api::sys::Timestamp>),
38}
39
40impl OdbcValueVec {
41    pub(crate) fn with_capacity_for_type(data_type: DataType, capacity: usize) -> Self {
42        match data_type {
43            DataType::TinyInt => OdbcValueVec::TinyInt(Vec::with_capacity(capacity)),
44            DataType::SmallInt => OdbcValueVec::SmallInt(Vec::with_capacity(capacity)),
45            // Some drivers report INTEGER even when the value range is 64-bit.
46            DataType::Integer | DataType::BigInt => {
47                OdbcValueVec::BigInt(Vec::with_capacity(capacity))
48            }
49            DataType::Real => OdbcValueVec::Real(Vec::with_capacity(capacity)),
50            DataType::Float { .. } | DataType::Double => {
51                OdbcValueVec::Double(Vec::with_capacity(capacity))
52            }
53            DataType::Bit => OdbcValueVec::Bit(Vec::with_capacity(capacity)),
54            DataType::Date => OdbcValueVec::Date(Vec::with_capacity(capacity)),
55            DataType::Time { .. } => OdbcValueVec::Time(Vec::with_capacity(capacity)),
56            DataType::Timestamp { .. } => OdbcValueVec::Timestamp(Vec::with_capacity(capacity)),
57            DataType::Binary { .. }
58            | DataType::Varbinary { .. }
59            | DataType::LongVarbinary { .. } => OdbcValueVec::Binary(Vec::with_capacity(capacity)),
60            _ => OdbcValueVec::Text(Vec::with_capacity(capacity)),
61        }
62    }
63
64    pub(crate) fn push_from_cursor_row(
65        &mut self,
66        cursor_row: &mut odbc_api::CursorRow<'_>,
67        col_index: u16,
68        nulls: &mut Vec<bool>,
69    ) -> Result<(), odbc_api::Error> {
70        match self {
71            OdbcValueVec::TinyInt(v) => push_get_data(cursor_row, col_index, v, nulls),
72            OdbcValueVec::SmallInt(v) => push_get_data(cursor_row, col_index, v, nulls),
73            OdbcValueVec::Integer(v) => push_get_data(cursor_row, col_index, v, nulls),
74            OdbcValueVec::BigInt(v) => push_get_data(cursor_row, col_index, v, nulls),
75            OdbcValueVec::Real(v) => push_get_data(cursor_row, col_index, v, nulls),
76            OdbcValueVec::Double(v) => push_get_data(cursor_row, col_index, v, nulls),
77            OdbcValueVec::Bit(v) => push_bit(cursor_row, col_index, v, nulls),
78            OdbcValueVec::Date(v) => push_get_data(cursor_row, col_index, v, nulls),
79            OdbcValueVec::Time(v) => push_get_data(cursor_row, col_index, v, nulls),
80            OdbcValueVec::Timestamp(v) => push_get_data(cursor_row, col_index, v, nulls),
81            OdbcValueVec::Binary(v) => push_binary(cursor_row, col_index, v, nulls),
82            OdbcValueVec::Text(v) => push_text(cursor_row, col_index, v, nulls),
83        }
84    }
85}
86
87fn push_get_data<T: Default + Copy + CElement + CDataMut>(
88    cursor_row: &mut odbc_api::CursorRow<'_>,
89    col_index: u16,
90    vec: &mut Vec<T>,
91    nulls: &mut Vec<bool>,
92) -> Result<(), odbc_api::Error>
93where
94    Nullable<T>: CElement + CDataMut,
95{
96    let mut tmp = Nullable::null();
97    cursor_row.get_data(col_index, &mut tmp)?;
98    let option = tmp.into_opt();
99    nulls.push(option.is_none());
100    vec.push(option.unwrap_or_default());
101    Ok(())
102}
103
104fn push_binary(
105    cursor_row: &mut odbc_api::CursorRow<'_>,
106    col_index: u16,
107    vec: &mut Vec<Vec<u8>>,
108    nulls: &mut Vec<bool>,
109) -> Result<(), odbc_api::Error> {
110    let mut buf = Vec::new();
111    let is_not_null = cursor_row.get_binary(col_index, &mut buf)?;
112    nulls.push(!is_not_null);
113    vec.push(buf);
114    Ok(())
115}
116
117fn push_text(
118    cursor_row: &mut odbc_api::CursorRow<'_>,
119    col_index: u16,
120    vec: &mut Vec<String>,
121    nulls: &mut Vec<bool>,
122) -> Result<(), odbc_api::Error> {
123    let mut buf = Vec::<u16>::new();
124    let is_not_null = cursor_row.get_wide_text(col_index, &mut buf)?;
125    vec.push(String::from_utf16_lossy(&buf).to_string());
126    nulls.push(!is_not_null);
127    Ok(())
128}
129
130fn push_bit(
131    cursor_row: &mut odbc_api::CursorRow<'_>,
132    col_index: u16,
133    vec: &mut Vec<bool>,
134    nulls: &mut Vec<bool>,
135) -> Result<(), odbc_api::Error> {
136    let mut bit_val = Nullable::<odbc_api::Bit>::null();
137    cursor_row.get_data(col_index, &mut bit_val)?;
138    match bit_val.into_opt() {
139        Some(bit) => {
140            nulls.push(false);
141            vec.push(bit.as_bool());
142        }
143        None => {
144            nulls.push(true);
145            vec.push(false);
146        }
147    }
148    Ok(())
149}
150
151/// Container for column data with type information
152#[derive(Debug, Clone)]
153pub struct ColumnData {
154    pub values: OdbcValueVec,
155    pub type_info: OdbcTypeInfo,
156    pub nulls: Vec<bool>,
157}
158
159#[derive(Debug)]
160pub struct OdbcValueRef<'r> {
161    pub(crate) batch: &'r OdbcBatch,
162    pub(crate) row_index: usize,
163    pub(crate) column_index: usize,
164}
165
166#[derive(Debug, Clone)]
167pub struct OdbcValue {
168    pub(crate) batch: Arc<OdbcBatch>,
169    pub(crate) row_index: usize,
170    pub(crate) column_index: usize,
171}
172
173impl<'r> ValueRef<'r> for OdbcValueRef<'r> {
174    type Database = Odbc;
175
176    fn to_owned(&self) -> OdbcValue {
177        OdbcValue {
178            batch: Arc::new(self.batch.clone()),
179            row_index: self.row_index,
180            column_index: self.column_index,
181        }
182    }
183
184    fn type_info(&self) -> Cow<'_, OdbcTypeInfo> {
185        Cow::Borrowed(&self.batch.column_data[self.column_index].type_info)
186    }
187
188    fn is_null(&self) -> bool {
189        value_vec_is_null(&self.batch.column_data[self.column_index], self.row_index)
190    }
191}
192
193impl Value for OdbcValue {
194    type Database = Odbc;
195
196    fn as_ref(&self) -> OdbcValueRef<'_> {
197        OdbcValueRef {
198            batch: &self.batch,
199            row_index: self.row_index,
200            column_index: self.column_index,
201        }
202    }
203
204    fn type_info(&self) -> Cow<'_, OdbcTypeInfo> {
205        Cow::Borrowed(&self.batch.column_data[self.column_index].type_info)
206    }
207
208    fn is_null(&self) -> bool {
209        value_vec_is_null(&self.batch.column_data[self.column_index], self.row_index)
210    }
211}
212
213/// Utility methods for OdbcValue
214impl OdbcValue {
215    /// Create a new OdbcValue from batch, row index, and column index
216    pub fn new(batch: Arc<OdbcBatch>, row_index: usize, column_index: usize) -> Self {
217        Self {
218            batch,
219            row_index,
220            column_index,
221        }
222    }
223
224    /// Get the raw value from the column data
225    pub fn get_raw(&self) -> Option<OdbcValueType> {
226        value_vec_get_raw(&self.batch.column_data[self.column_index], self.row_index)
227    }
228
229    /// Try to get the value as i64
230    pub fn as_int<T: TryFromInt>(&self) -> Option<T> {
231        value_vec_int(&self.batch.column_data[self.column_index], self.row_index)
232    }
233
234    /// Try to get the value as f64
235    pub fn as_f64(&self) -> Option<f64> {
236        value_vec_float(&self.batch.column_data[self.column_index], self.row_index)
237    }
238
239    /// Try to get the value as string
240    pub fn as_str(&self) -> Option<Cow<'_, str>> {
241        value_vec_text(&self.batch.column_data[self.column_index], self.row_index)
242            .map(Cow::Borrowed)
243    }
244
245    /// Try to get the value as bytes
246    pub fn as_bytes(&self) -> Option<Cow<'_, [u8]>> {
247        value_vec_blob(&self.batch.column_data[self.column_index], self.row_index)
248            .map(Cow::Borrowed)
249    }
250}
251
252/// Utility methods for OdbcValueRef
253impl<'r> OdbcValueRef<'r> {
254    /// Create a new OdbcValueRef from batch, row index, and column index
255    pub fn new(batch: &'r OdbcBatch, row_index: usize, column_index: usize) -> Self {
256        Self {
257            batch,
258            row_index,
259            column_index,
260        }
261    }
262
263    /// Get the raw value from the column data
264    pub fn get_raw(&self) -> Option<OdbcValueType> {
265        value_vec_get_raw(&self.batch.column_data[self.column_index], self.row_index)
266    }
267
268    /// Try to get the value as i64
269    pub fn int<T: TryFromInt>(&self) -> Option<T> {
270        value_vec_int(&self.batch.column_data[self.column_index], self.row_index)
271    }
272
273    pub fn try_int<T: TryFromInt + crate::types::Type<Odbc>>(&self) -> crate::error::Result<T> {
274        self.int::<T>().ok_or_else(|| {
275            crate::error::Error::Decode(Box::new(crate::error::MismatchedTypeError {
276                rust_type: std::any::type_name::<T>().to_string(),
277                rust_sql_type: T::type_info().name().to_string(),
278                sql_type: self.batch.column_data[self.column_index]
279                    .type_info
280                    .name()
281                    .to_string(),
282                source: Some(format!("ODBC: cannot decode {:?}", self).into()),
283            }))
284        })
285    }
286
287    pub fn try_float<T: TryFromFloat + crate::types::Type<Odbc>>(&self) -> crate::error::Result<T> {
288        self.float::<T>().ok_or_else(|| {
289            crate::error::Error::Decode(Box::new(crate::error::MismatchedTypeError {
290                rust_type: std::any::type_name::<T>().to_string(),
291                rust_sql_type: T::type_info().name().to_string(),
292                sql_type: self.batch.column_data[self.column_index]
293                    .type_info
294                    .name()
295                    .to_string(),
296                source: Some(format!("ODBC: cannot decode {:?}", self).into()),
297            }))
298        })
299    }
300
301    /// Try to get the value as f64
302    pub fn float<T: TryFromFloat>(&self) -> Option<T> {
303        value_vec_float(&self.batch.column_data[self.column_index], self.row_index)
304    }
305
306    /// Try to get the value as string slice
307    pub fn text(&self) -> Option<&'r str> {
308        value_vec_text(&self.batch.column_data[self.column_index], self.row_index)
309    }
310
311    /// Try to get the value as binary slice
312    pub fn blob(&self) -> Option<&'r [u8]> {
313        value_vec_blob(&self.batch.column_data[self.column_index], self.row_index)
314    }
315
316    /// Try to get the raw ODBC Date value
317    pub fn date(&self) -> Option<odbc_api::sys::Date> {
318        if self.is_null() {
319            None
320        } else {
321            match &self.batch.column_data[self.column_index].values {
322                OdbcValueVec::Date(raw_values) => raw_values.get(self.row_index).copied(),
323                _ => None,
324            }
325        }
326    }
327
328    /// Try to get the raw ODBC Time value
329    pub fn time(&self) -> Option<odbc_api::sys::Time> {
330        if self.is_null() {
331            None
332        } else {
333            match &self.batch.column_data[self.column_index].values {
334                OdbcValueVec::Time(raw_values) => raw_values.get(self.row_index).copied(),
335                _ => None,
336            }
337        }
338    }
339
340    /// Try to get the raw ODBC Timestamp value
341    pub fn timestamp(&self) -> Option<odbc_api::sys::Timestamp> {
342        if self.is_null() {
343            None
344        } else {
345            match &self.batch.column_data[self.column_index].values {
346                OdbcValueVec::Timestamp(raw_values) => raw_values.get(self.row_index).copied(),
347                _ => None,
348            }
349        }
350    }
351}
352
353/// Individual ODBC value type
354#[derive(Debug, Clone)]
355pub enum OdbcValueType {
356    TinyInt(i8),
357    SmallInt(i16),
358    Integer(i32),
359    BigInt(i64),
360    Real(f32),
361    Double(f64),
362    Bit(bool),
363    Text(String),
364    Binary(Vec<u8>),
365    Date(odbc_api::sys::Date),
366    Time(odbc_api::sys::Time),
367    Timestamp(odbc_api::sys::Timestamp),
368}
369
370fn handle_non_nullable_slice_with<T: Copy, U>(
371    slice: &[T],
372    constructor: fn(Vec<U>) -> OdbcValueVec,
373    convert: impl FnMut(T) -> U,
374) -> (OdbcValueVec, Vec<bool>) {
375    let values = slice.iter().copied().map(convert).collect();
376    (constructor(values), vec![false; slice.len()])
377}
378
379fn handle_nullable_slice_with<T: Copy, U: Default>(
380    slice: NullableSlice<'_, T>,
381    constructor: fn(Vec<U>) -> OdbcValueVec,
382    mut convert: impl FnMut(T) -> U,
383) -> (OdbcValueVec, Vec<bool>) {
384    let size = slice.size_hint().1.unwrap_or(0);
385    let mut values = Vec::with_capacity(size);
386    let mut nulls = Vec::with_capacity(size);
387    for opt in slice {
388        let is_null = opt.is_none();
389        values.push(opt.copied().map(&mut convert).unwrap_or_default());
390        nulls.push(is_null);
391    }
392    (constructor(values), nulls)
393}
394
395fn handle_buffer_slice<T: Copy + odbc_api::Pod, U: Default>(
396    slice: &AnyColumnBufferSlice<'_>,
397    desc: BufferDesc,
398    nullable: bool,
399    constructor: fn(Vec<U>) -> OdbcValueVec,
400    convert: impl FnMut(T) -> U,
401) -> Result<(OdbcValueVec, Vec<bool>), Error> {
402    if nullable {
403        Ok(handle_nullable_slice_with(
404            expect_slice(slice.as_nullable_slice::<T>(), desc)?,
405            constructor,
406            convert,
407        ))
408    } else {
409        Ok(handle_non_nullable_slice_with(
410            expect_slice(slice.as_slice::<T>(), desc)?,
411            constructor,
412            convert,
413        ))
414    }
415}
416
417fn buffer_slice_mismatch(desc: BufferDesc) -> Error {
418    Error::Protocol(format!(
419        "ODBC column buffer {desc:?} did not match fetched slice"
420    ))
421}
422
423fn expect_slice<T>(slice: Option<T>, desc: BufferDesc) -> Result<T, Error> {
424    slice.ok_or_else(|| buffer_slice_mismatch(desc))
425}
426
427fn handle_optional_values<T, U: Default>(
428    len: usize,
429    values: impl IntoIterator<Item = Option<T>>,
430    constructor: fn(Vec<U>) -> OdbcValueVec,
431    mut convert: impl FnMut(T) -> U,
432) -> (OdbcValueVec, Vec<bool>) {
433    let mut converted = Vec::with_capacity(len);
434    let mut nulls = Vec::with_capacity(len);
435
436    for value in values {
437        let is_null = value.is_none();
438        converted.push(value.map(&mut convert).unwrap_or_default());
439        nulls.push(is_null);
440    }
441
442    (constructor(converted), nulls)
443}
444
445/// Convert a dynamic ODBC column slice to owned values, preserving original types.
446pub(crate) fn convert_dyn_slice_to_value_vec(
447    slice: AnyColumnBufferSlice<'_>,
448    desc: BufferDesc,
449) -> Result<(OdbcValueVec, Vec<bool>), Error> {
450    Ok(match desc {
451        BufferDesc::I8 { nullable } => {
452            handle_buffer_slice(&slice, desc, nullable, OdbcValueVec::TinyInt, |value| value)?
453        }
454        BufferDesc::I16 { nullable } => {
455            handle_buffer_slice(&slice, desc, nullable, OdbcValueVec::SmallInt, |value| {
456                value
457            })?
458        }
459        BufferDesc::I32 { nullable } => {
460            handle_buffer_slice(&slice, desc, nullable, OdbcValueVec::Integer, |value| value)?
461        }
462        BufferDesc::I64 { nullable } => {
463            handle_buffer_slice(&slice, desc, nullable, OdbcValueVec::BigInt, |value| value)?
464        }
465        BufferDesc::U8 { nullable } => {
466            handle_buffer_slice::<u8, i64>(&slice, desc, nullable, OdbcValueVec::BigInt, i64::from)?
467        }
468        BufferDesc::F32 { nullable } => {
469            handle_buffer_slice(&slice, desc, nullable, OdbcValueVec::Real, |value| value)?
470        }
471        BufferDesc::F64 { nullable } => {
472            handle_buffer_slice(&slice, desc, nullable, OdbcValueVec::Double, |value| value)?
473        }
474        BufferDesc::Bit { nullable } => handle_buffer_slice(
475            &slice,
476            desc,
477            nullable,
478            OdbcValueVec::Bit,
479            |value: odbc_api::Bit| value.as_bool(),
480        )?,
481        BufferDesc::Date { nullable } => {
482            handle_buffer_slice(&slice, desc, nullable, OdbcValueVec::Date, |value| value)?
483        }
484        BufferDesc::Time { nullable } => {
485            handle_buffer_slice(&slice, desc, nullable, OdbcValueVec::Time, |value| value)?
486        }
487        BufferDesc::Timestamp { nullable } => {
488            handle_buffer_slice(&slice, desc, nullable, OdbcValueVec::Timestamp, |value| {
489                value
490            })?
491        }
492        BufferDesc::Text { .. } => {
493            let s = expect_slice(slice.as_text(), desc)?;
494            handle_optional_values(s.len(), s.iter(), OdbcValueVec::Text, |bytes| {
495                String::from_utf8_lossy(bytes).into_owned()
496            })
497        }
498        BufferDesc::WText { .. } => {
499            let s = expect_slice(slice.as_wide_text(), desc)?;
500            handle_optional_values(s.len(), s.iter(), OdbcValueVec::Text, |chars| {
501                String::from_utf16_lossy(chars.into())
502            })
503        }
504        BufferDesc::Binary { .. } => {
505            let s = expect_slice(slice.as_binary(), desc)?;
506            handle_optional_values(s.len(), s.iter(), OdbcValueVec::Binary, |bytes| {
507                bytes.to_vec()
508            })
509        }
510        BufferDesc::Numeric => {
511            return Err(Error::Protocol(format!(
512                "unsupported ODBC buffer descriptor: {desc:?}"
513            )));
514        }
515    })
516}
517
518#[cfg(test)]
519mod tests {
520    use super::*;
521
522    #[test]
523    fn converts_unsigned_tinyint_slices() {
524        let (values, nulls) =
525            handle_non_nullable_slice_with(&[0, 255], OdbcValueVec::BigInt, i64::from);
526
527        assert_eq!(nulls, vec![false, false]);
528        assert!(matches!(values, OdbcValueVec::BigInt(values) if values == vec![0, 255]));
529    }
530}
531
532fn value_vec_is_null(column_data: &ColumnData, row_index: usize) -> bool {
533    column_data.nulls.get(row_index).copied().unwrap_or(false)
534}
535
536macro_rules! impl_get_raw_arm_copy {
537    ($vec:expr, $row_index:expr, $variant:ident, $type:ty) => {
538        $vec.get($row_index).copied().map(OdbcValueType::$variant)
539    };
540}
541
542fn value_vec_get_raw(column_data: &ColumnData, row_index: usize) -> Option<OdbcValueType> {
543    if value_vec_is_null(column_data, row_index) {
544        return None;
545    }
546    match &column_data.values {
547        OdbcValueVec::TinyInt(v) => v.get(row_index).map(|&val| OdbcValueType::TinyInt(val)),
548        OdbcValueVec::SmallInt(v) => v.get(row_index).map(|&val| OdbcValueType::SmallInt(val)),
549        OdbcValueVec::Integer(v) => v.get(row_index).map(|&val| OdbcValueType::Integer(val)),
550        OdbcValueVec::BigInt(v) => v.get(row_index).map(|&val| OdbcValueType::BigInt(val)),
551        OdbcValueVec::Real(v) => v.get(row_index).map(|&val| OdbcValueType::Real(val)),
552        OdbcValueVec::Double(v) => v.get(row_index).map(|&val| OdbcValueType::Double(val)),
553        OdbcValueVec::Bit(v) => v.get(row_index).map(|&val| OdbcValueType::Bit(val)),
554        OdbcValueVec::Text(v) => v.get(row_index).cloned().map(OdbcValueType::Text),
555        OdbcValueVec::Binary(v) => v.get(row_index).cloned().map(OdbcValueType::Binary),
556        OdbcValueVec::Date(v) => impl_get_raw_arm_copy!(v, row_index, Date, odbc_api::sys::Date),
557        OdbcValueVec::Time(v) => impl_get_raw_arm_copy!(v, row_index, Time, odbc_api::sys::Time),
558        OdbcValueVec::Timestamp(v) => {
559            impl_get_raw_arm_copy!(v, row_index, Timestamp, odbc_api::sys::Timestamp)
560        }
561    }
562}
563
564pub trait TryFromInt:
565    TryFrom<u8>
566    + TryFrom<i16>
567    + TryFrom<i32>
568    + TryFrom<i64>
569    + TryFrom<i8>
570    + TryFrom<u16>
571    + TryFrom<u32>
572    + TryFrom<u64>
573    + std::str::FromStr
574{
575}
576
577impl<
578        T: TryFrom<u8>
579            + TryFrom<i16>
580            + TryFrom<i32>
581            + TryFrom<i64>
582            + TryFrom<i8>
583            + TryFrom<u16>
584            + TryFrom<u32>
585            + TryFrom<u64>
586            + std::str::FromStr,
587    > TryFromInt for T
588{
589}
590
591macro_rules! impl_int_conversion {
592    ($vec:expr, $row_index:expr, $type:ty) => {
593        <$type>::try_from(*$vec.get($row_index)?).ok()
594    };
595    ($vec:expr, $row_index:expr, $type:ty, text) => {
596        if let Some(Some(text)) = $vec.get($row_index) {
597            text.trim().parse().ok()
598        } else {
599            None
600        }
601    };
602}
603
604fn value_vec_int<T: TryFromInt>(column_data: &ColumnData, row_index: usize) -> Option<T> {
605    if value_vec_is_null(column_data, row_index) {
606        return None;
607    }
608    match &column_data.values {
609        OdbcValueVec::TinyInt(v) => impl_int_conversion!(v, row_index, T),
610        OdbcValueVec::SmallInt(v) => impl_int_conversion!(v, row_index, T),
611        OdbcValueVec::Integer(v) => impl_int_conversion!(v, row_index, T),
612        OdbcValueVec::BigInt(v) => impl_int_conversion!(v, row_index, T),
613        OdbcValueVec::Bit(v) => T::try_from(*v.get(row_index)? as u8).ok(),
614        OdbcValueVec::Text(v) => v.get(row_index).and_then(|text| text.trim().parse().ok()),
615        _ => None,
616    }
617}
618
619pub trait TryFromFloat: TryFrom<f32> + TryFrom<f64> {}
620
621impl<T: TryFrom<f32> + TryFrom<f64>> TryFromFloat for T {}
622
623macro_rules! impl_float_conversion {
624    ($vec:expr, $row_index:expr, $type:ty) => {
625        <$type>::try_from(*$vec.get($row_index)?).ok()
626    };
627}
628
629fn value_vec_float<T: TryFromFloat>(column_data: &ColumnData, row_index: usize) -> Option<T> {
630    if value_vec_is_null(column_data, row_index) {
631        return None;
632    }
633    match &column_data.values {
634        OdbcValueVec::Real(v) => impl_float_conversion!(v, row_index, T),
635        OdbcValueVec::Double(v) => impl_float_conversion!(v, row_index, T),
636        _ => None,
637    }
638}
639
640fn value_vec_text(column_data: &ColumnData, row_index: usize) -> Option<&str> {
641    if value_vec_is_null(column_data, row_index) {
642        return None;
643    }
644    match &column_data.values {
645        OdbcValueVec::Text(v) => v.get(row_index).map(|s| s.as_str()),
646        _ => None,
647    }
648}
649
650fn value_vec_blob(column_data: &ColumnData, row_index: usize) -> Option<&[u8]> {
651    if value_vec_is_null(column_data, row_index) {
652        return None;
653    }
654    match &column_data.values {
655        OdbcValueVec::Binary(v) => v.get(row_index).map(|b| b.as_slice()),
656        _ => None,
657    }
658}
659
660#[cfg(feature = "any")]
661impl<'r> From<OdbcValueRef<'r>> for crate::any::AnyValueRef<'r> {
662    fn from(value: OdbcValueRef<'r>) -> Self {
663        crate::any::AnyValueRef {
664            type_info: crate::any::AnyTypeInfo::from(
665                value.batch.column_data[value.column_index]
666                    .type_info
667                    .clone(),
668            ),
669            kind: crate::any::value::AnyValueRefKind::Odbc(value),
670        }
671    }
672}
673
674#[cfg(feature = "any")]
675impl From<OdbcValue> for crate::any::AnyValue {
676    fn from(value: OdbcValue) -> Self {
677        crate::any::AnyValue {
678            type_info: crate::any::AnyTypeInfo::from(
679                value.batch.column_data[value.column_index]
680                    .type_info
681                    .clone(),
682            ),
683            kind: crate::any::value::AnyValueKind::Odbc(value),
684        }
685    }
686}