PostgreSQL Source Code  git master
numeric.c File Reference
#include "postgres_fe.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include "pgtypes_error.h"
#include "pgtypes_numeric.h"
#include "pgtypeslib_extern.h"
Include dependency graph for numeric.c:

Go to the source code of this file.

Macros

#define Max(x, y)   ((x) > (y) ? (x) : (y))
 
#define Min(x, y)   ((x) < (y) ? (x) : (y))
 
#define init_var(v)   memset(v,0,sizeof(numeric))
 
#define digitbuf_alloc(size)   ((NumericDigit *) pgtypes_alloc(size))
 
#define digitbuf_free(buf)   free(buf)
 

Functions

static int alloc_var (numeric *var, int ndigits)
 
numericPGTYPESnumeric_new (void)
 
decimalPGTYPESdecimal_new (void)
 
static int set_var_from_str (char *str, char **ptr, numeric *dest)
 
static char * get_str_from_var (numeric *var, int dscale)
 
numericPGTYPESnumeric_from_asc (char *str, char **endptr)
 
char * PGTYPESnumeric_to_asc (numeric *num, int dscale)
 
static void zero_var (numeric *var)
 
void PGTYPESnumeric_free (numeric *var)
 
void PGTYPESdecimal_free (decimal *var)
 
static int cmp_abs (numeric *var1, numeric *var2)
 
static int add_abs (numeric *var1, numeric *var2, numeric *result)
 
static int sub_abs (numeric *var1, numeric *var2, numeric *result)
 
int PGTYPESnumeric_add (numeric *var1, numeric *var2, numeric *result)
 
int PGTYPESnumeric_sub (numeric *var1, numeric *var2, numeric *result)
 
int PGTYPESnumeric_mul (numeric *var1, numeric *var2, numeric *result)
 
static int select_div_scale (numeric *var1, numeric *var2, int *rscale)
 
int PGTYPESnumeric_div (numeric *var1, numeric *var2, numeric *result)
 
int PGTYPESnumeric_cmp (numeric *var1, numeric *var2)
 
int PGTYPESnumeric_from_int (signed int int_val, numeric *var)
 
int PGTYPESnumeric_from_long (signed long int long_val, numeric *var)
 
int PGTYPESnumeric_copy (numeric *src, numeric *dst)
 
int PGTYPESnumeric_from_double (double d, numeric *dst)
 
static int numericvar_to_double (numeric *var, double *dp)
 
int PGTYPESnumeric_to_double (numeric *nv, double *dp)
 
int PGTYPESnumeric_to_int (numeric *nv, int *ip)
 
int PGTYPESnumeric_to_long (numeric *nv, long *lp)
 
int PGTYPESnumeric_to_decimal (numeric *src, decimal *dst)
 
int PGTYPESnumeric_from_decimal (decimal *src, numeric *dst)
 

Macro Definition Documentation

◆ digitbuf_alloc

#define digitbuf_alloc (   size)    ((NumericDigit *) pgtypes_alloc(size))

Definition at line 18 of file numeric.c.

◆ digitbuf_free

#define digitbuf_free (   buf)    free(buf)

Definition at line 19 of file numeric.c.

◆ init_var

#define init_var (   v)    memset(v,0,sizeof(numeric))

Definition at line 16 of file numeric.c.

◆ Max

#define Max (   x,
  y 
)    ((x) > (y) ? (x) : (y))

Definition at line 13 of file numeric.c.

◆ Min

#define Min (   x,
  y 
)    ((x) < (y) ? (x) : (y))

Definition at line 14 of file numeric.c.

Function Documentation

◆ add_abs()

static int add_abs ( numeric var1,
numeric var2,
numeric result 
)
static

Definition at line 465 of file numeric.c.

466 {
467  NumericDigit *res_buf;
468  NumericDigit *res_digits;
469  int res_ndigits;
470  int res_weight;
471  int res_rscale;
472  int res_dscale;
473  int i,
474  i1,
475  i2;
476  int carry = 0;
477 
478  /* copy these values into local vars for speed in inner loop */
479  int var1ndigits = var1->ndigits;
480  int var2ndigits = var2->ndigits;
481  NumericDigit *var1digits = var1->digits;
482  NumericDigit *var2digits = var2->digits;
483 
484  res_weight = Max(var1->weight, var2->weight) + 1;
485  res_rscale = Max(var1->rscale, var2->rscale);
486  res_dscale = Max(var1->dscale, var2->dscale);
487  res_ndigits = res_rscale + res_weight + 1;
488  if (res_ndigits <= 0)
489  res_ndigits = 1;
490 
491  if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
492  return -1;
493  res_digits = res_buf;
494 
495  i1 = res_rscale + var1->weight + 1;
496  i2 = res_rscale + var2->weight + 1;
497  for (i = res_ndigits - 1; i >= 0; i--)
498  {
499  i1--;
500  i2--;
501  if (i1 >= 0 && i1 < var1ndigits)
502  carry += var1digits[i1];
503  if (i2 >= 0 && i2 < var2ndigits)
504  carry += var2digits[i2];
505 
506  if (carry >= 10)
507  {
508  res_digits[i] = carry - 10;
509  carry = 1;
510  }
511  else
512  {
513  res_digits[i] = carry;
514  carry = 0;
515  }
516  }
517 
518  while (res_ndigits > 0 && *res_digits == 0)
519  {
520  res_digits++;
521  res_weight--;
522  res_ndigits--;
523  }
524  while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
525  res_ndigits--;
526 
527  if (res_ndigits == 0)
528  res_weight = 0;
529 
530  digitbuf_free(result->buf);
531  result->ndigits = res_ndigits;
532  result->buf = res_buf;
533  result->digits = res_digits;
534  result->weight = res_weight;
535  result->rscale = res_rscale;
536  result->dscale = res_dscale;
537 
538  return 0;
539 }
int16 NumericDigit
Definition: numeric.c:102
#define digitbuf_free(buf)
Definition: numeric.c:19
#define digitbuf_alloc(size)
Definition: numeric.c:18
#define Max(x, y)
Definition: numeric.c:13
int i
Definition: isn.c:73
NumericDigit * digits
NumericDigit * buf

References numeric::buf, digitbuf_alloc, digitbuf_free, numeric::digits, numeric::dscale, i, Max, numeric::ndigits, numeric::rscale, and numeric::weight.

Referenced by PGTYPESnumeric_add(), and PGTYPESnumeric_sub().

◆ alloc_var()

static int alloc_var ( numeric var,
int  ndigits 
)
static

Definition at line 29 of file numeric.c.

30 {
31  digitbuf_free(var->buf);
32  var->buf = digitbuf_alloc(ndigits + 1);
33  if (var->buf == NULL)
34  return -1;
35  var->buf[0] = 0;
36  var->digits = var->buf + 1;
37  var->ndigits = ndigits;
38  return 0;
39 }

