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)
 

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.

Referenced by add_abs(), alloc_var(), PGTYPESnumeric_div(), PGTYPESnumeric_mul(), and sub_abs().

◆ digitbuf_free

#define digitbuf_free (   buf)
Value:
do { \
if ((buf) != NULL) \
free(buf); \
} while (0)
static char * buf
Definition: pg_test_fsync.c:67

Definition at line 19 of file numeric.c.

Referenced by add_abs(), alloc_var(), PGTYPESnumeric_div(), PGTYPESnumeric_free(), PGTYPESnumeric_mul(), sub_abs(), and zero_var().

◆ init_var

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

Definition at line 16 of file numeric.c.

Referenced by PGTYPESnumeric_div().

◆ Max

◆ Min

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

Function Documentation

◆ add_abs()

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

Definition at line 551 of file numeric.c.

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().

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

◆ alloc_var()

static int alloc_var ( numeric var,
int  ndigits 
)
static

Definition at line 115 of file numeric.c.

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().

116 {
117  digitbuf_free(var->buf);
118  var->buf = digitbuf_alloc(ndigits + 1);
119  if (var->buf == NULL)
120  return -1;
121  var->buf[0] = 0;
122  var->digits = var->buf + 1;
123  var->ndigits = ndigits;
124  return 0;
125 }
NumericDigit * buf
#define digitbuf_alloc(size)
Definition: numeric.c:18
NumericDigit * digits
#define digitbuf_free(buf)
Definition: numeric.c:19

◆ cmp_abs()

static int cmp_abs ( numeric var1,
numeric var2 
)
static

Definition at line 493 of file numeric.c.

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

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

494 {
495  int i1 = 0;
496  int i2 = 0;
497  int w1 = var1->weight;
498  int w2 = var2->weight;
499  int stat;
500 
501  while (w1 > w2 && i1 < var1->ndigits)
502  {
503  if (var1->digits[i1++] != 0)
504  return 1;
505  w1--;
506  }
507  while (w2 > w1 && i2 < var2->ndigits)
508  {
509  if (var2->digits[i2++] != 0)
510  return -1;
511  w2--;
512  }
513 
514  if (w1 == w2)
515  {
516  while (i1 < var1->ndigits && i2 < var2->ndigits)
517  {
518  stat = var1->digits[i1++] - var2->digits[i2++];
519  if (stat)
520  {
521  if (stat > 0)
522  return 1;
523  return -1;
524  }
525  }
526  }
527 
528  while (i1 < var1->ndigits)
529  {
530  if (var1->digits[i1++] != 0)
531  return 1;
532  }
533  while (i2 < var2->ndigits)
534  {
535  if (var2->digits[i2++] != 0)
536  return -1;
537  }
538 
539  return 0;
540 }
NumericDigit * digits
#define stat(a, b)
Definition: win32_port.h:255

◆ get_str_from_var()

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

Definition at line 312 of file numeric.c.

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().

313 {
314  char *str;
315  char *cp;
316  int i;
317  int d;
318 
319  if (var->sign == NUMERIC_NAN)
320  {
321  str = (char *) pgtypes_alloc(4);
322  if (str == NULL)
323  return NULL;
324  sprintf(str, "NaN");
325  return str;
326  }
327 
328  /*
329  * Check if we must round up before printing the value and do so.
330  */
331  i = dscale + var->weight + 1;
332  if (i >= 0 && var->ndigits > i)
333  {
334  int carry = (var->digits[i] > 4) ? 1 : 0;
335 
336  var->ndigits = i;
337 
338  while (carry)
339  {
340  carry += var->digits[--i];
341  var->digits[i] = carry % 10;
342  carry /= 10;
343  }
344 
345  if (i < 0)
346  {
347  var->digits--;
348  var->ndigits++;
349  var->weight++;
350  }
351  }
352  else
353  var->ndigits = Max(0, Min(i, var->ndigits));
354 
355  /*
356  * Allocate space for the result
357  */
358  if ((str = (char *) pgtypes_alloc(Max(0, dscale) + Max(0, var->weight) + 4)) == NULL)
359  return NULL;
360  cp = str;
361 
362  /*
363  * Output a dash for negative values
364  */
365  if (var->sign == NUMERIC_NEG)
366  *cp++ = '-';
367 
368  /*
369  * Output all digits before the decimal point
370  */
371  i = Max(var->weight, 0);
372  d = 0;
373 
374  while (i >= 0)
375  {
376  if (i <= var->weight && d < var->ndigits)
377  *cp++ = var->digits[d++] + '0';
378  else
379  *cp++ = '0';
380  i--;
381  }
382 
383  /*
384  * If requested, output a decimal point and all the digits that follow it.
385  */
386  if (dscale > 0)
387  {
388  *cp++ = '.';
389  while (i >= -dscale)
390  {
391  if (i <= var->weight && d < var->ndigits)
392  *cp++ = var->digits[d++] + '0';
393  else
394  *cp++ = '0';
395  i--;
396  }
397  }
398 
399  /*
400  * terminate the string and return it
401  */
402  *cp = '\0';
403  return str;
404 }
#define Min(x, y)
Definition: numeric.c:14
#define NUMERIC_NEG
Definition: numeric.c:168
#define sprintf
Definition: port.h:194
char * pgtypes_alloc(long size)
Definition: common.c:10
NumericDigit * digits
#define NUMERIC_NAN
Definition: numeric.c:170
int i
#define Max(x, y)
Definition: numeric.c:13

◆ numericvar_to_double()

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

Definition at line 1520 of file numeric.c.

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().

