sqlx_sqlserver/
type_info.rs1use std::fmt::{self, Display, Formatter};
2
3use sqlx_core::type_info::TypeInfo;
4
5use crate::protocol::type_info as protocol;
6
7#[derive(Debug, Clone, PartialEq, Eq)]
9pub enum MssqlType {
10 Null,
12 Bit,
14 TinyInt,
16 SmallInt,
18 Int,
20 BigInt,
22 Real,
24 Float,
26 NVarChar,
28 VarBinary,
30 Other(String),
32}
33
34#[derive(Debug, Clone, PartialEq, Eq)]
36pub struct MssqlTypeInfo {
37 kind: MssqlType,
38 variable_length: bool,
39 size: Option<u16>,
40 protocol_type_info: Option<protocol::TypeInfo>,
41}
42
43impl MssqlTypeInfo {
44 pub const fn new(kind: MssqlType) -> Self {
46 Self {
47 kind,
48 variable_length: false,
49 size: None,
50 protocol_type_info: None,
51 }
52 }
53
54 pub fn kind(&self) -> &MssqlType {
56 &self.kind
57 }
58
59 pub(crate) const fn protocol_type_info(&self) -> Option<&protocol::TypeInfo> {
60 self.protocol_type_info.as_ref()
61 }
62
63 pub const NULL: Self = Self::new(MssqlType::Null);
65 pub const BIT: Self = Self::new(MssqlType::Bit);
67 pub const TINYINT: Self = Self::new(MssqlType::TinyInt);
69 pub const SMALLINT: Self = Self::new(MssqlType::SmallInt);
71 pub const INT: Self = Self::new(MssqlType::Int);
73 pub const BIGINT: Self = Self::new(MssqlType::BigInt);
75 pub const REAL: Self = Self::new(MssqlType::Real);
77 pub const FLOAT: Self = Self::new(MssqlType::Float);
79 pub const NVARCHAR: Self = Self::new(MssqlType::NVarChar);
81 pub const VARBINARY: Self = Self::new(MssqlType::VarBinary);
83
84 pub(crate) fn from_protocol(type_info: &protocol::TypeInfo) -> Self {
85 let kind = match type_info.ty {
86 protocol::DataType::Null => MssqlType::Null,
87 protocol::DataType::Bit | protocol::DataType::BitN => MssqlType::Bit,
88 protocol::DataType::TinyInt => MssqlType::TinyInt,
89 protocol::DataType::SmallInt => MssqlType::SmallInt,
90 protocol::DataType::Int => MssqlType::Int,
91 protocol::DataType::BigInt => MssqlType::BigInt,
92 protocol::DataType::Real => MssqlType::Real,
93 protocol::DataType::Float => MssqlType::Float,
94 protocol::DataType::IntN => match type_info.size {
95 1 => MssqlType::TinyInt,
96 2 => MssqlType::SmallInt,
97 4 => MssqlType::Int,
98 8 => MssqlType::BigInt,
99 _ => MssqlType::Other(type_info.name().to_owned()),
100 },
101 protocol::DataType::FloatN => match type_info.size {
102 4 => MssqlType::Real,
103 8 => MssqlType::Float,
104 _ => MssqlType::Other(type_info.name().to_owned()),
105 },
106 protocol::DataType::NVarChar
107 | protocol::DataType::NChar
108 | protocol::DataType::VarChar
109 | protocol::DataType::Char
110 | protocol::DataType::BigVarChar
111 | protocol::DataType::BigChar => MssqlType::NVarChar,
112 protocol::DataType::VarBinary
113 | protocol::DataType::Binary
114 | protocol::DataType::BigVarBinary
115 | protocol::DataType::BigBinary => MssqlType::VarBinary,
116 _ => MssqlType::Other(type_info.name().to_owned()),
117 };
118
119 Self {
120 kind,
121 variable_length: type_info.is_nullable_or_variable_length(),
122 size: u16::try_from(type_info.size).ok(),
123 protocol_type_info: Some(type_info.clone()),
124 }
125 }
126}
127
128impl TypeInfo for MssqlTypeInfo {
129 fn is_null(&self) -> bool {
130 matches!(self.kind, MssqlType::Null)
131 }
132
133 fn name(&self) -> &str {
134 match &self.kind {
135 MssqlType::Null => "NULL",
136 MssqlType::Bit => "BIT",
137 MssqlType::TinyInt => "TINYINT",
138 MssqlType::SmallInt => "SMALLINT",
139 MssqlType::Int => "INT",
140 MssqlType::BigInt => "BIGINT",
141 MssqlType::Real => "REAL",
142 MssqlType::Float => "FLOAT",
143 MssqlType::NVarChar => "NVARCHAR",
144 MssqlType::VarBinary => "VARBINARY",
145 MssqlType::Other(name) => name,
146 }
147 }
148
149 fn type_compatible(&self, other: &Self) -> bool {
150 self.kind == other.kind || self.is_null() || other.is_null()
151 }
152}
153
154impl Display for MssqlTypeInfo {
155 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
156 f.write_str(self.name())
157 }
158}
159
160#[cfg(test)]
161mod tests {
162 use super::*;
163
164 #[test]
165 fn exposes_sql_server_type_names() {
166 assert_eq!("INT", MssqlTypeInfo::INT.name());
167 assert_eq!("NVARCHAR", MssqlTypeInfo::NVARCHAR.to_string());
168 }
169
170 #[test]
171 fn null_is_compatible_with_known_types() {
172 assert!(MssqlTypeInfo::NULL.type_compatible(&MssqlTypeInfo::INT));
173 assert!(MssqlTypeInfo::NVARCHAR.type_compatible(&MssqlTypeInfo::NULL));
174 assert!(!MssqlTypeInfo::INT.type_compatible(&MssqlTypeInfo::BIGINT));
175 }
176}