References numeric::buf, digitbuf_alloc, digitbuf_free, numeric::digits, and numeric::ndigits.

Referenced by PGTYPESnumeric_copy(), PGTYPESnumeric_from_decimal(), PGTYPESnumeric_from_long(), PGTYPESnumeric_new(), and set_var_from_str().

◆ cmp_abs()

static int cmp_abs ( numeric var1,
numeric var2 
)
static

Definition at line 407 of file numeric.c.

408 {
409  int i1 = 0;
410  int i2 = 0;
411  int w1 = var1->weight;
412  int w2 = var2->weight;
413  int stat;
414 
415  while (w1 > w2 && i1 < var1->ndigits)
416  {
417  if (var1->digits[i1++] != 0)
418  return 1;
419  w1--;
420  }
421  while (w2 > w1 && i2 < var2->ndigits)
422  {
423  if (var2->digits[i2++] != 0)
424  return -1;
425  w2--;
426  }
427 
428  if (w1 == w2)
429  {
430  while (i1 < var1->ndigits && i2 < var2->ndigits)
431  {
432  stat = var1->digits[i1++] - var2->digits[i2++];
433  if (stat)
434  {
435  if (stat > 0)
436  return 1;
437  return -1;
438  }
439  }
440  }
441 
442  while (i1 < var1->ndigits)
443  {
444  if (var1->digits[i1++] != 0)
445  return 1;
446  }
447  while (i2 < var2->ndigits)
448  {
449  if (var2->digits[i2++] != 0)
450  return -1;
451  }
452 
453  return 0;
454 }
#define stat
Definition: win32_port.h:283

References numeric::digits, stat, and numeric::weight.

Referenced by PGTYPESnumeric_add(), PGTYPESnumeric_cmp(), PGTYPESnumeric_div(), and PGTYPESnumeric_sub().

◆ get_str_from_var()

static char* get_str_from_var ( numeric var,
int  dscale 
)
static

Definition at line 226 of file numeric.c.

227 {
228  char *str;
229  char *cp;
230  int i;
231  int d;
232 
233  if (var->sign == NUMERIC_NAN)
234  {
235  str = (char *) pgtypes_alloc(4);
236  if (str == NULL)
237  return NULL;
238  sprintf(str, "NaN");
239  return str;
240  }
241 
242  /*
243  * Check if we must round up before printing the value and do so.
244  */
245  i = dscale + var->weight + 1;
246  if (i >= 0 && var->ndigits > i)
247  {
248  int carry = (var->digits[i] > 4) ? 1 : 0;
249 
250  var->ndigits = i;
251 
252  while (carry)
253  {
254  carry += var->digits[--i];
255  var->digits[i] = carry % 10;
256  carry /= 10;
257  }
258 
259  if (i < 0)
260  {
261  var->digits--;
262  var->ndigits++;
263  var->weight++;
264  }
265  }
266  else
267  var->ndigits = Max(0, Min(i, var->ndigits));
268 
269  /*
270  * Allocate space for the result
271  */
272  if ((str = (char *) pgtypes_alloc(Max(0, dscale) + Max(0, var->weight) + 4)) == NULL)
273  return NULL;
274  cp = str;
275 
276  /*
277  * Output a dash for negative values
278  */
279  if (var->sign == NUMERIC_NEG)
280  *cp++ = '-';
281 
282  /*
283  * Output all digits before the decimal point
284  */
285  i = Max(var->weight, 0);
286  d = 0;
287 
288  while (i >= 0)
289  {
290  if (i <= var->weight && d < var->ndigits)
291  *cp++ = var->digits[d++] + '0';
292  else
293  *cp++ = '0';
294  i--;
295  }
296 
297  /*
298  * If requested, output a decimal point and all the digits that follow it.
299  */
300  if (dscale > 0)
301  {
302  *cp++ = '.';
303  while (i >= -dscale)
304  {
305  if (i <= var->weight && d < var->ndigits)
306  *cp++ = var->digits[d++] + '0';
307  else
308  *cp++ = '0';
309  i--;
310  }
311  }
312 
313  /*
314  * terminate the string and return it
315  */
316  *cp = '\0';
317  return str;
318 }
#define NUMERIC_NEG
Definition: numeric.c:167
#define NUMERIC_NAN
Definition: numeric.c:198
char * pgtypes_alloc(long size)
Definition: common.c:10
#define Min(x, y)
Definition: numeric.c:14
#define sprintf
Definition: port.h:227

References numeric::digits, i, Max, Min, numeric::ndigits, NUMERIC_NAN, NUMERIC_NEG, pgtypes_alloc(), numeric::sign, sprintf, generate_unaccent_rules::str, and numeric::weight.

Referenced by numericvar_to_double(), and PGTYPESnumeric_to_asc().

◆ numericvar_to_double()

static int numericvar_to_double ( numeric var,
double *  dp 
)
static

Definition at line 1433 of file numeric.c.

1434 {
1435  char *tmp;
1436  double val;
1437  char *endptr;
1438  numeric *varcopy = PGTYPESnumeric_new();
1439 
1440  if (varcopy == NULL)
1441  return -1;
1442 
1443  if (PGTYPESnumeric_copy(var, varcopy) < 0)
1444  {
1445  PGTYPESnumeric_free(varcopy);
1446  return -1;
1447  }
1448 
1449  tmp = get_str_from_var(varcopy, varcopy->dscale);
1450  PGTYPESnumeric_free(varcopy);
1451 
1452  if (tmp == NULL)
1453  return -1;
1454 
1455  /*
1456  * strtod does not reset errno to 0 in case of success.
1457  */
1458  errno = 0;
1459  val = strtod(tmp, &endptr);
1460  if (errno == ERANGE)
1461  {
1462  free(tmp);
1463  if (val == 0)
1464  errno = PGTYPES_NUM_UNDERFLOW;
1465  else
1466  errno = PGTYPES_NUM_OVERFLOW;
1467  return -1;
1468  }
1469 
1470  /* can't free tmp yet, endptr points still into it */
1471  if (*endptr != '\0')
1472  {
1473  /* shouldn't happen ... */
1474  free(tmp);
1475  errno = PGTYPES_NUM_BAD_NUMERIC;
1476  return -1;
1477  }
1478  free(tmp);
1479  *dp = val;
1480  return 0;
1481 }
#define free(a)
Definition: header.h:65
long val
Definition: informix.c:664
int PGTYPESnumeric_copy(numeric *src, numeric *dst)
Definition: numeric.c:1389
static char * get_str_from_var(numeric *var, int dscale)
Definition: numeric.c:226
numeric * PGTYPESnumeric_new(void)
Definition: numeric.c:42
void PGTYPESnumeric_free(numeric *var)
Definition: numeric.c:385
#define PGTYPES_NUM_BAD_NUMERIC
Definition: pgtypes_error.h:4
#define PGTYPES_NUM_OVERFLOW
Definition: pgtypes_error.h:3
#define PGTYPES_NUM_UNDERFLOW
Definition: pgtypes_error.h:6