1521 {
1522  char *tmp;
1523  double val;
1524  char *endptr;
1525  numeric *varcopy = PGTYPESnumeric_new();
1526 
1527  if (varcopy == NULL)
1528  return -1;
1529 
1530  if (PGTYPESnumeric_copy(var, varcopy) < 0)
1531  {
1532  PGTYPESnumeric_free(varcopy);
1533  return -1;
1534  }
1535 
1536  tmp = get_str_from_var(varcopy, varcopy->dscale);
1537  PGTYPESnumeric_free(varcopy);
1538 
1539  if (tmp == NULL)
1540  return -1;
1541 
1542  /*
1543  * strtod does not reset errno to 0 in case of success.
1544  */
1545  errno = 0;
1546  val = strtod(tmp, &endptr);
1547  if (errno == ERANGE)
1548  {
1549  free(tmp);
1550  if (val == 0)
1551  errno = PGTYPES_NUM_UNDERFLOW;
1552  else
1553  errno = PGTYPES_NUM_OVERFLOW;
1554  return -1;
1555  }
1556 
1557  /* can't free tmp yet, endptr points still into it */
1558  if (*endptr != '\0')
1559  {
1560  /* shouldn't happen ... */
1561  free(tmp);
1562  errno = PGTYPES_NUM_BAD_NUMERIC;
1563  return -1;
1564  }
1565  free(tmp);
1566  *dp = val;
1567  return 0;
1568 }
numeric * PGTYPESnumeric_new(void)
Definition: numeric.c:128
void PGTYPESnumeric_free(numeric *var)
Definition: numeric.c:471
int PGTYPESnumeric_copy(numeric *src, numeric *dst)
Definition: numeric.c:1476
#define PGTYPES_NUM_OVERFLOW
Definition: pgtypes_error.h:3
#define PGTYPES_NUM_UNDERFLOW
Definition: pgtypes_error.h:6
#define free(a)
Definition: header.h:65
static char * get_str_from_var(numeric *var, int dscale)
Definition: numeric.c:312
#define PGTYPES_NUM_BAD_NUMERIC
Definition: pgtypes_error.h:4
long val
Definition: informix.c:684

◆ PGTYPESdecimal_free()

void PGTYPESdecimal_free ( decimal var)

Definition at line 478 of file numeric.c.

References free.

Referenced by main().

479 {
480  free(var);
481 }
#define free(a)
Definition: header.h:65

◆ PGTYPESdecimal_new()

decimal* PGTYPESdecimal_new ( void  )

Definition at line 145 of file numeric.c.

References pgtypes_alloc().

Referenced by main().

146 {
147  decimal *var;
148 
149  if ((var = (decimal *) pgtypes_alloc(sizeof(decimal))) == NULL)
150  return NULL;
151 
152  memset(var, 0, sizeof(decimal));
153 
154  return var;
155 }
char * pgtypes_alloc(long size)
Definition: common.c:10

◆ PGTYPESnumeric_add()

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

Definition at line 723 of file numeric.c.

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().

724 {
725  /*
726  * Decide on the signs of the two variables what to do
727  */
728  if (var1->sign == NUMERIC_POS)
729  {
730  if (var2->sign == NUMERIC_POS)
731  {
732  /*
733  * Both are positive result = +(ABS(var1) + ABS(var2))
734  */
735  if (add_abs(var1, var2, result) != 0)
736  return -1;
737  result->sign = NUMERIC_POS;
738  }
739  else
740  {
741  /*
742  * var1 is positive, var2 is negative Must compare absolute values
743  */
744  switch (cmp_abs(var1, var2))
745  {
746  case 0:
747  /* ----------
748  * ABS(var1) == ABS(var2)
749  * result = ZERO
750  * ----------
751  */
752  zero_var(result);
753  result->rscale = Max(var1->rscale, var2->rscale);
754  result->dscale = Max(var1->dscale, var2->dscale);
755  break;
756 
757  case 1:
758  /* ----------
759  * ABS(var1) > ABS(var2)
760  * result = +(ABS(var1) - ABS(var2))
761  * ----------
762  */
763  if (sub_abs(var1, var2, result) != 0)
764  return -1;
765  result->sign = NUMERIC_POS;
766  break;
767 
768  case -1:
769  /* ----------
770  * ABS(var1) < ABS(var2)
771  * result = -(ABS(var2) - ABS(var1))
772  * ----------
773  */
774  if (sub_abs(var2, var1, result) != 0)
775  return -1;
776  result->sign = NUMERIC_NEG;
777  break;
778  }
779  }
780  }
781  else
782  {
783  if (var2->sign == NUMERIC_POS)
784  {
785  /* ----------
786  * var1 is negative, var2 is 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_NEG;
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_POS;
823  break;
824  }
825  }
826  else
827  {
828  /* ----------
829  * Both are negative
830  * result = -(ABS(var1) + ABS(var2))
831  * ----------
832  */
833  if (add_abs(var1, var2, result) != 0)
834  return -1;
835  result->sign = NUMERIC_NEG;
836  }
837  }
838 
839  return 0;
840 }
static int add_abs(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:551
#define NUMERIC_POS
Definition: numeric.c:167
static void zero_var(numeric *var)
Definition: numeric.c:460
#define NUMERIC_NEG
Definition: numeric.c:168
static int cmp_abs(numeric *var1, numeric *var2)
Definition: numeric.c:493
static int sub_abs(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:639
#define Max(x, y)
Definition: numeric.c:13

◆ PGTYPESnumeric_cmp()

int PGTYPESnumeric_cmp ( numeric var1,
numeric var2 
)

Definition at line 1368 of file numeric.c.

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

Referenced by deccmp(), and main().

1369 {
1370  /* use cmp_abs function to calculate the result */
1371 
1372  /* both are positive: normal comparison with cmp_abs */
1373  if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_POS)
1374  return cmp_abs(var1, var2);
1375 
1376  /* both are negative: return the inverse of the normal comparison */
1377  if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_NEG)
1378  {
1379  /*
1380  * instead of inverting the result, we invert the parameter ordering
1381  */
1382  return cmp_abs(var2, var1);
1383  }
1384 
1385  /* one is positive, one is negative: trivial */
1386  if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_NEG)
1387  return 1;
1388  if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_POS)
1389  return -1;
1390 
1391  errno = PGTYPES_NUM_BAD_NUMERIC;
1392  return INT_MAX;
1393 
1394 }
#define NUMERIC_POS
Definition: numeric.c:167
#define NUMERIC_NEG
Definition: numeric.c:168
static int cmp_abs(numeric *var1, numeric *var2)
Definition: numeric.c:493
#define PGTYPES_NUM_BAD_NUMERIC
Definition: pgtypes_error.h:4

◆ PGTYPESnumeric_copy()

