1use itertools::all;
2use odbc_api::{DataType, Nullability};
3use std::borrow::Cow;
4use std::num::NonZeroUsize;
5
6pub fn format_type(dtype: &DataType) -> String {
7 match dtype {
8 DataType::Unknown => String::from("UNKNOWN"),
9 DataType::Char { length } => format_varchar("CHAR", length),
10 DataType::WChar { length } => format_varchar("WCHAR", length),
11 DataType::Numeric { precision, scale } => format_numeric("NUMERIC", *precision, *scale),
12 DataType::Decimal { precision, scale } => format_numeric("DECIMAL", *precision, *scale),
13 DataType::Integer => String::from("INTEGER"),
14 DataType::SmallInt => String::from("SMALLINT"),
15 DataType::Float { precision } => format_float("FLOAT", *precision),
16 DataType::Real => String::from("REAL"),
17 DataType::Double => String::from("DOUBLE"),
18 DataType::Varchar { length } => format_varchar("VARCHAR", length),
19 DataType::WVarchar { length } => format_varchar("WVARCHAR", length),
20 DataType::LongVarchar { length } => format_varchar("LONGVARCHAR", length),
21 DataType::WLongVarchar { length } => format_varchar("WLONGVARCHAR", length),
22 DataType::LongVarbinary { length } => format_varchar("LONGVARBINARY", length),
23 DataType::Date => String::from("DATE"),
24 DataType::Time { precision } => format_time("TIME", *precision),
25 DataType::Timestamp { precision } => format_time("TIMESTAMP", *precision),
26 DataType::BigInt => String::from("BIGINT"),
27 DataType::TinyInt => String::from("TINYINT"),
28 DataType::Bit => String::from("BIT"),
29 DataType::Varbinary { length } => format_varchar("VARBINARY", length),
30 DataType::Binary { length } => format_varchar("BINARY", length),
31 DataType::Other { .. } => String::from("OTHER"),
32 }
33}
34
35fn format_varchar(name: &str, length: &Option<NonZeroUsize>) -> String {
36 if let Some(length) = length {
37 format!("{name}({length})")
38 } else {
39 format!("{name}")
40 }
41}
42
43fn format_numeric(name: &str, precision: usize, scale: i16) -> String {
44 format!("{name}({precision}, {scale})")
45}
46
47fn format_float(name: &str, precision: usize) -> String {
48 format!("{name}({precision})")
49}
50
51fn format_time(name: &str, precision: i16) -> String {
52 format!("{name}({precision})")
53}
54
55pub fn format_null(null: &Nullability) -> &'static str {
56 match null {
57 Nullability::Unknown => "UNKNOWN",
58 Nullability::Nullable => "NULL",
59 Nullability::NoNulls => "NOT NULL",
60 }
61}
62
63pub fn parse_type(dtype: Cow<str>, dsize: usize, dprec: usize) -> Cow<str> {
64 let dtype = dtype.to_uppercase();
65 if all(dtype.chars(), char::is_uppercase) {
66 let dtype = match dtype.as_str() {
67 "CHAR" | "VARCHAR" | "LONGVARCHAR" |
68 "WCHAR" | "WVARCHAR" | "WLONGVARCHAR" |
69 "NCHAR" | "NVARCHAR" | "NLONGVARCHAR" |
70 "BINARY" | "VARBINARY" | "LONGVARBINARY" |
71 "TEXT" | "FLOAT" | "TIME" | "TIMESTAMP" if dsize != 0 => {
72 format!("{}({})", dtype, dsize)
73 }
74 "NUMERIC" | "DECIMAL" if dsize != 0 => {
75 format!("{}({}, {})", dtype, dsize, dprec)
76 }
77 _ => {
78 dtype
79 }
80 };
81 Cow::Owned(dtype)
82 } else {
83 Cow::Owned(dtype)
84 }
85}
86
87pub fn parse_null(value: Cow<str>) -> Nullability {
88 match value.as_ref() {
89 "0" | "YES" => Nullability::Nullable,
90 "1" | "NO" => Nullability::NoNulls,
91 _ => Nullability::Unknown,
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use crate::cow_str;
98 use crate::util::convert::{format_null, format_type, parse_null, parse_type};
99 use odbc_api::sys::SqlDataType;
100 use odbc_api::DataType::*;
101 use odbc_api::Nullability;
102 use pretty_assertions::assert_eq;
103 use std::borrow::Cow;
104 use std::num::NonZeroUsize;
105
106 #[test]
107 fn test_sized_varchar_data_types_are_formatted() {
108 assert_eq!(format_type(&Char { length: NonZeroUsize::new(20) }), "CHAR(20)");
109 assert_eq!(format_type(&WChar { length: NonZeroUsize::new(20) }), "WCHAR(20)");
110 assert_eq!(format_type(&Varchar { length: NonZeroUsize::new(20) }), "VARCHAR(20)");
111 assert_eq!(format_type(&WVarchar { length: NonZeroUsize::new(20) }), "WVARCHAR(20)");
112 assert_eq!(format_type(&LongVarchar { length: NonZeroUsize::new(20) }), "LONGVARCHAR(20)");
113 assert_eq!(format_type(&WLongVarchar { length: NonZeroUsize::new(20) }), "WLONGVARCHAR(20)");
114 assert_eq!(format_type(&Binary { length: NonZeroUsize::new(20) }), "BINARY(20)");
115 assert_eq!(format_type(&Varbinary { length: NonZeroUsize::new(20) }), "VARBINARY(20)");
116 assert_eq!(format_type(&LongVarbinary { length: NonZeroUsize::new(20) }), "LONGVARBINARY(20)");
117 }
118
119 #[test]
120 fn test_unsized_varchar_data_types_are_formatted() {
121 assert_eq!(format_type(&Char { length: None }), "CHAR");
122 assert_eq!(format_type(&WChar { length: None }), "WCHAR");
123 assert_eq!(format_type(&Varchar { length: None }), "VARCHAR");
124 assert_eq!(format_type(&WVarchar { length: None }), "WVARCHAR");
125 assert_eq!(format_type(&LongVarchar { length: None }), "LONGVARCHAR");
126 assert_eq!(format_type(&WLongVarchar { length: None }), "WLONGVARCHAR");
127 assert_eq!(format_type(&Binary { length: None }), "BINARY");
128 assert_eq!(format_type(&Varbinary { length: None }), "VARBINARY");
129 assert_eq!(format_type(&LongVarbinary { length: None }), "LONGVARBINARY");
130 }
131
132 #[test]
133 fn test_numeric_and_decimal_data_types_are_formatted() {
134 assert_eq!(format_type(&Numeric { precision: 10, scale: 2 }), "NUMERIC(10, 2)");
135 assert_eq!(format_type(&Decimal { precision: 10, scale: 2 }), "DECIMAL(10, 2)");
136 }
137
138 #[test]
139 fn test_float_and_time_data_types_are_formatted() {
140 assert_eq!(format_type(&Float { precision: 10 }), "FLOAT(10)");
141 assert_eq!(format_type(&Time { precision: 10 }), "TIME(10)");
142 assert_eq!(format_type(&Timestamp { precision: 10 }), "TIMESTAMP(10)");
143 }
144
145 #[test]
146 fn test_integer_and_other_data_types_are_formatted() {
147 assert_eq!(format_type(&Unknown), "UNKNOWN");
148 assert_eq!(format_type(&Integer), "INTEGER");
149 assert_eq!(format_type(&SmallInt), "SMALLINT");
150 assert_eq!(format_type(&Real), "REAL");
151 assert_eq!(format_type(&Double), "DOUBLE");
152 assert_eq!(format_type(&Date), "DATE");
153 assert_eq!(format_type(&BigInt), "BIGINT");
154 assert_eq!(format_type(&TinyInt), "TINYINT");
155 assert_eq!(format_type(&Bit), "BIT");
156 assert_eq!(format_type(&Other { data_type: SqlDataType::UNKNOWN_TYPE, column_size: None, decimal_digits: 0 }), "OTHER");
157 }
158
159 #[test]
160 fn test_nullability_types_are_formatted() {
161 assert_eq!(format_null(&Nullability::Unknown), "UNKNOWN");
162 assert_eq!(format_null(&Nullability::Nullable), "NULL");
163 assert_eq!(format_null(&Nullability::NoNulls), "NOT NULL");
164 }
165
166 #[test]
167 fn test_sized_varchar_data_types_are_parsed() {
168 assert_eq!(parse_type(cow_str!("CHAR(10)"), 15, 0), "CHAR(10)");
169 assert_eq!(parse_type(cow_str!("WCHAR(10)"), 15, 0), "WCHAR(10)");
170 assert_eq!(parse_type(cow_str!("NCHAR(10)"), 15, 0), "NCHAR(10)");
171 assert_eq!(parse_type(cow_str!("VARCHAR(10)"), 15, 0), "VARCHAR(10)");
172 assert_eq!(parse_type(cow_str!("WVARCHAR(10)"), 15, 0), "WVARCHAR(10)");
173 assert_eq!(parse_type(cow_str!("NVARCHAR(10)"), 15, 0), "NVARCHAR(10)");
174 assert_eq!(parse_type(cow_str!("LONGVARCHAR(10)"), 15, 0), "LONGVARCHAR(10)");
175 assert_eq!(parse_type(cow_str!("WLONGVARCHAR(10)"), 15, 0), "WLONGVARCHAR(10)");
176 assert_eq!(parse_type(cow_str!("NLONGVARCHAR(10)"), 15, 0), "NLONGVARCHAR(10)");
177 assert_eq!(parse_type(cow_str!("BINARY(10)"), 15, 0), "BINARY(10)");
178 assert_eq!(parse_type(cow_str!("VARBINARY(10)"), 15, 0), "VARBINARY(10)");
179 assert_eq!(parse_type(cow_str!("LONGVARBINARY(10)"), 15, 0), "LONGVARBINARY(10)");
180 assert_eq!(parse_type(cow_str!("TEXT(10)"), 15, 0), "TEXT(10)");
181 }
182
183 #[test]
184 fn test_unsized_varchar_data_types_are_parsed() {
185 assert_eq!(parse_type(cow_str!("CHAR"), 15, 0), "CHAR(15)");
186 assert_eq!(parse_type(cow_str!("WCHAR"), 15, 0), "WCHAR(15)");
187 assert_eq!(parse_type(cow_str!("NCHAR"), 15, 0), "NCHAR(15)");
188 assert_eq!(parse_type(cow_str!("VARCHAR"), 15, 0), "VARCHAR(15)");
189 assert_eq!(parse_type(cow_str!("WVARCHAR"), 15, 0), "WVARCHAR(15)");
190 assert_eq!(parse_type(cow_str!("NVARCHAR"), 15, 0), "NVARCHAR(15)");
191 assert_eq!(parse_type(cow_str!("LONGVARCHAR"), 15, 0), "LONGVARCHAR(15)");
192 assert_eq!(parse_type(cow_str!("WLONGVARCHAR"), 15, 0), "WLONGVARCHAR(15)");
193 assert_eq!(parse_type(cow_str!("NLONGVARCHAR"), 15, 0), "NLONGVARCHAR(15)");
194 assert_eq!(parse_type(cow_str!("BINARY"), 15, 0), "BINARY(15)");
195 assert_eq!(parse_type(cow_str!("VARBINARY"), 15, 0), "VARBINARY(15)");
196 assert_eq!(parse_type(cow_str!("LONGVARBINARY"), 15, 0), "LONGVARBINARY(15)");
197 assert_eq!(parse_type(cow_str!("TEXT"), 15, 0), "TEXT(15)");
198 }
199
200 #[test]
201 fn test_unknown_varchar_data_types_are_parsed() {
202 assert_eq!(parse_type(cow_str!("CHAR"), 0, 0), "CHAR");
203 assert_eq!(parse_type(cow_str!("WCHAR"), 0, 0), "WCHAR");
204 assert_eq!(parse_type(cow_str!("NCHAR"), 0, 0), "NCHAR");
205 assert_eq!(parse_type(cow_str!("VARCHAR"), 0, 0), "VARCHAR");
206 assert_eq!(parse_type(cow_str!("WVARCHAR"), 0, 0), "WVARCHAR");
207 assert_eq!(parse_type(cow_str!("NVARCHAR"), 0, 0), "NVARCHAR");
208 assert_eq!(parse_type(cow_str!("LONGVARCHAR"), 0, 0), "LONGVARCHAR");
209 assert_eq!(parse_type(cow_str!("WLONGVARCHAR"), 0, 0), "WLONGVARCHAR");
210 assert_eq!(parse_type(cow_str!("NLONGVARCHAR"), 0, 0), "NLONGVARCHAR");
211 assert_eq!(parse_type(cow_str!("BINARY"), 0, 0), "BINARY");
212 assert_eq!(parse_type(cow_str!("VARBINARY"), 0, 0), "VARBINARY");
213 assert_eq!(parse_type(cow_str!("LONGVARBINARY"), 0, 0), "LONGVARBINARY");
214 assert_eq!(parse_type(cow_str!("TEXT"), 0, 0), "TEXT");
215 }
216
217 #[test]
218 fn test_sized_numeric_and_decimal_data_types_are_parsed() {
219 assert_eq!(parse_type(cow_str!("NUMERIC(10, 2)"), 15, 3), "NUMERIC(10, 2)");
220 assert_eq!(parse_type(cow_str!("DECIMAL(10, 2)"), 15, 3), "DECIMAL(10, 2)");
221 }
222
223 #[test]
224 fn test_unsized_numeric_and_decimal_data_types_are_parsed() {
225 assert_eq!(parse_type(cow_str!("NUMERIC"), 15, 3), "NUMERIC(15, 3)");
226 assert_eq!(parse_type(cow_str!("DECIMAL"), 15, 3), "DECIMAL(15, 3)");
227 }
228
229 #[test]
230 fn test_unknown_numeric_and_decimal_data_types_are_parsed() {
231 assert_eq!(parse_type(cow_str!("NUMERIC"), 0, 3), "NUMERIC");
232 assert_eq!(parse_type(cow_str!("DECIMAL"), 0, 3), "DECIMAL");
233 }
234
235 #[test]
236 fn test_sized_float_and_time_data_types_are_parsed() {
237 assert_eq!(parse_type(cow_str!("FLOAT(10)"), 15, 0), "FLOAT(10)");
238 assert_eq!(parse_type(cow_str!("TIME(10)"), 15, 0), "TIME(10)");
239 assert_eq!(parse_type(cow_str!("TIMESTAMP(10)"), 15, 0), "TIMESTAMP(10)");
240 }
241
242 #[test]
243 fn test_unsized_float_and_time_data_types_are_parsed() {
244 assert_eq!(parse_type(cow_str!("FLOAT"), 15, 0), "FLOAT(15)");
245 assert_eq!(parse_type(cow_str!("TIME"), 15, 0), "TIME(15)");
246 assert_eq!(parse_type(cow_str!("TIMESTAMP"), 15, 0), "TIMESTAMP(15)");
247 }
248
249 #[test]
250 fn test_unknown_float_and_time_data_types_are_parsed() {
251 assert_eq!(parse_type(cow_str!("FLOAT"), 0, 0), "FLOAT");
252 assert_eq!(parse_type(cow_str!("TIME"), 0, 0), "TIME");
253 assert_eq!(parse_type(cow_str!("TIMESTAMP"), 0, 0), "TIMESTAMP");
254 }
255
256 #[test]
257 fn test_sized_integer_and_other_data_types_are_parsed() {
258 assert_eq!(parse_type(cow_str!("UNKNOWN(10)"), 15, 0), "UNKNOWN(10)");
259 assert_eq!(parse_type(cow_str!("INTEGER(10)"), 15, 0), "INTEGER(10)");
260 assert_eq!(parse_type(cow_str!("SMALLINT(10)"), 15, 0), "SMALLINT(10)");
261 assert_eq!(parse_type(cow_str!("REAL(10)"), 15, 0), "REAL(10)");
262 assert_eq!(parse_type(cow_str!("DOUBLE(10)"), 15, 0), "DOUBLE(10)");
263 assert_eq!(parse_type(cow_str!("DATE(10)"), 15, 0), "DATE(10)");
264 assert_eq!(parse_type(cow_str!("BIGINT(10)"), 15, 0), "BIGINT(10)");
265 assert_eq!(parse_type(cow_str!("TINYINT(10)"), 15, 0), "TINYINT(10)");
266 assert_eq!(parse_type(cow_str!("BIT(10)"), 15, 0), "BIT(10)");
267 assert_eq!(parse_type(cow_str!("OTHER(10)"), 15, 0), "OTHER(10)");
268 }
269
270 #[test]
271 fn test_unsized_integer_and_other_data_types_are_parsed() {
272 assert_eq!(parse_type(cow_str!("UNKNOWN"), 15, 0), "UNKNOWN");
273 assert_eq!(parse_type(cow_str!("INTEGER"), 15, 0), "INTEGER");
274 assert_eq!(parse_type(cow_str!("SMALLINT"), 15, 0), "SMALLINT");
275 assert_eq!(parse_type(cow_str!("REAL"), 15, 0), "REAL");
276 assert_eq!(parse_type(cow_str!("DOUBLE"), 15, 0), "DOUBLE");
277 assert_eq!(parse_type(cow_str!("DATE"), 15, 0), "DATE");
278 assert_eq!(parse_type(cow_str!("BIGINT"), 15, 0), "BIGINT");
279 assert_eq!(parse_type(cow_str!("TINYINT"), 15, 0), "TINYINT");
280 assert_eq!(parse_type(cow_str!("BIT"), 15, 0), "BIT");
281 assert_eq!(parse_type(cow_str!("OTHER"), 15, 0), "OTHER");
282 }
283
284 #[test]
285 fn test_unknown_integer_and_other_data_types_are_parsed() {
286 assert_eq!(parse_type(cow_str!("UNKNOWN"), 0, 0), "UNKNOWN");
287 assert_eq!(parse_type(cow_str!("INTEGER"), 0, 0), "INTEGER");
288 assert_eq!(parse_type(cow_str!("SMALLINT"), 0, 0), "SMALLINT");
289 assert_eq!(parse_type(cow_str!("REAL"), 0, 0), "REAL");
290 assert_eq!(parse_type(cow_str!("DOUBLE"), 0, 0), "DOUBLE");
291 assert_eq!(parse_type(cow_str!("DATE"), 0, 0), "DATE");
292 assert_eq!(parse_type(cow_str!("BIGINT"), 0, 0), "BIGINT");
293 assert_eq!(parse_type(cow_str!("TINYINT"), 0, 0), "TINYINT");
294 assert_eq!(parse_type(cow_str!("BIT"), 0, 0), "BIT");
295 assert_eq!(parse_type(cow_str!("OTHER"), 0, 0), "OTHER");
296 }
297
298 #[test]
299 fn test_nullability_types_are_parsed() {
300 assert_eq!(parse_null(cow_str!("0")), Nullability::Nullable); assert_eq!(parse_null(cow_str!("1")), Nullability::NoNulls); assert_eq!(parse_null(cow_str!("YES")), Nullability::Nullable); assert_eq!(parse_null(cow_str!("NO")), Nullability::NoNulls); assert_eq!(parse_null(cow_str!("")), Nullability::Unknown);
305 }
306}