References numeric::dscale, free, get_str_from_var(), PGTYPES_NUM_BAD_NUMERIC, PGTYPES_NUM_OVERFLOW, PGTYPES_NUM_UNDERFLOW, PGTYPESnumeric_copy(), PGTYPESnumeric_free(), PGTYPESnumeric_new(), and val.

Referenced by PGTYPESnumeric_to_double().

◆ PGTYPESdecimal_free()

void PGTYPESdecimal_free ( decimal var)

Definition at line 392 of file numeric.c.

393 {
394  free(var);
395 }

References free.

Referenced by main().

◆ PGTYPESdecimal_new()

decimal* PGTYPESdecimal_new ( void  )

Definition at line 59 of file numeric.c.

60 {
61  decimal *var;
62 
63  if ((var = (decimal *) pgtypes_alloc(sizeof(decimal))) == NULL)
64  return NULL;
65 
66  memset(var, 0, sizeof(decimal));
67 
68  return var;
69 }

References pgtypes_alloc().

Referenced by main().

◆ PGTYPESnumeric_add()

int PGTYPESnumeric_add ( numeric var1,
numeric var2,
numeric result 
)

Definition at line 637 of file numeric.c.

638 {
639  /*
640  * Decide on the signs of the two variables what to do
641  */
642  if (var1->sign == NUMERIC_POS)
643  {
644  if (var2->sign == NUMERIC_POS)
645  {
646  /*
647  * Both are positive result = +(ABS(var1) + ABS(var2))
648  */
649  if (add_abs(var1, var2, result) != 0)
650  return -1;
651  result->sign = NUMERIC_POS;
652  }
653  else
654  {
655  /*
656  * var1 is positive, var2 is negative Must compare absolute values
657  */
658  switch (cmp_abs(var1, var2))
659  {
660  case 0:
661  /* ----------
662  * ABS(var1) == ABS(var2)
663  * result = ZERO
664  * ----------
665  */
666  zero_var(result);
667  result->rscale = Max(var1->rscale, var2->rscale);
668  result->dscale = Max(var1->dscale, var2->dscale);
669  break;
670 
671  case 1:
672  /* ----------
673  * ABS(var1) > ABS(var2)
674  * result = +(ABS(var1) - ABS(var2))
675  * ----------
676  */
677  if (sub_abs(var1, var2, result) != 0)
678  return -1;
679  result->sign = NUMERIC_POS;
680  break;
681 
682  case -1:
683  /* ----------
684  * ABS(var1) < ABS(var2)
685  * result = -(ABS(var2) - ABS(var1))
686  * ----------
687  */
688  if (sub_abs(var2, var1, result) != 0)
689  return -1;
690  result->sign = NUMERIC_NEG;
691  break;
692  }
693  }
694  }
695  else
696  {
697  if (var2->sign == NUMERIC_POS)
698  {
699  /* ----------
700  * var1 is negative, var2 is positive
701  * Must compare absolute values
702  * ----------
703  */
704  switch (cmp_abs(var1, var2))
705  {
706  case 0:
707  /* ----------
708  * ABS(var1) == ABS(var2)
709  * result = ZERO
710  * ----------
711  */
712  zero_var(result);
713  result->rscale = Max(var1->rscale, var2->rscale);
714  result->dscale = Max(var1->dscale, var2->dscale);
715  break;
716 
717  case 1:
718  /* ----------
719  * ABS(var1) > ABS(var2)
720  * result = -(ABS(var1) - ABS(var2))
721  * ----------
722  */
723  if (sub_abs(var1, var2, result) != 0)
724  return -1;
725  result->sign = NUMERIC_NEG;
726  break;
727 
728  case -1:
729  /* ----------
730  * ABS(var1) < ABS(var2)
731  * result = +(ABS(var2) - ABS(var1))
732  * ----------
733  */
734  if (sub_abs(var2, var1, result) != 0)
735  return -1;
736  result->sign = NUMERIC_POS;
737  break;
738  }
739  }
740  else
741  {
742  /* ----------
743  * Both are negative
744  * result = -(ABS(var1) + ABS(var2))
745  * ----------
746  */
747  if (add_abs(var1, var2, result) != 0)
748  return -1;
749  result->sign = NUMERIC_NEG;
750  }
751  }
752 
753  return 0;
754 }
#define NUMERIC_POS
Definition: numeric.c:166
static int sub_abs(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:553
static int add_abs(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:465
static void zero_var(numeric *var)
Definition: numeric.c:374
static int cmp_abs(numeric *var1, numeric *var2)
Definition: numeric.c:407

References add_abs(), cmp_abs(), numeric::dscale, Max, NUMERIC_NEG, NUMERIC_POS, numeric::rscale, numeric::sign, sub_abs(), and zero_var().

Referenced by decadd(), and main().

◆ PGTYPESnumeric_cmp()

int PGTYPESnumeric_cmp ( numeric var1,
numeric var2 
)

Definition at line 1282 of file numeric.c.

1283 {
1284  /* use cmp_abs function to calculate the result */
1285 
1286  /* both are positive: normal comparison with cmp_abs */
1287  if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_POS)
1288  return cmp_abs(var1, var2);
1289 
1290  /* both are negative: return the inverse of the normal comparison */
1291  if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_NEG)
1292  {
1293  /*
1294  * instead of inverting the result, we invert the parameter ordering
1295  */
1296  return cmp_abs(var2, var1);
1297  }
1298 
1299  /* one is positive, one is negative: trivial */
1300  if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_NEG)
1301  return 1;
1302  if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_POS)
1303  return -1;
1304 
1305  errno = PGTYPES_NUM_BAD_NUMERIC;
1306  return INT_MAX;
1307 }

References cmp_abs(), NUMERIC_NEG, NUMERIC_POS, PGTYPES_NUM_BAD_NUMERIC, and numeric::sign.

Referenced by deccmp(), and main().

◆ PGTYPESnumeric_copy()

int PGTYPESnumeric_copy ( numeric src,
numeric dst 
)

Definition at line 1389 of file numeric.c.

1390 {
1391  int i;
1392 
1393  if (dst == NULL)
1394  return -1;
1395  zero_var(dst);
1396 
1397  dst->weight = src->weight;
1398  dst->rscale = src->rscale;
1399  dst->dscale = src->dscale;
1400  dst->sign = src->sign;
1401 
1402  if (alloc_var(dst, src->ndigits) != 0)
1403  return -1;
1404 
1405  for (i = 0; i < src->ndigits; i++)
1406  dst->digits[i] = src->digits[i];
1407 
1408  return 0;
1409 }
static int alloc_var(numeric *var, int ndigits)
Definition: numeric.c:29

References alloc_var(), numeric::digits, numeric::dscale, i, numeric::ndigits, numeric::rscale, numeric::sign, numeric::weight, and zero_var().

