1use crate::odbc::{Odbc, OdbcBatch, OdbcTypeInfo};
2use crate::type_info::TypeInfo;
3use crate::value::{Value, ValueRef};
4use odbc_api::buffers::{AnySlice, NullableSlice};
5use odbc_api::sys::NULL_DATA;
6use std::borrow::Cow;
7use std::sync::Arc;
8
9#[derive(Debug, Clone)]
11pub enum OdbcValueVec {
12 TinyInt(Vec<i8>),
14 SmallInt(Vec<i16>),
15 Integer(Vec<i32>),
16 BigInt(Vec<i64>),
17
18 Real(Vec<f32>),
20 Double(Vec<f64>),
21
22 Bit(Vec<odbc_api::Bit>),
24
25 Text(Vec<String>),
27
28 Binary(Vec<Vec<u8>>),
30
31 Date(Vec<odbc_api::sys::Date>),
33 Time(Vec<odbc_api::sys::Time>),
34 Timestamp(Vec<odbc_api::sys::Timestamp>),
35}
36
37#[derive(Debug, Clone)]
39pub struct ColumnData {
40 pub values: OdbcValueVec,
41 pub type_info: OdbcTypeInfo,
42 pub nulls: Vec<bool>,
43}
44
45#[derive(Debug)]
46pub struct OdbcValueRef<'r> {
47 pub(crate) batch: &'r OdbcBatch,
48 pub(crate) row_index: usize,
49 pub(crate) column_index: usize,
50}
51
52#[derive(Debug, Clone)]
53pub struct OdbcValue {
54 pub(crate) batch: Arc<OdbcBatch>,
55 pub(crate) row_index: usize,
56 pub(crate) column_index: usize,
57}
58
59impl<'r> ValueRef<'r> for OdbcValueRef<'r> {
60 type Database = Odbc;
61
62 fn to_owned(&self) -> OdbcValue {
63 OdbcValue {
64 batch: Arc::new(self.batch.clone()),
65 row_index: self.row_index,
66 column_index: self.column_index,
67 }
68 }
69
70 fn type_info(&self) -> Cow<'_, OdbcTypeInfo> {
71 Cow::Borrowed(&self.batch.column_data[self.column_index].type_info)
72 }
73
74 fn is_null(&self) -> bool {
75 value_vec_is_null(&self.batch.column_data[self.column_index], self.row_index)
76 }
77}
78
79impl Value for OdbcValue {
80 type Database = Odbc;
81
82 fn as_ref(&self) -> OdbcValueRef<'_> {
83 OdbcValueRef {
84 batch: &self.batch,
85 row_index: self.row_index,
86 column_index: self.column_index,
87 }
88 }
89
90 fn type_info(&self) -> Cow<'_, OdbcTypeInfo> {
91 Cow::Borrowed(&self.batch.column_data[self.column_index].type_info)
92 }
93
94 fn is_null(&self) -> bool {
95 value_vec_is_null(&self.batch.column_data[self.column_index], self.row_index)
96 }
97}
98
99impl OdbcValue {
101 pub fn new(batch: Arc<OdbcBatch>, row_index: usize, column_index: usize) -> Self {
103 Self {
104 batch,
105 row_index,
106 column_index,
107 }
108 }
109
110 pub fn get_raw(&self) -> Option<OdbcValueType> {
112 value_vec_get_raw(&self.batch.column_data[self.column_index], self.row_index)
113 }
114
115 pub fn as_int<T: TryFromInt>(&self) -> Option<T> {
117 value_vec_int(&self.batch.column_data[self.column_index], self.row_index)
118 }
119
120 pub fn as_f64(&self) -> Option<f64> {
122 value_vec_float(&self.batch.column_data[self.column_index], self.row_index)
123 }
124
125 pub fn as_str(&self) -> Option<Cow<'_, str>> {
127 value_vec_text(&self.batch.column_data[self.column_index], self.row_index)
128 .map(Cow::Borrowed)
129 }
130
131 pub fn as_bytes(&self) -> Option<Cow<'_, [u8]>> {
133 value_vec_blob(&self.batch.column_data[self.column_index], self.row_index)
134 .map(Cow::Borrowed)
135 }
136}
137
138impl<'r> OdbcValueRef<'r> {
140 pub fn new(batch: &'r OdbcBatch, row_index: usize, column_index: usize) -> Self {
142 Self {
143 batch,
144 row_index,
145 column_index,
146 }
147 }
148
149 pub fn get_raw(&self) -> Option<OdbcValueType> {
151 value_vec_get_raw(&self.batch.column_data[self.column_index], self.row_index)
152 }
153
154 pub fn int<T: TryFromInt>(&self) -> Option<T> {
156 value_vec_int(&self.batch.column_data[self.column_index], self.row_index)
157 }
158
159 pub fn try_int<T: TryFromInt + crate::types::Type<Odbc>>(&self) -> crate::error::Result<T> {
160 self.int::<T>().ok_or_else(|| {
161 crate::error::Error::Decode(Box::new(crate::error::MismatchedTypeError {
162 rust_type: T::type_info().name().to_string(),
163 rust_sql_type: T::type_info().name().to_string(),
164 sql_type: self.batch.column_data[self.column_index]
165 .type_info
166 .name()
167 .to_string(),
168 source: Some(format!("ODBC: cannot decode {:?}", self).into()),
169 }))
170 })
171 }
172
173 pub fn try_float<T: TryFromFloat + crate::types::Type<Odbc>>(&self) -> crate::error::Result<T> {
174 self.float::<T>().ok_or_else(|| {
175 crate::error::Error::Decode(Box::new(crate::error::MismatchedTypeError {
176 rust_type: T::type_info().name().to_string(),
177 rust_sql_type: T::type_info().name().to_string(),
178 sql_type: self.batch.column_data[self.column_index]
179 .type_info
180 .name()
181 .to_string(),
182 source: Some(format!("ODBC: cannot decode {:?}", self).into()),
183 }))
184 })
185 }
186
187 pub fn float<T: TryFromFloat>(&self) -> Option<T> {
189 value_vec_float(&self.batch.column_data[self.column_index], self.row_index)
190 }
191
192 pub fn text(&self) -> Option<&'r str> {
194 value_vec_text(&self.batch.column_data[self.column_index], self.row_index)
195 }
196
197 pub fn blob(&self) -> Option<&'r [u8]> {
199 value_vec_blob(&self.batch.column_data[self.column_index], self.row_index)
200 }
201
202 pub fn date(&self) -> Option<odbc_api::sys::Date> {
204 if self.is_null() {
205 None
206 } else {
207 match &self.batch.column_data[self.column_index].values {
208 OdbcValueVec::Date(raw_values) => raw_values.get(self.row_index).copied(),
209 _ => None,
210 }
211 }
212 }
213
214 pub fn time(&self) -> Option<odbc_api::sys::Time> {
216 if self.is_null() {
217 None
218 } else {
219 match &self.batch.column_data[self.column_index].values {
220 OdbcValueVec::Time(raw_values) => raw_values.get(self.row_index).copied(),
221 _ => None,
222 }
223 }
224 }
225
226 pub fn timestamp(&self) -> Option<odbc_api::sys::Timestamp> {
228 if self.is_null() {
229 None
230 } else {
231 match &self.batch.column_data[self.column_index].values {
232 OdbcValueVec::Timestamp(raw_values) => raw_values.get(self.row_index).copied(),
233 _ => None,
234 }
235 }
236 }
237}
238
239#[derive(Debug, Clone)]
241pub enum OdbcValueType {
242 TinyInt(i8),
243 SmallInt(i16),
244 Integer(i32),
245 BigInt(i64),
246 Real(f32),
247 Double(f64),
248 Bit(odbc_api::Bit),
249 Text(String),
250 Binary(Vec<u8>),
251 Date(odbc_api::sys::Date),
252 Time(odbc_api::sys::Time),
253 Timestamp(odbc_api::sys::Timestamp),
254}
255
256fn handle_non_nullable_slice<T: Copy>(
258 slice: &[T],
259 constructor: fn(Vec<T>) -> OdbcValueVec,
260) -> (OdbcValueVec, Vec<bool>) {
261 let vec = slice.to_vec();
262 (constructor(vec), vec![false; slice.len()])
263}
264
265fn handle_nullable_slice<'a, T: Default + Copy>(
267 slice: NullableSlice<'a, T>,
268 constructor: fn(Vec<T>) -> OdbcValueVec,
269) -> (OdbcValueVec, Vec<bool>) {
270 let size = slice.size_hint().1.unwrap_or(0);
271 let mut values = Vec::with_capacity(size);
272 let mut nulls = Vec::with_capacity(size);
273 for opt in slice {
274 values.push(opt.copied().unwrap_or_default());
275 nulls.push(opt.is_none());
276 }
277 (constructor(values), nulls)
278}
279
280fn handle_nullable_with_indicators<T: Default + Copy>(
282 raw_values: &[T],
283 indicators: &[isize],
284 constructor: fn(Vec<T>) -> OdbcValueVec,
285) -> (OdbcValueVec, Vec<bool>) {
286 let nulls = indicators.iter().map(|&ind| ind == NULL_DATA).collect();
287 (constructor(raw_values.to_vec()), nulls)
288}
289
290pub fn convert_any_slice_to_value_vec(slice: AnySlice<'_>) -> (OdbcValueVec, Vec<bool>) {
292 match slice {
293 AnySlice::I8(s) => handle_non_nullable_slice(s, OdbcValueVec::TinyInt),
295 AnySlice::I16(s) => handle_non_nullable_slice(s, OdbcValueVec::SmallInt),
296 AnySlice::I32(s) => handle_non_nullable_slice(s, OdbcValueVec::Integer),
297 AnySlice::I64(s) => handle_non_nullable_slice(s, OdbcValueVec::BigInt),
298
299 AnySlice::F32(s) => handle_non_nullable_slice(s, OdbcValueVec::Real),
301 AnySlice::F64(s) => handle_non_nullable_slice(s, OdbcValueVec::Double),
302
303 AnySlice::Bit(s) => handle_non_nullable_slice(s, OdbcValueVec::Bit),
305 AnySlice::Date(s) => handle_non_nullable_slice(s, OdbcValueVec::Date),
306 AnySlice::Time(s) => handle_non_nullable_slice(s, OdbcValueVec::Time),
307 AnySlice::Timestamp(s) => handle_non_nullable_slice(s, OdbcValueVec::Timestamp),
308
309 AnySlice::NullableI8(s) => handle_nullable_slice(s, OdbcValueVec::TinyInt),
311 AnySlice::NullableI16(s) => handle_nullable_slice(s, OdbcValueVec::SmallInt),
312 AnySlice::NullableI32(s) => handle_nullable_slice(s, OdbcValueVec::Integer),
313 AnySlice::NullableI64(s) => handle_nullable_slice(s, OdbcValueVec::BigInt),
314 AnySlice::NullableF32(s) => handle_nullable_slice(s, OdbcValueVec::Real),
315 AnySlice::NullableF64(s) => handle_nullable_slice(s, OdbcValueVec::Double),
316 AnySlice::NullableBit(s) => {
317 let values: Vec<Option<odbc_api::Bit>> = s.map(|opt| opt.copied()).collect();
318 let nulls = values.iter().map(|opt| opt.is_none()).collect();
319 (
320 OdbcValueVec::Bit(
321 values
322 .into_iter()
323 .map(|opt| opt.unwrap_or(odbc_api::Bit(0)))
324 .collect(),
325 ),
326 nulls,
327 )
328 }
329
330 AnySlice::Text(s) => {
332 let mut values = Vec::with_capacity(s.len());
333 let mut nulls = Vec::with_capacity(s.len());
334 for bytes_opt in s.iter() {
335 match bytes_opt {
336 Some(bytes) => {
337 values.push(String::from_utf8_lossy(bytes).to_string());
338 nulls.push(false);
339 }
340 None => {
341 values.push(String::new());
342 nulls.push(true);
343 }
344 }
345 }
346 (OdbcValueVec::Text(values), nulls)
347 }
348 AnySlice::Binary(s) => {
349 let mut values = Vec::with_capacity(s.len());
350 let mut nulls = Vec::with_capacity(s.len());
351 for bytes_opt in s.iter() {
352 match bytes_opt {
353 Some(bytes) => {
354 values.push(bytes.to_vec());
355 nulls.push(false);
356 }
357 None => {
358 values.push(Vec::new());
359 nulls.push(true);
360 }
361 }
362 }
363 (OdbcValueVec::Binary(values), nulls)
364 }
365
366 AnySlice::NullableDate(s) => {
368 let (raw_values, indicators) = s.raw_values();
369 handle_nullable_with_indicators(raw_values, indicators, OdbcValueVec::Date)
370 }
371 AnySlice::NullableTime(s) => {
372 let (raw_values, indicators) = s.raw_values();
373 handle_nullable_with_indicators(raw_values, indicators, OdbcValueVec::Time)
374 }
375 AnySlice::NullableTimestamp(s) => {
376 let (raw_values, indicators) = s.raw_values();
377 handle_nullable_with_indicators(raw_values, indicators, OdbcValueVec::Timestamp)
378 }
379
380 _ => panic!("Unsupported AnySlice variant"),
381 }
382}
383
384fn value_vec_is_null(column_data: &ColumnData, row_index: usize) -> bool {
385 column_data.nulls.get(row_index).copied().unwrap_or(false)
386}
387
388macro_rules! impl_get_raw_arm_copy {
389 ($vec:expr, $row_index:expr, $variant:ident, $type:ty) => {
390 $vec.get($row_index).copied().map(OdbcValueType::$variant)
391 };
392}
393
394fn value_vec_get_raw(column_data: &ColumnData, row_index: usize) -> Option<OdbcValueType> {
395 if value_vec_is_null(column_data, row_index) {
396 return None;
397 }
398 match &column_data.values {
399 OdbcValueVec::TinyInt(v) => v.get(row_index).map(|&val| OdbcValueType::TinyInt(val)),
400 OdbcValueVec::SmallInt(v) => v.get(row_index).map(|&val| OdbcValueType::SmallInt(val)),
401 OdbcValueVec::Integer(v) => v.get(row_index).map(|&val| OdbcValueType::Integer(val)),
402 OdbcValueVec::BigInt(v) => v.get(row_index).map(|&val| OdbcValueType::BigInt(val)),
403 OdbcValueVec::Real(v) => v.get(row_index).map(|&val| OdbcValueType::Real(val)),
404 OdbcValueVec::Double(v) => v.get(row_index).map(|&val| OdbcValueType::Double(val)),
405 OdbcValueVec::Bit(v) => v.get(row_index).map(|&val| OdbcValueType::Bit(val)),
406 OdbcValueVec::Text(v) => v.get(row_index).cloned().map(OdbcValueType::Text),
407 OdbcValueVec::Binary(v) => v.get(row_index).cloned().map(OdbcValueType::Binary),
408 OdbcValueVec::Date(v) => impl_get_raw_arm_copy!(v, row_index, Date, odbc_api::sys::Date),
409 OdbcValueVec::Time(v) => impl_get_raw_arm_copy!(v, row_index, Time, odbc_api::sys::Time),
410 OdbcValueVec::Timestamp(v) => {
411 impl_get_raw_arm_copy!(v, row_index, Timestamp, odbc_api::sys::Timestamp)
412 }
413 }
414}
415
416pub trait TryFromInt:
417 TryFrom<u8>
418 + TryFrom<i16>
419 + TryFrom<i32>
420 + TryFrom<i64>
421 + TryFrom<i8>
422 + TryFrom<u16>
423 + TryFrom<u32>
424 + TryFrom<u64>
425 + std::str::FromStr
426{
427}
428
429impl<
430 T: TryFrom<u8>
431 + TryFrom<i16>
432 + TryFrom<i32>
433 + TryFrom<i64>
434 + TryFrom<i8>
435 + TryFrom<u16>
436 + TryFrom<u32>
437 + TryFrom<u64>
438 + std::str::FromStr,
439 > TryFromInt for T
440{
441}
442
443macro_rules! impl_int_conversion {
444 ($vec:expr, $row_index:expr, $type:ty) => {
445 <$type>::try_from(*$vec.get($row_index)?).ok()
446 };
447 ($vec:expr, $row_index:expr, $type:ty, bit) => {
448 <$type>::try_from($vec.get($row_index)?.0).ok()
449 };
450 ($vec:expr, $row_index:expr, $type:ty, text) => {
451 if let Some(Some(text)) = $vec.get($row_index) {
452 text.trim().parse().ok()
453 } else {
454 None
455 }
456 };
457}
458
459fn value_vec_int<T: TryFromInt>(column_data: &ColumnData, row_index: usize) -> Option<T> {
460 if value_vec_is_null(column_data, row_index) {
461 return None;
462 }
463 match &column_data.values {
464 OdbcValueVec::TinyInt(v) => impl_int_conversion!(v, row_index, T),
465 OdbcValueVec::SmallInt(v) => impl_int_conversion!(v, row_index, T),
466 OdbcValueVec::Integer(v) => impl_int_conversion!(v, row_index, T),
467 OdbcValueVec::BigInt(v) => impl_int_conversion!(v, row_index, T),
468 OdbcValueVec::Bit(v) => impl_int_conversion!(v, row_index, T, bit),
469 OdbcValueVec::Text(v) => v.get(row_index).and_then(|text| text.trim().parse().ok()),
470 _ => None,
471 }
472}
473
474pub trait TryFromFloat: TryFrom<f32> + TryFrom<f64> {}
475
476impl<T: TryFrom<f32> + TryFrom<f64>> TryFromFloat for T {}
477
478macro_rules! impl_float_conversion {
479 ($vec:expr, $row_index:expr, $type:ty) => {
480 <$type>::try_from(*$vec.get($row_index)?).ok()
481 };
482}
483
484fn value_vec_float<T: TryFromFloat>(column_data: &ColumnData, row_index: usize) -> Option<T> {
485 if value_vec_is_null(column_data, row_index) {
486 return None;
487 }
488 match &column_data.values {
489 OdbcValueVec::Real(v) => impl_float_conversion!(v, row_index, T),
490 OdbcValueVec::Double(v) => impl_float_conversion!(v, row_index, T),
491 _ => None,
492 }
493}
494
495fn value_vec_text(column_data: &ColumnData, row_index: usize) -> Option<&str> {
496 if value_vec_is_null(column_data, row_index) {
497 return None;
498 }
499 match &column_data.values {
500 OdbcValueVec::Text(v) => v.get(row_index).map(|s| s.as_str()),
501 _ => None,
502 }
503}
504
505fn value_vec_blob(column_data: &ColumnData, row_index: usize) -> Option<&[u8]> {
506 if value_vec_is_null(column_data, row_index) {
507 return None;
508 }
509 match &column_data.values {
510 OdbcValueVec::Binary(v) => v.get(row_index).map(|b| b.as_slice()),
511 _ => None,
512 }
513}
514
515#[cfg(feature = "any")]
518impl<'r> From<OdbcValueRef<'r>> for crate::any::AnyValueRef<'r> {
519 fn from(value: OdbcValueRef<'r>) -> Self {
520 crate::any::AnyValueRef {
521 type_info: crate::any::AnyTypeInfo::from(
522 value.batch.column_data[value.column_index]
523 .type_info
524 .clone(),
525 ),
526 kind: crate::any::value::AnyValueRefKind::Odbc(value),
527 }
528 }
529}
530
531#[cfg(feature = "any")]
532impl From<OdbcValue> for crate::any::AnyValue {
533 fn from(value: OdbcValue) -> Self {
534 crate::any::AnyValue {
535 type_info: crate::any::AnyTypeInfo::from(
536 value.batch.column_data[value.column_index]
537 .type_info
538 .clone(),
539 ),
540 kind: crate::any::value::AnyValueKind::Odbc(value),
541 }
542 }
543}