1
#include "postgres_fe.h"
6
#include "pgtypes_error.h"
8
#define Max(x, y) ((x) > (y) ? (x) : (y))
9
#define Min(x, y) ((x) < (y) ? (x) : (y))
11
#define init_var(v) memset(v,0,sizeof(numeric))
13
#define digitbuf_alloc(size) ((NumericDigit *) pgtypes_alloc(size))
14
#define digitbuf_free(buf) \
20
#include "pgtypes_numeric.h"
26
* Do bounds checking and rounding according to the attributes
31
apply_typmod(numeric *var, long typmod)
38
/* Do nothing if we have a default typmod (-1) */
39
if (typmod < (long) (VARHDRSZ))
43
precision = (typmod >> 16) & 0xffff;
44
scale = typmod & 0xffff;
45
maxweight = precision - scale;
47
/* Round to target scale */
48
i = scale + var->weight + 1;
49
if (i >= 0 && var->ndigits > i)
51
int carry = (var->digits[i] > 4) ? 1 : 0;
57
carry += var->digits[--i];
58
var->digits[i] = carry % 10;
70
var->ndigits = Max(0, Min(i, var->ndigits));
73
* Check for overflow - note we can't do this before rounding, because
74
* rounding could raise the weight. Also note that the var's weight
75
* could be inflated by leading zeroes, which will be stripped before
76
* storage but perhaps might not have been yet. In any case, we must
77
* recognize a true zero, whose weight doesn't mean anything.
79
if (var->weight >= maxweight)
81
/* Determine true weight; and check for all-zero result */
82
int tweight = var->weight;
84
for (i = 0; i < var->ndigits; i++)
91
if (tweight >= maxweight && i < var->ndigits)
93
errno = PGTYPES_NUM_OVERFLOW;
107
* Allocate a digit buffer of ndigits digits (plus a spare digit for rounding)
111
alloc_var(numeric *var, int ndigits)
113
digitbuf_free(var->buf);
114
var->buf = digitbuf_alloc(ndigits + 1);
115
if (var->buf == NULL)
118
var->digits = var->buf + 1;
119
var->ndigits = ndigits;
124
PGTYPESnumeric_new(void)
128
if ((var = (numeric *) pgtypes_alloc(sizeof(numeric))) == NULL)
131
if (alloc_var(var, 0) < 0)
140
* Parse a string and put the number into a variable
144
set_var_from_str(char *str, char **ptr, numeric *dest)
146
bool have_dp = FALSE;
153
if (!isspace((unsigned char) *(*ptr)))
158
if (alloc_var(dest, strlen((*ptr))) < 0)
162
dest->sign = NUMERIC_POS;
167
dest->sign = NUMERIC_POS;
172
dest->sign = NUMERIC_NEG;
183
if (!isdigit((unsigned char) *(*ptr)))
185
errno = PGTYPES_NUM_BAD_NUMERIC;
191
if (isdigit((unsigned char) *(*ptr)))
193
dest->digits[i++] = *(*ptr)++ - '0';
199
else if (*(*ptr) == '.')
203
errno = PGTYPES_NUM_BAD_NUMERIC;
214
/* Handle exponent, if any */
215
if (*(*ptr) == 'e' || *(*ptr) == 'E')
221
exponent = strtol((*ptr), &endptr, 10);
222
if (endptr == (*ptr))
224
errno = PGTYPES_NUM_BAD_NUMERIC;
228
if (exponent > NUMERIC_MAX_PRECISION ||
229
exponent < -NUMERIC_MAX_PRECISION)
231
errno = PGTYPES_NUM_BAD_NUMERIC;
234
dest->weight += (int) exponent;
235
dest->dscale -= (int) exponent;
236
if (dest->dscale < 0)
240
/* Should be nothing left but spaces */
243
if (!isspace((unsigned char) *(*ptr)))
245
errno = PGTYPES_NUM_BAD_NUMERIC;
251
/* Strip any leading zeroes */
252
while (dest->ndigits > 0 && *(dest->digits) == 0)
258
if (dest->ndigits == 0)
261
dest->rscale = dest->dscale;
267
* get_str_from_var() -
269
* Convert a var to text representation (guts of numeric_out).
270
* CAUTION: var's contents may be modified by rounding!
274
get_str_from_var(numeric *var, int dscale)
282
* Check if we must round up before printing the value and do so.
284
i = dscale + var->weight + 1;
285
if (i >= 0 && var->ndigits > i)
287
int carry = (var->digits[i] > 4) ? 1 : 0;
293
carry += var->digits[--i];
294
var->digits[i] = carry % 10;
306
var->ndigits = Max(0, Min(i, var->ndigits));
309
* Allocate space for the result
311
if ((str = (char *) pgtypes_alloc(Max(0, dscale) + Max(0, var->weight) + 4)) == NULL)
316
* Output a dash for negative values
318
if (var->sign == NUMERIC_NEG)
322
* Output all digits before the decimal point
324
i = Max(var->weight, 0);
329
if (i <= var->weight && d < var->ndigits)
330
*cp++ = var->digits[d++] + '0';
337
* If requested, output a decimal point and all the digits that follow
345
if (i <= var->weight && d < var->ndigits)
346
*cp++ = var->digits[d++] + '0';
354
* terminate the string and return it
361
PGTYPESnumeric_from_asc(char *str, char **endptr)
363
numeric *value = (numeric *) pgtypes_alloc(sizeof(numeric));
370
char **ptr = (endptr != NULL) ? endptr : &realptr;
375
ret = set_var_from_str(str, ptr, value);
380
ret = apply_typmod(value, typmod);
388
PGTYPESnumeric_to_asc(numeric *num, int dscale)
391
dscale = num->dscale;
393
return (get_str_from_var(num, dscale));
399
* Set a variable to ZERO.
400
* Note: rscale and dscale are not touched.
404
zero_var(numeric *var)
406
digitbuf_free(var->buf);
410
var->weight = 0; /* by convention; doesn't really matter */
411
var->sign = NUMERIC_POS; /* anything but NAN... */
415
PGTYPESnumeric_free(numeric *var)
417
digitbuf_free(var->buf);
424
* Compare the absolute values of var1 and var2
425
* Returns: -1 for ABS(var1) < ABS(var2)
426
* 0 for ABS(var1) == ABS(var2)
427
* 1 for ABS(var1) > ABS(var2)
431
cmp_abs(numeric *var1, numeric *var2)
435
int w1 = var1->weight;
436
int w2 = var2->weight;
439
while (w1 > w2 && i1 < var1->ndigits)
441
if (var1->digits[i1++] != 0)
445
while (w2 > w1 && i2 < var2->ndigits)
447
if (var2->digits[i2++] != 0)
454
while (i1 < var1->ndigits && i2 < var2->ndigits)
456
stat = var1->digits[i1++] - var2->digits[i2++];
466
while (i1 < var1->ndigits)
468
if (var1->digits[i1++] != 0)
471
while (i2 < var2->ndigits)
473
if (var2->digits[i2++] != 0)
484
* Add the absolute values of two variables into result.
485
* result might point to one of the operands without danger.
489
add_abs(numeric *var1, numeric *var2, numeric *result)
491
NumericDigit *res_buf;
492
NumericDigit *res_digits;
502
/* copy these values into local vars for speed in inner loop */
503
int var1ndigits = var1->ndigits;
504
int var2ndigits = var2->ndigits;
505
NumericDigit *var1digits = var1->digits;
506
NumericDigit *var2digits = var2->digits;
508
res_weight = Max(var1->weight, var2->weight) + 1;
509
res_rscale = Max(var1->rscale, var2->rscale);
510
res_dscale = Max(var1->dscale, var2->dscale);
511
res_ndigits = res_rscale + res_weight + 1;
512
if (res_ndigits <= 0)
515
if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
517
res_digits = res_buf;
519
i1 = res_rscale + var1->weight + 1;
520
i2 = res_rscale + var2->weight + 1;
521
for (i = res_ndigits - 1; i >= 0; i--)
525
if (i1 >= 0 && i1 < var1ndigits)
526
carry += var1digits[i1];
527
if (i2 >= 0 && i2 < var2ndigits)
528
carry += var2digits[i2];
532
res_digits[i] = carry - 10;
537
res_digits[i] = carry;
542
while (res_ndigits > 0 && *res_digits == 0)
548
while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
551
if (res_ndigits == 0)
554
digitbuf_free(result->buf);
555
result->ndigits = res_ndigits;
556
result->buf = res_buf;
557
result->digits = res_digits;
558
result->weight = res_weight;
559
result->rscale = res_rscale;
560
result->dscale = res_dscale;
569
* Subtract the absolute value of var2 from the absolute value of var1
570
* and store in result. result might point to one of the operands
573
* ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!!
577
sub_abs(numeric *var1, numeric *var2, numeric *result)
579
NumericDigit *res_buf;
580
NumericDigit *res_digits;
590
/* copy these values into local vars for speed in inner loop */
591
int var1ndigits = var1->ndigits;
592
int var2ndigits = var2->ndigits;
593
NumericDigit *var1digits = var1->digits;
594
NumericDigit *var2digits = var2->digits;
596
res_weight = var1->weight;
597
res_rscale = Max(var1->rscale, var2->rscale);
598
res_dscale = Max(var1->dscale, var2->dscale);
599
res_ndigits = res_rscale + res_weight + 1;
600
if (res_ndigits <= 0)
603
if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
605
res_digits = res_buf;
607
i1 = res_rscale + var1->weight + 1;
608
i2 = res_rscale + var2->weight + 1;
609
for (i = res_ndigits - 1; i >= 0; i--)
613
if (i1 >= 0 && i1 < var1ndigits)
614
borrow += var1digits[i1];
615
if (i2 >= 0 && i2 < var2ndigits)
616
borrow -= var2digits[i2];
620
res_digits[i] = borrow + 10;
625
res_digits[i] = borrow;
630
while (res_ndigits > 0 && *res_digits == 0)
636
while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
639
if (res_ndigits == 0)
642
digitbuf_free(result->buf);
643
result->ndigits = res_ndigits;
644
result->buf = res_buf;
645
result->digits = res_digits;
646
result->weight = res_weight;
647
result->rscale = res_rscale;
648
result->dscale = res_dscale;
656
* Full version of add functionality on variable level (handling signs).
657
* result might point to one of the operands too without danger.
661
PGTYPESnumeric_add(numeric *var1, numeric *var2, numeric *result)
664
* Decide on the signs of the two variables what to do
666
if (var1->sign == NUMERIC_POS)
668
if (var2->sign == NUMERIC_POS)
671
* Both are positive result = +(ABS(var1) + ABS(var2))
673
if (add_abs(var1, var2, result) != 0)
675
result->sign = NUMERIC_POS;
680
* var1 is positive, var2 is negative Must compare absolute
683
switch (cmp_abs(var1, var2))
687
* ABS(var1) == ABS(var2)
692
result->rscale = Max(var1->rscale, var2->rscale);
693
result->dscale = Max(var1->dscale, var2->dscale);
698
* ABS(var1) > ABS(var2)
699
* result = +(ABS(var1) - ABS(var2))
702
if (sub_abs(var1, var2, result) != 0)
704
result->sign = NUMERIC_POS;
709
* ABS(var1) < ABS(var2)
710
* result = -(ABS(var2) - ABS(var1))
713
if (sub_abs(var2, var1, result) != 0)
715
result->sign = NUMERIC_NEG;
722
if (var2->sign == NUMERIC_POS)
725
* var1 is negative, var2 is positive
726
* Must compare absolute values
729
switch (cmp_abs(var1, var2))
733
* ABS(var1) == ABS(var2)
738
result->rscale = Max(var1->rscale, var2->rscale);
739
result->dscale = Max(var1->dscale, var2->dscale);
744
* ABS(var1) > ABS(var2)
745
* result = -(ABS(var1) - ABS(var2))
748
if (sub_abs(var1, var2, result) != 0)
750
result->sign = NUMERIC_NEG;
755
* ABS(var1) < ABS(var2)
756
* result = +(ABS(var2) - ABS(var1))
759
if (sub_abs(var2, var1, result) != 0)
761
result->sign = NUMERIC_POS;
769
* result = -(ABS(var1) + ABS(var2))
772
if (add_abs(var1, var2, result) != 0)
774
result->sign = NUMERIC_NEG;
785
* Full version of sub functionality on variable level (handling signs).
786
* result might point to one of the operands too without danger.
790
PGTYPESnumeric_sub(numeric *var1, numeric *var2, numeric *result)
793
* Decide on the signs of the two variables what to do
795
if (var1->sign == NUMERIC_POS)
797
if (var2->sign == NUMERIC_NEG)
800
* var1 is positive, var2 is negative
801
* result = +(ABS(var1) + ABS(var2))
804
if (add_abs(var1, var2, result) != 0)
806
result->sign = NUMERIC_POS;
812
* Must compare absolute values
815
switch (cmp_abs(var1, var2))
819
* ABS(var1) == ABS(var2)
824
result->rscale = Max(var1->rscale, var2->rscale);
825
result->dscale = Max(var1->dscale, var2->dscale);
830
* ABS(var1) > ABS(var2)
831
* result = +(ABS(var1) - ABS(var2))
834
if (sub_abs(var1, var2, result) != 0)
836
result->sign = NUMERIC_POS;
841
* ABS(var1) < ABS(var2)
842
* result = -(ABS(var2) - ABS(var1))
845
if (sub_abs(var2, var1, result) != 0)
847
result->sign = NUMERIC_NEG;
854
if (var2->sign == NUMERIC_NEG)
858
* Must compare absolute values
861
switch (cmp_abs(var1, var2))
865
* ABS(var1) == ABS(var2)
870
result->rscale = Max(var1->rscale, var2->rscale);
871
result->dscale = Max(var1->dscale, var2->dscale);
876
* ABS(var1) > ABS(var2)
877
* result = -(ABS(var1) - ABS(var2))
880
if (sub_abs(var1, var2, result) != 0)
882
result->sign = NUMERIC_NEG;
887
* ABS(var1) < ABS(var2)
888
* result = +(ABS(var2) - ABS(var1))
891
if (sub_abs(var2, var1, result) != 0)
893
result->sign = NUMERIC_POS;
900
* var1 is negative, var2 is positive
901
* result = -(ABS(var1) + ABS(var2))
904
if (add_abs(var1, var2, result) != 0)
906
result->sign = NUMERIC_NEG;
916
* Multiplication on variable level. Product of var1 * var2 is stored
917
* in result. Accuracy of result is determined by global_rscale.
921
PGTYPESnumeric_mul(numeric *var1, numeric *var2, numeric *result)
923
NumericDigit *res_buf;
924
NumericDigit *res_digits;
933
int global_rscale = var1->rscale + var2->rscale;
935
res_weight = var1->weight + var2->weight + 2;
936
res_ndigits = var1->ndigits + var2->ndigits + 1;
937
if (var1->sign == var2->sign)
938
res_sign = NUMERIC_POS;
940
res_sign = NUMERIC_NEG;
942
if ((res_buf = digitbuf_alloc(res_ndigits)) == NULL)
944
res_digits = res_buf;
945
memset(res_digits, 0, res_ndigits);
948
for (i1 = var1->ndigits - 1; i1 >= 0; i1--)
953
for (i2 = var2->ndigits - 1; i2 >= 0; i2--)
955
sum += res_digits[i] + var1->digits[i1] * var2->digits[i2];
956
res_digits[i--] = sum % 10;
962
i = res_weight + global_rscale + 2;
963
if (i >= 0 && i < res_ndigits)
965
sum = (res_digits[i] > 4) ? 1 : 0;
970
sum += res_digits[i];
971
res_digits[i--] = sum % 10;
976
while (res_ndigits > 0 && *res_digits == 0)
982
while (res_ndigits > 0 && res_digits[res_ndigits - 1] == 0)
985
if (res_ndigits == 0)
987
res_sign = NUMERIC_POS;
991
digitbuf_free(result->buf);
992
result->buf = res_buf;
993
result->digits = res_digits;
994
result->ndigits = res_ndigits;
995
result->weight = res_weight;
996
result->rscale = global_rscale;
997
result->sign = res_sign;
998
result->dscale = var1->dscale + var2->dscale;
1004
* Default scale selection for division
1006
* Returns the appropriate display scale for the division result,
1007
* and sets global_rscale to the result scale to use during div_var.
1009
* Note that this must be called before div_var.
1012
select_div_scale(numeric *var1, numeric *var2, int *rscale)
1018
NumericDigit firstdigit1,
1024
* The result scale of a division isn't specified in any SQL standard.
1025
* For PostgreSQL we select a display scale that will give at least
1026
* NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a
1027
* result no less accurate than float8; but use a scale not less than
1028
* either input's display scale.
1031
/* Get the actual (normalized) weight and first digit of each input */
1033
weight1 = 0; /* values to use if var1 is zero */
1035
for (i = 0; i < var1->ndigits; i++)
1037
firstdigit1 = var1->digits[i];
1038
if (firstdigit1 != 0)
1040
weight1 = var1->weight - i;
1045
weight2 = 0; /* values to use if var2 is zero */
1047
for (i = 0; i < var2->ndigits; i++)
1049
firstdigit2 = var2->digits[i];
1050
if (firstdigit2 != 0)
1052
weight2 = var2->weight - i;
1058
* Estimate weight of quotient. If the two first digits are equal, we
1059
* can't be sure, but assume that var1 is less than var2.
1061
qweight = weight1 - weight2;
1062
if (firstdigit1 <= firstdigit2)
1065
/* Select display scale */
1066
res_dscale = NUMERIC_MIN_SIG_DIGITS - qweight;
1067
res_dscale = Max(res_dscale, var1->dscale);
1068
res_dscale = Max(res_dscale, var2->dscale);
1069
res_dscale = Max(res_dscale, NUMERIC_MIN_DISPLAY_SCALE);
1070
res_dscale = Min(res_dscale, NUMERIC_MAX_DISPLAY_SCALE);
1072
/* Select result scale */
1073
*rscale = res_rscale = res_dscale + 4;
1079
PGTYPESnumeric_div(numeric *var1, numeric *var2, numeric *result)
1081
NumericDigit *res_digits;
1086
numeric divisor[10];
1095
int first_nextdigit;
1098
int res_dscale = select_div_scale(var1, var2, &rscale);
1101
* First of all division by zero check
1103
ndigits_tmp = var2->ndigits + 1;
1104
if (ndigits_tmp == 1)
1106
errno = PGTYPES_NUM_DIVIDE_ZERO;
1111
* Determine the result sign, weight and number of digits to calculate
1113
if (var1->sign == var2->sign)
1114
res_sign = NUMERIC_POS;
1116
res_sign = NUMERIC_NEG;
1117
res_weight = var1->weight - var2->weight + 1;
1118
res_ndigits = rscale + res_weight;
1119
if (res_ndigits <= 0)
1123
* Now result zero check
1125
if (var1->ndigits == 0)
1128
result->rscale = rscale;
1133
* Initialize local variables
1135
init_var(÷nd);
1136
for (i = 1; i < 10; i++)
1137
init_var(&divisor[i]);
1140
* Make a copy of the divisor which has one leading zero digit
1142
divisor[1].ndigits = ndigits_tmp;
1143
divisor[1].rscale = var2->ndigits;
1144
divisor[1].sign = NUMERIC_POS;
1145
divisor[1].buf = digitbuf_alloc(ndigits_tmp);
1146
divisor[1].digits = divisor[1].buf;
1147
divisor[1].digits[0] = 0;
1148
memcpy(&(divisor[1].digits[1]), var2->digits, ndigits_tmp - 1);
1151
* Make a copy of the dividend
1153
dividend.ndigits = var1->ndigits;
1154
dividend.weight = 0;
1155
dividend.rscale = var1->ndigits;
1156
dividend.sign = NUMERIC_POS;
1157
dividend.buf = digitbuf_alloc(var1->ndigits);
1158
dividend.digits = dividend.buf;
1159
memcpy(dividend.digits, var1->digits, var1->ndigits);
1164
digitbuf_free(result->buf);
1165
result->buf = digitbuf_alloc(res_ndigits + 2);
1166
res_digits = result->buf;
1167
result->digits = res_digits;
1168
result->ndigits = res_ndigits;
1169
result->weight = res_weight;
1170
result->rscale = rscale;
1171
result->sign = res_sign;
1174
first_div = divisor[1].digits[1] * 10;
1175
if (ndigits_tmp > 2)
1176
first_div += divisor[1].digits[2];
1179
first_nextdigit = 0;
1182
rscale_tmp = divisor[1].rscale;
1184
for (ri = 0; ri <= res_ndigits; ri++)
1186
first_have = first_have * 10;
1187
if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1188
first_have += dividend.digits[first_nextdigit];
1191
guess = (first_have * 10) / first_div + 1;
1197
if (divisor[guess].buf == NULL)
1202
memcpy(&divisor[guess], &divisor[1], sizeof(numeric));
1203
divisor[guess].buf = digitbuf_alloc(divisor[guess].ndigits);
1204
divisor[guess].digits = divisor[guess].buf;
1205
for (i = divisor[1].ndigits - 1; i >= 0; i--)
1207
sum += divisor[1].digits[i] * guess;
1208
divisor[guess].digits[i] = sum % 10;
1213
divisor[guess].weight = weight_tmp;
1214
divisor[guess].rscale = rscale_tmp;
1216
stat = cmp_abs(÷nd, &divisor[guess]);
1223
res_digits[ri + 1] = guess;
1236
sub_abs(÷nd, &divisor[guess], ÷nd);
1238
first_nextdigit = dividend.weight - weight_tmp;
1240
if (first_nextdigit >= 0 && first_nextdigit < dividend.ndigits)
1241
first_have = dividend.digits[first_nextdigit];
1245
result->ndigits = ri + 1;
1246
if (ri == res_ndigits + 1)
1248
int carry = (res_digits[ri] > 4) ? 1 : 0;
1250
result->ndigits = ri;
1253
while (carry && ri > 0)
1255
carry += res_digits[--ri];
1256
res_digits[ri] = carry % 10;
1261
while (result->ndigits > 0 && *(result->digits) == 0)
1265
(result->ndigits)--;
1267
while (result->ndigits > 0 && result->digits[result->ndigits - 1] == 0)
1268
(result->ndigits)--;
1269
if (result->ndigits == 0)
1270
result->sign = NUMERIC_POS;
1275
digitbuf_free(dividend.buf);
1276
for (i = 1; i < 10; i++)
1277
digitbuf_free(divisor[i].buf);
1279
result->dscale = res_dscale;
1285
PGTYPESnumeric_cmp(numeric *var1, numeric *var2)
1288
/* use cmp_abs function to calculate the result */
1290
/* both are positive: normal comparation with cmp_abs */
1291
if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_POS)
1292
return cmp_abs(var1, var2);
1294
/* both are negative: return the inverse of the normal comparation */
1295
if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_NEG)
1298
* instead of inverting the result, we invert the paramter
1301
return cmp_abs(var2, var1);
1304
/* one is positive, one is negative: trivial */
1305
if (var1->sign == NUMERIC_POS && var2->sign == NUMERIC_NEG)
1307
if (var1->sign == NUMERIC_NEG && var2->sign == NUMERIC_POS)
1310
errno = PGTYPES_NUM_BAD_NUMERIC;
1316
PGTYPESnumeric_from_int(signed int int_val, numeric *var)
1318
/* implicit conversion */
1319
signed long int long_int = int_val;
1321
return PGTYPESnumeric_from_long(long_int, var);
1325
PGTYPESnumeric_from_long(signed long int long_val, numeric *var)
1327
/* calculate the size of the long int number */
1328
/* a number n needs log_10 n digits */
1331
* however we multiply by 10 each time and compare instead of
1332
* calculating the logarithm
1337
signed long int abs_long_val = long_val;
1338
signed long int extract;
1339
signed long int reach_limit;
1341
if (abs_long_val < 0)
1344
var->sign = NUMERIC_NEG;
1347
var->sign = NUMERIC_POS;
1354
} while ((reach_limit - 1) < abs_long_val && reach_limit <= LONG_MAX / 10);
1356
if (reach_limit > LONG_MAX / 10)
1358
/* add the first digit and a .0 */
1363
/* always add a .0 */
1368
if (alloc_var(var, size) < 0)
1373
var->weight = size - 2;
1378
extract = abs_long_val - (abs_long_val % reach_limit);
1379
var->digits[i] = extract / reach_limit;
1380
abs_long_val -= extract;
1385
* we can abandon if abs_long_val reaches 0, because the memory is
1386
* initialized properly and filled with '0', so converting 10000
1387
* in only one step is no problem
1389
} while (abs_long_val > 0);
1395
PGTYPESnumeric_copy(numeric *src, numeric *dst)
1403
dst->weight = src->weight;
1404
dst->rscale = src->rscale;
1405
dst->dscale = src->dscale;
1406
dst->sign = src->sign;
1408
if (alloc_var(dst, src->ndigits) != 0)
1411
for (i = 0; i < src->ndigits; i++)
1412
dst->digits[i] = src->digits[i];
1418
PGTYPESnumeric_from_double(double d, numeric *dst)
1423
if (sprintf(buffer, "%f", d) == 0)
1426
if ((tmp = PGTYPESnumeric_from_asc(buffer, NULL)) == NULL)
1428
if (PGTYPESnumeric_copy(tmp, dst) != 0)
1430
PGTYPESnumeric_free(tmp);
1435
numericvar_to_double_no_overflow(numeric *var, double *dp)
1441
if ((tmp = get_str_from_var(var, var->dscale)) == NULL)
1444
/* unlike float8in, we ignore ERANGE from strtod */
1445
val = strtod(tmp, &endptr);
1446
if (*endptr != '\0')
1448
/* shouldn't happen ... */
1450
errno = PGTYPES_NUM_BAD_NUMERIC;
1459
PGTYPESnumeric_to_double(numeric *nv, double *dp)
1464
if ((i = numericvar_to_double_no_overflow(nv, &tmp)) != 0)
1471
PGTYPESnumeric_to_int(numeric *nv, int *ip)
1476
if ((i = PGTYPESnumeric_to_long(nv, &l)) != 0)
1479
if (l < -INT_MAX || l > INT_MAX)
1481
errno = PGTYPES_NUM_OVERFLOW;
1490
PGTYPESnumeric_to_long(numeric *nv, long *lp)
1495
for (i = 1; i < nv->weight + 2; i++)
1500
if (nv->buf[i] >= 5)
1505
if (l > LONG_MAX || l < 0)
1507
errno = PGTYPES_NUM_OVERFLOW;
1511
if (nv->sign == NUMERIC_NEG)
1518
PGTYPESnumeric_to_decimal(numeric *src, decimal *dst)
1522
if (src->ndigits > DECSIZE)
1524
errno = PGTYPES_NUM_OVERFLOW;
1528
dst->weight = src->weight;
1529
dst->rscale = src->rscale;
1530
dst->dscale = src->dscale;
1531
dst->sign = src->sign;
1532
dst->ndigits = src->ndigits;
1534
for (i = 0; i < src->ndigits; i++)
1535
dst->digits[i] = src->digits[i];
1541
PGTYPESnumeric_from_decimal(decimal *src, numeric *dst)
1547
dst->weight = src->weight;
1548
dst->rscale = src->rscale;
1549
dst->dscale = src->dscale;
1550
dst->sign = src->sign;
1552
if (alloc_var(dst, src->ndigits) != 0)
1555
for (i = 0; i < src->ndigits; i++)
1556
dst->digits[i] = src->digits[i];