Referenced by ecpg_get_data(), ecpg_store_input(), main(), numericvar_to_double(), PGTYPESnumeric_from_double(), and PGTYPESnumeric_to_asc().

◆ PGTYPESnumeric_div()

int PGTYPESnumeric_div ( numeric var1,
numeric var2,
numeric result 
)

Definition at line 1053 of file numeric.c.

1054 {
1055  NumericDigit *res_digits;
1056  int res_ndigits;
1057  int res_sign;
1058  int res_weight;
1059  numeric dividend;
1060  numeric divisor[10];
1061  int ndigits_tmp;
1062  int weight_tmp;
1063  int rscale_tmp;
1064  int ri;
1065  int i;
1066  long guess;
1067  long first_have;
1068  long first_div;
1069  int first_nextdigit;
1070  int stat = 0;
1071  int rscale;
1072  int res_dscale = select_div_scale(var1, var2, &rscale);
1073  int err = -1;
1074  NumericDigit *tmp_buf;
1075 
1076  /*
1077  * First of all division by zero check
1078  */
1079  ndigits_tmp = var2->ndigits + 1;
1080  if (ndigits_tmp == 1)
1081  {
1082  errno = PGTYPES_NUM_DIVIDE_ZERO;
1083  return -1;
1084  }
1085 
1086  /*
1087  * Determine the result sign, weight and number of digits to calculate
1088  */
1089  if (var1->sign == var2->sign)
1090  res_sign = NUMERIC_POS;
1091  else
1092  res_sign = NUMERIC_NEG;
1093  res_weight = var1->weight - var2->weight + 1;
1094  res_ndigits = rscale + res_weight;
1095  if (res_ndigits <= 0)
1096  res_ndigits = 1;
1097 
1098  /*
1099  * Now result zero check
1100  */
1101  if (var1->ndigits == 0)
1102  {
1103  zero_var(result);
1104  result->rscale = rscale;
1105  return 0;
1106  }
1107 
1108  /*
1109  * Initialize local variables
1110  */
1111  init_var(&dividend);
1112  for (i = 1; i < 10; i++)
1113  init_var(&divisor[i]);
1114 
1115  /*
1116  * Make a copy of the divisor which has one leading zero digit
1117  */
1118  divisor[1].ndigits = ndigits_tmp;
1119  divisor[1].rscale = var2->ndigits;
1120  divisor[1].sign = NUMERIC_POS;
1121  divisor[1].buf = digitbuf_alloc(ndigits_tmp);
1122  if (divisor[1].buf == NULL)
1123  goto done;
1124  divisor[1].digits = divisor[1].buf;
1125  divisor[1].digits[0] = 0;
1126  memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
1127 
1128  /*
1129  * Make a copy of the dividend
1130  */
1131  dividend.ndigits = var1->ndigits;
1132  dividend.weight = 0;
1133  dividend.rscale = var1->ndigits;
1134  dividend.sign = NUMERIC_POS;
1135  dividend.buf = digitbuf_alloc(var1->ndigits);
1136  if (dividend.buf == NULL)
1137  goto done;
1138  dividend.digits = dividend.buf;
1139  memcpy(dividend.digits, var1->digits, var1->ndigits);
1140 
1141  /*
1142  * Setup the result. Do the allocation in a temporary buffer first, so we
1143  * don't free result->buf unless we have successfully allocated a buffer
1144  * to replace it with.
1145  */
1146  tmp_buf = digitbuf_alloc(res_ndigits + 2);
1147  if (tmp_buf == NULL)
1148  goto done;
1149  digitbuf_free(result->buf);
1150  result->buf = tmp_buf;
1151  res_digits = result->buf;
1152  result->digits = res_digits;
1153  result->ndigits = res_ndigits;
1154  result->weight = res_weight;
1155  result->rscale = rscale;
1156  result->sign = res_sign;
1157  res_digits[0] = 0;
1158 
1159  first_div = divisor[1].digits[1] * 10;
1160  if (ndigits_tmp > 2)
1161  first_div += divisor[1].digits[2];
1162 
1163  first_have = 0;
1164  first_nextdigit = 0;
1165 
1166  weight_tmp = 1;
1167  rscale_tmp = divisor[1].rscale;
1168 
1169  for (ri = 0; ri <= res_ndigits; ri++)
1170  {
1171  first_have = first_have * 10;
1172  if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1173  first_have += dividend.digits[first_nextdigit];
1174  first_nextdigit++;
1175 
1176  guess = (first_have * 10) / first_div + 1;
1177  if (guess > 9)
1178  guess = 9;
1179 
1180  while (guess > 0)
1181  {
1182  if (divisor[guess].buf == NULL)
1183  {
1184  int i;
1185  long sum = 0;
1186 
1187  memcpy(&divisor[guess], &divisor[1], sizeof(numeric));
1188  divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);
1189  if (divisor[guess].buf == NULL)
1190  goto done;
1191  divisor[guess].digits = divisor[guess].buf;
1192  for (i = divisor[1].ndigits - 1; i >= 0; i--)
1193  {
1194  sum += divisor[1].digits[i] * guess;
1195  divisor[guess].digits[i] = sum % 10;
1196  sum /= 10;
1197  }
1198  }
1199 
1200  divisor[guess].weight = weight_tmp;
1201  divisor[guess].rscale = rscale_tmp;
1202 
1203  stat = cmp_abs(&dividend, &divisor[guess]);
1204  if (stat >= 0)
1205  break;
1206 
1207  guess--;
1208  }
1209 
1210  res_digits[ri + 1] = guess;
1211  if (stat == 0)
1212  {
1213  ri++;
1214  break;
1215  }
1216 
1217  weight_tmp--;
1218  rscale_tmp++;
1219 
1220  if (guess == 0)
1221  continue;
1222 
1223  if (sub_abs(&dividend, &divisor[guess], &dividend) != 0)
1224  goto done;
1225 
1226  first_nextdigit = dividend.weight - weight_tmp;
1227  first_have = 0;
1228  if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1229  first_have = dividend.digits[first_nextdigit];
1230  first_nextdigit++;
1231  }
1232 
1233  result->ndigits = ri + 1;
1234  if (ri == res_ndigits + 1)
1235  {
1236  int carry = (res_digits[ri] > 4) ? 1 : 0;
1237 
1238  result->ndigits = ri;
1239  res_digits[ri] = 0;
1240 
1241  while (carry && ri > 0)
1242  {
1243  carry += res_digits[--ri];
1244  res_digits[ri] = carry % 10;
1245  carry /= 10;
1246  }
1247  }
1248 
1249  while (result->ndigits > 0 && *(result->digits) == 0)
1250  {
1251  (result->digits)++;
1252  (result->weight)--;
1253  (result->ndigits)--;
1254  }
1255  while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)
1256  (result->ndigits)--;
1257  if (result->ndigits == 0)
1258  result->sign = NUMERIC_POS;
1259 
1260  result->dscale = res_dscale;
1261  err = 0; /* if we've made it this far, return success */
1262 
1263 done:
1264 
1265  /*
1266  * Tidy up
1267  */
1268  if (dividend.buf != NULL)
1269  digitbuf_free(dividend.buf);
1270 
1271  for (i = 1; i < 10; i++)
1272  {
1273  if (divisor[i].buf != NULL)
1274  digitbuf_free(divisor[i].buf);
1275  }
1276 
1277  return err;
1278 }
int digits
Definition: informix.c:666
static int select_div_scale(numeric *var1, numeric *var2, int *rscale)
Definition: numeric.c:987
#define init_var(v)
Definition: numeric.c:16
static char * buf
Definition: pg_test_fsync.c:67
#define PGTYPES_NUM_DIVIDE_ZERO
Definition: pgtypes_error.h:5

