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:74
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:274

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 = 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 = 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:169
#define NUMERIC_NAN
Definition: numeric.c:200
const char * str
char * pgtypes_alloc(long size)
Definition: common.c:10
#define Min(x, y)
Definition: numeric.c:14
#define sprintf
Definition: port.h:241

References numeric::digits, i, Max, Min, numeric::ndigits, NUMERIC_NAN, NUMERIC_NEG, pgtypes_alloc(), numeric::sign, sprintf, 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 1432 of file numeric.c.

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

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

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 1388 of file numeric.c.

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

1571{
1572 int i;
1573
1574 zero_var(dst);
1575
1576 dst->weight = src->weight;
1577 dst->rscale = src->rscale;
1578 dst->dscale = src->dscale;
1579 dst->sign = src->sign;
1580
1581 if (alloc_var(dst, src->ndigits) != 0)
1582 return -1;
1583
1584 for (i = 0; i < src->ndigits; i++)
1585 dst->digits[i] = src->digits[i];
1586
1587 return 0;
1588}
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 1411 of file numeric.c.

1412{
1413 char buffer[DBL_DIG + 100];
1414 numeric *tmp;
1415 int i;
1416
1417 if (sprintf(buffer, "%.*g", DBL_DIG, d) <= 0)
1418 return -1;
1419
1420 if ((tmp = PGTYPESnumeric_from_asc(buffer, NULL)) == NULL)
1421 return -1;
1422 i = PGTYPESnumeric_copy(tmp, dst);
1424 if (i != 0)
1425 return -1;
1426
1427 errno = 0;
1428 return 0;
1429}
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 1309 of file numeric.c.

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

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 1318 of file numeric.c.

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

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 1547 of file numeric.c.

1548{
1549 int i;
1550
1551 if (src->ndigits > DECSIZE)
1552 {
1553 errno = PGTYPES_NUM_OVERFLOW;
1554 return -1;
1555 }
1556
1557 dst->weight = src->weight;
1558 dst->rscale = src->rscale;
1559 dst->dscale = src->dscale;
1560 dst->sign = src->sign;
1561 dst->ndigits = src->ndigits;
1562
1563 for (i = 0; i < src->ndigits; i++)
1564 dst->digits[i] = src->digits[i];
1565
1566 return 0;
1567}
#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 1483 of file numeric.c.

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

References numericvar_to_double().

Referenced by dectodbl(), and main().

◆ PGTYPESnumeric_to_int()

int PGTYPESnumeric_to_int ( numeric nv,
int *  ip 
)

Definition at line 1494 of file numeric.c.

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

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 1518 of file numeric.c.

1519{
1520 char *s = PGTYPESnumeric_to_asc(nv, 0);
1521 char *endptr;
1522
1523 if (s == NULL)
1524 return -1;
1525
1526 errno = 0;
1527 *lp = strtol(s, &endptr, 10);
1528 if (endptr == s)
1529 {
1530 /* this should not happen actually */
1531 free(s);
1532 return -1;
1533 }
1534 free(s);
1535 if (errno == ERANGE)
1536 {
1537 if (*lp == LONG_MIN)
1538 errno = PGTYPES_NUM_UNDERFLOW;
1539 else
1540 errno = PGTYPES_NUM_OVERFLOW;
1541 return -1;
1542 }
1543 return 0;
1544}
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:40
#define NUMERIC_MIN_SIG_DIGITS
Definition: numeric.h:50
#define NUMERIC_MIN_DISPLAY_SCALE
Definition: numeric.h:41

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 {
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 {
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 {
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 {
178 return -1;
179 }
180 (*ptr) = endptr;
181 if (exponent >= INT_MAX / 2 || exponent <= -(INT_MAX / 2))
182 {
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 {
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 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().