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]
49 pub fn is_utf8(&self) -> bool {
50 (self.lcid & 0x0800_0000) != 0
51 }
52
53 #[cfg(feature = "encoding")]
58 #[must_use]
59 pub fn encoding(&self) -> Option<&'static encoding_rs::Encoding> {
60 encoding_for_lcid(self.lcid)
61 }
62}
63
64#[cfg(feature = "encoding")]
66const UTF8_COLLATION_FLAG: u32 = 0x0800_0000;
67
68#[cfg(feature = "encoding")]
70fn encoding_for_lcid(lcid: u32) -> Option<&'static encoding_rs::Encoding> {
71 if (lcid & UTF8_COLLATION_FLAG) != 0 {
73 return Some(encoding_rs::UTF_8);
74 }
75
76 let code_page = code_page_for_lcid(lcid)?;
78
79 match code_page {
81 874 => Some(encoding_rs::WINDOWS_874),
82 932 => Some(encoding_rs::SHIFT_JIS),
83 936 => Some(encoding_rs::GB18030),
84 949 => Some(encoding_rs::EUC_KR),
85 950 => Some(encoding_rs::BIG5),
86 1250 => Some(encoding_rs::WINDOWS_1250),
87 1251 => Some(encoding_rs::WINDOWS_1251),
88 1252 => Some(encoding_rs::WINDOWS_1252),
89 1253 => Some(encoding_rs::WINDOWS_1253),
90 1254 => Some(encoding_rs::WINDOWS_1254),
91 1255 => Some(encoding_rs::WINDOWS_1255),
92 1256 => Some(encoding_rs::WINDOWS_1256),
93 1257 => Some(encoding_rs::WINDOWS_1257),
94 1258 => Some(encoding_rs::WINDOWS_1258),
95 _ => None,
96 }
97}
98
99#[cfg(feature = "encoding")]
101fn code_page_for_lcid(lcid: u32) -> Option<u16> {
102 const PRIMARY_LANGUAGE_MASK: u32 = 0x3FF;
104 let primary_lang = lcid & PRIMARY_LANGUAGE_MASK;
105
106 match primary_lang {
107 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
116 | 0x041C => Some(1250),
117
118 0x0419 | 0x0422 | 0x0423 | 0x0402 | 0x042F | 0x0C1A | 0x201A | 0x0440 | 0x0843 | 0x0444
120 | 0x0450 | 0x0485 => Some(1251),
121
122 0x0408 => Some(1253), 0x041F | 0x042C => Some(1254), 0x040D => Some(1255), 0x0401 | 0x0801 | 0x0C01 | 0x1001 | 0x1401 | 0x1801 | 0x1C01 | 0x2001 | 0x2401 | 0x2801
128 | 0x2C01 | 0x3001 | 0x3401 | 0x3801 | 0x3C01 | 0x4001 | 0x0429 | 0x0420 | 0x048C
129 | 0x0463 => Some(1256),
130
131 0x0425..=0x0427 => Some(1257),
133
134 0x0409 | 0x0809 | 0x0C09 | 0x1009 | 0x1409 | 0x1809 | 0x1C09 | 0x2009 | 0x2409 | 0x2809
136 | 0x2C09 | 0x3009 | 0x3409 | 0x0407 | 0x0807 | 0x0C07 | 0x1007 | 0x1407 | 0x040C
137 | 0x080C | 0x0C0C | 0x100C | 0x140C | 0x180C | 0x0410 | 0x0810 | 0x0413 | 0x0813
138 | 0x0416 | 0x0816 | 0x040A | 0x080A | 0x0C0A | 0x100A | 0x140A | 0x180A | 0x1C0A
139 | 0x200A | 0x240A | 0x280A | 0x2C0A | 0x300A | 0x340A | 0x380A | 0x3C0A | 0x400A
140 | 0x440A | 0x480A | 0x4C0A | 0x500A => Some(1252),
141
142 _ => Some(1252), }
144}
145
146impl TypeInfo {
147 #[must_use]
149 pub fn int(type_id: u8) -> Self {
150 Self {
151 type_id,
152 length: None,
153 scale: None,
154 precision: None,
155 collation: None,
156 }
157 }
158
159 #[must_use]
161 pub fn varchar(length: u32) -> Self {
162 Self {
163 type_id: 0xE7, length: Some(length),
165 scale: None,
166 precision: None,
167 collation: None,
168 }
169 }
170
171 #[must_use]
173 pub fn decimal(precision: u8, scale: u8) -> Self {
174 Self {
175 type_id: 0x6C,
176 length: None,
177 scale: Some(scale),
178 precision: Some(precision),
179 collation: None,
180 }
181 }
182
183 #[must_use]
185 pub fn datetime_with_scale(type_id: u8, scale: u8) -> Self {
186 Self {
187 type_id,
188 length: None,
189 scale: Some(scale),
190 precision: None,
191 collation: None,
192 }
193 }
194}
195
196pub fn decode_value(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
198 match type_info.type_id {
199 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),
211
212 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),
223
224 0x6C | 0x6A => decode_decimal(buf, type_info),
226
227 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),
237
238 _ => Err(TypeError::UnsupportedConversion {
239 from: format!("TDS type 0x{:02X}", type_info.type_id),
240 to: "SqlValue",
241 }),
242 }
243}
244
245fn decode_bit(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
246 if buf.remaining() < 1 {
247 return Err(TypeError::BufferTooSmall {
248 needed: 1,
249 available: buf.remaining(),
250 });
251 }
252 Ok(SqlValue::Bool(buf.get_u8() != 0))
253}
254
255fn decode_tinyint(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
256 if buf.remaining() < 1 {
257 return Err(TypeError::BufferTooSmall {
258 needed: 1,
259 available: buf.remaining(),
260 });
261 }
262 Ok(SqlValue::TinyInt(buf.get_u8()))
263}
264
265fn decode_smallint(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
266 if buf.remaining() < 2 {
267 return Err(TypeError::BufferTooSmall {
268 needed: 2,
269 available: buf.remaining(),
270 });
271 }
272 Ok(SqlValue::SmallInt(buf.get_i16_le()))
273}
274
275fn decode_int(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
276 if buf.remaining() < 4 {
277 return Err(TypeError::BufferTooSmall {
278 needed: 4,
279 available: buf.remaining(),
280 });
281 }
282 Ok(SqlValue::Int(buf.get_i32_le()))
283}
284
285fn decode_bigint(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
286 if buf.remaining() < 8 {
287 return Err(TypeError::BufferTooSmall {
288 needed: 8,
289 available: buf.remaining(),
290 });
291 }
292 Ok(SqlValue::BigInt(buf.get_i64_le()))
293}
294
295fn decode_float(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
296 if buf.remaining() < 4 {
297 return Err(TypeError::BufferTooSmall {
298 needed: 4,
299 available: buf.remaining(),
300 });
301 }
302 Ok(SqlValue::Float(buf.get_f32_le()))
303}
304
305fn decode_double(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
306 if buf.remaining() < 8 {
307 return Err(TypeError::BufferTooSmall {
308 needed: 8,
309 available: buf.remaining(),
310 });
311 }
312 Ok(SqlValue::Double(buf.get_f64_le()))
313}
314
315fn decode_intn(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
316 if buf.remaining() < 1 {
317 return Err(TypeError::BufferTooSmall {
318 needed: 1,
319 available: buf.remaining(),
320 });
321 }
322
323 let actual_len = buf.get_u8() as usize;
324 if actual_len == 0 {
325 return Ok(SqlValue::Null);
326 }
327
328 if buf.remaining() < actual_len {
329 return Err(TypeError::BufferTooSmall {
330 needed: actual_len,
331 available: buf.remaining(),
332 });
333 }
334
335 match actual_len {
336 1 => Ok(SqlValue::TinyInt(buf.get_u8())),
337 2 => Ok(SqlValue::SmallInt(buf.get_i16_le())),
338 4 => Ok(SqlValue::Int(buf.get_i32_le())),
339 8 => Ok(SqlValue::BigInt(buf.get_i64_le())),
340 _ => Err(TypeError::InvalidBinary(format!(
341 "invalid INTN length: {actual_len}"
342 ))),
343 }
344}
345
346fn decode_nvarchar(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
347 if buf.remaining() < 2 {
348 return Err(TypeError::BufferTooSmall {
349 needed: 2,
350 available: buf.remaining(),
351 });
352 }
353
354 let byte_len = buf.get_u16_le() as usize;
355
356 if byte_len == 0xFFFF {
358 return Ok(SqlValue::Null);
359 }
360
361 if buf.remaining() < byte_len {
362 return Err(TypeError::BufferTooSmall {
363 needed: byte_len,
364 available: buf.remaining(),
365 });
366 }
367
368 let utf16_data = buf.copy_to_bytes(byte_len);
369 let s = decode_utf16_string(&utf16_data)?;
370 Ok(SqlValue::String(s))
371}
372
373fn decode_varchar(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
374 if buf.remaining() < 2 {
375 return Err(TypeError::BufferTooSmall {
376 needed: 2,
377 available: buf.remaining(),
378 });
379 }
380
381 let byte_len = buf.get_u16_le() as usize;
382
383 if byte_len == 0xFFFF {
385 return Ok(SqlValue::Null);
386 }
387
388 if buf.remaining() < byte_len {
389 return Err(TypeError::BufferTooSmall {
390 needed: byte_len,
391 available: buf.remaining(),
392 });
393 }
394
395 let data = buf.copy_to_bytes(byte_len);
396
397 if let Ok(s) = String::from_utf8(data.to_vec()) {
399 return Ok(SqlValue::String(s));
400 }
401
402 #[cfg(feature = "encoding")]
404 if let Some(ref collation) = type_info.collation {
405 if let Some(encoding) = collation.encoding() {
406 let (decoded, _, had_errors) = encoding.decode(&data);
407 if !had_errors {
408 return Ok(SqlValue::String(decoded.into_owned()));
409 }
410 }
411 }
412
413 #[cfg(not(feature = "encoding"))]
415 let _ = type_info;
416
417 Ok(SqlValue::String(
419 String::from_utf8_lossy(&data).into_owned(),
420 ))
421}
422
423fn decode_varbinary(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
424 if buf.remaining() < 2 {
425 return Err(TypeError::BufferTooSmall {
426 needed: 2,
427 available: buf.remaining(),
428 });
429 }
430
431 let byte_len = buf.get_u16_le() as usize;
432
433 if byte_len == 0xFFFF {
435 return Ok(SqlValue::Null);
436 }
437
438 if buf.remaining() < byte_len {
439 return Err(TypeError::BufferTooSmall {
440 needed: byte_len,
441 available: buf.remaining(),
442 });
443 }
444
445 let data = buf.copy_to_bytes(byte_len);
446 Ok(SqlValue::Binary(data))
447}
448
449#[cfg(feature = "uuid")]
450fn decode_guid(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
451 if buf.remaining() < 1 {
452 return Err(TypeError::BufferTooSmall {
453 needed: 1,
454 available: buf.remaining(),
455 });
456 }
457
458 let len = buf.get_u8() as usize;
459 if len == 0 {
460 return Ok(SqlValue::Null);
461 }
462
463 if len != 16 {
464 return Err(TypeError::InvalidBinary(format!(
465 "invalid GUID length: {len}"
466 )));
467 }
468
469 if buf.remaining() < 16 {
470 return Err(TypeError::BufferTooSmall {
471 needed: 16,
472 available: buf.remaining(),
473 });
474 }
475
476 let mut bytes = [0u8; 16];
478
479 bytes[3] = buf.get_u8();
481 bytes[2] = buf.get_u8();
482 bytes[1] = buf.get_u8();
483 bytes[0] = buf.get_u8();
484
485 bytes[5] = buf.get_u8();
487 bytes[4] = buf.get_u8();
488
489 bytes[7] = buf.get_u8();
491 bytes[6] = buf.get_u8();
492
493 for byte in &mut bytes[8..16] {
495 *byte = buf.get_u8();
496 }
497
498 Ok(SqlValue::Uuid(uuid::Uuid::from_bytes(bytes)))
499}
500
501#[cfg(not(feature = "uuid"))]
502fn decode_guid(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
503 if buf.remaining() < 1 {
505 return Err(TypeError::BufferTooSmall {
506 needed: 1,
507 available: buf.remaining(),
508 });
509 }
510
511 let len = buf.get_u8() as usize;
512 if len == 0 {
513 return Ok(SqlValue::Null);
514 }
515
516 if buf.remaining() < len {
517 return Err(TypeError::BufferTooSmall {
518 needed: len,
519 available: buf.remaining(),
520 });
521 }
522
523 let data = buf.copy_to_bytes(len);
524 Ok(SqlValue::Binary(data))
525}
526
527#[cfg(feature = "decimal")]
528fn decode_decimal(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
529 use rust_decimal::Decimal;
530
531 if buf.remaining() < 1 {
532 return Err(TypeError::BufferTooSmall {
533 needed: 1,
534 available: buf.remaining(),
535 });
536 }
537
538 let len = buf.get_u8() as usize;
539 if len == 0 {
540 return Ok(SqlValue::Null);
541 }
542
543 if buf.remaining() < len {
544 return Err(TypeError::BufferTooSmall {
545 needed: len,
546 available: buf.remaining(),
547 });
548 }
549
550 let sign = buf.get_u8();
552 let remaining = len - 1;
553
554 let mut mantissa_bytes = [0u8; 16];
556 for byte in mantissa_bytes.iter_mut().take(remaining.min(16)) {
557 *byte = buf.get_u8();
558 }
559
560 let mantissa = u128::from_le_bytes(mantissa_bytes);
561 let scale = type_info.scale.unwrap_or(0) as u32;
562
563 let mut decimal = Decimal::from_i128_with_scale(mantissa as i128, scale);
564 if sign == 0 {
565 decimal.set_sign_negative(true);
566 }
567
568 Ok(SqlValue::Decimal(decimal))
569}
570
571#[cfg(not(feature = "decimal"))]
572fn decode_decimal(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
573 if buf.remaining() < 1 {
575 return Err(TypeError::BufferTooSmall {
576 needed: 1,
577 available: buf.remaining(),
578 });
579 }
580
581 let len = buf.get_u8() as usize;
582 if len == 0 {
583 return Ok(SqlValue::Null);
584 }
585
586 if buf.remaining() < len {
587 return Err(TypeError::BufferTooSmall {
588 needed: len,
589 available: buf.remaining(),
590 });
591 }
592
593 buf.advance(len);
594 Ok(SqlValue::String("DECIMAL (feature disabled)".to_string()))
595}
596
597#[cfg(feature = "chrono")]
598fn decode_date(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
599 if buf.remaining() < 1 {
600 return Err(TypeError::BufferTooSmall {
601 needed: 1,
602 available: buf.remaining(),
603 });
604 }
605
606 let len = buf.get_u8() as usize;
607 if len == 0 {
608 return Ok(SqlValue::Null);
609 }
610
611 if len != 3 {
612 return Err(TypeError::InvalidDateTime(format!(
613 "invalid DATE length: {len}"
614 )));
615 }
616
617 if buf.remaining() < 3 {
618 return Err(TypeError::BufferTooSmall {
619 needed: 3,
620 available: buf.remaining(),
621 });
622 }
623
624 let days = buf.get_u8() as u32 | ((buf.get_u8() as u32) << 8) | ((buf.get_u8() as u32) << 16);
626
627 let base = chrono::NaiveDate::from_ymd_opt(1, 1, 1).expect("valid date");
628 let date = base + chrono::Duration::days(days as i64);
629
630 Ok(SqlValue::Date(date))
631}
632
633#[cfg(not(feature = "chrono"))]
634fn decode_date(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
635 if buf.remaining() < 1 {
636 return Err(TypeError::BufferTooSmall {
637 needed: 1,
638 available: buf.remaining(),
639 });
640 }
641
642 let len = buf.get_u8() as usize;
643 if len == 0 {
644 return Ok(SqlValue::Null);
645 }
646
647 if buf.remaining() < len {
648 return Err(TypeError::BufferTooSmall {
649 needed: len,
650 available: buf.remaining(),
651 });
652 }
653
654 buf.advance(len);
655 Ok(SqlValue::String("DATE (feature disabled)".to_string()))
656}
657
658#[cfg(feature = "chrono")]
659fn decode_time(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
660 let scale = type_info.scale.unwrap_or(7);
661 let time_len = time_bytes_for_scale(scale);
662
663 if buf.remaining() < 1 {
664 return Err(TypeError::BufferTooSmall {
665 needed: 1,
666 available: buf.remaining(),
667 });
668 }
669
670 let len = buf.get_u8() as usize;
671 if len == 0 {
672 return Ok(SqlValue::Null);
673 }
674
675 if buf.remaining() < len {
676 return Err(TypeError::BufferTooSmall {
677 needed: len,
678 available: buf.remaining(),
679 });
680 }
681
682 let mut time_bytes = [0u8; 8];
684 for byte in time_bytes.iter_mut().take(time_len) {
685 *byte = buf.get_u8();
686 }
687
688 let intervals = u64::from_le_bytes(time_bytes);
689 let time = intervals_to_time(intervals, scale);
690
691 Ok(SqlValue::Time(time))
692}
693
694#[cfg(not(feature = "chrono"))]
695fn decode_time(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
696 if buf.remaining() < 1 {
697 return Err(TypeError::BufferTooSmall {
698 needed: 1,
699 available: buf.remaining(),
700 });
701 }
702
703 let len = buf.get_u8() as usize;
704 if len == 0 {
705 return Ok(SqlValue::Null);
706 }
707
708 if buf.remaining() < len {
709 return Err(TypeError::BufferTooSmall {
710 needed: len,
711 available: buf.remaining(),
712 });
713 }
714
715 buf.advance(len);
716 Ok(SqlValue::String("TIME (feature disabled)".to_string()))
717}
718
719#[cfg(feature = "chrono")]
720fn decode_datetime2(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
721 let scale = type_info.scale.unwrap_or(7);
722 let time_len = time_bytes_for_scale(scale);
723
724 if buf.remaining() < 1 {
725 return Err(TypeError::BufferTooSmall {
726 needed: 1,
727 available: buf.remaining(),
728 });
729 }
730
731 let len = buf.get_u8() as usize;
732 if len == 0 {
733 return Ok(SqlValue::Null);
734 }
735
736 if buf.remaining() < len {
737 return Err(TypeError::BufferTooSmall {
738 needed: len,
739 available: buf.remaining(),
740 });
741 }
742
743 let mut time_bytes = [0u8; 8];
745 for byte in time_bytes.iter_mut().take(time_len) {
746 *byte = buf.get_u8();
747 }
748 let intervals = u64::from_le_bytes(time_bytes);
749 let time = intervals_to_time(intervals, scale);
750
751 let days = buf.get_u8() as u32 | ((buf.get_u8() as u32) << 8) | ((buf.get_u8() as u32) << 16);
753 let base = chrono::NaiveDate::from_ymd_opt(1, 1, 1).expect("valid date");
754 let date = base + chrono::Duration::days(days as i64);
755
756 Ok(SqlValue::DateTime(date.and_time(time)))
757}
758
759#[cfg(not(feature = "chrono"))]
760fn decode_datetime2(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
761 if buf.remaining() < 1 {
762 return Err(TypeError::BufferTooSmall {
763 needed: 1,
764 available: buf.remaining(),
765 });
766 }
767
768 let len = buf.get_u8() as usize;
769 if len == 0 {
770 return Ok(SqlValue::Null);
771 }
772
773 if buf.remaining() < len {
774 return Err(TypeError::BufferTooSmall {
775 needed: len,
776 available: buf.remaining(),
777 });
778 }
779
780 buf.advance(len);
781 Ok(SqlValue::String("DATETIME2 (feature disabled)".to_string()))
782}
783
784#[cfg(feature = "chrono")]
785fn decode_datetimeoffset(buf: &mut Bytes, type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
786 use chrono::TimeZone;
787
788 let scale = type_info.scale.unwrap_or(7);
789 let time_len = time_bytes_for_scale(scale);
790
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 let mut time_bytes = [0u8; 8];
812 for byte in time_bytes.iter_mut().take(time_len) {
813 *byte = buf.get_u8();
814 }
815 let intervals = u64::from_le_bytes(time_bytes);
816 let time = intervals_to_time(intervals, scale);
817
818 let days = buf.get_u8() as u32 | ((buf.get_u8() as u32) << 8) | ((buf.get_u8() as u32) << 16);
820 let base = chrono::NaiveDate::from_ymd_opt(1, 1, 1).expect("valid date");
821 let date = base + chrono::Duration::days(days as i64);
822
823 let offset_minutes = buf.get_i16_le();
825 let offset = chrono::FixedOffset::east_opt((offset_minutes as i32) * 60)
826 .ok_or_else(|| TypeError::InvalidDateTime(format!("invalid offset: {offset_minutes}")))?;
827
828 let datetime = offset
829 .from_local_datetime(&date.and_time(time))
830 .single()
831 .ok_or_else(|| TypeError::InvalidDateTime("ambiguous datetime".to_string()))?;
832
833 Ok(SqlValue::DateTimeOffset(datetime))
834}
835
836#[cfg(not(feature = "chrono"))]
837fn decode_datetimeoffset(buf: &mut Bytes, _type_info: &TypeInfo) -> Result<SqlValue, TypeError> {
838 if buf.remaining() < 1 {
839 return Err(TypeError::BufferTooSmall {
840 needed: 1,
841 available: buf.remaining(),
842 });
843 }
844
845 let len = buf.get_u8() as usize;
846 if len == 0 {
847 return Ok(SqlValue::Null);
848 }
849
850 if buf.remaining() < len {
851 return Err(TypeError::BufferTooSmall {
852 needed: len,
853 available: buf.remaining(),
854 });
855 }
856
857 buf.advance(len);
858 Ok(SqlValue::String(
859 "DATETIMEOFFSET (feature disabled)".to_string(),
860 ))
861}
862
863#[cfg(feature = "chrono")]
864fn decode_datetime(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
865 if buf.remaining() < 8 {
867 return Err(TypeError::BufferTooSmall {
868 needed: 8,
869 available: buf.remaining(),
870 });
871 }
872
873 let days = buf.get_i32_le();
874 let time_300ths = buf.get_u32_le();
875
876 let base = chrono::NaiveDate::from_ymd_opt(1900, 1, 1).expect("valid date");
877 let date = base + chrono::Duration::days(days as i64);
878
879 let total_ms = (time_300ths as u64 * 1000) / 300;
881 let secs = (total_ms / 1000) as u32;
882 let nanos = ((total_ms % 1000) * 1_000_000) as u32;
883
884 let time = chrono::NaiveTime::from_num_seconds_from_midnight_opt(secs, nanos)
885 .ok_or_else(|| TypeError::InvalidDateTime("invalid DATETIME time".to_string()))?;
886
887 Ok(SqlValue::DateTime(date.and_time(time)))
888}
889
890#[cfg(not(feature = "chrono"))]
891fn decode_datetime(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
892 if buf.remaining() < 8 {
893 return Err(TypeError::BufferTooSmall {
894 needed: 8,
895 available: buf.remaining(),
896 });
897 }
898
899 buf.advance(8);
900 Ok(SqlValue::String("DATETIME (feature disabled)".to_string()))
901}
902
903#[cfg(feature = "chrono")]
904fn decode_smalldatetime(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
905 if buf.remaining() < 4 {
907 return Err(TypeError::BufferTooSmall {
908 needed: 4,
909 available: buf.remaining(),
910 });
911 }
912
913 let days = buf.get_u16_le();
914 let minutes = buf.get_u16_le();
915
916 let base = chrono::NaiveDate::from_ymd_opt(1900, 1, 1).expect("valid date");
917 let date = base + chrono::Duration::days(days as i64);
918
919 let time = chrono::NaiveTime::from_num_seconds_from_midnight_opt((minutes as u32) * 60, 0)
920 .ok_or_else(|| TypeError::InvalidDateTime("invalid SMALLDATETIME time".to_string()))?;
921
922 Ok(SqlValue::DateTime(date.and_time(time)))
923}
924
925#[cfg(not(feature = "chrono"))]
926fn decode_smalldatetime(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
927 if buf.remaining() < 4 {
928 return Err(TypeError::BufferTooSmall {
929 needed: 4,
930 available: buf.remaining(),
931 });
932 }
933
934 buf.advance(4);
935 Ok(SqlValue::String(
936 "SMALLDATETIME (feature disabled)".to_string(),
937 ))
938}
939
940fn decode_xml(buf: &mut Bytes) -> Result<SqlValue, TypeError> {
941 if buf.remaining() < 2 {
943 return Err(TypeError::BufferTooSmall {
944 needed: 2,
945 available: buf.remaining(),
946 });
947 }
948
949 let byte_len = buf.get_u16_le() as usize;
950
951 if byte_len == 0xFFFF {
952 return Ok(SqlValue::Null);
953 }
954
955 if buf.remaining() < byte_len {
956 return Err(TypeError::BufferTooSmall {
957 needed: byte_len,
958 available: buf.remaining(),
959 });
960 }
961
962 let utf16_data = buf.copy_to_bytes(byte_len);
963 let s = decode_utf16_string(&utf16_data)?;
964 Ok(SqlValue::Xml(s))
965}
966
967pub fn decode_utf16_string(data: &[u8]) -> Result<String, TypeError> {
969 if data.len() % 2 != 0 {
970 return Err(TypeError::InvalidEncoding(
971 "UTF-16 data must have even length".to_string(),
972 ));
973 }
974
975 let utf16: Vec<u16> = data
976 .chunks_exact(2)
977 .map(|chunk| u16::from_le_bytes([chunk[0], chunk[1]]))
978 .collect();
979
980 String::from_utf16(&utf16).map_err(|e| TypeError::InvalidEncoding(e.to_string()))
981}
982
983#[cfg(feature = "chrono")]
985fn time_bytes_for_scale(scale: u8) -> usize {
986 match scale {
987 0..=2 => 3,
988 3..=4 => 4,
989 5..=7 => 5,
990 _ => 5, }
992}
993
994#[cfg(feature = "chrono")]
996fn intervals_to_time(intervals: u64, scale: u8) -> chrono::NaiveTime {
997 let nanos = match scale {
1008 0 => intervals * 1_000_000_000,
1009 1 => intervals * 100_000_000,
1010 2 => intervals * 10_000_000,
1011 3 => intervals * 1_000_000,
1012 4 => intervals * 100_000,
1013 5 => intervals * 10_000,
1014 6 => intervals * 1_000,
1015 7 => intervals * 100,
1016 _ => intervals * 100,
1017 };
1018
1019 let secs = (nanos / 1_000_000_000) as u32;
1020 let nano_part = (nanos % 1_000_000_000) as u32;
1021
1022 chrono::NaiveTime::from_num_seconds_from_midnight_opt(secs, nano_part)
1023 .unwrap_or_else(|| chrono::NaiveTime::from_hms_opt(0, 0, 0).expect("valid time"))
1024}
1025
1026#[cfg(test)]
1027#[allow(clippy::unwrap_used)]
1028mod tests {
1029 use super::*;
1030
1031 #[test]
1032 fn test_decode_int() {
1033 let mut buf = Bytes::from_static(&[42, 0, 0, 0]);
1034 let type_info = TypeInfo::int(0x38);
1035 let result = decode_value(&mut buf, &type_info).unwrap();
1036 assert_eq!(result, SqlValue::Int(42));
1037 }
1038
1039 #[test]
1040 fn test_decode_utf16_string() {
1041 let data = [0x41, 0x00, 0x42, 0x00];
1043 let result = decode_utf16_string(&data).unwrap();
1044 assert_eq!(result, "AB");
1045 }
1046
1047 #[test]
1048 fn test_decode_nvarchar() {
1049 let mut buf = Bytes::from_static(&[4, 0, 0x41, 0x00, 0x42, 0x00]);
1051 let type_info = TypeInfo::varchar(100);
1052 let type_info = TypeInfo {
1053 type_id: 0xE7,
1054 ..type_info
1055 };
1056 let result = decode_value(&mut buf, &type_info).unwrap();
1057 assert_eq!(result, SqlValue::String("AB".to_string()));
1058 }
1059
1060 #[test]
1061 fn test_decode_null_nvarchar() {
1062 let mut buf = Bytes::from_static(&[0xFF, 0xFF]);
1064 let type_info = TypeInfo {
1065 type_id: 0xE7,
1066 length: Some(100),
1067 scale: None,
1068 precision: None,
1069 collation: None,
1070 };
1071 let result = decode_value(&mut buf, &type_info).unwrap();
1072 assert_eq!(result, SqlValue::Null);
1073 }
1074}