PostgreSQL Source Code  git master
numeric.c
Go to the documentation of this file.
1 /* src/interfaces/ecpg/pgtypeslib/numeric.c */
2 
3 #include "postgres_fe.h"
4 
5 #include <ctype.h>
6 #include <float.h>
7 #include <limits.h>
8 
9 #include "pgtypes_error.h"
10 #include "pgtypes_numeric.h"
11 #include "pgtypeslib_extern.h"
12 
13 #define Max(x, y) ((x) > (y) ? (x) : (y))
14 #define Min(x, y) ((x) < (y) ? (x) : (y))
15 
16 #define init_var(v) memset(v,0,sizeof(numeric))
17 
18 #define digitbuf_alloc(size) ((NumericDigit *) pgtypes_alloc(size))
19 #define digitbuf_free(buf) \
20  do { \
21  if ((buf) != NULL) \
22  free(buf); \
23  } while (0)
24 
25 
26 /* ----------
27  * alloc_var() -
28  *
29  * Allocate a digit buffer of ndigits digits (plus a spare digit for rounding)
30  * ----------
31  */
32 static int
33 alloc_var(numeric *var, int ndigits)
34 {
35  digitbuf_free(var->buf);
36  var->buf = digitbuf_alloc(ndigits + 1);
37  if (var->buf == NULL)
38  return -1;
39  var->buf[0] = 0;
40  var->digits = var->buf + 1;
41  var->ndigits = ndigits;
42  return 0;
43 }
44 
45 numeric *
47 {
48  numeric *var;
49 
50  if ((var = (numeric *) pgtypes_alloc(sizeof(numeric))) == NULL)
51  return NULL;
52 
53  if (alloc_var(var, 0) < 0)
54  {
55  free(var);
56  return NULL;
57  }
58 
59  return var;
60 }
61 
62 decimal *
64 {
65  decimal *var;
66 
67  if ((var = (decimal *) pgtypes_alloc(sizeof(decimal))) == NULL)
68  return NULL;
69 
70  memset(var, 0, sizeof(decimal));
71 
72  return var;
73 }
74 
75 /* ----------
76  * set_var_from_str()
77  *
78  * Parse a string and put the number into a variable
79  * ----------
80  */
81 static int
82 set_var_from_str(char *str, char **ptr, numeric *dest)
83 {
84  bool have_dp = false;
85  int i = 0;
86 
87  errno = 0;
88  *ptr = str;
89  while (*(*ptr))
90  {
91  if (!isspace((unsigned char) *(*ptr)))
92  break;
93  (*ptr)++;
94  }
95 
96  if (pg_strncasecmp(*ptr, "NaN", 3) == 0)
97  {
98  *ptr += 3;
99  dest->sign = NUMERIC_NAN;
100 
101  /* Should be nothing left but spaces */
102  while (*(*ptr))
103  {
104  if (!isspace((unsigned char) *(*ptr)))
105  {
106  errno = PGTYPES_NUM_BAD_NUMERIC;
107  return -1;
108  }
109  (*ptr)++;
110  }
111 
112  return 0;
113  }
114 
115  if (alloc_var(dest, strlen((*ptr))) < 0)
116  return -1;
117  dest->weight = -1;
118  dest->dscale = 0;
119  dest->sign = NUMERIC_POS;
120 
121  switch (*(*ptr))
122  {
123  case '+':
124  dest->sign = NUMERIC_POS;
125  (*ptr)++;
126  break;
127 
128  case '-':
129  dest->sign = NUMERIC_NEG;
130  (*ptr)++;
131  break;
132  }
133 
134  if (*(*ptr) == '.')
135  {
136  have_dp = true;
137  (*ptr)++;
138  }
139 
140  if (!isdigit((unsigned char) *(*ptr)))
141  {
142  errno = PGTYPES_NUM_BAD_NUMERIC;
143  return -1;
144  }
145 
146  while (*(*ptr))
147  {
148  if (isdigit((unsigned char) *(*ptr)))
149  {
150  dest->digits[i++] = *(*ptr)++ - '0';
151  if (!have_dp)
152  dest->weight++;
153  else
154  dest->dscale++;
155  }
156  else if (*(*ptr) == '.')
157  {
158  if (have_dp)
159  {
160  errno = PGTYPES_NUM_BAD_NUMERIC;
161  return -1;
162  }
163  have_dp = true;
164  (*ptr)++;
165  }
166  else
167  break;
168  }
169  dest->ndigits = i;
170 
171  /* Handle exponent, if any */
172  if (*(*ptr) == 'e' || *(*ptr) == 'E')
173  {
174  long exponent;
175  char *endptr;
176 
177  (*ptr)++;
178  exponent = strtol(*ptr, &endptr, 10);
179  if (endptr == (*ptr))
180  {
181  errno = PGTYPES_NUM_BAD_NUMERIC;
182  return -1;
183  }
184  (*ptr) = endptr;
185  if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
186  {
187  errno = PGTYPES_NUM_BAD_NUMERIC;
188  return -1;
189  }
190  dest->weight += (int) exponent;
191  dest->dscale -= (int) exponent;
192  if (dest->dscale < 0)
193  dest->dscale = 0;
194  }
195 
196  /* Should be nothing left but spaces */
197  while (*(*ptr))
198  {
199  if (!isspace((unsigned char) *(*ptr)))
200  {
201  errno = PGTYPES_NUM_BAD_NUMERIC;
202  return -1;
203  }
204  (*ptr)++;
205  }
206 
207  /* Strip any leading zeroes */
208  while (dest->ndigits > 0 && *(dest->digits) == 0)
209  {
210  (dest->digits)++;
211  (dest->weight)--;
212  (dest->ndigits)--;
213  }
214  if (dest->ndigits == 0)
215  dest->weight = 0;
216 
217  dest->rscale = dest->dscale;
218  return 0;
219 }
220 
221 
222 /* ----------
223  * get_str_from_var() -
224  *
225  * Convert a var to text representation (guts of numeric_out).
226  * CAUTION: var's contents may be modified by rounding!
227  * ----------
228  */
229 static char *
230 get_str_from_var(numeric *var, int dscale)
231 {
232  char *str;
233  char *cp;
234  int i;
235  int d;
236 
237  if (var->sign == NUMERIC_NAN)
238  {
239  str = (char *) pgtypes_alloc(4);
240  if (str == NULL)
241  return NULL;
242  sprintf(str, "NaN");
243  return str;
244  }
245 
246  /*
247  * Check if we must round up before printing the value and do so.
248  */
249  i = dscale + var->weight + 1;
250  if (i >= 0 && var->ndigits > i)
251  {
252  int carry = (var->digits[i] > 4) ? 1 : 0;
253 
254  var->ndigits = i;
255 
256  while (carry)
257  {
258  carry += var->digits[--i];
259  var->digits[i] = carry % 10;
260  carry /= 10;
261  }
262 
263  if (i < 0)
264  {
265  var->digits--;
266  var->ndigits++;
267  var->weight++;
268  }
269  }
270  else
271  var->ndigits = Max(0, Min(i, var->ndigits));
272 
273  /*
274  * Allocate space for the result
275  */
276  if ((str = (char *) pgtypes_alloc(Max(0, dscale) + Max(0, var->weight) + 4)) == NULL)
277  return NULL;
278  cp = str;
279 
280  /*
281  * Output a dash for negative values
282  */
283  if (var->sign == NUMERIC_NEG)
284  *cp++ = '-';
285 
286  /*
287  * Output all digits before the decimal point
288  */
289  i = Max(var->weight, 0);
290  d = 0;
291 
292  while (i >= 0)
293  {
294  if (i <= var->weight && d < var->ndigits)
295  *cp++ = var->digits[d++] + '0';
296  else
297  *cp++ = '0';
298  i--;
299  }
300 
301  /*
302  * If requested, output a decimal point and all the digits that follow it.
303  */
304  if (dscale > 0)
305  {
306  *cp++ = '.';
307  while (i >= -dscale)
308  {
309  if (i <= var->weight && d < var->ndigits)
310  *cp++ = var->digits[d++] + '0';
311  else
312  *cp++ = '0';
313  i--;
314  }
315  }
316 
317  /*
318  * terminate the string and return it
319  */
320  *cp = '\0';
321  return str;
322 }
323 
324 numeric *
325 PGTYPESnumeric_from_asc(char *str, char **endptr)
326 {
327  numeric *value = (numeric *) pgtypes_alloc(sizeof(numeric));
328  int ret;
329 
330  char *realptr;
331  char **ptr = (endptr != NULL) ? endptr : &realptr;
332 
333  if (!value)
334  return NULL;
335 
336  ret = set_var_from_str(str, ptr, value);
337  if (ret)
338  {
339  PGTYPESnumeric_free(value);
340  return NULL;
341  }
342 
343  return value;
344 }
345 
346 char *
348 {
349  numeric *numcopy = PGTYPESnumeric_new();
350  char *s;
351 
352  if (numcopy == NULL)
353  return NULL;
354 
355  if (PGTYPESnumeric_copy(num, numcopy) < 0)
356  {
357  PGTYPESnumeric_free(numcopy);
358  return NULL;
359  }
360 
361  if (dscale < 0)
362  dscale = num->dscale;
363 
364  /* get_str_from_var may change its argument */
365  s = get_str_from_var(numcopy, dscale);
366  PGTYPESnumeric_free(numcopy);
367  return s;
368 }
369 
370 /* ----------
371  * zero_var() -
372  *
373  * Set a variable to ZERO.
374  * Note: rscale and dscale are not touched.
375  * ----------
376  */
377 static void
379 {
380  digitbuf_free(var->buf);
381  var->buf = NULL;
382  var->digits = NULL;
383  var->ndigits = 0;
384  var->weight = 0; /* by convention; doesn't really matter */
385  var->sign = NUMERIC_POS; /* anything but NAN... */
386 }
387 
388 void
390 {
391  digitbuf_free(var->buf);
392  free(var);
393 }
394 
395 void
397 {
398  free(var);
399 }
400 
401 /* ----------
402  * cmp_abs() -
403  *
404  * Compare the absolute values of var1 and var2
405  * Returns: -1 for ABS(var1) < ABS(var2)
406  * 0 for ABS(var1) == ABS(var2)
407  * 1 for ABS(var1) > ABS(var2)
408  * ----------
409  */
410 static int
411 cmp_abs(numeric *var1, numeric *var2)
412 {
413  int i1 = 0;
414  int i2 = 0;
415  int w1 = var1->weight;
416  int w2 = var2->weight;
417  int stat;
418 
419  while (w1 > w2 && i1 < var1->ndigits)
420  {
421  if (var1->digits[i1++] != 0)
422  return 1;
423  w1--;
424  }
425  while (w2 > w1 && i2 < var2->ndigits)
426  {
427  if (var2->digits[i2++] != 0)
428  return -1;
429  w2--;
430  }
431 
432  if (w1 == w2)
433  {
434  while (i1 < var1->ndigits && i2 < var2->ndigits)
435  {
436  stat = var1->digits[i1++] - var2->digits[i2++];
437  if (stat)
438  {
439  if (stat > 0)
440  return 1;
441  return -1;
442  }
443  }
444  }
445 
446  while (i1 < var1->ndigits)
447  {
448  if (var1->digits[i1++] != 0)
449  return 1;
450  }
451  while (i2 < var2->ndigits)
452  {
453  if (var2->digits[i2++] != 0)
454  return -1;
455  }
456 
457  return 0;
458 }
459 
460 
461 /* ----------
462  * add_abs() -
463  *
464  * Add the absolute values of two variables into result.
465  * result might point to one of the operands without danger.
466  * ----------
467  */
468 static int
469 add_abs(numeric *var1, numeric *var2, numeric *result)
470 {
471  NumericDigit *res_buf;
472  NumericDigit *res_digits;
473  int res_ndigits;
474  int res_weight;
475  int res_rscale;
476  int res_dscale;
477  int i,
478  i1,
479  i2;
480  int carry = 0;
481 
482  /* copy these values into local vars for speed in inner loop */
483  int var1ndigits = var1->ndigits;
484  int var2ndigits = var2->ndigits;
485  NumericDigit *var1digits = var1->digits;
486  NumericDigit *var2digits = var2->digits;
487 
488  res_weight = Max(var1->weight, var2->weight) + 1;
489  res_rscale = Max(var1->rscale, var2->rscale);
490  res_dscale = Max(var1->dscale, var2->dscale);
491  res_ndigits = res_rscale + res_weight + 1;
492  if (res_ndigits <= 0)
493  res_ndigits = 1;
494 
495  if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
496  return -1;
497  res_digits = res_buf;
498 
499  i1 = res_rscale + var1->weight + 1;
500  i2 = res_rscale + var2->weight + 1;
501  for (i = res_ndigits - 1; i >= 0; i--)
502  {
503  i1--;
504  i2--;
505  if (i1 >= 0 && i1 < var1ndigits)
506  carry += var1digits[i1];
507  if (i2 >= 0 && i2 < var2ndigits)
508  carry += var2digits[i2];
509 
510  if (carry >= 10)
511  {
512  res_digits[i] = carry - 10;
513  carry = 1;
514  }
515  else
516  {
517  res_digits[i] = carry;
518  carry = 0;
519  }
520  }
521 
522  while (res_ndigits > 0 && *res_digits == 0)
523  {
524  res_digits++;
525  res_weight--;
526  res_ndigits--;
527  }
528  while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
529  res_ndigits--;
530 
531  if (res_ndigits == 0)
532  res_weight = 0;
533 
534  digitbuf_free(result->buf);
535  result->ndigits = res_ndigits;
536  result->buf = res_buf;
537  result->digits = res_digits;
538  result->weight = res_weight;
539  result->rscale = res_rscale;
540  result->dscale = res_dscale;
541 
542  return 0;
543 }
544 
545 
546 /* ----------
547  * sub_abs() -
548  *
549  * Subtract the absolute value of var2 from the absolute value of var1
550  * and store in result. result might point to one of the operands
551  * without danger.
552  *
553  * ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!!
554  * ----------
555  */
556 static int
557 sub_abs(numeric *var1, numeric *var2, numeric *result)
558 {
559  NumericDigit *res_buf;
560  NumericDigit *res_digits;
561  int res_ndigits;
562  int res_weight;
563  int res_rscale;
564  int res_dscale;
565  int i,
566  i1,
567  i2;
568  int borrow = 0;
569 
570  /* copy these values into local vars for speed in inner loop */
571  int var1ndigits = var1->ndigits;
572  int var2ndigits = var2->ndigits;
573  NumericDigit *var1digits = var1->digits;
574  NumericDigit *var2digits = var2->digits;
575 
576  res_weight = var1->weight;
577  res_rscale = Max(var1->rscale, var2->rscale);
578  res_dscale = Max(var1->dscale, var2->dscale);
579  res_ndigits = res_rscale + res_weight + 1;
580  if (res_ndigits <= 0)
581  res_ndigits = 1;
582 
583  if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
584  return -1;
585  res_digits = res_buf;
586 
587  i1 = res_rscale + var1->weight + 1;
588  i2 = res_rscale + var2->weight + 1;
589  for (i = res_ndigits - 1; i >= 0; i--)
590  {
591  i1--;
592  i2--;
593  if (i1 >= 0 && i1 < var1ndigits)
594  borrow += var1digits[i1];
595  if (i2 >= 0 && i2 < var2ndigits)
596  borrow -= var2digits[i2];
597 
598  if (borrow < 0)
599  {
600  res_digits[i] = borrow + 10;
601  borrow = -1;
602  }
603  else
604  {
605  res_digits[i] = borrow;
606  borrow = 0;
607  }
608  }
609 
610  while (res_ndigits > 0 && *res_digits == 0)
611  {
612  res_digits++;
613  res_weight--;
614  res_ndigits--;
615  }
616  while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
617  res_ndigits--;
618 
619  if (res_ndigits == 0)
620  res_weight = 0;
621 
622  digitbuf_free(result->buf);
623  result->ndigits = res_ndigits;
624  result->buf = res_buf;
625  result->digits = res_digits;
626  result->weight = res_weight;
627  result->rscale = res_rscale;
628  result->dscale = res_dscale;
629 
630  return 0;
631 }
632 
633 /* ----------
634  * add_var() -
635  *
636  * Full version of add functionality on variable level (handling signs).
637  * result might point to one of the operands too without danger.
638  * ----------
639  */
640 int
642 {
643  /*
644  * Decide on the signs of the two variables what to do
645  */
646  if (var1->sign == NUMERIC_POS)
647  {
648  if (var2->sign == NUMERIC_POS)
649  {
650  /*
651  * Both are positive result = +(ABS(var1) + ABS(var2))
652  */
653  if (add_abs(var1, var2, result) != 0)
654  return -1;
655  result->sign = NUMERIC_POS;
656  }
657  else
658  {
659  /*
660  * var1 is positive, var2 is negative Must compare absolute values
661  */
662  switch (cmp_abs(var1, var2))
663  {
664  case 0:
665  /* ----------
666  * ABS(var1) == ABS(var2)
667  * result = ZERO
668  * ----------
669  */
670  zero_var(result);
671  result->rscale = Max(var1->rscale, var2->rscale);
672  result->dscale = Max(var1->dscale, var2->dscale);
673  break;
674 
675  case 1:
676  /* ----------
677  * ABS(var1) > ABS(var2)
678  * result = +(ABS(var1) - ABS(var2))
679  * ----------
680  */
681  if (sub_abs(var1, var2, result) != 0)
682  return -1;
683  result->sign = NUMERIC_POS;
684  break;
685 
686  case -1:
687  /* ----------
688  * ABS(var1) < ABS(var2)
689  * result = -(ABS(var2) - ABS(var1))
690  * ----------
691  */
692  if (sub_abs(var2, var1, result) != 0)
693  return -1;
694  result->sign = NUMERIC_NEG;
695  break;
696  }
697  }
698  }
699  else
700  {
701  if (var2->sign == NUMERIC_POS)
702  {
703  /* ----------
704  * var1 is negative, var2 is positive
705  * Must compare absolute values
706  * ----------
707  */
708  switch (cmp_abs(var1, var2))
709  {
710  case 0:
711  /* ----------
712  * ABS(var1) == ABS(var2)
713  * result = ZERO
714  * ----------
715  */
716  zero_var(result);
717  result->rscale = Max(var1->rscale, var2->rscale);
718  result->dscale = Max(var1->dscale, var2->dscale);
719  break;
720 
721  case 1:
722  /* ----------
723  * ABS(var1) > ABS(var2)
724  * result = -(ABS(var1) - ABS(var2))
725  * ----------
726  */
727  if (sub_abs(var1, var2, result) != 0)
728  return -1;
729  result->sign = NUMERIC_NEG;
730  break;
731 
732  case -1:
733  /* ----------
734  * ABS(var1) < ABS(var2)
735  * result = +(ABS(var2) - ABS(var1))
736  * ----------
737  */
738  if (sub_abs(var2, var1, result) != 0)
739  return -1;
740  result->sign = NUMERIC_POS;
741  break;
742  }
743  }
744  else
745  {
746  /* ----------
747  * Both are negative
748  * result = -(ABS(var1) + ABS(var2))
749  * ----------
750  */
751  if (add_abs(var1, var2, result) != 0)
752  return -1;
753  result->sign = NUMERIC_NEG;
754  }
755  }
756 
757  return 0;
758 }
759 
760 
761 /* ----------
762  * sub_var() -
763  *
764  * Full version of sub functionality on variable level (handling signs).
765  * result might point to one of the operands too without danger.
766  * ----------
767  */
768 int
770 {
771  /*
772  * Decide on the signs of the two variables what to do
773  */
774  if (var1->sign == NUMERIC_POS)
775  {
776  if (var2->sign == NUMERIC_NEG)
777  {
778  /* ----------
779  * var1 is positive, var2 is negative
780  * result = +(ABS(var1) + ABS(var2))
781  * ----------
782  */
783  if (add_abs(var1, var2, result) != 0)
784  return -1;
785  result->sign = NUMERIC_POS;
786  }
787  else
788  {
789  /* ----------
790  * Both are positive
791  * Must compare absolute values
792  * ----------
793  */
794  switch (cmp_abs(var1, var2))
795  {
796  case 0:
797  /* ----------
798  * ABS(var1) == ABS(var2)
799  * result = ZERO
800  * ----------
801  */
802  zero_var(result);
803  result->rscale = Max(var1->rscale, var2->rscale);
804  result->dscale = Max(var1->dscale, var2->dscale);
805  break;
806 
807  case 1:
808  /* ----------
809  * ABS(var1) > ABS(var2)
810  * result = +(ABS(var1) - ABS(var2))
811  * ----------
812  */
813  if (sub_abs(var1, var2, result) != 0)
814  return -1;
815  result->sign = NUMERIC_POS;
816  break;
817 
818  case -1:
819  /* ----------
820  * ABS(var1) < ABS(var2)
821  * result = -(ABS(var2) - ABS(var1))
822  * ----------
823  */
824  if (sub_abs(var2, var1, result) != 0)
825  return -1;
826  result->sign = NUMERIC_NEG;
827  break;
828  }
829  }
830  }
831  else
832  {
833  if (var2->sign == NUMERIC_NEG)
834  {
835  /* ----------
836  * Both are negative
837  * Must compare absolute values
838  * ----------
839  */
840  switch (cmp_abs(var1, var2))
841  {
842  case 0:
843  /* ----------
844  * ABS(var1) == ABS(var2)
845  * result = ZERO
846  * ----------
847  */
848  zero_var(result);
849  result->rscale = Max(var1->rscale, var2->rscale);
850  result->dscale = Max(var1->dscale, var2->dscale);
851  break;
852 
853  case 1:
854  /* ----------
855  * ABS(var1) > ABS(var2)
856  * result = -(ABS(var1) - ABS(var2))
857  * ----------
858  */
859  if (sub_abs(var1, var2, result) != 0)
860  return -1;
861  result->sign = NUMERIC_NEG;
862  break;
863 
864  case -1:
865  /* ----------
866  * ABS(var1) < ABS(var2)
867  * result = +(ABS(var2) - ABS(var1))
868  * ----------
869  */
870  if (sub_abs(var2, var1, result) != 0)
871  return -1;
872  result->sign = NUMERIC_POS;
873  break;
874  }
875  }
876  else
877  {
878  /* ----------
879  * var1 is negative, var2 is positive
880  * result = -(ABS(var1) + ABS(var2))
881  * ----------
882  */
883  if (add_abs(var1, var2, result) != 0)
884  return -1;
885  result->sign = NUMERIC_NEG;
886  }
887  }
888 
889  return 0;
890 }
891 
892 /* ----------
893  * mul_var() -
894  *
895  * Multiplication on variable level. Product of var1 * var2 is stored
896  * in result. Accuracy of result is determined by global_rscale.
897  * ----------
898  */
899 int
901 {
902  NumericDigit *res_buf;
903  NumericDigit *res_digits;
904  int res_ndigits;
905  int res_weight;
906  int res_sign;
907  int i,
908  ri,
909  i1,
910  i2;
911  long sum = 0;
912  int global_rscale = var1->rscale + var2->rscale;
913 
914  res_weight = var1->weight + var2->weight + 2;
915  res_ndigits = var1->ndigits + var2->ndigits + 1;
916  if (var1->sign == var2->sign)
917  res_sign = NUMERIC_POS;
918  else
919  res_sign = NUMERIC_NEG;
920 
921  if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
922  return -1;
923  res_digits = res_buf;
924  memset(res_digits, 0, res_ndigits);
925 
926  ri = res_ndigits;
927  for (i1 = var1->ndigits - 1; i1 >= 0; i1--)
928  {
929  sum = 0;
930  i = --ri;
931 
932  for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
933  {
934  sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
935  res_digits[i--] = sum % 10;
936  sum /= 10;
937  }
938  res_digits[i] = sum;
939  }
940 
941  i = res_weight + global_rscale + 2;
942  if (i >= 0 && i < res_ndigits)
943  {
944  sum = (res_digits[i] > 4) ? 1 : 0;
945  res_ndigits = i;
946  i--;
947  while (sum)
948  {
949  sum += res_digits[i];
950  res_digits[i--] = sum % 10;
951  sum /= 10;
952  }
953  }
954 
955  while (res_ndigits > 0 && *res_digits == 0)
956  {
957  res_digits++;
958  res_weight--;
959  res_ndigits--;
960  }
961  while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
962  res_ndigits--;
963 
964  if (res_ndigits == 0)
965  {
966  res_sign = NUMERIC_POS;
967  res_weight = 0;
968  }
969 
970  digitbuf_free(result->buf);
971  result->buf = res_buf;
972  result->digits = res_digits;
973  result->ndigits = res_ndigits;
974  result->weight = res_weight;
975  result->rscale = global_rscale;
976  result->sign = res_sign;
977  result->dscale = var1->dscale + var2->dscale;
978 
979  return 0;
980 }
981 
982 /*
983  * Default scale selection for division
984  *
985  * Returns the appropriate display scale for the division result,
986  * and sets global_rscale to the result scale to use during div_var.
987  *
988  * Note that this must be called before div_var.
989  */
990 static int
991 select_div_scale(numeric *var1, numeric *var2, int *rscale)
992 {
993  int weight1,
994  weight2,
995  qweight,
996  i;
997  NumericDigit firstdigit1,
998  firstdigit2;
999  int res_dscale;
1000 
1001  /*
1002  * The result scale of a division isn't specified in any SQL standard. For
1003  * PostgreSQL we select a display scale that will give at least
1004  * NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a
1005  * result no less accurate than float8; but use a scale not less than
1006  * either input's display scale.
1007  */
1008 
1009  /* Get the actual (normalized) weight and first digit of each input */
1010 
1011  weight1 = 0; /* values to use if var1 is zero */
1012  firstdigit1 = 0;
1013  for (i = 0; i < var1->ndigits; i++)
1014  {
1015  firstdigit1 = var1->digits[i];
1016  if (firstdigit1 != 0)
1017  {
1018  weight1 = var1->weight - i;
1019  break;
1020  }
1021  }
1022 
1023  weight2 = 0; /* values to use if var2 is zero */
1024  firstdigit2 = 0;
1025  for (i = 0; i < var2->ndigits; i++)
1026  {
1027  firstdigit2 = var2->digits[i];
1028  if (firstdigit2 != 0)
1029  {
1030  weight2 = var2->weight - i;
1031  break;
1032  }
1033  }
1034 
1035  /*
1036  * Estimate weight of quotient. If the two first digits are equal, we
1037  * can't be sure, but assume that var1 is less than var2.
1038  */
1039  qweight = weight1 - weight2;
1040  if (firstdigit1 <= firstdigit2)
1041  qweight--;
1042 
1043  /* Select display scale */
1044  res_dscale = NUMERIC_MIN_SIG_DIGITS - qweight;
1045  res_dscale = Max(res_dscale, var1->dscale);
1046  res_dscale = Max(res_dscale, var2->dscale);
1047  res_dscale = Max(res_dscale, NUMERIC_MIN_DISPLAY_SCALE);
1048  res_dscale = Min(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1049 
1050  /* Select result scale */
1051  *rscale = res_dscale + 4;
1052 
1053  return res_dscale;
1054 }
1055 
1056 int
1058 {
1059  NumericDigit *res_digits;
1060  int res_ndigits;
1061  int res_sign;
1062  int res_weight;
1063  numeric dividend;
1064  numeric divisor[10];
1065  int ndigits_tmp;
1066  int weight_tmp;
1067  int rscale_tmp;
1068  int ri;
1069  int i;
1070  long guess;
1071  long first_have;
1072  long first_div;
1073  int first_nextdigit;
1074  int stat = 0;
1075  int rscale;
1076  int res_dscale = select_div_scale(var1, var2, &rscale);
1077  int err = -1;
1078  NumericDigit *tmp_buf;
1079 
1080  /*
1081  * First of all division by zero check
1082  */
1083  ndigits_tmp = var2->ndigits + 1;
1084  if (ndigits_tmp == 1)
1085  {
1086  errno = PGTYPES_NUM_DIVIDE_ZERO;
1087  return -1;
1088  }
1089 
1090  /*
1091  * Determine the result sign, weight and number of digits to calculate
1092  */
1093  if (var1->sign == var2->sign)
1094  res_sign = NUMERIC_POS;
1095  else
1096  res_sign = NUMERIC_NEG;
1097  res_weight = var1->weight - var2->weight + 1;
1098  res_ndigits = rscale + res_weight;
1099  if (res_ndigits <= 0)
1100  res_ndigits = 1;
1101 
1102  /*
1103  * Now result zero check
1104  */
1105  if (var1->ndigits == 0)
1106  {
1107  zero_var(result);
1108  result->rscale = rscale;
1109  return 0;
1110  }
1111 
1112  /*
1113  * Initialize local variables
1114  */
1115  init_var(&dividend);
1116  for (i = 1; i < 10; i++)
1117  init_var(&divisor[i]);
1118 
1119  /*
1120  * Make a copy of the divisor which has one leading zero digit
1121  */
1122  divisor[1].ndigits = ndigits_tmp;
1123  divisor[1].rscale = var2->ndigits;
1124  divisor[1].sign = NUMERIC_POS;
1125  divisor[1].buf = digitbuf_alloc(ndigits_tmp);
1126  if (divisor[1].buf == NULL)
1127  goto done;
1128  divisor[1].digits = divisor[1].buf;
1129  divisor[1].digits[0] = 0;
1130  memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
1131 
1132  /*
1133  * Make a copy of the dividend
1134  */
1135  dividend.ndigits = var1->ndigits;
1136  dividend.weight = 0;
1137  dividend.rscale = var1->ndigits;
1138  dividend.sign = NUMERIC_POS;
1139  dividend.buf = digitbuf_alloc(var1->ndigits);
1140  if (dividend.buf == NULL)
1141  goto done;
1142  dividend.digits = dividend.buf;
1143  memcpy(dividend.digits, var1->digits, var1->ndigits);
1144 
1145  /*
1146  * Setup the result. Do the allocation in a temporary buffer first, so we
1147  * don't free result->buf unless we have successfully allocated a buffer
1148  * to replace it with.
1149  */
1150  tmp_buf = digitbuf_alloc(res_ndigits + 2);
1151  if (tmp_buf == NULL)
1152  goto done;
1153  digitbuf_free(result->buf);
1154  result->buf = tmp_buf;
1155  res_digits = result->buf;
1156  result->digits = res_digits;
1157  result->ndigits = res_ndigits;
1158  result->weight = res_weight;
1159  result->rscale = rscale;
1160  result->sign = res_sign;
1161  res_digits[0] = 0;
1162 
1163  first_div = divisor[1].digits[1] * 10;
1164  if (ndigits_tmp > 2)
1165  first_div += divisor[1].digits[2];
1166 
1167  first_have = 0;
1168  first_nextdigit = 0;
1169 
1170  weight_tmp = 1;
1171  rscale_tmp = divisor[1].rscale;
1172 
1173  for (ri = 0; ri <= res_ndigits; ri++)
1174  {
1175  first_have = first_have * 10;
1176  if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1177  first_have += dividend.digits[first_nextdigit];
1178  first_nextdigit++;
1179 
1180  guess = (first_have * 10) / first_div + 1;
1181  if (guess > 9)
1182  guess = 9;
1183 
1184  while (guess > 0)
1185  {
1186  if (divisor[guess].buf == NULL)
1187  {
1188  int i;
1189  long sum = 0;
1190 
1191  memcpy(&divisor[guess], &divisor[1], sizeof(numeric));
1192  divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);
1193  if (divisor[guess].buf == NULL)
1194  goto done;
1195  divisor[guess].digits = divisor[guess].buf;
1196  for (i = divisor[1].ndigits - 1; i >= 0; i--)
1197  {
1198  sum += divisor[1].digits[i] * guess;
1199  divisor[guess].digits[i] = sum % 10;
1200  sum /= 10;
1201  }
1202  }
1203 
1204  divisor[guess].weight = weight_tmp;
1205  divisor[guess].rscale = rscale_tmp;
1206 
1207  stat = cmp_abs(&dividend, &divisor[guess]);
1208  if (stat >= 0)
1209  break;
1210 
1211  guess--;
1212  }
1213 
1214  res_digits[ri + 1] = guess;
1215  if (stat == 0)
1216  {
1217  ri++;
1218  break;
1219  }
1220 
1221  weight_tmp--;
1222  rscale_tmp++;
1223 
1224  if (guess == 0)
1225  continue;
1226 
1227  if (sub_abs(&dividend, &divisor[guess], &dividend) != 0)
1228  goto done;
1229 
1230  first_nextdigit = dividend.weight - weight_tmp;
1231  first_have = 0;
1232  if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1233  first_have = dividend.digits[first_nextdigit];
1234  first_nextdigit++;
1235  }
1236 
1237  result->ndigits = ri + 1;
1238  if (ri == res_ndigits + 1)
1239  {
1240  int carry = (res_digits[ri] > 4) ? 1 : 0;
1241 
1242  result->ndigits = ri;
1243  res_digits[ri] = 0;
1244 
1245  while (carry && ri > 0)
1246  {
1247  carry += res_digits[--ri];
1248  res_digits[ri] = carry % 10;
1249  carry /= 10;
1250  }
1251  }
1252 
1253  while (result->ndigits > 0 && *(result->digits) == 0)
1254  {
1255  (result->digits)++;
1256  (result->weight)--;
1257  (result->ndigits)--;
1258  }
1259  while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)
1260  (result->ndigits)--;
1261  if (result->ndigits == 0)
1262  result->sign = NUMERIC_POS;
1263 
1264  result->dscale = res_dscale;
1265  err = 0; /* if we've made it this far, return success */
1266 
1267 done:
1268 
1269  /*
1270  * Tidy up
1271  */
1272  if (dividend.buf != NULL)
1273  digitbuf_free(dividend.buf);
1274 
1275  for (i = 1; i < 10; i++)
1276  {
1277  if (divisor[i].buf != NULL)
1278  digitbuf_free(divisor[i].buf);
1279  }
1280 
1281  return err;
1282 }
1283 
1284 
1285 int
1287 {
1288  /* use cmp_abs function to calculate the result */
1289 
1290  /* both are positive: normal comparison with cmp_abs */
1291  if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_POS)
1292  return cmp_abs(var1, var2);
1293 
1294  /* both are negative: return the inverse of the normal comparison */
1295  if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_NEG)
1296  {
1297  /*
1298  * instead of inverting the result, we invert the parameter ordering
1299  */
1300  return cmp_abs(var2, var1);
1301  }
1302 
1303  /* one is positive, one is negative: trivial */
1304  if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_NEG)
1305  return 1;
1306  if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_POS)
1307  return -1;
1308 
1309  errno = PGTYPES_NUM_BAD_NUMERIC;
1310  return INT_MAX;
1311 
1312 }
1313 
1314 int
1315 PGTYPESnumeric_from_int(signed int int_val, numeric *var)
1316 {
1317  /* implicit conversion */
1318  signed long int long_int = int_val;
1319 
1320  return PGTYPESnumeric_from_long(long_int, var);
1321 }
1322 
1323 int
1324 PGTYPESnumeric_from_long(signed long int long_val, numeric *var)
1325 {
1326  /* calculate the size of the long int number */
1327  /* a number n needs log_10 n digits */
1328 
1329  /*
1330  * however we multiply by 10 each time and compare instead of calculating
1331  * the logarithm
1332  */
1333 
1334  int size = 0;
1335  int i;
1336  signed long int abs_long_val = long_val;
1337  signed long int extract;
1338  signed long int reach_limit;
1339 
1340  if (abs_long_val < 0)
1341  {
1342  abs_long_val *= -1;
1343  var->sign = NUMERIC_NEG;
1344  }
1345  else
1346  var->sign = NUMERIC_POS;
1347 
1348  reach_limit = 1;
1349  do
1350  {
1351  size++;
1352  reach_limit *= 10;
1353  } while (reach_limit - 1 < abs_long_val && reach_limit <= LONG_MAX / 10);
1354 
1355  if (reach_limit > LONG_MAX / 10)
1356  {
1357  /* add the first digit and a .0 */
1358  size += 2;
1359  }
1360  else
1361  {
1362  /* always add a .0 */
1363  size++;
1364  reach_limit /= 10;
1365  }
1366 
1367  if (alloc_var(var, size) < 0)
1368  return -1;
1369 
1370  var->rscale = 1;
1371  var->dscale = 1;
1372  var->weight = size - 2;
1373 
1374  i = 0;
1375  do
1376  {
1377  extract = abs_long_val - (abs_long_val % reach_limit);
1378  var->digits[i] = extract / reach_limit;
1379  abs_long_val -= extract;
1380  i++;
1381  reach_limit /= 10;
1382 
1383  /*
1384  * we can abandon if abs_long_val reaches 0, because the memory is
1385  * initialized properly and filled with '0', so converting 10000 in
1386  * only one step is no problem
1387  */
1388  } while (abs_long_val > 0);
1389 
1390  return 0;
1391 }
1392 
1393 int
1395 {
1396  int i;
1397 
1398  if (dst == NULL)
1399  return -1;
1400  zero_var(dst);
1401 
1402  dst->weight = src->weight;
1403  dst->rscale = src->rscale;
1404  dst->dscale = src->dscale;
1405  dst->sign = src->sign;
1406 
1407  if (alloc_var(dst, src->ndigits) != 0)
1408  return -1;
1409 
1410  for (i = 0; i < src->ndigits; i++)
1411  dst->digits[i] = src->digits[i];
1412 
1413  return 0;
1414 }
1415 
1416 int
1418 {
1419  char buffer[DBL_DIG + 100];
1420  numeric *tmp;
1421  int i;
1422 
1423  if (sprintf(buffer, "%.*g", DBL_DIG, d) <= 0)
1424  return -1;
1425 
1426  if ((tmp = PGTYPESnumeric_from_asc(buffer, NULL)) == NULL)
1427  return -1;
1428  i = PGTYPESnumeric_copy(tmp, dst);
1429  PGTYPESnumeric_free(tmp);
1430  if (i != 0)
1431  return -1;
1432 
1433  errno = 0;
1434  return 0;
1435 }
1436 
1437 static int
1439 {
1440  char *tmp;
1441  double val;
1442  char *endptr;
1443  numeric *varcopy = PGTYPESnumeric_new();
1444 
1445  if (varcopy == NULL)
1446  return -1;
1447 
1448  if (PGTYPESnumeric_copy(var, varcopy) < 0)
1449  {
1450  PGTYPESnumeric_free(varcopy);
1451  return -1;
1452  }
1453 
1454  tmp = get_str_from_var(varcopy, varcopy->dscale);
1455  PGTYPESnumeric_free(varcopy);
1456 
1457  if (tmp == NULL)
1458  return -1;
1459 
1460  /*
1461  * strtod does not reset errno to 0 in case of success.
1462  */
1463  errno = 0;
1464  val = strtod(tmp, &endptr);
1465  if (errno == ERANGE)
1466  {
1467  free(tmp);
1468  if (val == 0)
1469  errno = PGTYPES_NUM_UNDERFLOW;
1470  else
1471  errno = PGTYPES_NUM_OVERFLOW;
1472  return -1;
1473  }
1474 
1475  /* can't free tmp yet, endptr points still into it */
1476  if (*endptr != '\0')
1477  {
1478  /* shouldn't happen ... */
1479  free(tmp);
1480  errno = PGTYPES_NUM_BAD_NUMERIC;
1481  return -1;
1482  }
1483  free(tmp);
1484  *dp = val;
1485  return 0;
1486 }
1487 
1488 int
1490 {
1491  double tmp;
1492 
1493  if (numericvar_to_double(nv, &tmp) != 0)
1494  return -1;
1495  *dp = tmp;
1496  return 0;
1497 }
1498 
1499 int
1501 {
1502  long l;
1503  int i;
1504 
1505  if ((i = PGTYPESnumeric_to_long(nv, &l)) != 0)
1506  return i;
1507 
1508  if (l < -INT_MAX || l > INT_MAX)
1509  {
1510  errno = PGTYPES_NUM_OVERFLOW;
1511  return -1;
1512  }
1513 
1514  *ip = (int) l;
1515  return 0;
1516 }
1517 
1518 int
1520 {
1521  char *s = PGTYPESnumeric_to_asc(nv, 0);
1522  char *endptr;
1523 
1524  if (s == NULL)
1525  return -1;
1526 
1527  errno = 0;
1528  *lp = strtol(s, &endptr, 10);
1529  if (endptr == s)
1530  {
1531  /* this should not happen actually */
1532  free(s);
1533  return -1;
1534  }
1535  free(s);
1536  if (errno == ERANGE)
1537  {
1538  if (*lp == LONG_MIN)
1539  errno = PGTYPES_NUM_UNDERFLOW;
1540  else
1541  errno = PGTYPES_NUM_OVERFLOW;
1542  return -1;
1543  }
1544  return 0;
1545 }
1546 
1547 int
1549 {
1550  int i;
1551 
1552  if (src->ndigits > DECSIZE)
1553  {
1554  errno = PGTYPES_NUM_OVERFLOW;
1555  return -1;
1556  }
1557 
1558  dst->weight = src->weight;
1559  dst->rscale = src->rscale;
1560  dst->dscale = src->dscale;
1561  dst->sign = src->sign;
1562  dst->ndigits = src->ndigits;
1563 
1564  for (i = 0; i < src->ndigits; i++)
1565  dst->digits[i] = src->digits[i];
1566 
1567  return 0;
1568 }
1569 
1570 int
1572 {
1573  int i;
1574 
1575  zero_var(dst);
1576 
1577  dst->weight = src->weight;
1578  dst->rscale = src->rscale;
1579  dst->dscale = src->dscale;
1580  dst->sign = src->sign;
1581 
1582  if (alloc_var(dst, src->ndigits) != 0)
1583  return -1;
1584 
1585  for (i = 0; i < src->ndigits; i++)
1586  dst->digits[i] = src->digits[i];
1587 
1588  return 0;
1589 }
#define NUMERIC_MIN_SIG_DIGITS
Definition: numeric.h:39
numeric * PGTYPESnumeric_new(void)
Definition: numeric.c:46
int PGTYPESnumeric_cmp(numeric *var1, numeric *var2)
Definition: numeric.c:1286
static int add_abs(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:469
void PGTYPESdecimal_free(decimal *var)
Definition: numeric.c:396
#define PGTYPES_NUM_DIVIDE_ZERO
Definition: pgtypes_error.h:5
#define NUMERIC_POS
Definition: numeric.c:167
void PGTYPESnumeric_free(numeric *var)
Definition: numeric.c:389
static void zero_var(numeric *var)
Definition: numeric.c:378
NumericDigit * buf
#define Min(x, y)
Definition: numeric.c:14
#define NUMERIC_NEG
Definition: numeric.c:168
#define sprintf
Definition: port.h:217
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
int PGTYPESnumeric_div(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:1057
int PGTYPESnumeric_copy(numeric *src, numeric *dst)
Definition: numeric.c:1394
#define digitbuf_alloc(size)
Definition: numeric.c:18
char * pgtypes_alloc(long size)
Definition: common.c:10
static int numericvar_to_double(numeric *var, double *dp)
Definition: numeric.c:1438
NumericDigit * digits
static char * buf
Definition: pg_test_fsync.c:68
int16 NumericDigit
Definition: numeric.c:103
int PGTYPESnumeric_to_double(numeric *nv, double *dp)
Definition: numeric.c:1489
NumericDigit digits[DECSIZE]
#define NUMERIC_MIN_DISPLAY_SCALE
Definition: numeric.h:30
#define NUMERIC_NAN
Definition: numeric.c:199
int PGTYPESnumeric_from_int(signed int int_val, numeric *var)
Definition: numeric.c:1315
int PGTYPESnumeric_mul(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:900
#define PGTYPES_NUM_OVERFLOW
Definition: pgtypes_error.h:3
decimal * PGTYPESdecimal_new(void)
Definition: numeric.c:63
#define PGTYPES_NUM_UNDERFLOW
Definition: pgtypes_error.h:6
static int cmp_abs(numeric *var1, numeric *var2)
Definition: numeric.c:411
int PGTYPESnumeric_from_decimal(decimal *src, numeric *dst)
Definition: numeric.c:1571
static int select_div_scale(numeric *var1, numeric *var2, int *rscale)
Definition: numeric.c:991
static int alloc_var(numeric *var, int ndigits)
Definition: numeric.c:33
static struct @143 value
#define free(a)
Definition: header.h:65
static int set_var_from_str(char *str, char **ptr, numeric *dest)
Definition: numeric.c:82
static char * get_str_from_var(numeric *var, int dscale)
Definition: numeric.c:230
static int sub_abs(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:557
#define DECSIZE
#define PGTYPES_NUM_BAD_NUMERIC
Definition: pgtypes_error.h:4
#define digitbuf_free(buf)
Definition: numeric.c:19
int PGTYPESnumeric_sub(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:769
numeric * PGTYPESnumeric_from_asc(char *str, char **endptr)
Definition: numeric.c:325
int PGTYPESnumeric_add(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:641
int PGTYPESnumeric_from_long(signed long int long_val, numeric *var)
Definition: numeric.c:1324
char * PGTYPESnumeric_to_asc(numeric *num, int dscale)
Definition: numeric.c:347
int PGTYPESnumeric_from_double(double d, numeric *dst)
Definition: numeric.c:1417
#define init_var(v)
Definition: numeric.c:16
int PGTYPESnumeric_to_decimal(numeric *src, decimal *dst)
Definition: numeric.c:1548
int i
int PGTYPESnumeric_to_long(numeric *nv, long *lp)
Definition: numeric.c:1519
#define Max(x, y)
Definition: numeric.c:13
#define NUMERIC_MAX_DISPLAY_SCALE
Definition: numeric.h:29
long val
Definition: informix.c:664
int PGTYPESnumeric_to_int(numeric *nv, int *ip)
Definition: numeric.c:1500
#define stat
Definition: win32_port.h:275
int digits
Definition: informix.c:666