1mod binary;
2mod bit;
3mod bytes_mut_with_type_info;
4#[cfg(feature = "tds73")]
5mod date;
6#[cfg(feature = "tds73")]
7mod datetime2;
8mod datetimen;
9#[cfg(feature = "tds73")]
10mod datetimeoffsetn;
11mod fixed_len;
12mod float;
13mod guid;
14mod image;
15mod int;
16mod money;
17mod plp;
18mod sql_variant;
19mod string;
20mod text;
21#[cfg(feature = "tds73")]
22mod time;
23mod udt;
24mod var_len;
25mod xml;
26
27pub(crate) const MAX_PREALLOC: usize = 8192; pub(crate) const MAX_PLP_SIZE: usize = i32::MAX as usize;
46
47use super::{Encode, FixedLenType, TypeInfo, VarLenType};
48#[cfg(feature = "tds73")]
49use crate::tds::time::{Date, DateTime2, DateTimeOffset, Time};
50use crate::{
51 tds::{time::DateTime, time::SmallDateTime, xml::XmlData, Numeric},
52 FromSql, FromSqlOwned, IntoSql, SqlReadBytes, ToSql,
53};
54use bytes::BufMut;
55pub(crate) use bytes_mut_with_type_info::BytesMutWithTypeInfo;
56use std::borrow::{BorrowMut, Cow};
57use uuid::Uuid;
58
59const MAX_NVARCHAR_SIZE: usize = 1 << 30;
60
61#[cfg(feature = "tds73")]
64const DAYS_YEAR_1_TO_1900: u32 = 693_595;
65
66#[cfg(feature = "tds73")]
78fn datetime2_to_datetime(dt2: &DateTime2) -> crate::Result<DateTime> {
79 let dt2_days = dt2.date().days();
80
81 let days = dt2_days.checked_sub(DAYS_YEAR_1_TO_1900).ok_or_else(|| {
82 crate::Error::Conversion(
83 format!(
84 "invalid datetime, expecting a date not earlier than 1900-01-01 but got {} days after year 1",
85 dt2_days
86 )
87 .into(),
88 )
89 })? as i32;
90
91 let time = dt2.time();
95 let nanos = time.increments() as u128 * 10u128.pow(9 - time.scale() as u32);
96 let seconds_fragments = (nanos * 300 / 1_000_000_000) as u32;
97
98 Ok(DateTime::new(days, seconds_fragments))
99}
100
101#[derive(Clone, Debug, PartialEq)]
102#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
103pub enum ColumnData<'a> {
105 U8(Option<u8>),
107 I16(Option<i16>),
109 I32(Option<i32>),
111 I64(Option<i64>),
113 F32(Option<f32>),
115 F64(Option<f64>),
117 Bit(Option<bool>),
119 String(Option<Cow<'a, str>>),
121 Guid(Option<Uuid>),
123 Binary(Option<Cow<'a, [u8]>>),
125 Numeric(Option<Numeric>),
127 Xml(Option<Cow<'a, XmlData>>),
129 DateTime(Option<DateTime>),
131 SmallDateTime(Option<SmallDateTime>),
133 #[cfg(feature = "tds73")]
134 #[cfg_attr(docsrs, doc(cfg(feature = "tds73")))]
135 Time(Option<Time>),
137 #[cfg(feature = "tds73")]
138 #[cfg_attr(docsrs, doc(cfg(feature = "tds73")))]
139 Date(Option<Date>),
141 #[cfg(feature = "tds73")]
142 #[cfg_attr(docsrs, doc(cfg(feature = "tds73")))]
143 DateTime2(Option<DateTime2>),
145 #[cfg(feature = "tds73")]
146 #[cfg_attr(docsrs, doc(cfg(feature = "tds73")))]
147 DateTimeOffset(Option<DateTimeOffset>),
149}
150
151impl<'a> ColumnData<'a> {
152 pub(crate) fn type_name(&self) -> Cow<'static, str> {
153 match self {
154 ColumnData::U8(_) => "tinyint".into(),
155 ColumnData::I16(_) => "smallint".into(),
156 ColumnData::I32(_) => "int".into(),
157 ColumnData::I64(_) => "bigint".into(),
158 ColumnData::F32(_) => "float(24)".into(),
159 ColumnData::F64(_) => "float(53)".into(),
160 ColumnData::Bit(_) => "bit".into(),
161 ColumnData::String(None) => "nvarchar(4000)".into(),
162 ColumnData::String(Some(ref s)) if s.len() <= 4000 => "nvarchar(4000)".into(),
163 ColumnData::String(Some(ref s)) if s.len() <= MAX_NVARCHAR_SIZE => {
164 "nvarchar(max)".into()
165 }
166 ColumnData::String(_) => "ntext(max)".into(),
167 ColumnData::Guid(_) => "uniqueidentifier".into(),
168 ColumnData::Binary(Some(ref b)) if b.len() <= 8000 => "varbinary(8000)".into(),
169 ColumnData::Binary(_) => "varbinary(max)".into(),
170 ColumnData::Numeric(Some(ref n)) => {
171 format!("numeric({},{})", n.precision(), n.scale()).into()
172 }
173 ColumnData::Numeric(None) => "numeric".into(),
174 ColumnData::Xml(_) => "xml".into(),
175 ColumnData::DateTime(_) => "datetime".into(),
176 ColumnData::SmallDateTime(_) => "smalldatetime".into(),
177 #[cfg(feature = "tds73")]
178 ColumnData::Time(_) => "time".into(),
179 #[cfg(feature = "tds73")]
180 ColumnData::Date(_) => "date".into(),
181 #[cfg(feature = "tds73")]
182 ColumnData::DateTime2(_) => "datetime2".into(),
183 #[cfg(feature = "tds73")]
184 ColumnData::DateTimeOffset(_) => "datetimeoffset".into(),
185 }
186 }
187
188 pub(crate) async fn decode<R>(src: &mut R, ctx: &TypeInfo) -> crate::Result<ColumnData<'a>>
189 where
190 R: SqlReadBytes + Unpin,
191 {
192 let res = match ctx {
193 TypeInfo::FixedLen(fixed_ty) => fixed_len::decode(src, fixed_ty).await?,
194 TypeInfo::VarLenSized(cx) => var_len::decode(src, cx).await?,
195 TypeInfo::VarLenSizedPrecision { ty, scale, .. } => match ty {
196 VarLenType::Decimaln | VarLenType::Numericn => {
197 ColumnData::Numeric(Numeric::decode(src, *scale).await?)
198 }
199 _ => todo!(),
200 },
201 TypeInfo::Xml { schema, size } => xml::decode(src, *size, schema.clone()).await?,
202 TypeInfo::Udt(_) => udt::decode(src).await?,
203 };
204
205 Ok(res)
206 }
207}
208
209impl<'a> Encode<BytesMutWithTypeInfo<'a>> for ColumnData<'a> {
210 fn encode(self, dst: &mut BytesMutWithTypeInfo<'a>) -> crate::Result<()> {
211 match (self, dst.type_info()) {
212 (ColumnData::Bit(opt), Some(TypeInfo::VarLenSized(vlc)))
213 if vlc.r#type() == VarLenType::Bitn =>
214 {
215 if let Some(val) = opt {
216 dst.put_u8(1);
217 dst.put_u8(val as u8);
218 } else {
219 dst.put_u8(0);
220 }
221 }
222 (ColumnData::Bit(Some(val)), Some(TypeInfo::FixedLen(FixedLenType::Bit))) => {
223 dst.put_u8(val as u8);
224 }
225 (ColumnData::Bit(opt), None) => {
226 let header = [VarLenType::Bitn as u8, 1];
229 dst.extend_from_slice(&header);
230 if let Some(val) = opt {
231 dst.put_u8(1);
233 dst.put_u8(val as u8);
234 } else {
235 dst.put_u8(0);
236 }
237 }
238 (ColumnData::U8(opt), Some(TypeInfo::VarLenSized(vlc)))
239 if vlc.r#type() == VarLenType::Intn =>
240 {
241 if let Some(val) = opt {
242 dst.put_u8(1);
243 dst.put_u8(val);
244 } else {
245 dst.put_u8(0);
246 }
247 }
248 (ColumnData::U8(Some(val)), Some(TypeInfo::FixedLen(FixedLenType::Int1))) => {
249 dst.put_u8(val);
250 }
251 (ColumnData::U8(opt), None) => {
252 let header = [VarLenType::Intn as u8, 1];
253 dst.extend_from_slice(&header);
254 if let Some(val) = opt {
255 dst.put_u8(1);
256 dst.put_u8(val);
257 } else {
258 dst.put_u8(0);
259 }
260 }
261 (ColumnData::I16(Some(val)), Some(TypeInfo::FixedLen(FixedLenType::Int2))) => {
262 dst.put_i16_le(val);
263 }
264 (ColumnData::I16(opt), Some(TypeInfo::VarLenSized(vlc)))
265 if vlc.r#type() == VarLenType::Intn =>
266 {
267 if let Some(val) = opt {
268 dst.put_u8(2);
269 dst.put_i16_le(val);
270 } else {
271 dst.put_u8(0);
272 }
273 }
274 (ColumnData::I16(opt), None) => {
275 let header = [VarLenType::Intn as u8, 2];
276 dst.extend_from_slice(&header);
277 if let Some(val) = opt {
278 dst.put_u8(2);
279 dst.put_i16_le(val);
280 } else {
281 dst.put_u8(0);
282 }
283 }
284 (ColumnData::I32(Some(val)), Some(TypeInfo::FixedLen(FixedLenType::Int4))) => {
285 dst.put_i32_le(val);
286 }
287 (ColumnData::I32(opt), Some(TypeInfo::VarLenSized(vlc)))
288 if vlc.r#type() == VarLenType::Intn =>
289 {
290 if let Some(val) = opt {
291 dst.put_u8(4);
292 dst.put_i32_le(val);
293 } else {
294 dst.put_u8(0);
295 }
296 }
297 (ColumnData::I32(opt), None) => {
298 let header = [VarLenType::Intn as u8, 4];
299 dst.extend_from_slice(&header);
300 if let Some(val) = opt {
301 dst.put_u8(4);
302 dst.put_i32_le(val);
303 } else {
304 dst.put_u8(0);
305 }
306 }
307 (ColumnData::I64(Some(val)), Some(TypeInfo::FixedLen(FixedLenType::Int8))) => {
308 dst.put_i64_le(val);
309 }
310 (ColumnData::I64(opt), Some(TypeInfo::VarLenSized(vlc)))
311 if vlc.r#type() == VarLenType::Intn =>
312 {
313 if let Some(val) = opt {
314 dst.put_u8(8);
315 dst.put_i64_le(val);
316 } else {
317 dst.put_u8(0);
318 }
319 }
320 (ColumnData::I64(opt), None) => {
321 let header = [VarLenType::Intn as u8, 8];
322 dst.extend_from_slice(&header);
323 if let Some(val) = opt {
324 dst.put_u8(8);
325 dst.put_i64_le(val);
326 } else {
327 dst.put_u8(0);
328 }
329 }
330 (ColumnData::F32(Some(val)), Some(TypeInfo::FixedLen(FixedLenType::Float4))) => {
331 dst.put_f32_le(val);
332 }
333 (ColumnData::F32(opt), Some(TypeInfo::VarLenSized(vlc)))
334 if vlc.r#type() == VarLenType::Floatn =>
335 {
336 if let Some(val) = opt {
337 dst.put_u8(4);
338 dst.put_f32_le(val);
339 } else {
340 dst.put_u8(0);
341 }
342 }
343 (ColumnData::F32(opt), None) => {
344 let header = [VarLenType::Floatn as u8, 4];
345 dst.extend_from_slice(&header);
346 if let Some(val) = opt {
347 dst.put_u8(4);
348 dst.put_f32_le(val);
349 } else {
350 dst.put_u8(0);
351 }
352 }
353 (ColumnData::F64(Some(val)), Some(TypeInfo::FixedLen(FixedLenType::Float8))) => {
354 dst.put_f64_le(val);
355 }
356 (ColumnData::F64(opt), Some(TypeInfo::VarLenSized(vlc)))
357 if vlc.r#type() == VarLenType::Floatn =>
358 {
359 if let Some(val) = opt {
360 dst.put_u8(8);
361 dst.put_f64_le(val);
362 } else {
363 dst.put_u8(0);
364 }
365 }
366 (ColumnData::F64(opt), None) => {
367 let header = [VarLenType::Floatn as u8, 8];
368 dst.extend_from_slice(&header);
369 if let Some(val) = opt {
370 dst.put_u8(8);
371 dst.put_f64_le(val);
372 } else {
373 dst.put_u8(0);
374 }
375 }
376 (ColumnData::F64(opt), Some(TypeInfo::VarLenSized(vlc)))
377 if vlc.r#type() == VarLenType::Money =>
378 {
379 if let Some(val) = opt {
380 money::encode(dst, vlc.len(), val);
381 } else {
382 dst.put_u8(0);
383 }
384 }
385 (ColumnData::Guid(opt), Some(TypeInfo::VarLenSized(vlc)))
386 if vlc.r#type() == VarLenType::Guid =>
387 {
388 if let Some(uuid) = opt {
389 dst.put_u8(16);
390
391 let mut data = *uuid.as_bytes();
392 super::guid::reorder_bytes(&mut data);
393 dst.extend_from_slice(&data);
394 } else {
395 dst.put_u8(0);
396 }
397 }
398 (ColumnData::Guid(opt), None) => {
399 let header = [VarLenType::Guid as u8, 16];
400 dst.extend_from_slice(&header);
401 if let Some(uuid) = opt {
402 dst.put_u8(16);
403 let mut data = *uuid.as_bytes();
404 super::guid::reorder_bytes(&mut data);
405 dst.extend_from_slice(&data);
406 } else {
407 dst.put_u8(0);
408 }
409 }
410 (ColumnData::String(opt), Some(TypeInfo::VarLenSized(vlc)))
411 if vlc.r#type() == VarLenType::BigChar
412 || vlc.r#type() == VarLenType::BigVarChar =>
413 {
414 if let Some(str) = opt {
415 let mut encoder = vlc.collation().as_ref().unwrap().encoding()?.new_encoder();
416 let len = encoder
417 .max_buffer_length_from_utf8_without_replacement(str.len())
418 .unwrap();
419 let mut bytes = Vec::with_capacity(len);
420 let (res, _) = encoder.encode_from_utf8_to_vec_without_replacement(
421 str.as_ref(),
422 &mut bytes,
423 true,
424 );
425 if let encoding_rs::EncoderResult::Unmappable(_) = res {
426 return Err(crate::Error::Encoding("unrepresentable character".into()));
427 }
428
429 if bytes.len() > vlc.len() {
430 return Err(crate::Error::BulkInput(
431 format!(
432 "Encoded string length {} exceed column limit {}",
433 bytes.len(),
434 vlc.len()
435 )
436 .into(),
437 ));
438 }
439
440 if vlc.len() < 0xffff {
441 dst.put_u16_le(bytes.len() as u16);
442 dst.extend_from_slice(bytes.as_slice());
443 } else {
444 dst.put_u64_le(0xfffffffffffffffe);
446
447 assert!(
448 str.len() < 0xffffffff,
449 "if str longer than this, need to implement multiple blobs"
450 );
451
452 dst.put_u32_le(bytes.len() as u32);
453 dst.extend_from_slice(bytes.as_slice());
454
455 if !bytes.is_empty() {
456 dst.put_u32_le(0u32);
458 }
459 }
460 } else if vlc.len() < 0xffff {
461 dst.put_u16_le(0xffff);
462 } else {
463 dst.put_u64_le(0xffffffffffffffff)
464 }
465 }
466 (ColumnData::String(opt), Some(TypeInfo::VarLenSized(vlc)))
467 if vlc.r#type() == VarLenType::NVarchar || vlc.r#type() == VarLenType::NChar =>
468 {
469 if let Some(str) = opt {
470 if vlc.len() < 0xffff {
471 let len_pos = dst.len();
472 dst.put_u16_le(0u16);
473
474 for chr in str.encode_utf16() {
475 dst.put_u16_le(chr);
476 }
477
478 let length = dst.len() - len_pos - 2;
479
480 if length > vlc.len() {
481 return Err(crate::Error::BulkInput(
482 format!(
483 "Encoded string length {} exceed column limit {}",
484 length,
485 vlc.len()
486 )
487 .into(),
488 ));
489 }
490
491 let dst: &mut [u8] = dst.borrow_mut();
492 let mut dst = &mut dst[len_pos..];
493 dst.put_u16_le(length as u16);
494 } else {
495 dst.put_u64_le(0xfffffffffffffffe);
497
498 assert!(
499 str.len() < 0xffffffff,
500 "if str longer than this, need to implement multiple blobs"
501 );
502
503 let len_pos = dst.len();
504 dst.put_u32_le(0u32);
505
506 for chr in str.encode_utf16() {
507 dst.put_u16_le(chr);
508 }
509
510 let length = dst.len() - len_pos - 4;
511
512 if length > vlc.len() {
513 return Err(crate::Error::BulkInput(
514 format!(
515 "Encoded string length {} exceed column limit {}",
516 length,
517 vlc.len()
518 )
519 .into(),
520 ));
521 }
522
523 if length > 0 {
524 dst.put_u32_le(0u32);
526 }
527
528 let dst: &mut [u8] = dst.borrow_mut();
529 let mut dst = &mut dst[len_pos..];
530 dst.put_u32_le(length as u32);
531 }
532 } else if vlc.len() < 0xffff {
533 dst.put_u16_le(0xffff);
534 } else {
535 dst.put_u64_le(0xffffffffffffffff)
536 }
537 }
538 (ColumnData::String(opt), Some(TypeInfo::VarLenSized(vlc)))
539 if vlc.r#type() == VarLenType::Text || vlc.r#type() == VarLenType::NText =>
540 {
541 if let Some(str) = opt {
542 dst.put_u8(16); dst.extend_from_slice(&[0u8; 16]); dst.extend_from_slice(&[0u8; 8]); if vlc.r#type() == VarLenType::Text {
551 let mut encoder =
553 vlc.collation().as_ref().unwrap().encoding()?.new_encoder();
554 let len = encoder
555 .max_buffer_length_from_utf8_without_replacement(str.len())
556 .unwrap();
557 let mut bytes = Vec::with_capacity(len);
558 let (res, _) = encoder.encode_from_utf8_to_vec_without_replacement(
559 str.as_ref(),
560 &mut bytes,
561 true,
562 );
563 if let encoding_rs::EncoderResult::Unmappable(_) = res {
564 return Err(crate::Error::Encoding("unrepresentable character".into()));
565 }
566
567 dst.put_u32_le(bytes.len() as u32);
568 dst.extend_from_slice(bytes.as_slice());
569 } else {
570 let len_pos = dst.len();
572 dst.put_u32_le(0u32);
573
574 let mut length = 0u32;
575 for chr in str.encode_utf16() {
576 length += 2;
577 dst.put_u16_le(chr);
578 }
579
580 let dst: &mut [u8] = dst.borrow_mut();
581 let bytes = length.to_le_bytes();
582 dst[len_pos..len_pos + 4].copy_from_slice(&bytes);
583 }
584 } else {
585 dst.put_u8(0);
587 }
588 }
589 (ColumnData::String(Some(ref s)), None) if s.len() <= 4000 => {
590 dst.put_u8(VarLenType::NVarchar as u8);
591 dst.put_u16_le(8000);
592 dst.extend_from_slice(&[0u8; 5][..]);
593
594 let mut length = 0u16;
595 let len_pos = dst.len();
596
597 dst.put_u16_le(length);
598
599 for chr in s.encode_utf16() {
600 length += 1;
601 dst.put_u16_le(chr);
602 }
603
604 let dst: &mut [u8] = dst.borrow_mut();
605 let bytes = (length * 2).to_le_bytes(); for (i, byte) in bytes.iter().enumerate() {
608 dst[len_pos + i] = *byte;
609 }
610 }
611 (ColumnData::String(Some(ref s)), None) => {
612 dst.put_u8(VarLenType::NVarchar as u8);
614 dst.extend_from_slice(&[0xff_u8; 2]);
615 dst.extend_from_slice(&[0u8; 5]);
616
617 dst.put_u64_le(0xfffffffffffffffe_u64);
620
621 let mut length = 0u32;
623 let len_pos = dst.len();
624
625 dst.put_u32_le(length);
626
627 for chr in s.encode_utf16() {
628 length += 1;
629 dst.put_u16_le(chr);
630 }
631
632 if length > 0 {
633 dst.put_u32_le(0);
635 }
636
637 let dst: &mut [u8] = dst.borrow_mut();
638 let bytes = (length * 2).to_le_bytes(); for (i, byte) in bytes.iter().enumerate() {
641 dst[len_pos + i] = *byte;
642 }
643 }
644 (ColumnData::Binary(opt), Some(TypeInfo::VarLenSized(vlc)))
645 if vlc.r#type() == VarLenType::BigBinary
646 || vlc.r#type() == VarLenType::BigVarBin =>
647 {
648 if let Some(bytes) = opt {
649 if bytes.len() > vlc.len() {
650 return Err(crate::Error::BulkInput(
651 format!(
652 "Binary length {} exceed column limit {}",
653 bytes.len(),
654 vlc.len()
655 )
656 .into(),
657 ));
658 }
659
660 if vlc.len() < 0xffff {
661 dst.put_u16_le(bytes.len() as u16);
662 dst.extend(bytes.into_owned());
663 } else {
664 dst.put_u64_le(0xfffffffffffffffe);
666 dst.put_u32_le(bytes.len() as u32);
667
668 if !bytes.is_empty() {
669 dst.extend(bytes.into_owned());
670 dst.put_u32_le(0);
671 }
672 }
673 } else if vlc.len() < 0xffff {
674 dst.put_u16_le(0xffff);
675 } else {
676 dst.put_u64_le(0xffffffffffffffff);
677 }
678 }
679 (ColumnData::Binary(Some(bytes)), None) if bytes.len() <= 8000 => {
680 dst.put_u8(VarLenType::BigVarBin as u8);
681 dst.put_u16_le(8000);
682 dst.put_u16_le(bytes.len() as u16);
683 dst.extend(bytes.into_owned());
684 }
685 (ColumnData::Binary(Some(bytes)), None) => {
686 dst.put_u8(VarLenType::BigVarBin as u8);
687 dst.put_u16_le(0xffff_u16);
689 dst.put_u64_le(0xfffffffffffffffe_u64);
691 dst.put_u32_le(bytes.len() as u32);
693
694 if !bytes.is_empty() {
695 dst.extend(bytes.into_owned());
697 dst.put_u32_le(0);
699 }
700 }
701 (ColumnData::DateTime(opt), Some(TypeInfo::VarLenSized(vlc)))
702 if vlc.r#type() == VarLenType::Datetimen =>
703 {
704 if let Some(dt) = opt {
705 dst.put_u8(8);
706 dt.encode(dst)?;
707 } else {
708 dst.put_u8(0);
709 }
710 }
711 (ColumnData::DateTime(Some(dt)), Some(TypeInfo::FixedLen(FixedLenType::Datetime))) => {
712 dt.encode(dst)?;
713 }
714 (ColumnData::DateTime(Some(dt)), None) => {
715 dst.extend_from_slice(&[VarLenType::Datetimen as u8, 8, 8]);
716 dt.encode(&mut *dst)?;
717 }
718 (ColumnData::SmallDateTime(opt), Some(TypeInfo::VarLenSized(vlc)))
719 if vlc.r#type() == VarLenType::Datetimen =>
720 {
721 if let Some(dt) = opt {
722 dst.put_u8(4);
723 dt.encode(dst)?;
724 } else {
725 dst.put_u8(0);
726 }
727 }
728 (
729 ColumnData::SmallDateTime(Some(dt)),
730 Some(TypeInfo::FixedLen(FixedLenType::Datetime4)),
731 ) => {
732 dt.encode(dst)?;
733 }
734 (ColumnData::SmallDateTime(Some(dt)), None) => {
735 dst.extend_from_slice(&[VarLenType::Datetimen as u8, 4, 4]);
736 dt.encode(&mut *dst)?;
737 }
738 #[cfg(feature = "tds73")]
739 (ColumnData::Date(opt), Some(TypeInfo::VarLenSized(vlc)))
740 if vlc.r#type() == VarLenType::Daten =>
741 {
742 if let Some(dt) = opt {
743 dst.put_u8(3);
744 dt.encode(dst)?;
745 } else {
746 dst.put_u8(0);
747 }
748 }
749 #[cfg(feature = "tds73")]
750 (ColumnData::Date(Some(date)), None) => {
751 dst.extend_from_slice(&[VarLenType::Daten as u8, 3]);
752 date.encode(&mut *dst)?;
753 }
754 #[cfg(feature = "tds73")]
755 (ColumnData::Time(opt), Some(TypeInfo::VarLenSized(vlc)))
756 if vlc.r#type() == VarLenType::Timen =>
757 {
758 if let Some(time) = opt {
759 dst.put_u8(time.len()?);
760 time.encode(dst)?;
761 } else {
762 dst.put_u8(0);
763 }
764 }
765 #[cfg(feature = "tds73")]
766 (ColumnData::Time(Some(time)), None) => {
767 dst.extend_from_slice(&[VarLenType::Timen as u8, time.scale(), time.len()?]);
768 time.encode(&mut *dst)?;
769 }
770 #[cfg(feature = "tds73")]
771 (ColumnData::DateTime2(opt), Some(TypeInfo::VarLenSized(vlc)))
772 if vlc.r#type() == VarLenType::Datetimen =>
773 {
774 if let Some(dt2) = opt {
775 let dt = datetime2_to_datetime(&dt2)?;
776 dst.put_u8(8);
777 dt.encode(dst)?;
778 } else {
779 dst.put_u8(0);
780 }
781 }
782 #[cfg(feature = "tds73")]
783 (ColumnData::DateTime2(opt), Some(TypeInfo::VarLenSized(vlc)))
784 if vlc.r#type() == VarLenType::Datetime2 =>
785 {
786 if let Some(mut dt2) = opt {
787 if dt2.time().scale() != vlc.len() as u8 {
788 let time = dt2.time();
789 let increments = (time.increments() as f64
790 * 10_f64.powi(vlc.len() as i32 - time.scale() as i32))
791 as u64;
792 dt2 = DateTime2::new(dt2.date(), Time::new(increments, vlc.len() as u8));
793 }
794 dst.put_u8(dt2.time().len()? + 3);
795 dt2.encode(dst)?;
796 } else {
797 dst.put_u8(0);
798 }
799 }
800 #[cfg(feature = "tds73")]
801 (ColumnData::DateTime2(Some(dt)), None) => {
802 let len = dt.time().len()? + 3;
803 dst.extend_from_slice(&[VarLenType::Datetime2 as u8, dt.time().scale(), len]);
804 dt.encode(&mut *dst)?;
805 }
806 #[cfg(feature = "tds73")]
807 (ColumnData::DateTimeOffset(opt), Some(TypeInfo::VarLenSized(vlc)))
808 if vlc.r#type() == VarLenType::DatetimeOffsetn =>
809 {
810 if let Some(dto) = opt {
811 dst.put_u8(dto.datetime2().time().len()? + 5);
812 dto.encode(dst)?;
813 } else {
814 dst.put_u8(0);
815 }
816 }
817 #[cfg(feature = "tds73")]
818 (ColumnData::DateTimeOffset(Some(dto)), None) => {
819 let headers = [
820 VarLenType::DatetimeOffsetn as u8,
821 dto.datetime2().time().scale(),
822 dto.datetime2().time().len()? + 5,
823 ];
824
825 dst.extend_from_slice(&headers);
826 dto.encode(&mut *dst)?;
827 }
828 (ColumnData::Xml(opt), Some(TypeInfo::Xml { .. })) => {
829 if let Some(xml) = opt {
830 xml.into_owned().encode(dst)?;
831 } else {
832 dst.put_u64_le(0xffffffffffffffff_u64);
833 }
834 }
835 (ColumnData::Xml(Some(xml)), None) => {
836 dst.put_u8(VarLenType::Xml as u8);
837 dst.put_u8(0);
838 xml.into_owned().encode(&mut *dst)?;
839 }
840 (ColumnData::Numeric(opt), Some(TypeInfo::VarLenSized(vlc)))
841 if vlc.r#type() == VarLenType::Money =>
842 {
843 if let Some(num) = opt {
844 money::encode(dst, vlc.len(), f64::from(num));
845 } else {
846 dst.put_u8(0);
847 }
848 }
849 (ColumnData::Numeric(opt), Some(TypeInfo::VarLenSizedPrecision { ty, scale, .. }))
850 if ty == &VarLenType::Numericn || ty == &VarLenType::Decimaln =>
851 {
852 if let Some(num) = opt {
853 let target_scale = *scale;
857 let num = if target_scale == num.scale() {
858 num
859 } else if target_scale > num.scale() {
860 let factor = 10i128.pow((target_scale - num.scale()) as u32);
862 let value = num.value().checked_mul(factor).ok_or_else(|| {
863 crate::Error::Conversion(
864 "numeric value overflows when scaling to the column's scale".into(),
865 )
866 })?;
867 Numeric::new_with_scale(value, target_scale)
868 } else {
869 let factor = 10i128.pow((num.scale() - target_scale) as u32);
872 let half = factor / 2;
873 let v = num.value();
874 let value = if v >= 0 {
875 (v + half) / factor
876 } else {
877 (v - half) / factor
878 };
879 Numeric::new_with_scale(value, target_scale)
880 };
881 num.encode(&mut *dst)?;
882 } else {
883 dst.put_u8(0);
884 }
885 }
886 (ColumnData::Numeric(Some(num)), None) => {
887 let headers = &[
888 VarLenType::Numericn as u8,
889 num.len(),
890 num.precision(),
891 num.scale(),
892 ];
893
894 dst.extend_from_slice(headers);
895 num.encode(&mut *dst)?;
896 }
897 (data, Some(TypeInfo::VarLenSized(vlc))) if vlc.r#type() == VarLenType::SSVariant => {
898 sql_variant::encode(&mut *dst, data)?;
899 }
900 (_, None) => {
901 dst.put_u8(FixedLenType::Null as u8);
903 }
904 (v, ref ti) => {
905 return Err(crate::Error::BulkInput(
906 format!("invalid data type, expecting {:?} but found {:?}", ti, v).into(),
907 ));
908 }
909 }
910
911 Ok(())
912 }
913}
914
915impl<'a> FromSql<'a> for ColumnData<'a> {
918 fn from_sql(value: &'a ColumnData<'static>) -> crate::Result<Option<Self>> {
919 Ok(Some(value.clone()))
920 }
921}
922
923impl<'a> FromSqlOwned for ColumnData<'a> {
926 fn from_sql_owned(value: ColumnData<'static>) -> crate::Result<Option<Self>> {
927 Ok(Some(value))
928 }
929}
930
931impl<'a> ToSql for ColumnData<'a> {
933 fn to_sql(&self) -> ColumnData<'_> {
934 self.clone()
935 }
936}
937
938impl<'a> IntoSql<'a> for ColumnData<'a> {
940 fn into_sql(self) -> ColumnData<'a> {
941 self
942 }
943}
944
945#[cfg(test)]
946mod tests {
947 use super::*;
948 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
949 use crate::tds::Collation;
950 use crate::{Error, VarLenContext};
951 use bytes::BytesMut;
952
953 async fn test_round_trip(ti: TypeInfo, d: ColumnData<'_>) {
954 let mut buf = BytesMut::new();
955 let mut buf_with_ti = BytesMutWithTypeInfo::new(&mut buf).with_type_info(&ti);
956
957 d.clone()
958 .encode(&mut buf_with_ti)
959 .expect("encode must succeed");
960
961 let reader = &mut buf.into_sql_read_bytes();
962 let nd = ColumnData::decode(reader, &ti)
963 .await
964 .expect("decode must succeed");
965
966 assert_eq!(nd, d);
967
968 reader
969 .read_u8()
970 .await
971 .expect_err("decode must consume entire buffer");
972 }
973
974 #[test]
975 fn type_name_maps_each_variant() {
976 assert_eq!(ColumnData::U8(Some(1)).type_name(), "tinyint");
977 assert_eq!(ColumnData::I16(Some(1)).type_name(), "smallint");
978 assert_eq!(ColumnData::I32(Some(1)).type_name(), "int");
979 assert_eq!(ColumnData::I64(Some(1)).type_name(), "bigint");
980 assert_eq!(ColumnData::F32(Some(1.0)).type_name(), "float(24)");
981 assert_eq!(ColumnData::F64(Some(1.0)).type_name(), "float(53)");
982 assert_eq!(ColumnData::Bit(Some(true)).type_name(), "bit");
983 assert_eq!(ColumnData::Guid(None).type_name(), "uniqueidentifier");
984 assert_eq!(ColumnData::Numeric(None).type_name(), "numeric");
985 assert_eq!(ColumnData::DateTime(None).type_name(), "datetime");
986 assert_eq!(ColumnData::SmallDateTime(None).type_name(), "smalldatetime");
987 }
988
989 #[test]
990 fn type_name_string_length_thresholds() {
991 assert_eq!(ColumnData::String(None).type_name(), "nvarchar(4000)");
995 assert_eq!(
996 ColumnData::String(Some("a".repeat(100).into())).type_name(),
997 "nvarchar(4000)"
998 );
999 assert_eq!(
1000 ColumnData::String(Some("a".repeat(4000).into())).type_name(),
1001 "nvarchar(4000)"
1002 );
1003 assert_eq!(
1004 ColumnData::String(Some("a".repeat(4001).into())).type_name(),
1005 "nvarchar(max)"
1006 );
1007 }
1008
1009 #[test]
1010 fn type_name_binary_length_threshold() {
1011 assert_eq!(
1012 ColumnData::Binary(Some(vec![0u8; 8000].into())).type_name(),
1013 "varbinary(8000)"
1014 );
1015 assert_eq!(
1016 ColumnData::Binary(Some(vec![0u8; 8001].into())).type_name(),
1017 "varbinary(max)"
1018 );
1019 assert_eq!(ColumnData::Binary(None).type_name(), "varbinary(max)");
1020 }
1021
1022 #[test]
1023 #[cfg(feature = "serde")]
1024 fn serde_json_round_trip() {
1025 let value = ColumnData::I32(Some(1234));
1026 let json = serde_json::to_string(&value).expect("serialize");
1027 let back: ColumnData<'static> = serde_json::from_str(&json).expect("deserialize");
1028 assert_eq!(value, back);
1029 }
1030
1031 #[tokio::test]
1032 async fn i32_with_varlen_int() {
1033 test_round_trip(
1034 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Intn, 4, None)),
1035 ColumnData::I32(Some(42)),
1036 )
1037 .await;
1038 }
1039
1040 #[tokio::test]
1041 async fn none_with_varlen_int() {
1042 test_round_trip(
1043 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Intn, 4, None)),
1044 ColumnData::I32(None),
1045 )
1046 .await;
1047 }
1048
1049 #[tokio::test]
1050 async fn i32_with_fixedlen_int() {
1051 test_round_trip(
1052 TypeInfo::FixedLen(FixedLenType::Int4),
1053 ColumnData::I32(Some(42)),
1054 )
1055 .await;
1056 }
1057
1058 #[tokio::test]
1059 async fn bit_with_varlen_bit() {
1060 test_round_trip(
1061 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Bitn, 1, None)),
1062 ColumnData::Bit(Some(true)),
1063 )
1064 .await;
1065 }
1066
1067 #[tokio::test]
1068 async fn none_with_varlen_bit() {
1069 test_round_trip(
1070 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Bitn, 1, None)),
1071 ColumnData::Bit(None),
1072 )
1073 .await;
1074 }
1075
1076 #[tokio::test]
1077 async fn bit_with_fixedlen_bit() {
1078 test_round_trip(
1079 TypeInfo::FixedLen(FixedLenType::Bit),
1080 ColumnData::Bit(Some(true)),
1081 )
1082 .await;
1083 }
1084
1085 #[tokio::test]
1086 async fn u8_with_varlen_int() {
1087 test_round_trip(
1088 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Intn, 1, None)),
1089 ColumnData::U8(Some(8u8)),
1090 )
1091 .await;
1092 }
1093
1094 #[tokio::test]
1095 async fn none_u8_with_varlen_int() {
1096 test_round_trip(
1097 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Intn, 1, None)),
1098 ColumnData::U8(None),
1099 )
1100 .await;
1101 }
1102
1103 #[tokio::test]
1104 async fn u8_with_fixedlen_int() {
1105 test_round_trip(
1106 TypeInfo::FixedLen(FixedLenType::Int1),
1107 ColumnData::U8(Some(8u8)),
1108 )
1109 .await;
1110 }
1111
1112 #[tokio::test]
1113 async fn i16_with_varlen_intn() {
1114 test_round_trip(
1115 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Intn, 2, None)),
1116 ColumnData::I16(Some(8i16)),
1117 )
1118 .await;
1119 }
1120
1121 #[tokio::test]
1122 async fn none_i16_with_varlen_intn() {
1123 test_round_trip(
1124 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Intn, 2, None)),
1125 ColumnData::I16(None),
1126 )
1127 .await;
1128 }
1129
1130 #[tokio::test]
1131 async fn none_with_varlen_intn() {
1132 test_round_trip(
1133 TypeInfo::FixedLen(FixedLenType::Int2),
1134 ColumnData::I16(Some(8i16)),
1135 )
1136 .await;
1137 }
1138
1139 #[tokio::test]
1140 async fn i64_with_varlen_intn() {
1141 test_round_trip(
1142 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Intn, 8, None)),
1143 ColumnData::I64(Some(8i64)),
1144 )
1145 .await;
1146 }
1147
1148 #[tokio::test]
1149 async fn i64_none_with_varlen_intn() {
1150 test_round_trip(
1151 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Intn, 8, None)),
1152 ColumnData::I64(None),
1153 )
1154 .await;
1155 }
1156
1157 #[tokio::test]
1158 async fn i64_with_fixedlen_int8() {
1159 test_round_trip(
1160 TypeInfo::FixedLen(FixedLenType::Int8),
1161 ColumnData::I64(Some(8i64)),
1162 )
1163 .await;
1164 }
1165
1166 #[tokio::test]
1167 async fn f32_with_varlen_floatn() {
1168 test_round_trip(
1169 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Floatn, 4, None)),
1170 ColumnData::F32(Some(8f32)),
1171 )
1172 .await;
1173 }
1174
1175 #[tokio::test]
1176 async fn null_f32_with_varlen_floatn() {
1177 test_round_trip(
1178 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Floatn, 4, None)),
1179 ColumnData::F32(None),
1180 )
1181 .await;
1182 }
1183
1184 #[tokio::test]
1185 async fn f32_with_fixedlen_float4() {
1186 test_round_trip(
1187 TypeInfo::FixedLen(FixedLenType::Float4),
1188 ColumnData::F32(Some(8f32)),
1189 )
1190 .await;
1191 }
1192
1193 #[tokio::test]
1194 async fn f64_with_varlen_floatn() {
1195 test_round_trip(
1196 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Floatn, 8, None)),
1197 ColumnData::F64(Some(8f64)),
1198 )
1199 .await;
1200 }
1201
1202 #[tokio::test]
1203 async fn none_f64_with_varlen_floatn() {
1204 test_round_trip(
1205 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Floatn, 8, None)),
1206 ColumnData::F64(None),
1207 )
1208 .await;
1209 }
1210
1211 #[tokio::test]
1212 async fn f64_with_fixedlen_float8() {
1213 test_round_trip(
1214 TypeInfo::FixedLen(FixedLenType::Float8),
1215 ColumnData::F64(Some(8f64)),
1216 )
1217 .await;
1218 }
1219
1220 #[tokio::test]
1221 async fn guid_with_varlen_guid() {
1222 test_round_trip(
1223 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Guid, 16, None)),
1224 ColumnData::Guid(Some(Uuid::new_v4())),
1225 )
1226 .await;
1227 }
1228
1229 #[tokio::test]
1230 async fn none_guid_with_varlen_guid() {
1231 test_round_trip(
1232 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Guid, 16, None)),
1233 ColumnData::Guid(None),
1234 )
1235 .await;
1236 }
1237
1238 #[tokio::test]
1239 async fn numeric_with_varlen_sized_precision() {
1240 test_round_trip(
1241 TypeInfo::VarLenSizedPrecision {
1242 ty: VarLenType::Numericn,
1243 size: 17,
1244 precision: 18,
1245 scale: 0,
1246 },
1247 ColumnData::Numeric(Some(Numeric::new_with_scale(23, 0))),
1248 )
1249 .await;
1250 }
1251
1252 #[tokio::test]
1253 async fn none_numeric_with_varlen_sized_precision() {
1254 test_round_trip(
1255 TypeInfo::VarLenSizedPrecision {
1256 ty: VarLenType::Numericn,
1257 size: 17,
1258 precision: 18,
1259 scale: 0,
1260 },
1261 ColumnData::Numeric(None),
1262 )
1263 .await;
1264 }
1265
1266 #[tokio::test]
1267 async fn string_with_varlen_bigchar() {
1268 test_round_trip(
1269 TypeInfo::VarLenSized(VarLenContext::new(
1270 VarLenType::BigChar,
1271 40,
1272 Some(Collation::new(13632521, 52)),
1273 )),
1274 ColumnData::String(Some("aaa".into())),
1275 )
1276 .await;
1277 }
1278
1279 #[tokio::test]
1280 async fn long_string_with_varlen_bigchar() {
1281 test_round_trip(
1282 TypeInfo::VarLenSized(VarLenContext::new(
1283 VarLenType::BigChar,
1284 0x8ffff,
1285 Some(Collation::new(13632521, 52)),
1286 )),
1287 ColumnData::String(Some("aaa".into())),
1288 )
1289 .await;
1290 }
1291
1292 #[tokio::test]
1293 async fn none_long_string_with_varlen_bigchar() {
1294 test_round_trip(
1295 TypeInfo::VarLenSized(VarLenContext::new(
1296 VarLenType::BigChar,
1297 0x8ffff,
1298 Some(Collation::new(13632521, 52)),
1299 )),
1300 ColumnData::String(None),
1301 )
1302 .await;
1303 }
1304
1305 #[tokio::test]
1306 async fn none_string_with_varlen_bigchar() {
1307 test_round_trip(
1308 TypeInfo::VarLenSized(VarLenContext::new(
1309 VarLenType::BigChar,
1310 40,
1311 Some(Collation::new(13632521, 52)),
1312 )),
1313 ColumnData::String(None),
1314 )
1315 .await;
1316 }
1317
1318 #[tokio::test]
1319 async fn string_with_varlen_bigvarchar() {
1320 test_round_trip(
1321 TypeInfo::VarLenSized(VarLenContext::new(
1322 VarLenType::BigVarChar,
1323 40,
1324 Some(Collation::new(13632521, 52)),
1325 )),
1326 ColumnData::String(Some("aaa".into())),
1327 )
1328 .await;
1329 }
1330
1331 #[tokio::test]
1332 async fn none_string_with_varlen_bigvarchar() {
1333 test_round_trip(
1334 TypeInfo::VarLenSized(VarLenContext::new(
1335 VarLenType::BigVarChar,
1336 40,
1337 Some(Collation::new(13632521, 52)),
1338 )),
1339 ColumnData::String(None),
1340 )
1341 .await;
1342 }
1343
1344 #[tokio::test]
1345 async fn empty_string_with_varlen_bigvarchar() {
1346 test_round_trip(
1347 TypeInfo::VarLenSized(VarLenContext::new(
1348 VarLenType::BigVarChar,
1349 0x8ffff,
1350 Some(Collation::new(13632521, 52)),
1351 )),
1352 ColumnData::String(Some("".into())),
1353 )
1354 .await;
1355 }
1356
1357 #[tokio::test]
1358 async fn string_with_varlen_nvarchar() {
1359 test_round_trip(
1360 TypeInfo::VarLenSized(VarLenContext::new(
1361 VarLenType::NVarchar,
1362 40,
1363 Some(Collation::new(13632521, 52)),
1364 )),
1365 ColumnData::String(Some("hhh".into())),
1366 )
1367 .await;
1368 }
1369
1370 #[tokio::test]
1371 async fn none_string_with_varlen_nvarchar() {
1372 test_round_trip(
1373 TypeInfo::VarLenSized(VarLenContext::new(
1374 VarLenType::NVarchar,
1375 40,
1376 Some(Collation::new(13632521, 52)),
1377 )),
1378 ColumnData::String(None),
1379 )
1380 .await;
1381 }
1382
1383 #[tokio::test]
1384 async fn empty_string_with_varlen_nvarchar() {
1385 test_round_trip(
1386 TypeInfo::VarLenSized(VarLenContext::new(
1387 VarLenType::NVarchar,
1388 0x8ffff,
1389 Some(Collation::new(13632521, 52)),
1390 )),
1391 ColumnData::String(Some("".into())),
1392 )
1393 .await;
1394 }
1395
1396 #[tokio::test]
1397 async fn string_with_varlen_nchar() {
1398 test_round_trip(
1399 TypeInfo::VarLenSized(VarLenContext::new(
1400 VarLenType::NChar,
1401 40,
1402 Some(Collation::new(13632521, 52)),
1403 )),
1404 ColumnData::String(Some("hhh".into())),
1405 )
1406 .await;
1407 }
1408
1409 #[tokio::test]
1410 async fn long_string_with_varlen_nchar() {
1411 test_round_trip(
1412 TypeInfo::VarLenSized(VarLenContext::new(
1413 VarLenType::NChar,
1414 0x8ffff,
1415 Some(Collation::new(13632521, 52)),
1416 )),
1417 ColumnData::String(Some("hhh".into())),
1418 )
1419 .await;
1420 }
1421
1422 #[tokio::test]
1423 async fn none_long_string_with_varlen_nchar() {
1424 test_round_trip(
1425 TypeInfo::VarLenSized(VarLenContext::new(
1426 VarLenType::NChar,
1427 0x8ffff,
1428 Some(Collation::new(13632521, 52)),
1429 )),
1430 ColumnData::String(None),
1431 )
1432 .await;
1433 }
1434
1435 #[tokio::test]
1436 async fn none_string_with_varlen_nchar() {
1437 test_round_trip(
1438 TypeInfo::VarLenSized(VarLenContext::new(
1439 VarLenType::NChar,
1440 40,
1441 Some(Collation::new(13632521, 52)),
1442 )),
1443 ColumnData::String(None),
1444 )
1445 .await;
1446 }
1447
1448 #[tokio::test]
1449 async fn binary_with_varlen_bigbinary() {
1450 test_round_trip(
1451 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::BigBinary, 40, None)),
1452 ColumnData::Binary(Some(b"aaa".as_slice().into())),
1453 )
1454 .await;
1455 }
1456
1457 #[tokio::test]
1458 async fn long_binary_with_varlen_bigbinary() {
1459 test_round_trip(
1460 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::BigBinary, 0x8ffff, None)),
1461 ColumnData::Binary(Some(b"aaa".as_slice().into())),
1462 )
1463 .await;
1464 }
1465
1466 #[tokio::test]
1467 async fn none_binary_with_varlen_bigbinary() {
1468 test_round_trip(
1469 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::BigBinary, 40, None)),
1470 ColumnData::Binary(None),
1471 )
1472 .await;
1473 }
1474
1475 #[tokio::test]
1476 async fn none_long_binary_with_varlen_bigbinary() {
1477 test_round_trip(
1478 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::BigBinary, 0x8ffff, None)),
1479 ColumnData::Binary(None),
1480 )
1481 .await;
1482 }
1483
1484 #[tokio::test]
1485 async fn binary_with_varlen_bigvarbin() {
1486 test_round_trip(
1487 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::BigVarBin, 40, None)),
1488 ColumnData::Binary(Some(b"aaa".as_slice().into())),
1489 )
1490 .await;
1491 }
1492
1493 #[tokio::test]
1494 async fn none_binary_with_varlen_bigvarbin() {
1495 test_round_trip(
1496 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::BigVarBin, 40, None)),
1497 ColumnData::Binary(None),
1498 )
1499 .await;
1500 }
1501
1502 #[tokio::test]
1503 async fn empty_binary_with_varlen_bigvarbin() {
1504 test_round_trip(
1505 TypeInfo::VarLenSized(VarLenContext::new(
1506 VarLenType::BigVarBin,
1507 0x8ffff,
1508 Some(Collation::new(13632521, 52)),
1509 )),
1510 ColumnData::Binary(Some(b"".as_slice().into())),
1511 )
1512 .await;
1513 }
1514
1515 #[tokio::test]
1516 async fn datetime_with_varlen_datetimen() {
1517 test_round_trip(
1518 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Datetimen, 8, None)),
1519 ColumnData::DateTime(Some(DateTime::new(200, 3000))),
1520 )
1521 .await;
1522 }
1523
1524 #[tokio::test]
1527 async fn none_datetime_with_varlen_datetimen() {
1528 test_round_trip(
1529 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Datetimen, 8, None)),
1530 ColumnData::DateTime(None),
1531 )
1532 .await;
1533 }
1534
1535 #[tokio::test]
1536 async fn datetime_with_fixedlen_datetime() {
1537 test_round_trip(
1538 TypeInfo::FixedLen(FixedLenType::Datetime),
1539 ColumnData::DateTime(Some(DateTime::new(200, 3000))),
1540 )
1541 .await;
1542 }
1543
1544 #[tokio::test]
1545 async fn smalldatetime_with_varlen_datetimen() {
1546 test_round_trip(
1547 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Datetimen, 4, None)),
1548 ColumnData::SmallDateTime(Some(SmallDateTime::new(200, 3000))),
1549 )
1550 .await;
1551 }
1552
1553 #[tokio::test]
1554 async fn none_smalldatetime_with_varlen_datetimen() {
1555 test_round_trip(
1556 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Datetimen, 4, None)),
1557 ColumnData::SmallDateTime(None),
1558 )
1559 .await;
1560 }
1561
1562 #[tokio::test]
1563 async fn smalldatetime_with_fixedlen_datetime4() {
1564 test_round_trip(
1565 TypeInfo::FixedLen(FixedLenType::Datetime4),
1566 ColumnData::SmallDateTime(Some(SmallDateTime::new(200, 3000))),
1567 )
1568 .await;
1569 }
1570
1571 #[cfg(feature = "tds73")]
1572 #[tokio::test]
1573 async fn date_with_varlen_daten() {
1574 test_round_trip(
1575 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Daten, 3, None)),
1576 ColumnData::Date(Some(Date::new(200))),
1577 )
1578 .await;
1579 }
1580
1581 #[cfg(feature = "tds73")]
1582 #[tokio::test]
1583 async fn none_date_with_varlen_daten() {
1584 test_round_trip(
1585 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Daten, 3, None)),
1586 ColumnData::Date(None),
1587 )
1588 .await;
1589 }
1590
1591 #[cfg(feature = "tds73")]
1592 #[tokio::test]
1593 async fn time_with_varlen_timen() {
1594 test_round_trip(
1595 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Timen, 7, None)),
1596 ColumnData::Time(Some(Time::new(55, 7))),
1597 )
1598 .await;
1599 }
1600
1601 #[cfg(feature = "tds73")]
1602 #[tokio::test]
1603 async fn none_time_with_varlen_timen() {
1604 test_round_trip(
1605 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Timen, 7, None)),
1606 ColumnData::Time(None),
1607 )
1608 .await;
1609 }
1610
1611 #[cfg(feature = "tds73")]
1612 #[tokio::test]
1613 async fn datetime2_with_varlen_datetime2() {
1614 test_round_trip(
1615 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Datetime2, 7, None)),
1616 ColumnData::DateTime2(Some(DateTime2::new(Date::new(55), Time::new(222, 7)))),
1617 )
1618 .await;
1619 }
1620
1621 #[cfg(feature = "tds73")]
1622 #[tokio::test]
1623 async fn none_datetime2_with_varlen_datetime2() {
1624 test_round_trip(
1625 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Datetime2, 7, None)),
1626 ColumnData::DateTime2(None),
1627 )
1628 .await;
1629 }
1630
1631 #[cfg(feature = "tds73")]
1632 #[tokio::test]
1633 async fn datetimeoffset_with_varlen_datetimeoffsetn() {
1634 test_round_trip(
1635 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::DatetimeOffsetn, 7, None)),
1636 ColumnData::DateTimeOffset(Some(DateTimeOffset::new(
1637 DateTime2::new(Date::new(55), Time::new(222, 7)),
1638 -8,
1639 ))),
1640 )
1641 .await;
1642 }
1643
1644 #[cfg(feature = "tds73")]
1645 #[tokio::test]
1646 async fn none_datetimeoffset_with_varlen_datetimeoffsetn() {
1647 test_round_trip(
1648 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::DatetimeOffsetn, 7, None)),
1649 ColumnData::DateTimeOffset(None),
1650 )
1651 .await;
1652 }
1653
1654 #[cfg(feature = "tds73")]
1655 #[tokio::test]
1656 async fn xml_with_xml() {
1657 test_round_trip(
1658 TypeInfo::Xml {
1659 schema: None,
1660 size: 0xfffffffffffffffe_usize,
1661 },
1662 ColumnData::Xml(Some(Cow::Owned(XmlData::new("<a>ddd</a>")))),
1663 )
1664 .await;
1665 }
1666
1667 #[cfg(feature = "tds73")]
1668 #[tokio::test]
1669 async fn none_xml_with_xml() {
1670 test_round_trip(
1671 TypeInfo::Xml {
1672 schema: None,
1673 size: 0xfffffffffffffffe_usize,
1674 },
1675 ColumnData::Xml(None),
1676 )
1677 .await;
1678 }
1679
1680 #[tokio::test]
1681 async fn invalid_type_fails() {
1682 let data = vec![
1683 (
1684 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Floatn, 4, None)),
1685 ColumnData::I32(Some(42)),
1686 ),
1687 (
1688 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Floatn, 4, None)),
1689 ColumnData::I32(None),
1690 ),
1691 (
1692 TypeInfo::FixedLen(FixedLenType::Int4),
1693 ColumnData::I32(None),
1694 ),
1695 ];
1696
1697 for (ti, d) in data {
1698 let mut buf = BytesMut::new();
1699 let mut buf_ti = BytesMutWithTypeInfo::new(&mut buf).with_type_info(&ti);
1700
1701 let err = d.encode(&mut buf_ti).expect_err("encode should fail");
1702
1703 if let Error::BulkInput(_) = err {
1704 } else {
1705 panic!("Expected: Error::BulkInput, got: {:?}", err);
1706 }
1707 }
1708 }
1709
1710 #[test]
1711 fn column_data_from_sql_clones_by_reference() {
1712 let value: ColumnData<'static> = ColumnData::I32(Some(42));
1713 let out = ColumnData::from_sql(&value).unwrap();
1714 assert_eq!(out, Some(ColumnData::I32(Some(42))));
1715 }
1716
1717 #[test]
1718 fn column_data_from_sql_owned_passes_through() {
1719 let value: ColumnData<'static> = ColumnData::String(Some(Cow::Borrowed("hello")));
1720 let out = ColumnData::from_sql_owned(value).unwrap();
1721 assert_eq!(out, Some(ColumnData::String(Some(Cow::Borrowed("hello")))));
1722 }
1723
1724 #[test]
1725 fn column_data_to_sql_clones_by_reference() {
1726 let value = ColumnData::Bit(Some(true));
1727 assert_eq!(value.to_sql(), ColumnData::Bit(Some(true)));
1728 assert_eq!(value, ColumnData::Bit(Some(true)));
1730 }
1731
1732 #[test]
1733 fn column_data_into_sql_passes_through() {
1734 let value = ColumnData::F64(Some(1.5));
1735 assert_eq!(value.into_sql(), ColumnData::F64(Some(1.5)));
1736 }
1737
1738 #[cfg(feature = "tds73")]
1739 #[test]
1740 fn datetime2_to_datetime_conversion() {
1741 use crate::tds::time::{Date, DateTime2, Time};
1742
1743 let dt2 = DateTime2::new(Date::new(737_425), Time::new(0, 7));
1746 let dt = datetime2_to_datetime(&dt2).expect("conversion must succeed");
1747
1748 assert_eq!(dt.days(), (737_425 - DAYS_YEAR_1_TO_1900) as i32);
1749 assert_eq!(dt.seconds_fragments(), 0);
1750
1751 let noon_increments = 12u64 * 3600 * 10u64.pow(7);
1753 let dt2 = DateTime2::new(Date::new(737_425), Time::new(noon_increments, 7));
1754 let dt = datetime2_to_datetime(&dt2).expect("conversion must succeed");
1755
1756 assert_eq!(dt.seconds_fragments(), 12 * 3600 * 300);
1757
1758 let dt2 = DateTime2::new(Date::new(0), Time::new(0, 7));
1760 assert!(datetime2_to_datetime(&dt2).is_err());
1761 }
1762
1763 fn encode_with_ti(ti: &TypeInfo, d: ColumnData<'_>) -> crate::Result<BytesMut> {
1766 let mut buf = BytesMut::new();
1767 {
1768 let mut b = BytesMutWithTypeInfo::new(&mut buf).with_type_info(ti);
1769 d.encode(&mut b)?;
1770 }
1771 Ok(buf)
1772 }
1773
1774 fn encode_without_ti(d: ColumnData<'_>) -> crate::Result<BytesMut> {
1775 let mut buf = BytesMut::new();
1776 {
1777 let mut b = BytesMutWithTypeInfo::new(&mut buf);
1778 d.encode(&mut b)?;
1779 }
1780 Ok(buf)
1781 }
1782
1783 fn expect_bulk_input(ti: TypeInfo, d: ColumnData<'_>) {
1784 let mut buf = BytesMut::new();
1785 let mut b = BytesMutWithTypeInfo::new(&mut buf).with_type_info(&ti);
1786 let err = d.encode(&mut b).expect_err("encode should fail");
1787 assert!(matches!(err, Error::BulkInput(_)), "got {:?}", err);
1788 }
1789
1790 #[tokio::test]
1798 #[should_panic]
1799 async fn decode_varlen_sized_precision_unsupported_panics() {
1800 let ti = TypeInfo::VarLenSizedPrecision {
1801 ty: VarLenType::Money,
1802 size: 8,
1803 precision: 0,
1804 scale: 0,
1805 };
1806 let buf = BytesMut::new();
1807 let reader = &mut buf.into_sql_read_bytes();
1808 let _ = ColumnData::decode(reader, &ti).await;
1809 }
1810
1811 #[tokio::test]
1814 async fn decode_udt_type_info() {
1815 use bytes::BufMut;
1816
1817 let ti = TypeInfo::Udt(crate::tds::codec::type_info::UdtInfo {
1818 max_byte_size: 0xffff,
1819 db_name: "db".into(),
1820 schema_name: "dbo".into(),
1821 type_name: "geometry".into(),
1822 assembly_qualified_name: String::new(),
1823 });
1824
1825 let mut buf = BytesMut::new();
1826 buf.put_u64_le(0xfffffffffffffffe);
1828 buf.put_u32_le(4);
1829 buf.extend_from_slice(&[1, 2, 3, 4]);
1830 buf.put_u32_le(0);
1831
1832 let reader = &mut buf.into_sql_read_bytes();
1833 let nd = ColumnData::decode(reader, &ti).await.unwrap();
1834 assert_eq!(nd, ColumnData::Binary(Some(vec![1, 2, 3, 4].into())));
1835 }
1836
1837 #[tokio::test]
1840 async fn f64_with_varlen_money() {
1841 test_round_trip(
1842 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Money, 8, None)),
1843 ColumnData::F64(Some(3.5)),
1844 )
1845 .await;
1846 }
1847
1848 #[tokio::test]
1849 async fn none_f64_with_varlen_money() {
1850 test_round_trip(
1851 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Money, 8, None)),
1852 ColumnData::F64(None),
1853 )
1854 .await;
1855 }
1856
1857 #[tokio::test]
1860 async fn bigchar_unrepresentable_character_errors() {
1861 let ti = TypeInfo::VarLenSized(VarLenContext::new(
1862 VarLenType::BigChar,
1863 40,
1864 Some(Collation::new(13632521, 52)),
1865 ));
1866 let mut buf = BytesMut::new();
1867 let mut b = BytesMutWithTypeInfo::new(&mut buf).with_type_info(&ti);
1868 let err = ColumnData::String(Some("\u{1F600}".into()))
1870 .encode(&mut b)
1871 .expect_err("encode should fail");
1872 assert!(matches!(err, Error::Encoding(_)), "got {:?}", err);
1873 }
1874
1875 #[tokio::test]
1876 async fn bigchar_too_long_errors() {
1877 expect_bulk_input(
1878 TypeInfo::VarLenSized(VarLenContext::new(
1879 VarLenType::BigChar,
1880 2,
1881 Some(Collation::new(13632521, 52)),
1882 )),
1883 ColumnData::String(Some("aaa".into())),
1884 );
1885 }
1886
1887 #[tokio::test]
1890 async fn nvarchar_too_long_small_errors() {
1891 expect_bulk_input(
1892 TypeInfo::VarLenSized(VarLenContext::new(
1893 VarLenType::NVarchar,
1894 2,
1895 Some(Collation::new(13632521, 52)),
1896 )),
1897 ColumnData::String(Some("aaa".into())),
1898 );
1899 }
1900
1901 #[tokio::test]
1902 async fn nvarchar_too_long_unknown_size_errors() {
1903 expect_bulk_input(
1906 TypeInfo::VarLenSized(VarLenContext::new(
1907 VarLenType::NVarchar,
1908 0xffff,
1909 Some(Collation::new(13632521, 52)),
1910 )),
1911 ColumnData::String(Some("a".repeat(40_000).into())),
1912 );
1913 }
1914
1915 #[tokio::test]
1918 async fn string_with_varlen_text() {
1919 test_round_trip(
1920 TypeInfo::VarLenSized(VarLenContext::new(
1921 VarLenType::Text,
1922 40,
1923 Some(Collation::new(13632521, 52)),
1924 )),
1925 ColumnData::String(Some("hello".into())),
1926 )
1927 .await;
1928 }
1929
1930 #[tokio::test]
1931 async fn none_string_with_varlen_text() {
1932 test_round_trip(
1933 TypeInfo::VarLenSized(VarLenContext::new(
1934 VarLenType::Text,
1935 40,
1936 Some(Collation::new(13632521, 52)),
1937 )),
1938 ColumnData::String(None),
1939 )
1940 .await;
1941 }
1942
1943 #[tokio::test]
1944 async fn string_with_varlen_ntext() {
1945 test_round_trip(
1946 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::NText, 40, None)),
1947 ColumnData::String(Some("hi".into())),
1948 )
1949 .await;
1950 }
1951
1952 #[tokio::test]
1953 async fn none_string_with_varlen_ntext() {
1954 test_round_trip(
1955 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::NText, 40, None)),
1956 ColumnData::String(None),
1957 )
1958 .await;
1959 }
1960
1961 #[tokio::test]
1964 async fn binary_too_long_errors() {
1965 expect_bulk_input(
1966 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::BigVarBin, 2, None)),
1967 ColumnData::Binary(Some(b"aaa".as_slice().into())),
1968 );
1969 }
1970
1971 #[tokio::test]
1974 async fn datetime_encode_without_type_info() {
1975 let buf = encode_without_ti(ColumnData::DateTime(Some(DateTime::new(200, 3000)))).unwrap();
1976 assert_eq!(buf[0], VarLenType::Datetimen as u8);
1977 assert_eq!(buf[1], 8);
1978 assert_eq!(buf[2], 8);
1979 }
1980
1981 #[tokio::test]
1982 async fn smalldatetime_encode_without_type_info() {
1983 let buf = encode_without_ti(ColumnData::SmallDateTime(Some(SmallDateTime::new(
1984 200, 3000,
1985 ))))
1986 .unwrap();
1987 assert_eq!(buf[0], VarLenType::Datetimen as u8);
1988 assert_eq!(buf[1], 4);
1989 assert_eq!(buf[2], 4);
1990 }
1991
1992 #[cfg(feature = "tds73")]
1995 #[tokio::test]
1996 async fn datetime2_with_varlen_datetimen() {
1997 let ti = TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Datetimen, 8, None));
1998 let dt2 = DateTime2::new(Date::new(737_425), Time::new(0, 7));
2000 let buf = encode_with_ti(&ti, ColumnData::DateTime2(Some(dt2))).unwrap();
2001
2002 let reader = &mut buf.into_sql_read_bytes();
2003 let nd = ColumnData::decode(reader, &ti).await.unwrap();
2004 assert!(matches!(nd, ColumnData::DateTime(Some(_))), "got {:?}", nd);
2005 }
2006
2007 #[cfg(feature = "tds73")]
2008 #[tokio::test]
2009 async fn none_datetime2_with_varlen_datetimen() {
2010 let ti = TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Datetimen, 8, None));
2011 let buf = encode_with_ti(&ti, ColumnData::DateTime2(None)).unwrap();
2012
2013 let reader = &mut buf.into_sql_read_bytes();
2014 ColumnData::decode(reader, &ti).await.unwrap();
2016 }
2017
2018 #[tokio::test]
2021 async fn numeric_with_varlen_money() {
2022 let ti = TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Money, 8, None));
2023 let buf = encode_with_ti(
2025 &ti,
2026 ColumnData::Numeric(Some(Numeric::new_with_scale(35000, 4))),
2027 )
2028 .unwrap();
2029
2030 let reader = &mut buf.into_sql_read_bytes();
2031 let nd = ColumnData::decode(reader, &ti).await.unwrap();
2032 assert_eq!(nd, ColumnData::F64(Some(3.5)));
2033 }
2034
2035 #[tokio::test]
2036 async fn none_numeric_with_varlen_money() {
2037 let ti = TypeInfo::VarLenSized(VarLenContext::new(VarLenType::Money, 8, None));
2038 let buf = encode_with_ti(&ti, ColumnData::Numeric(None)).unwrap();
2039
2040 let reader = &mut buf.into_sql_read_bytes();
2041 let nd = ColumnData::decode(reader, &ti).await.unwrap();
2042 assert_eq!(nd, ColumnData::F64(None));
2043 }
2044
2045 #[tokio::test]
2048 async fn numeric_scaled_up_to_column_scale() {
2049 let ti = TypeInfo::VarLenSizedPrecision {
2051 ty: VarLenType::Numericn,
2052 size: 17,
2053 precision: 18,
2054 scale: 2,
2055 };
2056 let buf = encode_with_ti(
2057 &ti,
2058 ColumnData::Numeric(Some(Numeric::new_with_scale(23, 0))),
2059 )
2060 .unwrap();
2061
2062 let reader = &mut buf.into_sql_read_bytes();
2063 let nd = ColumnData::decode(reader, &ti).await.unwrap();
2064 assert_eq!(
2065 nd,
2066 ColumnData::Numeric(Some(Numeric::new_with_scale(2300, 2)))
2067 );
2068 }
2069
2070 #[tokio::test]
2071 async fn numeric_scaled_down_to_column_scale() {
2072 let ti = TypeInfo::VarLenSizedPrecision {
2074 ty: VarLenType::Numericn,
2075 size: 17,
2076 precision: 18,
2077 scale: 2,
2078 };
2079 let buf = encode_with_ti(
2080 &ti,
2081 ColumnData::Numeric(Some(Numeric::new_with_scale(12345, 4))),
2082 )
2083 .unwrap();
2084
2085 let reader = &mut buf.into_sql_read_bytes();
2086 let nd = ColumnData::decode(reader, &ti).await.unwrap();
2087 assert_eq!(
2088 nd,
2089 ColumnData::Numeric(Some(Numeric::new_with_scale(123, 2)))
2090 );
2091 }
2092
2093 #[tokio::test]
2096 async fn ssvariant_round_trip_i32() {
2097 test_round_trip(
2098 TypeInfo::VarLenSized(VarLenContext::new(VarLenType::SSVariant, 0, None)),
2099 ColumnData::I32(Some(42)),
2100 )
2101 .await;
2102 }
2103}