1use std::num::NonZeroUsize;
2
3use odbc_sys::SqlDataType;
4
5use crate::{
6 ColumnDescription, DataType, Error, Nullability,
7 handles::{AsStatementRef, SqlChar, Statement, slice_to_utf8},
8};
9
10pub trait ResultSetMetadata: AsStatementRef {
17 fn describe_col(
27 &mut self,
28 column_number: u16,
29 column_description: &mut ColumnDescription,
30 ) -> Result<(), Error> {
31 let stmt = self.as_stmt_ref();
32 stmt.describe_col(column_number, column_description)
33 .into_result(&stmt)
34 }
35
36 fn num_result_cols(&mut self) -> Result<i16, Error> {
43 let stmt = self.as_stmt_ref();
44 stmt.num_result_cols().into_result(&stmt)
45 }
46
47 fn column_is_unsigned(&mut self, column_number: u16) -> Result<bool, Error> {
52 let stmt = self.as_stmt_ref();
53 stmt.is_unsigned_column(column_number).into_result(&stmt)
54 }
55
56 fn col_octet_length(&mut self, column_number: u16) -> Result<Option<NonZeroUsize>, Error> {
61 let stmt = self.as_stmt_ref();
62 stmt.col_octet_length(column_number)
63 .into_result(&stmt)
64 .map(|signed| NonZeroUsize::new(signed.max(0) as usize))
65 }
66
67 fn col_display_size(&mut self, column_number: u16) -> Result<Option<NonZeroUsize>, Error> {
72 let stmt = self.as_stmt_ref();
73 stmt.col_display_size(column_number)
74 .into_result(&stmt)
75 .map(|signed| NonZeroUsize::new(signed.max(0) as usize))
82 }
83
84 fn col_precision(&mut self, column_number: u16) -> Result<isize, Error> {
90 let stmt = self.as_stmt_ref();
91 stmt.col_precision(column_number).into_result(&stmt)
92 }
93
94 fn col_scale(&mut self, column_number: u16) -> Result<isize, Error> {
97 let stmt = self.as_stmt_ref();
98 stmt.col_scale(column_number).into_result(&stmt)
99 }
100
101 fn col_nullability(&mut self, column_number: u16) -> Result<Nullability, Error> {
108 let stmt = self.as_stmt_ref();
109 stmt.col_nullability(column_number).into_result(&stmt)
110 }
111
112 fn col_name(&mut self, column_number: u16) -> Result<String, Error> {
115 let stmt = self.as_stmt_ref();
116 let mut buf = vec![0; 1024];
117 stmt.col_name(column_number, &mut buf).into_result(&stmt)?;
118 Ok(slice_to_utf8(&buf).unwrap())
119 }
120
121 fn column_names(&mut self) -> Result<ColumnNamesIt<'_, Self>, Error> {
125 ColumnNamesIt::new(self)
126 }
127
128 fn col_data_type(&mut self, column_number: u16) -> Result<DataType, Error> {
132 let stmt = self.as_stmt_ref();
136 let kind = stmt.col_concise_type(column_number).into_result(&stmt)?;
137 let dt = match kind {
138 SqlDataType::UNKNOWN_TYPE => DataType::Unknown,
139 SqlDataType::EXT_VAR_BINARY => DataType::Varbinary {
140 length: self.col_octet_length(column_number)?,
141 },
142 SqlDataType::EXT_LONG_VAR_BINARY => DataType::LongVarbinary {
143 length: self.col_octet_length(column_number)?,
144 },
145 SqlDataType::EXT_BINARY => DataType::Binary {
146 length: self.col_octet_length(column_number)?,
147 },
148 SqlDataType::EXT_W_VARCHAR => DataType::WVarchar {
149 length: self.col_display_size(column_number)?,
150 },
151 SqlDataType::EXT_W_CHAR => DataType::WChar {
152 length: self.col_display_size(column_number)?,
153 },
154 SqlDataType::EXT_LONG_VARCHAR => DataType::LongVarchar {
155 length: self.col_display_size(column_number)?,
156 },
157 SqlDataType::EXT_W_LONG_VARCHAR => DataType::WLongVarchar {
158 length: self.col_display_size(column_number)?,
159 },
160 SqlDataType::CHAR => DataType::Char {
161 length: self.col_display_size(column_number)?,
162 },
163 SqlDataType::VARCHAR => DataType::Varchar {
164 length: self.col_display_size(column_number)?,
165 },
166 SqlDataType::NUMERIC => DataType::Numeric {
167 precision: self.col_precision(column_number)?.try_into().unwrap(),
168 scale: self.col_scale(column_number)?.try_into().unwrap(),
169 },
170 SqlDataType::DECIMAL => DataType::Decimal {
171 precision: self.col_precision(column_number)?.try_into().unwrap(),
172 scale: self.col_scale(column_number)?.try_into().unwrap(),
173 },
174 SqlDataType::INTEGER => DataType::Integer,
175 SqlDataType::SMALLINT => DataType::SmallInt,
176 SqlDataType::FLOAT => DataType::Float {
177 precision: self.col_precision(column_number)?.try_into().unwrap(),
178 },
179 SqlDataType::REAL => DataType::Real,
180 SqlDataType::DOUBLE => DataType::Double,
181 SqlDataType::DATE => DataType::Date,
182 SqlDataType::TIME => DataType::Time {
183 precision: self.col_precision(column_number)?.try_into().unwrap(),
184 },
185 SqlDataType::TIMESTAMP => DataType::Timestamp {
186 precision: self.col_precision(column_number)?.try_into().unwrap(),
187 },
188 SqlDataType::EXT_BIG_INT => DataType::BigInt,
189 SqlDataType::EXT_TINY_INT => DataType::TinyInt,
190 SqlDataType::EXT_BIT => DataType::Bit,
191 other => {
192 let mut column_description = ColumnDescription::default();
193 self.describe_col(column_number, &mut column_description)?;
194 DataType::Other {
195 data_type: other,
196 column_size: column_description.data_type.column_size(),
197 decimal_digits: column_description.data_type.decimal_digits(),
198 }
199 }
200 };
201 Ok(dt)
202 }
203}
204
205pub fn utf8_display_sizes(
216 metadata: &mut impl ResultSetMetadata,
217) -> Result<impl Iterator<Item = Result<Option<NonZeroUsize>, Error>> + '_, Error> {
218 let num_cols: u16 = metadata.num_result_cols()?.try_into().unwrap();
219 let it = (1..(num_cols + 1)).map(move |col_index| {
220 let max_str_len = if let Some(encoded_len) = metadata.col_data_type(col_index)?.utf8_len() {
222 Some(encoded_len)
223 } else {
224 metadata.col_display_size(col_index)?
225 };
226 Ok(max_str_len)
227 });
228 Ok(it)
229}
230
231pub struct ColumnNamesIt<'c, C: ?Sized> {
234 cursor: &'c mut C,
235 buffer: Vec<SqlChar>,
236 column: u16,
237 num_cols: u16,
238}
239
240impl<'c, C: ResultSetMetadata + ?Sized> ColumnNamesIt<'c, C> {
241 fn new(cursor: &'c mut C) -> Result<Self, Error> {
242 let num_cols = cursor.num_result_cols()?.try_into().unwrap();
243 Ok(Self {
244 cursor,
245 buffer: Vec::with_capacity(128),
249 num_cols,
250 column: 1,
251 })
252 }
253}
254
255impl<C> Iterator for ColumnNamesIt<'_, C>
256where
257 C: ResultSetMetadata,
258{
259 type Item = Result<String, Error>;
260
261 fn next(&mut self) -> Option<Self::Item> {
262 if self.column <= self.num_cols {
263 let stmt = self.cursor.as_stmt_ref();
266
267 let result = stmt
268 .col_name(self.column, &mut self.buffer)
269 .into_result(&stmt)
270 .map(|()| slice_to_utf8(&self.buffer).unwrap());
271 self.column += 1;
272 Some(result)
273 } else {
274 None
275 }
276 }
277
278 fn size_hint(&self) -> (usize, Option<usize>) {
279 let num_cols = self.num_cols as usize;
280 (num_cols, Some(num_cols))
281 }
282}
283
284impl<C> ExactSizeIterator for ColumnNamesIt<'_, C> where C: ResultSetMetadata {}