odbc_iter/
row.rs

1/*!
2Fetching data from ODBC Cursor and conversion to Rust native types.
3!*/
4
5use error_context::prelude::*;
6use odbc::ffi::SqlDataType;
7use odbc::{ColumnDescriptor, DiagnosticRecord, OdbcType};
8use odbc::{SqlDate, SqlSsTime2, SqlTime, SqlTimestamp};
9use std::convert::TryFrom;
10use std::error::Error;
11use std::fmt;
12use std::string::FromUtf16Error;
13use std::convert::TryInto;
14
15#[cfg(feature = "rust_decimal")]
16use rust_decimal::Decimal;
17#[cfg(feature = "rust_decimal")]
18use std::str::FromStr;
19
20/// Data access configuration that can be used to configure data retrieval and conversion configured per `ResultSet` for given `Item` type.
21/// Configuration can be attached to `Handle` and will be cloned per query so it can store per query state.
22pub trait Configuration: Default + Clone + fmt::Debug {}
23
24/// Default configuration that allows converting rows to types supported by this crate.
25#[derive(Debug, Default, Clone)]
26pub struct DefaultConfiguration;
27impl Configuration for DefaultConfiguration {}
28
29/// Runtime settings configured per connection.
30#[derive(Debug, Default)]
31pub struct Settings {
32    /// When `true` the `ResultSet` iterator will try to fetch strings as UTF-16 (wide) strings before converting them to Rust's UTF-8 `String`.
33    pub utf_16_strings: bool,
34}
35
36/// This error can be returned if database provided column type does not match type requested by
37/// client
38#[derive(Debug)]
39pub struct SqlDataTypeMismatch {
40    requested: &'static str,
41    queried: SqlDataType,
42}
43
44impl fmt::Display for SqlDataTypeMismatch {
45    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
46        write!(
47            f,
48            "requested SQL column data type '{:?}' does not match queried data type '{:?}'",
49            self.requested, self.queried
50        )
51    }
52}
53
54impl Error for SqlDataTypeMismatch {}
55
56/// This error can be returned if database provided column of type that currently cannot be mapped to `Value` type.
57#[derive(Debug)]
58pub struct UnsupportedSqlDataType(SqlDataType);
59
60impl fmt::Display for UnsupportedSqlDataType {
61    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62        write!(f, "unsupported SQL data type: {:?}", self.0)
63    }
64}
65
66impl Error for UnsupportedSqlDataType {}
67
68/// Errors related to datum access of ODBC cursor.
69#[derive(Debug)]
70#[allow(clippy::large_enum_variant)]
71pub enum DatumAccessError {
72    OdbcCursorError(DiagnosticRecord),
73    SqlDataTypeMismatch(SqlDataTypeMismatch),
74    FromUtf16Error(FromUtf16Error, &'static str),
75    #[cfg(feature = "serde_json")]
76    JsonError(serde_json::Error),
77}
78
79impl fmt::Display for DatumAccessError {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        match self {
82            DatumAccessError::OdbcCursorError(_) => {
83                write!(f, "failed to access data in ODBC cursor")
84            }
85            DatumAccessError::SqlDataTypeMismatch(_) => {
86                write!(f, "failed to handle data type conversion")
87            }
88            DatumAccessError::FromUtf16Error(_, context) => write!(
89                f,
90                "failed to create String from UTF-16 column data while {}",
91                context
92            ),
93            #[cfg(feature = "serde_json")]
94            DatumAccessError::JsonError(_) => write!(f, "failed to convert data to JSON Value"),
95        }
96    }
97}
98
99impl Error for DatumAccessError {
100    fn source(&self) -> Option<&(dyn Error + 'static)> {
101        match self {
102            DatumAccessError::OdbcCursorError(err) => Some(err),
103            DatumAccessError::SqlDataTypeMismatch(err) => Some(err),
104            DatumAccessError::FromUtf16Error(err, _) => Some(err),
105            #[cfg(feature = "serde_json")]
106            DatumAccessError::JsonError(err) => Some(err),
107        }
108    }
109}
110
111impl From<ErrorContext<FromUtf16Error, &'static str>> for DatumAccessError {
112    fn from(err: ErrorContext<FromUtf16Error, &'static str>) -> DatumAccessError {
113        DatumAccessError::FromUtf16Error(err.error, err.context)
114    }
115}
116
117#[cfg(feature = "serde_json")]
118impl From<serde_json::Error> for DatumAccessError {
119    fn from(err: serde_json::Error) -> DatumAccessError {
120        DatumAccessError::JsonError(err)
121    }
122}
123
124/// Description of column type, name and nullability properties used to represent row schema.
125#[derive(Debug, Clone, PartialEq)]
126pub struct ColumnType {
127    /// Supported type of datum that this column holds. See `DatumType` documentation of usage of corresponding `Column::into_*()` functions.
128    pub datum_type: DatumType,
129    /// ODBC SQL Data Type as returned by the driver.
130    pub odbc_type: SqlDataType,
131    /// `true` if column can contain `NULL` value. If `false` the `Column::into_*()` functions should always return `Some` value.
132    pub nullable: bool,
133    /// Name of the column as provided by the ODBC driver.
134    pub name: String,
135}
136
137/// Types of values that column can be converted to.
138#[derive(Debug, Clone, Copy, PartialEq)]
139pub enum DatumType {
140    /// Use `Column::into_bool()` to get column value.
141    Bit,
142    /// Use `Column::into_i8()` to get column value.
143    Tinyint,
144    /// Use `Column::into_i16()` to get column value.
145    Smallint,
146    /// Use `Column::into_i32()` to get column value.
147    Integer,
148    /// Use `Column::into_i64()` to get column value.
149    Bigint,
150    /// Use `Column::into_f32()` to get column value.
151    Float,
152    /// Use `Column::into_f64()` to get column value.
153    Double,
154    #[cfg(feature = "rust_decimal")]
155    /// Use `Column::into_decimal()` to get column value.
156    Decimal,
157    /// Use `Column::into_string()` to get column value.
158    String,
159    /// Use `Column::into_timestamp()` to get column value.
160    Timestamp,
161    /// Use `Column::into_date()` to get column value.
162    Date,
163    /// Use `Column::into_time()` to get column value.
164    Time,
165    #[cfg(feature = "serde_json")]
166    /// Use `Column::into_json()` to parse as `serde_json::Value` or `Column::into_string()` to get it as `String`.
167    Json,
168}
169
170impl DatumType {
171    /// Static string describing type of column datum.
172    pub fn description(self) -> &'static str {
173        match self {
174            DatumType::Bit => "BIT",
175            DatumType::Tinyint => "TINYINT",
176            DatumType::Smallint => "SMALLINT",
177            DatumType::Integer => "INTEGER",
178            DatumType::Bigint => "BIGINT",
179            DatumType::Float => "FLOAT",
180            DatumType::Double => "DOUBLE",
181            #[cfg(feature = "rust_decimal")]
182            DatumType::Decimal => "DECIMAL",
183            DatumType::String => "STRING",
184            DatumType::Timestamp => "TIMESTAMP",
185            DatumType::Date => "DATE",
186            DatumType::Time => "TIME",
187            #[cfg(feature = "serde_json")]
188            DatumType::Json => "JSON",
189        }
190    }
191}
192
193impl TryFrom<ColumnDescriptor> for ColumnType {
194    type Error = UnsupportedSqlDataType;
195
196    fn try_from(column_descriptor: ColumnDescriptor) -> Result<ColumnType, UnsupportedSqlDataType> {
197        use SqlDataType::*;
198        let datum_type = match column_descriptor.data_type {
199            SQL_EXT_BIT => DatumType::Bit,
200            SQL_EXT_TINYINT => DatumType::Tinyint,
201            SQL_SMALLINT => DatumType::Smallint,
202            SQL_INTEGER => DatumType::Integer,
203            SQL_EXT_BIGINT => DatumType::Bigint,
204            SQL_FLOAT | SQL_REAL => DatumType::Float,
205            SQL_DOUBLE => DatumType::Double,
206            #[cfg(feature = "rust_decimal")]
207            SQL_DECIMAL | SQL_NUMERIC => DatumType::Decimal,
208            SQL_CHAR | SQL_VARCHAR | SQL_EXT_LONGVARCHAR | SQL_EXT_WCHAR | SQL_EXT_WVARCHAR
209            | SQL_EXT_WLONGVARCHAR => DatumType::String,
210            SQL_TIMESTAMP => DatumType::Timestamp,
211            SQL_DATE => DatumType::Date,
212            SQL_TIME | SQL_SS_TIME2 => DatumType::Time,
213            SQL_UNKNOWN_TYPE => {
214                #[cfg(feature = "serde_json")]
215                {
216                    DatumType::Json
217                }
218                #[cfg(not(feature = "serde_json"))]
219                {
220                    DatumType::String
221                }
222            }
223            _ => return Err(UnsupportedSqlDataType(column_descriptor.data_type)),
224        };
225
226        Ok(ColumnType {
227            datum_type,
228            odbc_type: column_descriptor.data_type,
229            nullable: column_descriptor.nullable.unwrap_or(true),
230            name: column_descriptor.name,
231        })
232    }
233}
234
235/// Represents SQL table column which can be converted to Rust native type.
236pub struct Column<'r, 's, 'c, S, C: Configuration> {
237    /// Type information about this column
238    pub column_type: &'r ColumnType,
239    /// Data access configuration
240    pub configuration: &'s C,
241    /// Runtime settings
242    settings: &'r Settings,
243    /// ODBC Cursor object pointed at this column
244    cursor: &'r mut odbc::Cursor<'s, 'c, 'c, S>,
245    /// Which column are we at
246    index: u16,
247}
248
249impl<'r, 's, 'c, S, C: Configuration> fmt::Debug for Column<'r, 's, 'c, S, C> {
250    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
251        f.debug_struct("Column")
252            .field("column_type", &self.column_type)
253            .field("settings", &self.settings)
254            .field("configuration", &self.configuration)
255            .field("index", &self.index)
256            .finish()
257    }
258}
259
260impl<'r, 's, 'c, S, C: Configuration> Column<'r, 's, 'c, S, C> {
261    fn into<T: OdbcType<'r>>(self) -> Result<Option<T>, DatumAccessError> {
262        self.cursor
263            .get_data::<T>(self.index + 1)
264            .map_err(DatumAccessError::OdbcCursorError)
265    }
266
267    // https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/c-data-types?view=sql-server-2017
268
269    /// Reads `bool` value from column.
270    pub fn into_bool(self) -> Result<Option<bool>, DatumAccessError> {
271        Ok(match self.column_type.odbc_type {
272            SqlDataType::SQL_EXT_BIT => self.into::<u8>()?.map(|byte| byte != 0),
273            queried => {
274                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
275                    requested: "BIT",
276                    queried,
277                }))
278            }
279        })
280    }
281
282    /// Reads `i8` value from column.
283    pub fn into_i8(self) -> Result<Option<i8>, DatumAccessError> {
284        Ok(match self.column_type.odbc_type {
285            SqlDataType::SQL_EXT_TINYINT => self.into::<i8>()?,
286            queried => {
287                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
288                    requested: "TINYINT",
289                    queried,
290                }))
291            }
292        })
293    }
294
295    /// Reads `i16` value from column.
296    pub fn into_i16(self) -> Result<Option<i16>, DatumAccessError> {
297        Ok(match self.column_type.odbc_type {
298            SqlDataType::SQL_SMALLINT => self.into::<i16>()?,
299            queried => {
300                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
301                    requested: "SMALLINT",
302                    queried,
303                }))
304            }
305        })
306    }
307
308    /// Reads `i32` value from column.
309    pub fn into_i32(self) -> Result<Option<i32>, DatumAccessError> {
310        Ok(match self.column_type.odbc_type {
311            SqlDataType::SQL_INTEGER => self.into::<i32>()?,
312            queried => {
313                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
314                    requested: "INTEGER",
315                    queried,
316                }))
317            }
318        })
319    }
320
321    /// Reads `i64` value from column.
322    pub fn into_i64(self) -> Result<Option<i64>, DatumAccessError> {
323        Ok(match self.column_type.odbc_type {
324            SqlDataType::SQL_EXT_BIGINT => self.into::<i64>()?,
325            queried => {
326                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
327                    requested: "BIGINT",
328                    queried,
329                }))
330            }
331        })
332    }
333
334    /// Reads `f32` value from column.
335    pub fn into_f32(self) -> Result<Option<f32>, DatumAccessError> {
336        Ok(match self.column_type.odbc_type {
337            SqlDataType::SQL_REAL | SqlDataType::SQL_FLOAT => self.into::<f32>()?,
338            queried => {
339                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
340                    requested: "FLOAT",
341                    queried,
342                }))
343            }
344        })
345    }
346
347    /// Reads `f64` value from column.
348    pub fn into_f64(self) -> Result<Option<f64>, DatumAccessError> {
349        Ok(match self.column_type.odbc_type {
350            SqlDataType::SQL_DOUBLE => self.into::<f64>()?,
351            queried => {
352                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
353                    requested: "DOUBLE",
354                    queried,
355                }))
356            }
357        })
358    }
359
360    #[cfg(feature = "rust_decimal")]
361    /// Reads `Decimal` value from column.
362    pub fn into_decimal(self) -> Result<Option<Decimal>, DatumAccessError> {
363        Ok(match self.column_type.odbc_type {
364            SqlDataType::SQL_DECIMAL | SqlDataType::SQL_NUMERIC => {
365                // Since Decimal isn't an OdbcType, get the String representation and convert that to a Decimal instead
366                let decimal_as_string = &self.into::<String>()?;
367                match decimal_as_string {
368                    Some(s) => Some(Decimal::from_str(&s).unwrap()),
369                    None => None
370                }
371            },
372            queried => {
373                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
374                    requested: "DECIMAL",
375                    queried,
376                }))
377            }
378        })
379    }
380
381    /// Reads `String` value from column.
382    pub fn into_string(self) -> Result<Option<String>, DatumAccessError> {
383        use SqlDataType::*;
384        Ok(match self.column_type.odbc_type {
385            SQL_CHAR | SQL_VARCHAR | SQL_EXT_LONGVARCHAR => self.into::<String>()?,
386            SQL_EXT_WCHAR | SQL_EXT_WVARCHAR | SQL_EXT_WLONGVARCHAR |
387            SQL_UNKNOWN_TYPE => {
388                if self.settings.utf_16_strings {
389                    self.into::<&[u16]>()?
390                        .map(|bytes| String::from_utf16(bytes).wrap_error_while("getting UTF-16 string (SQL_EXT_WCHAR | SQL_EXT_WVARCHAR | SQL_EXT_WLONGVARCHAR)"))
391                        .transpose()?
392                } else {
393                    self.into::<String>()?
394                }
395            }
396            queried => {
397                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
398                    requested: "STRING",
399                    queried,
400                }))
401            }
402        })
403    }
404
405    /// Reads `SqlTimestamp` value from column.
406    pub fn into_timestamp(self) -> Result<Option<SqlTimestamp>, DatumAccessError> {
407        Ok(match self.column_type.odbc_type {
408            SqlDataType::SQL_TIMESTAMP => self.into::<SqlTimestamp>()?,
409            queried => {
410                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
411                    requested: "TIMESTAMP",
412                    queried,
413                }))
414            }
415        })
416    }
417
418    /// Reads `SqlDate` value from column.
419    pub fn into_date(self) -> Result<Option<SqlDate>, DatumAccessError> {
420        Ok(match self.column_type.odbc_type {
421            SqlDataType::SQL_DATE => self.into::<SqlDate>()?,
422            queried => {
423                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
424                    requested: "DATE",
425                    queried,
426                }))
427            }
428        })
429    }
430
431    /// Reads `SqlSsTime2` value from column.
432    pub fn into_time(self) -> Result<Option<SqlSsTime2>, DatumAccessError> {
433        Ok(match self.column_type.odbc_type {
434            SqlDataType::SQL_TIME => self.into::<SqlTime>()?.map(|ss| SqlSsTime2 {
435                hour: ss.hour,
436                minute: ss.minute,
437                second: ss.second,
438                fraction: 0,
439            }),
440            SqlDataType::SQL_SS_TIME2 => self.into::<SqlSsTime2>()?,
441            queried => {
442                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
443                    requested: "TIME",
444                    queried,
445                }))
446            }
447        })
448    }
449
450    #[cfg(feature = "serde_json")]
451    /// Reads `serde_json::Value` value from column.
452    pub fn into_json(self) -> Result<Option<serde_json::Value>, DatumAccessError> {
453        Ok(match self.column_type.odbc_type {
454            queried @ SqlDataType::SQL_UNKNOWN_TYPE => {
455                self.into::<String>()?
456                    .map(|data| {
457                        // MonetDB can only store arrays or objects as top level JSON values so check if data looks like JSON in case we are not talking to MonetDB
458                        if (data.starts_with("[") && data.ends_with("]"))
459                            || (data.starts_with("{") && data.ends_with("}"))
460                        {
461                            serde_json::from_str(&data).map_err(Into::into)
462                        } else {
463                            //TOOD: better error?
464                            return Err(DatumAccessError::SqlDataTypeMismatch(
465                                SqlDataTypeMismatch {
466                                    requested: "JSON",
467                                    queried,
468                                },
469                            ));
470                        }
471                    })
472                    .transpose()?
473            }
474            queried => {
475                return Err(DatumAccessError::SqlDataTypeMismatch(SqlDataTypeMismatch {
476                    requested: "JSON",
477                    queried,
478                }))
479            }
480        })
481    }
482
483    /// Gets column number in the row (first column is 0)
484    pub fn index(&self) -> u16 {
485        self.index
486    }
487}
488
489/// Represents SQL table row of `Column` objects.
490pub struct Row<'r, 's, 'c, S, C: Configuration> {
491    /// Schema information about this row
492    pub schema: &'r [ColumnType],
493    /// Data access configuration
494    pub configuration: &'s C,
495    /// Runtime settings
496    settings: &'r Settings,
497    /// ODBC Cursor object
498    cursor: odbc::Cursor<'s, 'c, 'c, S>,
499    /// Which column will shift next
500    index: u16,
501    /// Number of columns
502    columns: u16,
503}
504
505impl<'r, 's, 'c, S, C: Configuration> fmt::Debug for Row<'r, 's, 'c, S, C> {
506    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
507        f.debug_struct("Row")
508            .field("schema", &self.schema)
509            .field("settings", &self.settings)
510            .field("configuration", &self.configuration)
511            .field("index", &self.index)
512            .field("columns", &self.columns)
513            .finish()
514    }
515}
516
517impl<'r, 's, 'c, S, C: Configuration> Row<'r, 's, 'c, S, C> {
518    pub fn new(
519        cursor: odbc::Cursor<'s, 'c, 'c, S>,
520        schema: &'r [ColumnType],
521        settings: &'r Settings,
522        configuration: &'s C,
523    ) -> Row<'r, 's, 'c, S, C> {
524        Row {
525            schema,
526            configuration,
527            settings,
528            cursor,
529            index: 0,
530            columns: schema.len() as u16,
531        }
532    }
533
534    pub fn shift_column<'i>(&'i mut self) -> Option<Column<'i, 's, 'c, S, C>> {
535        self.schema
536            .get(self.index as usize)
537            .map(move |column_type| {
538                let column = Column {
539                    column_type,
540                    configuration: self.configuration,
541                    settings: &self.settings,
542                    cursor: &mut self.cursor,
543                    index: self.index,
544                };
545
546                self.index += 1;
547                column
548            })
549    }
550
551    /// Gets number of columns
552    pub fn columns(&self) -> u16 {
553        self.columns
554    }
555}
556
557
558/// Column values can be converted to types implementing this trait.
559///
560/// This trait is implemented for primitive Rust types, `String` and `chrono` date and time types.
561pub trait TryFromColumn<C: Configuration>: Sized {
562    type Error: Error + 'static;
563    /// Create `Self` from row column.
564    fn try_from_column<'i, 's, 'c, S>(column: Column<'i, 's, 'c, S, C>) -> Result<Self, Self::Error>;
565}
566
567/// This traits allow for conversion of `Row` type representing ODBC cursor used internally by `ResultSet` iterator to any other type returned as `Item` that implements it.
568///
569/// This trait is implemented for Rust tuple type enabling conversion of rows to tuples of types implementing `TryFromValue`.
570/// Also this trait implementation allows to convert single column rows to types implementing `TryFromColumn`.
571///
572/// This trait can be implemented for custom objects. This will enable them to be queried directly from database as `Item` of `ResultSet` iterator.
573pub trait TryFromRow<C: Configuration>: Sized {
574    type Error: Error + 'static;
575    /// Given `ColumnType` convert from `Row` to other type of value representing table row.
576    fn try_from_row<'r, 's, 'c, S>(row: Row<'r, 's, 'c, S, C>) -> Result<Self, Self::Error>;
577}
578
579/// Error type that represents different problems when converting column values to specific types.
580#[derive(Debug)]
581pub enum ColumnConvertError {
582    UnexpectedNullValue(&'static str),
583    DatumAccessError(DatumAccessError),
584    ValueOutOfRange {
585        expected: &'static str,
586    },
587}
588
589impl From<DatumAccessError> for ColumnConvertError {
590    fn from(err: DatumAccessError) -> ColumnConvertError {
591        ColumnConvertError::DatumAccessError(err)
592    }
593}
594
595impl fmt::Display for ColumnConvertError {
596    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
597        match self {
598            ColumnConvertError::UnexpectedNullValue(t) => {
599                write!(f, "expecting value of type {} but got NULL", t)
600            }
601            ColumnConvertError::DatumAccessError(_) => {
602                write!(f, "problem accessing datum")
603            }
604            ColumnConvertError::ValueOutOfRange { expected } => {
605                write!(f, "value is out of range for type {}", expected)
606            }
607        }
608    }
609}
610
611impl Error for ColumnConvertError {
612    fn source(&self) -> Option<&(dyn Error + 'static)> {
613        match self {
614            ColumnConvertError::DatumAccessError(err) => Some(err),
615            ColumnConvertError::UnexpectedNullValue(_) |
616            ColumnConvertError::ValueOutOfRange { .. } => None,
617        }
618    }
619}
620
621macro_rules! try_from_row_not_null {
622    ($t:ty) => {
623        impl<C: Configuration> TryFromColumn<C> for $t {
624            type Error = ColumnConvertError;
625            fn try_from_column<'i, 's, 'c, S>(column: Column<'i, 's, 'c, S, C>) -> Result<Self, Self::Error> {
626                let value: Option<$t> = TryFromColumn::try_from_column(column)?;
627                value.ok_or_else(|| ColumnConvertError::UnexpectedNullValue(stringify!($t)))
628            }
629        }
630    }
631}
632
633macro_rules! try_from_row {
634    ($t:ty, $f:ident) => {
635        impl<C: Configuration> TryFromColumn<C> for Option<$t> {
636            type Error = ColumnConvertError;
637            fn try_from_column<'i, 's, 'c, S>(column: Column<'i, 's, 'c, S, C>) -> Result<Self, Self::Error> {
638                column.$f().map_err(Into::into)
639            }
640        }
641
642        try_from_row_not_null!($t);
643    };
644}
645
646macro_rules! try_from_row_unsigned {
647    ($it:ty, $t:ty) => {
648        impl<C: Configuration> TryFromColumn<C> for Option<$t> {
649            type Error = ColumnConvertError;
650            fn try_from_column<'i, 's, 'c, S>(column: Column<'i, 's, 'c, S, C>) -> Result<Self, Self::Error> {
651                let value: Option<$it> = TryFromColumn::try_from_column(column)?;
652                value.map(|value|
653                    value
654                    .try_into()
655                    .map_err(|_| ColumnConvertError::ValueOutOfRange {
656                        expected: stringify!($t),
657                    })
658                ).transpose()
659            }
660        }
661
662        try_from_row_not_null!($t);
663    };
664}
665
666try_from_row![bool, into_bool];
667try_from_row![i8, into_i8];
668try_from_row_unsigned![i8, u8];
669try_from_row![i16, into_i16];
670try_from_row_unsigned![i16, u16];
671try_from_row![i32, into_i32];
672try_from_row_unsigned![i32, u32];
673try_from_row![i64, into_i64];
674try_from_row_unsigned![i64, u64];
675try_from_row![f32, into_f32];
676try_from_row![f64, into_f64];
677try_from_row![String, into_string];
678try_from_row![SqlTimestamp, into_timestamp];
679try_from_row![SqlDate, into_date];
680try_from_row![SqlSsTime2, into_time];
681#[cfg(feature = "serde_json")]
682try_from_row![serde_json::Value, into_json];
683
684#[cfg(feature = "chrono")]
685use chrono::{NaiveDateTime, NaiveDate, NaiveTime};
686
687#[cfg(feature = "chrono")]
688impl<C: Configuration> TryFromColumn<C> for Option<NaiveDateTime> {
689    type Error = ColumnConvertError;
690    fn try_from_column<'i, 's, 'c, S>(column: Column<'i, 's, 'c, S, C>) -> Result<Self, Self::Error> {
691        let value: Option<SqlTimestamp> = TryFromColumn::try_from_column(column)?;
692
693        Ok(value.map(|value| {
694            NaiveDate::from_ymd(
695                i32::from(value.year),
696                u32::from(value.month),
697                u32::from(value.day),
698            )
699            .and_hms_nano(
700                u32::from(value.hour),
701                u32::from(value.minute),
702                u32::from(value.second),
703                value.fraction,
704            )
705        }))
706    }
707}
708
709#[cfg(feature = "chrono")]
710try_from_row_not_null!(NaiveDateTime);
711
712#[cfg(feature = "chrono")]
713impl<C: Configuration> TryFromColumn<C> for Option<NaiveDate> {
714    type Error = ColumnConvertError;
715    fn try_from_column<'i, 's, 'c, S>(column: Column<'i, 's, 'c, S, C>) -> Result<Self, Self::Error> {
716        let value: Option<SqlDate> = TryFromColumn::try_from_column(column)?;
717
718        Ok(value.map(|value| {
719            NaiveDate::from_ymd(
720                i32::from(value.year),
721                u32::from(value.month),
722                u32::from(value.day),
723            )
724        }))
725    }
726}
727
728#[cfg(feature = "chrono")]
729try_from_row_not_null!(NaiveDate);
730
731#[cfg(feature = "chrono")]
732impl<C: Configuration> TryFromColumn<C> for Option<NaiveTime> {
733    type Error = ColumnConvertError;
734    fn try_from_column<'i, 's, 'c, S>(column: Column<'i, 's, 'c, S, C>) -> Result<Self, Self::Error> {
735        let value: Option<SqlSsTime2> = TryFromColumn::try_from_column(column)?;
736
737        Ok(value.map(|value| {
738            NaiveTime::from_hms_nano(
739                u32::from(value.hour),
740                u32::from(value.minute),
741                u32::from(value.second),
742                value.fraction,
743            )
744        }))
745    }
746}
747
748#[cfg(feature = "chrono")]
749try_from_row_not_null!(NaiveTime);
750
751/// Errors that may happen during conversion of `ValueRow` to given type.
752#[derive(Debug)]
753pub enum RowConvertError {
754    UnexpectedNullValue(&'static str),
755    UnexpectedValue,
756    UnexpectedNumberOfColumns { expected: u16, got: u16 },
757    ColumnConvertError(Box<dyn Error>),
758}
759
760impl From<ColumnConvertError> for RowConvertError {
761    fn from(err: ColumnConvertError) -> RowConvertError {
762        RowConvertError::ColumnConvertError(Box::new(err))
763    }
764}
765
766impl fmt::Display for RowConvertError {
767    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
768        match self {
769            RowConvertError::UnexpectedNullValue(t) => {
770                write!(f, "expecting value of type {} but got NULL", t)
771            }
772            RowConvertError::UnexpectedValue => write!(f, "expecting no data (unit) but got a row"),
773            RowConvertError::UnexpectedNumberOfColumns { expected, got } => write!(
774                f,
775                "unexpected number of columns: expected {} but got {}",
776                expected, got
777            ),
778            RowConvertError::ColumnConvertError(_) => {
779                write!(f, "failed to convert column value to target type")
780            }
781        }
782    }
783}
784
785impl Error for RowConvertError {
786    fn source(&self) -> Option<&(dyn Error + 'static)> {
787        match self {
788            RowConvertError::UnexpectedNullValue(_)
789            | RowConvertError::UnexpectedValue
790            | RowConvertError::UnexpectedNumberOfColumns { .. } => None,
791            RowConvertError::ColumnConvertError(err) => Some(err.as_ref()),
792        }
793    }
794}
795
796/// Unit can be used to signal that no rows of data should be produced.
797impl TryFromRow<DefaultConfiguration> for () {
798    type Error = RowConvertError;
799    fn try_from_row<'r, 's, 'c, S>(_row: Row<'r, 's, 'c, S, DefaultConfiguration>) -> Result<Self, Self::Error> {
800        Err(RowConvertError::UnexpectedValue)
801    }
802}
803
804/// Convert row with single column to any type implementing `TryFromColumn`.
805impl<T> TryFromRow<DefaultConfiguration> for T
806where
807    T: TryFromColumn<DefaultConfiguration>,
808{
809    type Error = RowConvertError;
810    fn try_from_row<'r, 's, 'c, S>(mut row: Row<'r, 's, 'c, S, DefaultConfiguration>) -> Result<Self, Self::Error> {
811        if row.columns() != 1 {
812            return Err(RowConvertError::UnexpectedNumberOfColumns {
813                expected: 1,
814                got: row.columns(),
815            });
816        }
817
818        let column = row.shift_column().unwrap();
819
820        TryFromColumn::try_from_column(column)
821            .map_err(|e| RowConvertError::ColumnConvertError(Box::new(e)))
822
823    }
824}
825
826/// Errors that my arise when converting rows to tuples.
827#[derive(Debug)]
828pub enum RowConvertTupleError {
829    UnexpectedNumberOfColumns { expected: u16, tuple: &'static str },
830    ValueConvertError(Box<dyn Error>),
831}
832
833impl fmt::Display for RowConvertTupleError {
834    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
835        match self {
836            RowConvertTupleError::UnexpectedNumberOfColumns { expected, tuple } => write!(
837                f,
838                "failed to convert row with {} columns to tuple {}",
839                expected, tuple
840            ),
841            RowConvertTupleError::ValueConvertError(_) => {
842                write!(f, "failed to convert column value to target type")
843            }
844        }
845    }
846}
847
848impl Error for RowConvertTupleError {
849    fn source(&self) -> Option<&(dyn Error + 'static)> {
850        match self {
851            RowConvertTupleError::UnexpectedNumberOfColumns { .. } => None,
852            RowConvertTupleError::ValueConvertError(err) => Some(err.as_ref()),
853        }
854    }
855}
856
857macro_rules! count {
858    () => (0u16);
859    ( $x:tt $($xs:tt)* ) => (1u16 + count!($($xs)*));
860}
861
862macro_rules! try_from_tuple {
863    ($(
864        $Tuple:ident {
865            $(($idx:tt) -> $T:ident)+
866        }
867    )+) => {
868        $(
869            impl<C: Configuration, $($T: TryFromColumn<C>),+> TryFromRow<C> for ($($T,)+) {
870                type Error = RowConvertTupleError;
871                fn try_from_row<'r, 's, 'c, S>(mut row: Row<'r, 's, 'c, S, C>) -> Result<($($T,)+), Self::Error> {
872                    if row.columns() != count!($($T)+) {
873                        return Err(RowConvertTupleError::UnexpectedNumberOfColumns { expected: row.columns(), tuple: stringify![($($T,)+)] })
874                    }
875                    Ok(($({ let x: $T = $T::try_from_column(row.shift_column().unwrap()).map_err(|err| RowConvertTupleError::ValueConvertError(Box::new(err)))?; x},)+))
876                }
877            }
878        )+
879    }
880}
881
882try_from_tuple! {
883    Tuple1 {
884        (0) -> TA
885    }
886    Tuple2 {
887        (0) -> TA
888        (1) -> TB
889    }
890    Tuple3 {
891        (0) -> TA
892        (1) -> TB
893        (2) -> TC
894    }
895    Tuple4 {
896        (0) -> TA
897        (1) -> TB
898        (2) -> TC
899        (3) -> TD
900    }
901    Tuple5 {
902        (0) -> TA
903        (1) -> TB
904        (2) -> TC
905        (3) -> TD
906        (4) -> TE
907    }
908    Tuple6 {
909        (0) -> TA
910        (1) -> TB
911        (2) -> TC
912        (3) -> TD
913        (4) -> TE
914        (5) -> TF
915    }
916    Tuple7 {
917        (0) -> TA
918        (1) -> TB
919        (2) -> TC
920        (3) -> TD
921        (4) -> TE
922        (5) -> TF
923        (6) -> TG
924    }
925    Tuple8 {
926        (0) -> TA
927        (1) -> TB
928        (2) -> TC
929        (3) -> TD
930        (4) -> TE
931        (5) -> TF
932        (6) -> TG
933        (7) -> TH
934    }
935    Tuple9 {
936        (0) -> TA
937        (1) -> TB
938        (2) -> TC
939        (3) -> TD
940        (4) -> TE
941        (5) -> TF
942        (6) -> TG
943        (7) -> TH
944        (8) -> TI
945    }
946    Tuple10 {
947        (0) -> TA
948        (1) -> TB
949        (2) -> TC
950        (3) -> TD
951        (4) -> TE
952        (5) -> TF
953        (6) -> TG
954        (7) -> TH
955        (8) -> TI
956        (9) -> TJ
957    }
958    Tuple11 {
959        (0) -> TA
960        (1) -> TB
961        (2) -> TC
962        (3) -> TD
963        (4) -> TE
964        (5) -> TF
965        (6) -> TG
966        (7) -> TH
967        (8) -> TI
968        (9) -> TJ
969        (10) -> TK
970    }
971    Tuple12 {
972        (0) -> TA
973        (1) -> TB
974        (2) -> TC
975        (3) -> TD
976        (4) -> TE
977        (5) -> TF
978        (6) -> TG
979        (7) -> TH
980        (8) -> TI
981        (9) -> TJ
982        (10) -> TK
983        (11) -> TL
984    }
985    Tuple13 {
986        (0) -> TA
987        (1) -> TB
988        (2) -> TC
989        (3) -> TD
990        (4) -> TE
991        (5) -> TF
992        (6) -> TG
993        (7) -> TH
994        (8) -> TI
995        (9) -> TJ
996        (10) -> TK
997        (11) -> TL
998        (13) -> TM
999    }
1000    Tuple14 {
1001        (0) -> TA
1002        (1) -> TB
1003        (2) -> TC
1004        (3) -> TD
1005        (4) -> TE
1006        (5) -> TF
1007        (6) -> TG
1008        (7) -> TH
1009        (8) -> TI
1010        (9) -> TJ
1011        (10) -> TK
1012        (11) -> TL
1013        (13) -> TM
1014        (14) -> TN
1015    }
1016    Tuple15 {
1017        (0) -> TA
1018        (1) -> TB
1019        (2) -> TC
1020        (3) -> TD
1021        (4) -> TE
1022        (5) -> TF
1023        (6) -> TG
1024        (7) -> TH
1025        (8) -> TI
1026        (9) -> TJ
1027        (10) -> TK
1028        (11) -> TL
1029        (13) -> TM
1030        (14) -> TN
1031        (15) -> TO
1032    }
1033    Tuple16 {
1034        (0) -> TA
1035        (1) -> TB
1036        (2) -> TC
1037        (3) -> TD
1038        (4) -> TE
1039        (5) -> TF
1040        (6) -> TG
1041        (7) -> TH
1042        (8) -> TI
1043        (9) -> TJ
1044        (10) -> TK
1045        (11) -> TL
1046        (13) -> TM
1047        (14) -> TN
1048        (15) -> TO
1049        (16) -> TP
1050    }
1051    Tuple17 {
1052        (0) -> TA
1053        (1) -> TB
1054        (2) -> TC
1055        (3) -> TD
1056        (4) -> TE
1057        (5) -> TF
1058        (6) -> TG
1059        (7) -> TH
1060        (8) -> TI
1061        (9) -> TJ
1062        (10) -> TK
1063        (11) -> TL
1064        (13) -> TM
1065        (14) -> TN
1066        (15) -> TO
1067        (16) -> TP
1068        (17) -> TQ
1069    }
1070    Tuple18 {
1071        (0) -> TA
1072        (1) -> TB
1073        (2) -> TC
1074        (3) -> TD
1075        (4) -> TE
1076        (5) -> TF
1077        (6) -> TG
1078        (7) -> TH
1079        (8) -> TI
1080        (9) -> TJ
1081        (10) -> TK
1082        (11) -> TL
1083        (13) -> TM
1084        (14) -> TN
1085        (15) -> TO
1086        (16) -> TP
1087        (17) -> TQ
1088        (18) -> TR
1089    }
1090    Tuple19 {
1091        (0) -> TA
1092        (1) -> TB
1093        (2) -> TC
1094        (3) -> TD
1095        (4) -> TE
1096        (5) -> TF
1097        (6) -> TG
1098        (7) -> TH
1099        (8) -> TI
1100        (9) -> TJ
1101        (10) -> TK
1102        (11) -> TL
1103        (13) -> TM
1104        (14) -> TN
1105        (15) -> TO
1106        (16) -> TP
1107        (17) -> TQ
1108        (18) -> TR
1109        (19) -> TS
1110    }
1111    Tuple20 {
1112        (0) -> TA
1113        (1) -> TB
1114        (2) -> TC
1115        (3) -> TD
1116        (4) -> TE
1117        (5) -> TF
1118        (6) -> TG
1119        (7) -> TH
1120        (8) -> TI
1121        (9) -> TJ
1122        (10) -> TK
1123        (11) -> TL
1124        (13) -> TM
1125        (14) -> TN
1126        (15) -> TO
1127        (16) -> TP
1128        (17) -> TQ
1129        (18) -> TR
1130        (19) -> TS
1131        (20) -> TT
1132    }
1133    Tuple21 {
1134        (0) -> TA
1135        (1) -> TB
1136        (2) -> TC
1137        (3) -> TD
1138        (4) -> TE
1139        (5) -> TF
1140        (6) -> TG
1141        (7) -> TH
1142        (8) -> TI
1143        (9) -> TJ
1144        (10) -> TK
1145        (11) -> TL
1146        (13) -> TM
1147        (14) -> TN
1148        (15) -> TO
1149        (16) -> TP
1150        (17) -> TQ
1151        (18) -> TR
1152        (19) -> TS
1153        (20) -> TT
1154        (21) -> TU
1155    }
1156    Tuple22 {
1157        (0) -> TA
1158        (1) -> TB
1159        (2) -> TC
1160        (3) -> TD
1161        (4) -> TE
1162        (5) -> TF
1163        (6) -> TG
1164        (7) -> TH
1165        (8) -> TI
1166        (9) -> TJ
1167        (10) -> TK
1168        (11) -> TL
1169        (13) -> TM
1170        (14) -> TN
1171        (15) -> TO
1172        (16) -> TP
1173        (17) -> TQ
1174        (18) -> TR
1175        (19) -> TS
1176        (20) -> TT
1177        (21) -> TU
1178        (22) -> TV
1179    }
1180    Tuple23 {
1181        (0) -> TA
1182        (1) -> TB
1183        (2) -> TC
1184        (3) -> TD
1185        (4) -> TE
1186        (5) -> TF
1187        (6) -> TG
1188        (7) -> TH
1189        (8) -> TI
1190        (9) -> TJ
1191        (10) -> TK
1192        (11) -> TL
1193        (13) -> TM
1194        (14) -> TN
1195        (15) -> TO
1196        (16) -> TP
1197        (17) -> TQ
1198        (18) -> TR
1199        (19) -> TS
1200        (20) -> TT
1201        (21) -> TU
1202        (22) -> TV
1203        (23) -> TW
1204    }
1205    Tuple24 {
1206        (0) -> TA
1207        (1) -> TB
1208        (2) -> TC
1209        (3) -> TD
1210        (4) -> TE
1211        (5) -> TF
1212        (6) -> TG
1213        (7) -> TH
1214        (8) -> TI
1215        (9) -> TJ
1216        (10) -> TK
1217        (11) -> TL
1218        (13) -> TM
1219        (14) -> TN
1220        (15) -> TO
1221        (16) -> TP
1222        (17) -> TQ
1223        (18) -> TR
1224        (19) -> TS
1225        (20) -> TT
1226        (21) -> TU
1227        (22) -> TV
1228        (23) -> TW
1229        (24) -> TY
1230    }
1231}