1use super::codec::Encode;
4use crate::{sql_read_bytes::SqlReadBytes, Error};
5#[cfg(feature = "bigdecimal")]
6#[cfg_attr(docsrs, doc(cfg(feature = "bigdecimal")))]
7pub use bigdecimal::{num_bigint::BigInt, BigDecimal};
8use byteorder::{ByteOrder, LittleEndian};
9use bytes::{BufMut, BytesMut};
10#[cfg(feature = "rust_decimal")]
11#[cfg_attr(docsrs, doc(cfg(feature = "rust_decimal")))]
12pub use rust_decimal::Decimal;
13use std::cmp::{Ordering, PartialEq};
14use std::fmt::{self, Debug, Display, Formatter};
15
16#[derive(Copy, Clone)]
22#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
23pub struct Numeric {
24 value: i128,
25 scale: u8,
26}
27
28impl Numeric {
29 pub fn new_with_scale(value: i128, scale: u8) -> Self {
34 assert!(scale <= 38);
38
39 Numeric { value, scale }
40 }
41
42 pub fn dec_part(self) -> i128 {
44 let scale = self.pow_scale();
45 self.value - (self.value / scale) * scale
46 }
47
48 pub fn int_part(self) -> i128 {
50 self.value / self.pow_scale()
51 }
52
53 #[inline]
54 fn pow_scale(self) -> i128 {
55 10i128.pow(self.scale as u32)
56 }
57
58 #[inline]
60 pub fn scale(self) -> u8 {
61 self.scale
62 }
63
64 #[inline]
66 pub fn value(self) -> i128 {
67 self.value
68 }
69
70 pub fn precision(self) -> u8 {
72 let mut result = 0;
73 let mut n = self.int_part();
74
75 while n != 0 {
76 n /= 10;
77 result += 1;
78 }
79
80 if result == 0 {
81 1 + self.scale()
82 } else {
83 result + self.scale()
84 }
85 }
86
87 pub(crate) fn len(self) -> u8 {
88 match self.precision() {
89 1..=9 => 5,
90 10..=19 => 9,
91 20..=28 => 13,
92 _ => 17,
93 }
94 }
95
96 pub(crate) async fn decode<R>(src: &mut R, scale: u8) -> crate::Result<Option<Self>>
97 where
98 R: SqlReadBytes + Unpin,
99 {
100 fn decode_d128(buf: &[u8]) -> u128 {
101 let low_part = LittleEndian::read_u64(&buf[0..]) as u128;
102
103 if !buf[8..].iter().any(|x| *x != 0) {
104 return low_part;
105 }
106
107 let high_part = match buf.len() {
108 12 => LittleEndian::read_u32(&buf[8..]) as u128,
109 16 => LittleEndian::read_u64(&buf[8..]) as u128,
110 _ => unreachable!(),
111 };
112
113 let high_part = high_part * (u64::MAX as u128 + 1);
118 low_part + high_part
119 }
120
121 let len = src.read_u8().await?;
122
123 if len == 0 {
124 Ok(None)
125 } else {
126 let sign = match src.read_u8().await? {
127 0 => -1i128,
128 1 => 1i128,
129 _ => return Err(Error::Protocol("decimal: invalid sign".into())),
130 };
131
132 let value = match len {
133 5 => src.read_u32_le().await? as i128 * sign,
134 9 => src.read_u64_le().await? as i128 * sign,
135 13 => {
136 let mut bytes = [0u8; 12]; for item in &mut bytes {
138 *item = src.read_u8().await?;
139 }
140 decode_d128(&bytes) as i128 * sign
141 }
142 17 => {
143 let mut bytes = [0u8; 16];
144 for item in &mut bytes {
145 *item = src.read_u8().await?;
146 }
147 let magnitude = decode_d128(&bytes);
148 if magnitude > i128::MAX as u128 {
153 return Err(Error::Protocol(
154 "decimal/numeric: magnitude exceeds the representable range".into(),
155 ));
156 }
157 magnitude as i128 * sign
158 }
159 x => {
160 return Err(Error::Protocol(
161 format!("decimal/numeric: invalid length of {} received", x).into(),
162 ))
163 }
164 };
165
166 Ok(Some(Numeric::new_with_scale(value, scale)))
167 }
168 }
169}
170
171impl Encode<BytesMut> for Numeric {
172 fn encode(self, dst: &mut BytesMut) -> crate::Result<()> {
173 let len = self.len();
175 dst.put_u8(len);
176
177 if self.value < 0 {
178 dst.put_u8(0);
179 } else {
180 dst.put_u8(1);
181 }
182
183 let value = self.value().abs();
184
185 match len {
186 5 => dst.put_u32_le(value as u32),
187 9 => dst.put_u64_le(value as u64),
188 13 => {
189 dst.put_u64_le(value as u64);
190 dst.put_u32_le((value >> 64) as u32)
191 }
192 _ => dst.put_u128_le(value as u128),
193 }
194
195 Ok(())
196 }
197}
198
199impl Debug for Numeric {
200 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
201 write!(
202 f,
203 "{}{}.{:0pad$}",
204 if self.value() < 0 { "-" } else { "" },
205 self.int_part().abs(),
206 self.dec_part().abs(),
207 pad = self.scale as usize
208 )
209 }
210}
211
212impl Display for Numeric {
213 fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), fmt::Error> {
214 write!(f, "{:?}", self)
215 }
216}
217
218impl Eq for Numeric {}
219
220impl From<Numeric> for f64 {
221 fn from(n: Numeric) -> f64 {
222 n.dec_part() as f64 / n.pow_scale() as f64 + n.int_part() as f64
223 }
224}
225
226impl From<Numeric> for i128 {
227 fn from(n: Numeric) -> i128 {
228 n.int_part()
229 }
230}
231
232impl From<Numeric> for u128 {
233 fn from(n: Numeric) -> u128 {
234 n.int_part() as u128
235 }
236}
237
238impl PartialEq for Numeric {
239 fn eq(&self, other: &Self) -> bool {
240 match self.scale.cmp(&other.scale) {
241 Ordering::Greater => {
242 10i128.pow((self.scale - other.scale) as u32) * other.value == self.value
243 }
244 Ordering::Less => {
245 10i128.pow((other.scale - self.scale) as u32) * self.value == other.value
246 }
247 Ordering::Equal => self.value == other.value,
248 }
249 }
250}
251
252#[cfg(feature = "rust_decimal")]
253mod decimal {
254 use super::{Decimal, Numeric};
255 use crate::ColumnData;
256
257 #[cfg(feature = "tds73")]
258 from_sql!(Decimal: ColumnData::Numeric(ref num) => num.map(|num| {
259 Decimal::from_i128_with_scale(
260 num.value(),
261 num.scale() as u32,
262 )})
263 );
264
265 #[cfg(feature = "tds73")]
266 to_sql!(self_,
267 Decimal: (ColumnData::Numeric, {
268 let unpacked = self_.unpack();
269
270 let mut value = (((unpacked.hi as u128) << 64)
271 + ((unpacked.mid as u128) << 32)
272 + unpacked.lo as u128) as i128;
273
274 if self_.is_sign_negative() {
275 value = -value;
276 }
277
278 Numeric::new_with_scale(value, self_.scale() as u8)
279 });
280 );
281
282 #[cfg(feature = "tds73")]
283 into_sql!(self_,
284 Decimal: (ColumnData::Numeric, {
285 let unpacked = self_.unpack();
286
287 let mut value = (((unpacked.hi as u128) << 64)
288 + ((unpacked.mid as u128) << 32)
289 + unpacked.lo as u128) as i128;
290
291 if self_.is_sign_negative() {
292 value = -value;
293 }
294
295 Numeric::new_with_scale(value, self_.scale() as u8)
296 });
297 );
298}
299
300#[cfg(feature = "bigdecimal")]
301mod bigdecimal_ {
302 use super::{BigDecimal, BigInt, Numeric};
303 use crate::ColumnData;
304 use num_traits::ToPrimitive;
305 use std::convert::TryFrom;
306
307 #[cfg(feature = "tds73")]
308 from_sql!(BigDecimal: ColumnData::Numeric(ref num) => num.map(|num| {
309 let int = BigInt::from(num.value());
310
311 BigDecimal::new(int, num.scale() as i64)
312 }));
313
314 #[cfg(feature = "tds73")]
315 to_sql!(self_,
316 BigDecimal: (ColumnData::Numeric, {
317 let (int, exp) = self_.as_bigint_and_exponent();
318 let (int, exp) = if exp < 0 {
325 self_.with_scale(0).into_bigint_and_exponent()
326 } else {
327 (int, exp)
328 };
329
330 let value = int.to_i128().expect("Given BigDecimal overflowing the maximum accepted value.");
331
332 let scale = u8::try_from(std::cmp::max(exp, 0))
333 .expect("Given BigDecimal exponent overflowing the maximum accepted scale (255).");
334
335 Numeric::new_with_scale(value, scale)
336 });
337 );
338
339 #[cfg(feature = "tds73")]
340 into_sql!(self_,
341 BigDecimal: (ColumnData::Numeric, {
342 let (int, exp) = self_.as_bigint_and_exponent();
343 let (int, exp) = if exp < 0 {
350 self_.with_scale(0).into_bigint_and_exponent()
351 } else {
352 (int, exp)
353 };
354 let value = int.to_i128().expect("Given BigDecimal overflowing the maximum accepted value.");
355
356 let scale = u8::try_from(std::cmp::max(exp, 0))
357 .expect("Given BigDecimal exponent overflowing the maximum accepted scale (255).");
358
359 Numeric::new_with_scale(value, scale)
360 });
361 );
362}
363
364#[cfg(test)]
365mod tests {
366 use super::*;
367
368 #[test]
369 fn numeric_eq() {
370 assert_eq!(
371 Numeric {
372 value: 100501,
373 scale: 2
374 },
375 Numeric {
376 value: 1005010,
377 scale: 3
378 }
379 );
380 assert!(
381 Numeric {
382 value: 100501,
383 scale: 2
384 } != Numeric {
385 value: 10050,
386 scale: 1
387 }
388 );
389 }
390
391 #[test]
392 fn numeric_eq_normalizes_across_a_scale_gap() {
393 let wide = Numeric {
399 value: 123_000,
400 scale: 5,
401 };
402 let narrow = Numeric {
403 value: 123,
404 scale: 2,
405 };
406 assert_eq!(wide, narrow); assert_eq!(narrow, wide); assert!(
409 narrow
410 != Numeric {
411 value: 124,
412 scale: 2
413 }
414 );
415 }
416
417 #[test]
418 fn encode_byte_layout_matches_length_bucket() {
419 for value in [1i128, 10i128.pow(12), 10i128.pow(20), 10i128.pow(30)] {
423 let n = Numeric::new_with_scale(value, 0);
424 let expected = n.len() as usize + 1;
425 let mut buf = BytesMut::new();
426 n.encode(&mut buf).unwrap();
427 assert_eq!(buf.len(), expected, "byte count for {value}");
428 }
429
430 let mut zero = BytesMut::new();
432 Numeric::new_with_scale(0, 0).encode(&mut zero).unwrap();
433 assert_eq!(zero[1], 1, "zero must carry the positive sign byte");
434 }
435
436 #[tokio::test]
437 async fn decode_d128_keeps_high_and_low_words() {
438 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
439
440 let value = 0x0101_0101_0101_0101_0101_0101_0101_0101i128;
444 let n = Numeric::new_with_scale(value, 0);
445 let mut buf = BytesMut::new();
446 n.encode(&mut buf).unwrap();
447 let decoded = Numeric::decode(&mut buf.into_sql_read_bytes(), 0)
448 .await
449 .unwrap()
450 .unwrap();
451 assert_eq!(decoded.value(), value);
452 }
453
454 #[tokio::test]
455 async fn decode_accepts_magnitude_at_i128_max_but_rejects_beyond() {
456 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
457
458 let mut at_max = BytesMut::new();
460 at_max.put_u8(17);
461 at_max.put_u8(1);
462 at_max.put_i128_le(i128::MAX); let decoded = Numeric::decode(&mut at_max.into_sql_read_bytes(), 0)
464 .await
465 .expect("i128::MAX magnitude is representable")
466 .unwrap();
467 assert_eq!(decoded.value(), i128::MAX);
468
469 let mut beyond = BytesMut::new();
471 beyond.put_u8(17);
472 beyond.put_u8(1);
473 beyond.put_u128_le((i128::MAX as u128) + 1);
474 assert!(Numeric::decode(&mut beyond.into_sql_read_bytes(), 0)
475 .await
476 .is_err());
477 }
478
479 #[test]
480 fn numeric_to_f64() {
481 assert_eq!(f64::from(Numeric::new_with_scale(57705, 2)), 577.05);
482 }
483
484 #[test]
485 fn numeric_to_int_dec_part() {
486 let n = Numeric::new_with_scale(57705, 2);
487 assert_eq!(n.int_part(), 577);
488 assert_eq!(n.dec_part(), 5);
489 }
490
491 #[test]
492 fn numeric_to_string() {
493 assert_eq!(Numeric::new_with_scale(123, 0).to_string(), "123.0");
494 assert_eq!(Numeric::new_with_scale(123, 1).to_string(), "12.3");
495 assert_eq!(Numeric::new_with_scale(123, 2).to_string(), "1.23");
496 assert_eq!(Numeric::new_with_scale(123, 3).to_string(), "0.123");
497 assert_eq!(Numeric::new_with_scale(123, 4).to_string(), "0.0123");
498 assert_eq!(
499 Numeric::new_with_scale(123, 36).to_string(),
500 "0.000000000000000000000000000000000123"
501 );
502 assert_eq!(
503 Numeric::new_with_scale(123, 37).to_string(),
504 "0.0000000000000000000000000000000000123"
505 );
506 assert_eq!(Numeric::new_with_scale(-123, 0).to_string(), "-123.0");
507 assert_eq!(Numeric::new_with_scale(-123, 1).to_string(), "-12.3");
508 assert_eq!(Numeric::new_with_scale(-123, 2).to_string(), "-1.23");
509 assert_eq!(Numeric::new_with_scale(-123, 3).to_string(), "-0.123");
510 assert_eq!(Numeric::new_with_scale(-123, 4).to_string(), "-0.0123");
511 assert_eq!(
512 Numeric::new_with_scale(-123, 36).to_string(),
513 "-0.000000000000000000000000000000000123"
514 );
515 assert_eq!(
516 Numeric::new_with_scale(-123, 37).to_string(),
517 "-0.0000000000000000000000000000000000123"
518 );
519 }
520
521 #[test]
522 fn calculates_precision_correctly() {
523 let n = Numeric::new_with_scale(57705, 2);
524 assert_eq!(5, n.precision());
525 }
526
527 #[test]
528 fn new_with_scale_accessors() {
529 let n = Numeric::new_with_scale(12345, 3);
530 assert_eq!(n.value(), 12345);
531 assert_eq!(n.scale(), 3);
532 assert_eq!(n.int_part(), 12);
533 assert_eq!(n.dec_part(), 345);
534 }
535
536 #[test]
537 fn new_with_scale_allows_max_scale() {
538 assert_eq!(Numeric::new_with_scale(1, 38).scale(), 38);
540 }
541
542 #[test]
543 #[should_panic]
544 fn new_with_scale_panics_on_too_large_scale() {
545 Numeric::new_with_scale(1, 39);
546 }
547
548 #[test]
549 fn precision_with_zero_int_part() {
550 let n = Numeric::new_with_scale(5, 2);
552 assert_eq!(n.int_part(), 0);
553 assert_eq!(n.precision(), 3);
554 }
555
556 #[test]
557 fn precision_scaling_by_length_buckets() {
558 assert_eq!(Numeric::new_with_scale(1, 0).len(), 5);
559 assert_eq!(Numeric::new_with_scale(1_000_000_000, 0).len(), 9);
560 assert_eq!(Numeric::new_with_scale(10i128.pow(19), 0).len(), 13);
561 assert_eq!(Numeric::new_with_scale(10i128.pow(28), 0).len(), 17);
562 }
563
564 #[test]
565 fn display_and_debug() {
566 let n = Numeric::new_with_scale(57705, 2);
567 assert_eq!(format!("{:?}", n), "577.05");
568 assert_eq!(format!("{}", n), "577.05");
569
570 let n = Numeric::new_with_scale(-57705, 3);
573 assert_eq!(format!("{}", n), "-57.705");
574
575 let n = Numeric::new_with_scale(102, 4);
577 assert_eq!(format!("{}", n), "0.0102");
578 }
579
580 #[test]
581 fn from_numeric_conversions() {
582 let n = Numeric::new_with_scale(57705, 2);
583 assert_eq!(i128::from(n), 577);
584 assert_eq!(u128::from(n), 577);
585 assert!((f64::from(n) - 577.05).abs() < f64::EPSILON);
586 }
587
588 #[test]
589 fn eq_across_scales_negative() {
590 assert_eq!(
591 Numeric::new_with_scale(-100501, 2),
592 Numeric::new_with_scale(-1005010, 3),
593 );
594 }
595
596 async fn round_trip(value: i128, scale: u8) {
597 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
598
599 let n = Numeric::new_with_scale(value, scale);
600 let mut buf = BytesMut::new();
601 n.encode(&mut buf).expect("encode must succeed");
602
603 let decoded = Numeric::decode(&mut buf.into_sql_read_bytes(), scale)
604 .await
605 .expect("decode must succeed")
606 .expect("value must be present");
607
608 assert_eq!(decoded, n);
609 assert_eq!(decoded.value(), value);
610 }
611
612 #[tokio::test]
613 async fn encode_decode_round_trip() {
614 round_trip(0, 0).await; round_trip(42, 0).await; round_trip(-42, 2).await; round_trip(10i128.pow(12), 0).await; round_trip(10i128.pow(20), 0).await; round_trip(-(10i128.pow(20)), 3).await; round_trip(10i128.pow(30), 0).await; }
622
623 #[tokio::test]
624 async fn decode_zero_length_is_none() {
625 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
626
627 let mut buf = BytesMut::new();
628 buf.put_u8(0);
629
630 let decoded = Numeric::decode(&mut buf.into_sql_read_bytes(), 0)
631 .await
632 .expect("decode must succeed");
633
634 assert!(decoded.is_none());
635 }
636
637 #[tokio::test]
638 async fn decode_rejects_len17_magnitude_over_i128_max() {
639 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
640
641 let mut buf = BytesMut::new();
645 buf.put_u8(17);
646 buf.put_u8(1);
647 let mut mag = [0u8; 16];
648 mag[15] = 0x80;
649 buf.extend_from_slice(&mag);
650
651 let err = Numeric::decode(&mut buf.into_sql_read_bytes(), 0)
652 .await
653 .expect_err("out-of-range magnitude must error");
654 assert!(matches!(err, Error::Protocol(_)));
655 }
656
657 #[tokio::test]
658 async fn decode_rejects_invalid_sign_and_length() {
659 use crate::sql_read_bytes::test_utils::IntoSqlReadBytes;
660
661 let mut buf = BytesMut::new();
663 buf.put_u8(5);
664 buf.put_u8(2);
665 buf.put_u32_le(1);
666 let err = Numeric::decode(&mut buf.into_sql_read_bytes(), 0)
667 .await
668 .expect_err("invalid sign must error");
669 assert!(matches!(err, Error::Protocol(_)));
670
671 let mut buf = BytesMut::new();
673 buf.put_u8(6);
674 buf.put_u8(1);
675 buf.extend_from_slice(&[0u8; 4]);
676 let err = Numeric::decode(&mut buf.into_sql_read_bytes(), 0)
677 .await
678 .expect_err("invalid length must error");
679 assert!(matches!(err, Error::Protocol(_)));
680 }
681
682 #[test]
683 #[cfg(feature = "bigdecimal")]
684 fn no_overflowing_pow() {
685 use crate::{ColumnData, ToSql};
686 use bigdecimal::FromPrimitive;
687
688 let dec = BigDecimal::new(BigInt::from_i8(1).unwrap(), -20);
689 let res = dec.to_sql();
690
691 assert_eq!(
692 ColumnData::Numeric(Some(Numeric::new_with_scale(100000000000000000000i128, 0))),
693 res
694 );
695 }
696}