int PGTYPESnumeric_copy ( numeric src,
numeric dst 
)

Definition at line 1476 of file numeric.c.

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().

1477 {
1478  int i;
1479 
1480  if (dst == NULL)
1481  return -1;
1482  zero_var(dst);
1483 
1484  dst->weight = src->weight;
1485  dst->rscale = src->rscale;
1486  dst->dscale = src->dscale;
1487  dst->sign = src->sign;
1488 
1489  if (alloc_var(dst, src->ndigits) != 0)
1490  return -1;
1491 
1492  for (i = 0; i < src->ndigits; i++)
1493  dst->digits[i] = src->digits[i];
1494 
1495  return 0;
1496 }
static void zero_var(numeric *var)
Definition: numeric.c:460
NumericDigit * digits
static int alloc_var(numeric *var, int ndigits)
Definition: numeric.c:115
int i

◆ PGTYPESnumeric_div()

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

Definition at line 1139 of file numeric.c.

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

Referenced by decdiv(), and main().

1140 {
1141  NumericDigit *res_digits;
1142  int res_ndigits;
1143  int res_sign;
1144  int res_weight;
1145  numeric dividend;
1146  numeric divisor[10];
1147  int ndigits_tmp;
1148  int weight_tmp;
1149  int rscale_tmp;
1150  int ri;
1151  int i;
1152  long guess;
1153  long first_have;
1154  long first_div;
1155  int first_nextdigit;
1156  int stat = 0;
1157  int rscale;
1158  int res_dscale = select_div_scale(var1, var2, &rscale);
1159  int err = -1;
1160  NumericDigit *tmp_buf;
1161 
1162  /*
1163  * First of all division by zero check
1164  */
1165  ndigits_tmp = var2->ndigits + 1;
1166  if (ndigits_tmp == 1)
1167  {
1168  errno = PGTYPES_NUM_DIVIDE_ZERO;
1169  return -1;
1170  }
1171 
1172  /*
1173  * Determine the result sign, weight and number of digits to calculate
1174  */
1175  if (var1->sign == var2->sign)
1176  res_sign = NUMERIC_POS;
1177  else
1178  res_sign = NUMERIC_NEG;
1179  res_weight = var1->weight - var2->weight + 1;
1180  res_ndigits = rscale + res_weight;
1181  if (res_ndigits <= 0)
1182  res_ndigits = 1;
1183 
1184  /*
1185  * Now result zero check
1186  */
1187  if (var1->ndigits == 0)
1188  {
1189  zero_var(result);
1190  result->rscale = rscale;
1191  return 0;
1192  }
1193 
1194  /*
1195  * Initialize local variables
1196  */
1197  init_var(&dividend);
1198  for (i = 1; i < 10; i++)
1199  init_var(&divisor[i]);
1200 
1201  /*
1202  * Make a copy of the divisor which has one leading zero digit
1203  */
1204  divisor[1].ndigits = ndigits_tmp;
1205  divisor[1].rscale = var2->ndigits;
1206  divisor[1].sign = NUMERIC_POS;
1207  divisor[1].buf = digitbuf_alloc(ndigits_tmp);
1208  if (divisor[1].buf == NULL)
1209  goto done;
1210  divisor[1].digits = divisor[1].buf;
1211  divisor[1].digits[0] = 0;
1212  memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
1213 
1214  /*
1215  * Make a copy of the dividend
1216  */
1217  dividend.ndigits = var1->ndigits;
1218  dividend.weight = 0;
1219  dividend.rscale = var1->ndigits;
1220  dividend.sign = NUMERIC_POS;
1221  dividend.buf = digitbuf_alloc(var1->ndigits);
1222  if (dividend.buf == NULL)
1223  goto done;
1224  dividend.digits = dividend.buf;
1225  memcpy(dividend.digits, var1->digits, var1->ndigits);
1226 
1227  /*
1228  * Setup the result. Do the allocation in a temporary buffer first, so we
1229  * don't free result->buf unless we have successfully allocated a buffer
1230  * to replace it with.
1231  */
1232  tmp_buf = digitbuf_alloc(res_ndigits + 2);
1233  if (tmp_buf == NULL)
1234  goto done;
1235  digitbuf_free(result->buf);
1236  result->buf = tmp_buf;
1237  res_digits = result->buf;
1238  result->digits = res_digits;
1239  result->ndigits = res_ndigits;
1240  result->weight = res_weight;
1241  result->rscale = rscale;
1242  result->sign = res_sign;
1243  res_digits[0] = 0;
1244 
1245  first_div = divisor[1].digits[1] * 10;
1246  if (ndigits_tmp > 2)
1247  first_div += divisor[1].digits[2];
1248 
1249  first_have = 0;
1250  first_nextdigit = 0;
1251 
1252  weight_tmp = 1;
1253  rscale_tmp = divisor[1].rscale;
1254 
1255  for (ri = 0; ri <= res_ndigits; ri++)
1256  {
1257  first_have = first_have * 10;
1258  if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1259  first_have += dividend.digits[first_nextdigit];
1260  first_nextdigit++;
1261 
1262  guess = (first_have * 10) / first_div + 1;
1263  if (guess > 9)
1264  guess = 9;
1265 
1266  while (guess > 0)
1267  {
1268  if (divisor[guess].buf == NULL)
1269  {
1270  int i;
1271  long sum = 0;
1272 
1273  memcpy(&divisor[guess], &divisor[1], sizeof(numeric));
1274  divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);
1275  if (divisor[guess].buf == NULL)
1276  goto done;
1277  divisor[guess].digits = divisor[guess].buf;
1278  for (i = divisor[1].ndigits - 1; i >= 0; i--)
1279  {
1280  sum += divisor[1].digits[i] * guess;
1281  divisor[guess].digits[i] = sum % 10;
1282  sum /= 10;
1283  }
1284  }
1285 
1286  divisor[guess].weight = weight_tmp;
1287  divisor[guess].rscale = rscale_tmp;
1288 
1289  stat = cmp_abs(&dividend, &divisor[guess]);
1290  if (stat >= 0)
1291  break;
1292 
1293  guess--;
1294  }
1295 
1296  res_digits[ri + 1] = guess;
1297  if (stat == 0)
1298  {
1299  ri++;
1300  break;
1301  }
1302 
1303  weight_tmp--;
1304  rscale_tmp++;
1305 
1306  if (guess == 0)
1307  continue;
1308 
1309  if (sub_abs(&dividend, &divisor[guess], &dividend) != 0)
1310  goto done;
1311 
1312  first_nextdigit = dividend.weight - weight_tmp;
1313  first_have = 0;
1314  if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1315  first_have = dividend.digits[first_nextdigit];
1316  first_nextdigit++;
1317  }
1318 
1319  result->ndigits = ri + 1;
1320  if (ri == res_ndigits + 1)
1321  {
1322  int carry = (res_digits[ri] > 4) ? 1 : 0;
1323 
1324  result->ndigits = ri;
1325  res_digits[ri] = 0;
1326 
1327  while (carry && ri > 0)
1328  {
1329  carry += res_digits[--ri];
1330  res_digits[ri] = carry % 10;
1331  carry /= 10;
1332  }
1333  }
1334 
1335  while (result->ndigits > 0 && *(result->digits) == 0)
1336  {
1337  (result->digits)++;
1338  (result->weight)--;
1339  (result->ndigits)--;
1340  }
1341  while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)
1342  (result->ndigits)--;
1343  if (result->ndigits == 0)
1344  result->sign = NUMERIC_POS;
1345 
1346  result->dscale = res_dscale;
1347  err = 0; /* if we've made it this far, return success */
1348 
1349 done:
1350 
1351  /*
1352  * Tidy up
1353  */
1354  if (dividend.buf != NULL)
1355  digitbuf_free(dividend.buf);
1356 
1357  for (i = 1; i < 10; i++)
1358  {
1359  if (divisor[i].buf != NULL)
1360  digitbuf_free(divisor[i].buf);
1361  }
1362 
1363  return err;
1364 }
#define PGTYPES_NUM_DIVIDE_ZERO
Definition: pgtypes_error.h:5
#define NUMERIC_POS
Definition: numeric.c:167
static void zero_var(numeric *var)
Definition: numeric.c:460
NumericDigit * buf
#define NUMERIC_NEG
Definition: numeric.c:168
#define digitbuf_alloc(size)
Definition: numeric.c:18
NumericDigit * digits
static char * buf
Definition: pg_test_fsync.c:67
int16 NumericDigit
Definition: numeric.c:102
#define stat(a, b)
Definition: win32_port.h:255
static int cmp_abs(numeric *var1, numeric *var2)
Definition: numeric.c:493
static int select_div_scale(numeric *var1, numeric *var2, int *rscale)
Definition: numeric.c:1073
static int sub_abs(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:639
#define digitbuf_free(buf)
Definition: numeric.c:19
#define init_var(v)
Definition: numeric.c:16
int i
int digits
Definition: informix.c:686

◆ PGTYPESnumeric_free()

◆ PGTYPESnumeric_from_asc()

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

Definition at line 407 of file numeric.c.

References pgtypes_alloc(), PGTYPESnumeric_free(), set_var_from_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().

408 {
409  numeric *value = (numeric *) pgtypes_alloc(sizeof(numeric));
410  int ret;
411 
412  char *realptr;
413  char **ptr = (endptr != NULL) ? endptr : &realptr;
414 
415  if (!value)
416  return NULL;
417 
418  ret = set_var_from_str(str, ptr, value);
419  if (ret)
420  {
421  PGTYPESnumeric_free(value);
422  return NULL;
423  }
424 
425  return value;
426 }
void PGTYPESnumeric_free(numeric *var)
Definition: numeric.c:471
static struct @145 value
char * pgtypes_alloc(long size)
Definition: common.c:10
static int set_var_from_str(char *str, char **ptr, numeric *dest)
Definition: numeric.c:164

◆ PGTYPESnumeric_from_decimal()

int PGTYPESnumeric_from_decimal ( decimal src,
numeric dst 
)

Definition at line 1653 of file numeric.c.

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().

1654 {
1655  int i;
1656 
1657  zero_var(dst);
1658 
1659  dst->weight = src->weight;
1660  dst->rscale = src->rscale;
1661  dst->dscale = src->dscale;
1662  dst->sign = src->sign;
1663 
1664  if (alloc_var(dst, src->ndigits) != 0)
1665  return -1;
1666 
1667  for (i = 0; i < src->ndigits; i++)
1668  dst->digits[i] = src->digits[i];
1669 
1670  return 0;
1671 }
static void zero_var(numeric *var)
Definition: numeric.c:460
NumericDigit * digits
NumericDigit digits[DECSIZE]
static int alloc_var(numeric *var, int ndigits)
Definition: numeric.c:115
int i

◆ PGTYPESnumeric_from_double()

int PGTYPESnumeric_from_double ( double  d,
numeric dst 
)

Definition at line 1499 of file numeric.c.

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

Referenced by deccvdbl().

1500 {
1501  char buffer[DBL_DIG + 100];
1502  numeric *tmp;
1503  int i;
1504 
1505  if (sprintf(buffer, "%.*g", DBL_DIG, d) <= 0)
1506  return -1;
1507 
1508  if ((tmp = PGTYPESnumeric_from_asc(buffer, NULL)) == NULL)
1509  return -1;
1510  i = PGTYPESnumeric_copy(tmp, dst);
1511  PGTYPESnumeric_free(tmp);
1512  if (i != 0)
1513  return -1;
1514 
1515  errno = 0;
1516  return 0;
1517 }
void PGTYPESnumeric_free(numeric *var)
Definition: numeric.c:471
#define sprintf
Definition: port.h:194
int PGTYPESnumeric_copy(numeric *src, numeric *dst)
Definition: numeric.c:1476
numeric * PGTYPESnumeric_from_asc(char *str, char **endptr)
Definition: numeric.c:407
int i

◆ PGTYPESnumeric_from_int()

int PGTYPESnumeric_from_int ( signed int  int_val,
numeric var 
)

Definition at line 1397 of file numeric.c.

References PGTYPESnumeric_from_long().

Referenced by deccvint(), and main().

1398 {
1399  /* implicit conversion */
1400  signed long int long_int = int_val;
1401 
1402  return PGTYPESnumeric_from_long(long_int, var);
1403 }
int PGTYPESnumeric_from_long(signed long int long_val, numeric *var)
Definition: numeric.c:1406

◆ PGTYPESnumeric_from_long()

int PGTYPESnumeric_from_long ( signed long int  long_val,
numeric var 
)

Definition at line 1406 of file numeric.c.

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().

1407 {
1408  /* calculate the size of the long int number */
1409  /* a number n needs log_10 n digits */
1410 
1411  /*
1412  * however we multiply by 10 each time and compare instead of calculating
1413  * the logarithm
1414  */
1415 
1416  int size = 0;
1417  int i;
1418  signed long int abs_long_val = long_val;
1419  signed long int extract;
1420  signed long int reach_limit;
1421 
1422  if (abs_long_val < 0)
1423  {
1424  abs_long_val *= -1;
1425  var->sign = NUMERIC_NEG;
1426  }
1427  else
1428  var->sign = NUMERIC_POS;
1429 
1430  reach_limit = 1;
1431  do
1432  {
1433  size++;
1434  reach_limit *= 10;
1435  } while (reach_limit - 1 < abs_long_val && reach_limit <= LONG_MAX / 10);
1436 
1437  if (reach_limit > LONG_MAX / 10)
1438  {
1439  /* add the first digit and a .0 */
1440  size += 2;
1441  }
1442  else
1443  {
1444  /* always add a .0 */
1445  size++;
1446  reach_limit /= 10;
1447  }
1448 
1449  if (alloc_var(var, size) < 0)
1450  return -1;
1451 
1452  var->rscale = 1;
1453  var->dscale = 1;
1454  var->weight = size - 2;
1455 
1456  i = 0;
1457  do
1458  {
1459  extract = abs_long_val - (abs_long_val % reach_limit);
1460  var->digits[i] = extract / reach_limit;
1461  abs_long_val -= extract;
1462  i++;
1463  reach_limit /= 10;
1464 
1465  /*
1466  * we can abandon if abs_long_val reaches 0, because the memory is
1467  * initialized properly and filled with '0', so converting 10000 in
1468  * only one step is no problem
1469  */
1470  } while (abs_long_val > 0);
1471 
1472  return 0;
1473 }
#define NUMERIC_POS
Definition: numeric.c:167
#define NUMERIC_NEG
Definition: numeric.c:168
NumericDigit * digits
static int alloc_var(numeric *var, int ndigits)
Definition: numeric.c:115
int i

◆ PGTYPESnumeric_mul()

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

Definition at line 982 of file numeric.c.

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().

983 {
984  NumericDigit *res_buf;
985  NumericDigit *res_digits;
986  int res_ndigits;
987  int res_weight;
988  int res_sign;
989  int i,
990  ri,
991  i1,
992  i2;
993  long sum = 0;
994  int global_rscale = var1->rscale + var2->rscale;
995 
996  res_weight = var1->weight + var2->weight + 2;
997  res_ndigits = var1->ndigits + var2->ndigits + 1;
998  if (var1->sign == var2->sign)
999  res_sign = NUMERIC_POS;
1000  else
1001  res_sign = NUMERIC_NEG;
1002 
1003  if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
1004  return -1;
1005  res_digits = res_buf;
1006  memset(res_digits, 0, res_ndigits);
1007 
1008  ri = res_ndigits;
1009  for (i1 = var1->ndigits - 1; i1 >= 0; i1--)
1010  {
1011  sum = 0;
1012  i = --ri;
1013 
1014  for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
1015  {
1016  sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
1017  res_digits[i--] = sum % 10;
1018  sum /= 10;
1019  }
1020  res_digits[i] = sum;
1021  }
1022 
1023  i = res_weight + global_rscale + 2;
1024  if (i >= 0 && i < res_ndigits)
1025  {
1026  sum = (res_digits[i] > 4) ? 1 : 0;
1027  res_ndigits = i;
1028  i--;
1029  while (sum)
1030  {
1031  sum += res_digits[i];
1032  res_digits[i--] = sum % 10;
1033  sum /= 10;
1034  }
1035  }
1036 
1037  while (res_ndigits > 0 && *res_digits == 0)
1038  {
1039  res_digits++;
1040  res_weight--;
1041  res_ndigits--;
1042  }
1043  while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
1044  res_ndigits--;
1045 
1046  if (res_ndigits == 0)
1047  {
1048  res_sign = NUMERIC_POS;
1049  res_weight = 0;
1050  }
1051 
1052  digitbuf_free(result->buf);
1053  result->buf = res_buf;
1054  result->digits = res_digits;
1055  result->ndigits = res_ndigits;
1056  result->weight = res_weight;
1057  result->rscale = global_rscale;
1058  result->sign = res_sign;
1059  result->dscale = var1->dscale + var2->dscale;
1060 
1061  return 0;
1062 }
#define NUMERIC_POS
Definition: numeric.c:167
NumericDigit * buf
#define NUMERIC_NEG
Definition: numeric.c:168
#define digitbuf_alloc(size)
Definition: numeric.c:18
NumericDigit * digits
int16 NumericDigit
Definition: numeric.c:102
#define digitbuf_free(buf)
Definition: numeric.c:19
int i

◆ PGTYPESnumeric_new()

numeric* PGTYPESnumeric_new ( void  )

Definition at line 128 of file numeric.c.

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().

129 {
130  numeric *var;
131 
132  if ((var = (numeric *) pgtypes_alloc(sizeof(numeric))) == NULL)
133  return NULL;
134 
135  if (alloc_var(var, 0) < 0)
136  {
137  free(var);
138  return NULL;
139  }
140 
141  return var;
142 }
char * pgtypes_alloc(long size)
Definition: common.c:10
static int alloc_var(numeric *var, int ndigits)
Definition: numeric.c:115
#define free(a)
Definition: header.h:65

◆ PGTYPESnumeric_sub()

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

Definition at line 851 of file numeric.c.

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().

852 {
853  /*
854  * Decide on the signs of the two variables what to do
855  */
856  if (var1->sign == NUMERIC_POS)
857  {
858  if (var2->sign == NUMERIC_NEG)
859  {
860  /* ----------
861  * var1 is positive, var2 is negative
862  * result = +(ABS(var1) + ABS(var2))
863  * ----------
864  */
865  if (add_abs(var1, var2, result) != 0)
866  return -1;
867  result->sign = NUMERIC_POS;
868  }
869  else
870  {
871  /* ----------
872  * Both are positive
873  * Must compare absolute values
874  * ----------
875  */
876  switch (cmp_abs(var1, var2))
877  {
878  case 0:
879  /* ----------
880  * ABS(var1) == ABS(var2)
881  * result = ZERO
882  * ----------
883  */
884  zero_var(result);
885  result->rscale = Max(var1->rscale, var2->rscale);
886  result->dscale = Max(var1->dscale, var2->dscale);
887  break;
888 
889  case 1:
890  /* ----------
891  * ABS(var1) > ABS(var2)
892  * result = +(ABS(var1) - ABS(var2))
893  * ----------
894  */
895  if (sub_abs(var1, var2, result) != 0)
896  return -1;
897  result->sign = NUMERIC_POS;
898  break;
899 
900  case -1:
901  /* ----------
902  * ABS(var1) < ABS(var2)
903  * result = -(ABS(var2) - ABS(var1))
904  * ----------
905  */
906  if (sub_abs(var2, var1, result) != 0)
907  return -1;
908  result->sign = NUMERIC_NEG;
909  break;
910  }
911  }
912  }
913  else
914  {
915  if (var2->sign == NUMERIC_NEG)
916  {
917  /* ----------
918  * Both are negative
919  * Must compare absolute values
920  * ----------
921  */
922  switch (cmp_abs(var1, var2))
923  {
924  case 0:
925  /* ----------
926  * ABS(var1) == ABS(var2)
927  * result = ZERO
928  * ----------
929  */
930  zero_var(result);
931  result->rscale = Max(var1->rscale, var2->rscale);
932  result->dscale = Max(var1->dscale, var2->dscale);
933  break;
934 
935  case 1:
936  /* ----------
937  * ABS(var1) > ABS(var2)
938  * result = -(ABS(var1) - ABS(var2))
939  * ----------
940  */
941  if (sub_abs(var1, var2, result) != 0)
942  return -1;
943  result->sign = NUMERIC_NEG;
944  break;
945 
946  case -1:
947  /* ----------
948  * ABS(var1) < ABS(var2)
949  * result = +(ABS(var2) - ABS(var1))
950  * ----------
951  */
952  if (sub_abs(var2, var1, result) != 0)
953  return -1;
954  result->sign = NUMERIC_POS;
955  break;
956  }
957  }
958  else
959  {
960  /* ----------
961  * var1 is negative, var2 is positive
962  * result = -(ABS(var1) + ABS(var2))
963  * ----------
964  */
965  if (add_abs(var1, var2, result) != 0)
966  return -1;
967  result->sign = NUMERIC_NEG;
968  }
969  }
970 
971  return 0;
972 }
static int add_abs(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:551
#define NUMERIC_POS
Definition: numeric.c:167
static void zero_var(numeric *var)
Definition: numeric.c:460
#define NUMERIC_NEG
Definition: numeric.c:168
static int cmp_abs(numeric *var1, numeric *var2)
Definition: numeric.c:493
static int sub_abs(numeric *var1, numeric *var2, numeric *result)
Definition: numeric.c:639
#define Max(x, y)
Definition: numeric.c:13

◆ PGTYPESnumeric_to_asc()

char* PGTYPESnumeric_to_asc ( numeric num,
int  dscale 
)

Definition at line 429 of file numeric.c.

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().

430 {
431  numeric *numcopy = PGTYPESnumeric_new();
432  char *s;
433 
434  if (numcopy == NULL)
435  return NULL;
436 
437  if (PGTYPESnumeric_copy(num, numcopy) < 0)
438  {
439  PGTYPESnumeric_free(numcopy);
440  return NULL;
441  }
442 
443  if (dscale < 0)
444  dscale = num->dscale;
445 
446  /* get_str_from_var may change its argument */
447  s = get_str_from_var(numcopy, dscale);
448  PGTYPESnumeric_free(numcopy);
449  return s;
450 }
numeric * PGTYPESnumeric_new(void)
Definition: numeric.c:128
void PGTYPESnumeric_free(numeric *var)
Definition: numeric.c:471
int PGTYPESnumeric_copy(numeric *src, numeric *dst)
Definition: numeric.c:1476
static char * get_str_from_var(numeric *var, int dscale)
Definition: numeric.c:312

◆ PGTYPESnumeric_to_decimal()

int PGTYPESnumeric_to_decimal ( numeric src,
decimal dst 
)

Definition at line 1630 of file numeric.c.

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().

1631 {
1632  int i;
1633 
1634  if (src->ndigits > DECSIZE)
1635  {
1636  errno = PGTYPES_NUM_OVERFLOW;
1637  return -1;
1638  }
1639 
1640  dst->weight = src->weight;
1641  dst->rscale = src->rscale;
1642  dst->dscale = src->dscale;
1643  dst->sign = src->sign;
1644  dst->ndigits = src->ndigits;
1645 
1646  for (i = 0; i < src->ndigits; i++)
1647  dst->digits[i] = src->digits[i];
1648 
1649  return 0;
1650 }
NumericDigit * digits
NumericDigit digits[DECSIZE]
#define PGTYPES_NUM_OVERFLOW
Definition: pgtypes_error.h:3
#define DECSIZE
int i

◆ PGTYPESnumeric_to_double()

int PGTYPESnumeric_to_double ( numeric nv,
double *  dp 
)

Definition at line 1571 of file numeric.c.

References numericvar_to_double().

Referenced by dectodbl(), and main().

1572 {
1573  double tmp;
1574 
1575  if (numericvar_to_double(nv, &tmp) != 0)
1576  return -1;
1577  *dp = tmp;
1578  return 0;
1579 }
static int numericvar_to_double(numeric *var, double *dp)
Definition: numeric.c:1520

◆ PGTYPESnumeric_to_int()

int PGTYPESnumeric_to_int ( numeric nv,
int *  ip 
)

Definition at line 1582 of file numeric.c.

References i, PGTYPES_NUM_OVERFLOW, and PGTYPESnumeric_to_long().

Referenced by dectoint(), and main().

1583 {
1584  long l;
1585  int i;
1586 
1587  if ((i = PGTYPESnumeric_to_long(nv, &l)) != 0)
1588  return i;
1589 
1590  if (l < -INT_MAX || l > INT_MAX)
1591  {
1592  errno = PGTYPES_NUM_OVERFLOW;
1593  return -1;
1594  }
1595 
1596  *ip = (int) l;
1597  return 0;
1598 }
#define PGTYPES_NUM_OVERFLOW
Definition: pgtypes_error.h:3
int i
int PGTYPESnumeric_to_long(numeric *nv, long *lp)
Definition: numeric.c:1601

◆ PGTYPESnumeric_to_long()

int PGTYPESnumeric_to_long ( numeric nv,
long *  lp 
)

Definition at line 1601 of file numeric.c.

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

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

1602 {
1603  char *s = PGTYPESnumeric_to_asc(nv, 0);
1604  char *endptr;
1605 
1606  if (s == NULL)
1607  return -1;
1608 
1609  errno = 0;
1610  *lp = strtol(s, &endptr, 10);
1611  if (endptr == s)
1612  {
1613  /* this should not happen actually */
1614  free(s);
1615  return -1;
1616  }
1617  free(s);
1618  if (errno == ERANGE)
1619  {
1620  if (*lp == LONG_MIN)
1621  errno = PGTYPES_NUM_UNDERFLOW;
1622  else
1623  errno = PGTYPES_NUM_OVERFLOW;
1624  return -1;
1625  }
1626  return 0;
1627 }
#define PGTYPES_NUM_OVERFLOW
Definition: pgtypes_error.h:3
#define PGTYPES_NUM_UNDERFLOW
Definition: pgtypes_error.h:6
#define free(a)
Definition: header.h:65
char * PGTYPESnumeric_to_asc(numeric *num, int dscale)
Definition: numeric.c:429

◆ select_div_scale()

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

Definition at line 1073 of file numeric.c.

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().

1074 {
1075  int weight1,
1076  weight2,
1077  qweight,
1078  i;
1079  NumericDigit firstdigit1,
1080  firstdigit2;
1081  int res_dscale;
1082 
1083  /*
1084  * The result scale of a division isn't specified in any SQL standard. For
1085  * PostgreSQL we select a display scale that will give at least
1086  * NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a
1087  * result no less accurate than float8; but use a scale not less than
1088  * either input's display scale.
1089  */
1090 
1091  /* Get the actual (normalized) weight and first digit of each input */
1092 
1093  weight1 = 0; /* values to use if var1 is zero */
1094  firstdigit1 = 0;
1095  for (i = 0; i < var1->ndigits; i++)
1096  {
1097  firstdigit1 = var1->digits[i];
1098  if (firstdigit1 != 0)
1099  {
1100  weight1 = var1->weight - i;
1101  break;
1102  }
1103  }
1104 
1105  weight2 = 0; /* values to use if var2 is zero */
1106  firstdigit2 = 0;
1107  for (i = 0; i < var2->ndigits; i++)
1108  {
1109  firstdigit2 = var2->digits[i];
1110  if (firstdigit2 != 0)
1111  {
1112  weight2 = var2->weight - i;
1113  break;
1114  }
1115  }
1116 
1117  /*
1118  * Estimate weight of quotient. If the two first digits are equal, we
1119  * can't be sure, but assume that var1 is less than var2.
1120  */
1121  qweight = weight1 - weight2;
1122  if (firstdigit1 <= firstdigit2)
1123  qweight--;
1124 
1125  /* Select display scale */
1126  res_dscale = NUMERIC_MIN_SIG_DIGITS - qweight;
1127  res_dscale = Max(res_dscale, var1->dscale);
1128  res_dscale = Max(res_dscale, var2->dscale);
1129  res_dscale = Max(res_dscale, NUMERIC_MIN_DISPLAY_SCALE);
1130  res_dscale = Min(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1131 
1132  /* Select result scale */
1133  *rscale = res_dscale + 4;
1134 
1135  return res_dscale;
1136 }
#define NUMERIC_MIN_SIG_DIGITS
Definition: numeric.h:39
#define Min(x, y)
Definition: numeric.c:14
NumericDigit * digits
int16 NumericDigit
Definition: numeric.c:102
#define NUMERIC_MIN_DISPLAY_SCALE
Definition: numeric.h:30
int i
#define Max(x, y)
Definition: numeric.c:13
#define NUMERIC_MAX_DISPLAY_SCALE
Definition: numeric.h:29

◆ set_var_from_str()

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

Definition at line 164 of file numeric.c.

References alloc_var(), numeric::digits, numeric::dscale, i, numeric::ndigits, NUMERIC_NAN, NUMERIC_NEG, NUMERIC_POS, pg_strncasecmp(), PGTYPES_NUM_BAD_NUMERIC, numeric::rscale, numeric::sign, generate_unaccent_rules::str, and numeric::weight.

Referenced by PGTYPESnumeric_from_asc().

165 {
166  bool have_dp = false;
167  int i = 0;
168 
169  errno = 0;
170  *ptr = str;
171  while (*(*ptr))
172  {
173  if (!isspace((unsigned char) *(*ptr)))
174  break;
175  (*ptr)++;
176  }
177 
178  if (pg_strncasecmp(*ptr, "NaN", 3) == 0)
179  {
180  *ptr += 3;
181  dest->sign = NUMERIC_NAN;
182 
183  /* Should be nothing left but spaces */
184  while (*(*ptr))
185  {
186  if (!isspace((unsigned char) *(*ptr)))
187  {
188  errno = PGTYPES_NUM_BAD_NUMERIC;
189  return -1;
190  }
191  (*ptr)++;
192  }
193 
194  return 0;
195  }
196 
197  if (alloc_var(dest, strlen((*ptr))) < 0)
198  return -1;
199  dest->weight = -1;
200  dest->dscale = 0;
201  dest->sign = NUMERIC_POS;
202 
203  switch (*(*ptr))
204  {
205  case '+':
206  dest->sign = NUMERIC_POS;
207  (*ptr)++;
208  break;
209 
210  case '-':
211  dest->sign = NUMERIC_NEG;
212  (*ptr)++;
213  break;
214  }
215 
216  if (*(*ptr) == '.')
217  {
218  have_dp = true;
219  (*ptr)++;
220  }
221 
222  if (!isdigit((unsigned char) *(*ptr)))
223  {
224  errno = PGTYPES_NUM_BAD_NUMERIC;
225  return -1;
226  }
227 
228  while (*(*ptr))
229  {
230  if (isdigit((unsigned char) *(*ptr)))
231  {
232  dest->digits[i++] = *(*ptr)++ - '0';
233  if (!have_dp)
234  dest->weight++;
235  else
236  dest->dscale++;
237  }
238  else if (*(*ptr) == '.')
239  {
240  if (have_dp)
241  {
242  errno = PGTYPES_NUM_BAD_NUMERIC;
243  return -1;
244  }
245  have_dp = true;
246  (*ptr)++;
247  }
248  else
249  break;
250  }
251  dest->ndigits = i;
252 
253  /* Handle exponent, if any */
254  if (*(*ptr) == 'e' || *(*ptr) == 'E')
255  {
256  long exponent;
257  char *endptr;
258 
259  (*ptr)++;
260  exponent = strtol(*ptr, &endptr, 10);
261  if (endptr == (*ptr))
262  {
263  errno = PGTYPES_NUM_BAD_NUMERIC;
264  return -1;
265  }
266  (*ptr) = endptr;
267  if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
268  {
269  errno = PGTYPES_NUM_BAD_NUMERIC;
270  return -1;
271  }
272  dest->weight += (int) exponent;
273  dest->dscale -= (int) exponent;
274  if (dest->dscale < 0)
275  dest->dscale = 0;
276  }
277 
278  /* Should be nothing left but spaces */
279  while (*(*ptr))
280  {
281  if (!isspace((unsigned char) *(*ptr)))
282  {
283  errno = PGTYPES_NUM_BAD_NUMERIC;
284  return -1;
285  }
286  (*ptr)++;
287  }
288 
289  /* Strip any leading zeroes */
290  while (dest->ndigits > 0 && *(dest->digits) == 0)
291  {
292  (dest->digits)++;
293  (dest->weight)--;
294  (dest->ndigits)--;
295  }
296  if (dest->ndigits == 0)
297  dest->weight = 0;
298 
299  dest->rscale = dest->dscale;
300  return 0;
301 }
#define NUMERIC_POS
Definition: numeric.c:167
#define NUMERIC_NEG
Definition: numeric.c:168
int pg_strncasecmp(const char *s1, const char *s2, size_t n)
Definition: pgstrcasecmp.c:69
NumericDigit * digits
#define NUMERIC_NAN
Definition: numeric.c:170
static int alloc_var(numeric *var, int ndigits)
Definition: numeric.c:115
#define PGTYPES_NUM_BAD_NUMERIC
Definition: pgtypes_error.h:4
int i

◆ sub_abs()

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

Definition at line 639 of file numeric.c.

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().

640 {
641  NumericDigit *res_buf;
642  NumericDigit *res_digits;
643  int res_ndigits;
644  int res_weight;
645  int res_rscale;
646  int res_dscale;
647  int i,
648  i1,
649  i2;
650  int borrow = 0;
651 
652  /* copy these values into local vars for speed in inner loop */
653  int var1ndigits = var1->ndigits;
654  int var2ndigits = var2->ndigits;
655  NumericDigit *var1digits = var1->digits;
656  NumericDigit *var2digits = var2->digits;
657 
658  res_weight = var1->weight;
659  res_rscale = Max(var1->rscale, var2->rscale);
660  res_dscale = Max(var1->dscale, var2->dscale);
661  res_ndigits = res_rscale + res_weight + 1;
662  if (res_ndigits <= 0)
663  res_ndigits = 1;
664 
665  if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
666  return -1;
667  res_digits = res_buf;
668 
669  i1 = res_rscale + var1->weight + 1;
670  i2 = res_rscale + var2->weight + 1;
671  for (i = res_ndigits - 1; i >= 0; i--)
672  {
673  i1--;
674  i2--;
675  if (i1 >= 0 && i1 < var1ndigits)
676  borrow += var1digits[i1];
677  if (i2 >= 0 && i2 < var2ndigits)
678  borrow -= var2digits[i2];
679 
680  if (borrow < 0)
681  {
682  res_digits[i] = borrow + 10;
683  borrow = -1;
684  }
685  else
686  {
687  res_digits[i] = borrow;
688  borrow = 0;
689  }
690  }
691 
692  while (res_ndigits > 0 && *res_digits == 0)
693  {
694  res_digits++;
695  res_weight--;
696  res_ndigits--;
697  }
698  while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
699  res_ndigits--;
700 
701  if (res_ndigits == 0)
702  res_weight = 0;
703 
704  digitbuf_free(result->buf);
705  result->ndigits = res_ndigits;
706  result->buf = res_buf;
707  result->digits = res_digits;
708  result->weight = res_weight;
709  result->rscale = res_rscale;
710  result->dscale = res_dscale;
711 
712  return 0;
713 }
NumericDigit * buf
#define digitbuf_alloc(size)
Definition: numeric.c:18
NumericDigit * digits
int16 NumericDigit
Definition: numeric.c:102
#define digitbuf_free(buf)
Definition: numeric.c:19
int i
#define Max(x, y)
Definition: numeric.c:13

◆ zero_var()

static void zero_var ( numeric var)
static

Definition at line 460 of file numeric.c.

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().

461 {
462  digitbuf_free(var->buf);
463  var->buf = NULL;
464  var->digits = NULL;
465  var->ndigits = 0;
466  var->weight = 0; /* by convention; doesn't really matter */
467  var->sign = NUMERIC_POS; /* anything but NAN... */
468 }
#define NUMERIC_POS
Definition: numeric.c:167
NumericDigit * buf
NumericDigit * digits
#define digitbuf_free(buf)
Definition: numeric.c:19