odbc_api/handles/
column_description.rs

1use super::{
2    data_type::DataType,
3    sql_char::{DecodingError, SqlChar, slice_to_utf8},
4};
5
6/// Indication of whether a column is nullable or not.
7#[derive(Clone, Copy, Hash, Debug, Eq, PartialEq, Default)]
8pub enum Nullability {
9    /// Indicates that we do not know whether the column is Nullable or not.
10    #[default]
11    Unknown,
12    /// The column may hold NULL values.
13    Nullable,
14    /// The column can not hold NULL values.
15    NoNulls,
16}
17
18impl Nullability {
19    /// Construct a new instance from a `Nullability` new type constant.
20    ///
21    /// ```
22    /// use odbc_api::Nullability;
23    ///
24    /// assert_eq!(Nullability::Unknown, Nullability::new(odbc_sys::Nullability::UNKNOWN));
25    /// assert_eq!(Nullability::NoNulls, Nullability::new(odbc_sys::Nullability::NO_NULLS));
26    /// assert_eq!(Nullability::Nullable, Nullability::new(odbc_sys::Nullability::NULLABLE));
27    /// ```
28    pub fn new(nullability: odbc_sys::Nullability) -> Self {
29        match nullability {
30            odbc_sys::Nullability::UNKNOWN => Nullability::Unknown,
31            odbc_sys::Nullability::NO_NULLS => Nullability::NoNulls,
32            odbc_sys::Nullability::NULLABLE => Nullability::Nullable,
33            other => panic!("ODBC returned invalid value for Nullable: {}", other.0),
34        }
35    }
36
37    /// `true` if the column is `Nullable` or it is not know whether the column is nullable. `false`
38    /// if and only if the column is `NoNulls`.
39    pub fn could_be_nullable(&self) -> bool {
40        match self {
41            Nullability::Nullable | Nullability::Unknown => true,
42            Nullability::NoNulls => false,
43        }
44    }
45}
46
47/// Describes the type and attributes of a column.
48#[derive(Clone, Debug, Eq, PartialEq, Default)]
49pub struct ColumnDescription {
50    /// Column name. May be empty if unavailable.
51    pub name: Vec<SqlChar>,
52    /// Type of the column
53    pub data_type: DataType,
54    /// Indicates whether the column is nullable or not.
55    pub nullability: Nullability,
56}
57
58impl ColumnDescription {
59    /// In production, an 'empty' [`ColumnDescription`] is expected to be constructed via the
60    /// [`Default`] trait. It is then filled using [`crate::ResultSetMetadata::describe_col`]. When
61    /// writing test cases however it might be desirable to directly instantiate a
62    /// [`ColumnDescription`]. This constructor enables you to do that, without caring which type
63    /// `SqlChar` resolves to.
64    pub fn new(name: &str, data_type: DataType, nullability: Nullability) -> Self {
65        #[cfg(not(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows"))))]
66        pub fn utf8_to_vec_char(text: &str) -> Vec<u8> {
67            text.to_owned().into_bytes()
68        }
69        #[cfg(any(feature = "wide", all(not(feature = "narrow"), target_os = "windows")))]
70        pub fn utf8_to_vec_char(text: &str) -> Vec<u16> {
71            use widestring::U16String;
72            U16String::from_str(text).into_vec()
73        }
74        Self {
75            name: utf8_to_vec_char(name),
76            data_type,
77            nullability,
78        }
79    }
80
81    /// Converts the internal UTF16 representation of the column name into UTF8 and returns the
82    /// result as a `String`.
83    pub fn name_to_string(&self) -> Result<String, DecodingError> {
84        slice_to_utf8(&self.name)
85    }
86
87    /// `true` if the column is `Nullable` or it is not know whether the column is nullable. `false`
88    /// if and only if the column is `NoNulls`.
89    pub fn could_be_nullable(&self) -> bool {
90        self.nullability.could_be_nullable()
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use crate::Nullability;
97
98    /// Application should panic if ODBC driver returns unsupported value for nullable
99    #[test]
100    #[should_panic(expected = "ODBC returned invalid value for Nullable: 5")]
101    fn invalid_nullable_representation() {
102        Nullability::new(odbc_sys::Nullability(5));
103    }
104}