1#![allow(clippy::expect_used)]
8
9use bytes::{Buf, Bytes};
10
11use crate::error::TypeError;
12use crate::value::SqlValue;
13
14pub trait TdsDecode: Sized {
16 fn decode(buf: &mut Bytes, type_info: &TypeInfo) -> Result<Self, TypeError>;
18}
19
20#[derive(Debug, Clone)]
22pub struct TypeInfo {
23 pub type_id: u8,
25 pub length: Option<u32>,
27 pub scale: Option<u8>,
29 pub precision: Option<u8>,
31 pub collation: Option<Collation>,
33}
34
35#[derive(Debug, Clone, Copy)]
37pub struct Collation {
38 pub lcid: u32,
40 pub flags: u8,
42}
43
44impl Collation {
45 #[must_use]
50 pub fn is_utf8(&self) -> bool {
51 (self.lcid & 0x0400_0000) != 0
52 }
53
54 #[cfg(feature = "encoding")]
59 #[must_use]
60 pub fn encoding(&self) -> Option<&'static encoding_rs::Encoding> {
61 encoding_for_lcid(self.lcid)
62 }
63}
64
65#[cfg(feature = "encoding")]
68const UTF8_COLLATION_FLAG: u32 = 0x0400_0000;
69
70#[cfg(feature = "encoding")]
72fn encoding_for_lcid(lcid: u32) -> Option<&'static encoding_rs::Encoding> {
73 if (lcid & UTF8_COLLATION_FLAG) != 0 {
75 return Some(encoding_rs::UTF_8);
76 }
77
78 let code_page = code_page_for_lcid(lcid)?;
80
81 match code_page {
83 874 => Some(encoding_rs::WINDOWS_874),
84 932 => Some(encoding_rs::SHIFT_JIS),
85 936 => Some(encoding_rs::GB18030),
86 949 => Some(encoding_rs::EUC_KR),
87 950 => Some(encoding_rs::BIG5),
88 1250 => Some(encoding_rs::WINDOWS_1250),
89 1251 => Some(encoding_rs::WINDOWS_1251),
90 1252 => Some(encoding_rs::WINDOWS_1252),
91 1253 => Some(encoding_rs::WINDOWS_1253),
92 1254 => Some(encoding_rs::WINDOWS_1254),
93 1255 => Some(encoding_rs::WINDOWS_1255),
94 1256 => Some(encoding_rs::WINDOWS_1256),
95 1257 => Some(encoding_rs::WINDOWS_1257),
96 1258 => Some(encoding_rs::WINDOWS_1258),
97 _ => None,
98 }
99}
100
101#[cfg(feature = "encoding")]
103fn code_page_for_lcid(lcid: u32) -> Option<u16> {
104 const PRIMARY_LANGUAGE_MASK: u32 = 0x3FF;
106 let primary_lang = lcid & PRIMARY_LANGUAGE_MASK;
107
108 match primary_lang {
109 0x0411 => Some(932), 0x0804 | 0x1004 => Some(936), 0x0404 | 0x0C04 | 0x1404 => Some(950), 0x0412 => Some(949), 0x041E => Some(874), 0x042A => Some(1258), 0x0405 | 0x0415 | 0x040E | 0x041A | 0x081A | 0x141A | 0x101A | 0x041B | 0x0424 | 0x0418
118 | 0x041C => Some(1250),
119
120 0x0419 | 0x0422 | 0x0423 | 0x0402 | 0x042F | 0x0C1A | 0x201A | 0x0440 | 0x0843 | 0x0444
122 | 0x0450 | 0x0485 => Some(1251),
123
124 0x0408 => Some(1253), 0x041F | 0x042C => Some(1254), 0x040D => Some(1255), 0x0401 | 0x0801 | 0x0C01 | 0x1001 | 0x1401 | 0x1801 | 0x1C01 | 0x2001 | 0x2401 | 0x2801
130 | 0x2C01 | 0x3001 | 0x3401 | 0x3801 | 0x3C01 | 0x4001 | 0x0429 | 0x0420 | 0x048C
131 | 0x0463 => Some(1256),
132
133 0x0425..=0x0427 => Some(1257),
135
136 0x0409 | 0x0809 | 0x0C09 | 0x1009 | 0x1409 | 0x1809 | 0x1C09 | 0x2009 | 0x2409 | 0x2809
138 | 0x2C09 | 0x3009 | 0x3409 | 0x0407 | 0x0807 | 0x0C07 | 0x1007 | 0x1407 | 0x040C
139 | 0x080C | 0x0C0C | 0x100C | 0x140C | 0x180C | 0x0410 | 0x0810 | 0x0413 | 0x0813
140 | 0x0416 | 0x0816 | 0x040A | 0x080A | 0x0C0A | 0x100A | 0x140A | 0x180A | 0x1C0A
141 | 0x200A | 0x240A | 0x280A | 0x2C0A | 0x300A | 0x340A | 0x380A | 0x3C0A | 0x400A
142 | 0x440A | 0x480A | 0x4C0A | 0x500A => Some(1252),
143
144 _ => Some(1252), }
146}
147
148impl TypeInfo {
149 #[must_use]
151 pub fn int(type_id: u8) -> Self {
152 Self {
153 type_id,
154 length: None,
155 scale: None,
156 precision: None,
157 collation: None,
158 }
159 }
160
161 #[must_use]
163 pub fn varchar(length: u32) -> Self {
164 Self {
165 type_id: 0xE7, length: Some(length),
167 scale: None,
168 precision: None,
169 collation: None,
170 }
171 }
172
173 #[must_use]
175 pub fn decimal(precision: u8, scale: u8) -> Self {
176 Self {
177 type_id: 0x6C,
178 length: None,
179 scale: Some(scale),
180 precision: Some(precision),
181 collation: None,
182 }
183 }
184
185 #[must_use]
187 pub fn datetime_with_scale(type_id: u8, scale: u8) -> Self {
188 Self {
189 type_id,
190 length: None,
191 scale: Some(scale),
192 precision: None,
193 collation: None,
194 }
195 }
196}
197
198pub fn decode_value(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
200 match type_info.type_id {
201 0x1F => Ok(SqlValue::Null), 0x32 => decode_bit(buf), 0x30 => decode_tinyint(buf), 0x34 => decode_smallint(buf), 0x38 => decode_int(buf), 0x7F => decode_bigint(buf), 0x3B => decode_float(buf), 0x3E => decode_double(buf), 0x26 => decode_intn(buf, type_info),
213
214 0xE7 => decode_nvarchar(buf, type_info), 0xAF => decode_varchar(buf, type_info), 0xA7 => decode_varchar(buf, type_info), 0xA5 => decode_varbinary(buf, type_info), 0xAD => decode_varbinary(buf, type_info), 0x24 => decode_guid(buf),
225
226 0x6C | 0x6A => decode_decimal(buf, type_info),
228
229 0x28 => decode_date(buf), 0x29 => decode_time(buf, type_info), 0x2A => decode_datetime2(buf, type_info), 0x2B => decode_datetimeoffset(buf, type_info), 0x3D => decode_datetime(buf), 0x3F => decode_smalldatetime(buf), 0xF1 => decode_xml(buf),
239
240 _ => Err(TypeError::UnsupportedConversion {
241 from: format!("TDS type 0x{:02X}", type_info.type_id),
242 to: "SqlValue",
243 }),
244 }
245}
246
247fn decode_bit(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
248 if buf.remaining() < 1 {
249 return Err(TypeError::BufferTooSmall {
250 needed: 1,
251 available: buf.remaining(),
252 });
253 }
254 Ok(SqlValue::Bool(buf.get_u8() != 0))
255}
256
257fn decode_tinyint(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
258 if buf.remaining() < 1 {
259 return Err(TypeError::BufferTooSmall {
260 needed: 1,
261 available: buf.remaining(),
262 });
263 }
264 Ok(SqlValue::TinyInt(buf.get_u8()))
265}
266
267fn decode_smallint(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
268 if buf.remaining() < 2 {
269 return Err(TypeError::BufferTooSmall {
270 needed: 2,
271 available: buf.remaining(),
272 });
273 }
274 Ok(SqlValue::SmallInt(buf.get_i16_le()))
275}
276
277fn decode_int(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
278 if buf.remaining() < 4 {
279 return Err(TypeError::BufferTooSmall {
280 needed: 4,
281 available: buf.remaining(),
282 });
283 }
284 Ok(SqlValue::Int(buf.get_i32_le()))
285}
286
287fn decode_bigint(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
288 if buf.remaining() < 8 {
289 return Err(TypeError::BufferTooSmall {
290 needed: 8,
291 available: buf.remaining(),
292 });
293 }
294 Ok(SqlValue::BigInt(buf.get_i64_le()))
295}
296
297fn decode_float(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
298 if buf.remaining() < 4 {
299 return Err(TypeError::BufferTooSmall {
300 needed: 4,
301 available: buf.remaining(),
302 });
303 }
304 Ok(SqlValue::Float(buf.get_f32_le()))
305}
306
307fn decode_double(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
308 if buf.remaining() < 8 {
309 return Err(TypeError::BufferTooSmall {
310 needed: 8,
311 available: buf.remaining(),
312 });
313 }
314 Ok(SqlValue::Double(buf.get_f64_le()))
315}
316
317fn decode_intn(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
318 if buf.remaining() < 1 {
319 return Err(TypeError::BufferTooSmall {
320 needed: 1,
321 available: buf.remaining(),
322 });
323 }
324
325 let actual_len = buf.get_u8() as usize;
326 if actual_len == 0 {
327 return Ok(SqlValue::Null);
328 }
329
330 if buf.remaining() < actual_len {
331 return Err(TypeError::BufferTooSmall {
332 needed: actual_len,
333 available: buf.remaining(),
334 });
335 }
336
337 match actual_len {
338 1 => Ok(SqlValue::TinyInt(buf.get_u8())),
339 2 => Ok(SqlValue::SmallInt(buf.get_i16_le())),
340 4 => Ok(SqlValue::Int(buf.get_i32_le())),
341 8 => Ok(SqlValue::BigInt(buf.get_i64_le())),
342 _ => Err(TypeError::InvalidBinary(format!(
343 "invalid INTN length: {actual_len}"
344 ))),
345 }
346}
347
348fn decode_nvarchar(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
349 if buf.remaining() < 2 {
350 return Err(TypeError::BufferTooSmall {
351 needed: 2,
352 available: buf.remaining(),
353 });
354 }
355
356 let byte_len = buf.get_u16_le() as usize;
357
358 if byte_len == 0xFFFF {
360 return Ok(SqlValue::Null);
361 }
362
363 if buf.remaining() < byte_len {
364 return Err(TypeError::BufferTooSmall {
365 needed: byte_len,
366 available: buf.remaining(),
367 });
368 }
369
370 let utf16_data = buf.copy_to_bytes(byte_len);
371 let s = decode_utf16_string(&utf16_data)?;
372 Ok(SqlValue::String(s))
373}
374
375fn decode_varchar(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
376 if buf.remaining() < 2 {
377 return Err(TypeError::BufferTooSmall {
378 needed: 2,
379 available: buf.remaining(),
380 });
381 }
382
383 let byte_len = buf.get_u16_le() as usize;
384
385 if byte_len == 0xFFFF {
387 return Ok(SqlValue::Null);
388 }
389
390 if buf.remaining() < byte_len {
391 return Err(TypeError::BufferTooSmall {
392 needed: byte_len,
393 available: buf.remaining(),
394 });
395 }
396
397 let data = buf.copy_to_bytes(byte_len);
398
399 if let Ok(s) = String::from_utf8(data.to_vec()) {
401 return Ok(SqlValue::String(s));
402 }
403
404 #[cfg(feature = "encoding")]
406 if let Some(ref collation) = type_info.collation {
407 if let Some(encoding) = collation.encoding() {
408 let (decoded, _, had_errors) = encoding.decode(&data);
409 if !had_errors {
410 return Ok(SqlValue::String(decoded.into_owned()));
411 }
412 }
413 }
414
415 #[cfg(not(feature = "encoding"))]
417 let _ = type_info;
418
419 Ok(SqlValue::String(
421 String::from_utf8_lossy(&data).into_owned(),
422 ))
423}
424
425fn decode_varbinary(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
426 if buf.remaining() < 2 {
427 return Err(TypeError::BufferTooSmall {
428 needed: 2,
429 available: buf.remaining(),
430 });
431 }
432
433 let byte_len = buf.get_u16_le() as usize;
434
435 if byte_len == 0xFFFF {
437 return Ok(SqlValue::Null);
438 }
439
440 if buf.remaining() < byte_len {
441 return Err(TypeError::BufferTooSmall {
442 needed: byte_len,
443 available: buf.remaining(),
444 });
445 }
446
447 let data = buf.copy_to_bytes(byte_len);
448 Ok(SqlValue::Binary(data))
449}
450
451#[cfg(feature = "uuid")]
452fn decode_guid(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
453 if buf.remaining() < 1 {
454 return Err(TypeError::BufferTooSmall {
455 needed: 1,
456 available: buf.remaining(),
457 });
458 }
459
460 let len = buf.get_u8() as usize;
461 if len == 0 {
462 return Ok(SqlValue::Null);
463 }
464
465 if len != 16 {
466 return Err(TypeError::InvalidBinary(format!(
467 "invalid GUID length: {len}"
468 )));
469 }
470
471 if buf.remaining() < 16 {
472 return Err(TypeError::BufferTooSmall {
473 needed: 16,
474 available: buf.remaining(),
475 });
476 }
477
478 let mut bytes = [0u8; 16];
480
481 bytes[3] = buf.get_u8();
483 bytes[2] = buf.get_u8();
484 bytes[1] = buf.get_u8();
485 bytes[0] = buf.get_u8();
486
487 bytes[5] = buf.get_u8();
489 bytes[4] = buf.get_u8();
490
491 bytes[7] = buf.get_u8();
493 bytes[6] = buf.get_u8();
494
495 for byte in &mut bytes[8..16] {
497 *byte = buf.get_u8();
498 }
499
500 Ok(SqlValue::Uuid(uuid::Uuid::from_bytes(bytes)))
501}
502
503#[cfg(not(feature = "uuid"))]
504fn decode_guid(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
505 if buf.remaining() < 1 {
507 return Err(TypeError::BufferTooSmall {
508 needed: 1,
509 available: buf.remaining(),
510 });
511 }
512
513 let len = buf.get_u8() as usize;
514 if len == 0 {
515 return Ok(SqlValue::Null);
516 }
517
518 if buf.remaining() < len {
519 return Err(TypeError::BufferTooSmall {
520 needed: len,
521 available: buf.remaining(),
522 });
523 }
524
525 let data = buf.copy_to_bytes(len);
526 Ok(SqlValue::Binary(data))
527}
528
529#[cfg(feature = "decimal")]
530fn decode_decimal(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
531 use rust_decimal::Decimal;
532
533 if buf.remaining() < 1 {
534 return Err(TypeError::BufferTooSmall {
535 needed: 1,
536 available: buf.remaining(),
537 });
538 }
539
540 let len = buf.get_u8() as usize;
541 if len == 0 {
542 return Ok(SqlValue::Null);
543 }
544
545 if buf.remaining() < len {
546 return Err(TypeError::BufferTooSmall {
547 needed: len,
548 available: buf.remaining(),
549 });
550 }
551
552 let sign = buf.get_u8();
554 let remaining = len - 1;
555
556 let mut mantissa_bytes = [0u8; 16];
558 for byte in mantissa_bytes.iter_mut().take(remaining.min(16)) {
559 *byte = buf.get_u8();
560 }
561
562 let mantissa = u128::from_le_bytes(mantissa_bytes);
563 let scale = type_info.scale.unwrap_or(0) as u32;
564
565 let decimal = i128::try_from(mantissa)
569 .ok()
570 .and_then(|m| Decimal::try_from_i128_with_scale(m, scale).ok());
571 match decimal {
572 Some(mut decimal) => {
573 if sign == 0 {
574 decimal.set_sign_negative(true);
575 }
576 Ok(SqlValue::Decimal(decimal))
577 }
578 None => {
579 let divisor = 10f64.powi(scale as i32);
580 let value = (mantissa as f64) / divisor;
581 let value = if sign == 0 { -value } else { value };
582 Ok(SqlValue::Double(value))
583 }
584 }
585}
586
587#[cfg(not(feature = "decimal"))]
588fn decode_decimal(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
589 if buf.remaining() < 1 {
591 return Err(TypeError::BufferTooSmall {
592 needed: 1,
593 available: buf.remaining(),
594 });
595 }
596
597 let len = buf.get_u8() as usize;
598 if len == 0 {
599 return Ok(SqlValue::Null);
600 }
601
602 if buf.remaining() < len {
603 return Err(TypeError::BufferTooSmall {
604 needed: len,
605 available: buf.remaining(),
606 });
607 }
608
609 buf.advance(len);
610 Ok(SqlValue::String("DECIMAL (feature disabled)".to_string()))
611}
612
613#[cfg(feature = "chrono")]
614fn decode_date(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
615 if buf.remaining() < 1 {
616 return Err(TypeError::BufferTooSmall {
617 needed: 1,
618 available: buf.remaining(),
619 });
620 }
621
622 let len = buf.get_u8() as usize;
623 if len == 0 {
624 return Ok(SqlValue::Null);
625 }
626
627 if len != 3 {
628 return Err(TypeError::InvalidDateTime(format!(
629 "invalid DATE length: {len}"
630 )));
631 }
632
633 if buf.remaining() < 3 {
634 return Err(TypeError::BufferTooSmall {
635 needed: 3,
636 available: buf.remaining(),
637 });
638 }
639
640 let days = buf.get_u8() as u32 | ((buf.get_u8() as u32) << 8) | ((buf.get_u8() as u32) << 16);
642
643 let base = chrono::NaiveDate::from_ymd_opt(1, 1, 1).expect("valid date");
644 let date = base + chrono::Duration::days(days as i64);
645
646 Ok(SqlValue::Date(date))
647}
648
649#[cfg(not(feature = "chrono"))]
650fn decode_date(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
651 if buf.remaining() < 1 {
652 return Err(TypeError::BufferTooSmall {
653 needed: 1,
654 available: buf.remaining(),
655 });
656 }
657
658 let len = buf.get_u8() as usize;
659 if len == 0 {
660 return Ok(SqlValue::Null);
661 }
662
663 if buf.remaining() < len {
664 return Err(TypeError::BufferTooSmall {
665 needed: len,
666 available: buf.remaining(),
667 });
668 }
669
670 buf.advance(len);
671 Ok(SqlValue::String("DATE (feature disabled)".to_string()))
672}
673
674#[cfg(feature = "chrono")]
675fn decode_time(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
676 let scale = type_info.scale.unwrap_or(7);
677 let time_len = time_bytes_for_scale(scale);
678
679 if buf.remaining() < 1 {
680 return Err(TypeError::BufferTooSmall {
681 needed: 1,
682 available: buf.remaining(),
683 });
684 }
685
686 let len = buf.get_u8() as usize;
687 if len == 0 {
688 return Ok(SqlValue::Null);
689 }
690
691 if buf.remaining() < len {
692 return Err(TypeError::BufferTooSmall {
693 needed: len,
694 available: buf.remaining(),
695 });
696 }
697 if len < time_len {
700 return Err(TypeError::InvalidDateTime(format!(
701 "TIME length {len} too short for scale {scale}"
702 )));
703 }
704
705 let mut time_bytes = [0u8; 8];
707 for byte in time_bytes.iter_mut().take(time_len) {
708 *byte = buf.get_u8();
709 }
710
711 let intervals = u64::from_le_bytes(time_bytes);
712 let time = intervals_to_time(intervals, scale);
713
714 Ok(SqlValue::Time(time))
715}
716
717#[cfg(not(feature = "chrono"))]
718fn decode_time(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
719 if buf.remaining() < 1 {
720 return Err(TypeError::BufferTooSmall {
721 needed: 1,
722 available: buf.remaining(),
723 });
724 }
725
726 let len = buf.get_u8() as usize;
727 if len == 0 {
728 return Ok(SqlValue::Null);
729 }
730
731 if buf.remaining() < len {
732 return Err(TypeError::BufferTooSmall {
733 needed: len,
734 available: buf.remaining(),
735 });
736 }
737
738 buf.advance(len);
739 Ok(SqlValue::String("TIME (feature disabled)".to_string()))
740}
741
742#[cfg(feature = "chrono")]
743fn decode_datetime2(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
744 let scale = type_info.scale.unwrap_or(7);
745 let time_len = time_bytes_for_scale(scale);
746
747 if buf.remaining() < 1 {
748 return Err(TypeError::BufferTooSmall {
749 needed: 1,
750 available: buf.remaining(),
751 });
752 }
753
754 let len = buf.get_u8() as usize;
755 if len == 0 {
756 return Ok(SqlValue::Null);
757 }
758
759 if buf.remaining() < len {
760 return Err(TypeError::BufferTooSmall {
761 needed: len,
762 available: buf.remaining(),
763 });
764 }
765 if len < time_len + 3 {
768 return Err(TypeError::InvalidDateTime(format!(
769 "DATETIME2 length {len} too short for scale {scale}"
770 )));
771 }
772
773 let mut time_bytes = [0u8; 8];
775 for byte in time_bytes.iter_mut().take(time_len) {
776 *byte = buf.get_u8();
777 }
778 let intervals = u64::from_le_bytes(time_bytes);
779 let time = intervals_to_time(intervals, scale);
780
781 let days = buf.get_u8() as u32 | ((buf.get_u8() as u32) << 8) | ((buf.get_u8() as u32) << 16);
783 let base = chrono::NaiveDate::from_ymd_opt(1, 1, 1).expect("valid date");
784 let date = base + chrono::Duration::days(days as i64);
785
786 Ok(SqlValue::DateTime(date.and_time(time)))
787}
788
789#[cfg(not(feature = "chrono"))]
790fn decode_datetime2(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
791 if buf.remaining() < 1 {
792 return Err(TypeError::BufferTooSmall {
793 needed: 1,
794 available: buf.remaining(),
795 });
796 }
797
798 let len = buf.get_u8() as usize;
799 if len == 0 {
800 return Ok(SqlValue::Null);
801 }
802
803 if buf.remaining() < len {
804 return Err(TypeError::BufferTooSmall {
805 needed: len,
806 available: buf.remaining(),
807 });
808 }
809
810 buf.advance(len);
811 Ok(SqlValue::String("DATETIME2 (feature disabled)".to_string()))
812}
813
814#[cfg(feature = "chrono")]
815fn decode_datetimeoffset(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
816 use chrono::TimeZone;
817
818 let scale = type_info.scale.unwrap_or(7);
819 let time_len = time_bytes_for_scale(scale);
820
821 if buf.remaining() < 1 {
822 return Err(TypeError::BufferTooSmall {
823 needed: 1,
824 available: buf.remaining(),
825 });
826 }
827
828 let len = buf.get_u8() as usize;
829 if len == 0 {
830 return Ok(SqlValue::Null);
831 }
832
833 if buf.remaining() < len {
834 return Err(TypeError::BufferTooSmall {
835 needed: len,
836 available: buf.remaining(),
837 });
838 }
839 if len < time_len + 5 {
842 return Err(TypeError::InvalidDateTime(format!(
843 "DATETIMEOFFSET length {len} too short for scale {scale}"
844 )));
845 }
846
847 let mut time_bytes = [0u8; 8];
849 for byte in time_bytes.iter_mut().take(time_len) {
850 *byte = buf.get_u8();
851 }
852 let intervals = u64::from_le_bytes(time_bytes);
853 let time = intervals_to_time(intervals, scale);
854
855 let days = buf.get_u8() as u32 | ((buf.get_u8() as u32) << 8) | ((buf.get_u8() as u32) << 16);
857 let base = chrono::NaiveDate::from_ymd_opt(1, 1, 1).expect("valid date");
858 let date = base + chrono::Duration::days(days as i64);
859
860 let offset_minutes = buf.get_i16_le();
862 let offset = chrono::FixedOffset::east_opt((offset_minutes as i32) * 60)
863 .ok_or_else(|| TypeError::InvalidDateTime(format!("invalid offset: {offset_minutes}")))?;
864
865 let datetime = offset.from_utc_datetime(&date.and_time(time));
868
869 Ok(SqlValue::DateTimeOffset(datetime))
870}
871
872#[cfg(not(feature = "chrono"))]
873fn decode_datetimeoffset(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
874 if buf.remaining() < 1 {
875 return Err(TypeError::BufferTooSmall {
876 needed: 1,
877 available: buf.remaining(),
878 });
879 }
880
881 let len = buf.get_u8() as usize;
882 if len == 0 {
883 return Ok(SqlValue::Null);
884 }
885
886 if buf.remaining() < len {
887 return Err(TypeError::BufferTooSmall {
888 needed: len,
889 available: buf.remaining(),
890 });
891 }
892
893 buf.advance(len);
894 Ok(SqlValue::String(
895 "DATETIMEOFFSET (feature disabled)".to_string(),
896 ))
897}
898
899#[cfg(feature = "chrono")]
900fn decode_datetime(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
901 if buf.remaining() < 8 {
903 return Err(TypeError::BufferTooSmall {
904 needed: 8,
905 available: buf.remaining(),
906 });
907 }
908
909 let days = buf.get_i32_le();
910 let time_300ths = buf.get_u32_le();
911
912 let base = chrono::NaiveDate::from_ymd_opt(1900, 1, 1).expect("valid date");
913 let date = base
915 .checked_add_signed(chrono::Duration::days(days as i64))
916 .ok_or_else(|| TypeError::InvalidDateTime(format!("DATETIME days out of range: {days}")))?;
917
918 let total_ms = (time_300ths as u64 * 1000) / 300;
920 let secs = (total_ms / 1000) as u32;
921 let nanos = ((total_ms % 1000) * 1_000_000) as u32;
922
923 let time = chrono::NaiveTime::from_num_seconds_from_midnight_opt(secs, nanos)
924 .ok_or_else(|| TypeError::InvalidDateTime("invalid DATETIME time".to_string()))?;
925
926 Ok(SqlValue::DateTime(date.and_time(time)))
927}
928
929#[cfg(not(feature = "chrono"))]
930fn decode_datetime(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
931 if buf.remaining() < 8 {
932 return Err(TypeError::BufferTooSmall {
933 needed: 8,
934 available: buf.remaining(),
935 });
936 }
937
938 buf.advance(8);
939 Ok(SqlValue::String("DATETIME (feature disabled)".to_string()))
940}
941
942#[cfg(feature = "chrono")]
943fn decode_smalldatetime(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
944 if buf.remaining() < 4 {
946 return Err(TypeError::BufferTooSmall {
947 needed: 4,
948 available: buf.remaining(),
949 });
950 }
951
952 let days = buf.get_u16_le();
953 let minutes = buf.get_u16_le();
954
955 let base = chrono::NaiveDate::from_ymd_opt(1900, 1, 1).expect("valid date");
956 let date = base + chrono::Duration::days(days as i64);
957
958 let time = chrono::NaiveTime::from_num_seconds_from_midnight_opt((minutes as u32) * 60, 0)
959 .ok_or_else(|| TypeError::InvalidDateTime("invalid SMALLDATETIME time".to_string()))?;
960
961 Ok(SqlValue::DateTime(date.and_time(time)))
962}
963
964#[cfg(not(feature = "chrono"))]
965fn decode_smalldatetime(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
966 if buf.remaining() < 4 {
967 return Err(TypeError::BufferTooSmall {
968 needed: 4,
969 available: buf.remaining(),
970 });
971 }
972
973 buf.advance(4);
974 Ok(SqlValue::String(
975 "SMALLDATETIME (feature disabled)".to_string(),
976 ))
977}
978
979fn decode_xml(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
980 if buf.remaining() < 2 {
982 return Err(TypeError::BufferTooSmall {
983 needed: 2,
984 available: buf.remaining(),
985 });
986 }
987
988 let byte_len = buf.get_u16_le() as usize;
989
990 if byte_len == 0xFFFF {
991 return Ok(SqlValue::Null);
992 }
993
994 if buf.remaining() < byte_len {
995 return Err(TypeError::BufferTooSmall {
996 needed: byte_len,
997 available: buf.remaining(),
998 });
999 }
1000
1001 let utf16_data = buf.copy_to_bytes(byte_len);
1002 let s = decode_utf16_string(&utf16_data)?;
1003 Ok(SqlValue::Xml(s))
1004}
1005
1006pub fn decode_utf16_string(data: &[u8]) -> Result<String, TypeError> {
1008 if data.len() % 2 != 0 {
1009 return Err(TypeError::InvalidEncoding(
1010 "UTF-16 data must have even length".to_string(),
1011 ));
1012 }
1013
1014 let utf16: Vec<u16> = data
1015 .chunks_exact(2)
1016 .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
1017 .collect();
1018
1019 String::from_utf16(&utf16).map_err(|e| TypeError::InvalidEncoding(e.to_string()))
1020}
1021
1022#[cfg(feature = "chrono")]
1024fn time_bytes_for_scale(scale: u8) -> usize {
1025 match scale {
1026 0..=2 => 3,
1027 3..=4 => 4,
1028 5..=7 => 5,
1029 _ => 5, }
1031}
1032
1033#[cfg(feature = "chrono")]
1035fn intervals_to_time(intervals: u64, scale: u8) -> chrono::NaiveTime {
1036 let nanos = match scale {
1050 0 => intervals.saturating_mul(1_000_000_000),
1051 1 => intervals.saturating_mul(100_000_000),
1052 2 => intervals.saturating_mul(10_000_000),
1053 3 => intervals.saturating_mul(1_000_000),
1054 4 => intervals.saturating_mul(100_000),
1055 5 => intervals.saturating_mul(10_000),
1056 6 => intervals.saturating_mul(1_000),
1057 7 => intervals.saturating_mul(100),
1058 _ => intervals.saturating_mul(100),
1059 };
1060
1061 let secs = (nanos / 1_000_000_000) as u32;
1062 let nano_part = (nanos % 1_000_000_000) as u32;
1063
1064 chrono::NaiveTime::from_num_seconds_from_midnight_opt(secs, nano_part)
1065 .unwrap_or_else(|| chrono::NaiveTime::from_hms_opt(0, 0, 0).expect("valid time"))
1066}
1067
1068#[cfg(test)]
1069#[allow(clippy::unwrap_used, clippy::panic)]
1070mod tests {
1071 use super::*;
1072
1073 #[test]
1074 fn test_decode_int() {
1075 let mut buf = Bytes::from_static(&[42, 0, 0, 0]);
1076 let type_info = TypeInfo::int(0x38);
1077 let result = decode_value(&mut buf, &type_info).unwrap();
1078 assert_eq!(result, SqlValue::Int(42));
1079 }
1080
1081 #[cfg(feature = "chrono")]
1082 #[test]
1083 fn hostile_datetime_days_overflow_is_error_not_panic() {
1084 let mut data = Vec::new();
1087 data.extend_from_slice(&i32::MAX.to_le_bytes());
1088 data.extend_from_slice(&0u32.to_le_bytes());
1089 let mut buf = Bytes::from(data);
1090 assert!(decode_datetime(&mut buf).is_err());
1091 }
1092
1093 #[cfg(feature = "chrono")]
1100 #[test]
1101 fn test_datetimeoffset_decodes_wire_as_utc() {
1102 use chrono::TimeZone;
1103
1104 let mut data = Vec::new();
1105 data.push(10u8); let intervals: u64 = 10 * 3600 * 10_000_000; for i in 0..5 {
1108 data.push(((intervals >> (8 * i)) & 0xFF) as u8);
1109 }
1110 let base = chrono::NaiveDate::from_ymd_opt(1, 1, 1).unwrap();
1111 let days = (chrono::NaiveDate::from_ymd_opt(2024, 3, 15).unwrap() - base).num_days() as u32;
1112 data.push((days & 0xFF) as u8);
1113 data.push(((days >> 8) & 0xFF) as u8);
1114 data.push(((days >> 16) & 0xFF) as u8);
1115 data.extend_from_slice(&120i16.to_le_bytes()); let type_info = TypeInfo {
1118 type_id: 0x2B,
1119 length: None,
1120 scale: Some(7),
1121 precision: None,
1122 collation: None,
1123 };
1124 let mut buf = Bytes::from(data);
1125 let value = decode_datetimeoffset(&mut buf, &type_info).unwrap();
1126
1127 let offset = chrono::FixedOffset::east_opt(2 * 3600).unwrap();
1128 let expected = offset.with_ymd_and_hms(2024, 3, 15, 12, 0, 0).unwrap();
1129 match value {
1130 SqlValue::DateTimeOffset(dt) => {
1131 assert_eq!(dt, expected);
1132 assert_eq!(dt.offset().local_minus_utc(), 7200);
1133 assert_eq!(
1134 dt.naive_utc(),
1135 chrono::NaiveDate::from_ymd_opt(2024, 3, 15)
1136 .unwrap()
1137 .and_hms_opt(10, 0, 0)
1138 .unwrap()
1139 );
1140 }
1141 other => panic!("expected DateTimeOffset, got {other:?}"),
1142 }
1143 }
1144
1145 #[test]
1146 fn test_decode_utf16_string() {
1147 let data = [0x41, 0x00, 0x42, 0x00];
1149 let result = decode_utf16_string(&data).unwrap();
1150 assert_eq!(result, "AB");
1151 }
1152
1153 #[test]
1154 fn test_decode_nvarchar() {
1155 let mut buf = Bytes::from_static(&[4, 0, 0x41, 0x00, 0x42, 0x00]);
1157 let type_info = TypeInfo::varchar(100);
1158 let type_info = TypeInfo {
1159 type_id: 0xE7,
1160 ..type_info
1161 };
1162 let result = decode_value(&mut buf, &type_info).unwrap();
1163 assert_eq!(result, SqlValue::String("AB".to_string()));
1164 }
1165
1166 #[test]
1167 fn test_decode_null_nvarchar() {
1168 let mut buf = Bytes::from_static(&[0xFF, 0xFF]);
1170 let type_info = TypeInfo {
1171 type_id: 0xE7,
1172 length: Some(100),
1173 scale: None,
1174 precision: None,
1175 collation: None,
1176 };
1177 let result = decode_value(&mut buf, &type_info).unwrap();
1178 assert_eq!(result, SqlValue::Null);
1179 }
1180
1181 #[cfg(feature = "decimal")]
1186 mod decimal_roundtrip {
1187 use super::*;
1188 use bytes::{BufMut, BytesMut};
1189 use rust_decimal::Decimal;
1190
1191 fn roundtrip_decimal(value: Decimal, precision: u8, scale: u8) -> Decimal {
1193 let mut encode_buf = BytesMut::new();
1195 crate::encode::encode_decimal(value, &mut encode_buf);
1196 let encoded_len = encode_buf.len() as u8; let mut decode_buf = BytesMut::with_capacity(1 + encoded_len as usize);
1200 decode_buf.put_u8(encoded_len);
1201 decode_buf.extend_from_slice(&encode_buf);
1202
1203 let mut bytes = decode_buf.freeze();
1204 let type_info = TypeInfo::decimal(precision, scale);
1205 match decode_value(&mut bytes, &type_info).unwrap() {
1206 SqlValue::Decimal(d) => d,
1207 other => panic!("expected Decimal, got {other:?}"),
1208 }
1209 }
1210
1211 #[test]
1212 fn test_negative_decimal_17_80() {
1213 let d = Decimal::new(-1780, 2); let result = roundtrip_decimal(d, 18, 2);
1215 assert_eq!(result, d, "round-trip of -17.80 must be exact");
1216 }
1217
1218 #[test]
1219 fn test_negative_decimal_0_01() {
1220 let d = Decimal::new(-1, 2); let result = roundtrip_decimal(d, 18, 2);
1222 assert_eq!(result, d, "round-trip of -0.01 must be exact");
1223 }
1224
1225 #[test]
1226 fn test_negative_decimal_large() {
1227 let d = Decimal::new(-9999999999, 2); let result = roundtrip_decimal(d, 18, 2);
1229 assert_eq!(result, d, "round-trip of -99999999.99 must be exact");
1230 }
1231
1232 #[test]
1233 fn test_positive_decimal() {
1234 let d = Decimal::new(1780, 2); let result = roundtrip_decimal(d, 18, 2);
1236 assert_eq!(result, d, "round-trip of 17.80 must be exact");
1237 }
1238
1239 #[test]
1240 fn test_decimal_zero() {
1241 let d = Decimal::ZERO;
1242 let result = roundtrip_decimal(d, 18, 0);
1243 assert_eq!(result, d, "round-trip of 0 must be exact");
1244 }
1245
1246 #[test]
1247 fn test_decimal_max_precision() {
1248 let d = Decimal::new(i64::MAX, 0);
1250 let result = roundtrip_decimal(d, 38, 0);
1251 assert_eq!(result, d, "round-trip of large positive must be exact");
1252 }
1253
1254 #[test]
1255 fn test_decimal_min_precision() {
1256 let d = Decimal::new(i64::MIN + 1, 0);
1257 let result = roundtrip_decimal(d, 38, 0);
1258 assert_eq!(result, d, "round-trip of large negative must be exact");
1259 }
1260 }
1261
1262 #[cfg(feature = "chrono")]
1267 mod date_tests {
1268 use bytes::{BufMut, BytesMut};
1269 use chrono::NaiveDate;
1270
1271 #[test]
1272 fn test_encode_date_pre_1900() {
1273 let mut buf = BytesMut::new();
1275 let date = NaiveDate::from_ymd_opt(1753, 1, 1).unwrap();
1276 crate::encode::encode_date(date, &mut buf);
1277 assert_eq!(buf.len(), 3, "DATE encoding is always 3 bytes");
1278 }
1279
1280 #[test]
1281 fn test_encode_date_epoch() {
1282 let mut buf = BytesMut::new();
1284 let date = NaiveDate::from_ymd_opt(1, 1, 1).unwrap();
1285 crate::encode::encode_date(date, &mut buf);
1286 assert_eq!(&buf[..], &[0, 0, 0]);
1288 }
1289
1290 #[test]
1291 fn test_encode_date_max() {
1292 let mut buf = BytesMut::new();
1294 let date = NaiveDate::from_ymd_opt(9999, 12, 31).unwrap();
1295 crate::encode::encode_date(date, &mut buf);
1296 assert_eq!(buf.len(), 3, "DATE encoding is always 3 bytes");
1297 let days = buf[0] as u32 | ((buf[1] as u32) << 8) | ((buf[2] as u32) << 16);
1299 assert_eq!(days, 3_652_058);
1300 }
1301
1302 #[test]
1303 fn test_decode_datetime_pre_1900() {
1304 use super::*;
1307
1308 let base = NaiveDate::from_ymd_opt(1900, 1, 1).unwrap();
1309 let target = NaiveDate::from_ymd_opt(1753, 1, 1).unwrap();
1310 let days = target.signed_duration_since(base).num_days() as i32;
1311
1312 let mut raw = BytesMut::new();
1314 raw.put_i32_le(days);
1315 raw.put_u32_le(0); let mut buf = raw.freeze();
1318 let result = decode_datetime(&mut buf).unwrap();
1319
1320 match result {
1321 SqlValue::DateTime(dt) => {
1322 assert_eq!(dt.date(), target);
1323 }
1324 other => panic!("expected DateTime, got {other:?}"),
1325 }
1326 }
1327
1328 #[test]
1329 fn test_decode_smalldatetime_1900() {
1330 use super::*;
1332
1333 let mut raw = BytesMut::new();
1335 raw.put_u16_le(0);
1336 raw.put_u16_le(0);
1337
1338 let mut buf = raw.freeze();
1339 let result = decode_smalldatetime(&mut buf).unwrap();
1340
1341 match result {
1342 SqlValue::DateTime(dt) => {
1343 assert_eq!(
1344 dt,
1345 NaiveDate::from_ymd_opt(1900, 1, 1)
1346 .unwrap()
1347 .and_hms_opt(0, 0, 0)
1348 .unwrap()
1349 );
1350 }
1351 other => panic!("expected DateTime, got {other:?}"),
1352 }
1353 }
1354 }
1355
1356 #[cfg(feature = "decimal")]
1361 mod proptest_decimal {
1362 use super::*;
1363 use bytes::{BufMut, BytesMut};
1364 use proptest::prelude::*;
1365 use rust_decimal::Decimal;
1366
1367 fn roundtrip_decimal(value: Decimal, scale: u8) -> Decimal {
1369 let mut encode_buf = BytesMut::new();
1370 crate::encode::encode_decimal(value, &mut encode_buf);
1371 let encoded_len = encode_buf.len() as u8;
1372
1373 let mut decode_buf = BytesMut::with_capacity(1 + encoded_len as usize);
1374 decode_buf.put_u8(encoded_len);
1375 decode_buf.extend_from_slice(&encode_buf);
1376
1377 let mut bytes = decode_buf.freeze();
1378 let type_info = TypeInfo::decimal(38, scale);
1379 match decode_value(&mut bytes, &type_info).unwrap() {
1380 SqlValue::Decimal(d) => d,
1381 other => panic!("expected Decimal, got {other:?}"),
1382 }
1383 }
1384
1385 proptest! {
1386 #[test]
1387 fn decimal_roundtrip_scale0(mantissa in -999_999_999_999i64..=999_999_999_999i64) {
1388 let d = Decimal::new(mantissa, 0);
1389 let result = roundtrip_decimal(d, 0);
1390 prop_assert_eq!(result, d);
1391 }
1392
1393 #[test]
1394 fn decimal_roundtrip_scale2(mantissa in -999_999_999_999i64..=999_999_999_999i64) {
1395 let d = Decimal::new(mantissa, 2);
1396 let result = roundtrip_decimal(d, 2);
1397 prop_assert_eq!(result, d);
1398 }
1399
1400 #[test]
1401 fn decimal_roundtrip_various_scales(
1402 mantissa in -999_999_999i64..=999_999_999i64,
1403 scale in 0u8..=10u8,
1404 ) {
1405 let d = Decimal::new(mantissa, scale as u32);
1406 let result = roundtrip_decimal(d, scale);
1407 prop_assert_eq!(result, d);
1408 }
1409 }
1410 }
1411
1412 #[cfg(feature = "chrono")]
1413 mod proptest_date {
1414 use bytes::BytesMut;
1415 use chrono::NaiveDate;
1416 use proptest::prelude::*;
1417
1418 proptest! {
1419 #[test]
1420 fn date_encode_never_panics(
1421 year in 1i32..=9999i32,
1422 month in 1u32..=12u32,
1423 day in 1u32..=28u32, ) {
1425 let date = NaiveDate::from_ymd_opt(year, month, day).unwrap();
1426 let mut buf = BytesMut::new();
1427 crate::encode::encode_date(date, &mut buf);
1428 prop_assert_eq!(buf.len(), 3);
1429 }
1430 }
1431 }
1432}