References buf, numeric::buf, cmp_abs(), digitbuf_alloc, digitbuf_free, digits, numeric::digits, numeric::dscale, i, init_var, numeric::ndigits, NUMERIC_NEG, NUMERIC_POS, PGTYPES_NUM_DIVIDE_ZERO, numeric::rscale, select_div_scale(), numeric::sign, sub_abs(), numeric::weight, and zero_var().

Referenced by decdiv(), and main().

◆ PGTYPESnumeric_free()

◆ PGTYPESnumeric_from_asc()

numeric* PGTYPESnumeric_from_asc ( char *  str,
char **  endptr 
)

Definition at line 321 of file numeric.c.

322 {
323  numeric *value = (numeric *) pgtypes_alloc(sizeof(numeric));
324  int ret;
325 
326  char *realptr;
327  char **ptr = (endptr != NULL) ? endptr : &realptr;
328 
329  if (!value)
330  return NULL;
331 
332  ret = set_var_from_str(str, ptr, value);
333  if (ret)
334  {
336  return NULL;
337  }
338 
339  return value;
340 }
static struct @151 value
static int set_var_from_str(char *str, char **ptr, numeric *dest)
Definition: numeric.c:78

References pgtypes_alloc(), PGTYPESnumeric_free(), set_var_from_str(), generate_unaccent_rules::str, and value.

Referenced by deccvasc(), ecpg_get_data(), ecpg_set_compat_sqlda(), ecpg_set_native_sqlda(), main(), PGTYPESnumeric_from_double(), and sqlda_common_total_size().

◆ PGTYPESnumeric_from_decimal()

int PGTYPESnumeric_from_decimal ( decimal src,
numeric dst 
)

Definition at line 1571 of file numeric.c.

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 }
NumericDigit digits[DECSIZE]

References alloc_var(), numeric::digits, decimal::digits, numeric::dscale, decimal::dscale, i, decimal::ndigits, numeric::rscale, decimal::rscale, numeric::sign, decimal::sign, numeric::weight, decimal::weight, and zero_var().

Referenced by deccall2(), deccall3(), dectoasc(), dectodbl(), dectoint(), dectolong(), ecpg_store_input(), and main().

◆ PGTYPESnumeric_from_double()

int PGTYPESnumeric_from_double ( double  d,
numeric dst 
)

Definition at line 1412 of file numeric.c.

1413 {
1414  char buffer[DBL_DIG + 100];
1415  numeric *tmp;
1416  int i;
1417 
1418  if (sprintf(buffer, "%.*g", DBL_DIG, d) <= 0)
1419  return -1;
1420 
1421  if ((tmp = PGTYPESnumeric_from_asc(buffer, NULL)) == NULL)
1422  return -1;
1423  i = PGTYPESnumeric_copy(tmp, dst);
1424  PGTYPESnumeric_free(tmp);
1425  if (i != 0)
1426  return -1;
1427 
1428  errno = 0;
1429  return 0;
1430 }
numeric * PGTYPESnumeric_from_asc(char *str, char **endptr)
Definition: numeric.c:321

References i, PGTYPESnumeric_copy(), PGTYPESnumeric_free(), PGTYPESnumeric_from_asc(), and sprintf.

Referenced by deccvdbl().

◆ PGTYPESnumeric_from_int()

int PGTYPESnumeric_from_int ( signed int  int_val,
numeric var 
)

Definition at line 1310 of file numeric.c.

1311 {
1312  /* implicit conversion */
1313  signed long int long_int = int_val;
1314 
1315  return PGTYPESnumeric_from_long(long_int, var);
1316 }
int PGTYPESnumeric_from_long(signed long int long_val, numeric *var)
Definition: numeric.c:1319

References PGTYPESnumeric_from_long().

Referenced by deccvint(), and main().

◆ PGTYPESnumeric_from_long()

int PGTYPESnumeric_from_long ( signed long int  long_val,
numeric var 
)

Definition at line 1319 of file numeric.c.

1320 {
1321  /* calculate the size of the long int number */
1322  /* a number n needs log_10 n digits */
1323 
1324  /*
1325  * however we multiply by 10 each time and compare instead of calculating
1326  * the logarithm
1327  */
1328 
1329  int size = 0;
1330  int i;
1331  signed long int abs_long_val = long_val;
1332  signed long int extract;
1333  signed long int reach_limit;
1334 
1335  if (abs_long_val < 0)
1336  {
1337  abs_long_val *= -1;
1338  var->sign = NUMERIC_NEG;
1339  }
1340  else
1341  var->sign = NUMERIC_POS;
1342 
1343  reach_limit = 1;
1344  do
1345  {
1346  size++;
1347  reach_limit *= 10;
1348  } while (reach_limit - 1 < abs_long_val && reach_limit <= LONG_MAX / 10);
1349 
1350  if (reach_limit > LONG_MAX / 10)
1351  {
1352  /* add the first digit and a .0 */
1353  size += 2;
1354  }
1355  else
1356  {
1357  /* always add a .0 */
1358  size++;
1359  reach_limit /= 10;
1360  }
1361 
1362  if (alloc_var(var, size) < 0)
1363  return -1;
1364 
1365  var->rscale = 1;
1366  var->dscale = 1;
1367  var->weight = size - 2;
1368 
1369  i = 0;
1370  do
1371  {
1372  extract = abs_long_val - (abs_long_val % reach_limit);
1373  var->digits[i] = extract / reach_limit;
1374  abs_long_val -= extract;
1375  i++;
1376  reach_limit /= 10;
1377 
1378  /*
1379  * we can abandon if abs_long_val reaches 0, because the memory is
1380  * initialized properly and filled with '0', so converting 10000 in
1381  * only one step is no problem
1382  */
1383  } while (abs_long_val > 0);
1384 
1385  return 0;
1386 }

References alloc_var(), numeric::digits, numeric::dscale, i, NUMERIC_NEG, NUMERIC_POS, numeric::rscale, numeric::sign, and numeric::weight.

Referenced by deccvlong(), main(), and PGTYPESnumeric_from_int().

◆ PGTYPESnumeric_mul()

