1use std::mem::size_of;
2
3use odbc_sys::{Date, Numeric, Time, Timestamp};
4
5use crate::{Bit, DataType, TooLargeBufferSize};
6
7use super::{
8 BinColumn, BoxColumnBuffer, TextColumn,
9 column_with_indicator::{
10 OptBitColumn, OptDateColumn, OptF32Column, OptF64Column, OptI8Column, OptI16Column,
11 OptI32Column, OptI64Column, OptTimeColumn, OptTimestampColumn, OptU8Column,
12 },
13};
14
15#[derive(Clone, Copy, Debug, PartialEq, Eq)]
24pub enum BufferDesc {
25 Binary {
27 max_bytes: usize,
29 },
30 Text {
42 max_str_len: usize,
45 },
46 WText {
49 max_str_len: usize,
52 },
53 F64 {
55 nullable: bool,
58 },
59 F32 {
61 nullable: bool,
64 },
65 Date {
67 nullable: bool,
70 },
71 Time {
73 nullable: bool,
76 },
77 Timestamp {
79 nullable: bool,
82 },
83 I8 {
85 nullable: bool,
88 },
89 I16 {
91 nullable: bool,
94 },
95 I32 {
97 nullable: bool,
100 },
101 I64 {
103 nullable: bool,
106 },
107 U8 {
109 nullable: bool,
112 },
113 Bit {
115 nullable: bool,
118 },
119 Numeric,
132}
133
134impl BufferDesc {
135 pub fn from_data_type(data_type: DataType, nullable: bool) -> Option<Self> {
136 let buffer_desc = match data_type {
137 DataType::Numeric { precision, scale }
138 | DataType::Decimal { precision, scale } if scale == 0 && precision < 3 => BufferDesc::I8 { nullable },
139 DataType::Numeric { precision, scale }
140 | DataType::Decimal { precision, scale } if scale == 0 && precision < 10 => BufferDesc::I32 { nullable },
141 DataType::Numeric { precision, scale }
142 | DataType::Decimal { precision, scale } if scale == 0 && precision < 19 => BufferDesc::I64 { nullable },
143 DataType::Integer => BufferDesc::I32 { nullable },
144 DataType::SmallInt => BufferDesc::I16 { nullable },
145 DataType::Float { precision: 0..=24 } | DataType::Real => BufferDesc::F32 { nullable },
146 DataType::Float { precision: 25..=53 } |DataType::Double => BufferDesc::F64 { nullable },
147 DataType::Date => BufferDesc::Date { nullable },
148 DataType::Time { precision: 0 } => BufferDesc::Time { nullable },
149 DataType::Timestamp { precision: _ } => BufferDesc::Timestamp { nullable },
150 DataType::BigInt => BufferDesc::I64 { nullable },
151 DataType::TinyInt => BufferDesc::I8 { nullable },
152 DataType::Bit => BufferDesc::Bit { nullable },
153 DataType::Varbinary { length }
154 | DataType::Binary { length }
155 | DataType::LongVarbinary { length } => length.map(|l| BufferDesc::Binary { max_bytes: l.get() })?,
156 DataType::Varchar { length }
157 | DataType::WVarchar { length }
158 | DataType::WChar {length }
160 | DataType::Char { length }
161 | DataType::WLongVarchar { length }
162 | DataType::LongVarchar { length } => {
163 length.map(|length| BufferDesc::Text { max_str_len : length.get() } )?
164 },
165 | DataType::Numeric { precision: _, scale: _ }
167 | DataType::Decimal { precision: _, scale: _ }
168 | DataType::Time { precision: _ } => BufferDesc::Text { max_str_len: data_type.display_size().unwrap().get() },
169 DataType::Unknown
170 | DataType::Float { precision: _ }
171 | DataType::Other { data_type: _, column_size: _, decimal_digits: _ } => return None,
172 };
173 Some(buffer_desc)
174 }
175
176 pub fn bytes_per_row(&self) -> usize {
179 let size_indicator = |nullable: bool| if nullable { size_of::<isize>() } else { 0 };
180 match *self {
181 BufferDesc::Binary { max_bytes: length } => length + size_indicator(true),
182 BufferDesc::Text { max_str_len } => max_str_len + 1 + size_indicator(true),
183 BufferDesc::WText { max_str_len } => (max_str_len + 1) * 2 + size_indicator(true),
184 BufferDesc::F64 { nullable } => size_of::<f64>() + size_indicator(nullable),
185 BufferDesc::F32 { nullable } => size_of::<f32>() + size_indicator(nullable),
186 BufferDesc::Date { nullable } => size_of::<Date>() + size_indicator(nullable),
187 BufferDesc::Time { nullable } => size_of::<Time>() + size_indicator(nullable),
188 BufferDesc::Timestamp { nullable } => size_of::<Timestamp>() + size_indicator(nullable),
189 BufferDesc::I8 { nullable } => size_of::<i8>() + size_indicator(nullable),
190 BufferDesc::I16 { nullable } => size_of::<i16>() + size_indicator(nullable),
191 BufferDesc::I32 { nullable } => size_of::<i32>() + size_indicator(nullable),
192 BufferDesc::I64 { nullable } => size_of::<i64>() + size_indicator(nullable),
193 BufferDesc::U8 { nullable } => size_of::<u8>() + size_indicator(nullable),
194 BufferDesc::Bit { nullable } => size_of::<Bit>() + size_indicator(nullable),
195 BufferDesc::Numeric => size_of::<Numeric>(),
196 }
197 }
198
199 pub fn column_buffer(self, capacity: usize) -> BoxColumnBuffer {
201 self.impl_column_buffer(capacity, false).unwrap()
202 }
203
204 pub fn try_column_buffer(self, capacity: usize) -> Result<BoxColumnBuffer, TooLargeBufferSize> {
206 self.impl_column_buffer(capacity, true)
207 }
208
209 fn impl_column_buffer(
210 self,
211 capacity: usize,
212 fallible: bool,
213 ) -> Result<BoxColumnBuffer, TooLargeBufferSize> {
214 let buffer: BoxColumnBuffer = match self {
215 BufferDesc::Binary { max_bytes } => {
216 if fallible {
217 Box::new(BinColumn::try_new(capacity, max_bytes)?)
218 } else {
219 Box::new(BinColumn::new(capacity, max_bytes))
220 }
221 }
222 BufferDesc::Text { max_str_len } => {
223 if fallible {
224 Box::new(TextColumn::<u8>::try_new(capacity, max_str_len)?)
225 } else {
226 Box::new(TextColumn::<u8>::new(capacity, max_str_len))
227 }
228 }
229 BufferDesc::WText { max_str_len } => {
230 if fallible {
231 Box::new(TextColumn::<u16>::try_new(capacity, max_str_len)?)
232 } else {
233 Box::new(TextColumn::<u16>::new(capacity, max_str_len))
234 }
235 }
236 BufferDesc::F64 { nullable: false } => Box::new(vec![f64::default(); capacity]),
237 BufferDesc::F64 { nullable: true } => Box::new(OptF64Column::new(capacity)),
238 BufferDesc::F32 { nullable: false } => Box::new(vec![f32::default(); capacity]),
239 BufferDesc::F32 { nullable: true } => Box::new(OptF32Column::new(capacity)),
240 BufferDesc::Date { nullable: false } => Box::new(vec![Date::default(); capacity]),
241 BufferDesc::Date { nullable: true } => Box::new(OptDateColumn::new(capacity)),
242 BufferDesc::Time { nullable: false } => Box::new(vec![Time::default(); capacity]),
243 BufferDesc::Time { nullable: true } => Box::new(OptTimeColumn::new(capacity)),
244 BufferDesc::Timestamp { nullable: false } => {
245 Box::new(vec![Timestamp::default(); capacity])
246 }
247 BufferDesc::Timestamp { nullable: true } => Box::new(OptTimestampColumn::new(capacity)),
248 BufferDesc::I8 { nullable: false } => Box::new(vec![i8::default(); capacity]),
249 BufferDesc::I8 { nullable: true } => Box::new(OptI8Column::new(capacity)),
250 BufferDesc::I16 { nullable: false } => Box::new(vec![i16::default(); capacity]),
251 BufferDesc::I16 { nullable: true } => Box::new(OptI16Column::new(capacity)),
252 BufferDesc::I32 { nullable: false } => Box::new(vec![i32::default(); capacity]),
253 BufferDesc::I32 { nullable: true } => Box::new(OptI32Column::new(capacity)),
254 BufferDesc::I64 { nullable: false } => Box::new(vec![i64::default(); capacity]),
255 BufferDesc::I64 { nullable: true } => Box::new(OptI64Column::new(capacity)),
256 BufferDesc::U8 { nullable: false } => Box::new(vec![u8::default(); capacity]),
257 BufferDesc::U8 { nullable: true } => Box::new(OptU8Column::new(capacity)),
258 BufferDesc::Bit { nullable: false } => Box::new(vec![Bit::default(); capacity]),
259 BufferDesc::Bit { nullable: true } => Box::new(OptBitColumn::new(capacity)),
260 BufferDesc::Numeric => Box::new(vec![Numeric::default(); capacity]),
261 };
262 Ok(buffer)
263 }
264}
265
266#[cfg(test)]
267mod tests {
268
269 use super::*;
270
271 #[test]
272 #[cfg(target_pointer_width = "64")] fn bytes_per_row() {
274 assert_eq!(5 + 8, BufferDesc::Binary { max_bytes: 5 }.bytes_per_row());
275 assert_eq!(
276 5 + 1 + 8,
277 BufferDesc::Text { max_str_len: 5 }.bytes_per_row()
278 );
279 assert_eq!(
280 10 + 2 + 8,
281 BufferDesc::WText { max_str_len: 5 }.bytes_per_row()
282 );
283 assert_eq!(6, BufferDesc::Date { nullable: false }.bytes_per_row());
284 assert_eq!(6, BufferDesc::Time { nullable: false }.bytes_per_row());
285 assert_eq!(
286 16,
287 BufferDesc::Timestamp { nullable: false }.bytes_per_row()
288 );
289 assert_eq!(1, BufferDesc::Bit { nullable: false }.bytes_per_row());
290 assert_eq!(1 + 8, BufferDesc::Bit { nullable: true }.bytes_per_row());
291 assert_eq!(4, BufferDesc::F32 { nullable: false }.bytes_per_row());
292 assert_eq!(8, BufferDesc::F64 { nullable: false }.bytes_per_row());
293 assert_eq!(1, BufferDesc::I8 { nullable: false }.bytes_per_row());
294 assert_eq!(2, BufferDesc::I16 { nullable: false }.bytes_per_row());
295 assert_eq!(4, BufferDesc::I32 { nullable: false }.bytes_per_row());
296 assert_eq!(8, BufferDesc::I64 { nullable: false }.bytes_per_row());
297 assert_eq!(1, BufferDesc::U8 { nullable: false }.bytes_per_row());
298 assert_eq!(19, BufferDesc::Numeric.bytes_per_row());
299 }
300}