1use std::mem::size_of;
18
19use odbc_sys::{SQLLEN, SQL_NULL_DATA};
20use serde::ser::{Serialize, SerializeStruct, Serializer};
21
22use crate::binder::with_indicator;
23
24#[derive(Clone, Copy, Debug)]
25pub struct Nullable<T> {
26 indicator: SQLLEN,
27 value: T,
28}
29
30impl<T: Serialize> Serialize for Nullable<T> {
31 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
32 let mut serializer = serializer.serialize_struct("Nullable", 1)?;
33 with_indicator(&self.indicator as *const _ as *mut _, || {
34 serializer.serialize_field("value", &self.value)
35 })?;
36 serializer.end()
37 }
38}
39
40impl<T> Nullable<T> {
41 pub fn as_ref(&self) -> Option<&T> {
42 match self.indicator {
43 SQL_NULL_DATA => None,
44 _ => Some(&self.value),
45 }
46 }
47
48 pub fn as_mut(&mut self) -> Option<&mut T> {
49 match self.indicator {
50 SQL_NULL_DATA => None,
51 _ => Some(&mut self.value),
52 }
53 }
54}
55
56impl<T: Default> Default for Nullable<T> {
57 fn default() -> Self {
58 Self {
59 indicator: SQL_NULL_DATA,
60 value: Default::default(),
61 }
62 }
63}
64
65impl<T: Default> From<Option<T>> for Nullable<T> {
66 fn from(value: Option<T>) -> Self {
67 match value {
68 None => Default::default(),
69 Some(value) => Nullable {
70 indicator: size_of::<T>() as SQLLEN,
71 value,
72 },
73 }
74 }
75}
76
77impl<T> Into<Option<T>> for Nullable<T> {
78 fn into(self) -> Option<T> {
79 match self.indicator {
80 SQL_NULL_DATA => None,
81 _ => Some(self.value),
82 }
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89
90 use crate::{
91 col_binding::Cols,
92 connection::{Connection, Environment},
93 param_binding::Params,
94 statement::Statement,
95 tests::CONN_STR,
96 };
97
98 #[test]
99 fn bind_nullable_param() {
100 let env = Environment::new().unwrap();
101 let conn = Connection::new(&env, CONN_STR).unwrap();
102
103 let mut stmt: Statement<Params<Nullable<i32>>, Cols<i32>> =
104 Statement::new(&conn, "SELECT ?").unwrap();
105 *stmt.params() = Some(42).into();
106 stmt.exec().unwrap();
107 assert!(stmt.fetch().unwrap());
108 assert_eq!(42, *stmt.cols());
109 assert!(!stmt.fetch().unwrap());
110 }
111
112 #[test]
113 fn bind_nullable_col() {
114 let env = Environment::new().unwrap();
115 let conn = Connection::new(&env, CONN_STR).unwrap();
116
117 let mut stmt: Statement<Params<i32>, Cols<Nullable<i32>>> =
118 Statement::new(&conn, "SELECT ?").unwrap();
119 *stmt.params() = 42;
120 stmt.exec().unwrap();
121 assert!(stmt.fetch().unwrap());
122 assert_eq!(Some(42), (*stmt.cols()).into());
123 assert!(!stmt.fetch().unwrap());
124 }
125}