int PGTYPESnumeric_mul ( numeric var1,
numeric var2,
numeric result 
)

Definition at line 896 of file numeric.c.

897 {
898  NumericDigit *res_buf;
899  NumericDigit *res_digits;
900  int res_ndigits;
901  int res_weight;
902  int res_sign;
903  int i,
904  ri,
905  i1,
906  i2;
907  long sum = 0;
908  int global_rscale = var1->rscale + var2->rscale;
909 
910  res_weight = var1->weight + var2->weight + 2;
911  res_ndigits = var1->ndigits + var2->ndigits + 1;
912  if (var1->sign == var2->sign)
913  res_sign = NUMERIC_POS;
914  else
915  res_sign = NUMERIC_NEG;
916 
917  if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
918  return -1;
919  res_digits = res_buf;
920  memset(res_digits, 0, res_ndigits);
921 
922  ri = res_ndigits;
923  for (i1 = var1->ndigits - 1; i1 >= 0; i1--)
924  {
925  sum = 0;
926  i = --ri;
927 
928  for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
929  {
930  sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
931  res_digits[i--] = sum % 10;
932  sum /= 10;
933  }
934  res_digits[i] = sum;
935  }
936 
937  i = res_weight + global_rscale + 2;
938  if (i >= 0 && i < res_ndigits)
939  {
940  sum = (res_digits[i] > 4) ? 1 : 0;
941  res_ndigits = i;
942  i--;
943  while (sum)
944  {
945  sum += res_digits[i];
946  res_digits[i--] = sum % 10;
947  sum /= 10;
948  }
949  }
950 
951  while (res_ndigits > 0 && *res_digits == 0)
952  {
953  res_digits++;
954  res_weight--;
955  res_ndigits--;
956  }
957  while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
958  res_ndigits--;
959 
960  if (res_ndigits == 0)
961  {
962  res_sign = NUMERIC_POS;
963  res_weight = 0;
964  }
965 
966  digitbuf_free(result->buf);
967  result->buf = res_buf;
968  result->digits = res_digits;
969  result->ndigits = res_ndigits;
970  result->weight = res_weight;
971  result->rscale = global_rscale;
972  result->sign = res_sign;
973  result->dscale = var1->dscale + var2->dscale;
974 
975  return 0;
976 }

References numeric::buf, digitbuf_alloc, digitbuf_free, numeric::digits, numeric::dscale, i, numeric::ndigits, NUMERIC_NEG, NUMERIC_POS, numeric::rscale, numeric::sign, and numeric::weight.

Referenced by decmul(), and main().

◆ PGTYPESnumeric_new()

numeric* PGTYPESnumeric_new ( void  )

Definition at line 42 of file numeric.c.

43 {
44  numeric *var;
45 
46  if ((var = (numeric *) pgtypes_alloc(sizeof(numeric))) == NULL)
47  return NULL;
48 
49  if (alloc_var(var, 0) < 0)
50  {
51  free(var);
52  return NULL;
53  }
54 
55  return var;
56 }

References alloc_var(), free, and pgtypes_alloc().

Referenced by deccall2(), deccall3(), deccvdbl(), deccvint(), deccvlong(), dectoasc(), dectodbl(), dectoint(), dectolong(), ecpg_get_data(), ecpg_store_input(), main(), numericvar_to_double(), and PGTYPESnumeric_to_asc().

◆ PGTYPESnumeric_sub()

int PGTYPESnumeric_sub ( numeric var1,
numeric var2,
numeric result 
)

Definition at line 765 of file numeric.c.

766 {
767  /*
768  * Decide on the signs of the two variables what to do
769  */
770  if (var1->sign == NUMERIC_POS)
771  {
772  if (var2->sign == NUMERIC_NEG)
773  {
774  /* ----------
775  * var1 is positive, var2 is negative
776  * result = +(ABS(var1) + ABS(var2))
777  * ----------
778  */
779  if (add_abs(var1, var2, result) != 0)
780  return -1;
781  result->sign = NUMERIC_POS;
782  }
783  else
784  {
785  /* ----------
786  * Both are positive
787  * Must compare absolute values
788  * ----------
789  */
790  switch (cmp_abs(var1, var2))
791  {
792  case 0:
793  /* ----------
794  * ABS(var1) == ABS(var2)
795  * result = ZERO
796  * ----------
797  */
798  zero_var(result);
799  result->rscale = Max(var1->rscale, var2->rscale);
800  result->dscale = Max(var1->dscale, var2->dscale);
801  break;
802 
803  case 1:
804  /* ----------
805  * ABS(var1) > ABS(var2)
806  * result = +(ABS(var1) - ABS(var2))
807  * ----------
808  */
809  if (sub_abs(var1, var2, result) != 0)
810  return -1;
811  result->sign = NUMERIC_POS;
812  break;
813 
814  case -1:
815  /* ----------
816  * ABS(var1) < ABS(var2)
817  * result = -(ABS(var2) - ABS(var1))
818  * ----------
819  */
820  if (sub_abs(var2, var1, result) != 0)
821  return -1;
822  result->sign = NUMERIC_NEG;
823  break;
824  }
825  }
826  }
827  else
828  {
829  if (var2->sign == NUMERIC_NEG)
830  {
831  /* ----------
832  * Both are negative
833  * Must compare absolute values
834  * ----------
835  */
836  switch (cmp_abs(var1, var2))
837  {
838  case 0:
839  /* ----------
840  * ABS(var1) == ABS(var2)
841  * result = ZERO
842  * ----------
843  */
844  zero_var(result);
845  result->rscale = Max(var1->rscale, var2->rscale);
846  result->dscale = Max(var1->dscale, var2->dscale);
847  break;
848 
849  case 1:
850  /* ----------
851  * ABS(var1) > ABS(var2)
852  * result = -(ABS(var1) - ABS(var2))
853  * ----------
854  */
855  if (sub_abs(var1, var2, result) != 0)
856  return -1;
857  result->sign = NUMERIC_NEG;
858  break;
859 
860  case -1:
861  /* ----------
862  * ABS(var1) < ABS(var2)
863  * result = +(ABS(var2) - ABS(var1))
864  * ----------
865  */
866  if (sub_abs(var2, var1, result) != 0)
867  return -1;
868  result->sign = NUMERIC_POS;
869  break;
870  }
871  }
872  else
873  {
874  /* ----------
875  * var1 is negative, var2 is positive
876  * result = -(ABS(var1) + ABS(var2))
877  * ----------
878  */
879  if (add_abs(var1, var2, result) != 0)
880  return -1;
881  result->sign = NUMERIC_NEG;
882  }
883  }
884 
885  return 0;
886 }

References add_abs(), cmp_abs(), numeric::dscale, Max, NUMERIC_NEG, NUMERIC_POS, numeric::rscale, numeric::sign, sub_abs(), and zero_var().

Referenced by decsub(), and main().

◆ PGTYPESnumeric_to_asc()

