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<bool>),
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: std::any::type_name::<T>().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: std::any::type_name::<T>().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(bool),
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) => {
305 let vec: Vec<bool> = s.iter().map(|bit| bit.as_bool()).collect();
306 (OdbcValueVec::Bit(vec), vec![false; s.len()])
307 }
308 AnySlice::Date(s) => handle_non_nullable_slice(s, OdbcValueVec::Date),
309 AnySlice::Time(s) => handle_non_nullable_slice(s, OdbcValueVec::Time),
310 AnySlice::Timestamp(s) => handle_non_nullable_slice(s, OdbcValueVec::Timestamp),
311
312 AnySlice::NullableI8(s) => handle_nullable_slice(s, OdbcValueVec::TinyInt),
314 AnySlice::NullableI16(s) => handle_nullable_slice(s, OdbcValueVec::SmallInt),
315 AnySlice::NullableI32(s) => handle_nullable_slice(s, OdbcValueVec::Integer),
316 AnySlice::NullableI64(s) => handle_nullable_slice(s, OdbcValueVec::BigInt),
317 AnySlice::NullableF32(s) => handle_nullable_slice(s, OdbcValueVec::Real),
318 AnySlice::NullableF64(s) => handle_nullable_slice(s, OdbcValueVec::Double),
319 AnySlice::NullableBit(s) => {
320 let values: Vec<Option<odbc_api::Bit>> = s.map(|opt| opt.copied()).collect();
321 let nulls = values.iter().map(|opt| opt.is_none()).collect();
322 (
323 OdbcValueVec::Bit(
324 values
325 .into_iter()
326 .map(|opt| opt.is_some_and(|bit| bit.as_bool()))
327 .collect(),
328 ),
329 nulls,
330 )
331 }
332
333 AnySlice::Text(s) => {
335 let mut values = Vec::with_capacity(s.len());
336 let mut nulls = Vec::with_capacity(s.len());
337 for bytes_opt in s.iter() {
338 nulls.push(bytes_opt.is_none());
339 values.push(String::from_utf8_lossy(bytes_opt.unwrap_or_default()).into_owned());
340 }
341 (OdbcValueVec::Text(values), nulls)
342 }
343 AnySlice::Binary(s) => {
344 let mut values = Vec::with_capacity(s.len());
345 let mut nulls = Vec::with_capacity(s.len());
346 for bytes_opt in s.iter() {
347 nulls.push(bytes_opt.is_none());
348 values.push(bytes_opt.unwrap_or_default().to_vec());
349 }
350 (OdbcValueVec::Binary(values), nulls)
351 }
352
353 AnySlice::NullableDate(s) => {
355 let (raw_values, indicators) = s.raw_values();
356 handle_nullable_with_indicators(raw_values, indicators, OdbcValueVec::Date)
357 }
358 AnySlice::NullableTime(s) => {
359 let (raw_values, indicators) = s.raw_values();
360 handle_nullable_with_indicators(raw_values, indicators, OdbcValueVec::Time)
361 }
362 AnySlice::NullableTimestamp(s) => {
363 let (raw_values, indicators) = s.raw_values();
364 handle_nullable_with_indicators(raw_values, indicators, OdbcValueVec::Timestamp)
365 }
366
367 _ => panic!("Unsupported AnySlice variant"),
368 }
369}
370
371fn value_vec_is_null(column_data: &ColumnData, row_index: usize) -> bool {
372 column_data.nulls.get(row_index).copied().unwrap_or(false)
373}
374
375macro_rules! impl_get_raw_arm_copy {
376 ($vec:expr, $row_index:expr, $variant:ident, $type:ty) => {
377 $vec.get($row_index).copied().map(OdbcValueType::$variant)
378 };
379}
380
381fn value_vec_get_raw(column_data: &ColumnData, row_index: usize) -> Option<OdbcValueType> {
382 if value_vec_is_null(column_data, row_index) {
383 return None;
384 }
385 match &column_data.values {
386 OdbcValueVec::TinyInt(v) => v.get(row_index).map(|&val| OdbcValueType::TinyInt(val)),
387 OdbcValueVec::SmallInt(v) => v.get(row_index).map(|&val| OdbcValueType::SmallInt(val)),
388 OdbcValueVec::Integer(v) => v.get(row_index).map(|&val| OdbcValueType::Integer(val)),
389 OdbcValueVec::BigInt(v) => v.get(row_index).map(|&val| OdbcValueType::BigInt(val)),
390 OdbcValueVec::Real(v) => v.get(row_index).map(|&val| OdbcValueType::Real(val)),
391 OdbcValueVec::Double(v) => v.get(row_index).map(|&val| OdbcValueType::Double(val)),
392 OdbcValueVec::Bit(v) => v.get(row_index).map(|&val| OdbcValueType::Bit(val)),
393 OdbcValueVec::Text(v) => v.get(row_index).cloned().map(OdbcValueType::Text),
394 OdbcValueVec::Binary(v) => v.get(row_index).cloned().map(OdbcValueType::Binary),
395 OdbcValueVec::Date(v) => impl_get_raw_arm_copy!(v, row_index, Date, odbc_api::sys::Date),
396 OdbcValueVec::Time(v) => impl_get_raw_arm_copy!(v, row_index, Time, odbc_api::sys::Time),
397 OdbcValueVec::Timestamp(v) => {
398 impl_get_raw_arm_copy!(v, row_index, Timestamp, odbc_api::sys::Timestamp)
399 }
400 }
401}
402
403pub trait TryFromInt:
404 TryFrom<u8>
405 + TryFrom<i16>
406 + TryFrom<i32>
407 + TryFrom<i64>
408 + TryFrom<i8>
409 + TryFrom<u16>
410 + TryFrom<u32>
411 + TryFrom<u64>
412 + std::str::FromStr
413{
414}
415
416impl<
417 T: 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 > TryFromInt for T
427{
428}
429
430macro_rules! impl_int_conversion {
431 ($vec:expr, $row_index:expr, $type:ty) => {
432 <$type>::try_from(*$vec.get($row_index)?).ok()
433 };
434 ($vec:expr, $row_index:expr, $type:ty, text) => {
435 if let Some(Some(text)) = $vec.get($row_index) {
436 text.trim().parse().ok()
437 } else {
438 None
439 }
440 };
441}
442
443fn value_vec_int<T: TryFromInt>(column_data: &ColumnData, row_index: usize) -> Option<T> {
444 if value_vec_is_null(column_data, row_index) {
445 return None;
446 }
447 match &column_data.values {
448 OdbcValueVec::TinyInt(v) => impl_int_conversion!(v, row_index, T),
449 OdbcValueVec::SmallInt(v) => impl_int_conversion!(v, row_index, T),
450 OdbcValueVec::Integer(v) => impl_int_conversion!(v, row_index, T),
451 OdbcValueVec::BigInt(v) => impl_int_conversion!(v, row_index, T),
452 OdbcValueVec::Bit(v) => T::try_from(*v.get(row_index)? as u8).ok(),
453 OdbcValueVec::Text(v) => v.get(row_index).and_then(|text| text.trim().parse().ok()),
454 _ => None,
455 }
456}
457
458pub trait TryFromFloat: TryFrom<f32> + TryFrom<f64> {}
459
460impl<T: TryFrom<f32> + TryFrom<f64>> TryFromFloat for T {}
461
462macro_rules! impl_float_conversion {
463 ($vec:expr, $row_index:expr, $type:ty) => {
464 <$type>::try_from(*$vec.get($row_index)?).ok()
465 };
466}
467
468fn value_vec_float<T: TryFromFloat>(column_data: &ColumnData, row_index: usize) -> Option<T> {
469 if value_vec_is_null(column_data, row_index) {
470 return None;
471 }
472 match &column_data.values {
473 OdbcValueVec::Real(v) => impl_float_conversion!(v, row_index, T),
474 OdbcValueVec::Double(v) => impl_float_conversion!(v, row_index, T),
475 _ => None,
476 }
477}
478
479fn value_vec_text(column_data: &ColumnData, row_index: usize) -> Option<&str> {
480 if value_vec_is_null(column_data, row_index) {
481 return None;
482 }
483 match &column_data.values {
484 OdbcValueVec::Text(v) => v.get(row_index).map(|s| s.as_str()),
485 _ => None,
486 }
487}
488
489fn value_vec_blob(column_data: &ColumnData, row_index: usize) -> Option<&[u8]> {
490 if value_vec_is_null(column_data, row_index) {
491 return None;
492 }
493 match &column_data.values {
494 OdbcValueVec::Binary(v) => v.get(row_index).map(|b| b.as_slice()),
495 _ => None,
496 }
497}
498
499#[cfg(feature = "any")]
502impl<'r> From<OdbcValueRef<'r>> for crate::any::AnyValueRef<'r> {
503 fn from(value: OdbcValueRef<'r>) -> Self {
504 crate::any::AnyValueRef {
505 type_info: crate::any::AnyTypeInfo::from(
506 value.batch.column_data[value.column_index]
507 .type_info
508 .clone(),
509 ),
510 kind: crate::any::value::AnyValueRefKind::Odbc(value),
511 }
512 }
513}
514
515#[cfg(feature = "any")]
516impl From<OdbcValue> for crate::any::AnyValue {
517 fn from(value: OdbcValue) -> Self {
518 crate::any::AnyValue {
519 type_info: crate::any::AnyTypeInfo::from(
520 value.batch.column_data[value.column_index]
521 .type_info
522 .clone(),
523 ),
524 kind: crate::any::value::AnyValueKind::Odbc(value),
525 }
526 }
527}