Age Owner Branch data TLA Line data Source code
1 : : /*-------------------------------------------------------------------------
2 : : *
3 : : * numeric.c
4 : : * An exact numeric data type for the Postgres database system
5 : : *
6 : : * Original coding 1998, Jan Wieck. Heavily revised 2003, Tom Lane.
7 : : *
8 : : * Many of the algorithmic ideas are borrowed from David M. Smith's "FM"
9 : : * multiple-precision math library, most recently published as Algorithm
10 : : * 786: Multiple-Precision Complex Arithmetic and Functions, ACM
11 : : * Transactions on Mathematical Software, Vol. 24, No. 4, December 1998,
12 : : * pages 359-367.
13 : : *
14 : : * Copyright (c) 1998-2024, PostgreSQL Global Development Group
15 : : *
16 : : * IDENTIFICATION
17 : : * src/backend/utils/adt/numeric.c
18 : : *
19 : : *-------------------------------------------------------------------------
20 : : */
21 : :
22 : : #include "postgres.h"
23 : :
24 : : #include <ctype.h>
25 : : #include <float.h>
26 : : #include <limits.h>
27 : : #include <math.h>
28 : :
29 : : #include "common/hashfn.h"
30 : : #include "common/int.h"
31 : : #include "funcapi.h"
32 : : #include "lib/hyperloglog.h"
33 : : #include "libpq/pqformat.h"
34 : : #include "miscadmin.h"
35 : : #include "nodes/nodeFuncs.h"
36 : : #include "nodes/supportnodes.h"
37 : : #include "utils/array.h"
38 : : #include "utils/builtins.h"
39 : : #include "utils/float.h"
40 : : #include "utils/guc.h"
41 : : #include "utils/numeric.h"
42 : : #include "utils/pg_lsn.h"
43 : : #include "utils/sortsupport.h"
44 : :
45 : : /* ----------
46 : : * Uncomment the following to enable compilation of dump_numeric()
47 : : * and dump_var() and to get a dump of any result produced by make_result().
48 : : * ----------
49 : : #define NUMERIC_DEBUG
50 : : */
51 : :
52 : :
53 : : /* ----------
54 : : * Local data types
55 : : *
56 : : * Numeric values are represented in a base-NBASE floating point format.
57 : : * Each "digit" ranges from 0 to NBASE-1. The type NumericDigit is signed
58 : : * and wide enough to store a digit. We assume that NBASE*NBASE can fit in
59 : : * an int. Although the purely calculational routines could handle any even
60 : : * NBASE that's less than sqrt(INT_MAX), in practice we are only interested
61 : : * in NBASE a power of ten, so that I/O conversions and decimal rounding
62 : : * are easy. Also, it's actually more efficient if NBASE is rather less than
63 : : * sqrt(INT_MAX), so that there is "headroom" for mul_var and div_var_fast to
64 : : * postpone processing carries.
65 : : *
66 : : * Values of NBASE other than 10000 are considered of historical interest only
67 : : * and are no longer supported in any sense; no mechanism exists for the client
68 : : * to discover the base, so every client supporting binary mode expects the
69 : : * base-10000 format. If you plan to change this, also note the numeric
70 : : * abbreviation code, which assumes NBASE=10000.
71 : : * ----------
72 : : */
73 : :
74 : : #if 0
75 : : #define NBASE 10
76 : : #define HALF_NBASE 5
77 : : #define DEC_DIGITS 1 /* decimal digits per NBASE digit */
78 : : #define MUL_GUARD_DIGITS 4 /* these are measured in NBASE digits */
79 : : #define DIV_GUARD_DIGITS 8
80 : :
81 : : typedef signed char NumericDigit;
82 : : #endif
83 : :
84 : : #if 0
85 : : #define NBASE 100
86 : : #define HALF_NBASE 50
87 : : #define DEC_DIGITS 2 /* decimal digits per NBASE digit */
88 : : #define MUL_GUARD_DIGITS 3 /* these are measured in NBASE digits */
89 : : #define DIV_GUARD_DIGITS 6
90 : :
91 : : typedef signed char NumericDigit;
92 : : #endif
93 : :
94 : : #if 1
95 : : #define NBASE 10000
96 : : #define HALF_NBASE 5000
97 : : #define DEC_DIGITS 4 /* decimal digits per NBASE digit */
98 : : #define MUL_GUARD_DIGITS 2 /* these are measured in NBASE digits */
99 : : #define DIV_GUARD_DIGITS 4
100 : :
101 : : typedef int16 NumericDigit;
102 : : #endif
103 : :
104 : : /*
105 : : * The Numeric type as stored on disk.
106 : : *
107 : : * If the high bits of the first word of a NumericChoice (n_header, or
108 : : * n_short.n_header, or n_long.n_sign_dscale) are NUMERIC_SHORT, then the
109 : : * numeric follows the NumericShort format; if they are NUMERIC_POS or
110 : : * NUMERIC_NEG, it follows the NumericLong format. If they are NUMERIC_SPECIAL,
111 : : * the value is a NaN or Infinity. We currently always store SPECIAL values
112 : : * using just two bytes (i.e. only n_header), but previous releases used only
113 : : * the NumericLong format, so we might find 4-byte NaNs (though not infinities)
114 : : * on disk if a database has been migrated using pg_upgrade. In either case,
115 : : * the low-order bits of a special value's header are reserved and currently
116 : : * should always be set to zero.
117 : : *
118 : : * In the NumericShort format, the remaining 14 bits of the header word
119 : : * (n_short.n_header) are allocated as follows: 1 for sign (positive or
120 : : * negative), 6 for dynamic scale, and 7 for weight. In practice, most
121 : : * commonly-encountered values can be represented this way.
122 : : *
123 : : * In the NumericLong format, the remaining 14 bits of the header word
124 : : * (n_long.n_sign_dscale) represent the display scale; and the weight is
125 : : * stored separately in n_weight.
126 : : *
127 : : * NOTE: by convention, values in the packed form have been stripped of
128 : : * all leading and trailing zero digits (where a "digit" is of base NBASE).
129 : : * In particular, if the value is zero, there will be no digits at all!
130 : : * The weight is arbitrary in that case, but we normally set it to zero.
131 : : */
132 : :
133 : : struct NumericShort
134 : : {
135 : : uint16 n_header; /* Sign + display scale + weight */
136 : : NumericDigit n_data[FLEXIBLE_ARRAY_MEMBER]; /* Digits */
137 : : };
138 : :
139 : : struct NumericLong
140 : : {
141 : : uint16 n_sign_dscale; /* Sign + display scale */
142 : : int16 n_weight; /* Weight of 1st digit */
143 : : NumericDigit n_data[FLEXIBLE_ARRAY_MEMBER]; /* Digits */
144 : : };
145 : :
146 : : union NumericChoice
147 : : {
148 : : uint16 n_header; /* Header word */
149 : : struct NumericLong n_long; /* Long form (4-byte header) */
150 : : struct NumericShort n_short; /* Short form (2-byte header) */
151 : : };
152 : :
153 : : struct NumericData
154 : : {
155 : : int32 vl_len_; /* varlena header (do not touch directly!) */
156 : : union NumericChoice choice; /* choice of format */
157 : : };
158 : :
159 : :
160 : : /*
161 : : * Interpretation of high bits.
162 : : */
163 : :
164 : : #define NUMERIC_SIGN_MASK 0xC000
165 : : #define NUMERIC_POS 0x0000
166 : : #define NUMERIC_NEG 0x4000
167 : : #define NUMERIC_SHORT 0x8000
168 : : #define NUMERIC_SPECIAL 0xC000
169 : :
170 : : #define NUMERIC_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_SIGN_MASK)
171 : : #define NUMERIC_IS_SHORT(n) (NUMERIC_FLAGBITS(n) == NUMERIC_SHORT)
172 : : #define NUMERIC_IS_SPECIAL(n) (NUMERIC_FLAGBITS(n) == NUMERIC_SPECIAL)
173 : :
174 : : #define NUMERIC_HDRSZ (VARHDRSZ + sizeof(uint16) + sizeof(int16))
175 : : #define NUMERIC_HDRSZ_SHORT (VARHDRSZ + sizeof(uint16))
176 : :
177 : : /*
178 : : * If the flag bits are NUMERIC_SHORT or NUMERIC_SPECIAL, we want the short
179 : : * header; otherwise, we want the long one. Instead of testing against each
180 : : * value, we can just look at the high bit, for a slight efficiency gain.
181 : : */
182 : : #define NUMERIC_HEADER_IS_SHORT(n) (((n)->choice.n_header & 0x8000) != 0)
183 : : #define NUMERIC_HEADER_SIZE(n) \
184 : : (VARHDRSZ + sizeof(uint16) + \
185 : : (NUMERIC_HEADER_IS_SHORT(n) ? 0 : sizeof(int16)))
186 : :
187 : : /*
188 : : * Definitions for special values (NaN, positive infinity, negative infinity).
189 : : *
190 : : * The two bits after the NUMERIC_SPECIAL bits are 00 for NaN, 01 for positive
191 : : * infinity, 11 for negative infinity. (This makes the sign bit match where
192 : : * it is in a short-format value, though we make no use of that at present.)
193 : : * We could mask off the remaining bits before testing the active bits, but
194 : : * currently those bits must be zeroes, so masking would just add cycles.
195 : : */
196 : : #define NUMERIC_EXT_SIGN_MASK 0xF000 /* high bits plus NaN/Inf flag bits */
197 : : #define NUMERIC_NAN 0xC000
198 : : #define NUMERIC_PINF 0xD000
199 : : #define NUMERIC_NINF 0xF000
200 : : #define NUMERIC_INF_SIGN_MASK 0x2000
201 : :
202 : : #define NUMERIC_EXT_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_EXT_SIGN_MASK)
203 : : #define NUMERIC_IS_NAN(n) ((n)->choice.n_header == NUMERIC_NAN)
204 : : #define NUMERIC_IS_PINF(n) ((n)->choice.n_header == NUMERIC_PINF)
205 : : #define NUMERIC_IS_NINF(n) ((n)->choice.n_header == NUMERIC_NINF)
206 : : #define NUMERIC_IS_INF(n) \
207 : : (((n)->choice.n_header & ~NUMERIC_INF_SIGN_MASK) == NUMERIC_PINF)
208 : :
209 : : /*
210 : : * Short format definitions.
211 : : */
212 : :
213 : : #define NUMERIC_SHORT_SIGN_MASK 0x2000
214 : : #define NUMERIC_SHORT_DSCALE_MASK 0x1F80
215 : : #define NUMERIC_SHORT_DSCALE_SHIFT 7
216 : : #define NUMERIC_SHORT_DSCALE_MAX \
217 : : (NUMERIC_SHORT_DSCALE_MASK >> NUMERIC_SHORT_DSCALE_SHIFT)
218 : : #define NUMERIC_SHORT_WEIGHT_SIGN_MASK 0x0040
219 : : #define NUMERIC_SHORT_WEIGHT_MASK 0x003F
220 : : #define NUMERIC_SHORT_WEIGHT_MAX NUMERIC_SHORT_WEIGHT_MASK
221 : : #define NUMERIC_SHORT_WEIGHT_MIN (-(NUMERIC_SHORT_WEIGHT_MASK+1))
222 : :
223 : : /*
224 : : * Extract sign, display scale, weight. These macros extract field values
225 : : * suitable for the NumericVar format from the Numeric (on-disk) format.
226 : : *
227 : : * Note that we don't trouble to ensure that dscale and weight read as zero
228 : : * for an infinity; however, that doesn't matter since we never convert
229 : : * "special" numerics to NumericVar form. Only the constants defined below
230 : : * (const_nan, etc) ever represent a non-finite value as a NumericVar.
231 : : */
232 : :
233 : : #define NUMERIC_DSCALE_MASK 0x3FFF
234 : : #define NUMERIC_DSCALE_MAX NUMERIC_DSCALE_MASK
235 : :
236 : : #define NUMERIC_SIGN(n) \
237 : : (NUMERIC_IS_SHORT(n) ? \
238 : : (((n)->choice.n_short.n_header & NUMERIC_SHORT_SIGN_MASK) ? \
239 : : NUMERIC_NEG : NUMERIC_POS) : \
240 : : (NUMERIC_IS_SPECIAL(n) ? \
241 : : NUMERIC_EXT_FLAGBITS(n) : NUMERIC_FLAGBITS(n)))
242 : : #define NUMERIC_DSCALE(n) (NUMERIC_HEADER_IS_SHORT((n)) ? \
243 : : ((n)->choice.n_short.n_header & NUMERIC_SHORT_DSCALE_MASK) \
244 : : >> NUMERIC_SHORT_DSCALE_SHIFT \
245 : : : ((n)->choice.n_long.n_sign_dscale & NUMERIC_DSCALE_MASK))
246 : : #define NUMERIC_WEIGHT(n) (NUMERIC_HEADER_IS_SHORT((n)) ? \
247 : : (((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_SIGN_MASK ? \
248 : : ~NUMERIC_SHORT_WEIGHT_MASK : 0) \
249 : : | ((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \
250 : : : ((n)->choice.n_long.n_weight))
251 : :
252 : : /* ----------
253 : : * NumericVar is the format we use for arithmetic. The digit-array part
254 : : * is the same as the NumericData storage format, but the header is more
255 : : * complex.
256 : : *
257 : : * The value represented by a NumericVar is determined by the sign, weight,
258 : : * ndigits, and digits[] array. If it is a "special" value (NaN or Inf)
259 : : * then only the sign field matters; ndigits should be zero, and the weight
260 : : * and dscale fields are ignored.
261 : : *
262 : : * Note: the first digit of a NumericVar's value is assumed to be multiplied
263 : : * by NBASE ** weight. Another way to say it is that there are weight+1
264 : : * digits before the decimal point. It is possible to have weight < 0.
265 : : *
266 : : * buf points at the physical start of the palloc'd digit buffer for the
267 : : * NumericVar. digits points at the first digit in actual use (the one
268 : : * with the specified weight). We normally leave an unused digit or two
269 : : * (preset to zeroes) between buf and digits, so that there is room to store
270 : : * a carry out of the top digit without reallocating space. We just need to
271 : : * decrement digits (and increment weight) to make room for the carry digit.
272 : : * (There is no such extra space in a numeric value stored in the database,
273 : : * only in a NumericVar in memory.)
274 : : *
275 : : * If buf is NULL then the digit buffer isn't actually palloc'd and should
276 : : * not be freed --- see the constants below for an example.
277 : : *
278 : : * dscale, or display scale, is the nominal precision expressed as number
279 : : * of digits after the decimal point (it must always be >= 0 at present).
280 : : * dscale may be more than the number of physically stored fractional digits,
281 : : * implying that we have suppressed storage of significant trailing zeroes.
282 : : * It should never be less than the number of stored digits, since that would
283 : : * imply hiding digits that are present. NOTE that dscale is always expressed
284 : : * in *decimal* digits, and so it may correspond to a fractional number of
285 : : * base-NBASE digits --- divide by DEC_DIGITS to convert to NBASE digits.
286 : : *
287 : : * rscale, or result scale, is the target precision for a computation.
288 : : * Like dscale it is expressed as number of *decimal* digits after the decimal
289 : : * point, and is always >= 0 at present.
290 : : * Note that rscale is not stored in variables --- it's figured on-the-fly
291 : : * from the dscales of the inputs.
292 : : *
293 : : * While we consistently use "weight" to refer to the base-NBASE weight of
294 : : * a numeric value, it is convenient in some scale-related calculations to
295 : : * make use of the base-10 weight (ie, the approximate log10 of the value).
296 : : * To avoid confusion, such a decimal-units weight is called a "dweight".
297 : : *
298 : : * NB: All the variable-level functions are written in a style that makes it
299 : : * possible to give one and the same variable as argument and destination.
300 : : * This is feasible because the digit buffer is separate from the variable.
301 : : * ----------
302 : : */
303 : : typedef struct NumericVar
304 : : {
305 : : int ndigits; /* # of digits in digits[] - can be 0! */
306 : : int weight; /* weight of first digit */
307 : : int sign; /* NUMERIC_POS, _NEG, _NAN, _PINF, or _NINF */
308 : : int dscale; /* display scale */
309 : : NumericDigit *buf; /* start of palloc'd space for digits[] */
310 : : NumericDigit *digits; /* base-NBASE digits */
311 : : } NumericVar;
312 : :
313 : :
314 : : /* ----------
315 : : * Data for generate_series
316 : : * ----------
317 : : */
318 : : typedef struct
319 : : {
320 : : NumericVar current;
321 : : NumericVar stop;
322 : : NumericVar step;
323 : : } generate_series_numeric_fctx;
324 : :
325 : :
326 : : /* ----------
327 : : * Sort support.
328 : : * ----------
329 : : */
330 : : typedef struct
331 : : {
332 : : void *buf; /* buffer for short varlenas */
333 : : int64 input_count; /* number of non-null values seen */
334 : : bool estimating; /* true if estimating cardinality */
335 : :
336 : : hyperLogLogState abbr_card; /* cardinality estimator */
337 : : } NumericSortSupport;
338 : :
339 : :
340 : : /* ----------
341 : : * Fast sum accumulator.
342 : : *
343 : : * NumericSumAccum is used to implement SUM(), and other standard aggregates
344 : : * that track the sum of input values. It uses 32-bit integers to store the
345 : : * digits, instead of the normal 16-bit integers (with NBASE=10000). This
346 : : * way, we can safely accumulate up to NBASE - 1 values without propagating
347 : : * carry, before risking overflow of any of the digits. 'num_uncarried'
348 : : * tracks how many values have been accumulated without propagating carry.
349 : : *
350 : : * Positive and negative values are accumulated separately, in 'pos_digits'
351 : : * and 'neg_digits'. This is simpler and faster than deciding whether to add
352 : : * or subtract from the current value, for each new value (see sub_var() for
353 : : * the logic we avoid by doing this). Both buffers are of same size, and
354 : : * have the same weight and scale. In accum_sum_final(), the positive and
355 : : * negative sums are added together to produce the final result.
356 : : *
357 : : * When a new value has a larger ndigits or weight than the accumulator
358 : : * currently does, the accumulator is enlarged to accommodate the new value.
359 : : * We normally have one zero digit reserved for carry propagation, and that
360 : : * is indicated by the 'have_carry_space' flag. When accum_sum_carry() uses
361 : : * up the reserved digit, it clears the 'have_carry_space' flag. The next
362 : : * call to accum_sum_add() will enlarge the buffer, to make room for the
363 : : * extra digit, and set the flag again.
364 : : *
365 : : * To initialize a new accumulator, simply reset all fields to zeros.
366 : : *
367 : : * The accumulator does not handle NaNs.
368 : : * ----------
369 : : */
370 : : typedef struct NumericSumAccum
371 : : {
372 : : int ndigits;
373 : : int weight;
374 : : int dscale;
375 : : int num_uncarried;
376 : : bool have_carry_space;
377 : : int32 *pos_digits;
378 : : int32 *neg_digits;
379 : : } NumericSumAccum;
380 : :
381 : :
382 : : /*
383 : : * We define our own macros for packing and unpacking abbreviated-key
384 : : * representations for numeric values in order to avoid depending on
385 : : * USE_FLOAT8_BYVAL. The type of abbreviation we use is based only on
386 : : * the size of a datum, not the argument-passing convention for float8.
387 : : *
388 : : * The range of abbreviations for finite values is from +PG_INT64/32_MAX
389 : : * to -PG_INT64/32_MAX. NaN has the abbreviation PG_INT64/32_MIN, and we
390 : : * define the sort ordering to make that work out properly (see further
391 : : * comments below). PINF and NINF share the abbreviations of the largest
392 : : * and smallest finite abbreviation classes.
393 : : */
394 : : #define NUMERIC_ABBREV_BITS (SIZEOF_DATUM * BITS_PER_BYTE)
395 : : #if SIZEOF_DATUM == 8
396 : : #define NumericAbbrevGetDatum(X) ((Datum) (X))
397 : : #define DatumGetNumericAbbrev(X) ((int64) (X))
398 : : #define NUMERIC_ABBREV_NAN NumericAbbrevGetDatum(PG_INT64_MIN)
399 : : #define NUMERIC_ABBREV_PINF NumericAbbrevGetDatum(-PG_INT64_MAX)
400 : : #define NUMERIC_ABBREV_NINF NumericAbbrevGetDatum(PG_INT64_MAX)
401 : : #else
402 : : #define NumericAbbrevGetDatum(X) ((Datum) (X))
403 : : #define DatumGetNumericAbbrev(X) ((int32) (X))
404 : : #define NUMERIC_ABBREV_NAN NumericAbbrevGetDatum(PG_INT32_MIN)
405 : : #define NUMERIC_ABBREV_PINF NumericAbbrevGetDatum(-PG_INT32_MAX)
406 : : #define NUMERIC_ABBREV_NINF NumericAbbrevGetDatum(PG_INT32_MAX)
407 : : #endif
408 : :
409 : :
410 : : /* ----------
411 : : * Some preinitialized constants
412 : : * ----------
413 : : */
414 : : static const NumericDigit const_zero_data[1] = {0};
415 : : static const NumericVar const_zero =
416 : : {0, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_zero_data};
417 : :
418 : : static const NumericDigit const_one_data[1] = {1};
419 : : static const NumericVar const_one =
420 : : {1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_one_data};
421 : :
422 : : static const NumericVar const_minus_one =
423 : : {1, 0, NUMERIC_NEG, 0, NULL, (NumericDigit *) const_one_data};
424 : :
425 : : static const NumericDigit const_two_data[1] = {2};
426 : : static const NumericVar const_two =
427 : : {1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_two_data};
428 : :
429 : : #if DEC_DIGITS == 4
430 : : static const NumericDigit const_zero_point_nine_data[1] = {9000};
431 : : #elif DEC_DIGITS == 2
432 : : static const NumericDigit const_zero_point_nine_data[1] = {90};
433 : : #elif DEC_DIGITS == 1
434 : : static const NumericDigit const_zero_point_nine_data[1] = {9};
435 : : #endif
436 : : static const NumericVar const_zero_point_nine =
437 : : {1, -1, NUMERIC_POS, 1, NULL, (NumericDigit *) const_zero_point_nine_data};
438 : :
439 : : #if DEC_DIGITS == 4
440 : : static const NumericDigit const_one_point_one_data[2] = {1, 1000};
441 : : #elif DEC_DIGITS == 2
442 : : static const NumericDigit const_one_point_one_data[2] = {1, 10};
443 : : #elif DEC_DIGITS == 1
444 : : static const NumericDigit const_one_point_one_data[2] = {1, 1};
445 : : #endif
446 : : static const NumericVar const_one_point_one =
447 : : {2, 0, NUMERIC_POS, 1, NULL, (NumericDigit *) const_one_point_one_data};
448 : :
449 : : static const NumericVar const_nan =
450 : : {0, 0, NUMERIC_NAN, 0, NULL, NULL};
451 : :
452 : : static const NumericVar const_pinf =
453 : : {0, 0, NUMERIC_PINF, 0, NULL, NULL};
454 : :
455 : : static const NumericVar const_ninf =
456 : : {0, 0, NUMERIC_NINF, 0, NULL, NULL};
457 : :
458 : : #if DEC_DIGITS == 4
459 : : static const int round_powers[4] = {0, 1000, 100, 10};
460 : : #endif
461 : :
462 : :
463 : : /* ----------
464 : : * Local functions
465 : : * ----------
466 : : */
467 : :
468 : : #ifdef NUMERIC_DEBUG
469 : : static void dump_numeric(const char *str, Numeric num);
470 : : static void dump_var(const char *str, NumericVar *var);
471 : : #else
472 : : #define dump_numeric(s,n)
473 : : #define dump_var(s,v)
474 : : #endif
475 : :
476 : : #define digitbuf_alloc(ndigits) \
477 : : ((NumericDigit *) palloc((ndigits) * sizeof(NumericDigit)))
478 : : #define digitbuf_free(buf) \
479 : : do { \
480 : : if ((buf) != NULL) \
481 : : pfree(buf); \
482 : : } while (0)
483 : :
484 : : #define init_var(v) memset(v, 0, sizeof(NumericVar))
485 : :
486 : : #define NUMERIC_DIGITS(num) (NUMERIC_HEADER_IS_SHORT(num) ? \
487 : : (num)->choice.n_short.n_data : (num)->choice.n_long.n_data)
488 : : #define NUMERIC_NDIGITS(num) \
489 : : ((VARSIZE(num) - NUMERIC_HEADER_SIZE(num)) / sizeof(NumericDigit))
490 : : #define NUMERIC_CAN_BE_SHORT(scale,weight) \
491 : : ((scale) <= NUMERIC_SHORT_DSCALE_MAX && \
492 : : (weight) <= NUMERIC_SHORT_WEIGHT_MAX && \
493 : : (weight) >= NUMERIC_SHORT_WEIGHT_MIN)
494 : :
495 : : static void alloc_var(NumericVar *var, int ndigits);
496 : : static void free_var(NumericVar *var);
497 : : static void zero_var(NumericVar *var);
498 : :
499 : : static bool set_var_from_str(const char *str, const char *cp,
500 : : NumericVar *dest, const char **endptr,
501 : : Node *escontext);
502 : : static bool set_var_from_non_decimal_integer_str(const char *str,
503 : : const char *cp, int sign,
504 : : int base, NumericVar *dest,
505 : : const char **endptr,
506 : : Node *escontext);
507 : : static void set_var_from_num(Numeric num, NumericVar *dest);
508 : : static void init_var_from_num(Numeric num, NumericVar *dest);
509 : : static void set_var_from_var(const NumericVar *value, NumericVar *dest);
510 : : static char *get_str_from_var(const NumericVar *var);
511 : : static char *get_str_from_var_sci(const NumericVar *var, int rscale);
512 : :
513 : : static void numericvar_serialize(StringInfo buf, const NumericVar *var);
514 : : static void numericvar_deserialize(StringInfo buf, NumericVar *var);
515 : :
516 : : static Numeric duplicate_numeric(Numeric num);
517 : : static Numeric make_result(const NumericVar *var);
518 : : static Numeric make_result_opt_error(const NumericVar *var, bool *have_error);
519 : :
520 : : static bool apply_typmod(NumericVar *var, int32 typmod, Node *escontext);
521 : : static bool apply_typmod_special(Numeric num, int32 typmod, Node *escontext);
522 : :
523 : : static bool numericvar_to_int32(const NumericVar *var, int32 *result);
524 : : static bool numericvar_to_int64(const NumericVar *var, int64 *result);
525 : : static void int64_to_numericvar(int64 val, NumericVar *var);
526 : : static bool numericvar_to_uint64(const NumericVar *var, uint64 *result);
527 : : #ifdef HAVE_INT128
528 : : static bool numericvar_to_int128(const NumericVar *var, int128 *result);
529 : : static void int128_to_numericvar(int128 val, NumericVar *var);
530 : : #endif
531 : : static double numericvar_to_double_no_overflow(const NumericVar *var);
532 : :
533 : : static Datum numeric_abbrev_convert(Datum original_datum, SortSupport ssup);
534 : : static bool numeric_abbrev_abort(int memtupcount, SortSupport ssup);
535 : : static int numeric_fast_cmp(Datum x, Datum y, SortSupport ssup);
536 : : static int numeric_cmp_abbrev(Datum x, Datum y, SortSupport ssup);
537 : :
538 : : static Datum numeric_abbrev_convert_var(const NumericVar *var,
539 : : NumericSortSupport *nss);
540 : :
541 : : static int cmp_numerics(Numeric num1, Numeric num2);
542 : : static int cmp_var(const NumericVar *var1, const NumericVar *var2);
543 : : static int cmp_var_common(const NumericDigit *var1digits, int var1ndigits,
544 : : int var1weight, int var1sign,
545 : : const NumericDigit *var2digits, int var2ndigits,
546 : : int var2weight, int var2sign);
547 : : static void add_var(const NumericVar *var1, const NumericVar *var2,
548 : : NumericVar *result);
549 : : static void sub_var(const NumericVar *var1, const NumericVar *var2,
550 : : NumericVar *result);
551 : : static void mul_var(const NumericVar *var1, const NumericVar *var2,
552 : : NumericVar *result,
553 : : int rscale);
554 : : static void div_var(const NumericVar *var1, const NumericVar *var2,
555 : : NumericVar *result,
556 : : int rscale, bool round);
557 : : static void div_var_fast(const NumericVar *var1, const NumericVar *var2,
558 : : NumericVar *result, int rscale, bool round);
559 : : static void div_var_int(const NumericVar *var, int ival, int ival_weight,
560 : : NumericVar *result, int rscale, bool round);
561 : : #ifdef HAVE_INT128
562 : : static void div_var_int64(const NumericVar *var, int64 ival, int ival_weight,
563 : : NumericVar *result, int rscale, bool round);
564 : : #endif
565 : : static int select_div_scale(const NumericVar *var1, const NumericVar *var2);
566 : : static void mod_var(const NumericVar *var1, const NumericVar *var2,
567 : : NumericVar *result);
568 : : static void div_mod_var(const NumericVar *var1, const NumericVar *var2,
569 : : NumericVar *quot, NumericVar *rem);
570 : : static void ceil_var(const NumericVar *var, NumericVar *result);
571 : : static void floor_var(const NumericVar *var, NumericVar *result);
572 : :
573 : : static void gcd_var(const NumericVar *var1, const NumericVar *var2,
574 : : NumericVar *result);
575 : : static void sqrt_var(const NumericVar *arg, NumericVar *result, int rscale);
576 : : static void exp_var(const NumericVar *arg, NumericVar *result, int rscale);
577 : : static int estimate_ln_dweight(const NumericVar *var);
578 : : static void ln_var(const NumericVar *arg, NumericVar *result, int rscale);
579 : : static void log_var(const NumericVar *base, const NumericVar *num,
580 : : NumericVar *result);
581 : : static void power_var(const NumericVar *base, const NumericVar *exp,
582 : : NumericVar *result);
583 : : static void power_var_int(const NumericVar *base, int exp, int exp_dscale,
584 : : NumericVar *result);
585 : : static void power_ten_int(int exp, NumericVar *result);
586 : : static void random_var(pg_prng_state *state, const NumericVar *rmin,
587 : : const NumericVar *rmax, NumericVar *result);
588 : :
589 : : static int cmp_abs(const NumericVar *var1, const NumericVar *var2);
590 : : static int cmp_abs_common(const NumericDigit *var1digits, int var1ndigits,
591 : : int var1weight,
592 : : const NumericDigit *var2digits, int var2ndigits,
593 : : int var2weight);
594 : : static void add_abs(const NumericVar *var1, const NumericVar *var2,
595 : : NumericVar *result);
596 : : static void sub_abs(const NumericVar *var1, const NumericVar *var2,
597 : : NumericVar *result);
598 : : static void round_var(NumericVar *var, int rscale);
599 : : static void trunc_var(NumericVar *var, int rscale);
600 : : static void strip_var(NumericVar *var);
601 : : static void compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
602 : : const NumericVar *count_var, bool reversed_bounds,
603 : : NumericVar *result_var);
604 : :
605 : : static void accum_sum_add(NumericSumAccum *accum, const NumericVar *val);
606 : : static void accum_sum_rescale(NumericSumAccum *accum, const NumericVar *val);
607 : : static void accum_sum_carry(NumericSumAccum *accum);
608 : : static void accum_sum_reset(NumericSumAccum *accum);
609 : : static void accum_sum_final(NumericSumAccum *accum, NumericVar *result);
610 : : static void accum_sum_copy(NumericSumAccum *dst, NumericSumAccum *src);
611 : : static void accum_sum_combine(NumericSumAccum *accum, NumericSumAccum *accum2);
612 : :
613 : :
614 : : /* ----------------------------------------------------------------------
615 : : *
616 : : * Input-, output- and rounding-functions
617 : : *
618 : : * ----------------------------------------------------------------------
619 : : */
620 : :
621 : :
622 : : /*
623 : : * numeric_in() -
624 : : *
625 : : * Input function for numeric data type
626 : : */
627 : : Datum
8706 tgl@sss.pgh.pa.us 628 :CBC 53302 : numeric_in(PG_FUNCTION_ARGS)
629 : : {
630 : 53302 : char *str = PG_GETARG_CSTRING(0);
631 : : #ifdef NOT_USED
632 : : Oid typelem = PG_GETARG_OID(1);
633 : : #endif
634 : 53302 : int32 typmod = PG_GETARG_INT32(2);
492 635 : 53302 : Node *escontext = fcinfo->context;
636 : : Numeric res;
637 : : const char *cp;
638 : : const char *numstart;
639 : : int sign;
640 : :
641 : : /* Skip leading spaces */
5485 642 : 53302 : cp = str;
643 [ + + ]: 53494 : while (*cp)
644 : : {
645 [ + + ]: 53488 : if (!isspace((unsigned char) *cp))
646 : 53296 : break;
647 : 192 : cp++;
648 : : }
649 : :
650 : : /*
651 : : * Process the number's sign. This duplicates logic in set_var_from_str(),
652 : : * but it's worth doing here, since it simplifies the handling of
653 : : * infinities and non-decimal integers.
654 : : */
447 dean.a.rasheed@gmail 655 : 53302 : numstart = cp;
656 : 53302 : sign = NUMERIC_POS;
657 : :
658 [ + + ]: 53302 : if (*cp == '+')
659 : 24 : cp++;
660 [ + + ]: 53278 : else if (*cp == '-')
661 : : {
662 : 1846 : sign = NUMERIC_NEG;
663 : 1846 : cp++;
664 : : }
665 : :
666 : : /*
667 : : * Check for NaN and infinities. We recognize the same strings allowed by
668 : : * float8in().
669 : : *
670 : : * Since all other legal inputs have a digit or a decimal point after the
671 : : * sign, we need only check for NaN/infinity if that's not the case.
672 : : */
673 [ + + + + ]: 53302 : if (!isdigit((unsigned char) *cp) && *cp != '.')
674 : : {
675 : : /*
676 : : * The number must be NaN or infinity; anything else can only be a
677 : : * syntax error. Note that NaN mustn't have a sign.
678 : : */
679 [ + + ]: 833 : if (pg_strncasecmp(numstart, "NaN", 3) == 0)
680 : : {
681 : 289 : res = make_result(&const_nan);
682 : 289 : cp = numstart + 3;
683 : : }
684 [ + + ]: 544 : else if (pg_strncasecmp(cp, "Infinity", 8) == 0)
685 : : {
686 [ + + ]: 198 : res = make_result(sign == NUMERIC_POS ? &const_pinf : &const_ninf);
687 : 198 : cp += 8;
688 : : }
689 [ + + ]: 346 : else if (pg_strncasecmp(cp, "inf", 3) == 0)
690 : : {
691 [ + + ]: 294 : res = make_result(sign == NUMERIC_POS ? &const_pinf : &const_ninf);
692 : 294 : cp += 3;
693 : : }
694 : : else
695 : 52 : goto invalid_syntax;
696 : :
697 : : /*
698 : : * Check for trailing junk; there should be nothing left but spaces.
699 : : *
700 : : * We intentionally do this check before applying the typmod because
701 : : * we would like to throw any trailing-junk syntax error before any
702 : : * semantic error resulting from apply_typmod_special().
703 : : */
704 [ + + ]: 802 : while (*cp)
705 : : {
706 [ - + ]: 21 : if (!isspace((unsigned char) *cp))
447 dean.a.rasheed@gmail 707 :UBC 0 : goto invalid_syntax;
447 dean.a.rasheed@gmail 708 :CBC 21 : cp++;
709 : : }
710 : :
711 [ - + ]: 781 : if (!apply_typmod_special(res, typmod, escontext))
447 dean.a.rasheed@gmail 712 :UBC 0 : PG_RETURN_NULL();
713 : : }
714 : : else
715 : : {
716 : : /*
717 : : * We have a normal numeric value, which may be a non-decimal integer
718 : : * or a regular decimal number.
719 : : */
720 : : NumericVar value;
721 : : int base;
722 : : bool have_error;
723 : :
5485 tgl@sss.pgh.pa.us 724 :CBC 52469 : init_var(&value);
725 : :
726 : : /*
727 : : * Determine the number's base by looking for a non-decimal prefix
728 : : * indicator ("0x", "0o", or "0b").
729 : : */
447 dean.a.rasheed@gmail 730 [ + + ]: 52469 : if (cp[0] == '0')
731 : : {
732 [ + + + + ]: 13521 : switch (cp[1])
733 : : {
734 : 36 : case 'x':
735 : : case 'X':
736 : 36 : base = 16;
737 : 36 : break;
738 : 21 : case 'o':
739 : : case 'O':
740 : 21 : base = 8;
741 : 21 : break;
742 : 21 : case 'b':
743 : : case 'B':
744 : 21 : base = 2;
745 : 21 : break;
746 : 13443 : default:
747 : 13443 : base = 10;
748 : : }
749 : : }
750 : : else
751 : 38948 : base = 10;
752 : :
753 : : /* Parse the rest of the number and apply the sign */
754 [ + + ]: 52469 : if (base == 10)
755 : : {
756 [ - + ]: 52391 : if (!set_var_from_str(str, cp, &value, &cp, escontext))
447 dean.a.rasheed@gmail 757 :UBC 0 : PG_RETURN_NULL();
447 dean.a.rasheed@gmail 758 :CBC 52367 : value.sign = sign;
759 : : }
760 : : else
761 : : {
762 [ - + ]: 78 : if (!set_var_from_non_decimal_integer_str(str, cp + 2, sign, base,
763 : : &value, &cp, escontext))
447 dean.a.rasheed@gmail 764 :UBC 0 : PG_RETURN_NULL();
765 : : }
766 : :
767 : : /*
768 : : * Should be nothing left but spaces. As above, throw any typmod error
769 : : * after finishing syntax check.
770 : : */
5485 tgl@sss.pgh.pa.us 771 [ + + ]:CBC 52475 : while (*cp)
772 : : {
773 [ + + ]: 75 : if (!isspace((unsigned char) *cp))
447 dean.a.rasheed@gmail 774 : 36 : goto invalid_syntax;
5485 tgl@sss.pgh.pa.us 775 : 39 : cp++;
776 : : }
777 : :
492 778 [ + + ]: 52400 : if (!apply_typmod(&value, typmod, escontext))
779 : 12 : PG_RETURN_NULL();
780 : :
781 : 52388 : res = make_result_opt_error(&value, &have_error);
782 : :
783 [ + + ]: 52388 : if (have_error)
784 [ + + ]: 9 : ereturn(escontext, (Datum) 0,
785 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
786 : : errmsg("value overflows numeric format")));
787 : :
5485 788 : 52379 : free_var(&value);
789 : : }
790 : :
8706 791 : 53160 : PG_RETURN_NUMERIC(res);
792 : :
447 dean.a.rasheed@gmail 793 : 88 : invalid_syntax:
794 [ + + ]: 88 : ereturn(escontext, (Datum) 0,
795 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
796 : : errmsg("invalid input syntax for type %s: \"%s\"",
797 : : "numeric", str)));
798 : : }
799 : :
800 : :
801 : : /*
802 : : * numeric_out() -
803 : : *
804 : : * Output function for numeric data type
805 : : */
806 : : Datum
8706 tgl@sss.pgh.pa.us 807 : 392192 : numeric_out(PG_FUNCTION_ARGS)
808 : : {
809 : 392192 : Numeric num = PG_GETARG_NUMERIC(0);
810 : : NumericVar x;
811 : : char *str;
812 : :
813 : : /*
814 : : * Handle NaN and infinities
815 : : */
1362 816 [ + + ]: 392192 : if (NUMERIC_IS_SPECIAL(num))
817 : : {
818 [ + + ]: 1740 : if (NUMERIC_IS_PINF(num))
819 : 499 : PG_RETURN_CSTRING(pstrdup("Infinity"));
820 [ + + ]: 1241 : else if (NUMERIC_IS_NINF(num))
821 : 308 : PG_RETURN_CSTRING(pstrdup("-Infinity"));
822 : : else
823 : 933 : PG_RETURN_CSTRING(pstrdup("NaN"));
824 : : }
825 : :
826 : : /*
827 : : * Get the number in the variable format.
828 : : */
4162 heikki.linnakangas@i 829 : 390452 : init_var_from_num(num, &x);
830 : :
831 : 390452 : str = get_str_from_var(&x);
832 : :
8706 tgl@sss.pgh.pa.us 833 : 390452 : PG_RETURN_CSTRING(str);
834 : : }
835 : :
836 : : /*
837 : : * numeric_is_nan() -
838 : : *
839 : : * Is Numeric value a NaN?
840 : : */
841 : : bool
5007 rhaas@postgresql.org 842 : 6801 : numeric_is_nan(Numeric num)
843 : : {
844 : 6801 : return NUMERIC_IS_NAN(num);
845 : : }
846 : :
847 : : /*
848 : : * numeric_is_inf() -
849 : : *
850 : : * Is Numeric value an infinity?
851 : : */
852 : : bool
1362 tgl@sss.pgh.pa.us 853 : 156 : numeric_is_inf(Numeric num)
854 : : {
855 : 156 : return NUMERIC_IS_INF(num);
856 : : }
857 : :
858 : : /*
859 : : * numeric_is_integral() -
860 : : *
861 : : * Is Numeric value integral?
862 : : */
863 : : static bool
864 : 33 : numeric_is_integral(Numeric num)
865 : : {
866 : : NumericVar arg;
867 : :
868 : : /* Reject NaN, but infinities are considered integral */
869 [ + + ]: 33 : if (NUMERIC_IS_SPECIAL(num))
870 : : {
871 [ - + ]: 15 : if (NUMERIC_IS_NAN(num))
1362 tgl@sss.pgh.pa.us 872 :UBC 0 : return false;
1362 tgl@sss.pgh.pa.us 873 :CBC 15 : return true;
874 : : }
875 : :
876 : : /* Integral if there are no digits to the right of the decimal point */
877 : 18 : init_var_from_num(num, &arg);
878 : :
879 [ + + + + ]: 18 : return (arg.ndigits == 0 || arg.ndigits <= arg.weight + 1);
880 : : }
881 : :
882 : : /*
883 : : * make_numeric_typmod() -
884 : : *
885 : : * Pack numeric precision and scale values into a typmod. The upper 16 bits
886 : : * are used for the precision (though actually not all these bits are needed,
887 : : * since the maximum allowed precision is 1000). The lower 16 bits are for
888 : : * the scale, but since the scale is constrained to the range [-1000, 1000],
889 : : * we use just the lower 11 of those 16 bits, and leave the remaining 5 bits
890 : : * unset, for possible future use.
891 : : *
892 : : * For purely historical reasons VARHDRSZ is then added to the result, thus
893 : : * the unused space in the upper 16 bits is not all as freely available as it
894 : : * might seem. (We can't let the result overflow to a negative int32, as
895 : : * other parts of the system would interpret that as not-a-valid-typmod.)
896 : : */
897 : : static inline int32
993 dean.a.rasheed@gmail 898 : 937 : make_numeric_typmod(int precision, int scale)
899 : : {
900 : 937 : return ((precision << 16) | (scale & 0x7ff)) + VARHDRSZ;
901 : : }
902 : :
903 : : /*
904 : : * Because of the offset, valid numeric typmods are at least VARHDRSZ
905 : : */
906 : : static inline bool
907 : 65122 : is_valid_numeric_typmod(int32 typmod)
908 : : {
909 : 65122 : return typmod >= (int32) VARHDRSZ;
910 : : }
911 : :
912 : : /*
913 : : * numeric_typmod_precision() -
914 : : *
915 : : * Extract the precision from a numeric typmod --- see make_numeric_typmod().
916 : : */
917 : : static inline int
918 : 12302 : numeric_typmod_precision(int32 typmod)
919 : : {
920 : 12302 : return ((typmod - VARHDRSZ) >> 16) & 0xffff;
921 : : }
922 : :
923 : : /*
924 : : * numeric_typmod_scale() -
925 : : *
926 : : * Extract the scale from a numeric typmod --- see make_numeric_typmod().
927 : : *
928 : : * Note that the scale may be negative, so we must do sign extension when
929 : : * unpacking it. We do this using the bit hack (x^1024)-1024, which sign
930 : : * extends an 11-bit two's complement number x.
931 : : */
932 : : static inline int
933 : 8535 : numeric_typmod_scale(int32 typmod)
934 : : {
935 : 8535 : return (((typmod - VARHDRSZ) & 0x7ff) ^ 1024) - 1024;
936 : : }
937 : :
938 : : /*
939 : : * numeric_maximum_size() -
940 : : *
941 : : * Maximum size of a numeric with given typmod, or -1 if unlimited/unknown.
942 : : */
943 : : int32
5002 rhaas@postgresql.org 944 : 3767 : numeric_maximum_size(int32 typmod)
945 : : {
946 : : int precision;
947 : : int numeric_digits;
948 : :
993 dean.a.rasheed@gmail 949 [ - + ]: 3767 : if (!is_valid_numeric_typmod(typmod))
5007 rhaas@postgresql.org 950 :UBC 0 : return -1;
951 : :
952 : : /* precision (ie, max # of digits) is in upper bits of typmod */
993 dean.a.rasheed@gmail 953 :CBC 3767 : precision = numeric_typmod_precision(typmod);
954 : :
955 : : /*
956 : : * This formula computes the maximum number of NumericDigits we could need
957 : : * in order to store the specified number of decimal digits. Because the
958 : : * weight is stored as a number of NumericDigits rather than a number of
959 : : * decimal digits, it's possible that the first NumericDigit will contain
960 : : * only a single decimal digit. Thus, the first two decimal digits can
961 : : * require two NumericDigits to store, but it isn't until we reach
962 : : * DEC_DIGITS + 2 decimal digits that we potentially need a third
963 : : * NumericDigit.
964 : : */
5002 rhaas@postgresql.org 965 : 3767 : numeric_digits = (precision + 2 * (DEC_DIGITS - 1)) / DEC_DIGITS;
966 : :
967 : : /*
968 : : * In most cases, the size of a numeric will be smaller than the value
969 : : * computed below, because the varlena header will typically get toasted
970 : : * down to a single byte before being stored on disk, and it may also be
971 : : * possible to use a short numeric header. But our job here is to compute
972 : : * the worst case.
973 : : */
974 : 3767 : return NUMERIC_HDRSZ + (numeric_digits * sizeof(NumericDigit));
975 : : }
976 : :
977 : : /*
978 : : * numeric_out_sci() -
979 : : *
980 : : * Output function for numeric data type in scientific notation.
981 : : */
982 : : char *
5361 tgl@sss.pgh.pa.us 983 : 117 : numeric_out_sci(Numeric num, int scale)
984 : : {
985 : : NumericVar x;
986 : : char *str;
987 : :
988 : : /*
989 : : * Handle NaN and infinities
990 : : */
1362 991 [ + + ]: 117 : if (NUMERIC_IS_SPECIAL(num))
992 : : {
993 [ + + ]: 9 : if (NUMERIC_IS_PINF(num))
994 : 3 : return pstrdup("Infinity");
995 [ + + ]: 6 : else if (NUMERIC_IS_NINF(num))
996 : 3 : return pstrdup("-Infinity");
997 : : else
998 : 3 : return pstrdup("NaN");
999 : : }
1000 : :
4162 heikki.linnakangas@i 1001 : 108 : init_var_from_num(num, &x);
1002 : :
5361 tgl@sss.pgh.pa.us 1003 : 108 : str = get_str_from_var_sci(&x, scale);
1004 : :
1005 : 108 : return str;
1006 : : }
1007 : :
1008 : : /*
1009 : : * numeric_normalize() -
1010 : : *
1011 : : * Output function for numeric data type, suppressing insignificant trailing
1012 : : * zeroes and then any trailing decimal point. The intent of this is to
1013 : : * produce strings that are equal if and only if the input numeric values
1014 : : * compare equal.
1015 : : */
1016 : : char *
3675 andrew@dunslane.net 1017 : 6483 : numeric_normalize(Numeric num)
1018 : : {
1019 : : NumericVar x;
1020 : : char *str;
1021 : : int last;
1022 : :
1023 : : /*
1024 : : * Handle NaN and infinities
1025 : : */
1362 tgl@sss.pgh.pa.us 1026 [ - + ]: 6483 : if (NUMERIC_IS_SPECIAL(num))
1027 : : {
1362 tgl@sss.pgh.pa.us 1028 [ # # ]:UBC 0 : if (NUMERIC_IS_PINF(num))
1029 : 0 : return pstrdup("Infinity");
1030 [ # # ]: 0 : else if (NUMERIC_IS_NINF(num))
1031 : 0 : return pstrdup("-Infinity");
1032 : : else
1033 : 0 : return pstrdup("NaN");
1034 : : }
1035 : :
3675 andrew@dunslane.net 1036 :CBC 6483 : init_var_from_num(num, &x);
1037 : :
1038 : 6483 : str = get_str_from_var(&x);
1039 : :
1040 : : /* If there's no decimal point, there's certainly nothing to remove. */
3447 tgl@sss.pgh.pa.us 1041 [ + + ]: 6483 : if (strchr(str, '.') != NULL)
1042 : : {
1043 : : /*
1044 : : * Back up over trailing fractional zeroes. Since there is a decimal
1045 : : * point, this loop will terminate safely.
1046 : : */
1047 : 21 : last = strlen(str) - 1;
1048 [ + + ]: 42 : while (str[last] == '0')
1049 : 21 : last--;
1050 : :
1051 : : /* We want to get rid of the decimal point too, if it's now last. */
1052 [ + - ]: 21 : if (str[last] == '.')
1053 : 21 : last--;
1054 : :
1055 : : /* Delete whatever we backed up over. */
1056 : 21 : str[last + 1] = '\0';
1057 : : }
1058 : :
3675 andrew@dunslane.net 1059 : 6483 : return str;
1060 : : }
1061 : :
1062 : : /*
1063 : : * numeric_recv - converts external binary format to numeric
1064 : : *
1065 : : * External format is a sequence of int16's:
1066 : : * ndigits, weight, sign, dscale, NumericDigits.
1067 : : */
1068 : : Datum
7643 tgl@sss.pgh.pa.us 1069 : 51 : numeric_recv(PG_FUNCTION_ARGS)
1070 : : {
1071 : 51 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
1072 : :
1073 : : #ifdef NOT_USED
1074 : : Oid typelem = PG_GETARG_OID(1);
1075 : : #endif
6853 1076 : 51 : int32 typmod = PG_GETARG_INT32(2);
1077 : : NumericVar value;
1078 : : Numeric res;
1079 : : int len,
1080 : : i;
1081 : :
7643 1082 : 51 : init_var(&value);
1083 : :
1084 : 51 : len = (uint16) pq_getmsgint(buf, sizeof(uint16));
1085 : :
1086 : 51 : alloc_var(&value, len);
1087 : :
1088 : 51 : value.weight = (int16) pq_getmsgint(buf, sizeof(int16));
1089 : : /* we allow any int16 for weight --- OK? */
1090 : :
1091 : 51 : value.sign = (uint16) pq_getmsgint(buf, sizeof(uint16));
1092 [ - + ]: 51 : if (!(value.sign == NUMERIC_POS ||
7643 tgl@sss.pgh.pa.us 1093 [ # # ]:UBC 0 : value.sign == NUMERIC_NEG ||
1362 1094 [ # # ]: 0 : value.sign == NUMERIC_NAN ||
1095 [ # # ]: 0 : value.sign == NUMERIC_PINF ||
1096 [ # # ]: 0 : value.sign == NUMERIC_NINF))
7567 1097 [ # # ]: 0 : ereport(ERROR,
1098 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1099 : : errmsg("invalid sign in external \"numeric\" value")));
1100 : :
7643 tgl@sss.pgh.pa.us 1101 :CBC 51 : value.dscale = (uint16) pq_getmsgint(buf, sizeof(uint16));
3422 1102 [ - + ]: 51 : if ((value.dscale & NUMERIC_DSCALE_MASK) != value.dscale)
3422 tgl@sss.pgh.pa.us 1103 [ # # ]:UBC 0 : ereport(ERROR,
1104 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1105 : : errmsg("invalid scale in external \"numeric\" value")));
1106 : :
7643 tgl@sss.pgh.pa.us 1107 [ + + ]:CBC 137 : for (i = 0; i < len; i++)
1108 : : {
7559 bruce@momjian.us 1109 : 86 : NumericDigit d = pq_getmsgint(buf, sizeof(NumericDigit));
1110 : :
7643 tgl@sss.pgh.pa.us 1111 [ + - - + ]: 86 : if (d < 0 || d >= NBASE)
7567 tgl@sss.pgh.pa.us 1112 [ # # ]:UBC 0 : ereport(ERROR,
1113 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1114 : : errmsg("invalid digit in external \"numeric\" value")));
7643 tgl@sss.pgh.pa.us 1115 :CBC 86 : value.digits[i] = d;
1116 : : }
1117 : :
1118 : : /*
1119 : : * If the given dscale would hide any digits, truncate those digits away.
1120 : : * We could alternatively throw an error, but that would take a bunch of
1121 : : * extra code (about as much as trunc_var involves), and it might cause
1122 : : * client compatibility issues. Be careful not to apply trunc_var to
1123 : : * special values, as it could do the wrong thing; we don't need it
1124 : : * anyway, since make_result will ignore all but the sign field.
1125 : : *
1126 : : * After doing that, be sure to check the typmod restriction.
1127 : : */
1362 1128 [ - + ]: 51 : if (value.sign == NUMERIC_POS ||
1362 tgl@sss.pgh.pa.us 1129 [ # # ]:UBC 0 : value.sign == NUMERIC_NEG)
1130 : : {
1362 tgl@sss.pgh.pa.us 1131 :CBC 51 : trunc_var(&value, value.dscale);
1132 : :
492 1133 : 51 : (void) apply_typmod(&value, typmod, NULL);
1134 : :
1362 1135 : 51 : res = make_result(&value);
1136 : : }
1137 : : else
1138 : : {
1139 : : /* apply_typmod_special wants us to make the Numeric first */
1362 tgl@sss.pgh.pa.us 1140 :UBC 0 : res = make_result(&value);
1141 : :
492 1142 : 0 : (void) apply_typmod_special(res, typmod, NULL);
1143 : : }
1144 : :
7643 tgl@sss.pgh.pa.us 1145 :CBC 51 : free_var(&value);
1146 : :
1147 : 51 : PG_RETURN_NUMERIC(res);
1148 : : }
1149 : :
1150 : : /*
1151 : : * numeric_send - converts numeric to binary format
1152 : : */
1153 : : Datum
1154 : 35 : numeric_send(PG_FUNCTION_ARGS)
1155 : : {
1156 : 35 : Numeric num = PG_GETARG_NUMERIC(0);
1157 : : NumericVar x;
1158 : : StringInfoData buf;
1159 : : int i;
1160 : :
4162 heikki.linnakangas@i 1161 : 35 : init_var_from_num(num, &x);
1162 : :
7643 tgl@sss.pgh.pa.us 1163 : 35 : pq_begintypsend(&buf);
1164 : :
2377 andres@anarazel.de 1165 : 35 : pq_sendint16(&buf, x.ndigits);
1166 : 35 : pq_sendint16(&buf, x.weight);
1167 : 35 : pq_sendint16(&buf, x.sign);
1168 : 35 : pq_sendint16(&buf, x.dscale);
7643 tgl@sss.pgh.pa.us 1169 [ + + ]: 97 : for (i = 0; i < x.ndigits; i++)
2377 andres@anarazel.de 1170 : 62 : pq_sendint16(&buf, x.digits[i]);
1171 : :
7643 tgl@sss.pgh.pa.us 1172 : 35 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1173 : : }
1174 : :
1175 : :
1176 : : /*
1177 : : * numeric_support()
1178 : : *
1179 : : * Planner support function for the numeric() length coercion function.
1180 : : *
1181 : : * Flatten calls that solely represent increases in allowable precision.
1182 : : * Scale changes mutate every datum, so they are unoptimizable. Some values,
1183 : : * e.g. 1E-1001, can only fit into an unconstrained numeric, so a change from
1184 : : * an unconstrained numeric to any constrained numeric is also unoptimizable.
1185 : : */
1186 : : Datum
1891 1187 : 258 : numeric_support(PG_FUNCTION_ARGS)
1188 : : {
1189 : 258 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
4450 rhaas@postgresql.org 1190 : 258 : Node *ret = NULL;
1191 : :
1891 tgl@sss.pgh.pa.us 1192 [ + + ]: 258 : if (IsA(rawreq, SupportRequestSimplify))
1193 : : {
1194 : 114 : SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
1195 : 114 : FuncExpr *expr = req->fcall;
1196 : : Node *typmod;
1197 : :
1198 [ - + ]: 114 : Assert(list_length(expr->args) >= 2);
1199 : :
1200 : 114 : typmod = (Node *) lsecond(expr->args);
1201 : :
1429 1202 [ + - + - ]: 114 : if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
1203 : : {
1891 1204 : 114 : Node *source = (Node *) linitial(expr->args);
1205 : 114 : int32 old_typmod = exprTypmod(source);
1206 : 114 : int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
993 dean.a.rasheed@gmail 1207 : 114 : int32 old_scale = numeric_typmod_scale(old_typmod);
1208 : 114 : int32 new_scale = numeric_typmod_scale(new_typmod);
1209 : 114 : int32 old_precision = numeric_typmod_precision(old_typmod);
1210 : 114 : int32 new_precision = numeric_typmod_precision(new_typmod);
1211 : :
1212 : : /*
1213 : : * If new_typmod is invalid, the destination is unconstrained;
1214 : : * that's always OK. If old_typmod is valid, the source is
1215 : : * constrained, and we're OK if the scale is unchanged and the
1216 : : * precision is not decreasing. See further notes in function
1217 : : * header comment.
1218 : : */
1219 [ + - + + ]: 228 : if (!is_valid_numeric_typmod(new_typmod) ||
1220 [ + + ]: 120 : (is_valid_numeric_typmod(old_typmod) &&
1891 tgl@sss.pgh.pa.us 1221 [ + - ]: 3 : new_scale == old_scale && new_precision >= old_precision))
1222 : 3 : ret = relabel_to_typmod(source, new_typmod);
1223 : : }
1224 : : }
1225 : :
4450 rhaas@postgresql.org 1226 : 258 : PG_RETURN_POINTER(ret);
1227 : : }
1228 : :
1229 : : /*
1230 : : * numeric() -
1231 : : *
1232 : : * This is a special function called by the Postgres database system
1233 : : * before a value is stored in a tuple's attribute. The precision and
1234 : : * scale of the attribute have to be applied on the value.
1235 : : */
1236 : : Datum
5995 bruce@momjian.us 1237 : 5881 : numeric (PG_FUNCTION_ARGS)
1238 : : {
8706 tgl@sss.pgh.pa.us 1239 : 5881 : Numeric num = PG_GETARG_NUMERIC(0);
1240 : 5881 : int32 typmod = PG_GETARG_INT32(1);
1241 : : Numeric new;
1242 : : int precision;
1243 : : int scale;
1244 : : int ddigits;
1245 : : int maxdigits;
1246 : : int dscale;
1247 : : NumericVar var;
1248 : :
1249 : : /*
1250 : : * Handle NaN and infinities: if apply_typmod_special doesn't complain,
1251 : : * just return a copy of the input.
1252 : : */
1362 1253 [ + + ]: 5881 : if (NUMERIC_IS_SPECIAL(num))
1254 : : {
492 1255 : 105 : (void) apply_typmod_special(num, typmod, NULL);
1362 1256 : 96 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1257 : : }
1258 : :
1259 : : /*
1260 : : * If the value isn't a valid type modifier, simply return a copy of the
1261 : : * input value
1262 : : */
993 dean.a.rasheed@gmail 1263 [ - + ]: 5776 : if (!is_valid_numeric_typmod(typmod))
1362 tgl@sss.pgh.pa.us 1264 :UBC 0 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1265 : :
1266 : : /*
1267 : : * Get the precision and scale out of the typmod value
1268 : : */
993 dean.a.rasheed@gmail 1269 :CBC 5776 : precision = numeric_typmod_precision(typmod);
1270 : 5776 : scale = numeric_typmod_scale(typmod);
7695 tgl@sss.pgh.pa.us 1271 : 5776 : maxdigits = precision - scale;
1272 : :
1273 : : /* The target display scale is non-negative */
993 dean.a.rasheed@gmail 1274 : 5776 : dscale = Max(scale, 0);
1275 : :
1276 : : /*
1277 : : * If the number is certainly in bounds and due to the target scale no
1278 : : * rounding could be necessary, just make a copy of the input and modify
1279 : : * its scale fields, unless the larger scale forces us to abandon the
1280 : : * short representation. (Note we assume the existing dscale is
1281 : : * honest...)
1282 : : */
5003 rhaas@postgresql.org 1283 [ + + + + ]: 5776 : ddigits = (NUMERIC_WEIGHT(num) + 1) * DEC_DIGITS;
1284 [ + + + + : 5776 : if (ddigits <= maxdigits && scale >= NUMERIC_DSCALE(num)
+ + ]
993 dean.a.rasheed@gmail 1285 [ + - + - : 3565 : && (NUMERIC_CAN_BE_SHORT(dscale, NUMERIC_WEIGHT(num))
+ + + - -
- + - + +
- + - - ]
4753 bruce@momjian.us 1286 [ # # ]:UBC 0 : || !NUMERIC_IS_SHORT(num)))
1287 : : {
1362 tgl@sss.pgh.pa.us 1288 :CBC 3565 : new = duplicate_numeric(num);
5003 rhaas@postgresql.org 1289 [ + - ]: 3565 : if (NUMERIC_IS_SHORT(num))
1290 : 3565 : new->choice.n_short.n_header =
1291 : 3565 : (num->choice.n_short.n_header & ~NUMERIC_SHORT_DSCALE_MASK)
993 dean.a.rasheed@gmail 1292 : 3565 : | (dscale << NUMERIC_SHORT_DSCALE_SHIFT);
1293 : : else
5003 rhaas@postgresql.org 1294 [ # # # # ]:UBC 0 : new->choice.n_long.n_sign_dscale = NUMERIC_SIGN(new) |
993 dean.a.rasheed@gmail 1295 : 0 : ((uint16) dscale & NUMERIC_DSCALE_MASK);
8706 tgl@sss.pgh.pa.us 1296 :CBC 3565 : PG_RETURN_NUMERIC(new);
1297 : : }
1298 : :
1299 : : /*
1300 : : * We really need to fiddle with things - unpack the number into a
1301 : : * variable and let apply_typmod() do it.
1302 : : */
9237 JanWieck@Yahoo.com 1303 : 2211 : init_var(&var);
1304 : :
1305 : 2211 : set_var_from_num(num, &var);
492 tgl@sss.pgh.pa.us 1306 : 2211 : (void) apply_typmod(&var, typmod, NULL);
9237 JanWieck@Yahoo.com 1307 : 2181 : new = make_result(&var);
1308 : :
1309 : 2181 : free_var(&var);
1310 : :
8706 tgl@sss.pgh.pa.us 1311 : 2181 : PG_RETURN_NUMERIC(new);
1312 : : }
1313 : :
1314 : : Datum
6315 1315 : 958 : numerictypmodin(PG_FUNCTION_ARGS)
1316 : : {
5995 bruce@momjian.us 1317 : 958 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
1318 : : int32 *tl;
1319 : : int n;
1320 : : int32 typmod;
1321 : :
6148 tgl@sss.pgh.pa.us 1322 : 958 : tl = ArrayGetIntegerTypmods(ta, &n);
1323 : :
6315 1324 [ + + ]: 958 : if (n == 2)
1325 : : {
1326 [ + + + + ]: 950 : if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
6315 tgl@sss.pgh.pa.us 1327 [ + - ]:GBC 9 : ereport(ERROR,
1328 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1329 : : errmsg("NUMERIC precision %d must be between 1 and %d",
1330 : : tl[0], NUMERIC_MAX_PRECISION)));
993 dean.a.rasheed@gmail 1331 [ + + + + ]:CBC 941 : if (tl[1] < NUMERIC_MIN_SCALE || tl[1] > NUMERIC_MAX_SCALE)
6315 tgl@sss.pgh.pa.us 1332 [ + - ]:GBC 6 : ereport(ERROR,
1333 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1334 : : errmsg("NUMERIC scale %d must be between %d and %d",
1335 : : tl[1], NUMERIC_MIN_SCALE, NUMERIC_MAX_SCALE)));
993 dean.a.rasheed@gmail 1336 :CBC 935 : typmod = make_numeric_typmod(tl[0], tl[1]);
1337 : : }
6315 tgl@sss.pgh.pa.us 1338 [ + + ]: 8 : else if (n == 1)
1339 : : {
1340 [ + - - + ]: 2 : if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
6315 tgl@sss.pgh.pa.us 1341 [ # # ]:UBC 0 : ereport(ERROR,
1342 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1343 : : errmsg("NUMERIC precision %d must be between 1 and %d",
1344 : : tl[0], NUMERIC_MAX_PRECISION)));
1345 : : /* scale defaults to zero */
993 dean.a.rasheed@gmail 1346 :CBC 2 : typmod = make_numeric_typmod(tl[0], 0);
1347 : : }
1348 : : else
1349 : : {
6315 tgl@sss.pgh.pa.us 1350 [ + - ]: 6 : ereport(ERROR,
1351 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1352 : : errmsg("invalid NUMERIC type modifier")));
1353 : : typmod = 0; /* keep compiler quiet */
1354 : : }
1355 : :
1356 : 937 : PG_RETURN_INT32(typmod);
1357 : : }
1358 : :
1359 : : Datum
1360 : 188 : numerictypmodout(PG_FUNCTION_ARGS)
1361 : : {
5995 bruce@momjian.us 1362 : 188 : int32 typmod = PG_GETARG_INT32(0);
1363 : 188 : char *res = (char *) palloc(64);
1364 : :
993 dean.a.rasheed@gmail 1365 [ + - ]: 188 : if (is_valid_numeric_typmod(typmod))
6315 tgl@sss.pgh.pa.us 1366 : 188 : snprintf(res, 64, "(%d,%d)",
1367 : : numeric_typmod_precision(typmod),
1368 : : numeric_typmod_scale(typmod));
1369 : : else
6315 tgl@sss.pgh.pa.us 1370 :UBC 0 : *res = '\0';
1371 : :
6315 tgl@sss.pgh.pa.us 1372 :CBC 188 : PG_RETURN_CSTRING(res);
1373 : : }
1374 : :
1375 : :
1376 : : /* ----------------------------------------------------------------------
1377 : : *
1378 : : * Sign manipulation, rounding and the like
1379 : : *
1380 : : * ----------------------------------------------------------------------
1381 : : */
1382 : :
1383 : : Datum
8660 1384 : 9753 : numeric_abs(PG_FUNCTION_ARGS)
1385 : : {
1386 : 9753 : Numeric num = PG_GETARG_NUMERIC(0);
1387 : : Numeric res;
1388 : :
1389 : : /*
1390 : : * Do it the easy way directly on the packed format
1391 : : */
1362 1392 : 9753 : res = duplicate_numeric(num);
1393 : :
5003 rhaas@postgresql.org 1394 [ + + ]: 9753 : if (NUMERIC_IS_SHORT(num))
1395 : 9720 : res->choice.n_short.n_header =
1396 : 9720 : num->choice.n_short.n_header & ~NUMERIC_SHORT_SIGN_MASK;
1362 tgl@sss.pgh.pa.us 1397 [ + + ]: 33 : else if (NUMERIC_IS_SPECIAL(num))
1398 : : {
1399 : : /* This changes -Inf to Inf, and doesn't affect NaN */
1400 : 9 : res->choice.n_short.n_header =
1401 : 9 : num->choice.n_short.n_header & ~NUMERIC_INF_SIGN_MASK;
1402 : : }
1403 : : else
5003 rhaas@postgresql.org 1404 [ - + ]: 24 : res->choice.n_long.n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
1405 : :
8660 tgl@sss.pgh.pa.us 1406 : 9753 : PG_RETURN_NUMERIC(res);
1407 : : }
1408 : :
1409 : :
1410 : : Datum
1411 : 442 : numeric_uminus(PG_FUNCTION_ARGS)
1412 : : {
1413 : 442 : Numeric num = PG_GETARG_NUMERIC(0);
1414 : : Numeric res;
1415 : :
1416 : : /*
1417 : : * Do it the easy way directly on the packed format
1418 : : */
1362 1419 : 442 : res = duplicate_numeric(num);
1420 : :
1421 [ + + ]: 442 : if (NUMERIC_IS_SPECIAL(num))
1422 : : {
1423 : : /* Flip the sign, if it's Inf or -Inf */
1424 [ + + ]: 63 : if (!NUMERIC_IS_NAN(num))
1425 : 42 : res->choice.n_short.n_header =
1426 : 42 : num->choice.n_short.n_header ^ NUMERIC_INF_SIGN_MASK;
1427 : : }
1428 : :
1429 : : /*
1430 : : * The packed format is known to be totally zero digit trimmed always. So
1431 : : * once we've eliminated specials, we can identify a zero by the fact that
1432 : : * there are no digits at all. Do nothing to a zero.
1433 : : */
1434 [ + - + + ]: 379 : else if (NUMERIC_NDIGITS(num) != 0)
1435 : : {
1436 : : /* Else, flip the sign */
5003 rhaas@postgresql.org 1437 [ + - ]: 322 : if (NUMERIC_IS_SHORT(num))
1438 : 322 : res->choice.n_short.n_header =
1439 : 322 : num->choice.n_short.n_header ^ NUMERIC_SHORT_SIGN_MASK;
5003 rhaas@postgresql.org 1440 [ # # # # :UBC 0 : else if (NUMERIC_SIGN(num) == NUMERIC_POS)
# # ]
1441 : 0 : res->choice.n_long.n_sign_dscale =
1442 [ # # ]: 0 : NUMERIC_NEG | NUMERIC_DSCALE(num);
1443 : : else
1444 : 0 : res->choice.n_long.n_sign_dscale =
1445 [ # # ]: 0 : NUMERIC_POS | NUMERIC_DSCALE(num);
1446 : : }
1447 : :
8660 tgl@sss.pgh.pa.us 1448 :CBC 442 : PG_RETURN_NUMERIC(res);
1449 : : }
1450 : :
1451 : :
1452 : : Datum
8347 bruce@momjian.us 1453 : 249 : numeric_uplus(PG_FUNCTION_ARGS)
1454 : : {
1455 : 249 : Numeric num = PG_GETARG_NUMERIC(0);
1456 : :
1362 tgl@sss.pgh.pa.us 1457 : 249 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1458 : : }
1459 : :
1460 : :
1461 : : /*
1462 : : * numeric_sign_internal() -
1463 : : *
1464 : : * Returns -1 if the argument is less than 0, 0 if the argument is equal
1465 : : * to 0, and 1 if the argument is greater than zero. Caller must have
1466 : : * taken care of the NaN case, but we can handle infinities here.
1467 : : */
1468 : : static int
1469 : 1773 : numeric_sign_internal(Numeric num)
1470 : : {
1471 [ + + ]: 1773 : if (NUMERIC_IS_SPECIAL(num))
1472 : : {
1473 [ - + ]: 156 : Assert(!NUMERIC_IS_NAN(num));
1474 : : /* Must be Inf or -Inf */
1475 [ + + ]: 156 : if (NUMERIC_IS_PINF(num))
1476 : 93 : return 1;
1477 : : else
1478 : 63 : return -1;
1479 : : }
1480 : :
1481 : : /*
1482 : : * The packed format is known to be totally zero digit trimmed always. So
1483 : : * once we've eliminated specials, we can identify a zero by the fact that
1484 : : * there are no digits at all.
1485 : : */
1486 [ + + + + ]: 1617 : else if (NUMERIC_NDIGITS(num) == 0)
1487 : 114 : return 0;
1488 [ + + - + : 1503 : else if (NUMERIC_SIGN(num) == NUMERIC_NEG)
+ + ]
1489 : 363 : return -1;
1490 : : else
1491 : 1140 : return 1;
1492 : : }
1493 : :
1494 : : /*
1495 : : * numeric_sign() -
1496 : : *
1497 : : * returns -1 if the argument is less than 0, 0 if the argument is equal
1498 : : * to 0, and 1 if the argument is greater than zero.
1499 : : */
1500 : : Datum
8660 1501 : 24 : numeric_sign(PG_FUNCTION_ARGS)
1502 : : {
1503 : 24 : Numeric num = PG_GETARG_NUMERIC(0);
1504 : :
1505 : : /*
1506 : : * Handle NaN (infinities can be handled normally)
1507 : : */
9237 JanWieck@Yahoo.com 1508 [ + + ]: 24 : if (NUMERIC_IS_NAN(num))
8660 tgl@sss.pgh.pa.us 1509 : 3 : PG_RETURN_NUMERIC(make_result(&const_nan));
1510 : :
1362 1511 [ + + + - ]: 21 : switch (numeric_sign_internal(num))
1512 : : {
1513 : 3 : case 0:
1514 : 3 : PG_RETURN_NUMERIC(make_result(&const_zero));
1515 : 9 : case 1:
1516 : 9 : PG_RETURN_NUMERIC(make_result(&const_one));
1517 : 9 : case -1:
1518 : 9 : PG_RETURN_NUMERIC(make_result(&const_minus_one));
1519 : : }
1520 : :
1362 tgl@sss.pgh.pa.us 1521 :UBC 0 : Assert(false);
1522 : : return (Datum) 0;
1523 : : }
1524 : :
1525 : :
1526 : : /*
1527 : : * numeric_round() -
1528 : : *
1529 : : * Round a value to have 'scale' digits after the decimal point.
1530 : : * We allow negative 'scale', implying rounding before the decimal
1531 : : * point --- Oracle interprets rounding that way.
1532 : : */
1533 : : Datum
8706 tgl@sss.pgh.pa.us 1534 :CBC 3871 : numeric_round(PG_FUNCTION_ARGS)
1535 : : {
1536 : 3871 : Numeric num = PG_GETARG_NUMERIC(0);
1537 : 3871 : int32 scale = PG_GETARG_INT32(1);
1538 : : Numeric res;
1539 : : NumericVar arg;
1540 : :
1541 : : /*
1542 : : * Handle NaN and infinities
1543 : : */
1362 1544 [ + + ]: 3871 : if (NUMERIC_IS_SPECIAL(num))
1545 : 48 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1546 : :
1547 : : /*
1548 : : * Limit the scale value to avoid possible overflow in calculations
1549 : : */
7865 1550 : 3823 : scale = Max(scale, -NUMERIC_MAX_RESULT_SCALE);
1551 : 3823 : scale = Min(scale, NUMERIC_MAX_RESULT_SCALE);
1552 : :
1553 : : /*
1554 : : * Unpack the argument and round it at the proper digit position
1555 : : */
8798 1556 : 3823 : init_var(&arg);
1557 : 3823 : set_var_from_num(num, &arg);
1558 : :
7695 1559 : 3823 : round_var(&arg, scale);
1560 : :
1561 : : /* We don't allow negative output dscale */
1562 [ + + ]: 3823 : if (scale < 0)
1563 : 90 : arg.dscale = 0;
1564 : :
1565 : : /*
1566 : : * Return the rounded result
1567 : : */
8798 1568 : 3823 : res = make_result(&arg);
1569 : :
1570 : 3823 : free_var(&arg);
8706 1571 : 3823 : PG_RETURN_NUMERIC(res);
1572 : : }
1573 : :
1574 : :
1575 : : /*
1576 : : * numeric_trunc() -
1577 : : *
1578 : : * Truncate a value to have 'scale' digits after the decimal point.
1579 : : * We allow negative 'scale', implying a truncation before the decimal
1580 : : * point --- Oracle interprets truncation that way.
1581 : : */
1582 : : Datum
1583 : 289 : numeric_trunc(PG_FUNCTION_ARGS)
1584 : : {
1585 : 289 : Numeric num = PG_GETARG_NUMERIC(0);
1586 : 289 : int32 scale = PG_GETARG_INT32(1);
1587 : : Numeric res;
1588 : : NumericVar arg;
1589 : :
1590 : : /*
1591 : : * Handle NaN and infinities
1592 : : */
1362 1593 [ + + ]: 289 : if (NUMERIC_IS_SPECIAL(num))
1594 : 18 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1595 : :
1596 : : /*
1597 : : * Limit the scale value to avoid possible overflow in calculations
1598 : : */
7865 1599 : 271 : scale = Max(scale, -NUMERIC_MAX_RESULT_SCALE);
1600 : 271 : scale = Min(scale, NUMERIC_MAX_RESULT_SCALE);
1601 : :
1602 : : /*
1603 : : * Unpack the argument and truncate it at the proper digit position
1604 : : */
9237 JanWieck@Yahoo.com 1605 : 271 : init_var(&arg);
1606 : 271 : set_var_from_num(num, &arg);
1607 : :
7695 tgl@sss.pgh.pa.us 1608 : 271 : trunc_var(&arg, scale);
1609 : :
1610 : : /* We don't allow negative output dscale */
1611 [ - + ]: 271 : if (scale < 0)
7695 tgl@sss.pgh.pa.us 1612 :UBC 0 : arg.dscale = 0;
1613 : :
1614 : : /*
1615 : : * Return the truncated result
1616 : : */
9237 JanWieck@Yahoo.com 1617 :CBC 271 : res = make_result(&arg);
1618 : :
1619 : 271 : free_var(&arg);
8706 tgl@sss.pgh.pa.us 1620 : 271 : PG_RETURN_NUMERIC(res);
1621 : : }
1622 : :
1623 : :
1624 : : /*
1625 : : * numeric_ceil() -
1626 : : *
1627 : : * Return the smallest integer greater than or equal to the argument
1628 : : */
1629 : : Datum
8660 1630 : 111 : numeric_ceil(PG_FUNCTION_ARGS)
1631 : : {
1632 : 111 : Numeric num = PG_GETARG_NUMERIC(0);
1633 : : Numeric res;
1634 : : NumericVar result;
1635 : :
1636 : : /*
1637 : : * Handle NaN and infinities
1638 : : */
1362 1639 [ + + ]: 111 : if (NUMERIC_IS_SPECIAL(num))
1640 : 9 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1641 : :
4162 heikki.linnakangas@i 1642 : 102 : init_var_from_num(num, &result);
9237 JanWieck@Yahoo.com 1643 : 102 : ceil_var(&result, &result);
1644 : :
1645 : 102 : res = make_result(&result);
1646 : 102 : free_var(&result);
1647 : :
8660 tgl@sss.pgh.pa.us 1648 : 102 : PG_RETURN_NUMERIC(res);
1649 : : }
1650 : :
1651 : :
1652 : : /*
1653 : : * numeric_floor() -
1654 : : *
1655 : : * Return the largest integer equal to or less than the argument
1656 : : */
1657 : : Datum
1658 : 63 : numeric_floor(PG_FUNCTION_ARGS)
1659 : : {
1660 : 63 : Numeric num = PG_GETARG_NUMERIC(0);
1661 : : Numeric res;
1662 : : NumericVar result;
1663 : :
1664 : : /*
1665 : : * Handle NaN and infinities
1666 : : */
1362 1667 [ + + ]: 63 : if (NUMERIC_IS_SPECIAL(num))
1668 : 9 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1669 : :
4162 heikki.linnakangas@i 1670 : 54 : init_var_from_num(num, &result);
9237 JanWieck@Yahoo.com 1671 : 54 : floor_var(&result, &result);
1672 : :
1673 : 54 : res = make_result(&result);
1674 : 54 : free_var(&result);
1675 : :
8660 tgl@sss.pgh.pa.us 1676 : 54 : PG_RETURN_NUMERIC(res);
1677 : : }
1678 : :
1679 : :
1680 : : /*
1681 : : * generate_series_numeric() -
1682 : : *
1683 : : * Generate series of numeric.
1684 : : */
1685 : : Datum
3442 fujii@postgresql.org 1686 : 108 : generate_series_numeric(PG_FUNCTION_ARGS)
1687 : : {
1688 : 108 : return generate_series_step_numeric(fcinfo);
1689 : : }
1690 : :
1691 : : Datum
1692 : 210 : generate_series_step_numeric(PG_FUNCTION_ARGS)
1693 : : {
1694 : : generate_series_numeric_fctx *fctx;
1695 : : FuncCallContext *funcctx;
1696 : : MemoryContext oldcontext;
1697 : :
1698 [ + + ]: 210 : if (SRF_IS_FIRSTCALL())
1699 : : {
1700 : 69 : Numeric start_num = PG_GETARG_NUMERIC(0);
1701 : 69 : Numeric stop_num = PG_GETARG_NUMERIC(1);
1702 : 69 : NumericVar steploc = const_one;
1703 : :
1704 : : /* Reject NaN and infinities in start and stop values */
1362 tgl@sss.pgh.pa.us 1705 [ + + ]: 69 : if (NUMERIC_IS_SPECIAL(start_num))
1706 : : {
1707 [ + + ]: 6 : if (NUMERIC_IS_NAN(start_num))
1708 [ + - ]: 3 : ereport(ERROR,
1709 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1710 : : errmsg("start value cannot be NaN")));
1711 : : else
1712 [ + - ]: 3 : ereport(ERROR,
1713 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1714 : : errmsg("start value cannot be infinity")));
1715 : : }
1716 [ + + ]: 63 : if (NUMERIC_IS_SPECIAL(stop_num))
1717 : : {
1718 [ + + ]: 6 : if (NUMERIC_IS_NAN(stop_num))
1719 [ + - ]: 3 : ereport(ERROR,
1720 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1721 : : errmsg("stop value cannot be NaN")));
1722 : : else
1723 [ + - ]: 3 : ereport(ERROR,
1724 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1725 : : errmsg("stop value cannot be infinity")));
1726 : : }
1727 : :
1728 : : /* see if we were given an explicit step size */
3442 fujii@postgresql.org 1729 [ + + ]: 57 : if (PG_NARGS() == 3)
1730 : : {
3340 tgl@sss.pgh.pa.us 1731 : 27 : Numeric step_num = PG_GETARG_NUMERIC(2);
1732 : :
1362 1733 [ + + ]: 27 : if (NUMERIC_IS_SPECIAL(step_num))
1734 : : {
1735 [ + + ]: 6 : if (NUMERIC_IS_NAN(step_num))
1736 [ + - ]: 3 : ereport(ERROR,
1737 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1738 : : errmsg("step size cannot be NaN")));
1739 : : else
1740 [ + - ]: 3 : ereport(ERROR,
1741 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1742 : : errmsg("step size cannot be infinity")));
1743 : : }
1744 : :
3442 fujii@postgresql.org 1745 : 21 : init_var_from_num(step_num, &steploc);
1746 : :
1747 [ + + ]: 21 : if (cmp_var(&steploc, &const_zero) == 0)
1748 [ + - ]: 3 : ereport(ERROR,
1749 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1750 : : errmsg("step size cannot equal zero")));
1751 : : }
1752 : :
1753 : : /* create a function context for cross-call persistence */
1754 : 48 : funcctx = SRF_FIRSTCALL_INIT();
1755 : :
1756 : : /*
1757 : : * Switch to memory context appropriate for multiple function calls.
1758 : : */
1759 : 48 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1760 : :
1761 : : /* allocate memory for user context */
1762 : : fctx = (generate_series_numeric_fctx *)
1763 : 48 : palloc(sizeof(generate_series_numeric_fctx));
1764 : :
1765 : : /*
1766 : : * Use fctx to keep state from call to call. Seed current with the
1767 : : * original start value. We must copy the start_num and stop_num
1768 : : * values rather than pointing to them, since we may have detoasted
1769 : : * them in the per-call context.
1770 : : */
3405 1771 : 48 : init_var(&fctx->current);
1772 : 48 : init_var(&fctx->stop);
3442 1773 : 48 : init_var(&fctx->step);
1774 : :
3405 1775 : 48 : set_var_from_num(start_num, &fctx->current);
1776 : 48 : set_var_from_num(stop_num, &fctx->stop);
3442 1777 : 48 : set_var_from_var(&steploc, &fctx->step);
1778 : :
1779 : 48 : funcctx->user_fctx = fctx;
1780 : 48 : MemoryContextSwitchTo(oldcontext);
1781 : : }
1782 : :
1783 : : /* stuff done on every call of the function */
1784 : 189 : funcctx = SRF_PERCALL_SETUP();
1785 : :
1786 : : /*
1787 : : * Get the saved state and use current state as the result of this
1788 : : * iteration.
1789 : : */
1790 : 189 : fctx = funcctx->user_fctx;
1791 : :
1792 [ + + + + ]: 366 : if ((fctx->step.sign == NUMERIC_POS &&
1793 : 177 : cmp_var(&fctx->current, &fctx->stop) <= 0) ||
1794 [ + + + + ]: 69 : (fctx->step.sign == NUMERIC_NEG &&
1795 : 12 : cmp_var(&fctx->current, &fctx->stop) >= 0))
1796 : : {
3340 tgl@sss.pgh.pa.us 1797 : 141 : Numeric result = make_result(&fctx->current);
1798 : :
1799 : : /* switch to memory context appropriate for iteration calculation */
3442 fujii@postgresql.org 1800 : 141 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1801 : :
1802 : : /* increment current in preparation for next iteration */
1803 : 141 : add_var(&fctx->current, &fctx->step, &fctx->current);
1804 : 141 : MemoryContextSwitchTo(oldcontext);
1805 : :
1806 : : /* do when there is more left to send */
1807 : 141 : SRF_RETURN_NEXT(funcctx, NumericGetDatum(result));
1808 : : }
1809 : : else
1810 : : /* do when there is no more left */
1811 : 48 : SRF_RETURN_DONE(funcctx);
1812 : : }
1813 : :
1814 : :
1815 : : /*
1816 : : * Implements the numeric version of the width_bucket() function
1817 : : * defined by SQL2003. See also width_bucket_float8().
1818 : : *
1819 : : * 'bound1' and 'bound2' are the lower and upper bounds of the
1820 : : * histogram's range, respectively. 'count' is the number of buckets
1821 : : * in the histogram. width_bucket() returns an integer indicating the
1822 : : * bucket number that 'operand' belongs to in an equiwidth histogram
1823 : : * with the specified characteristics. An operand smaller than the
1824 : : * lower bound is assigned to bucket 0. An operand greater than the
1825 : : * upper bound is assigned to an additional bucket (with number
1826 : : * count+1). We don't allow "NaN" for any of the numeric arguments.
1827 : : */
1828 : : Datum
7275 neilc@samurai.com 1829 : 390 : width_bucket_numeric(PG_FUNCTION_ARGS)
1830 : : {
1831 : 390 : Numeric operand = PG_GETARG_NUMERIC(0);
1832 : 390 : Numeric bound1 = PG_GETARG_NUMERIC(1);
1833 : 390 : Numeric bound2 = PG_GETARG_NUMERIC(2);
1834 : 390 : int32 count = PG_GETARG_INT32(3);
1835 : : NumericVar count_var;
1836 : : NumericVar result_var;
1837 : : int32 result;
1838 : :
1839 [ + + ]: 390 : if (count <= 0)
1840 [ + - ]: 6 : ereport(ERROR,
1841 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
1842 : : errmsg("count must be greater than zero")));
1843 : :
1362 tgl@sss.pgh.pa.us 1844 [ + + ]: 384 : if (NUMERIC_IS_SPECIAL(operand) ||
1845 [ + + ]: 375 : NUMERIC_IS_SPECIAL(bound1) ||
1846 [ + + ]: 372 : NUMERIC_IS_SPECIAL(bound2))
1847 : : {
1848 [ + + ]: 18 : if (NUMERIC_IS_NAN(operand) ||
1849 [ + - ]: 15 : NUMERIC_IS_NAN(bound1) ||
1850 [ - + ]: 15 : NUMERIC_IS_NAN(bound2))
1851 [ + - ]: 3 : ereport(ERROR,
1852 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
1853 : : errmsg("operand, lower bound, and upper bound cannot be NaN")));
1854 : : /* We allow "operand" to be infinite; cmp_numerics will cope */
1284 1855 [ + + + + ]: 15 : if (NUMERIC_IS_INF(bound1) || NUMERIC_IS_INF(bound2))
1362 1856 [ + - ]: 9 : ereport(ERROR,
1857 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
1858 : : errmsg("lower and upper bounds must be finite")));
1859 : : }
1860 : :
7275 neilc@samurai.com 1861 : 372 : init_var(&result_var);
1862 : 372 : init_var(&count_var);
1863 : :
1864 : : /* Convert 'count' to a numeric, for ease of use later */
3313 andres@anarazel.de 1865 : 372 : int64_to_numericvar((int64) count, &count_var);
1866 : :
7275 neilc@samurai.com 1867 [ + + + - ]: 372 : switch (cmp_numerics(bound1, bound2))
1868 : : {
1869 : 3 : case 0:
1870 [ + - ]: 3 : ereport(ERROR,
1871 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
1872 : : errmsg("lower bound cannot equal upper bound")));
1873 : : break;
1874 : :
1875 : : /* bound1 < bound2 */
1876 : 273 : case -1:
1877 [ + + ]: 273 : if (cmp_numerics(operand, bound1) < 0)
1878 : 57 : set_var_from_var(&const_zero, &result_var);
1879 [ + + ]: 216 : else if (cmp_numerics(operand, bound2) >= 0)
1880 : 54 : add_var(&count_var, &const_one, &result_var);
1881 : : else
1284 tgl@sss.pgh.pa.us 1882 : 162 : compute_bucket(operand, bound1, bound2, &count_var, false,
1883 : : &result_var);
7275 neilc@samurai.com 1884 : 273 : break;
1885 : :
1886 : : /* bound1 > bound2 */
1887 : 96 : case 1:
1888 [ + + ]: 96 : if (cmp_numerics(operand, bound1) > 0)
1889 : 6 : set_var_from_var(&const_zero, &result_var);
1890 [ + + ]: 90 : else if (cmp_numerics(operand, bound2) <= 0)
1891 : 12 : add_var(&count_var, &const_one, &result_var);
1892 : : else
1284 tgl@sss.pgh.pa.us 1893 : 78 : compute_bucket(operand, bound1, bound2, &count_var, true,
1894 : : &result_var);
7275 neilc@samurai.com 1895 : 96 : break;
1896 : : }
1897 : :
1898 : : /* if result exceeds the range of a legal int4, we ereport here */
1856 akorotkov@postgresql 1899 [ - + ]: 369 : if (!numericvar_to_int32(&result_var, &result))
1856 akorotkov@postgresql 1900 [ # # ]:UBC 0 : ereport(ERROR,
1901 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
1902 : : errmsg("integer out of range")));
1903 : :
7275 neilc@samurai.com 1904 :CBC 369 : free_var(&count_var);
1905 : 369 : free_var(&result_var);
1906 : :
1907 : 369 : PG_RETURN_INT32(result);
1908 : : }
1909 : :
1910 : : /*
1911 : : * 'operand' is inside the bucket range, so determine the correct
1912 : : * bucket for it to go. The calculations performed by this function
1913 : : * are derived directly from the SQL2003 spec. Note however that we
1914 : : * multiply by count before dividing, to avoid unnecessary roundoff error.
1915 : : */
1916 : : static void
1917 : 240 : compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
1918 : : const NumericVar *count_var, bool reversed_bounds,
1919 : : NumericVar *result_var)
1920 : : {
1921 : : NumericVar bound1_var;
1922 : : NumericVar bound2_var;
1923 : : NumericVar operand_var;
1924 : :
4162 heikki.linnakangas@i 1925 : 240 : init_var_from_num(bound1, &bound1_var);
1926 : 240 : init_var_from_num(bound2, &bound2_var);
1927 : 240 : init_var_from_num(operand, &operand_var);
1928 : :
1284 tgl@sss.pgh.pa.us 1929 [ + + ]: 240 : if (!reversed_bounds)
1930 : : {
7275 neilc@samurai.com 1931 : 162 : sub_var(&operand_var, &bound1_var, &operand_var);
1932 : 162 : sub_var(&bound2_var, &bound1_var, &bound2_var);
1933 : : }
1934 : : else
1935 : : {
1936 : 78 : sub_var(&bound1_var, &operand_var, &operand_var);
1284 tgl@sss.pgh.pa.us 1937 : 78 : sub_var(&bound1_var, &bound2_var, &bound2_var);
1938 : : }
1939 : :
1940 : 240 : mul_var(&operand_var, count_var, &operand_var,
1941 : 240 : operand_var.dscale + count_var->dscale);
1942 : 240 : div_var(&operand_var, &bound2_var, result_var,
1943 : : select_div_scale(&operand_var, &bound2_var), true);
1944 : :
1945 : : /*
1946 : : * Roundoff in the division could give us a quotient exactly equal to
1947 : : * "count", which is too large. Clamp so that we do not emit a result
1948 : : * larger than "count".
1949 : : */
380 1950 [ + + ]: 240 : if (cmp_var(result_var, count_var) >= 0)
1951 : 6 : set_var_from_var(count_var, result_var);
1952 : : else
1953 : : {
1954 : 234 : add_var(result_var, &const_one, result_var);
1955 : 234 : floor_var(result_var, result_var);
1956 : : }
1957 : :
7275 neilc@samurai.com 1958 : 240 : free_var(&bound1_var);
1959 : 240 : free_var(&bound2_var);
1960 : 240 : free_var(&operand_var);
7168 bruce@momjian.us 1961 : 240 : }
1962 : :
1963 : : /* ----------------------------------------------------------------------
1964 : : *
1965 : : * Comparison functions
1966 : : *
1967 : : * Note: btree indexes need these routines not to leak memory; therefore,
1968 : : * be careful to free working copies of toasted datums. Most places don't
1969 : : * need to be so careful.
1970 : : *
1971 : : * Sort support:
1972 : : *
1973 : : * We implement the sortsupport strategy routine in order to get the benefit of
1974 : : * abbreviation. The ordinary numeric comparison can be quite slow as a result
1975 : : * of palloc/pfree cycles (due to detoasting packed values for alignment);
1976 : : * while this could be worked on itself, the abbreviation strategy gives more
1977 : : * speedup in many common cases.
1978 : : *
1979 : : * Two different representations are used for the abbreviated form, one in
1980 : : * int32 and one in int64, whichever fits into a by-value Datum. In both cases
1981 : : * the representation is negated relative to the original value, because we use
1982 : : * the largest negative value for NaN, which sorts higher than other values. We
1983 : : * convert the absolute value of the numeric to a 31-bit or 63-bit positive
1984 : : * value, and then negate it if the original number was positive.
1985 : : *
1986 : : * We abort the abbreviation process if the abbreviation cardinality is below
1987 : : * 0.01% of the row count (1 per 10k non-null rows). The actual break-even
1988 : : * point is somewhat below that, perhaps 1 per 30k (at 1 per 100k there's a
1989 : : * very small penalty), but we don't want to build up too many abbreviated
1990 : : * values before first testing for abort, so we take the slightly pessimistic
1991 : : * number. We make no attempt to estimate the cardinality of the real values,
1992 : : * since it plays no part in the cost model here (if the abbreviation is equal,
1993 : : * the cost of comparing equal and unequal underlying values is comparable).
1994 : : * We discontinue even checking for abort (saving us the hashing overhead) if
1995 : : * the estimated cardinality gets to 100k; that would be enough to support many
1996 : : * billions of rows while doing no worse than breaking even.
1997 : : *
1998 : : * ----------------------------------------------------------------------
1999 : : */
2000 : :
2001 : : /*
2002 : : * Sort support strategy routine.
2003 : : */
2004 : : Datum
3300 rhaas@postgresql.org 2005 : 505 : numeric_sortsupport(PG_FUNCTION_ARGS)
2006 : : {
2007 : 505 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
2008 : :
2009 : 505 : ssup->comparator = numeric_fast_cmp;
2010 : :
2011 [ + + ]: 505 : if (ssup->abbreviate)
2012 : : {
2013 : : NumericSortSupport *nss;
2014 : 123 : MemoryContext oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
2015 : :
2016 : 123 : nss = palloc(sizeof(NumericSortSupport));
2017 : :
2018 : : /*
2019 : : * palloc a buffer for handling unaligned packed values in addition to
2020 : : * the support struct
2021 : : */
2022 : 123 : nss->buf = palloc(VARATT_SHORT_MAX + VARHDRSZ + 1);
2023 : :
2024 : 123 : nss->input_count = 0;
2025 : 123 : nss->estimating = true;
2026 : 123 : initHyperLogLog(&nss->abbr_card, 10);
2027 : :
2028 : 123 : ssup->ssup_extra = nss;
2029 : :
2030 : 123 : ssup->abbrev_full_comparator = ssup->comparator;
2031 : 123 : ssup->comparator = numeric_cmp_abbrev;
2032 : 123 : ssup->abbrev_converter = numeric_abbrev_convert;
2033 : 123 : ssup->abbrev_abort = numeric_abbrev_abort;
2034 : :
2035 : 123 : MemoryContextSwitchTo(oldcontext);
2036 : : }
2037 : :
2038 : 505 : PG_RETURN_VOID();
2039 : : }
2040 : :
2041 : : /*
2042 : : * Abbreviate a numeric datum, handling NaNs and detoasting
2043 : : * (must not leak memory!)
2044 : : */
2045 : : static Datum
2046 : 9566 : numeric_abbrev_convert(Datum original_datum, SortSupport ssup)
2047 : : {
2048 : 9566 : NumericSortSupport *nss = ssup->ssup_extra;
2049 : 9566 : void *original_varatt = PG_DETOAST_DATUM_PACKED(original_datum);
2050 : : Numeric value;
2051 : : Datum result;
2052 : :
2053 : 9566 : nss->input_count += 1;
2054 : :
2055 : : /*
2056 : : * This is to handle packed datums without needing a palloc/pfree cycle;
2057 : : * we keep and reuse a buffer large enough to handle any short datum.
2058 : : */
2059 [ + + ]: 9566 : if (VARATT_IS_SHORT(original_varatt))
2060 : : {
2061 : 513 : void *buf = nss->buf;
2062 : 513 : Size sz = VARSIZE_SHORT(original_varatt) - VARHDRSZ_SHORT;
2063 : :
2064 [ - + ]: 513 : Assert(sz <= VARATT_SHORT_MAX - VARHDRSZ_SHORT);
2065 : :
2066 : 513 : SET_VARSIZE(buf, VARHDRSZ + sz);
2067 : 513 : memcpy(VARDATA(buf), VARDATA_SHORT(original_varatt), sz);
2068 : :
2069 : 513 : value = (Numeric) buf;
2070 : : }
2071 : : else
2072 : 9053 : value = (Numeric) original_varatt;
2073 : :
1362 tgl@sss.pgh.pa.us 2074 [ + + ]: 9566 : if (NUMERIC_IS_SPECIAL(value))
2075 : : {
2076 [ + + ]: 75 : if (NUMERIC_IS_PINF(value))
2077 : 24 : result = NUMERIC_ABBREV_PINF;
2078 [ + + ]: 51 : else if (NUMERIC_IS_NINF(value))
2079 : 24 : result = NUMERIC_ABBREV_NINF;
2080 : : else
2081 : 27 : result = NUMERIC_ABBREV_NAN;
2082 : : }
2083 : : else
2084 : : {
2085 : : NumericVar var;
2086 : :
3300 rhaas@postgresql.org 2087 : 9491 : init_var_from_num(value, &var);
2088 : :
2089 : 9491 : result = numeric_abbrev_convert_var(&var, nss);
2090 : : }
2091 : :
2092 : : /* should happen only for external/compressed toasts */
2093 [ - + ]: 9566 : if ((Pointer) original_varatt != DatumGetPointer(original_datum))
3300 rhaas@postgresql.org 2094 :UBC 0 : pfree(original_varatt);
2095 : :
3300 rhaas@postgresql.org 2096 :CBC 9566 : return result;
2097 : : }
2098 : :
2099 : : /*
2100 : : * Consider whether to abort abbreviation.
2101 : : *
2102 : : * We pay no attention to the cardinality of the non-abbreviated data. There is
2103 : : * no reason to do so: unlike text, we have no fast check for equal values, so
2104 : : * we pay the full overhead whenever the abbreviations are equal regardless of
2105 : : * whether the underlying values are also equal.
2106 : : */
2107 : : static bool
2108 : 72 : numeric_abbrev_abort(int memtupcount, SortSupport ssup)
2109 : : {
2110 : 72 : NumericSortSupport *nss = ssup->ssup_extra;
2111 : : double abbr_card;
2112 : :
2113 [ - + - - : 72 : if (memtupcount < 10000 || nss->input_count < 10000 || !nss->estimating)
- - ]
2114 : 72 : return false;
2115 : :
3300 rhaas@postgresql.org 2116 :UBC 0 : abbr_card = estimateHyperLogLog(&nss->abbr_card);
2117 : :
2118 : : /*
2119 : : * If we have >100k distinct values, then even if we were sorting many
2120 : : * billion rows we'd likely still break even, and the penalty of undoing
2121 : : * that many rows of abbrevs would probably not be worth it. Stop even
2122 : : * counting at that point.
2123 : : */
2124 [ # # ]: 0 : if (abbr_card > 100000.0)
2125 : : {
2126 : : #ifdef TRACE_SORT
2127 [ # # ]: 0 : if (trace_sort)
2128 [ # # ]: 0 : elog(LOG,
2129 : : "numeric_abbrev: estimation ends at cardinality %f"
2130 : : " after " INT64_FORMAT " values (%d rows)",
2131 : : abbr_card, nss->input_count, memtupcount);
2132 : : #endif
2133 : 0 : nss->estimating = false;
2134 : 0 : return false;
2135 : : }
2136 : :
2137 : : /*
2138 : : * Target minimum cardinality is 1 per ~10k of non-null inputs. (The
2139 : : * break even point is somewhere between one per 100k rows, where
2140 : : * abbreviation has a very slight penalty, and 1 per 10k where it wins by
2141 : : * a measurable percentage.) We use the relatively pessimistic 10k
2142 : : * threshold, and add a 0.5 row fudge factor, because it allows us to
2143 : : * abort earlier on genuinely pathological data where we've had exactly
2144 : : * one abbreviated value in the first 10k (non-null) rows.
2145 : : */
2146 [ # # ]: 0 : if (abbr_card < nss->input_count / 10000.0 + 0.5)
2147 : : {
2148 : : #ifdef TRACE_SORT
2149 [ # # ]: 0 : if (trace_sort)
2150 [ # # ]: 0 : elog(LOG,
2151 : : "numeric_abbrev: aborting abbreviation at cardinality %f"
2152 : : " below threshold %f after " INT64_FORMAT " values (%d rows)",
2153 : : abbr_card, nss->input_count / 10000.0 + 0.5,
2154 : : nss->input_count, memtupcount);
2155 : : #endif
2156 : 0 : return true;
2157 : : }
2158 : :
2159 : : #ifdef TRACE_SORT
2160 [ # # ]: 0 : if (trace_sort)
2161 [ # # ]: 0 : elog(LOG,
2162 : : "numeric_abbrev: cardinality %f"
2163 : : " after " INT64_FORMAT " values (%d rows)",
2164 : : abbr_card, nss->input_count, memtupcount);
2165 : : #endif
2166 : :
2167 : 0 : return false;
2168 : : }
2169 : :
2170 : : /*
2171 : : * Non-fmgr interface to the comparison routine to allow sortsupport to elide
2172 : : * the fmgr call. The saving here is small given how slow numeric comparisons
2173 : : * are, but it is a required part of the sort support API when abbreviations
2174 : : * are performed.
2175 : : *
2176 : : * Two palloc/pfree cycles could be saved here by using persistent buffers for
2177 : : * aligning short-varlena inputs, but this has not so far been considered to
2178 : : * be worth the effort.
2179 : : */
2180 : : static int
3300 rhaas@postgresql.org 2181 :CBC 2356553 : numeric_fast_cmp(Datum x, Datum y, SortSupport ssup)
2182 : : {
2183 : 2356553 : Numeric nx = DatumGetNumeric(x);
2184 : 2356553 : Numeric ny = DatumGetNumeric(y);
2185 : : int result;
2186 : :
2187 : 2356553 : result = cmp_numerics(nx, ny);
2188 : :
2189 [ + + ]: 2356553 : if ((Pointer) nx != DatumGetPointer(x))
2190 : 86415 : pfree(nx);
2191 [ + + ]: 2356553 : if ((Pointer) ny != DatumGetPointer(y))
2192 : 86412 : pfree(ny);
2193 : :
2194 : 2356553 : return result;
2195 : : }
2196 : :
2197 : : /*
2198 : : * Compare abbreviations of values. (Abbreviations may be equal where the true
2199 : : * values differ, but if the abbreviations differ, they must reflect the
2200 : : * ordering of the true values.)
2201 : : */
2202 : : static int
2203 : 94507 : numeric_cmp_abbrev(Datum x, Datum y, SortSupport ssup)
2204 : : {
2205 : : /*
2206 : : * NOTE WELL: this is intentionally backwards, because the abbreviation is
2207 : : * negated relative to the original value, to handle NaN/infinity cases.
2208 : : */
2209 [ + + ]: 94507 : if (DatumGetNumericAbbrev(x) < DatumGetNumericAbbrev(y))
2210 : 49283 : return 1;
2211 [ + + ]: 45224 : if (DatumGetNumericAbbrev(x) > DatumGetNumericAbbrev(y))
2212 : 45114 : return -1;
2213 : 110 : return 0;
2214 : : }
2215 : :
2216 : : /*
2217 : : * Abbreviate a NumericVar according to the available bit size.
2218 : : *
2219 : : * The 31-bit value is constructed as:
2220 : : *
2221 : : * 0 + 7bits digit weight + 24 bits digit value
2222 : : *
2223 : : * where the digit weight is in single decimal digits, not digit words, and
2224 : : * stored in excess-44 representation[1]. The 24-bit digit value is the 7 most
2225 : : * significant decimal digits of the value converted to binary. Values whose
2226 : : * weights would fall outside the representable range are rounded off to zero
2227 : : * (which is also used to represent actual zeros) or to 0x7FFFFFFF (which
2228 : : * otherwise cannot occur). Abbreviation therefore fails to gain any advantage
2229 : : * where values are outside the range 10^-44 to 10^83, which is not considered
2230 : : * to be a serious limitation, or when values are of the same magnitude and
2231 : : * equal in the first 7 decimal digits, which is considered to be an
2232 : : * unavoidable limitation given the available bits. (Stealing three more bits
2233 : : * to compare another digit would narrow the range of representable weights by
2234 : : * a factor of 8, which starts to look like a real limiting factor.)
2235 : : *
2236 : : * (The value 44 for the excess is essentially arbitrary)
2237 : : *
2238 : : * The 63-bit value is constructed as:
2239 : : *
2240 : : * 0 + 7bits weight + 4 x 14-bit packed digit words
2241 : : *
2242 : : * The weight in this case is again stored in excess-44, but this time it is
2243 : : * the original weight in digit words (i.e. powers of 10000). The first four
2244 : : * digit words of the value (if present; trailing zeros are assumed as needed)
2245 : : * are packed into 14 bits each to form the rest of the value. Again,
2246 : : * out-of-range values are rounded off to 0 or 0x7FFFFFFFFFFFFFFF. The
2247 : : * representable range in this case is 10^-176 to 10^332, which is considered
2248 : : * to be good enough for all practical purposes, and comparison of 4 words
2249 : : * means that at least 13 decimal digits are compared, which is considered to
2250 : : * be a reasonable compromise between effectiveness and efficiency in computing
2251 : : * the abbreviation.
2252 : : *
2253 : : * (The value 44 for the excess is even more arbitrary here, it was chosen just
2254 : : * to match the value used in the 31-bit case)
2255 : : *
2256 : : * [1] - Excess-k representation means that the value is offset by adding 'k'
2257 : : * and then treated as unsigned, so the smallest representable value is stored
2258 : : * with all bits zero. This allows simple comparisons to work on the composite
2259 : : * value.
2260 : : */
2261 : :
2262 : : #if NUMERIC_ABBREV_BITS == 64
2263 : :
2264 : : static Datum
2408 andres@anarazel.de 2265 : 9491 : numeric_abbrev_convert_var(const NumericVar *var, NumericSortSupport *nss)
2266 : : {
3300 rhaas@postgresql.org 2267 : 9491 : int ndigits = var->ndigits;
2268 : 9491 : int weight = var->weight;
2269 : : int64 result;
2270 : :
2271 [ + + - + ]: 9491 : if (ndigits == 0 || weight < -44)
2272 : : {
2273 : 26 : result = 0;
2274 : : }
2275 [ + + ]: 9465 : else if (weight > 83)
2276 : : {
2277 : 6 : result = PG_INT64_MAX;
2278 : : }
2279 : : else
2280 : : {
2281 : 9459 : result = ((int64) (weight + 44) << 56);
2282 : :
2283 [ - + + + ]: 9459 : switch (ndigits)
2284 : : {
3300 rhaas@postgresql.org 2285 :UBC 0 : default:
2286 : 0 : result |= ((int64) var->digits[3]);
2287 : : /* FALLTHROUGH */
3300 rhaas@postgresql.org 2288 :CBC 3104 : case 3:
2289 : 3104 : result |= ((int64) var->digits[2]) << 14;
2290 : : /* FALLTHROUGH */
2291 : 9132 : case 2:
2292 : 9132 : result |= ((int64) var->digits[1]) << 28;
2293 : : /* FALLTHROUGH */
2294 : 9459 : case 1:
2295 : 9459 : result |= ((int64) var->digits[0]) << 42;
2296 : 9459 : break;
2297 : : }
2298 : : }
2299 : :
2300 : : /* the abbrev is negated relative to the original */
2301 [ + + ]: 9491 : if (var->sign == NUMERIC_POS)
2302 : 9442 : result = -result;
2303 : :
2304 [ + - ]: 9491 : if (nss->estimating)
2305 : : {
2306 : 9491 : uint32 tmp = ((uint32) result
2307 : 9491 : ^ (uint32) ((uint64) result >> 32));
2308 : :
2309 : 9491 : addHyperLogLog(&nss->abbr_card, DatumGetUInt32(hash_uint32(tmp)));
2310 : : }
2311 : :
3299 2312 : 9491 : return NumericAbbrevGetDatum(result);
2313 : : }
2314 : :
2315 : : #endif /* NUMERIC_ABBREV_BITS == 64 */
2316 : :
2317 : : #if NUMERIC_ABBREV_BITS == 32
2318 : :
2319 : : static Datum
2320 : : numeric_abbrev_convert_var(const NumericVar *var, NumericSortSupport *nss)
2321 : : {
2322 : : int ndigits = var->ndigits;
2323 : : int weight = var->weight;
2324 : : int32 result;
2325 : :
2326 : : if (ndigits == 0 || weight < -11)
2327 : : {
2328 : : result = 0;
2329 : : }
2330 : : else if (weight > 20)
2331 : : {
2332 : : result = PG_INT32_MAX;
2333 : : }
2334 : : else
2335 : : {
2336 : : NumericDigit nxt1 = (ndigits > 1) ? var->digits[1] : 0;
2337 : :
2338 : : weight = (weight + 11) * 4;
2339 : :
2340 : : result = var->digits[0];
2341 : :
2342 : : /*
2343 : : * "result" now has 1 to 4 nonzero decimal digits. We pack in more
2344 : : * digits to make 7 in total (largest we can fit in 24 bits)
2345 : : */
2346 : :
2347 : : if (result > 999)
2348 : : {
2349 : : /* already have 4 digits, add 3 more */
2350 : : result = (result * 1000) + (nxt1 / 10);
2351 : : weight += 3;
2352 : : }
2353 : : else if (result > 99)
2354 : : {
2355 : : /* already have 3 digits, add 4 more */
2356 : : result = (result * 10000) + nxt1;
2357 : : weight += 2;
2358 : : }
2359 : : else if (result > 9)
2360 : : {
2361 : : NumericDigit nxt2 = (ndigits > 2) ? var->digits[2] : 0;
2362 : :
2363 : : /* already have 2 digits, add 5 more */
2364 : : result = (result * 100000) + (nxt1 * 10) + (nxt2 / 1000);
2365 : : weight += 1;
2366 : : }
2367 : : else
2368 : : {
2369 : : NumericDigit nxt2 = (ndigits > 2) ? var->digits[2] : 0;
2370 : :
2371 : : /* already have 1 digit, add 6 more */
2372 : : result = (result * 1000000) + (nxt1 * 100) + (nxt2 / 100);
2373 : : }
2374 : :
2375 : : result = result | (weight << 24);
2376 : : }
2377 : :
2378 : : /* the abbrev is negated relative to the original */
2379 : : if (var->sign == NUMERIC_POS)
2380 : : result = -result;
2381 : :
2382 : : if (nss->estimating)
2383 : : {
2384 : : uint32 tmp = (uint32) result;
2385 : :
2386 : : addHyperLogLog(&nss->abbr_card, DatumGetUInt32(hash_uint32(tmp)));
2387 : : }
2388 : :
2389 : : return NumericAbbrevGetDatum(result);
2390 : : }
2391 : :
2392 : : #endif /* NUMERIC_ABBREV_BITS == 32 */
2393 : :
2394 : : /*
2395 : : * Ordinary (non-sortsupport) comparisons follow.
2396 : : */
2397 : :
2398 : : Datum
8660 tgl@sss.pgh.pa.us 2399 : 471315 : numeric_cmp(PG_FUNCTION_ARGS)
2400 : : {
2401 : 471315 : Numeric num1 = PG_GETARG_NUMERIC(0);
2402 : 471315 : Numeric num2 = PG_GETARG_NUMERIC(1);
2403 : : int result;
2404 : :
8382 2405 : 471315 : result = cmp_numerics(num1, num2);
2406 : :
8660 2407 [ + + ]: 471315 : PG_FREE_IF_COPY(num1, 0);
2408 [ + + ]: 471315 : PG_FREE_IF_COPY(num2, 1);
2409 : :
2410 : 471315 : PG_RETURN_INT32(result);
2411 : : }
2412 : :
2413 : :
2414 : : Datum
2415 : 328908 : numeric_eq(PG_FUNCTION_ARGS)
2416 : : {
2417 : 328908 : Numeric num1 = PG_GETARG_NUMERIC(0);
2418 : 328908 : Numeric num2 = PG_GETARG_NUMERIC(1);
2419 : : bool result;
2420 : :
8382 2421 : 328908 : result = cmp_numerics(num1, num2) == 0;
2422 : :
8660 2423 [ + + ]: 328908 : PG_FREE_IF_COPY(num1, 0);
2424 [ + + ]: 328908 : PG_FREE_IF_COPY(num2, 1);
2425 : :
2426 : 328908 : PG_RETURN_BOOL(result);
2427 : : }
2428 : :
2429 : : Datum
2430 : 2688 : numeric_ne(PG_FUNCTION_ARGS)
2431 : : {
2432 : 2688 : Numeric num1 = PG_GETARG_NUMERIC(0);
2433 : 2688 : Numeric num2 = PG_GETARG_NUMERIC(1);
2434 : : bool result;
2435 : :
8382 2436 : 2688 : result = cmp_numerics(num1, num2) != 0;
2437 : :
8660 2438 [ + + ]: 2688 : PG_FREE_IF_COPY(num1, 0);
2439 [ + + ]: 2688 : PG_FREE_IF_COPY(num2, 1);
2440 : :
2441 : 2688 : PG_RETURN_BOOL(result);
2442 : : }
2443 : :
2444 : : Datum
2445 : 30798 : numeric_gt(PG_FUNCTION_ARGS)
2446 : : {
2447 : 30798 : Numeric num1 = PG_GETARG_NUMERIC(0);
2448 : 30798 : Numeric num2 = PG_GETARG_NUMERIC(1);
2449 : : bool result;
2450 : :
8382 2451 : 30798 : result = cmp_numerics(num1, num2) > 0;
2452 : :
8660 2453 [ + + ]: 30798 : PG_FREE_IF_COPY(num1, 0);
2454 [ + + ]: 30798 : PG_FREE_IF_COPY(num2, 1);
2455 : :
2456 : 30798 : PG_RETURN_BOOL(result);
2457 : : }
2458 : :
2459 : : Datum
2460 : 8391 : numeric_ge(PG_FUNCTION_ARGS)
2461 : : {
2462 : 8391 : Numeric num1 = PG_GETARG_NUMERIC(0);
2463 : 8391 : Numeric num2 = PG_GETARG_NUMERIC(1);
2464 : : bool result;
2465 : :
8382 2466 : 8391 : result = cmp_numerics(num1, num2) >= 0;
2467 : :
8660 2468 [ + + ]: 8391 : PG_FREE_IF_COPY(num1, 0);
2469 [ - + ]: 8391 : PG_FREE_IF_COPY(num2, 1);
2470 : :
2471 : 8391 : PG_RETURN_BOOL(result);
2472 : : }
2473 : :
2474 : : Datum
2475 : 65098 : numeric_lt(PG_FUNCTION_ARGS)
2476 : : {
2477 : 65098 : Numeric num1 = PG_GETARG_NUMERIC(0);
2478 : 65098 : Numeric num2 = PG_GETARG_NUMERIC(1);
2479 : : bool result;
2480 : :
8382 2481 : 65098 : result = cmp_numerics(num1, num2) < 0;
2482 : :
8660 2483 [ + + ]: 65098 : PG_FREE_IF_COPY(num1, 0);
2484 [ + + ]: 65098 : PG_FREE_IF_COPY(num2, 1);
2485 : :
2486 : 65098 : PG_RETURN_BOOL(result);
2487 : : }
2488 : :
2489 : : Datum
2490 : 8156 : numeric_le(PG_FUNCTION_ARGS)
2491 : : {
2492 : 8156 : Numeric num1 = PG_GETARG_NUMERIC(0);
2493 : 8156 : Numeric num2 = PG_GETARG_NUMERIC(1);
2494 : : bool result;
2495 : :
8382 2496 : 8156 : result = cmp_numerics(num1, num2) <= 0;
2497 : :
2498 [ + + ]: 8156 : PG_FREE_IF_COPY(num1, 0);
2499 [ + + ]: 8156 : PG_FREE_IF_COPY(num2, 1);
2500 : :
2501 : 8156 : PG_RETURN_BOOL(result);
2502 : : }
2503 : :
2504 : : static int
2505 : 3282668 : cmp_numerics(Numeric num1, Numeric num2)
2506 : : {
2507 : : int result;
2508 : :
2509 : : /*
2510 : : * We consider all NANs to be equal and larger than any non-NAN (including
2511 : : * Infinity). This is somewhat arbitrary; the important thing is to have
2512 : : * a consistent sort order.
2513 : : */
1362 2514 [ + + ]: 3282668 : if (NUMERIC_IS_SPECIAL(num1))
2515 : : {
2516 [ + + ]: 4375 : if (NUMERIC_IS_NAN(num1))
2517 : : {
2518 [ + + ]: 4330 : if (NUMERIC_IS_NAN(num2))
2519 : 714 : result = 0; /* NAN = NAN */
2520 : : else
2521 : 3616 : result = 1; /* NAN > non-NAN */
2522 : : }
2523 [ + + ]: 45 : else if (NUMERIC_IS_PINF(num1))
2524 : : {
2525 [ - + ]: 36 : if (NUMERIC_IS_NAN(num2))
1362 tgl@sss.pgh.pa.us 2526 :UBC 0 : result = -1; /* PINF < NAN */
1362 tgl@sss.pgh.pa.us 2527 [ + + ]:CBC 36 : else if (NUMERIC_IS_PINF(num2))
2528 : 3 : result = 0; /* PINF = PINF */
2529 : : else
2530 : 33 : result = 1; /* PINF > anything else */
2531 : : }
2532 : : else /* num1 must be NINF */
2533 : : {
2534 [ + + ]: 9 : if (NUMERIC_IS_NINF(num2))
2535 : 3 : result = 0; /* NINF = NINF */
2536 : : else
2537 : 6 : result = -1; /* NINF < anything else */
2538 : : }
2539 : : }
2540 [ + + ]: 3278293 : else if (NUMERIC_IS_SPECIAL(num2))
2541 : : {
2542 [ + + ]: 5662 : if (NUMERIC_IS_NINF(num2))
2543 : 6 : result = 1; /* normal > NINF */
2544 : : else
2545 : 5656 : result = -1; /* normal < NAN or PINF */
2546 : : }
2547 : : else
2548 : : {
6641 bruce@momjian.us 2549 [ + + + + ]: 6545833 : result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1),
5003 rhaas@postgresql.org 2550 [ + + - + : 3272776 : NUMERIC_WEIGHT(num1), NUMERIC_SIGN(num1),
+ + + + ]
6641 bruce@momjian.us 2551 [ + + + + ]: 3272631 : NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2),
5003 rhaas@postgresql.org 2552 [ + + - + : 3273057 : NUMERIC_WEIGHT(num2), NUMERIC_SIGN(num2));
+ + + + ]
2553 : : }
2554 : :
8382 tgl@sss.pgh.pa.us 2555 : 3282668 : return result;
2556 : : }
2557 : :
2558 : : /*
2559 : : * in_range support function for numeric.
2560 : : */
2561 : : Datum
2241 2562 : 576 : in_range_numeric_numeric(PG_FUNCTION_ARGS)
2563 : : {
2564 : 576 : Numeric val = PG_GETARG_NUMERIC(0);
2565 : 576 : Numeric base = PG_GETARG_NUMERIC(1);
2566 : 576 : Numeric offset = PG_GETARG_NUMERIC(2);
2567 : 576 : bool sub = PG_GETARG_BOOL(3);
2568 : 576 : bool less = PG_GETARG_BOOL(4);
2569 : : bool result;
2570 : :
2571 : : /*
2572 : : * Reject negative (including -Inf) or NaN offset. Negative is per spec,
2573 : : * and NaN is because appropriate semantics for that seem non-obvious.
2574 : : */
1362 2575 [ + + ]: 576 : if (NUMERIC_IS_NAN(offset) ||
2576 [ + - ]: 573 : NUMERIC_IS_NINF(offset) ||
2577 [ + + - + : 573 : NUMERIC_SIGN(offset) == NUMERIC_NEG)
+ - - + -
- ]
2241 2578 [ + - ]: 3 : ereport(ERROR,
2579 : : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2580 : : errmsg("invalid preceding or following size in window function")));
2581 : :
2582 : : /*
2583 : : * Deal with cases where val and/or base is NaN, following the rule that
2584 : : * NaN sorts after non-NaN (cf cmp_numerics). The offset cannot affect
2585 : : * the conclusion.
2586 : : */
2587 [ + + ]: 573 : if (NUMERIC_IS_NAN(val))
2588 : : {
2589 [ + + ]: 93 : if (NUMERIC_IS_NAN(base))
2590 : 30 : result = true; /* NAN = NAN */
2591 : : else
2592 : 63 : result = !less; /* NAN > non-NAN */
2593 : : }
2594 [ + + ]: 480 : else if (NUMERIC_IS_NAN(base))
2595 : : {
2596 : 63 : result = less; /* non-NAN < NAN */
2597 : : }
2598 : :
2599 : : /*
2600 : : * Deal with infinite offset (necessarily +Inf, at this point).
2601 : : */
1362 2602 [ + + ]: 417 : else if (NUMERIC_IS_SPECIAL(offset))
2603 : : {
2604 [ - + ]: 210 : Assert(NUMERIC_IS_PINF(offset));
2605 [ + + + + ]: 210 : if (sub ? NUMERIC_IS_PINF(base) : NUMERIC_IS_NINF(base))
2606 : : {
2607 : : /*
2608 : : * base +/- offset would produce NaN, so return true for any val
2609 : : * (see in_range_float8_float8() for reasoning).
2610 : : */
2611 : 87 : result = true;
2612 : : }
2613 [ + + ]: 123 : else if (sub)
2614 : : {
2615 : : /* base - offset must be -inf */
2616 [ + + ]: 75 : if (less)
2617 : 27 : result = NUMERIC_IS_NINF(val); /* only -inf is <= sum */
2618 : : else
2619 : 48 : result = true; /* any val is >= sum */
2620 : : }
2621 : : else
2622 : : {
2623 : : /* base + offset must be +inf */
2624 [ - + ]: 48 : if (less)
1362 tgl@sss.pgh.pa.us 2625 :UBC 0 : result = true; /* any val is <= sum */
2626 : : else
1362 tgl@sss.pgh.pa.us 2627 :CBC 48 : result = NUMERIC_IS_PINF(val); /* only +inf is >= sum */
2628 : : }
2629 : : }
2630 : :
2631 : : /*
2632 : : * Deal with cases where val and/or base is infinite. The offset, being
2633 : : * now known finite, cannot affect the conclusion.
2634 : : */
2635 [ + + ]: 207 : else if (NUMERIC_IS_SPECIAL(val))
2636 : : {
2637 [ + + ]: 39 : if (NUMERIC_IS_PINF(val))
2638 : : {
2639 [ + + ]: 18 : if (NUMERIC_IS_PINF(base))
2640 : 12 : result = true; /* PINF = PINF */
2641 : : else
2642 : 6 : result = !less; /* PINF > any other non-NAN */
2643 : : }
2644 : : else /* val must be NINF */
2645 : : {
2646 [ + + ]: 21 : if (NUMERIC_IS_NINF(base))
2647 : 15 : result = true; /* NINF = NINF */
2648 : : else
2649 : 6 : result = less; /* NINF < anything else */
2650 : : }
2651 : : }
2652 [ + + ]: 168 : else if (NUMERIC_IS_SPECIAL(base))
2653 : : {
2654 [ + + ]: 12 : if (NUMERIC_IS_NINF(base))
2655 : 6 : result = !less; /* normal > NINF */
2656 : : else
2657 : 6 : result = less; /* normal < PINF */
2658 : : }
2659 : : else
2660 : : {
2661 : : /*
2662 : : * Otherwise go ahead and compute base +/- offset. While it's
2663 : : * possible for this to overflow the numeric format, it's unlikely
2664 : : * enough that we don't take measures to prevent it.
2665 : : */
2666 : : NumericVar valv;
2667 : : NumericVar basev;
2668 : : NumericVar offsetv;
2669 : : NumericVar sum;
2670 : :
2241 2671 : 156 : init_var_from_num(val, &valv);
2672 : 156 : init_var_from_num(base, &basev);
2673 : 156 : init_var_from_num(offset, &offsetv);
2674 : 156 : init_var(&sum);
2675 : :
2676 [ + + ]: 156 : if (sub)
2677 : 78 : sub_var(&basev, &offsetv, &sum);
2678 : : else
2679 : 78 : add_var(&basev, &offsetv, &sum);
2680 : :
2681 [ + + ]: 156 : if (less)
2682 : 78 : result = (cmp_var(&valv, &sum) <= 0);
2683 : : else
2684 : 78 : result = (cmp_var(&valv, &sum) >= 0);
2685 : :
2686 : 156 : free_var(&sum);
2687 : : }
2688 : :
2689 [ + - ]: 573 : PG_FREE_IF_COPY(val, 0);
2690 [ + - ]: 573 : PG_FREE_IF_COPY(base, 1);
2691 [ - + ]: 573 : PG_FREE_IF_COPY(offset, 2);
2692 : :
2693 : 573 : PG_RETURN_BOOL(result);
2694 : : }
2695 : :
2696 : : Datum
6186 neilc@samurai.com 2697 : 303741 : hash_numeric(PG_FUNCTION_ARGS)
2698 : : {
5995 bruce@momjian.us 2699 : 303741 : Numeric key = PG_GETARG_NUMERIC(0);
2700 : : Datum digit_hash;
2701 : : Datum result;
2702 : : int weight;
2703 : : int start_offset;
2704 : : int end_offset;
2705 : : int i;
2706 : : int hash_len;
2707 : : NumericDigit *digits;
2708 : :
2709 : : /* If it's NaN or infinity, don't try to hash the rest of the fields */
1362 tgl@sss.pgh.pa.us 2710 [ - + ]: 303741 : if (NUMERIC_IS_SPECIAL(key))
6186 neilc@samurai.com 2711 :UBC 0 : PG_RETURN_UINT32(0);
2712 : :
5003 rhaas@postgresql.org 2713 [ + - + + ]:CBC 303741 : weight = NUMERIC_WEIGHT(key);
6186 neilc@samurai.com 2714 : 303741 : start_offset = 0;
5995 bruce@momjian.us 2715 : 303741 : end_offset = 0;
2716 : :
2717 : : /*
2718 : : * Omit any leading or trailing zeros from the input to the hash. The
2719 : : * numeric implementation *should* guarantee that leading and trailing
2720 : : * zeros are suppressed, but we're paranoid. Note that we measure the
2721 : : * starting and ending offsets in units of NumericDigits, not bytes.
2722 : : */
5003 rhaas@postgresql.org 2723 [ + - ]: 303741 : digits = NUMERIC_DIGITS(key);
6186 neilc@samurai.com 2724 [ + - + + ]: 303741 : for (i = 0; i < NUMERIC_NDIGITS(key); i++)
2725 : : {
5003 rhaas@postgresql.org 2726 [ + - ]: 302933 : if (digits[i] != (NumericDigit) 0)
6186 neilc@samurai.com 2727 : 302933 : break;
2728 : :
6186 neilc@samurai.com 2729 :UBC 0 : start_offset++;
2730 : :
2731 : : /*
2732 : : * The weight is effectively the # of digits before the decimal point,
2733 : : * so decrement it for each leading zero we skip.
2734 : : */
2735 : 0 : weight--;
2736 : : }
2737 : :
2738 : : /*
2739 : : * If there are no non-zero digits, then the value of the number is zero,
2740 : : * regardless of any other fields.
2741 : : */
6186 neilc@samurai.com 2742 [ + - + + ]:CBC 303741 : if (NUMERIC_NDIGITS(key) == start_offset)
2743 : 808 : PG_RETURN_UINT32(-1);
2744 : :
2745 [ + - + - ]: 302933 : for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)
2746 : : {
5003 rhaas@postgresql.org 2747 [ + - ]: 302933 : if (digits[i] != (NumericDigit) 0)
6186 neilc@samurai.com 2748 : 302933 : break;
2749 : :
6186 neilc@samurai.com 2750 :UBC 0 : end_offset++;
2751 : : }
2752 : :
2753 : : /* If we get here, there should be at least one non-zero digit */
6186 neilc@samurai.com 2754 [ + - - + ]:CBC 302933 : Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));
2755 : :
2756 : : /*
2757 : : * Note that we don't hash on the Numeric's scale, since two numerics can
2758 : : * compare equal but have different scales. We also don't hash on the
2759 : : * sign, although we could: since a sign difference implies inequality,
2760 : : * this shouldn't affect correctness.
2761 : : */
2762 [ + - ]: 302933 : hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;
2763 [ + - ]: 302933 : digit_hash = hash_any((unsigned char *) (NUMERIC_DIGITS(key) + start_offset),
2764 : : hash_len * sizeof(NumericDigit));
2765 : :
2766 : : /* Mix in the weight, via XOR */
2767 : 302933 : result = digit_hash ^ weight;
2768 : :
2769 : 302933 : PG_RETURN_DATUM(result);
2770 : : }
2771 : :
2772 : : /*
2773 : : * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
2774 : : * Otherwise, similar to hash_numeric.
2775 : : */
2776 : : Datum
2418 rhaas@postgresql.org 2777 : 42 : hash_numeric_extended(PG_FUNCTION_ARGS)
2778 : : {
2779 : 42 : Numeric key = PG_GETARG_NUMERIC(0);
2780 : 42 : uint64 seed = PG_GETARG_INT64(1);
2781 : : Datum digit_hash;
2782 : : Datum result;
2783 : : int weight;
2784 : : int start_offset;
2785 : : int end_offset;
2786 : : int i;
2787 : : int hash_len;
2788 : : NumericDigit *digits;
2789 : :
2790 : : /* If it's NaN or infinity, don't try to hash the rest of the fields */
1362 tgl@sss.pgh.pa.us 2791 [ - + ]: 42 : if (NUMERIC_IS_SPECIAL(key))
2418 rhaas@postgresql.org 2792 :UBC 0 : PG_RETURN_UINT64(seed);
2793 : :
2418 rhaas@postgresql.org 2794 [ + - - + ]:CBC 42 : weight = NUMERIC_WEIGHT(key);
2795 : 42 : start_offset = 0;
2796 : 42 : end_offset = 0;
2797 : :
2798 [ + - ]: 42 : digits = NUMERIC_DIGITS(key);
2799 [ + - + + ]: 42 : for (i = 0; i < NUMERIC_NDIGITS(key); i++)
2800 : : {
2801 [ + - ]: 36 : if (digits[i] != (NumericDigit) 0)
2802 : 36 : break;
2803 : :
2418 rhaas@postgresql.org 2804 :UBC 0 : start_offset++;
2805 : :
2806 : 0 : weight--;
2807 : : }
2808 : :
2418 rhaas@postgresql.org 2809 [ + - + + ]:CBC 42 : if (NUMERIC_NDIGITS(key) == start_offset)
2810 : 6 : PG_RETURN_UINT64(seed - 1);
2811 : :
2812 [ + - + - ]: 36 : for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)
2813 : : {
2814 [ + - ]: 36 : if (digits[i] != (NumericDigit) 0)
2815 : 36 : break;
2816 : :
2418 rhaas@postgresql.org 2817 :UBC 0 : end_offset++;
2818 : : }
2819 : :
2418 rhaas@postgresql.org 2820 [ + - - + ]:CBC 36 : Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));
2821 : :
2822 [ + - ]: 36 : hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;
2823 [ + - ]: 36 : digit_hash = hash_any_extended((unsigned char *) (NUMERIC_DIGITS(key)
2824 : 36 : + start_offset),
2825 : : hash_len * sizeof(NumericDigit),
2826 : : seed);
2827 : :
2417 2828 : 36 : result = UInt64GetDatum(DatumGetUInt64(digit_hash) ^ weight);
2829 : :
2418 2830 : 36 : PG_RETURN_DATUM(result);
2831 : : }
2832 : :
2833 : :
2834 : : /* ----------------------------------------------------------------------
2835 : : *
2836 : : * Basic arithmetic functions
2837 : : *
2838 : : * ----------------------------------------------------------------------
2839 : : */
2840 : :
2841 : :
2842 : : /*
2843 : : * numeric_add() -
2844 : : *
2845 : : * Add two numerics
2846 : : */
2847 : : Datum
8660 tgl@sss.pgh.pa.us 2848 : 126026 : numeric_add(PG_FUNCTION_ARGS)
2849 : : {
2850 : 126026 : Numeric num1 = PG_GETARG_NUMERIC(0);
2851 : 126026 : Numeric num2 = PG_GETARG_NUMERIC(1);
2852 : : Numeric res;
2853 : :
1856 akorotkov@postgresql 2854 : 126026 : res = numeric_add_opt_error(num1, num2, NULL);
2855 : :
2856 : 126026 : PG_RETURN_NUMERIC(res);
2857 : : }
2858 : :
2859 : : /*
2860 : : * numeric_add_opt_error() -
2861 : : *
2862 : : * Internal version of numeric_add(). If "*have_error" flag is provided,
2863 : : * on error it's set to true, NULL returned. This is helpful when caller
2864 : : * need to handle errors by itself.
2865 : : */
2866 : : Numeric
2867 : 126545 : numeric_add_opt_error(Numeric num1, Numeric num2, bool *have_error)
2868 : : {
2869 : : NumericVar arg1;
2870 : : NumericVar arg2;
2871 : : NumericVar result;
2872 : : Numeric res;
2873 : :
2874 : : /*
2875 : : * Handle NaN and infinities
2876 : : */
1362 tgl@sss.pgh.pa.us 2877 [ + + + + ]: 126545 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
2878 : : {
2879 [ + + + + ]: 99 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
2880 : 39 : return make_result(&const_nan);
2881 [ + + ]: 60 : if (NUMERIC_IS_PINF(num1))
2882 : : {
2883 [ + + ]: 18 : if (NUMERIC_IS_NINF(num2))
2884 : 3 : return make_result(&const_nan); /* Inf + -Inf */
2885 : : else
2886 : 15 : return make_result(&const_pinf);
2887 : : }
2888 [ + + ]: 42 : if (NUMERIC_IS_NINF(num1))
2889 : : {
2890 [ + + ]: 18 : if (NUMERIC_IS_PINF(num2))
2891 : 3 : return make_result(&const_nan); /* -Inf + Inf */
2892 : : else
2893 : 15 : return make_result(&const_ninf);
2894 : : }
2895 : : /* by here, num1 must be finite, so num2 is not */
2896 [ + + ]: 24 : if (NUMERIC_IS_PINF(num2))
2897 : 12 : return make_result(&const_pinf);
2898 [ - + ]: 12 : Assert(NUMERIC_IS_NINF(num2));
2899 : 12 : return make_result(&const_ninf);
2900 : : }
2901 : :
2902 : : /*
2903 : : * Unpack the values, let add_var() compute the result and return it.
2904 : : */
4162 heikki.linnakangas@i 2905 : 126446 : init_var_from_num(num1, &arg1);
2906 : 126446 : init_var_from_num(num2, &arg2);
2907 : :
2908 : 126446 : init_var(&result);
9237 JanWieck@Yahoo.com 2909 : 126446 : add_var(&arg1, &arg2, &result);
2910 : :
1856 akorotkov@postgresql 2911 : 126446 : res = make_result_opt_error(&result, have_error);
2912 : :
9237 JanWieck@Yahoo.com 2913 : 126446 : free_var(&result);
2914 : :
1856 akorotkov@postgresql 2915 : 126446 : return res;
2916 : : }
2917 : :
2918 : :
2919 : : /*
2920 : : * numeric_sub() -
2921 : : *
2922 : : * Subtract one numeric from another
2923 : : */
2924 : : Datum
8660 tgl@sss.pgh.pa.us 2925 : 46324 : numeric_sub(PG_FUNCTION_ARGS)
2926 : : {
2927 : 46324 : Numeric num1 = PG_GETARG_NUMERIC(0);
2928 : 46324 : Numeric num2 = PG_GETARG_NUMERIC(1);
2929 : : Numeric res;
2930 : :
1856 akorotkov@postgresql 2931 : 46324 : res = numeric_sub_opt_error(num1, num2, NULL);
2932 : :
2933 : 46324 : PG_RETURN_NUMERIC(res);
2934 : : }
2935 : :
2936 : :
2937 : : /*
2938 : : * numeric_sub_opt_error() -
2939 : : *
2940 : : * Internal version of numeric_sub(). If "*have_error" flag is provided,
2941 : : * on error it's set to true, NULL returned. This is helpful when caller
2942 : : * need to handle errors by itself.
2943 : : */
2944 : : Numeric
2945 : 46399 : numeric_sub_opt_error(Numeric num1, Numeric num2, bool *have_error)
2946 : : {
2947 : : NumericVar arg1;
2948 : : NumericVar arg2;
2949 : : NumericVar result;
2950 : : Numeric res;
2951 : :
2952 : : /*
2953 : : * Handle NaN and infinities
2954 : : */
1362 tgl@sss.pgh.pa.us 2955 [ + + + + ]: 46399 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
2956 : : {
2957 [ + + + + ]: 1073 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
2958 : 1013 : return make_result(&const_nan);
2959 [ + + ]: 60 : if (NUMERIC_IS_PINF(num1))
2960 : : {
2961 [ + + ]: 18 : if (NUMERIC_IS_PINF(num2))
2962 : 3 : return make_result(&const_nan); /* Inf - Inf */
2963 : : else
2964 : 15 : return make_result(&const_pinf);
2965 : : }
2966 [ + + ]: 42 : if (NUMERIC_IS_NINF(num1))
2967 : : {
2968 [ + + ]: 18 : if (NUMERIC_IS_NINF(num2))
2969 : 3 : return make_result(&const_nan); /* -Inf - -Inf */
2970 : : else
2971 : 15 : return make_result(&const_ninf);
2972 : : }
2973 : : /* by here, num1 must be finite, so num2 is not */
2974 [ + + ]: 24 : if (NUMERIC_IS_PINF(num2))
2975 : 12 : return make_result(&const_ninf);
2976 [ - + ]: 12 : Assert(NUMERIC_IS_NINF(num2));
2977 : 12 : return make_result(&const_pinf);
2978 : : }
2979 : :
2980 : : /*
2981 : : * Unpack the values, let sub_var() compute the result and return it.
2982 : : */
4162 heikki.linnakangas@i 2983 : 45326 : init_var_from_num(num1, &arg1);
2984 : 45326 : init_var_from_num(num2, &arg2);
2985 : :
2986 : 45326 : init_var(&result);
9237 JanWieck@Yahoo.com 2987 : 45326 : sub_var(&arg1, &arg2, &result);
2988 : :
1856 akorotkov@postgresql 2989 : 45326 : res = make_result_opt_error(&result, have_error);
2990 : :
9237 JanWieck@Yahoo.com 2991 : 45326 : free_var(&result);
2992 : :
1856 akorotkov@postgresql 2993 : 45326 : return res;
2994 : : }
2995 : :
2996 : :
2997 : : /*
2998 : : * numeric_mul() -
2999 : : *
3000 : : * Calculate the product of two numerics
3001 : : */
3002 : : Datum
8660 tgl@sss.pgh.pa.us 3003 : 244839 : numeric_mul(PG_FUNCTION_ARGS)
3004 : : {
3005 : 244839 : Numeric num1 = PG_GETARG_NUMERIC(0);
3006 : 244839 : Numeric num2 = PG_GETARG_NUMERIC(1);
3007 : : Numeric res;
3008 : :
1856 akorotkov@postgresql 3009 : 244839 : res = numeric_mul_opt_error(num1, num2, NULL);
3010 : :
3011 : 244839 : PG_RETURN_NUMERIC(res);
3012 : : }
3013 : :
3014 : :
3015 : : /*
3016 : : * numeric_mul_opt_error() -
3017 : : *
3018 : : * Internal version of numeric_mul(). If "*have_error" flag is provided,
3019 : : * on error it's set to true, NULL returned. This is helpful when caller
3020 : : * need to handle errors by itself.
3021 : : */
3022 : : Numeric
3023 : 244857 : numeric_mul_opt_error(Numeric num1, Numeric num2, bool *have_error)
3024 : : {
3025 : : NumericVar arg1;
3026 : : NumericVar arg2;
3027 : : NumericVar result;
3028 : : Numeric res;
3029 : :
3030 : : /*
3031 : : * Handle NaN and infinities
3032 : : */
1362 tgl@sss.pgh.pa.us 3033 [ + + + + ]: 244857 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3034 : : {
3035 [ + + + + ]: 99 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
3036 : 39 : return make_result(&const_nan);
3037 [ + + ]: 60 : if (NUMERIC_IS_PINF(num1))
3038 : : {
3039 [ + + + - ]: 18 : switch (numeric_sign_internal(num2))
3040 : : {
3041 : 3 : case 0:
3042 : 3 : return make_result(&const_nan); /* Inf * 0 */
3043 : 9 : case 1:
3044 : 9 : return make_result(&const_pinf);
3045 : 6 : case -1:
3046 : 6 : return make_result(&const_ninf);
3047 : : }
1362 tgl@sss.pgh.pa.us 3048 :UBC 0 : Assert(false);
3049 : : }
1362 tgl@sss.pgh.pa.us 3050 [ + + ]:CBC 42 : if (NUMERIC_IS_NINF(num1))
3051 : : {
3052 [ + + + - ]: 18 : switch (numeric_sign_internal(num2))
3053 : : {
3054 : 3 : case 0:
3055 : 3 : return make_result(&const_nan); /* -Inf * 0 */
3056 : 9 : case 1:
3057 : 9 : return make_result(&const_ninf);
3058 : 6 : case -1:
3059 : 6 : return make_result(&const_pinf);
3060 : : }
1362 tgl@sss.pgh.pa.us 3061 :UBC 0 : Assert(false);
3062 : : }
3063 : : /* by here, num1 must be finite, so num2 is not */
1362 tgl@sss.pgh.pa.us 3064 [ + + ]:CBC 24 : if (NUMERIC_IS_PINF(num2))
3065 : : {
3066 [ + + + - ]: 12 : switch (numeric_sign_internal(num1))
3067 : : {
3068 : 3 : case 0:
3069 : 3 : return make_result(&const_nan); /* 0 * Inf */
3070 : 6 : case 1:
3071 : 6 : return make_result(&const_pinf);
3072 : 3 : case -1:
3073 : 3 : return make_result(&const_ninf);
3074 : : }
1362 tgl@sss.pgh.pa.us 3075 :UBC 0 : Assert(false);
3076 : : }
1362 tgl@sss.pgh.pa.us 3077 [ - + ]:CBC 12 : Assert(NUMERIC_IS_NINF(num2));
3078 [ + + + - ]: 12 : switch (numeric_sign_internal(num1))
3079 : : {
3080 : 3 : case 0:
3081 : 3 : return make_result(&const_nan); /* 0 * -Inf */
3082 : 6 : case 1:
3083 : 6 : return make_result(&const_ninf);
3084 : 3 : case -1:
3085 : 3 : return make_result(&const_pinf);
3086 : : }
1362 tgl@sss.pgh.pa.us 3087 :UBC 0 : Assert(false);
3088 : : }
3089 : :
3090 : : /*
3091 : : * Unpack the values, let mul_var() compute the result and return it.
3092 : : * Unlike add_var() and sub_var(), mul_var() will round its result. In the
3093 : : * case of numeric_mul(), which is invoked for the * operator on numerics,
3094 : : * we request exact representation for the product (rscale = sum(dscale of
3095 : : * arg1, dscale of arg2)). If the exact result has more digits after the
3096 : : * decimal point than can be stored in a numeric, we round it. Rounding
3097 : : * after computing the exact result ensures that the final result is
3098 : : * correctly rounded (rounding in mul_var() using a truncated product
3099 : : * would not guarantee this).
3100 : : */
4162 heikki.linnakangas@i 3101 :CBC 244758 : init_var_from_num(num1, &arg1);
3102 : 244758 : init_var_from_num(num2, &arg2);
3103 : :
3104 : 244758 : init_var(&result);
7695 tgl@sss.pgh.pa.us 3105 : 244758 : mul_var(&arg1, &arg2, &result, arg1.dscale + arg2.dscale);
3106 : :
1009 dean.a.rasheed@gmail 3107 [ + + ]: 244758 : if (result.dscale > NUMERIC_DSCALE_MAX)
3108 : 3 : round_var(&result, NUMERIC_DSCALE_MAX);
3109 : :
1856 akorotkov@postgresql 3110 : 244758 : res = make_result_opt_error(&result, have_error);
3111 : :
9237 JanWieck@Yahoo.com 3112 : 244758 : free_var(&result);
3113 : :
1856 akorotkov@postgresql 3114 : 244758 : return res;
3115 : : }
3116 : :
3117 : :
3118 : : /*
3119 : : * numeric_div() -
3120 : : *
3121 : : * Divide one numeric into another
3122 : : */
3123 : : Datum
8660 tgl@sss.pgh.pa.us 3124 : 75711 : numeric_div(PG_FUNCTION_ARGS)
3125 : : {
3126 : 75711 : Numeric num1 = PG_GETARG_NUMERIC(0);
3127 : 75711 : Numeric num2 = PG_GETARG_NUMERIC(1);
3128 : : Numeric res;
3129 : :
1856 akorotkov@postgresql 3130 : 75711 : res = numeric_div_opt_error(num1, num2, NULL);
3131 : :
3132 : 75695 : PG_RETURN_NUMERIC(res);
3133 : : }
3134 : :
3135 : :
3136 : : /*
3137 : : * numeric_div_opt_error() -
3138 : : *
3139 : : * Internal version of numeric_div(). If "*have_error" flag is provided,
3140 : : * on error it's set to true, NULL returned. This is helpful when caller
3141 : : * need to handle errors by itself.
3142 : : */
3143 : : Numeric
3144 : 76131 : numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
3145 : : {
3146 : : NumericVar arg1;
3147 : : NumericVar arg2;
3148 : : NumericVar result;
3149 : : Numeric res;
3150 : : int rscale;
3151 : :
1714 michael@paquier.xyz 3152 [ + + ]: 76131 : if (have_error)
3153 : 24 : *have_error = false;
3154 : :
3155 : : /*
3156 : : * Handle NaN and infinities
3157 : : */
1362 tgl@sss.pgh.pa.us 3158 [ + + + + ]: 76131 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3159 : : {
3160 [ + + + + ]: 99 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
3161 : 39 : return make_result(&const_nan);
3162 [ + + ]: 60 : if (NUMERIC_IS_PINF(num1))
3163 : : {
3164 [ + + ]: 18 : if (NUMERIC_IS_SPECIAL(num2))
3165 : 6 : return make_result(&const_nan); /* Inf / [-]Inf */
3166 [ + + + - ]: 12 : switch (numeric_sign_internal(num2))
3167 : : {
3168 : 3 : case 0:
3169 [ - + ]: 3 : if (have_error)
3170 : : {
1362 tgl@sss.pgh.pa.us 3171 :UBC 0 : *have_error = true;
3172 : 0 : return NULL;
3173 : : }
1362 tgl@sss.pgh.pa.us 3174 [ + - ]:CBC 3 : ereport(ERROR,
3175 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
3176 : : errmsg("division by zero")));
3177 : : break;
3178 : 6 : case 1:
3179 : 6 : return make_result(&const_pinf);
3180 : 3 : case -1:
3181 : 3 : return make_result(&const_ninf);
3182 : : }
1362 tgl@sss.pgh.pa.us 3183 :UBC 0 : Assert(false);
3184 : : }
1362 tgl@sss.pgh.pa.us 3185 [ + + ]:CBC 42 : if (NUMERIC_IS_NINF(num1))
3186 : : {
3187 [ + + ]: 18 : if (NUMERIC_IS_SPECIAL(num2))
3188 : 6 : return make_result(&const_nan); /* -Inf / [-]Inf */
3189 [ + + + - ]: 12 : switch (numeric_sign_internal(num2))
3190 : : {
3191 : 3 : case 0:
3192 [ - + ]: 3 : if (have_error)
3193 : : {
1362 tgl@sss.pgh.pa.us 3194 :UBC 0 : *have_error = true;
3195 : 0 : return NULL;
3196 : : }
1362 tgl@sss.pgh.pa.us 3197 [ + - ]:CBC 3 : ereport(ERROR,
3198 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
3199 : : errmsg("division by zero")));
3200 : : break;
3201 : 6 : case 1:
3202 : 6 : return make_result(&const_ninf);
3203 : 3 : case -1:
3204 : 3 : return make_result(&const_pinf);
3205 : : }
1362 tgl@sss.pgh.pa.us 3206 :UBC 0 : Assert(false);
3207 : : }
3208 : : /* by here, num1 must be finite, so num2 is not */
3209 : :
3210 : : /*
3211 : : * POSIX would have us return zero or minus zero if num1 is zero, and
3212 : : * otherwise throw an underflow error. But the numeric type doesn't
3213 : : * really do underflow, so let's just return zero.
3214 : : */
1362 tgl@sss.pgh.pa.us 3215 :CBC 24 : return make_result(&const_zero);
3216 : : }
3217 : :
3218 : : /*
3219 : : * Unpack the arguments
3220 : : */
4162 heikki.linnakangas@i 3221 : 76032 : init_var_from_num(num1, &arg1);
3222 : 76032 : init_var_from_num(num2, &arg2);
3223 : :
3224 : 76032 : init_var(&result);
3225 : :
3226 : : /*
3227 : : * Select scale for division result
3228 : : */
7695 tgl@sss.pgh.pa.us 3229 : 76032 : rscale = select_div_scale(&arg1, &arg2);
3230 : :
3231 : : /*
3232 : : * If "have_error" is provided, check for division by zero here
3233 : : */
1856 akorotkov@postgresql 3234 [ + + + + : 76032 : if (have_error && (arg2.ndigits == 0 || arg2.digits[0] == 0))
- + ]
3235 : : {
3236 : 6 : *have_error = true;
3237 : 6 : return NULL;
3238 : : }
3239 : :
3240 : : /*
3241 : : * Do the divide and return the result
3242 : : */
6889 bruce@momjian.us 3243 : 76026 : div_var(&arg1, &arg2, &result, rscale, true);
3244 : :
1856 akorotkov@postgresql 3245 : 76007 : res = make_result_opt_error(&result, have_error);
3246 : :
9237 JanWieck@Yahoo.com 3247 : 76007 : free_var(&result);
3248 : :
1856 akorotkov@postgresql 3249 : 76007 : return res;
3250 : : }
3251 : :
3252 : :
3253 : : /*
3254 : : * numeric_div_trunc() -
3255 : : *
3256 : : * Divide one numeric into another, truncating the result to an integer
3257 : : */
3258 : : Datum
5854 tgl@sss.pgh.pa.us 3259 : 600 : numeric_div_trunc(PG_FUNCTION_ARGS)
3260 : : {
3261 : 600 : Numeric num1 = PG_GETARG_NUMERIC(0);
3262 : 600 : Numeric num2 = PG_GETARG_NUMERIC(1);
3263 : : NumericVar arg1;
3264 : : NumericVar arg2;
3265 : : NumericVar result;
3266 : : Numeric res;
3267 : :
3268 : : /*
3269 : : * Handle NaN and infinities
3270 : : */
1362 3271 [ + + + + ]: 600 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3272 : : {
3273 [ + + + + ]: 99 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
3274 : 39 : PG_RETURN_NUMERIC(make_result(&const_nan));
3275 [ + + ]: 60 : if (NUMERIC_IS_PINF(num1))
3276 : : {
3277 [ + + ]: 18 : if (NUMERIC_IS_SPECIAL(num2))
3278 : 6 : PG_RETURN_NUMERIC(make_result(&const_nan)); /* Inf / [-]Inf */
3279 [ + + + - ]: 12 : switch (numeric_sign_internal(num2))
3280 : : {
3281 : 3 : case 0:
3282 [ + - ]: 3 : ereport(ERROR,
3283 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
3284 : : errmsg("division by zero")));
3285 : : break;
3286 : 6 : case 1:
3287 : 6 : PG_RETURN_NUMERIC(make_result(&const_pinf));
3288 : 3 : case -1:
3289 : 3 : PG_RETURN_NUMERIC(make_result(&const_ninf));
3290 : : }
1362 tgl@sss.pgh.pa.us 3291 :UBC 0 : Assert(false);
3292 : : }
1362 tgl@sss.pgh.pa.us 3293 [ + + ]:CBC 42 : if (NUMERIC_IS_NINF(num1))
3294 : : {
3295 [ + + ]: 18 : if (NUMERIC_IS_SPECIAL(num2))
3296 : 6 : PG_RETURN_NUMERIC(make_result(&const_nan)); /* -Inf / [-]Inf */
3297 [ + + + - ]: 12 : switch (numeric_sign_internal(num2))
3298 : : {
3299 : 3 : case 0:
3300 [ + - ]: 3 : ereport(ERROR,
3301 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
3302 : : errmsg("division by zero")));
3303 : : break;
3304 : 6 : case 1:
3305 : 6 : PG_RETURN_NUMERIC(make_result(&const_ninf));
3306 : 3 : case -1:
3307 : 3 : PG_RETURN_NUMERIC(make_result(&const_pinf));
3308 : : }
1362 tgl@sss.pgh.pa.us 3309 :UBC 0 : Assert(false);
3310 : : }
3311 : : /* by here, num1 must be finite, so num2 is not */
3312 : :
3313 : : /*
3314 : : * POSIX would have us return zero or minus zero if num1 is zero, and
3315 : : * otherwise throw an underflow error. But the numeric type doesn't
3316 : : * really do underflow, so let's just return zero.
3317 : : */
1362 tgl@sss.pgh.pa.us 3318 :CBC 24 : PG_RETURN_NUMERIC(make_result(&const_zero));
3319 : : }
3320 : :
3321 : : /*
3322 : : * Unpack the arguments
3323 : : */
4162 heikki.linnakangas@i 3324 : 501 : init_var_from_num(num1, &arg1);
3325 : 501 : init_var_from_num(num2, &arg2);
3326 : :
3327 : 501 : init_var(&result);
3328 : :
3329 : : /*
3330 : : * Do the divide and return the result
3331 : : */
5854 tgl@sss.pgh.pa.us 3332 : 501 : div_var(&arg1, &arg2, &result, 0, false);
3333 : :
3334 : 498 : res = make_result(&result);
3335 : :
3336 : 498 : free_var(&result);
3337 : :
3338 : 498 : PG_RETURN_NUMERIC(res);
3339 : : }
3340 : :
3341 : :
3342 : : /*
3343 : : * numeric_mod() -
3344 : : *
3345 : : * Calculate the modulo of two numerics
3346 : : */
3347 : : Datum
8660 3348 : 27064 : numeric_mod(PG_FUNCTION_ARGS)
3349 : : {
3350 : 27064 : Numeric num1 = PG_GETARG_NUMERIC(0);
3351 : 27064 : Numeric num2 = PG_GETARG_NUMERIC(1);
3352 : : Numeric res;
3353 : :
1856 akorotkov@postgresql 3354 : 27064 : res = numeric_mod_opt_error(num1, num2, NULL);
3355 : :
3356 : 27055 : PG_RETURN_NUMERIC(res);
3357 : : }
3358 : :
3359 : :
3360 : : /*
3361 : : * numeric_mod_opt_error() -
3362 : : *
3363 : : * Internal version of numeric_mod(). If "*have_error" flag is provided,
3364 : : * on error it's set to true, NULL returned. This is helpful when caller
3365 : : * need to handle errors by itself.
3366 : : */
3367 : : Numeric
3368 : 27070 : numeric_mod_opt_error(Numeric num1, Numeric num2, bool *have_error)
3369 : : {
3370 : : Numeric res;
3371 : : NumericVar arg1;
3372 : : NumericVar arg2;
3373 : : NumericVar result;
3374 : :
1714 michael@paquier.xyz 3375 [ - + ]: 27070 : if (have_error)
1714 michael@paquier.xyz 3376 :UBC 0 : *have_error = false;
3377 : :
3378 : : /*
3379 : : * Handle NaN and infinities. We follow POSIX fmod() on this, except that
3380 : : * POSIX treats x-is-infinite and y-is-zero identically, raising EDOM and
3381 : : * returning NaN. We choose to throw error only for y-is-zero.
3382 : : */
1362 tgl@sss.pgh.pa.us 3383 [ + + + + ]:CBC 27070 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3384 : : {
3385 [ + + + + ]: 99 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
3386 : 39 : return make_result(&const_nan);
3387 [ + + ]: 60 : if (NUMERIC_IS_INF(num1))
3388 : : {
3389 [ + + ]: 36 : if (numeric_sign_internal(num2) == 0)
3390 : : {
3391 [ - + ]: 6 : if (have_error)
3392 : : {
1362 tgl@sss.pgh.pa.us 3393 :UBC 0 : *have_error = true;
3394 : 0 : return NULL;
3395 : : }
1362 tgl@sss.pgh.pa.us 3396 [ + - ]:CBC 6 : ereport(ERROR,
3397 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
3398 : : errmsg("division by zero")));
3399 : : }
3400 : : /* Inf % any nonzero = NaN */
3401 : 30 : return make_result(&const_nan);
3402 : : }
3403 : : /* num2 must be [-]Inf; result is num1 regardless of sign of num2 */
3404 : 24 : return duplicate_numeric(num1);
3405 : : }
3406 : :
4162 heikki.linnakangas@i 3407 : 26971 : init_var_from_num(num1, &arg1);
3408 : 26971 : init_var_from_num(num2, &arg2);
3409 : :
3410 : 26971 : init_var(&result);
3411 : :
3412 : : /*
3413 : : * If "have_error" is provided, check for division by zero here
3414 : : */
1856 akorotkov@postgresql 3415 [ - + - - : 26971 : if (have_error && (arg2.ndigits == 0 || arg2.digits[0] == 0))
- - ]
3416 : : {
1856 akorotkov@postgresql 3417 :UBC 0 : *have_error = true;
3418 : 0 : return NULL;
3419 : : }
3420 : :
9237 JanWieck@Yahoo.com 3421 :CBC 26971 : mod_var(&arg1, &arg2, &result);
3422 : :
1856 akorotkov@postgresql 3423 : 26965 : res = make_result_opt_error(&result, NULL);
3424 : :
9237 JanWieck@Yahoo.com 3425 : 26965 : free_var(&result);
3426 : :
1856 akorotkov@postgresql 3427 : 26965 : return res;
3428 : : }
3429 : :
3430 : :
3431 : : /*
3432 : : * numeric_inc() -
3433 : : *
3434 : : * Increment a number by one
3435 : : */
3436 : : Datum
8660 tgl@sss.pgh.pa.us 3437 : 24 : numeric_inc(PG_FUNCTION_ARGS)
3438 : : {
3439 : 24 : Numeric num = PG_GETARG_NUMERIC(0);
3440 : : NumericVar arg;
3441 : : Numeric res;
3442 : :
3443 : : /*
3444 : : * Handle NaN and infinities
3445 : : */
1362 3446 [ + + ]: 24 : if (NUMERIC_IS_SPECIAL(num))
3447 : 9 : PG_RETURN_NUMERIC(duplicate_numeric(num));
3448 : :
3449 : : /*
3450 : : * Compute the result and return it
3451 : : */
4162 heikki.linnakangas@i 3452 : 15 : init_var_from_num(num, &arg);
3453 : :
9237 JanWieck@Yahoo.com 3454 : 15 : add_var(&arg, &const_one, &arg);
3455 : :
3456 : 15 : res = make_result(&arg);
3457 : :
3458 : 15 : free_var(&arg);
3459 : :
8660 tgl@sss.pgh.pa.us 3460 : 15 : PG_RETURN_NUMERIC(res);
3461 : : }
3462 : :
3463 : :
3464 : : /*
3465 : : * numeric_smaller() -
3466 : : *
3467 : : * Return the smaller of two numbers
3468 : : */
3469 : : Datum
3470 : 399 : numeric_smaller(PG_FUNCTION_ARGS)
3471 : : {
3472 : 399 : Numeric num1 = PG_GETARG_NUMERIC(0);
3473 : 399 : Numeric num2 = PG_GETARG_NUMERIC(1);
3474 : :
3475 : : /*
3476 : : * Use cmp_numerics so that this will agree with the comparison operators,
3477 : : * particularly as regards comparisons involving NaN.
3478 : : */
7564 3479 [ + + ]: 399 : if (cmp_numerics(num1, num2) < 0)
3480 : 321 : PG_RETURN_NUMERIC(num1);
3481 : : else
3482 : 78 : PG_RETURN_NUMERIC(num2);
3483 : : }
3484 : :
3485 : :
3486 : : /*
3487 : : * numeric_larger() -
3488 : : *
3489 : : * Return the larger of two numbers
3490 : : */
3491 : : Datum
8660 3492 : 9315 : numeric_larger(PG_FUNCTION_ARGS)
3493 : : {
3494 : 9315 : Numeric num1 = PG_GETARG_NUMERIC(0);
3495 : 9315 : Numeric num2 = PG_GETARG_NUMERIC(1);
3496 : :
3497 : : /*
3498 : : * Use cmp_numerics so that this will agree with the comparison operators,
3499 : : * particularly as regards comparisons involving NaN.
3500 : : */
7564 3501 [ + + ]: 9315 : if (cmp_numerics(num1, num2) > 0)
3502 : 8954 : PG_RETURN_NUMERIC(num1);
3503 : : else
3504 : 361 : PG_RETURN_NUMERIC(num2);
3505 : : }
3506 : :
3507 : :
3508 : : /* ----------------------------------------------------------------------
3509 : : *
3510 : : * Advanced math functions
3511 : : *
3512 : : * ----------------------------------------------------------------------
3513 : : */
3514 : :
3515 : : /*
3516 : : * numeric_gcd() -
3517 : : *
3518 : : * Calculate the greatest common divisor of two numerics
3519 : : */
3520 : : Datum
1541 dean.a.rasheed@gmail 3521 : 108 : numeric_gcd(PG_FUNCTION_ARGS)
3522 : : {
3523 : 108 : Numeric num1 = PG_GETARG_NUMERIC(0);
3524 : 108 : Numeric num2 = PG_GETARG_NUMERIC(1);
3525 : : NumericVar arg1;
3526 : : NumericVar arg2;
3527 : : NumericVar result;
3528 : : Numeric res;
3529 : :
3530 : : /*
3531 : : * Handle NaN and infinities: we consider the result to be NaN in all such
3532 : : * cases.
3533 : : */
1362 tgl@sss.pgh.pa.us 3534 [ + + + + ]: 108 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
1541 dean.a.rasheed@gmail 3535 : 48 : PG_RETURN_NUMERIC(make_result(&const_nan));
3536 : :
3537 : : /*
3538 : : * Unpack the arguments
3539 : : */
3540 : 60 : init_var_from_num(num1, &arg1);
3541 : 60 : init_var_from_num(num2, &arg2);
3542 : :
3543 : 60 : init_var(&result);
3544 : :
3545 : : /*
3546 : : * Find the GCD and return the result
3547 : : */
3548 : 60 : gcd_var(&arg1, &arg2, &result);
3549 : :
3550 : 60 : res = make_result(&result);
3551 : :
3552 : 60 : free_var(&result);
3553 : :
3554 : 60 : PG_RETURN_NUMERIC(res);
3555 : : }
3556 : :
3557 : :
3558 : : /*
3559 : : * numeric_lcm() -
3560 : : *
3561 : : * Calculate the least common multiple of two numerics
3562 : : */
3563 : : Datum
3564 : 123 : numeric_lcm(PG_FUNCTION_ARGS)
3565 : : {
3566 : 123 : Numeric num1 = PG_GETARG_NUMERIC(0);
3567 : 123 : Numeric num2 = PG_GETARG_NUMERIC(1);
3568 : : NumericVar arg1;
3569 : : NumericVar arg2;
3570 : : NumericVar result;
3571 : : Numeric res;
3572 : :
3573 : : /*
3574 : : * Handle NaN and infinities: we consider the result to be NaN in all such
3575 : : * cases.
3576 : : */
1362 tgl@sss.pgh.pa.us 3577 [ + + + + ]: 123 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
1541 dean.a.rasheed@gmail 3578 : 48 : PG_RETURN_NUMERIC(make_result(&const_nan));
3579 : :
3580 : : /*
3581 : : * Unpack the arguments
3582 : : */
3583 : 75 : init_var_from_num(num1, &arg1);
3584 : 75 : init_var_from_num(num2, &arg2);
3585 : :
3586 : 75 : init_var(&result);
3587 : :
3588 : : /*
3589 : : * Compute the result using lcm(x, y) = abs(x / gcd(x, y) * y), returning
3590 : : * zero if either input is zero.
3591 : : *
3592 : : * Note that the division is guaranteed to be exact, returning an integer
3593 : : * result, so the LCM is an integral multiple of both x and y. A display
3594 : : * scale of Min(x.dscale, y.dscale) would be sufficient to represent it,
3595 : : * but as with other numeric functions, we choose to return a result whose
3596 : : * display scale is no smaller than either input.
3597 : : */
3598 [ + + + + ]: 75 : if (arg1.ndigits == 0 || arg2.ndigits == 0)
3599 : 24 : set_var_from_var(&const_zero, &result);
3600 : : else
3601 : : {
3602 : 51 : gcd_var(&arg1, &arg2, &result);
3603 : 51 : div_var(&arg1, &result, &result, 0, false);
3604 : 51 : mul_var(&arg2, &result, &result, arg2.dscale);
3605 : 51 : result.sign = NUMERIC_POS;
3606 : : }
3607 : :
3608 : 75 : result.dscale = Max(arg1.dscale, arg2.dscale);
3609 : :
3610 : 75 : res = make_result(&result);
3611 : :
3612 : 72 : free_var(&result);
3613 : :
3614 : 72 : PG_RETURN_NUMERIC(res);
3615 : : }
3616 : :
3617 : :
3618 : : /*
3619 : : * numeric_fac()
3620 : : *
3621 : : * Compute factorial
3622 : : */
3623 : : Datum
7440 bruce@momjian.us 3624 : 21 : numeric_fac(PG_FUNCTION_ARGS)
3625 : : {
3626 : 21 : int64 num = PG_GETARG_INT64(0);
3627 : : Numeric res;
3628 : : NumericVar fact;
3629 : : NumericVar result;
3630 : :
1396 peter@eisentraut.org 3631 [ + + ]: 21 : if (num < 0)
3632 [ + - ]: 3 : ereport(ERROR,
3633 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
3634 : : errmsg("factorial of a negative number is undefined")));
7439 tgl@sss.pgh.pa.us 3635 [ + + ]: 18 : if (num <= 1)
3636 : : {
7440 bruce@momjian.us 3637 : 3 : res = make_result(&const_one);
3638 : 3 : PG_RETURN_NUMERIC(res);
3639 : : }
3640 : : /* Fail immediately if the result would overflow */
6154 tgl@sss.pgh.pa.us 3641 [ + + ]: 15 : if (num > 32177)
3642 [ + - ]: 3 : ereport(ERROR,
3643 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
3644 : : errmsg("value overflows numeric format")));
3645 : :
7440 bruce@momjian.us 3646 : 12 : init_var(&fact);
3647 : 12 : init_var(&result);
3648 : :
3313 andres@anarazel.de 3649 : 12 : int64_to_numericvar(num, &result);
3650 : :
7439 tgl@sss.pgh.pa.us 3651 [ + + ]: 147 : for (num = num - 1; num > 1; num--)
3652 : : {
3653 : : /* this loop can take awhile, so allow it to be interrupted */
6154 3654 [ - + ]: 135 : CHECK_FOR_INTERRUPTS();
3655 : :
3313 andres@anarazel.de 3656 : 135 : int64_to_numericvar(num, &fact);
3657 : :
7439 tgl@sss.pgh.pa.us 3658 : 135 : mul_var(&result, &fact, &result, 0);
3659 : : }
3660 : :
3661 : 12 : res = make_result(&result);
3662 : :
7440 bruce@momjian.us 3663 : 12 : free_var(&fact);
3664 : 12 : free_var(&result);
3665 : :
3666 : 12 : PG_RETURN_NUMERIC(res);
3667 : : }
3668 : :
3669 : :
3670 : : /*
3671 : : * numeric_sqrt() -
3672 : : *
3673 : : * Compute the square root of a numeric.
3674 : : */
3675 : : Datum
8660 tgl@sss.pgh.pa.us 3676 : 75 : numeric_sqrt(PG_FUNCTION_ARGS)
3677 : : {
3678 : 75 : Numeric num = PG_GETARG_NUMERIC(0);
3679 : : Numeric res;
3680 : : NumericVar arg;
3681 : : NumericVar result;
3682 : : int sweight;
3683 : : int rscale;
3684 : :
3685 : : /*
3686 : : * Handle NaN and infinities
3687 : : */
1362 3688 [ + + ]: 75 : if (NUMERIC_IS_SPECIAL(num))
3689 : : {
3690 : : /* error should match that in sqrt_var() */
3691 [ + + ]: 9 : if (NUMERIC_IS_NINF(num))
3692 [ + - ]: 3 : ereport(ERROR,
3693 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
3694 : : errmsg("cannot take square root of a negative number")));
3695 : : /* For NAN or PINF, just duplicate the input */
3696 : 6 : PG_RETURN_NUMERIC(duplicate_numeric(num));
3697 : : }
3698 : :
3699 : : /*
3700 : : * Unpack the argument and determine the result scale. We choose a scale
3701 : : * to give at least NUMERIC_MIN_SIG_DIGITS significant digits; but in any
3702 : : * case not less than the input's dscale.
3703 : : */
4162 heikki.linnakangas@i 3704 : 66 : init_var_from_num(num, &arg);
3705 : :
3706 : 66 : init_var(&result);
3707 : :
3708 : : /*
3709 : : * Assume the input was normalized, so arg.weight is accurate. The result
3710 : : * then has at least sweight = floor(arg.weight * DEC_DIGITS / 2 + 1)
3711 : : * digits before the decimal point. When DEC_DIGITS is even, we can save
3712 : : * a few cycles, since the division is exact and there is no need to round
3713 : : * towards negative infinity.
3714 : : */
3715 : : #if DEC_DIGITS == ((DEC_DIGITS / 2) * 2)
437 dean.a.rasheed@gmail 3716 : 66 : sweight = arg.weight * DEC_DIGITS / 2 + 1;
3717 : : #else
3718 : : if (arg.weight >= 0)
3719 : : sweight = arg.weight * DEC_DIGITS / 2 + 1;
3720 : : else
3721 : : sweight = 1 - (1 - arg.weight * DEC_DIGITS) / 2;
3722 : : #endif
3723 : :
7695 tgl@sss.pgh.pa.us 3724 : 66 : rscale = NUMERIC_MIN_SIG_DIGITS - sweight;
3725 : 66 : rscale = Max(rscale, arg.dscale);
3726 : 66 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
3727 : 66 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
3728 : :
3729 : : /*
3730 : : * Let sqrt_var() do the calculation and return the result.
3731 : : */
3732 : 66 : sqrt_var(&arg, &result, rscale);
3733 : :
9237 JanWieck@Yahoo.com 3734 : 63 : res = make_result(&result);
3735 : :
3736 : 63 : free_var(&result);
3737 : :
8660 tgl@sss.pgh.pa.us 3738 : 63 : PG_RETURN_NUMERIC(res);
3739 : : }
3740 : :
3741 : :
3742 : : /*
3743 : : * numeric_exp() -
3744 : : *
3745 : : * Raise e to the power of x
3746 : : */
3747 : : Datum
3748 : 39 : numeric_exp(PG_FUNCTION_ARGS)
3749 : : {
3750 : 39 : Numeric num = PG_GETARG_NUMERIC(0);
3751 : : Numeric res;
3752 : : NumericVar arg;
3753 : : NumericVar result;
3754 : : int rscale;
3755 : : double val;
3756 : :
3757 : : /*
3758 : : * Handle NaN and infinities
3759 : : */
1362 3760 [ + + ]: 39 : if (NUMERIC_IS_SPECIAL(num))
3761 : : {
3762 : : /* Per POSIX, exp(-Inf) is zero */
3763 [ + + ]: 9 : if (NUMERIC_IS_NINF(num))
3764 : 3 : PG_RETURN_NUMERIC(make_result(&const_zero));
3765 : : /* For NAN or PINF, just duplicate the input */
3766 : 6 : PG_RETURN_NUMERIC(duplicate_numeric(num));
3767 : : }
3768 : :
3769 : : /*
3770 : : * Unpack the argument and determine the result scale. We choose a scale
3771 : : * to give at least NUMERIC_MIN_SIG_DIGITS significant digits; but in any
3772 : : * case not less than the input's dscale.
3773 : : */
4162 heikki.linnakangas@i 3774 : 30 : init_var_from_num(num, &arg);
3775 : :
3776 : 30 : init_var(&result);
3777 : :
3778 : : /* convert input to float8, ignoring overflow */
7695 tgl@sss.pgh.pa.us 3779 : 30 : val = numericvar_to_double_no_overflow(&arg);
3780 : :
3781 : : /*
3782 : : * log10(result) = num * log10(e), so this is approximately the decimal
3783 : : * weight of the result:
3784 : : */
7865 3785 : 30 : val *= 0.434294481903252;
3786 : :
3787 : : /* limit to something that won't cause integer overflow */
3788 [ + + ]: 30 : val = Max(val, -NUMERIC_MAX_RESULT_SCALE);
3789 [ + - ]: 30 : val = Min(val, NUMERIC_MAX_RESULT_SCALE);
3790 : :
7695 3791 : 30 : rscale = NUMERIC_MIN_SIG_DIGITS - (int) val;
3792 : 30 : rscale = Max(rscale, arg.dscale);
3793 : 30 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
3794 : 30 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
3795 : :
3796 : : /*
3797 : : * Let exp_var() do the calculation and return the result.
3798 : : */
3799 : 30 : exp_var(&arg, &result, rscale);
3800 : :
9237 JanWieck@Yahoo.com 3801 : 30 : res = make_result(&result);
3802 : :
3803 : 30 : free_var(&result);
3804 : :
8660 tgl@sss.pgh.pa.us 3805 : 30 : PG_RETURN_NUMERIC(res);
3806 : : }
3807 : :
3808 : :
3809 : : /*
3810 : : * numeric_ln() -
3811 : : *
3812 : : * Compute the natural logarithm of x
3813 : : */
3814 : : Datum
3815 : 99 : numeric_ln(PG_FUNCTION_ARGS)
3816 : : {
3817 : 99 : Numeric num = PG_GETARG_NUMERIC(0);
3818 : : Numeric res;
3819 : : NumericVar arg;
3820 : : NumericVar result;
3821 : : int ln_dweight;
3822 : : int rscale;
3823 : :
3824 : : /*
3825 : : * Handle NaN and infinities
3826 : : */
1362 3827 [ + + ]: 99 : if (NUMERIC_IS_SPECIAL(num))
3828 : : {
3829 [ + + ]: 9 : if (NUMERIC_IS_NINF(num))
3830 [ + - ]: 3 : ereport(ERROR,
3831 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
3832 : : errmsg("cannot take logarithm of a negative number")));
3833 : : /* For NAN or PINF, just duplicate the input */
3834 : 6 : PG_RETURN_NUMERIC(duplicate_numeric(num));
3835 : : }
3836 : :
4162 heikki.linnakangas@i 3837 : 90 : init_var_from_num(num, &arg);
9237 JanWieck@Yahoo.com 3838 : 90 : init_var(&result);
3839 : :
3840 : : /* Estimated dweight of logarithm */
3074 tgl@sss.pgh.pa.us 3841 : 90 : ln_dweight = estimate_ln_dweight(&arg);
3842 : :
3843 : 90 : rscale = NUMERIC_MIN_SIG_DIGITS - ln_dweight;
7695 3844 : 90 : rscale = Max(rscale, arg.dscale);
3845 : 90 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
3846 : 90 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
3847 : :
3848 : 90 : ln_var(&arg, &result, rscale);
3849 : :
9237 JanWieck@Yahoo.com 3850 : 78 : res = make_result(&result);
3851 : :
3852 : 78 : free_var(&result);
3853 : :
8660 tgl@sss.pgh.pa.us 3854 : 78 : PG_RETURN_NUMERIC(res);
3855 : : }
3856 : :
3857 : :
3858 : : /*
3859 : : * numeric_log() -
3860 : : *
3861 : : * Compute the logarithm of x in a given base
3862 : : */
3863 : : Datum
3864 : 171 : numeric_log(PG_FUNCTION_ARGS)
3865 : : {
3866 : 171 : Numeric num1 = PG_GETARG_NUMERIC(0);
3867 : 171 : Numeric num2 = PG_GETARG_NUMERIC(1);
3868 : : Numeric res;
3869 : : NumericVar arg1;
3870 : : NumericVar arg2;
3871 : : NumericVar result;
3872 : :
3873 : : /*
3874 : : * Handle NaN and infinities
3875 : : */
1362 3876 [ + + + + ]: 171 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3877 : : {
3878 : : int sign1,
3879 : : sign2;
3880 : :
3881 [ + + + + ]: 63 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
3882 : 27 : PG_RETURN_NUMERIC(make_result(&const_nan));
3883 : : /* fail on negative inputs including -Inf, as log_var would */
3884 : 36 : sign1 = numeric_sign_internal(num1);
3885 : 36 : sign2 = numeric_sign_internal(num2);
3886 [ + + + + ]: 36 : if (sign1 < 0 || sign2 < 0)
3887 [ + - ]: 12 : ereport(ERROR,
3888 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
3889 : : errmsg("cannot take logarithm of a negative number")));
3890 : : /* fail on zero inputs, as log_var would */
3891 [ + - + + ]: 24 : if (sign1 == 0 || sign2 == 0)
3892 [ + - ]: 3 : ereport(ERROR,
3893 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
3894 : : errmsg("cannot take logarithm of zero")));
3895 [ + + ]: 21 : if (NUMERIC_IS_PINF(num1))
3896 : : {
3897 : : /* log(Inf, Inf) reduces to Inf/Inf, so it's NaN */
3898 [ + + ]: 9 : if (NUMERIC_IS_PINF(num2))
3899 : 3 : PG_RETURN_NUMERIC(make_result(&const_nan));
3900 : : /* log(Inf, finite-positive) is zero (we don't throw underflow) */
3901 : 6 : PG_RETURN_NUMERIC(make_result(&const_zero));
3902 : : }
3903 [ - + ]: 12 : Assert(NUMERIC_IS_PINF(num2));
3904 : : /* log(finite-positive, Inf) is Inf */
3905 : 12 : PG_RETURN_NUMERIC(make_result(&const_pinf));
3906 : : }
3907 : :
3908 : : /*
3909 : : * Initialize things
3910 : : */
4162 heikki.linnakangas@i 3911 : 108 : init_var_from_num(num1, &arg1);
3912 : 108 : init_var_from_num(num2, &arg2);
9237 JanWieck@Yahoo.com 3913 : 108 : init_var(&result);
3914 : :
3915 : : /*
3916 : : * Call log_var() to compute and return the result; note it handles scale
3917 : : * selection itself.
3918 : : */
3919 : 108 : log_var(&arg1, &arg2, &result);
3920 : :
3921 : 78 : res = make_result(&result);
3922 : :
3923 : 78 : free_var(&result);
3924 : :
8660 tgl@sss.pgh.pa.us 3925 : 78 : PG_RETURN_NUMERIC(res);
3926 : : }
3927 : :
3928 : :
3929 : : /*
3930 : : * numeric_power() -
3931 : : *
3932 : : * Raise x to the power of y
3933 : : */
3934 : : Datum
3935 : 816 : numeric_power(PG_FUNCTION_ARGS)
3936 : : {
3937 : 816 : Numeric num1 = PG_GETARG_NUMERIC(0);
3938 : 816 : Numeric num2 = PG_GETARG_NUMERIC(1);
3939 : : Numeric res;
3940 : : NumericVar arg1;
3941 : : NumericVar arg2;
3942 : : NumericVar result;
3943 : : int sign1,
3944 : : sign2;
3945 : :
3946 : : /*
3947 : : * Handle NaN and infinities
3948 : : */
1362 3949 [ + + + + ]: 816 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3950 : : {
3951 : : /*
3952 : : * We follow the POSIX spec for pow(3), which says that NaN ^ 0 = 1,
3953 : : * and 1 ^ NaN = 1, while all other cases with NaN inputs yield NaN
3954 : : * (with no error).
3955 : : */
3956 [ + + ]: 117 : if (NUMERIC_IS_NAN(num1))
3957 : : {
3958 [ + + ]: 27 : if (!NUMERIC_IS_SPECIAL(num2))
3959 : : {
3960 : 18 : init_var_from_num(num2, &arg2);
3961 [ + + ]: 18 : if (cmp_var(&arg2, &const_zero) == 0)
3962 : 6 : PG_RETURN_NUMERIC(make_result(&const_one));
3963 : : }
3964 : 21 : PG_RETURN_NUMERIC(make_result(&const_nan));
3965 : : }
3966 [ + + ]: 90 : if (NUMERIC_IS_NAN(num2))
3967 : : {
3968 [ + + ]: 21 : if (!NUMERIC_IS_SPECIAL(num1))
3969 : : {
3970 : 18 : init_var_from_num(num1, &arg1);
3971 [ + + ]: 18 : if (cmp_var(&arg1, &const_one) == 0)
3972 : 6 : PG_RETURN_NUMERIC(make_result(&const_one));
3973 : : }
3974 : 15 : PG_RETURN_NUMERIC(make_result(&const_nan));
3975 : : }
3976 : : /* At least one input is infinite, but error rules still apply */
3977 : 69 : sign1 = numeric_sign_internal(num1);
3978 : 69 : sign2 = numeric_sign_internal(num2);
3979 [ + + + + ]: 69 : if (sign1 == 0 && sign2 < 0)
3980 [ + - ]: 3 : ereport(ERROR,
3981 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
3982 : : errmsg("zero raised to a negative power is undefined")));
3983 [ + + + + ]: 66 : if (sign1 < 0 && !numeric_is_integral(num2))
3984 [ + - ]: 3 : ereport(ERROR,
3985 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
3986 : : errmsg("a negative number raised to a non-integer power yields a complex result")));
3987 : :
3988 : : /*
3989 : : * POSIX gives this series of rules for pow(3) with infinite inputs:
3990 : : *
3991 : : * For any value of y, if x is +1, 1.0 shall be returned.
3992 : : */
3993 [ + + ]: 63 : if (!NUMERIC_IS_SPECIAL(num1))
3994 : : {
3995 : 21 : init_var_from_num(num1, &arg1);
3996 [ + + ]: 21 : if (cmp_var(&arg1, &const_one) == 0)
2159 3997 : 3 : PG_RETURN_NUMERIC(make_result(&const_one));
3998 : : }
3999 : :
4000 : : /*
4001 : : * For any value of x, if y is [-]0, 1.0 shall be returned.
4002 : : */
1362 4003 [ + + ]: 60 : if (sign2 == 0)
2159 4004 : 6 : PG_RETURN_NUMERIC(make_result(&const_one));
4005 : :
4006 : : /*
4007 : : * For any odd integer value of y > 0, if x is [-]0, [-]0 shall be
4008 : : * returned. For y > 0 and not an odd integer, if x is [-]0, +0 shall
4009 : : * be returned. (Since we don't deal in minus zero, we need not
4010 : : * distinguish these two cases.)
4011 : : */
1362 4012 [ + + + - ]: 54 : if (sign1 == 0 && sign2 > 0)
4013 : 3 : PG_RETURN_NUMERIC(make_result(&const_zero));
4014 : :
4015 : : /*
4016 : : * If x is -1, and y is [-]Inf, 1.0 shall be returned.
4017 : : *
4018 : : * For |x| < 1, if y is -Inf, +Inf shall be returned.
4019 : : *
4020 : : * For |x| > 1, if y is -Inf, +0 shall be returned.
4021 : : *
4022 : : * For |x| < 1, if y is +Inf, +0 shall be returned.
4023 : : *
4024 : : * For |x| > 1, if y is +Inf, +Inf shall be returned.
4025 : : */
4026 [ + + ]: 51 : if (NUMERIC_IS_INF(num2))
4027 : : {
4028 : : bool abs_x_gt_one;
4029 : :
4030 [ + + ]: 27 : if (NUMERIC_IS_SPECIAL(num1))
4031 : 12 : abs_x_gt_one = true; /* x is either Inf or -Inf */
4032 : : else
4033 : : {
4034 : 15 : init_var_from_num(num1, &arg1);
4035 [ + + ]: 15 : if (cmp_var(&arg1, &const_minus_one) == 0)
4036 : 3 : PG_RETURN_NUMERIC(make_result(&const_one));
4037 : 12 : arg1.sign = NUMERIC_POS; /* now arg1 = abs(x) */
4038 : 12 : abs_x_gt_one = (cmp_var(&arg1, &const_one) > 0);
4039 : : }
4040 [ + + ]: 24 : if (abs_x_gt_one == (sign2 > 0))
4041 : 15 : PG_RETURN_NUMERIC(make_result(&const_pinf));
4042 : : else
4043 : 9 : PG_RETURN_NUMERIC(make_result(&const_zero));
4044 : : }
4045 : :
4046 : : /*
4047 : : * For y < 0, if x is +Inf, +0 shall be returned.
4048 : : *
4049 : : * For y > 0, if x is +Inf, +Inf shall be returned.
4050 : : */
4051 [ + + ]: 24 : if (NUMERIC_IS_PINF(num1))
4052 : : {
4053 [ + + ]: 12 : if (sign2 > 0)
4054 : 9 : PG_RETURN_NUMERIC(make_result(&const_pinf));
4055 : : else
4056 : 3 : PG_RETURN_NUMERIC(make_result(&const_zero));
4057 : : }
4058 : :
4059 [ - + ]: 12 : Assert(NUMERIC_IS_NINF(num1));
4060 : :
4061 : : /*
4062 : : * For y an odd integer < 0, if x is -Inf, -0 shall be returned. For
4063 : : * y < 0 and not an odd integer, if x is -Inf, +0 shall be returned.
4064 : : * (Again, we need not distinguish these two cases.)
4065 : : */
4066 [ + + ]: 12 : if (sign2 < 0)
4067 : 6 : PG_RETURN_NUMERIC(make_result(&const_zero));
4068 : :
4069 : : /*
4070 : : * For y an odd integer > 0, if x is -Inf, -Inf shall be returned. For
4071 : : * y > 0 and not an odd integer, if x is -Inf, +Inf shall be returned.
4072 : : */
4073 : 6 : init_var_from_num(num2, &arg2);
4074 [ + - + - ]: 6 : if (arg2.ndigits > 0 && arg2.ndigits == arg2.weight + 1 &&
4075 [ + + ]: 6 : (arg2.digits[arg2.ndigits - 1] & 1))
4076 : 3 : PG_RETURN_NUMERIC(make_result(&const_ninf));
4077 : : else
4078 : 3 : PG_RETURN_NUMERIC(make_result(&const_pinf));
4079 : : }
4080 : :
4081 : : /*
4082 : : * The SQL spec requires that we emit a particular SQLSTATE error code for
4083 : : * certain error conditions. Specifically, we don't return a
4084 : : * divide-by-zero error code for 0 ^ -1. Raising a negative number to a
4085 : : * non-integer power must produce the same error code, but that case is
4086 : : * handled in power_var().
4087 : : */
4088 : 699 : sign1 = numeric_sign_internal(num1);
4089 : 699 : sign2 = numeric_sign_internal(num2);
4090 : :
4091 [ + + + + ]: 699 : if (sign1 == 0 && sign2 < 0)
7273 neilc@samurai.com 4092 [ + - ]: 6 : ereport(ERROR,
4093 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
4094 : : errmsg("zero raised to a negative power is undefined")));
4095 : :
4096 : : /*
4097 : : * Initialize things
4098 : : */
1362 tgl@sss.pgh.pa.us 4099 : 693 : init_var(&result);
4100 : 693 : init_var_from_num(num1, &arg1);
4101 : 693 : init_var_from_num(num2, &arg2);
4102 : :
4103 : : /*
4104 : : * Call power_var() to compute and return the result; note it handles
4105 : : * scale selection itself.
4106 : : */
9237 JanWieck@Yahoo.com 4107 : 693 : power_var(&arg1, &arg2, &result);
4108 : :
4109 : 678 : res = make_result(&result);
4110 : :
4111 : 678 : free_var(&result);
4112 : :
8660 tgl@sss.pgh.pa.us 4113 : 678 : PG_RETURN_NUMERIC(res);
4114 : : }
4115 : :
4116 : : /*
4117 : : * numeric_scale() -
4118 : : *
4119 : : * Returns the scale, i.e. the count of decimal digits in the fractional part
4120 : : */
4121 : : Datum
3022 alvherre@alvh.no-ip. 4122 : 54 : numeric_scale(PG_FUNCTION_ARGS)
4123 : : {
4124 : 54 : Numeric num = PG_GETARG_NUMERIC(0);
4125 : :
1362 tgl@sss.pgh.pa.us 4126 [ + + ]: 54 : if (NUMERIC_IS_SPECIAL(num))
3022 alvherre@alvh.no-ip. 4127 : 9 : PG_RETURN_NULL();
4128 : :
4129 [ + - ]: 45 : PG_RETURN_INT32(NUMERIC_DSCALE(num));
4130 : : }
4131 : :
4132 : : /*
4133 : : * Calculate minimum scale for value.
4134 : : */
4135 : : static int
1560 tgl@sss.pgh.pa.us 4136 : 186 : get_min_scale(NumericVar *var)
4137 : : {
4138 : : int min_scale;
4139 : : int last_digit_pos;
4140 : :
4141 : : /*
4142 : : * Ordinarily, the input value will be "stripped" so that the last
4143 : : * NumericDigit is nonzero. But we don't want to get into an infinite
4144 : : * loop if it isn't, so explicitly find the last nonzero digit.
4145 : : */
4146 : 186 : last_digit_pos = var->ndigits - 1;
4147 [ + + ]: 186 : while (last_digit_pos >= 0 &&
4148 [ - + ]: 171 : var->digits[last_digit_pos] == 0)
1560 tgl@sss.pgh.pa.us 4149 :UBC 0 : last_digit_pos--;
4150 : :
1560 tgl@sss.pgh.pa.us 4151 [ + + ]:CBC 186 : if (last_digit_pos >= 0)
4152 : : {
4153 : : /* compute min_scale assuming that last ndigit has no zeroes */
4154 : 171 : min_scale = (last_digit_pos - var->weight) * DEC_DIGITS;
4155 : :
4156 : : /*
4157 : : * We could get a negative result if there are no digits after the
4158 : : * decimal point. In this case the min_scale must be zero.
4159 : : */
4160 [ + + ]: 171 : if (min_scale > 0)
4161 : : {
4162 : : /*
4163 : : * Reduce min_scale if trailing digit(s) in last NumericDigit are
4164 : : * zero.
4165 : : */
4166 : 93 : NumericDigit last_digit = var->digits[last_digit_pos];
4167 : :
4168 [ + + ]: 249 : while (last_digit % 10 == 0)
4169 : : {
4170 : 156 : min_scale--;
4171 : 156 : last_digit /= 10;
4172 : : }
4173 : : }
4174 : : else
4175 : 78 : min_scale = 0;
4176 : : }
4177 : : else
4178 : 15 : min_scale = 0; /* result if input is zero */
4179 : :
4180 : 186 : return min_scale;
4181 : : }
4182 : :
4183 : : /*
4184 : : * Returns minimum scale required to represent supplied value without loss.
4185 : : */
4186 : : Datum
4187 : 36 : numeric_min_scale(PG_FUNCTION_ARGS)
4188 : : {
4189 : 36 : Numeric num = PG_GETARG_NUMERIC(0);
4190 : : NumericVar arg;
4191 : : int min_scale;
4192 : :
1362 4193 [ + + ]: 36 : if (NUMERIC_IS_SPECIAL(num))
1560 4194 : 6 : PG_RETURN_NULL();
4195 : :
4196 : 30 : init_var_from_num(num, &arg);
4197 : 30 : min_scale = get_min_scale(&arg);
4198 : 30 : free_var(&arg);
4199 : :
4200 : 30 : PG_RETURN_INT32(min_scale);
4201 : : }
4202 : :
4203 : : /*
4204 : : * Reduce scale of numeric value to represent supplied value without loss.
4205 : : */
4206 : : Datum
4207 : 162 : numeric_trim_scale(PG_FUNCTION_ARGS)
4208 : : {
4209 : 162 : Numeric num = PG_GETARG_NUMERIC(0);
4210 : : Numeric res;
4211 : : NumericVar result;
4212 : :
1362 4213 [ + + ]: 162 : if (NUMERIC_IS_SPECIAL(num))
4214 : 6 : PG_RETURN_NUMERIC(duplicate_numeric(num));
4215 : :
1560 4216 : 156 : init_var_from_num(num, &result);
4217 : 156 : result.dscale = get_min_scale(&result);
4218 : 156 : res = make_result(&result);
4219 : 156 : free_var(&result);
4220 : :
4221 : 156 : PG_RETURN_NUMERIC(res);
4222 : : }
4223 : :
4224 : : /*
4225 : : * Return a random numeric value in the range [rmin, rmax].
4226 : : */
4227 : : Numeric
18 dean.a.rasheed@gmail 4228 :GNC 16731 : random_numeric(pg_prng_state *state, Numeric rmin, Numeric rmax)
4229 : : {
4230 : : NumericVar rmin_var;
4231 : : NumericVar rmax_var;
4232 : : NumericVar result;
4233 : : Numeric res;
4234 : :
4235 : : /* Range bounds must not be NaN/infinity */
4236 [ + + ]: 16731 : if (NUMERIC_IS_SPECIAL(rmin))
4237 : : {
4238 [ + + ]: 6 : if (NUMERIC_IS_NAN(rmin))
4239 [ + - ]: 3 : ereport(ERROR,
4240 : : errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4241 : : errmsg("lower bound cannot be NaN"));
4242 : : else
4243 [ + - ]: 3 : ereport(ERROR,
4244 : : errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4245 : : errmsg("lower bound cannot be infinity"));
4246 : : }
4247 [ + + ]: 16725 : if (NUMERIC_IS_SPECIAL(rmax))
4248 : : {
4249 [ + + ]: 6 : if (NUMERIC_IS_NAN(rmax))
4250 [ + - ]: 3 : ereport(ERROR,
4251 : : errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4252 : : errmsg("upper bound cannot be NaN"));
4253 : : else
4254 [ + - ]: 3 : ereport(ERROR,
4255 : : errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4256 : : errmsg("upper bound cannot be infinity"));
4257 : : }
4258 : :
4259 : : /* Return a random value in the range [rmin, rmax] */
4260 : 16719 : init_var_from_num(rmin, &rmin_var);
4261 : 16719 : init_var_from_num(rmax, &rmax_var);
4262 : :
4263 : 16719 : init_var(&result);
4264 : :
4265 : 16719 : random_var(state, &rmin_var, &rmax_var, &result);
4266 : :
4267 : 16716 : res = make_result(&result);
4268 : :
4269 : 16716 : free_var(&result);
4270 : :
4271 : 16716 : return res;
4272 : : }
4273 : :
4274 : :
4275 : : /* ----------------------------------------------------------------------
4276 : : *
4277 : : * Type conversion functions
4278 : : *
4279 : : * ----------------------------------------------------------------------
4280 : : */
4281 : :
4282 : : Numeric
1313 peter@eisentraut.org 4283 :CBC 924860 : int64_to_numeric(int64 val)
4284 : : {
4285 : : Numeric res;
4286 : : NumericVar result;
4287 : :
9237 JanWieck@Yahoo.com 4288 : 924860 : init_var(&result);
4289 : :
1313 peter@eisentraut.org 4290 : 924860 : int64_to_numericvar(val, &result);
4291 : :
9237 JanWieck@Yahoo.com 4292 : 924860 : res = make_result(&result);
4293 : :
4294 : 924860 : free_var(&result);
4295 : :
1313 peter@eisentraut.org 4296 : 924860 : return res;
4297 : : }
4298 : :
4299 : : /*
4300 : : * Convert val1/(10**log10val2) to numeric. This is much faster than normal
4301 : : * numeric division.
4302 : : */
4303 : : Numeric
1104 4304 : 14604 : int64_div_fast_to_numeric(int64 val1, int log10val2)
4305 : : {
4306 : : Numeric res;
4307 : : NumericVar result;
4308 : : int rscale;
4309 : : int w;
4310 : : int m;
4311 : :
436 dean.a.rasheed@gmail 4312 : 14604 : init_var(&result);
4313 : :
4314 : : /* result scale */
4315 : 14604 : rscale = log10val2 < 0 ? 0 : log10val2;
4316 : :
4317 : : /* how much to decrease the weight by */
1104 peter@eisentraut.org 4318 : 14604 : w = log10val2 / DEC_DIGITS;
4319 : : /* how much is left to divide by */
4320 : 14604 : m = log10val2 % DEC_DIGITS;
436 dean.a.rasheed@gmail 4321 [ - + ]: 14604 : if (m < 0)
4322 : : {
436 dean.a.rasheed@gmail 4323 :UBC 0 : m += DEC_DIGITS;
4324 : 0 : w--;
4325 : : }
4326 : :
4327 : : /*
4328 : : * If there is anything left to divide by (10^m with 0 < m < DEC_DIGITS),
4329 : : * multiply the dividend by 10^(DEC_DIGITS - m), and shift the weight by
4330 : : * one more.
4331 : : */
1104 peter@eisentraut.org 4332 [ + - ]:CBC 14604 : if (m > 0)
4333 : : {
4334 : : #if DEC_DIGITS == 4
4335 : : static const int pow10[] = {1, 10, 100, 1000};
4336 : : #elif DEC_DIGITS == 2
4337 : : static const int pow10[] = {1, 10};
4338 : : #elif DEC_DIGITS == 1
4339 : : static const int pow10[] = {1};
4340 : : #else
4341 : : #error unsupported NBASE
4342 : : #endif
436 dean.a.rasheed@gmail 4343 : 14604 : int64 factor = pow10[DEC_DIGITS - m];
4344 : : int64 new_val1;
4345 : :
4346 : : StaticAssertDecl(lengthof(pow10) == DEC_DIGITS, "mismatch with DEC_DIGITS");
4347 : :
4348 [ + + ]: 14604 : if (unlikely(pg_mul_s64_overflow(val1, factor, &new_val1)))
4349 : : {
4350 : : #ifdef HAVE_INT128
4351 : : /* do the multiplication using 128-bit integers */
4352 : : int128 tmp;
4353 : :
4354 : 6 : tmp = (int128) val1 * (int128) factor;
4355 : :
4356 : 6 : int128_to_numericvar(tmp, &result);
4357 : : #else
4358 : : /* do the multiplication using numerics */
4359 : : NumericVar tmp;
4360 : :
4361 : : init_var(&tmp);
4362 : :
4363 : : int64_to_numericvar(val1, &result);
4364 : : int64_to_numericvar(factor, &tmp);
4365 : : mul_var(&result, &tmp, &result, 0);
4366 : :
4367 : : free_var(&tmp);
4368 : : #endif
4369 : : }
4370 : : else
4371 : 14598 : int64_to_numericvar(new_val1, &result);
4372 : :
1104 peter@eisentraut.org 4373 : 14604 : w++;
4374 : : }
4375 : : else
436 dean.a.rasheed@gmail 4376 :UBC 0 : int64_to_numericvar(val1, &result);
4377 : :
1104 peter@eisentraut.org 4378 :CBC 14604 : result.weight -= w;
436 dean.a.rasheed@gmail 4379 : 14604 : result.dscale = rscale;
4380 : :
1104 peter@eisentraut.org 4381 : 14604 : res = make_result(&result);
4382 : :
4383 : 14604 : free_var(&result);
4384 : :
4385 : 14604 : return res;
4386 : : }
4387 : :
4388 : : Datum
1313 4389 : 766161 : int4_numeric(PG_FUNCTION_ARGS)
4390 : : {
4391 : 766161 : int32 val = PG_GETARG_INT32(0);
4392 : :
4393 : 766161 : PG_RETURN_NUMERIC(int64_to_numeric(val));
4394 : : }
4395 : :
4396 : : int32
1856 akorotkov@postgresql 4397 : 4197 : numeric_int4_opt_error(Numeric num, bool *have_error)
4398 : : {
4399 : : NumericVar x;
4400 : : int32 result;
4401 : :
1714 michael@paquier.xyz 4402 [ + + ]: 4197 : if (have_error)
4403 : 750 : *have_error = false;
4404 : :
1362 tgl@sss.pgh.pa.us 4405 [ + + ]: 4197 : if (NUMERIC_IS_SPECIAL(num))
4406 : : {
1856 akorotkov@postgresql 4407 [ - + ]: 9 : if (have_error)
4408 : : {
1856 akorotkov@postgresql 4409 :UBC 0 : *have_error = true;
4410 : 0 : return 0;
4411 : : }
4412 : : else
4413 : : {
1362 tgl@sss.pgh.pa.us 4414 [ + + ]:CBC 9 : if (NUMERIC_IS_NAN(num))
4415 [ + - ]: 3 : ereport(ERROR,
4416 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4417 : : errmsg("cannot convert NaN to %s", "integer")));
4418 : : else
4419 [ + - ]: 6 : ereport(ERROR,
4420 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4421 : : errmsg("cannot convert infinity to %s", "integer")));
4422 : : }
4423 : : }
4424 : :
4425 : : /* Convert to variable format, then convert to int4 */
4162 heikki.linnakangas@i 4426 : 4188 : init_var_from_num(num, &x);
4427 : :
1856 akorotkov@postgresql 4428 [ + + ]: 4188 : if (!numericvar_to_int32(&x, &result))
4429 : : {
4430 [ + + ]: 42 : if (have_error)
4431 : : {
4432 : 36 : *have_error = true;
4433 : 36 : return 0;
4434 : : }
4435 : : else
4436 : : {
4437 [ + - ]: 6 : ereport(ERROR,
4438 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4439 : : errmsg("integer out of range")));
4440 : : }
4441 : : }
4442 : :
4443 : 4146 : return result;
4444 : : }
4445 : :
4446 : : Datum
4447 : 3447 : numeric_int4(PG_FUNCTION_ARGS)
4448 : : {
4449 : 3447 : Numeric num = PG_GETARG_NUMERIC(0);
4450 : :
4451 : 3447 : PG_RETURN_INT32(numeric_int4_opt_error(num, NULL));
4452 : : }
4453 : :
4454 : : /*
4455 : : * Given a NumericVar, convert it to an int32. If the NumericVar
4456 : : * exceeds the range of an int32, false is returned, otherwise true is returned.
4457 : : * The input NumericVar is *not* free'd.
4458 : : */
4459 : : static bool
4460 : 4557 : numericvar_to_int32(const NumericVar *var, int32 *result)
4461 : : {
4462 : : int64 val;
4463 : :
3313 andres@anarazel.de 4464 [ + + ]: 4557 : if (!numericvar_to_int64(var, &val))
1856 akorotkov@postgresql 4465 :GBC 3 : return false;
4466 : :
982 dean.a.rasheed@gmail 4467 [ + + + + ]:CBC 4554 : if (unlikely(val < PG_INT32_MIN) || unlikely(val > PG_INT32_MAX))
4468 : 39 : return false;
4469 : :
4470 : : /* Down-convert to int4 */
1856 akorotkov@postgresql 4471 : 4515 : *result = (int32) val;
4472 : :
982 dean.a.rasheed@gmail 4473 : 4515 : return true;
4474 : : }
4475 : :
4476 : : Datum
8672 tgl@sss.pgh.pa.us 4477 : 18412 : int8_numeric(PG_FUNCTION_ARGS)
4478 : : {
7695 4479 : 18412 : int64 val = PG_GETARG_INT64(0);
4480 : :
1313 peter@eisentraut.org 4481 : 18412 : PG_RETURN_NUMERIC(int64_to_numeric(val));
4482 : : }
4483 : :
4484 : : int64
102 peter@eisentraut.org 4485 :GNC 282 : numeric_int8_opt_error(Numeric num, bool *have_error)
4486 : : {
4487 : : NumericVar x;
4488 : : int64 result;
4489 : :
4490 [ + + ]: 282 : if (have_error)
4491 : 24 : *have_error = false;
4492 : :
1362 tgl@sss.pgh.pa.us 4493 [ + + ]: 282 : if (NUMERIC_IS_SPECIAL(num))
4494 : : {
102 peter@eisentraut.org 4495 [ - + ]: 9 : if (have_error)
4496 : : {
102 peter@eisentraut.org 4497 :UNC 0 : *have_error = true;
4498 : 0 : return 0;
4499 : : }
4500 : : else
4501 : : {
102 peter@eisentraut.org 4502 [ + + ]:GNC 9 : if (NUMERIC_IS_NAN(num))
4503 [ + - ]: 3 : ereport(ERROR,
4504 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4505 : : errmsg("cannot convert NaN to %s", "bigint")));
4506 : : else
4507 [ + - ]: 6 : ereport(ERROR,
4508 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4509 : : errmsg("cannot convert infinity to %s", "bigint")));
4510 : : }
4511 : : }
4512 : :
4513 : : /* Convert to variable format, then convert to int8 */
4162 heikki.linnakangas@i 4514 : 273 : init_var_from_num(num, &x);
4515 : :
3313 andres@anarazel.de 4516 [ + + ]: 273 : if (!numericvar_to_int64(&x, &result))
4517 : : {
102 peter@eisentraut.org 4518 [ + + ]: 30 : if (have_error)
4519 : : {
4520 : 6 : *have_error = true;
4521 : 6 : return 0;
4522 : : }
4523 : : else
4524 : : {
4525 [ + - ]: 24 : ereport(ERROR,
4526 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4527 : : errmsg("bigint out of range")));
4528 : : }
4529 : : }
4530 : :
4531 : 243 : return result;
4532 : : }
4533 : :
4534 : : Datum
102 peter@eisentraut.org 4535 :CBC 258 : numeric_int8(PG_FUNCTION_ARGS)
4536 : : {
4537 : 258 : Numeric num = PG_GETARG_NUMERIC(0);
4538 : :
102 peter@eisentraut.org 4539 :GNC 258 : PG_RETURN_INT64(numeric_int8_opt_error(num, NULL));
4540 : : }
4541 : :
4542 : :
4543 : : Datum
8714 tgl@sss.pgh.pa.us 4544 :CBC 3 : int2_numeric(PG_FUNCTION_ARGS)
4545 : : {
4546 : 3 : int16 val = PG_GETARG_INT16(0);
4547 : :
1313 peter@eisentraut.org 4548 : 3 : PG_RETURN_NUMERIC(int64_to_numeric(val));
4549 : : }
4550 : :
4551 : :
4552 : : Datum
8714 tgl@sss.pgh.pa.us 4553 : 48 : numeric_int2(PG_FUNCTION_ARGS)
4554 : : {
4555 : 48 : Numeric num = PG_GETARG_NUMERIC(0);
4556 : : NumericVar x;
4557 : : int64 val;
4558 : : int16 result;
4559 : :
1362 4560 [ + + ]: 48 : if (NUMERIC_IS_SPECIAL(num))
4561 : : {
4562 [ + + ]: 9 : if (NUMERIC_IS_NAN(num))
4563 [ + - ]: 3 : ereport(ERROR,
4564 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4565 : : errmsg("cannot convert NaN to %s", "smallint")));
4566 : : else
4567 [ + - ]: 6 : ereport(ERROR,
4568 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4569 : : errmsg("cannot convert infinity to %s", "smallint")));
4570 : : }
4571 : :
4572 : : /* Convert to variable format and thence to int8 */
4162 heikki.linnakangas@i 4573 : 39 : init_var_from_num(num, &x);
4574 : :
3313 andres@anarazel.de 4575 [ - + ]: 39 : if (!numericvar_to_int64(&x, &val))
7567 tgl@sss.pgh.pa.us 4576 [ # # ]:UBC 0 : ereport(ERROR,
4577 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4578 : : errmsg("smallint out of range")));
4579 : :
982 dean.a.rasheed@gmail 4580 [ + + + + ]:CBC 39 : if (unlikely(val < PG_INT16_MIN) || unlikely(val > PG_INT16_MAX))
7567 tgl@sss.pgh.pa.us 4581 [ + - ]: 6 : ereport(ERROR,
4582 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4583 : : errmsg("smallint out of range")));
4584 : :
4585 : : /* Down-convert to int2 */
982 dean.a.rasheed@gmail 4586 : 33 : result = (int16) val;
4587 : :
7695 tgl@sss.pgh.pa.us 4588 : 33 : PG_RETURN_INT16(result);
4589 : : }
4590 : :
4591 : :
4592 : : Datum
8660 4593 : 537 : float8_numeric(PG_FUNCTION_ARGS)
4594 : : {
4595 : 537 : float8 val = PG_GETARG_FLOAT8(0);
4596 : : Numeric res;
4597 : : NumericVar result;
4598 : : char buf[DBL_DIG + 100];
4599 : : const char *endptr;
4600 : :
4601 [ + + ]: 537 : if (isnan(val))
4602 : 3 : PG_RETURN_NUMERIC(make_result(&const_nan));
4603 : :
2391 4604 [ + + ]: 534 : if (isinf(val))
4605 : : {
1362 4606 [ + + ]: 6 : if (val < 0)
4607 : 3 : PG_RETURN_NUMERIC(make_result(&const_ninf));
4608 : : else
4609 : 3 : PG_RETURN_NUMERIC(make_result(&const_pinf));
4610 : : }
4611 : :
2391 4612 : 528 : snprintf(buf, sizeof(buf), "%.*g", DBL_DIG, val);
4613 : :
9237 JanWieck@Yahoo.com 4614 : 528 : init_var(&result);
4615 : :
4616 : : /* Assume we need not worry about leading/trailing spaces */
492 tgl@sss.pgh.pa.us 4617 : 528 : (void) set_var_from_str(buf, buf, &result, &endptr, NULL);
4618 : :
9237 JanWieck@Yahoo.com 4619 : 528 : res = make_result(&result);
4620 : :
4621 : 528 : free_var(&result);
4622 : :
8660 tgl@sss.pgh.pa.us 4623 : 528 : PG_RETURN_NUMERIC(res);
4624 : : }
4625 : :
4626 : :
4627 : : Datum
4628 : 259637 : numeric_float8(PG_FUNCTION_ARGS)
4629 : : {
4630 : 259637 : Numeric num = PG_GETARG_NUMERIC(0);
4631 : : char *tmp;
4632 : : Datum result;
4633 : :
1362 4634 [ + + ]: 259637 : if (NUMERIC_IS_SPECIAL(num))
4635 : : {
4636 [ + + ]: 39 : if (NUMERIC_IS_PINF(num))
4637 : 12 : PG_RETURN_FLOAT8(get_float8_infinity());
4638 [ + + ]: 27 : else if (NUMERIC_IS_NINF(num))
4639 : 12 : PG_RETURN_FLOAT8(-get_float8_infinity());
4640 : : else
4641 : 15 : PG_RETURN_FLOAT8(get_float8_nan());
4642 : : }
4643 : :
8706 4644 : 259598 : tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
4645 : : NumericGetDatum(num)));
4646 : :
8657 4647 : 259598 : result = DirectFunctionCall1(float8in, CStringGetDatum(tmp));
4648 : :
9237 JanWieck@Yahoo.com 4649 : 259598 : pfree(tmp);
4650 : :
8657 tgl@sss.pgh.pa.us 4651 : 259598 : PG_RETURN_DATUM(result);
4652 : : }
4653 : :
4654 : :
4655 : : /*
4656 : : * Convert numeric to float8; if out of range, return +/- HUGE_VAL
4657 : : *
4658 : : * (internal helper function, not directly callable from SQL)
4659 : : */
4660 : : Datum
8219 4661 : 1608 : numeric_float8_no_overflow(PG_FUNCTION_ARGS)
4662 : : {
4663 : 1608 : Numeric num = PG_GETARG_NUMERIC(0);
4664 : : double val;
4665 : :
1362 4666 [ - + ]: 1608 : if (NUMERIC_IS_SPECIAL(num))
4667 : : {
1362 tgl@sss.pgh.pa.us 4668 [ # # ]:UBC 0 : if (NUMERIC_IS_PINF(num))
4669 : 0 : val = HUGE_VAL;
4670 [ # # ]: 0 : else if (NUMERIC_IS_NINF(num))
4671 : 0 : val = -HUGE_VAL;
4672 : : else
4673 : 0 : val = get_float8_nan();
4674 : : }
4675 : : else
4676 : : {
4677 : : NumericVar x;
4678 : :
1362 tgl@sss.pgh.pa.us 4679 :CBC 1608 : init_var_from_num(num, &x);
4680 : 1608 : val = numericvar_to_double_no_overflow(&x);
4681 : : }
4682 : :
8219 4683 : 1608 : PG_RETURN_FLOAT8(val);
4684 : : }
4685 : :
4686 : : Datum
8660 4687 : 10887 : float4_numeric(PG_FUNCTION_ARGS)
4688 : : {
4689 : 10887 : float4 val = PG_GETARG_FLOAT4(0);
4690 : : Numeric res;
4691 : : NumericVar result;
4692 : : char buf[FLT_DIG + 100];
4693 : : const char *endptr;
4694 : :
4695 [ + + ]: 10887 : if (isnan(val))
4696 : 3 : PG_RETURN_NUMERIC(make_result(&const_nan));
4697 : :
2391 4698 [ + + ]: 10884 : if (isinf(val))
4699 : : {
1362 4700 [ + + ]: 6 : if (val < 0)
4701 : 3 : PG_RETURN_NUMERIC(make_result(&const_ninf));
4702 : : else
4703 : 3 : PG_RETURN_NUMERIC(make_result(&const_pinf));
4704 : : }
4705 : :
2391 4706 : 10878 : snprintf(buf, sizeof(buf), "%.*g", FLT_DIG, val);
4707 : :
9237 JanWieck@Yahoo.com 4708 : 10878 : init_var(&result);
4709 : :
4710 : : /* Assume we need not worry about leading/trailing spaces */
492 tgl@sss.pgh.pa.us 4711 : 10878 : (void) set_var_from_str(buf, buf, &result, &endptr, NULL);
4712 : :
9237 JanWieck@Yahoo.com 4713 : 10878 : res = make_result(&result);
4714 : :
4715 : 10878 : free_var(&result);
4716 : :
8660 tgl@sss.pgh.pa.us 4717 : 10878 : PG_RETURN_NUMERIC(res);
4718 : : }
4719 : :
4720 : :
4721 : : Datum
4722 : 1096 : numeric_float4(PG_FUNCTION_ARGS)
4723 : : {
4724 : 1096 : Numeric num = PG_GETARG_NUMERIC(0);
4725 : : char *tmp;
4726 : : Datum result;
4727 : :
1362 4728 [ + + ]: 1096 : if (NUMERIC_IS_SPECIAL(num))
4729 : : {
4730 [ + + ]: 39 : if (NUMERIC_IS_PINF(num))
4731 : 12 : PG_RETURN_FLOAT4(get_float4_infinity());
4732 [ + + ]: 27 : else if (NUMERIC_IS_NINF(num))
4733 : 12 : PG_RETURN_FLOAT4(-get_float4_infinity());
4734 : : else
4735 : 15 : PG_RETURN_FLOAT4(get_float4_nan());
4736 : : }
4737 : :
8706 4738 : 1057 : tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
4739 : : NumericGetDatum(num)));
4740 : :
8657 4741 : 1057 : result = DirectFunctionCall1(float4in, CStringGetDatum(tmp));
4742 : :
9237 JanWieck@Yahoo.com 4743 : 1057 : pfree(tmp);
4744 : :
8657 tgl@sss.pgh.pa.us 4745 : 1057 : PG_RETURN_DATUM(result);
4746 : : }
4747 : :
4748 : :
4749 : : Datum
1384 fujii@postgresql.org 4750 : 60 : numeric_pg_lsn(PG_FUNCTION_ARGS)
4751 : : {
4752 : 60 : Numeric num = PG_GETARG_NUMERIC(0);
4753 : : NumericVar x;
4754 : : XLogRecPtr result;
4755 : :
1362 tgl@sss.pgh.pa.us 4756 [ + + ]: 60 : if (NUMERIC_IS_SPECIAL(num))
4757 : : {
4758 [ + - ]: 3 : if (NUMERIC_IS_NAN(num))
4759 [ + - ]: 3 : ereport(ERROR,
4760 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4761 : : errmsg("cannot convert NaN to %s", "pg_lsn")));
4762 : : else
1362 tgl@sss.pgh.pa.us 4763 [ # # ]:UBC 0 : ereport(ERROR,
4764 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4765 : : errmsg("cannot convert infinity to %s", "pg_lsn")));
4766 : : }
4767 : :
4768 : : /* Convert to variable format and thence to pg_lsn */
1384 fujii@postgresql.org 4769 :CBC 57 : init_var_from_num(num, &x);
4770 : :
4771 [ + + ]: 57 : if (!numericvar_to_uint64(&x, (uint64 *) &result))
4772 [ + - ]: 12 : ereport(ERROR,
4773 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4774 : : errmsg("pg_lsn out of range")));
4775 : :
4776 : 45 : PG_RETURN_LSN(result);
4777 : : }
4778 : :
4779 : :
4780 : : /* ----------------------------------------------------------------------
4781 : : *
4782 : : * Aggregate functions
4783 : : *
4784 : : * The transition datatype for all these aggregates is declared as INTERNAL.
4785 : : * Actually, it's a pointer to a NumericAggState allocated in the aggregate
4786 : : * context. The digit buffers for the NumericVars will be there too.
4787 : : *
4788 : : * On platforms which support 128-bit integers some aggregates instead use a
4789 : : * 128-bit integer based transition datatype to speed up calculations.
4790 : : *
4791 : : * ----------------------------------------------------------------------
4792 : : */
4793 : :
4794 : : typedef struct NumericAggState
4795 : : {
4796 : : bool calcSumX2; /* if true, calculate sumX2 */
4797 : : MemoryContext agg_context; /* context we're calculating in */
4798 : : int64 N; /* count of processed numbers */
4799 : : NumericSumAccum sumX; /* sum of processed numbers */
4800 : : NumericSumAccum sumX2; /* sum of squares of processed numbers */
4801 : : int maxScale; /* maximum scale seen so far */
4802 : : int64 maxScaleCount; /* number of values seen with maximum scale */
4803 : : /* These counts are *not* included in N! Use NA_TOTAL_COUNT() as needed */
4804 : : int64 NaNcount; /* count of NaN values */
4805 : : int64 pInfcount; /* count of +Inf values */
4806 : : int64 nInfcount; /* count of -Inf values */
4807 : : } NumericAggState;
4808 : :
4809 : : #define NA_TOTAL_COUNT(na) \
4810 : : ((na)->N + (na)->NaNcount + (na)->pInfcount + (na)->nInfcount)
4811 : :
4812 : : /*
4813 : : * Prepare state data for a numeric aggregate function that needs to compute
4814 : : * sum, count and optionally sum of squares of the input.
4815 : : */
4816 : : static NumericAggState *
3802 tgl@sss.pgh.pa.us 4817 : 85570 : makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
4818 : : {
4819 : : NumericAggState *state;
4820 : : MemoryContext agg_context;
4821 : : MemoryContext old_context;
4822 : :
4823 [ - + ]: 85570 : if (!AggCheckCallContext(fcinfo, &agg_context))
3802 tgl@sss.pgh.pa.us 4824 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
4825 : :
3802 tgl@sss.pgh.pa.us 4826 :CBC 85570 : old_context = MemoryContextSwitchTo(agg_context);
4827 : :
4828 : 85570 : state = (NumericAggState *) palloc0(sizeof(NumericAggState));
4829 : 85570 : state->calcSumX2 = calcSumX2;
4830 : 85570 : state->agg_context = agg_context;
4831 : :
4832 : 85570 : MemoryContextSwitchTo(old_context);
4833 : :
4834 : 85570 : return state;
4835 : : }
4836 : :
4837 : : /*
4838 : : * Like makeNumericAggState(), but allocate the state in the current memory
4839 : : * context.
4840 : : */
4841 : : static NumericAggState *
2852 4842 : 42 : makeNumericAggStateCurrentContext(bool calcSumX2)
4843 : : {
4844 : : NumericAggState *state;
4845 : :
4846 : 42 : state = (NumericAggState *) palloc0(sizeof(NumericAggState));
4847 : 42 : state->calcSumX2 = calcSumX2;
4848 : 42 : state->agg_context = CurrentMemoryContext;
4849 : :
4850 : 42 : return state;
4851 : : }
4852 : :
4853 : : /*
4854 : : * Accumulate a new input value for numeric aggregate functions.
4855 : : */
4856 : : static void
3802 4857 : 1056776 : do_numeric_accum(NumericAggState *state, Numeric newval)
4858 : : {
4859 : : NumericVar X;
4860 : : NumericVar X2;
4861 : : MemoryContext old_context;
4862 : :
4863 : : /* Count NaN/infinity inputs separately from all else */
1362 4864 [ + + ]: 1056776 : if (NUMERIC_IS_SPECIAL(newval))
4865 : : {
4866 [ + + ]: 81 : if (NUMERIC_IS_PINF(newval))
4867 : 36 : state->pInfcount++;
4868 [ + + ]: 45 : else if (NUMERIC_IS_NINF(newval))
4869 : 18 : state->nInfcount++;
4870 : : else
4871 : 27 : state->NaNcount++;
3802 4872 : 81 : return;
4873 : : }
4874 : :
4875 : : /* load processed number in short-lived context */
4876 : 1056695 : init_var_from_num(newval, &X);
4877 : :
4878 : : /*
4879 : : * Track the highest input dscale that we've seen, to support inverse
4880 : : * transitions (see do_numeric_discard).
4881 : : */
3655 4882 [ + + ]: 1056695 : if (X.dscale > state->maxScale)
4883 : : {
4884 : 78 : state->maxScale = X.dscale;
4885 : 78 : state->maxScaleCount = 1;
4886 : : }
4887 [ + + ]: 1056617 : else if (X.dscale == state->maxScale)
4888 : 1056599 : state->maxScaleCount++;
4889 : :
4890 : : /* if we need X^2, calculate that in short-lived context */
3802 4891 [ + + ]: 1056695 : if (state->calcSumX2)
4892 : : {
4893 : 120366 : init_var(&X2);
4894 : 120366 : mul_var(&X, &X, &X2, X.dscale * 2);
4895 : : }
4896 : :
4897 : : /* The rest of this needs to work in the aggregate context */
4898 : 1056695 : old_context = MemoryContextSwitchTo(state->agg_context);
4899 : :
2781 heikki.linnakangas@i 4900 : 1056695 : state->N++;
4901 : :
4902 : : /* Accumulate sums */
4903 : 1056695 : accum_sum_add(&(state->sumX), &X);
4904 : :
4905 [ + + ]: 1056695 : if (state->calcSumX2)
4906 : 120366 : accum_sum_add(&(state->sumX2), &X2);
4907 : :
3802 tgl@sss.pgh.pa.us 4908 : 1056695 : MemoryContextSwitchTo(old_context);
4909 : : }
4910 : :
4911 : : /*
4912 : : * Attempt to remove an input value from the aggregated state.
4913 : : *
4914 : : * If the value cannot be removed then the function will return false; the
4915 : : * possible reasons for failing are described below.
4916 : : *
4917 : : * If we aggregate the values 1.01 and 2 then the result will be 3.01.
4918 : : * If we are then asked to un-aggregate the 1.01 then we must fail as we
4919 : : * won't be able to tell what the new aggregated value's dscale should be.
4920 : : * We don't want to return 2.00 (dscale = 2), since the sum's dscale would
4921 : : * have been zero if we'd really aggregated only 2.
4922 : : *
4923 : : * Note: alternatively, we could count the number of inputs with each possible
4924 : : * dscale (up to some sane limit). Not yet clear if it's worth the trouble.
4925 : : */
4926 : : static bool
3655 4927 : 171 : do_numeric_discard(NumericAggState *state, Numeric newval)
4928 : : {
4929 : : NumericVar X;
4930 : : NumericVar X2;
4931 : : MemoryContext old_context;
4932 : :
4933 : : /* Count NaN/infinity inputs separately from all else */
1362 4934 [ + + ]: 171 : if (NUMERIC_IS_SPECIAL(newval))
4935 : : {
4936 [ - + ]: 3 : if (NUMERIC_IS_PINF(newval))
1362 tgl@sss.pgh.pa.us 4937 :UBC 0 : state->pInfcount--;
1362 tgl@sss.pgh.pa.us 4938 [ - + ]:CBC 3 : else if (NUMERIC_IS_NINF(newval))
1362 tgl@sss.pgh.pa.us 4939 :UBC 0 : state->nInfcount--;
4940 : : else
1362 tgl@sss.pgh.pa.us 4941 :CBC 3 : state->NaNcount--;
3655 4942 : 3 : return true;
4943 : : }
4944 : :
4945 : : /* load processed number in short-lived context */
4946 : 168 : init_var_from_num(newval, &X);
4947 : :
4948 : : /*
4949 : : * state->sumX's dscale is the maximum dscale of any of the inputs.
4950 : : * Removing the last input with that dscale would require us to recompute
4951 : : * the maximum dscale of the *remaining* inputs, which we cannot do unless
4952 : : * no more non-NaN inputs remain at all. So we report a failure instead,
4953 : : * and force the aggregation to be redone from scratch.
4954 : : */
4955 [ + - ]: 168 : if (X.dscale == state->maxScale)
4956 : : {
4957 [ + + + + ]: 168 : if (state->maxScaleCount > 1 || state->maxScale == 0)
4958 : : {
4959 : : /*
4960 : : * Some remaining inputs have same dscale, or dscale hasn't gotten
4961 : : * above zero anyway
4962 : : */
4963 : 159 : state->maxScaleCount--;
4964 : : }
4965 [ + + ]: 9 : else if (state->N == 1)
4966 : : {
4967 : : /* No remaining non-NaN inputs at all, so reset maxScale */
4968 : 6 : state->maxScale = 0;
4969 : 6 : state->maxScaleCount = 0;
4970 : : }
4971 : : else
4972 : : {
4973 : : /* Correct new maxScale is uncertain, must fail */
4974 : 3 : return false;
4975 : : }
4976 : : }
4977 : :
4978 : : /* if we need X^2, calculate that in short-lived context */
4979 [ + + ]: 165 : if (state->calcSumX2)
4980 : : {
4981 : 144 : init_var(&X2);
4982 : 144 : mul_var(&X, &X, &X2, X.dscale * 2);
4983 : : }
4984 : :
4985 : : /* The rest of this needs to work in the aggregate context */
4986 : 165 : old_context = MemoryContextSwitchTo(state->agg_context);
4987 : :
4988 [ + + ]: 165 : if (state->N-- > 1)
4989 : : {
4990 : : /* Negate X, to subtract it from the sum */
2781 heikki.linnakangas@i 4991 [ + - ]: 156 : X.sign = (X.sign == NUMERIC_POS ? NUMERIC_NEG : NUMERIC_POS);
4992 : 156 : accum_sum_add(&(state->sumX), &X);
4993 : :
3655 tgl@sss.pgh.pa.us 4994 [ + + ]: 156 : if (state->calcSumX2)
4995 : : {
4996 : : /* Negate X^2. X^2 is always positive */
2781 heikki.linnakangas@i 4997 : 144 : X2.sign = NUMERIC_NEG;
4998 : 144 : accum_sum_add(&(state->sumX2), &X2);
4999 : : }
5000 : : }
5001 : : else
5002 : : {
5003 : : /* Zero the sums */
3655 tgl@sss.pgh.pa.us 5004 [ - + ]: 9 : Assert(state->N == 0);
5005 : :
2781 heikki.linnakangas@i 5006 : 9 : accum_sum_reset(&state->sumX);
5007 [ - + ]: 9 : if (state->calcSumX2)
2781 heikki.linnakangas@i 5008 :UBC 0 : accum_sum_reset(&state->sumX2);
5009 : : }
5010 : :
3655 tgl@sss.pgh.pa.us 5011 :CBC 165 : MemoryContextSwitchTo(old_context);
5012 : :
5013 : 165 : return true;
5014 : : }
5015 : :
5016 : : /*
5017 : : * Generic transition function for numeric aggregates that require sumX2.
5018 : : */
5019 : : Datum
8672 5020 : 321 : numeric_accum(PG_FUNCTION_ARGS)
5021 : : {
5022 : : NumericAggState *state;
5023 : :
3802 5024 [ + + ]: 321 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5025 : :
5026 : : /* Create the state data on the first call */
3655 5027 [ + + ]: 321 : if (state == NULL)
5028 : 87 : state = makeNumericAggState(fcinfo, true);
5029 : :
5030 [ + + ]: 321 : if (!PG_ARGISNULL(1))
3802 5031 : 312 : do_numeric_accum(state, PG_GETARG_NUMERIC(1));
5032 : :
5033 : 321 : PG_RETURN_POINTER(state);
5034 : : }
5035 : :
5036 : : /*
5037 : : * Generic combine function for numeric aggregates which require sumX2
5038 : : */
5039 : : Datum
2931 rhaas@postgresql.org 5040 : 18 : numeric_combine(PG_FUNCTION_ARGS)
5041 : : {
5042 : : NumericAggState *state1;
5043 : : NumericAggState *state2;
5044 : : MemoryContext agg_context;
5045 : : MemoryContext old_context;
5046 : :
5047 [ - + ]: 18 : if (!AggCheckCallContext(fcinfo, &agg_context))
2931 rhaas@postgresql.org 5048 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5049 : :
2931 rhaas@postgresql.org 5050 [ + + ]:CBC 18 : state1 = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5051 [ + - ]: 18 : state2 = PG_ARGISNULL(1) ? NULL : (NumericAggState *) PG_GETARG_POINTER(1);
5052 : :
5053 [ - + ]: 18 : if (state2 == NULL)
2931 rhaas@postgresql.org 5054 :UBC 0 : PG_RETURN_POINTER(state1);
5055 : :
5056 : : /* manually copy all fields from state2 to state1 */
2931 rhaas@postgresql.org 5057 [ + + ]:CBC 18 : if (state1 == NULL)
5058 : : {
5059 : 9 : old_context = MemoryContextSwitchTo(agg_context);
5060 : :
2852 tgl@sss.pgh.pa.us 5061 : 9 : state1 = makeNumericAggStateCurrentContext(true);
2931 rhaas@postgresql.org 5062 : 9 : state1->N = state2->N;
5063 : 9 : state1->NaNcount = state2->NaNcount;
1362 tgl@sss.pgh.pa.us 5064 : 9 : state1->pInfcount = state2->pInfcount;
5065 : 9 : state1->nInfcount = state2->nInfcount;
2931 rhaas@postgresql.org 5066 : 9 : state1->maxScale = state2->maxScale;
5067 : 9 : state1->maxScaleCount = state2->maxScaleCount;
5068 : :
2781 heikki.linnakangas@i 5069 : 9 : accum_sum_copy(&state1->sumX, &state2->sumX);
5070 : 9 : accum_sum_copy(&state1->sumX2, &state2->sumX2);
5071 : :
2931 rhaas@postgresql.org 5072 : 9 : MemoryContextSwitchTo(old_context);
5073 : :
5074 : 9 : PG_RETURN_POINTER(state1);
5075 : : }
5076 : :
1403 tgl@sss.pgh.pa.us 5077 : 9 : state1->N += state2->N;
5078 : 9 : state1->NaNcount += state2->NaNcount;
1362 5079 : 9 : state1->pInfcount += state2->pInfcount;
5080 : 9 : state1->nInfcount += state2->nInfcount;
5081 : :
2931 rhaas@postgresql.org 5082 [ + - ]: 9 : if (state2->N > 0)
5083 : : {
5084 : : /*
5085 : : * These are currently only needed for moving aggregates, but let's do
5086 : : * the right thing anyway...
5087 : : */
5088 [ - + ]: 9 : if (state2->maxScale > state1->maxScale)
5089 : : {
2931 rhaas@postgresql.org 5090 :UBC 0 : state1->maxScale = state2->maxScale;
5091 : 0 : state1->maxScaleCount = state2->maxScaleCount;
5092 : : }
2931 rhaas@postgresql.org 5093 [ + - ]:CBC 9 : else if (state2->maxScale == state1->maxScale)
5094 : 9 : state1->maxScaleCount += state2->maxScaleCount;
5095 : :
5096 : : /* The rest of this needs to work in the aggregate context */
5097 : 9 : old_context = MemoryContextSwitchTo(agg_context);
5098 : :
5099 : : /* Accumulate sums */
2781 heikki.linnakangas@i 5100 : 9 : accum_sum_combine(&state1->sumX, &state2->sumX);
5101 : 9 : accum_sum_combine(&state1->sumX2, &state2->sumX2);
5102 : :
2931 rhaas@postgresql.org 5103 : 9 : MemoryContextSwitchTo(old_context);
5104 : : }
5105 : 9 : PG_RETURN_POINTER(state1);
5106 : : }
5107 : :
5108 : : /*
5109 : : * Generic transition function for numeric aggregates that don't require sumX2.
5110 : : */
5111 : : Datum
6266 bruce@momjian.us 5112 : 936404 : numeric_avg_accum(PG_FUNCTION_ARGS)
5113 : : {
5114 : : NumericAggState *state;
5115 : :
3802 tgl@sss.pgh.pa.us 5116 [ + + ]: 936404 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5117 : :
5118 : : /* Create the state data on the first call */
3655 5119 [ + + ]: 936404 : if (state == NULL)
5120 : 85453 : state = makeNumericAggState(fcinfo, false);
5121 : :
5122 [ + + ]: 936404 : if (!PG_ARGISNULL(1))
3802 5123 : 936374 : do_numeric_accum(state, PG_GETARG_NUMERIC(1));
5124 : :
3655 5125 : 936404 : PG_RETURN_POINTER(state);
5126 : : }
5127 : :
5128 : : /*
5129 : : * Combine function for numeric aggregates which don't require sumX2
5130 : : */
5131 : : Datum
2931 rhaas@postgresql.org 5132 : 12 : numeric_avg_combine(PG_FUNCTION_ARGS)
5133 : : {
5134 : : NumericAggState *state1;
5135 : : NumericAggState *state2;
5136 : : MemoryContext agg_context;
5137 : : MemoryContext old_context;
5138 : :
5139 [ - + ]: 12 : if (!AggCheckCallContext(fcinfo, &agg_context))
2931 rhaas@postgresql.org 5140 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5141 : :
2931 rhaas@postgresql.org 5142 [ + + ]:CBC 12 : state1 = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5143 [ + - ]: 12 : state2 = PG_ARGISNULL(1) ? NULL : (NumericAggState *) PG_GETARG_POINTER(1);
5144 : :
5145 [ - + ]: 12 : if (state2 == NULL)
2931 rhaas@postgresql.org 5146 :UBC 0 : PG_RETURN_POINTER(state1);
5147 : :
5148 : : /* manually copy all fields from state2 to state1 */
2931 rhaas@postgresql.org 5149 [ + + ]:CBC 12 : if (state1 == NULL)
5150 : : {
5151 : 3 : old_context = MemoryContextSwitchTo(agg_context);
5152 : :
2852 tgl@sss.pgh.pa.us 5153 : 3 : state1 = makeNumericAggStateCurrentContext(false);
2931 rhaas@postgresql.org 5154 : 3 : state1->N = state2->N;
5155 : 3 : state1->NaNcount = state2->NaNcount;
1362 tgl@sss.pgh.pa.us 5156 : 3 : state1->pInfcount = state2->pInfcount;
5157 : 3 : state1->nInfcount = state2->nInfcount;
2931 rhaas@postgresql.org 5158 : 3 : state1->maxScale = state2->maxScale;
5159 : 3 : state1->maxScaleCount = state2->maxScaleCount;
5160 : :
2781 heikki.linnakangas@i 5161 : 3 : accum_sum_copy(&state1->sumX, &state2->sumX);
5162 : :
2931 rhaas@postgresql.org 5163 : 3 : MemoryContextSwitchTo(old_context);
5164 : :
5165 : 3 : PG_RETURN_POINTER(state1);
5166 : : }
5167 : :
1403 tgl@sss.pgh.pa.us 5168 : 9 : state1->N += state2->N;
5169 : 9 : state1->NaNcount += state2->NaNcount;
1362 5170 : 9 : state1->pInfcount += state2->pInfcount;
5171 : 9 : state1->nInfcount += state2->nInfcount;
5172 : :
2931 rhaas@postgresql.org 5173 [ + - ]: 9 : if (state2->N > 0)
5174 : : {
5175 : : /*
5176 : : * These are currently only needed for moving aggregates, but let's do
5177 : : * the right thing anyway...
5178 : : */
5179 [ - + ]: 9 : if (state2->maxScale > state1->maxScale)
5180 : : {
2931 rhaas@postgresql.org 5181 :UBC 0 : state1->maxScale = state2->maxScale;
5182 : 0 : state1->maxScaleCount = state2->maxScaleCount;
5183 : : }
2931 rhaas@postgresql.org 5184 [ + - ]:CBC 9 : else if (state2->maxScale == state1->maxScale)
5185 : 9 : state1->maxScaleCount += state2->maxScaleCount;
5186 : :
5187 : : /* The rest of this needs to work in the aggregate context */
5188 : 9 : old_context = MemoryContextSwitchTo(agg_context);
5189 : :
5190 : : /* Accumulate sums */
2781 heikki.linnakangas@i 5191 : 9 : accum_sum_combine(&state1->sumX, &state2->sumX);
5192 : :
2931 rhaas@postgresql.org 5193 : 9 : MemoryContextSwitchTo(old_context);
5194 : : }
5195 : 9 : PG_RETURN_POINTER(state1);
5196 : : }
5197 : :
5198 : : /*
5199 : : * numeric_avg_serialize
5200 : : * Serialize NumericAggState for numeric aggregates that don't require
5201 : : * sumX2.
5202 : : */
5203 : : Datum
5204 : 12 : numeric_avg_serialize(PG_FUNCTION_ARGS)
5205 : : {
5206 : : NumericAggState *state;
5207 : : StringInfoData buf;
5208 : : bytea *result;
5209 : : NumericVar tmp_var;
5210 : :
5211 : : /* Ensure we disallow calling when not in aggregate context */
5212 [ - + ]: 12 : if (!AggCheckCallContext(fcinfo, NULL))
2931 rhaas@postgresql.org 5213 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5214 : :
2931 rhaas@postgresql.org 5215 :CBC 12 : state = (NumericAggState *) PG_GETARG_POINTER(0);
5216 : :
2781 heikki.linnakangas@i 5217 : 12 : init_var(&tmp_var);
5218 : :
2931 rhaas@postgresql.org 5219 : 12 : pq_begintypsend(&buf);
5220 : :
5221 : : /* N */
5222 : 12 : pq_sendint64(&buf, state->N);
5223 : :
5224 : : /* sumX */
1014 dean.a.rasheed@gmail 5225 : 12 : accum_sum_final(&state->sumX, &tmp_var);
5226 : 12 : numericvar_serialize(&buf, &tmp_var);
5227 : :
5228 : : /* maxScale */
2377 andres@anarazel.de 5229 : 12 : pq_sendint32(&buf, state->maxScale);
5230 : :
5231 : : /* maxScaleCount */
2931 rhaas@postgresql.org 5232 : 12 : pq_sendint64(&buf, state->maxScaleCount);
5233 : :
5234 : : /* NaNcount */
5235 : 12 : pq_sendint64(&buf, state->NaNcount);
5236 : :
5237 : : /* pInfcount */
1362 tgl@sss.pgh.pa.us 5238 : 12 : pq_sendint64(&buf, state->pInfcount);
5239 : :
5240 : : /* nInfcount */
5241 : 12 : pq_sendint64(&buf, state->nInfcount);
5242 : :
2931 rhaas@postgresql.org 5243 : 12 : result = pq_endtypsend(&buf);
5244 : :
1014 dean.a.rasheed@gmail 5245 : 12 : free_var(&tmp_var);
5246 : :
2931 rhaas@postgresql.org 5247 : 12 : PG_RETURN_BYTEA_P(result);
5248 : : }
5249 : :
5250 : : /*
5251 : : * numeric_avg_deserialize
5252 : : * Deserialize bytea into NumericAggState for numeric aggregates that
5253 : : * don't require sumX2.
5254 : : */
5255 : : Datum
5256 : 12 : numeric_avg_deserialize(PG_FUNCTION_ARGS)
5257 : : {
5258 : : bytea *sstate;
5259 : : NumericAggState *result;
5260 : : StringInfoData buf;
5261 : : NumericVar tmp_var;
5262 : :
5263 [ - + ]: 12 : if (!AggCheckCallContext(fcinfo, NULL))
2931 rhaas@postgresql.org 5264 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5265 : :
2590 noah@leadboat.com 5266 :CBC 12 : sstate = PG_GETARG_BYTEA_PP(0);
5267 : :
1014 dean.a.rasheed@gmail 5268 : 12 : init_var(&tmp_var);
5269 : :
5270 : : /*
5271 : : * Initialize a StringInfo so that we can "receive" it using the standard
5272 : : * recv-function infrastructure.
5273 : : */
170 drowley@postgresql.o 5274 [ + - ]:GNC 12 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
5275 [ - + - - : 12 : VARSIZE_ANY_EXHDR(sstate));
- - - - +
- ]
5276 : :
2852 tgl@sss.pgh.pa.us 5277 :CBC 12 : result = makeNumericAggStateCurrentContext(false);
5278 : :
5279 : : /* N */
2931 rhaas@postgresql.org 5280 : 12 : result->N = pq_getmsgint64(&buf);
5281 : :
5282 : : /* sumX */
1014 dean.a.rasheed@gmail 5283 : 12 : numericvar_deserialize(&buf, &tmp_var);
2781 heikki.linnakangas@i 5284 : 12 : accum_sum_add(&(result->sumX), &tmp_var);
5285 : :
5286 : : /* maxScale */
2931 rhaas@postgresql.org 5287 : 12 : result->maxScale = pq_getmsgint(&buf, 4);
5288 : :
5289 : : /* maxScaleCount */
5290 : 12 : result->maxScaleCount = pq_getmsgint64(&buf);
5291 : :
5292 : : /* NaNcount */
5293 : 12 : result->NaNcount = pq_getmsgint64(&buf);
5294 : :
5295 : : /* pInfcount */
1362 tgl@sss.pgh.pa.us 5296 : 12 : result->pInfcount = pq_getmsgint64(&buf);
5297 : :
5298 : : /* nInfcount */
5299 : 12 : result->nInfcount = pq_getmsgint64(&buf);
5300 : :
2931 rhaas@postgresql.org 5301 : 12 : pq_getmsgend(&buf);
5302 : :
1014 dean.a.rasheed@gmail 5303 : 12 : free_var(&tmp_var);
5304 : :
2931 rhaas@postgresql.org 5305 : 12 : PG_RETURN_POINTER(result);
5306 : : }
5307 : :
5308 : : /*
5309 : : * numeric_serialize
5310 : : * Serialization function for NumericAggState for numeric aggregates that
5311 : : * require sumX2.
5312 : : */
5313 : : Datum
5314 : 18 : numeric_serialize(PG_FUNCTION_ARGS)
5315 : : {
5316 : : NumericAggState *state;
5317 : : StringInfoData buf;
5318 : : bytea *result;
5319 : : NumericVar tmp_var;
5320 : :
5321 : : /* Ensure we disallow calling when not in aggregate context */
5322 [ - + ]: 18 : if (!AggCheckCallContext(fcinfo, NULL))
2931 rhaas@postgresql.org 5323 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5324 : :
2931 rhaas@postgresql.org 5325 :CBC 18 : state = (NumericAggState *) PG_GETARG_POINTER(0);
5326 : :
2781 heikki.linnakangas@i 5327 : 18 : init_var(&tmp_var);
5328 : :
2931 rhaas@postgresql.org 5329 : 18 : pq_begintypsend(&buf);
5330 : :
5331 : : /* N */
5332 : 18 : pq_sendint64(&buf, state->N);
5333 : :
5334 : : /* sumX */
1014 dean.a.rasheed@gmail 5335 : 18 : accum_sum_final(&state->sumX, &tmp_var);
5336 : 18 : numericvar_serialize(&buf, &tmp_var);
5337 : :
5338 : : /* sumX2 */
5339 : 18 : accum_sum_final(&state->sumX2, &tmp_var);
5340 : 18 : numericvar_serialize(&buf, &tmp_var);
5341 : :
5342 : : /* maxScale */
2377 andres@anarazel.de 5343 : 18 : pq_sendint32(&buf, state->maxScale);
5344 : :
5345 : : /* maxScaleCount */
2931 rhaas@postgresql.org 5346 : 18 : pq_sendint64(&buf, state->maxScaleCount);
5347 : :
5348 : : /* NaNcount */
5349 : 18 : pq_sendint64(&buf, state->NaNcount);
5350 : :
5351 : : /* pInfcount */
1362 tgl@sss.pgh.pa.us 5352 : 18 : pq_sendint64(&buf, state->pInfcount);
5353 : :
5354 : : /* nInfcount */
5355 : 18 : pq_sendint64(&buf, state->nInfcount);
5356 : :
2931 rhaas@postgresql.org 5357 : 18 : result = pq_endtypsend(&buf);
5358 : :
1014 dean.a.rasheed@gmail 5359 : 18 : free_var(&tmp_var);
5360 : :
2931 rhaas@postgresql.org 5361 : 18 : PG_RETURN_BYTEA_P(result);
5362 : : }
5363 : :
5364 : : /*
5365 : : * numeric_deserialize
5366 : : * Deserialization function for NumericAggState for numeric aggregates that
5367 : : * require sumX2.
5368 : : */
5369 : : Datum
5370 : 18 : numeric_deserialize(PG_FUNCTION_ARGS)
5371 : : {
5372 : : bytea *sstate;
5373 : : NumericAggState *result;
5374 : : StringInfoData buf;
5375 : : NumericVar tmp_var;
5376 : :
5377 [ - + ]: 18 : if (!AggCheckCallContext(fcinfo, NULL))
2931 rhaas@postgresql.org 5378 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5379 : :
2590 noah@leadboat.com 5380 :CBC 18 : sstate = PG_GETARG_BYTEA_PP(0);
5381 : :
1014 dean.a.rasheed@gmail 5382 : 18 : init_var(&tmp_var);
5383 : :
5384 : : /*
5385 : : * Initialize a StringInfo so that we can "receive" it using the standard
5386 : : * recv-function infrastructure.
5387 : : */
170 drowley@postgresql.o 5388 [ + + ]:GNC 18 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
5389 [ - + - - : 18 : VARSIZE_ANY_EXHDR(sstate));
- - - - +
+ ]
5390 : :
2852 tgl@sss.pgh.pa.us 5391 :CBC 18 : result = makeNumericAggStateCurrentContext(false);
5392 : :
5393 : : /* N */
2931 rhaas@postgresql.org 5394 : 18 : result->N = pq_getmsgint64(&buf);
5395 : :
5396 : : /* sumX */
1014 dean.a.rasheed@gmail 5397 : 18 : numericvar_deserialize(&buf, &tmp_var);
5398 : 18 : accum_sum_add(&(result->sumX), &tmp_var);
5399 : :
5400 : : /* sumX2 */
5401 : 18 : numericvar_deserialize(&buf, &tmp_var);
5402 : 18 : accum_sum_add(&(result->sumX2), &tmp_var);
5403 : :
5404 : : /* maxScale */
2931 rhaas@postgresql.org 5405 : 18 : result->maxScale = pq_getmsgint(&buf, 4);
5406 : :
5407 : : /* maxScaleCount */
5408 : 18 : result->maxScaleCount = pq_getmsgint64(&buf);
5409 : :
5410 : : /* NaNcount */
5411 : 18 : result->NaNcount = pq_getmsgint64(&buf);
5412 : :
5413 : : /* pInfcount */
1362 tgl@sss.pgh.pa.us 5414 : 18 : result->pInfcount = pq_getmsgint64(&buf);
5415 : :
5416 : : /* nInfcount */
5417 : 18 : result->nInfcount = pq_getmsgint64(&buf);
5418 : :
2931 rhaas@postgresql.org 5419 : 18 : pq_getmsgend(&buf);
5420 : :
1014 dean.a.rasheed@gmail 5421 : 18 : free_var(&tmp_var);
5422 : :
2931 rhaas@postgresql.org 5423 : 18 : PG_RETURN_POINTER(result);
5424 : : }
5425 : :
5426 : : /*
5427 : : * Generic inverse transition function for numeric aggregates
5428 : : * (with or without requirement for X^2).
5429 : : */
5430 : : Datum
3655 tgl@sss.pgh.pa.us 5431 : 114 : numeric_accum_inv(PG_FUNCTION_ARGS)
5432 : : {
5433 : : NumericAggState *state;
5434 : :
5435 [ + - ]: 114 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5436 : :
5437 : : /* Should not get here with no state */
5438 [ - + ]: 114 : if (state == NULL)
3655 tgl@sss.pgh.pa.us 5439 [ # # ]:UBC 0 : elog(ERROR, "numeric_accum_inv called with NULL state");
5440 : :
3655 tgl@sss.pgh.pa.us 5441 [ + + ]:CBC 114 : if (!PG_ARGISNULL(1))
5442 : : {
5443 : : /* If we fail to perform the inverse transition, return NULL */
5444 [ + + ]: 99 : if (!do_numeric_discard(state, PG_GETARG_NUMERIC(1)))
5445 : 3 : PG_RETURN_NULL();
5446 : : }
5447 : :
3802 5448 : 111 : PG_RETURN_POINTER(state);
5449 : : }
5450 : :
5451 : :
5452 : : /*
5453 : : * Integer data types in general use Numeric accumulators to share code
5454 : : * and avoid risk of overflow.
5455 : : *
5456 : : * However for performance reasons optimized special-purpose accumulator
5457 : : * routines are used when possible.
5458 : : *
5459 : : * On platforms with 128-bit integer support, the 128-bit routines will be
5460 : : * used when sum(X) or sum(X*X) fit into 128-bit.
5461 : : *
5462 : : * For 16 and 32 bit inputs, the N and sum(X) fit into 64-bit so the 64-bit
5463 : : * accumulators will be used for SUM and AVG of these data types.
5464 : : */
5465 : :
5466 : : #ifdef HAVE_INT128
5467 : : typedef struct Int128AggState
5468 : : {
5469 : : bool calcSumX2; /* if true, calculate sumX2 */
5470 : : int64 N; /* count of processed numbers */
5471 : : int128 sumX; /* sum of processed numbers */
5472 : : int128 sumX2; /* sum of squares of processed numbers */
5473 : : } Int128AggState;
5474 : :
5475 : : /*
5476 : : * Prepare state data for a 128-bit aggregate function that needs to compute
5477 : : * sum, count and optionally sum of squares of the input.
5478 : : */
5479 : : static Int128AggState *
3313 andres@anarazel.de 5480 : 360 : makeInt128AggState(FunctionCallInfo fcinfo, bool calcSumX2)
5481 : : {
5482 : : Int128AggState *state;
5483 : : MemoryContext agg_context;
5484 : : MemoryContext old_context;
5485 : :
5486 [ - + ]: 360 : if (!AggCheckCallContext(fcinfo, &agg_context))
3313 andres@anarazel.de 5487 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5488 : :
3313 andres@anarazel.de 5489 :CBC 360 : old_context = MemoryContextSwitchTo(agg_context);
5490 : :
5491 : 360 : state = (Int128AggState *) palloc0(sizeof(Int128AggState));
5492 : 360 : state->calcSumX2 = calcSumX2;
5493 : :
5494 : 360 : MemoryContextSwitchTo(old_context);
5495 : :
5496 : 360 : return state;
5497 : : }
5498 : :
5499 : : /*
5500 : : * Like makeInt128AggState(), but allocate the state in the current memory
5501 : : * context.
5502 : : */
5503 : : static Int128AggState *
2852 tgl@sss.pgh.pa.us 5504 : 39 : makeInt128AggStateCurrentContext(bool calcSumX2)
5505 : : {
5506 : : Int128AggState *state;
5507 : :
5508 : 39 : state = (Int128AggState *) palloc0(sizeof(Int128AggState));
5509 : 39 : state->calcSumX2 = calcSumX2;
5510 : :
5511 : 39 : return state;
5512 : : }
5513 : :
5514 : : /*
5515 : : * Accumulate a new input value for 128-bit aggregate functions.
5516 : : */
5517 : : static void
3313 andres@anarazel.de 5518 : 276769 : do_int128_accum(Int128AggState *state, int128 newval)
5519 : : {
5520 [ + + ]: 276769 : if (state->calcSumX2)
5521 : 121180 : state->sumX2 += newval * newval;
5522 : :
5523 : 276769 : state->sumX += newval;
5524 : 276769 : state->N++;
5525 : 276769 : }
5526 : :
5527 : : /*
5528 : : * Remove an input value from the aggregated state.
5529 : : */
5530 : : static void
5531 : 156 : do_int128_discard(Int128AggState *state, int128 newval)
5532 : : {
5533 [ + + ]: 156 : if (state->calcSumX2)
5534 : 144 : state->sumX2 -= newval * newval;
5535 : :
5536 : 156 : state->sumX -= newval;
5537 : 156 : state->N--;
5538 : 156 : }
5539 : :
5540 : : typedef Int128AggState PolyNumAggState;
5541 : : #define makePolyNumAggState makeInt128AggState
5542 : : #define makePolyNumAggStateCurrentContext makeInt128AggStateCurrentContext
5543 : : #else
5544 : : typedef NumericAggState PolyNumAggState;
5545 : : #define makePolyNumAggState makeNumericAggState
5546 : : #define makePolyNumAggStateCurrentContext makeNumericAggStateCurrentContext
5547 : : #endif
5548 : :
5549 : : Datum
8672 tgl@sss.pgh.pa.us 5550 : 99 : int2_accum(PG_FUNCTION_ARGS)
5551 : : {
5552 : : PolyNumAggState *state;
5553 : :
3313 andres@anarazel.de 5554 [ + + ]: 99 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5555 : :
5556 : : /* Create the state data on the first call */
3655 tgl@sss.pgh.pa.us 5557 [ + + ]: 99 : if (state == NULL)
3313 andres@anarazel.de 5558 : 18 : state = makePolyNumAggState(fcinfo, true);
5559 : :
3802 tgl@sss.pgh.pa.us 5560 [ + + ]: 99 : if (!PG_ARGISNULL(1))
5561 : : {
5562 : : #ifdef HAVE_INT128
3311 andres@anarazel.de 5563 : 90 : do_int128_accum(state, (int128) PG_GETARG_INT16(1));
5564 : : #else
5565 : : do_numeric_accum(state, int64_to_numeric(PG_GETARG_INT16(1)));
5566 : : #endif
5567 : : }
5568 : :
3802 tgl@sss.pgh.pa.us 5569 : 99 : PG_RETURN_POINTER(state);
5570 : : }
5571 : :
5572 : : Datum
8672 5573 : 121099 : int4_accum(PG_FUNCTION_ARGS)
5574 : : {
5575 : : PolyNumAggState *state;
5576 : :
3313 andres@anarazel.de 5577 [ + + ]: 121099 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5578 : :
5579 : : /* Create the state data on the first call */
3655 tgl@sss.pgh.pa.us 5580 [ + + ]: 121099 : if (state == NULL)
3313 andres@anarazel.de 5581 : 40 : state = makePolyNumAggState(fcinfo, true);
5582 : :
3802 tgl@sss.pgh.pa.us 5583 [ + + ]: 121099 : if (!PG_ARGISNULL(1))
5584 : : {
5585 : : #ifdef HAVE_INT128
3313 andres@anarazel.de 5586 : 121090 : do_int128_accum(state, (int128) PG_GETARG_INT32(1));
5587 : : #else
5588 : : do_numeric_accum(state, int64_to_numeric(PG_GETARG_INT32(1)));
5589 : : #endif
5590 : : }
5591 : :
3802 tgl@sss.pgh.pa.us 5592 : 121099 : PG_RETURN_POINTER(state);
5593 : : }
5594 : :
5595 : : Datum
8672 5596 : 120099 : int8_accum(PG_FUNCTION_ARGS)
5597 : : {
5598 : : NumericAggState *state;
5599 : :
3802 5600 [ + + ]: 120099 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5601 : :
5602 : : /* Create the state data on the first call */
3655 5603 [ + + ]: 120099 : if (state == NULL)
5604 : 30 : state = makeNumericAggState(fcinfo, true);
5605 : :
3802 5606 [ + + ]: 120099 : if (!PG_ARGISNULL(1))
1313 peter@eisentraut.org 5607 : 120090 : do_numeric_accum(state, int64_to_numeric(PG_GETARG_INT64(1)));
5608 : :
3802 tgl@sss.pgh.pa.us 5609 : 120099 : PG_RETURN_POINTER(state);
5610 : : }
5611 : :
5612 : : /*
5613 : : * Combine function for numeric aggregates which require sumX2
5614 : : */
5615 : : Datum
2931 rhaas@postgresql.org 5616 : 12 : numeric_poly_combine(PG_FUNCTION_ARGS)
5617 : : {
5618 : : PolyNumAggState *state1;
5619 : : PolyNumAggState *state2;
5620 : : MemoryContext agg_context;
5621 : : MemoryContext old_context;
5622 : :
5623 [ - + ]: 12 : if (!AggCheckCallContext(fcinfo, &agg_context))
2931 rhaas@postgresql.org 5624 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5625 : :
2931 rhaas@postgresql.org 5626 [ + + ]:CBC 12 : state1 = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5627 [ + - ]: 12 : state2 = PG_ARGISNULL(1) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(1);
5628 : :
5629 [ - + ]: 12 : if (state2 == NULL)
2931 rhaas@postgresql.org 5630 :UBC 0 : PG_RETURN_POINTER(state1);
5631 : :
5632 : : /* manually copy all fields from state2 to state1 */
2931 rhaas@postgresql.org 5633 [ + + ]:CBC 12 : if (state1 == NULL)
5634 : : {
5635 : 3 : old_context = MemoryContextSwitchTo(agg_context);
5636 : :
5637 : 3 : state1 = makePolyNumAggState(fcinfo, true);
5638 : 3 : state1->N = state2->N;
5639 : :
5640 : : #ifdef HAVE_INT128
5641 : 3 : state1->sumX = state2->sumX;
5642 : 3 : state1->sumX2 = state2->sumX2;
5643 : : #else
5644 : : accum_sum_copy(&state1->sumX, &state2->sumX);
5645 : : accum_sum_copy(&state1->sumX2, &state2->sumX2);
5646 : : #endif
5647 : :
5648 : 3 : MemoryContextSwitchTo(old_context);
5649 : :
5650 : 3 : PG_RETURN_POINTER(state1);
5651 : : }
5652 : :
5653 [ + - ]: 9 : if (state2->N > 0)
5654 : : {
5655 : 9 : state1->N += state2->N;
5656 : :
5657 : : #ifdef HAVE_INT128
5658 : 9 : state1->sumX += state2->sumX;
5659 : 9 : state1->sumX2 += state2->sumX2;
5660 : : #else
5661 : : /* The rest of this needs to work in the aggregate context */
5662 : : old_context = MemoryContextSwitchTo(agg_context);
5663 : :
5664 : : /* Accumulate sums */
5665 : : accum_sum_combine(&state1->sumX, &state2->sumX);
5666 : : accum_sum_combine(&state1->sumX2, &state2->sumX2);
5667 : :
5668 : : MemoryContextSwitchTo(old_context);
5669 : : #endif
5670 : :
5671 : : }
5672 : 9 : PG_RETURN_POINTER(state1);
5673 : : }
5674 : :
5675 : : /*
5676 : : * numeric_poly_serialize
5677 : : * Serialize PolyNumAggState into bytea for aggregate functions which
5678 : : * require sumX2.
5679 : : */
5680 : : Datum
5681 : 12 : numeric_poly_serialize(PG_FUNCTION_ARGS)
5682 : : {
5683 : : PolyNumAggState *state;
5684 : : StringInfoData buf;
5685 : : bytea *result;
5686 : : NumericVar tmp_var;
5687 : :
5688 : : /* Ensure we disallow calling when not in aggregate context */
5689 [ - + ]: 12 : if (!AggCheckCallContext(fcinfo, NULL))
2931 rhaas@postgresql.org 5690 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5691 : :
2931 rhaas@postgresql.org 5692 :CBC 12 : state = (PolyNumAggState *) PG_GETARG_POINTER(0);
5693 : :
5694 : : /*
5695 : : * If the platform supports int128 then sumX and sumX2 will be a 128 bit
5696 : : * integer type. Here we'll convert that into a numeric type so that the
5697 : : * combine state is in the same format for both int128 enabled machines
5698 : : * and machines which don't support that type. The logic here is that one
5699 : : * day we might like to send these over to another server for further
5700 : : * processing and we want a standard format to work with.
5701 : : */
5702 : :
1014 dean.a.rasheed@gmail 5703 : 12 : init_var(&tmp_var);
5704 : :
2931 rhaas@postgresql.org 5705 : 12 : pq_begintypsend(&buf);
5706 : :
5707 : : /* N */
5708 : 12 : pq_sendint64(&buf, state->N);
5709 : :
5710 : : /* sumX */
5711 : : #ifdef HAVE_INT128
1014 dean.a.rasheed@gmail 5712 : 12 : int128_to_numericvar(state->sumX, &tmp_var);
5713 : : #else
5714 : : accum_sum_final(&state->sumX, &tmp_var);
5715 : : #endif
5716 : 12 : numericvar_serialize(&buf, &tmp_var);
5717 : :
5718 : : /* sumX2 */
5719 : : #ifdef HAVE_INT128
5720 : 12 : int128_to_numericvar(state->sumX2, &tmp_var);
5721 : : #else
5722 : : accum_sum_final(&state->sumX2, &tmp_var);
5723 : : #endif
5724 : 12 : numericvar_serialize(&buf, &tmp_var);
5725 : :
2931 rhaas@postgresql.org 5726 : 12 : result = pq_endtypsend(&buf);
5727 : :
1014 dean.a.rasheed@gmail 5728 : 12 : free_var(&tmp_var);
5729 : :
2931 rhaas@postgresql.org 5730 : 12 : PG_RETURN_BYTEA_P(result);
5731 : : }
5732 : :
5733 : : /*
5734 : : * numeric_poly_deserialize
5735 : : * Deserialize PolyNumAggState from bytea for aggregate functions which
5736 : : * require sumX2.
5737 : : */
5738 : : Datum
5739 : 12 : numeric_poly_deserialize(PG_FUNCTION_ARGS)
5740 : : {
5741 : : bytea *sstate;
5742 : : PolyNumAggState *result;
5743 : : StringInfoData buf;
5744 : : NumericVar tmp_var;
5745 : :
5746 [ - + ]: 12 : if (!AggCheckCallContext(fcinfo, NULL))
2931 rhaas@postgresql.org 5747 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5748 : :
2590 noah@leadboat.com 5749 :CBC 12 : sstate = PG_GETARG_BYTEA_PP(0);
5750 : :
1014 dean.a.rasheed@gmail 5751 : 12 : init_var(&tmp_var);
5752 : :
5753 : : /*
5754 : : * Initialize a StringInfo so that we can "receive" it using the standard
5755 : : * recv-function infrastructure.
5756 : : */
170 drowley@postgresql.o 5757 [ + - ]:GNC 12 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
5758 [ - + - - : 12 : VARSIZE_ANY_EXHDR(sstate));
- - - - +
- ]
5759 : :
2852 tgl@sss.pgh.pa.us 5760 :CBC 12 : result = makePolyNumAggStateCurrentContext(false);
5761 : :
5762 : : /* N */
2931 rhaas@postgresql.org 5763 : 12 : result->N = pq_getmsgint64(&buf);
5764 : :
5765 : : /* sumX */
1014 dean.a.rasheed@gmail 5766 : 12 : numericvar_deserialize(&buf, &tmp_var);
5767 : : #ifdef HAVE_INT128
5768 : 12 : numericvar_to_int128(&tmp_var, &result->sumX);
5769 : : #else
5770 : : accum_sum_add(&result->sumX, &tmp_var);
5771 : : #endif
5772 : :
5773 : : /* sumX2 */
5774 : 12 : numericvar_deserialize(&buf, &tmp_var);
5775 : : #ifdef HAVE_INT128
5776 : 12 : numericvar_to_int128(&tmp_var, &result->sumX2);
5777 : : #else
5778 : : accum_sum_add(&result->sumX2, &tmp_var);
5779 : : #endif
5780 : :
2931 rhaas@postgresql.org 5781 : 12 : pq_getmsgend(&buf);
5782 : :
1014 dean.a.rasheed@gmail 5783 : 12 : free_var(&tmp_var);
5784 : :
2931 rhaas@postgresql.org 5785 : 12 : PG_RETURN_POINTER(result);
5786 : : }
5787 : :
5788 : : /*
5789 : : * Transition function for int8 input when we don't need sumX2.
5790 : : */
5791 : : Datum
6266 bruce@momjian.us 5792 : 156147 : int8_avg_accum(PG_FUNCTION_ARGS)
5793 : : {
5794 : : PolyNumAggState *state;
5795 : :
3313 andres@anarazel.de 5796 [ + + ]: 156147 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5797 : :
5798 : : /* Create the state data on the first call */
3655 tgl@sss.pgh.pa.us 5799 [ + + ]: 156147 : if (state == NULL)
3313 andres@anarazel.de 5800 : 293 : state = makePolyNumAggState(fcinfo, false);
5801 : :
3802 tgl@sss.pgh.pa.us 5802 [ + + ]: 156147 : if (!PG_ARGISNULL(1))
5803 : : {
5804 : : #ifdef HAVE_INT128
3313 andres@anarazel.de 5805 : 155589 : do_int128_accum(state, (int128) PG_GETARG_INT64(1));
5806 : : #else
5807 : : do_numeric_accum(state, int64_to_numeric(PG_GETARG_INT64(1)));
5808 : : #endif
5809 : : }
5810 : :
3655 tgl@sss.pgh.pa.us 5811 : 156147 : PG_RETURN_POINTER(state);
5812 : : }
5813 : :
5814 : : /*
5815 : : * Combine function for PolyNumAggState for aggregates which don't require
5816 : : * sumX2
5817 : : */
5818 : : Datum
2931 rhaas@postgresql.org 5819 : 27 : int8_avg_combine(PG_FUNCTION_ARGS)
5820 : : {
5821 : : PolyNumAggState *state1;
5822 : : PolyNumAggState *state2;
5823 : : MemoryContext agg_context;
5824 : : MemoryContext old_context;
5825 : :
5826 [ - + ]: 27 : if (!AggCheckCallContext(fcinfo, &agg_context))
2931 rhaas@postgresql.org 5827 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5828 : :
2931 rhaas@postgresql.org 5829 [ + + ]:CBC 27 : state1 = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5830 [ + - ]: 27 : state2 = PG_ARGISNULL(1) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(1);
5831 : :
5832 [ - + ]: 27 : if (state2 == NULL)
2931 rhaas@postgresql.org 5833 :UBC 0 : PG_RETURN_POINTER(state1);
5834 : :
5835 : : /* manually copy all fields from state2 to state1 */
2931 rhaas@postgresql.org 5836 [ + + ]:CBC 27 : if (state1 == NULL)
5837 : : {
5838 : 6 : old_context = MemoryContextSwitchTo(agg_context);
5839 : :
5840 : 6 : state1 = makePolyNumAggState(fcinfo, false);
5841 : 6 : state1->N = state2->N;
5842 : :
5843 : : #ifdef HAVE_INT128
5844 : 6 : state1->sumX = state2->sumX;
5845 : : #else
5846 : : accum_sum_copy(&state1->sumX, &state2->sumX);
5847 : : #endif
5848 : 6 : MemoryContextSwitchTo(old_context);
5849 : :
5850 : 6 : PG_RETURN_POINTER(state1);
5851 : : }
5852 : :
5853 [ + - ]: 21 : if (state2->N > 0)
5854 : : {
5855 : 21 : state1->N += state2->N;
5856 : :
5857 : : #ifdef HAVE_INT128
5858 : 21 : state1->sumX += state2->sumX;
5859 : : #else
5860 : : /* The rest of this needs to work in the aggregate context */
5861 : : old_context = MemoryContextSwitchTo(agg_context);
5862 : :
5863 : : /* Accumulate sums */
5864 : : accum_sum_combine(&state1->sumX, &state2->sumX);
5865 : :
5866 : : MemoryContextSwitchTo(old_context);
5867 : : #endif
5868 : :
5869 : : }
5870 : 21 : PG_RETURN_POINTER(state1);
5871 : : }
5872 : :
5873 : : /*
5874 : : * int8_avg_serialize
5875 : : * Serialize PolyNumAggState into bytea using the standard
5876 : : * recv-function infrastructure.
5877 : : */
5878 : : Datum
5879 : 27 : int8_avg_serialize(PG_FUNCTION_ARGS)
5880 : : {
5881 : : PolyNumAggState *state;
5882 : : StringInfoData buf;
5883 : : bytea *result;
5884 : : NumericVar tmp_var;
5885 : :
5886 : : /* Ensure we disallow calling when not in aggregate context */
5887 [ - + ]: 27 : if (!AggCheckCallContext(fcinfo, NULL))
2931 rhaas@postgresql.org 5888 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5889 : :
2931 rhaas@postgresql.org 5890 :CBC 27 : state = (PolyNumAggState *) PG_GETARG_POINTER(0);
5891 : :
5892 : : /*
5893 : : * If the platform supports int128 then sumX will be a 128 integer type.
5894 : : * Here we'll convert that into a numeric type so that the combine state
5895 : : * is in the same format for both int128 enabled machines and machines
5896 : : * which don't support that type. The logic here is that one day we might
5897 : : * like to send these over to another server for further processing and we
5898 : : * want a standard format to work with.
5899 : : */
5900 : :
1014 dean.a.rasheed@gmail 5901 : 27 : init_var(&tmp_var);
5902 : :
2931 rhaas@postgresql.org 5903 : 27 : pq_begintypsend(&buf);
5904 : :
5905 : : /* N */
5906 : 27 : pq_sendint64(&buf, state->N);
5907 : :
5908 : : /* sumX */
5909 : : #ifdef HAVE_INT128
1014 dean.a.rasheed@gmail 5910 : 27 : int128_to_numericvar(state->sumX, &tmp_var);
5911 : : #else
5912 : : accum_sum_final(&state->sumX, &tmp_var);
5913 : : #endif
5914 : 27 : numericvar_serialize(&buf, &tmp_var);
5915 : :
2931 rhaas@postgresql.org 5916 : 27 : result = pq_endtypsend(&buf);
5917 : :
1014 dean.a.rasheed@gmail 5918 : 27 : free_var(&tmp_var);
5919 : :
2931 rhaas@postgresql.org 5920 : 27 : PG_RETURN_BYTEA_P(result);
5921 : : }
5922 : :
5923 : : /*
5924 : : * int8_avg_deserialize
5925 : : * Deserialize bytea back into PolyNumAggState.
5926 : : */
5927 : : Datum
5928 : 27 : int8_avg_deserialize(PG_FUNCTION_ARGS)
5929 : : {
5930 : : bytea *sstate;
5931 : : PolyNumAggState *result;
5932 : : StringInfoData buf;
5933 : : NumericVar tmp_var;
5934 : :
5935 [ - + ]: 27 : if (!AggCheckCallContext(fcinfo, NULL))
2931 rhaas@postgresql.org 5936 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5937 : :
2590 noah@leadboat.com 5938 :CBC 27 : sstate = PG_GETARG_BYTEA_PP(0);
5939 : :
1014 dean.a.rasheed@gmail 5940 : 27 : init_var(&tmp_var);
5941 : :
5942 : : /*
5943 : : * Initialize a StringInfo so that we can "receive" it using the standard
5944 : : * recv-function infrastructure.
5945 : : */
170 drowley@postgresql.o 5946 [ + - ]:GNC 27 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
5947 [ - + - - : 27 : VARSIZE_ANY_EXHDR(sstate));
- - - - +
- ]
5948 : :
2852 tgl@sss.pgh.pa.us 5949 :CBC 27 : result = makePolyNumAggStateCurrentContext(false);
5950 : :
5951 : : /* N */
2931 rhaas@postgresql.org 5952 : 27 : result->N = pq_getmsgint64(&buf);
5953 : :
5954 : : /* sumX */
1014 dean.a.rasheed@gmail 5955 : 27 : numericvar_deserialize(&buf, &tmp_var);
5956 : : #ifdef HAVE_INT128
5957 : 27 : numericvar_to_int128(&tmp_var, &result->sumX);
5958 : : #else
5959 : : accum_sum_add(&result->sumX, &tmp_var);
5960 : : #endif
5961 : :
2931 rhaas@postgresql.org 5962 : 27 : pq_getmsgend(&buf);
5963 : :
1014 dean.a.rasheed@gmail 5964 : 27 : free_var(&tmp_var);
5965 : :
2931 rhaas@postgresql.org 5966 : 27 : PG_RETURN_POINTER(result);
5967 : : }
5968 : :
5969 : : /*
5970 : : * Inverse transition functions to go with the above.
5971 : : */
5972 : :
5973 : : Datum
3655 tgl@sss.pgh.pa.us 5974 : 81 : int2_accum_inv(PG_FUNCTION_ARGS)
5975 : : {
5976 : : PolyNumAggState *state;
5977 : :
3313 andres@anarazel.de 5978 [ + - ]: 81 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5979 : :
5980 : : /* Should not get here with no state */
3655 tgl@sss.pgh.pa.us 5981 [ - + ]: 81 : if (state == NULL)
3655 tgl@sss.pgh.pa.us 5982 [ # # ]:UBC 0 : elog(ERROR, "int2_accum_inv called with NULL state");
5983 : :
3655 tgl@sss.pgh.pa.us 5984 [ + + ]:CBC 81 : if (!PG_ARGISNULL(1))
5985 : : {
5986 : : #ifdef HAVE_INT128
3313 andres@anarazel.de 5987 : 72 : do_int128_discard(state, (int128) PG_GETARG_INT16(1));
5988 : : #else
5989 : : /* Should never fail, all inputs have dscale 0 */
5990 : : if (!do_numeric_discard(state, int64_to_numeric(PG_GETARG_INT16(1))))
5991 : : elog(ERROR, "do_numeric_discard failed unexpectedly");
5992 : : #endif
5993 : : }
5994 : :
3802 tgl@sss.pgh.pa.us 5995 : 81 : PG_RETURN_POINTER(state);
5996 : : }
5997 : :
5998 : : Datum
3655 5999 : 81 : int4_accum_inv(PG_FUNCTION_ARGS)
6000 : : {
6001 : : PolyNumAggState *state;
6002 : :
3313 andres@anarazel.de 6003 [ + - ]: 81 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
6004 : :
6005 : : /* Should not get here with no state */
3655 tgl@sss.pgh.pa.us 6006 [ - + ]: 81 : if (state == NULL)
3655 tgl@sss.pgh.pa.us 6007 [ # # ]:UBC 0 : elog(ERROR, "int4_accum_inv called with NULL state");
6008 : :
3655 tgl@sss.pgh.pa.us 6009 [ + + ]:CBC 81 : if (!PG_ARGISNULL(1))
6010 : : {
6011 : : #ifdef HAVE_INT128
3313 andres@anarazel.de 6012 : 72 : do_int128_discard(state, (int128) PG_GETARG_INT32(1));
6013 : : #else
6014 : : /* Should never fail, all inputs have dscale 0 */
6015 : : if (!do_numeric_discard(state, int64_to_numeric(PG_GETARG_INT32(1))))
6016 : : elog(ERROR, "do_numeric_discard failed unexpectedly");
6017 : : #endif
6018 : : }
6019 : :
3655 tgl@sss.pgh.pa.us 6020 : 81 : PG_RETURN_POINTER(state);
6021 : : }
6022 : :
6023 : : Datum
6024 : 81 : int8_accum_inv(PG_FUNCTION_ARGS)
6025 : : {
6026 : : NumericAggState *state;
6027 : :
6028 [ + - ]: 81 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6029 : :
6030 : : /* Should not get here with no state */
6031 [ - + ]: 81 : if (state == NULL)
3655 tgl@sss.pgh.pa.us 6032 [ # # ]:UBC 0 : elog(ERROR, "int8_accum_inv called with NULL state");
6033 : :
3655 tgl@sss.pgh.pa.us 6034 [ + + ]:CBC 81 : if (!PG_ARGISNULL(1))
6035 : : {
6036 : : /* Should never fail, all inputs have dscale 0 */
1313 peter@eisentraut.org 6037 [ - + ]: 72 : if (!do_numeric_discard(state, int64_to_numeric(PG_GETARG_INT64(1))))
3655 tgl@sss.pgh.pa.us 6038 [ # # ]:UBC 0 : elog(ERROR, "do_numeric_discard failed unexpectedly");
6039 : : }
6040 : :
3655 tgl@sss.pgh.pa.us 6041 :CBC 81 : PG_RETURN_POINTER(state);
6042 : : }
6043 : :
6044 : : Datum
3313 andres@anarazel.de 6045 : 18 : int8_avg_accum_inv(PG_FUNCTION_ARGS)
6046 : : {
6047 : : PolyNumAggState *state;
6048 : :
6049 [ + - ]: 18 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
6050 : :
6051 : : /* Should not get here with no state */
6052 [ - + ]: 18 : if (state == NULL)
3313 andres@anarazel.de 6053 [ # # ]:UBC 0 : elog(ERROR, "int8_avg_accum_inv called with NULL state");
6054 : :
3313 andres@anarazel.de 6055 [ + + ]:CBC 18 : if (!PG_ARGISNULL(1))
6056 : : {
6057 : : #ifdef HAVE_INT128
6058 : 12 : do_int128_discard(state, (int128) PG_GETARG_INT64(1));
6059 : : #else
6060 : : /* Should never fail, all inputs have dscale 0 */
6061 : : if (!do_numeric_discard(state, int64_to_numeric(PG_GETARG_INT64(1))))
6062 : : elog(ERROR, "do_numeric_discard failed unexpectedly");
6063 : : #endif
6064 : : }
6065 : :
6066 : 18 : PG_RETURN_POINTER(state);
6067 : : }
6068 : :
6069 : : Datum
6070 : 389 : numeric_poly_sum(PG_FUNCTION_ARGS)
6071 : : {
6072 : : #ifdef HAVE_INT128
6073 : : PolyNumAggState *state;
6074 : : Numeric res;
6075 : : NumericVar result;
6076 : :
6077 [ + + ]: 389 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
6078 : :
6079 : : /* If there were no non-null inputs, return NULL */
6080 [ + + + + ]: 389 : if (state == NULL || state->N == 0)
6081 : 12 : PG_RETURN_NULL();
6082 : :
6083 : 377 : init_var(&result);
6084 : :
6085 : 377 : int128_to_numericvar(state->sumX, &result);
6086 : :
6087 : 377 : res = make_result(&result);
6088 : :
6089 : 377 : free_var(&result);
6090 : :
6091 : 377 : PG_RETURN_NUMERIC(res);
6092 : : #else
6093 : : return numeric_sum(fcinfo);
6094 : : #endif
6095 : : }
6096 : :
6097 : : Datum
6098 : 18 : numeric_poly_avg(PG_FUNCTION_ARGS)
6099 : : {
6100 : : #ifdef HAVE_INT128
6101 : : PolyNumAggState *state;
6102 : : NumericVar result;
6103 : : Datum countd,
6104 : : sumd;
6105 : :
6106 [ + - ]: 18 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
6107 : :
6108 : : /* If there were no non-null inputs, return NULL */
6109 [ + - + + ]: 18 : if (state == NULL || state->N == 0)
6110 : 9 : PG_RETURN_NULL();
6111 : :
6112 : 9 : init_var(&result);
6113 : :
6114 : 9 : int128_to_numericvar(state->sumX, &result);
6115 : :
1313 peter@eisentraut.org 6116 : 9 : countd = NumericGetDatum(int64_to_numeric(state->N));
3313 andres@anarazel.de 6117 : 9 : sumd = NumericGetDatum(make_result(&result));
6118 : :
6119 : 9 : free_var(&result);
6120 : :
6121 : 9 : PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
6122 : : #else
6123 : : return numeric_avg(fcinfo);
6124 : : #endif
6125 : : }
6126 : :
6127 : : Datum
8672 tgl@sss.pgh.pa.us 6128 : 39 : numeric_avg(PG_FUNCTION_ARGS)
6129 : : {
6130 : : NumericAggState *state;
6131 : : Datum N_datum;
6132 : : Datum sumX_datum;
6133 : : NumericVar sumX_var;
6134 : :
3802 6135 [ + - ]: 39 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6136 : :
6137 : : /* If there were no non-null inputs, return NULL */
1362 6138 [ + - + + ]: 39 : if (state == NULL || NA_TOTAL_COUNT(state) == 0)
3802 6139 : 9 : PG_RETURN_NULL();
6140 : :
3631 bruce@momjian.us 6141 [ + + ]: 30 : if (state->NaNcount > 0) /* there was at least one NaN input */
3802 tgl@sss.pgh.pa.us 6142 : 3 : PG_RETURN_NUMERIC(make_result(&const_nan));
6143 : :
6144 : : /* adding plus and minus infinities gives NaN */
1362 6145 [ + + + + ]: 27 : if (state->pInfcount > 0 && state->nInfcount > 0)
6146 : 3 : PG_RETURN_NUMERIC(make_result(&const_nan));
6147 [ + + ]: 24 : if (state->pInfcount > 0)
6148 : 9 : PG_RETURN_NUMERIC(make_result(&const_pinf));
6149 [ + + ]: 15 : if (state->nInfcount > 0)
6150 : 3 : PG_RETURN_NUMERIC(make_result(&const_ninf));
6151 : :
1313 peter@eisentraut.org 6152 : 12 : N_datum = NumericGetDatum(int64_to_numeric(state->N));
6153 : :
2781 heikki.linnakangas@i 6154 : 12 : init_var(&sumX_var);
6155 : 12 : accum_sum_final(&state->sumX, &sumX_var);
6156 : 12 : sumX_datum = NumericGetDatum(make_result(&sumX_var));
6157 : 12 : free_var(&sumX_var);
6158 : :
3802 tgl@sss.pgh.pa.us 6159 : 12 : PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumX_datum, N_datum));
6160 : : }
6161 : :
6162 : : Datum
6163 : 85453 : numeric_sum(PG_FUNCTION_ARGS)
6164 : : {
6165 : : NumericAggState *state;
6166 : : NumericVar sumX_var;
6167 : : Numeric result;
6168 : :
6169 [ + - ]: 85453 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6170 : :
6171 : : /* If there were no non-null inputs, return NULL */
1362 6172 [ + - + + ]: 85453 : if (state == NULL || NA_TOTAL_COUNT(state) == 0)
8672 6173 : 9 : PG_RETURN_NULL();
6174 : :
3631 bruce@momjian.us 6175 [ + + ]: 85444 : if (state->NaNcount > 0) /* there was at least one NaN input */
3802 tgl@sss.pgh.pa.us 6176 : 9 : PG_RETURN_NUMERIC(make_result(&const_nan));
6177 : :
6178 : : /* adding plus and minus infinities gives NaN */
1362 6179 [ + + + + ]: 85435 : if (state->pInfcount > 0 && state->nInfcount > 0)
6180 : 3 : PG_RETURN_NUMERIC(make_result(&const_nan));
6181 [ + + ]: 85432 : if (state->pInfcount > 0)
6182 : 9 : PG_RETURN_NUMERIC(make_result(&const_pinf));
6183 [ + + ]: 85423 : if (state->nInfcount > 0)
6184 : 3 : PG_RETURN_NUMERIC(make_result(&const_ninf));
6185 : :
2781 heikki.linnakangas@i 6186 : 85420 : init_var(&sumX_var);
6187 : 85420 : accum_sum_final(&state->sumX, &sumX_var);
6188 : 85420 : result = make_result(&sumX_var);
6189 : 85420 : free_var(&sumX_var);
6190 : :
6191 : 85420 : PG_RETURN_NUMERIC(result);
6192 : : }
6193 : :
6194 : : /*
6195 : : * Workhorse routine for the standard deviance and variance
6196 : : * aggregates. 'state' is aggregate's transition state.
6197 : : * 'variance' specifies whether we should calculate the
6198 : : * variance or the standard deviation. 'sample' indicates whether the
6199 : : * caller is interested in the sample or the population
6200 : : * variance/stddev.
6201 : : *
6202 : : * If appropriate variance statistic is undefined for the input,
6203 : : * *is_null is set to true and NULL is returned.
6204 : : */
6205 : : static Numeric
3802 tgl@sss.pgh.pa.us 6206 : 493 : numeric_stddev_internal(NumericAggState *state,
6207 : : bool variance, bool sample,
6208 : : bool *is_null)
6209 : : {
6210 : : Numeric res;
6211 : : NumericVar vN,
6212 : : vsumX,
6213 : : vsumX2,
6214 : : vNminus1;
6215 : : int64 totCount;
6216 : : int rscale;
6217 : :
6218 : : /*
6219 : : * Sample stddev and variance are undefined when N <= 1; population stddev
6220 : : * is undefined when N == 0. Return NULL in either case (note that NaNs
6221 : : * and infinities count as normal inputs for this purpose).
6222 : : */
1362 6223 [ + - - + ]: 493 : if (state == NULL || (totCount = NA_TOTAL_COUNT(state)) == 0)
6224 : : {
1401 tgl@sss.pgh.pa.us 6225 :UBC 0 : *is_null = true;
6226 : 0 : return NULL;
6227 : : }
6228 : :
1401 tgl@sss.pgh.pa.us 6229 [ + + + + ]:CBC 493 : if (sample && totCount <= 1)
6230 : : {
3802 6231 : 66 : *is_null = true;
6232 : 66 : return NULL;
6233 : : }
6234 : :
6610 neilc@samurai.com 6235 : 427 : *is_null = false;
6236 : :
6237 : : /*
6238 : : * Deal with NaN and infinity cases. By analogy to the behavior of the
6239 : : * float8 functions, any infinity input produces NaN output.
6240 : : */
1362 tgl@sss.pgh.pa.us 6241 [ + + + + : 427 : if (state->NaNcount > 0 || state->pInfcount > 0 || state->nInfcount > 0)
+ + ]
6610 neilc@samurai.com 6242 : 27 : return make_result(&const_nan);
6243 : :
6244 : : /* OK, normal calculation applies */
3802 tgl@sss.pgh.pa.us 6245 : 400 : init_var(&vN);
6246 : 400 : init_var(&vsumX);
6247 : 400 : init_var(&vsumX2);
6248 : :
3313 andres@anarazel.de 6249 : 400 : int64_to_numericvar(state->N, &vN);
2781 heikki.linnakangas@i 6250 : 400 : accum_sum_final(&(state->sumX), &vsumX);
6251 : 400 : accum_sum_final(&(state->sumX2), &vsumX2);
6252 : :
7664 tgl@sss.pgh.pa.us 6253 : 400 : init_var(&vNminus1);
6254 : 400 : sub_var(&vN, &const_one, &vNminus1);
6255 : :
6256 : : /* compute rscale for mul_var calls */
7695 6257 : 400 : rscale = vsumX.dscale * 2;
6258 : :
6259 : 400 : mul_var(&vsumX, &vsumX, &vsumX, rscale); /* vsumX = sumX * sumX */
2489 6260 : 400 : mul_var(&vN, &vsumX2, &vsumX2, rscale); /* vsumX2 = N * sumX2 */
6402 bruce@momjian.us 6261 : 400 : sub_var(&vsumX2, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */
6262 : :
8160 tgl@sss.pgh.pa.us 6263 [ + + ]: 400 : if (cmp_var(&vsumX2, &const_zero) <= 0)
6264 : : {
6265 : : /* Watch out for roundoff error producing a negative numerator */
6266 : 40 : res = make_result(&const_zero);
6267 : : }
6268 : : else
6269 : : {
6124 6270 [ + + ]: 360 : if (sample)
2489 6271 : 246 : mul_var(&vN, &vNminus1, &vNminus1, 0); /* N * (N - 1) */
6272 : : else
5995 bruce@momjian.us 6273 : 114 : mul_var(&vN, &vN, &vNminus1, 0); /* N * N */
7695 tgl@sss.pgh.pa.us 6274 : 360 : rscale = select_div_scale(&vsumX2, &vNminus1);
2489 6275 : 360 : div_var(&vsumX2, &vNminus1, &vsumX, rscale, true); /* variance */
6610 neilc@samurai.com 6276 [ + + ]: 360 : if (!variance)
6402 bruce@momjian.us 6277 : 189 : sqrt_var(&vsumX, &vsumX, rscale); /* stddev */
6278 : :
8160 tgl@sss.pgh.pa.us 6279 : 360 : res = make_result(&vsumX);
6280 : : }
6281 : :
8672 6282 : 400 : free_var(&vNminus1);
6283 : 400 : free_var(&vsumX);
6284 : 400 : free_var(&vsumX2);
6285 : :
6610 neilc@samurai.com 6286 : 400 : return res;
6287 : : }
6288 : :
6289 : : Datum
6290 : 90 : numeric_var_samp(PG_FUNCTION_ARGS)
6291 : : {
6292 : : NumericAggState *state;
6293 : : Numeric res;
6294 : : bool is_null;
6295 : :
3802 tgl@sss.pgh.pa.us 6296 [ + - ]: 90 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6297 : :
6298 : 90 : res = numeric_stddev_internal(state, true, true, &is_null);
6299 : :
6610 neilc@samurai.com 6300 [ + + ]: 90 : if (is_null)
7664 tgl@sss.pgh.pa.us 6301 : 21 : PG_RETURN_NULL();
6302 : : else
6610 neilc@samurai.com 6303 : 69 : PG_RETURN_NUMERIC(res);
6304 : : }
6305 : :
6306 : : Datum
6307 : 87 : numeric_stddev_samp(PG_FUNCTION_ARGS)
6308 : : {
6309 : : NumericAggState *state;
6310 : : Numeric res;
6311 : : bool is_null;
6312 : :
3802 tgl@sss.pgh.pa.us 6313 [ + - ]: 87 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6314 : :
6315 : 87 : res = numeric_stddev_internal(state, false, true, &is_null);
6316 : :
6610 neilc@samurai.com 6317 [ + + ]: 87 : if (is_null)
6318 : 21 : PG_RETURN_NULL();
6319 : : else
6320 : 66 : PG_RETURN_NUMERIC(res);
6321 : : }
6322 : :
6323 : : Datum
6324 : 57 : numeric_var_pop(PG_FUNCTION_ARGS)
6325 : : {
6326 : : NumericAggState *state;
6327 : : Numeric res;
6328 : : bool is_null;
6329 : :
3802 tgl@sss.pgh.pa.us 6330 [ + - ]: 57 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6331 : :
6332 : 57 : res = numeric_stddev_internal(state, true, false, &is_null);
6333 : :
6610 neilc@samurai.com 6334 [ - + ]: 57 : if (is_null)
6610 neilc@samurai.com 6335 :UBC 0 : PG_RETURN_NULL();
6336 : : else
6610 neilc@samurai.com 6337 :CBC 57 : PG_RETURN_NUMERIC(res);
6338 : : }
6339 : :
6340 : : Datum
6341 : 48 : numeric_stddev_pop(PG_FUNCTION_ARGS)
6342 : : {
6343 : : NumericAggState *state;
6344 : : Numeric res;
6345 : : bool is_null;
6346 : :
3802 tgl@sss.pgh.pa.us 6347 [ + - ]: 48 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6348 : :
6349 : 48 : res = numeric_stddev_internal(state, false, false, &is_null);
6350 : :
6610 neilc@samurai.com 6351 [ - + ]: 48 : if (is_null)
6610 neilc@samurai.com 6352 :UBC 0 : PG_RETURN_NULL();
6353 : : else
6610 neilc@samurai.com 6354 :CBC 48 : PG_RETURN_NUMERIC(res);
6355 : : }
6356 : :
6357 : : #ifdef HAVE_INT128
6358 : : static Numeric
3313 andres@anarazel.de 6359 : 211 : numeric_poly_stddev_internal(Int128AggState *state,
6360 : : bool variance, bool sample,
6361 : : bool *is_null)
6362 : : {
6363 : : NumericAggState numstate;
6364 : : Numeric res;
6365 : :
6366 : : /* Initialize an empty agg state */
2781 heikki.linnakangas@i 6367 : 211 : memset(&numstate, 0, sizeof(NumericAggState));
6368 : :
3313 andres@anarazel.de 6369 [ + - ]: 211 : if (state)
6370 : : {
6371 : : NumericVar tmp_var;
6372 : :
6373 : 211 : numstate.N = state->N;
6374 : :
2781 heikki.linnakangas@i 6375 : 211 : init_var(&tmp_var);
6376 : :
6377 : 211 : int128_to_numericvar(state->sumX, &tmp_var);
6378 : 211 : accum_sum_add(&numstate.sumX, &tmp_var);
6379 : :
6380 : 211 : int128_to_numericvar(state->sumX2, &tmp_var);
6381 : 211 : accum_sum_add(&numstate.sumX2, &tmp_var);
6382 : :
6383 : 211 : free_var(&tmp_var);
6384 : : }
6385 : :
3313 andres@anarazel.de 6386 : 211 : res = numeric_stddev_internal(&numstate, variance, sample, is_null);
6387 : :
2781 heikki.linnakangas@i 6388 [ + - ]: 211 : if (numstate.sumX.ndigits > 0)
6389 : : {
6390 : 211 : pfree(numstate.sumX.pos_digits);
6391 : 211 : pfree(numstate.sumX.neg_digits);
6392 : : }
6393 [ + - ]: 211 : if (numstate.sumX2.ndigits > 0)
6394 : : {
6395 : 211 : pfree(numstate.sumX2.pos_digits);
6396 : 211 : pfree(numstate.sumX2.neg_digits);
6397 : : }
6398 : :
3313 andres@anarazel.de 6399 : 211 : return res;
6400 : : }
6401 : : #endif
6402 : :
6403 : : Datum
6404 : 63 : numeric_poly_var_samp(PG_FUNCTION_ARGS)
6405 : : {
6406 : : #ifdef HAVE_INT128
6407 : : PolyNumAggState *state;
6408 : : Numeric res;
6409 : : bool is_null;
6410 : :
6411 [ + - ]: 63 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
6412 : :
6413 : 63 : res = numeric_poly_stddev_internal(state, true, true, &is_null);
6414 : :
6415 [ + + ]: 63 : if (is_null)
6416 : 12 : PG_RETURN_NULL();
6417 : : else
6418 : 51 : PG_RETURN_NUMERIC(res);
6419 : : #else
6420 : : return numeric_var_samp(fcinfo);
6421 : : #endif
6422 : : }
6423 : :
6424 : : Datum
6425 : 82 : numeric_poly_stddev_samp(PG_FUNCTION_ARGS)
6426 : : {
6427 : : #ifdef HAVE_INT128
6428 : : PolyNumAggState *state;
6429 : : Numeric res;
6430 : : bool is_null;
6431 : :
6432 [ + - ]: 82 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
6433 : :
6434 : 82 : res = numeric_poly_stddev_internal(state, false, true, &is_null);
6435 : :
6436 [ + + ]: 82 : if (is_null)
6437 : 12 : PG_RETURN_NULL();
6438 : : else
6439 : 70 : PG_RETURN_NUMERIC(res);
6440 : : #else
6441 : : return numeric_stddev_samp(fcinfo);
6442 : : #endif
6443 : : }
6444 : :
6445 : : Datum
6446 : 30 : numeric_poly_var_pop(PG_FUNCTION_ARGS)
6447 : : {
6448 : : #ifdef HAVE_INT128
6449 : : PolyNumAggState *state;
6450 : : Numeric res;
6451 : : bool is_null;
6452 : :
6453 [ + - ]: 30 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
6454 : :
6455 : 30 : res = numeric_poly_stddev_internal(state, true, false, &is_null);
6456 : :
6457 [ - + ]: 30 : if (is_null)
3313 andres@anarazel.de 6458 :UBC 0 : PG_RETURN_NULL();
6459 : : else
3313 andres@anarazel.de 6460 :CBC 30 : PG_RETURN_NUMERIC(res);
6461 : : #else
6462 : : return numeric_var_pop(fcinfo);
6463 : : #endif
6464 : : }
6465 : :
6466 : : Datum
6467 : 36 : numeric_poly_stddev_pop(PG_FUNCTION_ARGS)
6468 : : {
6469 : : #ifdef HAVE_INT128
6470 : : PolyNumAggState *state;
6471 : : Numeric res;
6472 : : bool is_null;
6473 : :
6474 [ + - ]: 36 : state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
6475 : :
6476 : 36 : res = numeric_poly_stddev_internal(state, false, false, &is_null);
6477 : :
6478 [ - + ]: 36 : if (is_null)
3313 andres@anarazel.de 6479 :UBC 0 : PG_RETURN_NULL();
6480 : : else
3313 andres@anarazel.de 6481 :CBC 36 : PG_RETURN_NUMERIC(res);
6482 : : #else
6483 : : return numeric_stddev_pop(fcinfo);
6484 : : #endif
6485 : : }
6486 : :
6487 : : /*
6488 : : * SUM transition functions for integer datatypes.
6489 : : *
6490 : : * To avoid overflow, we use accumulators wider than the input datatype.
6491 : : * A Numeric accumulator is needed for int8 input; for int4 and int2
6492 : : * inputs, we use int8 accumulators which should be sufficient for practical
6493 : : * purposes. (The latter two therefore don't really belong in this file,
6494 : : * but we keep them here anyway.)
6495 : : *
6496 : : * Because SQL defines the SUM() of no values to be NULL, not zero,
6497 : : * the initial condition of the transition data value needs to be NULL. This
6498 : : * means we can't rely on ExecAgg to automatically insert the first non-null
6499 : : * data value into the transition data: it doesn't know how to do the type
6500 : : * conversion. The upshot is that these routines have to be marked non-strict
6501 : : * and handle substitution of the first non-null input themselves.
6502 : : *
6503 : : * Note: these functions are used only in plain aggregation mode.
6504 : : * In moving-aggregate mode, we use intX_avg_accum and intX_avg_accum_inv.
6505 : : */
6506 : :
6507 : : Datum
8672 tgl@sss.pgh.pa.us 6508 : 12 : int2_sum(PG_FUNCTION_ARGS)
6509 : : {
6510 : : int64 newval;
6511 : :
6512 [ + + ]: 12 : if (PG_ARGISNULL(0))
6513 : : {
6514 : : /* No non-null input seen so far... */
6515 [ - + ]: 3 : if (PG_ARGISNULL(1))
8672 tgl@sss.pgh.pa.us 6516 :UBC 0 : PG_RETURN_NULL(); /* still no non-null */
6517 : : /* This is the first non-null input. */
8279 tgl@sss.pgh.pa.us 6518 :CBC 3 : newval = (int64) PG_GETARG_INT16(1);
6519 : 3 : PG_RETURN_INT64(newval);
6520 : : }
6521 : :
6522 : : /*
6523 : : * If we're invoked as an aggregate, we can cheat and modify our first
6524 : : * parameter in-place to avoid palloc overhead. If not, we need to return
6525 : : * the new value of the transition variable. (If int8 is pass-by-value,
6526 : : * then of course this is useless as well as incorrect, so just ifdef it
6527 : : * out.)
6528 : : */
6529 : : #ifndef USE_FLOAT8_BYVAL /* controls int8 too */
6530 : : if (AggCheckCallContext(fcinfo, NULL))
6531 : : {
6532 : : int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
6533 : :
6534 : : /* Leave the running sum unchanged in the new input is null */
6535 : : if (!PG_ARGISNULL(1))
6536 : : *oldsum = *oldsum + (int64) PG_GETARG_INT16(1);
6537 : :
6538 : : PG_RETURN_POINTER(oldsum);
6539 : : }
6540 : : else
6541 : : #endif
6542 : : {
6948 neilc@samurai.com 6543 : 9 : int64 oldsum = PG_GETARG_INT64(0);
6544 : :
6545 : : /* Leave sum unchanged if new input is null. */
6546 [ - + ]: 9 : if (PG_ARGISNULL(1))
6948 neilc@samurai.com 6547 :UBC 0 : PG_RETURN_INT64(oldsum);
6548 : :
6549 : : /* OK to do the addition. */
6948 neilc@samurai.com 6550 :CBC 9 : newval = oldsum + (int64) PG_GETARG_INT16(1);
6551 : :
6552 : 9 : PG_RETURN_INT64(newval);
6553 : : }
6554 : : }
6555 : :
6556 : : Datum
8672 tgl@sss.pgh.pa.us 6557 : 1789030 : int4_sum(PG_FUNCTION_ARGS)
6558 : : {
6559 : : int64 newval;
6560 : :
6561 [ + + ]: 1789030 : if (PG_ARGISNULL(0))
6562 : : {
6563 : : /* No non-null input seen so far... */
6564 [ + + ]: 103689 : if (PG_ARGISNULL(1))
6565 : 493 : PG_RETURN_NULL(); /* still no non-null */
6566 : : /* This is the first non-null input. */
8279 6567 : 103196 : newval = (int64) PG_GETARG_INT32(1);
6568 : 103196 : PG_RETURN_INT64(newval);
6569 : : }
6570 : :
6571 : : /*
6572 : : * If we're invoked as an aggregate, we can cheat and modify our first
6573 : : * parameter in-place to avoid palloc overhead. If not, we need to return
6574 : : * the new value of the transition variable. (If int8 is pass-by-value,
6575 : : * then of course this is useless as well as incorrect, so just ifdef it
6576 : : * out.)
6577 : : */
6578 : : #ifndef USE_FLOAT8_BYVAL /* controls int8 too */
6579 : : if (AggCheckCallContext(fcinfo, NULL))
6580 : : {
6581 : : int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
6582 : :
6583 : : /* Leave the running sum unchanged in the new input is null */
6584 : : if (!PG_ARGISNULL(1))
6585 : : *oldsum = *oldsum + (int64) PG_GETARG_INT32(1);
6586 : :
6587 : : PG_RETURN_POINTER(oldsum);
6588 : : }
6589 : : else
6590 : : #endif
6591 : : {
6948 neilc@samurai.com 6592 : 1685341 : int64 oldsum = PG_GETARG_INT64(0);
6593 : :
6594 : : /* Leave sum unchanged if new input is null. */
6595 [ + + ]: 1685341 : if (PG_ARGISNULL(1))
6596 : 437 : PG_RETURN_INT64(oldsum);
6597 : :
6598 : : /* OK to do the addition. */
6599 : 1684904 : newval = oldsum + (int64) PG_GETARG_INT32(1);
6600 : :
6601 : 1684904 : PG_RETURN_INT64(newval);
6602 : : }
6603 : : }
6604 : :
6605 : : /*
6606 : : * Note: this function is obsolete, it's no longer used for SUM(int8).
6607 : : */
6608 : : Datum
8672 tgl@sss.pgh.pa.us 6609 :UBC 0 : int8_sum(PG_FUNCTION_ARGS)
6610 : : {
6611 : : Numeric oldsum;
6612 : :
6613 [ # # ]: 0 : if (PG_ARGISNULL(0))
6614 : : {
6615 : : /* No non-null input seen so far... */
6616 [ # # ]: 0 : if (PG_ARGISNULL(1))
6617 : 0 : PG_RETURN_NULL(); /* still no non-null */
6618 : : /* This is the first non-null input. */
1313 peter@eisentraut.org 6619 : 0 : PG_RETURN_NUMERIC(int64_to_numeric(PG_GETARG_INT64(1)));
6620 : : }
6621 : :
6622 : : /*
6623 : : * Note that we cannot special-case the aggregate case here, as we do for
6624 : : * int2_sum and int4_sum: numeric is of variable size, so we cannot modify
6625 : : * our first parameter in-place.
6626 : : */
6627 : :
8672 tgl@sss.pgh.pa.us 6628 : 0 : oldsum = PG_GETARG_NUMERIC(0);
6629 : :
6630 : : /* Leave sum unchanged if new input is null. */
6631 [ # # ]: 0 : if (PG_ARGISNULL(1))
6632 : 0 : PG_RETURN_NUMERIC(oldsum);
6633 : :
6634 : : /* OK to do the addition. */
8660 6635 : 0 : PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,
6636 : : NumericGetDatum(oldsum),
6637 : : NumericGetDatum(int64_to_numeric(PG_GETARG_INT64(1)))));
6638 : : }
6639 : :
6640 : :
6641 : : /*
6642 : : * Routines for avg(int2) and avg(int4). The transition datatype
6643 : : * is a two-element int8 array, holding count and sum.
6644 : : *
6645 : : * These functions are also used for sum(int2) and sum(int4) when
6646 : : * operating in moving-aggregate mode, since for correct inverse transitions
6647 : : * we need to count the inputs.
6648 : : */
6649 : :
6650 : : typedef struct Int8TransTypeData
6651 : : {
6652 : : int64 count;
6653 : : int64 sum;
6654 : : } Int8TransTypeData;
6655 : :
6656 : : Datum
8279 tgl@sss.pgh.pa.us 6657 :CBC 21 : int2_avg_accum(PG_FUNCTION_ARGS)
6658 : : {
6659 : : ArrayType *transarray;
6660 : 21 : int16 newval = PG_GETARG_INT16(1);
6661 : : Int8TransTypeData *transdata;
6662 : :
6663 : : /*
6664 : : * If we're invoked as an aggregate, we can cheat and modify our first
6665 : : * parameter in-place to reduce palloc overhead. Otherwise we need to make
6666 : : * a copy of it before scribbling on it.
6667 : : */
5179 6668 [ + - ]: 21 : if (AggCheckCallContext(fcinfo, NULL))
6950 neilc@samurai.com 6669 : 21 : transarray = PG_GETARG_ARRAYTYPE_P(0);
6670 : : else
6950 neilc@samurai.com 6671 :UBC 0 : transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6672 : :
6723 tgl@sss.pgh.pa.us 6673 [ + - ]:CBC 21 : if (ARR_HASNULL(transarray) ||
6674 [ - + ]: 21 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
7567 tgl@sss.pgh.pa.us 6675 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6676 : :
6950 neilc@samurai.com 6677 [ - + ]:CBC 21 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
8279 tgl@sss.pgh.pa.us 6678 : 21 : transdata->count++;
6679 : 21 : transdata->sum += newval;
6680 : :
6681 : 21 : PG_RETURN_ARRAYTYPE_P(transarray);
6682 : : }
6683 : :
6684 : : Datum
6685 : 1298151 : int4_avg_accum(PG_FUNCTION_ARGS)
6686 : : {
6687 : : ArrayType *transarray;
6688 : 1298151 : int32 newval = PG_GETARG_INT32(1);
6689 : : Int8TransTypeData *transdata;
6690 : :
6691 : : /*
6692 : : * If we're invoked as an aggregate, we can cheat and modify our first
6693 : : * parameter in-place to reduce palloc overhead. Otherwise we need to make
6694 : : * a copy of it before scribbling on it.
6695 : : */
5179 6696 [ + - ]: 1298151 : if (AggCheckCallContext(fcinfo, NULL))
6950 neilc@samurai.com 6697 : 1298151 : transarray = PG_GETARG_ARRAYTYPE_P(0);
6698 : : else
6950 neilc@samurai.com 6699 :UBC 0 : transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6700 : :
6723 tgl@sss.pgh.pa.us 6701 [ + - ]:CBC 1298151 : if (ARR_HASNULL(transarray) ||
6702 [ - + ]: 1298151 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
7567 tgl@sss.pgh.pa.us 6703 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6704 : :
6950 neilc@samurai.com 6705 [ - + ]:CBC 1298151 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
8279 tgl@sss.pgh.pa.us 6706 : 1298151 : transdata->count++;
6707 : 1298151 : transdata->sum += newval;
6708 : :
6709 : 1298151 : PG_RETURN_ARRAYTYPE_P(transarray);
6710 : : }
6711 : :
6712 : : Datum
2931 rhaas@postgresql.org 6713 : 2201 : int4_avg_combine(PG_FUNCTION_ARGS)
6714 : : {
6715 : : ArrayType *transarray1;
6716 : : ArrayType *transarray2;
6717 : : Int8TransTypeData *state1;
6718 : : Int8TransTypeData *state2;
6719 : :
6720 [ - + ]: 2201 : if (!AggCheckCallContext(fcinfo, NULL))
2931 rhaas@postgresql.org 6721 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
6722 : :
2931 rhaas@postgresql.org 6723 :CBC 2201 : transarray1 = PG_GETARG_ARRAYTYPE_P(0);
6724 : 2201 : transarray2 = PG_GETARG_ARRAYTYPE_P(1);
6725 : :
6726 [ + - ]: 2201 : if (ARR_HASNULL(transarray1) ||
6727 [ - + ]: 2201 : ARR_SIZE(transarray1) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
2931 rhaas@postgresql.org 6728 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6729 : :
2931 rhaas@postgresql.org 6730 [ + - ]:CBC 2201 : if (ARR_HASNULL(transarray2) ||
6731 [ - + ]: 2201 : ARR_SIZE(transarray2) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
2931 rhaas@postgresql.org 6732 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6733 : :
2931 rhaas@postgresql.org 6734 [ - + ]:CBC 2201 : state1 = (Int8TransTypeData *) ARR_DATA_PTR(transarray1);
6735 [ - + ]: 2201 : state2 = (Int8TransTypeData *) ARR_DATA_PTR(transarray2);
6736 : :
6737 : 2201 : state1->count += state2->count;
6738 : 2201 : state1->sum += state2->sum;
6739 : :
6740 : 2201 : PG_RETURN_ARRAYTYPE_P(transarray1);
6741 : : }
6742 : :
6743 : : Datum
3655 tgl@sss.pgh.pa.us 6744 : 6 : int2_avg_accum_inv(PG_FUNCTION_ARGS)
6745 : : {
6746 : : ArrayType *transarray;
6747 : 6 : int16 newval = PG_GETARG_INT16(1);
6748 : : Int8TransTypeData *transdata;
6749 : :
6750 : : /*
6751 : : * If we're invoked as an aggregate, we can cheat and modify our first
6752 : : * parameter in-place to reduce palloc overhead. Otherwise we need to make
6753 : : * a copy of it before scribbling on it.
6754 : : */
6755 [ + - ]: 6 : if (AggCheckCallContext(fcinfo, NULL))
6756 : 6 : transarray = PG_GETARG_ARRAYTYPE_P(0);
6757 : : else
3655 tgl@sss.pgh.pa.us 6758 :UBC 0 : transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6759 : :
3655 tgl@sss.pgh.pa.us 6760 [ + - ]:CBC 6 : if (ARR_HASNULL(transarray) ||
6761 [ - + ]: 6 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
3655 tgl@sss.pgh.pa.us 6762 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6763 : :
3655 tgl@sss.pgh.pa.us 6764 [ - + ]:CBC 6 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6765 : 6 : transdata->count--;
6766 : 6 : transdata->sum -= newval;
6767 : :
6768 : 6 : PG_RETURN_ARRAYTYPE_P(transarray);
6769 : : }
6770 : :
6771 : : Datum
6772 : 726 : int4_avg_accum_inv(PG_FUNCTION_ARGS)
6773 : : {
6774 : : ArrayType *transarray;
6775 : 726 : int32 newval = PG_GETARG_INT32(1);
6776 : : Int8TransTypeData *transdata;
6777 : :
6778 : : /*
6779 : : * If we're invoked as an aggregate, we can cheat and modify our first
6780 : : * parameter in-place to reduce palloc overhead. Otherwise we need to make
6781 : : * a copy of it before scribbling on it.
6782 : : */
6783 [ + - ]: 726 : if (AggCheckCallContext(fcinfo, NULL))
6784 : 726 : transarray = PG_GETARG_ARRAYTYPE_P(0);
6785 : : else
3655 tgl@sss.pgh.pa.us 6786 :UBC 0 : transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6787 : :
3655 tgl@sss.pgh.pa.us 6788 [ + - ]:CBC 726 : if (ARR_HASNULL(transarray) ||
6789 [ - + ]: 726 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
3655 tgl@sss.pgh.pa.us 6790 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6791 : :
3655 tgl@sss.pgh.pa.us 6792 [ - + ]:CBC 726 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6793 : 726 : transdata->count--;
6794 : 726 : transdata->sum -= newval;
6795 : :
6796 : 726 : PG_RETURN_ARRAYTYPE_P(transarray);
6797 : : }
6798 : :
6799 : : Datum
8279 6800 : 5375 : int8_avg(PG_FUNCTION_ARGS)
6801 : : {
6802 : 5375 : ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
6803 : : Int8TransTypeData *transdata;
6804 : : Datum countd,
6805 : : sumd;
6806 : :
6723 6807 [ + - ]: 5375 : if (ARR_HASNULL(transarray) ||
6808 [ - + ]: 5375 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
7567 tgl@sss.pgh.pa.us 6809 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
8279 tgl@sss.pgh.pa.us 6810 [ - + ]:CBC 5375 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6811 : :
6812 : : /* SQL defines AVG of no values to be NULL */
6813 [ + + ]: 5375 : if (transdata->count == 0)
6814 : 59 : PG_RETURN_NULL();
6815 : :
1313 peter@eisentraut.org 6816 : 5316 : countd = NumericGetDatum(int64_to_numeric(transdata->count));
6817 : 5316 : sumd = NumericGetDatum(int64_to_numeric(transdata->sum));
6818 : :
8279 tgl@sss.pgh.pa.us 6819 : 5316 : PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
6820 : : }
6821 : :
6822 : : /*
6823 : : * SUM(int2) and SUM(int4) both return int8, so we can use this
6824 : : * final function for both.
6825 : : */
6826 : : Datum
3655 6827 : 1917 : int2int4_sum(PG_FUNCTION_ARGS)
6828 : : {
6829 : 1917 : ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
6830 : : Int8TransTypeData *transdata;
6831 : :
6832 [ + - ]: 1917 : if (ARR_HASNULL(transarray) ||
6833 [ - + ]: 1917 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
3655 tgl@sss.pgh.pa.us 6834 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
3655 tgl@sss.pgh.pa.us 6835 [ - + ]:CBC 1917 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6836 : :
6837 : : /* SQL defines SUM of no values to be NULL */
6838 [ + + ]: 1917 : if (transdata->count == 0)
6839 : 240 : PG_RETURN_NULL();
6840 : :
6841 : 1677 : PG_RETURN_DATUM(Int64GetDatumFast(transdata->sum));
6842 : : }
6843 : :
6844 : :
6845 : : /* ----------------------------------------------------------------------
6846 : : *
6847 : : * Debug support
6848 : : *
6849 : : * ----------------------------------------------------------------------
6850 : : */
6851 : :
6852 : : #ifdef NUMERIC_DEBUG
6853 : :
6854 : : /*
6855 : : * dump_numeric() - Dump a value in the db storage format for debugging
6856 : : */
6857 : : static void
6858 : : dump_numeric(const char *str, Numeric num)
6859 : : {
6860 : : NumericDigit *digits = NUMERIC_DIGITS(num);
6861 : : int ndigits;
6862 : : int i;
6863 : :
6864 : : ndigits = NUMERIC_NDIGITS(num);
6865 : :
6866 : : printf("%s: NUMERIC w=%d d=%d ", str,
6867 : : NUMERIC_WEIGHT(num), NUMERIC_DSCALE(num));
6868 : : switch (NUMERIC_SIGN(num))
6869 : : {
6870 : : case NUMERIC_POS:
6871 : : printf("POS");
6872 : : break;
6873 : : case NUMERIC_NEG:
6874 : : printf("NEG");
6875 : : break;
6876 : : case NUMERIC_NAN:
6877 : : printf("NaN");
6878 : : break;
6879 : : case NUMERIC_PINF:
6880 : : printf("Infinity");
6881 : : break;
6882 : : case NUMERIC_NINF:
6883 : : printf("-Infinity");
6884 : : break;
6885 : : default:
6886 : : printf("SIGN=0x%x", NUMERIC_SIGN(num));
6887 : : break;
6888 : : }
6889 : :
6890 : : for (i = 0; i < ndigits; i++)
6891 : : printf(" %0*d", DEC_DIGITS, digits[i]);
6892 : : printf("\n");
6893 : : }
6894 : :
6895 : :
6896 : : /*
6897 : : * dump_var() - Dump a value in the variable format for debugging
6898 : : */
6899 : : static void
6900 : : dump_var(const char *str, NumericVar *var)
6901 : : {
6902 : : int i;
6903 : :
6904 : : printf("%s: VAR w=%d d=%d ", str, var->weight, var->dscale);
6905 : : switch (var->sign)
6906 : : {
6907 : : case NUMERIC_POS:
6908 : : printf("POS");
6909 : : break;
6910 : : case NUMERIC_NEG:
6911 : : printf("NEG");
6912 : : break;
6913 : : case NUMERIC_NAN:
6914 : : printf("NaN");
6915 : : break;
6916 : : case NUMERIC_PINF:
6917 : : printf("Infinity");
6918 : : break;
6919 : : case NUMERIC_NINF:
6920 : : printf("-Infinity");
6921 : : break;
6922 : : default:
6923 : : printf("SIGN=0x%x", var->sign);
6924 : : break;
6925 : : }
6926 : :
6927 : : for (i = 0; i < var->ndigits; i++)
6928 : : printf(" %0*d", DEC_DIGITS, var->digits[i]);
6929 : :
6930 : : printf("\n");
6931 : : }
6932 : : #endif /* NUMERIC_DEBUG */
6933 : :
6934 : :
6935 : : /* ----------------------------------------------------------------------
6936 : : *
6937 : : * Local functions follow
6938 : : *
6939 : : * In general, these do not support "special" (NaN or infinity) inputs;
6940 : : * callers should handle those possibilities first.
6941 : : * (There are one or two exceptions, noted in their header comments.)
6942 : : *
6943 : : * ----------------------------------------------------------------------
6944 : : */
6945 : :
6946 : :
6947 : : /*
6948 : : * alloc_var() -
6949 : : *
6950 : : * Allocate a digit buffer of ndigits digits (plus a spare digit for rounding)
6951 : : */
6952 : : static void
8853 6953 : 1452120 : alloc_var(NumericVar *var, int ndigits)
6954 : : {
6955 [ + + ]: 1452120 : digitbuf_free(var->buf);
6956 : 1452120 : var->buf = digitbuf_alloc(ndigits + 1);
7559 bruce@momjian.us 6957 : 1452120 : var->buf[0] = 0; /* spare digit for rounding */
8853 tgl@sss.pgh.pa.us 6958 : 1452120 : var->digits = var->buf + 1;
6959 : 1452120 : var->ndigits = ndigits;
9237 JanWieck@Yahoo.com 6960 : 1452120 : }
6961 : :
6962 : :
6963 : : /*
6964 : : * free_var() -
6965 : : *
6966 : : * Return the digit buffer of a variable to the free pool
6967 : : */
6968 : : static void
9091 bruce@momjian.us 6969 : 1706634 : free_var(NumericVar *var)
6970 : : {
8853 tgl@sss.pgh.pa.us 6971 [ + + ]: 1706634 : digitbuf_free(var->buf);
6972 : 1706634 : var->buf = NULL;
6973 : 1706634 : var->digits = NULL;
9237 JanWieck@Yahoo.com 6974 : 1706634 : var->sign = NUMERIC_NAN;
6975 : 1706634 : }
6976 : :
6977 : :
6978 : : /*
6979 : : * zero_var() -
6980 : : *
6981 : : * Set a variable to ZERO.
6982 : : * Note: its dscale is not touched.
6983 : : */
6984 : : static void
8853 tgl@sss.pgh.pa.us 6985 : 20268 : zero_var(NumericVar *var)
6986 : : {
6987 [ + + ]: 20268 : digitbuf_free(var->buf);
6988 : 20268 : var->buf = NULL;
6989 : 20268 : var->digits = NULL;
6990 : 20268 : var->ndigits = 0;
6991 : 20268 : var->weight = 0; /* by convention; doesn't really matter */
6992 : 20268 : var->sign = NUMERIC_POS; /* anything but NAN... */
9237 JanWieck@Yahoo.com 6993 : 20268 : }
6994 : :
6995 : :
6996 : : /*
6997 : : * set_var_from_str()
6998 : : *
6999 : : * Parse a string and put the number into a variable
7000 : : *
7001 : : * This function does not handle leading or trailing spaces. It returns
7002 : : * the end+1 position parsed into *endptr, so that caller can check for
7003 : : * trailing spaces/garbage if deemed necessary.
7004 : : *
7005 : : * cp is the place to actually start parsing; str is what to use in error
7006 : : * reports. (Typically cp would be the same except advanced over spaces.)
7007 : : *
7008 : : * Returns true on success, false on failure (if escontext points to an
7009 : : * ErrorSaveContext; otherwise errors are thrown).
7010 : : */
7011 : : static bool
492 tgl@sss.pgh.pa.us 7012 : 63797 : set_var_from_str(const char *str, const char *cp,
7013 : : NumericVar *dest, const char **endptr,
7014 : : Node *escontext)
7015 : : {
2433 peter_e@gmx.net 7016 : 63797 : bool have_dp = false;
7017 : : int i;
7018 : : unsigned char *decdigits;
7695 tgl@sss.pgh.pa.us 7019 : 63797 : int sign = NUMERIC_POS;
7020 : 63797 : int dweight = -1;
7021 : : int ddigits;
7022 : 63797 : int dscale = 0;
7023 : : int weight;
7024 : : int ndigits;
7025 : : int offset;
7026 : : NumericDigit *digits;
7027 : :
7028 : : /*
7029 : : * We first parse the string to extract decimal digits and determine the
7030 : : * correct decimal weight. Then convert to NBASE representation.
7031 : : */
9237 JanWieck@Yahoo.com 7032 [ - + + ]: 63797 : switch (*cp)
7033 : : {
9091 bruce@momjian.us 7034 :UBC 0 : case '+':
7695 tgl@sss.pgh.pa.us 7035 : 0 : sign = NUMERIC_POS;
9091 bruce@momjian.us 7036 : 0 : cp++;
7037 : 0 : break;
7038 : :
9091 bruce@momjian.us 7039 :CBC 150 : case '-':
7695 tgl@sss.pgh.pa.us 7040 : 150 : sign = NUMERIC_NEG;
9091 bruce@momjian.us 7041 : 150 : cp++;
7042 : 150 : break;
7043 : : }
7044 : :
9237 JanWieck@Yahoo.com 7045 [ + + ]: 63797 : if (*cp == '.')
7046 : : {
2433 peter_e@gmx.net 7047 : 191 : have_dp = true;
9237 JanWieck@Yahoo.com 7048 : 191 : cp++;
7049 : : }
7050 : :
8533 tgl@sss.pgh.pa.us 7051 [ - + ]: 63797 : if (!isdigit((unsigned char) *cp))
435 dean.a.rasheed@gmail 7052 :UBC 0 : goto invalid_syntax;
7053 : :
7559 bruce@momjian.us 7054 :CBC 63797 : decdigits = (unsigned char *) palloc(strlen(cp) + DEC_DIGITS * 2);
7055 : :
7056 : : /* leading padding for digit alignment later */
7695 tgl@sss.pgh.pa.us 7057 : 63797 : memset(decdigits, 0, DEC_DIGITS);
7058 : 63797 : i = DEC_DIGITS;
7059 : :
9237 JanWieck@Yahoo.com 7060 [ + + ]: 261405 : while (*cp)
7061 : : {
8533 tgl@sss.pgh.pa.us 7062 [ + + ]: 198181 : if (isdigit((unsigned char) *cp))
7063 : : {
7695 7064 : 189464 : decdigits[i++] = *cp++ - '0';
8853 7065 [ + + ]: 189464 : if (!have_dp)
7695 7066 : 153742 : dweight++;
7067 : : else
7068 : 35722 : dscale++;
7069 : : }
8853 7070 [ + + ]: 8717 : else if (*cp == '.')
7071 : : {
7072 [ - + ]: 8063 : if (have_dp)
435 dean.a.rasheed@gmail 7073 :UBC 0 : goto invalid_syntax;
2433 peter_e@gmx.net 7074 :CBC 8063 : have_dp = true;
8853 tgl@sss.pgh.pa.us 7075 : 8063 : cp++;
7076 : : /* decimal point must not be followed by underscore */
435 dean.a.rasheed@gmail 7077 [ + + ]: 8063 : if (*cp == '_')
7078 : 3 : goto invalid_syntax;
7079 : : }
7080 [ + + ]: 654 : else if (*cp == '_')
7081 : : {
7082 : : /* underscore must be followed by more digits */
7083 : 93 : cp++;
7084 [ + + ]: 93 : if (!isdigit((unsigned char) *cp))
7085 : 9 : goto invalid_syntax;
7086 : : }
7087 : : else
8853 tgl@sss.pgh.pa.us 7088 : 561 : break;
7089 : : }
7090 : :
7695 7091 : 63785 : ddigits = i - DEC_DIGITS;
7092 : : /* trailing padding for digit alignment later */
7559 bruce@momjian.us 7093 : 63785 : memset(decdigits + i, 0, DEC_DIGITS - 1);
7094 : :
7095 : : /* Handle exponent, if any */
9237 JanWieck@Yahoo.com 7096 [ + + + + ]: 63785 : if (*cp == 'e' || *cp == 'E')
7097 : : {
435 dean.a.rasheed@gmail 7098 : 537 : int64 exponent = 0;
7099 : 537 : bool neg = false;
7100 : :
7101 : : /*
7102 : : * At this point, dweight and dscale can't be more than about
7103 : : * INT_MAX/2 due to the MaxAllocSize limit on string length, so
7104 : : * constraining the exponent similarly should be enough to prevent
7105 : : * integer overflow in this function. If the value is too large to
7106 : : * fit in storage format, make_result() will complain about it later;
7107 : : * for consistency use the same ereport errcode/text as make_result().
7108 : : */
7109 : :
7110 : : /* exponent sign */
7111 : 537 : cp++;
7112 [ + + ]: 537 : if (*cp == '+')
7113 : 77 : cp++;
7114 [ + + ]: 460 : else if (*cp == '-')
7115 : : {
7116 : 196 : neg = true;
7117 : 196 : cp++;
7118 : : }
7119 : :
7120 : : /* exponent digits */
7121 [ + + ]: 537 : if (!isdigit((unsigned char) *cp))
7122 : 3 : goto invalid_syntax;
7123 : :
7124 [ + + ]: 1662 : while (*cp)
7125 : : {
7126 [ + + ]: 1137 : if (isdigit((unsigned char) *cp))
7127 : : {
7128 : 1116 : exponent = exponent * 10 + (*cp++ - '0');
7129 [ + + ]: 1116 : if (exponent > PG_INT32_MAX / 2)
7130 : 3 : goto out_of_range;
7131 : : }
7132 [ + - ]: 21 : else if (*cp == '_')
7133 : : {
7134 : : /* underscore must be followed by more digits */
7135 : 21 : cp++;
7136 [ + + ]: 21 : if (!isdigit((unsigned char) *cp))
7137 : 6 : goto invalid_syntax;
7138 : : }
7139 : : else
435 dean.a.rasheed@gmail 7140 :UBC 0 : break;
7141 : : }
7142 : :
435 dean.a.rasheed@gmail 7143 [ + + ]:CBC 525 : if (neg)
7144 : 196 : exponent = -exponent;
7145 : :
7695 tgl@sss.pgh.pa.us 7146 : 525 : dweight += (int) exponent;
7147 : 525 : dscale -= (int) exponent;
7148 [ + + ]: 525 : if (dscale < 0)
7149 : 227 : dscale = 0;
7150 : : }
7151 : :
7152 : : /*
7153 : : * Okay, convert pure-decimal representation to base NBASE. First we need
7154 : : * to determine the converted weight and ndigits. offset is the number of
7155 : : * decimal zeroes to insert before the first given digit to have a
7156 : : * correctly aligned first NBASE digit.
7157 : : */
7158 [ + + ]: 63773 : if (dweight >= 0)
7559 bruce@momjian.us 7159 : 63437 : weight = (dweight + 1 + DEC_DIGITS - 1) / DEC_DIGITS - 1;
7160 : : else
7161 : 336 : weight = -((-dweight - 1) / DEC_DIGITS + 1);
7695 tgl@sss.pgh.pa.us 7162 : 63773 : offset = (weight + 1) * DEC_DIGITS - (dweight + 1);
7559 bruce@momjian.us 7163 : 63773 : ndigits = (ddigits + offset + DEC_DIGITS - 1) / DEC_DIGITS;
7164 : :
7695 tgl@sss.pgh.pa.us 7165 : 63773 : alloc_var(dest, ndigits);
7166 : 63773 : dest->sign = sign;
7167 : 63773 : dest->weight = weight;
7168 : 63773 : dest->dscale = dscale;
7169 : :
7170 : 63773 : i = DEC_DIGITS - offset;
7171 : 63773 : digits = dest->digits;
7172 : :
7173 [ + + ]: 150374 : while (ndigits-- > 0)
7174 : : {
7175 : : #if DEC_DIGITS == 4
7559 bruce@momjian.us 7176 : 86601 : *digits++ = ((decdigits[i] * 10 + decdigits[i + 1]) * 10 +
7177 : 86601 : decdigits[i + 2]) * 10 + decdigits[i + 3];
7178 : : #elif DEC_DIGITS == 2
7179 : : *digits++ = decdigits[i] * 10 + decdigits[i + 1];
7180 : : #elif DEC_DIGITS == 1
7181 : : *digits++ = decdigits[i];
7182 : : #else
7183 : : #error unsupported NBASE
7184 : : #endif
7695 tgl@sss.pgh.pa.us 7185 : 86601 : i += DEC_DIGITS;
7186 : : }
7187 : :
7188 : 63773 : pfree(decdigits);
7189 : :
7190 : : /* Strip any leading/trailing zeroes, and normalize weight if zero */
7191 : 63773 : strip_var(dest);
7192 : :
7193 : : /* Return end+1 position for caller */
492 7194 : 63773 : *endptr = cp;
7195 : :
7196 : 63773 : return true;
7197 : :
435 dean.a.rasheed@gmail 7198 : 3 : out_of_range:
7199 [ + - ]: 3 : ereturn(escontext, false,
7200 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7201 : : errmsg("value overflows numeric format")));
7202 : :
7203 : 21 : invalid_syntax:
7204 [ + - ]: 21 : ereturn(escontext, false,
7205 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
7206 : : errmsg("invalid input syntax for type %s: \"%s\"",
7207 : : "numeric", str)));
7208 : : }
7209 : :
7210 : :
7211 : : /*
7212 : : * Return the numeric value of a single hex digit.
7213 : : */
7214 : : static inline int
447 7215 : 354 : xdigit_value(char dig)
7216 : : {
7217 [ + - + + ]: 447 : return dig >= '0' && dig <= '9' ? dig - '0' :
7218 [ + + + - ]: 147 : dig >= 'a' && dig <= 'f' ? dig - 'a' + 10 :
7219 [ + - + - ]: 54 : dig >= 'A' && dig <= 'F' ? dig - 'A' + 10 : -1;
7220 : : }
7221 : :
7222 : : /*
7223 : : * set_var_from_non_decimal_integer_str()
7224 : : *
7225 : : * Parse a string containing a non-decimal integer
7226 : : *
7227 : : * This function does not handle leading or trailing spaces. It returns
7228 : : * the end+1 position parsed into *endptr, so that caller can check for
7229 : : * trailing spaces/garbage if deemed necessary.
7230 : : *
7231 : : * cp is the place to actually start parsing; str is what to use in error
7232 : : * reports. The number's sign and base prefix indicator (e.g., "0x") are
7233 : : * assumed to have already been parsed, so cp should point to the number's
7234 : : * first digit in the base specified.
7235 : : *
7236 : : * base is expected to be 2, 8 or 16.
7237 : : *
7238 : : * Returns true on success, false on failure (if escontext points to an
7239 : : * ErrorSaveContext; otherwise errors are thrown).
7240 : : */
7241 : : static bool
7242 : 78 : set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign,
7243 : : int base, NumericVar *dest,
7244 : : const char **endptr, Node *escontext)
7245 : : {
7246 : 78 : const char *firstdigit = cp;
7247 : : int64 tmp;
7248 : : int64 mul;
7249 : : NumericVar tmp_var;
7250 : :
7251 : 78 : init_var(&tmp_var);
7252 : :
7253 : 78 : zero_var(dest);
7254 : :
7255 : : /*
7256 : : * Process input digits in groups that fit in int64. Here "tmp" is the
7257 : : * value of the digits in the group, and "mul" is base^n, where n is the
7258 : : * number of digits in the group. Thus tmp < mul, and we must start a new
7259 : : * group when mul * base threatens to overflow PG_INT64_MAX.
7260 : : */
7261 : 78 : tmp = 0;
7262 : 78 : mul = 1;
7263 : :
7264 [ + + ]: 78 : if (base == 16)
7265 : : {
7266 [ + + ]: 414 : while (*cp)
7267 : : {
7268 [ + + ]: 399 : if (isxdigit((unsigned char) *cp))
7269 : : {
7270 [ + + ]: 354 : if (mul > PG_INT64_MAX / 16)
7271 : : {
7272 : : /* Add the contribution from this group of digits */
7273 : 15 : int64_to_numericvar(mul, &tmp_var);
7274 : 15 : mul_var(dest, &tmp_var, dest, 0);
7275 : 15 : int64_to_numericvar(tmp, &tmp_var);
7276 : 15 : add_var(dest, &tmp_var, dest);
7277 : :
7278 : : /* Result will overflow if weight overflows int16 */
7279 [ - + ]: 15 : if (dest->weight > SHRT_MAX)
447 dean.a.rasheed@gmail 7280 :UBC 0 : goto out_of_range;
7281 : :
7282 : : /* Begin a new group */
447 dean.a.rasheed@gmail 7283 :CBC 15 : tmp = 0;
7284 : 15 : mul = 1;
7285 : : }
7286 : :
7287 : 354 : tmp = tmp * 16 + xdigit_value(*cp++);
7288 : 354 : mul = mul * 16;
7289 : : }
435 7290 [ + + ]: 45 : else if (*cp == '_')
7291 : : {
7292 : : /* Underscore must be followed by more digits */
7293 : 33 : cp++;
7294 [ + + ]: 33 : if (!isxdigit((unsigned char) *cp))
7295 : 9 : goto invalid_syntax;
7296 : : }
7297 : : else
447 7298 : 12 : break;
7299 : : }
7300 : : }
7301 [ + + ]: 42 : else if (base == 8)
7302 : : {
7303 [ + + ]: 318 : while (*cp)
7304 : : {
7305 [ + + + + ]: 303 : if (*cp >= '0' && *cp <= '7')
7306 : : {
7307 [ + + ]: 279 : if (mul > PG_INT64_MAX / 8)
7308 : : {
7309 : : /* Add the contribution from this group of digits */
7310 : 9 : int64_to_numericvar(mul, &tmp_var);
7311 : 9 : mul_var(dest, &tmp_var, dest, 0);
7312 : 9 : int64_to_numericvar(tmp, &tmp_var);
7313 : 9 : add_var(dest, &tmp_var, dest);
7314 : :
7315 : : /* Result will overflow if weight overflows int16 */
7316 [ - + ]: 9 : if (dest->weight > SHRT_MAX)
447 dean.a.rasheed@gmail 7317 :UBC 0 : goto out_of_range;
7318 : :
7319 : : /* Begin a new group */
447 dean.a.rasheed@gmail 7320 :CBC 9 : tmp = 0;
7321 : 9 : mul = 1;
7322 : : }
7323 : :
7324 : 279 : tmp = tmp * 8 + (*cp++ - '0');
7325 : 279 : mul = mul * 8;
7326 : : }
435 7327 [ + + ]: 24 : else if (*cp == '_')
7328 : : {
7329 : : /* Underscore must be followed by more digits */
7330 : 18 : cp++;
7331 [ + - - + ]: 18 : if (*cp < '0' || *cp > '7')
435 dean.a.rasheed@gmail 7332 :UBC 0 : goto invalid_syntax;
7333 : : }
7334 : : else
447 dean.a.rasheed@gmail 7335 :CBC 6 : break;
7336 : : }
7337 : : }
7338 [ + - ]: 21 : else if (base == 2)
7339 : : {
7340 [ + + ]: 780 : while (*cp)
7341 : : {
7342 [ + + + + ]: 765 : if (*cp >= '0' && *cp <= '1')
7343 : : {
7344 [ + + ]: 708 : if (mul > PG_INT64_MAX / 2)
7345 : : {
7346 : : /* Add the contribution from this group of digits */
7347 : 9 : int64_to_numericvar(mul, &tmp_var);
7348 : 9 : mul_var(dest, &tmp_var, dest, 0);
7349 : 9 : int64_to_numericvar(tmp, &tmp_var);
7350 : 9 : add_var(dest, &tmp_var, dest);
7351 : :
7352 : : /* Result will overflow if weight overflows int16 */
7353 [ - + ]: 9 : if (dest->weight > SHRT_MAX)
447 dean.a.rasheed@gmail 7354 :UBC 0 : goto out_of_range;
7355 : :
7356 : : /* Begin a new group */
447 dean.a.rasheed@gmail 7357 :CBC 9 : tmp = 0;
7358 : 9 : mul = 1;
7359 : : }
7360 : :
7361 : 708 : tmp = tmp * 2 + (*cp++ - '0');
7362 : 708 : mul = mul * 2;
7363 : : }
435 7364 [ + + ]: 57 : else if (*cp == '_')
7365 : : {
7366 : : /* Underscore must be followed by more digits */
7367 : 51 : cp++;
7368 [ + - - + ]: 51 : if (*cp < '0' || *cp > '1')
435 dean.a.rasheed@gmail 7369 :UBC 0 : goto invalid_syntax;
7370 : : }
7371 : : else
447 dean.a.rasheed@gmail 7372 :CBC 6 : break;
7373 : : }
7374 : : }
7375 : : else
7376 : : /* Should never happen; treat as invalid input */
447 dean.a.rasheed@gmail 7377 :UBC 0 : goto invalid_syntax;
7378 : :
7379 : : /* Check that we got at least one digit */
447 dean.a.rasheed@gmail 7380 [ - + ]:CBC 69 : if (unlikely(cp == firstdigit))
447 dean.a.rasheed@gmail 7381 :UBC 0 : goto invalid_syntax;
7382 : :
7383 : : /* Add the contribution from the final group of digits */
447 dean.a.rasheed@gmail 7384 :CBC 69 : int64_to_numericvar(mul, &tmp_var);
7385 : 69 : mul_var(dest, &tmp_var, dest, 0);
7386 : 69 : int64_to_numericvar(tmp, &tmp_var);
7387 : 69 : add_var(dest, &tmp_var, dest);
7388 : :
7389 [ - + ]: 69 : if (dest->weight > SHRT_MAX)
447 dean.a.rasheed@gmail 7390 :UBC 0 : goto out_of_range;
7391 : :
447 dean.a.rasheed@gmail 7392 :CBC 69 : dest->sign = sign;
7393 : :
7394 : 69 : free_var(&tmp_var);
7395 : :
7396 : : /* Return end+1 position for caller */
7397 : 69 : *endptr = cp;
7398 : :
7399 : 69 : return true;
7400 : :
447 dean.a.rasheed@gmail 7401 :UBC 0 : out_of_range:
7402 [ # # ]: 0 : ereturn(escontext, false,
7403 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7404 : : errmsg("value overflows numeric format")));
7405 : :
447 dean.a.rasheed@gmail 7406 :CBC 9 : invalid_syntax:
7407 [ + - ]: 9 : ereturn(escontext, false,
7408 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
7409 : : errmsg("invalid input syntax for type %s: \"%s\"",
7410 : : "numeric", str)));
7411 : : }
7412 : :
7413 : :
7414 : : /*
7415 : : * set_var_from_num() -
7416 : : *
7417 : : * Convert the packed db format into a variable
7418 : : */
7419 : : static void
9091 bruce@momjian.us 7420 : 6401 : set_var_from_num(Numeric num, NumericVar *dest)
7421 : : {
7422 : : int ndigits;
7423 : :
6641 7424 [ + + ]: 6401 : ndigits = NUMERIC_NDIGITS(num);
7425 : :
7695 tgl@sss.pgh.pa.us 7426 : 6401 : alloc_var(dest, ndigits);
7427 : :
5003 rhaas@postgresql.org 7428 [ + + + + ]: 6401 : dest->weight = NUMERIC_WEIGHT(num);
9091 bruce@momjian.us 7429 [ + + - + ]: 6401 : dest->sign = NUMERIC_SIGN(num);
7695 tgl@sss.pgh.pa.us 7430 [ + + ]: 6401 : dest->dscale = NUMERIC_DSCALE(num);
7431 : :
5003 rhaas@postgresql.org 7432 [ + + ]: 6401 : memcpy(dest->digits, NUMERIC_DIGITS(num), ndigits * sizeof(NumericDigit));
9237 JanWieck@Yahoo.com 7433 : 6401 : }
7434 : :
7435 : :
7436 : : /*
7437 : : * init_var_from_num() -
7438 : : *
7439 : : * Initialize a variable from packed db format. The digits array is not
7440 : : * copied, which saves some cycles when the resulting var is not modified.
7441 : : * Also, there's no need to call free_var(), as long as you don't assign any
7442 : : * other value to it (with set_var_* functions, or by using the var as the
7443 : : * destination of a function like add_var())
7444 : : *
7445 : : * CAUTION: Do not modify the digits buffer of a var initialized with this
7446 : : * function, e.g by calling round_var() or trunc_var(), as the changes will
7447 : : * propagate to the original Numeric! It's OK to use it as the destination
7448 : : * argument of one of the calculational functions, though.
7449 : : */
7450 : : static void
4162 heikki.linnakangas@i 7451 : 2546823 : init_var_from_num(Numeric num, NumericVar *dest)
7452 : : {
7453 [ + + ]: 2546823 : dest->ndigits = NUMERIC_NDIGITS(num);
7454 [ + + + + ]: 2546823 : dest->weight = NUMERIC_WEIGHT(num);
7455 [ + + - + ]: 2546823 : dest->sign = NUMERIC_SIGN(num);
7456 [ + + ]: 2546823 : dest->dscale = NUMERIC_DSCALE(num);
7457 [ + + ]: 2546823 : dest->digits = NUMERIC_DIGITS(num);
3973 bruce@momjian.us 7458 : 2546823 : dest->buf = NULL; /* digits array is not palloc'd */
4162 heikki.linnakangas@i 7459 : 2546823 : }
7460 : :
7461 : :
7462 : : /*
7463 : : * set_var_from_var() -
7464 : : *
7465 : : * Copy one variable into another
7466 : : */
7467 : : static void
2408 andres@anarazel.de 7468 : 18432 : set_var_from_var(const NumericVar *value, NumericVar *dest)
7469 : : {
7470 : : NumericDigit *newbuf;
7471 : :
8853 tgl@sss.pgh.pa.us 7472 : 18432 : newbuf = digitbuf_alloc(value->ndigits + 1);
7473 : 18432 : newbuf[0] = 0; /* spare digit for rounding */
3178 7474 [ + + ]: 18432 : if (value->ndigits > 0) /* else value->digits might be null */
7475 : 17965 : memcpy(newbuf + 1, value->digits,
7476 : 17965 : value->ndigits * sizeof(NumericDigit));
7477 : :
9237 JanWieck@Yahoo.com 7478 [ + + ]: 18432 : digitbuf_free(dest->buf);
7479 : :
7375 neilc@samurai.com 7480 : 18432 : memmove(dest, value, sizeof(NumericVar));
9091 bruce@momjian.us 7481 : 18432 : dest->buf = newbuf;
8853 tgl@sss.pgh.pa.us 7482 : 18432 : dest->digits = newbuf + 1;
7483 : 18432 : }
7484 : :
7485 : :
7486 : : /*
7487 : : * get_str_from_var() -
7488 : : *
7489 : : * Convert a var to text representation (guts of numeric_out).
7490 : : * The var is displayed to the number of digits indicated by its dscale.
7491 : : * Returns a palloc'd string.
7492 : : */
7493 : : static char *
2408 andres@anarazel.de 7494 : 398834 : get_str_from_var(const NumericVar *var)
7495 : : {
7496 : : int dscale;
7497 : : char *str;
7498 : : char *cp;
7499 : : char *endcp;
7500 : : int i;
7501 : : int d;
7502 : : NumericDigit dig;
7503 : :
7504 : : #if DEC_DIGITS > 1
7505 : : NumericDigit d1;
7506 : : #endif
7507 : :
4162 heikki.linnakangas@i 7508 : 398834 : dscale = var->dscale;
7509 : :
7510 : : /*
7511 : : * Allocate space for the result.
7512 : : *
7513 : : * i is set to the # of decimal digits before decimal point. dscale is the
7514 : : * # of decimal digits we will print after decimal point. We may generate
7515 : : * as many as DEC_DIGITS-1 excess digits at the end, and in addition we
7516 : : * need room for sign, decimal point, null terminator.
7517 : : */
7695 tgl@sss.pgh.pa.us 7518 : 398834 : i = (var->weight + 1) * DEC_DIGITS;
7519 [ + + ]: 398834 : if (i <= 0)
7520 : 69576 : i = 1;
7521 : :
7522 : 398834 : str = palloc(i + dscale + DEC_DIGITS + 2);
8853 7523 : 398834 : cp = str;
7524 : :
7525 : : /*
7526 : : * Output a dash for negative values
7527 : : */
7528 [ + + ]: 398834 : if (var->sign == NUMERIC_NEG)
7529 : 2473 : *cp++ = '-';
7530 : :
7531 : : /*
7532 : : * Output all digits before the decimal point
7533 : : */
7695 7534 [ + + ]: 398834 : if (var->weight < 0)
7535 : : {
7536 : 69576 : d = var->weight + 1;
7537 : 69576 : *cp++ = '0';
7538 : : }
7539 : : else
7540 : : {
7541 [ + + ]: 710965 : for (d = 0; d <= var->weight; d++)
7542 : : {
7543 [ + + ]: 381707 : dig = (d < var->ndigits) ? var->digits[d] : 0;
7544 : : /* In the first digit, suppress extra leading decimal zeroes */
7545 : : #if DEC_DIGITS == 4
7546 : : {
7559 bruce@momjian.us 7547 : 381707 : bool putit = (d > 0);
7548 : :
7695 tgl@sss.pgh.pa.us 7549 : 381707 : d1 = dig / 1000;
7550 : 381707 : dig -= d1 * 1000;
7551 : 381707 : putit |= (d1 > 0);
7552 [ + + ]: 381707 : if (putit)
7553 : 55691 : *cp++ = d1 + '0';
7554 : 381707 : d1 = dig / 100;
7555 : 381707 : dig -= d1 * 100;
7556 : 381707 : putit |= (d1 > 0);
7557 [ + + ]: 381707 : if (putit)
7558 : 258128 : *cp++ = d1 + '0';
7559 : 381707 : d1 = dig / 10;
7560 : 381707 : dig -= d1 * 10;
7561 : 381707 : putit |= (d1 > 0);
7562 [ + + ]: 381707 : if (putit)
7563 : 321560 : *cp++ = d1 + '0';
7564 : 381707 : *cp++ = dig + '0';
7565 : : }
7566 : : #elif DEC_DIGITS == 2
7567 : : d1 = dig / 10;
7568 : : dig -= d1 * 10;
7569 : : if (d1 > 0 || d > 0)
7570 : : *cp++ = d1 + '0';
7571 : : *cp++ = dig + '0';
7572 : : #elif DEC_DIGITS == 1
7573 : : *cp++ = dig + '0';
7574 : : #else
7575 : : #error unsupported NBASE
7576 : : #endif
7577 : : }
7578 : : }
7579 : :
7580 : : /*
7581 : : * If requested, output a decimal point and all the digits that follow it.
7582 : : * We initially put out a multiple of DEC_DIGITS digits, then truncate if
7583 : : * needed.
7584 : : */
8853 7585 [ + + ]: 398834 : if (dscale > 0)
7586 : : {
7587 : 321783 : *cp++ = '.';
7695 7588 : 321783 : endcp = cp + dscale;
7589 [ + + ]: 949093 : for (i = 0; i < dscale; d++, i += DEC_DIGITS)
7590 : : {
7591 [ + + + + ]: 627310 : dig = (d >= 0 && d < var->ndigits) ? var->digits[d] : 0;
7592 : : #if DEC_DIGITS == 4
7593 : 627310 : d1 = dig / 1000;
7594 : 627310 : dig -= d1 * 1000;
7595 : 627310 : *cp++ = d1 + '0';
7596 : 627310 : d1 = dig / 100;
7597 : 627310 : dig -= d1 * 100;
7598 : 627310 : *cp++ = d1 + '0';
7599 : 627310 : d1 = dig / 10;
7600 : 627310 : dig -= d1 * 10;
7601 : 627310 : *cp++ = d1 + '0';
7602 : 627310 : *cp++ = dig + '0';
7603 : : #elif DEC_DIGITS == 2
7604 : : d1 = dig / 10;
7605 : : dig -= d1 * 10;
7606 : : *cp++ = d1 + '0';
7607 : : *cp++ = dig + '0';
7608 : : #elif DEC_DIGITS == 1
7609 : : *cp++ = dig + '0';
7610 : : #else
7611 : : #error unsupported NBASE
7612 : : #endif
7613 : : }
7614 : 321783 : cp = endcp;
7615 : : }
7616 : :
7617 : : /*
7618 : : * terminate the string and return it
7619 : : */
8853 7620 : 398834 : *cp = '\0';
7621 : 398834 : return str;
7622 : : }
7623 : :
7624 : : /*
7625 : : * get_str_from_var_sci() -
7626 : : *
7627 : : * Convert a var to a normalised scientific notation text representation.
7628 : : * This function does the heavy lifting for numeric_out_sci().
7629 : : *
7630 : : * This notation has the general form a * 10^b, where a is known as the
7631 : : * "significand" and b is known as the "exponent".
7632 : : *
7633 : : * Because we can't do superscript in ASCII (and because we want to copy
7634 : : * printf's behaviour) we display the exponent using E notation, with a
7635 : : * minimum of two exponent digits.
7636 : : *
7637 : : * For example, the value 1234 could be output as 1.2e+03.
7638 : : *
7639 : : * We assume that the exponent can fit into an int32.
7640 : : *
7641 : : * rscale is the number of decimal digits desired after the decimal point in
7642 : : * the output, negative values will be treated as meaning zero.
7643 : : *
7644 : : * Returns a palloc'd string.
7645 : : */
7646 : : static char *
2408 andres@anarazel.de 7647 : 108 : get_str_from_var_sci(const NumericVar *var, int rscale)
7648 : : {
7649 : : int32 exponent;
7650 : : NumericVar tmp_var;
7651 : : size_t len;
7652 : : char *str;
7653 : : char *sig_out;
7654 : :
5361 tgl@sss.pgh.pa.us 7655 [ - + ]: 108 : if (rscale < 0)
5361 tgl@sss.pgh.pa.us 7656 :UBC 0 : rscale = 0;
7657 : :
7658 : : /*
7659 : : * Determine the exponent of this number in normalised form.
7660 : : *
7661 : : * This is the exponent required to represent the number with only one
7662 : : * significant digit before the decimal place.
7663 : : */
5361 tgl@sss.pgh.pa.us 7664 [ + + ]:CBC 108 : if (var->ndigits > 0)
7665 : : {
7666 : 99 : exponent = (var->weight + 1) * DEC_DIGITS;
7667 : :
7668 : : /*
7669 : : * Compensate for leading decimal zeroes in the first numeric digit by
7670 : : * decrementing the exponent.
7671 : : */
7672 : 99 : exponent -= DEC_DIGITS - (int) log10(var->digits[0]);
7673 : : }
7674 : : else
7675 : : {
7676 : : /*
7677 : : * If var has no digits, then it must be zero.
7678 : : *
7679 : : * Zero doesn't technically have a meaningful exponent in normalised
7680 : : * notation, but we just display the exponent as zero for consistency
7681 : : * of output.
7682 : : */
7683 : 9 : exponent = 0;
7684 : : }
7685 : :
7686 : : /*
7687 : : * Divide var by 10^exponent to get the significand, rounding to rscale
7688 : : * decimal digits in the process.
7689 : : */
983 dean.a.rasheed@gmail 7690 : 108 : init_var(&tmp_var);
7691 : :
7692 : 108 : power_ten_int(exponent, &tmp_var);
7693 : 108 : div_var(var, &tmp_var, &tmp_var, rscale, true);
7694 : 108 : sig_out = get_str_from_var(&tmp_var);
7695 : :
7696 : 108 : free_var(&tmp_var);
7697 : :
7698 : : /*
7699 : : * Allocate space for the result.
7700 : : *
7701 : : * In addition to the significand, we need room for the exponent
7702 : : * decoration ("e"), the sign of the exponent, up to 10 digits for the
7703 : : * exponent itself, and of course the null terminator.
7704 : : */
5361 tgl@sss.pgh.pa.us 7705 : 108 : len = strlen(sig_out) + 13;
7706 : 108 : str = palloc(len);
7707 : 108 : snprintf(str, len, "%se%+03d", sig_out, exponent);
7708 : :
7709 : 108 : pfree(sig_out);
7710 : :
7711 : 108 : return str;
7712 : : }
7713 : :
7714 : :
7715 : : /*
7716 : : * numericvar_serialize - serialize NumericVar to binary format
7717 : : *
7718 : : * At variable level, no checks are performed on the weight or dscale, allowing
7719 : : * us to pass around intermediate values with higher precision than supported
7720 : : * by the numeric type. Note: this is incompatible with numeric_send/recv(),
7721 : : * which use 16-bit integers for these fields.
7722 : : */
7723 : : static void
1014 dean.a.rasheed@gmail 7724 : 99 : numericvar_serialize(StringInfo buf, const NumericVar *var)
7725 : : {
7726 : : int i;
7727 : :
7728 : 99 : pq_sendint32(buf, var->ndigits);
7729 : 99 : pq_sendint32(buf, var->weight);
7730 : 99 : pq_sendint32(buf, var->sign);
7731 : 99 : pq_sendint32(buf, var->dscale);
7732 [ + + ]: 319044 : for (i = 0; i < var->ndigits; i++)
7733 : 318945 : pq_sendint16(buf, var->digits[i]);
7734 : 99 : }
7735 : :
7736 : : /*
7737 : : * numericvar_deserialize - deserialize binary format to NumericVar
7738 : : */
7739 : : static void
7740 : 99 : numericvar_deserialize(StringInfo buf, NumericVar *var)
7741 : : {
7742 : : int len,
7743 : : i;
7744 : :
7745 : 99 : len = pq_getmsgint(buf, sizeof(int32));
7746 : :
7747 : 99 : alloc_var(var, len); /* sets var->ndigits */
7748 : :
7749 : 99 : var->weight = pq_getmsgint(buf, sizeof(int32));
7750 : 99 : var->sign = pq_getmsgint(buf, sizeof(int32));
7751 : 99 : var->dscale = pq_getmsgint(buf, sizeof(int32));
7752 [ + + ]: 319044 : for (i = 0; i < len; i++)
7753 : 318945 : var->digits[i] = pq_getmsgint(buf, sizeof(int16));
7754 : 99 : }
7755 : :
7756 : :
7757 : : /*
7758 : : * duplicate_numeric() - copy a packed-format Numeric
7759 : : *
7760 : : * This will handle NaN and Infinity cases.
7761 : : */
7762 : : static Numeric
1362 tgl@sss.pgh.pa.us 7763 : 14246 : duplicate_numeric(Numeric num)
7764 : : {
7765 : : Numeric res;
7766 : :
7767 : 14246 : res = (Numeric) palloc(VARSIZE(num));
7768 : 14246 : memcpy(res, num, VARSIZE(num));
7769 : 14246 : return res;
7770 : : }
7771 : :
7772 : : /*
7773 : : * make_result_opt_error() -
7774 : : *
7775 : : * Create the packed db numeric format in palloc()'d memory from
7776 : : * a variable. This will handle NaN and Infinity cases.
7777 : : *
7778 : : * If "have_error" isn't NULL, on overflow *have_error is set to true and
7779 : : * NULL is returned. This is helpful when caller needs to handle errors.
7780 : : */
7781 : : static Numeric
1856 akorotkov@postgresql 7782 : 1636739 : make_result_opt_error(const NumericVar *var, bool *have_error)
7783 : : {
7784 : : Numeric result;
7695 tgl@sss.pgh.pa.us 7785 : 1636739 : NumericDigit *digits = var->digits;
9091 bruce@momjian.us 7786 : 1636739 : int weight = var->weight;
7787 : 1636739 : int sign = var->sign;
7788 : : int n;
7789 : : Size len;
7790 : :
1714 michael@paquier.xyz 7791 [ + + ]: 1636739 : if (have_error)
7792 : 52592 : *have_error = false;
7793 : :
1362 tgl@sss.pgh.pa.us 7794 [ + + ]: 1636739 : if ((sign & NUMERIC_SIGN_MASK) == NUMERIC_SPECIAL)
7795 : : {
7796 : : /*
7797 : : * Verify valid special value. This could be just an Assert, perhaps,
7798 : : * but it seems worthwhile to expend a few cycles to ensure that we
7799 : : * never write any nonzero reserved bits to disk.
7800 : : */
7801 [ + + + + : 2553 : if (!(sign == NUMERIC_NAN ||
- + ]
7802 : : sign == NUMERIC_PINF ||
7803 : : sign == NUMERIC_NINF))
1362 tgl@sss.pgh.pa.us 7804 [ # # ]:UBC 0 : elog(ERROR, "invalid numeric sign value 0x%x", sign);
7805 : :
5003 rhaas@postgresql.org 7806 :CBC 2553 : result = (Numeric) palloc(NUMERIC_HDRSZ_SHORT);
7807 : :
7808 : 2553 : SET_VARSIZE(result, NUMERIC_HDRSZ_SHORT);
1362 tgl@sss.pgh.pa.us 7809 : 2553 : result->choice.n_header = sign;
7810 : : /* the header word is all we need */
7811 : :
7812 : : dump_numeric("make_result()", result);
9237 JanWieck@Yahoo.com 7813 : 2553 : return result;
7814 : : }
7815 : :
7695 tgl@sss.pgh.pa.us 7816 : 1634186 : n = var->ndigits;
7817 : :
7818 : : /* truncate leading zeroes */
7819 [ + + + + ]: 1634198 : while (n > 0 && *digits == 0)
7820 : : {
7821 : 12 : digits++;
9237 JanWieck@Yahoo.com 7822 : 12 : weight--;
7823 : 12 : n--;
7824 : : }
7825 : : /* truncate trailing zeroes */
7695 tgl@sss.pgh.pa.us 7826 [ + + + + ]: 1676767 : while (n > 0 && digits[n - 1] == 0)
9237 JanWieck@Yahoo.com 7827 : 42581 : n--;
7828 : :
7829 : : /* If zero result, force to weight=0 and positive sign */
7830 [ + + ]: 1634186 : if (n == 0)
7831 : : {
7832 : 47459 : weight = 0;
9091 bruce@momjian.us 7833 : 47459 : sign = NUMERIC_POS;
7834 : : }
7835 : :
7836 : : /* Build the result */
5003 rhaas@postgresql.org 7837 [ + + + + : 1634186 : if (NUMERIC_CAN_BE_SHORT(var->dscale, weight))
+ - ]
7838 : : {
7839 : 1633301 : len = NUMERIC_HDRSZ_SHORT + n * sizeof(NumericDigit);
7840 : 1633301 : result = (Numeric) palloc(len);
7841 : 1633301 : SET_VARSIZE(result, len);
4891 peter_e@gmx.net 7842 : 1633301 : result->choice.n_short.n_header =
7843 : : (sign == NUMERIC_NEG ? (NUMERIC_SHORT | NUMERIC_SHORT_SIGN_MASK)
7844 : : : NUMERIC_SHORT)
5003 rhaas@postgresql.org 7845 [ + + ]: 1633301 : | (var->dscale << NUMERIC_SHORT_DSCALE_SHIFT)
7846 : 1633301 : | (weight < 0 ? NUMERIC_SHORT_WEIGHT_SIGN_MASK : 0)
7847 : 1633301 : | (weight & NUMERIC_SHORT_WEIGHT_MASK);
7848 : : }
7849 : : else
7850 : : {
7851 : 885 : len = NUMERIC_HDRSZ + n * sizeof(NumericDigit);
7852 : 885 : result = (Numeric) palloc(len);
7853 : 885 : SET_VARSIZE(result, len);
7854 : 885 : result->choice.n_long.n_sign_dscale =
7855 : 885 : sign | (var->dscale & NUMERIC_DSCALE_MASK);
7856 : 885 : result->choice.n_long.n_weight = weight;
7857 : : }
7858 : :
7859 [ + + - + ]: 1634186 : Assert(NUMERIC_NDIGITS(result) == n);
3178 tgl@sss.pgh.pa.us 7860 [ + + ]: 1634186 : if (n > 0)
7861 [ + + ]: 1586727 : memcpy(NUMERIC_DIGITS(result), digits, n * sizeof(NumericDigit));
7862 : :
7863 : : /* Check for overflow of int16 fields */
5003 rhaas@postgresql.org 7864 [ + + + + : 1634186 : if (NUMERIC_WEIGHT(result) != weight ||
+ + ]
7695 tgl@sss.pgh.pa.us 7865 [ + + - + ]: 1634174 : NUMERIC_DSCALE(result) != var->dscale)
7866 : : {
1856 akorotkov@postgresql 7867 [ + + ]: 12 : if (have_error)
7868 : : {
7869 : 9 : *have_error = true;
7870 : 9 : return NULL;
7871 : : }
7872 : : else
7873 : : {
7874 [ + - ]: 3 : ereport(ERROR,
7875 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7876 : : errmsg("value overflows numeric format")));
7877 : : }
7878 : : }
7879 : :
7880 : : dump_numeric("make_result()", result);
9237 JanWieck@Yahoo.com 7881 : 1634174 : return result;
7882 : : }
7883 : :
7884 : :
7885 : : /*
7886 : : * make_result() -
7887 : : *
7888 : : * An interface to make_result_opt_error() without "have_error" argument.
7889 : : */
7890 : : static Numeric
1856 akorotkov@postgresql 7891 : 1064849 : make_result(const NumericVar *var)
7892 : : {
7893 : 1064849 : return make_result_opt_error(var, NULL);
7894 : : }
7895 : :
7896 : :
7897 : : /*
7898 : : * apply_typmod() -
7899 : : *
7900 : : * Do bounds checking and rounding according to the specified typmod.
7901 : : * Note that this is only applied to normal finite values.
7902 : : *
7903 : : * Returns true on success, false on failure (if escontext points to an
7904 : : * ErrorSaveContext; otherwise errors are thrown).
7905 : : */
7906 : : static bool
492 tgl@sss.pgh.pa.us 7907 : 54662 : apply_typmod(NumericVar *var, int32 typmod, Node *escontext)
7908 : : {
7909 : : int precision;
7910 : : int scale;
7911 : : int maxdigits;
7912 : : int ddigits;
7913 : : int i;
7914 : :
7915 : : /* Do nothing if we have an invalid typmod */
993 dean.a.rasheed@gmail 7916 [ + + ]: 54662 : if (!is_valid_numeric_typmod(typmod))
492 tgl@sss.pgh.pa.us 7917 : 52328 : return true;
7918 : :
993 dean.a.rasheed@gmail 7919 : 2334 : precision = numeric_typmod_precision(typmod);
7920 : 2334 : scale = numeric_typmod_scale(typmod);
7695 tgl@sss.pgh.pa.us 7921 : 2334 : maxdigits = precision - scale;
7922 : :
7923 : : /* Round to target scale (and set var->dscale) */
7924 : 2334 : round_var(var, scale);
7925 : :
7926 : : /* but don't allow var->dscale to be negative */
993 dean.a.rasheed@gmail 7927 [ + + ]: 2334 : if (var->dscale < 0)
7928 : 63 : var->dscale = 0;
7929 : :
7930 : : /*
7931 : : * Check for overflow - note we can't do this before rounding, because
7932 : : * rounding could raise the weight. Also note that the var's weight could
7933 : : * be inflated by leading zeroes, which will be stripped before storage
7934 : : * but perhaps might not have been yet. In any case, we must recognize a
7935 : : * true zero, whose weight doesn't mean anything.
7936 : : */
7695 tgl@sss.pgh.pa.us 7937 : 2334 : ddigits = (var->weight + 1) * DEC_DIGITS;
7938 [ + + ]: 2334 : if (ddigits > maxdigits)
7939 : : {
7940 : : /* Determine true weight; and check for all-zero result */
8856 7941 [ + + ]: 191 : for (i = 0; i < var->ndigits; i++)
7942 : : {
7695 7943 : 184 : NumericDigit dig = var->digits[i];
7944 : :
7945 [ + - ]: 184 : if (dig)
7946 : : {
7947 : : /* Adjust for any high-order decimal zero digits */
7948 : : #if DEC_DIGITS == 4
7949 [ + + ]: 184 : if (dig < 10)
7950 : 117 : ddigits -= 3;
7951 [ + + ]: 67 : else if (dig < 100)
7952 : 33 : ddigits -= 2;
7953 [ + + ]: 34 : else if (dig < 1000)
7954 : 25 : ddigits -= 1;
7955 : : #elif DEC_DIGITS == 2
7956 : : if (dig < 10)
7957 : : ddigits -= 1;
7958 : : #elif DEC_DIGITS == 1
7959 : : /* no adjustment */
7960 : : #else
7961 : : #error unsupported NBASE
7962 : : #endif
7963 [ + + ]: 184 : if (ddigits > maxdigits)
492 7964 [ + + + + : 42 : ereturn(escontext, false,
+ + ]
7965 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7966 : : errmsg("numeric field overflow"),
7967 : : errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.",
7968 : : precision, scale,
7969 : : /* Display 10^0 as 1 */
7970 : : maxdigits ? "10^" : "",
7971 : : maxdigits ? maxdigits : 1
7972 : : )));
8856 7973 : 142 : break;
7974 : : }
7695 tgl@sss.pgh.pa.us 7975 :UBC 0 : ddigits -= DEC_DIGITS;
7976 : : }
7977 : : }
7978 : :
492 tgl@sss.pgh.pa.us 7979 :CBC 2292 : return true;
7980 : : }
7981 : :
7982 : : /*
7983 : : * apply_typmod_special() -
7984 : : *
7985 : : * Do bounds checking according to the specified typmod, for an Inf or NaN.
7986 : : * For convenience of most callers, the value is presented in packed form.
7987 : : *
7988 : : * Returns true on success, false on failure (if escontext points to an
7989 : : * ErrorSaveContext; otherwise errors are thrown).
7990 : : */
7991 : : static bool
7992 : 886 : apply_typmod_special(Numeric num, int32 typmod, Node *escontext)
7993 : : {
7994 : : int precision;
7995 : : int scale;
7996 : :
1362 7997 [ - + ]: 886 : Assert(NUMERIC_IS_SPECIAL(num)); /* caller error if not */
7998 : :
7999 : : /*
8000 : : * NaN is allowed regardless of the typmod; that's rather dubious perhaps,
8001 : : * but it's a longstanding behavior. Inf is rejected if we have any
8002 : : * typmod restriction, since an infinity shouldn't be claimed to fit in
8003 : : * any finite number of digits.
8004 : : */
8005 [ + + ]: 886 : if (NUMERIC_IS_NAN(num))
492 8006 : 385 : return true;
8007 : :
8008 : : /* Do nothing if we have a default typmod (-1) */
993 dean.a.rasheed@gmail 8009 [ + + ]: 501 : if (!is_valid_numeric_typmod(typmod))
492 tgl@sss.pgh.pa.us 8010 : 492 : return true;
8011 : :
993 dean.a.rasheed@gmail 8012 : 9 : precision = numeric_typmod_precision(typmod);
8013 : 9 : scale = numeric_typmod_scale(typmod);
8014 : :
492 tgl@sss.pgh.pa.us 8015 [ + - ]: 9 : ereturn(escontext, false,
8016 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
8017 : : errmsg("numeric field overflow"),
8018 : : errdetail("A field with precision %d, scale %d cannot hold an infinite value.",
8019 : : precision, scale)));
8020 : : }
8021 : :
8022 : :
8023 : : /*
8024 : : * Convert numeric to int8, rounding if needed.
8025 : : *
8026 : : * If overflow, return false (no error is raised). Return true if okay.
8027 : : */
8028 : : static bool
2408 andres@anarazel.de 8029 : 5499 : numericvar_to_int64(const NumericVar *var, int64 *result)
8030 : : {
8031 : : NumericDigit *digits;
8032 : : int ndigits;
8033 : : int weight;
8034 : : int i;
8035 : : int64 val;
8036 : : bool neg;
8037 : : NumericVar rounded;
8038 : :
8039 : : /* Round to nearest integer */
4162 heikki.linnakangas@i 8040 : 5499 : init_var(&rounded);
8041 : 5499 : set_var_from_var(var, &rounded);
8042 : 5499 : round_var(&rounded, 0);
8043 : :
8044 : : /* Check for zero input */
8045 : 5499 : strip_var(&rounded);
8046 : 5499 : ndigits = rounded.ndigits;
7695 tgl@sss.pgh.pa.us 8047 [ + + ]: 5499 : if (ndigits == 0)
8048 : : {
8049 : 233 : *result = 0;
4162 heikki.linnakangas@i 8050 : 233 : free_var(&rounded);
7695 tgl@sss.pgh.pa.us 8051 : 233 : return true;
8052 : : }
8053 : :
8054 : : /*
8055 : : * For input like 10000000000, we must treat stripped digits as real. So
8056 : : * the loop assumes there are weight+1 digits before the decimal point.
8057 : : */
4162 heikki.linnakangas@i 8058 : 5266 : weight = rounded.weight;
7559 bruce@momjian.us 8059 [ + - - + ]: 5266 : Assert(weight >= 0 && ndigits <= weight + 1);
8060 : :
8061 : : /*
8062 : : * Construct the result. To avoid issues with converting a value
8063 : : * corresponding to INT64_MIN (which can't be represented as a positive 64
8064 : : * bit two's complement integer), accumulate value as a negative number.
8065 : : */
4162 heikki.linnakangas@i 8066 : 5266 : digits = rounded.digits;
8067 : 5266 : neg = (rounded.sign == NUMERIC_NEG);
2315 andres@anarazel.de 8068 : 5266 : val = -digits[0];
7591 tgl@sss.pgh.pa.us 8069 [ + + ]: 7711 : for (i = 1; i <= weight; i++)
8070 : : {
2315 andres@anarazel.de 8071 [ + + ]: 2469 : if (unlikely(pg_mul_s64_overflow(val, NBASE, &val)))
8072 : : {
8073 : 15 : free_var(&rounded);
8074 : 15 : return false;
8075 : : }
8076 : :
8077 [ + + ]: 2454 : if (i < ndigits)
8078 : : {
8079 [ + + ]: 2323 : if (unlikely(pg_sub_s64_overflow(val, digits[i], &val)))
8080 : : {
4162 heikki.linnakangas@i 8081 : 9 : free_var(&rounded);
7695 tgl@sss.pgh.pa.us 8082 : 9 : return false;
8083 : : }
8084 : : }
8085 : : }
8086 : :
4162 heikki.linnakangas@i 8087 : 5242 : free_var(&rounded);
8088 : :
2315 andres@anarazel.de 8089 [ + + ]: 5242 : if (!neg)
8090 : : {
8091 [ + + ]: 4858 : if (unlikely(val == PG_INT64_MIN))
8092 : 12 : return false;
8093 : 4846 : val = -val;
8094 : : }
8095 : 5230 : *result = val;
8096 : :
7695 tgl@sss.pgh.pa.us 8097 : 5230 : return true;
8098 : : }
8099 : :
8100 : : /*
8101 : : * Convert int8 value to numeric.
8102 : : */
8103 : : static void
3313 andres@anarazel.de 8104 : 940581 : int64_to_numericvar(int64 val, NumericVar *var)
8105 : : {
8106 : : uint64 uval,
8107 : : newuval;
8108 : : NumericDigit *ptr;
8109 : : int ndigits;
8110 : :
8111 : : /* int64 can require at most 19 decimal digits; add one for safety */
7559 bruce@momjian.us 8112 : 940581 : alloc_var(var, 20 / DEC_DIGITS);
7695 tgl@sss.pgh.pa.us 8113 [ + + ]: 940581 : if (val < 0)
8114 : : {
8115 : 805 : var->sign = NUMERIC_NEG;
8116 : 805 : uval = -val;
8117 : : }
8118 : : else
8119 : : {
8120 : 939776 : var->sign = NUMERIC_POS;
8121 : 939776 : uval = val;
8122 : : }
8123 : 940581 : var->dscale = 0;
8124 [ + + ]: 940581 : if (val == 0)
8125 : : {
8126 : 17440 : var->ndigits = 0;
8127 : 17440 : var->weight = 0;
8128 : 17440 : return;
8129 : : }
8130 : 923141 : ptr = var->digits + var->ndigits;
8131 : 923141 : ndigits = 0;
8132 : : do
8133 : : {
8134 : 1085673 : ptr--;
8135 : 1085673 : ndigits++;
8136 : 1085673 : newuval = uval / NBASE;
8137 : 1085673 : *ptr = uval - newuval * NBASE;
8138 : 1085673 : uval = newuval;
8139 [ + + ]: 1085673 : } while (uval);
8140 : 923141 : var->digits = ptr;
8141 : 923141 : var->ndigits = ndigits;
8142 : 923141 : var->weight = ndigits - 1;
8143 : : }
8144 : :
8145 : : /*
8146 : : * Convert numeric to uint64, rounding if needed.
8147 : : *
8148 : : * If overflow, return false (no error is raised). Return true if okay.
8149 : : */
8150 : : static bool
1384 fujii@postgresql.org 8151 : 57 : numericvar_to_uint64(const NumericVar *var, uint64 *result)
8152 : : {
8153 : : NumericDigit *digits;
8154 : : int ndigits;
8155 : : int weight;
8156 : : int i;
8157 : : uint64 val;
8158 : : NumericVar rounded;
8159 : :
8160 : : /* Round to nearest integer */
8161 : 57 : init_var(&rounded);
8162 : 57 : set_var_from_var(var, &rounded);
8163 : 57 : round_var(&rounded, 0);
8164 : :
8165 : : /* Check for zero input */
8166 : 57 : strip_var(&rounded);
8167 : 57 : ndigits = rounded.ndigits;
8168 [ + + ]: 57 : if (ndigits == 0)
8169 : : {
8170 : 9 : *result = 0;
8171 : 9 : free_var(&rounded);
8172 : 9 : return true;
8173 : : }
8174 : :
8175 : : /* Check for negative input */
8176 [ + + ]: 48 : if (rounded.sign == NUMERIC_NEG)
8177 : : {
8178 : 6 : free_var(&rounded);
8179 : 6 : return false;
8180 : : }
8181 : :
8182 : : /*
8183 : : * For input like 10000000000, we must treat stripped digits as real. So
8184 : : * the loop assumes there are weight+1 digits before the decimal point.
8185 : : */
8186 : 42 : weight = rounded.weight;
8187 [ + - - + ]: 42 : Assert(weight >= 0 && ndigits <= weight + 1);
8188 : :
8189 : : /* Construct the result */
8190 : 42 : digits = rounded.digits;
8191 : 42 : val = digits[0];
8192 [ + + ]: 123 : for (i = 1; i <= weight; i++)
8193 : : {
8194 [ - + ]: 87 : if (unlikely(pg_mul_u64_overflow(val, NBASE, &val)))
8195 : : {
1384 fujii@postgresql.org 8196 :UBC 0 : free_var(&rounded);
8197 : 0 : return false;
8198 : : }
8199 : :
1384 fujii@postgresql.org 8200 [ + - ]:CBC 87 : if (i < ndigits)
8201 : : {
8202 [ + + ]: 87 : if (unlikely(pg_add_u64_overflow(val, digits[i], &val)))
8203 : : {
8204 : 6 : free_var(&rounded);
8205 : 6 : return false;
8206 : : }
8207 : : }
8208 : : }
8209 : :
8210 : 36 : free_var(&rounded);
8211 : :
8212 : 36 : *result = val;
8213 : :
8214 : 36 : return true;
8215 : : }
8216 : :
8217 : : #ifdef HAVE_INT128
8218 : : /*
8219 : : * Convert numeric to int128, rounding if needed.
8220 : : *
8221 : : * If overflow, return false (no error is raised). Return true if okay.
8222 : : */
8223 : : static bool
2408 andres@anarazel.de 8224 : 51 : numericvar_to_int128(const NumericVar *var, int128 *result)
8225 : : {
8226 : : NumericDigit *digits;
8227 : : int ndigits;
8228 : : int weight;
8229 : : int i;
8230 : : int128 val,
8231 : : oldval;
8232 : : bool neg;
8233 : : NumericVar rounded;
8234 : :
8235 : : /* Round to nearest integer */
2931 rhaas@postgresql.org 8236 : 51 : init_var(&rounded);
8237 : 51 : set_var_from_var(var, &rounded);
8238 : 51 : round_var(&rounded, 0);
8239 : :
8240 : : /* Check for zero input */
8241 : 51 : strip_var(&rounded);
8242 : 51 : ndigits = rounded.ndigits;
8243 [ - + ]: 51 : if (ndigits == 0)
8244 : : {
2931 rhaas@postgresql.org 8245 :UBC 0 : *result = 0;
8246 : 0 : free_var(&rounded);
8247 : 0 : return true;
8248 : : }
8249 : :
8250 : : /*
8251 : : * For input like 10000000000, we must treat stripped digits as real. So
8252 : : * the loop assumes there are weight+1 digits before the decimal point.
8253 : : */
2931 rhaas@postgresql.org 8254 :CBC 51 : weight = rounded.weight;
8255 [ + - - + ]: 51 : Assert(weight >= 0 && ndigits <= weight + 1);
8256 : :
8257 : : /* Construct the result */
8258 : 51 : digits = rounded.digits;
8259 : 51 : neg = (rounded.sign == NUMERIC_NEG);
8260 : 51 : val = digits[0];
8261 [ + + ]: 114 : for (i = 1; i <= weight; i++)
8262 : : {
8263 : 63 : oldval = val;
8264 : 63 : val *= NBASE;
8265 [ + - ]: 63 : if (i < ndigits)
8266 : 63 : val += digits[i];
8267 : :
8268 : : /*
8269 : : * The overflow check is a bit tricky because we want to accept
8270 : : * INT128_MIN, which will overflow the positive accumulator. We can
8271 : : * detect this case easily though because INT128_MIN is the only
8272 : : * nonzero value for which -val == val (on a two's complement machine,
8273 : : * anyway).
8274 : : */
8275 [ - + ]: 63 : if ((val / NBASE) != oldval) /* possible overflow? */
8276 : : {
2931 rhaas@postgresql.org 8277 [ # # # # :UBC 0 : if (!neg || (-val) != val || val == 0 || oldval < 0)
# # # # ]
8278 : : {
8279 : 0 : free_var(&rounded);
8280 : 0 : return false;
8281 : : }
8282 : : }
8283 : : }
8284 : :
2931 rhaas@postgresql.org 8285 :CBC 51 : free_var(&rounded);
8286 : :
8287 [ - + ]: 51 : *result = neg ? -val : val;
8288 : 51 : return true;
8289 : : }
8290 : :
8291 : : /*
8292 : : * Convert 128 bit integer to numeric.
8293 : : */
8294 : : static void
3313 andres@anarazel.de 8295 : 4312 : int128_to_numericvar(int128 val, NumericVar *var)
8296 : : {
8297 : : uint128 uval,
8298 : : newuval;
8299 : : NumericDigit *ptr;
8300 : : int ndigits;
8301 : :
8302 : : /* int128 can require at most 39 decimal digits; add one for safety */
8303 : 4312 : alloc_var(var, 40 / DEC_DIGITS);
8304 [ - + ]: 4312 : if (val < 0)
8305 : : {
3313 andres@anarazel.de 8306 :UBC 0 : var->sign = NUMERIC_NEG;
8307 : 0 : uval = -val;
8308 : : }
8309 : : else
8310 : : {
3313 andres@anarazel.de 8311 :CBC 4312 : var->sign = NUMERIC_POS;
8312 : 4312 : uval = val;
8313 : : }
8314 : 4312 : var->dscale = 0;
8315 [ + + ]: 4312 : if (val == 0)
8316 : : {
8317 : 65 : var->ndigits = 0;
8318 : 65 : var->weight = 0;
8319 : 65 : return;
8320 : : }
8321 : 4247 : ptr = var->digits + var->ndigits;
8322 : 4247 : ndigits = 0;
8323 : : do
8324 : : {
8325 : 22520 : ptr--;
8326 : 22520 : ndigits++;
8327 : 22520 : newuval = uval / NBASE;
8328 : 22520 : *ptr = uval - newuval * NBASE;
8329 : 22520 : uval = newuval;
8330 [ + + ]: 22520 : } while (uval);
8331 : 4247 : var->digits = ptr;
8332 : 4247 : var->ndigits = ndigits;
8333 : 4247 : var->weight = ndigits - 1;
8334 : : }
8335 : : #endif
8336 : :
8337 : : /*
8338 : : * Convert a NumericVar to float8; if out of range, return +/- HUGE_VAL
8339 : : */
8340 : : static double
2408 8341 : 1791 : numericvar_to_double_no_overflow(const NumericVar *var)
8342 : : {
8343 : : char *tmp;
8344 : : double val;
8345 : : char *endptr;
8346 : :
4162 heikki.linnakangas@i 8347 : 1791 : tmp = get_str_from_var(var);
8348 : :
8349 : : /* unlike float8in, we ignore ERANGE from strtod */
7865 tgl@sss.pgh.pa.us 8350 : 1791 : val = strtod(tmp, &endptr);
8351 [ - + ]: 1791 : if (*endptr != '\0')
8352 : : {
8353 : : /* shouldn't happen ... */
7567 tgl@sss.pgh.pa.us 8354 [ # # ]:UBC 0 : ereport(ERROR,
8355 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
8356 : : errmsg("invalid input syntax for type %s: \"%s\"",
8357 : : "double precision", tmp)));
8358 : : }
8359 : :
7865 tgl@sss.pgh.pa.us 8360 :CBC 1791 : pfree(tmp);
8361 : :
8362 : 1791 : return val;
8363 : : }
8364 : :
8365 : :
8366 : : /*
8367 : : * cmp_var() -
8368 : : *
8369 : : * Compare two values on variable level. We assume zeroes have been
8370 : : * truncated to no digits.
8371 : : */
8372 : : static int
2408 andres@anarazel.de 8373 : 25093 : cmp_var(const NumericVar *var1, const NumericVar *var2)
8374 : : {
6641 bruce@momjian.us 8375 : 50186 : return cmp_var_common(var1->digits, var1->ndigits,
8376 : 25093 : var1->weight, var1->sign,
8377 : 25093 : var2->digits, var2->ndigits,
8378 : 25093 : var2->weight, var2->sign);
8379 : : }
8380 : :
8381 : : /*
8382 : : * cmp_var_common() -
8383 : : *
8384 : : * Main routine of cmp_var(). This function can be used by both
8385 : : * NumericVar and Numeric.
8386 : : */
8387 : : static int
8388 : 3297724 : cmp_var_common(const NumericDigit *var1digits, int var1ndigits,
8389 : : int var1weight, int var1sign,
8390 : : const NumericDigit *var2digits, int var2ndigits,
8391 : : int var2weight, int var2sign)
8392 : : {
8393 [ + + ]: 3297724 : if (var1ndigits == 0)
8394 : : {
8395 [ + + ]: 98104 : if (var2ndigits == 0)
9237 JanWieck@Yahoo.com 8396 : 83746 : return 0;
6641 bruce@momjian.us 8397 [ + + ]: 14358 : if (var2sign == NUMERIC_NEG)
9237 JanWieck@Yahoo.com 8398 : 2245 : return 1;
8399 : 12113 : return -1;
8400 : : }
6641 bruce@momjian.us 8401 [ + + ]: 3199620 : if (var2ndigits == 0)
8402 : : {
8403 [ + + ]: 16972 : if (var1sign == NUMERIC_POS)
9237 JanWieck@Yahoo.com 8404 : 13190 : return 1;
8405 : 3782 : return -1;
8406 : : }
8407 : :
6641 bruce@momjian.us 8408 [ + + ]: 3182648 : if (var1sign == NUMERIC_POS)
8409 : : {
8410 [ + + ]: 3135627 : if (var2sign == NUMERIC_NEG)
9237 JanWieck@Yahoo.com 8411 : 13434 : return 1;
6641 bruce@momjian.us 8412 : 3122193 : return cmp_abs_common(var1digits, var1ndigits, var1weight,
8413 : : var2digits, var2ndigits, var2weight);
8414 : : }
8415 : :
8416 [ + + ]: 47021 : if (var2sign == NUMERIC_POS)
9237 JanWieck@Yahoo.com 8417 : 14561 : return -1;
8418 : :
6641 bruce@momjian.us 8419 : 32460 : return cmp_abs_common(var2digits, var2ndigits, var2weight,
8420 : : var1digits, var1ndigits, var1weight);
8421 : : }
8422 : :
8423 : :
8424 : : /*
8425 : : * add_var() -
8426 : : *
8427 : : * Full version of add functionality on variable level (handling signs).
8428 : : * result might point to one of the operands too without danger.
8429 : : */
8430 : : static void
2408 andres@anarazel.de 8431 : 248792 : add_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
8432 : : {
8433 : : /*
8434 : : * Decide on the signs of the two variables what to do
8435 : : */
9237 JanWieck@Yahoo.com 8436 [ + + ]: 248792 : if (var1->sign == NUMERIC_POS)
8437 : : {
8438 [ + + ]: 248009 : if (var2->sign == NUMERIC_POS)
8439 : : {
8440 : : /*
8441 : : * Both are positive result = +(ABS(var1) + ABS(var2))
8442 : : */
8443 : 147896 : add_abs(var1, var2, result);
8444 : 147896 : result->sign = NUMERIC_POS;
8445 : : }
8446 : : else
8447 : : {
8448 : : /*
8449 : : * var1 is positive, var2 is negative Must compare absolute values
8450 : : */
8451 [ + + + - ]: 100113 : switch (cmp_abs(var1, var2))
8452 : : {
8672 tgl@sss.pgh.pa.us 8453 : 83 : case 0:
8454 : : /* ----------
8455 : : * ABS(var1) == ABS(var2)
8456 : : * result = ZERO
8457 : : * ----------
8458 : : */
8853 8459 : 83 : zero_var(result);
8091 bruce@momjian.us 8460 : 83 : result->dscale = Max(var1->dscale, var2->dscale);
9091 8461 : 83 : break;
8462 : :
8672 tgl@sss.pgh.pa.us 8463 : 93085 : case 1:
8464 : : /* ----------
8465 : : * ABS(var1) > ABS(var2)
8466 : : * result = +(ABS(var1) - ABS(var2))
8467 : : * ----------
8468 : : */
9091 bruce@momjian.us 8469 : 93085 : sub_abs(var1, var2, result);
8470 : 93085 : result->sign = NUMERIC_POS;
8471 : 93085 : break;
8472 : :
8672 tgl@sss.pgh.pa.us 8473 : 6945 : case -1:
8474 : : /* ----------
8475 : : * ABS(var1) < ABS(var2)
8476 : : * result = -(ABS(var2) - ABS(var1))
8477 : : * ----------
8478 : : */
9091 bruce@momjian.us 8479 : 6945 : sub_abs(var2, var1, result);
8480 : 6945 : result->sign = NUMERIC_NEG;
8481 : 6945 : break;
8482 : : }
8483 : : }
8484 : : }
8485 : : else
8486 : : {
9237 JanWieck@Yahoo.com 8487 [ + + ]: 783 : if (var2->sign == NUMERIC_POS)
8488 : : {
8489 : : /* ----------
8490 : : * var1 is negative, var2 is positive
8491 : : * Must compare absolute values
8492 : : * ----------
8493 : : */
8494 [ + + + - ]: 234 : switch (cmp_abs(var1, var2))
8495 : : {
8672 tgl@sss.pgh.pa.us 8496 : 15 : case 0:
8497 : : /* ----------
8498 : : * ABS(var1) == ABS(var2)
8499 : : * result = ZERO
8500 : : * ----------
8501 : : */
8853 8502 : 15 : zero_var(result);
8091 bruce@momjian.us 8503 : 15 : result->dscale = Max(var1->dscale, var2->dscale);
9091 8504 : 15 : break;
8505 : :
8672 tgl@sss.pgh.pa.us 8506 : 147 : case 1:
8507 : : /* ----------
8508 : : * ABS(var1) > ABS(var2)
8509 : : * result = -(ABS(var1) - ABS(var2))
8510 : : * ----------
8511 : : */
9091 bruce@momjian.us 8512 : 147 : sub_abs(var1, var2, result);
8513 : 147 : result->sign = NUMERIC_NEG;
8514 : 147 : break;
8515 : :
8672 tgl@sss.pgh.pa.us 8516 : 72 : case -1:
8517 : : /* ----------
8518 : : * ABS(var1) < ABS(var2)
8519 : : * result = +(ABS(var2) - ABS(var1))
8520 : : * ----------
8521 : : */
9091 bruce@momjian.us 8522 : 72 : sub_abs(var2, var1, result);
8523 : 72 : result->sign = NUMERIC_POS;
8524 : 72 : break;
8525 : : }
8526 : : }
8527 : : else
8528 : : {
8529 : : /* ----------
8530 : : * Both are negative
8531 : : * result = -(ABS(var1) + ABS(var2))
8532 : : * ----------
8533 : : */
9237 JanWieck@Yahoo.com 8534 : 549 : add_abs(var1, var2, result);
8535 : 549 : result->sign = NUMERIC_NEG;
8536 : : }
8537 : : }
8538 : 248792 : }
8539 : :
8540 : :
8541 : : /*
8542 : : * sub_var() -
8543 : : *
8544 : : * Full version of sub functionality on variable level (handling signs).
8545 : : * result might point to one of the operands too without danger.
8546 : : */
8547 : : static void
2408 andres@anarazel.de 8548 : 94334 : sub_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
8549 : : {
8550 : : /*
8551 : : * Decide on the signs of the two variables what to do
8552 : : */
9237 JanWieck@Yahoo.com 8553 [ + + ]: 94334 : if (var1->sign == NUMERIC_POS)
8554 : : {
8555 [ + + ]: 92878 : if (var2->sign == NUMERIC_NEG)
8556 : : {
8557 : : /* ----------
8558 : : * var1 is positive, var2 is negative
8559 : : * result = +(ABS(var1) + ABS(var2))
8560 : : * ----------
8561 : : */
8562 : 16790 : add_abs(var1, var2, result);
8563 : 16790 : result->sign = NUMERIC_POS;
8564 : : }
8565 : : else
8566 : : {
8567 : : /* ----------
8568 : : * Both are positive
8569 : : * Must compare absolute values
8570 : : * ----------
8571 : : */
8572 [ + + + - ]: 76088 : switch (cmp_abs(var1, var2))
8573 : : {
8672 tgl@sss.pgh.pa.us 8574 : 14874 : case 0:
8575 : : /* ----------
8576 : : * ABS(var1) == ABS(var2)
8577 : : * result = ZERO
8578 : : * ----------
8579 : : */
8853 8580 : 14874 : zero_var(result);
8091 bruce@momjian.us 8581 : 14874 : result->dscale = Max(var1->dscale, var2->dscale);
9091 8582 : 14874 : break;
8583 : :
8672 tgl@sss.pgh.pa.us 8584 : 56177 : case 1:
8585 : : /* ----------
8586 : : * ABS(var1) > ABS(var2)
8587 : : * result = +(ABS(var1) - ABS(var2))
8588 : : * ----------
8589 : : */
9091 bruce@momjian.us 8590 : 56177 : sub_abs(var1, var2, result);
8591 : 56177 : result->sign = NUMERIC_POS;
8592 : 56177 : break;
8593 : :
8672 tgl@sss.pgh.pa.us 8594 : 5037 : case -1:
8595 : : /* ----------
8596 : : * ABS(var1) < ABS(var2)
8597 : : * result = -(ABS(var2) - ABS(var1))
8598 : : * ----------
8599 : : */
9091 bruce@momjian.us 8600 : 5037 : sub_abs(var2, var1, result);
8601 : 5037 : result->sign = NUMERIC_NEG;
8602 : 5037 : break;
8603 : : }
8604 : : }
8605 : : }
8606 : : else
8607 : : {
9237 JanWieck@Yahoo.com 8608 [ + + ]: 1456 : if (var2->sign == NUMERIC_NEG)
8609 : : {
8610 : : /* ----------
8611 : : * Both are negative
8612 : : * Must compare absolute values
8613 : : * ----------
8614 : : */
8615 [ + + + - ]: 1231 : switch (cmp_abs(var1, var2))
8616 : : {
8672 tgl@sss.pgh.pa.us 8617 : 83 : case 0:
8618 : : /* ----------
8619 : : * ABS(var1) == ABS(var2)
8620 : : * result = ZERO
8621 : : * ----------
8622 : : */
8853 8623 : 83 : zero_var(result);
8091 bruce@momjian.us 8624 : 83 : result->dscale = Max(var1->dscale, var2->dscale);
9091 8625 : 83 : break;
8626 : :
8672 tgl@sss.pgh.pa.us 8627 : 120 : case 1:
8628 : : /* ----------
8629 : : * ABS(var1) > ABS(var2)
8630 : : * result = -(ABS(var1) - ABS(var2))
8631 : : * ----------
8632 : : */
9091 bruce@momjian.us 8633 : 120 : sub_abs(var1, var2, result);
8634 : 120 : result->sign = NUMERIC_NEG;
8635 : 120 : break;
8636 : :
8672 tgl@sss.pgh.pa.us 8637 : 1028 : case -1:
8638 : : /* ----------
8639 : : * ABS(var1) < ABS(var2)
8640 : : * result = +(ABS(var2) - ABS(var1))
8641 : : * ----------
8642 : : */
9091 bruce@momjian.us 8643 : 1028 : sub_abs(var2, var1, result);
8644 : 1028 : result->sign = NUMERIC_POS;
8645 : 1028 : break;
8646 : : }
8647 : : }
8648 : : else
8649 : : {
8650 : : /* ----------
8651 : : * var1 is negative, var2 is positive
8652 : : * result = -(ABS(var1) + ABS(var2))
8653 : : * ----------
8654 : : */
9237 JanWieck@Yahoo.com 8655 : 225 : add_abs(var1, var2, result);
8656 : 225 : result->sign = NUMERIC_NEG;
8657 : : }
8658 : : }
8659 : 94334 : }
8660 : :
8661 : :
8662 : : /*
8663 : : * mul_var() -
8664 : : *
8665 : : * Multiplication on variable level. Product of var1 * var2 is stored
8666 : : * in result. Result is rounded to no more than rscale fractional digits.
8667 : : */
8668 : : static void
2408 andres@anarazel.de 8669 : 415251 : mul_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result,
8670 : : int rscale)
8671 : : {
8672 : : int res_ndigits;
8673 : : int res_sign;
8674 : : int res_weight;
8675 : : int maxdigits;
8676 : : int *dig;
8677 : : int carry;
8678 : : int maxdig;
8679 : : int newdig;
8680 : : int var1ndigits;
8681 : : int var2ndigits;
8682 : : NumericDigit *var1digits;
8683 : : NumericDigit *var2digits;
8684 : : NumericDigit *res_digits;
8685 : : int i,
8686 : : i1,
8687 : : i2;
8688 : :
8689 : : /*
8690 : : * Arrange for var1 to be the shorter of the two numbers. This improves
8691 : : * performance because the inner multiplication loop is much simpler than
8692 : : * the outer loop, so it's better to have a smaller number of iterations
8693 : : * of the outer loop. This also reduces the number of times that the
8694 : : * accumulator array needs to be normalized.
8695 : : */
3074 tgl@sss.pgh.pa.us 8696 [ + + ]: 415251 : if (var1->ndigits > var2->ndigits)
8697 : : {
2408 andres@anarazel.de 8698 : 7386 : const NumericVar *tmp = var1;
8699 : :
3074 tgl@sss.pgh.pa.us 8700 : 7386 : var1 = var2;
8701 : 7386 : var2 = tmp;
8702 : : }
8703 : :
8704 : : /* copy these values into local vars for speed in inner loop */
8705 : 415251 : var1ndigits = var1->ndigits;
8706 : 415251 : var2ndigits = var2->ndigits;
8707 : 415251 : var1digits = var1->digits;
8708 : 415251 : var2digits = var2->digits;
8709 : :
7695 8710 [ + + - + ]: 415251 : if (var1ndigits == 0 || var2ndigits == 0)
8711 : : {
8712 : : /* one or both inputs is zero; so is result */
8713 : 856 : zero_var(result);
8714 : 856 : result->dscale = rscale;
8715 : 856 : return;
8716 : : }
8717 : :
8718 : : /* Determine result sign and (maximum possible) weight */
9237 JanWieck@Yahoo.com 8719 [ + + ]: 414395 : if (var1->sign == var2->sign)
8720 : 413130 : res_sign = NUMERIC_POS;
8721 : : else
8722 : 1265 : res_sign = NUMERIC_NEG;
7695 tgl@sss.pgh.pa.us 8723 : 414395 : res_weight = var1->weight + var2->weight + 2;
8724 : :
8725 : : /*
8726 : : * Determine the number of result digits to compute. If the exact result
8727 : : * would have more than rscale fractional digits, truncate the computation
8728 : : * with MUL_GUARD_DIGITS guard digits, i.e., ignore input digits that
8729 : : * would only contribute to the right of that. (This will give the exact
8730 : : * rounded-to-rscale answer unless carries out of the ignored positions
8731 : : * would have propagated through more than MUL_GUARD_DIGITS digits.)
8732 : : *
8733 : : * Note: an exact computation could not produce more than var1ndigits +
8734 : : * var2ndigits digits, but we allocate one extra output digit in case
8735 : : * rscale-driven rounding produces a carry out of the highest exact digit.
8736 : : */
8737 : 414395 : res_ndigits = var1ndigits + var2ndigits + 1;
3074 8738 : 414395 : maxdigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS +
8739 : : MUL_GUARD_DIGITS;
8740 : 414395 : res_ndigits = Min(res_ndigits, maxdigits);
8741 : :
8742 [ + + ]: 414395 : if (res_ndigits < 3)
8743 : : {
8744 : : /* All input digits will be ignored; so result is zero */
8745 : 6 : zero_var(result);
8746 : 6 : result->dscale = rscale;
8747 : 6 : return;
8748 : : }
8749 : :
8750 : : /*
8751 : : * We do the arithmetic in an array "dig[]" of signed int's. Since
8752 : : * INT_MAX is noticeably larger than NBASE*NBASE, this gives us headroom
8753 : : * to avoid normalizing carries immediately.
8754 : : *
8755 : : * maxdig tracks the maximum possible value of any dig[] entry; when this
8756 : : * threatens to exceed INT_MAX, we take the time to propagate carries.
8757 : : * Furthermore, we need to ensure that overflow doesn't occur during the
8758 : : * carry propagation passes either. The carry values could be as much as
8759 : : * INT_MAX/NBASE, so really we must normalize when digits threaten to
8760 : : * exceed INT_MAX - INT_MAX/NBASE.
8761 : : *
8762 : : * To avoid overflow in maxdig itself, it actually represents the max
8763 : : * possible value divided by NBASE-1, ie, at the top of the loop it is
8764 : : * known that no dig[] entry exceeds maxdig * (NBASE-1).
8765 : : */
7695 8766 : 414389 : dig = (int *) palloc0(res_ndigits * sizeof(int));
8767 : 414389 : maxdig = 0;
8768 : :
8769 : : /*
8770 : : * The least significant digits of var1 should be ignored if they don't
8771 : : * contribute directly to the first res_ndigits digits of the result that
8772 : : * we are computing.
8773 : : *
8774 : : * Digit i1 of var1 and digit i2 of var2 are multiplied and added to digit
8775 : : * i1+i2+2 of the accumulator array, so we need only consider digits of
8776 : : * var1 for which i1 <= res_ndigits - 3.
8777 : : */
3074 8778 [ + + ]: 2316712 : for (i1 = Min(var1ndigits - 1, res_ndigits - 3); i1 >= 0; i1--)
8779 : : {
777 dean.a.rasheed@gmail 8780 : 1902323 : NumericDigit var1digit = var1digits[i1];
8781 : :
7695 tgl@sss.pgh.pa.us 8782 [ + + ]: 1902323 : if (var1digit == 0)
8783 : 1179720 : continue;
8784 : :
8785 : : /* Time to normalize? */
8786 : 722603 : maxdig += var1digit;
3128 8787 [ + + ]: 722603 : if (maxdig > (INT_MAX - INT_MAX / NBASE) / (NBASE - 1))
8788 : : {
8789 : : /* Yes, do it */
7695 8790 : 4572 : carry = 0;
7559 bruce@momjian.us 8791 [ + + ]: 22905348 : for (i = res_ndigits - 1; i >= 0; i--)
8792 : : {
7695 tgl@sss.pgh.pa.us 8793 : 22900776 : newdig = dig[i] + carry;
8794 [ + + ]: 22900776 : if (newdig >= NBASE)
8795 : : {
7559 bruce@momjian.us 8796 : 11532801 : carry = newdig / NBASE;
8797 : 11532801 : newdig -= carry * NBASE;
8798 : : }
8799 : : else
7695 tgl@sss.pgh.pa.us 8800 : 11367975 : carry = 0;
8801 : 22900776 : dig[i] = newdig;
8802 : : }
8803 [ - + ]: 4572 : Assert(carry == 0);
8804 : : /* Reset maxdig to indicate new worst-case */
8805 : 4572 : maxdig = 1 + var1digit;
8806 : : }
8807 : :
8808 : : /*
8809 : : * Add the appropriate multiple of var2 into the accumulator.
8810 : : *
8811 : : * As above, digits of var2 can be ignored if they don't contribute,
8812 : : * so we only include digits for which i1+i2+2 < res_ndigits.
8813 : : *
8814 : : * This inner loop is the performance bottleneck for multiplication,
8815 : : * so we want to keep it simple enough so that it can be
8816 : : * auto-vectorized. Accordingly, process the digits left-to-right
8817 : : * even though schoolbook multiplication would suggest right-to-left.
8818 : : * Since we aren't propagating carries in this loop, the order does
8819 : : * not matter.
8820 : : */
8821 : : {
1315 8822 : 722603 : int i2limit = Min(var2ndigits, res_ndigits - i1 - 2);
8823 : 722603 : int *dig_i1_2 = &dig[i1 + 2];
8824 : :
8825 [ + + ]: 249559007 : for (i2 = 0; i2 < i2limit; i2++)
8826 : 248836404 : dig_i1_2[i2] += var1digit * var2digits[i2];
8827 : : }
8828 : : }
8829 : :
8830 : : /*
8831 : : * Now we do a final carry propagation pass to normalize the result, which
8832 : : * we combine with storing the result digits into the output. Note that
8833 : : * this is still done at full precision w/guard digits.
8834 : : */
7695 8835 : 414389 : alloc_var(result, res_ndigits);
8836 : 414389 : res_digits = result->digits;
8837 : 414389 : carry = 0;
7559 bruce@momjian.us 8838 [ + + ]: 5120661 : for (i = res_ndigits - 1; i >= 0; i--)
8839 : : {
7695 tgl@sss.pgh.pa.us 8840 : 4706272 : newdig = dig[i] + carry;
8841 [ + + ]: 4706272 : if (newdig >= NBASE)
8842 : : {
7559 bruce@momjian.us 8843 : 991612 : carry = newdig / NBASE;
8844 : 991612 : newdig -= carry * NBASE;
8845 : : }
8846 : : else
7695 tgl@sss.pgh.pa.us 8847 : 3714660 : carry = 0;
8848 : 4706272 : res_digits[i] = newdig;
8849 : : }
8850 [ - + ]: 414389 : Assert(carry == 0);
8851 : :
8852 : 414389 : pfree(dig);
8853 : :
8854 : : /*
8855 : : * Finally, round the result to the requested precision.
8856 : : */
9091 bruce@momjian.us 8857 : 414389 : result->weight = res_weight;
8858 : 414389 : result->sign = res_sign;
8859 : :
8860 : : /* Round to target rscale (and set result->dscale) */
7695 tgl@sss.pgh.pa.us 8861 : 414389 : round_var(result, rscale);
8862 : :
8863 : : /* Strip leading and trailing zeroes */
8864 : 414389 : strip_var(result);
8865 : : }
8866 : :
8867 : :
8868 : : /*
8869 : : * div_var() -
8870 : : *
8871 : : * Division on variable level. Quotient of var1 / var2 is stored in result.
8872 : : * The quotient is figured to exactly rscale fractional digits.
8873 : : * If round is true, it is rounded at the rscale'th digit; if false, it
8874 : : * is truncated (towards zero) at that digit.
8875 : : */
8876 : : static void
2408 andres@anarazel.de 8877 : 104566 : div_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result,
8878 : : int rscale, bool round)
8879 : : {
8880 : : int div_ndigits;
8881 : : int res_ndigits;
8882 : : int res_sign;
8883 : : int res_weight;
8884 : : int carry;
8885 : : int borrow;
8886 : : int divisor1;
8887 : : int divisor2;
8888 : : NumericDigit *dividend;
8889 : : NumericDigit *divisor;
8890 : : NumericDigit *res_digits;
8891 : : int i;
8892 : : int j;
8893 : :
8894 : : /* copy these values into local vars for speed in inner loop */
5854 tgl@sss.pgh.pa.us 8895 : 104566 : int var1ndigits = var1->ndigits;
8896 : 104566 : int var2ndigits = var2->ndigits;
8897 : :
8898 : : /*
8899 : : * First of all division by zero check; we must not be handed an
8900 : : * unnormalized divisor.
8901 : : */
8902 [ + + - + ]: 104566 : if (var2ndigits == 0 || var2->digits[0] == 0)
8903 [ + - ]: 28 : ereport(ERROR,
8904 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
8905 : : errmsg("division by zero")));
8906 : :
8907 : : /*
8908 : : * If the divisor has just one or two digits, delegate to div_var_int(),
8909 : : * which uses fast short division.
8910 : : *
8911 : : * Similarly, on platforms with 128-bit integer support, delegate to
8912 : : * div_var_int64() for divisors with three or four digits.
8913 : : */
777 dean.a.rasheed@gmail 8914 [ + + ]: 104538 : if (var2ndigits <= 2)
8915 : : {
8916 : : int idivisor;
8917 : : int idivisor_weight;
8918 : :
8919 : 102649 : idivisor = var2->digits[0];
8920 : 102649 : idivisor_weight = var2->weight;
8921 [ + + ]: 102649 : if (var2ndigits == 2)
8922 : : {
8923 : 2326 : idivisor = idivisor * NBASE + var2->digits[1];
8924 : 2326 : idivisor_weight--;
8925 : : }
8926 [ + + ]: 102649 : if (var2->sign == NUMERIC_NEG)
8927 : 243 : idivisor = -idivisor;
8928 : :
8929 : 102649 : div_var_int(var1, idivisor, idivisor_weight, result, rscale, round);
8930 : 102649 : return;
8931 : : }
8932 : : #ifdef HAVE_INT128
447 8933 [ + + ]: 1889 : if (var2ndigits <= 4)
8934 : : {
8935 : : int64 idivisor;
8936 : : int idivisor_weight;
8937 : :
8938 : 249 : idivisor = var2->digits[0];
8939 : 249 : idivisor_weight = var2->weight;
8940 [ + + ]: 936 : for (i = 1; i < var2ndigits; i++)
8941 : : {
8942 : 687 : idivisor = idivisor * NBASE + var2->digits[i];
8943 : 687 : idivisor_weight--;
8944 : : }
8945 [ + + ]: 249 : if (var2->sign == NUMERIC_NEG)
8946 : 60 : idivisor = -idivisor;
8947 : :
8948 : 249 : div_var_int64(var1, idivisor, idivisor_weight, result, rscale, round);
8949 : 249 : return;
8950 : : }
8951 : : #endif
8952 : :
8953 : : /*
8954 : : * Otherwise, perform full long division.
8955 : : */
8956 : :
8957 : : /* Result zero check */
5854 tgl@sss.pgh.pa.us 8958 [ + + ]: 1640 : if (var1ndigits == 0)
8959 : : {
8960 : 12 : zero_var(result);
8961 : 12 : result->dscale = rscale;
8962 : 12 : return;
8963 : : }
8964 : :
8965 : : /*
8966 : : * Determine the result sign, weight and number of digits to calculate.
8967 : : * The weight figured here is correct if the emitted quotient has no
8968 : : * leading zero digits; otherwise strip_var() will fix things up.
8969 : : */
8970 [ + + ]: 1628 : if (var1->sign == var2->sign)
8971 : 1598 : res_sign = NUMERIC_POS;
8972 : : else
8973 : 30 : res_sign = NUMERIC_NEG;
8974 : 1628 : res_weight = var1->weight - var2->weight;
8975 : : /* The number of accurate result digits we need to produce: */
8976 : 1628 : res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
8977 : : /* ... but always at least 1 */
8978 : 1628 : res_ndigits = Max(res_ndigits, 1);
8979 : : /* If rounding needed, figure one more digit to ensure correct result */
8980 [ + - ]: 1628 : if (round)
8981 : 1628 : res_ndigits++;
8982 : :
8983 : : /*
8984 : : * The working dividend normally requires res_ndigits + var2ndigits
8985 : : * digits, but make it at least var1ndigits so we can load all of var1
8986 : : * into it. (There will be an additional digit dividend[0] in the
8987 : : * dividend space, but for consistency with Knuth's notation we don't
8988 : : * count that in div_ndigits.)
8989 : : */
8990 : 1628 : div_ndigits = res_ndigits + var2ndigits;
8991 : 1628 : div_ndigits = Max(div_ndigits, var1ndigits);
8992 : :
8993 : : /*
8994 : : * We need a workspace with room for the working dividend (div_ndigits+1
8995 : : * digits) plus room for the possibly-normalized divisor (var2ndigits
8996 : : * digits). It is convenient also to have a zero at divisor[0] with the
8997 : : * actual divisor data in divisor[1 .. var2ndigits]. Transferring the
8998 : : * digits into the workspace also allows us to realloc the result (which
8999 : : * might be the same as either input var) before we begin the main loop.
9000 : : * Note that we use palloc0 to ensure that divisor[0], dividend[0], and
9001 : : * any additional dividend positions beyond var1ndigits, start out 0.
9002 : : */
9003 : : dividend = (NumericDigit *)
9004 : 1628 : palloc0((div_ndigits + var2ndigits + 2) * sizeof(NumericDigit));
9005 : 1628 : divisor = dividend + (div_ndigits + 1);
9006 : 1628 : memcpy(dividend + 1, var1->digits, var1ndigits * sizeof(NumericDigit));
9007 : 1628 : memcpy(divisor + 1, var2->digits, var2ndigits * sizeof(NumericDigit));
9008 : :
9009 : : /*
9010 : : * Now we can realloc the result to hold the generated quotient digits.
9011 : : */
9012 : 1628 : alloc_var(result, res_ndigits);
9013 : 1628 : res_digits = result->digits;
9014 : :
9015 : : /*
9016 : : * The full multiple-place algorithm is taken from Knuth volume 2,
9017 : : * Algorithm 4.3.1D.
9018 : : *
9019 : : * We need the first divisor digit to be >= NBASE/2. If it isn't, make it
9020 : : * so by scaling up both the divisor and dividend by the factor "d". (The
9021 : : * reason for allocating dividend[0] above is to leave room for possible
9022 : : * carry here.)
9023 : : */
703 9024 [ + - ]: 1628 : if (divisor[1] < HALF_NBASE)
9025 : : {
9026 : 1628 : int d = NBASE / (divisor[1] + 1);
9027 : :
9028 : 1628 : carry = 0;
9029 [ + + ]: 13853 : for (i = var2ndigits; i > 0; i--)
9030 : : {
9031 : 12225 : carry += divisor[i] * d;
9032 : 12225 : divisor[i] = carry % NBASE;
9033 : 12225 : carry = carry / NBASE;
9034 : : }
9035 [ - + ]: 1628 : Assert(carry == 0);
9036 : 1628 : carry = 0;
9037 : : /* at this point only var1ndigits of dividend can be nonzero */
9038 [ + + ]: 13867 : for (i = var1ndigits; i >= 0; i--)
9039 : : {
9040 : 12239 : carry += dividend[i] * d;
9041 : 12239 : dividend[i] = carry % NBASE;
9042 : 12239 : carry = carry / NBASE;
9043 : : }
9044 [ - + ]: 1628 : Assert(carry == 0);
9045 [ - + ]: 1628 : Assert(divisor[1] >= HALF_NBASE);
9046 : : }
9047 : : /* First 2 divisor digits are used repeatedly in main loop */
9048 : 1628 : divisor1 = divisor[1];
9049 : 1628 : divisor2 = divisor[2];
9050 : :
9051 : : /*
9052 : : * Begin the main loop. Each iteration of this loop produces the j'th
9053 : : * quotient digit by dividing dividend[j .. j + var2ndigits] by the
9054 : : * divisor; this is essentially the same as the common manual procedure
9055 : : * for long division.
9056 : : */
9057 [ + + ]: 12300 : for (j = 0; j < res_ndigits; j++)
9058 : : {
9059 : : /* Estimate quotient digit from the first two dividend digits */
9060 : 10672 : int next2digits = dividend[j] * NBASE + dividend[j + 1];
9061 : : int qhat;
9062 : :
9063 : : /*
9064 : : * If next2digits are 0, then quotient digit must be 0 and there's no
9065 : : * need to adjust the working dividend. It's worth testing here to
9066 : : * fall out ASAP when processing trailing zeroes in a dividend.
9067 : : */
9068 [ + + ]: 10672 : if (next2digits == 0)
9069 : : {
9070 : 36 : res_digits[j] = 0;
9071 : 36 : continue;
9072 : : }
9073 : :
9074 [ + + ]: 10636 : if (dividend[j] == divisor1)
9075 : 60 : qhat = NBASE - 1;
9076 : : else
9077 : 10576 : qhat = next2digits / divisor1;
9078 : :
9079 : : /*
9080 : : * Adjust quotient digit if it's too large. Knuth proves that after
9081 : : * this step, the quotient digit will be either correct or just one
9082 : : * too large. (Note: it's OK to use dividend[j+2] here because we
9083 : : * know the divisor length is at least 2.)
9084 : : */
9085 : 10636 : while (divisor2 * qhat >
9086 [ + + ]: 12471 : (next2digits - qhat * divisor1) * NBASE + dividend[j + 2])
9087 : 1835 : qhat--;
9088 : :
9089 : : /* As above, need do nothing more when quotient digit is 0 */
9090 [ + + ]: 10636 : if (qhat > 0)
9091 : : {
9092 : 9832 : NumericDigit *dividend_j = ÷nd[j];
9093 : :
9094 : : /*
9095 : : * Multiply the divisor by qhat, and subtract that from the
9096 : : * working dividend. The multiplication and subtraction are
9097 : : * folded together here, noting that qhat <= NBASE (since it might
9098 : : * be one too large), and so the intermediate result "tmp_result"
9099 : : * is in the range [-NBASE^2, NBASE - 1], and "borrow" is in the
9100 : : * range [0, NBASE].
9101 : : */
9102 : 9832 : borrow = 0;
9103 [ + + ]: 95930 : for (i = var2ndigits; i >= 0; i--)
9104 : : {
9105 : : int tmp_result;
9106 : :
9107 : 86098 : tmp_result = dividend_j[i] - borrow - divisor[i] * qhat;
9108 : 86098 : borrow = (NBASE - 1 - tmp_result) / NBASE;
9109 : 86098 : dividend_j[i] = tmp_result + borrow * NBASE;
9110 : : }
9111 : :
9112 : : /*
9113 : : * If we got a borrow out of the top dividend digit, then indeed
9114 : : * qhat was one too large. Fix it, and add back the divisor to
9115 : : * correct the working dividend. (Knuth proves that this will
9116 : : * occur only about 3/NBASE of the time; hence, it's a good idea
9117 : : * to test this code with small NBASE to be sure this section gets
9118 : : * exercised.)
9119 : : */
9120 [ + + ]: 9832 : if (borrow)
9121 : : {
9122 : 14 : qhat--;
9123 : 14 : carry = 0;
5854 9124 [ + + ]: 1163 : for (i = var2ndigits; i >= 0; i--)
9125 : : {
703 9126 : 1149 : carry += dividend_j[i] + divisor[i];
9127 [ + + ]: 1149 : if (carry >= NBASE)
9128 : : {
9129 : 1050 : dividend_j[i] = carry - NBASE;
9130 : 1050 : carry = 1;
9131 : : }
9132 : : else
9133 : : {
9134 : 99 : dividend_j[i] = carry;
9135 : 99 : carry = 0;
9136 : : }
9137 : : }
9138 : : /* A carry should occur here to cancel the borrow above */
9139 [ - + ]: 14 : Assert(carry == 1);
9140 : : }
9141 : : }
9142 : :
9143 : : /* And we're done with this quotient digit */
9144 : 10636 : res_digits[j] = qhat;
9145 : : }
9146 : :
5854 9147 : 1628 : pfree(dividend);
9148 : :
9149 : : /*
9150 : : * Finally, round or truncate the result to the requested precision.
9151 : : */
9152 : 1628 : result->weight = res_weight;
9153 : 1628 : result->sign = res_sign;
9154 : :
9155 : : /* Round or truncate to target rscale (and set result->dscale) */
9156 [ + - ]: 1628 : if (round)
9157 : 1628 : round_var(result, rscale);
9158 : : else
5854 tgl@sss.pgh.pa.us 9159 :UBC 0 : trunc_var(result, rscale);
9160 : :
9161 : : /* Strip leading and trailing zeroes */
5854 tgl@sss.pgh.pa.us 9162 :CBC 1628 : strip_var(result);
9163 : : }
9164 : :
9165 : :
9166 : : /*
9167 : : * div_var_fast() -
9168 : : *
9169 : : * This has the same API as div_var, but is implemented using the division
9170 : : * algorithm from the "FM" library, rather than Knuth's schoolbook-division
9171 : : * approach. This is significantly faster but can produce inaccurate
9172 : : * results, because it sometimes has to propagate rounding to the left,
9173 : : * and so we can never be entirely sure that we know the requested digits
9174 : : * exactly. We compute DIV_GUARD_DIGITS extra digits, but there is
9175 : : * no certainty that that's enough. We use this only in the transcendental
9176 : : * function calculation routines, where everything is approximate anyway.
9177 : : *
9178 : : * Although we provide a "round" argument for consistency with div_var,
9179 : : * it is unwise to use this function with round=false. In truncation mode
9180 : : * it is possible to get a result with no significant digits, for example
9181 : : * with rscale=0 we might compute 0.99999... and truncate that to 0 when
9182 : : * the correct answer is 1.
9183 : : */
9184 : : static void
2408 andres@anarazel.de 9185 : 2958 : div_var_fast(const NumericVar *var1, const NumericVar *var2,
9186 : : NumericVar *result, int rscale, bool round)
9187 : : {
9188 : : int div_ndigits;
9189 : : int load_ndigits;
9190 : : int res_sign;
9191 : : int res_weight;
9192 : : int *div;
9193 : : int qdigit;
9194 : : int carry;
9195 : : int maxdiv;
9196 : : int newdig;
9197 : : NumericDigit *res_digits;
9198 : : double fdividend,
9199 : : fdivisor,
9200 : : fdivisorinverse,
9201 : : fquotient;
9202 : : int qi;
9203 : : int i;
9204 : :
9205 : : /* copy these values into local vars for speed in inner loop */
7695 tgl@sss.pgh.pa.us 9206 : 2958 : int var1ndigits = var1->ndigits;
9207 : 2958 : int var2ndigits = var2->ndigits;
9208 : 2958 : NumericDigit *var1digits = var1->digits;
9209 : 2958 : NumericDigit *var2digits = var2->digits;
9210 : :
9211 : : /*
9212 : : * First of all division by zero check; we must not be handed an
9213 : : * unnormalized divisor.
9214 : : */
9215 [ + + - + ]: 2958 : if (var2ndigits == 0 || var2digits[0] == 0)
7567 9216 [ + - ]: 3 : ereport(ERROR,
9217 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
9218 : : errmsg("division by zero")));
9219 : :
9220 : : /*
9221 : : * If the divisor has just one or two digits, delegate to div_var_int(),
9222 : : * which uses fast short division.
9223 : : *
9224 : : * Similarly, on platforms with 128-bit integer support, delegate to
9225 : : * div_var_int64() for divisors with three or four digits.
9226 : : */
777 dean.a.rasheed@gmail 9227 [ + + ]: 2955 : if (var2ndigits <= 2)
9228 : : {
9229 : : int idivisor;
9230 : : int idivisor_weight;
9231 : :
9232 : 264 : idivisor = var2->digits[0];
9233 : 264 : idivisor_weight = var2->weight;
9234 [ - + ]: 264 : if (var2ndigits == 2)
9235 : : {
777 dean.a.rasheed@gmail 9236 :UBC 0 : idivisor = idivisor * NBASE + var2->digits[1];
9237 : 0 : idivisor_weight--;
9238 : : }
777 dean.a.rasheed@gmail 9239 [ - + ]:CBC 264 : if (var2->sign == NUMERIC_NEG)
777 dean.a.rasheed@gmail 9240 :UBC 0 : idivisor = -idivisor;
9241 : :
777 dean.a.rasheed@gmail 9242 :CBC 264 : div_var_int(var1, idivisor, idivisor_weight, result, rscale, round);
9243 : 264 : return;
9244 : : }
9245 : : #ifdef HAVE_INT128
447 9246 [ + + ]: 2691 : if (var2ndigits <= 4)
9247 : : {
9248 : : int64 idivisor;
9249 : : int idivisor_weight;
9250 : :
9251 : 21 : idivisor = var2->digits[0];
9252 : 21 : idivisor_weight = var2->weight;
9253 [ + + ]: 75 : for (i = 1; i < var2ndigits; i++)
9254 : : {
9255 : 54 : idivisor = idivisor * NBASE + var2->digits[i];
9256 : 54 : idivisor_weight--;
9257 : : }
9258 [ - + ]: 21 : if (var2->sign == NUMERIC_NEG)
447 dean.a.rasheed@gmail 9259 :UBC 0 : idivisor = -idivisor;
9260 : :
447 dean.a.rasheed@gmail 9261 :CBC 21 : div_var_int64(var1, idivisor, idivisor_weight, result, rscale, round);
9262 : 21 : return;
9263 : : }
9264 : : #endif
9265 : :
9266 : : /*
9267 : : * Otherwise, perform full long division.
9268 : : */
9269 : :
9270 : : /* Result zero check */
7695 tgl@sss.pgh.pa.us 9271 [ + + ]: 2670 : if (var1ndigits == 0)
9272 : : {
8853 9273 : 6 : zero_var(result);
7695 9274 : 6 : result->dscale = rscale;
9237 JanWieck@Yahoo.com 9275 : 6 : return;
9276 : : }
9277 : :
9278 : : /*
9279 : : * Determine the result sign, weight and number of digits to calculate
9280 : : */
7695 tgl@sss.pgh.pa.us 9281 [ + + ]: 2664 : if (var1->sign == var2->sign)
9282 : 2628 : res_sign = NUMERIC_POS;
9283 : : else
9284 : 36 : res_sign = NUMERIC_NEG;
9285 : 2664 : res_weight = var1->weight - var2->weight + 1;
9286 : : /* The number of accurate result digits we need to produce: */
7559 bruce@momjian.us 9287 : 2664 : div_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9288 : : /* Add guard digits for roundoff error */
7695 tgl@sss.pgh.pa.us 9289 : 2664 : div_ndigits += DIV_GUARD_DIGITS;
9290 [ - + ]: 2664 : if (div_ndigits < DIV_GUARD_DIGITS)
7695 tgl@sss.pgh.pa.us 9291 :UBC 0 : div_ndigits = DIV_GUARD_DIGITS;
9292 : :
9293 : : /*
9294 : : * We do the arithmetic in an array "div[]" of signed int's. Since
9295 : : * INT_MAX is noticeably larger than NBASE*NBASE, this gives us headroom
9296 : : * to avoid normalizing carries immediately.
9297 : : *
9298 : : * We start with div[] containing one zero digit followed by the
9299 : : * dividend's digits (plus appended zeroes to reach the desired precision
9300 : : * including guard digits). Each step of the main loop computes an
9301 : : * (approximate) quotient digit and stores it into div[], removing one
9302 : : * position of dividend space. A final pass of carry propagation takes
9303 : : * care of any mistaken quotient digits.
9304 : : *
9305 : : * Note that div[] doesn't necessarily contain all of the digits from the
9306 : : * dividend --- the desired precision plus guard digits might be less than
9307 : : * the dividend's precision. This happens, for example, in the square
9308 : : * root algorithm, where we typically divide a 2N-digit number by an
9309 : : * N-digit number, and only require a result with N digits of precision.
9310 : : */
7695 tgl@sss.pgh.pa.us 9311 :CBC 2664 : div = (int *) palloc0((div_ndigits + 1) * sizeof(int));
1478 dean.a.rasheed@gmail 9312 : 2664 : load_ndigits = Min(div_ndigits, var1ndigits);
9313 [ + + ]: 36354 : for (i = 0; i < load_ndigits; i++)
7559 bruce@momjian.us 9314 : 33690 : div[i + 1] = var1digits[i];
9315 : :
9316 : : /*
9317 : : * We estimate each quotient digit using floating-point arithmetic, taking
9318 : : * the first four digits of the (current) dividend and divisor. This must
9319 : : * be float to avoid overflow. The quotient digits will generally be off
9320 : : * by no more than one from the exact answer.
9321 : : */
7695 tgl@sss.pgh.pa.us 9322 : 2664 : fdivisor = (double) var2digits[0];
9323 [ + + ]: 10656 : for (i = 1; i < 4; i++)
9324 : : {
9325 : 7992 : fdivisor *= NBASE;
9326 [ + - ]: 7992 : if (i < var2ndigits)
9327 : 7992 : fdivisor += (double) var2digits[i];
9328 : : }
9329 : 2664 : fdivisorinverse = 1.0 / fdivisor;
9330 : :
9331 : : /*
9332 : : * maxdiv tracks the maximum possible absolute value of any div[] entry;
9333 : : * when this threatens to exceed INT_MAX, we take the time to propagate
9334 : : * carries. Furthermore, we need to ensure that overflow doesn't occur
9335 : : * during the carry propagation passes either. The carry values may have
9336 : : * an absolute value as high as INT_MAX/NBASE + 1, so really we must
9337 : : * normalize when digits threaten to exceed INT_MAX - INT_MAX/NBASE - 1.
9338 : : *
9339 : : * To avoid overflow in maxdiv itself, it represents the max absolute
9340 : : * value divided by NBASE-1, ie, at the top of the loop it is known that
9341 : : * no div[] entry has an absolute value exceeding maxdiv * (NBASE-1).
9342 : : *
9343 : : * Actually, though, that holds good only for div[] entries after div[qi];
9344 : : * the adjustment done at the bottom of the loop may cause div[qi + 1] to
9345 : : * exceed the maxdiv limit, so that div[qi] in the next iteration is
9346 : : * beyond the limit. This does not cause problems, as explained below.
9347 : : */
9348 : 2664 : maxdiv = 1;
9349 : :
9350 : : /*
9351 : : * Outer loop computes next quotient digit, which will go into div[qi]
9352 : : */
9353 [ + + ]: 45144 : for (qi = 0; qi < div_ndigits; qi++)
9354 : : {
9355 : : /* Approximate the current dividend value */
9356 : 42480 : fdividend = (double) div[qi];
9357 [ + + ]: 169920 : for (i = 1; i < 4; i++)
9358 : : {
9359 : 127440 : fdividend *= NBASE;
7559 bruce@momjian.us 9360 [ + + ]: 127440 : if (qi + i <= div_ndigits)
9361 : 119448 : fdividend += (double) div[qi + i];
9362 : : }
9363 : : /* Compute the (approximate) quotient digit */
7695 tgl@sss.pgh.pa.us 9364 : 42480 : fquotient = fdividend * fdivisorinverse;
9365 [ + + ]: 42480 : qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
7559 bruce@momjian.us 9366 : 3 : (((int) fquotient) - 1); /* truncate towards -infinity */
9367 : :
7695 tgl@sss.pgh.pa.us 9368 [ + + ]: 42480 : if (qdigit != 0)
9369 : : {
9370 : : /* Do we need to normalize now? */
555 peter@eisentraut.org 9371 : 37983 : maxdiv += abs(qdigit);
3071 tgl@sss.pgh.pa.us 9372 [ + + ]: 37983 : if (maxdiv > (INT_MAX - INT_MAX / NBASE - 1) / (NBASE - 1))
9373 : : {
9374 : : /*
9375 : : * Yes, do it. Note that if var2ndigits is much smaller than
9376 : : * div_ndigits, we can save a significant amount of effort
9377 : : * here by noting that we only need to normalise those div[]
9378 : : * entries touched where prior iterations subtracted multiples
9379 : : * of the divisor.
9380 : : */
7695 9381 : 48 : carry = 0;
1478 dean.a.rasheed@gmail 9382 [ + + ]: 948 : for (i = Min(qi + var2ndigits - 2, div_ndigits); i > qi; i--)
9383 : : {
7695 tgl@sss.pgh.pa.us 9384 : 900 : newdig = div[i] + carry;
9385 [ + - ]: 900 : if (newdig < 0)
9386 : : {
7559 bruce@momjian.us 9387 : 900 : carry = -((-newdig - 1) / NBASE) - 1;
9388 : 900 : newdig -= carry * NBASE;
9389 : : }
7695 tgl@sss.pgh.pa.us 9390 [ # # ]:UBC 0 : else if (newdig >= NBASE)
9391 : : {
7559 bruce@momjian.us 9392 : 0 : carry = newdig / NBASE;
9393 : 0 : newdig -= carry * NBASE;
9394 : : }
9395 : : else
7695 tgl@sss.pgh.pa.us 9396 : 0 : carry = 0;
7695 tgl@sss.pgh.pa.us 9397 :CBC 900 : div[i] = newdig;
9398 : : }
9399 : 48 : newdig = div[qi] + carry;
9400 : 48 : div[qi] = newdig;
9401 : :
9402 : : /*
9403 : : * All the div[] digits except possibly div[qi] are now in the
9404 : : * range 0..NBASE-1. We do not need to consider div[qi] in
9405 : : * the maxdiv value anymore, so we can reset maxdiv to 1.
9406 : : */
3063 9407 : 48 : maxdiv = 1;
9408 : :
9409 : : /*
9410 : : * Recompute the quotient digit since new info may have
9411 : : * propagated into the top four dividend digits
9412 : : */
7695 9413 : 48 : fdividend = (double) div[qi];
9414 [ + + ]: 192 : for (i = 1; i < 4; i++)
9415 : : {
9416 : 144 : fdividend *= NBASE;
7559 bruce@momjian.us 9417 [ + - ]: 144 : if (qi + i <= div_ndigits)
9418 : 144 : fdividend += (double) div[qi + i];
9419 : : }
9420 : : /* Compute the (approximate) quotient digit */
7695 tgl@sss.pgh.pa.us 9421 : 48 : fquotient = fdividend * fdivisorinverse;
9422 [ + - ]: 48 : qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
6756 bruce@momjian.us 9423 :UBC 0 : (((int) fquotient) - 1); /* truncate towards -infinity */
555 peter@eisentraut.org 9424 :CBC 48 : maxdiv += abs(qdigit);
9425 : : }
9426 : :
9427 : : /*
9428 : : * Subtract off the appropriate multiple of the divisor.
9429 : : *
9430 : : * The digits beyond div[qi] cannot overflow, because we know they
9431 : : * will fall within the maxdiv limit. As for div[qi] itself, note
9432 : : * that qdigit is approximately trunc(div[qi] / vardigits[0]),
9433 : : * which would make the new value simply div[qi] mod vardigits[0].
9434 : : * The lower-order terms in qdigit can change this result by not
9435 : : * more than about twice INT_MAX/NBASE, so overflow is impossible.
9436 : : *
9437 : : * This inner loop is the performance bottleneck for division, so
9438 : : * code it in the same way as the inner loop of mul_var() so that
9439 : : * it can be auto-vectorized. We cast qdigit to NumericDigit
9440 : : * before multiplying to allow the compiler to generate more
9441 : : * efficient code (using 16-bit multiplication), which is safe
9442 : : * since we know that the quotient digit is off by at most one, so
9443 : : * there is no overflow risk.
9444 : : */
7695 tgl@sss.pgh.pa.us 9445 [ + - ]: 37983 : if (qdigit != 0)
9446 : : {
7559 bruce@momjian.us 9447 : 37983 : int istop = Min(var2ndigits, div_ndigits - qi + 1);
777 dean.a.rasheed@gmail 9448 : 37983 : int *div_qi = &div[qi];
9449 : :
7695 tgl@sss.pgh.pa.us 9450 [ + + ]: 465018 : for (i = 0; i < istop; i++)
777 dean.a.rasheed@gmail 9451 : 427035 : div_qi[i] -= ((NumericDigit) qdigit) * var2digits[i];
9452 : : }
9453 : : }
9454 : :
9455 : : /*
9456 : : * The dividend digit we are about to replace might still be nonzero.
9457 : : * Fold it into the next digit position.
9458 : : *
9459 : : * There is no risk of overflow here, although proving that requires
9460 : : * some care. Much as with the argument for div[qi] not overflowing,
9461 : : * if we consider the first two terms in the numerator and denominator
9462 : : * of qdigit, we can see that the final value of div[qi + 1] will be
9463 : : * approximately a remainder mod (vardigits[0]*NBASE + vardigits[1]).
9464 : : * Accounting for the lower-order terms is a bit complicated but ends
9465 : : * up adding not much more than INT_MAX/NBASE to the possible range.
9466 : : * Thus, div[qi + 1] cannot overflow here, and in its role as div[qi]
9467 : : * in the next loop iteration, it can't be large enough to cause
9468 : : * overflow in the carry propagation step (if any), either.
9469 : : *
9470 : : * But having said that: div[qi] can be more than INT_MAX/NBASE, as
9471 : : * noted above, which means that the product div[qi] * NBASE *can*
9472 : : * overflow. When that happens, adding it to div[qi + 1] will always
9473 : : * cause a canceling overflow so that the end result is correct. We
9474 : : * could avoid the intermediate overflow by doing the multiplication
9475 : : * and addition in int64 arithmetic, but so far there appears no need.
9476 : : */
7559 bruce@momjian.us 9477 : 42480 : div[qi + 1] += div[qi] * NBASE;
9478 : :
7695 tgl@sss.pgh.pa.us 9479 : 42480 : div[qi] = qdigit;
9480 : : }
9481 : :
9482 : : /*
9483 : : * Approximate and store the last quotient digit (div[div_ndigits])
9484 : : */
9485 : 2664 : fdividend = (double) div[qi];
9486 [ + + ]: 10656 : for (i = 1; i < 4; i++)
9487 : 7992 : fdividend *= NBASE;
9488 : 2664 : fquotient = fdividend * fdivisorinverse;
9489 [ + - ]: 2664 : qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
7559 bruce@momjian.us 9490 :UBC 0 : (((int) fquotient) - 1); /* truncate towards -infinity */
7695 tgl@sss.pgh.pa.us 9491 :CBC 2664 : div[qi] = qdigit;
9492 : :
9493 : : /*
9494 : : * Because the quotient digits might be off by one, some of them might be
9495 : : * -1 or NBASE at this point. The represented value is correct in a
9496 : : * mathematical sense, but it doesn't look right. We do a final carry
9497 : : * propagation pass to normalize the digits, which we combine with storing
9498 : : * the result digits into the output. Note that this is still done at
9499 : : * full precision w/guard digits.
9500 : : */
7559 bruce@momjian.us 9501 : 2664 : alloc_var(result, div_ndigits + 1);
7695 tgl@sss.pgh.pa.us 9502 : 2664 : res_digits = result->digits;
9503 : 2664 : carry = 0;
9504 [ + + ]: 47808 : for (i = div_ndigits; i >= 0; i--)
9505 : : {
9506 : 45144 : newdig = div[i] + carry;
9507 [ + + ]: 45144 : if (newdig < 0)
9508 : : {
7559 bruce@momjian.us 9509 : 6 : carry = -((-newdig - 1) / NBASE) - 1;
9510 : 6 : newdig -= carry * NBASE;
9511 : : }
7695 tgl@sss.pgh.pa.us 9512 [ + + ]: 45138 : else if (newdig >= NBASE)
9513 : : {
7559 bruce@momjian.us 9514 : 174 : carry = newdig / NBASE;
9515 : 174 : newdig -= carry * NBASE;
9516 : : }
9517 : : else
7695 tgl@sss.pgh.pa.us 9518 : 44964 : carry = 0;
9519 : 45144 : res_digits[i] = newdig;
9520 : : }
9521 [ - + ]: 2664 : Assert(carry == 0);
9522 : :
9523 : 2664 : pfree(div);
9524 : :
9525 : : /*
9526 : : * Finally, round the result to the requested precision.
9527 : : */
9528 : 2664 : result->weight = res_weight;
9529 : 2664 : result->sign = res_sign;
9530 : :
9531 : : /* Round to target rscale (and set result->dscale) */
6889 bruce@momjian.us 9532 [ + + ]: 2664 : if (round)
9533 : 405 : round_var(result, rscale);
9534 : : else
9535 : 2259 : trunc_var(result, rscale);
9536 : :
9537 : : /* Strip leading and trailing zeroes */
7695 tgl@sss.pgh.pa.us 9538 : 2664 : strip_var(result);
9539 : : }
9540 : :
9541 : :
9542 : : /*
9543 : : * div_var_int() -
9544 : : *
9545 : : * Divide a numeric variable by a 32-bit integer with the specified weight.
9546 : : * The quotient var / (ival * NBASE^ival_weight) is stored in result.
9547 : : */
9548 : : static void
777 dean.a.rasheed@gmail 9549 : 112492 : div_var_int(const NumericVar *var, int ival, int ival_weight,
9550 : : NumericVar *result, int rscale, bool round)
9551 : : {
9552 : 112492 : NumericDigit *var_digits = var->digits;
9553 : 112492 : int var_ndigits = var->ndigits;
9554 : : int res_sign;
9555 : : int res_weight;
9556 : : int res_ndigits;
9557 : : NumericDigit *res_buf;
9558 : : NumericDigit *res_digits;
9559 : : uint32 divisor;
9560 : : int i;
9561 : :
9562 : : /* Guard against division by zero */
9563 [ - + ]: 112492 : if (ival == 0)
777 dean.a.rasheed@gmail 9564 [ # # ]:UBC 0 : ereport(ERROR,
9565 : : errcode(ERRCODE_DIVISION_BY_ZERO),
9566 : : errmsg("division by zero"));
9567 : :
9568 : : /* Result zero check */
777 dean.a.rasheed@gmail 9569 [ + + ]:CBC 112492 : if (var_ndigits == 0)
9570 : : {
9571 : 1180 : zero_var(result);
9572 : 1180 : result->dscale = rscale;
9573 : 1180 : return;
9574 : : }
9575 : :
9576 : : /*
9577 : : * Determine the result sign, weight and number of digits to calculate.
9578 : : * The weight figured here is correct if the emitted quotient has no
9579 : : * leading zero digits; otherwise strip_var() will fix things up.
9580 : : */
9581 [ + + ]: 111312 : if (var->sign == NUMERIC_POS)
9582 [ + + ]: 109899 : res_sign = ival > 0 ? NUMERIC_POS : NUMERIC_NEG;
9583 : : else
9584 [ + + ]: 1413 : res_sign = ival > 0 ? NUMERIC_NEG : NUMERIC_POS;
9585 : 111312 : res_weight = var->weight - ival_weight;
9586 : : /* The number of accurate result digits we need to produce: */
9587 : 111312 : res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9588 : : /* ... but always at least 1 */
9589 : 111312 : res_ndigits = Max(res_ndigits, 1);
9590 : : /* If rounding needed, figure one more digit to ensure correct result */
9591 [ + + ]: 111312 : if (round)
9592 : 83522 : res_ndigits++;
9593 : :
9594 : 111312 : res_buf = digitbuf_alloc(res_ndigits + 1);
9595 : 111312 : res_buf[0] = 0; /* spare digit for later rounding */
9596 : 111312 : res_digits = res_buf + 1;
9597 : :
9598 : : /*
9599 : : * Now compute the quotient digits. This is the short division algorithm
9600 : : * described in Knuth volume 2, section 4.3.1 exercise 16, except that we
9601 : : * allow the divisor to exceed the internal base.
9602 : : *
9603 : : * In this algorithm, the carry from one digit to the next is at most
9604 : : * divisor - 1. Therefore, while processing the next digit, carry may
9605 : : * become as large as divisor * NBASE - 1, and so it requires a 64-bit
9606 : : * integer if this exceeds UINT_MAX.
9607 : : */
555 peter@eisentraut.org 9608 : 111312 : divisor = abs(ival);
9609 : :
777 dean.a.rasheed@gmail 9610 [ + + ]: 111312 : if (divisor <= UINT_MAX / NBASE)
9611 : : {
9612 : : /* carry cannot overflow 32 bits */
9613 : 109280 : uint32 carry = 0;
9614 : :
9615 [ + + ]: 1063241 : for (i = 0; i < res_ndigits; i++)
9616 : : {
9617 [ + + ]: 953961 : carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9618 : 953961 : res_digits[i] = (NumericDigit) (carry / divisor);
9619 : 953961 : carry = carry % divisor;
9620 : : }
9621 : : }
9622 : : else
9623 : : {
9624 : : /* carry may exceed 32 bits */
9625 : 2032 : uint64 carry = 0;
9626 : :
9627 [ + + ]: 6429 : for (i = 0; i < res_ndigits; i++)
9628 : : {
9629 [ + + ]: 4397 : carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9630 : 4397 : res_digits[i] = (NumericDigit) (carry / divisor);
9631 : 4397 : carry = carry % divisor;
9632 : : }
9633 : : }
9634 : :
9635 : : /* Store the quotient in result */
9636 [ + + ]: 111312 : digitbuf_free(result->buf);
9637 : 111312 : result->ndigits = res_ndigits;
9638 : 111312 : result->buf = res_buf;
9639 : 111312 : result->digits = res_digits;
9640 : 111312 : result->weight = res_weight;
9641 : 111312 : result->sign = res_sign;
9642 : :
9643 : : /* Round or truncate to target rscale (and set result->dscale) */
9644 [ + + ]: 111312 : if (round)
9645 : 83522 : round_var(result, rscale);
9646 : : else
9647 : 27790 : trunc_var(result, rscale);
9648 : :
9649 : : /* Strip leading/trailing zeroes */
9650 : 111312 : strip_var(result);
9651 : : }
9652 : :
9653 : :
9654 : : #ifdef HAVE_INT128
9655 : : /*
9656 : : * div_var_int64() -
9657 : : *
9658 : : * Divide a numeric variable by a 64-bit integer with the specified weight.
9659 : : * The quotient var / (ival * NBASE^ival_weight) is stored in result.
9660 : : *
9661 : : * This duplicates the logic in div_var_int(), so any changes made there
9662 : : * should be made here too.
9663 : : */
9664 : : static void
447 9665 : 270 : div_var_int64(const NumericVar *var, int64 ival, int ival_weight,
9666 : : NumericVar *result, int rscale, bool round)
9667 : : {
9668 : 270 : NumericDigit *var_digits = var->digits;
9669 : 270 : int var_ndigits = var->ndigits;
9670 : : int res_sign;
9671 : : int res_weight;
9672 : : int res_ndigits;
9673 : : NumericDigit *res_buf;
9674 : : NumericDigit *res_digits;
9675 : : uint64 divisor;
9676 : : int i;
9677 : :
9678 : : /* Guard against division by zero */
9679 [ - + ]: 270 : if (ival == 0)
447 dean.a.rasheed@gmail 9680 [ # # ]:UBC 0 : ereport(ERROR,
9681 : : errcode(ERRCODE_DIVISION_BY_ZERO),
9682 : : errmsg("division by zero"));
9683 : :
9684 : : /* Result zero check */
447 dean.a.rasheed@gmail 9685 [ + + ]:CBC 270 : if (var_ndigits == 0)
9686 : : {
9687 : 48 : zero_var(result);
9688 : 48 : result->dscale = rscale;
9689 : 48 : return;
9690 : : }
9691 : :
9692 : : /*
9693 : : * Determine the result sign, weight and number of digits to calculate.
9694 : : * The weight figured here is correct if the emitted quotient has no
9695 : : * leading zero digits; otherwise strip_var() will fix things up.
9696 : : */
9697 [ + + ]: 222 : if (var->sign == NUMERIC_POS)
9698 [ + + ]: 135 : res_sign = ival > 0 ? NUMERIC_POS : NUMERIC_NEG;
9699 : : else
9700 [ + + ]: 87 : res_sign = ival > 0 ? NUMERIC_NEG : NUMERIC_POS;
9701 : 222 : res_weight = var->weight - ival_weight;
9702 : : /* The number of accurate result digits we need to produce: */
9703 : 222 : res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9704 : : /* ... but always at least 1 */
9705 : 222 : res_ndigits = Max(res_ndigits, 1);
9706 : : /* If rounding needed, figure one more digit to ensure correct result */
9707 [ + - ]: 222 : if (round)
9708 : 222 : res_ndigits++;
9709 : :
9710 : 222 : res_buf = digitbuf_alloc(res_ndigits + 1);
9711 : 222 : res_buf[0] = 0; /* spare digit for later rounding */
9712 : 222 : res_digits = res_buf + 1;
9713 : :
9714 : : /*
9715 : : * Now compute the quotient digits. This is the short division algorithm
9716 : : * described in Knuth volume 2, section 4.3.1 exercise 16, except that we
9717 : : * allow the divisor to exceed the internal base.
9718 : : *
9719 : : * In this algorithm, the carry from one digit to the next is at most
9720 : : * divisor - 1. Therefore, while processing the next digit, carry may
9721 : : * become as large as divisor * NBASE - 1, and so it requires a 128-bit
9722 : : * integer if this exceeds PG_UINT64_MAX.
9723 : : */
9724 : 222 : divisor = i64abs(ival);
9725 : :
9726 [ + + ]: 222 : if (divisor <= PG_UINT64_MAX / NBASE)
9727 : : {
9728 : : /* carry cannot overflow 64 bits */
9729 : 174 : uint64 carry = 0;
9730 : :
9731 [ + + ]: 1785 : for (i = 0; i < res_ndigits; i++)
9732 : : {
9733 [ + + ]: 1611 : carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9734 : 1611 : res_digits[i] = (NumericDigit) (carry / divisor);
9735 : 1611 : carry = carry % divisor;
9736 : : }
9737 : : }
9738 : : else
9739 : : {
9740 : : /* carry may exceed 64 bits */
9741 : 48 : uint128 carry = 0;
9742 : :
9743 [ + + ]: 516 : for (i = 0; i < res_ndigits; i++)
9744 : : {
9745 [ + + ]: 468 : carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9746 : 468 : res_digits[i] = (NumericDigit) (carry / divisor);
9747 : 468 : carry = carry % divisor;
9748 : : }
9749 : : }
9750 : :
9751 : : /* Store the quotient in result */
9752 [ + + ]: 222 : digitbuf_free(result->buf);
9753 : 222 : result->ndigits = res_ndigits;
9754 : 222 : result->buf = res_buf;
9755 : 222 : result->digits = res_digits;
9756 : 222 : result->weight = res_weight;
9757 : 222 : result->sign = res_sign;
9758 : :
9759 : : /* Round or truncate to target rscale (and set result->dscale) */
9760 [ + - ]: 222 : if (round)
9761 : 222 : round_var(result, rscale);
9762 : : else
447 dean.a.rasheed@gmail 9763 :UBC 0 : trunc_var(result, rscale);
9764 : :
9765 : : /* Strip leading/trailing zeroes */
447 dean.a.rasheed@gmail 9766 :CBC 222 : strip_var(result);
9767 : : }
9768 : : #endif
9769 : :
9770 : :
9771 : : /*
9772 : : * Default scale selection for division
9773 : : *
9774 : : * Returns the appropriate result scale for the division result.
9775 : : */
9776 : : static int
2408 andres@anarazel.de 9777 : 76632 : select_div_scale(const NumericVar *var1, const NumericVar *var2)
9778 : : {
9779 : : int weight1,
9780 : : weight2,
9781 : : qweight,
9782 : : i;
9783 : : NumericDigit firstdigit1,
9784 : : firstdigit2;
9785 : : int rscale;
9786 : :
9787 : : /*
9788 : : * The result scale of a division isn't specified in any SQL standard. For
9789 : : * PostgreSQL we select a result scale that will give at least
9790 : : * NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a
9791 : : * result no less accurate than float8; but use a scale not less than
9792 : : * either input's display scale.
9793 : : */
9794 : :
9795 : : /* Get the actual (normalized) weight and first digit of each input */
9796 : :
7865 tgl@sss.pgh.pa.us 9797 : 76632 : weight1 = 0; /* values to use if var1 is zero */
9798 : 76632 : firstdigit1 = 0;
9799 [ + + ]: 76632 : for (i = 0; i < var1->ndigits; i++)
9800 : : {
9801 : 75737 : firstdigit1 = var1->digits[i];
9802 [ + - ]: 75737 : if (firstdigit1 != 0)
9803 : : {
9804 : 75737 : weight1 = var1->weight - i;
9805 : 75737 : break;
9806 : : }
9807 : : }
9808 : :
9809 : 76632 : weight2 = 0; /* values to use if var2 is zero */
9810 : 76632 : firstdigit2 = 0;
9811 [ + + ]: 76632 : for (i = 0; i < var2->ndigits; i++)
9812 : : {
9813 : 76607 : firstdigit2 = var2->digits[i];
9814 [ + - ]: 76607 : if (firstdigit2 != 0)
9815 : : {
9816 : 76607 : weight2 = var2->weight - i;
9817 : 76607 : break;
9818 : : }
9819 : : }
9820 : :
9821 : : /*
9822 : : * Estimate weight of quotient. If the two first digits are equal, we
9823 : : * can't be sure, but assume that var1 is less than var2.
9824 : : */
9825 : 76632 : qweight = weight1 - weight2;
9826 [ + + ]: 76632 : if (firstdigit1 <= firstdigit2)
9827 : 67241 : qweight--;
9828 : :
9829 : : /* Select result scale */
7695 9830 : 76632 : rscale = NUMERIC_MIN_SIG_DIGITS - qweight * DEC_DIGITS;
9831 : 76632 : rscale = Max(rscale, var1->dscale);
9832 : 76632 : rscale = Max(rscale, var2->dscale);
9833 : 76632 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
9834 : 76632 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
9835 : :
9836 : 76632 : return rscale;
9837 : : }
9838 : :
9839 : :
9840 : : /*
9841 : : * mod_var() -
9842 : : *
9843 : : * Calculate the modulo of two numerics at variable level
9844 : : */
9845 : : static void
2408 andres@anarazel.de 9846 : 27265 : mod_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
9847 : : {
9848 : : NumericVar tmp;
9849 : :
9237 JanWieck@Yahoo.com 9850 : 27265 : init_var(&tmp);
9851 : :
9852 : : /* ---------
9853 : : * We do this using the equation
9854 : : * mod(x,y) = x - trunc(x/y)*y
9855 : : * div_var can be persuaded to give us trunc(x/y) directly.
9856 : : * ----------
9857 : : */
5854 tgl@sss.pgh.pa.us 9858 : 27265 : div_var(var1, var2, &tmp, 0, false);
9859 : :
9860 : 27259 : mul_var(var2, &tmp, &tmp, var2->dscale);
9861 : :
9237 JanWieck@Yahoo.com 9862 : 27259 : sub_var(var1, &tmp, result);
9863 : :
9864 : 27259 : free_var(&tmp);
9865 : 27259 : }
9866 : :
9867 : :
9868 : : /*
9869 : : * div_mod_var() -
9870 : : *
9871 : : * Calculate the truncated integer quotient and numeric remainder of two
9872 : : * numeric variables. The remainder is precise to var2's dscale.
9873 : : */
9874 : : static void
1478 dean.a.rasheed@gmail 9875 : 2259 : div_mod_var(const NumericVar *var1, const NumericVar *var2,
9876 : : NumericVar *quot, NumericVar *rem)
9877 : : {
9878 : : NumericVar q;
9879 : : NumericVar r;
9880 : :
9881 : 2259 : init_var(&q);
9882 : 2259 : init_var(&r);
9883 : :
9884 : : /*
9885 : : * Use div_var_fast() to get an initial estimate for the integer quotient.
9886 : : * This might be inaccurate (per the warning in div_var_fast's comments),
9887 : : * but we can correct it below.
9888 : : */
9889 : 2259 : div_var_fast(var1, var2, &q, 0, false);
9890 : :
9891 : : /* Compute initial estimate of remainder using the quotient estimate. */
9892 : 2259 : mul_var(var2, &q, &r, var2->dscale);
9893 : 2259 : sub_var(var1, &r, &r);
9894 : :
9895 : : /*
9896 : : * Adjust the results if necessary --- the remainder should have the same
9897 : : * sign as var1, and its absolute value should be less than the absolute
9898 : : * value of var2.
9899 : : */
9900 [ + - - + ]: 2259 : while (r.ndigits != 0 && r.sign != var1->sign)
9901 : : {
9902 : : /* The absolute value of the quotient is too large */
1478 dean.a.rasheed@gmail 9903 [ # # ]:UBC 0 : if (var1->sign == var2->sign)
9904 : : {
9905 : 0 : sub_var(&q, &const_one, &q);
9906 : 0 : add_var(&r, var2, &r);
9907 : : }
9908 : : else
9909 : : {
9910 : 0 : add_var(&q, &const_one, &q);
9911 : 0 : sub_var(&r, var2, &r);
9912 : : }
9913 : : }
9914 : :
1478 dean.a.rasheed@gmail 9915 [ - + ]:CBC 2259 : while (cmp_abs(&r, var2) >= 0)
9916 : : {
9917 : : /* The absolute value of the quotient is too small */
1478 dean.a.rasheed@gmail 9918 [ # # ]:UBC 0 : if (var1->sign == var2->sign)
9919 : : {
9920 : 0 : add_var(&q, &const_one, &q);
9921 : 0 : sub_var(&r, var2, &r);
9922 : : }
9923 : : else
9924 : : {
9925 : 0 : sub_var(&q, &const_one, &q);
9926 : 0 : add_var(&r, var2, &r);
9927 : : }
9928 : : }
9929 : :
1478 dean.a.rasheed@gmail 9930 :CBC 2259 : set_var_from_var(&q, quot);
9931 : 2259 : set_var_from_var(&r, rem);
9932 : :
9933 : 2259 : free_var(&q);
9934 : 2259 : free_var(&r);
9935 : 2259 : }
9936 : :
9937 : :
9938 : : /*
9939 : : * ceil_var() -
9940 : : *
9941 : : * Return the smallest integer greater than or equal to the argument
9942 : : * on variable level
9943 : : */
9944 : : static void
2408 andres@anarazel.de 9945 : 102 : ceil_var(const NumericVar *var, NumericVar *result)
9946 : : {
9947 : : NumericVar tmp;
9948 : :
9237 JanWieck@Yahoo.com 9949 : 102 : init_var(&tmp);
9950 : 102 : set_var_from_var(var, &tmp);
9951 : :
7695 tgl@sss.pgh.pa.us 9952 : 102 : trunc_var(&tmp, 0);
9953 : :
9954 [ + + + + ]: 102 : if (var->sign == NUMERIC_POS && cmp_var(var, &tmp) != 0)
9237 JanWieck@Yahoo.com 9955 : 30 : add_var(&tmp, &const_one, &tmp);
9956 : :
9957 : 102 : set_var_from_var(&tmp, result);
9958 : 102 : free_var(&tmp);
9959 : 102 : }
9960 : :
9961 : :
9962 : : /*
9963 : : * floor_var() -
9964 : : *
9965 : : * Return the largest integer equal to or less than the argument
9966 : : * on variable level
9967 : : */
9968 : : static void
2408 andres@anarazel.de 9969 : 288 : floor_var(const NumericVar *var, NumericVar *result)
9970 : : {
9971 : : NumericVar tmp;
9972 : :
9237 JanWieck@Yahoo.com 9973 : 288 : init_var(&tmp);
9974 : 288 : set_var_from_var(var, &tmp);
9975 : :
7695 tgl@sss.pgh.pa.us 9976 : 288 : trunc_var(&tmp, 0);
9977 : :
9978 [ + + + + ]: 288 : if (var->sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0)
9237 JanWieck@Yahoo.com 9979 : 15 : sub_var(&tmp, &const_one, &tmp);
9980 : :
9981 : 288 : set_var_from_var(&tmp, result);
9982 : 288 : free_var(&tmp);
9983 : 288 : }
9984 : :
9985 : :
9986 : : /*
9987 : : * gcd_var() -
9988 : : *
9989 : : * Calculate the greatest common divisor of two numerics at variable level
9990 : : */
9991 : : static void
1541 dean.a.rasheed@gmail 9992 : 111 : gcd_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
9993 : : {
9994 : : int res_dscale;
9995 : : int cmp;
9996 : : NumericVar tmp_arg;
9997 : : NumericVar mod;
9998 : :
9999 : 111 : res_dscale = Max(var1->dscale, var2->dscale);
10000 : :
10001 : : /*
10002 : : * Arrange for var1 to be the number with the greater absolute value.
10003 : : *
10004 : : * This would happen automatically in the loop below, but avoids an
10005 : : * expensive modulo operation.
10006 : : */
10007 : 111 : cmp = cmp_abs(var1, var2);
10008 [ + + ]: 111 : if (cmp < 0)
10009 : : {
10010 : 42 : const NumericVar *tmp = var1;
10011 : :
10012 : 42 : var1 = var2;
10013 : 42 : var2 = tmp;
10014 : : }
10015 : :
10016 : : /*
10017 : : * Also avoid the taking the modulo if the inputs have the same absolute
10018 : : * value, or if the smaller input is zero.
10019 : : */
10020 [ + + + + ]: 111 : if (cmp == 0 || var2->ndigits == 0)
10021 : : {
10022 : 36 : set_var_from_var(var1, result);
10023 : 36 : result->sign = NUMERIC_POS;
10024 : 36 : result->dscale = res_dscale;
10025 : 36 : return;
10026 : : }
10027 : :
10028 : 75 : init_var(&tmp_arg);
10029 : 75 : init_var(&mod);
10030 : :
10031 : : /* Use the Euclidean algorithm to find the GCD */
10032 : 75 : set_var_from_var(var1, &tmp_arg);
10033 : 75 : set_var_from_var(var2, result);
10034 : :
10035 : : for (;;)
10036 : : {
10037 : : /* this loop can take a while, so allow it to be interrupted */
10038 [ - + ]: 294 : CHECK_FOR_INTERRUPTS();
10039 : :
10040 : 294 : mod_var(&tmp_arg, result, &mod);
10041 [ + + ]: 294 : if (mod.ndigits == 0)
10042 : 75 : break;
10043 : 219 : set_var_from_var(result, &tmp_arg);
10044 : 219 : set_var_from_var(&mod, result);
10045 : : }
10046 : 75 : result->sign = NUMERIC_POS;
10047 : 75 : result->dscale = res_dscale;
10048 : :
10049 : 75 : free_var(&tmp_arg);
10050 : 75 : free_var(&mod);
10051 : : }
10052 : :
10053 : :
10054 : : /*
10055 : : * sqrt_var() -
10056 : : *
10057 : : * Compute the square root of x using the Karatsuba Square Root algorithm.
10058 : : * NOTE: we allow rscale < 0 here, implying rounding before the decimal
10059 : : * point.
10060 : : */
10061 : : static void
2408 andres@anarazel.de 10062 : 2097 : sqrt_var(const NumericVar *arg, NumericVar *result, int rscale)
10063 : : {
10064 : : int stat;
10065 : : int res_weight;
10066 : : int res_ndigits;
10067 : : int src_ndigits;
10068 : : int step;
10069 : : int ndigits[32];
10070 : : int blen;
10071 : : int64 arg_int64;
10072 : : int src_idx;
10073 : : int64 s_int64;
10074 : : int64 r_int64;
10075 : : NumericVar s_var;
10076 : : NumericVar r_var;
10077 : : NumericVar a0_var;
10078 : : NumericVar a1_var;
10079 : : NumericVar q_var;
10080 : : NumericVar u_var;
10081 : :
9237 JanWieck@Yahoo.com 10082 : 2097 : stat = cmp_var(arg, &const_zero);
10083 [ + + ]: 2097 : if (stat == 0)
10084 : : {
7695 tgl@sss.pgh.pa.us 10085 : 9 : zero_var(result);
10086 : 9 : result->dscale = rscale;
9237 JanWieck@Yahoo.com 10087 : 9 : return;
10088 : : }
10089 : :
10090 : : /*
10091 : : * SQL2003 defines sqrt() in terms of power, so we need to emit the right
10092 : : * SQLSTATE error code if the operand is negative.
10093 : : */
10094 [ + + ]: 2088 : if (stat < 0)
7567 tgl@sss.pgh.pa.us 10095 [ + - ]: 3 : ereport(ERROR,
10096 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
10097 : : errmsg("cannot take square root of a negative number")));
10098 : :
1478 dean.a.rasheed@gmail 10099 : 2085 : init_var(&s_var);
10100 : 2085 : init_var(&r_var);
10101 : 2085 : init_var(&a0_var);
10102 : 2085 : init_var(&a1_var);
10103 : 2085 : init_var(&q_var);
10104 : 2085 : init_var(&u_var);
10105 : :
10106 : : /*
10107 : : * The result weight is half the input weight, rounded towards minus
10108 : : * infinity --- res_weight = floor(arg->weight / 2).
10109 : : */
10110 [ + + ]: 2085 : if (arg->weight >= 0)
10111 : 1929 : res_weight = arg->weight / 2;
10112 : : else
10113 : 156 : res_weight = -((-arg->weight - 1) / 2 + 1);
10114 : :
10115 : : /*
10116 : : * Number of NBASE digits to compute. To ensure correct rounding, compute
10117 : : * at least 1 extra decimal digit. We explicitly allow rscale to be
10118 : : * negative here, but must always compute at least 1 NBASE digit. Thus
10119 : : * res_ndigits = res_weight + 1 + ceil((rscale + 1) / DEC_DIGITS) or 1.
10120 : : */
10121 [ + - ]: 2085 : if (rscale + 1 >= 0)
10122 : 2085 : res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS) / DEC_DIGITS;
10123 : : else
1478 dean.a.rasheed@gmail 10124 :UBC 0 : res_ndigits = res_weight + 1 - (-rscale - 1) / DEC_DIGITS;
1478 dean.a.rasheed@gmail 10125 :CBC 2085 : res_ndigits = Max(res_ndigits, 1);
10126 : :
10127 : : /*
10128 : : * Number of source NBASE digits logically required to produce a result
10129 : : * with this precision --- every digit before the decimal point, plus 2
10130 : : * for each result digit after the decimal point (or minus 2 for each
10131 : : * result digit we round before the decimal point).
10132 : : */
10133 : 2085 : src_ndigits = arg->weight + 1 + (res_ndigits - res_weight - 1) * 2;
10134 : 2085 : src_ndigits = Max(src_ndigits, 1);
10135 : :
10136 : : /* ----------
10137 : : * From this point on, we treat the input and the result as integers and
10138 : : * compute the integer square root and remainder using the Karatsuba
10139 : : * Square Root algorithm, which may be written recursively as follows:
10140 : : *
10141 : : * SqrtRem(n = a3*b^3 + a2*b^2 + a1*b + a0):
10142 : : * [ for some base b, and coefficients a0,a1,a2,a3 chosen so that
10143 : : * 0 <= a0,a1,a2 < b and a3 >= b/4 ]
10144 : : * Let (s,r) = SqrtRem(a3*b + a2)
10145 : : * Let (q,u) = DivRem(r*b + a1, 2*s)
10146 : : * Let s = s*b + q
10147 : : * Let r = u*b + a0 - q^2
10148 : : * If r < 0 Then
10149 : : * Let r = r + s
10150 : : * Let s = s - 1
10151 : : * Let r = r + s
10152 : : * Return (s,r)
10153 : : *
10154 : : * See "Karatsuba Square Root", Paul Zimmermann, INRIA Research Report
10155 : : * RR-3805, November 1999. At the time of writing this was available
10156 : : * on the net at <https://hal.inria.fr/inria-00072854>.
10157 : : *
10158 : : * The way to read the assumption "n = a3*b^3 + a2*b^2 + a1*b + a0" is
10159 : : * "choose a base b such that n requires at least four base-b digits to
10160 : : * express; then those digits are a3,a2,a1,a0, with a3 possibly larger
10161 : : * than b". For optimal performance, b should have approximately a
10162 : : * quarter the number of digits in the input, so that the outer square
10163 : : * root computes roughly twice as many digits as the inner one. For
10164 : : * simplicity, we choose b = NBASE^blen, an integer power of NBASE.
10165 : : *
10166 : : * We implement the algorithm iteratively rather than recursively, to
10167 : : * allow the working variables to be reused. With this approach, each
10168 : : * digit of the input is read precisely once --- src_idx tracks the number
10169 : : * of input digits used so far.
10170 : : *
10171 : : * The array ndigits[] holds the number of NBASE digits of the input that
10172 : : * will have been used at the end of each iteration, which roughly doubles
10173 : : * each time. Note that the array elements are stored in reverse order,
10174 : : * so if the final iteration requires src_ndigits = 37 input digits, the
10175 : : * array will contain [37,19,11,7,5,3], and we would start by computing
10176 : : * the square root of the 3 most significant NBASE digits.
10177 : : *
10178 : : * In each iteration, we choose blen to be the largest integer for which
10179 : : * the input number has a3 >= b/4, when written in the form above. In
10180 : : * general, this means blen = src_ndigits / 4 (truncated), but if
10181 : : * src_ndigits is a multiple of 4, that might lead to the coefficient a3
10182 : : * being less than b/4 (if the first input digit is less than NBASE/4), in
10183 : : * which case we choose blen = src_ndigits / 4 - 1. The number of digits
10184 : : * in the inner square root is then src_ndigits - 2*blen. So, for
10185 : : * example, if we have src_ndigits = 26 initially, the array ndigits[]
10186 : : * will be either [26,14,8,4] or [26,14,8,6,4], depending on the size of
10187 : : * the first input digit.
10188 : : *
10189 : : * Additionally, we can put an upper bound on the number of steps required
10190 : : * as follows --- suppose that the number of source digits is an n-bit
10191 : : * number in the range [2^(n-1), 2^n-1], then blen will be in the range
10192 : : * [2^(n-3)-1, 2^(n-2)-1] and the number of digits in the inner square
10193 : : * root will be in the range [2^(n-2), 2^(n-1)+1]. In the next step, blen
10194 : : * will be in the range [2^(n-4)-1, 2^(n-3)] and the number of digits in
10195 : : * the next inner square root will be in the range [2^(n-3), 2^(n-2)+1].
10196 : : * This pattern repeats, and in the worst case the array ndigits[] will
10197 : : * contain [2^n-1, 2^(n-1)+1, 2^(n-2)+1, ... 9, 5, 3], and the computation
10198 : : * will require n steps. Therefore, since all digit array sizes are
10199 : : * signed 32-bit integers, the number of steps required is guaranteed to
10200 : : * be less than 32.
10201 : : * ----------
10202 : : */
10203 : 2085 : step = 0;
10204 [ + + ]: 9981 : while ((ndigits[step] = src_ndigits) > 4)
10205 : : {
10206 : : /* Choose b so that a3 >= b/4, as described above */
10207 : 7896 : blen = src_ndigits / 4;
10208 [ + + + + ]: 7896 : if (blen * 4 == src_ndigits && arg->digits[0] < NBASE / 4)
10209 : 162 : blen--;
10210 : :
10211 : : /* Number of digits in the next step (inner square root) */
10212 : 7896 : src_ndigits -= 2 * blen;
10213 : 7896 : step++;
10214 : : }
10215 : :
10216 : : /*
10217 : : * First iteration (innermost square root and remainder):
10218 : : *
10219 : : * Here src_ndigits <= 4, and the input fits in an int64. Its square root
10220 : : * has at most 9 decimal digits, so estimate it using double precision
10221 : : * arithmetic, which will in fact almost certainly return the correct
10222 : : * result with no further correction required.
10223 : : */
10224 : 2085 : arg_int64 = arg->digits[0];
10225 [ + + ]: 6657 : for (src_idx = 1; src_idx < src_ndigits; src_idx++)
10226 : : {
10227 : 4572 : arg_int64 *= NBASE;
10228 [ + + ]: 4572 : if (src_idx < arg->ndigits)
10229 : 3843 : arg_int64 += arg->digits[src_idx];
10230 : : }
10231 : :
10232 : 2085 : s_int64 = (int64) sqrt((double) arg_int64);
10233 : 2085 : r_int64 = arg_int64 - s_int64 * s_int64;
10234 : :
10235 : : /*
10236 : : * Use Newton's method to correct the result, if necessary.
10237 : : *
10238 : : * This uses integer division with truncation to compute the truncated
10239 : : * integer square root by iterating using the formula x -> (x + n/x) / 2.
10240 : : * This is known to converge to isqrt(n), unless n+1 is a perfect square.
10241 : : * If n+1 is a perfect square, the sequence will oscillate between the two
10242 : : * values isqrt(n) and isqrt(n)+1, so we can be assured of convergence by
10243 : : * checking the remainder.
10244 : : */
10245 [ - + - + ]: 2085 : while (r_int64 < 0 || r_int64 > 2 * s_int64)
10246 : : {
1478 dean.a.rasheed@gmail 10247 :UBC 0 : s_int64 = (s_int64 + arg_int64 / s_int64) / 2;
10248 : 0 : r_int64 = arg_int64 - s_int64 * s_int64;
10249 : : }
10250 : :
10251 : : /*
10252 : : * Iterations with src_ndigits <= 8:
10253 : : *
10254 : : * The next 1 or 2 iterations compute larger (outer) square roots with
10255 : : * src_ndigits <= 8, so the result still fits in an int64 (even though the
10256 : : * input no longer does) and we can continue to compute using int64
10257 : : * variables to avoid more expensive numeric computations.
10258 : : *
10259 : : * It is fairly easy to see that there is no risk of the intermediate
10260 : : * values below overflowing 64-bit integers. In the worst case, the
10261 : : * previous iteration will have computed a 3-digit square root (of a
10262 : : * 6-digit input less than NBASE^6 / 4), so at the start of this
10263 : : * iteration, s will be less than NBASE^3 / 2 = 10^12 / 2, and r will be
10264 : : * less than 10^12. In this case, blen will be 1, so numer will be less
10265 : : * than 10^17, and denom will be less than 10^12 (and hence u will also be
10266 : : * less than 10^12). Finally, since q^2 = u*b + a0 - r, we can also be
10267 : : * sure that q^2 < 10^17. Therefore all these quantities fit comfortably
10268 : : * in 64-bit integers.
10269 : : */
1478 dean.a.rasheed@gmail 10270 :CBC 2085 : step--;
10271 [ + - + + ]: 5283 : while (step >= 0 && (src_ndigits = ndigits[step]) <= 8)
10272 : : {
10273 : : int b;
10274 : : int a0;
10275 : : int a1;
10276 : : int i;
10277 : : int64 numer;
10278 : : int64 denom;
10279 : : int64 q;
10280 : : int64 u;
10281 : :
10282 : 3198 : blen = (src_ndigits - src_idx) / 2;
10283 : :
10284 : : /* Extract a1 and a0, and compute b */
10285 : 3198 : a0 = 0;
10286 : 3198 : a1 = 0;
10287 : 3198 : b = 1;
10288 : :
10289 [ + + ]: 6468 : for (i = 0; i < blen; i++, src_idx++)
10290 : : {
10291 : 3270 : b *= NBASE;
10292 : 3270 : a1 *= NBASE;
10293 [ + + ]: 3270 : if (src_idx < arg->ndigits)
10294 : 2400 : a1 += arg->digits[src_idx];
10295 : : }
10296 : :
10297 [ + + ]: 6468 : for (i = 0; i < blen; i++, src_idx++)
10298 : : {
10299 : 3270 : a0 *= NBASE;
10300 [ + + ]: 3270 : if (src_idx < arg->ndigits)
10301 : 2322 : a0 += arg->digits[src_idx];
10302 : : }
10303 : :
10304 : : /* Compute (q,u) = DivRem(r*b + a1, 2*s) */
10305 : 3198 : numer = r_int64 * b + a1;
10306 : 3198 : denom = 2 * s_int64;
10307 : 3198 : q = numer / denom;
10308 : 3198 : u = numer - q * denom;
10309 : :
10310 : : /* Compute s = s*b + q and r = u*b + a0 - q^2 */
10311 : 3198 : s_int64 = s_int64 * b + q;
10312 : 3198 : r_int64 = u * b + a0 - q * q;
10313 : :
10314 [ + + ]: 3198 : if (r_int64 < 0)
10315 : : {
10316 : : /* s is too large by 1; set r += s, s--, r += s */
10317 : 105 : r_int64 += s_int64;
10318 : 105 : s_int64--;
10319 : 105 : r_int64 += s_int64;
10320 : : }
10321 : :
10322 [ - + ]: 3198 : Assert(src_idx == src_ndigits); /* All input digits consumed */
10323 : 3198 : step--;
10324 : : }
10325 : :
10326 : : /*
10327 : : * On platforms with 128-bit integer support, we can further delay the
10328 : : * need to use numeric variables.
10329 : : */
10330 : : #ifdef HAVE_INT128
10331 [ + - ]: 2085 : if (step >= 0)
10332 : : {
10333 : : int128 s_int128;
10334 : : int128 r_int128;
10335 : :
10336 : 2085 : s_int128 = s_int64;
10337 : 2085 : r_int128 = r_int64;
10338 : :
10339 : : /*
10340 : : * Iterations with src_ndigits <= 16:
10341 : : *
10342 : : * The result fits in an int128 (even though the input doesn't) so we
10343 : : * use int128 variables to avoid more expensive numeric computations.
10344 : : */
10345 [ + + + + ]: 4524 : while (step >= 0 && (src_ndigits = ndigits[step]) <= 16)
10346 : : {
10347 : : int64 b;
10348 : : int64 a0;
10349 : : int64 a1;
10350 : : int64 i;
10351 : : int128 numer;
10352 : : int128 denom;
10353 : : int128 q;
10354 : : int128 u;
10355 : :
10356 : 2439 : blen = (src_ndigits - src_idx) / 2;
10357 : :
10358 : : /* Extract a1 and a0, and compute b */
10359 : 2439 : a0 = 0;
10360 : 2439 : a1 = 0;
10361 : 2439 : b = 1;
10362 : :
10363 [ + + ]: 8040 : for (i = 0; i < blen; i++, src_idx++)
10364 : : {
10365 : 5601 : b *= NBASE;
10366 : 5601 : a1 *= NBASE;
10367 [ + + ]: 5601 : if (src_idx < arg->ndigits)
10368 : 3303 : a1 += arg->digits[src_idx];
10369 : : }
10370 : :
10371 [ + + ]: 8040 : for (i = 0; i < blen; i++, src_idx++)
10372 : : {
10373 : 5601 : a0 *= NBASE;
10374 [ + + ]: 5601 : if (src_idx < arg->ndigits)
10375 : 2235 : a0 += arg->digits[src_idx];
10376 : : }
10377 : :
10378 : : /* Compute (q,u) = DivRem(r*b + a1, 2*s) */
10379 : 2439 : numer = r_int128 * b + a1;
10380 : 2439 : denom = 2 * s_int128;
10381 : 2439 : q = numer / denom;
10382 : 2439 : u = numer - q * denom;
10383 : :
10384 : : /* Compute s = s*b + q and r = u*b + a0 - q^2 */
10385 : 2439 : s_int128 = s_int128 * b + q;
10386 : 2439 : r_int128 = u * b + a0 - q * q;
10387 : :
10388 [ + + ]: 2439 : if (r_int128 < 0)
10389 : : {
10390 : : /* s is too large by 1; set r += s, s--, r += s */
10391 : 96 : r_int128 += s_int128;
10392 : 96 : s_int128--;
10393 : 96 : r_int128 += s_int128;
10394 : : }
10395 : :
10396 [ - + ]: 2439 : Assert(src_idx == src_ndigits); /* All input digits consumed */
10397 : 2439 : step--;
10398 : : }
10399 : :
10400 : : /*
10401 : : * All remaining iterations require numeric variables. Convert the
10402 : : * integer values to NumericVar and continue. Note that in the final
10403 : : * iteration we don't need the remainder, so we can save a few cycles
10404 : : * there by not fully computing it.
10405 : : */
10406 : 2085 : int128_to_numericvar(s_int128, &s_var);
10407 [ + + ]: 2085 : if (step >= 0)
10408 : 1362 : int128_to_numericvar(r_int128, &r_var);
10409 : : }
10410 : : else
10411 : : {
1478 dean.a.rasheed@gmail 10412 :UBC 0 : int64_to_numericvar(s_int64, &s_var);
10413 : : /* step < 0, so we certainly don't need r */
10414 : : }
10415 : : #else /* !HAVE_INT128 */
10416 : : int64_to_numericvar(s_int64, &s_var);
10417 : : if (step >= 0)
10418 : : int64_to_numericvar(r_int64, &r_var);
10419 : : #endif /* HAVE_INT128 */
10420 : :
10421 : : /*
10422 : : * The remaining iterations with src_ndigits > 8 (or 16, if have int128)
10423 : : * use numeric variables.
10424 : : */
1478 dean.a.rasheed@gmail 10425 [ + + ]:CBC 4344 : while (step >= 0)
10426 : : {
10427 : : int tmp_len;
10428 : :
10429 : 2259 : src_ndigits = ndigits[step];
10430 : 2259 : blen = (src_ndigits - src_idx) / 2;
10431 : :
10432 : : /* Extract a1 and a0 */
10433 [ + + ]: 2259 : if (src_idx < arg->ndigits)
10434 : : {
10435 : 756 : tmp_len = Min(blen, arg->ndigits - src_idx);
10436 : 756 : alloc_var(&a1_var, tmp_len);
10437 : 756 : memcpy(a1_var.digits, arg->digits + src_idx,
10438 : : tmp_len * sizeof(NumericDigit));
10439 : 756 : a1_var.weight = blen - 1;
10440 : 756 : a1_var.sign = NUMERIC_POS;
10441 : 756 : a1_var.dscale = 0;
10442 : 756 : strip_var(&a1_var);
10443 : : }
10444 : : else
10445 : : {
10446 : 1503 : zero_var(&a1_var);
10447 : 1503 : a1_var.dscale = 0;
10448 : : }
10449 : 2259 : src_idx += blen;
10450 : :
10451 [ + + ]: 2259 : if (src_idx < arg->ndigits)
10452 : : {
10453 : 756 : tmp_len = Min(blen, arg->ndigits - src_idx);
10454 : 756 : alloc_var(&a0_var, tmp_len);
10455 : 756 : memcpy(a0_var.digits, arg->digits + src_idx,
10456 : : tmp_len * sizeof(NumericDigit));
10457 : 756 : a0_var.weight = blen - 1;
10458 : 756 : a0_var.sign = NUMERIC_POS;
10459 : 756 : a0_var.dscale = 0;
10460 : 756 : strip_var(&a0_var);
10461 : : }
10462 : : else
10463 : : {
10464 : 1503 : zero_var(&a0_var);
10465 : 1503 : a0_var.dscale = 0;
10466 : : }
10467 : 2259 : src_idx += blen;
10468 : :
10469 : : /* Compute (q,u) = DivRem(r*b + a1, 2*s) */
10470 : 2259 : set_var_from_var(&r_var, &q_var);
10471 : 2259 : q_var.weight += blen;
10472 : 2259 : add_var(&q_var, &a1_var, &q_var);
10473 : 2259 : add_var(&s_var, &s_var, &u_var);
10474 : 2259 : div_mod_var(&q_var, &u_var, &q_var, &u_var);
10475 : :
10476 : : /* Compute s = s*b + q */
10477 : 2259 : s_var.weight += blen;
10478 : 2259 : add_var(&s_var, &q_var, &s_var);
10479 : :
10480 : : /*
10481 : : * Compute r = u*b + a0 - q^2.
10482 : : *
10483 : : * In the final iteration, we don't actually need r; we just need to
10484 : : * know whether it is negative, so that we know whether to adjust s.
10485 : : * So instead of the final subtraction we can just compare.
10486 : : */
10487 : 2259 : u_var.weight += blen;
10488 : 2259 : add_var(&u_var, &a0_var, &u_var);
10489 : 2259 : mul_var(&q_var, &q_var, &q_var, 0);
10490 : :
10491 [ + + ]: 2259 : if (step > 0)
10492 : : {
10493 : : /* Need r for later iterations */
10494 : 897 : sub_var(&u_var, &q_var, &r_var);
10495 [ + + ]: 897 : if (r_var.sign == NUMERIC_NEG)
10496 : : {
10497 : : /* s is too large by 1; set r += s, s--, r += s */
10498 : 60 : add_var(&r_var, &s_var, &r_var);
10499 : 60 : sub_var(&s_var, &const_one, &s_var);
10500 : 60 : add_var(&r_var, &s_var, &r_var);
10501 : : }
10502 : : }
10503 : : else
10504 : : {
10505 : : /* Don't need r anymore, except to test if s is too large by 1 */
10506 [ + + ]: 1362 : if (cmp_var(&u_var, &q_var) < 0)
10507 : 18 : sub_var(&s_var, &const_one, &s_var);
10508 : : }
10509 : :
10510 [ - + ]: 2259 : Assert(src_idx == src_ndigits); /* All input digits consumed */
10511 : 2259 : step--;
10512 : : }
10513 : :
10514 : : /*
10515 : : * Construct the final result, rounding it to the requested precision.
10516 : : */
10517 : 2085 : set_var_from_var(&s_var, result);
10518 : 2085 : result->weight = res_weight;
10519 : 2085 : result->sign = NUMERIC_POS;
10520 : :
10521 : : /* Round to target rscale (and set result->dscale) */
7695 tgl@sss.pgh.pa.us 10522 : 2085 : round_var(result, rscale);
10523 : :
10524 : : /* Strip leading and trailing zeroes */
1478 dean.a.rasheed@gmail 10525 : 2085 : strip_var(result);
10526 : :
10527 : 2085 : free_var(&s_var);
10528 : 2085 : free_var(&r_var);
10529 : 2085 : free_var(&a0_var);
10530 : 2085 : free_var(&a1_var);
10531 : 2085 : free_var(&q_var);
10532 : 2085 : free_var(&u_var);
10533 : : }
10534 : :
10535 : :
10536 : : /*
10537 : : * exp_var() -
10538 : : *
10539 : : * Raise e to the power of x, computed to rscale fractional digits
10540 : : */
10541 : : static void
2408 andres@anarazel.de 10542 : 90 : exp_var(const NumericVar *arg, NumericVar *result, int rscale)
10543 : : {
10544 : : NumericVar x;
10545 : : NumericVar elem;
10546 : : int ni;
10547 : : double val;
10548 : : int dweight;
10549 : : int ndiv2;
10550 : : int sig_digits;
10551 : : int local_rscale;
10552 : :
9237 JanWieck@Yahoo.com 10553 : 90 : init_var(&x);
3074 tgl@sss.pgh.pa.us 10554 : 90 : init_var(&elem);
10555 : :
9237 JanWieck@Yahoo.com 10556 : 90 : set_var_from_var(arg, &x);
10557 : :
10558 : : /*
10559 : : * Estimate the dweight of the result using floating point arithmetic, so
10560 : : * that we can choose an appropriate local rscale for the calculation.
10561 : : */
3074 tgl@sss.pgh.pa.us 10562 : 90 : val = numericvar_to_double_no_overflow(&x);
10563 : :
10564 : : /* Guard against overflow/underflow */
10565 : : /* If you change this limit, see also power_var()'s limit */
555 peter@eisentraut.org 10566 [ + + ]: 90 : if (fabs(val) >= NUMERIC_MAX_RESULT_SCALE * 3)
10567 : : {
988 dean.a.rasheed@gmail 10568 [ - + ]: 3 : if (val > 0)
988 dean.a.rasheed@gmail 10569 [ # # ]:UBC 0 : ereport(ERROR,
10570 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
10571 : : errmsg("value overflows numeric format")));
988 dean.a.rasheed@gmail 10572 :CBC 3 : zero_var(result);
10573 : 3 : result->dscale = rscale;
10574 : 3 : return;
10575 : : }
10576 : :
10577 : : /* decimal weight = log10(e^x) = x * log10(e) */
3074 tgl@sss.pgh.pa.us 10578 : 87 : dweight = (int) (val * 0.434294481903252);
10579 : :
10580 : : /*
10581 : : * Reduce x to the range -0.01 <= x <= 0.01 (approximately) by dividing by
10582 : : * 2^ndiv2, to improve the convergence rate of the Taylor series.
10583 : : *
10584 : : * Note that the overflow check above ensures that fabs(x) < 6000, which
10585 : : * means that ndiv2 <= 20 here.
10586 : : */
555 peter@eisentraut.org 10587 [ + + ]: 87 : if (fabs(val) > 0.01)
10588 : : {
3074 tgl@sss.pgh.pa.us 10589 : 72 : ndiv2 = 1;
10590 : 72 : val /= 2;
10591 : :
555 peter@eisentraut.org 10592 [ + + ]: 909 : while (fabs(val) > 0.01)
10593 : : {
3074 tgl@sss.pgh.pa.us 10594 : 837 : ndiv2++;
10595 : 837 : val /= 2;
10596 : : }
10597 : :
10598 : 72 : local_rscale = x.dscale + ndiv2;
777 dean.a.rasheed@gmail 10599 : 72 : div_var_int(&x, 1 << ndiv2, 0, &x, local_rscale, true);
10600 : : }
10601 : : else
3074 tgl@sss.pgh.pa.us 10602 : 15 : ndiv2 = 0;
10603 : :
10604 : : /*
10605 : : * Set the scale for the Taylor series expansion. The final result has
10606 : : * (dweight + rscale + 1) significant digits. In addition, we have to
10607 : : * raise the Taylor series result to the power 2^ndiv2, which introduces
10608 : : * an error of up to around log10(2^ndiv2) digits, so work with this many
10609 : : * extra digits of precision (plus a few more for good measure).
10610 : : */
10611 : 87 : sig_digits = 1 + dweight + rscale + (int) (ndiv2 * 0.301029995663981);
10612 : 87 : sig_digits = Max(sig_digits, 0) + 8;
10613 : :
10614 : 87 : local_rscale = sig_digits - 1;
10615 : :
10616 : : /*
10617 : : * Use the Taylor series
10618 : : *
10619 : : * exp(x) = 1 + x + x^2/2! + x^3/3! + ...
10620 : : *
10621 : : * Given the limited range of x, this should converge reasonably quickly.
10622 : : * We run the series until the terms fall below the local_rscale limit.
10623 : : */
9237 JanWieck@Yahoo.com 10624 : 87 : add_var(&const_one, &x, result);
10625 : :
3074 tgl@sss.pgh.pa.us 10626 : 87 : mul_var(&x, &x, &elem, local_rscale);
777 dean.a.rasheed@gmail 10627 : 87 : ni = 2;
10628 : 87 : div_var_int(&elem, ni, 0, &elem, local_rscale, true);
10629 : :
3074 tgl@sss.pgh.pa.us 10630 [ + + ]: 2496 : while (elem.ndigits != 0)
10631 : : {
9237 JanWieck@Yahoo.com 10632 : 2409 : add_var(result, &elem, result);
10633 : :
3074 tgl@sss.pgh.pa.us 10634 : 2409 : mul_var(&elem, &x, &elem, local_rscale);
777 dean.a.rasheed@gmail 10635 : 2409 : ni++;
10636 : 2409 : div_var_int(&elem, ni, 0, &elem, local_rscale, true);
10637 : : }
10638 : :
10639 : : /*
10640 : : * Compensate for the argument range reduction. Since the weight of the
10641 : : * result doubles with each multiplication, we can reduce the local rscale
10642 : : * as we proceed.
10643 : : */
9237 JanWieck@Yahoo.com 10644 [ + + ]: 996 : while (ndiv2-- > 0)
10645 : : {
3074 tgl@sss.pgh.pa.us 10646 : 909 : local_rscale = sig_digits - result->weight * 2 * DEC_DIGITS;
10647 : 909 : local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
7695 10648 : 909 : mul_var(result, result, result, local_rscale);
10649 : : }
10650 : :
10651 : : /* Round to requested rscale */
3074 10652 : 87 : round_var(result, rscale);
10653 : :
9237 JanWieck@Yahoo.com 10654 : 87 : free_var(&x);
10655 : 87 : free_var(&elem);
10656 : : }
10657 : :
10658 : :
10659 : : /*
10660 : : * Estimate the dweight of the most significant decimal digit of the natural
10661 : : * logarithm of a number.
10662 : : *
10663 : : * Essentially, we're approximating log10(abs(ln(var))). This is used to
10664 : : * determine the appropriate rscale when computing natural logarithms.
10665 : : *
10666 : : * Note: many callers call this before range-checking the input. Therefore,
10667 : : * we must be robust against values that are invalid to apply ln() to.
10668 : : * We don't wish to throw an error here, so just return zero in such cases.
10669 : : */
10670 : : static int
2408 andres@anarazel.de 10671 : 369 : estimate_ln_dweight(const NumericVar *var)
10672 : : {
10673 : : int ln_dweight;
10674 : :
10675 : : /* Caller should fail on ln(negative), but for the moment return zero */
773 tgl@sss.pgh.pa.us 10676 [ + + ]: 369 : if (var->sign != NUMERIC_POS)
10677 : 21 : return 0;
10678 : :
3074 10679 [ + + + + ]: 657 : if (cmp_var(var, &const_zero_point_nine) >= 0 &&
10680 : 309 : cmp_var(var, &const_one_point_one) <= 0)
10681 : 45 : {
10682 : : /*
10683 : : * 0.9 <= var <= 1.1
10684 : : *
10685 : : * ln(var) has a negative weight (possibly very large). To get a
10686 : : * reasonably accurate result, estimate it using ln(1+x) ~= x.
10687 : : */
10688 : : NumericVar x;
10689 : :
10690 : 45 : init_var(&x);
10691 : 45 : sub_var(var, &const_one, &x);
10692 : :
10693 [ + + ]: 45 : if (x.ndigits > 0)
10694 : : {
10695 : : /* Use weight of most significant decimal digit of x */
10696 : 21 : ln_dweight = x.weight * DEC_DIGITS + (int) log10(x.digits[0]);
10697 : : }
10698 : : else
10699 : : {
10700 : : /* x = 0. Since ln(1) = 0 exactly, we don't need extra digits */
10701 : 24 : ln_dweight = 0;
10702 : : }
10703 : :
10704 : 45 : free_var(&x);
10705 : : }
10706 : : else
10707 : : {
10708 : : /*
10709 : : * Estimate the logarithm using the first couple of digits from the
10710 : : * input number. This will give an accurate result whenever the input
10711 : : * is not too close to 1.
10712 : : */
10713 [ + + ]: 303 : if (var->ndigits > 0)
10714 : : {
10715 : : int digits;
10716 : : int dweight;
10717 : : double ln_var;
10718 : :
10719 : 282 : digits = var->digits[0];
10720 : 282 : dweight = var->weight * DEC_DIGITS;
10721 : :
10722 [ + + ]: 282 : if (var->ndigits > 1)
10723 : : {
10724 : 171 : digits = digits * NBASE + var->digits[1];
10725 : 171 : dweight -= DEC_DIGITS;
10726 : : }
10727 : :
10728 : : /*----------
10729 : : * We have var ~= digits * 10^dweight
10730 : : * so ln(var) ~= ln(digits) + dweight * ln(10)
10731 : : *----------
10732 : : */
10733 : 282 : ln_var = log((double) digits) + dweight * 2.302585092994046;
555 peter@eisentraut.org 10734 : 282 : ln_dweight = (int) log10(fabs(ln_var));
10735 : : }
10736 : : else
10737 : : {
10738 : : /* Caller should fail on ln(0), but for the moment return zero */
3074 tgl@sss.pgh.pa.us 10739 : 21 : ln_dweight = 0;
10740 : : }
10741 : : }
10742 : :
10743 : 348 : return ln_dweight;
10744 : : }
10745 : :
10746 : :
10747 : : /*
10748 : : * ln_var() -
10749 : : *
10750 : : * Compute the natural log of x
10751 : : */
10752 : : static void
2408 andres@anarazel.de 10753 : 417 : ln_var(const NumericVar *arg, NumericVar *result, int rscale)
10754 : : {
10755 : : NumericVar x;
10756 : : NumericVar xx;
10757 : : int ni;
10758 : : NumericVar elem;
10759 : : NumericVar fact;
10760 : : int nsqrt;
10761 : : int local_rscale;
10762 : : int cmp;
10763 : :
7273 neilc@samurai.com 10764 : 417 : cmp = cmp_var(arg, &const_zero);
10765 [ + + ]: 417 : if (cmp == 0)
7567 tgl@sss.pgh.pa.us 10766 [ + - ]: 21 : ereport(ERROR,
10767 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
10768 : : errmsg("cannot take logarithm of zero")));
7273 neilc@samurai.com 10769 [ + + ]: 396 : else if (cmp < 0)
10770 [ + - ]: 18 : ereport(ERROR,
10771 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
10772 : : errmsg("cannot take logarithm of a negative number")));
10773 : :
9237 JanWieck@Yahoo.com 10774 : 378 : init_var(&x);
10775 : 378 : init_var(&xx);
10776 : 378 : init_var(&elem);
10777 : 378 : init_var(&fact);
10778 : :
10779 : 378 : set_var_from_var(arg, &x);
7695 tgl@sss.pgh.pa.us 10780 : 378 : set_var_from_var(&const_two, &fact);
10781 : :
10782 : : /*
10783 : : * Reduce input into range 0.9 < x < 1.1 with repeated sqrt() operations.
10784 : : *
10785 : : * The final logarithm will have up to around rscale+6 significant digits.
10786 : : * Each sqrt() will roughly halve the weight of x, so adjust the local
10787 : : * rscale as we work so that we keep this many significant digits at each
10788 : : * step (plus a few more for good measure).
10789 : : *
10790 : : * Note that we allow local_rscale < 0 during this input reduction
10791 : : * process, which implies rounding before the decimal point. sqrt_var()
10792 : : * explicitly supports this, and it significantly reduces the work
10793 : : * required to reduce very large inputs to the required range. Once the
10794 : : * input reduction is complete, x.weight will be 0 and its display scale
10795 : : * will be non-negative again.
10796 : : */
1505 dean.a.rasheed@gmail 10797 : 378 : nsqrt = 0;
7865 tgl@sss.pgh.pa.us 10798 [ + + ]: 534 : while (cmp_var(&x, &const_zero_point_nine) <= 0)
10799 : : {
3074 10800 : 156 : local_rscale = rscale - x.weight * DEC_DIGITS / 2 + 8;
7695 10801 : 156 : sqrt_var(&x, &x, local_rscale);
10802 : 156 : mul_var(&fact, &const_two, &fact, 0);
1505 dean.a.rasheed@gmail 10803 : 156 : nsqrt++;
10804 : : }
7865 tgl@sss.pgh.pa.us 10805 [ + + ]: 2064 : while (cmp_var(&x, &const_one_point_one) >= 0)
10806 : : {
3074 10807 : 1686 : local_rscale = rscale - x.weight * DEC_DIGITS / 2 + 8;
7695 10808 : 1686 : sqrt_var(&x, &x, local_rscale);
10809 : 1686 : mul_var(&fact, &const_two, &fact, 0);
1505 dean.a.rasheed@gmail 10810 : 1686 : nsqrt++;
10811 : : }
10812 : :
10813 : : /*
10814 : : * We use the Taylor series for 0.5 * ln((1+z)/(1-z)),
10815 : : *
10816 : : * z + z^3/3 + z^5/5 + ...
10817 : : *
10818 : : * where z = (x-1)/(x+1) is in the range (approximately) -0.053 .. 0.048
10819 : : * due to the above range-reduction of x.
10820 : : *
10821 : : * The convergence of this is not as fast as one would like, but is
10822 : : * tolerable given that z is small.
10823 : : *
10824 : : * The Taylor series result will be multiplied by 2^(nsqrt+1), which has a
10825 : : * decimal weight of (nsqrt+1) * log10(2), so work with this many extra
10826 : : * digits of precision (plus a few more for good measure).
10827 : : */
10828 : 378 : local_rscale = rscale + (int) ((nsqrt + 1) * 0.301029995663981) + 8;
10829 : :
9237 JanWieck@Yahoo.com 10830 : 378 : sub_var(&x, &const_one, result);
10831 : 378 : add_var(&x, &const_one, &elem);
5854 tgl@sss.pgh.pa.us 10832 : 378 : div_var_fast(result, &elem, result, local_rscale, true);
9237 JanWieck@Yahoo.com 10833 : 378 : set_var_from_var(result, &xx);
7695 tgl@sss.pgh.pa.us 10834 : 378 : mul_var(result, result, &x, local_rscale);
10835 : :
777 dean.a.rasheed@gmail 10836 : 378 : ni = 1;
10837 : :
10838 : : for (;;)
10839 : : {
10840 : 7011 : ni += 2;
7695 tgl@sss.pgh.pa.us 10841 : 7011 : mul_var(&xx, &x, &xx, local_rscale);
777 dean.a.rasheed@gmail 10842 : 7011 : div_var_int(&xx, ni, 0, &elem, local_rscale, true);
10843 : :
7865 tgl@sss.pgh.pa.us 10844 [ + + ]: 7011 : if (elem.ndigits == 0)
9237 JanWieck@Yahoo.com 10845 : 378 : break;
10846 : :
10847 : 6633 : add_var(result, &elem, result);
10848 : :
7559 bruce@momjian.us 10849 [ - + ]: 6633 : if (elem.weight < (result->weight - local_rscale * 2 / DEC_DIGITS))
7702 tgl@sss.pgh.pa.us 10850 :UBC 0 : break;
10851 : : }
10852 : :
10853 : : /* Compensate for argument range reduction, round to requested rscale */
7695 tgl@sss.pgh.pa.us 10854 :CBC 378 : mul_var(result, &fact, result, rscale);
10855 : :
9237 JanWieck@Yahoo.com 10856 : 378 : free_var(&x);
10857 : 378 : free_var(&xx);
10858 : 378 : free_var(&elem);
10859 : 378 : free_var(&fact);
10860 : 378 : }
10861 : :
10862 : :
10863 : : /*
10864 : : * log_var() -
10865 : : *
10866 : : * Compute the logarithm of num in a given base.
10867 : : *
10868 : : * Note: this routine chooses dscale of the result.
10869 : : */
10870 : : static void
2408 andres@anarazel.de 10871 : 108 : log_var(const NumericVar *base, const NumericVar *num, NumericVar *result)
10872 : : {
10873 : : NumericVar ln_base;
10874 : : NumericVar ln_num;
10875 : : int ln_base_dweight;
10876 : : int ln_num_dweight;
10877 : : int result_dweight;
10878 : : int rscale;
10879 : : int ln_base_rscale;
10880 : : int ln_num_rscale;
10881 : :
9237 JanWieck@Yahoo.com 10882 : 108 : init_var(&ln_base);
10883 : 108 : init_var(&ln_num);
10884 : :
10885 : : /* Estimated dweights of ln(base), ln(num) and the final result */
3074 tgl@sss.pgh.pa.us 10886 : 108 : ln_base_dweight = estimate_ln_dweight(base);
10887 : 108 : ln_num_dweight = estimate_ln_dweight(num);
10888 : 108 : result_dweight = ln_num_dweight - ln_base_dweight;
10889 : :
10890 : : /*
10891 : : * Select the scale of the result so that it will have at least
10892 : : * NUMERIC_MIN_SIG_DIGITS significant digits and is not less than either
10893 : : * input's display scale.
10894 : : */
10895 : 108 : rscale = NUMERIC_MIN_SIG_DIGITS - result_dweight;
7695 10896 : 108 : rscale = Max(rscale, base->dscale);
10897 : 108 : rscale = Max(rscale, num->dscale);
10898 : 108 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
10899 : 108 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
10900 : :
10901 : : /*
10902 : : * Set the scales for ln(base) and ln(num) so that they each have more
10903 : : * significant digits than the final result.
10904 : : */
3074 10905 : 108 : ln_base_rscale = rscale + result_dweight - ln_base_dweight + 8;
10906 : 108 : ln_base_rscale = Max(ln_base_rscale, NUMERIC_MIN_DISPLAY_SCALE);
10907 : :
10908 : 108 : ln_num_rscale = rscale + result_dweight - ln_num_dweight + 8;
10909 : 108 : ln_num_rscale = Max(ln_num_rscale, NUMERIC_MIN_DISPLAY_SCALE);
10910 : :
10911 : : /* Form natural logarithms */
10912 : 108 : ln_var(base, &ln_base, ln_base_rscale);
10913 : 96 : ln_var(num, &ln_num, ln_num_rscale);
10914 : :
10915 : : /* Divide and round to the required scale */
5854 10916 : 81 : div_var_fast(&ln_num, &ln_base, result, rscale, true);
10917 : :
9237 JanWieck@Yahoo.com 10918 : 78 : free_var(&ln_num);
10919 : 78 : free_var(&ln_base);
10920 : 78 : }
10921 : :
10922 : :
10923 : : /*
10924 : : * power_var() -
10925 : : *
10926 : : * Raise base to the power of exp
10927 : : *
10928 : : * Note: this routine chooses dscale of the result.
10929 : : */
10930 : : static void
2408 andres@anarazel.de 10931 : 693 : power_var(const NumericVar *base, const NumericVar *exp, NumericVar *result)
10932 : : {
10933 : : int res_sign;
10934 : : NumericVar abs_base;
10935 : : NumericVar ln_base;
10936 : : NumericVar ln_num;
10937 : : int ln_dweight;
10938 : : int rscale;
10939 : : int sig_digits;
10940 : : int local_rscale;
10941 : : double val;
10942 : :
10943 : : /* If exp can be represented as an integer, use power_var_int */
7695 tgl@sss.pgh.pa.us 10944 [ + + + + ]: 693 : if (exp->ndigits == 0 || exp->ndigits <= exp->weight + 1)
10945 : : {
10946 : : /* exact integer, but does it fit in int? */
10947 : : int64 expval64;
10948 : :
3313 andres@anarazel.de 10949 [ + + ]: 630 : if (numericvar_to_int64(exp, &expval64))
10950 : : {
982 dean.a.rasheed@gmail 10951 [ + - + + ]: 627 : if (expval64 >= PG_INT32_MIN && expval64 <= PG_INT32_MAX)
10952 : : {
10953 : : /* Okay, use power_var_int */
542 10954 : 612 : power_var_int(base, (int) expval64, exp->dscale, result);
7695 tgl@sss.pgh.pa.us 10955 : 606 : return;
10956 : : }
10957 : : }
10958 : : }
10959 : :
10960 : : /*
10961 : : * This avoids log(0) for cases of 0 raised to a non-integer. 0 ^ 0 is
10962 : : * handled by power_var_int().
10963 : : */
5820 bruce@momjian.us 10964 [ + + ]: 81 : if (cmp_var(base, &const_zero) == 0)
10965 : : {
10966 : 9 : set_var_from_var(&const_zero, result);
2489 tgl@sss.pgh.pa.us 10967 : 9 : result->dscale = NUMERIC_MIN_SIG_DIGITS; /* no need to round */
5820 bruce@momjian.us 10968 : 9 : return;
10969 : : }
10970 : :
988 dean.a.rasheed@gmail 10971 : 72 : init_var(&abs_base);
9237 JanWieck@Yahoo.com 10972 : 72 : init_var(&ln_base);
10973 : 72 : init_var(&ln_num);
10974 : :
10975 : : /*
10976 : : * If base is negative, insist that exp be an integer. The result is then
10977 : : * positive if exp is even and negative if exp is odd.
10978 : : */
988 dean.a.rasheed@gmail 10979 [ + + ]: 72 : if (base->sign == NUMERIC_NEG)
10980 : : {
10981 : : /*
10982 : : * Check that exp is an integer. This error code is defined by the
10983 : : * SQL standard, and matches other errors in numeric_power().
10984 : : */
10985 [ + - + + ]: 18 : if (exp->ndigits > 0 && exp->ndigits > exp->weight + 1)
10986 [ + - ]: 9 : ereport(ERROR,
10987 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
10988 : : errmsg("a negative number raised to a non-integer power yields a complex result")));
10989 : :
10990 : : /* Test if exp is odd or even */
10991 [ + - + + ]: 9 : if (exp->ndigits > 0 && exp->ndigits == exp->weight + 1 &&
10992 [ + + ]: 6 : (exp->digits[exp->ndigits - 1] & 1))
10993 : 3 : res_sign = NUMERIC_NEG;
10994 : : else
10995 : 6 : res_sign = NUMERIC_POS;
10996 : :
10997 : : /* Then work with abs(base) below */
10998 : 9 : set_var_from_var(base, &abs_base);
10999 : 9 : abs_base.sign = NUMERIC_POS;
11000 : 9 : base = &abs_base;
11001 : : }
11002 : : else
11003 : 54 : res_sign = NUMERIC_POS;
11004 : :
11005 : : /*----------
11006 : : * Decide on the scale for the ln() calculation. For this we need an
11007 : : * estimate of the weight of the result, which we obtain by doing an
11008 : : * initial low-precision calculation of exp * ln(base).
11009 : : *
11010 : : * We want result = e ^ (exp * ln(base))
11011 : : * so result dweight = log10(result) = exp * ln(base) * log10(e)
11012 : : *
11013 : : * We also perform a crude overflow test here so that we can exit early if
11014 : : * the full-precision result is sure to overflow, and to guard against
11015 : : * integer overflow when determining the scale for the real calculation.
11016 : : * exp_var() supports inputs up to NUMERIC_MAX_RESULT_SCALE * 3, so the
11017 : : * result will overflow if exp * ln(base) >= NUMERIC_MAX_RESULT_SCALE * 3.
11018 : : * Since the values here are only approximations, we apply a small fuzz
11019 : : * factor to this overflow test and let exp_var() determine the exact
11020 : : * overflow threshold so that it is consistent for all inputs.
11021 : : *----------
11022 : : */
3074 tgl@sss.pgh.pa.us 11023 : 63 : ln_dweight = estimate_ln_dweight(base);
11024 : :
11025 : : /*
11026 : : * Set the scale for the low-precision calculation, computing ln(base) to
11027 : : * around 8 significant digits. Note that ln_dweight may be as small as
11028 : : * -SHRT_MAX, so the scale may exceed NUMERIC_MAX_DISPLAY_SCALE here.
11029 : : */
11030 : 63 : local_rscale = 8 - ln_dweight;
11031 : 63 : local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
11032 : :
7695 11033 : 63 : ln_var(base, &ln_base, local_rscale);
11034 : :
11035 : 63 : mul_var(&ln_base, exp, &ln_num, local_rscale);
11036 : :
7865 11037 : 63 : val = numericvar_to_double_no_overflow(&ln_num);
11038 : :
11039 : : /* initial overflow/underflow test with fuzz factor */
555 peter@eisentraut.org 11040 [ + + ]: 63 : if (fabs(val) > NUMERIC_MAX_RESULT_SCALE * 3.01)
11041 : : {
988 dean.a.rasheed@gmail 11042 [ - + ]: 3 : if (val > 0)
988 dean.a.rasheed@gmail 11043 [ # # ]:UBC 0 : ereport(ERROR,
11044 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
11045 : : errmsg("value overflows numeric format")));
988 dean.a.rasheed@gmail 11046 :CBC 3 : zero_var(result);
11047 : 3 : result->dscale = NUMERIC_MAX_DISPLAY_SCALE;
11048 : 3 : return;
11049 : : }
11050 : :
2901 11051 : 60 : val *= 0.434294481903252; /* approximate decimal result weight */
11052 : :
11053 : : /* choose the result scale */
7695 tgl@sss.pgh.pa.us 11054 : 60 : rscale = NUMERIC_MIN_SIG_DIGITS - (int) val;
11055 : 60 : rscale = Max(rscale, base->dscale);
11056 : 60 : rscale = Max(rscale, exp->dscale);
11057 : 60 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
11058 : 60 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
11059 : :
11060 : : /* significant digits required in the result */
988 dean.a.rasheed@gmail 11061 : 60 : sig_digits = rscale + (int) val;
11062 : 60 : sig_digits = Max(sig_digits, 0);
11063 : :
11064 : : /* set the scale for the real exp * ln(base) calculation */
11065 : 60 : local_rscale = sig_digits - ln_dweight + 8;
3074 tgl@sss.pgh.pa.us 11066 : 60 : local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
11067 : :
11068 : : /* and do the real calculation */
11069 : :
11070 : 60 : ln_var(base, &ln_base, local_rscale);
11071 : :
11072 : 60 : mul_var(&ln_base, exp, &ln_num, local_rscale);
11073 : :
7695 11074 : 60 : exp_var(&ln_num, result, rscale);
11075 : :
988 dean.a.rasheed@gmail 11076 [ + + + - ]: 60 : if (res_sign == NUMERIC_NEG && result->ndigits > 0)
11077 : 3 : result->sign = NUMERIC_NEG;
11078 : :
7695 tgl@sss.pgh.pa.us 11079 : 60 : free_var(&ln_num);
11080 : 60 : free_var(&ln_base);
988 dean.a.rasheed@gmail 11081 : 60 : free_var(&abs_base);
11082 : : }
11083 : :
11084 : : /*
11085 : : * power_var_int() -
11086 : : *
11087 : : * Raise base to the power of exp, where exp is an integer.
11088 : : *
11089 : : * Note: this routine chooses dscale of the result.
11090 : : */
11091 : : static void
542 11092 : 612 : power_var_int(const NumericVar *base, int exp, int exp_dscale,
11093 : : NumericVar *result)
11094 : : {
11095 : : double f;
11096 : : int p;
11097 : : int i;
11098 : : int rscale;
11099 : : int sig_digits;
11100 : : unsigned int mask;
11101 : : bool neg;
11102 : : NumericVar base_prod;
11103 : : int local_rscale;
11104 : :
11105 : : /*
11106 : : * Choose the result scale. For this we need an estimate of the decimal
11107 : : * weight of the result, which we obtain by approximating using double
11108 : : * precision arithmetic.
11109 : : *
11110 : : * We also perform crude overflow/underflow tests here so that we can exit
11111 : : * early if the result is sure to overflow/underflow, and to guard against
11112 : : * integer overflow when choosing the result scale.
11113 : : */
11114 [ + + ]: 612 : if (base->ndigits != 0)
11115 : : {
11116 : : /*----------
11117 : : * Choose f (double) and p (int) such that base ~= f * 10^p.
11118 : : * Then log10(result) = log10(base^exp) ~= exp * (log10(f) + p).
11119 : : *----------
11120 : : */
11121 : 597 : f = base->digits[0];
11122 : 597 : p = base->weight * DEC_DIGITS;
11123 : :
11124 [ + + + - ]: 639 : for (i = 1; i < base->ndigits && i * DEC_DIGITS < 16; i++)
11125 : : {
11126 : 42 : f = f * NBASE + base->digits[i];
11127 : 42 : p -= DEC_DIGITS;
11128 : : }
11129 : :
11130 : 597 : f = exp * (log10(f) + p); /* approximate decimal result weight */
11131 : : }
11132 : : else
11133 : 15 : f = 0; /* result is 0 or 1 (weight 0), or error */
11134 : :
11135 : : /* overflow/underflow tests with fuzz factors */
11136 [ + + ]: 612 : if (f > (SHRT_MAX + 1) * DEC_DIGITS)
11137 [ + - ]: 6 : ereport(ERROR,
11138 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
11139 : : errmsg("value overflows numeric format")));
11140 [ + + ]: 606 : if (f + 1 < -NUMERIC_MAX_DISPLAY_SCALE)
11141 : : {
11142 : 6 : zero_var(result);
11143 : 6 : result->dscale = NUMERIC_MAX_DISPLAY_SCALE;
11144 : 105 : return;
11145 : : }
11146 : :
11147 : : /*
11148 : : * Choose the result scale in the same way as power_var(), so it has at
11149 : : * least NUMERIC_MIN_SIG_DIGITS significant digits and is not less than
11150 : : * either input's display scale.
11151 : : */
11152 : 600 : rscale = NUMERIC_MIN_SIG_DIGITS - (int) f;
11153 : 600 : rscale = Max(rscale, base->dscale);
11154 : 600 : rscale = Max(rscale, exp_dscale);
11155 : 600 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
11156 : 600 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
11157 : :
11158 : : /* Handle some common special cases, as well as corner cases */
7695 tgl@sss.pgh.pa.us 11159 [ + + + + : 600 : switch (exp)
+ ]
11160 : : {
11161 : 36 : case 0:
11162 : :
11163 : : /*
11164 : : * While 0 ^ 0 can be either 1 or indeterminate (error), we treat
11165 : : * it as 1 because most programming languages do this. SQL:2003
11166 : : * also requires a return value of 1.
11167 : : * https://en.wikipedia.org/wiki/Exponentiation#Zero_to_the_zero_power
11168 : : */
11169 : 36 : set_var_from_var(&const_one, result);
7559 bruce@momjian.us 11170 : 36 : result->dscale = rscale; /* no need to round */
7695 tgl@sss.pgh.pa.us 11171 : 36 : return;
11172 : 24 : case 1:
11173 : 24 : set_var_from_var(base, result);
11174 : 24 : round_var(result, rscale);
11175 : 24 : return;
11176 : 15 : case -1:
6889 bruce@momjian.us 11177 : 15 : div_var(&const_one, base, result, rscale, true);
7695 tgl@sss.pgh.pa.us 11178 : 15 : return;
11179 : 24 : case 2:
11180 : 24 : mul_var(base, base, result, rscale);
11181 : 24 : return;
11182 : 501 : default:
11183 : 501 : break;
11184 : : }
11185 : :
11186 : : /* Handle the special case where the base is zero */
3074 11187 [ - + ]: 501 : if (base->ndigits == 0)
11188 : : {
3074 tgl@sss.pgh.pa.us 11189 [ # # ]:UBC 0 : if (exp < 0)
11190 [ # # ]: 0 : ereport(ERROR,
11191 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
11192 : : errmsg("division by zero")));
11193 : 0 : zero_var(result);
11194 : 0 : result->dscale = rscale;
11195 : 0 : return;
11196 : : }
11197 : :
11198 : : /*
11199 : : * The general case repeatedly multiplies base according to the bit
11200 : : * pattern of exp.
11201 : : *
11202 : : * The local rscale used for each multiplication is varied to keep a fixed
11203 : : * number of significant digits, sufficient to give the required result
11204 : : * scale.
11205 : : */
11206 : :
11207 : : /*
11208 : : * Approximate number of significant digits in the result. Note that the
11209 : : * underflow test above, together with the choice of rscale, ensures that
11210 : : * this approximation is necessarily > 0.
11211 : : */
3074 tgl@sss.pgh.pa.us 11212 :CBC 501 : sig_digits = 1 + rscale + (int) f;
11213 : :
11214 : : /*
11215 : : * The multiplications to produce the result may introduce an error of up
11216 : : * to around log10(abs(exp)) digits, so work with this many extra digits
11217 : : * of precision (plus a few more for good measure).
11218 : : */
1195 dean.a.rasheed@gmail 11219 : 501 : sig_digits += (int) log(fabs((double) exp)) + 8;
11220 : :
11221 : : /*
11222 : : * Now we can proceed with the multiplications.
11223 : : */
7695 tgl@sss.pgh.pa.us 11224 : 501 : neg = (exp < 0);
555 peter@eisentraut.org 11225 : 501 : mask = abs(exp);
11226 : :
7695 tgl@sss.pgh.pa.us 11227 : 501 : init_var(&base_prod);
11228 : 501 : set_var_from_var(base, &base_prod);
11229 : :
3503 11230 [ + + ]: 501 : if (mask & 1)
7695 11231 : 249 : set_var_from_var(base, result);
11232 : : else
11233 : 252 : set_var_from_var(&const_one, result);
11234 : :
3503 11235 [ + + ]: 2532 : while ((mask >>= 1) > 0)
11236 : : {
11237 : : /*
11238 : : * Do the multiplications using rscales large enough to hold the
11239 : : * results to the required number of significant digits, but don't
11240 : : * waste time by exceeding the scales of the numbers themselves.
11241 : : */
3074 11242 : 2031 : local_rscale = sig_digits - 2 * base_prod.weight * DEC_DIGITS;
11243 : 2031 : local_rscale = Min(local_rscale, 2 * base_prod.dscale);
11244 : 2031 : local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
11245 : :
7695 11246 : 2031 : mul_var(&base_prod, &base_prod, &base_prod, local_rscale);
11247 : :
3503 11248 [ + + ]: 2031 : if (mask & 1)
11249 : : {
3074 11250 : 1326 : local_rscale = sig_digits -
11251 : 1326 : (base_prod.weight + result->weight) * DEC_DIGITS;
11252 : 1326 : local_rscale = Min(local_rscale,
11253 : : base_prod.dscale + result->dscale);
11254 : 1326 : local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
11255 : :
7695 11256 : 1326 : mul_var(&base_prod, result, result, local_rscale);
11257 : : }
11258 : :
11259 : : /*
11260 : : * When abs(base) > 1, the number of digits to the left of the decimal
11261 : : * point in base_prod doubles at each iteration, so if exp is large we
11262 : : * could easily spend large amounts of time and memory space doing the
11263 : : * multiplications. But once the weight exceeds what will fit in
11264 : : * int16, the final result is guaranteed to overflow (or underflow, if
11265 : : * exp < 0), so we can give up before wasting too many cycles.
11266 : : */
3503 11267 [ + - - + ]: 2031 : if (base_prod.weight > SHRT_MAX || result->weight > SHRT_MAX)
11268 : : {
11269 : : /* overflow, unless neg, in which case result should be 0 */
3503 tgl@sss.pgh.pa.us 11270 [ # # ]:UBC 0 : if (!neg)
11271 [ # # ]: 0 : ereport(ERROR,
11272 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
11273 : : errmsg("value overflows numeric format")));
11274 : 0 : zero_var(result);
11275 : 0 : neg = false;
11276 : 0 : break;
11277 : : }
11278 : : }
11279 : :
7695 tgl@sss.pgh.pa.us 11280 :CBC 501 : free_var(&base_prod);
11281 : :
11282 : : /* Compensate for input sign, and round to requested rscale */
11283 [ + + ]: 501 : if (neg)
5854 11284 : 240 : div_var_fast(&const_one, result, result, rscale, true);
11285 : : else
7695 11286 : 261 : round_var(result, rscale);
11287 : : }
11288 : :
11289 : : /*
11290 : : * power_ten_int() -
11291 : : *
11292 : : * Raise ten to the power of exp, where exp is an integer. Note that unlike
11293 : : * power_var_int(), this does no overflow/underflow checking or rounding.
11294 : : */
11295 : : static void
983 dean.a.rasheed@gmail 11296 : 108 : power_ten_int(int exp, NumericVar *result)
11297 : : {
11298 : : /* Construct the result directly, starting from 10^0 = 1 */
11299 : 108 : set_var_from_var(&const_one, result);
11300 : :
11301 : : /* Scale needed to represent the result exactly */
11302 [ + + ]: 108 : result->dscale = exp < 0 ? -exp : 0;
11303 : :
11304 : : /* Base-NBASE weight of result and remaining exponent */
11305 [ + + ]: 108 : if (exp >= 0)
11306 : 75 : result->weight = exp / DEC_DIGITS;
11307 : : else
11308 : 33 : result->weight = (exp + 1) / DEC_DIGITS - 1;
11309 : :
11310 : 108 : exp -= result->weight * DEC_DIGITS;
11311 : :
11312 : : /* Final adjustment of the result's single NBASE digit */
11313 [ + + ]: 273 : while (exp-- > 0)
11314 : 165 : result->digits[0] *= 10;
11315 : 108 : }
11316 : :
11317 : : /*
11318 : : * random_var() - return a random value in the range [rmin, rmax].
11319 : : */
11320 : : static void
18 dean.a.rasheed@gmail 11321 :GNC 16719 : random_var(pg_prng_state *state, const NumericVar *rmin,
11322 : : const NumericVar *rmax, NumericVar *result)
11323 : : {
11324 : : int rscale;
11325 : : NumericVar rlen;
11326 : : int res_ndigits;
11327 : : int n;
11328 : : int pow10;
11329 : : int i;
11330 : : uint64 rlen64;
11331 : : int rlen64_ndigits;
11332 : :
11333 : 16719 : rscale = Max(rmin->dscale, rmax->dscale);
11334 : :
11335 : : /* Compute rlen = rmax - rmin and check the range bounds */
11336 : 16719 : init_var(&rlen);
11337 : 16719 : sub_var(rmax, rmin, &rlen);
11338 : :
11339 [ + + ]: 16719 : if (rlen.sign == NUMERIC_NEG)
11340 [ + - ]: 3 : ereport(ERROR,
11341 : : errcode(ERRCODE_INVALID_PARAMETER_VALUE),
11342 : : errmsg("lower bound must be less than or equal to upper bound"));
11343 : :
11344 : : /* Special case for an empty range */
11345 [ + + ]: 16716 : if (rlen.ndigits == 0)
11346 : : {
11347 : 6 : set_var_from_var(rmin, result);
11348 : 6 : result->dscale = rscale;
11349 : 6 : free_var(&rlen);
11350 : 6 : return;
11351 : : }
11352 : :
11353 : : /*
11354 : : * Otherwise, select a random value in the range [0, rlen = rmax - rmin],
11355 : : * and shift it to the required range by adding rmin.
11356 : : */
11357 : :
11358 : : /* Required result digits */
11359 : 16710 : res_ndigits = rlen.weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
11360 : :
11361 : : /*
11362 : : * To get the required rscale, the final result digit must be a multiple
11363 : : * of pow10 = 10^n, where n = (-rscale) mod DEC_DIGITS.
11364 : : */
11365 : 16710 : n = ((rscale + DEC_DIGITS - 1) / DEC_DIGITS) * DEC_DIGITS - rscale;
11366 : 16710 : pow10 = 1;
11367 [ + + ]: 43950 : for (i = 0; i < n; i++)
11368 : 27240 : pow10 *= 10;
11369 : :
11370 : : /*
11371 : : * To choose a random value uniformly from the range [0, rlen], we choose
11372 : : * from the slightly larger range [0, rlen2], where rlen2 is formed from
11373 : : * rlen by copying the first 4 NBASE digits, and setting all remaining
11374 : : * decimal digits to "9".
11375 : : *
11376 : : * Without loss of generality, we can ignore the weight of rlen2 and treat
11377 : : * it as a pure integer for the purposes of this discussion. The process
11378 : : * above gives rlen2 + 1 = rlen64 * 10^N, for some integer N, where rlen64
11379 : : * is a 64-bit integer formed from the first 4 NBASE digits copied from
11380 : : * rlen. Since this trivially factors into smaller pieces that fit in
11381 : : * 64-bit integers, the task of choosing a random value uniformly from the
11382 : : * rlen2 + 1 possible values in [0, rlen2] is much simpler.
11383 : : *
11384 : : * If the random value selected is too large, it is rejected, and we try
11385 : : * again until we get a result <= rlen, ensuring that the overall result
11386 : : * is uniform (no particular value is any more likely than any other).
11387 : : *
11388 : : * Since rlen64 holds 4 NBASE digits from rlen, it contains at least
11389 : : * DEC_DIGITS * 3 + 1 decimal digits (i.e., at least 13 decimal digits,
11390 : : * when DEC_DIGITS is 4). Therefore the probability of needing to reject
11391 : : * the value chosen and retry is less than 1e-13.
11392 : : */
11393 : 16710 : rlen64 = (uint64) rlen.digits[0];
11394 : 16710 : rlen64_ndigits = 1;
11395 [ + + + + ]: 38106 : while (rlen64_ndigits < res_ndigits && rlen64_ndigits < 4)
11396 : : {
11397 : 21396 : rlen64 *= NBASE;
11398 [ + + ]: 21396 : if (rlen64_ndigits < rlen.ndigits)
11399 : 3306 : rlen64 += rlen.digits[rlen64_ndigits];
11400 : 21396 : rlen64_ndigits++;
11401 : : }
11402 : :
11403 : : /* Loop until we get a result <= rlen */
11404 : : do
11405 : : {
11406 : : NumericDigit *res_digits;
11407 : : uint64 rand;
11408 : : int whole_ndigits;
11409 : :
11410 : 16710 : alloc_var(result, res_ndigits);
11411 : 16710 : result->sign = NUMERIC_POS;
11412 : 16710 : result->weight = rlen.weight;
11413 : 16710 : result->dscale = rscale;
11414 : 16710 : res_digits = result->digits;
11415 : :
11416 : : /*
11417 : : * Set the first rlen64_ndigits using a random value in [0, rlen64].
11418 : : *
11419 : : * If this is the whole result, and rscale is not a multiple of
11420 : : * DEC_DIGITS (pow10 from above is not 1), then we need this to be a
11421 : : * multiple of pow10.
11422 : : */
11423 [ + + + + ]: 16710 : if (rlen64_ndigits == res_ndigits && pow10 != 1)
11424 : 10566 : rand = pg_prng_uint64_range(state, 0, rlen64 / pow10) * pow10;
11425 : : else
11426 : 6144 : rand = pg_prng_uint64_range(state, 0, rlen64);
11427 : :
11428 [ + + ]: 54816 : for (i = rlen64_ndigits - 1; i >= 0; i--)
11429 : : {
11430 : 38106 : res_digits[i] = (NumericDigit) (rand % NBASE);
11431 : 38106 : rand = rand / NBASE;
11432 : : }
11433 : :
11434 : : /*
11435 : : * Set the remaining digits to random values in range [0, NBASE),
11436 : : * noting that the last digit needs to be a multiple of pow10.
11437 : : */
11438 : 16710 : whole_ndigits = res_ndigits;
11439 [ + + ]: 16710 : if (pow10 != 1)
11440 : 16605 : whole_ndigits--;
11441 : :
11442 : : /* Set whole digits in groups of 4 for best performance */
11443 : 16710 : i = rlen64_ndigits;
11444 [ + + ]: 16740 : while (i < whole_ndigits - 3)
11445 : : {
11446 : 30 : rand = pg_prng_uint64_range(state, 0,
11447 : : (uint64) NBASE * NBASE * NBASE * NBASE - 1);
11448 : 30 : res_digits[i++] = (NumericDigit) (rand % NBASE);
11449 : 30 : rand = rand / NBASE;
11450 : 30 : res_digits[i++] = (NumericDigit) (rand % NBASE);
11451 : 30 : rand = rand / NBASE;
11452 : 30 : res_digits[i++] = (NumericDigit) (rand % NBASE);
11453 : 30 : rand = rand / NBASE;
11454 : 30 : res_digits[i++] = (NumericDigit) rand;
11455 : : }
11456 : :
11457 : : /* Remaining whole digits */
11458 [ + + ]: 16815 : while (i < whole_ndigits)
11459 : : {
11460 : 105 : rand = pg_prng_uint64_range(state, 0, NBASE - 1);
11461 : 105 : res_digits[i++] = (NumericDigit) rand;
11462 : : }
11463 : :
11464 : : /* Final partial digit (multiple of pow10) */
11465 [ + + ]: 16710 : if (i < res_ndigits)
11466 : : {
11467 : 6039 : rand = pg_prng_uint64_range(state, 0, NBASE / pow10 - 1) * pow10;
11468 : 6039 : res_digits[i] = (NumericDigit) rand;
11469 : : }
11470 : :
11471 : : /* Remove leading/trailing zeroes */
11472 : 16710 : strip_var(result);
11473 : :
11474 : : /* If result > rlen, try again */
11475 : :
11476 [ - + ]: 16710 : } while (cmp_var(result, &rlen) > 0);
11477 : :
11478 : : /* Offset the result to the required range */
11479 : 16710 : add_var(result, rmin, result);
11480 : :
11481 : 16710 : free_var(&rlen);
11482 : : }
11483 : :
11484 : :
11485 : : /* ----------------------------------------------------------------------
11486 : : *
11487 : : * Following are the lowest level functions that operate unsigned
11488 : : * on the variable level
11489 : : *
11490 : : * ----------------------------------------------------------------------
11491 : : */
11492 : :
11493 : :
11494 : : /* ----------
11495 : : * cmp_abs() -
11496 : : *
11497 : : * Compare the absolute values of var1 and var2
11498 : : * Returns: -1 for ABS(var1) < ABS(var2)
11499 : : * 0 for ABS(var1) == ABS(var2)
11500 : : * 1 for ABS(var1) > ABS(var2)
11501 : : * ----------
11502 : : */
11503 : : static int
2408 andres@anarazel.de 11504 :CBC 180036 : cmp_abs(const NumericVar *var1, const NumericVar *var2)
11505 : : {
6641 bruce@momjian.us 11506 : 360072 : return cmp_abs_common(var1->digits, var1->ndigits, var1->weight,
11507 : 180036 : var2->digits, var2->ndigits, var2->weight);
11508 : : }
11509 : :
11510 : : /* ----------
11511 : : * cmp_abs_common() -
11512 : : *
11513 : : * Main routine of cmp_abs(). This function can be used by both
11514 : : * NumericVar and Numeric.
11515 : : * ----------
11516 : : */
11517 : : static int
11518 : 3334689 : cmp_abs_common(const NumericDigit *var1digits, int var1ndigits, int var1weight,
11519 : : const NumericDigit *var2digits, int var2ndigits, int var2weight)
11520 : : {
9091 11521 : 3334689 : int i1 = 0;
11522 : 3334689 : int i2 = 0;
11523 : :
11524 : : /* Check any digits before the first common digit */
11525 : :
6641 11526 [ + + + + ]: 3334689 : while (var1weight > var2weight && i1 < var1ndigits)
11527 : : {
7695 tgl@sss.pgh.pa.us 11528 [ + - ]: 15713 : if (var1digits[i1++] != 0)
9091 bruce@momjian.us 11529 : 15713 : return 1;
6641 bruce@momjian.us 11530 :UBC 0 : var1weight--;
11531 : : }
6641 bruce@momjian.us 11532 [ + + + + ]:CBC 3318976 : while (var2weight > var1weight && i2 < var2ndigits)
11533 : : {
7695 tgl@sss.pgh.pa.us 11534 [ + - ]: 17682 : if (var2digits[i2++] != 0)
9091 bruce@momjian.us 11535 : 17682 : return -1;
6641 bruce@momjian.us 11536 :UBC 0 : var2weight--;
11537 : : }
11538 : :
11539 : : /* At this point, either w1 == w2 or we've run out of digits */
11540 : :
6641 bruce@momjian.us 11541 [ + + ]:CBC 3301294 : if (var1weight == var2weight)
11542 : : {
11543 [ + + + + ]: 6126883 : while (i1 < var1ndigits && i2 < var2ndigits)
11544 : : {
7695 tgl@sss.pgh.pa.us 11545 : 4100271 : int stat = var1digits[i1++] - var2digits[i2++];
11546 : :
9232 JanWieck@Yahoo.com 11547 [ + + ]: 4100271 : if (stat)
11548 : : {
11549 [ + + ]: 1271518 : if (stat > 0)
11550 : 822161 : return 1;
11551 : 449357 : return -1;
11552 : : }
11553 : : }
11554 : : }
11555 : :
11556 : : /*
11557 : : * At this point, we've run out of digits on one side or the other; so any
11558 : : * remaining nonzero digits imply that side is larger
11559 : : */
6641 bruce@momjian.us 11560 [ + + ]: 2029926 : while (i1 < var1ndigits)
11561 : : {
7695 tgl@sss.pgh.pa.us 11562 [ + + ]: 4193 : if (var1digits[i1++] != 0)
9237 JanWieck@Yahoo.com 11563 : 4043 : return 1;
11564 : : }
6641 bruce@momjian.us 11565 [ + + ]: 2025823 : while (i2 < var2ndigits)
11566 : : {
7695 tgl@sss.pgh.pa.us 11567 [ + + ]: 461 : if (var2digits[i2++] != 0)
9237 JanWieck@Yahoo.com 11568 : 371 : return -1;
11569 : : }
11570 : :
11571 : 2025362 : return 0;
11572 : : }
11573 : :
11574 : :
11575 : : /*
11576 : : * add_abs() -
11577 : : *
11578 : : * Add the absolute values of two variables into result.
11579 : : * result might point to one of the operands without danger.
11580 : : */
11581 : : static void
2408 andres@anarazel.de 11582 : 165460 : add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
11583 : : {
11584 : : NumericDigit *res_buf;
11585 : : NumericDigit *res_digits;
11586 : : int res_ndigits;
11587 : : int res_weight;
11588 : : int res_rscale,
11589 : : rscale1,
11590 : : rscale2;
11591 : : int res_dscale;
11592 : : int i,
11593 : : i1,
11594 : : i2;
9091 bruce@momjian.us 11595 : 165460 : int carry = 0;
11596 : :
11597 : : /* copy these values into local vars for speed in inner loop */
8672 tgl@sss.pgh.pa.us 11598 : 165460 : int var1ndigits = var1->ndigits;
11599 : 165460 : int var2ndigits = var2->ndigits;
11600 : 165460 : NumericDigit *var1digits = var1->digits;
11601 : 165460 : NumericDigit *var2digits = var2->digits;
11602 : :
8091 bruce@momjian.us 11603 : 165460 : res_weight = Max(var1->weight, var2->weight) + 1;
11604 : :
11605 : 165460 : res_dscale = Max(var1->dscale, var2->dscale);
11606 : :
11607 : : /* Note: here we are figuring rscale in base-NBASE digits */
7695 tgl@sss.pgh.pa.us 11608 : 165460 : rscale1 = var1->ndigits - var1->weight - 1;
11609 : 165460 : rscale2 = var2->ndigits - var2->weight - 1;
11610 : 165460 : res_rscale = Max(rscale1, rscale2);
11611 : :
9237 JanWieck@Yahoo.com 11612 : 165460 : res_ndigits = res_rscale + res_weight + 1;
8853 tgl@sss.pgh.pa.us 11613 [ - + ]: 165460 : if (res_ndigits <= 0)
8853 tgl@sss.pgh.pa.us 11614 :UBC 0 : res_ndigits = 1;
11615 : :
7695 tgl@sss.pgh.pa.us 11616 :CBC 165460 : res_buf = digitbuf_alloc(res_ndigits + 1);
11617 : 165460 : res_buf[0] = 0; /* spare digit for later rounding */
11618 : 165460 : res_digits = res_buf + 1;
11619 : :
9237 JanWieck@Yahoo.com 11620 : 165460 : i1 = res_rscale + var1->weight + 1;
11621 : 165460 : i2 = res_rscale + var2->weight + 1;
11622 [ + + ]: 1659569 : for (i = res_ndigits - 1; i >= 0; i--)
11623 : : {
11624 : 1494109 : i1--;
11625 : 1494109 : i2--;
8672 tgl@sss.pgh.pa.us 11626 [ + + + + ]: 1494109 : if (i1 >= 0 && i1 < var1ndigits)
11627 : 660220 : carry += var1digits[i1];
11628 [ + + + + ]: 1494109 : if (i2 >= 0 && i2 < var2ndigits)
11629 : 519524 : carry += var2digits[i2];
11630 : :
7695 11631 [ + + ]: 1494109 : if (carry >= NBASE)
11632 : : {
11633 : 116596 : res_digits[i] = carry - NBASE;
8672 11634 : 116596 : carry = 1;
11635 : : }
11636 : : else
11637 : : {
11638 : 1377513 : res_digits[i] = carry;
11639 : 1377513 : carry = 0;
11640 : : }
11641 : : }
11642 : :
11643 [ - + ]: 165460 : Assert(carry == 0); /* else we failed to allow for carry out */
11644 : :
9237 JanWieck@Yahoo.com 11645 [ + + ]: 165460 : digitbuf_free(result->buf);
11646 : 165460 : result->ndigits = res_ndigits;
9091 bruce@momjian.us 11647 : 165460 : result->buf = res_buf;
11648 : 165460 : result->digits = res_digits;
11649 : 165460 : result->weight = res_weight;
11650 : 165460 : result->dscale = res_dscale;
11651 : :
11652 : : /* Remove leading/trailing zeroes */
7695 tgl@sss.pgh.pa.us 11653 : 165460 : strip_var(result);
9237 JanWieck@Yahoo.com 11654 : 165460 : }
11655 : :
11656 : :
11657 : : /*
11658 : : * sub_abs()
11659 : : *
11660 : : * Subtract the absolute value of var2 from the absolute value of var1
11661 : : * and store in result. result might point to one of the operands
11662 : : * without danger.
11663 : : *
11664 : : * ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!!
11665 : : */
11666 : : static void
2408 andres@anarazel.de 11667 : 162611 : sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
11668 : : {
11669 : : NumericDigit *res_buf;
11670 : : NumericDigit *res_digits;
11671 : : int res_ndigits;
11672 : : int res_weight;
11673 : : int res_rscale,
11674 : : rscale1,
11675 : : rscale2;
11676 : : int res_dscale;
11677 : : int i,
11678 : : i1,
11679 : : i2;
9091 bruce@momjian.us 11680 : 162611 : int borrow = 0;
11681 : :
11682 : : /* copy these values into local vars for speed in inner loop */
8672 tgl@sss.pgh.pa.us 11683 : 162611 : int var1ndigits = var1->ndigits;
11684 : 162611 : int var2ndigits = var2->ndigits;
11685 : 162611 : NumericDigit *var1digits = var1->digits;
11686 : 162611 : NumericDigit *var2digits = var2->digits;
11687 : :
9237 JanWieck@Yahoo.com 11688 : 162611 : res_weight = var1->weight;
11689 : :
8091 bruce@momjian.us 11690 : 162611 : res_dscale = Max(var1->dscale, var2->dscale);
11691 : :
11692 : : /* Note: here we are figuring rscale in base-NBASE digits */
7695 tgl@sss.pgh.pa.us 11693 : 162611 : rscale1 = var1->ndigits - var1->weight - 1;
11694 : 162611 : rscale2 = var2->ndigits - var2->weight - 1;
11695 : 162611 : res_rscale = Max(rscale1, rscale2);
11696 : :
9237 JanWieck@Yahoo.com 11697 : 162611 : res_ndigits = res_rscale + res_weight + 1;
8853 tgl@sss.pgh.pa.us 11698 [ - + ]: 162611 : if (res_ndigits <= 0)
8853 tgl@sss.pgh.pa.us 11699 :UBC 0 : res_ndigits = 1;
11700 : :
7695 tgl@sss.pgh.pa.us 11701 :CBC 162611 : res_buf = digitbuf_alloc(res_ndigits + 1);
11702 : 162611 : res_buf[0] = 0; /* spare digit for later rounding */
11703 : 162611 : res_digits = res_buf + 1;
11704 : :
9237 JanWieck@Yahoo.com 11705 : 162611 : i1 = res_rscale + var1->weight + 1;
11706 : 162611 : i2 = res_rscale + var2->weight + 1;
11707 [ + + ]: 2260686 : for (i = res_ndigits - 1; i >= 0; i--)
11708 : : {
11709 : 2098075 : i1--;
11710 : 2098075 : i2--;
8672 tgl@sss.pgh.pa.us 11711 [ + - + + ]: 2098075 : if (i1 >= 0 && i1 < var1ndigits)
11712 : 1912503 : borrow += var1digits[i1];
11713 [ + + + + ]: 2098075 : if (i2 >= 0 && i2 < var2ndigits)
11714 : 1860949 : borrow -= var2digits[i2];
11715 : :
9237 JanWieck@Yahoo.com 11716 [ + + ]: 2098075 : if (borrow < 0)
11717 : : {
7695 tgl@sss.pgh.pa.us 11718 : 211005 : res_digits[i] = borrow + NBASE;
9237 JanWieck@Yahoo.com 11719 : 211005 : borrow = -1;
11720 : : }
11721 : : else
11722 : : {
11723 : 1887070 : res_digits[i] = borrow;
11724 : 1887070 : borrow = 0;
11725 : : }
11726 : : }
11727 : :
8672 tgl@sss.pgh.pa.us 11728 [ - + ]: 162611 : Assert(borrow == 0); /* else caller gave us var1 < var2 */
11729 : :
9237 JanWieck@Yahoo.com 11730 [ + + ]: 162611 : digitbuf_free(result->buf);
11731 : 162611 : result->ndigits = res_ndigits;
9091 bruce@momjian.us 11732 : 162611 : result->buf = res_buf;
11733 : 162611 : result->digits = res_digits;
11734 : 162611 : result->weight = res_weight;
11735 : 162611 : result->dscale = res_dscale;
11736 : :
11737 : : /* Remove leading/trailing zeroes */
7695 tgl@sss.pgh.pa.us 11738 : 162611 : strip_var(result);
11739 : 162611 : }
11740 : :
11741 : : /*
11742 : : * round_var
11743 : : *
11744 : : * Round the value of a variable to no more than rscale decimal digits
11745 : : * after the decimal point. NOTE: we allow rscale < 0 here, implying
11746 : : * rounding before the decimal point.
11747 : : */
11748 : : static void
11749 : 514390 : round_var(NumericVar *var, int rscale)
11750 : : {
7559 bruce@momjian.us 11751 : 514390 : NumericDigit *digits = var->digits;
11752 : : int di;
11753 : : int ndigits;
11754 : : int carry;
11755 : :
7695 tgl@sss.pgh.pa.us 11756 : 514390 : var->dscale = rscale;
11757 : :
11758 : : /* decimal digits wanted */
11759 : 514390 : di = (var->weight + 1) * DEC_DIGITS + rscale;
11760 : :
11761 : : /*
11762 : : * If di = 0, the value loses all digits, but could round up to 1 if its
11763 : : * first extra digit is >= 5. If di < 0 the result must be 0.
11764 : : */
11765 [ + + ]: 514390 : if (di < 0)
11766 : : {
11767 : 37 : var->ndigits = 0;
11768 : 37 : var->weight = 0;
11769 : 37 : var->sign = NUMERIC_POS;
11770 : : }
11771 : : else
11772 : : {
11773 : : /* NBASE digits wanted */
7559 bruce@momjian.us 11774 : 514353 : ndigits = (di + DEC_DIGITS - 1) / DEC_DIGITS;
11775 : :
11776 : : /* 0, or number of decimal digits to keep in last NBASE digit */
7695 tgl@sss.pgh.pa.us 11777 : 514353 : di %= DEC_DIGITS;
11778 : :
11779 [ + + ]: 514353 : if (ndigits < var->ndigits ||
11780 [ + + + + ]: 412714 : (ndigits == var->ndigits && di > 0))
11781 : : {
11782 : 345035 : var->ndigits = ndigits;
11783 : :
11784 : : #if DEC_DIGITS == 1
11785 : : /* di must be zero */
11786 : : carry = (digits[ndigits] >= HALF_NBASE) ? 1 : 0;
11787 : : #else
11788 [ + + ]: 345035 : if (di == 0)
11789 : 82354 : carry = (digits[ndigits] >= HALF_NBASE) ? 1 : 0;
11790 : : else
11791 : : {
11792 : : /* Must round within last NBASE digit */
11793 : : int extra,
11794 : : pow10;
11795 : :
11796 : : #if DEC_DIGITS == 4
11797 : 262681 : pow10 = round_powers[di];
11798 : : #elif DEC_DIGITS == 2
11799 : : pow10 = 10;
11800 : : #else
11801 : : #error unsupported NBASE
11802 : : #endif
11803 : 262681 : extra = digits[--ndigits] % pow10;
11804 : 262681 : digits[ndigits] -= extra;
11805 : 262681 : carry = 0;
7559 bruce@momjian.us 11806 [ + + ]: 262681 : if (extra >= pow10 / 2)
11807 : : {
7695 tgl@sss.pgh.pa.us 11808 : 9737 : pow10 += digits[ndigits];
11809 [ + + ]: 9737 : if (pow10 >= NBASE)
11810 : : {
11811 : 406 : pow10 -= NBASE;
11812 : 406 : carry = 1;
11813 : : }
11814 : 9737 : digits[ndigits] = pow10;
11815 : : }
11816 : : }
11817 : : #endif
11818 : :
11819 : : /* Propagate carry if needed */
11820 [ + + ]: 362701 : while (carry)
11821 : : {
11822 : 17666 : carry += digits[--ndigits];
11823 [ + + ]: 17666 : if (carry >= NBASE)
11824 : : {
11825 : 12387 : digits[ndigits] = carry - NBASE;
11826 : 12387 : carry = 1;
11827 : : }
11828 : : else
11829 : : {
11830 : 5279 : digits[ndigits] = carry;
11831 : 5279 : carry = 0;
11832 : : }
11833 : : }
11834 : :
11835 [ + + ]: 345035 : if (ndigits < 0)
11836 : : {
11837 [ - + ]: 45 : Assert(ndigits == -1); /* better not have added > 1 digit */
11838 [ - + ]: 45 : Assert(var->digits > var->buf);
11839 : 45 : var->digits--;
11840 : 45 : var->ndigits++;
11841 : 45 : var->weight++;
11842 : : }
11843 : : }
11844 : : }
11845 : 514390 : }
11846 : :
11847 : : /*
11848 : : * trunc_var
11849 : : *
11850 : : * Truncate (towards zero) the value of a variable at rscale decimal digits
11851 : : * after the decimal point. NOTE: we allow rscale < 0 here, implying
11852 : : * truncation before the decimal point.
11853 : : */
11854 : : static void
11855 : 30761 : trunc_var(NumericVar *var, int rscale)
11856 : : {
11857 : : int di;
11858 : : int ndigits;
11859 : :
11860 : 30761 : var->dscale = rscale;
11861 : :
11862 : : /* decimal digits wanted */
11863 : 30761 : di = (var->weight + 1) * DEC_DIGITS + rscale;
11864 : :
11865 : : /*
11866 : : * If di <= 0, the value loses all digits.
11867 : : */
11868 [ + + ]: 30761 : if (di <= 0)
11869 : : {
11870 : 27 : var->ndigits = 0;
11871 : 27 : var->weight = 0;
11872 : 27 : var->sign = NUMERIC_POS;
11873 : : }
11874 : : else
11875 : : {
11876 : : /* NBASE digits wanted */
7559 bruce@momjian.us 11877 : 30734 : ndigits = (di + DEC_DIGITS - 1) / DEC_DIGITS;
11878 : :
7695 tgl@sss.pgh.pa.us 11879 [ + + ]: 30734 : if (ndigits <= var->ndigits)
11880 : : {
11881 : 30599 : var->ndigits = ndigits;
11882 : :
11883 : : #if DEC_DIGITS == 1
11884 : : /* no within-digit stuff to worry about */
11885 : : #else
11886 : : /* 0, or number of decimal digits to keep in last NBASE digit */
11887 : 30599 : di %= DEC_DIGITS;
11888 : :
11889 [ + + ]: 30599 : if (di > 0)
11890 : : {
11891 : : /* Must truncate within last NBASE digit */
7559 bruce@momjian.us 11892 : 41 : NumericDigit *digits = var->digits;
11893 : : int extra,
11894 : : pow10;
11895 : :
11896 : : #if DEC_DIGITS == 4
7695 tgl@sss.pgh.pa.us 11897 : 41 : pow10 = round_powers[di];
11898 : : #elif DEC_DIGITS == 2
11899 : : pow10 = 10;
11900 : : #else
11901 : : #error unsupported NBASE
11902 : : #endif
11903 : 41 : extra = digits[--ndigits] % pow10;
11904 : 41 : digits[ndigits] -= extra;
11905 : : }
11906 : : #endif
11907 : : }
11908 : : }
11909 : 30761 : }
11910 : :
11911 : : /*
11912 : : * strip_var
11913 : : *
11914 : : * Strip any leading and trailing zeroes from a numeric variable
11915 : : */
11916 : : static void
11917 : 1034280 : strip_var(NumericVar *var)
11918 : : {
7559 bruce@momjian.us 11919 : 1034280 : NumericDigit *digits = var->digits;
7695 tgl@sss.pgh.pa.us 11920 : 1034280 : int ndigits = var->ndigits;
11921 : :
11922 : : /* Strip leading zeroes */
11923 [ + + + + ]: 2364325 : while (ndigits > 0 && *digits == 0)
11924 : : {
11925 : 1330045 : digits++;
11926 : 1330045 : var->weight--;
11927 : 1330045 : ndigits--;
11928 : : }
11929 : :
11930 : : /* Strip trailing zeroes */
11931 [ + + + + ]: 1369235 : while (ndigits > 0 && digits[ndigits - 1] == 0)
11932 : 334955 : ndigits--;
11933 : :
11934 : : /* If it's zero, normalize the sign and weight */
11935 [ + + ]: 1034280 : if (ndigits == 0)
11936 : : {
11937 : 13700 : var->sign = NUMERIC_POS;
11938 : 13700 : var->weight = 0;
11939 : : }
11940 : :
11941 : 1034280 : var->digits = digits;
11942 : 1034280 : var->ndigits = ndigits;
9237 JanWieck@Yahoo.com 11943 : 1034280 : }
11944 : :
11945 : :
11946 : : /* ----------------------------------------------------------------------
11947 : : *
11948 : : * Fast sum accumulator functions
11949 : : *
11950 : : * ----------------------------------------------------------------------
11951 : : */
11952 : :
11953 : : /*
11954 : : * Reset the accumulator's value to zero. The buffers to hold the digits
11955 : : * are not free'd.
11956 : : */
11957 : : static void
2781 heikki.linnakangas@i 11958 : 9 : accum_sum_reset(NumericSumAccum *accum)
11959 : : {
11960 : : int i;
11961 : :
11962 : 9 : accum->dscale = 0;
11963 [ + + ]: 33 : for (i = 0; i < accum->ndigits; i++)
11964 : : {
11965 : 24 : accum->pos_digits[i] = 0;
11966 : 24 : accum->neg_digits[i] = 0;
11967 : : }
11968 : 9 : }
11969 : :
11970 : : /*
11971 : : * Accumulate a new value.
11972 : : */
11973 : : static void
2408 andres@anarazel.de 11974 : 1177858 : accum_sum_add(NumericSumAccum *accum, const NumericVar *val)
11975 : : {
11976 : : int32 *accum_digits;
11977 : : int i,
11978 : : val_i;
11979 : : int val_ndigits;
11980 : : NumericDigit *val_digits;
11981 : :
11982 : : /*
11983 : : * If we have accumulated too many values since the last carry
11984 : : * propagation, do it now, to avoid overflowing. (We could allow more
11985 : : * than NBASE - 1, if we reserved two extra digits, rather than one, for
11986 : : * carry propagation. But even with NBASE - 1, this needs to be done so
11987 : : * seldom, that the performance difference is negligible.)
11988 : : */
2781 heikki.linnakangas@i 11989 [ + + ]: 1177858 : if (accum->num_uncarried == NBASE - 1)
11990 : 78 : accum_sum_carry(accum);
11991 : :
11992 : : /*
11993 : : * Adjust the weight or scale of the old value, so that it can accommodate
11994 : : * the new value.
11995 : : */
11996 : 1177858 : accum_sum_rescale(accum, val);
11997 : :
11998 : : /* */
11999 [ + + ]: 1177858 : if (val->sign == NUMERIC_POS)
12000 : 877519 : accum_digits = accum->pos_digits;
12001 : : else
12002 : 300339 : accum_digits = accum->neg_digits;
12003 : :
12004 : : /* copy these values into local vars for speed in loop */
12005 : 1177858 : val_ndigits = val->ndigits;
12006 : 1177858 : val_digits = val->digits;
12007 : :
12008 : 1177858 : i = accum->weight - val->weight;
12009 [ + + ]: 5944987 : for (val_i = 0; val_i < val_ndigits; val_i++)
12010 : : {
12011 : 4767129 : accum_digits[i] += (int32) val_digits[val_i];
12012 : 4767129 : i++;
12013 : : }
12014 : :
12015 : 1177858 : accum->num_uncarried++;
12016 : 1177858 : }
12017 : :
12018 : : /*
12019 : : * Propagate carries.
12020 : : */
12021 : : static void
12022 : 86385 : accum_sum_carry(NumericSumAccum *accum)
12023 : : {
12024 : : int i;
12025 : : int ndigits;
12026 : : int32 *dig;
12027 : : int32 carry;
12028 : 86385 : int32 newdig = 0;
12029 : :
12030 : : /*
12031 : : * If no new values have been added since last carry propagation, nothing
12032 : : * to do.
12033 : : */
12034 [ + + ]: 86385 : if (accum->num_uncarried == 0)
12035 : 36 : return;
12036 : :
12037 : : /*
12038 : : * We maintain that the weight of the accumulator is always one larger
12039 : : * than needed to hold the current value, before carrying, to make sure
12040 : : * there is enough space for the possible extra digit when carry is
12041 : : * propagated. We cannot expand the buffer here, unless we require
12042 : : * callers of accum_sum_final() to switch to the right memory context.
12043 : : */
12044 [ + - - + ]: 86349 : Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0);
12045 : :
12046 : 86349 : ndigits = accum->ndigits;
12047 : :
12048 : : /* Propagate carry in the positive sum */
12049 : 86349 : dig = accum->pos_digits;
12050 : 86349 : carry = 0;
12051 [ + + ]: 1302785 : for (i = ndigits - 1; i >= 0; i--)
12052 : : {
12053 : 1216436 : newdig = dig[i] + carry;
12054 [ + + ]: 1216436 : if (newdig >= NBASE)
12055 : : {
12056 : 55407 : carry = newdig / NBASE;
12057 : 55407 : newdig -= carry * NBASE;
12058 : : }
12059 : : else
12060 : 1161029 : carry = 0;
12061 : 1216436 : dig[i] = newdig;
12062 : : }
12063 : : /* Did we use up the digit reserved for carry propagation? */
12064 [ + + ]: 86349 : if (newdig > 0)
12065 : 1320 : accum->have_carry_space = false;
12066 : :
12067 : : /* And the same for the negative sum */
12068 : 86349 : dig = accum->neg_digits;
12069 : 86349 : carry = 0;
12070 [ + + ]: 1302785 : for (i = ndigits - 1; i >= 0; i--)
12071 : : {
12072 : 1216436 : newdig = dig[i] + carry;
12073 [ + + ]: 1216436 : if (newdig >= NBASE)
12074 : : {
12075 : 99 : carry = newdig / NBASE;
12076 : 99 : newdig -= carry * NBASE;
12077 : : }
12078 : : else
12079 : 1216337 : carry = 0;
12080 : 1216436 : dig[i] = newdig;
12081 : : }
12082 [ + + ]: 86349 : if (newdig > 0)
12083 : 15 : accum->have_carry_space = false;
12084 : :
12085 : 86349 : accum->num_uncarried = 0;
12086 : : }
12087 : :
12088 : : /*
12089 : : * Re-scale accumulator to accommodate new value.
12090 : : *
12091 : : * If the new value has more digits than the current digit buffers in the
12092 : : * accumulator, enlarge the buffers.
12093 : : */
12094 : : static void
2408 andres@anarazel.de 12095 : 1177858 : accum_sum_rescale(NumericSumAccum *accum, const NumericVar *val)
12096 : : {
2781 heikki.linnakangas@i 12097 : 1177858 : int old_weight = accum->weight;
12098 : 1177858 : int old_ndigits = accum->ndigits;
12099 : : int accum_ndigits;
12100 : : int accum_weight;
12101 : : int accum_rscale;
12102 : : int val_rscale;
12103 : :
12104 : 1177858 : accum_weight = old_weight;
12105 : 1177858 : accum_ndigits = old_ndigits;
12106 : :
12107 : : /*
12108 : : * Does the new value have a larger weight? If so, enlarge the buffers,
12109 : : * and shift the existing value to the new weight, by adding leading
12110 : : * zeros.
12111 : : *
12112 : : * We enforce that the accumulator always has a weight one larger than
12113 : : * needed for the inputs, so that we have space for an extra digit at the
12114 : : * final carry-propagation phase, if necessary.
12115 : : */
12116 [ + + ]: 1177858 : if (val->weight >= accum_weight)
12117 : : {
12118 : 131118 : accum_weight = val->weight + 1;
12119 : 131118 : accum_ndigits = accum_ndigits + (accum_weight - old_weight);
12120 : : }
12121 : :
12122 : : /*
12123 : : * Even though the new value is small, we might've used up the space
12124 : : * reserved for the carry digit in the last call to accum_sum_carry(). If
12125 : : * so, enlarge to make room for another one.
12126 : : */
12127 [ + + ]: 1046740 : else if (!accum->have_carry_space)
12128 : : {
12129 : 42 : accum_weight++;
12130 : 42 : accum_ndigits++;
12131 : : }
12132 : :
12133 : : /* Is the new value wider on the right side? */
12134 : 1177858 : accum_rscale = accum_ndigits - accum_weight - 1;
12135 : 1177858 : val_rscale = val->ndigits - val->weight - 1;
12136 [ + + ]: 1177858 : if (val_rscale > accum_rscale)
12137 : 86129 : accum_ndigits = accum_ndigits + (val_rscale - accum_rscale);
12138 : :
12139 [ + + - + ]: 1177858 : if (accum_ndigits != old_ndigits ||
12140 : : accum_weight != old_weight)
12141 : : {
12142 : : int32 *new_pos_digits;
12143 : : int32 *new_neg_digits;
12144 : : int weightdiff;
12145 : :
12146 : 131298 : weightdiff = accum_weight - old_weight;
12147 : :
12148 : 131298 : new_pos_digits = palloc0(accum_ndigits * sizeof(int32));
12149 : 131298 : new_neg_digits = palloc0(accum_ndigits * sizeof(int32));
12150 : :
12151 [ + + ]: 131298 : if (accum->pos_digits)
12152 : : {
12153 : 45204 : memcpy(&new_pos_digits[weightdiff], accum->pos_digits,
12154 : : old_ndigits * sizeof(int32));
12155 : 45204 : pfree(accum->pos_digits);
12156 : :
12157 : 45204 : memcpy(&new_neg_digits[weightdiff], accum->neg_digits,
12158 : : old_ndigits * sizeof(int32));
12159 : 45204 : pfree(accum->neg_digits);
12160 : : }
12161 : :
12162 : 131298 : accum->pos_digits = new_pos_digits;
12163 : 131298 : accum->neg_digits = new_neg_digits;
12164 : :
12165 : 131298 : accum->weight = accum_weight;
12166 : 131298 : accum->ndigits = accum_ndigits;
12167 : :
12168 [ + - - + ]: 131298 : Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0);
12169 : 131298 : accum->have_carry_space = true;
12170 : : }
12171 : :
12172 [ + + ]: 1177858 : if (val->dscale > accum->dscale)
12173 : 150 : accum->dscale = val->dscale;
12174 : 1177858 : }
12175 : :
12176 : : /*
12177 : : * Return the current value of the accumulator. This perform final carry
12178 : : * propagation, and adds together the positive and negative sums.
12179 : : *
12180 : : * Unlike all the other routines, the caller is not required to switch to
12181 : : * the memory context that holds the accumulator.
12182 : : */
12183 : : static void
12184 : 86307 : accum_sum_final(NumericSumAccum *accum, NumericVar *result)
12185 : : {
12186 : : int i;
12187 : : NumericVar pos_var;
12188 : : NumericVar neg_var;
12189 : :
12190 [ - + ]: 86307 : if (accum->ndigits == 0)
12191 : : {
2781 heikki.linnakangas@i 12192 :UBC 0 : set_var_from_var(&const_zero, result);
12193 : 0 : return;
12194 : : }
12195 : :
12196 : : /* Perform final carry */
2781 heikki.linnakangas@i 12197 :CBC 86307 : accum_sum_carry(accum);
12198 : :
12199 : : /* Create NumericVars representing the positive and negative sums */
12200 : 86307 : init_var(&pos_var);
12201 : 86307 : init_var(&neg_var);
12202 : :
12203 : 86307 : pos_var.ndigits = neg_var.ndigits = accum->ndigits;
12204 : 86307 : pos_var.weight = neg_var.weight = accum->weight;
12205 : 86307 : pos_var.dscale = neg_var.dscale = accum->dscale;
12206 : 86307 : pos_var.sign = NUMERIC_POS;
12207 : 86307 : neg_var.sign = NUMERIC_NEG;
12208 : :
12209 : 86307 : pos_var.buf = pos_var.digits = digitbuf_alloc(accum->ndigits);
12210 : 86307 : neg_var.buf = neg_var.digits = digitbuf_alloc(accum->ndigits);
12211 : :
12212 [ + + ]: 1302569 : for (i = 0; i < accum->ndigits; i++)
12213 : : {
12214 [ - + ]: 1216262 : Assert(accum->pos_digits[i] < NBASE);
12215 : 1216262 : pos_var.digits[i] = (int16) accum->pos_digits[i];
12216 : :
12217 [ - + ]: 1216262 : Assert(accum->neg_digits[i] < NBASE);
12218 : 1216262 : neg_var.digits[i] = (int16) accum->neg_digits[i];
12219 : : }
12220 : :
12221 : : /* And add them together */
12222 : 86307 : add_var(&pos_var, &neg_var, result);
12223 : :
12224 : : /* Remove leading/trailing zeroes */
12225 : 86307 : strip_var(result);
12226 : : }
12227 : :
12228 : : /*
12229 : : * Copy an accumulator's state.
12230 : : *
12231 : : * 'dst' is assumed to be uninitialized beforehand. No attempt is made at
12232 : : * freeing old values.
12233 : : */
12234 : : static void
12235 : 21 : accum_sum_copy(NumericSumAccum *dst, NumericSumAccum *src)
12236 : : {
12237 : 21 : dst->pos_digits = palloc(src->ndigits * sizeof(int32));
12238 : 21 : dst->neg_digits = palloc(src->ndigits * sizeof(int32));
12239 : :
12240 : 21 : memcpy(dst->pos_digits, src->pos_digits, src->ndigits * sizeof(int32));
12241 : 21 : memcpy(dst->neg_digits, src->neg_digits, src->ndigits * sizeof(int32));
12242 : 21 : dst->num_uncarried = src->num_uncarried;
12243 : 21 : dst->ndigits = src->ndigits;
12244 : 21 : dst->weight = src->weight;
12245 : 21 : dst->dscale = src->dscale;
12246 : 21 : }
12247 : :
12248 : : /*
12249 : : * Add the current value of 'accum2' into 'accum'.
12250 : : */
12251 : : static void
12252 : 27 : accum_sum_combine(NumericSumAccum *accum, NumericSumAccum *accum2)
12253 : : {
12254 : : NumericVar tmp_var;
12255 : :
12256 : 27 : init_var(&tmp_var);
12257 : :
12258 : 27 : accum_sum_final(accum2, &tmp_var);
12259 : 27 : accum_sum_add(accum, &tmp_var);
12260 : :
12261 : 27 : free_var(&tmp_var);
12262 : 27 : }
|