char* PGTYPESnumeric_to_asc ( numeric num,
int  dscale 
)

Definition at line 343 of file numeric.c.

344 {
345  numeric *numcopy = PGTYPESnumeric_new();
346  char *s;
347 
348  if (numcopy == NULL)
349  return NULL;
350 
351  if (PGTYPESnumeric_copy(num, numcopy) < 0)
352  {
353  PGTYPESnumeric_free(numcopy);
354  return NULL;
355  }
356 
357  if (dscale < 0)
358  dscale = num->dscale;
359 
360  /* get_str_from_var may change its argument */
361  s = get_str_from_var(numcopy, dscale);
362  PGTYPESnumeric_free(numcopy);
363  return s;
364 }

References numeric::dscale, get_str_from_var(), PGTYPESnumeric_copy(), PGTYPESnumeric_free(), and PGTYPESnumeric_new().

Referenced by dectoasc(), dump_sqlda(), ecpg_store_input(), main(), and PGTYPESnumeric_to_long().

◆ PGTYPESnumeric_to_decimal()

int PGTYPESnumeric_to_decimal ( numeric src,
decimal dst 
)

Definition at line 1548 of file numeric.c.

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 }
#define DECSIZE

References DECSIZE, numeric::digits, decimal::digits, numeric::dscale, decimal::dscale, i, numeric::ndigits, decimal::ndigits, PGTYPES_NUM_OVERFLOW, numeric::rscale, decimal::rscale, numeric::sign, decimal::sign, numeric::weight, and decimal::weight.

Referenced by deccall3(), deccvasc(), deccvdbl(), deccvint(), deccvlong(), ecpg_get_data(), and main().

◆ PGTYPESnumeric_to_double()

int PGTYPESnumeric_to_double ( numeric nv,
double *  dp 
)

Definition at line 1484 of file numeric.c.

1485 {
1486  double tmp;
1487 
1488  if (numericvar_to_double(nv, &tmp) != 0)
1489  return -1;
1490  *dp = tmp;
1491  return 0;
1492 }
static int numericvar_to_double(numeric *var, double *dp)
Definition: numeric.c:1433

References numericvar_to_double().

Referenced by dectodbl(), and main().

◆ PGTYPESnumeric_to_int()

int PGTYPESnumeric_to_int ( numeric nv,
int *  ip 
)

Definition at line 1495 of file numeric.c.

1496 {
1497  long l;
1498  int i;
1499 
1500  if ((i = PGTYPESnumeric_to_long(nv, &l)) != 0)
1501  return i;
1502 
1503 /* silence compilers that might complain about useless tests */
1504 #if SIZEOF_LONG > SIZEOF_INT
1505 
1506  if (l < INT_MIN || l > INT_MAX)
1507  {
1508  errno = PGTYPES_NUM_OVERFLOW;
1509  return -1;
1510  }
1511 
1512 #endif
1513 
1514  *ip = (int) l;
1515  return 0;
1516 }
int PGTYPESnumeric_to_long(numeric *nv, long *lp)
Definition: numeric.c:1519

References i, PGTYPES_NUM_OVERFLOW, and PGTYPESnumeric_to_long().

Referenced by dectoint(), and main().

◆ PGTYPESnumeric_to_long()

int PGTYPESnumeric_to_long ( numeric nv,
long *  lp 
)

Definition at line 1519 of file numeric.c.

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 }
char * PGTYPESnumeric_to_asc(numeric *num, int dscale)
Definition: numeric.c:343

References free, PGTYPES_NUM_OVERFLOW, PGTYPES_NUM_UNDERFLOW, and PGTYPESnumeric_to_asc().

Referenced by dectolong(), main(), and PGTYPESnumeric_to_int().

◆ select_div_scale()

static int select_div_scale ( numeric var1,
numeric var2,
int *  rscale 
)
static

Definition at line 987 of file numeric.c.

