1extern crate byteorder;
2extern crate bytes;
3
4use self::byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
5use self::bytes::{BufMut, BytesMut};
6use postgres_types::{FromSql, IsNull, ToSql, Type};
7
8use crate::{GenericFraction, Sign, Zero};
9use division::{divide_integral, divide_rem};
10use generic::GenericInteger;
11
12use std::error::Error;
13use std::fmt;
14use std::mem;
15
16const PG_POS: u16 = 0x0000;
17const PG_NEG: u16 = 0x4000;
18const PG_NAN: u16 = 0xC000;
19const PG_NBASE_U: u16 = 10000;
20const PG_NBASE_I: i16 = 10000;
21pub const PG_MAX_PRECISION: usize = 16383;
22
23#[inline]
24pub fn read_i16(mut buf: &[u8]) -> Result<i16, Box<dyn Error + Sync + Send>> {
25 match buf.read_i16::<BigEndian>() {
26 Ok(n) => Ok(n),
27 Err(e) => Err(e.into()),
28 }
29}
30
31#[inline]
32pub fn read_u16(mut buf: &[u8]) -> Result<u16, Box<dyn Error + Sync + Send>> {
33 match buf.read_u16::<BigEndian>() {
34 Ok(n) => Ok(n),
35 Err(e) => Err(e.into()),
36 }
37}
38
39#[inline]
40pub fn write_i16(mut buf: &mut [u8], value: i16) -> Result<(), Box<dyn Error + Sync + Send>> {
41 match buf.write_i16::<BigEndian>(value) {
42 Ok(()) => Ok(()),
43 Err(e) => Err(e.into()),
44 }
45}
46
47#[inline]
48pub fn write_u16(mut buf: &mut [u8], value: u16) -> Result<(), Box<dyn Error + Sync + Send>> {
49 match buf.write_u16::<BigEndian>(value) {
50 Ok(()) => Ok(()),
51 Err(e) => Err(e.into()),
52 }
53}
54
55impl<'a, T> FromSql<'a> for GenericFraction<T>
56where
57 T: Clone + GenericInteger + From<u16>,
58{
59 fn from_sql(_ty: &Type, raw: &'a [u8]) -> Result<Self, Box<dyn Error + Sync + Send>> {
60 if raw.len() < 8 {
61 return Err("unexpected data package from the database".into());
62 }
63
64 let sign: u16 = read_u16(&raw[4..6])?;
65 let sign = match sign {
66 PG_NEG => Sign::Minus,
67 PG_POS => Sign::Plus,
68 PG_NAN => return Ok(Self::nan()),
69 _ => return Err("unexpected sign byte in the data package".into()),
70 };
71
72 let ndigits: i16 = read_i16(&raw[0..2])?;
73 if ndigits <= 0 {
74 return Ok(match sign {
75 Sign::Minus => Self::neg_zero(),
76 Sign::Plus => Self::zero(),
77 });
78 }
79
80 let ndigits: usize = unsafe { mem::transmute::<i16, u16>(ndigits) }.into();
82 if (raw.len() - 8) / 2 < ndigits {
83 return Err("data package declares more digits than received".into());
84 }
85
86 let weight: i16 = read_i16(&raw[2..4])?;
87 let uweight: usize = if weight <= 0 {
88 0
89 } else {
90 unsafe { mem::transmute::<i16, u16>(weight) }.into()
92 };
93
94 let mut num: T = 0u16.into();
95 let mut den: T = 1u16.into();
96 let mut exp: T = 1u16.into();
97
98 let nbase: T = PG_NBASE_U.into();
99
100 let overflow_message = "integer overflow during unpacking the database value (try to use bigger integer as the base for Fraction, or you may even try BigFraction to use heap memory)";
101
102 if weight < 0 {
103 for _ in weight..0 {
104 den = match den.checked_mul(&nbase) {
105 Some(n) => n,
106 None => return Err(overflow_message.into()),
107 };
108 }
109 } else {
110 for _ in 0..weight {
111 exp = match exp.checked_mul(&nbase) {
112 Some(n) => n,
113 None => return Err(overflow_message.into()),
114 };
115 }
116 }
117
118 for iteration in 0..ndigits {
119 let i = 8 + iteration * 2;
121
122 let digits: i16 = read_i16(&raw[i..i + 2])?;
123 let mut digits = if digits < 0 {
124 return Err("database sent unexpected negative value".into());
125 } else {
126 unsafe { mem::transmute::<i16, u16>(digits) }
127 };
128
129 let digit: u16 = digits / 1000 * 1000;
131 digits -= digit;
132
133 let d: T = digit.into();
134 let d = match d.checked_mul(&exp) {
135 Some(n) => n,
136 None => return Err(overflow_message.into()),
137 };
138
139 num = match num.checked_add(&d) {
140 Some(n) => n,
141 None => return Err(overflow_message.into()),
142 };
143
144 let digit: u16 = digits / 100 * 100;
146 digits -= digit;
147
148 let d: T = digit.into();
149 let d = match d.checked_mul(&exp) {
150 Some(n) => n,
151 None => return Err(overflow_message.into()),
152 };
153 num = match num.checked_add(&d) {
154 Some(n) => n,
155 None => return Err(overflow_message.into()),
156 };
157
158 let digit: u16 = digits / 10 * 10;
160 digits -= digit;
161
162 let d: T = digit.into();
163 let d = match d.checked_mul(&exp) {
164 Some(n) => n,
165 None => return Err(overflow_message.into()),
166 };
167 num = match num.checked_add(&d) {
168 Some(n) => n,
169 None => return Err(overflow_message.into()),
170 };
171
172 let d: T = digits.into();
174 let d = match d.checked_mul(&exp) {
175 Some(n) => n,
176 None => return Err(overflow_message.into()),
177 };
178 num = match num.checked_add(&d) {
179 Some(n) => n,
180 None => return Err(overflow_message.into()),
181 };
182
183 if iteration >= uweight {
185 num = match num.checked_mul(&nbase) {
187 Some(n) => n,
188 None => return Err(overflow_message.into()),
189 };
190
191 den = match den.checked_mul(&nbase) {
192 Some(n) => n,
193 None => return Err(overflow_message.into()),
194 };
195 } else if uweight > 0 {
196 exp = match exp.checked_div(&nbase) {
198 Some(n) => n,
199 None => return Err(overflow_message.into()),
200 };
201 }
202 }
203
204 Ok(match sign {
205 Sign::Plus => Self::new(num, den),
206 Sign::Minus => Self::new_neg(num, den),
207 })
208 }
209
210 accepts!(NUMERIC);
211}
212
213impl<T> ToSql for GenericFraction<T>
214where
215 T: Clone + GenericInteger + From<u8> + fmt::Debug,
216{
217 fn to_sql(
218 &self,
219 ty: &Type,
220 buf: &mut BytesMut,
221 ) -> Result<IsNull, Box<dyn Error + Sync + Send>> {
222 fraction_to_sql_buf(self, ty, buf, PG_MAX_PRECISION)
223 }
224
225 accepts!(NUMERIC);
226
227 to_sql_checked!();
228}
229
230pub fn fraction_to_sql_buf<T>(
231 source: &GenericFraction<T>,
232 _ty: &Type,
233 buf: &mut BytesMut,
234 precision: usize,
235) -> Result<IsNull, Box<dyn Error + Sync + Send>>
236where
237 T: Clone + GenericInteger + From<u8>,
238{
239 let precision = if precision <= PG_MAX_PRECISION {
240 precision
241 } else {
242 PG_MAX_PRECISION
243 };
244
245 let buffer_offset: usize = buf.len();
246 buf.put_u64(0); if source.is_zero() {
249 return Ok(IsNull::No);
250 }
251
252 if source.is_nan() {
253 write_u16(&mut buf[buffer_offset + 4..buffer_offset + 6], PG_NAN)?;
254 return Ok(IsNull::No);
255 }
256
257 let numer: T = if let Some(n) = source.numer() {
258 n.clone()
259 } else {
260 unreachable!();
261 };
262 let denom: T = if let Some(d) = source.denom() {
263 d.clone()
264 } else {
265 unreachable!();
266 };
267
268 let mut ndigits: i16 = 0;
269 let mut weight: i16 = -1;
270 let mut scale: i16 = 0;
271 let mut uscale: usize = 0;
272
273 let mut ndigit: i16 = 0;
274 let mut nptr: u32 = 0;
275
276 let mut padding = true;
277 let mut rpad = 0;
278
279 let div_state = divide_integral(numer, denom, |digit: u8| {
280 if padding && digit == 0 {
281 return Ok(true);
282 } else {
283 padding = false;
284 }
285
286 let digit: i16 = digit.into();
287
288 ndigit *= 10;
289 ndigit += digit;
290
291 nptr += 1;
292
293 if nptr > 3 {
294 nptr = 0;
295 weight += 1;
296
297 if ndigit == 0 {
298 rpad += 1;
299 } else {
300 rpad = 0;
301 }
302
303 ndigits += 1;
304 buf.put_i16(ndigit);
305 ndigit = 0;
306 }
307
308 Ok(true)
309 })?;
310
311 if nptr != 0 {
312 let shift = 4 - nptr;
313
314 ndigits += 1;
315 weight += 1;
316 nptr = 0;
317
318 let digits = (buf.len() - buffer_offset - 8) / 2;
319 let mut rem_: i16 = 0;
320
321 for i in 0..digits {
322 let pos = buffer_offset + 8 + i * 2;
323 let mut digit = read_i16(&buf[pos..pos + 2])?;
324
325 let mut tmp_rem: i16 = (digit - (digit / 10 * 10)) * 1000;
326 digit /= 10;
327
328 if shift > 1 {
329 tmp_rem /= 10;
330 tmp_rem += (digit - (digit / 10 * 10)) * 1000;
331 digit /= 10;
332
333 if shift > 2 {
334 tmp_rem /= 10;
335 tmp_rem += (digit - (digit / 10 * 10)) * 1000;
336 digit /= 10;
337 }
338 }
339
340 digit += rem_;
341 rem_ = tmp_rem;
342
343 write_i16(&mut buf[pos..pos + 2], digit)?;
344 }
345
346 ndigit += rem_;
347 if ndigit == 0 {
348 rpad += 1;
349 } else {
350 rpad = 0;
351 }
352
353 buf.put_i16(ndigit);
354 ndigit = 0;
355 }
356
357 if div_state.remainder.is_zero() && rpad > 0 {
358 ndigits -= rpad;
359 buf.truncate(buffer_offset + 8 + (ndigits as usize) * 2);
360 }
361
362 if !div_state.remainder.is_zero() {
363 padding = weight < 0; divide_rem(
365 div_state.remainder,
366 div_state.divisor,
367 |state, digit: u8| {
368 let digit: i16 = digit.into();
369
370 if digit != 0 {
371 if padding && weight > 0 {
372 ndigits += weight;
373 for _ in 0..weight {
374 buf.put_i16(ndigit);
375 }
376 }
377 padding = false;
378 }
379
380 nptr += 1;
381
382 ndigit += digit * (PG_NBASE_I / 10i16.pow(nptr));
383
384 scale += 1;
385 uscale += 1;
386
387 if nptr > 3 {
388 if padding && weight < 0 {
389 weight -= 1;
390 } else {
391 ndigits += 1;
392 buf.put_i16(ndigit);
393 }
394
395 nptr = 0;
396 ndigit = 0;
397 }
398
399 Ok(if uscale < precision {
400 Ok(state)
401 } else {
402 Err(state)
403 })
404 },
405 )?;
406
407 if nptr != 0 && !padding {
408 ndigits += 1;
409 buf.put_i16(ndigit);
410 }
411 }
412
413 write_i16(&mut buf[buffer_offset..buffer_offset + 2], ndigits)?;
414 write_i16(&mut buf[buffer_offset + 2..buffer_offset + 4], weight)?;
415 write_u16(
416 &mut buf[buffer_offset + 4..buffer_offset + 6],
417 match source.sign() {
418 Some(Sign::Minus) => PG_NEG,
419 _ => PG_POS,
420 },
421 )?;
422
423 write_i16(&mut buf[buffer_offset + 6..buffer_offset + 8], scale)?;
424
425 Ok(IsNull::No)
426}
427
428#[cfg(test)]
429mod tests {
430 use super::*;
431
432 type Fraction = GenericFraction<u128>;
433 const NUMERIC_OID: u32 = 1700;
434
435 fn get_tests() -> Vec<(Fraction, &'static [u8])> {
436 vec![
437 (
438 Fraction::new_raw_signed(Sign::Minus, 12345678901234u128, 1u128),
439 &[0, 4, 0, 3, 64, 0, 0, 0, 0, 12, 13, 128, 30, 210, 4, 210],
440 ),
441 (
442 Fraction::new_raw_signed(Sign::Minus, 12345678u128, 1u128),
443 &[0, 2, 0, 1, 64, 0, 0, 0, 4, 210, 22, 46],
444 ),
445 (
446 Fraction::new_raw_signed(Sign::Minus, 10000000000000000001u128, 10000000000u128),
447 &[
448 0, 6, 0, 2, 64, 0, 0, 10, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100,
449 ],
450 ),
451 (
452 Fraction::new_raw_signed(Sign::Minus, 1000000000u128, 1u128),
453 &[0, 1, 0, 2, 64, 0, 0, 0, 0, 10],
454 ),
455 (
456 Fraction::new_raw_signed(Sign::Minus, 1234u128, 1u128),
457 &[0, 1, 0, 0, 64, 0, 0, 0, 4, 210],
458 ),
459 (
460 Fraction::new_raw_signed(Sign::Minus, 256u128, 1u128),
461 &[0, 1, 0, 0, 64, 0, 0, 0, 1, 0],
462 ),
463 (
464 Fraction::new_raw_signed(Sign::Minus, 42u128, 1u128),
465 &[0, 1, 0, 0, 64, 0, 0, 0, 0, 42],
466 ),
467 (
468 Fraction::new_raw_signed(Sign::Minus, 1u128, 1u128),
469 &[0, 1, 0, 0, 64, 0, 0, 0, 0, 1],
470 ),
471 (
472 Fraction::new_raw_signed(Sign::Minus, 1u128, 2u128),
473 &[0, 1, 255, 255, 64, 0, 0, 1, 19, 136],
474 ),
475 (
476 Fraction::new_raw_signed(Sign::Minus, 1u128, 10u128),
477 &[0, 1, 255, 255, 64, 0, 0, 1, 3, 232],
478 ),
479 (
480 Fraction::new_raw_signed(Sign::Minus, 66u128, 100u128),
481 &[0, 1, 255, 255, 64, 0, 0, 2, 25, 200],
482 ),
483 (
484 Fraction::new_raw_signed(Sign::Minus, 6172839450617u128, 50000000000000u128),
485 &[0, 4, 255, 255, 64, 0, 0, 14, 4, 210, 22, 46, 35, 52, 13, 72],
486 ),
487 (
488 Fraction::new_raw_signed(Sign::Minus, 1u128, 100u128),
489 &[0, 1, 255, 255, 64, 0, 0, 2, 0, 100],
490 ),
491 (
492 Fraction::new_raw_signed(Sign::Minus, 601u128, 2500u128),
493 &[0, 1, 255, 255, 64, 0, 0, 4, 9, 100],
494 ),
495 (
496 Fraction::new_raw_signed(Sign::Minus, 1u128, 1000000000u128),
497 &[0, 1, 255, 253, 64, 0, 0, 9, 3, 232],
498 ),
499 (
500 Fraction::new_raw_signed(
501 Sign::Minus,
502 617283945061706172839450617u128,
503 50000000000000u128,
504 ),
505 &[
506 0, 8, 0, 3, 64, 0, 0, 14, 0, 12, 13, 128, 30, 210, 4, 210, 4, 210, 22, 46, 35,
507 52, 13, 72,
508 ],
509 ),
510 (Fraction::zero(), &[0, 0, 0, 0, 0, 0, 0, 0]),
511 (Fraction::nan(), &[0, 0, 0, 0, 192, 0, 0, 0]),
512 (
513 Fraction::new_raw(617283945061706172839450617u128, 50000000000000u128),
514 &[
515 0, 8, 0, 3, 0, 0, 0, 14, 0, 12, 13, 128, 30, 210, 4, 210, 4, 210, 22, 46, 35,
516 52, 13, 72,
517 ],
518 ),
519 (
520 Fraction::new_raw(1u128, 1000000000u128),
521 &[0, 1, 255, 253, 0, 0, 0, 9, 3, 232],
522 ),
523 (
524 Fraction::new_raw(601u128, 2500u128),
525 &[0, 1, 255, 255, 0, 0, 0, 4, 9, 100],
526 ),
527 (
528 Fraction::new_raw(1u128, 100u128),
529 &[0, 1, 255, 255, 0, 0, 0, 2, 0, 100],
530 ),
531 (
532 Fraction::new_raw(66u128, 100u128),
533 &[0, 1, 255, 255, 0, 0, 0, 2, 25, 200],
534 ),
535 (
536 Fraction::new_raw(10000000000000000000001u128, 10000000000000000u128),
537 &[
538 0, 6, 0, 1, 0, 0, 0, 16, 0, 100, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1,
539 ],
540 ),
541 (
542 Fraction::new_raw(6172839450617u128, 50000000000000u128),
543 &[0, 4, 255, 255, 0, 0, 0, 14, 4, 210, 22, 46, 35, 52, 13, 72],
544 ),
545 (
546 Fraction::new_raw(1u128, 10u128),
547 &[0, 1, 255, 255, 0, 0, 0, 1, 3, 232],
548 ),
549 (
550 Fraction::new_raw(1u128, 2u128),
551 &[0, 1, 255, 255, 0, 0, 0, 1, 19, 136],
552 ),
553 (
554 Fraction::new_raw(1u128, 1u128),
555 &[0, 1, 0, 0, 0, 0, 0, 0, 0, 1],
556 ),
557 (
558 Fraction::new_raw(42u128, 1u128),
559 &[0, 1, 0, 0, 0, 0, 0, 0, 0, 42],
560 ),
561 (
562 Fraction::new_raw(256u128, 1u128),
563 &[0, 1, 0, 0, 0, 0, 0, 0, 1, 0],
564 ),
565 (
566 Fraction::new_raw(1234u128, 1u128),
567 &[0, 1, 0, 0, 0, 0, 0, 0, 4, 210],
568 ),
569 (
570 Fraction::new_raw(1000000000u128, 1u128),
571 &[0, 1, 0, 2, 0, 0, 0, 0, 0, 10],
572 ),
573 (
574 Fraction::new_raw(10000000000000000001u128, 10000000000u128),
575 &[
576 0, 6, 0, 2, 0, 0, 0, 10, 0, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 100,
577 ],
578 ),
579 (
580 Fraction::new_raw(12345678u128, 1u128),
581 &[0, 2, 0, 1, 0, 0, 0, 0, 4, 210, 22, 46],
582 ),
583 (
584 Fraction::new_raw(12345678901234u128, 1u128),
585 &[0, 4, 0, 3, 0, 0, 0, 0, 0, 12, 13, 128, 30, 210, 4, 210],
586 ),
587 (
588 Fraction::new_raw(33333333333333333333u128, 100000000000000000000u128),
589 &[
590 0, 5, 255, 255, 0, 0, 0, 20, 13, 5, 13, 5, 13, 5, 13, 5, 13, 5,
591 ],
592 ),
593 ]
594 }
595
596 #[test]
597 fn test_from_sql() {
598 let t = Type::from_oid(NUMERIC_OID).unwrap();
599 for ref test in &get_tests() {
600 assert_eq!(
601 test.0,
602 <Fraction as FromSql>::from_sql(&t, test.1).ok().unwrap()
603 )
604 }
605 }
606
607 #[test]
608 fn test_to_sql() {
609 let t = Type::from_oid(NUMERIC_OID).unwrap();
610 let mut buf = BytesMut::with_capacity(1024);
611
612 for ref test in &get_tests() {
613 buf.clear();
614 let res = <Fraction as ToSql>::to_sql(&test.0, &t, &mut buf)
615 .ok()
616 .unwrap();
617
618 match res {
619 IsNull::Yes => assert!(false),
620 IsNull::No => assert!(true),
621 };
622
623 assert_eq!(&buf, &test.1);
624 }
625 }
626}