1use rupg_common::SqlState;
10
11use crate::binary::Recv;
12use crate::error::TypeError;
13use crate::number::{digit, is_space, u64_out};
14use crate::typmod::numeric_precision_scale;
15
16mod math;
17
18const NBASE: i32 = 10000;
19const HALF_NBASE: i32 = 5000;
20const DEC_DIGITS: i64 = 4;
21const DSCALE_MAX: i64 = 0x3fff;
23const NUMERIC_MAX_RESULT_SCALE: i32 = 2000;
25const ROUND_POWERS: [i32; 4] = [0, 1000, 100, 10];
27const DECIMAL_DIGITS_MAX: usize = 12;
29
30#[derive(Debug, Clone, Copy, PartialEq, Eq)]
32pub enum NumericSign {
33 Positive,
34 Negative,
35 NaN,
36 Infinity,
37 NegativeInfinity,
38}
39
40impl NumericSign {
41 pub const fn code(self) -> u16 {
43 match self {
44 NumericSign::Positive => 0x0000,
45 NumericSign::Negative => 0x4000,
46 NumericSign::NaN => 0xc000,
47 NumericSign::Infinity => 0xd000,
48 NumericSign::NegativeInfinity => 0xf000,
49 }
50 }
51
52 pub const fn from_code(code: u16) -> Option<NumericSign> {
53 Some(match code {
54 0x0000 => NumericSign::Positive,
55 0x4000 => NumericSign::Negative,
56 0xc000 => NumericSign::NaN,
57 0xd000 => NumericSign::Infinity,
58 0xf000 => NumericSign::NegativeInfinity,
59 _ => return None,
60 })
61 }
62
63 const fn is_finite(self) -> bool {
64 matches!(self, NumericSign::Positive | NumericSign::Negative)
65 }
66}
67
68#[derive(Debug, Clone, PartialEq, Eq)]
70pub struct Numeric {
71 sign: NumericSign,
72 weight: i16,
73 dscale: u16,
74 digits: Vec<i16>,
75}
76
77impl Numeric {
78 pub const NAN: Numeric = Numeric::special(NumericSign::NaN);
79 pub const INFINITY: Numeric = Numeric::special(NumericSign::Infinity);
80 pub const NEGATIVE_INFINITY: Numeric = Numeric::special(NumericSign::NegativeInfinity);
81
82 const fn special(sign: NumericSign) -> Numeric {
83 Numeric { sign, weight: 0, dscale: 0, digits: Vec::new() }
84 }
85
86 pub fn sign(&self) -> NumericSign {
87 self.sign
88 }
89
90 pub fn weight(&self) -> i16 {
92 self.weight
93 }
94
95 pub fn dscale(&self) -> u16 {
97 self.dscale
98 }
99
100 pub fn digits(&self) -> &[i16] {
102 &self.digits
103 }
104
105 pub fn from_decimal(value: i128, scale: u32) -> Numeric {
107 let mut buf = [0; DECIMAL_DIGITS_MAX];
108 let (digits, weight) = decimal_digits(value.unsigned_abs(), scale, &mut buf);
109 let sign = if value < 0 { NumericSign::Negative } else { NumericSign::Positive };
110 Numeric { sign, weight, dscale: scale as u16, digits: digits.to_vec() }
111 }
112
113 pub fn to_decimal(&self, scale: u32) -> Option<i128> {
115 if !self.sign.is_finite() {
116 return None;
117 }
118 let mut var = Var::from(self);
119 var.round(i64::from(scale));
120 let exp = (var.weight + 1 - var.digits.len() as i64) * DEC_DIGITS + i64::from(scale);
122 let last = var.digits.len().saturating_sub(1);
123 let mut acc: i128 = 0;
124 for (k, &d) in var.digits.iter().enumerate() {
125 let (mul, d) = match exp {
126 -3..0 if k == last => (10i128.pow((4 + exp) as u32), d / 10i32.pow(-exp as u32)),
127 _ => (i128::from(NBASE), d),
128 };
129 acc = acc.checked_mul(mul)?.checked_add(i128::from(d))?;
130 }
131 if exp > 0 && acc != 0 {
132 acc = acc.checked_mul(10i128.checked_pow(u32::try_from(exp).ok()?)?)?;
133 }
134 Some(if var.sign == NumericSign::Negative { -acc } else { acc })
135 }
136}
137
138impl Numeric {
139 pub fn from_bytes(bytes: &[u8]) -> Numeric {
141 let unpacked = crate::numeric_layout::decode(bytes);
142 let sign = NumericSign::from_code(unpacked.sign).unwrap_or(NumericSign::NaN);
143 if !sign.is_finite() {
144 return Numeric::special(sign);
145 }
146 let sign = if unpacked.digits.is_empty() { NumericSign::Positive } else { sign };
147 Numeric { sign, weight: unpacked.weight, dscale: unpacked.dscale, digits: unpacked.digits }
148 }
149
150 pub fn to_bytes(&self) -> Vec<u8> {
152 crate::numeric_layout::encode(self.sign.code(), self.weight, self.dscale, &self.digits)
153 }
154
155 pub fn from_integer(value: i128) -> Numeric {
157 Numeric::from_decimal(value, 0)
158 }
159
160 pub fn from_f64(value: f64) -> Numeric {
162 if value.is_nan() {
163 return Numeric::NAN;
164 }
165 if value.is_infinite() {
166 return if value > 0.0 { Numeric::INFINITY } else { Numeric::NEGATIVE_INFINITY };
167 }
168 let text = format!("{value:.14e}");
170 let (mantissa, exponent) = text.split_once('e').unwrap_or((&text, "0"));
171 let mantissa = match mantissa.contains('.') {
172 true => mantissa.trim_end_matches('0').trim_end_matches('.'),
173 false => mantissa,
174 };
175 numeric_in(&format!("{mantissa}e{exponent}"), -1).unwrap_or(Numeric::NAN)
176 }
177
178 pub fn to_f64(&self) -> f64 {
180 match self.sign {
181 NumericSign::NaN => f64::NAN,
182 NumericSign::Infinity => f64::INFINITY,
183 NumericSign::NegativeInfinity => f64::NEG_INFINITY,
184 _ => {
185 let mut out = Vec::new();
186 numeric_out(self, &mut out);
187 std::str::from_utf8(&out)
188 .ok()
189 .and_then(|text| text.parse().ok())
190 .unwrap_or(f64::NAN)
191 }
192 }
193 }
194
195 pub fn to_integer(&self, type_name: &str) -> Result<i128, TypeError> {
197 let range = || {
198 TypeError::new(
199 SqlState::NUMERIC_VALUE_OUT_OF_RANGE,
200 format!("{type_name} out of range"),
201 )
202 };
203 match self.sign {
204 NumericSign::NaN => {
205 return Err(TypeError::new(
206 SqlState::FEATURE_NOT_SUPPORTED,
207 format!("cannot convert NaN to {type_name}"),
208 ));
209 }
210 NumericSign::Infinity | NumericSign::NegativeInfinity => {
211 return Err(TypeError::new(
212 SqlState::FEATURE_NOT_SUPPORTED,
213 format!("cannot convert infinity to {type_name}"),
214 ));
215 }
216 _ => {}
217 }
218 self.to_decimal(0).ok_or_else(range)
219 }
220
221 pub fn with_typmod(&self, typmod: i32) -> Result<Numeric, TypeError> {
223 if !self.sign.is_finite() {
224 apply_typmod_special(self.sign, typmod)?;
225 return Ok(self.clone());
226 }
227 let mut var = Var::from(self);
228 var.apply_typmod(typmod)?;
229 var.make()
230 }
231
232 pub fn round(&self, scale: i32) -> Result<Numeric, TypeError> {
234 self.rescaled(scale, Var::round)
235 }
236
237 pub fn trunc(&self, scale: i32) -> Result<Numeric, TypeError> {
239 self.rescaled(scale, Var::trunc)
240 }
241
242 fn rescaled(&self, scale: i32, drop: fn(&mut Var, i64)) -> Result<Numeric, TypeError> {
244 if !self.sign.is_finite() {
245 return Ok(self.clone());
246 }
247 let scale = i64::from(scale.clamp(-NUMERIC_MAX_RESULT_SCALE, NUMERIC_MAX_RESULT_SCALE));
248 let mut var = Var::from(self);
249 drop(&mut var, scale);
250 if scale < 0 {
251 var.dscale = 0;
252 }
253 var.make()
254 }
255
256 pub fn whole(&self, up: bool) -> Result<Numeric, TypeError> {
258 let truncated = self.trunc(0)?;
259 let toward = if up { NumericSign::Positive } else { NumericSign::Negative };
260 if self.sign != toward || truncated.compare(self).is_eq() {
261 return Ok(truncated);
262 }
263 let one = Numeric::from_integer(if up { 1 } else { -1 });
264 truncated.add(&one)
265 }
266
267 pub fn abs(&self) -> Numeric {
269 match self.sign {
270 NumericSign::Negative => self.negate(),
271 NumericSign::NegativeInfinity => self.negate(),
272 _ => self.clone(),
273 }
274 }
275
276 pub fn negate(&self) -> Numeric {
278 let sign = match self.sign {
279 NumericSign::Positive if !self.digits.is_empty() => NumericSign::Negative,
280 NumericSign::Negative => NumericSign::Positive,
281 NumericSign::Infinity => NumericSign::NegativeInfinity,
282 NumericSign::NegativeInfinity => NumericSign::Infinity,
283 sign => sign,
284 };
285 Numeric { sign, ..self.clone() }
286 }
287
288 pub fn add(&self, other: &Numeric) -> Result<Numeric, TypeError> {
290 if let Some(special) = special_sum(self.sign, other.sign) {
291 return Ok(special);
292 }
293 Var::from(self).add(&Var::from(other)).make()
294 }
295
296 pub fn sub(&self, other: &Numeric) -> Result<Numeric, TypeError> {
298 self.add(&other.negate())
299 }
300
301 pub fn mul(&self, other: &Numeric) -> Result<Numeric, TypeError> {
303 use NumericSign::{Infinity, NaN, Negative, NegativeInfinity};
304 let (a, b) = (self.sign, other.sign);
305 if !a.is_finite() || !b.is_finite() {
306 if a == NaN || b == NaN {
307 return Ok(Numeric::NAN);
308 }
309 let zero = (a.is_finite() && self.digits.is_empty())
310 || (b.is_finite() && other.digits.is_empty());
311 if zero {
312 return Ok(Numeric::NAN);
313 }
314 let negative = |sign| matches!(sign, Negative | NegativeInfinity);
315 return Ok(if negative(a) != negative(b) {
316 Numeric::NEGATIVE_INFINITY
317 } else {
318 Numeric::special(Infinity)
319 });
320 }
321 let rscale = (i64::from(self.dscale) + i64::from(other.dscale)).min(DSCALE_MAX);
322 let mut product = Var::from(self).mul(&Var::from(other));
323 product.round(rscale);
324 product.make()
325 }
326
327 pub fn div(&self, other: &Numeric) -> Result<Numeric, TypeError> {
329 use NumericSign::{Infinity, NaN, Negative, NegativeInfinity, Positive};
330 let (a, b) = (self.sign, other.sign);
331 let zero = || TypeError::new(SqlState::DIVISION_BY_ZERO, "division by zero".to_string());
332 if !a.is_finite() || !b.is_finite() {
333 if a == NaN || b == NaN {
334 return Ok(Numeric::NAN);
335 }
336 if a.is_finite() {
337 return Ok(Numeric { sign: Positive, weight: 0, dscale: 0, digits: Vec::new() });
339 }
340 if !b.is_finite() {
341 return Ok(Numeric::NAN);
342 }
343 if other.digits.is_empty() {
344 return Err(zero());
345 }
346 let negative = (a == NegativeInfinity) != (b == Negative);
347 return Ok(Numeric::special(if negative { NegativeInfinity } else { Infinity }));
348 }
349 let (x, y) = (Var::from(self), Var::from(other));
350 let rscale = select_div_scale(&x, &y);
351 if y.digits.is_empty() {
352 return Err(zero());
353 }
354 x.div(&y, rscale, true).make()
355 }
356
357 pub fn modulo(&self, other: &Numeric) -> Result<Numeric, TypeError> {
359 let (a, b) = (self.sign, other.sign);
360 if !a.is_finite() || !b.is_finite() {
361 if a == NumericSign::NaN || b == NumericSign::NaN || !a.is_finite() {
362 return Ok(Numeric::NAN);
363 }
364 return Ok(self.clone());
366 }
367 if other.digits.is_empty() {
368 return Err(TypeError::new(SqlState::DIVISION_BY_ZERO, "division by zero".to_string()));
369 }
370 Var::from(self).rem(&Var::from(other)).make()
371 }
372
373 pub fn compare(&self, other: &Numeric) -> std::cmp::Ordering {
375 let left = self.to_bytes();
376 let right = other.to_bytes();
377 crate::numeric_layout::key(&left).cmp(crate::numeric_layout::key(&right))
378 }
379}
380
381fn special_sum(a: NumericSign, b: NumericSign) -> Option<Numeric> {
383 use NumericSign::{Infinity, NaN, NegativeInfinity};
384 match (a, b) {
385 _ if a.is_finite() && b.is_finite() => None,
386 (NaN, _) | (_, NaN) => Some(Numeric::NAN),
387 (Infinity, NegativeInfinity) | (NegativeInfinity, Infinity) => Some(Numeric::NAN),
388 (Infinity, _) | (_, Infinity) => Some(Numeric::INFINITY),
389 _ => Some(Numeric::NEGATIVE_INFINITY),
390 }
391}
392
393const MIN_SIG_DIGITS: i64 = 16;
395
396fn select_div_scale(x: &Var, y: &Var) -> i64 {
398 let first = |v: &Var| match v.digits.iter().position(|&d| d != 0) {
399 Some(at) => (v.weight - at as i64, v.digits[at]),
400 None => (0, 0),
401 };
402 let (weight1, first1) = first(x);
403 let (weight2, first2) = first(y);
404 let mut qweight = weight1 - weight2;
405 if first1 <= first2 {
406 qweight -= 1;
407 }
408 let rscale = MIN_SIG_DIGITS - qweight * DEC_DIGITS;
409 rscale.max(x.dscale).max(y.dscale).clamp(0, 1000)
410}
411
412#[derive(Debug, Clone)]
414struct Var {
415 sign: NumericSign,
416 weight: i64,
417 dscale: i64,
418 digits: Vec<i32>,
419}
420
421impl From<&Numeric> for Var {
422 fn from(v: &Numeric) -> Var {
423 Var {
424 sign: v.sign,
425 weight: i64::from(v.weight),
426 dscale: i64::from(v.dscale),
427 digits: v.digits.iter().map(|&d| i32::from(d)).collect(),
428 }
429 }
430}
431
432impl Var {
433 fn from_decimal_digits(dec: &[u8], dweight: i64, dscale: i64) -> Var {
435 let weight = if dweight >= 0 {
436 (dweight + DEC_DIGITS) / DEC_DIGITS - 1
437 } else {
438 -((-dweight - 1) / DEC_DIGITS + 1)
439 };
440 let offset = (weight + 1) * DEC_DIGITS - (dweight + 1);
442 let ndigits = (dec.len() as i64 + offset + DEC_DIGITS - 1) / DEC_DIGITS;
443 let at = |k: i64| match usize::try_from(k - offset) {
444 Ok(k) if k < dec.len() => i32::from(dec[k]),
445 _ => 0,
446 };
447 let digits = (0..ndigits)
448 .map(|n| {
449 let k = n * DEC_DIGITS;
450 ((at(k) * 10 + at(k + 1)) * 10 + at(k + 2)) * 10 + at(k + 3)
451 })
452 .collect();
453 let mut var = Var { sign: NumericSign::Positive, weight, dscale, digits };
454 var.strip();
455 var
456 }
457
458 fn strip(&mut self) {
460 let lead = self.digits.iter().take_while(|&&d| d == 0).count();
461 self.digits.drain(..lead);
462 self.weight -= lead as i64;
463 while self.digits.last() == Some(&0) {
464 self.digits.pop();
465 }
466 if self.digits.is_empty() {
467 self.sign = NumericSign::Positive;
468 self.weight = 0;
469 }
470 }
471
472 fn round(&mut self, rscale: i64) {
474 self.dscale = rscale;
475 let di = (self.weight + 1) * DEC_DIGITS + rscale;
476 if di < 0 {
477 self.digits.clear();
478 self.weight = 0;
479 self.sign = NumericSign::Positive;
480 return;
481 }
482 let n = ((di + DEC_DIGITS - 1) / DEC_DIGITS) as usize;
483 let di = (di % DEC_DIGITS) as usize;
484 if n > self.digits.len() || (n == self.digits.len() && di == 0) {
485 return;
486 }
487 let (mut i, mut carry) = if di == 0 {
488 (n, i32::from(self.digits[n] >= HALF_NBASE))
489 } else {
490 let i = n - 1;
492 let pow10 = ROUND_POWERS[di];
493 let extra = self.digits[i] % pow10;
494 self.digits[i] -= extra;
495 let mut carry = 0;
496 if extra >= pow10 / 2 {
497 self.digits[i] += pow10;
498 if self.digits[i] >= NBASE {
499 self.digits[i] -= NBASE;
500 carry = 1;
501 }
502 }
503 (i, carry)
504 };
505 self.digits.truncate(n);
506 while carry != 0 {
507 if i == 0 {
508 self.digits.insert(0, carry);
509 self.weight += 1;
510 break;
511 }
512 i -= 1;
513 self.digits[i] += carry;
514 carry = 0;
515 if self.digits[i] >= NBASE {
516 self.digits[i] -= NBASE;
517 carry = 1;
518 }
519 }
520 }
521
522 fn trunc(&mut self, rscale: i64) {
524 self.dscale = rscale;
525 let di = (self.weight + 1) * DEC_DIGITS + rscale;
526 if di <= 0 {
527 self.digits.clear();
528 self.weight = 0;
529 self.sign = NumericSign::Positive;
530 return;
531 }
532 let n = ((di + DEC_DIGITS - 1) / DEC_DIGITS) as usize;
533 if n <= self.digits.len() {
534 self.digits.truncate(n);
535 let di = (di % DEC_DIGITS) as usize;
536 if di > 0 {
537 self.digits[n - 1] -= self.digits[n - 1] % ROUND_POWERS[di];
538 }
539 }
540 }
541
542 fn apply_typmod(&mut self, typmod: i32) -> Result<(), TypeError> {
544 let Some((precision, scale)) = numeric_precision_scale(typmod) else {
545 return Ok(());
546 };
547 let maxdigits = i64::from(precision - scale);
548 self.round(i64::from(scale));
549 self.dscale = self.dscale.max(0);
550 let mut ddigits = (self.weight + 1) * DEC_DIGITS;
552 if ddigits > maxdigits {
553 for &dig in &self.digits {
554 if dig != 0 {
555 ddigits -= match dig {
556 0..10 => 3,
557 10..100 => 2,
558 100..1000 => 1,
559 _ => 0,
560 };
561 if ddigits > maxdigits {
562 let limit = match maxdigits {
563 0 => "1".to_string(),
564 n => format!("10^{n}"),
565 };
566 return Err(field_overflow(format!(
567 "A field with precision {precision}, scale {scale} must round to an absolute value less than {limit}."
568 )));
569 }
570 break;
571 }
572 ddigits -= DEC_DIGITS;
573 }
574 }
575 Ok(())
576 }
577
578 fn make(mut self) -> Result<Numeric, TypeError> {
580 if !self.sign.is_finite() {
581 return Ok(Numeric::special(self.sign));
582 }
583 self.strip();
584 match (i16::try_from(self.weight), u16::try_from(self.dscale)) {
585 (Ok(weight), Ok(dscale)) if self.dscale <= DSCALE_MAX => Ok(Numeric {
586 sign: self.sign,
587 weight,
588 dscale,
589 digits: self.digits.iter().map(|&d| d as i16).collect(),
590 }),
591 _ => Err(overflow()),
592 }
593 }
594}
595
596impl Var {
597 fn digit(&self, weight: i64) -> i32 {
599 usize::try_from(self.weight - weight)
600 .ok()
601 .and_then(|at| self.digits.get(at))
602 .copied()
603 .unwrap_or(0)
604 }
605
606 fn low(&self) -> i64 {
608 self.weight + 1 - self.digits.len() as i64
609 }
610
611 fn cmp_abs(&self, other: &Var) -> std::cmp::Ordering {
613 let high = self.weight.max(other.weight);
614 let low = self.low().min(other.low());
615 for weight in (low..=high).rev() {
616 match self.digit(weight).cmp(&other.digit(weight)) {
617 std::cmp::Ordering::Equal => {}
618 order => return order,
619 }
620 }
621 std::cmp::Ordering::Equal
622 }
623
624 fn add_abs(&self, other: &Var, subtract: bool, sign: NumericSign) -> Var {
626 let weight = self.weight.max(other.weight) + 1;
627 let low = self.low().min(other.low());
628 let mut digits = vec![0; (weight - low + 1) as usize];
629 let mut carry = 0;
630 for (at, w) in (low..=weight).enumerate() {
631 let other = other.digit(w);
632 let mut d = self.digit(w) + carry + if subtract { -other } else { other };
633 carry = 0;
634 if d >= NBASE {
635 d -= NBASE;
636 carry = 1;
637 } else if d < 0 {
638 d += NBASE;
639 carry = -1;
640 }
641 let end = digits.len() - 1 - at;
642 digits[end] = d;
643 }
644 let mut var = Var { sign, weight, dscale: self.dscale.max(other.dscale), digits };
645 var.strip();
646 var
647 }
648
649 fn add(&self, other: &Var) -> Var {
651 if self.sign == other.sign {
652 return self.add_abs(other, false, self.sign);
653 }
654 match self.cmp_abs(other) {
655 std::cmp::Ordering::Less => other.add_abs(self, true, other.sign),
656 _ => self.add_abs(other, true, self.sign),
657 }
658 }
659
660 fn rem(&self, other: &Var) -> Var {
662 let mut product = other.mul(&self.div(other, 0, false));
663 product.dscale = other.dscale;
664 product.sign = match product.sign {
665 NumericSign::Positive if !product.digits.is_empty() => NumericSign::Negative,
666 _ => NumericSign::Positive,
667 };
668 self.add(&product)
669 }
670
671 fn mul(&self, other: &Var) -> Var {
673 let sign =
674 if self.sign == other.sign { NumericSign::Positive } else { NumericSign::Negative };
675 if self.digits.is_empty() || other.digits.is_empty() {
676 return Var { sign: NumericSign::Positive, weight: 0, dscale: 0, digits: Vec::new() };
677 }
678 let mut acc = vec![0i64; self.digits.len() + other.digits.len()];
679 for (i, &a) in self.digits.iter().enumerate() {
680 for (j, &b) in other.digits.iter().enumerate() {
681 acc[i + j + 1] += i64::from(a) * i64::from(b);
682 }
683 }
684 let mut carry = 0;
685 for slot in acc.iter_mut().rev() {
686 let total = *slot + carry;
687 *slot = total % i64::from(NBASE);
688 carry = total / i64::from(NBASE);
689 }
690 let digits = acc.into_iter().map(|d| d as i32).collect();
691 let weight = self.weight + other.weight + 1;
692 let mut var = Var { sign, weight, dscale: self.dscale + other.dscale, digits };
693 var.strip();
694 var
695 }
696
697 fn div(&self, other: &Var, rscale: i64, round: bool) -> Var {
699 let sign =
700 if self.sign == other.sign { NumericSign::Positive } else { NumericSign::Negative };
701 let low = -((rscale + DEC_DIGITS - 1) / DEC_DIGITS + 1);
703 let shift = self.low() - other.low() - low;
704 let mut dividend: Vec<i64> = self.digits.iter().map(|&d| i64::from(d)).collect();
705 if shift >= 0 {
706 dividend.resize(dividend.len() + shift as usize, 0);
707 } else {
708 let keep = dividend.len().saturating_sub((-shift) as usize);
709 dividend.truncate(keep);
710 }
711 let divisor: Vec<i64> = other.digits.iter().map(|&d| i64::from(d)).collect();
712 let quotient = divide(÷nd, &divisor);
713 let weight = low + quotient.len() as i64 - 1;
714 let digits = quotient.into_iter().map(|d| d as i32).collect();
715 let mut var = Var { sign, weight, dscale: rscale, digits };
716 var.strip();
717 if round {
718 var.round(rscale);
719 } else {
720 var.trunc(rscale);
721 }
722 var.strip();
723 if var.digits.is_empty() {
724 var.sign = NumericSign::Positive;
725 }
726 var
727 }
728}
729
730fn divide(dividend: &[i64], divisor: &[i64]) -> Vec<i64> {
732 let base = i64::from(NBASE);
733 let n = divisor.len();
734 if dividend.len() < n {
735 return Vec::new();
736 }
737 if n == 1 {
738 let d = divisor[0];
739 let mut rest = 0;
740 return dividend
741 .iter()
742 .map(|&digit| {
743 let current = rest * base + digit;
744 rest = current % d;
745 current / d
746 })
747 .collect();
748 }
749 let scale = base / (divisor[0] + 1);
751 let times = |digits: &[i64]| -> Vec<i64> {
752 let mut out = vec![0; digits.len() + 1];
753 let mut carry = 0;
754 for (at, &digit) in digits.iter().enumerate().rev() {
755 let total = digit * scale + carry;
756 out[at + 1] = total % base;
757 carry = total / base;
758 }
759 out[0] = carry;
760 out
761 };
762 let mut u = times(dividend);
763 let v = times(divisor);
764 let v = &v[1..];
765 let m = dividend.len() - n;
766 let mut q = vec![0; m + 1];
767 for j in 0..=m {
768 let top = u[j] * base + u[j + 1];
769 let mut qhat = top / v[0];
770 let mut rhat = top % v[0];
771 while qhat >= base || qhat * v[1] > rhat * base + u[j + 2] {
772 qhat -= 1;
773 rhat += v[0];
774 if rhat >= base {
775 break;
776 }
777 }
778 let mut borrow = 0;
780 let mut carry = 0;
781 for i in (0..n).rev() {
782 let product = qhat * v[i] + carry;
783 carry = product / base;
784 let mut d = u[j + i + 1] - product % base - borrow;
785 borrow = 0;
786 if d < 0 {
787 d += base;
788 borrow = 1;
789 }
790 u[j + i + 1] = d;
791 }
792 let d = u[j] - carry - borrow;
793 if d < 0 {
794 qhat -= 1;
796 let mut carry = 0;
797 for i in (0..n).rev() {
798 let total = u[j + i + 1] + v[i] + carry;
799 u[j + i + 1] = total % base;
800 carry = total / base;
801 }
802 u[j] = d + carry;
803 } else {
804 u[j] = d;
805 }
806 q[j] = qhat;
807 }
808 q
809}
810
811fn overflow() -> TypeError {
812 TypeError::new(
813 SqlState::NUMERIC_VALUE_OUT_OF_RANGE,
814 "value overflows numeric format".to_string(),
815 )
816}
817
818fn field_overflow(detail: String) -> TypeError {
819 let mut error =
820 TypeError::new(SqlState::NUMERIC_VALUE_OUT_OF_RANGE, "numeric field overflow".to_string());
821 error.detail = Some(detail);
822 error
823}
824
825fn apply_typmod_special(sign: NumericSign, typmod: i32) -> Result<(), TypeError> {
827 match numeric_precision_scale(typmod) {
828 Some((precision, scale)) if sign != NumericSign::NaN => Err(field_overflow(format!(
829 "A field with precision {precision}, scale {scale} cannot hold an infinite value."
830 ))),
831 _ => Ok(()),
832 }
833}
834
835pub fn numeric_in(s: &str, typmod: i32) -> Result<Numeric, TypeError> {
837 let b = s.as_bytes();
838 let at = |i: usize| b.get(i).copied().unwrap_or(0);
839 let syntax = || TypeError::syntax("numeric", s);
840 let rest_is_space = |mut i: usize| {
841 while i < b.len() {
842 if !is_space(b[i]) {
843 return Err(syntax());
844 }
845 i += 1;
846 }
847 Ok(())
848 };
849
850 let mut i = 0;
851 while is_space(at(i)) {
852 i += 1;
853 }
854 let start = i;
855 let negative = at(i) == b'-';
856 if negative || at(i) == b'+' {
857 i += 1;
858 }
859
860 if !at(i).is_ascii_digit() && at(i) != b'.' {
862 let word = |from: usize, word: &str| {
863 b.get(from..from + word.len()).is_some_and(|w| w.eq_ignore_ascii_case(word.as_bytes()))
864 };
865 let infinity = if negative { NumericSign::NegativeInfinity } else { NumericSign::Infinity };
866 let (sign, end) = if word(start, "nan") {
867 (NumericSign::NaN, start + 3)
868 } else if word(i, "infinity") {
869 (infinity, i + 8)
870 } else if word(i, "inf") {
871 (infinity, i + 3)
872 } else {
873 return Err(syntax());
874 };
875 rest_is_space(end)?;
876 apply_typmod_special(sign, typmod)?;
877 return Ok(Numeric::special(sign));
878 }
879
880 let base = match (at(i), at(i + 1)) {
881 (b'0', b'x' | b'X') => 16,
882 (b'0', b'o' | b'O') => 8,
883 (b'0', b'b' | b'B') => 2,
884 _ => 10,
885 };
886 let (mut var, end) = match base {
887 10 => decimal(b, i, s)?,
888 _ => non_decimal(b, i + 2, base, s)?,
889 };
890 if negative {
891 var.sign = NumericSign::Negative;
892 }
893 rest_is_space(end)?;
894 var.apply_typmod(typmod)?;
895 var.make()
896}
897
898fn decimal(b: &[u8], mut i: usize, input: &str) -> Result<(Var, usize), TypeError> {
900 let at = |i: usize| b.get(i).copied().unwrap_or(0);
901 let syntax = || TypeError::syntax("numeric", input);
902 let mut have_point = at(i) == b'.';
903 if have_point {
904 i += 1;
905 }
906 if !at(i).is_ascii_digit() {
907 return Err(syntax());
908 }
909 let mut dec = Vec::with_capacity(b.len() - i);
910 let mut dweight: i64 = -1;
911 let mut dscale: i64 = 0;
912 loop {
913 match at(i) {
914 c @ b'0'..=b'9' => {
915 dec.push(c - b'0');
916 i += 1;
917 if have_point {
918 dscale += 1;
919 } else {
920 dweight += 1;
921 }
922 }
923 b'.' => {
924 if have_point || at(i + 1) == b'_' {
926 return Err(syntax());
927 }
928 have_point = true;
929 i += 1;
930 }
931 b'_' => {
932 i += 1;
933 if !at(i).is_ascii_digit() {
934 return Err(syntax());
935 }
936 }
937 _ => break,
938 }
939 }
940
941 if matches!(at(i), b'e' | b'E') {
942 i += 1;
943 let negative = at(i) == b'-';
944 if negative || at(i) == b'+' {
945 i += 1;
946 }
947 if !at(i).is_ascii_digit() {
948 return Err(syntax());
949 }
950 let mut exponent: i64 = 0;
951 loop {
952 match at(i) {
953 c @ b'0'..=b'9' => {
954 exponent = exponent * 10 + i64::from(c - b'0');
955 i += 1;
956 if exponent > i64::from(i32::MAX / 2) {
957 return Err(overflow());
958 }
959 }
960 b'_' => {
961 i += 1;
962 if !at(i).is_ascii_digit() {
963 return Err(syntax());
964 }
965 }
966 _ => break,
967 }
968 }
969 if negative {
970 exponent = -exponent;
971 }
972 dweight += exponent;
973 dscale = (dscale - exponent).max(0);
974 }
975 Ok((Var::from_decimal_digits(&dec, dweight, dscale), i))
976}
977
978fn non_decimal(b: &[u8], mut i: usize, base: u64, input: &str) -> Result<(Var, usize), TypeError> {
980 let at = |i: usize| b.get(i).copied().unwrap_or(0);
981 let syntax = || TypeError::syntax("numeric", input);
982 let mut value: Vec<i32> = Vec::new();
984 let add_group = |value: &mut Vec<i32>, tmp: u64, mul: u64| {
985 let mut carry = u128::from(tmp);
986 for d in value.iter_mut() {
987 let v = *d as u128 * u128::from(mul) + carry;
988 *d = (v % NBASE as u128) as i32;
989 carry = v / NBASE as u128;
990 }
991 while carry > 0 {
992 value.push((carry % NBASE as u128) as i32);
993 carry /= NBASE as u128;
994 }
995 if value.len() > i16::MAX as usize + 1 { Err(overflow()) } else { Ok(()) }
996 };
997 let first = i;
998 let (mut tmp, mut mul) = (0u64, 1u64);
999 loop {
1000 if let Some(d) = digit(at(i), base) {
1001 if mul > i64::MAX as u64 / base {
1002 add_group(&mut value, tmp, mul)?;
1003 (tmp, mul) = (0, 1);
1004 }
1005 tmp = tmp * base + d;
1006 mul *= base;
1007 i += 1;
1008 } else if at(i) == b'_' {
1009 i += 1;
1010 if digit(at(i), base).is_none() {
1011 return Err(syntax());
1012 }
1013 } else {
1014 break;
1015 }
1016 }
1017 if i == first {
1018 return Err(syntax());
1019 }
1020 add_group(&mut value, tmp, mul)?;
1021 value.reverse();
1022 let mut var = Var {
1023 sign: NumericSign::Positive,
1024 weight: value.len() as i64 - 1,
1025 dscale: 0,
1026 digits: value,
1027 };
1028 var.strip();
1029 Ok((var, i))
1030}
1031
1032fn four(dig: i32, out: &mut Vec<u8>) {
1034 let dig = dig as u16;
1035 out.extend_from_slice(&[
1036 b'0' + (dig / 1000) as u8,
1037 b'0' + (dig / 100 % 10) as u8,
1038 b'0' + (dig / 10 % 10) as u8,
1039 b'0' + (dig % 10) as u8,
1040 ]);
1041}
1042
1043pub fn numeric_out(v: &Numeric, out: &mut Vec<u8>) {
1045 match v.sign {
1046 NumericSign::NaN => return out.extend_from_slice(b"NaN"),
1047 NumericSign::Infinity => return out.extend_from_slice(b"Infinity"),
1048 NumericSign::NegativeInfinity => return out.extend_from_slice(b"-Infinity"),
1049 NumericSign::Negative => out.push(b'-'),
1050 NumericSign::Positive => {}
1051 }
1052 let at = |d: i32| match usize::try_from(d) {
1053 Ok(d) if d < v.digits.len() => i32::from(v.digits[d]),
1054 _ => 0,
1055 };
1056 let weight = i32::from(v.weight);
1057 if weight < 0 {
1058 out.push(b'0');
1059 } else {
1060 u64_out(at(0) as u64, out);
1062 for d in 1..=weight {
1063 four(at(d), out);
1064 }
1065 }
1066 let dscale = usize::from(v.dscale);
1067 if dscale > 0 {
1068 out.push(b'.');
1069 let end = out.len() + dscale;
1070 let mut d = weight + 1;
1071 while out.len() < end {
1072 four(at(d), out);
1073 d += 1;
1074 }
1075 out.truncate(end);
1076 }
1077}
1078
1079pub fn numeric_out_sci(v: &Numeric, scale: i32) -> String {
1081 match v.sign {
1082 NumericSign::NaN => return "NaN".to_string(),
1083 NumericSign::Infinity => return "Infinity".to_string(),
1084 NumericSign::NegativeInfinity => return "-Infinity".to_string(),
1085 _ => {}
1086 }
1087 let rscale = i64::from(scale.max(0));
1088 let (exponent, significand) = match v.digits.first() {
1089 Some(&first) => {
1090 let exponent = i64::from(v.weight) * DEC_DIGITS + i64::from(first.ilog10());
1091 let power = Var::from_decimal_digits(&[1], exponent, 0);
1092 (exponent, Var::from(v).div(&power, rscale, true))
1093 }
1094 None => {
1095 (0, Var { sign: NumericSign::Positive, weight: 0, dscale: rscale, digits: Vec::new() })
1096 }
1097 };
1098 let significand = Numeric {
1099 sign: significand.sign,
1100 weight: significand.weight as i16,
1101 dscale: significand.dscale as u16,
1102 digits: significand.digits.iter().map(|&d| d as i16).collect(),
1103 };
1104 let mut out = Vec::new();
1105 numeric_out(&significand, &mut out);
1106 format!("{}e{exponent:+03}", String::from_utf8_lossy(&out))
1107}
1108
1109pub fn numeric_send(v: &Numeric, out: &mut Vec<u8>) {
1111 let dscale = match v.sign {
1112 NumericSign::Infinity | NumericSign::NegativeInfinity => 32,
1113 _ => v.dscale,
1114 };
1115 write_binary(v.sign, v.weight, dscale, &v.digits, out);
1116}
1117
1118fn write_binary(sign: NumericSign, weight: i16, dscale: u16, digits: &[i16], out: &mut Vec<u8>) {
1119 out.reserve(8 + 2 * digits.len());
1120 out.extend_from_slice(&(digits.len() as u16).to_be_bytes());
1121 out.extend_from_slice(&weight.to_be_bytes());
1122 out.extend_from_slice(&sign.code().to_be_bytes());
1123 out.extend_from_slice(&dscale.to_be_bytes());
1124 for &d in digits {
1125 out.extend_from_slice(&d.to_be_bytes());
1126 }
1127}
1128
1129pub fn numeric_recv(recv: &mut Recv<'_>, typmod: i32) -> Result<Numeric, TypeError> {
1131 let bad = |what: &str| {
1132 TypeError::new(
1133 SqlState::INVALID_BINARY_REPRESENTATION,
1134 format!("invalid {what} in external \"numeric\" value"),
1135 )
1136 };
1137 let len = recv.i16()? as u16;
1138 let weight = recv.i16()?;
1139 let sign = NumericSign::from_code(recv.i16()? as u16).ok_or_else(|| bad("sign"))?;
1140 let dscale = recv.i16()? as u16;
1141 if i64::from(dscale) > DSCALE_MAX {
1142 return Err(bad("scale"));
1143 }
1144 let mut digits = Vec::new();
1145 for _ in 0..len {
1146 let d = recv.i16()?;
1147 if !(0..NBASE as i16).contains(&d) {
1148 return Err(bad("digit"));
1149 }
1150 digits.push(i32::from(d));
1151 }
1152 if !sign.is_finite() {
1153 apply_typmod_special(sign, typmod)?;
1154 return Ok(Numeric::special(sign));
1155 }
1156 let mut var = Var { sign, weight: i64::from(weight), dscale: i64::from(dscale), digits };
1157 var.trunc(i64::from(dscale));
1158 var.apply_typmod(typmod)?;
1159 var.make()
1160}
1161
1162fn decimal_digits(abs: u128, scale: u32, buf: &mut [i16; DECIMAL_DIGITS_MAX]) -> (&[i16], i16) {
1164 assert!(scale <= 38, "a decimal has at most 38 digits after the point");
1165 let pow = 10u128.pow(scale);
1166 let (mut int, mut frac) = (abs / pow, abs % pow);
1167 let mut at = buf.len();
1168 let partial = scale % 4;
1169 if partial != 0 {
1170 let q = 10u128.pow(partial);
1171 at -= 1;
1172 buf[at] = ((frac % q) * 10u128.pow(4 - partial)) as i16;
1173 frac /= q;
1174 }
1175 for _ in 0..scale / 4 {
1176 at -= 1;
1177 buf[at] = (frac % NBASE as u128) as i16;
1178 frac /= NBASE as u128;
1179 }
1180 let point = at;
1181 while int > 0 {
1182 at -= 1;
1183 buf[at] = (int % NBASE as u128) as i16;
1184 int /= NBASE as u128;
1185 }
1186 let mut weight = (point - at) as i16 - 1;
1187 while at < buf.len() && buf[at] == 0 {
1188 at += 1;
1189 weight -= 1;
1190 }
1191 let mut end = buf.len();
1192 while end > at && buf[end - 1] == 0 {
1193 end -= 1;
1194 }
1195 if at == end {
1196 weight = 0;
1197 }
1198 (&buf[at..end], weight)
1199}
1200
1201fn u128_out(n: u128, out: &mut Vec<u8>) {
1203 if let Ok(n) = u64::try_from(n) {
1204 return u64_out(n, out);
1205 }
1206 let mut buf = [0u8; 39];
1207 let mut at = buf.len();
1208 let mut n = n;
1209 while n > 0 {
1210 at -= 1;
1211 buf[at] = b'0' + (n % 10) as u8;
1212 n /= 10;
1213 }
1214 out.extend_from_slice(&buf[at..]);
1215}
1216
1217pub fn decimal_out(value: i128, scale: u32, out: &mut Vec<u8>) {
1219 if value < 0 {
1220 out.push(b'-');
1221 }
1222 let abs = value.unsigned_abs();
1223 if scale == 0 {
1224 return u128_out(abs, out);
1225 }
1226 let pow = 10u128.pow(scale);
1227 u128_out(abs / pow, out);
1228 out.push(b'.');
1229 let mut frac = abs % pow;
1230 let start = out.len();
1231 out.resize(start + scale as usize, b'0');
1232 for at in out[start..].iter_mut().rev() {
1233 *at = b'0' + (frac % 10) as u8;
1234 frac /= 10;
1235 }
1236}
1237
1238pub fn decimal_send(value: i128, scale: u32, out: &mut Vec<u8>) {
1240 let mut buf = [0; DECIMAL_DIGITS_MAX];
1241 let (digits, weight) = decimal_digits(value.unsigned_abs(), scale, &mut buf);
1242 let sign = if value < 0 { NumericSign::Negative } else { NumericSign::Positive };
1243 write_binary(sign, weight, scale as u16, digits, out);
1244}
1245
1246#[cfg(test)]
1247mod tests {
1248 use super::*;
1249
1250 fn text(v: &Numeric) -> String {
1251 let mut out = Vec::new();
1252 numeric_out(v, &mut out);
1253 String::from_utf8(out).unwrap()
1254 }
1255
1256 fn round_trip(input: &str, typmod: i32) -> String {
1257 numeric_in(input, typmod).map(|v| text(&v)).unwrap_or_else(|e| e.message)
1258 }
1259
1260 fn value(text: &str) -> Numeric {
1261 numeric_in(text, -1).unwrap()
1262 }
1263
1264 #[test]
1265 fn the_arithmetic_keeps_the_scales_of_postgres() {
1266 for (a, op, b, out) in [
1268 ("1.0", '/', "3", "0.33333333333333333333"),
1269 ("10.0", '/', "4", "2.5000000000000000"),
1270 ("1e20", '/', "3", "33333333333333333333"),
1271 ("0.000001", '/', "3", "0.000000333333333333333333"),
1272 ("2", '/', "3", "0.66666666666666666667"),
1273 ("-2", '/', "3", "-0.66666666666666666667"),
1274 ("123456789012345678901234567890", '/', "7", "17636684144620811271604938270"),
1275 ("1", '/', "98765432109876543210", "0.000000000000000000010124999998860938"),
1276 ("99999999", '/', "0.0001", "999999990000.00000000"),
1277 ("0", '/', "5", "0.00000000000000000000"),
1278 ("1.50", '+', "2.125", "3.625"),
1279 ("1.50", '-', "2.125", "-0.625"),
1280 ("1.5", '-', "1.5", "0.0"),
1281 ("1.50", '*', "2.125", "3.18750"),
1282 ("-0.01", '*', "0", "0.00"),
1283 ("9999.9999", '+', "0.0001", "10000.0000"),
1284 ("NaN", '+', "1", "NaN"),
1285 ("Infinity", '-', "Infinity", "NaN"),
1286 ("Infinity", '*', "-2", "-Infinity"),
1287 ("Infinity", '*', "0", "NaN"),
1288 ("1", '/', "Infinity", "0"),
1289 ("7.5", '%', "2", "1.5"),
1290 ("-7.5", '%', "2", "-1.5"),
1291 ("7", '%', "-0.25", "0.00"),
1292 ("10", '%', "Infinity", "10"),
1293 ("-Infinity", '/', "-3", "Infinity"),
1294 ] {
1295 let (a, b) = (value(a), value(b));
1296 let result = match op {
1297 '+' => a.add(&b),
1298 '-' => a.sub(&b),
1299 '*' => a.mul(&b),
1300 '%' => a.modulo(&b),
1301 _ => a.div(&b),
1302 };
1303 assert_eq!(text(&result.unwrap()), out, "{} {op} {}", text(&a), text(&b));
1304 }
1305 assert_eq!(value("1").div(&value("0")).unwrap_err().message, "division by zero");
1306 assert_eq!(value("Infinity").div(&value("0")).unwrap_err().message, "division by zero");
1307 }
1308
1309 #[test]
1310 fn the_long_division_agrees_with_the_integers() {
1311 let mut seed = 0x2545_f491_4f6c_dd1du64;
1312 let mut next = || {
1313 seed ^= seed << 13;
1314 seed ^= seed >> 7;
1315 seed ^= seed << 17;
1316 seed
1317 };
1318 for _ in 0..2000 {
1319 let a = i128::from(next() >> (next() % 60));
1320 let b = i128::from(next() >> (next() % 63)).max(1);
1321 let quotient = Numeric::from_integer(a).div(&Numeric::from_integer(b)).unwrap();
1322 assert_eq!(
1323 quotient.with_typmod(-1).unwrap().to_decimal(0),
1324 Some((2 * a + b) / (2 * b)),
1325 "{a} / {b}"
1326 );
1327 let back = quotient.mul(&Numeric::from_integer(b)).unwrap();
1328 let error = back.sub(&Numeric::from_integer(a)).unwrap().to_f64().abs();
1329 assert!(error <= b as f64, "{a} / {b} = {}", text("ient));
1330 }
1331 }
1332
1333 #[test]
1334 fn a_double_converts_with_fifteen_digits() {
1335 for (input, out) in [
1336 (0.1, "0.1"),
1337 (1.0 / 3.0, "0.333333333333333"),
1338 (1e20, "100000000000000000000"),
1339 (1.5e-7, "0.00000015"),
1340 (-2.0, "-2"),
1341 (123456.789, "123456.789"),
1342 ] {
1343 assert_eq!(text(&Numeric::from_f64(input)), out);
1344 }
1345 assert_eq!(value("0.33333333333333333333").to_f64(), 1.0 / 3.0);
1346 assert_eq!(value("2.5").to_integer("integer").unwrap(), 3);
1347 assert_eq!(value("-2.5").to_integer("integer").unwrap(), -3);
1348 assert_eq!(
1349 value("NaN").to_integer("integer").unwrap_err().message,
1350 "cannot convert NaN to integer"
1351 );
1352 }
1353
1354 #[test]
1355 fn the_bytes_hold_the_value_and_order_it() {
1356 for input in ["0.00", "-123456.78", "1e-30", "NaN", "-Infinity", "33333333333333333333.3"] {
1357 let v = value(input);
1358 assert_eq!(Numeric::from_bytes(&v.to_bytes()), v);
1359 }
1360 assert_eq!(value("1.0").compare(&value("1.000")), std::cmp::Ordering::Equal);
1361 assert_eq!(value("-1.1").compare(&value("-1.01")), std::cmp::Ordering::Less);
1362 }
1363
1364 #[test]
1365 fn the_input_keeps_the_scale_and_strips_the_zeros() {
1366 let v = numeric_in(" -0012.3400 ", -1).unwrap();
1367 assert_eq!(
1368 (v.sign(), v.weight(), v.dscale(), v.digits()),
1369 (NumericSign::Negative, 0, 4, &[12, 3400][..])
1370 );
1371 assert_eq!(text(&v), "-12.3400");
1372 let zero = numeric_in("-0.00", -1).unwrap();
1373 assert_eq!(
1374 (zero.sign(), zero.weight(), zero.dscale(), zero.digits()),
1375 (NumericSign::Positive, 0, 2, &[][..])
1376 );
1377 assert_eq!(round_trip("1e3", -1), "1000");
1378 assert_eq!(round_trip("1.5e-3", -1), "0.0015");
1379 assert_eq!(round_trip("0x_1F", -1), "31");
1380 assert_eq!(round_trip("-0b1_01", -1), "-5");
1381 assert_eq!(round_trip("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", -1), u128::MAX.to_string());
1382 assert_eq!(round_trip("1e-16384", -1), "value overflows numeric format");
1383 assert_eq!(round_trip("1e2147483647", -1), "value overflows numeric format");
1384 }
1385
1386 #[test]
1387 fn round_trunc_ceil_and_floor_keep_the_digits() {
1388 let text = |value: Numeric| {
1389 let mut out = Vec::new();
1390 numeric_out(&value, &mut out);
1391 String::from_utf8(out).unwrap()
1392 };
1393 let value = numeric_in("-123456789012345678901.555", -1).unwrap();
1394 assert_eq!(text(value.round(2).unwrap()), "-123456789012345678901.56");
1395 assert_eq!(text(value.round(-1).unwrap()), "-123456789012345678900");
1396 assert_eq!(text(value.trunc(1).unwrap()), "-123456789012345678901.5");
1397 assert_eq!(text(value.whole(true).unwrap()), "-123456789012345678901");
1398 assert_eq!(text(value.whole(false).unwrap()), "-123456789012345678902");
1399 assert_eq!(text(value.abs()), "123456789012345678901.555");
1400 let small = numeric_in("-0.5", -1).unwrap();
1401 assert_eq!(text(small.whole(true).unwrap()), "0");
1402 assert_eq!(text(small.whole(false).unwrap()), "-1");
1403 assert_eq!(text(numeric_in("9.99", -1).unwrap().round(1).unwrap()), "10.0");
1404 assert_eq!(text(numeric_in("5", -1).unwrap().round(1).unwrap()), "5.0");
1405 let nan = numeric_in("NaN", -1).unwrap();
1406 assert_eq!(text(nan.round(2).unwrap()), "NaN");
1407 }
1408
1409 #[test]
1410 fn rounding_carries_into_a_new_digit() {
1411 let typmod = crate::typmod::numeric_typmod;
1412 assert_eq!(round_trip("9999.99995", typmod(10, 4)), "10000.0000");
1413 assert_eq!(round_trip("0.6", typmod(1, 0)), "1");
1414 assert_eq!(round_trip("-0.004", typmod(5, 2)), "0.00");
1415 assert_eq!(round_trip("15", typmod(3, -1)), "20");
1416 assert_eq!(round_trip("-5", typmod(3, -1)), "-10");
1417 let error = numeric_in("999.995", typmod(5, 2)).unwrap_err();
1418 assert_eq!(
1419 (error.sqlstate.as_str(), error.message.as_str()),
1420 ("22003", "numeric field overflow")
1421 );
1422 assert_eq!(
1423 error.detail.as_deref(),
1424 Some(
1425 "A field with precision 5, scale 2 must round to an absolute value less than 10^3."
1426 )
1427 );
1428 let error = numeric_in("0.95", typmod(1, 1)).unwrap_err();
1429 assert_eq!(
1430 error.detail.as_deref(),
1431 Some("A field with precision 1, scale 1 must round to an absolute value less than 1.")
1432 );
1433 let error = numeric_in("-inf", typmod(5, 2)).unwrap_err();
1434 assert_eq!(
1435 error.detail.as_deref(),
1436 Some("A field with precision 5, scale 2 cannot hold an infinite value.")
1437 );
1438 assert_eq!(numeric_in("NaN", typmod(5, 2)), Ok(Numeric::NAN));
1439 }
1440
1441 #[test]
1442 fn the_binary_form_is_the_fields() {
1443 let mut out = Vec::new();
1444 numeric_send(&numeric_in("-12.3400", -1).unwrap(), &mut out);
1445 assert_eq!(out, [0, 2, 0, 0, 0x40, 0, 0, 4, 0, 12, 0x0d, 0x48]);
1446 let back = numeric_recv(&mut Recv::new(&out), -1).unwrap();
1447 assert_eq!(text(&back), "-12.3400");
1448
1449 let hidden = [0, 2, 0, 0, 0, 0, 0, 1, 0, 1, 0x13, 0x88];
1451 assert_eq!(text(&numeric_recv(&mut Recv::new(&hidden), -1).unwrap()), "1.5");
1452
1453 let bad = |bytes: &[u8]| numeric_recv(&mut Recv::new(bytes), -1).unwrap_err().message;
1454 assert_eq!(
1455 bad(&[0, 0, 0, 0, 0x12, 0x34, 0, 0]),
1456 "invalid sign in external \"numeric\" value"
1457 );
1458 assert_eq!(
1459 bad(&[0, 0, 0, 0, 0, 0, 0x40, 0]),
1460 "invalid scale in external \"numeric\" value"
1461 );
1462 assert_eq!(
1463 bad(&[0, 1, 0, 0, 0, 0, 0, 0, 0x27, 0x10]),
1464 "invalid digit in external \"numeric\" value"
1465 );
1466 assert_eq!(bad(&[0, 1, 0, 0, 0, 0, 0, 0]), "insufficient data left in message");
1467 let mut out = Vec::new();
1468 numeric_send(&Numeric::NEGATIVE_INFINITY, &mut out);
1469 assert_eq!(out, [0, 0, 0, 0, 0xf0, 0, 0, 32]);
1470 }
1471
1472 #[test]
1473 fn a_decimal_of_the_engine_writes_what_numeric_writes() {
1474 let values = [
1475 0i128,
1476 1,
1477 -1,
1478 5,
1479 -5,
1480 9999,
1481 10000,
1482 123456789,
1483 -100000000,
1484 i64::MAX as i128,
1485 i128::MAX,
1486 i128::MIN + 1,
1487 ];
1488 for value in values {
1489 for scale in [0, 1, 2, 3, 4, 5, 8, 9, 18, 19, 37, 38] {
1490 let v = Numeric::from_decimal(value, scale);
1491 let mut out = Vec::new();
1492 decimal_out(value, scale, &mut out);
1493 let decimal = String::from_utf8(out).unwrap();
1494 assert_eq!(decimal, text(&v), "{value} {scale}");
1495 assert_eq!(numeric_in(&decimal, -1), Ok(v.clone()), "{value} {scale}");
1496 let (mut sent, mut expected) = (Vec::new(), Vec::new());
1497 decimal_send(value, scale, &mut sent);
1498 numeric_send(&v, &mut expected);
1499 assert_eq!(sent, expected, "{value} {scale}");
1500 assert_eq!(v.to_decimal(scale), Some(value), "{value} {scale}");
1501 }
1502 }
1503 let v = numeric_in("-1.005", -1).unwrap();
1504 assert_eq!(
1505 (v.to_decimal(2), v.to_decimal(0), v.to_decimal(5)),
1506 (Some(-101), Some(-1), Some(-100500))
1507 );
1508 assert_eq!(numeric_in("1e40", -1).unwrap().to_decimal(0), None);
1509 assert_eq!(Numeric::NAN.to_decimal(0), None);
1510 }
1511}