988 {
989  int weight1,
990  weight2,
991  qweight,
992  i;
993  NumericDigit firstdigit1,
994  firstdigit2;
995  int res_dscale;
996 
997  /*
998  * The result scale of a division isn't specified in any SQL standard. For
999  * PostgreSQL we select a display scale that will give at least
1000  * NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a
1001  * result no less accurate than float8; but use a scale not less than
1002  * either input's display scale.
1003  */
1004 
1005  /* Get the actual (normalized) weight and first digit of each input */
1006 
1007  weight1 = 0; /* values to use if var1 is zero */
1008  firstdigit1 = 0;
1009  for (i = 0; i < var1->ndigits; i++)
1010  {
1011  firstdigit1 = var1->digits[i];
1012  if (firstdigit1 != 0)
1013  {
1014  weight1 = var1->weight - i;
1015  break;
1016  }
1017  }
1018 
1019  weight2 = 0; /* values to use if var2 is zero */
1020  firstdigit2 = 0;
1021  for (i = 0; i < var2->ndigits; i++)
1022  {
1023  firstdigit2 = var2->digits[i];
1024  if (firstdigit2 != 0)
1025  {
1026  weight2 = var2->weight - i;
1027  break;
1028  }
1029  }
1030 
1031  /*
1032  * Estimate weight of quotient. If the two first digits are equal, we
1033  * can't be sure, but assume that var1 is less than var2.
1034  */
1035  qweight = weight1 - weight2;
1036  if (firstdigit1 <= firstdigit2)
1037  qweight--;
1038 
1039  /* Select display scale */
1040  res_dscale = NUMERIC_MIN_SIG_DIGITS - qweight;
1041  res_dscale = Max(res_dscale, var1->dscale);
1042  res_dscale = Max(res_dscale, var2->dscale);
1043  res_dscale = Max(res_dscale, NUMERIC_MIN_DISPLAY_SCALE);
1044  res_dscale = Min(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1045 
1046  /* Select result scale */
1047  *rscale = res_dscale + 4;
1048 
1049  return res_dscale;
1050 }
#define NUMERIC_MAX_DISPLAY_SCALE
Definition: numeric.h:39
#define NUMERIC_MIN_SIG_DIGITS
Definition: numeric.h:49
#define NUMERIC_MIN_DISPLAY_SCALE
Definition: numeric.h:40

References numeric::digits, numeric::dscale, i, Max, Min, numeric::ndigits, NUMERIC_MAX_DISPLAY_SCALE, NUMERIC_MIN_DISPLAY_SCALE, NUMERIC_MIN_SIG_DIGITS, and numeric::weight.

Referenced by PGTYPESnumeric_div().

◆ set_var_from_str()

static int set_var_from_str ( char *  str,
char **  ptr,
numeric dest 
)
static

Definition at line 78 of file numeric.c.

79 {
80  bool have_dp = false;
81  int i = 0;
82 
83  errno = 0;
84  *ptr = str;
85  while (*(*ptr))
86  {
87  if (!isspace((unsigned char) *(*ptr)))
88  break;
89  (*ptr)++;
90  }
91 
92  if (pg_strncasecmp(*ptr, "NaN", 3) == 0)
93  {
94  *ptr += 3;
95  dest->sign = NUMERIC_NAN;
96 
97  /* Should be nothing left but spaces */
98  while (*(*ptr))
99  {
100  if (!isspace((unsigned char) *(*ptr)))
101  {
102  errno = PGTYPES_NUM_BAD_NUMERIC;
103  return -1;
104  }
105  (*ptr)++;
106  }
107 
108  return 0;
109  }
110 
111  if (alloc_var(dest, strlen((*ptr))) < 0)
112  return -1;
113  dest->weight = -1;
114  dest->dscale = 0;
115  dest->sign = NUMERIC_POS;
116 
117  switch (*(*ptr))
118  {
119  case '+':
120  dest->sign = NUMERIC_POS;
121  (*ptr)++;
122  break;
123 
124  case '-':
125  dest->sign = NUMERIC_NEG;
126  (*ptr)++;
127  break;
128  }
129 
130  if (*(*ptr) == '.')
131  {
132  have_dp = true;
133  (*ptr)++;
134  }
135 
136  if (!isdigit((unsigned char) *(*ptr)))
137  {
138  errno = PGTYPES_NUM_BAD_NUMERIC;
139  return -1;
140  }
141 
142  while (*(*ptr))
143  {
144  if (isdigit((unsigned char) *(*ptr)))
145  {
146  dest->digits[i++] = *(*ptr)++ - '0';
147  if (!have_dp)
148  dest->weight++;
149  else
150  dest->dscale++;
151  }
152  else if (*(*ptr) == '.')
153  {
154  if (have_dp)
155  {
156  errno = PGTYPES_NUM_BAD_NUMERIC;
157  return -1;
158  }
159  have_dp = true;
160  (*ptr)++;
161  }
162  else
163  break;
164  }
165  dest->ndigits = i;
166 
167  /* Handle exponent, if any */
168  if (*(*ptr) == 'e' || *(*ptr) == 'E')
169  {
170  long exponent;
171  char *endptr;
172 
173  (*ptr)++;
174  exponent = strtol(*ptr, &endptr, 10);
175  if (endptr == (*ptr))
176  {
177  errno = PGTYPES_NUM_BAD_NUMERIC;
178  return -1;
179  }
180  (*ptr) = endptr;
181  if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
182  {
183  errno = PGTYPES_NUM_BAD_NUMERIC;
184  return -1;
185  }
186  dest->weight += (int) exponent;
187  dest->dscale -= (int) exponent;
188  if (dest->dscale < 0)
189  dest->dscale = 0;
190  }
191 
192  /* Should be nothing left but spaces */
193  while (*(*ptr))
194  {
195  if (!isspace((unsigned char) *(*ptr)))
196  {
197  errno = PGTYPES_NUM_BAD_NUMERIC;
198  return -1;
199  }
200  (*ptr)++;
201  }
202 
203  /* Strip any leading zeroes */
204  while (dest->ndigits > 0 && *(dest->digits) == 0)
205  {
206  (dest->digits)++;
207  (dest->weight)--;
208  (dest->ndigits)--;
209  }
210  if (dest->ndigits == 0)
211  dest->weight = 0;
212 
213  dest->rscale = dest->dscale;
214  return 0;
215 }
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69

References alloc_var(), generate_unaccent_rules::dest, i, NUMERIC_NAN, NUMERIC_NEG, NUMERIC_POS, pg_strncasecmp(), PGTYPES_NUM_BAD_NUMERIC, and generate_unaccent_rules::str.

Referenced by PGTYPESnumeric_from_asc().

◆ sub_abs()

static int sub_abs ( numeric var1,
numeric var2,
numeric result 
)
static

Definition at line 553 of file numeric.c.

554 {
555  NumericDigit *res_buf;
556  NumericDigit *res_digits;
557  int res_ndigits;
558  int res_weight;
559  int res_rscale;
560  int res_dscale;
561  int i,
562  i1,
563  i2;
564  int borrow = 0;
565 
566  /* copy these values into local vars for speed in inner loop */
567  int var1ndigits = var1->ndigits;
568  int var2ndigits = var2->ndigits;
569  NumericDigit *var1digits = var1->digits;
570  NumericDigit *var2digits = var2->digits;
571 
572  res_weight = var1->weight;
573  res_rscale = Max(var1->rscale, var2->rscale);
574  res_dscale = Max(var1->dscale, var2->dscale);
575  res_ndigits = res_rscale + res_weight + 1;
576  if (res_ndigits <= 0)
577  res_ndigits = 1;
578 
579  if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
580  return -1;
581  res_digits = res_buf;
582 
583  i1 = res_rscale + var1->weight + 1;
584  i2 = res_rscale + var2->weight + 1;
585  for (i = res_ndigits - 1; i >= 0; i--)
586  {
587  i1--;
588  i2--;
589  if (i1 >= 0 && i1 < var1ndigits)
590  borrow += var1digits[i1];
591  if (i2 >= 0 && i2 < var2ndigits)
592  borrow -= var2digits[i2];
593 
594  if (borrow < 0)
595  {
596  res_digits[i] = borrow + 10;
597  borrow = -1;
598  }
599  else
600  {
601  res_digits[i] = borrow;
602  borrow = 0;
603  }
604  }
605 
606  while (res_ndigits > 0 && *res_digits == 0)
607  {
608  res_digits++;
609  res_weight--;
610  res_ndigits--;
611  }
612  while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
613  res_ndigits--;
614 
615  if (res_ndigits == 0)
616  res_weight = 0;
617 
618  digitbuf_free(result->buf);
619  result->ndigits = res_ndigits;
620  result->buf = res_buf;
621  result->digits = res_digits;
622  result->weight = res_weight;
623  result->rscale = res_rscale;
624  result->dscale = res_dscale;
625 
626  return 0;
627 }

References numeric::buf, digitbuf_alloc, digitbuf_free, numeric::digits, numeric::dscale, i, Max, numeric::ndigits, numeric::rscale, and numeric::weight.

Referenced by PGTYPESnumeric_add(), PGTYPESnumeric_div(), and PGTYPESnumeric_sub().

◆ zero_var()

static void zero_var ( numeric var)
static

Definition at line 374 of file numeric.c.

375 {
376  digitbuf_free(var->buf);
377  var->buf = NULL;
378  var->digits = NULL;
379  var->ndigits = 0;
380  var->weight = 0; /* by convention; doesn't really matter */
381  var->sign = NUMERIC_POS; /* anything but NAN... */
382 }

References numeric::buf, digitbuf_free, numeric::digits, numeric::ndigits, NUMERIC_POS, numeric::sign, and numeric::weight.

Referenced by PGTYPESnumeric_add(), PGTYPESnumeric_copy(), PGTYPESnumeric_div(), PGTYPESnumeric_from_decimal(), and PGTYPESnumeric_sub().