| 48 | |
| 49 | impl ToSql for Numeric { |
| 50 | fn to_sql( |
| 51 | &self, |
| 52 | _: &Type, |
| 53 | out: &mut BytesMut, |
| 54 | ) -> Result<IsNull, Box<dyn Error + 'static + Send + Sync>> { |
| 55 | let mut d = self.0.0.clone(); |
| 56 | let scale = u16::try_from(numeric::get_scale(&d))?; |
| 57 | let is_zero = d.is_zero(); |
| 58 | let is_nan = d.is_nan(); |
| 59 | let is_neg = d.is_negative() && !is_zero; |
| 60 | let is_infinite = d.is_infinite(); |
| 61 | |
| 62 | let mut cx = numeric::cx_datum(); |
| 63 | // Need to extend exponents slightly because fractional components need |
| 64 | // to be aligned to base 10,000. |
| 65 | cx.set_max_exponent(cx.max_exponent() + isize::cast_from(i64::from(TO_FROM_SQL_BASE_POW))) |
| 66 | .unwrap(); |
| 67 | cx.set_min_exponent(cx.min_exponent() - isize::cast_from(i64::from(TO_FROM_SQL_BASE_POW))) |
| 68 | .unwrap(); |
| 69 | cx.abs(&mut d); |
| 70 | |
| 71 | let mut digits = [0u16; UNITS_LEN]; |
| 72 | let mut d_i = UNITS_LEN; |
| 73 | |
| 74 | let (fract_units, leading_zero_units) = if d.exponent() < 0 { |
| 75 | let pos_exp = usize::try_from(-d.exponent()).expect("positive value < 40"); |
| 76 | // You have leading zeroes in the case where: |
| 77 | // - The exponent's absolute value exceeds the number of digits |
| 78 | // - `d` only contains fractional zeroes |
| 79 | let leading_zero_units = if pos_exp >= usize::cast_from(d.digits()) { |
| 80 | // If the value is zero, one zero digit gets double counted |
| 81 | // (this is also why the above inequality is not strict) |
| 82 | let digits = if d.is_zero() { |
| 83 | 0 |
| 84 | } else { |
| 85 | usize::cast_from(d.digits()) |
| 86 | }; |
| 87 | // integer division with rounding up instead of down |
| 88 | (pos_exp - digits + usize::cast_from(TO_FROM_SQL_BASE_POW) - 1) |
| 89 | / usize::cast_from(TO_FROM_SQL_BASE_POW) |
| 90 | } else { |
| 91 | 0 |
| 92 | }; |
| 93 | |
| 94 | // Ensure most significant fractional digit in ten's place of base |
| 95 | // 10,000 value. |
| 96 | let s = pos_exp % usize::cast_from(TO_FROM_SQL_BASE_POW); |
| 97 | let unit_shift_exp = if s != 0 { |
| 98 | pos_exp + usize::cast_from(TO_FROM_SQL_BASE_POW) - s |
| 99 | } else { |
| 100 | pos_exp |
| 101 | }; |
| 102 | |
| 103 | // Convert d into a "canonical coefficient" with most significant |
| 104 | // fractional digit properly aligned. |
| 105 | cx.scaleb(&mut d, &AdtNumeric::from(unit_shift_exp)); |
| 106 | |
| 107 | ( |