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