tds_driver/tds/codec/token/
token_row.rs1mod bytes_mut_with_data_columns;
2mod into_row;
3use crate::tds::codec::encode::Encode;
4use crate::{tds::codec::ColumnData, BytesMutWithTypeInfo, SqlReadBytes, TokenType};
5use bytes::BufMut;
6pub(crate) use bytes_mut_with_data_columns::BytesMutWithDataColumns;
7use futures_util::io::AsyncReadExt;
8pub use into_row::IntoRow;
9
10#[derive(Debug, Default, Clone)]
12#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
13pub struct TokenRow<'a> {
14 data: Vec<ColumnData<'a>>,
15}
16
17impl<'a> IntoIterator for TokenRow<'a> {
18 type Item = ColumnData<'a>;
19 type IntoIter = std::vec::IntoIter<Self::Item>;
20
21 fn into_iter(self) -> Self::IntoIter {
22 self.data.into_iter()
23 }
24}
25
26impl<'a> Encode<BytesMutWithDataColumns<'a>> for TokenRow<'a> {
27 fn encode(self, dst: &mut BytesMutWithDataColumns<'a>) -> crate::Result<()> {
28 dst.put_u8(TokenType::Row as u8);
29
30 if self.data.len() != dst.data_columns().len() {
31 return Err(crate::Error::BulkInput(
32 format!(
33 "Expecting {} columns but {} were given",
34 dst.data_columns().len(),
35 self.data.len()
36 )
37 .into(),
38 ));
39 }
40
41 for (value, column) in self.data.into_iter().zip(dst.data_columns()) {
42 let mut dst_ti = BytesMutWithTypeInfo::new(dst).with_type_info(&column.base.ty);
43 value.encode(&mut dst_ti)?
44 }
45
46 Ok(())
47 }
48}
49
50impl<'a> TokenRow<'a> {
51 pub const fn new() -> Self {
53 Self { data: Vec::new() }
54 }
55
56 pub fn with_capacity(capacity: usize) -> Self {
58 Self {
59 data: Vec::with_capacity(capacity),
60 }
61 }
62
63 pub fn clear(&mut self) {
67 self.data.clear();
68 }
69
70 pub fn len(&self) -> usize {
72 self.data.len()
73 }
74
75 pub fn iter(&self) -> std::slice::Iter<'_, ColumnData<'a>> {
77 self.data.iter()
78 }
79
80 pub fn is_empty(&self) -> bool {
82 self.data.is_empty()
83 }
84
85 pub fn get(&self, index: usize) -> Option<&ColumnData<'a>> {
88 self.data.get(index)
89 }
90
91 pub fn push(&mut self, value: ColumnData<'a>) {
93 self.data.push(value);
94 }
95}
96
97impl TokenRow<'static> {
98 pub(crate) async fn decode<R>(src: &mut R) -> crate::Result<Self>
101 where
102 R: SqlReadBytes + Unpin,
103 {
104 let col_meta = src.context().last_meta().ok_or_else(|| {
105 crate::Error::Protocol("ROW token arrived before any COLMETADATA".into())
106 })?;
107
108 let mut row = Self {
109 data: Vec::with_capacity(col_meta.columns.len()),
110 };
111
112 for column in col_meta.columns.iter() {
113 let data = ColumnData::decode(src, &column.base.ty).await?;
114 row.data.push(data);
115 }
116
117 Ok(row)
118 }
119
120 pub(crate) async fn decode_nbc<R>(src: &mut R) -> crate::Result<Self>
123 where
124 R: SqlReadBytes + Unpin,
125 {
126 let col_meta = src.context().last_meta().ok_or_else(|| {
127 crate::Error::Protocol("NBCROW token arrived before any COLMETADATA".into())
128 })?;
129 let row_bitmap = RowBitmap::decode(src, col_meta.columns.len()).await?;
130
131 let mut row = Self {
132 data: Vec::with_capacity(col_meta.columns.len()),
133 };
134
135 for (i, column) in col_meta.columns.iter().enumerate() {
136 let data = if row_bitmap.is_null(i) {
137 column.base.null_value()
138 } else {
139 ColumnData::decode(src, &column.base.ty).await?
140 };
141
142 row.data.push(data);
143 }
144
145 Ok(row)
146 }
147}
148
149enum RowBitmap {
166 Inline([u8; 32]),
168 Heap(Vec<u8>),
169}
170
171impl RowBitmap {
172 #[inline]
174 fn is_null(&self, i: usize) -> bool {
175 let data = match self {
176 Self::Inline(data) => &data[..],
177 Self::Heap(data) => &data[..],
178 };
179
180 data[i / 8] & (1 << (i % 8)) > 0
181 }
182
183 async fn decode<R>(src: &mut R, columns: usize) -> crate::Result<Self>
186 where
187 R: SqlReadBytes + Unpin,
188 {
189 let size = columns.div_ceil(8);
190 let mut bitmap = if size <= 32 {
191 Self::Inline([0; 32])
192 } else {
193 Self::Heap(vec![0; size])
194 };
195 let data = match &mut bitmap {
196 Self::Inline(data) => &mut data[..size],
197 Self::Heap(data) => &mut data[..],
198 };
199 src.read_exact(data).await?;
200
201 Ok(bitmap)
202 }
203}
204
205#[cfg(test)]
206mod tests {
207 use super::*;
208 use crate::{BaseMetaDataColumn, ColumnFlag, FixedLenType, MetaDataColumn, TypeInfo};
209 use bytes::BytesMut;
210
211 #[tokio::test]
212 async fn wrong_number_of_columns_will_fail() {
213 let row = (true, 5).into_row();
214 let columns = vec![MetaDataColumn {
215 base: BaseMetaDataColumn {
216 flags: ColumnFlag::Nullable.into(),
217 ty: TypeInfo::FixedLen(FixedLenType::Bit),
218 },
219 col_name: Default::default(),
220 }];
221 let mut buf = BytesMut::new();
222 let mut buf_with_columns = BytesMutWithDataColumns::new(&mut buf, &columns);
223
224 row.encode(&mut buf_with_columns)
225 .expect_err("wrong number of columns");
226 }
227
228 #[tokio::test]
229 async fn row_before_colmetadata_is_protocol_error() {
230 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
231 let buf = BytesMut::new();
234 let err = TokenRow::decode(&mut buf.into_sql_read_bytes())
235 .await
236 .expect_err("ROW before COLMETADATA must error");
237 assert!(matches!(err, crate::Error::Protocol(_)));
238 }
239
240 #[test]
241 fn basic_container_operations() {
242 let mut row = TokenRow::new();
243 assert!(row.is_empty());
244 assert_eq!(row.len(), 0);
245 assert_eq!(row.get(0), None);
246
247 row.push(ColumnData::I32(Some(1)));
248 row.push(ColumnData::I32(Some(2)));
249 assert_eq!(row.len(), 2);
250 assert!(!row.is_empty());
251 assert_eq!(row.get(0), Some(&ColumnData::I32(Some(1))));
252 assert_eq!(row.get(5), None);
253
254 let collected: Vec<_> = row.iter().collect();
255 assert_eq!(collected.len(), 2);
256
257 row.clear();
258 assert!(row.is_empty());
259
260 let with_cap = TokenRow::with_capacity(4);
261 assert!(with_cap.is_empty());
262 }
263
264 #[test]
265 fn with_capacity_preallocates() {
266 let row = TokenRow::with_capacity(16);
269 assert!(row.is_empty());
270 assert!(row.data.capacity() >= 16);
271 }
272
273 #[test]
274 fn row_bitmap_is_null_checks_correct_bit() {
275 let mut inline = [0; 32];
279 inline[0] = 0b0000_1000;
280 for bitmap in [
281 RowBitmap::Inline(inline),
282 RowBitmap::Heap(vec![0b0000_1000]),
283 ] {
284 assert!(bitmap.is_null(3));
285 assert!(!bitmap.is_null(0));
286 assert!(!bitmap.is_null(1));
287 assert!(!bitmap.is_null(2));
288 assert!(!bitmap.is_null(4));
289 }
290 }
291
292 #[tokio::test]
293 async fn row_bitmap_over_256_columns_is_read_whole() {
294 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
295
296 let mut bytes = [0u8; 38];
297 bytes[37] = 0b0000_1000; let mut src = bytes::BytesMut::from(&bytes[..]).into_sql_read_bytes();
299 let bitmap = RowBitmap::decode(&mut src, 300).await.unwrap();
300
301 assert!(matches!(bitmap, RowBitmap::Heap(_)));
302 assert!(bitmap.is_null(299));
303 assert!(!bitmap.is_null(298));
304 }
305
306 #[test]
307 fn into_iter_yields_owned_values() {
308 let mut row = TokenRow::new();
309 row.push(ColumnData::I32(Some(1)));
310 row.push(ColumnData::I32(Some(2)));
311
312 let values: Vec<_> = row.into_iter().collect();
313 assert_eq!(
314 values,
315 vec![ColumnData::I32(Some(1)), ColumnData::I32(Some(2))]
316 );
317 }
318
319 #[tokio::test]
320 async fn encode_matching_columns_round_trip() {
321 let row = (true, 5i32).into_row();
322 let columns = vec![
323 MetaDataColumn {
324 base: BaseMetaDataColumn {
325 flags: ColumnFlag::Nullable.into(),
326 ty: TypeInfo::FixedLen(FixedLenType::Bit),
327 },
328 col_name: Default::default(),
329 },
330 MetaDataColumn {
331 base: BaseMetaDataColumn {
332 flags: ColumnFlag::Nullable.into(),
333 ty: TypeInfo::FixedLen(FixedLenType::Int4),
334 },
335 col_name: Default::default(),
336 },
337 ];
338 let mut buf = BytesMut::new();
339 let mut buf_with_columns = BytesMutWithDataColumns::new(&mut buf, &columns);
340
341 row.encode(&mut buf_with_columns).unwrap();
342 assert!(!buf.is_empty());
343 }
344
345 #[tokio::test]
346 async fn decode_reads_columns_from_cached_meta() {
347 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
348 use crate::tds::codec::TokenColMetaData;
349 use std::sync::Arc;
350
351 let col_meta = TokenColMetaData {
352 columns: vec![MetaDataColumn {
353 base: BaseMetaDataColumn {
354 flags: ColumnFlag::Nullable.into(),
355 ty: TypeInfo::FixedLen(FixedLenType::Int4),
356 },
357 col_name: Default::default(),
358 }],
359 };
360
361 let mut buf = BytesMut::new();
362 buf.put_i32_le(42);
363
364 let mut reader = buf.into_sql_read_bytes();
365 reader.context_mut().set_last_meta(Arc::new(col_meta));
366
367 let row = TokenRow::decode(&mut reader).await.unwrap();
368 assert_eq!(row.len(), 1);
369 assert_eq!(row.get(0), Some(&ColumnData::I32(Some(42))));
370 }
371
372 #[tokio::test]
373 async fn decode_nbc_before_colmetadata_is_protocol_error() {
374 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
375
376 let buf = BytesMut::new();
377 let err = TokenRow::decode_nbc(&mut buf.into_sql_read_bytes())
378 .await
379 .expect_err("NBCROW before COLMETADATA must error");
380 assert!(matches!(err, crate::Error::Protocol(_)));
381 }
382
383 #[tokio::test]
384 async fn decode_nbc_uses_bitmap_for_nulls() {
385 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
386 use crate::tds::codec::TokenColMetaData;
387 use std::sync::Arc;
388
389 let col_meta = TokenColMetaData {
391 columns: vec![
392 MetaDataColumn {
393 base: BaseMetaDataColumn {
394 flags: ColumnFlag::Nullable.into(),
395 ty: TypeInfo::FixedLen(FixedLenType::Int4),
396 },
397 col_name: Default::default(),
398 },
399 MetaDataColumn {
400 base: BaseMetaDataColumn {
401 flags: ColumnFlag::Nullable.into(),
402 ty: TypeInfo::FixedLen(FixedLenType::Int4),
403 },
404 col_name: Default::default(),
405 },
406 ],
407 };
408
409 let mut buf = BytesMut::new();
410 buf.put_u8(0b0000_0001); buf.put_i32_le(7); let mut reader = buf.into_sql_read_bytes();
414 reader.context_mut().set_last_meta(Arc::new(col_meta));
415
416 let row = TokenRow::decode_nbc(&mut reader).await.unwrap();
417 assert_eq!(row.len(), 2);
418 assert_eq!(row.get(0), Some(&ColumnData::I32(None)));
419 assert_eq!(row.get(1), Some(&ColumnData::I32(Some(7))));
420 }
421}