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-2026, 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 "common/int128.h"
32 : : #include "funcapi.h"
33 : : #include "lib/hyperloglog.h"
34 : : #include "libpq/pqformat.h"
35 : : #include "miscadmin.h"
36 : : #include "nodes/nodeFuncs.h"
37 : : #include "nodes/supportnodes.h"
38 : : #include "optimizer/optimizer.h"
39 : : #include "utils/array.h"
40 : : #include "utils/builtins.h"
41 : : #include "utils/float.h"
42 : : #include "utils/guc.h"
43 : : #include "utils/numeric.h"
44 : : #include "utils/pg_lsn.h"
45 : : #include "utils/sortsupport.h"
46 : :
47 : : /* ----------
48 : : * Uncomment the following to enable compilation of dump_numeric()
49 : : * and dump_var() and to get a dump of any result produced by make_result().
50 : : * ----------
51 : : */
52 : : /* #define NUMERIC_DEBUG */
53 : :
54 : :
55 : : /* ----------
56 : : * Local data types
57 : : *
58 : : * Numeric values are represented in a base-NBASE floating point format.
59 : : * Each "digit" ranges from 0 to NBASE-1. The type NumericDigit is signed
60 : : * and wide enough to store a digit. We assume that NBASE*NBASE can fit in
61 : : * an int. Although the purely calculational routines could handle any even
62 : : * NBASE that's less than sqrt(INT_MAX), in practice we are only interested
63 : : * in NBASE a power of ten, so that I/O conversions and decimal rounding
64 : : * are easy. Also, it's actually more efficient if NBASE is rather less than
65 : : * sqrt(INT_MAX), so that there is "headroom" for mul_var and div_var to
66 : : * postpone processing carries.
67 : : *
68 : : * Values of NBASE other than 10000 are considered of historical interest only
69 : : * and are no longer supported in any sense; no mechanism exists for the client
70 : : * to discover the base, so every client supporting binary mode expects the
71 : : * base-10000 format. If you plan to change this, also note the numeric
72 : : * abbreviation code, which assumes NBASE=10000.
73 : : * ----------
74 : : */
75 : :
76 : : #if 0
77 : : #define NBASE 10
78 : : #define HALF_NBASE 5
79 : : #define DEC_DIGITS 1 /* decimal digits per NBASE digit */
80 : : #define MUL_GUARD_DIGITS 4 /* these are measured in NBASE digits */
81 : : #define DIV_GUARD_DIGITS 8
82 : :
83 : : typedef signed char NumericDigit;
84 : : #endif
85 : :
86 : : #if 0
87 : : #define NBASE 100
88 : : #define HALF_NBASE 50
89 : : #define DEC_DIGITS 2 /* decimal digits per NBASE digit */
90 : : #define MUL_GUARD_DIGITS 3 /* these are measured in NBASE digits */
91 : : #define DIV_GUARD_DIGITS 6
92 : :
93 : : typedef signed char NumericDigit;
94 : : #endif
95 : :
96 : : #if 1
97 : : #define NBASE 10000
98 : : #define HALF_NBASE 5000
99 : : #define DEC_DIGITS 4 /* decimal digits per NBASE digit */
100 : : #define MUL_GUARD_DIGITS 2 /* these are measured in NBASE digits */
101 : : #define DIV_GUARD_DIGITS 4
102 : :
103 : : typedef int16 NumericDigit;
104 : : #endif
105 : :
106 : : #define NBASE_SQR (NBASE * NBASE)
107 : :
108 : : /*
109 : : * The Numeric type as stored on disk.
110 : : *
111 : : * If the high bits of the first word of a NumericChoice (n_header, or
112 : : * n_short.n_header, or n_long.n_sign_dscale) are NUMERIC_SHORT, then the
113 : : * numeric follows the NumericShort format; if they are NUMERIC_POS or
114 : : * NUMERIC_NEG, it follows the NumericLong format. If they are NUMERIC_SPECIAL,
115 : : * the value is a NaN or Infinity. We currently always store SPECIAL values
116 : : * using just two bytes (i.e. only n_header), but previous releases used only
117 : : * the NumericLong format, so we might find 4-byte NaNs (though not infinities)
118 : : * on disk if a database has been migrated using pg_upgrade. In either case,
119 : : * the low-order bits of a special value's header are reserved and currently
120 : : * should always be set to zero.
121 : : *
122 : : * In the NumericShort format, the remaining 14 bits of the header word
123 : : * (n_short.n_header) are allocated as follows: 1 for sign (positive or
124 : : * negative), 6 for dynamic scale, and 7 for weight. In practice, most
125 : : * commonly-encountered values can be represented this way.
126 : : *
127 : : * In the NumericLong format, the remaining 14 bits of the header word
128 : : * (n_long.n_sign_dscale) represent the display scale; and the weight is
129 : : * stored separately in n_weight.
130 : : *
131 : : * NOTE: by convention, values in the packed form have been stripped of
132 : : * all leading and trailing zero digits (where a "digit" is of base NBASE).
133 : : * In particular, if the value is zero, there will be no digits at all!
134 : : * The weight is arbitrary in that case, but we normally set it to zero.
135 : : */
136 : :
137 : : struct NumericShort
138 : : {
139 : : uint16 n_header; /* Sign + display scale + weight */
140 : : NumericDigit n_data[FLEXIBLE_ARRAY_MEMBER]; /* Digits */
141 : : };
142 : :
143 : : struct NumericLong
144 : : {
145 : : uint16 n_sign_dscale; /* Sign + display scale */
146 : : int16 n_weight; /* Weight of 1st digit */
147 : : NumericDigit n_data[FLEXIBLE_ARRAY_MEMBER]; /* Digits */
148 : : };
149 : :
150 : : union NumericChoice
151 : : {
152 : : uint16 n_header; /* Header word */
153 : : struct NumericLong n_long; /* Long form (4-byte header) */
154 : : struct NumericShort n_short; /* Short form (2-byte header) */
155 : : };
156 : :
157 : : struct NumericData
158 : : {
159 : : int32 vl_len_; /* varlena header (do not touch directly!) */
160 : : union NumericChoice choice; /* choice of format */
161 : : };
162 : :
163 : :
164 : : /*
165 : : * Interpretation of high bits.
166 : : */
167 : :
168 : : #define NUMERIC_SIGN_MASK 0xC000
169 : : #define NUMERIC_POS 0x0000
170 : : #define NUMERIC_NEG 0x4000
171 : : #define NUMERIC_SHORT 0x8000
172 : : #define NUMERIC_SPECIAL 0xC000
173 : :
174 : : #define NUMERIC_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_SIGN_MASK)
175 : : #define NUMERIC_IS_SHORT(n) (NUMERIC_FLAGBITS(n) == NUMERIC_SHORT)
176 : : #define NUMERIC_IS_SPECIAL(n) (NUMERIC_FLAGBITS(n) == NUMERIC_SPECIAL)
177 : :
178 : : #define NUMERIC_HDRSZ (VARHDRSZ + sizeof(uint16) + sizeof(int16))
179 : : #define NUMERIC_HDRSZ_SHORT (VARHDRSZ + sizeof(uint16))
180 : :
181 : : /*
182 : : * If the flag bits are NUMERIC_SHORT or NUMERIC_SPECIAL, we want the short
183 : : * header; otherwise, we want the long one. Instead of testing against each
184 : : * value, we can just look at the high bit, for a slight efficiency gain.
185 : : */
186 : : #define NUMERIC_HEADER_IS_SHORT(n) (((n)->choice.n_header & 0x8000) != 0)
187 : : #define NUMERIC_HEADER_SIZE(n) \
188 : : (VARHDRSZ + sizeof(uint16) + \
189 : : (NUMERIC_HEADER_IS_SHORT(n) ? 0 : sizeof(int16)))
190 : :
191 : : /*
192 : : * Definitions for special values (NaN, positive infinity, negative infinity).
193 : : *
194 : : * The two bits after the NUMERIC_SPECIAL bits are 00 for NaN, 01 for positive
195 : : * infinity, 11 for negative infinity. (This makes the sign bit match where
196 : : * it is in a short-format value, though we make no use of that at present.)
197 : : * We could mask off the remaining bits before testing the active bits, but
198 : : * currently those bits must be zeroes, so masking would just add cycles.
199 : : */
200 : : #define NUMERIC_EXT_SIGN_MASK 0xF000 /* high bits plus NaN/Inf flag bits */
201 : : #define NUMERIC_NAN 0xC000
202 : : #define NUMERIC_PINF 0xD000
203 : : #define NUMERIC_NINF 0xF000
204 : : #define NUMERIC_INF_SIGN_MASK 0x2000
205 : :
206 : : #define NUMERIC_EXT_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_EXT_SIGN_MASK)
207 : : #define NUMERIC_IS_NAN(n) ((n)->choice.n_header == NUMERIC_NAN)
208 : : #define NUMERIC_IS_PINF(n) ((n)->choice.n_header == NUMERIC_PINF)
209 : : #define NUMERIC_IS_NINF(n) ((n)->choice.n_header == NUMERIC_NINF)
210 : : #define NUMERIC_IS_INF(n) \
211 : : (((n)->choice.n_header & ~NUMERIC_INF_SIGN_MASK) == NUMERIC_PINF)
212 : :
213 : : /*
214 : : * Short format definitions.
215 : : */
216 : :
217 : : #define NUMERIC_SHORT_SIGN_MASK 0x2000
218 : : #define NUMERIC_SHORT_DSCALE_MASK 0x1F80
219 : : #define NUMERIC_SHORT_DSCALE_SHIFT 7
220 : : #define NUMERIC_SHORT_DSCALE_MAX \
221 : : (NUMERIC_SHORT_DSCALE_MASK >> NUMERIC_SHORT_DSCALE_SHIFT)
222 : : #define NUMERIC_SHORT_WEIGHT_SIGN_MASK 0x0040
223 : : #define NUMERIC_SHORT_WEIGHT_MASK 0x003F
224 : : #define NUMERIC_SHORT_WEIGHT_MAX NUMERIC_SHORT_WEIGHT_MASK
225 : : #define NUMERIC_SHORT_WEIGHT_MIN (-(NUMERIC_SHORT_WEIGHT_MASK+1))
226 : :
227 : : /*
228 : : * Extract sign, display scale, weight. These macros extract field values
229 : : * suitable for the NumericVar format from the Numeric (on-disk) format.
230 : : *
231 : : * Note that we don't trouble to ensure that dscale and weight read as zero
232 : : * for an infinity; however, that doesn't matter since we never convert
233 : : * "special" numerics to NumericVar form. Only the constants defined below
234 : : * (const_nan, etc) ever represent a non-finite value as a NumericVar.
235 : : */
236 : :
237 : : #define NUMERIC_DSCALE_MASK 0x3FFF
238 : : #define NUMERIC_DSCALE_MAX NUMERIC_DSCALE_MASK
239 : :
240 : : #define NUMERIC_SIGN(n) \
241 : : (NUMERIC_IS_SHORT(n) ? \
242 : : (((n)->choice.n_short.n_header & NUMERIC_SHORT_SIGN_MASK) ? \
243 : : NUMERIC_NEG : NUMERIC_POS) : \
244 : : (NUMERIC_IS_SPECIAL(n) ? \
245 : : NUMERIC_EXT_FLAGBITS(n) : NUMERIC_FLAGBITS(n)))
246 : : #define NUMERIC_DSCALE(n) (NUMERIC_HEADER_IS_SHORT((n)) ? \
247 : : ((n)->choice.n_short.n_header & NUMERIC_SHORT_DSCALE_MASK) \
248 : : >> NUMERIC_SHORT_DSCALE_SHIFT \
249 : : : ((n)->choice.n_long.n_sign_dscale & NUMERIC_DSCALE_MASK))
250 : : #define NUMERIC_WEIGHT(n) (NUMERIC_HEADER_IS_SHORT((n)) ? \
251 : : (((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_SIGN_MASK ? \
252 : : ~NUMERIC_SHORT_WEIGHT_MASK : 0) \
253 : : | ((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \
254 : : : ((n)->choice.n_long.n_weight))
255 : :
256 : : /*
257 : : * Maximum weight of a stored Numeric value (based on the use of int16 for the
258 : : * weight in NumericLong). Note that intermediate values held in NumericVar
259 : : * and NumericSumAccum variables may have much larger weights.
260 : : */
261 : : #define NUMERIC_WEIGHT_MAX PG_INT16_MAX
262 : :
263 : : /* ----------
264 : : * NumericVar is the format we use for arithmetic. The digit-array part
265 : : * is the same as the NumericData storage format, but the header is more
266 : : * complex.
267 : : *
268 : : * The value represented by a NumericVar is determined by the sign, weight,
269 : : * ndigits, and digits[] array. If it is a "special" value (NaN or Inf)
270 : : * then only the sign field matters; ndigits should be zero, and the weight
271 : : * and dscale fields are ignored.
272 : : *
273 : : * Note: the first digit of a NumericVar's value is assumed to be multiplied
274 : : * by NBASE ** weight. Another way to say it is that there are weight+1
275 : : * digits before the decimal point. It is possible to have weight < 0.
276 : : *
277 : : * buf points at the physical start of the palloc'd digit buffer for the
278 : : * NumericVar. digits points at the first digit in actual use (the one
279 : : * with the specified weight). We normally leave an unused digit or two
280 : : * (preset to zeroes) between buf and digits, so that there is room to store
281 : : * a carry out of the top digit without reallocating space. We just need to
282 : : * decrement digits (and increment weight) to make room for the carry digit.
283 : : * (There is no such extra space in a numeric value stored in the database,
284 : : * only in a NumericVar in memory.)
285 : : *
286 : : * If buf is NULL then the digit buffer isn't actually palloc'd and should
287 : : * not be freed --- see the constants below for an example.
288 : : *
289 : : * dscale, or display scale, is the nominal precision expressed as number
290 : : * of digits after the decimal point (it must always be >= 0 at present).
291 : : * dscale may be more than the number of physically stored fractional digits,
292 : : * implying that we have suppressed storage of significant trailing zeroes.
293 : : * It should never be less than the number of stored digits, since that would
294 : : * imply hiding digits that are present. NOTE that dscale is always expressed
295 : : * in *decimal* digits, and so it may correspond to a fractional number of
296 : : * base-NBASE digits --- divide by DEC_DIGITS to convert to NBASE digits.
297 : : *
298 : : * rscale, or result scale, is the target precision for a computation.
299 : : * Like dscale it is expressed as number of *decimal* digits after the decimal
300 : : * point, and is always >= 0 at present.
301 : : * Note that rscale is not stored in variables --- it's figured on-the-fly
302 : : * from the dscales of the inputs.
303 : : *
304 : : * While we consistently use "weight" to refer to the base-NBASE weight of
305 : : * a numeric value, it is convenient in some scale-related calculations to
306 : : * make use of the base-10 weight (ie, the approximate log10 of the value).
307 : : * To avoid confusion, such a decimal-units weight is called a "dweight".
308 : : *
309 : : * NB: All the variable-level functions are written in a style that makes it
310 : : * possible to give one and the same variable as argument and destination.
311 : : * This is feasible because the digit buffer is separate from the variable.
312 : : * ----------
313 : : */
314 : : typedef struct NumericVar
315 : : {
316 : : int ndigits; /* # of digits in digits[] - can be 0! */
317 : : int weight; /* weight of first digit */
318 : : int sign; /* NUMERIC_POS, _NEG, _NAN, _PINF, or _NINF */
319 : : int dscale; /* display scale */
320 : : NumericDigit *buf; /* start of palloc'd space for digits[] */
321 : : NumericDigit *digits; /* base-NBASE digits */
322 : : } NumericVar;
323 : :
324 : :
325 : : /* ----------
326 : : * Data for generate_series
327 : : * ----------
328 : : */
329 : : typedef struct
330 : : {
331 : : NumericVar current;
332 : : NumericVar stop;
333 : : NumericVar step;
334 : : } generate_series_numeric_fctx;
335 : :
336 : :
337 : : /* ----------
338 : : * Sort support.
339 : : * ----------
340 : : */
341 : : typedef struct
342 : : {
343 : : void *buf; /* buffer for short varlenas */
344 : : int64 input_count; /* number of non-null values seen */
345 : : bool estimating; /* true if estimating cardinality */
346 : :
347 : : hyperLogLogState abbr_card; /* cardinality estimator */
348 : : } NumericSortSupport;
349 : :
350 : :
351 : : /* ----------
352 : : * Fast sum accumulator.
353 : : *
354 : : * NumericSumAccum is used to implement SUM(), and other standard aggregates
355 : : * that track the sum of input values. It uses 32-bit integers to store the
356 : : * digits, instead of the normal 16-bit integers (with NBASE=10000). This
357 : : * way, we can safely accumulate up to NBASE - 1 values without propagating
358 : : * carry, before risking overflow of any of the digits. 'num_uncarried'
359 : : * tracks how many values have been accumulated without propagating carry.
360 : : *
361 : : * Positive and negative values are accumulated separately, in 'pos_digits'
362 : : * and 'neg_digits'. This is simpler and faster than deciding whether to add
363 : : * or subtract from the current value, for each new value (see sub_var() for
364 : : * the logic we avoid by doing this). Both buffers are of same size, and
365 : : * have the same weight and scale. In accum_sum_final(), the positive and
366 : : * negative sums are added together to produce the final result.
367 : : *
368 : : * When a new value has a larger ndigits or weight than the accumulator
369 : : * currently does, the accumulator is enlarged to accommodate the new value.
370 : : * We normally have one zero digit reserved for carry propagation, and that
371 : : * is indicated by the 'have_carry_space' flag. When accum_sum_carry() uses
372 : : * up the reserved digit, it clears the 'have_carry_space' flag. The next
373 : : * call to accum_sum_add() will enlarge the buffer, to make room for the
374 : : * extra digit, and set the flag again.
375 : : *
376 : : * To initialize a new accumulator, simply reset all fields to zeros.
377 : : *
378 : : * The accumulator does not handle NaNs.
379 : : * ----------
380 : : */
381 : : typedef struct NumericSumAccum
382 : : {
383 : : int ndigits;
384 : : int weight;
385 : : int dscale;
386 : : int num_uncarried;
387 : : bool have_carry_space;
388 : : int32 *pos_digits;
389 : : int32 *neg_digits;
390 : : } NumericSumAccum;
391 : :
392 : :
393 : : /*
394 : : * We define our own macros for packing and unpacking abbreviated-key
395 : : * representations, just to have a notational indication that that's
396 : : * what we're doing. Now that sizeof(Datum) is always 8, we can rely
397 : : * on fitting an int64 into Datum.
398 : : *
399 : : * The range of abbreviations for finite values is from +PG_INT64_MAX
400 : : * to -PG_INT64_MAX. NaN has the abbreviation PG_INT64_MIN, and we
401 : : * define the sort ordering to make that work out properly (see further
402 : : * comments below). PINF and NINF share the abbreviations of the largest
403 : : * and smallest finite abbreviation classes.
404 : : */
405 : : #define NumericAbbrevGetDatum(X) Int64GetDatum(X)
406 : : #define DatumGetNumericAbbrev(X) DatumGetInt64(X)
407 : : #define NUMERIC_ABBREV_NAN NumericAbbrevGetDatum(PG_INT64_MIN)
408 : : #define NUMERIC_ABBREV_PINF NumericAbbrevGetDatum(-PG_INT64_MAX)
409 : : #define NUMERIC_ABBREV_NINF NumericAbbrevGetDatum(PG_INT64_MAX)
410 : :
411 : :
412 : : /* ----------
413 : : * Some preinitialized constants
414 : : * ----------
415 : : */
416 : : static const NumericDigit const_zero_data[1] = {0};
417 : : static const NumericVar const_zero =
418 : : {0, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_zero_data};
419 : :
420 : : static const NumericDigit const_one_data[1] = {1};
421 : : static const NumericVar const_one =
422 : : {1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_one_data};
423 : :
424 : : static const NumericVar const_minus_one =
425 : : {1, 0, NUMERIC_NEG, 0, NULL, (NumericDigit *) const_one_data};
426 : :
427 : : static const NumericDigit const_two_data[1] = {2};
428 : : static const NumericVar const_two =
429 : : {1, 0, NUMERIC_POS, 0, NULL, (NumericDigit *) const_two_data};
430 : :
431 : : #if DEC_DIGITS == 4
432 : : static const NumericDigit const_zero_point_nine_data[1] = {9000};
433 : : #elif DEC_DIGITS == 2
434 : : static const NumericDigit const_zero_point_nine_data[1] = {90};
435 : : #elif DEC_DIGITS == 1
436 : : static const NumericDigit const_zero_point_nine_data[1] = {9};
437 : : #endif
438 : : static const NumericVar const_zero_point_nine =
439 : : {1, -1, NUMERIC_POS, 1, NULL, (NumericDigit *) const_zero_point_nine_data};
440 : :
441 : : #if DEC_DIGITS == 4
442 : : static const NumericDigit const_one_point_one_data[2] = {1, 1000};
443 : : #elif DEC_DIGITS == 2
444 : : static const NumericDigit const_one_point_one_data[2] = {1, 10};
445 : : #elif DEC_DIGITS == 1
446 : : static const NumericDigit const_one_point_one_data[2] = {1, 1};
447 : : #endif
448 : : static const NumericVar const_one_point_one =
449 : : {2, 0, NUMERIC_POS, 1, NULL, (NumericDigit *) const_one_point_one_data};
450 : :
451 : : static const NumericVar const_nan =
452 : : {0, 0, NUMERIC_NAN, 0, NULL, NULL};
453 : :
454 : : static const NumericVar const_pinf =
455 : : {0, 0, NUMERIC_PINF, 0, NULL, NULL};
456 : :
457 : : static const NumericVar const_ninf =
458 : : {0, 0, NUMERIC_NINF, 0, NULL, NULL};
459 : :
460 : : #if DEC_DIGITS == 4
461 : : static const int round_powers[4] = {0, 1000, 100, 10};
462 : : #endif
463 : :
464 : :
465 : : /* ----------
466 : : * Local functions
467 : : * ----------
468 : : */
469 : :
470 : : #ifdef NUMERIC_DEBUG
471 : : static void dump_numeric(const char *str, Numeric num);
472 : : static void dump_var(const char *str, NumericVar *var);
473 : : #else
474 : : #define dump_numeric(s,n)
475 : : #define dump_var(s,v)
476 : : #endif
477 : :
478 : : #define digitbuf_alloc(ndigits) \
479 : : ((NumericDigit *) palloc((ndigits) * sizeof(NumericDigit)))
480 : : #define digitbuf_free(buf) \
481 : : do { \
482 : : if ((buf) != NULL) \
483 : : pfree(buf); \
484 : : } while (0)
485 : :
486 : : #define init_var(v) memset(v, 0, sizeof(NumericVar))
487 : :
488 : : #define NUMERIC_DIGITS(num) (NUMERIC_HEADER_IS_SHORT(num) ? \
489 : : (num)->choice.n_short.n_data : (num)->choice.n_long.n_data)
490 : : #define NUMERIC_NDIGITS(num) \
491 : : ((VARSIZE(num) - NUMERIC_HEADER_SIZE(num)) / sizeof(NumericDigit))
492 : : #define NUMERIC_CAN_BE_SHORT(scale,weight) \
493 : : ((scale) <= NUMERIC_SHORT_DSCALE_MAX && \
494 : : (weight) <= NUMERIC_SHORT_WEIGHT_MAX && \
495 : : (weight) >= NUMERIC_SHORT_WEIGHT_MIN)
496 : :
497 : : static void alloc_var(NumericVar *var, int ndigits);
498 : : static void free_var(NumericVar *var);
499 : : static void zero_var(NumericVar *var);
500 : :
501 : : static bool set_var_from_str(const char *str, const char *cp,
502 : : NumericVar *dest, const char **endptr,
503 : : Node *escontext);
504 : : static bool set_var_from_non_decimal_integer_str(const char *str,
505 : : const char *cp, int sign,
506 : : int base, NumericVar *dest,
507 : : const char **endptr,
508 : : Node *escontext);
509 : : static void set_var_from_num(Numeric num, NumericVar *dest);
510 : : static void init_var_from_num(Numeric num, NumericVar *dest);
511 : : static void set_var_from_var(const NumericVar *value, NumericVar *dest);
512 : : static char *get_str_from_var(const NumericVar *var);
513 : : static char *get_str_from_var_sci(const NumericVar *var, int rscale);
514 : :
515 : : static void numericvar_serialize(StringInfo buf, const NumericVar *var);
516 : : static void numericvar_deserialize(StringInfo buf, NumericVar *var);
517 : :
518 : : static Numeric duplicate_numeric(Numeric num);
519 : : static Numeric make_result(const NumericVar *var);
520 : : static Numeric make_result_safe(const NumericVar *var, Node *escontext);
521 : :
522 : : static bool apply_typmod(NumericVar *var, int32 typmod, Node *escontext);
523 : : static bool apply_typmod_special(Numeric num, int32 typmod, Node *escontext);
524 : :
525 : : static bool numericvar_to_int32(const NumericVar *var, int32 *result);
526 : : static bool numericvar_to_int64(const NumericVar *var, int64 *result);
527 : : static void int64_to_numericvar(int64 val, NumericVar *var);
528 : : static bool numericvar_to_uint64(const NumericVar *var, uint64 *result);
529 : : static void int128_to_numericvar(INT128 val, NumericVar *var);
530 : : static double numericvar_to_double_no_overflow(const NumericVar *var);
531 : :
532 : : static Datum numeric_abbrev_convert(Datum original_datum, SortSupport ssup);
533 : : static bool numeric_abbrev_abort(int memtupcount, SortSupport ssup);
534 : : static int numeric_fast_cmp(Datum x, Datum y, SortSupport ssup);
535 : : static int numeric_cmp_abbrev(Datum x, Datum y, SortSupport ssup);
536 : :
537 : : static Datum numeric_abbrev_convert_var(const NumericVar *var,
538 : : NumericSortSupport *nss);
539 : :
540 : : static int cmp_numerics(Numeric num1, Numeric num2);
541 : : static int cmp_var(const NumericVar *var1, const NumericVar *var2);
542 : : static int cmp_var_common(const NumericDigit *var1digits, int var1ndigits,
543 : : int var1weight, int var1sign,
544 : : const NumericDigit *var2digits, int var2ndigits,
545 : : int var2weight, int var2sign);
546 : : static void add_var(const NumericVar *var1, const NumericVar *var2,
547 : : NumericVar *result);
548 : : static void sub_var(const NumericVar *var1, const NumericVar *var2,
549 : : NumericVar *result);
550 : : static void mul_var(const NumericVar *var1, const NumericVar *var2,
551 : : NumericVar *result,
552 : : int rscale);
553 : : static void mul_var_short(const NumericVar *var1, const NumericVar *var2,
554 : : NumericVar *result);
555 : : static void div_var(const NumericVar *var1, const NumericVar *var2,
556 : : NumericVar *result, int rscale, bool round, bool exact);
557 : : static void div_var_int(const NumericVar *var, int ival, int ival_weight,
558 : : NumericVar *result, int rscale, bool round);
559 : : #ifdef HAVE_INT128
560 : : static void div_var_int64(const NumericVar *var, int64 ival, int ival_weight,
561 : : NumericVar *result, int rscale, bool round);
562 : : #endif
563 : : static int select_div_scale(const NumericVar *var1, const NumericVar *var2);
564 : : static void mod_var(const NumericVar *var1, const NumericVar *var2,
565 : : NumericVar *result);
566 : : static void div_mod_var(const NumericVar *var1, const NumericVar *var2,
567 : : NumericVar *quot, NumericVar *rem);
568 : : static void ceil_var(const NumericVar *var, NumericVar *result);
569 : : static void floor_var(const NumericVar *var, NumericVar *result);
570 : :
571 : : static void gcd_var(const NumericVar *var1, const NumericVar *var2,
572 : : NumericVar *result);
573 : : static void sqrt_var(const NumericVar *arg, NumericVar *result, int rscale);
574 : : static void exp_var(const NumericVar *arg, NumericVar *result, int rscale);
575 : : static int estimate_ln_dweight(const NumericVar *var);
576 : : static void ln_var(const NumericVar *arg, NumericVar *result, int rscale);
577 : : static void log_var(const NumericVar *base, const NumericVar *num,
578 : : NumericVar *result);
579 : : static void power_var(const NumericVar *base, const NumericVar *exp,
580 : : NumericVar *result);
581 : : static void power_var_int(const NumericVar *base, int exp, int exp_dscale,
582 : : NumericVar *result);
583 : : static void power_ten_int(int exp, NumericVar *result);
584 : : static void random_var(pg_prng_state *state, const NumericVar *rmin,
585 : : const NumericVar *rmax, NumericVar *result);
586 : :
587 : : static int cmp_abs(const NumericVar *var1, const NumericVar *var2);
588 : : static int cmp_abs_common(const NumericDigit *var1digits, int var1ndigits,
589 : : int var1weight,
590 : : const NumericDigit *var2digits, int var2ndigits,
591 : : int var2weight);
592 : : static void add_abs(const NumericVar *var1, const NumericVar *var2,
593 : : NumericVar *result);
594 : : static void sub_abs(const NumericVar *var1, const NumericVar *var2,
595 : : NumericVar *result);
596 : : static void round_var(NumericVar *var, int rscale);
597 : : static void trunc_var(NumericVar *var, int rscale);
598 : : static void strip_var(NumericVar *var);
599 : : static void compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
600 : : const NumericVar *count_var,
601 : : NumericVar *result_var);
602 : :
603 : : static void accum_sum_add(NumericSumAccum *accum, const NumericVar *val);
604 : : static void accum_sum_rescale(NumericSumAccum *accum, const NumericVar *val);
605 : : static void accum_sum_carry(NumericSumAccum *accum);
606 : : static void accum_sum_reset(NumericSumAccum *accum);
607 : : static void accum_sum_final(NumericSumAccum *accum, NumericVar *result);
608 : : static void accum_sum_copy(NumericSumAccum *dst, NumericSumAccum *src);
609 : : static void accum_sum_combine(NumericSumAccum *accum, NumericSumAccum *accum2);
610 : :
611 : :
612 : : /* ----------------------------------------------------------------------
613 : : *
614 : : * Input-, output- and rounding-functions
615 : : *
616 : : * ----------------------------------------------------------------------
617 : : */
618 : :
619 : :
620 : : /*
621 : : * numeric_in() -
622 : : *
623 : : * Input function for numeric data type
624 : : */
625 : : Datum
9457 tgl@sss.pgh.pa.us 626 :CBC 104109 : numeric_in(PG_FUNCTION_ARGS)
627 : : {
628 : 104109 : char *str = PG_GETARG_CSTRING(0);
629 : : #ifdef NOT_USED
630 : : Oid typelem = PG_GETARG_OID(1);
631 : : #endif
632 : 104109 : int32 typmod = PG_GETARG_INT32(2);
1243 633 : 104109 : Node *escontext = fcinfo->context;
634 : : Numeric res;
635 : : const char *cp;
636 : : const char *numstart;
637 : : int sign;
638 : :
639 : : /* Skip leading spaces */
6236 640 : 104109 : cp = str;
641 [ + + ]: 120389 : while (*cp)
642 : : {
643 [ + + ]: 120377 : if (!isspace((unsigned char) *cp))
644 : 104097 : break;
645 : 16280 : cp++;
646 : : }
647 : :
648 : : /*
649 : : * Process the number's sign. This duplicates logic in set_var_from_str(),
650 : : * but it's worth doing here, since it simplifies the handling of
651 : : * infinities and non-decimal integers.
652 : : */
1198 dean.a.rasheed@gmail 653 : 104109 : numstart = cp;
654 : 104109 : sign = NUMERIC_POS;
655 : :
656 [ + + ]: 104109 : if (*cp == '+')
657 : 32 : cp++;
658 [ + + ]: 104077 : else if (*cp == '-')
659 : : {
660 : 2487 : sign = NUMERIC_NEG;
661 : 2487 : cp++;
662 : : }
663 : :
664 : : /*
665 : : * Check for NaN and infinities. We recognize the same strings allowed by
666 : : * float8in().
667 : : *
668 : : * Since all other legal inputs have a digit or a decimal point after the
669 : : * sign, we need only check for NaN/infinity if that's not the case.
670 : : */
671 [ + + + + ]: 104109 : if (!isdigit((unsigned char) *cp) && *cp != '.')
672 : : {
673 : : /*
674 : : * The number must be NaN or infinity; anything else can only be a
675 : : * syntax error. Note that NaN mustn't have a sign.
676 : : */
677 [ + + ]: 1194 : if (pg_strncasecmp(numstart, "NaN", 3) == 0)
678 : : {
679 : 392 : res = make_result(&const_nan);
680 : 392 : cp = numstart + 3;
681 : : }
682 [ + + ]: 802 : else if (pg_strncasecmp(cp, "Infinity", 8) == 0)
683 : : {
684 [ + + ]: 337 : res = make_result(sign == NUMERIC_POS ? &const_pinf : &const_ninf);
685 : 337 : cp += 8;
686 : : }
687 [ + + ]: 465 : else if (pg_strncasecmp(cp, "inf", 3) == 0)
688 : : {
689 [ + + ]: 392 : res = make_result(sign == NUMERIC_POS ? &const_pinf : &const_ninf);
690 : 392 : cp += 3;
691 : : }
692 : : else
693 : 73 : goto invalid_syntax;
694 : :
695 : : /*
696 : : * Check for trailing junk; there should be nothing left but spaces.
697 : : *
698 : : * We intentionally do this check before applying the typmod because
699 : : * we would like to throw any trailing-junk syntax error before any
700 : : * semantic error resulting from apply_typmod_special().
701 : : */
702 [ + + ]: 1149 : while (*cp)
703 : : {
704 [ - + ]: 28 : if (!isspace((unsigned char) *cp))
1198 dean.a.rasheed@gmail 705 :UBC 0 : goto invalid_syntax;
1198 dean.a.rasheed@gmail 706 :CBC 28 : cp++;
707 : : }
708 : :
709 [ - + ]: 1121 : if (!apply_typmod_special(res, typmod, escontext))
1198 dean.a.rasheed@gmail 710 :UBC 0 : PG_RETURN_NULL();
711 : : }
712 : : else
713 : : {
714 : : /*
715 : : * We have a normal numeric value, which may be a non-decimal integer
716 : : * or a regular decimal number.
717 : : */
718 : : NumericVar value;
719 : : int base;
720 : :
6236 tgl@sss.pgh.pa.us 721 :CBC 102915 : init_var(&value);
722 : :
723 : : /*
724 : : * Determine the number's base by looking for a non-decimal prefix
725 : : * indicator ("0x", "0o", or "0b").
726 : : */
1198 dean.a.rasheed@gmail 727 [ + + ]: 102915 : if (cp[0] == '0')
728 : : {
729 [ + + + + ]: 33367 : switch (cp[1])
730 : : {
731 : 48 : case 'x':
732 : : case 'X':
733 : 48 : base = 16;
734 : 48 : break;
735 : 28 : case 'o':
736 : : case 'O':
737 : 28 : base = 8;
738 : 28 : break;
739 : 28 : case 'b':
740 : : case 'B':
741 : 28 : base = 2;
742 : 28 : break;
743 : 33263 : default:
744 : 33263 : base = 10;
745 : : }
746 : : }
747 : : else
748 : 69548 : base = 10;
749 : :
750 : : /* Parse the rest of the number and apply the sign */
751 [ + + ]: 102915 : if (base == 10)
752 : : {
753 [ - + ]: 102811 : if (!set_var_from_str(str, cp, &value, &cp, escontext))
754 : 16 : PG_RETURN_NULL();
755 : 102779 : value.sign = sign;
756 : : }
757 : : else
758 : : {
759 [ - + ]: 104 : if (!set_var_from_non_decimal_integer_str(str, cp + 2, sign, base,
760 : : &value, &cp, escontext))
1198 dean.a.rasheed@gmail 761 :UBC 0 : PG_RETURN_NULL();
762 : : }
763 : :
764 : : /*
765 : : * Should be nothing left but spaces. As above, throw any typmod error
766 : : * after finishing syntax check.
767 : : */
6236 tgl@sss.pgh.pa.us 768 [ + + ]:CBC 102923 : while (*cp)
769 : : {
770 [ + + ]: 100 : if (!isspace((unsigned char) *cp))
1198 dean.a.rasheed@gmail 771 : 48 : goto invalid_syntax;
6236 tgl@sss.pgh.pa.us 772 : 52 : cp++;
773 : : }
774 : :
1243 775 [ + + ]: 102823 : if (!apply_typmod(&value, typmod, escontext))
776 : 16 : PG_RETURN_NULL();
777 : :
242 michael@paquier.xyz 778 :GNC 102807 : res = make_result_safe(&value, escontext);
779 : :
6236 tgl@sss.pgh.pa.us 780 :CBC 102807 : free_var(&value);
781 : : }
782 : :
9457 783 : 103928 : PG_RETURN_NUMERIC(res);
784 : :
1198 dean.a.rasheed@gmail 785 : 121 : invalid_syntax:
786 [ + + ]: 121 : ereturn(escontext, (Datum) 0,
787 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
788 : : errmsg("invalid input syntax for type %s: \"%s\"",
789 : : "numeric", str)));
790 : : }
791 : :
792 : :
793 : : /*
794 : : * numeric_out() -
795 : : *
796 : : * Output function for numeric data type
797 : : */
798 : : Datum
9457 tgl@sss.pgh.pa.us 799 : 535635 : numeric_out(PG_FUNCTION_ARGS)
800 : : {
801 : 535635 : Numeric num = PG_GETARG_NUMERIC(0);
802 : : NumericVar x;
803 : : char *str;
804 : :
805 : : /*
806 : : * Handle NaN and infinities
807 : : */
2113 808 [ + + ]: 535635 : if (NUMERIC_IS_SPECIAL(num))
809 : : {
810 [ + + ]: 2332 : if (NUMERIC_IS_PINF(num))
811 : 688 : PG_RETURN_CSTRING(pstrdup("Infinity"));
812 [ + + ]: 1644 : else if (NUMERIC_IS_NINF(num))
813 : 436 : PG_RETURN_CSTRING(pstrdup("-Infinity"));
814 : : else
815 : 1208 : PG_RETURN_CSTRING(pstrdup("NaN"));
816 : : }
817 : :
818 : : /*
819 : : * Get the number in the variable format.
820 : : */
4913 heikki.linnakangas@i 821 : 533303 : init_var_from_num(num, &x);
822 : :
823 : 533303 : str = get_str_from_var(&x);
824 : :
9457 tgl@sss.pgh.pa.us 825 : 533303 : PG_RETURN_CSTRING(str);
826 : : }
827 : :
828 : : /*
829 : : * numeric_is_nan() -
830 : : *
831 : : * Is Numeric value a NaN?
832 : : */
833 : : bool
5758 rhaas@postgresql.org 834 : 4424 : numeric_is_nan(Numeric num)
835 : : {
836 : 4424 : return NUMERIC_IS_NAN(num);
837 : : }
838 : :
839 : : /*
840 : : * numeric_is_inf() -
841 : : *
842 : : * Is Numeric value an infinity?
843 : : */
844 : : bool
2113 tgl@sss.pgh.pa.us 845 : 808 : numeric_is_inf(Numeric num)
846 : : {
847 : 808 : return NUMERIC_IS_INF(num);
848 : : }
849 : :
850 : : /*
851 : : * numeric_is_integral() -
852 : : *
853 : : * Is Numeric value integral?
854 : : */
855 : : static bool
856 : 54 : numeric_is_integral(Numeric num)
857 : : {
858 : : NumericVar arg;
859 : :
860 : : /* Reject NaN, but infinities are considered integral */
861 [ + + ]: 54 : if (NUMERIC_IS_SPECIAL(num))
862 : : {
863 [ - + ]: 25 : if (NUMERIC_IS_NAN(num))
2113 tgl@sss.pgh.pa.us 864 :UBC 0 : return false;
2113 tgl@sss.pgh.pa.us 865 :CBC 25 : return true;
866 : : }
867 : :
868 : : /* Integral if there are no digits to the right of the decimal point */
869 : 29 : init_var_from_num(num, &arg);
870 : :
871 [ + + + + ]: 29 : return (arg.ndigits == 0 || arg.ndigits <= arg.weight + 1);
872 : : }
873 : :
874 : : /*
875 : : * make_numeric_typmod() -
876 : : *
877 : : * Pack numeric precision and scale values into a typmod. The upper 16 bits
878 : : * are used for the precision (though actually not all these bits are needed,
879 : : * since the maximum allowed precision is 1000). The lower 16 bits are for
880 : : * the scale, but since the scale is constrained to the range [-1000, 1000],
881 : : * we use just the lower 11 of those 16 bits, and leave the remaining 5 bits
882 : : * unset, for possible future use.
883 : : *
884 : : * For purely historical reasons VARHDRSZ is then added to the result, thus
885 : : * the unused space in the upper 16 bits is not all as freely available as it
886 : : * might seem. (We can't let the result overflow to a negative int32, as
887 : : * other parts of the system would interpret that as not-a-valid-typmod.)
888 : : */
889 : : static inline int32
1744 dean.a.rasheed@gmail 890 : 1051 : make_numeric_typmod(int precision, int scale)
891 : : {
892 : 1051 : return ((precision << 16) | (scale & 0x7ff)) + VARHDRSZ;
893 : : }
894 : :
895 : : /*
896 : : * Because of the offset, valid numeric typmods are at least VARHDRSZ
897 : : */
898 : : static inline bool
899 : 120032 : is_valid_numeric_typmod(int32 typmod)
900 : : {
901 : 120032 : return typmod >= (int32) VARHDRSZ;
902 : : }
903 : :
904 : : /*
905 : : * numeric_typmod_precision() -
906 : : *
907 : : * Extract the precision from a numeric typmod --- see make_numeric_typmod().
908 : : */
909 : : static inline int
910 : 32865 : numeric_typmod_precision(int32 typmod)
911 : : {
912 : 32865 : return ((typmod - VARHDRSZ) >> 16) & 0xffff;
913 : : }
914 : :
915 : : /*
916 : : * numeric_typmod_scale() -
917 : : *
918 : : * Extract the scale from a numeric typmod --- see make_numeric_typmod().
919 : : *
920 : : * Note that the scale may be negative, so we must do sign extension when
921 : : * unpacking it. We do this using the bit hack (x^1024)-1024, which sign
922 : : * extends an 11-bit two's complement number x.
923 : : */
924 : : static inline int
925 : 27988 : numeric_typmod_scale(int32 typmod)
926 : : {
927 : 27988 : return (((typmod - VARHDRSZ) & 0x7ff) ^ 1024) - 1024;
928 : : }
929 : :
930 : : /*
931 : : * numeric_maximum_size() -
932 : : *
933 : : * Maximum size of a numeric with given typmod, or -1 if unlimited/unknown.
934 : : */
935 : : int32
5753 rhaas@postgresql.org 936 : 4877 : numeric_maximum_size(int32 typmod)
937 : : {
938 : : int precision;
939 : : int numeric_digits;
940 : :
1744 dean.a.rasheed@gmail 941 [ - + ]: 4877 : if (!is_valid_numeric_typmod(typmod))
5758 rhaas@postgresql.org 942 :UBC 0 : return -1;
943 : :
944 : : /* precision (ie, max # of digits) is in upper bits of typmod */
1744 dean.a.rasheed@gmail 945 :CBC 4877 : precision = numeric_typmod_precision(typmod);
946 : :
947 : : /*
948 : : * This formula computes the maximum number of NumericDigits we could need
949 : : * in order to store the specified number of decimal digits. Because the
950 : : * weight is stored as a number of NumericDigits rather than a number of
951 : : * decimal digits, it's possible that the first NumericDigit will contain
952 : : * only a single decimal digit. Thus, the first two decimal digits can
953 : : * require two NumericDigits to store, but it isn't until we reach
954 : : * DEC_DIGITS + 2 decimal digits that we potentially need a third
955 : : * NumericDigit.
956 : : */
5753 rhaas@postgresql.org 957 : 4877 : numeric_digits = (precision + 2 * (DEC_DIGITS - 1)) / DEC_DIGITS;
958 : :
959 : : /*
960 : : * In most cases, the size of a numeric will be smaller than the value
961 : : * computed below, because the varlena header will typically get toasted
962 : : * down to a single byte before being stored on disk, and it may also be
963 : : * possible to use a short numeric header. But our job here is to compute
964 : : * the worst case.
965 : : */
966 : 4877 : return NUMERIC_HDRSZ + (numeric_digits * sizeof(NumericDigit));
967 : : }
968 : :
969 : : /*
970 : : * numeric_out_sci() -
971 : : *
972 : : * Output function for numeric data type in scientific notation.
973 : : */
974 : : char *
6112 tgl@sss.pgh.pa.us 975 : 164 : numeric_out_sci(Numeric num, int scale)
976 : : {
977 : : NumericVar x;
978 : : char *str;
979 : :
980 : : /*
981 : : * Handle NaN and infinities
982 : : */
2113 983 [ + + ]: 164 : if (NUMERIC_IS_SPECIAL(num))
984 : : {
985 [ + + ]: 12 : if (NUMERIC_IS_PINF(num))
986 : 4 : return pstrdup("Infinity");
987 [ + + ]: 8 : else if (NUMERIC_IS_NINF(num))
988 : 4 : return pstrdup("-Infinity");
989 : : else
990 : 4 : return pstrdup("NaN");
991 : : }
992 : :
4913 heikki.linnakangas@i 993 : 152 : init_var_from_num(num, &x);
994 : :
6112 tgl@sss.pgh.pa.us 995 : 152 : str = get_str_from_var_sci(&x, scale);
996 : :
997 : 152 : return str;
998 : : }
999 : :
1000 : : /*
1001 : : * numeric_normalize() -
1002 : : *
1003 : : * Output function for numeric data type, suppressing insignificant trailing
1004 : : * zeroes and then any trailing decimal point. The intent of this is to
1005 : : * produce strings that are equal if and only if the input numeric values
1006 : : * compare equal.
1007 : : */
1008 : : char *
4426 andrew@dunslane.net 1009 : 16755 : numeric_normalize(Numeric num)
1010 : : {
1011 : : NumericVar x;
1012 : : char *str;
1013 : : int last;
1014 : :
1015 : : /*
1016 : : * Handle NaN and infinities
1017 : : */
2113 tgl@sss.pgh.pa.us 1018 [ - + ]: 16755 : if (NUMERIC_IS_SPECIAL(num))
1019 : : {
2113 tgl@sss.pgh.pa.us 1020 [ # # ]:UBC 0 : if (NUMERIC_IS_PINF(num))
1021 : 0 : return pstrdup("Infinity");
1022 [ # # ]: 0 : else if (NUMERIC_IS_NINF(num))
1023 : 0 : return pstrdup("-Infinity");
1024 : : else
1025 : 0 : return pstrdup("NaN");
1026 : : }
1027 : :
4426 andrew@dunslane.net 1028 :CBC 16755 : init_var_from_num(num, &x);
1029 : :
1030 : 16755 : str = get_str_from_var(&x);
1031 : :
1032 : : /* If there's no decimal point, there's certainly nothing to remove. */
4198 tgl@sss.pgh.pa.us 1033 [ + + ]: 16755 : if (strchr(str, '.') != NULL)
1034 : : {
1035 : : /*
1036 : : * Back up over trailing fractional zeroes. Since there is a decimal
1037 : : * point, this loop will terminate safely.
1038 : : */
1039 : 31 : last = strlen(str) - 1;
1040 [ + + ]: 62 : while (str[last] == '0')
1041 : 31 : last--;
1042 : :
1043 : : /* We want to get rid of the decimal point too, if it's now last. */
1044 [ + - ]: 31 : if (str[last] == '.')
1045 : 31 : last--;
1046 : :
1047 : : /* Delete whatever we backed up over. */
1048 : 31 : str[last + 1] = '\0';
1049 : : }
1050 : :
4426 andrew@dunslane.net 1051 : 16755 : return str;
1052 : : }
1053 : :
1054 : : /*
1055 : : * numeric_recv - converts external binary format to numeric
1056 : : *
1057 : : * External format is a sequence of int16's:
1058 : : * ndigits, weight, sign, dscale, NumericDigits.
1059 : : */
1060 : : Datum
8394 tgl@sss.pgh.pa.us 1061 : 51 : numeric_recv(PG_FUNCTION_ARGS)
1062 : : {
1063 : 51 : StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
1064 : :
1065 : : #ifdef NOT_USED
1066 : : Oid typelem = PG_GETARG_OID(1);
1067 : : #endif
7604 1068 : 51 : int32 typmod = PG_GETARG_INT32(2);
1069 : : NumericVar value;
1070 : : Numeric res;
1071 : : int len,
1072 : : i;
1073 : :
8394 1074 : 51 : init_var(&value);
1075 : :
1076 : 51 : len = (uint16) pq_getmsgint(buf, sizeof(uint16));
1077 : :
1078 : 51 : alloc_var(&value, len);
1079 : :
1080 : 51 : value.weight = (int16) pq_getmsgint(buf, sizeof(int16));
1081 : : /* we allow any int16 for weight --- OK? */
1082 : :
1083 : 51 : value.sign = (uint16) pq_getmsgint(buf, sizeof(uint16));
1084 [ - + ]: 51 : if (!(value.sign == NUMERIC_POS ||
8394 tgl@sss.pgh.pa.us 1085 [ # # ]:UBC 0 : value.sign == NUMERIC_NEG ||
2113 1086 [ # # ]: 0 : value.sign == NUMERIC_NAN ||
1087 [ # # ]: 0 : value.sign == NUMERIC_PINF ||
1088 [ # # ]: 0 : value.sign == NUMERIC_NINF))
8318 1089 [ # # ]: 0 : ereport(ERROR,
1090 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1091 : : errmsg("invalid sign in external \"numeric\" value")));
1092 : :
8394 tgl@sss.pgh.pa.us 1093 :CBC 51 : value.dscale = (uint16) pq_getmsgint(buf, sizeof(uint16));
4173 1094 [ - + ]: 51 : if ((value.dscale & NUMERIC_DSCALE_MASK) != value.dscale)
4173 tgl@sss.pgh.pa.us 1095 [ # # ]:UBC 0 : ereport(ERROR,
1096 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1097 : : errmsg("invalid scale in external \"numeric\" value")));
1098 : :
8394 tgl@sss.pgh.pa.us 1099 [ + + ]:CBC 137 : for (i = 0; i < len; i++)
1100 : : {
8310 bruce@momjian.us 1101 : 86 : NumericDigit d = pq_getmsgint(buf, sizeof(NumericDigit));
1102 : :
8394 tgl@sss.pgh.pa.us 1103 [ + - - + ]: 86 : if (d < 0 || d >= NBASE)
8318 tgl@sss.pgh.pa.us 1104 [ # # ]:UBC 0 : ereport(ERROR,
1105 : : (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
1106 : : errmsg("invalid digit in external \"numeric\" value")));
8394 tgl@sss.pgh.pa.us 1107 :CBC 86 : value.digits[i] = d;
1108 : : }
1109 : :
1110 : : /*
1111 : : * If the given dscale would hide any digits, truncate those digits away.
1112 : : * We could alternatively throw an error, but that would take a bunch of
1113 : : * extra code (about as much as trunc_var involves), and it might cause
1114 : : * client compatibility issues. Be careful not to apply trunc_var to
1115 : : * special values, as it could do the wrong thing; we don't need it
1116 : : * anyway, since make_result will ignore all but the sign field.
1117 : : *
1118 : : * After doing that, be sure to check the typmod restriction.
1119 : : */
2113 1120 [ - + ]: 51 : if (value.sign == NUMERIC_POS ||
2113 tgl@sss.pgh.pa.us 1121 [ # # ]:UBC 0 : value.sign == NUMERIC_NEG)
1122 : : {
2113 tgl@sss.pgh.pa.us 1123 :CBC 51 : trunc_var(&value, value.dscale);
1124 : :
1243 1125 : 51 : (void) apply_typmod(&value, typmod, NULL);
1126 : :
2113 1127 : 51 : res = make_result(&value);
1128 : : }
1129 : : else
1130 : : {
1131 : : /* apply_typmod_special wants us to make the Numeric first */
2113 tgl@sss.pgh.pa.us 1132 :UBC 0 : res = make_result(&value);
1133 : :
1243 1134 : 0 : (void) apply_typmod_special(res, typmod, NULL);
1135 : : }
1136 : :
8394 tgl@sss.pgh.pa.us 1137 :CBC 51 : free_var(&value);
1138 : :
1139 : 51 : PG_RETURN_NUMERIC(res);
1140 : : }
1141 : :
1142 : : /*
1143 : : * numeric_send - converts numeric to binary format
1144 : : */
1145 : : Datum
1146 : 35 : numeric_send(PG_FUNCTION_ARGS)
1147 : : {
1148 : 35 : Numeric num = PG_GETARG_NUMERIC(0);
1149 : : NumericVar x;
1150 : : StringInfoData buf;
1151 : : int i;
1152 : :
4913 heikki.linnakangas@i 1153 : 35 : init_var_from_num(num, &x);
1154 : :
8394 tgl@sss.pgh.pa.us 1155 : 35 : pq_begintypsend(&buf);
1156 : :
3128 andres@anarazel.de 1157 : 35 : pq_sendint16(&buf, x.ndigits);
1158 : 35 : pq_sendint16(&buf, x.weight);
1159 : 35 : pq_sendint16(&buf, x.sign);
1160 : 35 : pq_sendint16(&buf, x.dscale);
8394 tgl@sss.pgh.pa.us 1161 [ + + ]: 97 : for (i = 0; i < x.ndigits; i++)
3128 andres@anarazel.de 1162 : 62 : pq_sendint16(&buf, x.digits[i]);
1163 : :
8394 tgl@sss.pgh.pa.us 1164 : 35 : PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
1165 : : }
1166 : :
1167 : :
1168 : : /*
1169 : : * numeric_support()
1170 : : *
1171 : : * Planner support function for the numeric() length coercion function.
1172 : : *
1173 : : * Flatten calls that solely represent increases in allowable precision.
1174 : : * Scale changes mutate every datum, so they are unoptimizable. Some values,
1175 : : * e.g. 1E-1001, can only fit into an unconstrained numeric, so a change from
1176 : : * an unconstrained numeric to any constrained numeric is also unoptimizable.
1177 : : */
1178 : : Datum
2642 1179 : 427 : numeric_support(PG_FUNCTION_ARGS)
1180 : : {
1181 : 427 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
5201 rhaas@postgresql.org 1182 : 427 : Node *ret = NULL;
1183 : :
2642 tgl@sss.pgh.pa.us 1184 [ + + ]: 427 : if (IsA(rawreq, SupportRequestSimplify))
1185 : : {
1186 : 187 : SupportRequestSimplify *req = (SupportRequestSimplify *) rawreq;
1187 : 187 : FuncExpr *expr = req->fcall;
1188 : : Node *typmod;
1189 : :
1190 [ - + ]: 187 : Assert(list_length(expr->args) >= 2);
1191 : :
1192 : 187 : typmod = (Node *) lsecond(expr->args);
1193 : :
2180 1194 [ + - + - ]: 187 : if (IsA(typmod, Const) && !((Const *) typmod)->constisnull)
1195 : : {
2642 1196 : 187 : Node *source = (Node *) linitial(expr->args);
1197 : 187 : int32 old_typmod = exprTypmod(source);
1198 : 187 : int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
1744 dean.a.rasheed@gmail 1199 : 187 : int32 old_scale = numeric_typmod_scale(old_typmod);
1200 : 187 : int32 new_scale = numeric_typmod_scale(new_typmod);
1201 : 187 : int32 old_precision = numeric_typmod_precision(old_typmod);
1202 : 187 : int32 new_precision = numeric_typmod_precision(new_typmod);
1203 : :
1204 : : /*
1205 : : * If new_typmod is invalid, the destination is unconstrained;
1206 : : * that's always OK. If old_typmod is valid, the source is
1207 : : * constrained, and we're OK if the scale is unchanged and the
1208 : : * precision is not decreasing. See further notes in function
1209 : : * header comment.
1210 : : */
1211 [ + - + + ]: 374 : if (!is_valid_numeric_typmod(new_typmod) ||
1212 [ + + ]: 196 : (is_valid_numeric_typmod(old_typmod) &&
2642 tgl@sss.pgh.pa.us 1213 [ + - ]: 4 : new_scale == old_scale && new_precision >= old_precision))
1214 : 4 : ret = relabel_to_typmod(source, new_typmod);
1215 : : }
1216 : : }
1217 : :
5201 rhaas@postgresql.org 1218 : 427 : PG_RETURN_POINTER(ret);
1219 : : }
1220 : :
1221 : : /*
1222 : : * numeric() -
1223 : : *
1224 : : * This is a special function called by the Postgres database system
1225 : : * before a value is stored in a tuple's attribute. The precision and
1226 : : * scale of the attribute have to be applied on the value.
1227 : : */
1228 : : Datum
6746 bruce@momjian.us 1229 : 8069 : numeric (PG_FUNCTION_ARGS)
1230 : : {
9457 tgl@sss.pgh.pa.us 1231 : 8069 : Numeric num = PG_GETARG_NUMERIC(0);
1232 : 8069 : int32 typmod = PG_GETARG_INT32(1);
1233 : : Numeric new;
1234 : : int precision;
1235 : : int scale;
1236 : : int ddigits;
1237 : : int maxdigits;
1238 : : int dscale;
1239 : : NumericVar var;
1240 : :
1241 : : /*
1242 : : * Handle NaN and infinities: if apply_typmod_special doesn't complain,
1243 : : * just return a copy of the input.
1244 : : */
2113 1245 [ + + ]: 8069 : if (NUMERIC_IS_SPECIAL(num))
1246 : : {
42 peter@eisentraut.org 1247 [ - + ]:GNC 172 : if (!apply_typmod_special(num, typmod, fcinfo->context))
42 peter@eisentraut.org 1248 :UNC 0 : PG_RETURN_NULL();
2113 tgl@sss.pgh.pa.us 1249 :CBC 160 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1250 : : }
1251 : :
1252 : : /*
1253 : : * If the value isn't a valid type modifier, simply return a copy of the
1254 : : * input value
1255 : : */
1744 dean.a.rasheed@gmail 1256 [ - + ]: 7897 : if (!is_valid_numeric_typmod(typmod))
2113 tgl@sss.pgh.pa.us 1257 :UBC 0 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1258 : :
1259 : : /*
1260 : : * Get the precision and scale out of the typmod value
1261 : : */
1744 dean.a.rasheed@gmail 1262 :CBC 7897 : precision = numeric_typmod_precision(typmod);
1263 : 7897 : scale = numeric_typmod_scale(typmod);
8446 tgl@sss.pgh.pa.us 1264 : 7897 : maxdigits = precision - scale;
1265 : :
1266 : : /* The target display scale is non-negative */
1744 dean.a.rasheed@gmail 1267 : 7897 : dscale = Max(scale, 0);
1268 : :
1269 : : /*
1270 : : * If the number is certainly in bounds and due to the target scale no
1271 : : * rounding could be necessary, just make a copy of the input and modify
1272 : : * its scale fields, unless the larger scale forces us to abandon the
1273 : : * short representation. (Note we assume the existing dscale is
1274 : : * honest...)
1275 : : */
5754 rhaas@postgresql.org 1276 [ + + + + ]: 7897 : ddigits = (NUMERIC_WEIGHT(num) + 1) * DEC_DIGITS;
1277 [ + + + + : 7897 : if (ddigits <= maxdigits && scale >= NUMERIC_DSCALE(num)
+ + ]
1744 dean.a.rasheed@gmail 1278 [ + - + - : 4837 : && (NUMERIC_CAN_BE_SHORT(dscale, NUMERIC_WEIGHT(num))
+ + + - -
- + - + +
- + - - ]
5504 bruce@momjian.us 1279 [ # # ]:UBC 0 : || !NUMERIC_IS_SHORT(num)))
1280 : : {
2113 tgl@sss.pgh.pa.us 1281 :CBC 4837 : new = duplicate_numeric(num);
5754 rhaas@postgresql.org 1282 [ + - ]: 4837 : if (NUMERIC_IS_SHORT(num))
1283 : 4837 : new->choice.n_short.n_header =
1284 : 4837 : (num->choice.n_short.n_header & ~NUMERIC_SHORT_DSCALE_MASK)
1744 dean.a.rasheed@gmail 1285 : 4837 : | (dscale << NUMERIC_SHORT_DSCALE_SHIFT);
1286 : : else
5754 rhaas@postgresql.org 1287 [ # # # # ]:UBC 0 : new->choice.n_long.n_sign_dscale = NUMERIC_SIGN(new) |
1744 dean.a.rasheed@gmail 1288 : 0 : ((uint16) dscale & NUMERIC_DSCALE_MASK);
9457 tgl@sss.pgh.pa.us 1289 :CBC 4837 : PG_RETURN_NUMERIC(new);
1290 : : }
1291 : :
1292 : : /*
1293 : : * We really need to fiddle with things - unpack the number into a
1294 : : * variable and let apply_typmod() do it.
1295 : : */
9988 JanWieck@Yahoo.com 1296 : 3060 : init_var(&var);
1297 : :
1298 : 3060 : set_var_from_num(num, &var);
42 peter@eisentraut.org 1299 [ - + ]:GNC 3060 : if (!apply_typmod(&var, typmod, fcinfo->context))
42 peter@eisentraut.org 1300 :UNC 0 : PG_RETURN_NULL();
42 peter@eisentraut.org 1301 :GNC 3020 : new = make_result_safe(&var, fcinfo->context);
1302 : :
9988 JanWieck@Yahoo.com 1303 :CBC 3020 : free_var(&var);
1304 : :
9457 tgl@sss.pgh.pa.us 1305 : 3020 : PG_RETURN_NUMERIC(new);
1306 : : }
1307 : :
1308 : : Datum
7066 1309 : 1079 : numerictypmodin(PG_FUNCTION_ARGS)
1310 : : {
6746 bruce@momjian.us 1311 : 1079 : ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
1312 : : int32 *tl;
1313 : : int n;
1314 : : int32 typmod;
1315 : :
6899 tgl@sss.pgh.pa.us 1316 : 1079 : tl = ArrayGetIntegerTypmods(ta, &n);
1317 : :
7066 1318 [ + + ]: 1079 : if (n == 2)
1319 : : {
1320 [ + + + + ]: 1069 : if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
1321 [ + - ]: 12 : ereport(ERROR,
1322 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1323 : : errmsg("NUMERIC precision %d must be between 1 and %d",
1324 : : tl[0], NUMERIC_MAX_PRECISION)));
1744 dean.a.rasheed@gmail 1325 [ + + + + ]: 1057 : if (tl[1] < NUMERIC_MIN_SCALE || tl[1] > NUMERIC_MAX_SCALE)
7066 tgl@sss.pgh.pa.us 1326 [ + - ]: 8 : ereport(ERROR,
1327 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1328 : : errmsg("NUMERIC scale %d must be between %d and %d",
1329 : : tl[1], NUMERIC_MIN_SCALE, NUMERIC_MAX_SCALE)));
1744 dean.a.rasheed@gmail 1330 : 1049 : typmod = make_numeric_typmod(tl[0], tl[1]);
1331 : : }
7066 tgl@sss.pgh.pa.us 1332 [ + + ]: 10 : else if (n == 1)
1333 : : {
1334 [ + - - + ]: 2 : if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
7066 tgl@sss.pgh.pa.us 1335 [ # # ]:UBC 0 : ereport(ERROR,
1336 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1337 : : errmsg("NUMERIC precision %d must be between 1 and %d",
1338 : : tl[0], NUMERIC_MAX_PRECISION)));
1339 : : /* scale defaults to zero */
1744 dean.a.rasheed@gmail 1340 :CBC 2 : typmod = make_numeric_typmod(tl[0], 0);
1341 : : }
1342 : : else
1343 : : {
7066 tgl@sss.pgh.pa.us 1344 [ + - ]: 8 : ereport(ERROR,
1345 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1346 : : errmsg("invalid NUMERIC type modifier")));
1347 : : typmod = 0; /* keep compiler quiet */
1348 : : }
1349 : :
1350 : 1051 : PG_RETURN_INT32(typmod);
1351 : : }
1352 : :
1353 : : Datum
1354 : 209 : numerictypmodout(PG_FUNCTION_ARGS)
1355 : : {
6746 bruce@momjian.us 1356 : 209 : int32 typmod = PG_GETARG_INT32(0);
1357 : 209 : char *res = (char *) palloc(64);
1358 : :
1744 dean.a.rasheed@gmail 1359 [ + - ]: 209 : if (is_valid_numeric_typmod(typmod))
7066 tgl@sss.pgh.pa.us 1360 : 209 : snprintf(res, 64, "(%d,%d)",
1361 : : numeric_typmod_precision(typmod),
1362 : : numeric_typmod_scale(typmod));
1363 : : else
7066 tgl@sss.pgh.pa.us 1364 :UBC 0 : *res = '\0';
1365 : :
7066 tgl@sss.pgh.pa.us 1366 :CBC 209 : PG_RETURN_CSTRING(res);
1367 : : }
1368 : :
1369 : :
1370 : : /* ----------------------------------------------------------------------
1371 : : *
1372 : : * Sign manipulation, rounding and the like
1373 : : *
1374 : : * ----------------------------------------------------------------------
1375 : : */
1376 : :
1377 : : Datum
9411 1378 : 13004 : numeric_abs(PG_FUNCTION_ARGS)
1379 : : {
1380 : 13004 : Numeric num = PG_GETARG_NUMERIC(0);
1381 : : Numeric res;
1382 : :
1383 : : /*
1384 : : * Do it the easy way directly on the packed format
1385 : : */
2113 1386 : 13004 : res = duplicate_numeric(num);
1387 : :
5754 rhaas@postgresql.org 1388 [ + + ]: 13004 : if (NUMERIC_IS_SHORT(num))
1389 : 12960 : res->choice.n_short.n_header =
1390 : 12960 : num->choice.n_short.n_header & ~NUMERIC_SHORT_SIGN_MASK;
2113 tgl@sss.pgh.pa.us 1391 [ + + ]: 44 : else if (NUMERIC_IS_SPECIAL(num))
1392 : : {
1393 : : /* This changes -Inf to Inf, and doesn't affect NaN */
1394 : 12 : res->choice.n_short.n_header =
1395 : 12 : num->choice.n_short.n_header & ~NUMERIC_INF_SIGN_MASK;
1396 : : }
1397 : : else
5754 rhaas@postgresql.org 1398 [ - + ]: 32 : res->choice.n_long.n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
1399 : :
9411 tgl@sss.pgh.pa.us 1400 : 13004 : PG_RETURN_NUMERIC(res);
1401 : : }
1402 : :
1403 : :
1404 : : Datum
1405 : 623 : numeric_uminus(PG_FUNCTION_ARGS)
1406 : : {
1407 : 623 : Numeric num = PG_GETARG_NUMERIC(0);
1408 : : Numeric res;
1409 : :
1410 : : /*
1411 : : * Do it the easy way directly on the packed format
1412 : : */
2113 1413 : 623 : res = duplicate_numeric(num);
1414 : :
1415 [ + + ]: 623 : if (NUMERIC_IS_SPECIAL(num))
1416 : : {
1417 : : /* Flip the sign, if it's Inf or -Inf */
1418 [ + + ]: 84 : if (!NUMERIC_IS_NAN(num))
1419 : 56 : res->choice.n_short.n_header =
1420 : 56 : num->choice.n_short.n_header ^ NUMERIC_INF_SIGN_MASK;
1421 : : }
1422 : :
1423 : : /*
1424 : : * The packed format is known to be totally zero digit trimmed always. So
1425 : : * once we've eliminated specials, we can identify a zero by the fact that
1426 : : * there are no digits at all. Do nothing to a zero.
1427 : : */
1428 [ + - + + ]: 539 : else if (NUMERIC_NDIGITS(num) != 0)
1429 : : {
1430 : : /* Else, flip the sign */
5754 rhaas@postgresql.org 1431 [ + - ]: 463 : if (NUMERIC_IS_SHORT(num))
1432 : 463 : res->choice.n_short.n_header =
1433 : 463 : num->choice.n_short.n_header ^ NUMERIC_SHORT_SIGN_MASK;
5754 rhaas@postgresql.org 1434 [ # # # # :UBC 0 : else if (NUMERIC_SIGN(num) == NUMERIC_POS)
# # ]
1435 : 0 : res->choice.n_long.n_sign_dscale =
1436 [ # # ]: 0 : NUMERIC_NEG | NUMERIC_DSCALE(num);
1437 : : else
1438 : 0 : res->choice.n_long.n_sign_dscale =
1439 [ # # ]: 0 : NUMERIC_POS | NUMERIC_DSCALE(num);
1440 : : }
1441 : :
9411 tgl@sss.pgh.pa.us 1442 :CBC 623 : PG_RETURN_NUMERIC(res);
1443 : : }
1444 : :
1445 : :
1446 : : Datum
9098 bruce@momjian.us 1447 :LBC (249) : numeric_uplus(PG_FUNCTION_ARGS)
1448 : : {
1449 : (249) : Numeric num = PG_GETARG_NUMERIC(0);
1450 : :
2113 tgl@sss.pgh.pa.us 1451 : (249) : PG_RETURN_NUMERIC(duplicate_numeric(num));
1452 : : }
1453 : :
1454 : :
1455 : : /*
1456 : : * numeric_sign_internal() -
1457 : : *
1458 : : * Returns -1 if the argument is less than 0, 0 if the argument is equal
1459 : : * to 0, and 1 if the argument is greater than zero. Caller must have
1460 : : * taken care of the NaN case, but we can handle infinities here.
1461 : : */
1462 : : static int
2113 tgl@sss.pgh.pa.us 1463 :CBC 2476 : numeric_sign_internal(Numeric num)
1464 : : {
1465 [ + + ]: 2476 : if (NUMERIC_IS_SPECIAL(num))
1466 : : {
1467 [ - + ]: 223 : Assert(!NUMERIC_IS_NAN(num));
1468 : : /* Must be Inf or -Inf */
1469 [ + + ]: 223 : if (NUMERIC_IS_PINF(num))
1470 : 129 : return 1;
1471 : : else
1472 : 94 : return -1;
1473 : : }
1474 : :
1475 : : /*
1476 : : * The packed format is known to be totally zero digit trimmed always. So
1477 : : * once we've eliminated specials, we can identify a zero by the fact that
1478 : : * there are no digits at all.
1479 : : */
1480 [ + + + + ]: 2253 : else if (NUMERIC_NDIGITS(num) == 0)
1481 : 161 : return 0;
1482 [ + + - + : 2092 : else if (NUMERIC_SIGN(num) == NUMERIC_NEG)
+ + ]
1483 : 511 : return -1;
1484 : : else
1485 : 1581 : return 1;
1486 : : }
1487 : :
1488 : : /*
1489 : : * numeric_sign() -
1490 : : *
1491 : : * returns -1 if the argument is less than 0, 0 if the argument is equal
1492 : : * to 0, and 1 if the argument is greater than zero.
1493 : : */
1494 : : Datum
9411 1495 : 32 : numeric_sign(PG_FUNCTION_ARGS)
1496 : : {
1497 : 32 : Numeric num = PG_GETARG_NUMERIC(0);
1498 : :
1499 : : /*
1500 : : * Handle NaN (infinities can be handled normally)
1501 : : */
9988 JanWieck@Yahoo.com 1502 [ + + ]: 32 : if (NUMERIC_IS_NAN(num))
9411 tgl@sss.pgh.pa.us 1503 : 4 : PG_RETURN_NUMERIC(make_result(&const_nan));
1504 : :
2113 1505 [ + + + - ]: 28 : switch (numeric_sign_internal(num))
1506 : : {
1507 : 4 : case 0:
1508 : 4 : PG_RETURN_NUMERIC(make_result(&const_zero));
1509 : 12 : case 1:
1510 : 12 : PG_RETURN_NUMERIC(make_result(&const_one));
1511 : 12 : case -1:
1512 : 12 : PG_RETURN_NUMERIC(make_result(&const_minus_one));
1513 : : }
1514 : :
2113 tgl@sss.pgh.pa.us 1515 :UBC 0 : Assert(false);
1516 : : return (Datum) 0;
1517 : : }
1518 : :
1519 : :
1520 : : /*
1521 : : * numeric_round() -
1522 : : *
1523 : : * Round a value to have 'scale' digits after the decimal point.
1524 : : * We allow negative 'scale', implying rounding before the decimal
1525 : : * point --- Oracle interprets rounding that way.
1526 : : */
1527 : : Datum
9457 tgl@sss.pgh.pa.us 1528 :CBC 5217 : numeric_round(PG_FUNCTION_ARGS)
1529 : : {
1530 : 5217 : Numeric num = PG_GETARG_NUMERIC(0);
1531 : 5217 : int32 scale = PG_GETARG_INT32(1);
1532 : : Numeric res;
1533 : : NumericVar arg;
1534 : :
1535 : : /*
1536 : : * Handle NaN and infinities
1537 : : */
2113 1538 [ + + ]: 5217 : if (NUMERIC_IS_SPECIAL(num))
1539 : 64 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1540 : :
1541 : : /*
1542 : : * Limit the scale value to avoid possible overflow in calculations.
1543 : : *
1544 : : * These limits are based on the maximum number of digits a Numeric value
1545 : : * can have before and after the decimal point, but we must allow for one
1546 : : * extra digit before the decimal point, in case the most significant
1547 : : * digit rounds up; we must check if that causes Numeric overflow.
1548 : : */
666 dean.a.rasheed@gmail 1549 : 5153 : scale = Max(scale, -(NUMERIC_WEIGHT_MAX + 1) * DEC_DIGITS - 1);
1550 : 5153 : scale = Min(scale, NUMERIC_DSCALE_MAX);
1551 : :
1552 : : /*
1553 : : * Unpack the argument and round it at the proper digit position
1554 : : */
9549 tgl@sss.pgh.pa.us 1555 : 5153 : init_var(&arg);
1556 : 5153 : set_var_from_num(num, &arg);
1557 : :
8446 1558 : 5153 : round_var(&arg, scale);
1559 : :
1560 : : /* We don't allow negative output dscale */
1561 [ + + ]: 5153 : if (scale < 0)
1562 : 149 : arg.dscale = 0;
1563 : :
1564 : : /*
1565 : : * Return the rounded result
1566 : : */
9549 1567 : 5153 : res = make_result(&arg);
1568 : :
1569 : 5149 : free_var(&arg);
9457 1570 : 5149 : PG_RETURN_NUMERIC(res);
1571 : : }
1572 : :
1573 : :
1574 : : /*
1575 : : * numeric_trunc() -
1576 : : *
1577 : : * Truncate a value to have 'scale' digits after the decimal point.
1578 : : * We allow negative 'scale', implying a truncation before the decimal
1579 : : * point --- Oracle interprets truncation that way.
1580 : : */
1581 : : Datum
1582 : 442 : numeric_trunc(PG_FUNCTION_ARGS)
1583 : : {
1584 : 442 : Numeric num = PG_GETARG_NUMERIC(0);
1585 : 442 : int32 scale = PG_GETARG_INT32(1);
1586 : : Numeric res;
1587 : : NumericVar arg;
1588 : :
1589 : : /*
1590 : : * Handle NaN and infinities
1591 : : */
2113 1592 [ + + ]: 442 : if (NUMERIC_IS_SPECIAL(num))
1593 : 24 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1594 : :
1595 : : /*
1596 : : * Limit the scale value to avoid possible overflow in calculations.
1597 : : *
1598 : : * These limits are based on the maximum number of digits a Numeric value
1599 : : * can have before and after the decimal point.
1600 : : */
666 dean.a.rasheed@gmail 1601 : 418 : scale = Max(scale, -(NUMERIC_WEIGHT_MAX + 1) * DEC_DIGITS);
1602 : 418 : scale = Min(scale, NUMERIC_DSCALE_MAX);
1603 : :
1604 : : /*
1605 : : * Unpack the argument and truncate it at the proper digit position
1606 : : */
9988 JanWieck@Yahoo.com 1607 : 418 : init_var(&arg);
1608 : 418 : set_var_from_num(num, &arg);
1609 : :
8446 tgl@sss.pgh.pa.us 1610 : 418 : trunc_var(&arg, scale);
1611 : :
1612 : : /* We don't allow negative output dscale */
1613 [ + + ]: 418 : if (scale < 0)
1614 : 20 : arg.dscale = 0;
1615 : :
1616 : : /*
1617 : : * Return the truncated result
1618 : : */
9988 JanWieck@Yahoo.com 1619 : 418 : res = make_result(&arg);
1620 : :
1621 : 418 : free_var(&arg);
9457 tgl@sss.pgh.pa.us 1622 : 418 : PG_RETURN_NUMERIC(res);
1623 : : }
1624 : :
1625 : :
1626 : : /*
1627 : : * numeric_ceil() -
1628 : : *
1629 : : * Return the smallest integer greater than or equal to the argument
1630 : : */
1631 : : Datum
9411 1632 : 148 : numeric_ceil(PG_FUNCTION_ARGS)
1633 : : {
1634 : 148 : Numeric num = PG_GETARG_NUMERIC(0);
1635 : : Numeric res;
1636 : : NumericVar result;
1637 : :
1638 : : /*
1639 : : * Handle NaN and infinities
1640 : : */
2113 1641 [ + + ]: 148 : if (NUMERIC_IS_SPECIAL(num))
1642 : 12 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1643 : :
4913 heikki.linnakangas@i 1644 : 136 : init_var_from_num(num, &result);
9988 JanWieck@Yahoo.com 1645 : 136 : ceil_var(&result, &result);
1646 : :
1647 : 136 : res = make_result(&result);
1648 : 136 : free_var(&result);
1649 : :
9411 tgl@sss.pgh.pa.us 1650 : 136 : PG_RETURN_NUMERIC(res);
1651 : : }
1652 : :
1653 : :
1654 : : /*
1655 : : * numeric_floor() -
1656 : : *
1657 : : * Return the largest integer equal to or less than the argument
1658 : : */
1659 : : Datum
1660 : 84 : numeric_floor(PG_FUNCTION_ARGS)
1661 : : {
1662 : 84 : Numeric num = PG_GETARG_NUMERIC(0);
1663 : : Numeric res;
1664 : : NumericVar result;
1665 : :
1666 : : /*
1667 : : * Handle NaN and infinities
1668 : : */
2113 1669 [ + + ]: 84 : if (NUMERIC_IS_SPECIAL(num))
1670 : 12 : PG_RETURN_NUMERIC(duplicate_numeric(num));
1671 : :
4913 heikki.linnakangas@i 1672 : 72 : init_var_from_num(num, &result);
9988 JanWieck@Yahoo.com 1673 : 72 : floor_var(&result, &result);
1674 : :
1675 : 72 : res = make_result(&result);
1676 : 72 : free_var(&result);
1677 : :
9411 tgl@sss.pgh.pa.us 1678 : 72 : PG_RETURN_NUMERIC(res);
1679 : : }
1680 : :
1681 : :
1682 : : /*
1683 : : * generate_series_numeric() -
1684 : : *
1685 : : * Generate series of numeric.
1686 : : */
1687 : : Datum
4193 fujii@postgresql.org 1688 : 80256 : generate_series_numeric(PG_FUNCTION_ARGS)
1689 : : {
1690 : 80256 : return generate_series_step_numeric(fcinfo);
1691 : : }
1692 : :
1693 : : Datum
1694 : 80556 : generate_series_step_numeric(PG_FUNCTION_ARGS)
1695 : : {
1696 : : generate_series_numeric_fctx *fctx;
1697 : : FuncCallContext *funcctx;
1698 : : MemoryContext oldcontext;
1699 : :
1700 [ + + ]: 80556 : if (SRF_IS_FIRSTCALL())
1701 : : {
1702 : 116 : Numeric start_num = PG_GETARG_NUMERIC(0);
1703 : 116 : Numeric stop_num = PG_GETARG_NUMERIC(1);
1704 : 116 : NumericVar steploc = const_one;
1705 : :
1706 : : /* Reject NaN and infinities in start and stop values */
2113 tgl@sss.pgh.pa.us 1707 [ + + ]: 116 : if (NUMERIC_IS_SPECIAL(start_num))
1708 : : {
1709 [ + + ]: 8 : if (NUMERIC_IS_NAN(start_num))
1710 [ + - ]: 4 : ereport(ERROR,
1711 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1712 : : errmsg("start value cannot be NaN")));
1713 : : else
1714 [ + - ]: 4 : ereport(ERROR,
1715 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1716 : : errmsg("start value cannot be infinity")));
1717 : : }
1718 [ + + ]: 108 : if (NUMERIC_IS_SPECIAL(stop_num))
1719 : : {
1720 [ + + ]: 8 : if (NUMERIC_IS_NAN(stop_num))
1721 [ + - ]: 4 : ereport(ERROR,
1722 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1723 : : errmsg("stop value cannot be NaN")));
1724 : : else
1725 [ + - ]: 4 : ereport(ERROR,
1726 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1727 : : errmsg("stop value cannot be infinity")));
1728 : : }
1729 : :
1730 : : /* see if we were given an explicit step size */
4193 fujii@postgresql.org 1731 [ + + ]: 100 : if (PG_NARGS() == 3)
1732 : : {
4091 tgl@sss.pgh.pa.us 1733 : 48 : Numeric step_num = PG_GETARG_NUMERIC(2);
1734 : :
2113 1735 [ + + ]: 48 : if (NUMERIC_IS_SPECIAL(step_num))
1736 : : {
1737 [ + + ]: 8 : if (NUMERIC_IS_NAN(step_num))
1738 [ + - ]: 4 : ereport(ERROR,
1739 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1740 : : errmsg("step size cannot be NaN")));
1741 : : else
1742 [ + - ]: 4 : ereport(ERROR,
1743 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1744 : : errmsg("step size cannot be infinity")));
1745 : : }
1746 : :
4193 fujii@postgresql.org 1747 : 40 : init_var_from_num(step_num, &steploc);
1748 : :
1749 [ + + ]: 40 : if (cmp_var(&steploc, &const_zero) == 0)
1750 [ + - ]: 4 : ereport(ERROR,
1751 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1752 : : errmsg("step size cannot equal zero")));
1753 : : }
1754 : :
1755 : : /* create a function context for cross-call persistence */
1756 : 88 : funcctx = SRF_FIRSTCALL_INIT();
1757 : :
1758 : : /*
1759 : : * Switch to memory context appropriate for multiple function calls.
1760 : : */
1761 : 88 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1762 : :
1763 : : /* allocate memory for user context */
146 michael@paquier.xyz 1764 :GNC 88 : fctx = palloc_object(generate_series_numeric_fctx);
1765 : :
1766 : : /*
1767 : : * Use fctx to keep state from call to call. Seed current with the
1768 : : * original start value. We must copy the start_num and stop_num
1769 : : * values rather than pointing to them, since we may have detoasted
1770 : : * them in the per-call context.
1771 : : */
4156 fujii@postgresql.org 1772 :CBC 88 : init_var(&fctx->current);
1773 : 88 : init_var(&fctx->stop);
4193 1774 : 88 : init_var(&fctx->step);
1775 : :
4156 1776 : 88 : set_var_from_num(start_num, &fctx->current);
1777 : 88 : set_var_from_num(stop_num, &fctx->stop);
4193 1778 : 88 : set_var_from_var(&steploc, &fctx->step);
1779 : :
1780 : 88 : funcctx->user_fctx = fctx;
1781 : 88 : MemoryContextSwitchTo(oldcontext);
1782 : : }
1783 : :
1784 : : /* stuff done on every call of the function */
1785 : 80528 : funcctx = SRF_PERCALL_SETUP();
1786 : :
1787 : : /*
1788 : : * Get the saved state and use current state as the result of this
1789 : : * iteration.
1790 : : */
1791 : 80528 : fctx = funcctx->user_fctx;
1792 : :
1793 [ + + + + ]: 160936 : if ((fctx->step.sign == NUMERIC_POS &&
1794 : 80408 : cmp_var(&fctx->current, &fctx->stop) <= 0) ||
1795 [ + + + + ]: 320 : (fctx->step.sign == NUMERIC_NEG &&
1796 : 120 : cmp_var(&fctx->current, &fctx->stop) >= 0))
1797 : : {
4091 tgl@sss.pgh.pa.us 1798 : 80440 : Numeric result = make_result(&fctx->current);
1799 : :
1800 : : /* switch to memory context appropriate for iteration calculation */
4193 fujii@postgresql.org 1801 : 80440 : oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1802 : :
1803 : : /* increment current in preparation for next iteration */
1804 : 80440 : add_var(&fctx->current, &fctx->step, &fctx->current);
1805 : 80440 : MemoryContextSwitchTo(oldcontext);
1806 : :
1807 : : /* do when there is more left to send */
1808 : 80440 : SRF_RETURN_NEXT(funcctx, NumericGetDatum(result));
1809 : : }
1810 : : else
1811 : : /* do when there is no more left */
1812 : 88 : SRF_RETURN_DONE(funcctx);
1813 : : }
1814 : :
1815 : : /*
1816 : : * Planner support function for generate_series(numeric, numeric [, numeric])
1817 : : */
1818 : : Datum
519 dean.a.rasheed@gmail 1819 : 535 : generate_series_numeric_support(PG_FUNCTION_ARGS)
1820 : : {
1821 : 535 : Node *rawreq = (Node *) PG_GETARG_POINTER(0);
1822 : 535 : Node *ret = NULL;
1823 : :
1824 [ + + ]: 535 : if (IsA(rawreq, SupportRequestRows))
1825 : : {
1826 : : /* Try to estimate the number of rows returned */
1827 : 130 : SupportRequestRows *req = (SupportRequestRows *) rawreq;
1828 : :
1829 [ + - ]: 130 : if (is_funcclause(req->node)) /* be paranoid */
1830 : : {
1831 : 130 : List *args = ((FuncExpr *) req->node)->args;
1832 : : Node *arg1,
1833 : : *arg2,
1834 : : *arg3;
1835 : :
1836 : : /* We can use estimated argument values here */
1837 : 130 : arg1 = estimate_expression_value(req->root, linitial(args));
1838 : 130 : arg2 = estimate_expression_value(req->root, lsecond(args));
1839 [ + + ]: 130 : if (list_length(args) >= 3)
1840 : 85 : arg3 = estimate_expression_value(req->root, lthird(args));
1841 : : else
1842 : 45 : arg3 = NULL;
1843 : :
1844 : : /*
1845 : : * If any argument is constant NULL, we can safely assume that
1846 : : * zero rows are returned. Otherwise, if they're all non-NULL
1847 : : * constants, we can calculate the number of rows that will be
1848 : : * returned.
1849 : : */
1850 [ + + ]: 130 : if ((IsA(arg1, Const) &&
1851 [ + - ]: 125 : ((Const *) arg1)->constisnull) ||
1852 [ + + ]: 130 : (IsA(arg2, Const) &&
1853 [ + - + + ]: 130 : ((Const *) arg2)->constisnull) ||
1854 [ + + ]: 85 : (arg3 != NULL && IsA(arg3, Const) &&
1855 [ - + ]: 80 : ((Const *) arg3)->constisnull))
1856 : : {
519 dean.a.rasheed@gmail 1857 :UBC 0 : req->rows = 0;
1858 : 0 : ret = (Node *) req;
1859 : : }
519 dean.a.rasheed@gmail 1860 [ + + ]:CBC 130 : else if (IsA(arg1, Const) &&
1861 [ + + + + ]: 125 : IsA(arg2, Const) &&
1862 [ + + ]: 85 : (arg3 == NULL || IsA(arg3, Const)))
1863 : : {
1864 : : Numeric start_num;
1865 : : Numeric stop_num;
1866 : 115 : NumericVar step = const_one;
1867 : :
1868 : : /*
1869 : : * If any argument is NaN or infinity, generate_series() will
1870 : : * error out, so we needn't produce an estimate.
1871 : : */
1872 : 115 : start_num = DatumGetNumeric(((Const *) arg1)->constvalue);
1873 : 115 : stop_num = DatumGetNumeric(((Const *) arg2)->constvalue);
1874 : :
1875 [ + + ]: 115 : if (NUMERIC_IS_SPECIAL(start_num) ||
1876 [ + + ]: 100 : NUMERIC_IS_SPECIAL(stop_num))
1877 : 40 : PG_RETURN_POINTER(NULL);
1878 : :
1879 [ + + ]: 90 : if (arg3)
1880 : : {
1881 : : Numeric step_num;
1882 : :
1883 : 55 : step_num = DatumGetNumeric(((Const *) arg3)->constvalue);
1884 : :
1885 [ + + ]: 55 : if (NUMERIC_IS_SPECIAL(step_num))
1886 : 15 : PG_RETURN_POINTER(NULL);
1887 : :
1888 : 40 : init_var_from_num(step_num, &step);
1889 : : }
1890 : :
1891 : : /*
1892 : : * The number of rows that will be returned is given by
1893 : : * floor((stop - start) / step) + 1, if the sign of step
1894 : : * matches the sign of stop - start. Otherwise, no rows will
1895 : : * be returned.
1896 : : */
1897 [ + + ]: 75 : if (cmp_var(&step, &const_zero) != 0)
1898 : : {
1899 : : NumericVar start;
1900 : : NumericVar stop;
1901 : : NumericVar res;
1902 : :
1903 : 65 : init_var_from_num(start_num, &start);
1904 : 65 : init_var_from_num(stop_num, &stop);
1905 : :
1906 : 65 : init_var(&res);
1907 : 65 : sub_var(&stop, &start, &res);
1908 : :
1909 [ + + ]: 65 : if (step.sign != res.sign)
1910 : : {
1911 : : /* no rows will be returned */
1912 : 5 : req->rows = 0;
1913 : 5 : ret = (Node *) req;
1914 : : }
1915 : : else
1916 : : {
1917 [ + + ]: 60 : if (arg3)
1918 : 25 : div_var(&res, &step, &res, 0, false, false);
1919 : : else
1920 : 35 : trunc_var(&res, 0); /* step = 1 */
1921 : :
1922 : 60 : req->rows = numericvar_to_double_no_overflow(&res) + 1;
1923 : 60 : ret = (Node *) req;
1924 : : }
1925 : :
1926 : 65 : free_var(&res);
1927 : : }
1928 : : }
1929 : : }
1930 : : }
1931 : :
1932 : 495 : PG_RETURN_POINTER(ret);
1933 : : }
1934 : :
1935 : :
1936 : : /*
1937 : : * Implements the numeric version of the width_bucket() function
1938 : : * defined by SQL2003. See also width_bucket_float8().
1939 : : *
1940 : : * 'bound1' and 'bound2' are the lower and upper bounds of the
1941 : : * histogram's range, respectively. 'count' is the number of buckets
1942 : : * in the histogram. width_bucket() returns an integer indicating the
1943 : : * bucket number that 'operand' belongs to in an equiwidth histogram
1944 : : * with the specified characteristics. An operand smaller than the
1945 : : * lower bound is assigned to bucket 0. An operand greater than or equal
1946 : : * to the upper bound is assigned to an additional bucket (with number
1947 : : * count+1). We don't allow the histogram bounds to be NaN or +/- infinity,
1948 : : * but we do allow those values for the operand (taking NaN to be larger
1949 : : * than any other value, as we do in comparisons).
1950 : : */
1951 : : Datum
8026 neilc@samurai.com 1952 : 529 : width_bucket_numeric(PG_FUNCTION_ARGS)
1953 : : {
1954 : 529 : Numeric operand = PG_GETARG_NUMERIC(0);
1955 : 529 : Numeric bound1 = PG_GETARG_NUMERIC(1);
1956 : 529 : Numeric bound2 = PG_GETARG_NUMERIC(2);
1957 : 529 : int32 count = PG_GETARG_INT32(3);
1958 : : NumericVar count_var;
1959 : : NumericVar result_var;
1960 : : int32 result;
1961 : :
1962 [ + + ]: 529 : if (count <= 0)
1963 [ + - ]: 8 : ereport(ERROR,
1964 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
1965 : : errmsg("count must be greater than zero")));
1966 : :
307 tgl@sss.pgh.pa.us 1967 [ + + + + ]:GNC 521 : if (NUMERIC_IS_SPECIAL(bound1) || NUMERIC_IS_SPECIAL(bound2))
1968 : : {
1969 [ + + - + ]: 16 : if (NUMERIC_IS_NAN(bound1) || NUMERIC_IS_NAN(bound2))
2113 tgl@sss.pgh.pa.us 1970 [ + - ]:CBC 4 : ereport(ERROR,
1971 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
1972 : : errmsg("lower and upper bounds cannot be NaN")));
1973 : :
2035 1974 [ + + + - ]: 12 : if (NUMERIC_IS_INF(bound1) || NUMERIC_IS_INF(bound2))
2113 1975 [ + - ]: 12 : ereport(ERROR,
1976 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
1977 : : errmsg("lower and upper bounds must be finite")));
1978 : : }
1979 : :
8026 neilc@samurai.com 1980 : 505 : init_var(&result_var);
1981 : 505 : init_var(&count_var);
1982 : :
1983 : : /* Convert 'count' to a numeric, for ease of use later */
4064 andres@anarazel.de 1984 : 505 : int64_to_numericvar((int64) count, &count_var);
1985 : :
8026 neilc@samurai.com 1986 [ + + + - ]: 505 : switch (cmp_numerics(bound1, bound2))
1987 : : {
1988 : 4 : case 0:
1989 [ + - ]: 4 : ereport(ERROR,
1990 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
1991 : : errmsg("lower bound cannot equal upper bound")));
1992 : : break;
1993 : :
1994 : : /* bound1 < bound2 */
1995 : 372 : case -1:
1996 [ + + ]: 372 : if (cmp_numerics(operand, bound1) < 0)
1997 : 77 : set_var_from_var(&const_zero, &result_var);
1998 [ + + ]: 295 : else if (cmp_numerics(operand, bound2) >= 0)
1999 : 78 : add_var(&count_var, &const_one, &result_var);
2000 : : else
664 dean.a.rasheed@gmail 2001 : 217 : compute_bucket(operand, bound1, bound2, &count_var,
2002 : : &result_var);
8026 neilc@samurai.com 2003 : 372 : break;
2004 : :
2005 : : /* bound1 > bound2 */
2006 : 129 : case 1:
2007 [ + + ]: 129 : if (cmp_numerics(operand, bound1) > 0)
2008 : 8 : set_var_from_var(&const_zero, &result_var);
2009 [ + + ]: 121 : else if (cmp_numerics(operand, bound2) <= 0)
2010 : 16 : add_var(&count_var, &const_one, &result_var);
2011 : : else
664 dean.a.rasheed@gmail 2012 : 105 : compute_bucket(operand, bound1, bound2, &count_var,
2013 : : &result_var);
8026 neilc@samurai.com 2014 : 129 : break;
2015 : : }
2016 : :
2017 : : /* if result exceeds the range of a legal int4, we ereport here */
2607 akorotkov@postgresql 2018 [ - + ]: 501 : if (!numericvar_to_int32(&result_var, &result))
2607 akorotkov@postgresql 2019 [ # # ]:UBC 0 : ereport(ERROR,
2020 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
2021 : : errmsg("integer out of range")));
2022 : :
8026 neilc@samurai.com 2023 :CBC 501 : free_var(&count_var);
2024 : 501 : free_var(&result_var);
2025 : :
2026 : 501 : PG_RETURN_INT32(result);
2027 : : }
2028 : :
2029 : : /*
2030 : : * 'operand' is inside the bucket range, so determine the correct
2031 : : * bucket for it to go in. The calculations performed by this function
2032 : : * are derived directly from the SQL2003 spec. Note however that we
2033 : : * multiply by count before dividing, to avoid unnecessary roundoff error.
2034 : : */
2035 : : static void
2036 : 322 : compute_bucket(Numeric operand, Numeric bound1, Numeric bound2,
2037 : : const NumericVar *count_var, NumericVar *result_var)
2038 : : {
2039 : : NumericVar bound1_var;
2040 : : NumericVar bound2_var;
2041 : : NumericVar operand_var;
2042 : :
4913 heikki.linnakangas@i 2043 : 322 : init_var_from_num(bound1, &bound1_var);
2044 : 322 : init_var_from_num(bound2, &bound2_var);
2045 : 322 : init_var_from_num(operand, &operand_var);
2046 : :
2047 : : /*
2048 : : * Per spec, bound1 is inclusive and bound2 is exclusive, and so we have
2049 : : * bound1 <= operand < bound2 or bound1 >= operand > bound2. Either way,
2050 : : * the result is ((operand - bound1) * count) / (bound2 - bound1) + 1,
2051 : : * where the quotient is computed using floor division (i.e., division to
2052 : : * zero decimal places with truncation), which guarantees that the result
2053 : : * is in the range [1, count]. Reversing the bounds doesn't affect the
2054 : : * computation, because the signs cancel out when dividing.
2055 : : */
664 dean.a.rasheed@gmail 2056 : 322 : sub_var(&operand_var, &bound1_var, &operand_var);
2057 : 322 : sub_var(&bound2_var, &bound1_var, &bound2_var);
2058 : :
2035 tgl@sss.pgh.pa.us 2059 : 322 : mul_var(&operand_var, count_var, &operand_var,
2060 : 322 : operand_var.dscale + count_var->dscale);
578 dean.a.rasheed@gmail 2061 : 322 : div_var(&operand_var, &bound2_var, result_var, 0, false, true);
664 2062 : 322 : add_var(result_var, &const_one, result_var);
2063 : :
8026 neilc@samurai.com 2064 : 322 : free_var(&bound1_var);
2065 : 322 : free_var(&bound2_var);
2066 : 322 : free_var(&operand_var);
7919 bruce@momjian.us 2067 : 322 : }
2068 : :
2069 : : /* ----------------------------------------------------------------------
2070 : : *
2071 : : * Comparison functions
2072 : : *
2073 : : * Note: btree indexes need these routines not to leak memory; therefore,
2074 : : * be careful to free working copies of toasted datums. Most places don't
2075 : : * need to be so careful.
2076 : : *
2077 : : * Sort support:
2078 : : *
2079 : : * We implement the sortsupport strategy routine in order to get the benefit of
2080 : : * abbreviation. The ordinary numeric comparison can be quite slow as a result
2081 : : * of palloc/pfree cycles (due to detoasting packed values for alignment);
2082 : : * while this could be worked on itself, the abbreviation strategy gives more
2083 : : * speedup in many common cases.
2084 : : *
2085 : : * The abbreviated format is an int64. The representation is negated relative
2086 : : * to the original value, because we use the largest negative value for NaN,
2087 : : * which sorts higher than other values. We convert the absolute value of the
2088 : : * numeric to a 63-bit positive value, and then negate it if the original
2089 : : * number was positive.
2090 : : *
2091 : : * We abort the abbreviation process if the abbreviation cardinality is below
2092 : : * 0.01% of the row count (1 per 10k non-null rows). The actual break-even
2093 : : * point is somewhat below that, perhaps 1 per 30k (at 1 per 100k there's a
2094 : : * very small penalty), but we don't want to build up too many abbreviated
2095 : : * values before first testing for abort, so we take the slightly pessimistic
2096 : : * number. We make no attempt to estimate the cardinality of the real values,
2097 : : * since it plays no part in the cost model here (if the abbreviation is equal,
2098 : : * the cost of comparing equal and unequal underlying values is comparable).
2099 : : * We discontinue even checking for abort (saving us the hashing overhead) if
2100 : : * the estimated cardinality gets to 100k; that would be enough to support many
2101 : : * billions of rows while doing no worse than breaking even.
2102 : : *
2103 : : * ----------------------------------------------------------------------
2104 : : */
2105 : :
2106 : : /*
2107 : : * Sort support strategy routine.
2108 : : */
2109 : : Datum
4051 rhaas@postgresql.org 2110 : 798 : numeric_sortsupport(PG_FUNCTION_ARGS)
2111 : : {
2112 : 798 : SortSupport ssup = (SortSupport) PG_GETARG_POINTER(0);
2113 : :
2114 : 798 : ssup->comparator = numeric_fast_cmp;
2115 : :
2116 [ + + ]: 798 : if (ssup->abbreviate)
2117 : : {
2118 : : NumericSortSupport *nss;
2119 : 169 : MemoryContext oldcontext = MemoryContextSwitchTo(ssup->ssup_cxt);
2120 : :
146 michael@paquier.xyz 2121 :GNC 169 : nss = palloc_object(NumericSortSupport);
2122 : :
2123 : : /*
2124 : : * palloc a buffer for handling unaligned packed values in addition to
2125 : : * the support struct
2126 : : */
4051 rhaas@postgresql.org 2127 :CBC 169 : nss->buf = palloc(VARATT_SHORT_MAX + VARHDRSZ + 1);
2128 : :
2129 : 169 : nss->input_count = 0;
2130 : 169 : nss->estimating = true;
2131 : 169 : initHyperLogLog(&nss->abbr_card, 10);
2132 : :
2133 : 169 : ssup->ssup_extra = nss;
2134 : :
2135 : 169 : ssup->abbrev_full_comparator = ssup->comparator;
2136 : 169 : ssup->comparator = numeric_cmp_abbrev;
2137 : 169 : ssup->abbrev_converter = numeric_abbrev_convert;
2138 : 169 : ssup->abbrev_abort = numeric_abbrev_abort;
2139 : :
2140 : 169 : MemoryContextSwitchTo(oldcontext);
2141 : : }
2142 : :
2143 : 798 : PG_RETURN_VOID();
2144 : : }
2145 : :
2146 : : /*
2147 : : * Abbreviate a numeric datum, handling NaNs and detoasting
2148 : : * (must not leak memory!)
2149 : : */
2150 : : static Datum
2151 : 12779 : numeric_abbrev_convert(Datum original_datum, SortSupport ssup)
2152 : : {
2153 : 12779 : NumericSortSupport *nss = ssup->ssup_extra;
2154 : 12779 : void *original_varatt = PG_DETOAST_DATUM_PACKED(original_datum);
2155 : : Numeric value;
2156 : : Datum result;
2157 : :
2158 : 12779 : nss->input_count += 1;
2159 : :
2160 : : /*
2161 : : * This is to handle packed datums without needing a palloc/pfree cycle;
2162 : : * we keep and reuse a buffer large enough to handle any short datum.
2163 : : */
2164 [ + + ]: 12779 : if (VARATT_IS_SHORT(original_varatt))
2165 : : {
2166 : 679 : void *buf = nss->buf;
2167 : 679 : Size sz = VARSIZE_SHORT(original_varatt) - VARHDRSZ_SHORT;
2168 : :
2169 [ - + ]: 679 : Assert(sz <= VARATT_SHORT_MAX - VARHDRSZ_SHORT);
2170 : :
2171 : 679 : SET_VARSIZE(buf, VARHDRSZ + sz);
2172 : 679 : memcpy(VARDATA(buf), VARDATA_SHORT(original_varatt), sz);
2173 : :
2174 : 679 : value = (Numeric) buf;
2175 : : }
2176 : : else
2177 : 12100 : value = (Numeric) original_varatt;
2178 : :
2113 tgl@sss.pgh.pa.us 2179 [ + + ]: 12779 : if (NUMERIC_IS_SPECIAL(value))
2180 : : {
2181 [ + + ]: 100 : if (NUMERIC_IS_PINF(value))
2182 : 32 : result = NUMERIC_ABBREV_PINF;
2183 [ + + ]: 68 : else if (NUMERIC_IS_NINF(value))
2184 : 32 : result = NUMERIC_ABBREV_NINF;
2185 : : else
2186 : 36 : result = NUMERIC_ABBREV_NAN;
2187 : : }
2188 : : else
2189 : : {
2190 : : NumericVar var;
2191 : :
4051 rhaas@postgresql.org 2192 : 12679 : init_var_from_num(value, &var);
2193 : :
2194 : 12679 : result = numeric_abbrev_convert_var(&var, nss);
2195 : : }
2196 : :
2197 : : /* should happen only for external/compressed toasts */
152 peter@eisentraut.org 2198 [ - + ]:GNC 12779 : if (original_varatt != DatumGetPointer(original_datum))
4051 rhaas@postgresql.org 2199 :UBC 0 : pfree(original_varatt);
2200 : :
4051 rhaas@postgresql.org 2201 :CBC 12779 : return result;
2202 : : }
2203 : :
2204 : : /*
2205 : : * Consider whether to abort abbreviation.
2206 : : *
2207 : : * We pay no attention to the cardinality of the non-abbreviated data. There is
2208 : : * no reason to do so: unlike text, we have no fast check for equal values, so
2209 : : * we pay the full overhead whenever the abbreviations are equal regardless of
2210 : : * whether the underlying values are also equal.
2211 : : */
2212 : : static bool
2213 : 96 : numeric_abbrev_abort(int memtupcount, SortSupport ssup)
2214 : : {
2215 : 96 : NumericSortSupport *nss = ssup->ssup_extra;
2216 : : double abbr_card;
2217 : :
2218 [ - + - - : 96 : if (memtupcount < 10000 || nss->input_count < 10000 || !nss->estimating)
- - ]
2219 : 96 : return false;
2220 : :
4051 rhaas@postgresql.org 2221 :UBC 0 : abbr_card = estimateHyperLogLog(&nss->abbr_card);
2222 : :
2223 : : /*
2224 : : * If we have >100k distinct values, then even if we were sorting many
2225 : : * billion rows we'd likely still break even, and the penalty of undoing
2226 : : * that many rows of abbrevs would probably not be worth it. Stop even
2227 : : * counting at that point.
2228 : : */
2229 [ # # ]: 0 : if (abbr_card > 100000.0)
2230 : : {
2231 [ # # ]: 0 : if (trace_sort)
2232 [ # # ]: 0 : elog(LOG,
2233 : : "numeric_abbrev: estimation ends at cardinality %f"
2234 : : " after " INT64_FORMAT " values (%d rows)",
2235 : : abbr_card, nss->input_count, memtupcount);
2236 : 0 : nss->estimating = false;
2237 : 0 : return false;
2238 : : }
2239 : :
2240 : : /*
2241 : : * Target minimum cardinality is 1 per ~10k of non-null inputs. (The
2242 : : * break even point is somewhere between one per 100k rows, where
2243 : : * abbreviation has a very slight penalty, and 1 per 10k where it wins by
2244 : : * a measurable percentage.) We use the relatively pessimistic 10k
2245 : : * threshold, and add a 0.5 row fudge factor, because it allows us to
2246 : : * abort earlier on genuinely pathological data where we've had exactly
2247 : : * one abbreviated value in the first 10k (non-null) rows.
2248 : : */
2249 [ # # ]: 0 : if (abbr_card < nss->input_count / 10000.0 + 0.5)
2250 : : {
2251 [ # # ]: 0 : if (trace_sort)
2252 [ # # ]: 0 : elog(LOG,
2253 : : "numeric_abbrev: aborting abbreviation at cardinality %f"
2254 : : " below threshold %f after " INT64_FORMAT " values (%d rows)",
2255 : : abbr_card, nss->input_count / 10000.0 + 0.5,
2256 : : nss->input_count, memtupcount);
2257 : 0 : return true;
2258 : : }
2259 : :
2260 [ # # ]: 0 : if (trace_sort)
2261 [ # # ]: 0 : elog(LOG,
2262 : : "numeric_abbrev: cardinality %f"
2263 : : " after " INT64_FORMAT " values (%d rows)",
2264 : : abbr_card, nss->input_count, memtupcount);
2265 : :
2266 : 0 : return false;
2267 : : }
2268 : :
2269 : : /*
2270 : : * Non-fmgr interface to the comparison routine to allow sortsupport to elide
2271 : : * the fmgr call. The saving here is small given how slow numeric comparisons
2272 : : * are, but it is a required part of the sort support API when abbreviations
2273 : : * are performed.
2274 : : *
2275 : : * Two palloc/pfree cycles could be saved here by using persistent buffers for
2276 : : * aligning short-varlena inputs, but this has not so far been considered to
2277 : : * be worth the effort.
2278 : : */
2279 : : static int
4051 rhaas@postgresql.org 2280 :CBC 17325437 : numeric_fast_cmp(Datum x, Datum y, SortSupport ssup)
2281 : : {
2282 : 17325437 : Numeric nx = DatumGetNumeric(x);
2283 : 17325437 : Numeric ny = DatumGetNumeric(y);
2284 : : int result;
2285 : :
2286 : 17325437 : result = cmp_numerics(nx, ny);
2287 : :
152 peter@eisentraut.org 2288 [ + + ]:GNC 17325437 : if (nx != DatumGetPointer(x))
4051 rhaas@postgresql.org 2289 :CBC 7429456 : pfree(nx);
152 peter@eisentraut.org 2290 [ + + ]:GNC 17325437 : if (ny != DatumGetPointer(y))
4051 rhaas@postgresql.org 2291 :CBC 7429452 : pfree(ny);
2292 : :
2293 : 17325437 : return result;
2294 : : }
2295 : :
2296 : : /*
2297 : : * Compare abbreviations of values. (Abbreviations may be equal where the true
2298 : : * values differ, but if the abbreviations differ, they must reflect the
2299 : : * ordering of the true values.)
2300 : : */
2301 : : static int
2302 : 125322 : numeric_cmp_abbrev(Datum x, Datum y, SortSupport ssup)
2303 : : {
2304 : : /*
2305 : : * NOTE WELL: this is intentionally backwards, because the abbreviation is
2306 : : * negated relative to the original value, to handle NaN/infinity cases.
2307 : : */
2308 [ + + ]: 125322 : if (DatumGetNumericAbbrev(x) < DatumGetNumericAbbrev(y))
2309 : 65051 : return 1;
2310 [ + + ]: 60271 : if (DatumGetNumericAbbrev(x) > DatumGetNumericAbbrev(y))
2311 : 60124 : return -1;
2312 : 147 : return 0;
2313 : : }
2314 : :
2315 : : /*
2316 : : * Abbreviate a NumericVar into the 64-bit sortsupport size.
2317 : : *
2318 : : * The 31-bit value is constructed as:
2319 : : *
2320 : : * 0 + 7bits digit weight + 24 bits digit value
2321 : : *
2322 : : * where the digit weight is in single decimal digits, not digit words, and
2323 : : * stored in excess-44 representation[1]. The 24-bit digit value is the 7 most
2324 : : * significant decimal digits of the value converted to binary. Values whose
2325 : : * weights would fall outside the representable range are rounded off to zero
2326 : : * (which is also used to represent actual zeros) or to 0x7FFFFFFF (which
2327 : : * otherwise cannot occur). Abbreviation therefore fails to gain any advantage
2328 : : * where values are outside the range 10^-44 to 10^83, which is not considered
2329 : : * to be a serious limitation, or when values are of the same magnitude and
2330 : : * equal in the first 7 decimal digits, which is considered to be an
2331 : : * unavoidable limitation given the available bits. (Stealing three more bits
2332 : : * to compare another digit would narrow the range of representable weights by
2333 : : * a factor of 8, which starts to look like a real limiting factor.)
2334 : : *
2335 : : * (The value 44 for the excess is essentially arbitrary)
2336 : : *
2337 : : * The 63-bit value is constructed as:
2338 : : *
2339 : : * 0 + 7bits weight + 4 x 14-bit packed digit words
2340 : : *
2341 : : * The weight in this case is again stored in excess-44, but this time it is
2342 : : * the original weight in digit words (i.e. powers of 10000). The first four
2343 : : * digit words of the value (if present; trailing zeros are assumed as needed)
2344 : : * are packed into 14 bits each to form the rest of the value. Again,
2345 : : * out-of-range values are rounded off to 0 or 0x7FFFFFFFFFFFFFFF. The
2346 : : * representable range in this case is 10^-176 to 10^332, which is considered
2347 : : * to be good enough for all practical purposes, and comparison of 4 words
2348 : : * means that at least 13 decimal digits are compared, which is considered to
2349 : : * be a reasonable compromise between effectiveness and efficiency in computing
2350 : : * the abbreviation.
2351 : : *
2352 : : * (The value 44 for the excess is even more arbitrary here, it was chosen just
2353 : : * to match the value used in the 31-bit case)
2354 : : *
2355 : : * [1] - Excess-k representation means that the value is offset by adding 'k'
2356 : : * and then treated as unsigned, so the smallest representable value is stored
2357 : : * with all bits zero. This allows simple comparisons to work on the composite
2358 : : * value.
2359 : : */
2360 : : static Datum
3159 andres@anarazel.de 2361 : 12679 : numeric_abbrev_convert_var(const NumericVar *var, NumericSortSupport *nss)
2362 : : {
4051 rhaas@postgresql.org 2363 : 12679 : int ndigits = var->ndigits;
2364 : 12679 : int weight = var->weight;
2365 : : int64 result;
2366 : :
2367 [ + + - + ]: 12679 : if (ndigits == 0 || weight < -44)
2368 : : {
2369 : 34 : result = 0;
2370 : : }
2371 [ + + ]: 12645 : else if (weight > 83)
2372 : : {
2373 : 8 : result = PG_INT64_MAX;
2374 : : }
2375 : : else
2376 : : {
2377 : 12637 : result = ((int64) (weight + 44) << 56);
2378 : :
2379 [ - + + + ]: 12637 : switch (ndigits)
2380 : : {
4051 rhaas@postgresql.org 2381 :UBC 0 : default:
2382 : 0 : result |= ((int64) var->digits[3]);
2383 : : pg_fallthrough;
4051 rhaas@postgresql.org 2384 :CBC 4137 : case 3:
2385 : 4137 : result |= ((int64) var->digits[2]) << 14;
2386 : : pg_fallthrough;
2387 : 12226 : case 2:
2388 : 12226 : result |= ((int64) var->digits[1]) << 28;
2389 : : pg_fallthrough;
2390 : 12637 : case 1:
2391 : 12637 : result |= ((int64) var->digits[0]) << 42;
2392 : 12637 : break;
2393 : : }
2394 : : }
2395 : :
2396 : : /* the abbrev is negated relative to the original */
2397 [ + + ]: 12679 : if (var->sign == NUMERIC_POS)
2398 : 12615 : result = -result;
2399 : :
2400 [ + - ]: 12679 : if (nss->estimating)
2401 : : {
2402 : 12679 : uint32 tmp = ((uint32) result
2403 : 12679 : ^ (uint32) ((uint64) result >> 32));
2404 : :
2405 : 12679 : addHyperLogLog(&nss->abbr_card, DatumGetUInt32(hash_uint32(tmp)));
2406 : : }
2407 : :
4050 2408 : 12679 : return NumericAbbrevGetDatum(result);
2409 : : }
2410 : :
2411 : :
2412 : : /*
2413 : : * Ordinary (non-sortsupport) comparisons follow.
2414 : : */
2415 : :
2416 : : Datum
9411 tgl@sss.pgh.pa.us 2417 : 608215 : numeric_cmp(PG_FUNCTION_ARGS)
2418 : : {
2419 : 608215 : Numeric num1 = PG_GETARG_NUMERIC(0);
2420 : 608215 : Numeric num2 = PG_GETARG_NUMERIC(1);
2421 : : int result;
2422 : :
9133 2423 : 608215 : result = cmp_numerics(num1, num2);
2424 : :
9411 2425 [ + + ]: 608215 : PG_FREE_IF_COPY(num1, 0);
2426 [ + + ]: 608215 : PG_FREE_IF_COPY(num2, 1);
2427 : :
2428 : 608215 : PG_RETURN_INT32(result);
2429 : : }
2430 : :
2431 : :
2432 : : Datum
2433 : 448491 : numeric_eq(PG_FUNCTION_ARGS)
2434 : : {
2435 : 448491 : Numeric num1 = PG_GETARG_NUMERIC(0);
2436 : 448491 : Numeric num2 = PG_GETARG_NUMERIC(1);
2437 : : bool result;
2438 : :
9133 2439 : 448491 : result = cmp_numerics(num1, num2) == 0;
2440 : :
9411 2441 [ + + ]: 448491 : PG_FREE_IF_COPY(num1, 0);
2442 [ + + ]: 448491 : PG_FREE_IF_COPY(num2, 1);
2443 : :
2444 : 448491 : PG_RETURN_BOOL(result);
2445 : : }
2446 : :
2447 : : Datum
2448 : 3584 : numeric_ne(PG_FUNCTION_ARGS)
2449 : : {
2450 : 3584 : Numeric num1 = PG_GETARG_NUMERIC(0);
2451 : 3584 : Numeric num2 = PG_GETARG_NUMERIC(1);
2452 : : bool result;
2453 : :
9133 2454 : 3584 : result = cmp_numerics(num1, num2) != 0;
2455 : :
9411 2456 [ + + ]: 3584 : PG_FREE_IF_COPY(num1, 0);
2457 [ + + ]: 3584 : PG_FREE_IF_COPY(num2, 1);
2458 : :
2459 : 3584 : PG_RETURN_BOOL(result);
2460 : : }
2461 : :
2462 : : Datum
2463 : 34137 : numeric_gt(PG_FUNCTION_ARGS)
2464 : : {
2465 : 34137 : Numeric num1 = PG_GETARG_NUMERIC(0);
2466 : 34137 : Numeric num2 = PG_GETARG_NUMERIC(1);
2467 : : bool result;
2468 : :
9133 2469 : 34137 : result = cmp_numerics(num1, num2) > 0;
2470 : :
9411 2471 [ + + ]: 34137 : PG_FREE_IF_COPY(num1, 0);
2472 [ + + ]: 34137 : PG_FREE_IF_COPY(num2, 1);
2473 : :
2474 : 34137 : PG_RETURN_BOOL(result);
2475 : : }
2476 : :
2477 : : Datum
2478 : 8167 : numeric_ge(PG_FUNCTION_ARGS)
2479 : : {
2480 : 8167 : Numeric num1 = PG_GETARG_NUMERIC(0);
2481 : 8167 : Numeric num2 = PG_GETARG_NUMERIC(1);
2482 : : bool result;
2483 : :
9133 2484 : 8167 : result = cmp_numerics(num1, num2) >= 0;
2485 : :
9411 2486 [ + + ]: 8167 : PG_FREE_IF_COPY(num1, 0);
2487 [ - + ]: 8167 : PG_FREE_IF_COPY(num2, 1);
2488 : :
2489 : 8167 : PG_RETURN_BOOL(result);
2490 : : }
2491 : :
2492 : : Datum
2493 : 250311 : numeric_lt(PG_FUNCTION_ARGS)
2494 : : {
2495 : 250311 : Numeric num1 = PG_GETARG_NUMERIC(0);
2496 : 250311 : Numeric num2 = PG_GETARG_NUMERIC(1);
2497 : : bool result;
2498 : :
9133 2499 : 250311 : result = cmp_numerics(num1, num2) < 0;
2500 : :
9411 2501 [ + + ]: 250311 : PG_FREE_IF_COPY(num1, 0);
2502 [ + + ]: 250311 : PG_FREE_IF_COPY(num2, 1);
2503 : :
2504 : 250311 : PG_RETURN_BOOL(result);
2505 : : }
2506 : :
2507 : : Datum
2508 : 10382 : numeric_le(PG_FUNCTION_ARGS)
2509 : : {
2510 : 10382 : Numeric num1 = PG_GETARG_NUMERIC(0);
2511 : 10382 : Numeric num2 = PG_GETARG_NUMERIC(1);
2512 : : bool result;
2513 : :
9133 2514 : 10382 : result = cmp_numerics(num1, num2) <= 0;
2515 : :
2516 [ + + ]: 10382 : PG_FREE_IF_COPY(num1, 0);
2517 [ + + ]: 10382 : PG_FREE_IF_COPY(num2, 1);
2518 : :
2519 : 10382 : PG_RETURN_BOOL(result);
2520 : : }
2521 : :
2522 : : static int
2523 : 18703109 : cmp_numerics(Numeric num1, Numeric num2)
2524 : : {
2525 : : int result;
2526 : :
2527 : : /*
2528 : : * We consider all NANs to be equal and larger than any non-NAN (including
2529 : : * Infinity). This is somewhat arbitrary; the important thing is to have
2530 : : * a consistent sort order.
2531 : : */
2113 2532 [ + + ]: 18703109 : if (NUMERIC_IS_SPECIAL(num1))
2533 : : {
2534 [ + + ]: 3327 : if (NUMERIC_IS_NAN(num1))
2535 : : {
2536 [ + + ]: 3264 : if (NUMERIC_IS_NAN(num2))
2537 : 463 : result = 0; /* NAN = NAN */
2538 : : else
2539 : 2801 : result = 1; /* NAN > non-NAN */
2540 : : }
2541 [ + + ]: 63 : else if (NUMERIC_IS_PINF(num1))
2542 : : {
2543 [ - + ]: 50 : if (NUMERIC_IS_NAN(num2))
2113 tgl@sss.pgh.pa.us 2544 :UBC 0 : result = -1; /* PINF < NAN */
2113 tgl@sss.pgh.pa.us 2545 [ + + ]:CBC 50 : else if (NUMERIC_IS_PINF(num2))
2546 : 4 : result = 0; /* PINF = PINF */
2547 : : else
2548 : 46 : result = 1; /* PINF > anything else */
2549 : : }
2550 : : else /* num1 must be NINF */
2551 : : {
2552 [ + + ]: 13 : if (NUMERIC_IS_NINF(num2))
2553 : 4 : result = 0; /* NINF = NINF */
2554 : : else
2555 : 9 : result = -1; /* NINF < anything else */
2556 : : }
2557 : : }
2558 [ + + ]: 18699782 : else if (NUMERIC_IS_SPECIAL(num2))
2559 : : {
2560 [ + + ]: 5594 : if (NUMERIC_IS_NINF(num2))
2561 : 8 : result = 1; /* normal > NINF */
2562 : : else
2563 : 5586 : result = -1; /* normal < NAN or PINF */
2564 : : }
2565 : : else
2566 : : {
7392 bruce@momjian.us 2567 [ + + + + ]: 37389020 : result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1),
5754 rhaas@postgresql.org 2568 [ + + - + : 18694368 : NUMERIC_WEIGHT(num1), NUMERIC_SIGN(num1),
+ + + + ]
7392 bruce@momjian.us 2569 [ + + + + ]: 18694188 : NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2),
5754 rhaas@postgresql.org 2570 [ + + - + : 18694652 : NUMERIC_WEIGHT(num2), NUMERIC_SIGN(num2));
+ + + + ]
2571 : : }
2572 : :
9133 tgl@sss.pgh.pa.us 2573 : 18703109 : return result;
2574 : : }
2575 : :
2576 : : /*
2577 : : * in_range support function for numeric.
2578 : : */
2579 : : Datum
2992 2580 : 768 : in_range_numeric_numeric(PG_FUNCTION_ARGS)
2581 : : {
2582 : 768 : Numeric val = PG_GETARG_NUMERIC(0);
2583 : 768 : Numeric base = PG_GETARG_NUMERIC(1);
2584 : 768 : Numeric offset = PG_GETARG_NUMERIC(2);
2585 : 768 : bool sub = PG_GETARG_BOOL(3);
2586 : 768 : bool less = PG_GETARG_BOOL(4);
2587 : : bool result;
2588 : :
2589 : : /*
2590 : : * Reject negative (including -Inf) or NaN offset. Negative is per spec,
2591 : : * and NaN is because appropriate semantics for that seem non-obvious.
2592 : : */
2113 2593 [ + + ]: 768 : if (NUMERIC_IS_NAN(offset) ||
2594 [ + - ]: 764 : NUMERIC_IS_NINF(offset) ||
2595 [ + + - + : 764 : NUMERIC_SIGN(offset) == NUMERIC_NEG)
+ - - + -
- ]
2992 2596 [ + - ]: 4 : ereport(ERROR,
2597 : : (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2598 : : errmsg("invalid preceding or following size in window function")));
2599 : :
2600 : : /*
2601 : : * Deal with cases where val and/or base is NaN, following the rule that
2602 : : * NaN sorts after non-NaN (cf cmp_numerics). The offset cannot affect
2603 : : * the conclusion.
2604 : : */
2605 [ + + ]: 764 : if (NUMERIC_IS_NAN(val))
2606 : : {
2607 [ + + ]: 124 : if (NUMERIC_IS_NAN(base))
2608 : 40 : result = true; /* NAN = NAN */
2609 : : else
2610 : 84 : result = !less; /* NAN > non-NAN */
2611 : : }
2612 [ + + ]: 640 : else if (NUMERIC_IS_NAN(base))
2613 : : {
2614 : 84 : result = less; /* non-NAN < NAN */
2615 : : }
2616 : :
2617 : : /*
2618 : : * Deal with infinite offset (necessarily +Inf, at this point).
2619 : : */
2113 2620 [ + + ]: 556 : else if (NUMERIC_IS_SPECIAL(offset))
2621 : : {
2622 [ - + ]: 280 : Assert(NUMERIC_IS_PINF(offset));
2623 [ + + + + ]: 280 : if (sub ? NUMERIC_IS_PINF(base) : NUMERIC_IS_NINF(base))
2624 : : {
2625 : : /*
2626 : : * base +/- offset would produce NaN, so return true for any val
2627 : : * (see in_range_float8_float8() for reasoning).
2628 : : */
2629 : 116 : result = true;
2630 : : }
2631 [ + + ]: 164 : else if (sub)
2632 : : {
2633 : : /* base - offset must be -inf */
2634 [ + + ]: 100 : if (less)
2635 : 36 : result = NUMERIC_IS_NINF(val); /* only -inf is <= sum */
2636 : : else
2637 : 64 : result = true; /* any val is >= sum */
2638 : : }
2639 : : else
2640 : : {
2641 : : /* base + offset must be +inf */
2642 [ - + ]: 64 : if (less)
2113 tgl@sss.pgh.pa.us 2643 :UBC 0 : result = true; /* any val is <= sum */
2644 : : else
2113 tgl@sss.pgh.pa.us 2645 :CBC 64 : result = NUMERIC_IS_PINF(val); /* only +inf is >= sum */
2646 : : }
2647 : : }
2648 : :
2649 : : /*
2650 : : * Deal with cases where val and/or base is infinite. The offset, being
2651 : : * now known finite, cannot affect the conclusion.
2652 : : */
2653 [ + + ]: 276 : else if (NUMERIC_IS_SPECIAL(val))
2654 : : {
2655 [ + + ]: 52 : if (NUMERIC_IS_PINF(val))
2656 : : {
2657 [ + + ]: 24 : if (NUMERIC_IS_PINF(base))
2658 : 16 : result = true; /* PINF = PINF */
2659 : : else
2660 : 8 : result = !less; /* PINF > any other non-NAN */
2661 : : }
2662 : : else /* val must be NINF */
2663 : : {
2664 [ + + ]: 28 : if (NUMERIC_IS_NINF(base))
2665 : 20 : result = true; /* NINF = NINF */
2666 : : else
2667 : 8 : result = less; /* NINF < anything else */
2668 : : }
2669 : : }
2670 [ + + ]: 224 : else if (NUMERIC_IS_SPECIAL(base))
2671 : : {
2672 [ + + ]: 16 : if (NUMERIC_IS_NINF(base))
2673 : 8 : result = !less; /* normal > NINF */
2674 : : else
2675 : 8 : result = less; /* normal < PINF */
2676 : : }
2677 : : else
2678 : : {
2679 : : /*
2680 : : * Otherwise go ahead and compute base +/- offset. While it's
2681 : : * possible for this to overflow the numeric format, it's unlikely
2682 : : * enough that we don't take measures to prevent it.
2683 : : */
2684 : : NumericVar valv;
2685 : : NumericVar basev;
2686 : : NumericVar offsetv;
2687 : : NumericVar sum;
2688 : :
2992 2689 : 208 : init_var_from_num(val, &valv);
2690 : 208 : init_var_from_num(base, &basev);
2691 : 208 : init_var_from_num(offset, &offsetv);
2692 : 208 : init_var(&sum);
2693 : :
2694 [ + + ]: 208 : if (sub)
2695 : 104 : sub_var(&basev, &offsetv, &sum);
2696 : : else
2697 : 104 : add_var(&basev, &offsetv, &sum);
2698 : :
2699 [ + + ]: 208 : if (less)
2700 : 104 : result = (cmp_var(&valv, &sum) <= 0);
2701 : : else
2702 : 104 : result = (cmp_var(&valv, &sum) >= 0);
2703 : :
2704 : 208 : free_var(&sum);
2705 : : }
2706 : :
2707 [ + - ]: 764 : PG_FREE_IF_COPY(val, 0);
2708 [ + - ]: 764 : PG_FREE_IF_COPY(base, 1);
2709 [ - + ]: 764 : PG_FREE_IF_COPY(offset, 2);
2710 : :
2711 : 764 : PG_RETURN_BOOL(result);
2712 : : }
2713 : :
2714 : : Datum
6937 neilc@samurai.com 2715 : 410038 : hash_numeric(PG_FUNCTION_ARGS)
2716 : : {
6746 bruce@momjian.us 2717 : 410038 : Numeric key = PG_GETARG_NUMERIC(0);
2718 : : Datum digit_hash;
2719 : : Datum result;
2720 : : int weight;
2721 : : int start_offset;
2722 : : int end_offset;
2723 : : int i;
2724 : : int hash_len;
2725 : : NumericDigit *digits;
2726 : :
2727 : : /* If it's NaN or infinity, don't try to hash the rest of the fields */
2113 tgl@sss.pgh.pa.us 2728 [ - + ]: 410038 : if (NUMERIC_IS_SPECIAL(key))
6937 neilc@samurai.com 2729 :UBC 0 : PG_RETURN_UINT32(0);
2730 : :
5754 rhaas@postgresql.org 2731 [ + - + + ]:CBC 410038 : weight = NUMERIC_WEIGHT(key);
6937 neilc@samurai.com 2732 : 410038 : start_offset = 0;
6746 bruce@momjian.us 2733 : 410038 : end_offset = 0;
2734 : :
2735 : : /*
2736 : : * Omit any leading or trailing zeros from the input to the hash. The
2737 : : * numeric implementation *should* guarantee that leading and trailing
2738 : : * zeros are suppressed, but we're paranoid. Note that we measure the
2739 : : * starting and ending offsets in units of NumericDigits, not bytes.
2740 : : */
5754 rhaas@postgresql.org 2741 [ + - ]: 410038 : digits = NUMERIC_DIGITS(key);
6937 neilc@samurai.com 2742 [ + - + + ]: 410038 : for (i = 0; i < NUMERIC_NDIGITS(key); i++)
2743 : : {
5754 rhaas@postgresql.org 2744 [ + - ]: 408781 : if (digits[i] != (NumericDigit) 0)
6937 neilc@samurai.com 2745 : 408781 : break;
2746 : :
6937 neilc@samurai.com 2747 :UBC 0 : start_offset++;
2748 : :
2749 : : /*
2750 : : * The weight is effectively the # of digits before the decimal point,
2751 : : * so decrement it for each leading zero we skip.
2752 : : */
2753 : 0 : weight--;
2754 : : }
2755 : :
2756 : : /*
2757 : : * If there are no non-zero digits, then the value of the number is zero,
2758 : : * regardless of any other fields.
2759 : : */
6937 neilc@samurai.com 2760 [ + - + + ]:CBC 410038 : if (NUMERIC_NDIGITS(key) == start_offset)
2761 : 1257 : PG_RETURN_UINT32(-1);
2762 : :
2763 [ + - + - ]: 408781 : for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)
2764 : : {
5754 rhaas@postgresql.org 2765 [ + - ]: 408781 : if (digits[i] != (NumericDigit) 0)
6937 neilc@samurai.com 2766 : 408781 : break;
2767 : :
6937 neilc@samurai.com 2768 :UBC 0 : end_offset++;
2769 : : }
2770 : :
2771 : : /* If we get here, there should be at least one non-zero digit */
6937 neilc@samurai.com 2772 [ + - - + ]:CBC 408781 : Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));
2773 : :
2774 : : /*
2775 : : * Note that we don't hash on the Numeric's scale, since two numerics can
2776 : : * compare equal but have different scales. We also don't hash on the
2777 : : * sign, although we could: since a sign difference implies inequality,
2778 : : * this shouldn't affect correctness.
2779 : : */
2780 [ + - ]: 408781 : hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;
2781 [ + - ]: 408781 : digit_hash = hash_any((unsigned char *) (NUMERIC_DIGITS(key) + start_offset),
2782 : : hash_len * sizeof(NumericDigit));
2783 : :
2784 : : /* Mix in the weight, via XOR */
2785 : 408781 : result = digit_hash ^ weight;
2786 : :
2787 : 408781 : PG_RETURN_DATUM(result);
2788 : : }
2789 : :
2790 : : /*
2791 : : * Returns 64-bit value by hashing a value to a 64-bit value, with a seed.
2792 : : * Otherwise, similar to hash_numeric.
2793 : : */
2794 : : Datum
3169 rhaas@postgresql.org 2795 : 56 : hash_numeric_extended(PG_FUNCTION_ARGS)
2796 : : {
2797 : 56 : Numeric key = PG_GETARG_NUMERIC(0);
2798 : 56 : uint64 seed = PG_GETARG_INT64(1);
2799 : : Datum digit_hash;
2800 : : Datum result;
2801 : : int weight;
2802 : : int start_offset;
2803 : : int end_offset;
2804 : : int i;
2805 : : int hash_len;
2806 : : NumericDigit *digits;
2807 : :
2808 : : /* If it's NaN or infinity, don't try to hash the rest of the fields */
2113 tgl@sss.pgh.pa.us 2809 [ - + ]: 56 : if (NUMERIC_IS_SPECIAL(key))
3169 rhaas@postgresql.org 2810 :UBC 0 : PG_RETURN_UINT64(seed);
2811 : :
3169 rhaas@postgresql.org 2812 [ + - - + ]:CBC 56 : weight = NUMERIC_WEIGHT(key);
2813 : 56 : start_offset = 0;
2814 : 56 : end_offset = 0;
2815 : :
2816 [ + - ]: 56 : digits = NUMERIC_DIGITS(key);
2817 [ + - + + ]: 56 : for (i = 0; i < NUMERIC_NDIGITS(key); i++)
2818 : : {
2819 [ + - ]: 48 : if (digits[i] != (NumericDigit) 0)
2820 : 48 : break;
2821 : :
3169 rhaas@postgresql.org 2822 :UBC 0 : start_offset++;
2823 : :
2824 : 0 : weight--;
2825 : : }
2826 : :
3169 rhaas@postgresql.org 2827 [ + - + + ]:CBC 56 : if (NUMERIC_NDIGITS(key) == start_offset)
2828 : 8 : PG_RETURN_UINT64(seed - 1);
2829 : :
2830 [ + - + - ]: 48 : for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)
2831 : : {
2832 [ + - ]: 48 : if (digits[i] != (NumericDigit) 0)
2833 : 48 : break;
2834 : :
3169 rhaas@postgresql.org 2835 :UBC 0 : end_offset++;
2836 : : }
2837 : :
3169 rhaas@postgresql.org 2838 [ + - - + ]:CBC 48 : Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));
2839 : :
2840 [ + - ]: 48 : hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;
2841 [ + - ]: 48 : digit_hash = hash_any_extended((unsigned char *) (NUMERIC_DIGITS(key)
2842 : 48 : + start_offset),
2843 : : hash_len * sizeof(NumericDigit),
2844 : : seed);
2845 : :
3168 2846 : 48 : result = UInt64GetDatum(DatumGetUInt64(digit_hash) ^ weight);
2847 : :
3169 2848 : 48 : PG_RETURN_DATUM(result);
2849 : : }
2850 : :
2851 : :
2852 : : /* ----------------------------------------------------------------------
2853 : : *
2854 : : * Basic arithmetic functions
2855 : : *
2856 : : * ----------------------------------------------------------------------
2857 : : */
2858 : :
2859 : :
2860 : : /*
2861 : : * numeric_add() -
2862 : : *
2863 : : * Add two numerics
2864 : : */
2865 : : Datum
9411 tgl@sss.pgh.pa.us 2866 : 168431 : numeric_add(PG_FUNCTION_ARGS)
2867 : : {
2868 : 168431 : Numeric num1 = PG_GETARG_NUMERIC(0);
2869 : 168431 : Numeric num2 = PG_GETARG_NUMERIC(1);
2870 : : Numeric res;
2871 : :
242 michael@paquier.xyz 2872 :GNC 168431 : res = numeric_add_safe(num1, num2, NULL);
2873 : :
2607 akorotkov@postgresql 2874 :CBC 168431 : PG_RETURN_NUMERIC(res);
2875 : : }
2876 : :
2877 : : /*
2878 : : * numeric_add_safe() -
2879 : : *
2880 : : * Internal version of numeric_add() with support for soft error reporting.
2881 : : */
2882 : : Numeric
242 michael@paquier.xyz 2883 :GNC 169125 : numeric_add_safe(Numeric num1, Numeric num2, Node *escontext)
2884 : : {
2885 : : NumericVar arg1;
2886 : : NumericVar arg2;
2887 : : NumericVar result;
2888 : : Numeric res;
2889 : :
2890 : : /*
2891 : : * Handle NaN and infinities
2892 : : */
2113 tgl@sss.pgh.pa.us 2893 [ + + + + ]:CBC 169125 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
2894 : : {
2895 [ + + + + ]: 132 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
2896 : 52 : return make_result(&const_nan);
2897 [ + + ]: 80 : if (NUMERIC_IS_PINF(num1))
2898 : : {
2899 [ + + ]: 24 : if (NUMERIC_IS_NINF(num2))
2900 : 4 : return make_result(&const_nan); /* Inf + -Inf */
2901 : : else
2902 : 20 : return make_result(&const_pinf);
2903 : : }
2904 [ + + ]: 56 : if (NUMERIC_IS_NINF(num1))
2905 : : {
2906 [ + + ]: 24 : if (NUMERIC_IS_PINF(num2))
2907 : 4 : return make_result(&const_nan); /* -Inf + Inf */
2908 : : else
2909 : 20 : return make_result(&const_ninf);
2910 : : }
2911 : : /* by here, num1 must be finite, so num2 is not */
2912 [ + + ]: 32 : if (NUMERIC_IS_PINF(num2))
2913 : 16 : return make_result(&const_pinf);
2914 [ - + ]: 16 : Assert(NUMERIC_IS_NINF(num2));
2915 : 16 : return make_result(&const_ninf);
2916 : : }
2917 : :
2918 : : /*
2919 : : * Unpack the values, let add_var() compute the result and return it.
2920 : : */
4913 heikki.linnakangas@i 2921 : 168993 : init_var_from_num(num1, &arg1);
2922 : 168993 : init_var_from_num(num2, &arg2);
2923 : :
2924 : 168993 : init_var(&result);
9988 JanWieck@Yahoo.com 2925 : 168993 : add_var(&arg1, &arg2, &result);
2926 : :
242 michael@paquier.xyz 2927 :GNC 168993 : res = make_result_safe(&result, escontext);
2928 : :
9988 JanWieck@Yahoo.com 2929 :CBC 168993 : free_var(&result);
2930 : :
2607 akorotkov@postgresql 2931 : 168993 : return res;
2932 : : }
2933 : :
2934 : :
2935 : : /*
2936 : : * numeric_sub() -
2937 : : *
2938 : : * Subtract one numeric from another
2939 : : */
2940 : : Datum
9411 tgl@sss.pgh.pa.us 2941 : 46332 : numeric_sub(PG_FUNCTION_ARGS)
2942 : : {
2943 : 46332 : Numeric num1 = PG_GETARG_NUMERIC(0);
2944 : 46332 : Numeric num2 = PG_GETARG_NUMERIC(1);
2945 : : Numeric res;
2946 : :
242 michael@paquier.xyz 2947 :GNC 46332 : res = numeric_sub_safe(num1, num2, NULL);
2948 : :
2607 akorotkov@postgresql 2949 :CBC 46332 : PG_RETURN_NUMERIC(res);
2950 : : }
2951 : :
2952 : :
2953 : : /*
2954 : : * numeric_sub_safe() -
2955 : : *
2956 : : * Internal version of numeric_sub() with support for soft error reporting.
2957 : : */
2958 : : Numeric
242 michael@paquier.xyz 2959 :GNC 46436 : numeric_sub_safe(Numeric num1, Numeric num2, Node *escontext)
2960 : : {
2961 : : NumericVar arg1;
2962 : : NumericVar arg2;
2963 : : NumericVar result;
2964 : : Numeric res;
2965 : :
2966 : : /*
2967 : : * Handle NaN and infinities
2968 : : */
2113 tgl@sss.pgh.pa.us 2969 [ + + + + ]:CBC 46436 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
2970 : : {
2971 [ + + + + ]: 132 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
2972 : 52 : return make_result(&const_nan);
2973 [ + + ]: 80 : if (NUMERIC_IS_PINF(num1))
2974 : : {
2975 [ + + ]: 24 : if (NUMERIC_IS_PINF(num2))
2976 : 4 : return make_result(&const_nan); /* Inf - Inf */
2977 : : else
2978 : 20 : return make_result(&const_pinf);
2979 : : }
2980 [ + + ]: 56 : if (NUMERIC_IS_NINF(num1))
2981 : : {
2982 [ + + ]: 24 : if (NUMERIC_IS_NINF(num2))
2983 : 4 : return make_result(&const_nan); /* -Inf - -Inf */
2984 : : else
2985 : 20 : return make_result(&const_ninf);
2986 : : }
2987 : : /* by here, num1 must be finite, so num2 is not */
2988 [ + + ]: 32 : if (NUMERIC_IS_PINF(num2))
2989 : 16 : return make_result(&const_ninf);
2990 [ - + ]: 16 : Assert(NUMERIC_IS_NINF(num2));
2991 : 16 : return make_result(&const_pinf);
2992 : : }
2993 : :
2994 : : /*
2995 : : * Unpack the values, let sub_var() compute the result and return it.
2996 : : */
4913 heikki.linnakangas@i 2997 : 46304 : init_var_from_num(num1, &arg1);
2998 : 46304 : init_var_from_num(num2, &arg2);
2999 : :
3000 : 46304 : init_var(&result);
9988 JanWieck@Yahoo.com 3001 : 46304 : sub_var(&arg1, &arg2, &result);
3002 : :
242 michael@paquier.xyz 3003 :GNC 46304 : res = make_result_safe(&result, escontext);
3004 : :
9988 JanWieck@Yahoo.com 3005 :CBC 46304 : free_var(&result);
3006 : :
2607 akorotkov@postgresql 3007 : 46304 : return res;
3008 : : }
3009 : :
3010 : :
3011 : : /*
3012 : : * numeric_mul() -
3013 : : *
3014 : : * Calculate the product of two numerics
3015 : : */
3016 : : Datum
9411 tgl@sss.pgh.pa.us 3017 : 326743 : numeric_mul(PG_FUNCTION_ARGS)
3018 : : {
3019 : 326743 : Numeric num1 = PG_GETARG_NUMERIC(0);
3020 : 326743 : Numeric num2 = PG_GETARG_NUMERIC(1);
3021 : : Numeric res;
3022 : :
42 peter@eisentraut.org 3023 :GNC 326743 : res = numeric_mul_safe(num1, num2, fcinfo->context);
3024 : :
3025 [ - + - - : 326743 : if (unlikely(SOFT_ERROR_OCCURRED(fcinfo->context)))
- - - + ]
42 peter@eisentraut.org 3026 :UNC 0 : PG_RETURN_NULL();
3027 : :
2607 akorotkov@postgresql 3028 :CBC 326743 : PG_RETURN_NUMERIC(res);
3029 : : }
3030 : :
3031 : :
3032 : : /*
3033 : : * numeric_mul_safe() -
3034 : : *
3035 : : * Internal version of numeric_mul() with support for soft error reporting.
3036 : : */
3037 : : Numeric
242 michael@paquier.xyz 3038 :GNC 326775 : numeric_mul_safe(Numeric num1, Numeric num2, Node *escontext)
3039 : : {
3040 : : NumericVar arg1;
3041 : : NumericVar arg2;
3042 : : NumericVar result;
3043 : : Numeric res;
3044 : :
3045 : : /*
3046 : : * Handle NaN and infinities
3047 : : */
2113 tgl@sss.pgh.pa.us 3048 [ + + + + ]:CBC 326775 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3049 : : {
3050 [ + + + + ]: 132 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
3051 : 52 : return make_result(&const_nan);
3052 [ + + ]: 80 : if (NUMERIC_IS_PINF(num1))
3053 : : {
3054 [ + + + - ]: 24 : switch (numeric_sign_internal(num2))
3055 : : {
3056 : 4 : case 0:
3057 : 4 : return make_result(&const_nan); /* Inf * 0 */
3058 : 12 : case 1:
3059 : 12 : return make_result(&const_pinf);
3060 : 8 : case -1:
3061 : 8 : return make_result(&const_ninf);
3062 : : }
2113 tgl@sss.pgh.pa.us 3063 :UBC 0 : Assert(false);
3064 : : }
2113 tgl@sss.pgh.pa.us 3065 [ + + ]:CBC 56 : if (NUMERIC_IS_NINF(num1))
3066 : : {
3067 [ + + + - ]: 24 : switch (numeric_sign_internal(num2))
3068 : : {
3069 : 4 : case 0:
3070 : 4 : return make_result(&const_nan); /* -Inf * 0 */
3071 : 12 : case 1:
3072 : 12 : return make_result(&const_ninf);
3073 : 8 : case -1:
3074 : 8 : return make_result(&const_pinf);
3075 : : }
2113 tgl@sss.pgh.pa.us 3076 :UBC 0 : Assert(false);
3077 : : }
3078 : : /* by here, num1 must be finite, so num2 is not */
2113 tgl@sss.pgh.pa.us 3079 [ + + ]:CBC 32 : if (NUMERIC_IS_PINF(num2))
3080 : : {
3081 [ + + + - ]: 16 : switch (numeric_sign_internal(num1))
3082 : : {
3083 : 4 : case 0:
3084 : 4 : return make_result(&const_nan); /* 0 * Inf */
3085 : 8 : case 1:
3086 : 8 : return make_result(&const_pinf);
3087 : 4 : case -1:
3088 : 4 : return make_result(&const_ninf);
3089 : : }
2113 tgl@sss.pgh.pa.us 3090 :UBC 0 : Assert(false);
3091 : : }
2113 tgl@sss.pgh.pa.us 3092 [ - + ]:CBC 16 : Assert(NUMERIC_IS_NINF(num2));
3093 [ + + + - ]: 16 : switch (numeric_sign_internal(num1))
3094 : : {
3095 : 4 : case 0:
3096 : 4 : return make_result(&const_nan); /* 0 * -Inf */
3097 : 8 : case 1:
3098 : 8 : return make_result(&const_ninf);
3099 : 4 : case -1:
3100 : 4 : return make_result(&const_pinf);
3101 : : }
2113 tgl@sss.pgh.pa.us 3102 :UBC 0 : Assert(false);
3103 : : }
3104 : :
3105 : : /*
3106 : : * Unpack the values, let mul_var() compute the result and return it.
3107 : : * Unlike add_var() and sub_var(), mul_var() will round its result. In the
3108 : : * case of numeric_mul(), which is invoked for the * operator on numerics,
3109 : : * we request exact representation for the product (rscale = sum(dscale of
3110 : : * arg1, dscale of arg2)). If the exact result has more digits after the
3111 : : * decimal point than can be stored in a numeric, we round it. Rounding
3112 : : * after computing the exact result ensures that the final result is
3113 : : * correctly rounded (rounding in mul_var() using a truncated product
3114 : : * would not guarantee this).
3115 : : */
4913 heikki.linnakangas@i 3116 :CBC 326643 : init_var_from_num(num1, &arg1);
3117 : 326643 : init_var_from_num(num2, &arg2);
3118 : :
3119 : 326643 : init_var(&result);
8446 tgl@sss.pgh.pa.us 3120 : 326643 : mul_var(&arg1, &arg2, &result, arg1.dscale + arg2.dscale);
3121 : :
1760 dean.a.rasheed@gmail 3122 [ + + ]: 326643 : if (result.dscale > NUMERIC_DSCALE_MAX)
3123 : 5 : round_var(&result, NUMERIC_DSCALE_MAX);
3124 : :
242 michael@paquier.xyz 3125 :GNC 326643 : res = make_result_safe(&result, escontext);
3126 : :
9988 JanWieck@Yahoo.com 3127 :CBC 326643 : free_var(&result);
3128 : :
2607 akorotkov@postgresql 3129 : 326643 : return res;
3130 : : }
3131 : :
3132 : :
3133 : : /*
3134 : : * numeric_div() -
3135 : : *
3136 : : * Divide one numeric into another
3137 : : */
3138 : : Datum
9411 tgl@sss.pgh.pa.us 3139 : 98470 : numeric_div(PG_FUNCTION_ARGS)
3140 : : {
3141 : 98470 : Numeric num1 = PG_GETARG_NUMERIC(0);
3142 : 98470 : Numeric num2 = PG_GETARG_NUMERIC(1);
3143 : : Numeric res;
3144 : :
242 michael@paquier.xyz 3145 :GNC 98470 : res = numeric_div_safe(num1, num2, NULL);
3146 : :
2607 akorotkov@postgresql 3147 :CBC 98449 : PG_RETURN_NUMERIC(res);
3148 : : }
3149 : :
3150 : :
3151 : : /*
3152 : : * numeric_div_safe() -
3153 : : *
3154 : : * Internal version of numeric_div() with support for soft error reporting.
3155 : : */
3156 : : Numeric
242 michael@paquier.xyz 3157 :GNC 99031 : numeric_div_safe(Numeric num1, Numeric num2, Node *escontext)
3158 : : {
3159 : : NumericVar arg1;
3160 : : NumericVar arg2;
3161 : : NumericVar result;
3162 : : Numeric res;
3163 : : int rscale;
3164 : :
3165 : : /*
3166 : : * Handle NaN and infinities
3167 : : */
2113 tgl@sss.pgh.pa.us 3168 [ + + + + ]:CBC 99031 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3169 : : {
3170 [ + + + + ]: 133 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
3171 : 53 : return make_result(&const_nan);
3172 [ + + ]: 80 : if (NUMERIC_IS_PINF(num1))
3173 : : {
3174 [ + + ]: 24 : if (NUMERIC_IS_SPECIAL(num2))
3175 : 8 : return make_result(&const_nan); /* Inf / [-]Inf */
3176 [ + + + - ]: 16 : switch (numeric_sign_internal(num2))
3177 : : {
3178 : 4 : case 0:
242 michael@paquier.xyz 3179 :GNC 4 : goto division_by_zero;
2113 tgl@sss.pgh.pa.us 3180 :CBC 8 : case 1:
3181 : 8 : return make_result(&const_pinf);
3182 : 4 : case -1:
3183 : 4 : return make_result(&const_ninf);
3184 : : }
2113 tgl@sss.pgh.pa.us 3185 :UBC 0 : Assert(false);
3186 : : }
2113 tgl@sss.pgh.pa.us 3187 [ + + ]:CBC 56 : if (NUMERIC_IS_NINF(num1))
3188 : : {
3189 [ + + ]: 24 : if (NUMERIC_IS_SPECIAL(num2))
3190 : 8 : return make_result(&const_nan); /* -Inf / [-]Inf */
3191 [ + + + - ]: 16 : switch (numeric_sign_internal(num2))
3192 : : {
3193 : 4 : case 0:
242 michael@paquier.xyz 3194 :GNC 4 : goto division_by_zero;
2113 tgl@sss.pgh.pa.us 3195 :CBC 8 : case 1:
3196 : 8 : return make_result(&const_ninf);
3197 : 4 : case -1:
3198 : 4 : return make_result(&const_pinf);
3199 : : }
2113 tgl@sss.pgh.pa.us 3200 :UBC 0 : Assert(false);
3201 : : }
3202 : : /* by here, num1 must be finite, so num2 is not */
3203 : :
3204 : : /*
3205 : : * POSIX would have us return zero or minus zero if num1 is zero, and
3206 : : * otherwise throw an underflow error. But the numeric type doesn't
3207 : : * really do underflow, so let's just return zero.
3208 : : */
2113 tgl@sss.pgh.pa.us 3209 :CBC 32 : return make_result(&const_zero);
3210 : : }
3211 : :
3212 : : /*
3213 : : * Unpack the arguments
3214 : : */
4913 heikki.linnakangas@i 3215 : 98898 : init_var_from_num(num1, &arg1);
3216 : 98898 : init_var_from_num(num2, &arg2);
3217 : :
3218 : 98898 : init_var(&result);
3219 : :
3220 : : /*
3221 : : * Select scale for division result
3222 : : */
8446 tgl@sss.pgh.pa.us 3223 : 98898 : rscale = select_div_scale(&arg1, &arg2);
3224 : :
3225 : : /* Check for division by zero */
242 michael@paquier.xyz 3226 [ + + - + ]:GNC 98898 : if (arg2.ndigits == 0 || arg2.digits[0] == 0)
3227 : 33 : goto division_by_zero;
3228 : :
3229 : : /*
3230 : : * Do the divide and return the result
3231 : : */
578 dean.a.rasheed@gmail 3232 :CBC 98865 : div_var(&arg1, &arg2, &result, rscale, true, true);
3233 : :
242 michael@paquier.xyz 3234 :GNC 98865 : res = make_result_safe(&result, escontext);
3235 : :
9988 JanWieck@Yahoo.com 3236 :CBC 98865 : free_var(&result);
3237 : :
2607 akorotkov@postgresql 3238 : 98865 : return res;
3239 : :
242 michael@paquier.xyz 3240 :GNC 41 : division_by_zero:
3241 [ + + ]: 41 : ereturn(escontext, NULL,
3242 : : errcode(ERRCODE_DIVISION_BY_ZERO),
3243 : : errmsg("division by zero"));
3244 : : }
3245 : :
3246 : :
3247 : : /*
3248 : : * numeric_div_trunc() -
3249 : : *
3250 : : * Divide one numeric into another, truncating the result to an integer
3251 : : */
3252 : : Datum
6605 tgl@sss.pgh.pa.us 3253 :CBC 822 : numeric_div_trunc(PG_FUNCTION_ARGS)
3254 : : {
3255 : 822 : Numeric num1 = PG_GETARG_NUMERIC(0);
3256 : 822 : Numeric num2 = PG_GETARG_NUMERIC(1);
3257 : : NumericVar arg1;
3258 : : NumericVar arg2;
3259 : : NumericVar result;
3260 : : Numeric res;
3261 : :
3262 : : /*
3263 : : * Handle NaN and infinities
3264 : : */
2113 3265 [ + + + + ]: 822 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3266 : : {
3267 [ + + + + ]: 133 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
3268 : 53 : PG_RETURN_NUMERIC(make_result(&const_nan));
3269 [ + + ]: 80 : if (NUMERIC_IS_PINF(num1))
3270 : : {
3271 [ + + ]: 24 : if (NUMERIC_IS_SPECIAL(num2))
3272 : 8 : PG_RETURN_NUMERIC(make_result(&const_nan)); /* Inf / [-]Inf */
3273 [ + + + - ]: 16 : switch (numeric_sign_internal(num2))
3274 : : {
3275 : 4 : case 0:
3276 [ + - ]: 4 : ereport(ERROR,
3277 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
3278 : : errmsg("division by zero")));
3279 : : break;
3280 : 8 : case 1:
3281 : 8 : PG_RETURN_NUMERIC(make_result(&const_pinf));
3282 : 4 : case -1:
3283 : 4 : PG_RETURN_NUMERIC(make_result(&const_ninf));
3284 : : }
2113 tgl@sss.pgh.pa.us 3285 :UBC 0 : Assert(false);
3286 : : }
2113 tgl@sss.pgh.pa.us 3287 [ + + ]:CBC 56 : if (NUMERIC_IS_NINF(num1))
3288 : : {
3289 [ + + ]: 24 : if (NUMERIC_IS_SPECIAL(num2))
3290 : 8 : PG_RETURN_NUMERIC(make_result(&const_nan)); /* -Inf / [-]Inf */
3291 [ + + + - ]: 16 : switch (numeric_sign_internal(num2))
3292 : : {
3293 : 4 : case 0:
3294 [ + - ]: 4 : ereport(ERROR,
3295 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
3296 : : errmsg("division by zero")));
3297 : : break;
3298 : 8 : case 1:
3299 : 8 : PG_RETURN_NUMERIC(make_result(&const_ninf));
3300 : 4 : case -1:
3301 : 4 : PG_RETURN_NUMERIC(make_result(&const_pinf));
3302 : : }
2113 tgl@sss.pgh.pa.us 3303 :UBC 0 : Assert(false);
3304 : : }
3305 : : /* by here, num1 must be finite, so num2 is not */
3306 : :
3307 : : /*
3308 : : * POSIX would have us return zero or minus zero if num1 is zero, and
3309 : : * otherwise throw an underflow error. But the numeric type doesn't
3310 : : * really do underflow, so let's just return zero.
3311 : : */
2113 tgl@sss.pgh.pa.us 3312 :CBC 32 : PG_RETURN_NUMERIC(make_result(&const_zero));
3313 : : }
3314 : :
3315 : : /*
3316 : : * Unpack the arguments
3317 : : */
4913 heikki.linnakangas@i 3318 : 689 : init_var_from_num(num1, &arg1);
3319 : 689 : init_var_from_num(num2, &arg2);
3320 : :
3321 : 689 : init_var(&result);
3322 : :
3323 : : /*
3324 : : * Do the divide and return the result
3325 : : */
578 dean.a.rasheed@gmail 3326 : 689 : div_var(&arg1, &arg2, &result, 0, false, true);
3327 : :
6605 tgl@sss.pgh.pa.us 3328 : 685 : res = make_result(&result);
3329 : :
3330 : 685 : free_var(&result);
3331 : :
3332 : 685 : PG_RETURN_NUMERIC(res);
3333 : : }
3334 : :
3335 : :
3336 : : /*
3337 : : * numeric_mod() -
3338 : : *
3339 : : * Calculate the modulo of two numerics
3340 : : */
3341 : : Datum
9411 3342 : 275090 : numeric_mod(PG_FUNCTION_ARGS)
3343 : : {
3344 : 275090 : Numeric num1 = PG_GETARG_NUMERIC(0);
3345 : 275090 : Numeric num2 = PG_GETARG_NUMERIC(1);
3346 : : Numeric res;
3347 : :
242 michael@paquier.xyz 3348 :GNC 275090 : res = numeric_mod_safe(num1, num2, NULL);
3349 : :
2607 akorotkov@postgresql 3350 :CBC 275078 : PG_RETURN_NUMERIC(res);
3351 : : }
3352 : :
3353 : :
3354 : : /*
3355 : : * numeric_mod_safe() -
3356 : : *
3357 : : * Internal version of numeric_mod() with support for soft error reporting.
3358 : : */
3359 : : Numeric
242 michael@paquier.xyz 3360 :GNC 275098 : numeric_mod_safe(Numeric num1, Numeric num2, Node *escontext)
3361 : : {
3362 : : Numeric res;
3363 : : NumericVar arg1;
3364 : : NumericVar arg2;
3365 : : NumericVar result;
3366 : :
3367 : : /*
3368 : : * Handle NaN and infinities. We follow POSIX fmod() on this, except that
3369 : : * POSIX treats x-is-infinite and y-is-zero identically, raising EDOM and
3370 : : * returning NaN. We choose to throw error only for y-is-zero.
3371 : : */
2113 tgl@sss.pgh.pa.us 3372 [ + + + + ]:CBC 275098 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3373 : : {
3374 [ + + + + ]: 133 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
3375 : 53 : return make_result(&const_nan);
3376 [ + + ]: 80 : if (NUMERIC_IS_INF(num1))
3377 : : {
3378 [ + + ]: 48 : if (numeric_sign_internal(num2) == 0)
242 michael@paquier.xyz 3379 :GNC 8 : goto division_by_zero;
3380 : :
3381 : : /* Inf % any nonzero = NaN */
2113 tgl@sss.pgh.pa.us 3382 :CBC 40 : return make_result(&const_nan);
3383 : : }
3384 : : /* num2 must be [-]Inf; result is num1 regardless of sign of num2 */
3385 : 32 : return duplicate_numeric(num1);
3386 : : }
3387 : :
4913 heikki.linnakangas@i 3388 : 274965 : init_var_from_num(num1, &arg1);
3389 : 274965 : init_var_from_num(num2, &arg2);
3390 : :
3391 : 274965 : init_var(&result);
3392 : :
3393 : : /* Check for division by zero */
242 michael@paquier.xyz 3394 [ + + - + ]:GNC 274965 : if (arg2.ndigits == 0 || arg2.digits[0] == 0)
3395 : 8 : goto division_by_zero;
3396 : :
9988 JanWieck@Yahoo.com 3397 :CBC 274957 : mod_var(&arg1, &arg2, &result);
3398 : :
242 michael@paquier.xyz 3399 :GNC 274957 : res = make_result_safe(&result, escontext);
3400 : :
9988 JanWieck@Yahoo.com 3401 :CBC 274957 : free_var(&result);
3402 : :
2607 akorotkov@postgresql 3403 : 274957 : return res;
3404 : :
242 michael@paquier.xyz 3405 :GNC 16 : division_by_zero:
3406 [ + - ]: 16 : ereturn(escontext, NULL,
3407 : : errcode(ERRCODE_DIVISION_BY_ZERO),
3408 : : errmsg("division by zero"));
3409 : : }
3410 : :
3411 : :
3412 : : /*
3413 : : * numeric_inc() -
3414 : : *
3415 : : * Increment a number by one
3416 : : */
3417 : : Datum
9411 tgl@sss.pgh.pa.us 3418 :CBC 32 : numeric_inc(PG_FUNCTION_ARGS)
3419 : : {
3420 : 32 : Numeric num = PG_GETARG_NUMERIC(0);
3421 : : NumericVar arg;
3422 : : Numeric res;
3423 : :
3424 : : /*
3425 : : * Handle NaN and infinities
3426 : : */
2113 3427 [ + + ]: 32 : if (NUMERIC_IS_SPECIAL(num))
3428 : 12 : PG_RETURN_NUMERIC(duplicate_numeric(num));
3429 : :
3430 : : /*
3431 : : * Compute the result and return it
3432 : : */
4913 heikki.linnakangas@i 3433 : 20 : init_var_from_num(num, &arg);
3434 : :
9988 JanWieck@Yahoo.com 3435 : 20 : add_var(&arg, &const_one, &arg);
3436 : :
3437 : 20 : res = make_result(&arg);
3438 : :
3439 : 20 : free_var(&arg);
3440 : :
9411 tgl@sss.pgh.pa.us 3441 : 20 : PG_RETURN_NUMERIC(res);
3442 : : }
3443 : :
3444 : :
3445 : : /*
3446 : : * numeric_smaller() -
3447 : : *
3448 : : * Return the smaller of two numbers
3449 : : */
3450 : : Datum
3451 : 543 : numeric_smaller(PG_FUNCTION_ARGS)
3452 : : {
3453 : 543 : Numeric num1 = PG_GETARG_NUMERIC(0);
3454 : 543 : Numeric num2 = PG_GETARG_NUMERIC(1);
3455 : :
3456 : : /*
3457 : : * Use cmp_numerics so that this will agree with the comparison operators,
3458 : : * particularly as regards comparisons involving NaN.
3459 : : */
8315 3460 [ + + ]: 543 : if (cmp_numerics(num1, num2) < 0)
3461 : 434 : PG_RETURN_NUMERIC(num1);
3462 : : else
3463 : 109 : PG_RETURN_NUMERIC(num2);
3464 : : }
3465 : :
3466 : :
3467 : : /*
3468 : : * numeric_larger() -
3469 : : *
3470 : : * Return the larger of two numbers
3471 : : */
3472 : : Datum
9411 3473 : 12420 : numeric_larger(PG_FUNCTION_ARGS)
3474 : : {
3475 : 12420 : Numeric num1 = PG_GETARG_NUMERIC(0);
3476 : 12420 : Numeric num2 = PG_GETARG_NUMERIC(1);
3477 : :
3478 : : /*
3479 : : * Use cmp_numerics so that this will agree with the comparison operators,
3480 : : * particularly as regards comparisons involving NaN.
3481 : : */
8315 3482 [ + + ]: 12420 : if (cmp_numerics(num1, num2) > 0)
3483 : 11919 : PG_RETURN_NUMERIC(num1);
3484 : : else
3485 : 501 : PG_RETURN_NUMERIC(num2);
3486 : : }
3487 : :
3488 : :
3489 : : /* ----------------------------------------------------------------------
3490 : : *
3491 : : * Advanced math functions
3492 : : *
3493 : : * ----------------------------------------------------------------------
3494 : : */
3495 : :
3496 : : /*
3497 : : * numeric_gcd() -
3498 : : *
3499 : : * Calculate the greatest common divisor of two numerics
3500 : : */
3501 : : Datum
2292 dean.a.rasheed@gmail 3502 : 144 : numeric_gcd(PG_FUNCTION_ARGS)
3503 : : {
3504 : 144 : Numeric num1 = PG_GETARG_NUMERIC(0);
3505 : 144 : Numeric num2 = PG_GETARG_NUMERIC(1);
3506 : : NumericVar arg1;
3507 : : NumericVar arg2;
3508 : : NumericVar result;
3509 : : Numeric res;
3510 : :
3511 : : /*
3512 : : * Handle NaN and infinities: we consider the result to be NaN in all such
3513 : : * cases.
3514 : : */
2113 tgl@sss.pgh.pa.us 3515 [ + + + + ]: 144 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
2292 dean.a.rasheed@gmail 3516 : 64 : PG_RETURN_NUMERIC(make_result(&const_nan));
3517 : :
3518 : : /*
3519 : : * Unpack the arguments
3520 : : */
3521 : 80 : init_var_from_num(num1, &arg1);
3522 : 80 : init_var_from_num(num2, &arg2);
3523 : :
3524 : 80 : init_var(&result);
3525 : :
3526 : : /*
3527 : : * Find the GCD and return the result
3528 : : */
3529 : 80 : gcd_var(&arg1, &arg2, &result);
3530 : :
3531 : 80 : res = make_result(&result);
3532 : :
3533 : 80 : free_var(&result);
3534 : :
3535 : 80 : PG_RETURN_NUMERIC(res);
3536 : : }
3537 : :
3538 : :
3539 : : /*
3540 : : * numeric_lcm() -
3541 : : *
3542 : : * Calculate the least common multiple of two numerics
3543 : : */
3544 : : Datum
3545 : 164 : numeric_lcm(PG_FUNCTION_ARGS)
3546 : : {
3547 : 164 : Numeric num1 = PG_GETARG_NUMERIC(0);
3548 : 164 : Numeric num2 = PG_GETARG_NUMERIC(1);
3549 : : NumericVar arg1;
3550 : : NumericVar arg2;
3551 : : NumericVar result;
3552 : : Numeric res;
3553 : :
3554 : : /*
3555 : : * Handle NaN and infinities: we consider the result to be NaN in all such
3556 : : * cases.
3557 : : */
2113 tgl@sss.pgh.pa.us 3558 [ + + + + ]: 164 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
2292 dean.a.rasheed@gmail 3559 : 64 : PG_RETURN_NUMERIC(make_result(&const_nan));
3560 : :
3561 : : /*
3562 : : * Unpack the arguments
3563 : : */
3564 : 100 : init_var_from_num(num1, &arg1);
3565 : 100 : init_var_from_num(num2, &arg2);
3566 : :
3567 : 100 : init_var(&result);
3568 : :
3569 : : /*
3570 : : * Compute the result using lcm(x, y) = abs(x / gcd(x, y) * y), returning
3571 : : * zero if either input is zero.
3572 : : *
3573 : : * Note that the division is guaranteed to be exact, returning an integer
3574 : : * result, so the LCM is an integral multiple of both x and y. A display
3575 : : * scale of Min(x.dscale, y.dscale) would be sufficient to represent it,
3576 : : * but as with other numeric functions, we choose to return a result whose
3577 : : * display scale is no smaller than either input.
3578 : : */
3579 [ + + + + ]: 100 : if (arg1.ndigits == 0 || arg2.ndigits == 0)
3580 : 32 : set_var_from_var(&const_zero, &result);
3581 : : else
3582 : : {
3583 : 68 : gcd_var(&arg1, &arg2, &result);
578 3584 : 68 : div_var(&arg1, &result, &result, 0, false, true);
2292 3585 : 68 : mul_var(&arg2, &result, &result, arg2.dscale);
3586 : 68 : result.sign = NUMERIC_POS;
3587 : : }
3588 : :
3589 : 100 : result.dscale = Max(arg1.dscale, arg2.dscale);
3590 : :
3591 : 100 : res = make_result(&result);
3592 : :
3593 : 96 : free_var(&result);
3594 : :
3595 : 96 : PG_RETURN_NUMERIC(res);
3596 : : }
3597 : :
3598 : :
3599 : : /*
3600 : : * numeric_fac()
3601 : : *
3602 : : * Compute factorial
3603 : : */
3604 : : Datum
8191 bruce@momjian.us 3605 : 33 : numeric_fac(PG_FUNCTION_ARGS)
3606 : : {
3607 : 33 : int64 num = PG_GETARG_INT64(0);
3608 : : Numeric res;
3609 : : NumericVar fact;
3610 : : NumericVar result;
3611 : :
2147 peter@eisentraut.org 3612 [ + + ]: 33 : if (num < 0)
3613 [ + - ]: 4 : ereport(ERROR,
3614 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
3615 : : errmsg("factorial of a negative number is undefined")));
8190 tgl@sss.pgh.pa.us 3616 [ + + ]: 29 : if (num <= 1)
3617 : : {
8191 bruce@momjian.us 3618 : 5 : res = make_result(&const_one);
3619 : 5 : PG_RETURN_NUMERIC(res);
3620 : : }
3621 : : /* Fail immediately if the result would overflow */
6905 tgl@sss.pgh.pa.us 3622 [ + + ]: 24 : if (num > 32177)
3623 [ + - ]: 4 : ereport(ERROR,
3624 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
3625 : : errmsg("value overflows numeric format")));
3626 : :
8191 bruce@momjian.us 3627 : 20 : init_var(&fact);
3628 : 20 : init_var(&result);
3629 : :
4064 andres@anarazel.de 3630 : 20 : int64_to_numericvar(num, &result);
3631 : :
8190 tgl@sss.pgh.pa.us 3632 [ + + ]: 245 : for (num = num - 1; num > 1; num--)
3633 : : {
3634 : : /* this loop can take awhile, so allow it to be interrupted */
6905 3635 [ - + ]: 225 : CHECK_FOR_INTERRUPTS();
3636 : :
4064 andres@anarazel.de 3637 : 225 : int64_to_numericvar(num, &fact);
3638 : :
8190 tgl@sss.pgh.pa.us 3639 : 225 : mul_var(&result, &fact, &result, 0);
3640 : : }
3641 : :
3642 : 20 : res = make_result(&result);
3643 : :
8191 bruce@momjian.us 3644 : 20 : free_var(&fact);
3645 : 20 : free_var(&result);
3646 : :
3647 : 20 : PG_RETURN_NUMERIC(res);
3648 : : }
3649 : :
3650 : :
3651 : : /*
3652 : : * numeric_sqrt() -
3653 : : *
3654 : : * Compute the square root of a numeric.
3655 : : */
3656 : : Datum
9411 tgl@sss.pgh.pa.us 3657 : 108 : numeric_sqrt(PG_FUNCTION_ARGS)
3658 : : {
3659 : 108 : Numeric num = PG_GETARG_NUMERIC(0);
3660 : : Numeric res;
3661 : : NumericVar arg;
3662 : : NumericVar result;
3663 : : int sweight;
3664 : : int rscale;
3665 : :
3666 : : /*
3667 : : * Handle NaN and infinities
3668 : : */
2113 3669 [ + + ]: 108 : if (NUMERIC_IS_SPECIAL(num))
3670 : : {
3671 : : /* error should match that in sqrt_var() */
3672 [ + + ]: 12 : if (NUMERIC_IS_NINF(num))
3673 [ + - ]: 4 : ereport(ERROR,
3674 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
3675 : : errmsg("cannot take square root of a negative number")));
3676 : : /* For NAN or PINF, just duplicate the input */
3677 : 8 : PG_RETURN_NUMERIC(duplicate_numeric(num));
3678 : : }
3679 : :
3680 : : /*
3681 : : * Unpack the argument and determine the result scale. We choose a scale
3682 : : * to give at least NUMERIC_MIN_SIG_DIGITS significant digits; but in any
3683 : : * case not less than the input's dscale.
3684 : : */
4913 heikki.linnakangas@i 3685 : 96 : init_var_from_num(num, &arg);
3686 : :
3687 : 96 : init_var(&result);
3688 : :
3689 : : /*
3690 : : * Assume the input was normalized, so arg.weight is accurate. The result
3691 : : * then has at least sweight = floor(arg.weight * DEC_DIGITS / 2 + 1)
3692 : : * digits before the decimal point. When DEC_DIGITS is even, we can save
3693 : : * a few cycles, since the division is exact and there is no need to round
3694 : : * towards negative infinity.
3695 : : */
3696 : : #if DEC_DIGITS == ((DEC_DIGITS / 2) * 2)
1188 dean.a.rasheed@gmail 3697 : 96 : sweight = arg.weight * DEC_DIGITS / 2 + 1;
3698 : : #else
3699 : : if (arg.weight >= 0)
3700 : : sweight = arg.weight * DEC_DIGITS / 2 + 1;
3701 : : else
3702 : : sweight = 1 - (1 - arg.weight * DEC_DIGITS) / 2;
3703 : : #endif
3704 : :
8446 tgl@sss.pgh.pa.us 3705 : 96 : rscale = NUMERIC_MIN_SIG_DIGITS - sweight;
3706 : 96 : rscale = Max(rscale, arg.dscale);
3707 : 96 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
3708 : 96 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
3709 : :
3710 : : /*
3711 : : * Let sqrt_var() do the calculation and return the result.
3712 : : */
3713 : 96 : sqrt_var(&arg, &result, rscale);
3714 : :
9988 JanWieck@Yahoo.com 3715 : 92 : res = make_result(&result);
3716 : :
3717 : 92 : free_var(&result);
3718 : :
9411 tgl@sss.pgh.pa.us 3719 : 92 : PG_RETURN_NUMERIC(res);
3720 : : }
3721 : :
3722 : :
3723 : : /*
3724 : : * numeric_exp() -
3725 : : *
3726 : : * Raise e to the power of x
3727 : : */
3728 : : Datum
3729 : 65 : numeric_exp(PG_FUNCTION_ARGS)
3730 : : {
3731 : 65 : Numeric num = PG_GETARG_NUMERIC(0);
3732 : : Numeric res;
3733 : : NumericVar arg;
3734 : : NumericVar result;
3735 : : int rscale;
3736 : : double val;
3737 : :
3738 : : /*
3739 : : * Handle NaN and infinities
3740 : : */
2113 3741 [ + + ]: 65 : if (NUMERIC_IS_SPECIAL(num))
3742 : : {
3743 : : /* Per POSIX, exp(-Inf) is zero */
3744 [ + + ]: 15 : if (NUMERIC_IS_NINF(num))
3745 : 5 : PG_RETURN_NUMERIC(make_result(&const_zero));
3746 : : /* For NAN or PINF, just duplicate the input */
3747 : 10 : PG_RETURN_NUMERIC(duplicate_numeric(num));
3748 : : }
3749 : :
3750 : : /*
3751 : : * Unpack the argument and determine the result scale. We choose a scale
3752 : : * to give at least NUMERIC_MIN_SIG_DIGITS significant digits; but in any
3753 : : * case not less than the input's dscale.
3754 : : */
4913 heikki.linnakangas@i 3755 : 50 : init_var_from_num(num, &arg);
3756 : :
3757 : 50 : init_var(&result);
3758 : :
3759 : : /* convert input to float8, ignoring overflow */
8446 tgl@sss.pgh.pa.us 3760 : 50 : val = numericvar_to_double_no_overflow(&arg);
3761 : :
3762 : : /*
3763 : : * log10(result) = num * log10(e), so this is approximately the decimal
3764 : : * weight of the result:
3765 : : */
8616 3766 : 50 : val *= 0.434294481903252;
3767 : :
3768 : : /* limit to something that won't cause integer overflow */
3769 [ + + ]: 50 : val = Max(val, -NUMERIC_MAX_RESULT_SCALE);
3770 [ + - ]: 50 : val = Min(val, NUMERIC_MAX_RESULT_SCALE);
3771 : :
8446 3772 : 50 : rscale = NUMERIC_MIN_SIG_DIGITS - (int) val;
3773 : 50 : rscale = Max(rscale, arg.dscale);
3774 : 50 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
3775 : 50 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
3776 : :
3777 : : /*
3778 : : * Let exp_var() do the calculation and return the result.
3779 : : */
3780 : 50 : exp_var(&arg, &result, rscale);
3781 : :
9988 JanWieck@Yahoo.com 3782 : 50 : res = make_result(&result);
3783 : :
3784 : 50 : free_var(&result);
3785 : :
9411 tgl@sss.pgh.pa.us 3786 : 50 : PG_RETURN_NUMERIC(res);
3787 : : }
3788 : :
3789 : :
3790 : : /*
3791 : : * numeric_ln() -
3792 : : *
3793 : : * Compute the natural logarithm of x
3794 : : */
3795 : : Datum
3796 : 140 : numeric_ln(PG_FUNCTION_ARGS)
3797 : : {
3798 : 140 : Numeric num = PG_GETARG_NUMERIC(0);
3799 : : Numeric res;
3800 : : NumericVar arg;
3801 : : NumericVar result;
3802 : : int ln_dweight;
3803 : : int rscale;
3804 : :
3805 : : /*
3806 : : * Handle NaN and infinities
3807 : : */
2113 3808 [ + + ]: 140 : if (NUMERIC_IS_SPECIAL(num))
3809 : : {
3810 [ + + ]: 12 : if (NUMERIC_IS_NINF(num))
3811 [ + - ]: 4 : ereport(ERROR,
3812 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
3813 : : errmsg("cannot take logarithm of a negative number")));
3814 : : /* For NAN or PINF, just duplicate the input */
3815 : 8 : PG_RETURN_NUMERIC(duplicate_numeric(num));
3816 : : }
3817 : :
4913 heikki.linnakangas@i 3818 : 128 : init_var_from_num(num, &arg);
9988 JanWieck@Yahoo.com 3819 : 128 : init_var(&result);
3820 : :
3821 : : /* Estimated dweight of logarithm */
3825 tgl@sss.pgh.pa.us 3822 : 128 : ln_dweight = estimate_ln_dweight(&arg);
3823 : :
3824 : 128 : rscale = NUMERIC_MIN_SIG_DIGITS - ln_dweight;
8446 3825 : 128 : rscale = Max(rscale, arg.dscale);
3826 : 128 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
3827 : 128 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
3828 : :
3829 : 128 : ln_var(&arg, &result, rscale);
3830 : :
9988 JanWieck@Yahoo.com 3831 : 112 : res = make_result(&result);
3832 : :
3833 : 112 : free_var(&result);
3834 : :
9411 tgl@sss.pgh.pa.us 3835 : 112 : PG_RETURN_NUMERIC(res);
3836 : : }
3837 : :
3838 : :
3839 : : /*
3840 : : * numeric_log() -
3841 : : *
3842 : : * Compute the logarithm of x in a given base
3843 : : */
3844 : : Datum
3845 : 240 : numeric_log(PG_FUNCTION_ARGS)
3846 : : {
3847 : 240 : Numeric num1 = PG_GETARG_NUMERIC(0);
3848 : 240 : Numeric num2 = PG_GETARG_NUMERIC(1);
3849 : : Numeric res;
3850 : : NumericVar arg1;
3851 : : NumericVar arg2;
3852 : : NumericVar result;
3853 : :
3854 : : /*
3855 : : * Handle NaN and infinities
3856 : : */
2113 3857 [ + + + + ]: 240 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3858 : : {
3859 : : int sign1,
3860 : : sign2;
3861 : :
3862 [ + + + + ]: 84 : if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
3863 : 36 : PG_RETURN_NUMERIC(make_result(&const_nan));
3864 : : /* fail on negative inputs including -Inf, as log_var would */
3865 : 48 : sign1 = numeric_sign_internal(num1);
3866 : 48 : sign2 = numeric_sign_internal(num2);
3867 [ + + + + ]: 48 : if (sign1 < 0 || sign2 < 0)
3868 [ + - ]: 16 : ereport(ERROR,
3869 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
3870 : : errmsg("cannot take logarithm of a negative number")));
3871 : : /* fail on zero inputs, as log_var would */
3872 [ + - + + ]: 32 : if (sign1 == 0 || sign2 == 0)
3873 [ + - ]: 4 : ereport(ERROR,
3874 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
3875 : : errmsg("cannot take logarithm of zero")));
3876 [ + + ]: 28 : if (NUMERIC_IS_PINF(num1))
3877 : : {
3878 : : /* log(Inf, Inf) reduces to Inf/Inf, so it's NaN */
3879 [ + + ]: 12 : if (NUMERIC_IS_PINF(num2))
3880 : 4 : PG_RETURN_NUMERIC(make_result(&const_nan));
3881 : : /* log(Inf, finite-positive) is zero (we don't throw underflow) */
3882 : 8 : PG_RETURN_NUMERIC(make_result(&const_zero));
3883 : : }
3884 [ - + ]: 16 : Assert(NUMERIC_IS_PINF(num2));
3885 : : /* log(finite-positive, Inf) is Inf */
3886 : 16 : PG_RETURN_NUMERIC(make_result(&const_pinf));
3887 : : }
3888 : :
3889 : : /*
3890 : : * Initialize things
3891 : : */
4913 heikki.linnakangas@i 3892 : 156 : init_var_from_num(num1, &arg1);
3893 : 156 : init_var_from_num(num2, &arg2);
9988 JanWieck@Yahoo.com 3894 : 156 : init_var(&result);
3895 : :
3896 : : /*
3897 : : * Call log_var() to compute and return the result; note it handles scale
3898 : : * selection itself.
3899 : : */
3900 : 156 : log_var(&arg1, &arg2, &result);
3901 : :
3902 : 116 : res = make_result(&result);
3903 : :
3904 : 116 : free_var(&result);
3905 : :
9411 tgl@sss.pgh.pa.us 3906 : 116 : PG_RETURN_NUMERIC(res);
3907 : : }
3908 : :
3909 : :
3910 : : /*
3911 : : * numeric_power() -
3912 : : *
3913 : : * Raise x to the power of y
3914 : : */
3915 : : Datum
3916 : 1149 : numeric_power(PG_FUNCTION_ARGS)
3917 : : {
3918 : 1149 : Numeric num1 = PG_GETARG_NUMERIC(0);
3919 : 1149 : Numeric num2 = PG_GETARG_NUMERIC(1);
3920 : : Numeric res;
3921 : : NumericVar arg1;
3922 : : NumericVar arg2;
3923 : : NumericVar result;
3924 : : int sign1,
3925 : : sign2;
3926 : :
3927 : : /*
3928 : : * Handle NaN and infinities
3929 : : */
2113 3930 [ + + + + ]: 1149 : if (NUMERIC_IS_SPECIAL(num1) || NUMERIC_IS_SPECIAL(num2))
3931 : : {
3932 : : /*
3933 : : * We follow the POSIX spec for pow(3), which says that NaN ^ 0 = 1,
3934 : : * and 1 ^ NaN = 1, while all other cases with NaN inputs yield NaN
3935 : : * (with no error).
3936 : : */
3937 [ + + ]: 173 : if (NUMERIC_IS_NAN(num1))
3938 : : {
3939 [ + + ]: 39 : if (!NUMERIC_IS_SPECIAL(num2))
3940 : : {
3941 : 26 : init_var_from_num(num2, &arg2);
3942 [ + + ]: 26 : if (cmp_var(&arg2, &const_zero) == 0)
3943 : 9 : PG_RETURN_NUMERIC(make_result(&const_one));
3944 : : }
3945 : 30 : PG_RETURN_NUMERIC(make_result(&const_nan));
3946 : : }
3947 [ + + ]: 134 : if (NUMERIC_IS_NAN(num2))
3948 : : {
3949 [ + + ]: 30 : if (!NUMERIC_IS_SPECIAL(num1))
3950 : : {
3951 : 26 : init_var_from_num(num1, &arg1);
3952 [ + + ]: 26 : if (cmp_var(&arg1, &const_one) == 0)
3953 : 9 : PG_RETURN_NUMERIC(make_result(&const_one));
3954 : : }
3955 : 21 : PG_RETURN_NUMERIC(make_result(&const_nan));
3956 : : }
3957 : : /* At least one input is infinite, but error rules still apply */
3958 : 104 : sign1 = numeric_sign_internal(num1);
3959 : 104 : sign2 = numeric_sign_internal(num2);
3960 [ + + + + ]: 104 : if (sign1 == 0 && sign2 < 0)
3961 [ + - ]: 4 : ereport(ERROR,
3962 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
3963 : : errmsg("zero raised to a negative power is undefined")));
3964 [ + + + + ]: 100 : if (sign1 < 0 && !numeric_is_integral(num2))
3965 [ + - ]: 4 : ereport(ERROR,
3966 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
3967 : : errmsg("a negative number raised to a non-integer power yields a complex result")));
3968 : :
3969 : : /*
3970 : : * POSIX gives this series of rules for pow(3) with infinite inputs:
3971 : : *
3972 : : * For any value of y, if x is +1, 1.0 shall be returned.
3973 : : */
3974 [ + + ]: 96 : if (!NUMERIC_IS_SPECIAL(num1))
3975 : : {
3976 : 31 : init_var_from_num(num1, &arg1);
3977 [ + + ]: 31 : if (cmp_var(&arg1, &const_one) == 0)
2910 3978 : 4 : PG_RETURN_NUMERIC(make_result(&const_one));
3979 : : }
3980 : :
3981 : : /*
3982 : : * For any value of x, if y is [-]0, 1.0 shall be returned.
3983 : : */
2113 3984 [ + + ]: 92 : if (sign2 == 0)
2910 3985 : 9 : PG_RETURN_NUMERIC(make_result(&const_one));
3986 : :
3987 : : /*
3988 : : * For any odd integer value of y > 0, if x is [-]0, [-]0 shall be
3989 : : * returned. For y > 0 and not an odd integer, if x is [-]0, +0 shall
3990 : : * be returned. (Since we don't deal in minus zero, we need not
3991 : : * distinguish these two cases.)
3992 : : */
2113 3993 [ + + + - ]: 83 : if (sign1 == 0 && sign2 > 0)
3994 : 4 : PG_RETURN_NUMERIC(make_result(&const_zero));
3995 : :
3996 : : /*
3997 : : * If x is -1, and y is [-]Inf, 1.0 shall be returned.
3998 : : *
3999 : : * For |x| < 1, if y is -Inf, +Inf shall be returned.
4000 : : *
4001 : : * For |x| > 1, if y is -Inf, +0 shall be returned.
4002 : : *
4003 : : * For |x| < 1, if y is +Inf, +0 shall be returned.
4004 : : *
4005 : : * For |x| > 1, if y is +Inf, +Inf shall be returned.
4006 : : */
4007 [ + + ]: 79 : if (NUMERIC_IS_INF(num2))
4008 : : {
4009 : : bool abs_x_gt_one;
4010 : :
4011 [ + + ]: 42 : if (NUMERIC_IS_SPECIAL(num1))
4012 : 19 : abs_x_gt_one = true; /* x is either Inf or -Inf */
4013 : : else
4014 : : {
4015 : 23 : init_var_from_num(num1, &arg1);
4016 [ + + ]: 23 : if (cmp_var(&arg1, &const_minus_one) == 0)
4017 : 5 : PG_RETURN_NUMERIC(make_result(&const_one));
4018 : 18 : arg1.sign = NUMERIC_POS; /* now arg1 = abs(x) */
4019 : 18 : abs_x_gt_one = (cmp_var(&arg1, &const_one) > 0);
4020 : : }
4021 [ + + ]: 37 : if (abs_x_gt_one == (sign2 > 0))
4022 : 22 : PG_RETURN_NUMERIC(make_result(&const_pinf));
4023 : : else
4024 : 15 : PG_RETURN_NUMERIC(make_result(&const_zero));
4025 : : }
4026 : :
4027 : : /*
4028 : : * For y < 0, if x is +Inf, +0 shall be returned.
4029 : : *
4030 : : * For y > 0, if x is +Inf, +Inf shall be returned.
4031 : : */
4032 [ + + ]: 37 : if (NUMERIC_IS_PINF(num1))
4033 : : {
4034 [ + + ]: 17 : if (sign2 > 0)
4035 : 12 : PG_RETURN_NUMERIC(make_result(&const_pinf));
4036 : : else
4037 : 5 : PG_RETURN_NUMERIC(make_result(&const_zero));
4038 : : }
4039 : :
4040 [ - + ]: 20 : Assert(NUMERIC_IS_NINF(num1));
4041 : :
4042 : : /*
4043 : : * For y an odd integer < 0, if x is -Inf, -0 shall be returned. For
4044 : : * y < 0 and not an odd integer, if x is -Inf, +0 shall be returned.
4045 : : * (Again, we need not distinguish these two cases.)
4046 : : */
4047 [ + + ]: 20 : if (sign2 < 0)
4048 : 10 : PG_RETURN_NUMERIC(make_result(&const_zero));
4049 : :
4050 : : /*
4051 : : * For y an odd integer > 0, if x is -Inf, -Inf shall be returned. For
4052 : : * y > 0 and not an odd integer, if x is -Inf, +Inf shall be returned.
4053 : : */
4054 : 10 : init_var_from_num(num2, &arg2);
4055 [ + - + - ]: 10 : if (arg2.ndigits > 0 && arg2.ndigits == arg2.weight + 1 &&
4056 [ + + ]: 10 : (arg2.digits[arg2.ndigits - 1] & 1))
4057 : 5 : PG_RETURN_NUMERIC(make_result(&const_ninf));
4058 : : else
4059 : 5 : PG_RETURN_NUMERIC(make_result(&const_pinf));
4060 : : }
4061 : :
4062 : : /*
4063 : : * The SQL spec requires that we emit a particular SQLSTATE error code for
4064 : : * certain error conditions. Specifically, we don't return a
4065 : : * divide-by-zero error code for 0 ^ -1. Raising a negative number to a
4066 : : * non-integer power must produce the same error code, but that case is
4067 : : * handled in power_var().
4068 : : */
4069 : 976 : sign1 = numeric_sign_internal(num1);
4070 : 976 : sign2 = numeric_sign_internal(num2);
4071 : :
4072 [ + + + + ]: 976 : if (sign1 == 0 && sign2 < 0)
8024 neilc@samurai.com 4073 [ + - ]: 8 : ereport(ERROR,
4074 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
4075 : : errmsg("zero raised to a negative power is undefined")));
4076 : :
4077 : : /*
4078 : : * Initialize things
4079 : : */
2113 tgl@sss.pgh.pa.us 4080 : 968 : init_var(&result);
4081 : 968 : init_var_from_num(num1, &arg1);
4082 : 968 : init_var_from_num(num2, &arg2);
4083 : :
4084 : : /*
4085 : : * Call power_var() to compute and return the result; note it handles
4086 : : * scale selection itself.
4087 : : */
9988 JanWieck@Yahoo.com 4088 : 968 : power_var(&arg1, &arg2, &result);
4089 : :
4090 : 948 : res = make_result(&result);
4091 : :
4092 : 948 : free_var(&result);
4093 : :
9411 tgl@sss.pgh.pa.us 4094 : 948 : PG_RETURN_NUMERIC(res);
4095 : : }
4096 : :
4097 : : /*
4098 : : * numeric_scale() -
4099 : : *
4100 : : * Returns the scale, i.e. the count of decimal digits in the fractional part
4101 : : */
4102 : : Datum
3773 alvherre@alvh.no-ip. 4103 : 81 : numeric_scale(PG_FUNCTION_ARGS)
4104 : : {
4105 : 81 : Numeric num = PG_GETARG_NUMERIC(0);
4106 : :
2113 tgl@sss.pgh.pa.us 4107 [ + + ]: 81 : if (NUMERIC_IS_SPECIAL(num))
3773 alvherre@alvh.no-ip. 4108 : 14 : PG_RETURN_NULL();
4109 : :
4110 [ + - ]: 67 : PG_RETURN_INT32(NUMERIC_DSCALE(num));
4111 : : }
4112 : :
4113 : : /*
4114 : : * Calculate minimum scale for value.
4115 : : */
4116 : : static int
2311 tgl@sss.pgh.pa.us 4117 : 267 : get_min_scale(NumericVar *var)
4118 : : {
4119 : : int min_scale;
4120 : : int last_digit_pos;
4121 : :
4122 : : /*
4123 : : * Ordinarily, the input value will be "stripped" so that the last
4124 : : * NumericDigit is nonzero. But we don't want to get into an infinite
4125 : : * loop if it isn't, so explicitly find the last nonzero digit.
4126 : : */
4127 : 267 : last_digit_pos = var->ndigits - 1;
4128 [ + + ]: 267 : while (last_digit_pos >= 0 &&
4129 [ - + ]: 243 : var->digits[last_digit_pos] == 0)
2311 tgl@sss.pgh.pa.us 4130 :UBC 0 : last_digit_pos--;
4131 : :
2311 tgl@sss.pgh.pa.us 4132 [ + + ]:CBC 267 : if (last_digit_pos >= 0)
4133 : : {
4134 : : /* compute min_scale assuming that last ndigit has no zeroes */
4135 : 243 : min_scale = (last_digit_pos - var->weight) * DEC_DIGITS;
4136 : :
4137 : : /*
4138 : : * We could get a negative result if there are no digits after the
4139 : : * decimal point. In this case the min_scale must be zero.
4140 : : */
4141 [ + + ]: 243 : if (min_scale > 0)
4142 : : {
4143 : : /*
4144 : : * Reduce min_scale if trailing digit(s) in last NumericDigit are
4145 : : * zero.
4146 : : */
4147 : 135 : NumericDigit last_digit = var->digits[last_digit_pos];
4148 : :
4149 [ + + ]: 365 : while (last_digit % 10 == 0)
4150 : : {
4151 : 230 : min_scale--;
4152 : 230 : last_digit /= 10;
4153 : : }
4154 : : }
4155 : : else
4156 : 108 : min_scale = 0;
4157 : : }
4158 : : else
4159 : 24 : min_scale = 0; /* result if input is zero */
4160 : :
4161 : 267 : return min_scale;
4162 : : }
4163 : :
4164 : : /*
4165 : : * Returns minimum scale required to represent supplied value without loss.
4166 : : */
4167 : : Datum
4168 : 60 : numeric_min_scale(PG_FUNCTION_ARGS)
4169 : : {
4170 : 60 : Numeric num = PG_GETARG_NUMERIC(0);
4171 : : NumericVar arg;
4172 : : int min_scale;
4173 : :
2113 4174 [ + + ]: 60 : if (NUMERIC_IS_SPECIAL(num))
2311 4175 : 10 : PG_RETURN_NULL();
4176 : :
4177 : 50 : init_var_from_num(num, &arg);
4178 : 50 : min_scale = get_min_scale(&arg);
4179 : 50 : free_var(&arg);
4180 : :
4181 : 50 : PG_RETURN_INT32(min_scale);
4182 : : }
4183 : :
4184 : : /*
4185 : : * Reduce scale of numeric value to represent supplied value without loss.
4186 : : */
4187 : : Datum
4188 : 227 : numeric_trim_scale(PG_FUNCTION_ARGS)
4189 : : {
4190 : 227 : Numeric num = PG_GETARG_NUMERIC(0);
4191 : : Numeric res;
4192 : : NumericVar result;
4193 : :
2113 4194 [ + + ]: 227 : if (NUMERIC_IS_SPECIAL(num))
4195 : 10 : PG_RETURN_NUMERIC(duplicate_numeric(num));
4196 : :
2311 4197 : 217 : init_var_from_num(num, &result);
4198 : 217 : result.dscale = get_min_scale(&result);
4199 : 217 : res = make_result(&result);
4200 : 217 : free_var(&result);
4201 : :
4202 : 217 : PG_RETURN_NUMERIC(res);
4203 : : }
4204 : :
4205 : : /*
4206 : : * Return a random numeric value in the range [rmin, rmax].
4207 : : */
4208 : : Numeric
769 dean.a.rasheed@gmail 4209 : 22308 : random_numeric(pg_prng_state *state, Numeric rmin, Numeric rmax)
4210 : : {
4211 : : NumericVar rmin_var;
4212 : : NumericVar rmax_var;
4213 : : NumericVar result;
4214 : : Numeric res;
4215 : :
4216 : : /* Range bounds must not be NaN/infinity */
4217 [ + + ]: 22308 : if (NUMERIC_IS_SPECIAL(rmin))
4218 : : {
4219 [ + + ]: 8 : if (NUMERIC_IS_NAN(rmin))
4220 [ + - ]: 4 : ereport(ERROR,
4221 : : errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4222 : : errmsg("lower bound cannot be NaN"));
4223 : : else
4224 [ + - ]: 4 : ereport(ERROR,
4225 : : errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4226 : : errmsg("lower bound cannot be infinity"));
4227 : : }
4228 [ + + ]: 22300 : if (NUMERIC_IS_SPECIAL(rmax))
4229 : : {
4230 [ + + ]: 8 : if (NUMERIC_IS_NAN(rmax))
4231 [ + - ]: 4 : ereport(ERROR,
4232 : : errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4233 : : errmsg("upper bound cannot be NaN"));
4234 : : else
4235 [ + - ]: 4 : ereport(ERROR,
4236 : : errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4237 : : errmsg("upper bound cannot be infinity"));
4238 : : }
4239 : :
4240 : : /* Return a random value in the range [rmin, rmax] */
4241 : 22292 : init_var_from_num(rmin, &rmin_var);
4242 : 22292 : init_var_from_num(rmax, &rmax_var);
4243 : :
4244 : 22292 : init_var(&result);
4245 : :
4246 : 22292 : random_var(state, &rmin_var, &rmax_var, &result);
4247 : :
4248 : 22288 : res = make_result(&result);
4249 : :
4250 : 22288 : free_var(&result);
4251 : :
4252 : 22288 : return res;
4253 : : }
4254 : :
4255 : :
4256 : : /* ----------------------------------------------------------------------
4257 : : *
4258 : : * Type conversion functions
4259 : : *
4260 : : * ----------------------------------------------------------------------
4261 : : */
4262 : :
4263 : : Numeric
2064 peter@eisentraut.org 4264 : 1245079 : int64_to_numeric(int64 val)
4265 : : {
4266 : : Numeric res;
4267 : : NumericVar result;
4268 : :
9988 JanWieck@Yahoo.com 4269 : 1245079 : init_var(&result);
4270 : :
2064 peter@eisentraut.org 4271 : 1245079 : int64_to_numericvar(val, &result);
4272 : :
9988 JanWieck@Yahoo.com 4273 : 1245079 : res = make_result(&result);
4274 : :
4275 : 1245079 : free_var(&result);
4276 : :
2064 peter@eisentraut.org 4277 : 1245079 : return res;
4278 : : }
4279 : :
4280 : : /*
4281 : : * Convert val1/(10**log10val2) to numeric. This is much faster than normal
4282 : : * numeric division.
4283 : : */
4284 : : Numeric
1855 4285 : 15153 : int64_div_fast_to_numeric(int64 val1, int log10val2)
4286 : : {
4287 : : Numeric res;
4288 : : NumericVar result;
4289 : : int rscale;
4290 : : int w;
4291 : : int m;
4292 : :
1187 dean.a.rasheed@gmail 4293 : 15153 : init_var(&result);
4294 : :
4295 : : /* result scale */
4296 : 15153 : rscale = log10val2 < 0 ? 0 : log10val2;
4297 : :
4298 : : /* how much to decrease the weight by */
1855 peter@eisentraut.org 4299 : 15153 : w = log10val2 / DEC_DIGITS;
4300 : : /* how much is left to divide by */
4301 : 15153 : m = log10val2 % DEC_DIGITS;
1187 dean.a.rasheed@gmail 4302 [ - + ]: 15153 : if (m < 0)
4303 : : {
1187 dean.a.rasheed@gmail 4304 :UBC 0 : m += DEC_DIGITS;
4305 : 0 : w--;
4306 : : }
4307 : :
4308 : : /*
4309 : : * If there is anything left to divide by (10^m with 0 < m < DEC_DIGITS),
4310 : : * multiply the dividend by 10^(DEC_DIGITS - m), and shift the weight by
4311 : : * one more.
4312 : : */
1855 peter@eisentraut.org 4313 [ + - ]:CBC 15153 : if (m > 0)
4314 : : {
4315 : : #if DEC_DIGITS == 4
4316 : : static const int pow10[] = {1, 10, 100, 1000};
4317 : : #elif DEC_DIGITS == 2
4318 : : static const int pow10[] = {1, 10};
4319 : : #elif DEC_DIGITS == 1
4320 : : static const int pow10[] = {1};
4321 : : #else
4322 : : #error unsupported NBASE
4323 : : #endif
1187 dean.a.rasheed@gmail 4324 : 15153 : int64 factor = pow10[DEC_DIGITS - m];
4325 : : int64 new_val1;
4326 : :
4327 : : StaticAssertDecl(lengthof(pow10) == DEC_DIGITS, "mismatch with DEC_DIGITS");
4328 : :
4329 [ + + ]: 15153 : if (unlikely(pg_mul_s64_overflow(val1, factor, &new_val1)))
4330 : : {
4331 : : /* do the multiplication using 128-bit integers */
4332 : : INT128 tmp;
4333 : :
271 dean.a.rasheed@gmail 4334 :GNC 9 : tmp = int64_to_int128(0);
4335 : 9 : int128_add_int64_mul_int64(&tmp, val1, factor);
4336 : :
1187 dean.a.rasheed@gmail 4337 :CBC 9 : int128_to_numericvar(tmp, &result);
4338 : : }
4339 : : else
4340 : 15144 : int64_to_numericvar(new_val1, &result);
4341 : :
1855 peter@eisentraut.org 4342 : 15153 : w++;
4343 : : }
4344 : : else
1187 dean.a.rasheed@gmail 4345 :UBC 0 : int64_to_numericvar(val1, &result);
4346 : :
1855 peter@eisentraut.org 4347 :CBC 15153 : result.weight -= w;
1187 dean.a.rasheed@gmail 4348 : 15153 : result.dscale = rscale;
4349 : :
1855 peter@eisentraut.org 4350 : 15153 : res = make_result(&result);
4351 : :
4352 : 15153 : free_var(&result);
4353 : :
4354 : 15153 : return res;
4355 : : }
4356 : :
4357 : : Datum
2064 4358 : 1037336 : int4_numeric(PG_FUNCTION_ARGS)
4359 : : {
4360 : 1037336 : int32 val = PG_GETARG_INT32(0);
4361 : :
4362 : 1037336 : PG_RETURN_NUMERIC(int64_to_numeric(val));
4363 : : }
4364 : :
4365 : : /*
4366 : : * Internal version of numeric_int4() with support for soft error reporting.
4367 : : */
4368 : : int32
242 michael@paquier.xyz 4369 :GNC 4709 : numeric_int4_safe(Numeric num, Node *escontext)
4370 : : {
4371 : : NumericVar x;
4372 : : int32 result;
4373 : :
2113 tgl@sss.pgh.pa.us 4374 [ + + ]:CBC 4709 : if (NUMERIC_IS_SPECIAL(num))
4375 : : {
242 michael@paquier.xyz 4376 [ + + ]:GNC 12 : if (NUMERIC_IS_NAN(num))
4377 [ + - ]: 4 : ereturn(escontext, 0,
4378 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4379 : : errmsg("cannot convert NaN to %s", "integer")));
4380 : : else
4381 [ + - ]: 8 : ereturn(escontext, 0,
4382 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4383 : : errmsg("cannot convert infinity to %s", "integer")));
4384 : : }
4385 : :
4386 : : /* Convert to variable format, then convert to int4 */
4913 heikki.linnakangas@i 4387 :CBC 4697 : init_var_from_num(num, &x);
4388 : :
2607 akorotkov@postgresql 4389 [ + + ]: 4697 : if (!numericvar_to_int32(&x, &result))
242 michael@paquier.xyz 4390 [ + + ]:GNC 62 : ereturn(escontext, 0,
4391 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4392 : : errmsg("integer out of range")));
4393 : :
2607 akorotkov@postgresql 4394 :CBC 4635 : return result;
4395 : : }
4396 : :
4397 : : Datum
4398 : 3635 : numeric_int4(PG_FUNCTION_ARGS)
4399 : : {
4400 : 3635 : Numeric num = PG_GETARG_NUMERIC(0);
4401 : : int32 result;
4402 : :
42 peter@eisentraut.org 4403 :GNC 3635 : result = numeric_int4_safe(num, fcinfo->context);
4404 : :
4405 [ - + - - : 3615 : if (unlikely(SOFT_ERROR_OCCURRED(fcinfo->context)))
- - - + ]
42 peter@eisentraut.org 4406 :UNC 0 : PG_RETURN_NULL();
4407 : :
42 peter@eisentraut.org 4408 :GNC 3615 : PG_RETURN_INT32(result);
4409 : : }
4410 : :
4411 : : /*
4412 : : * Given a NumericVar, convert it to an int32. If the NumericVar
4413 : : * exceeds the range of an int32, false is returned, otherwise true is returned.
4414 : : * The input NumericVar is *not* free'd.
4415 : : */
4416 : : static bool
2607 akorotkov@postgresql 4417 :CBC 5198 : numericvar_to_int32(const NumericVar *var, int32 *result)
4418 : : {
4419 : : int64 val;
4420 : :
4064 andres@anarazel.de 4421 [ + + ]: 5198 : if (!numericvar_to_int64(var, &val))
2607 akorotkov@postgresql 4422 : 4 : return false;
4423 : :
1733 dean.a.rasheed@gmail 4424 [ + + + + ]: 5194 : if (unlikely(val < PG_INT32_MIN) || unlikely(val > PG_INT32_MAX))
4425 : 58 : return false;
4426 : :
4427 : : /* Down-convert to int4 */
2607 akorotkov@postgresql 4428 : 5136 : *result = (int32) val;
4429 : :
1733 dean.a.rasheed@gmail 4430 : 5136 : return true;
4431 : : }
4432 : :
4433 : : Datum
9423 tgl@sss.pgh.pa.us 4434 : 24587 : int8_numeric(PG_FUNCTION_ARGS)
4435 : : {
8446 4436 : 24587 : int64 val = PG_GETARG_INT64(0);
4437 : :
2064 peter@eisentraut.org 4438 : 24587 : PG_RETURN_NUMERIC(int64_to_numeric(val));
4439 : : }
4440 : :
4441 : : /*
4442 : : * Internal version of numeric_int8() with support for soft error reporting.
4443 : : */
4444 : : int64
242 michael@paquier.xyz 4445 :GNC 387 : numeric_int8_safe(Numeric num, Node *escontext)
4446 : : {
4447 : : NumericVar x;
4448 : : int64 result;
4449 : :
2113 tgl@sss.pgh.pa.us 4450 [ + + ]:CBC 387 : if (NUMERIC_IS_SPECIAL(num))
4451 : : {
242 michael@paquier.xyz 4452 [ + + ]:GNC 12 : if (NUMERIC_IS_NAN(num))
4453 [ + - ]: 4 : ereturn(escontext, 0,
4454 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4455 : : errmsg("cannot convert NaN to %s", "bigint")));
4456 : : else
4457 [ + - ]: 8 : ereturn(escontext, 0,
4458 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4459 : : errmsg("cannot convert infinity to %s", "bigint")));
4460 : : }
4461 : :
4462 : : /* Convert to variable format, then convert to int8 */
4913 heikki.linnakangas@i 4463 :CBC 375 : init_var_from_num(num, &x);
4464 : :
4064 andres@anarazel.de 4465 [ + + ]: 375 : if (!numericvar_to_int64(&x, &result))
242 michael@paquier.xyz 4466 [ + + ]:GNC 40 : ereturn(escontext, 0,
4467 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4468 : : errmsg("bigint out of range")));
4469 : :
853 peter@eisentraut.org 4470 :CBC 335 : return result;
4471 : : }
4472 : :
4473 : : Datum
4474 : 347 : numeric_int8(PG_FUNCTION_ARGS)
4475 : : {
4476 : 347 : Numeric num = PG_GETARG_NUMERIC(0);
4477 : : int64 result;
4478 : :
42 peter@eisentraut.org 4479 :GNC 347 : result = numeric_int8_safe(num, fcinfo->context);
4480 : :
4481 [ - + - - : 303 : if (unlikely(SOFT_ERROR_OCCURRED(fcinfo->context)))
- - - + ]
42 peter@eisentraut.org 4482 :UNC 0 : PG_RETURN_NULL();
4483 : :
42 peter@eisentraut.org 4484 :GNC 303 : PG_RETURN_INT64(result);
4485 : : }
4486 : :
4487 : :
4488 : : Datum
9465 tgl@sss.pgh.pa.us 4489 :CBC 5 : int2_numeric(PG_FUNCTION_ARGS)
4490 : : {
4491 : 5 : int16 val = PG_GETARG_INT16(0);
4492 : :
2064 peter@eisentraut.org 4493 : 5 : PG_RETURN_NUMERIC(int64_to_numeric(val));
4494 : : }
4495 : :
4496 : :
4497 : : Datum
9465 tgl@sss.pgh.pa.us 4498 : 73 : numeric_int2(PG_FUNCTION_ARGS)
4499 : : {
4500 : 73 : Numeric num = PG_GETARG_NUMERIC(0);
4501 : : NumericVar x;
4502 : : int64 val;
4503 : : int16 result;
4504 : :
2113 4505 [ + + ]: 73 : if (NUMERIC_IS_SPECIAL(num))
4506 : : {
4507 [ + + ]: 12 : if (NUMERIC_IS_NAN(num))
42 peter@eisentraut.org 4508 [ + - ]:GNC 4 : ereturn(fcinfo->context, (Datum) 0,
4509 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4510 : : errmsg("cannot convert NaN to %s", "smallint")));
4511 : : else
4512 [ + - ]: 8 : ereturn(fcinfo->context, (Datum) 0,
4513 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4514 : : errmsg("cannot convert infinity to %s", "smallint")));
4515 : : }
4516 : :
4517 : : /* Convert to variable format and thence to int8 */
4913 heikki.linnakangas@i 4518 :CBC 61 : init_var_from_num(num, &x);
4519 : :
4064 andres@anarazel.de 4520 [ - + ]: 61 : if (!numericvar_to_int64(&x, &val))
42 peter@eisentraut.org 4521 [ # # ]:UNC 0 : ereturn(fcinfo->context, (Datum) 0,
4522 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4523 : : errmsg("smallint out of range")));
4524 : :
1733 dean.a.rasheed@gmail 4525 [ + + + + ]:CBC 61 : if (unlikely(val < PG_INT16_MIN) || unlikely(val > PG_INT16_MAX))
42 peter@eisentraut.org 4526 [ + - ]:GNC 8 : ereturn(fcinfo->context, (Datum) 0,
4527 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
4528 : : errmsg("smallint out of range")));
4529 : :
4530 : : /* Down-convert to int2 */
1733 dean.a.rasheed@gmail 4531 :CBC 53 : result = (int16) val;
4532 : :
8446 tgl@sss.pgh.pa.us 4533 : 53 : PG_RETURN_INT16(result);
4534 : : }
4535 : :
4536 : :
4537 : : Datum
9411 4538 : 654 : float8_numeric(PG_FUNCTION_ARGS)
4539 : : {
4540 : 654 : float8 val = PG_GETARG_FLOAT8(0);
4541 : : Numeric res;
4542 : : NumericVar result;
4543 : : char buf[DBL_DIG + 100];
4544 : : const char *endptr;
4545 : :
4546 [ + + ]: 654 : if (isnan(val))
4547 : 5 : PG_RETURN_NUMERIC(make_result(&const_nan));
4548 : :
3142 4549 [ + + ]: 649 : if (isinf(val))
4550 : : {
2113 4551 [ + + ]: 10 : if (val < 0)
4552 : 5 : PG_RETURN_NUMERIC(make_result(&const_ninf));
4553 : : else
4554 : 5 : PG_RETURN_NUMERIC(make_result(&const_pinf));
4555 : : }
4556 : :
3142 4557 : 639 : snprintf(buf, sizeof(buf), "%.*g", DBL_DIG, val);
4558 : :
9988 JanWieck@Yahoo.com 4559 : 639 : init_var(&result);
4560 : :
4561 : : /* Assume we need not worry about leading/trailing spaces */
42 peter@eisentraut.org 4562 [ - + ]:GNC 639 : if (!set_var_from_str(buf, buf, &result, &endptr, fcinfo->context))
42 peter@eisentraut.org 4563 :UNC 0 : PG_RETURN_NULL();
4564 : :
9988 JanWieck@Yahoo.com 4565 :CBC 639 : res = make_result(&result);
4566 : :
4567 : 639 : free_var(&result);
4568 : :
9411 tgl@sss.pgh.pa.us 4569 : 639 : PG_RETURN_NUMERIC(res);
4570 : : }
4571 : :
4572 : :
4573 : : Datum
4574 : 347489 : numeric_float8(PG_FUNCTION_ARGS)
4575 : : {
4576 : 347489 : Numeric num = PG_GETARG_NUMERIC(0);
4577 : : char *tmp;
4578 : : Datum result;
4579 : :
2113 4580 [ + + ]: 347489 : if (NUMERIC_IS_SPECIAL(num))
4581 : : {
4582 [ + + ]: 56 : if (NUMERIC_IS_PINF(num))
4583 : 17 : PG_RETURN_FLOAT8(get_float8_infinity());
4584 [ + + ]: 39 : else if (NUMERIC_IS_NINF(num))
4585 : 17 : PG_RETURN_FLOAT8(-get_float8_infinity());
4586 : : else
4587 : 22 : PG_RETURN_FLOAT8(get_float8_nan());
4588 : : }
4589 : :
9457 4590 : 347433 : tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
4591 : : NumericGetDatum(num)));
42 peter@eisentraut.org 4592 [ - + ]:GNC 347433 : if (!DirectInputFunctionCallSafe(float8in, tmp,
4593 : : InvalidOid, -1,
4594 : : (Node *) fcinfo->context,
4595 : : &result))
4596 : : {
42 peter@eisentraut.org 4597 :UNC 0 : pfree(tmp);
4598 : 0 : PG_RETURN_NULL();
4599 : : }
4600 : :
9408 tgl@sss.pgh.pa.us 4601 :CBC 347433 : PG_RETURN_DATUM(result);
4602 : : }
4603 : :
4604 : :
4605 : : /*
4606 : : * Convert numeric to float8; if out of range, return +/- HUGE_VAL
4607 : : *
4608 : : * (internal helper function, not directly callable from SQL)
4609 : : */
4610 : : Datum
8970 4611 : 22 : numeric_float8_no_overflow(PG_FUNCTION_ARGS)
4612 : : {
4613 : 22 : Numeric num = PG_GETARG_NUMERIC(0);
4614 : : double val;
4615 : :
2113 4616 [ - + ]: 22 : if (NUMERIC_IS_SPECIAL(num))
4617 : : {
2113 tgl@sss.pgh.pa.us 4618 [ # # ]:UBC 0 : if (NUMERIC_IS_PINF(num))
4619 : 0 : val = HUGE_VAL;
4620 [ # # ]: 0 : else if (NUMERIC_IS_NINF(num))
4621 : 0 : val = -HUGE_VAL;
4622 : : else
4623 : 0 : val = get_float8_nan();
4624 : : }
4625 : : else
4626 : : {
4627 : : NumericVar x;
4628 : :
2113 tgl@sss.pgh.pa.us 4629 :CBC 22 : init_var_from_num(num, &x);
4630 : 22 : val = numericvar_to_double_no_overflow(&x);
4631 : : }
4632 : :
8970 4633 : 22 : PG_RETURN_FLOAT8(val);
4634 : : }
4635 : :
4636 : : Datum
9411 4637 : 15060 : float4_numeric(PG_FUNCTION_ARGS)
4638 : : {
4639 : 15060 : float4 val = PG_GETARG_FLOAT4(0);
4640 : : Numeric res;
4641 : : NumericVar result;
4642 : : char buf[FLT_DIG + 100];
4643 : : const char *endptr;
4644 : :
4645 [ + + ]: 15060 : if (isnan(val))
4646 : 5 : PG_RETURN_NUMERIC(make_result(&const_nan));
4647 : :
3142 4648 [ + + ]: 15055 : if (isinf(val))
4649 : : {
2113 4650 [ + + ]: 10 : if (val < 0)
4651 : 5 : PG_RETURN_NUMERIC(make_result(&const_ninf));
4652 : : else
4653 : 5 : PG_RETURN_NUMERIC(make_result(&const_pinf));
4654 : : }
4655 : :
3142 4656 : 15045 : snprintf(buf, sizeof(buf), "%.*g", FLT_DIG, val);
4657 : :
9988 JanWieck@Yahoo.com 4658 : 15045 : init_var(&result);
4659 : :
4660 : : /* Assume we need not worry about leading/trailing spaces */
42 peter@eisentraut.org 4661 [ - + ]:GNC 15045 : if (!set_var_from_str(buf, buf, &result, &endptr, fcinfo->context))
42 peter@eisentraut.org 4662 :UNC 0 : PG_RETURN_NULL();
4663 : :
9988 JanWieck@Yahoo.com 4664 :CBC 15045 : res = make_result(&result);
4665 : :
4666 : 15045 : free_var(&result);
4667 : :
9411 tgl@sss.pgh.pa.us 4668 : 15045 : PG_RETURN_NUMERIC(res);
4669 : : }
4670 : :
4671 : :
4672 : : Datum
4673 : 1701 : numeric_float4(PG_FUNCTION_ARGS)
4674 : : {
4675 : 1701 : Numeric num = PG_GETARG_NUMERIC(0);
4676 : : char *tmp;
4677 : : Datum result;
4678 : :
2113 4679 [ + + ]: 1701 : if (NUMERIC_IS_SPECIAL(num))
4680 : : {
4681 [ + + ]: 56 : if (NUMERIC_IS_PINF(num))
4682 : 17 : PG_RETURN_FLOAT4(get_float4_infinity());
4683 [ + + ]: 39 : else if (NUMERIC_IS_NINF(num))
4684 : 17 : PG_RETURN_FLOAT4(-get_float4_infinity());
4685 : : else
4686 : 22 : PG_RETURN_FLOAT4(get_float4_nan());
4687 : : }
4688 : :
9457 4689 : 1645 : tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
4690 : : NumericGetDatum(num)));
4691 : :
42 peter@eisentraut.org 4692 [ - + ]:GNC 1645 : if (!DirectInputFunctionCallSafe(float4in, tmp,
4693 : : InvalidOid, -1,
4694 : : (Node *) fcinfo->context,
4695 : : &result))
4696 : : {
42 peter@eisentraut.org 4697 :UNC 0 : pfree(tmp);
4698 : 0 : PG_RETURN_NULL();
4699 : : }
4700 : :
9988 JanWieck@Yahoo.com 4701 :CBC 1645 : pfree(tmp);
4702 : :
9408 tgl@sss.pgh.pa.us 4703 : 1645 : PG_RETURN_DATUM(result);
4704 : : }
4705 : :
4706 : :
4707 : : Datum
2135 fujii@postgresql.org 4708 : 103 : numeric_pg_lsn(PG_FUNCTION_ARGS)
4709 : : {
4710 : 103 : Numeric num = PG_GETARG_NUMERIC(0);
4711 : : NumericVar x;
4712 : : XLogRecPtr result;
4713 : :
2113 tgl@sss.pgh.pa.us 4714 [ + + ]: 103 : if (NUMERIC_IS_SPECIAL(num))
4715 : : {
4716 [ + - ]: 4 : if (NUMERIC_IS_NAN(num))
4717 [ + - ]: 4 : ereport(ERROR,
4718 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4719 : : errmsg("cannot convert NaN to %s", "pg_lsn")));
4720 : : else
2113 tgl@sss.pgh.pa.us 4721 [ # # ]:UBC 0 : ereport(ERROR,
4722 : : (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4723 : : errmsg("cannot convert infinity to %s", "pg_lsn")));
4724 : : }
4725 : :
4726 : : /* Convert to variable format and thence to pg_lsn */
2135 fujii@postgresql.org 4727 :CBC 99 : init_var_from_num(num, &x);
4728 : :
4729 [ + + ]: 99 : if (!numericvar_to_uint64(&x, (uint64 *) &result))
4730 [ + - ]: 16 : ereport(ERROR,
4731 : : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
4732 : : errmsg("pg_lsn out of range")));
4733 : :
4734 : 83 : PG_RETURN_LSN(result);
4735 : : }
4736 : :
4737 : :
4738 : : /* ----------------------------------------------------------------------
4739 : : *
4740 : : * Aggregate functions
4741 : : *
4742 : : * The transition datatype for all these aggregates is declared as INTERNAL.
4743 : : * Actually, it's a pointer to a NumericAggState allocated in the aggregate
4744 : : * context. The digit buffers for the NumericVars will be there too.
4745 : : *
4746 : : * For integer inputs, some aggregates use special-purpose 64-bit or 128-bit
4747 : : * integer based transition datatypes to speed up calculations.
4748 : : *
4749 : : * ----------------------------------------------------------------------
4750 : : */
4751 : :
4752 : : typedef struct NumericAggState
4753 : : {
4754 : : bool calcSumX2; /* if true, calculate sumX2 */
4755 : : MemoryContext agg_context; /* context we're calculating in */
4756 : : int64 N; /* count of processed numbers */
4757 : : NumericSumAccum sumX; /* sum of processed numbers */
4758 : : NumericSumAccum sumX2; /* sum of squares of processed numbers */
4759 : : int maxScale; /* maximum scale seen so far */
4760 : : int64 maxScaleCount; /* number of values seen with maximum scale */
4761 : : /* These counts are *not* included in N! Use NA_TOTAL_COUNT() as needed */
4762 : : int64 NaNcount; /* count of NaN values */
4763 : : int64 pInfcount; /* count of +Inf values */
4764 : : int64 nInfcount; /* count of -Inf values */
4765 : : } NumericAggState;
4766 : :
4767 : : #define NA_TOTAL_COUNT(na) \
4768 : : ((na)->N + (na)->NaNcount + (na)->pInfcount + (na)->nInfcount)
4769 : :
4770 : : /*
4771 : : * Prepare state data for a numeric aggregate function that needs to compute
4772 : : * sum, count and optionally sum of squares of the input.
4773 : : */
4774 : : static NumericAggState *
4553 tgl@sss.pgh.pa.us 4775 : 114082 : makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
4776 : : {
4777 : : NumericAggState *state;
4778 : : MemoryContext agg_context;
4779 : : MemoryContext old_context;
4780 : :
4781 [ - + ]: 114082 : if (!AggCheckCallContext(fcinfo, &agg_context))
4553 tgl@sss.pgh.pa.us 4782 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
4783 : :
4553 tgl@sss.pgh.pa.us 4784 :CBC 114082 : old_context = MemoryContextSwitchTo(agg_context);
4785 : :
146 michael@paquier.xyz 4786 :GNC 114082 : state = palloc0_object(NumericAggState);
4553 tgl@sss.pgh.pa.us 4787 :CBC 114082 : state->calcSumX2 = calcSumX2;
4788 : 114082 : state->agg_context = agg_context;
4789 : :
4790 : 114082 : MemoryContextSwitchTo(old_context);
4791 : :
4792 : 114082 : return state;
4793 : : }
4794 : :
4795 : : /*
4796 : : * Like makeNumericAggState(), but allocate the state in the current memory
4797 : : * context.
4798 : : */
4799 : : static NumericAggState *
3603 4800 : 56 : makeNumericAggStateCurrentContext(bool calcSumX2)
4801 : : {
4802 : : NumericAggState *state;
4803 : :
146 michael@paquier.xyz 4804 :GNC 56 : state = palloc0_object(NumericAggState);
3603 tgl@sss.pgh.pa.us 4805 :CBC 56 : state->calcSumX2 = calcSumX2;
4806 : 56 : state->agg_context = CurrentMemoryContext;
4807 : :
4808 : 56 : return state;
4809 : : }
4810 : :
4811 : : /*
4812 : : * Accumulate a new input value for numeric aggregate functions.
4813 : : */
4814 : : static void
4553 4815 : 1409012 : do_numeric_accum(NumericAggState *state, Numeric newval)
4816 : : {
4817 : : NumericVar X;
4818 : : NumericVar X2;
4819 : : MemoryContext old_context;
4820 : :
4821 : : /* Count NaN/infinity inputs separately from all else */
2113 4822 [ + + ]: 1409012 : if (NUMERIC_IS_SPECIAL(newval))
4823 : : {
4824 [ + + ]: 108 : if (NUMERIC_IS_PINF(newval))
4825 : 48 : state->pInfcount++;
4826 [ + + ]: 60 : else if (NUMERIC_IS_NINF(newval))
4827 : 24 : state->nInfcount++;
4828 : : else
4829 : 36 : state->NaNcount++;
4553 4830 : 108 : return;
4831 : : }
4832 : :
4833 : : /* load processed number in short-lived context */
4834 : 1408904 : init_var_from_num(newval, &X);
4835 : :
4836 : : /*
4837 : : * Track the highest input dscale that we've seen, to support inverse
4838 : : * transitions (see do_numeric_discard).
4839 : : */
4406 4840 [ + + ]: 1408904 : if (X.dscale > state->maxScale)
4841 : : {
4842 : 104 : state->maxScale = X.dscale;
4843 : 104 : state->maxScaleCount = 1;
4844 : : }
4845 [ + + ]: 1408800 : else if (X.dscale == state->maxScale)
4846 : 1408776 : state->maxScaleCount++;
4847 : :
4848 : : /* if we need X^2, calculate that in short-lived context */
4553 4849 [ + + ]: 1408904 : if (state->calcSumX2)
4850 : : {
4851 : 160488 : init_var(&X2);
4852 : 160488 : mul_var(&X, &X, &X2, X.dscale * 2);
4853 : : }
4854 : :
4855 : : /* The rest of this needs to work in the aggregate context */
4856 : 1408904 : old_context = MemoryContextSwitchTo(state->agg_context);
4857 : :
3532 heikki.linnakangas@i 4858 : 1408904 : state->N++;
4859 : :
4860 : : /* Accumulate sums */
4861 : 1408904 : accum_sum_add(&(state->sumX), &X);
4862 : :
4863 [ + + ]: 1408904 : if (state->calcSumX2)
4864 : 160488 : accum_sum_add(&(state->sumX2), &X2);
4865 : :
4553 tgl@sss.pgh.pa.us 4866 : 1408904 : MemoryContextSwitchTo(old_context);
4867 : : }
4868 : :
4869 : : /*
4870 : : * Attempt to remove an input value from the aggregated state.
4871 : : *
4872 : : * If the value cannot be removed then the function will return false; the
4873 : : * possible reasons for failing are described below.
4874 : : *
4875 : : * If we aggregate the values 1.01 and 2 then the result will be 3.01.
4876 : : * If we are then asked to un-aggregate the 1.01 then we must fail as we
4877 : : * won't be able to tell what the new aggregated value's dscale should be.
4878 : : * We don't want to return 2.00 (dscale = 2), since the sum's dscale would
4879 : : * have been zero if we'd really aggregated only 2.
4880 : : *
4881 : : * Note: alternatively, we could count the number of inputs with each possible
4882 : : * dscale (up to some sane limit). Not yet clear if it's worth the trouble.
4883 : : */
4884 : : static bool
4406 4885 : 228 : do_numeric_discard(NumericAggState *state, Numeric newval)
4886 : : {
4887 : : NumericVar X;
4888 : : NumericVar X2;
4889 : : MemoryContext old_context;
4890 : :
4891 : : /* Count NaN/infinity inputs separately from all else */
2113 4892 [ + + ]: 228 : if (NUMERIC_IS_SPECIAL(newval))
4893 : : {
4894 [ - + ]: 4 : if (NUMERIC_IS_PINF(newval))
2113 tgl@sss.pgh.pa.us 4895 :UBC 0 : state->pInfcount--;
2113 tgl@sss.pgh.pa.us 4896 [ - + ]:CBC 4 : else if (NUMERIC_IS_NINF(newval))
2113 tgl@sss.pgh.pa.us 4897 :UBC 0 : state->nInfcount--;
4898 : : else
2113 tgl@sss.pgh.pa.us 4899 :CBC 4 : state->NaNcount--;
4406 4900 : 4 : return true;
4901 : : }
4902 : :
4903 : : /* load processed number in short-lived context */
4904 : 224 : init_var_from_num(newval, &X);
4905 : :
4906 : : /*
4907 : : * state->sumX's dscale is the maximum dscale of any of the inputs.
4908 : : * Removing the last input with that dscale would require us to recompute
4909 : : * the maximum dscale of the *remaining* inputs, which we cannot do unless
4910 : : * no more non-NaN inputs remain at all. So we report a failure instead,
4911 : : * and force the aggregation to be redone from scratch.
4912 : : */
4913 [ + - ]: 224 : if (X.dscale == state->maxScale)
4914 : : {
4915 [ + + + + ]: 224 : if (state->maxScaleCount > 1 || state->maxScale == 0)
4916 : : {
4917 : : /*
4918 : : * Some remaining inputs have same dscale, or dscale hasn't gotten
4919 : : * above zero anyway
4920 : : */
4921 : 212 : state->maxScaleCount--;
4922 : : }
4923 [ + + ]: 12 : else if (state->N == 1)
4924 : : {
4925 : : /* No remaining non-NaN inputs at all, so reset maxScale */
4926 : 8 : state->maxScale = 0;
4927 : 8 : state->maxScaleCount = 0;
4928 : : }
4929 : : else
4930 : : {
4931 : : /* Correct new maxScale is uncertain, must fail */
4932 : 4 : return false;
4933 : : }
4934 : : }
4935 : :
4936 : : /* if we need X^2, calculate that in short-lived context */
4937 [ + + ]: 220 : if (state->calcSumX2)
4938 : : {
4939 : 192 : init_var(&X2);
4940 : 192 : mul_var(&X, &X, &X2, X.dscale * 2);
4941 : : }
4942 : :
4943 : : /* The rest of this needs to work in the aggregate context */
4944 : 220 : old_context = MemoryContextSwitchTo(state->agg_context);
4945 : :
4946 [ + + ]: 220 : if (state->N-- > 1)
4947 : : {
4948 : : /* Negate X, to subtract it from the sum */
3532 heikki.linnakangas@i 4949 [ + - ]: 208 : X.sign = (X.sign == NUMERIC_POS ? NUMERIC_NEG : NUMERIC_POS);
4950 : 208 : accum_sum_add(&(state->sumX), &X);
4951 : :
4406 tgl@sss.pgh.pa.us 4952 [ + + ]: 208 : if (state->calcSumX2)
4953 : : {
4954 : : /* Negate X^2. X^2 is always positive */
3532 heikki.linnakangas@i 4955 : 192 : X2.sign = NUMERIC_NEG;
4956 : 192 : accum_sum_add(&(state->sumX2), &X2);
4957 : : }
4958 : : }
4959 : : else
4960 : : {
4961 : : /* Zero the sums */
4406 tgl@sss.pgh.pa.us 4962 [ - + ]: 12 : Assert(state->N == 0);
4963 : :
3532 heikki.linnakangas@i 4964 : 12 : accum_sum_reset(&state->sumX);
4965 [ - + ]: 12 : if (state->calcSumX2)
3532 heikki.linnakangas@i 4966 :UBC 0 : accum_sum_reset(&state->sumX2);
4967 : : }
4968 : :
4406 tgl@sss.pgh.pa.us 4969 :CBC 220 : MemoryContextSwitchTo(old_context);
4970 : :
4971 : 220 : return true;
4972 : : }
4973 : :
4974 : : /*
4975 : : * Generic transition function for numeric aggregates that require sumX2.
4976 : : */
4977 : : Datum
9423 4978 : 428 : numeric_accum(PG_FUNCTION_ARGS)
4979 : : {
4980 : : NumericAggState *state;
4981 : :
4553 4982 [ + + ]: 428 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
4983 : :
4984 : : /* Create the state data on the first call */
4406 4985 [ + + ]: 428 : if (state == NULL)
4986 : 116 : state = makeNumericAggState(fcinfo, true);
4987 : :
4988 [ + + ]: 428 : if (!PG_ARGISNULL(1))
4553 4989 : 416 : do_numeric_accum(state, PG_GETARG_NUMERIC(1));
4990 : :
4991 : 428 : PG_RETURN_POINTER(state);
4992 : : }
4993 : :
4994 : : /*
4995 : : * Generic combine function for numeric aggregates which require sumX2
4996 : : */
4997 : : Datum
3682 rhaas@postgresql.org 4998 : 24 : numeric_combine(PG_FUNCTION_ARGS)
4999 : : {
5000 : : NumericAggState *state1;
5001 : : NumericAggState *state2;
5002 : : MemoryContext agg_context;
5003 : : MemoryContext old_context;
5004 : :
5005 [ - + ]: 24 : if (!AggCheckCallContext(fcinfo, &agg_context))
3682 rhaas@postgresql.org 5006 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5007 : :
3682 rhaas@postgresql.org 5008 [ + + ]:CBC 24 : state1 = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5009 [ + - ]: 24 : state2 = PG_ARGISNULL(1) ? NULL : (NumericAggState *) PG_GETARG_POINTER(1);
5010 : :
5011 [ - + ]: 24 : if (state2 == NULL)
3682 rhaas@postgresql.org 5012 :UBC 0 : PG_RETURN_POINTER(state1);
5013 : :
5014 : : /* manually copy all fields from state2 to state1 */
3682 rhaas@postgresql.org 5015 [ + + ]:CBC 24 : if (state1 == NULL)
5016 : : {
5017 : 12 : old_context = MemoryContextSwitchTo(agg_context);
5018 : :
3603 tgl@sss.pgh.pa.us 5019 : 12 : state1 = makeNumericAggStateCurrentContext(true);
3682 rhaas@postgresql.org 5020 : 12 : state1->N = state2->N;
5021 : 12 : state1->NaNcount = state2->NaNcount;
2113 tgl@sss.pgh.pa.us 5022 : 12 : state1->pInfcount = state2->pInfcount;
5023 : 12 : state1->nInfcount = state2->nInfcount;
3682 rhaas@postgresql.org 5024 : 12 : state1->maxScale = state2->maxScale;
5025 : 12 : state1->maxScaleCount = state2->maxScaleCount;
5026 : :
3532 heikki.linnakangas@i 5027 : 12 : accum_sum_copy(&state1->sumX, &state2->sumX);
5028 : 12 : accum_sum_copy(&state1->sumX2, &state2->sumX2);
5029 : :
3682 rhaas@postgresql.org 5030 : 12 : MemoryContextSwitchTo(old_context);
5031 : :
5032 : 12 : PG_RETURN_POINTER(state1);
5033 : : }
5034 : :
2154 tgl@sss.pgh.pa.us 5035 : 12 : state1->N += state2->N;
5036 : 12 : state1->NaNcount += state2->NaNcount;
2113 5037 : 12 : state1->pInfcount += state2->pInfcount;
5038 : 12 : state1->nInfcount += state2->nInfcount;
5039 : :
3682 rhaas@postgresql.org 5040 [ + - ]: 12 : if (state2->N > 0)
5041 : : {
5042 : : /*
5043 : : * These are currently only needed for moving aggregates, but let's do
5044 : : * the right thing anyway...
5045 : : */
5046 [ - + ]: 12 : if (state2->maxScale > state1->maxScale)
5047 : : {
3682 rhaas@postgresql.org 5048 :UBC 0 : state1->maxScale = state2->maxScale;
5049 : 0 : state1->maxScaleCount = state2->maxScaleCount;
5050 : : }
3682 rhaas@postgresql.org 5051 [ + - ]:CBC 12 : else if (state2->maxScale == state1->maxScale)
5052 : 12 : state1->maxScaleCount += state2->maxScaleCount;
5053 : :
5054 : : /* The rest of this needs to work in the aggregate context */
5055 : 12 : old_context = MemoryContextSwitchTo(agg_context);
5056 : :
5057 : : /* Accumulate sums */
3532 heikki.linnakangas@i 5058 : 12 : accum_sum_combine(&state1->sumX, &state2->sumX);
5059 : 12 : accum_sum_combine(&state1->sumX2, &state2->sumX2);
5060 : :
3682 rhaas@postgresql.org 5061 : 12 : MemoryContextSwitchTo(old_context);
5062 : : }
5063 : 12 : PG_RETURN_POINTER(state1);
5064 : : }
5065 : :
5066 : : /*
5067 : : * Generic transition function for numeric aggregates that don't require sumX2.
5068 : : */
5069 : : Datum
7017 bruce@momjian.us 5070 : 1248516 : numeric_avg_accum(PG_FUNCTION_ARGS)
5071 : : {
5072 : : NumericAggState *state;
5073 : :
4553 tgl@sss.pgh.pa.us 5074 [ + + ]: 1248516 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5075 : :
5076 : : /* Create the state data on the first call */
4406 5077 [ + + ]: 1248516 : if (state == NULL)
5078 : 113926 : state = makeNumericAggState(fcinfo, false);
5079 : :
5080 [ + + ]: 1248516 : if (!PG_ARGISNULL(1))
4553 5081 : 1248476 : do_numeric_accum(state, PG_GETARG_NUMERIC(1));
5082 : :
4406 5083 : 1248516 : PG_RETURN_POINTER(state);
5084 : : }
5085 : :
5086 : : /*
5087 : : * Combine function for numeric aggregates which don't require sumX2
5088 : : */
5089 : : Datum
3682 rhaas@postgresql.org 5090 : 16 : numeric_avg_combine(PG_FUNCTION_ARGS)
5091 : : {
5092 : : NumericAggState *state1;
5093 : : NumericAggState *state2;
5094 : : MemoryContext agg_context;
5095 : : MemoryContext old_context;
5096 : :
5097 [ - + ]: 16 : if (!AggCheckCallContext(fcinfo, &agg_context))
3682 rhaas@postgresql.org 5098 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5099 : :
3682 rhaas@postgresql.org 5100 [ + + ]:CBC 16 : state1 = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5101 [ + - ]: 16 : state2 = PG_ARGISNULL(1) ? NULL : (NumericAggState *) PG_GETARG_POINTER(1);
5102 : :
5103 [ - + ]: 16 : if (state2 == NULL)
3682 rhaas@postgresql.org 5104 :UBC 0 : PG_RETURN_POINTER(state1);
5105 : :
5106 : : /* manually copy all fields from state2 to state1 */
3682 rhaas@postgresql.org 5107 [ + + ]:CBC 16 : if (state1 == NULL)
5108 : : {
5109 : 4 : old_context = MemoryContextSwitchTo(agg_context);
5110 : :
3603 tgl@sss.pgh.pa.us 5111 : 4 : state1 = makeNumericAggStateCurrentContext(false);
3682 rhaas@postgresql.org 5112 : 4 : state1->N = state2->N;
5113 : 4 : state1->NaNcount = state2->NaNcount;
2113 tgl@sss.pgh.pa.us 5114 : 4 : state1->pInfcount = state2->pInfcount;
5115 : 4 : state1->nInfcount = state2->nInfcount;
3682 rhaas@postgresql.org 5116 : 4 : state1->maxScale = state2->maxScale;
5117 : 4 : state1->maxScaleCount = state2->maxScaleCount;
5118 : :
3532 heikki.linnakangas@i 5119 : 4 : accum_sum_copy(&state1->sumX, &state2->sumX);
5120 : :
3682 rhaas@postgresql.org 5121 : 4 : MemoryContextSwitchTo(old_context);
5122 : :
5123 : 4 : PG_RETURN_POINTER(state1);
5124 : : }
5125 : :
2154 tgl@sss.pgh.pa.us 5126 : 12 : state1->N += state2->N;
5127 : 12 : state1->NaNcount += state2->NaNcount;
2113 5128 : 12 : state1->pInfcount += state2->pInfcount;
5129 : 12 : state1->nInfcount += state2->nInfcount;
5130 : :
3682 rhaas@postgresql.org 5131 [ + - ]: 12 : if (state2->N > 0)
5132 : : {
5133 : : /*
5134 : : * These are currently only needed for moving aggregates, but let's do
5135 : : * the right thing anyway...
5136 : : */
5137 [ - + ]: 12 : if (state2->maxScale > state1->maxScale)
5138 : : {
3682 rhaas@postgresql.org 5139 :UBC 0 : state1->maxScale = state2->maxScale;
5140 : 0 : state1->maxScaleCount = state2->maxScaleCount;
5141 : : }
3682 rhaas@postgresql.org 5142 [ + - ]:CBC 12 : else if (state2->maxScale == state1->maxScale)
5143 : 12 : state1->maxScaleCount += state2->maxScaleCount;
5144 : :
5145 : : /* The rest of this needs to work in the aggregate context */
5146 : 12 : old_context = MemoryContextSwitchTo(agg_context);
5147 : :
5148 : : /* Accumulate sums */
3532 heikki.linnakangas@i 5149 : 12 : accum_sum_combine(&state1->sumX, &state2->sumX);
5150 : :
3682 rhaas@postgresql.org 5151 : 12 : MemoryContextSwitchTo(old_context);
5152 : : }
5153 : 12 : PG_RETURN_POINTER(state1);
5154 : : }
5155 : :
5156 : : /*
5157 : : * numeric_avg_serialize
5158 : : * Serialize NumericAggState for numeric aggregates that don't require
5159 : : * sumX2.
5160 : : */
5161 : : Datum
5162 : 16 : numeric_avg_serialize(PG_FUNCTION_ARGS)
5163 : : {
5164 : : NumericAggState *state;
5165 : : StringInfoData buf;
5166 : : bytea *result;
5167 : : NumericVar tmp_var;
5168 : :
5169 : : /* Ensure we disallow calling when not in aggregate context */
5170 [ - + ]: 16 : if (!AggCheckCallContext(fcinfo, NULL))
3682 rhaas@postgresql.org 5171 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5172 : :
3682 rhaas@postgresql.org 5173 :CBC 16 : state = (NumericAggState *) PG_GETARG_POINTER(0);
5174 : :
3532 heikki.linnakangas@i 5175 : 16 : init_var(&tmp_var);
5176 : :
3682 rhaas@postgresql.org 5177 : 16 : pq_begintypsend(&buf);
5178 : :
5179 : : /* N */
5180 : 16 : pq_sendint64(&buf, state->N);
5181 : :
5182 : : /* sumX */
1765 dean.a.rasheed@gmail 5183 : 16 : accum_sum_final(&state->sumX, &tmp_var);
5184 : 16 : numericvar_serialize(&buf, &tmp_var);
5185 : :
5186 : : /* maxScale */
3128 andres@anarazel.de 5187 : 16 : pq_sendint32(&buf, state->maxScale);
5188 : :
5189 : : /* maxScaleCount */
3682 rhaas@postgresql.org 5190 : 16 : pq_sendint64(&buf, state->maxScaleCount);
5191 : :
5192 : : /* NaNcount */
5193 : 16 : pq_sendint64(&buf, state->NaNcount);
5194 : :
5195 : : /* pInfcount */
2113 tgl@sss.pgh.pa.us 5196 : 16 : pq_sendint64(&buf, state->pInfcount);
5197 : :
5198 : : /* nInfcount */
5199 : 16 : pq_sendint64(&buf, state->nInfcount);
5200 : :
3682 rhaas@postgresql.org 5201 : 16 : result = pq_endtypsend(&buf);
5202 : :
1765 dean.a.rasheed@gmail 5203 : 16 : free_var(&tmp_var);
5204 : :
3682 rhaas@postgresql.org 5205 : 16 : PG_RETURN_BYTEA_P(result);
5206 : : }
5207 : :
5208 : : /*
5209 : : * numeric_avg_deserialize
5210 : : * Deserialize bytea into NumericAggState for numeric aggregates that
5211 : : * don't require sumX2.
5212 : : */
5213 : : Datum
5214 : 16 : numeric_avg_deserialize(PG_FUNCTION_ARGS)
5215 : : {
5216 : : bytea *sstate;
5217 : : NumericAggState *result;
5218 : : StringInfoData buf;
5219 : : NumericVar tmp_var;
5220 : :
5221 [ - + ]: 16 : if (!AggCheckCallContext(fcinfo, NULL))
3682 rhaas@postgresql.org 5222 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5223 : :
3341 noah@leadboat.com 5224 :CBC 16 : sstate = PG_GETARG_BYTEA_PP(0);
5225 : :
1765 dean.a.rasheed@gmail 5226 : 16 : init_var(&tmp_var);
5227 : :
5228 : : /*
5229 : : * Initialize a StringInfo so that we can "receive" it using the standard
5230 : : * recv-function infrastructure.
5231 : : */
921 drowley@postgresql.o 5232 [ + - ]: 16 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
5233 [ - + - - : 16 : VARSIZE_ANY_EXHDR(sstate));
- - - - +
- ]
5234 : :
3603 tgl@sss.pgh.pa.us 5235 : 16 : result = makeNumericAggStateCurrentContext(false);
5236 : :
5237 : : /* N */
3682 rhaas@postgresql.org 5238 : 16 : result->N = pq_getmsgint64(&buf);
5239 : :
5240 : : /* sumX */
1765 dean.a.rasheed@gmail 5241 : 16 : numericvar_deserialize(&buf, &tmp_var);
3532 heikki.linnakangas@i 5242 : 16 : accum_sum_add(&(result->sumX), &tmp_var);
5243 : :
5244 : : /* maxScale */
3682 rhaas@postgresql.org 5245 : 16 : result->maxScale = pq_getmsgint(&buf, 4);
5246 : :
5247 : : /* maxScaleCount */
5248 : 16 : result->maxScaleCount = pq_getmsgint64(&buf);
5249 : :
5250 : : /* NaNcount */
5251 : 16 : result->NaNcount = pq_getmsgint64(&buf);
5252 : :
5253 : : /* pInfcount */
2113 tgl@sss.pgh.pa.us 5254 : 16 : result->pInfcount = pq_getmsgint64(&buf);
5255 : :
5256 : : /* nInfcount */
5257 : 16 : result->nInfcount = pq_getmsgint64(&buf);
5258 : :
3682 rhaas@postgresql.org 5259 : 16 : pq_getmsgend(&buf);
5260 : :
1765 dean.a.rasheed@gmail 5261 : 16 : free_var(&tmp_var);
5262 : :
3682 rhaas@postgresql.org 5263 : 16 : PG_RETURN_POINTER(result);
5264 : : }
5265 : :
5266 : : /*
5267 : : * numeric_serialize
5268 : : * Serialization function for NumericAggState for numeric aggregates that
5269 : : * require sumX2.
5270 : : */
5271 : : Datum
5272 : 24 : numeric_serialize(PG_FUNCTION_ARGS)
5273 : : {
5274 : : NumericAggState *state;
5275 : : StringInfoData buf;
5276 : : bytea *result;
5277 : : NumericVar tmp_var;
5278 : :
5279 : : /* Ensure we disallow calling when not in aggregate context */
5280 [ - + ]: 24 : if (!AggCheckCallContext(fcinfo, NULL))
3682 rhaas@postgresql.org 5281 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5282 : :
3682 rhaas@postgresql.org 5283 :CBC 24 : state = (NumericAggState *) PG_GETARG_POINTER(0);
5284 : :
3532 heikki.linnakangas@i 5285 : 24 : init_var(&tmp_var);
5286 : :
3682 rhaas@postgresql.org 5287 : 24 : pq_begintypsend(&buf);
5288 : :
5289 : : /* N */
5290 : 24 : pq_sendint64(&buf, state->N);
5291 : :
5292 : : /* sumX */
1765 dean.a.rasheed@gmail 5293 : 24 : accum_sum_final(&state->sumX, &tmp_var);
5294 : 24 : numericvar_serialize(&buf, &tmp_var);
5295 : :
5296 : : /* sumX2 */
5297 : 24 : accum_sum_final(&state->sumX2, &tmp_var);
5298 : 24 : numericvar_serialize(&buf, &tmp_var);
5299 : :
5300 : : /* maxScale */
3128 andres@anarazel.de 5301 : 24 : pq_sendint32(&buf, state->maxScale);
5302 : :
5303 : : /* maxScaleCount */
3682 rhaas@postgresql.org 5304 : 24 : pq_sendint64(&buf, state->maxScaleCount);
5305 : :
5306 : : /* NaNcount */
5307 : 24 : pq_sendint64(&buf, state->NaNcount);
5308 : :
5309 : : /* pInfcount */
2113 tgl@sss.pgh.pa.us 5310 : 24 : pq_sendint64(&buf, state->pInfcount);
5311 : :
5312 : : /* nInfcount */
5313 : 24 : pq_sendint64(&buf, state->nInfcount);
5314 : :
3682 rhaas@postgresql.org 5315 : 24 : result = pq_endtypsend(&buf);
5316 : :
1765 dean.a.rasheed@gmail 5317 : 24 : free_var(&tmp_var);
5318 : :
3682 rhaas@postgresql.org 5319 : 24 : PG_RETURN_BYTEA_P(result);
5320 : : }
5321 : :
5322 : : /*
5323 : : * numeric_deserialize
5324 : : * Deserialization function for NumericAggState for numeric aggregates that
5325 : : * require sumX2.
5326 : : */
5327 : : Datum
5328 : 24 : numeric_deserialize(PG_FUNCTION_ARGS)
5329 : : {
5330 : : bytea *sstate;
5331 : : NumericAggState *result;
5332 : : StringInfoData buf;
5333 : : NumericVar tmp_var;
5334 : :
5335 [ - + ]: 24 : if (!AggCheckCallContext(fcinfo, NULL))
3682 rhaas@postgresql.org 5336 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5337 : :
3341 noah@leadboat.com 5338 :CBC 24 : sstate = PG_GETARG_BYTEA_PP(0);
5339 : :
1765 dean.a.rasheed@gmail 5340 : 24 : init_var(&tmp_var);
5341 : :
5342 : : /*
5343 : : * Initialize a StringInfo so that we can "receive" it using the standard
5344 : : * recv-function infrastructure.
5345 : : */
921 drowley@postgresql.o 5346 [ + + ]: 24 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
5347 [ - + - - : 24 : VARSIZE_ANY_EXHDR(sstate));
- - - - +
+ ]
5348 : :
3603 tgl@sss.pgh.pa.us 5349 : 24 : result = makeNumericAggStateCurrentContext(false);
5350 : :
5351 : : /* N */
3682 rhaas@postgresql.org 5352 : 24 : result->N = pq_getmsgint64(&buf);
5353 : :
5354 : : /* sumX */
1765 dean.a.rasheed@gmail 5355 : 24 : numericvar_deserialize(&buf, &tmp_var);
5356 : 24 : accum_sum_add(&(result->sumX), &tmp_var);
5357 : :
5358 : : /* sumX2 */
5359 : 24 : numericvar_deserialize(&buf, &tmp_var);
5360 : 24 : accum_sum_add(&(result->sumX2), &tmp_var);
5361 : :
5362 : : /* maxScale */
3682 rhaas@postgresql.org 5363 : 24 : result->maxScale = pq_getmsgint(&buf, 4);
5364 : :
5365 : : /* maxScaleCount */
5366 : 24 : result->maxScaleCount = pq_getmsgint64(&buf);
5367 : :
5368 : : /* NaNcount */
5369 : 24 : result->NaNcount = pq_getmsgint64(&buf);
5370 : :
5371 : : /* pInfcount */
2113 tgl@sss.pgh.pa.us 5372 : 24 : result->pInfcount = pq_getmsgint64(&buf);
5373 : :
5374 : : /* nInfcount */
5375 : 24 : result->nInfcount = pq_getmsgint64(&buf);
5376 : :
3682 rhaas@postgresql.org 5377 : 24 : pq_getmsgend(&buf);
5378 : :
1765 dean.a.rasheed@gmail 5379 : 24 : free_var(&tmp_var);
5380 : :
3682 rhaas@postgresql.org 5381 : 24 : PG_RETURN_POINTER(result);
5382 : : }
5383 : :
5384 : : /*
5385 : : * Generic inverse transition function for numeric aggregates
5386 : : * (with or without requirement for X^2).
5387 : : */
5388 : : Datum
4406 tgl@sss.pgh.pa.us 5389 : 152 : numeric_accum_inv(PG_FUNCTION_ARGS)
5390 : : {
5391 : : NumericAggState *state;
5392 : :
5393 [ + - ]: 152 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5394 : :
5395 : : /* Should not get here with no state */
5396 [ - + ]: 152 : if (state == NULL)
4406 tgl@sss.pgh.pa.us 5397 [ # # ]:UBC 0 : elog(ERROR, "numeric_accum_inv called with NULL state");
5398 : :
4406 tgl@sss.pgh.pa.us 5399 [ + + ]:CBC 152 : if (!PG_ARGISNULL(1))
5400 : : {
5401 : : /* If we fail to perform the inverse transition, return NULL */
5402 [ + + ]: 132 : if (!do_numeric_discard(state, PG_GETARG_NUMERIC(1)))
5403 : 4 : PG_RETURN_NULL();
5404 : : }
5405 : :
4553 5406 : 148 : PG_RETURN_POINTER(state);
5407 : : }
5408 : :
5409 : :
5410 : : /*
5411 : : * Integer data types in general use Numeric accumulators to share code and
5412 : : * avoid risk of overflow. However for performance reasons optimized
5413 : : * special-purpose accumulator routines are used when possible:
5414 : : *
5415 : : * For 16-bit and 32-bit inputs, N and sum(X) fit into 64-bit, so 64-bit
5416 : : * accumulators are used for SUM and AVG of these data types.
5417 : : *
5418 : : * For 16-bit and 32-bit inputs, sum(X^2) fits into 128-bit, so 128-bit
5419 : : * accumulators are used for STDDEV_POP, STDDEV_SAMP, VAR_POP, and VAR_SAMP of
5420 : : * these data types.
5421 : : *
5422 : : * For 64-bit inputs, sum(X) fits into 128-bit, so a 128-bit accumulator is
5423 : : * used for SUM(int8) and AVG(int8).
5424 : : */
5425 : :
5426 : : typedef struct Int128AggState
5427 : : {
5428 : : bool calcSumX2; /* if true, calculate sumX2 */
5429 : : int64 N; /* count of processed numbers */
5430 : : INT128 sumX; /* sum of processed numbers */
5431 : : INT128 sumX2; /* sum of squares of processed numbers */
5432 : : } Int128AggState;
5433 : :
5434 : : /*
5435 : : * Prepare state data for a 128-bit aggregate function that needs to compute
5436 : : * sum, count and optionally sum of squares of the input.
5437 : : */
5438 : : static Int128AggState *
4064 andres@anarazel.de 5439 : 634 : makeInt128AggState(FunctionCallInfo fcinfo, bool calcSumX2)
5440 : : {
5441 : : Int128AggState *state;
5442 : : MemoryContext agg_context;
5443 : : MemoryContext old_context;
5444 : :
5445 [ - + ]: 634 : if (!AggCheckCallContext(fcinfo, &agg_context))
4064 andres@anarazel.de 5446 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5447 : :
4064 andres@anarazel.de 5448 :CBC 634 : old_context = MemoryContextSwitchTo(agg_context);
5449 : :
146 michael@paquier.xyz 5450 :GNC 634 : state = palloc0_object(Int128AggState);
4064 andres@anarazel.de 5451 :CBC 634 : state->calcSumX2 = calcSumX2;
5452 : :
5453 : 634 : MemoryContextSwitchTo(old_context);
5454 : :
5455 : 634 : return state;
5456 : : }
5457 : :
5458 : : /*
5459 : : * Like makeInt128AggState(), but allocate the state in the current memory
5460 : : * context.
5461 : : */
5462 : : static Int128AggState *
3603 tgl@sss.pgh.pa.us 5463 : 36 : makeInt128AggStateCurrentContext(bool calcSumX2)
5464 : : {
5465 : : Int128AggState *state;
5466 : :
146 michael@paquier.xyz 5467 :GNC 36 : state = palloc0_object(Int128AggState);
3603 tgl@sss.pgh.pa.us 5468 :CBC 36 : state->calcSumX2 = calcSumX2;
5469 : :
5470 : 36 : return state;
5471 : : }
5472 : :
5473 : : /*
5474 : : * Accumulate a new input value for 128-bit aggregate functions.
5475 : : */
5476 : : static void
271 dean.a.rasheed@gmail 5477 :GNC 371598 : do_int128_accum(Int128AggState *state, int64 newval)
5478 : : {
4064 andres@anarazel.de 5479 [ + + ]:CBC 371598 : if (state->calcSumX2)
271 dean.a.rasheed@gmail 5480 :GNC 161240 : int128_add_int64_mul_int64(&state->sumX2, newval, newval);
5481 : :
5482 : 371598 : int128_add_int64(&state->sumX, newval);
4064 andres@anarazel.de 5483 :CBC 371598 : state->N++;
5484 : 371598 : }
5485 : :
5486 : : /*
5487 : : * Remove an input value from the aggregated state.
5488 : : */
5489 : : static void
271 dean.a.rasheed@gmail 5490 :GNC 208 : do_int128_discard(Int128AggState *state, int64 newval)
5491 : : {
4064 andres@anarazel.de 5492 [ + + ]:CBC 208 : if (state->calcSumX2)
271 dean.a.rasheed@gmail 5493 :GNC 192 : int128_sub_int64_mul_int64(&state->sumX2, newval, newval);
5494 : :
5495 : 208 : int128_sub_int64(&state->sumX, newval);
4064 andres@anarazel.de 5496 :CBC 208 : state->N--;
5497 : 208 : }
5498 : :
5499 : : Datum
9423 tgl@sss.pgh.pa.us 5500 : 132 : int2_accum(PG_FUNCTION_ARGS)
5501 : : {
5502 : : Int128AggState *state;
5503 : :
271 dean.a.rasheed@gmail 5504 [ + + ]:GNC 132 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
5505 : :
5506 : : /* Create the state data on the first call */
4406 tgl@sss.pgh.pa.us 5507 [ + + ]:CBC 132 : if (state == NULL)
271 dean.a.rasheed@gmail 5508 :GNC 24 : state = makeInt128AggState(fcinfo, true);
5509 : :
4553 tgl@sss.pgh.pa.us 5510 [ + + ]:CBC 132 : if (!PG_ARGISNULL(1))
271 dean.a.rasheed@gmail 5511 :GNC 120 : do_int128_accum(state, PG_GETARG_INT16(1));
5512 : :
4553 tgl@sss.pgh.pa.us 5513 :CBC 132 : PG_RETURN_POINTER(state);
5514 : : }
5515 : :
5516 : : Datum
9423 5517 : 161132 : int4_accum(PG_FUNCTION_ARGS)
5518 : : {
5519 : : Int128AggState *state;
5520 : :
271 dean.a.rasheed@gmail 5521 [ + + ]:GNC 161132 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
5522 : :
5523 : : /* Create the state data on the first call */
4406 tgl@sss.pgh.pa.us 5524 [ + + ]:CBC 161132 : if (state == NULL)
271 dean.a.rasheed@gmail 5525 :GNC 50 : state = makeInt128AggState(fcinfo, true);
5526 : :
4553 tgl@sss.pgh.pa.us 5527 [ + + ]:CBC 161132 : if (!PG_ARGISNULL(1))
271 dean.a.rasheed@gmail 5528 :GNC 161120 : do_int128_accum(state, PG_GETARG_INT32(1));
5529 : :
4553 tgl@sss.pgh.pa.us 5530 :CBC 161132 : PG_RETURN_POINTER(state);
5531 : : }
5532 : :
5533 : : Datum
9423 5534 : 160132 : int8_accum(PG_FUNCTION_ARGS)
5535 : : {
5536 : : NumericAggState *state;
5537 : :
4553 5538 [ + + ]: 160132 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5539 : :
5540 : : /* Create the state data on the first call */
4406 5541 [ + + ]: 160132 : if (state == NULL)
5542 : 40 : state = makeNumericAggState(fcinfo, true);
5543 : :
4553 5544 [ + + ]: 160132 : if (!PG_ARGISNULL(1))
2064 peter@eisentraut.org 5545 : 160120 : do_numeric_accum(state, int64_to_numeric(PG_GETARG_INT64(1)));
5546 : :
4553 tgl@sss.pgh.pa.us 5547 : 160132 : PG_RETURN_POINTER(state);
5548 : : }
5549 : :
5550 : : /*
5551 : : * Combine function for Int128AggState for aggregates which require sumX2
5552 : : */
5553 : : Datum
3682 rhaas@postgresql.org 5554 : 16 : numeric_poly_combine(PG_FUNCTION_ARGS)
5555 : : {
5556 : : Int128AggState *state1;
5557 : : Int128AggState *state2;
5558 : : MemoryContext agg_context;
5559 : : MemoryContext old_context;
5560 : :
5561 [ - + ]: 16 : if (!AggCheckCallContext(fcinfo, &agg_context))
3682 rhaas@postgresql.org 5562 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5563 : :
271 dean.a.rasheed@gmail 5564 [ + + ]:GNC 16 : state1 = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
5565 [ + - ]: 16 : state2 = PG_ARGISNULL(1) ? NULL : (Int128AggState *) PG_GETARG_POINTER(1);
5566 : :
3682 rhaas@postgresql.org 5567 [ - + ]:CBC 16 : if (state2 == NULL)
3682 rhaas@postgresql.org 5568 :UBC 0 : PG_RETURN_POINTER(state1);
5569 : :
5570 : : /* manually copy all fields from state2 to state1 */
3682 rhaas@postgresql.org 5571 [ + + ]:CBC 16 : if (state1 == NULL)
5572 : : {
5573 : 4 : old_context = MemoryContextSwitchTo(agg_context);
5574 : :
271 dean.a.rasheed@gmail 5575 :GNC 4 : state1 = makeInt128AggState(fcinfo, true);
3682 rhaas@postgresql.org 5576 :CBC 4 : state1->N = state2->N;
5577 : 4 : state1->sumX = state2->sumX;
5578 : 4 : state1->sumX2 = state2->sumX2;
5579 : :
5580 : 4 : MemoryContextSwitchTo(old_context);
5581 : :
5582 : 4 : PG_RETURN_POINTER(state1);
5583 : : }
5584 : :
5585 [ + - ]: 12 : if (state2->N > 0)
5586 : : {
5587 : 12 : state1->N += state2->N;
271 dean.a.rasheed@gmail 5588 :GNC 12 : int128_add_int128(&state1->sumX, state2->sumX);
5589 : 12 : int128_add_int128(&state1->sumX2, state2->sumX2);
5590 : : }
5591 : 12 : PG_RETURN_POINTER(state1);
5592 : : }
5593 : :
5594 : : /*
5595 : : * int128_serialize - serialize a 128-bit integer to binary format
5596 : : */
5597 : : static inline void
5598 : 52 : int128_serialize(StringInfo buf, INT128 val)
5599 : : {
5600 : 52 : pq_sendint64(buf, PG_INT128_HI_INT64(val));
5601 : 52 : pq_sendint64(buf, PG_INT128_LO_UINT64(val));
5602 : 52 : }
5603 : :
5604 : : /*
5605 : : * int128_deserialize - deserialize binary format to a 128-bit integer.
5606 : : */
5607 : : static inline INT128
5608 : 52 : int128_deserialize(StringInfo buf)
5609 : : {
5610 : 52 : int64 hi = pq_getmsgint64(buf);
5611 : 52 : uint64 lo = pq_getmsgint64(buf);
5612 : :
5613 : 52 : return make_int128(hi, lo);
5614 : : }
5615 : :
5616 : : /*
5617 : : * numeric_poly_serialize
5618 : : * Serialize Int128AggState into bytea for aggregate functions which
5619 : : * require sumX2.
5620 : : */
5621 : : Datum
3682 rhaas@postgresql.org 5622 :CBC 16 : numeric_poly_serialize(PG_FUNCTION_ARGS)
5623 : : {
5624 : : Int128AggState *state;
5625 : : StringInfoData buf;
5626 : : bytea *result;
5627 : :
5628 : : /* Ensure we disallow calling when not in aggregate context */
5629 [ - + ]: 16 : if (!AggCheckCallContext(fcinfo, NULL))
3682 rhaas@postgresql.org 5630 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5631 : :
271 dean.a.rasheed@gmail 5632 :GNC 16 : state = (Int128AggState *) PG_GETARG_POINTER(0);
5633 : :
3682 rhaas@postgresql.org 5634 :CBC 16 : pq_begintypsend(&buf);
5635 : :
5636 : : /* N */
5637 : 16 : pq_sendint64(&buf, state->N);
5638 : :
5639 : : /* sumX */
271 dean.a.rasheed@gmail 5640 :GNC 16 : int128_serialize(&buf, state->sumX);
5641 : :
5642 : : /* sumX2 */
5643 : 16 : int128_serialize(&buf, state->sumX2);
5644 : :
3682 rhaas@postgresql.org 5645 :CBC 16 : result = pq_endtypsend(&buf);
5646 : :
5647 : 16 : PG_RETURN_BYTEA_P(result);
5648 : : }
5649 : :
5650 : : /*
5651 : : * numeric_poly_deserialize
5652 : : * Deserialize Int128AggState from bytea for aggregate functions which
5653 : : * require sumX2.
5654 : : */
5655 : : Datum
5656 : 16 : numeric_poly_deserialize(PG_FUNCTION_ARGS)
5657 : : {
5658 : : bytea *sstate;
5659 : : Int128AggState *result;
5660 : : StringInfoData buf;
5661 : :
5662 [ - + ]: 16 : if (!AggCheckCallContext(fcinfo, NULL))
3682 rhaas@postgresql.org 5663 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5664 : :
3341 noah@leadboat.com 5665 :CBC 16 : sstate = PG_GETARG_BYTEA_PP(0);
5666 : :
5667 : : /*
5668 : : * Initialize a StringInfo so that we can "receive" it using the standard
5669 : : * recv-function infrastructure.
5670 : : */
921 drowley@postgresql.o 5671 [ + - ]: 16 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
5672 [ - + - - : 16 : VARSIZE_ANY_EXHDR(sstate));
- - - - +
- ]
5673 : :
271 dean.a.rasheed@gmail 5674 :GNC 16 : result = makeInt128AggStateCurrentContext(false);
5675 : :
5676 : : /* N */
3682 rhaas@postgresql.org 5677 :CBC 16 : result->N = pq_getmsgint64(&buf);
5678 : :
5679 : : /* sumX */
271 dean.a.rasheed@gmail 5680 :GNC 16 : result->sumX = int128_deserialize(&buf);
5681 : :
5682 : : /* sumX2 */
5683 : 16 : result->sumX2 = int128_deserialize(&buf);
5684 : :
3682 rhaas@postgresql.org 5685 :CBC 16 : pq_getmsgend(&buf);
5686 : :
5687 : 16 : PG_RETURN_POINTER(result);
5688 : : }
5689 : :
5690 : : /*
5691 : : * Transition function for int8 input when we don't need sumX2.
5692 : : */
5693 : : Datum
7017 bruce@momjian.us 5694 : 213257 : int8_avg_accum(PG_FUNCTION_ARGS)
5695 : : {
5696 : : Int128AggState *state;
5697 : :
271 dean.a.rasheed@gmail 5698 [ + + ]:GNC 213257 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
5699 : :
5700 : : /* Create the state data on the first call */
4406 tgl@sss.pgh.pa.us 5701 [ + + ]:CBC 213257 : if (state == NULL)
271 dean.a.rasheed@gmail 5702 :GNC 548 : state = makeInt128AggState(fcinfo, false);
5703 : :
4553 tgl@sss.pgh.pa.us 5704 [ + + ]:CBC 213257 : if (!PG_ARGISNULL(1))
271 dean.a.rasheed@gmail 5705 :GNC 210358 : do_int128_accum(state, PG_GETARG_INT64(1));
5706 : :
4406 tgl@sss.pgh.pa.us 5707 :CBC 213257 : PG_RETURN_POINTER(state);
5708 : : }
5709 : :
5710 : : /*
5711 : : * Combine function for Int128AggState for aggregates which don't require
5712 : : * sumX2
5713 : : */
5714 : : Datum
3682 rhaas@postgresql.org 5715 : 20 : int8_avg_combine(PG_FUNCTION_ARGS)
5716 : : {
5717 : : Int128AggState *state1;
5718 : : Int128AggState *state2;
5719 : : MemoryContext agg_context;
5720 : : MemoryContext old_context;
5721 : :
5722 [ - + ]: 20 : if (!AggCheckCallContext(fcinfo, &agg_context))
3682 rhaas@postgresql.org 5723 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5724 : :
271 dean.a.rasheed@gmail 5725 [ + + ]:GNC 20 : state1 = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
5726 [ + - ]: 20 : state2 = PG_ARGISNULL(1) ? NULL : (Int128AggState *) PG_GETARG_POINTER(1);
5727 : :
3682 rhaas@postgresql.org 5728 [ - + ]:CBC 20 : if (state2 == NULL)
3682 rhaas@postgresql.org 5729 :UBC 0 : PG_RETURN_POINTER(state1);
5730 : :
5731 : : /* manually copy all fields from state2 to state1 */
3682 rhaas@postgresql.org 5732 [ + + ]:CBC 20 : if (state1 == NULL)
5733 : : {
5734 : 8 : old_context = MemoryContextSwitchTo(agg_context);
5735 : :
271 dean.a.rasheed@gmail 5736 :GNC 8 : state1 = makeInt128AggState(fcinfo, false);
3682 rhaas@postgresql.org 5737 :CBC 8 : state1->N = state2->N;
5738 : 8 : state1->sumX = state2->sumX;
5739 : :
5740 : 8 : MemoryContextSwitchTo(old_context);
5741 : :
5742 : 8 : PG_RETURN_POINTER(state1);
5743 : : }
5744 : :
5745 [ + - ]: 12 : if (state2->N > 0)
5746 : : {
5747 : 12 : state1->N += state2->N;
271 dean.a.rasheed@gmail 5748 :GNC 12 : int128_add_int128(&state1->sumX, state2->sumX);
5749 : : }
3682 rhaas@postgresql.org 5750 :CBC 12 : PG_RETURN_POINTER(state1);
5751 : : }
5752 : :
5753 : : /*
5754 : : * int8_avg_serialize
5755 : : * Serialize Int128AggState into bytea for aggregate functions which
5756 : : * don't require sumX2.
5757 : : */
5758 : : Datum
5759 : 20 : int8_avg_serialize(PG_FUNCTION_ARGS)
5760 : : {
5761 : : Int128AggState *state;
5762 : : StringInfoData buf;
5763 : : bytea *result;
5764 : :
5765 : : /* Ensure we disallow calling when not in aggregate context */
5766 [ - + ]: 20 : if (!AggCheckCallContext(fcinfo, NULL))
3682 rhaas@postgresql.org 5767 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5768 : :
271 dean.a.rasheed@gmail 5769 :GNC 20 : state = (Int128AggState *) PG_GETARG_POINTER(0);
5770 : :
3682 rhaas@postgresql.org 5771 :CBC 20 : pq_begintypsend(&buf);
5772 : :
5773 : : /* N */
5774 : 20 : pq_sendint64(&buf, state->N);
5775 : :
5776 : : /* sumX */
271 dean.a.rasheed@gmail 5777 :GNC 20 : int128_serialize(&buf, state->sumX);
5778 : :
3682 rhaas@postgresql.org 5779 :CBC 20 : result = pq_endtypsend(&buf);
5780 : :
5781 : 20 : PG_RETURN_BYTEA_P(result);
5782 : : }
5783 : :
5784 : : /*
5785 : : * int8_avg_deserialize
5786 : : * Deserialize Int128AggState from bytea for aggregate functions which
5787 : : * don't require sumX2.
5788 : : */
5789 : : Datum
5790 : 20 : int8_avg_deserialize(PG_FUNCTION_ARGS)
5791 : : {
5792 : : bytea *sstate;
5793 : : Int128AggState *result;
5794 : : StringInfoData buf;
5795 : :
5796 [ - + ]: 20 : if (!AggCheckCallContext(fcinfo, NULL))
3682 rhaas@postgresql.org 5797 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
5798 : :
3341 noah@leadboat.com 5799 :CBC 20 : sstate = PG_GETARG_BYTEA_PP(0);
5800 : :
5801 : : /*
5802 : : * Initialize a StringInfo so that we can "receive" it using the standard
5803 : : * recv-function infrastructure.
5804 : : */
921 drowley@postgresql.o 5805 [ + - ]: 20 : initReadOnlyStringInfo(&buf, VARDATA_ANY(sstate),
5806 [ - + - - : 20 : VARSIZE_ANY_EXHDR(sstate));
- - - - +
- ]
5807 : :
271 dean.a.rasheed@gmail 5808 :GNC 20 : result = makeInt128AggStateCurrentContext(false);
5809 : :
5810 : : /* N */
3682 rhaas@postgresql.org 5811 :CBC 20 : result->N = pq_getmsgint64(&buf);
5812 : :
5813 : : /* sumX */
271 dean.a.rasheed@gmail 5814 :GNC 20 : result->sumX = int128_deserialize(&buf);
5815 : :
3682 rhaas@postgresql.org 5816 :CBC 20 : pq_getmsgend(&buf);
5817 : :
5818 : 20 : PG_RETURN_POINTER(result);
5819 : : }
5820 : :
5821 : : /*
5822 : : * Inverse transition functions to go with the above.
5823 : : */
5824 : :
5825 : : Datum
4406 tgl@sss.pgh.pa.us 5826 : 108 : int2_accum_inv(PG_FUNCTION_ARGS)
5827 : : {
5828 : : Int128AggState *state;
5829 : :
271 dean.a.rasheed@gmail 5830 [ + - ]:GNC 108 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
5831 : :
5832 : : /* Should not get here with no state */
4406 tgl@sss.pgh.pa.us 5833 [ - + ]:CBC 108 : if (state == NULL)
4406 tgl@sss.pgh.pa.us 5834 [ # # ]:UBC 0 : elog(ERROR, "int2_accum_inv called with NULL state");
5835 : :
4406 tgl@sss.pgh.pa.us 5836 [ + + ]:CBC 108 : if (!PG_ARGISNULL(1))
271 dean.a.rasheed@gmail 5837 :GNC 96 : do_int128_discard(state, PG_GETARG_INT16(1));
5838 : :
4553 tgl@sss.pgh.pa.us 5839 :CBC 108 : PG_RETURN_POINTER(state);
5840 : : }
5841 : :
5842 : : Datum
4406 5843 : 108 : int4_accum_inv(PG_FUNCTION_ARGS)
5844 : : {
5845 : : Int128AggState *state;
5846 : :
271 dean.a.rasheed@gmail 5847 [ + - ]:GNC 108 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
5848 : :
5849 : : /* Should not get here with no state */
4406 tgl@sss.pgh.pa.us 5850 [ - + ]:CBC 108 : if (state == NULL)
4406 tgl@sss.pgh.pa.us 5851 [ # # ]:UBC 0 : elog(ERROR, "int4_accum_inv called with NULL state");
5852 : :
4406 tgl@sss.pgh.pa.us 5853 [ + + ]:CBC 108 : if (!PG_ARGISNULL(1))
271 dean.a.rasheed@gmail 5854 :GNC 96 : do_int128_discard(state, PG_GETARG_INT32(1));
5855 : :
4406 tgl@sss.pgh.pa.us 5856 :CBC 108 : PG_RETURN_POINTER(state);
5857 : : }
5858 : :
5859 : : Datum
5860 : 108 : int8_accum_inv(PG_FUNCTION_ARGS)
5861 : : {
5862 : : NumericAggState *state;
5863 : :
5864 [ + - ]: 108 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5865 : :
5866 : : /* Should not get here with no state */
5867 [ - + ]: 108 : if (state == NULL)
4406 tgl@sss.pgh.pa.us 5868 [ # # ]:UBC 0 : elog(ERROR, "int8_accum_inv called with NULL state");
5869 : :
4406 tgl@sss.pgh.pa.us 5870 [ + + ]:CBC 108 : if (!PG_ARGISNULL(1))
5871 : : {
5872 : : /* Should never fail, all inputs have dscale 0 */
2064 peter@eisentraut.org 5873 [ - + ]: 96 : if (!do_numeric_discard(state, int64_to_numeric(PG_GETARG_INT64(1))))
4406 tgl@sss.pgh.pa.us 5874 [ # # ]:UBC 0 : elog(ERROR, "do_numeric_discard failed unexpectedly");
5875 : : }
5876 : :
4406 tgl@sss.pgh.pa.us 5877 :CBC 108 : PG_RETURN_POINTER(state);
5878 : : }
5879 : :
5880 : : Datum
4064 andres@anarazel.de 5881 : 24 : int8_avg_accum_inv(PG_FUNCTION_ARGS)
5882 : : {
5883 : : Int128AggState *state;
5884 : :
271 dean.a.rasheed@gmail 5885 [ + - ]:GNC 24 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
5886 : :
5887 : : /* Should not get here with no state */
4064 andres@anarazel.de 5888 [ - + ]:CBC 24 : if (state == NULL)
4064 andres@anarazel.de 5889 [ # # ]:UBC 0 : elog(ERROR, "int8_avg_accum_inv called with NULL state");
5890 : :
4064 andres@anarazel.de 5891 [ + + ]:CBC 24 : if (!PG_ARGISNULL(1))
271 dean.a.rasheed@gmail 5892 :GNC 16 : do_int128_discard(state, PG_GETARG_INT64(1));
5893 : :
4064 andres@anarazel.de 5894 :CBC 24 : PG_RETURN_POINTER(state);
5895 : : }
5896 : :
5897 : : Datum
5898 : 692 : numeric_poly_sum(PG_FUNCTION_ARGS)
5899 : : {
5900 : : Int128AggState *state;
5901 : : Numeric res;
5902 : : NumericVar result;
5903 : :
271 dean.a.rasheed@gmail 5904 [ + + ]:GNC 692 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
5905 : :
5906 : : /* If there were no non-null inputs, return NULL */
4064 andres@anarazel.de 5907 [ + + + + ]:CBC 692 : if (state == NULL || state->N == 0)
5908 : 16 : PG_RETURN_NULL();
5909 : :
5910 : 676 : init_var(&result);
5911 : :
5912 : 676 : int128_to_numericvar(state->sumX, &result);
5913 : :
5914 : 676 : res = make_result(&result);
5915 : :
5916 : 676 : free_var(&result);
5917 : :
5918 : 676 : PG_RETURN_NUMERIC(res);
5919 : : }
5920 : :
5921 : : Datum
5922 : 24 : numeric_poly_avg(PG_FUNCTION_ARGS)
5923 : : {
5924 : : Int128AggState *state;
5925 : : NumericVar result;
5926 : : Datum countd,
5927 : : sumd;
5928 : :
271 dean.a.rasheed@gmail 5929 [ + - ]:GNC 24 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
5930 : :
5931 : : /* If there were no non-null inputs, return NULL */
4064 andres@anarazel.de 5932 [ + - + + ]:CBC 24 : if (state == NULL || state->N == 0)
5933 : 12 : PG_RETURN_NULL();
5934 : :
5935 : 12 : init_var(&result);
5936 : :
5937 : 12 : int128_to_numericvar(state->sumX, &result);
5938 : :
2064 peter@eisentraut.org 5939 : 12 : countd = NumericGetDatum(int64_to_numeric(state->N));
4064 andres@anarazel.de 5940 : 12 : sumd = NumericGetDatum(make_result(&result));
5941 : :
5942 : 12 : free_var(&result);
5943 : :
5944 : 12 : PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
5945 : : }
5946 : :
5947 : : Datum
9423 tgl@sss.pgh.pa.us 5948 : 52 : numeric_avg(PG_FUNCTION_ARGS)
5949 : : {
5950 : : NumericAggState *state;
5951 : : Datum N_datum;
5952 : : Datum sumX_datum;
5953 : : NumericVar sumX_var;
5954 : :
4553 5955 [ + - ]: 52 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5956 : :
5957 : : /* If there were no non-null inputs, return NULL */
2113 5958 [ + - + + ]: 52 : if (state == NULL || NA_TOTAL_COUNT(state) == 0)
4553 5959 : 12 : PG_RETURN_NULL();
5960 : :
4382 bruce@momjian.us 5961 [ + + ]: 40 : if (state->NaNcount > 0) /* there was at least one NaN input */
4553 tgl@sss.pgh.pa.us 5962 : 4 : PG_RETURN_NUMERIC(make_result(&const_nan));
5963 : :
5964 : : /* adding plus and minus infinities gives NaN */
2113 5965 [ + + + + ]: 36 : if (state->pInfcount > 0 && state->nInfcount > 0)
5966 : 4 : PG_RETURN_NUMERIC(make_result(&const_nan));
5967 [ + + ]: 32 : if (state->pInfcount > 0)
5968 : 12 : PG_RETURN_NUMERIC(make_result(&const_pinf));
5969 [ + + ]: 20 : if (state->nInfcount > 0)
5970 : 4 : PG_RETURN_NUMERIC(make_result(&const_ninf));
5971 : :
2064 peter@eisentraut.org 5972 : 16 : N_datum = NumericGetDatum(int64_to_numeric(state->N));
5973 : :
3532 heikki.linnakangas@i 5974 : 16 : init_var(&sumX_var);
5975 : 16 : accum_sum_final(&state->sumX, &sumX_var);
5976 : 16 : sumX_datum = NumericGetDatum(make_result(&sumX_var));
5977 : 16 : free_var(&sumX_var);
5978 : :
4553 tgl@sss.pgh.pa.us 5979 : 16 : PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumX_datum, N_datum));
5980 : : }
5981 : :
5982 : : Datum
5983 : 113926 : numeric_sum(PG_FUNCTION_ARGS)
5984 : : {
5985 : : NumericAggState *state;
5986 : : NumericVar sumX_var;
5987 : : Numeric result;
5988 : :
5989 [ + - ]: 113926 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5990 : :
5991 : : /* If there were no non-null inputs, return NULL */
2113 5992 [ + - + + ]: 113926 : if (state == NULL || NA_TOTAL_COUNT(state) == 0)
9423 5993 : 12 : PG_RETURN_NULL();
5994 : :
4382 bruce@momjian.us 5995 [ + + ]: 113914 : if (state->NaNcount > 0) /* there was at least one NaN input */
4553 tgl@sss.pgh.pa.us 5996 : 12 : PG_RETURN_NUMERIC(make_result(&const_nan));
5997 : :
5998 : : /* adding plus and minus infinities gives NaN */
2113 5999 [ + + + + ]: 113902 : if (state->pInfcount > 0 && state->nInfcount > 0)
6000 : 4 : PG_RETURN_NUMERIC(make_result(&const_nan));
6001 [ + + ]: 113898 : if (state->pInfcount > 0)
6002 : 12 : PG_RETURN_NUMERIC(make_result(&const_pinf));
6003 [ + + ]: 113886 : if (state->nInfcount > 0)
6004 : 4 : PG_RETURN_NUMERIC(make_result(&const_ninf));
6005 : :
3532 heikki.linnakangas@i 6006 : 113882 : init_var(&sumX_var);
6007 : 113882 : accum_sum_final(&state->sumX, &sumX_var);
6008 : 113882 : result = make_result(&sumX_var);
6009 : 113882 : free_var(&sumX_var);
6010 : :
6011 : 113882 : PG_RETURN_NUMERIC(result);
6012 : : }
6013 : :
6014 : : /*
6015 : : * Workhorse routine for the standard deviance and variance
6016 : : * aggregates. 'state' is aggregate's transition state.
6017 : : * 'variance' specifies whether we should calculate the
6018 : : * variance or the standard deviation. 'sample' indicates whether the
6019 : : * caller is interested in the sample or the population
6020 : : * variance/stddev.
6021 : : *
6022 : : * If appropriate variance statistic is undefined for the input,
6023 : : * *is_null is set to true and NULL is returned.
6024 : : */
6025 : : static Numeric
4553 tgl@sss.pgh.pa.us 6026 : 654 : numeric_stddev_internal(NumericAggState *state,
6027 : : bool variance, bool sample,
6028 : : bool *is_null)
6029 : : {
6030 : : Numeric res;
6031 : : NumericVar vN,
6032 : : vsumX,
6033 : : vsumX2,
6034 : : vNminus1;
6035 : : int64 totCount;
6036 : : int rscale;
6037 : :
6038 : : /*
6039 : : * Sample stddev and variance are undefined when N <= 1; population stddev
6040 : : * is undefined when N == 0. Return NULL in either case (note that NaNs
6041 : : * and infinities count as normal inputs for this purpose).
6042 : : */
2113 6043 [ + - - + ]: 654 : if (state == NULL || (totCount = NA_TOTAL_COUNT(state)) == 0)
6044 : : {
2152 tgl@sss.pgh.pa.us 6045 :UBC 0 : *is_null = true;
6046 : 0 : return NULL;
6047 : : }
6048 : :
2152 tgl@sss.pgh.pa.us 6049 [ + + + + ]:CBC 654 : if (sample && totCount <= 1)
6050 : : {
4553 6051 : 88 : *is_null = true;
6052 : 88 : return NULL;
6053 : : }
6054 : :
7361 neilc@samurai.com 6055 : 566 : *is_null = false;
6056 : :
6057 : : /*
6058 : : * Deal with NaN and infinity cases. By analogy to the behavior of the
6059 : : * float8 functions, any infinity input produces NaN output.
6060 : : */
2113 tgl@sss.pgh.pa.us 6061 [ + + + + : 566 : if (state->NaNcount > 0 || state->pInfcount > 0 || state->nInfcount > 0)
+ + ]
7361 neilc@samurai.com 6062 : 36 : return make_result(&const_nan);
6063 : :
6064 : : /* OK, normal calculation applies */
4553 tgl@sss.pgh.pa.us 6065 : 530 : init_var(&vN);
6066 : 530 : init_var(&vsumX);
6067 : 530 : init_var(&vsumX2);
6068 : :
4064 andres@anarazel.de 6069 : 530 : int64_to_numericvar(state->N, &vN);
3532 heikki.linnakangas@i 6070 : 530 : accum_sum_final(&(state->sumX), &vsumX);
6071 : 530 : accum_sum_final(&(state->sumX2), &vsumX2);
6072 : :
8415 tgl@sss.pgh.pa.us 6073 : 530 : init_var(&vNminus1);
6074 : 530 : sub_var(&vN, &const_one, &vNminus1);
6075 : :
6076 : : /* compute rscale for mul_var calls */
8446 6077 : 530 : rscale = vsumX.dscale * 2;
6078 : :
6079 : 530 : mul_var(&vsumX, &vsumX, &vsumX, rscale); /* vsumX = sumX * sumX */
3240 6080 : 530 : mul_var(&vN, &vsumX2, &vsumX2, rscale); /* vsumX2 = N * sumX2 */
7153 bruce@momjian.us 6081 : 530 : sub_var(&vsumX2, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */
6082 : :
8911 tgl@sss.pgh.pa.us 6083 [ + + ]: 530 : if (cmp_var(&vsumX2, &const_zero) <= 0)
6084 : : {
6085 : : /* Watch out for roundoff error producing a negative numerator */
6086 : 50 : res = make_result(&const_zero);
6087 : : }
6088 : : else
6089 : : {
6875 6090 [ + + ]: 480 : if (sample)
3240 6091 : 328 : mul_var(&vN, &vNminus1, &vNminus1, 0); /* N * (N - 1) */
6092 : : else
6746 bruce@momjian.us 6093 : 152 : mul_var(&vN, &vN, &vNminus1, 0); /* N * N */
8446 tgl@sss.pgh.pa.us 6094 : 480 : rscale = select_div_scale(&vsumX2, &vNminus1);
578 dean.a.rasheed@gmail 6095 : 480 : div_var(&vsumX2, &vNminus1, &vsumX, rscale, true, true); /* variance */
7361 neilc@samurai.com 6096 [ + + ]: 480 : if (!variance)
7153 bruce@momjian.us 6097 : 252 : sqrt_var(&vsumX, &vsumX, rscale); /* stddev */
6098 : :
8911 tgl@sss.pgh.pa.us 6099 : 480 : res = make_result(&vsumX);
6100 : : }
6101 : :
9423 6102 : 530 : free_var(&vNminus1);
6103 : 530 : free_var(&vsumX);
6104 : 530 : free_var(&vsumX2);
6105 : :
7361 neilc@samurai.com 6106 : 530 : return res;
6107 : : }
6108 : :
6109 : : Datum
6110 : 120 : numeric_var_samp(PG_FUNCTION_ARGS)
6111 : : {
6112 : : NumericAggState *state;
6113 : : Numeric res;
6114 : : bool is_null;
6115 : :
4553 tgl@sss.pgh.pa.us 6116 [ + - ]: 120 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6117 : :
6118 : 120 : res = numeric_stddev_internal(state, true, true, &is_null);
6119 : :
7361 neilc@samurai.com 6120 [ + + ]: 120 : if (is_null)
8415 tgl@sss.pgh.pa.us 6121 : 28 : PG_RETURN_NULL();
6122 : : else
7361 neilc@samurai.com 6123 : 92 : PG_RETURN_NUMERIC(res);
6124 : : }
6125 : :
6126 : : Datum
6127 : 116 : numeric_stddev_samp(PG_FUNCTION_ARGS)
6128 : : {
6129 : : NumericAggState *state;
6130 : : Numeric res;
6131 : : bool is_null;
6132 : :
4553 tgl@sss.pgh.pa.us 6133 [ + - ]: 116 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6134 : :
6135 : 116 : res = numeric_stddev_internal(state, false, true, &is_null);
6136 : :
7361 neilc@samurai.com 6137 [ + + ]: 116 : if (is_null)
6138 : 28 : PG_RETURN_NULL();
6139 : : else
6140 : 88 : PG_RETURN_NUMERIC(res);
6141 : : }
6142 : :
6143 : : Datum
6144 : 76 : numeric_var_pop(PG_FUNCTION_ARGS)
6145 : : {
6146 : : NumericAggState *state;
6147 : : Numeric res;
6148 : : bool is_null;
6149 : :
4553 tgl@sss.pgh.pa.us 6150 [ + - ]: 76 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6151 : :
6152 : 76 : res = numeric_stddev_internal(state, true, false, &is_null);
6153 : :
7361 neilc@samurai.com 6154 [ - + ]: 76 : if (is_null)
7361 neilc@samurai.com 6155 :UBC 0 : PG_RETURN_NULL();
6156 : : else
7361 neilc@samurai.com 6157 :CBC 76 : PG_RETURN_NUMERIC(res);
6158 : : }
6159 : :
6160 : : Datum
6161 : 64 : numeric_stddev_pop(PG_FUNCTION_ARGS)
6162 : : {
6163 : : NumericAggState *state;
6164 : : Numeric res;
6165 : : bool is_null;
6166 : :
4553 tgl@sss.pgh.pa.us 6167 [ + - ]: 64 : state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
6168 : :
6169 : 64 : res = numeric_stddev_internal(state, false, false, &is_null);
6170 : :
7361 neilc@samurai.com 6171 [ - + ]: 64 : if (is_null)
7361 neilc@samurai.com 6172 :UBC 0 : PG_RETURN_NULL();
6173 : : else
7361 neilc@samurai.com 6174 :CBC 64 : PG_RETURN_NUMERIC(res);
6175 : : }
6176 : :
6177 : : static Numeric
4064 andres@anarazel.de 6178 : 278 : numeric_poly_stddev_internal(Int128AggState *state,
6179 : : bool variance, bool sample,
6180 : : bool *is_null)
6181 : : {
6182 : : NumericAggState numstate;
6183 : : Numeric res;
6184 : :
6185 : : /* Initialize an empty agg state */
3532 heikki.linnakangas@i 6186 : 278 : memset(&numstate, 0, sizeof(NumericAggState));
6187 : :
4064 andres@anarazel.de 6188 [ + - ]: 278 : if (state)
6189 : : {
6190 : : NumericVar tmp_var;
6191 : :
6192 : 278 : numstate.N = state->N;
6193 : :
3532 heikki.linnakangas@i 6194 : 278 : init_var(&tmp_var);
6195 : :
6196 : 278 : int128_to_numericvar(state->sumX, &tmp_var);
6197 : 278 : accum_sum_add(&numstate.sumX, &tmp_var);
6198 : :
6199 : 278 : int128_to_numericvar(state->sumX2, &tmp_var);
6200 : 278 : accum_sum_add(&numstate.sumX2, &tmp_var);
6201 : :
6202 : 278 : free_var(&tmp_var);
6203 : : }
6204 : :
4064 andres@anarazel.de 6205 : 278 : res = numeric_stddev_internal(&numstate, variance, sample, is_null);
6206 : :
3532 heikki.linnakangas@i 6207 [ + - ]: 278 : if (numstate.sumX.ndigits > 0)
6208 : : {
6209 : 278 : pfree(numstate.sumX.pos_digits);
6210 : 278 : pfree(numstate.sumX.neg_digits);
6211 : : }
6212 [ + - ]: 278 : if (numstate.sumX2.ndigits > 0)
6213 : : {
6214 : 278 : pfree(numstate.sumX2.pos_digits);
6215 : 278 : pfree(numstate.sumX2.neg_digits);
6216 : : }
6217 : :
4064 andres@anarazel.de 6218 : 278 : return res;
6219 : : }
6220 : :
6221 : : Datum
6222 : 84 : numeric_poly_var_samp(PG_FUNCTION_ARGS)
6223 : : {
6224 : : Int128AggState *state;
6225 : : Numeric res;
6226 : : bool is_null;
6227 : :
271 dean.a.rasheed@gmail 6228 [ + - ]:GNC 84 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
6229 : :
4064 andres@anarazel.de 6230 :CBC 84 : res = numeric_poly_stddev_internal(state, true, true, &is_null);
6231 : :
6232 [ + + ]: 84 : if (is_null)
6233 : 16 : PG_RETURN_NULL();
6234 : : else
6235 : 68 : PG_RETURN_NUMERIC(res);
6236 : : }
6237 : :
6238 : : Datum
6239 : 106 : numeric_poly_stddev_samp(PG_FUNCTION_ARGS)
6240 : : {
6241 : : Int128AggState *state;
6242 : : Numeric res;
6243 : : bool is_null;
6244 : :
271 dean.a.rasheed@gmail 6245 [ + - ]:GNC 106 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
6246 : :
4064 andres@anarazel.de 6247 :CBC 106 : res = numeric_poly_stddev_internal(state, false, true, &is_null);
6248 : :
6249 [ + + ]: 106 : if (is_null)
6250 : 16 : PG_RETURN_NULL();
6251 : : else
6252 : 90 : PG_RETURN_NUMERIC(res);
6253 : : }
6254 : :
6255 : : Datum
6256 : 40 : numeric_poly_var_pop(PG_FUNCTION_ARGS)
6257 : : {
6258 : : Int128AggState *state;
6259 : : Numeric res;
6260 : : bool is_null;
6261 : :
271 dean.a.rasheed@gmail 6262 [ + - ]:GNC 40 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
6263 : :
4064 andres@anarazel.de 6264 :CBC 40 : res = numeric_poly_stddev_internal(state, true, false, &is_null);
6265 : :
6266 [ - + ]: 40 : if (is_null)
4064 andres@anarazel.de 6267 :UBC 0 : PG_RETURN_NULL();
6268 : : else
4064 andres@anarazel.de 6269 :CBC 40 : PG_RETURN_NUMERIC(res);
6270 : : }
6271 : :
6272 : : Datum
6273 : 48 : numeric_poly_stddev_pop(PG_FUNCTION_ARGS)
6274 : : {
6275 : : Int128AggState *state;
6276 : : Numeric res;
6277 : : bool is_null;
6278 : :
271 dean.a.rasheed@gmail 6279 [ + - ]:GNC 48 : state = PG_ARGISNULL(0) ? NULL : (Int128AggState *) PG_GETARG_POINTER(0);
6280 : :
4064 andres@anarazel.de 6281 :CBC 48 : res = numeric_poly_stddev_internal(state, false, false, &is_null);
6282 : :
6283 [ - + ]: 48 : if (is_null)
4064 andres@anarazel.de 6284 :UBC 0 : PG_RETURN_NULL();
6285 : : else
4064 andres@anarazel.de 6286 :CBC 48 : PG_RETURN_NUMERIC(res);
6287 : : }
6288 : :
6289 : : /*
6290 : : * SUM transition functions for integer datatypes.
6291 : : *
6292 : : * To avoid overflow, we use accumulators wider than the input datatype.
6293 : : * A Numeric accumulator is needed for int8 input; for int4 and int2
6294 : : * inputs, we use int8 accumulators which should be sufficient for practical
6295 : : * purposes. (The latter two therefore don't really belong in this file,
6296 : : * but we keep them here anyway.)
6297 : : *
6298 : : * Because SQL defines the SUM() of no values to be NULL, not zero,
6299 : : * the initial condition of the transition data value needs to be NULL. This
6300 : : * means we can't rely on ExecAgg to automatically insert the first non-null
6301 : : * data value into the transition data: it doesn't know how to do the type
6302 : : * conversion. The upshot is that these routines have to be marked non-strict
6303 : : * and handle substitution of the first non-null input themselves.
6304 : : *
6305 : : * Note: these functions are used only in plain aggregation mode.
6306 : : * In moving-aggregate mode, we use intX_avg_accum and intX_avg_accum_inv.
6307 : : */
6308 : :
6309 : : Datum
9423 tgl@sss.pgh.pa.us 6310 : 16 : int2_sum(PG_FUNCTION_ARGS)
6311 : : {
6312 : : int64 oldsum;
6313 : : int64 newval;
6314 : :
6315 [ + + ]: 16 : if (PG_ARGISNULL(0))
6316 : : {
6317 : : /* No non-null input seen so far... */
6318 [ - + ]: 4 : if (PG_ARGISNULL(1))
9423 tgl@sss.pgh.pa.us 6319 :UBC 0 : PG_RETURN_NULL(); /* still no non-null */
6320 : : /* This is the first non-null input. */
9030 tgl@sss.pgh.pa.us 6321 :CBC 4 : newval = (int64) PG_GETARG_INT16(1);
6322 : 4 : PG_RETURN_INT64(newval);
6323 : : }
6324 : :
265 tgl@sss.pgh.pa.us 6325 :GNC 12 : oldsum = PG_GETARG_INT64(0);
6326 : :
6327 : : /* Leave sum unchanged if new input is null. */
6328 [ - + ]: 12 : if (PG_ARGISNULL(1))
265 tgl@sss.pgh.pa.us 6329 :UNC 0 : PG_RETURN_INT64(oldsum);
6330 : :
6331 : : /* OK to do the addition. */
265 tgl@sss.pgh.pa.us 6332 :GNC 12 : newval = oldsum + (int64) PG_GETARG_INT16(1);
6333 : :
6334 : 12 : PG_RETURN_INT64(newval);
6335 : : }
6336 : :
6337 : : Datum
9423 tgl@sss.pgh.pa.us 6338 :CBC 3267520 : int4_sum(PG_FUNCTION_ARGS)
6339 : : {
6340 : : int64 oldsum;
6341 : : int64 newval;
6342 : :
6343 [ + + ]: 3267520 : if (PG_ARGISNULL(0))
6344 : : {
6345 : : /* No non-null input seen so far... */
6346 [ + + ]: 129175 : if (PG_ARGISNULL(1))
6347 : 654 : PG_RETURN_NULL(); /* still no non-null */
6348 : : /* This is the first non-null input. */
9030 6349 : 128521 : newval = (int64) PG_GETARG_INT32(1);
6350 : 128521 : PG_RETURN_INT64(newval);
6351 : : }
6352 : :
265 tgl@sss.pgh.pa.us 6353 :GNC 3138345 : oldsum = PG_GETARG_INT64(0);
6354 : :
6355 : : /* Leave sum unchanged if new input is null. */
6356 [ + + ]: 3138345 : if (PG_ARGISNULL(1))
6357 : 20606 : PG_RETURN_INT64(oldsum);
6358 : :
6359 : : /* OK to do the addition. */
6360 : 3117739 : newval = oldsum + (int64) PG_GETARG_INT32(1);
6361 : :
6362 : 3117739 : PG_RETURN_INT64(newval);
6363 : : }
6364 : :
6365 : : /*
6366 : : * Note: this function is obsolete, it's no longer used for SUM(int8).
6367 : : */
6368 : : Datum
9423 tgl@sss.pgh.pa.us 6369 :UBC 0 : int8_sum(PG_FUNCTION_ARGS)
6370 : : {
6371 : : Numeric oldsum;
6372 : :
6373 [ # # ]: 0 : if (PG_ARGISNULL(0))
6374 : : {
6375 : : /* No non-null input seen so far... */
6376 [ # # ]: 0 : if (PG_ARGISNULL(1))
6377 : 0 : PG_RETURN_NULL(); /* still no non-null */
6378 : : /* This is the first non-null input. */
2064 peter@eisentraut.org 6379 : 0 : PG_RETURN_NUMERIC(int64_to_numeric(PG_GETARG_INT64(1)));
6380 : : }
6381 : :
6382 : : /*
6383 : : * Note that we cannot special-case the aggregate case here, as we do for
6384 : : * int2_sum and int4_sum: numeric is of variable size, so we cannot modify
6385 : : * our first parameter in-place.
6386 : : */
6387 : :
9423 tgl@sss.pgh.pa.us 6388 : 0 : oldsum = PG_GETARG_NUMERIC(0);
6389 : :
6390 : : /* Leave sum unchanged if new input is null. */
6391 [ # # ]: 0 : if (PG_ARGISNULL(1))
6392 : 0 : PG_RETURN_NUMERIC(oldsum);
6393 : :
6394 : : /* OK to do the addition. */
9411 6395 : 0 : PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,
6396 : : NumericGetDatum(oldsum),
6397 : : NumericGetDatum(int64_to_numeric(PG_GETARG_INT64(1)))));
6398 : : }
6399 : :
6400 : :
6401 : : /*
6402 : : * Routines for avg(int2) and avg(int4). The transition datatype
6403 : : * is a two-element int8 array, holding count and sum.
6404 : : *
6405 : : * These functions are also used for sum(int2) and sum(int4) when
6406 : : * operating in moving-aggregate mode, since for correct inverse transitions
6407 : : * we need to count the inputs.
6408 : : */
6409 : :
6410 : : typedef struct Int8TransTypeData
6411 : : {
6412 : : int64 count;
6413 : : int64 sum;
6414 : : } Int8TransTypeData;
6415 : :
6416 : : Datum
9030 tgl@sss.pgh.pa.us 6417 :CBC 28 : int2_avg_accum(PG_FUNCTION_ARGS)
6418 : : {
6419 : : ArrayType *transarray;
6420 : 28 : int16 newval = PG_GETARG_INT16(1);
6421 : : Int8TransTypeData *transdata;
6422 : :
6423 : : /*
6424 : : * If we're invoked as an aggregate, we can cheat and modify our first
6425 : : * parameter in-place to reduce palloc overhead. Otherwise we need to make
6426 : : * a copy of it before scribbling on it.
6427 : : */
5930 6428 [ + - ]: 28 : if (AggCheckCallContext(fcinfo, NULL))
7701 neilc@samurai.com 6429 : 28 : transarray = PG_GETARG_ARRAYTYPE_P(0);
6430 : : else
7701 neilc@samurai.com 6431 :UBC 0 : transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6432 : :
7474 tgl@sss.pgh.pa.us 6433 [ + - - + ]:CBC 56 : if (ARR_HASNULL(transarray) ||
6434 [ - + ]: 28 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
8318 tgl@sss.pgh.pa.us 6435 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6436 : :
7701 neilc@samurai.com 6437 [ - + ]:CBC 28 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
9030 tgl@sss.pgh.pa.us 6438 : 28 : transdata->count++;
6439 : 28 : transdata->sum += newval;
6440 : :
6441 : 28 : PG_RETURN_ARRAYTYPE_P(transarray);
6442 : : }
6443 : :
6444 : : Datum
6445 : 1744070 : int4_avg_accum(PG_FUNCTION_ARGS)
6446 : : {
6447 : : ArrayType *transarray;
6448 : 1744070 : int32 newval = PG_GETARG_INT32(1);
6449 : : Int8TransTypeData *transdata;
6450 : :
6451 : : /*
6452 : : * If we're invoked as an aggregate, we can cheat and modify our first
6453 : : * parameter in-place to reduce palloc overhead. Otherwise we need to make
6454 : : * a copy of it before scribbling on it.
6455 : : */
5930 6456 [ + - ]: 1744070 : if (AggCheckCallContext(fcinfo, NULL))
7701 neilc@samurai.com 6457 : 1744070 : transarray = PG_GETARG_ARRAYTYPE_P(0);
6458 : : else
7701 neilc@samurai.com 6459 :UBC 0 : transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6460 : :
7474 tgl@sss.pgh.pa.us 6461 [ + - - + ]:CBC 3488140 : if (ARR_HASNULL(transarray) ||
6462 [ - + ]: 1744070 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
8318 tgl@sss.pgh.pa.us 6463 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6464 : :
7701 neilc@samurai.com 6465 [ - + ]:CBC 1744070 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
9030 tgl@sss.pgh.pa.us 6466 : 1744070 : transdata->count++;
6467 : 1744070 : transdata->sum += newval;
6468 : :
6469 : 1744070 : PG_RETURN_ARRAYTYPE_P(transarray);
6470 : : }
6471 : :
6472 : : Datum
3682 rhaas@postgresql.org 6473 : 6791 : int4_avg_combine(PG_FUNCTION_ARGS)
6474 : : {
6475 : : ArrayType *transarray1;
6476 : : ArrayType *transarray2;
6477 : : Int8TransTypeData *state1;
6478 : : Int8TransTypeData *state2;
6479 : :
6480 [ - + ]: 6791 : if (!AggCheckCallContext(fcinfo, NULL))
3682 rhaas@postgresql.org 6481 [ # # ]:UBC 0 : elog(ERROR, "aggregate function called in non-aggregate context");
6482 : :
3682 rhaas@postgresql.org 6483 :CBC 6791 : transarray1 = PG_GETARG_ARRAYTYPE_P(0);
6484 : 6791 : transarray2 = PG_GETARG_ARRAYTYPE_P(1);
6485 : :
6486 [ + - - + ]: 13582 : if (ARR_HASNULL(transarray1) ||
6487 [ - + ]: 6791 : ARR_SIZE(transarray1) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
3682 rhaas@postgresql.org 6488 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6489 : :
3682 rhaas@postgresql.org 6490 [ + - - + ]:CBC 13582 : if (ARR_HASNULL(transarray2) ||
6491 [ - + ]: 6791 : ARR_SIZE(transarray2) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
3682 rhaas@postgresql.org 6492 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6493 : :
3682 rhaas@postgresql.org 6494 [ - + ]:CBC 6791 : state1 = (Int8TransTypeData *) ARR_DATA_PTR(transarray1);
6495 [ - + ]: 6791 : state2 = (Int8TransTypeData *) ARR_DATA_PTR(transarray2);
6496 : :
6497 : 6791 : state1->count += state2->count;
6498 : 6791 : state1->sum += state2->sum;
6499 : :
6500 : 6791 : PG_RETURN_ARRAYTYPE_P(transarray1);
6501 : : }
6502 : :
6503 : : Datum
4406 tgl@sss.pgh.pa.us 6504 : 8 : int2_avg_accum_inv(PG_FUNCTION_ARGS)
6505 : : {
6506 : : ArrayType *transarray;
6507 : 8 : int16 newval = PG_GETARG_INT16(1);
6508 : : Int8TransTypeData *transdata;
6509 : :
6510 : : /*
6511 : : * If we're invoked as an aggregate, we can cheat and modify our first
6512 : : * parameter in-place to reduce palloc overhead. Otherwise we need to make
6513 : : * a copy of it before scribbling on it.
6514 : : */
6515 [ + - ]: 8 : if (AggCheckCallContext(fcinfo, NULL))
6516 : 8 : transarray = PG_GETARG_ARRAYTYPE_P(0);
6517 : : else
4406 tgl@sss.pgh.pa.us 6518 :UBC 0 : transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6519 : :
4406 tgl@sss.pgh.pa.us 6520 [ + - - + ]:CBC 16 : if (ARR_HASNULL(transarray) ||
6521 [ - + ]: 8 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
4406 tgl@sss.pgh.pa.us 6522 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6523 : :
4406 tgl@sss.pgh.pa.us 6524 [ - + ]:CBC 8 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6525 : 8 : transdata->count--;
6526 : 8 : transdata->sum -= newval;
6527 : :
6528 : 8 : PG_RETURN_ARRAYTYPE_P(transarray);
6529 : : }
6530 : :
6531 : : Datum
6532 : 1000 : int4_avg_accum_inv(PG_FUNCTION_ARGS)
6533 : : {
6534 : : ArrayType *transarray;
6535 : 1000 : int32 newval = PG_GETARG_INT32(1);
6536 : : Int8TransTypeData *transdata;
6537 : :
6538 : : /*
6539 : : * If we're invoked as an aggregate, we can cheat and modify our first
6540 : : * parameter in-place to reduce palloc overhead. Otherwise we need to make
6541 : : * a copy of it before scribbling on it.
6542 : : */
6543 [ + - ]: 1000 : if (AggCheckCallContext(fcinfo, NULL))
6544 : 1000 : transarray = PG_GETARG_ARRAYTYPE_P(0);
6545 : : else
4406 tgl@sss.pgh.pa.us 6546 :UBC 0 : transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6547 : :
4406 tgl@sss.pgh.pa.us 6548 [ + - - + ]:CBC 2000 : if (ARR_HASNULL(transarray) ||
6549 [ - + ]: 1000 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
4406 tgl@sss.pgh.pa.us 6550 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
6551 : :
4406 tgl@sss.pgh.pa.us 6552 [ - + ]:CBC 1000 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6553 : 1000 : transdata->count--;
6554 : 1000 : transdata->sum -= newval;
6555 : :
6556 : 1000 : PG_RETURN_ARRAYTYPE_P(transarray);
6557 : : }
6558 : :
6559 : : Datum
9030 6560 : 6817 : int8_avg(PG_FUNCTION_ARGS)
6561 : : {
6562 : 6817 : ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
6563 : : Int8TransTypeData *transdata;
6564 : : Datum countd,
6565 : : sumd;
6566 : :
7474 6567 [ + - - + ]: 13634 : if (ARR_HASNULL(transarray) ||
6568 [ - + ]: 6817 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
8318 tgl@sss.pgh.pa.us 6569 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
9030 tgl@sss.pgh.pa.us 6570 [ - + ]:CBC 6817 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6571 : :
6572 : : /* SQL defines AVG of no values to be NULL */
6573 [ + + ]: 6817 : if (transdata->count == 0)
6574 : 73 : PG_RETURN_NULL();
6575 : :
2064 peter@eisentraut.org 6576 : 6744 : countd = NumericGetDatum(int64_to_numeric(transdata->count));
6577 : 6744 : sumd = NumericGetDatum(int64_to_numeric(transdata->sum));
6578 : :
9030 tgl@sss.pgh.pa.us 6579 : 6744 : PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
6580 : : }
6581 : :
6582 : : /*
6583 : : * SUM(int2) and SUM(int4) both return int8, so we can use this
6584 : : * final function for both.
6585 : : */
6586 : : Datum
4406 6587 : 2716 : int2int4_sum(PG_FUNCTION_ARGS)
6588 : : {
6589 : 2716 : ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
6590 : : Int8TransTypeData *transdata;
6591 : :
6592 [ + - - + ]: 5432 : if (ARR_HASNULL(transarray) ||
6593 [ - + ]: 2716 : ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
4406 tgl@sss.pgh.pa.us 6594 [ # # ]:UBC 0 : elog(ERROR, "expected 2-element int8 array");
4406 tgl@sss.pgh.pa.us 6595 [ - + ]:CBC 2716 : transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6596 : :
6597 : : /* SQL defines SUM of no values to be NULL */
6598 [ + + ]: 2716 : if (transdata->count == 0)
6599 : 404 : PG_RETURN_NULL();
6600 : :
6601 : 2312 : PG_RETURN_DATUM(Int64GetDatumFast(transdata->sum));
6602 : : }
6603 : :
6604 : :
6605 : : /* ----------------------------------------------------------------------
6606 : : *
6607 : : * Debug support
6608 : : *
6609 : : * ----------------------------------------------------------------------
6610 : : */
6611 : :
6612 : : #ifdef NUMERIC_DEBUG
6613 : :
6614 : : /*
6615 : : * dump_numeric() - Dump a value in the db storage format for debugging
6616 : : */
6617 : : static void
6618 : : dump_numeric(const char *str, Numeric num)
6619 : : {
6620 : : NumericDigit *digits = NUMERIC_DIGITS(num);
6621 : : int ndigits;
6622 : : int i;
6623 : :
6624 : : ndigits = NUMERIC_NDIGITS(num);
6625 : :
6626 : : printf("%s: NUMERIC w=%d d=%d ", str,
6627 : : NUMERIC_WEIGHT(num), NUMERIC_DSCALE(num));
6628 : : switch (NUMERIC_SIGN(num))
6629 : : {
6630 : : case NUMERIC_POS:
6631 : : printf("POS");
6632 : : break;
6633 : : case NUMERIC_NEG:
6634 : : printf("NEG");
6635 : : break;
6636 : : case NUMERIC_NAN:
6637 : : printf("NaN");
6638 : : break;
6639 : : case NUMERIC_PINF:
6640 : : printf("Infinity");
6641 : : break;
6642 : : case NUMERIC_NINF:
6643 : : printf("-Infinity");
6644 : : break;
6645 : : default:
6646 : : printf("SIGN=0x%x", NUMERIC_SIGN(num));
6647 : : break;
6648 : : }
6649 : :
6650 : : for (i = 0; i < ndigits; i++)
6651 : : printf(" %0*d", DEC_DIGITS, digits[i]);
6652 : : printf("\n");
6653 : : }
6654 : :
6655 : :
6656 : : /*
6657 : : * dump_var() - Dump a value in the variable format for debugging
6658 : : */
6659 : : static void
6660 : : dump_var(const char *str, NumericVar *var)
6661 : : {
6662 : : int i;
6663 : :
6664 : : printf("%s: VAR w=%d d=%d ", str, var->weight, var->dscale);
6665 : : switch (var->sign)
6666 : : {
6667 : : case NUMERIC_POS:
6668 : : printf("POS");
6669 : : break;
6670 : : case NUMERIC_NEG:
6671 : : printf("NEG");
6672 : : break;
6673 : : case NUMERIC_NAN:
6674 : : printf("NaN");
6675 : : break;
6676 : : case NUMERIC_PINF:
6677 : : printf("Infinity");
6678 : : break;
6679 : : case NUMERIC_NINF:
6680 : : printf("-Infinity");
6681 : : break;
6682 : : default:
6683 : : printf("SIGN=0x%x", var->sign);
6684 : : break;
6685 : : }
6686 : :
6687 : : for (i = 0; i < var->ndigits; i++)
6688 : : printf(" %0*d", DEC_DIGITS, var->digits[i]);
6689 : :
6690 : : printf("\n");
6691 : : }
6692 : : #endif /* NUMERIC_DEBUG */
6693 : :
6694 : :
6695 : : /* ----------------------------------------------------------------------
6696 : : *
6697 : : * Local functions follow
6698 : : *
6699 : : * In general, these do not support "special" (NaN or infinity) inputs;
6700 : : * callers should handle those possibilities first.
6701 : : * (There are one or two exceptions, noted in their header comments.)
6702 : : *
6703 : : * ----------------------------------------------------------------------
6704 : : */
6705 : :
6706 : :
6707 : : /*
6708 : : * alloc_var() -
6709 : : *
6710 : : * Allocate a digit buffer of ndigits digits (plus a spare digit for rounding)
6711 : : */
6712 : : static void
9604 6713 : 1444536 : alloc_var(NumericVar *var, int ndigits)
6714 : : {
6715 [ + + ]: 1444536 : digitbuf_free(var->buf);
6716 : 1444536 : var->buf = digitbuf_alloc(ndigits + 1);
8310 bruce@momjian.us 6717 : 1444536 : var->buf[0] = 0; /* spare digit for rounding */
9604 tgl@sss.pgh.pa.us 6718 : 1444536 : var->digits = var->buf + 1;
6719 : 1444536 : var->ndigits = ndigits;
9988 JanWieck@Yahoo.com 6720 : 1444536 : }
6721 : :
6722 : :
6723 : : /*
6724 : : * free_var() -
6725 : : *
6726 : : * Return the digit buffer of a variable to the free pool
6727 : : */
6728 : : static void
9842 bruce@momjian.us 6729 : 2780364 : free_var(NumericVar *var)
6730 : : {
9604 tgl@sss.pgh.pa.us 6731 [ + + ]: 2780364 : digitbuf_free(var->buf);
6732 : 2780364 : var->buf = NULL;
6733 : 2780364 : var->digits = NULL;
9988 JanWieck@Yahoo.com 6734 : 2780364 : var->sign = NUMERIC_NAN;
6735 : 2780364 : }
6736 : :
6737 : :
6738 : : /*
6739 : : * zero_var() -
6740 : : *
6741 : : * Set a variable to ZERO.
6742 : : * Note: its dscale is not touched.
6743 : : */
6744 : : static void
9604 tgl@sss.pgh.pa.us 6745 : 38215 : zero_var(NumericVar *var)
6746 : : {
6747 [ + + ]: 38215 : digitbuf_free(var->buf);
6748 : 38215 : var->buf = NULL;
6749 : 38215 : var->digits = NULL;
6750 : 38215 : var->ndigits = 0;
6751 : 38215 : var->weight = 0; /* by convention; doesn't really matter */
6752 : 38215 : var->sign = NUMERIC_POS; /* anything but NAN... */
9988 JanWieck@Yahoo.com 6753 : 38215 : }
6754 : :
6755 : :
6756 : : /*
6757 : : * set_var_from_str()
6758 : : *
6759 : : * Parse a string and put the number into a variable
6760 : : *
6761 : : * This function does not handle leading or trailing spaces. It returns
6762 : : * the end+1 position parsed into *endptr, so that caller can check for
6763 : : * trailing spaces/garbage if deemed necessary.
6764 : : *
6765 : : * cp is the place to actually start parsing; str is what to use in error
6766 : : * reports. (Typically cp would be the same except advanced over spaces.)
6767 : : *
6768 : : * Returns true on success, false on failure (if escontext points to an
6769 : : * ErrorSaveContext; otherwise errors are thrown).
6770 : : */
6771 : : static bool
1243 tgl@sss.pgh.pa.us 6772 : 118495 : set_var_from_str(const char *str, const char *cp,
6773 : : NumericVar *dest, const char **endptr,
6774 : : Node *escontext)
6775 : : {
3184 peter_e@gmx.net 6776 : 118495 : bool have_dp = false;
6777 : : int i;
6778 : : unsigned char *decdigits;
8446 tgl@sss.pgh.pa.us 6779 : 118495 : int sign = NUMERIC_POS;
6780 : 118495 : int dweight = -1;
6781 : : int ddigits;
6782 : 118495 : int dscale = 0;
6783 : : int weight;
6784 : : int ndigits;
6785 : : int offset;
6786 : : NumericDigit *digits;
6787 : :
6788 : : /*
6789 : : * We first parse the string to extract decimal digits and determine the
6790 : : * correct decimal weight. Then convert to NBASE representation.
6791 : : */
9988 JanWieck@Yahoo.com 6792 [ - + + ]: 118495 : switch (*cp)
6793 : : {
9842 bruce@momjian.us 6794 :UBC 0 : case '+':
8446 tgl@sss.pgh.pa.us 6795 : 0 : sign = NUMERIC_POS;
9842 bruce@momjian.us 6796 : 0 : cp++;
6797 : 0 : break;
6798 : :
9842 bruce@momjian.us 6799 :CBC 183 : case '-':
8446 tgl@sss.pgh.pa.us 6800 : 183 : sign = NUMERIC_NEG;
9842 bruce@momjian.us 6801 : 183 : cp++;
6802 : 183 : break;
6803 : : }
6804 : :
9988 JanWieck@Yahoo.com 6805 [ + + ]: 118495 : if (*cp == '.')
6806 : : {
3184 peter_e@gmx.net 6807 : 252 : have_dp = true;
9988 JanWieck@Yahoo.com 6808 : 252 : cp++;
6809 : : }
6810 : :
9284 tgl@sss.pgh.pa.us 6811 [ - + ]: 118495 : if (!isdigit((unsigned char) *cp))
1186 dean.a.rasheed@gmail 6812 :UBC 0 : goto invalid_syntax;
6813 : :
8310 bruce@momjian.us 6814 :CBC 118495 : decdigits = (unsigned char *) palloc(strlen(cp) + DEC_DIGITS * 2);
6815 : :
6816 : : /* leading padding for digit alignment later */
8446 tgl@sss.pgh.pa.us 6817 : 118495 : memset(decdigits, 0, DEC_DIGITS);
6818 : 118495 : i = DEC_DIGITS;
6819 : :
9988 JanWieck@Yahoo.com 6820 [ + + ]: 506456 : while (*cp)
6821 : : {
9284 tgl@sss.pgh.pa.us 6822 [ + + ]: 388943 : if (isdigit((unsigned char) *cp))
6823 : : {
8446 6824 : 375930 : decdigits[i++] = *cp++ - '0';
9604 6825 [ + + ]: 375930 : if (!have_dp)
8446 6826 : 314025 : dweight++;
6827 : : else
6828 : 61905 : dscale++;
6829 : : }
9604 6830 [ + + ]: 13013 : else if (*cp == '.')
6831 : : {
6832 [ - + ]: 11923 : if (have_dp)
1186 dean.a.rasheed@gmail 6833 :UBC 0 : goto invalid_syntax;
3184 peter_e@gmx.net 6834 :CBC 11923 : have_dp = true;
9604 tgl@sss.pgh.pa.us 6835 : 11923 : cp++;
6836 : : /* decimal point must not be followed by underscore */
1186 dean.a.rasheed@gmail 6837 [ + + ]: 11923 : if (*cp == '_')
6838 : 4 : goto invalid_syntax;
6839 : : }
6840 [ + + ]: 1090 : else if (*cp == '_')
6841 : : {
6842 : : /* underscore must be followed by more digits */
6843 : 124 : cp++;
6844 [ + + ]: 124 : if (!isdigit((unsigned char) *cp))
6845 : 12 : goto invalid_syntax;
6846 : : }
6847 : : else
9604 tgl@sss.pgh.pa.us 6848 : 966 : break;
6849 : : }
6850 : :
8446 6851 : 118479 : ddigits = i - DEC_DIGITS;
6852 : : /* trailing padding for digit alignment later */
8310 bruce@momjian.us 6853 : 118479 : memset(decdigits + i, 0, DEC_DIGITS - 1);
6854 : :
6855 : : /* Handle exponent, if any */
9988 JanWieck@Yahoo.com 6856 [ + + + + ]: 118479 : if (*cp == 'e' || *cp == 'E')
6857 : : {
1186 dean.a.rasheed@gmail 6858 : 934 : int64 exponent = 0;
6859 : 934 : bool neg = false;
6860 : :
6861 : : /*
6862 : : * At this point, dweight and dscale can't be more than about
6863 : : * INT_MAX/2 due to the MaxAllocSize limit on string length, so
6864 : : * constraining the exponent similarly should be enough to prevent
6865 : : * integer overflow in this function. If the value is too large to
6866 : : * fit in storage format, make_result() will complain about it later;
6867 : : * for consistency use the same ereport errcode/text as make_result().
6868 : : */
6869 : :
6870 : : /* exponent sign */
6871 : 934 : cp++;
6872 [ + + ]: 934 : if (*cp == '+')
6873 : 102 : cp++;
6874 [ + + ]: 832 : else if (*cp == '-')
6875 : : {
6876 : 400 : neg = true;
6877 : 400 : cp++;
6878 : : }
6879 : :
6880 : : /* exponent digits */
6881 [ + + ]: 934 : if (!isdigit((unsigned char) *cp))
6882 : 4 : goto invalid_syntax;
6883 : :
6884 [ + + ]: 3233 : while (*cp)
6885 : : {
6886 [ + + ]: 2315 : if (isdigit((unsigned char) *cp))
6887 : : {
6888 : 2287 : exponent = exponent * 10 + (*cp++ - '0');
6889 [ + + ]: 2287 : if (exponent > PG_INT32_MAX / 2)
6890 : 4 : goto out_of_range;
6891 : : }
6892 [ + - ]: 28 : else if (*cp == '_')
6893 : : {
6894 : : /* underscore must be followed by more digits */
6895 : 28 : cp++;
6896 [ + + ]: 28 : if (!isdigit((unsigned char) *cp))
6897 : 8 : goto invalid_syntax;
6898 : : }
6899 : : else
1186 dean.a.rasheed@gmail 6900 :UBC 0 : break;
6901 : : }
6902 : :
1186 dean.a.rasheed@gmail 6903 [ + + ]:CBC 918 : if (neg)
6904 : 400 : exponent = -exponent;
6905 : :
8446 tgl@sss.pgh.pa.us 6906 : 918 : dweight += (int) exponent;
6907 : 918 : dscale -= (int) exponent;
6908 [ + + ]: 918 : if (dscale < 0)
6909 : 382 : dscale = 0;
6910 : : }
6911 : :
6912 : : /*
6913 : : * Okay, convert pure-decimal representation to base NBASE. First we need
6914 : : * to determine the converted weight and ndigits. offset is the number of
6915 : : * decimal zeroes to insert before the first given digit to have a
6916 : : * correctly aligned first NBASE digit.
6917 : : */
6918 [ + + ]: 118463 : if (dweight >= 0)
8310 bruce@momjian.us 6919 : 117879 : weight = (dweight + 1 + DEC_DIGITS - 1) / DEC_DIGITS - 1;
6920 : : else
6921 : 584 : weight = -((-dweight - 1) / DEC_DIGITS + 1);
8446 tgl@sss.pgh.pa.us 6922 : 118463 : offset = (weight + 1) * DEC_DIGITS - (dweight + 1);
8310 bruce@momjian.us 6923 : 118463 : ndigits = (ddigits + offset + DEC_DIGITS - 1) / DEC_DIGITS;
6924 : :
8446 tgl@sss.pgh.pa.us 6925 : 118463 : alloc_var(dest, ndigits);
6926 : 118463 : dest->sign = sign;
6927 : 118463 : dest->weight = weight;
6928 : 118463 : dest->dscale = dscale;
6929 : :
6930 : 118463 : i = DEC_DIGITS - offset;
6931 : 118463 : digits = dest->digits;
6932 : :
6933 [ + + ]: 283795 : while (ndigits-- > 0)
6934 : : {
6935 : : #if DEC_DIGITS == 4
8310 bruce@momjian.us 6936 : 165332 : *digits++ = ((decdigits[i] * 10 + decdigits[i + 1]) * 10 +
6937 : 165332 : decdigits[i + 2]) * 10 + decdigits[i + 3];
6938 : : #elif DEC_DIGITS == 2
6939 : : *digits++ = decdigits[i] * 10 + decdigits[i + 1];
6940 : : #elif DEC_DIGITS == 1
6941 : : *digits++ = decdigits[i];
6942 : : #else
6943 : : #error unsupported NBASE
6944 : : #endif
8446 tgl@sss.pgh.pa.us 6945 : 165332 : i += DEC_DIGITS;
6946 : : }
6947 : :
6948 : 118463 : pfree(decdigits);
6949 : :
6950 : : /* Strip any leading/trailing zeroes, and normalize weight if zero */
6951 : 118463 : strip_var(dest);
6952 : :
6953 : : /* Return end+1 position for caller */
1243 6954 : 118463 : *endptr = cp;
6955 : :
6956 : 118463 : return true;
6957 : :
1186 dean.a.rasheed@gmail 6958 : 4 : out_of_range:
6959 [ + - ]: 4 : ereturn(escontext, false,
6960 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
6961 : : errmsg("value overflows numeric format")));
6962 : :
6963 : 28 : invalid_syntax:
6964 [ + - ]: 28 : ereturn(escontext, false,
6965 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
6966 : : errmsg("invalid input syntax for type %s: \"%s\"",
6967 : : "numeric", str)));
6968 : : }
6969 : :
6970 : :
6971 : : /*
6972 : : * Return the numeric value of a single hex digit.
6973 : : */
6974 : : static inline int
1198 6975 : 472 : xdigit_value(char dig)
6976 : : {
6977 [ + - + + ]: 596 : return dig >= '0' && dig <= '9' ? dig - '0' :
6978 [ + + + - ]: 196 : dig >= 'a' && dig <= 'f' ? dig - 'a' + 10 :
6979 [ + - + - ]: 72 : dig >= 'A' && dig <= 'F' ? dig - 'A' + 10 : -1;
6980 : : }
6981 : :
6982 : : /*
6983 : : * set_var_from_non_decimal_integer_str()
6984 : : *
6985 : : * Parse a string containing a non-decimal integer
6986 : : *
6987 : : * This function does not handle leading or trailing spaces. It returns
6988 : : * the end+1 position parsed into *endptr, so that caller can check for
6989 : : * trailing spaces/garbage if deemed necessary.
6990 : : *
6991 : : * cp is the place to actually start parsing; str is what to use in error
6992 : : * reports. The number's sign and base prefix indicator (e.g., "0x") are
6993 : : * assumed to have already been parsed, so cp should point to the number's
6994 : : * first digit in the base specified.
6995 : : *
6996 : : * base is expected to be 2, 8 or 16.
6997 : : *
6998 : : * Returns true on success, false on failure (if escontext points to an
6999 : : * ErrorSaveContext; otherwise errors are thrown).
7000 : : */
7001 : : static bool
7002 : 104 : set_var_from_non_decimal_integer_str(const char *str, const char *cp, int sign,
7003 : : int base, NumericVar *dest,
7004 : : const char **endptr, Node *escontext)
7005 : : {
7006 : 104 : const char *firstdigit = cp;
7007 : : int64 tmp;
7008 : : int64 mul;
7009 : : NumericVar tmp_var;
7010 : :
7011 : 104 : init_var(&tmp_var);
7012 : :
7013 : 104 : zero_var(dest);
7014 : :
7015 : : /*
7016 : : * Process input digits in groups that fit in int64. Here "tmp" is the
7017 : : * value of the digits in the group, and "mul" is base^n, where n is the
7018 : : * number of digits in the group. Thus tmp < mul, and we must start a new
7019 : : * group when mul * base threatens to overflow PG_INT64_MAX.
7020 : : */
7021 : 104 : tmp = 0;
7022 : 104 : mul = 1;
7023 : :
7024 [ + + ]: 104 : if (base == 16)
7025 : : {
7026 [ + + ]: 552 : while (*cp)
7027 : : {
7028 [ + + ]: 532 : if (isxdigit((unsigned char) *cp))
7029 : : {
7030 [ + + ]: 472 : if (mul > PG_INT64_MAX / 16)
7031 : : {
7032 : : /* Add the contribution from this group of digits */
7033 : 20 : int64_to_numericvar(mul, &tmp_var);
7034 : 20 : mul_var(dest, &tmp_var, dest, 0);
7035 : 20 : int64_to_numericvar(tmp, &tmp_var);
7036 : 20 : add_var(dest, &tmp_var, dest);
7037 : :
7038 : : /* Result will overflow if weight overflows int16 */
666 7039 [ - + ]: 20 : if (dest->weight > NUMERIC_WEIGHT_MAX)
1198 dean.a.rasheed@gmail 7040 :UBC 0 : goto out_of_range;
7041 : :
7042 : : /* Begin a new group */
1198 dean.a.rasheed@gmail 7043 :CBC 20 : tmp = 0;
7044 : 20 : mul = 1;
7045 : : }
7046 : :
7047 : 472 : tmp = tmp * 16 + xdigit_value(*cp++);
7048 : 472 : mul = mul * 16;
7049 : : }
1186 7050 [ + + ]: 60 : else if (*cp == '_')
7051 : : {
7052 : : /* Underscore must be followed by more digits */
7053 : 44 : cp++;
7054 [ + + ]: 44 : if (!isxdigit((unsigned char) *cp))
7055 : 12 : goto invalid_syntax;
7056 : : }
7057 : : else
1198 7058 : 16 : break;
7059 : : }
7060 : : }
7061 [ + + ]: 56 : else if (base == 8)
7062 : : {
7063 [ + + ]: 424 : while (*cp)
7064 : : {
7065 [ + + + + ]: 404 : if (*cp >= '0' && *cp <= '7')
7066 : : {
7067 [ + + ]: 372 : if (mul > PG_INT64_MAX / 8)
7068 : : {
7069 : : /* Add the contribution from this group of digits */
7070 : 12 : int64_to_numericvar(mul, &tmp_var);
7071 : 12 : mul_var(dest, &tmp_var, dest, 0);
7072 : 12 : int64_to_numericvar(tmp, &tmp_var);
7073 : 12 : add_var(dest, &tmp_var, dest);
7074 : :
7075 : : /* Result will overflow if weight overflows int16 */
666 7076 [ - + ]: 12 : if (dest->weight > NUMERIC_WEIGHT_MAX)
1198 dean.a.rasheed@gmail 7077 :UBC 0 : goto out_of_range;
7078 : :
7079 : : /* Begin a new group */
1198 dean.a.rasheed@gmail 7080 :CBC 12 : tmp = 0;
7081 : 12 : mul = 1;
7082 : : }
7083 : :
7084 : 372 : tmp = tmp * 8 + (*cp++ - '0');
7085 : 372 : mul = mul * 8;
7086 : : }
1186 7087 [ + + ]: 32 : else if (*cp == '_')
7088 : : {
7089 : : /* Underscore must be followed by more digits */
7090 : 24 : cp++;
7091 [ + - - + ]: 24 : if (*cp < '0' || *cp > '7')
1186 dean.a.rasheed@gmail 7092 :UBC 0 : goto invalid_syntax;
7093 : : }
7094 : : else
1198 dean.a.rasheed@gmail 7095 :CBC 8 : break;
7096 : : }
7097 : : }
7098 [ + - ]: 28 : else if (base == 2)
7099 : : {
7100 [ + + ]: 1040 : while (*cp)
7101 : : {
7102 [ + + + + ]: 1020 : if (*cp >= '0' && *cp <= '1')
7103 : : {
7104 [ + + ]: 944 : if (mul > PG_INT64_MAX / 2)
7105 : : {
7106 : : /* Add the contribution from this group of digits */
7107 : 12 : int64_to_numericvar(mul, &tmp_var);
7108 : 12 : mul_var(dest, &tmp_var, dest, 0);
7109 : 12 : int64_to_numericvar(tmp, &tmp_var);
7110 : 12 : add_var(dest, &tmp_var, dest);
7111 : :
7112 : : /* Result will overflow if weight overflows int16 */
666 7113 [ - + ]: 12 : if (dest->weight > NUMERIC_WEIGHT_MAX)
1198 dean.a.rasheed@gmail 7114 :UBC 0 : goto out_of_range;
7115 : :
7116 : : /* Begin a new group */
1198 dean.a.rasheed@gmail 7117 :CBC 12 : tmp = 0;
7118 : 12 : mul = 1;
7119 : : }
7120 : :
7121 : 944 : tmp = tmp * 2 + (*cp++ - '0');
7122 : 944 : mul = mul * 2;
7123 : : }
1186 7124 [ + + ]: 76 : else if (*cp == '_')
7125 : : {
7126 : : /* Underscore must be followed by more digits */
7127 : 68 : cp++;
7128 [ + - - + ]: 68 : if (*cp < '0' || *cp > '1')
1186 dean.a.rasheed@gmail 7129 :UBC 0 : goto invalid_syntax;
7130 : : }
7131 : : else
1198 dean.a.rasheed@gmail 7132 :CBC 8 : break;
7133 : : }
7134 : : }
7135 : : else
7136 : : /* Should never happen; treat as invalid input */
1198 dean.a.rasheed@gmail 7137 :UBC 0 : goto invalid_syntax;
7138 : :
7139 : : /* Check that we got at least one digit */
1198 dean.a.rasheed@gmail 7140 [ - + ]:CBC 92 : if (unlikely(cp == firstdigit))
1198 dean.a.rasheed@gmail 7141 :UBC 0 : goto invalid_syntax;
7142 : :
7143 : : /* Add the contribution from the final group of digits */
1198 dean.a.rasheed@gmail 7144 :CBC 92 : int64_to_numericvar(mul, &tmp_var);
7145 : 92 : mul_var(dest, &tmp_var, dest, 0);
7146 : 92 : int64_to_numericvar(tmp, &tmp_var);
7147 : 92 : add_var(dest, &tmp_var, dest);
7148 : :
666 7149 [ - + ]: 92 : if (dest->weight > NUMERIC_WEIGHT_MAX)
1198 dean.a.rasheed@gmail 7150 :UBC 0 : goto out_of_range;
7151 : :
1198 dean.a.rasheed@gmail 7152 :CBC 92 : dest->sign = sign;
7153 : :
7154 : 92 : free_var(&tmp_var);
7155 : :
7156 : : /* Return end+1 position for caller */
7157 : 92 : *endptr = cp;
7158 : :
7159 : 92 : return true;
7160 : :
1198 dean.a.rasheed@gmail 7161 :UBC 0 : out_of_range:
7162 [ # # ]: 0 : ereturn(escontext, false,
7163 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7164 : : errmsg("value overflows numeric format")));
7165 : :
1198 dean.a.rasheed@gmail 7166 :CBC 12 : invalid_syntax:
7167 [ + - ]: 12 : ereturn(escontext, false,
7168 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
7169 : : errmsg("invalid input syntax for type %s: \"%s\"",
7170 : : "numeric", str)));
7171 : : }
7172 : :
7173 : :
7174 : : /*
7175 : : * set_var_from_num() -
7176 : : *
7177 : : * Convert the packed db format into a variable
7178 : : */
7179 : : static void
9842 bruce@momjian.us 7180 : 8807 : set_var_from_num(Numeric num, NumericVar *dest)
7181 : : {
7182 : : int ndigits;
7183 : :
7392 7184 [ + + ]: 8807 : ndigits = NUMERIC_NDIGITS(num);
7185 : :
8446 tgl@sss.pgh.pa.us 7186 : 8807 : alloc_var(dest, ndigits);
7187 : :
5754 rhaas@postgresql.org 7188 [ + + + + ]: 8807 : dest->weight = NUMERIC_WEIGHT(num);
9842 bruce@momjian.us 7189 [ + + - + ]: 8807 : dest->sign = NUMERIC_SIGN(num);
8446 tgl@sss.pgh.pa.us 7190 [ + + ]: 8807 : dest->dscale = NUMERIC_DSCALE(num);
7191 : :
5754 rhaas@postgresql.org 7192 [ + + ]: 8807 : memcpy(dest->digits, NUMERIC_DIGITS(num), ndigits * sizeof(NumericDigit));
9988 JanWieck@Yahoo.com 7193 : 8807 : }
7194 : :
7195 : :
7196 : : /*
7197 : : * init_var_from_num() -
7198 : : *
7199 : : * Initialize a variable from packed db format. The digits array is not
7200 : : * copied, which saves some cycles when the resulting var is not modified.
7201 : : * Also, there's no need to call free_var(), as long as you don't assign any
7202 : : * other value to it (with set_var_* functions, or by using the var as the
7203 : : * destination of a function like add_var())
7204 : : *
7205 : : * CAUTION: Do not modify the digits buffer of a var initialized with this
7206 : : * function, e.g by calling round_var() or trunc_var(), as the changes will
7207 : : * propagate to the original Numeric! It's OK to use it as the destination
7208 : : * argument of one of the calculational functions, though.
7209 : : */
7210 : : static void
4913 heikki.linnakangas@i 7211 : 3860196 : init_var_from_num(Numeric num, NumericVar *dest)
7212 : : {
7213 [ + + ]: 3860196 : dest->ndigits = NUMERIC_NDIGITS(num);
7214 [ + + + + ]: 3860196 : dest->weight = NUMERIC_WEIGHT(num);
7215 [ + + - + ]: 3860196 : dest->sign = NUMERIC_SIGN(num);
7216 [ + + ]: 3860196 : dest->dscale = NUMERIC_DSCALE(num);
7217 [ + + ]: 3860196 : dest->digits = NUMERIC_DIGITS(num);
4724 bruce@momjian.us 7218 : 3860196 : dest->buf = NULL; /* digits array is not palloc'd */
4913 heikki.linnakangas@i 7219 : 3860196 : }
7220 : :
7221 : :
7222 : : /*
7223 : : * set_var_from_var() -
7224 : : *
7225 : : * Copy one variable into another
7226 : : */
7227 : : static void
3159 andres@anarazel.de 7228 : 24436 : set_var_from_var(const NumericVar *value, NumericVar *dest)
7229 : : {
7230 : : NumericDigit *newbuf;
7231 : :
9604 tgl@sss.pgh.pa.us 7232 : 24436 : newbuf = digitbuf_alloc(value->ndigits + 1);
7233 : 24436 : newbuf[0] = 0; /* spare digit for rounding */
3929 7234 [ + + ]: 24436 : if (value->ndigits > 0) /* else value->digits might be null */
7235 : 23777 : memcpy(newbuf + 1, value->digits,
7236 : 23777 : value->ndigits * sizeof(NumericDigit));
7237 : :
9988 JanWieck@Yahoo.com 7238 [ + + ]: 24436 : digitbuf_free(dest->buf);
7239 : :
8126 neilc@samurai.com 7240 : 24436 : memmove(dest, value, sizeof(NumericVar));
9842 bruce@momjian.us 7241 : 24436 : dest->buf = newbuf;
9604 tgl@sss.pgh.pa.us 7242 : 24436 : dest->digits = newbuf + 1;
7243 : 24436 : }
7244 : :
7245 : :
7246 : : /*
7247 : : * get_str_from_var() -
7248 : : *
7249 : : * Convert a var to text representation (guts of numeric_out).
7250 : : * The var is displayed to the number of digits indicated by its dscale.
7251 : : * Returns a palloc'd string.
7252 : : */
7253 : : static char *
3159 andres@anarazel.de 7254 : 550575 : get_str_from_var(const NumericVar *var)
7255 : : {
7256 : : int dscale;
7257 : : char *str;
7258 : : char *cp;
7259 : : char *endcp;
7260 : : int i;
7261 : : int d;
7262 : : NumericDigit dig;
7263 : :
7264 : : #if DEC_DIGITS > 1
7265 : : NumericDigit d1;
7266 : : #endif
7267 : :
4913 heikki.linnakangas@i 7268 : 550575 : dscale = var->dscale;
7269 : :
7270 : : /*
7271 : : * Allocate space for the result.
7272 : : *
7273 : : * i is set to the # of decimal digits before decimal point. dscale is the
7274 : : * # of decimal digits we will print after decimal point. We may generate
7275 : : * as many as DEC_DIGITS-1 excess digits at the end, and in addition we
7276 : : * need room for sign, decimal point, null terminator.
7277 : : */
8446 tgl@sss.pgh.pa.us 7278 : 550575 : i = (var->weight + 1) * DEC_DIGITS;
7279 [ + + ]: 550575 : if (i <= 0)
7280 : 72412 : i = 1;
7281 : :
7282 : 550575 : str = palloc(i + dscale + DEC_DIGITS + 2);
9604 7283 : 550575 : cp = str;
7284 : :
7285 : : /*
7286 : : * Output a dash for negative values
7287 : : */
7288 [ + + ]: 550575 : if (var->sign == NUMERIC_NEG)
7289 : 3758 : *cp++ = '-';
7290 : :
7291 : : /*
7292 : : * Output all digits before the decimal point
7293 : : */
8446 7294 [ + + ]: 550575 : if (var->weight < 0)
7295 : : {
7296 : 72412 : d = var->weight + 1;
7297 : 72412 : *cp++ = '0';
7298 : : }
7299 : : else
7300 : : {
7301 [ + + ]: 1017293 : for (d = 0; d <= var->weight; d++)
7302 : : {
7303 [ + + ]: 539130 : dig = (d < var->ndigits) ? var->digits[d] : 0;
7304 : : /* In the first digit, suppress extra leading decimal zeroes */
7305 : : #if DEC_DIGITS == 4
7306 : : {
8310 bruce@momjian.us 7307 : 539130 : bool putit = (d > 0);
7308 : :
8446 tgl@sss.pgh.pa.us 7309 : 539130 : d1 = dig / 1000;
7310 : 539130 : dig -= d1 * 1000;
7311 : 539130 : putit |= (d1 > 0);
7312 [ + + ]: 539130 : if (putit)
7313 : 101501 : *cp++ = d1 + '0';
7314 : 539130 : d1 = dig / 100;
7315 : 539130 : dig -= d1 * 100;
7316 : 539130 : putit |= (d1 > 0);
7317 [ + + ]: 539130 : if (putit)
7318 : 374256 : *cp++ = d1 + '0';
7319 : 539130 : d1 = dig / 10;
7320 : 539130 : dig -= d1 * 10;
7321 : 539130 : putit |= (d1 > 0);
7322 [ + + ]: 539130 : if (putit)
7323 : 456274 : *cp++ = d1 + '0';
7324 : 539130 : *cp++ = dig + '0';
7325 : : }
7326 : : #elif DEC_DIGITS == 2
7327 : : d1 = dig / 10;
7328 : : dig -= d1 * 10;
7329 : : if (d1 > 0 || d > 0)
7330 : : *cp++ = d1 + '0';
7331 : : *cp++ = dig + '0';
7332 : : #elif DEC_DIGITS == 1
7333 : : *cp++ = dig + '0';
7334 : : #else
7335 : : #error unsupported NBASE
7336 : : #endif
7337 : : }
7338 : : }
7339 : :
7340 : : /*
7341 : : * If requested, output a decimal point and all the digits that follow it.
7342 : : * We initially put out a multiple of DEC_DIGITS digits, then truncate if
7343 : : * needed.
7344 : : */
9604 7345 [ + + ]: 550575 : if (dscale > 0)
7346 : : {
7347 : 409482 : *cp++ = '.';
8446 7348 : 409482 : endcp = cp + dscale;
7349 [ + + ]: 1150071 : for (i = 0; i < dscale; d++, i += DEC_DIGITS)
7350 : : {
7351 [ + + + + ]: 740589 : dig = (d >= 0 && d < var->ndigits) ? var->digits[d] : 0;
7352 : : #if DEC_DIGITS == 4
7353 : 740589 : d1 = dig / 1000;
7354 : 740589 : dig -= d1 * 1000;
7355 : 740589 : *cp++ = d1 + '0';
7356 : 740589 : d1 = dig / 100;
7357 : 740589 : dig -= d1 * 100;
7358 : 740589 : *cp++ = d1 + '0';
7359 : 740589 : d1 = dig / 10;
7360 : 740589 : dig -= d1 * 10;
7361 : 740589 : *cp++ = d1 + '0';
7362 : 740589 : *cp++ = dig + '0';
7363 : : #elif DEC_DIGITS == 2
7364 : : d1 = dig / 10;
7365 : : dig -= d1 * 10;
7366 : : *cp++ = d1 + '0';
7367 : : *cp++ = dig + '0';
7368 : : #elif DEC_DIGITS == 1
7369 : : *cp++ = dig + '0';
7370 : : #else
7371 : : #error unsupported NBASE
7372 : : #endif
7373 : : }
7374 : 409482 : cp = endcp;
7375 : : }
7376 : :
7377 : : /*
7378 : : * terminate the string and return it
7379 : : */
9604 7380 : 550575 : *cp = '\0';
7381 : 550575 : return str;
7382 : : }
7383 : :
7384 : : /*
7385 : : * get_str_from_var_sci() -
7386 : : *
7387 : : * Convert a var to a normalised scientific notation text representation.
7388 : : * This function does the heavy lifting for numeric_out_sci().
7389 : : *
7390 : : * This notation has the general form a * 10^b, where a is known as the
7391 : : * "significand" and b is known as the "exponent".
7392 : : *
7393 : : * Because we can't do superscript in ASCII (and because we want to copy
7394 : : * printf's behaviour) we display the exponent using E notation, with a
7395 : : * minimum of two exponent digits.
7396 : : *
7397 : : * For example, the value 1234 could be output as 1.2e+03.
7398 : : *
7399 : : * We assume that the exponent can fit into an int32.
7400 : : *
7401 : : * rscale is the number of decimal digits desired after the decimal point in
7402 : : * the output, negative values will be treated as meaning zero.
7403 : : *
7404 : : * Returns a palloc'd string.
7405 : : */
7406 : : static char *
3159 andres@anarazel.de 7407 : 152 : get_str_from_var_sci(const NumericVar *var, int rscale)
7408 : : {
7409 : : int32 exponent;
7410 : : NumericVar tmp_var;
7411 : : size_t len;
7412 : : char *str;
7413 : : char *sig_out;
7414 : :
6112 tgl@sss.pgh.pa.us 7415 [ - + ]: 152 : if (rscale < 0)
6112 tgl@sss.pgh.pa.us 7416 :UBC 0 : rscale = 0;
7417 : :
7418 : : /*
7419 : : * Determine the exponent of this number in normalised form.
7420 : : *
7421 : : * This is the exponent required to represent the number with only one
7422 : : * significant digit before the decimal place.
7423 : : */
6112 tgl@sss.pgh.pa.us 7424 [ + + ]:CBC 152 : if (var->ndigits > 0)
7425 : : {
7426 : 140 : exponent = (var->weight + 1) * DEC_DIGITS;
7427 : :
7428 : : /*
7429 : : * Compensate for leading decimal zeroes in the first numeric digit by
7430 : : * decrementing the exponent.
7431 : : */
7432 : 140 : exponent -= DEC_DIGITS - (int) log10(var->digits[0]);
7433 : : }
7434 : : else
7435 : : {
7436 : : /*
7437 : : * If var has no digits, then it must be zero.
7438 : : *
7439 : : * Zero doesn't technically have a meaningful exponent in normalised
7440 : : * notation, but we just display the exponent as zero for consistency
7441 : : * of output.
7442 : : */
7443 : 12 : exponent = 0;
7444 : : }
7445 : :
7446 : : /*
7447 : : * Divide var by 10^exponent to get the significand, rounding to rscale
7448 : : * decimal digits in the process.
7449 : : */
1734 dean.a.rasheed@gmail 7450 : 152 : init_var(&tmp_var);
7451 : :
7452 : 152 : power_ten_int(exponent, &tmp_var);
578 7453 : 152 : div_var(var, &tmp_var, &tmp_var, rscale, true, true);
1734 7454 : 152 : sig_out = get_str_from_var(&tmp_var);
7455 : :
7456 : 152 : free_var(&tmp_var);
7457 : :
7458 : : /*
7459 : : * Allocate space for the result.
7460 : : *
7461 : : * In addition to the significand, we need room for the exponent
7462 : : * decoration ("e"), the sign of the exponent, up to 10 digits for the
7463 : : * exponent itself, and of course the null terminator.
7464 : : */
6112 tgl@sss.pgh.pa.us 7465 : 152 : len = strlen(sig_out) + 13;
7466 : 152 : str = palloc(len);
7467 : 152 : snprintf(str, len, "%se%+03d", sig_out, exponent);
7468 : :
7469 : 152 : pfree(sig_out);
7470 : :
7471 : 152 : return str;
7472 : : }
7473 : :
7474 : :
7475 : : /*
7476 : : * numericvar_serialize - serialize NumericVar to binary format
7477 : : *
7478 : : * At variable level, no checks are performed on the weight or dscale, allowing
7479 : : * us to pass around intermediate values with higher precision than supported
7480 : : * by the numeric type. Note: this is incompatible with numeric_send/recv(),
7481 : : * which use 16-bit integers for these fields.
7482 : : */
7483 : : static void
1765 dean.a.rasheed@gmail 7484 : 64 : numericvar_serialize(StringInfo buf, const NumericVar *var)
7485 : : {
7486 : : int i;
7487 : :
7488 : 64 : pq_sendint32(buf, var->ndigits);
7489 : 64 : pq_sendint32(buf, var->weight);
7490 : 64 : pq_sendint32(buf, var->sign);
7491 : 64 : pq_sendint32(buf, var->dscale);
7492 [ + + ]: 425172 : for (i = 0; i < var->ndigits; i++)
7493 : 425108 : pq_sendint16(buf, var->digits[i]);
7494 : 64 : }
7495 : :
7496 : : /*
7497 : : * numericvar_deserialize - deserialize binary format to NumericVar
7498 : : */
7499 : : static void
7500 : 64 : numericvar_deserialize(StringInfo buf, NumericVar *var)
7501 : : {
7502 : : int len,
7503 : : i;
7504 : :
7505 : 64 : len = pq_getmsgint(buf, sizeof(int32));
7506 : :
7507 : 64 : alloc_var(var, len); /* sets var->ndigits */
7508 : :
7509 : 64 : var->weight = pq_getmsgint(buf, sizeof(int32));
7510 : 64 : var->sign = pq_getmsgint(buf, sizeof(int32));
7511 : 64 : var->dscale = pq_getmsgint(buf, sizeof(int32));
7512 [ + + ]: 425172 : for (i = 0; i < len; i++)
7513 : 425108 : var->digits[i] = pq_getmsgint(buf, sizeof(int16));
7514 : 64 : }
7515 : :
7516 : :
7517 : : /*
7518 : : * duplicate_numeric() - copy a packed-format Numeric
7519 : : *
7520 : : * This will handle NaN and Infinity cases.
7521 : : */
7522 : : static Numeric
2113 tgl@sss.pgh.pa.us 7523 : 18816 : duplicate_numeric(Numeric num)
7524 : : {
7525 : : Numeric res;
7526 : :
7527 : 18816 : res = (Numeric) palloc(VARSIZE(num));
7528 : 18816 : memcpy(res, num, VARSIZE(num));
7529 : 18816 : return res;
7530 : : }
7531 : :
7532 : : /*
7533 : : * make_result_safe() -
7534 : : *
7535 : : * Create the packed db numeric format in palloc()'d memory from
7536 : : * a variable. This will handle NaN and Infinity cases.
7537 : : */
7538 : : static Numeric
242 michael@paquier.xyz 7539 :GNC 2526000 : make_result_safe(const NumericVar *var, Node *escontext)
7540 : : {
7541 : : Numeric result;
8446 tgl@sss.pgh.pa.us 7542 :CBC 2526000 : NumericDigit *digits = var->digits;
9842 bruce@momjian.us 7543 : 2526000 : int weight = var->weight;
7544 : 2526000 : int sign = var->sign;
7545 : : int n;
7546 : : Size len;
7547 : :
2113 tgl@sss.pgh.pa.us 7548 [ + + ]: 2526000 : if ((sign & NUMERIC_SIGN_MASK) == NUMERIC_SPECIAL)
7549 : : {
7550 : : /*
7551 : : * Verify valid special value. This could be just an Assert, perhaps,
7552 : : * but it seems worthwhile to expend a few cycles to ensure that we
7553 : : * never write any nonzero reserved bits to disk.
7554 : : */
7555 [ + + + + : 2201 : if (!(sign == NUMERIC_NAN ||
- + ]
7556 : : sign == NUMERIC_PINF ||
7557 : : sign == NUMERIC_NINF))
2113 tgl@sss.pgh.pa.us 7558 [ # # ]:UBC 0 : elog(ERROR, "invalid numeric sign value 0x%x", sign);
7559 : :
5754 rhaas@postgresql.org 7560 :CBC 2201 : result = (Numeric) palloc(NUMERIC_HDRSZ_SHORT);
7561 : :
7562 : 2201 : SET_VARSIZE(result, NUMERIC_HDRSZ_SHORT);
2113 tgl@sss.pgh.pa.us 7563 : 2201 : result->choice.n_header = sign;
7564 : : /* the header word is all we need */
7565 : :
7566 : : dump_numeric("make_result()", result);
9988 JanWieck@Yahoo.com 7567 : 2201 : return result;
7568 : : }
7569 : :
8446 tgl@sss.pgh.pa.us 7570 : 2523799 : n = var->ndigits;
7571 : :
7572 : : /* truncate leading zeroes */
7573 [ + + + + ]: 2523829 : while (n > 0 && *digits == 0)
7574 : : {
7575 : 30 : digits++;
9988 JanWieck@Yahoo.com 7576 : 30 : weight--;
7577 : 30 : n--;
7578 : : }
7579 : : /* truncate trailing zeroes */
8446 tgl@sss.pgh.pa.us 7580 [ + + + + ]: 2575925 : while (n > 0 && digits[n - 1] == 0)
9988 JanWieck@Yahoo.com 7581 : 52126 : n--;
7582 : :
7583 : : /* If zero result, force to weight=0 and positive sign */
7584 [ + + ]: 2523799 : if (n == 0)
7585 : : {
7586 : 84234 : weight = 0;
9842 bruce@momjian.us 7587 : 84234 : sign = NUMERIC_POS;
7588 : : }
7589 : :
7590 : : /* Build the result */
5754 rhaas@postgresql.org 7591 [ + + + + : 2523799 : if (NUMERIC_CAN_BE_SHORT(var->dscale, weight))
+ - ]
7592 : : {
7593 : 2521909 : len = NUMERIC_HDRSZ_SHORT + n * sizeof(NumericDigit);
7594 : 2521909 : result = (Numeric) palloc(len);
7595 : 2521909 : SET_VARSIZE(result, len);
5642 peter_e@gmx.net 7596 : 2521909 : result->choice.n_short.n_header =
7597 : : (sign == NUMERIC_NEG ? (NUMERIC_SHORT | NUMERIC_SHORT_SIGN_MASK)
7598 : : : NUMERIC_SHORT)
5754 rhaas@postgresql.org 7599 [ + + ]: 2521909 : | (var->dscale << NUMERIC_SHORT_DSCALE_SHIFT)
7600 : 2521909 : | (weight < 0 ? NUMERIC_SHORT_WEIGHT_SIGN_MASK : 0)
7601 : 2521909 : | (weight & NUMERIC_SHORT_WEIGHT_MASK);
7602 : : }
7603 : : else
7604 : : {
7605 : 1890 : len = NUMERIC_HDRSZ + n * sizeof(NumericDigit);
7606 : 1890 : result = (Numeric) palloc(len);
7607 : 1890 : SET_VARSIZE(result, len);
7608 : 1890 : result->choice.n_long.n_sign_dscale =
7609 : 1890 : sign | (var->dscale & NUMERIC_DSCALE_MASK);
7610 : 1890 : result->choice.n_long.n_weight = weight;
7611 : : }
7612 : :
7613 [ + + - + ]: 2523799 : Assert(NUMERIC_NDIGITS(result) == n);
3929 tgl@sss.pgh.pa.us 7614 [ + + ]: 2523799 : if (n > 0)
7615 [ + + ]: 2439565 : memcpy(NUMERIC_DIGITS(result), digits, n * sizeof(NumericDigit));
7616 : :
7617 : : /* Check for overflow of int16 fields */
5754 rhaas@postgresql.org 7618 [ + + + + : 2523799 : if (NUMERIC_WEIGHT(result) != weight ||
+ + ]
8446 tgl@sss.pgh.pa.us 7619 [ + + - + ]: 2523779 : NUMERIC_DSCALE(result) != var->dscale)
242 michael@paquier.xyz 7620 [ + + ]:GNC 20 : ereturn(escontext, NULL,
7621 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7622 : : errmsg("value overflows numeric format")));
7623 : :
7624 : : dump_numeric("make_result()", result);
9988 JanWieck@Yahoo.com 7625 :CBC 2523779 : return result;
7626 : : }
7627 : :
7628 : :
7629 : : /*
7630 : : * make_result() -
7631 : : *
7632 : : * An interface to make_result_safe() without "escontext" argument.
7633 : : */
7634 : : static Numeric
2607 akorotkov@postgresql 7635 : 1504411 : make_result(const NumericVar *var)
7636 : : {
242 michael@paquier.xyz 7637 :GNC 1504411 : return make_result_safe(var, NULL);
7638 : : }
7639 : :
7640 : :
7641 : : /*
7642 : : * apply_typmod() -
7643 : : *
7644 : : * Do bounds checking and rounding according to the specified typmod.
7645 : : * Note that this is only applied to normal finite values.
7646 : : *
7647 : : * Returns true on success, false on failure (if escontext points to an
7648 : : * ErrorSaveContext; otherwise errors are thrown).
7649 : : */
7650 : : static bool
1243 tgl@sss.pgh.pa.us 7651 :CBC 105934 : apply_typmod(NumericVar *var, int32 typmod, Node *escontext)
7652 : : {
7653 : : int precision;
7654 : : int scale;
7655 : : int maxdigits;
7656 : : int ddigits;
7657 : : int i;
7658 : :
7659 : : /* Do nothing if we have an invalid typmod */
1744 dean.a.rasheed@gmail 7660 [ + + ]: 105934 : if (!is_valid_numeric_typmod(typmod))
1243 tgl@sss.pgh.pa.us 7661 : 86438 : return true;
7662 : :
1744 dean.a.rasheed@gmail 7663 : 19496 : precision = numeric_typmod_precision(typmod);
7664 : 19496 : scale = numeric_typmod_scale(typmod);
8446 tgl@sss.pgh.pa.us 7665 : 19496 : maxdigits = precision - scale;
7666 : :
7667 : : /* Round to target scale (and set var->dscale) */
7668 : 19496 : round_var(var, scale);
7669 : :
7670 : : /* but don't allow var->dscale to be negative */
1744 dean.a.rasheed@gmail 7671 [ + + ]: 19496 : if (var->dscale < 0)
7672 : 100 : var->dscale = 0;
7673 : :
7674 : : /*
7675 : : * Check for overflow - note we can't do this before rounding, because
7676 : : * rounding could raise the weight. Also note that the var's weight could
7677 : : * be inflated by leading zeroes, which will be stripped before storage
7678 : : * but perhaps might not have been yet. In any case, we must recognize a
7679 : : * true zero, whose weight doesn't mean anything.
7680 : : */
8446 tgl@sss.pgh.pa.us 7681 : 19496 : ddigits = (var->weight + 1) * DEC_DIGITS;
7682 [ + + ]: 19496 : if (ddigits > maxdigits)
7683 : : {
7684 : : /* Determine true weight; and check for all-zero result */
9607 7685 [ + + ]: 4278 : for (i = 0; i < var->ndigits; i++)
7686 : : {
8446 7687 : 4268 : NumericDigit dig = var->digits[i];
7688 : :
7689 [ + - ]: 4268 : if (dig)
7690 : : {
7691 : : /* Adjust for any high-order decimal zero digits */
7692 : : #if DEC_DIGITS == 4
7693 [ + + ]: 4268 : if (dig < 10)
7694 : 197 : ddigits -= 3;
7695 [ + + ]: 4071 : else if (dig < 100)
7696 : 420 : ddigits -= 2;
7697 [ + + ]: 3651 : else if (dig < 1000)
7698 : 3639 : ddigits -= 1;
7699 : : #elif DEC_DIGITS == 2
7700 : : if (dig < 10)
7701 : : ddigits -= 1;
7702 : : #elif DEC_DIGITS == 1
7703 : : /* no adjustment */
7704 : : #else
7705 : : #error unsupported NBASE
7706 : : #endif
7707 [ + + ]: 4268 : if (ddigits > maxdigits)
1243 7708 [ + + + + : 56 : ereturn(escontext, false,
+ + ]
7709 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7710 : : errmsg("numeric field overflow"),
7711 : : errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.",
7712 : : precision, scale,
7713 : : /* Display 10^0 as 1 */
7714 : : maxdigits ? "10^" : "",
7715 : : maxdigits ? maxdigits : 1
7716 : : )));
9607 7717 : 4212 : break;
7718 : : }
8446 tgl@sss.pgh.pa.us 7719 :UBC 0 : ddigits -= DEC_DIGITS;
7720 : : }
7721 : : }
7722 : :
1243 tgl@sss.pgh.pa.us 7723 :CBC 19440 : return true;
7724 : : }
7725 : :
7726 : : /*
7727 : : * apply_typmod_special() -
7728 : : *
7729 : : * Do bounds checking according to the specified typmod, for an Inf or NaN.
7730 : : * For convenience of most callers, the value is presented in packed form.
7731 : : *
7732 : : * Returns true on success, false on failure (if escontext points to an
7733 : : * ErrorSaveContext; otherwise errors are thrown).
7734 : : */
7735 : : static bool
7736 : 1293 : apply_typmod_special(Numeric num, int32 typmod, Node *escontext)
7737 : : {
7738 : : int precision;
7739 : : int scale;
7740 : :
2113 7741 [ - + ]: 1293 : Assert(NUMERIC_IS_SPECIAL(num)); /* caller error if not */
7742 : :
7743 : : /*
7744 : : * NaN is allowed regardless of the typmod; that's rather dubious perhaps,
7745 : : * but it's a longstanding behavior. Inf is rejected if we have any
7746 : : * typmod restriction, since an infinity shouldn't be claimed to fit in
7747 : : * any finite number of digits.
7748 : : */
7749 [ + + ]: 1293 : if (NUMERIC_IS_NAN(num))
1243 7750 : 552 : return true;
7751 : :
7752 : : /* Do nothing if we have a default typmod (-1) */
1744 dean.a.rasheed@gmail 7753 [ + + ]: 741 : if (!is_valid_numeric_typmod(typmod))
1243 tgl@sss.pgh.pa.us 7754 : 729 : return true;
7755 : :
1744 dean.a.rasheed@gmail 7756 : 12 : precision = numeric_typmod_precision(typmod);
7757 : 12 : scale = numeric_typmod_scale(typmod);
7758 : :
1243 tgl@sss.pgh.pa.us 7759 [ + - ]: 12 : ereturn(escontext, false,
7760 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7761 : : errmsg("numeric field overflow"),
7762 : : errdetail("A field with precision %d, scale %d cannot hold an infinite value.",
7763 : : precision, scale)));
7764 : : }
7765 : :
7766 : :
7767 : : /*
7768 : : * Convert numeric to int8, rounding if needed.
7769 : : *
7770 : : * If overflow, return false (no error is raised). Return true if okay.
7771 : : */
7772 : : static bool
3159 andres@anarazel.de 7773 : 6512 : numericvar_to_int64(const NumericVar *var, int64 *result)
7774 : : {
7775 : : NumericDigit *digits;
7776 : : int ndigits;
7777 : : int weight;
7778 : : int i;
7779 : : int64 val;
7780 : : bool neg;
7781 : : NumericVar rounded;
7782 : :
7783 : : /* Round to nearest integer */
4913 heikki.linnakangas@i 7784 : 6512 : init_var(&rounded);
7785 : 6512 : set_var_from_var(var, &rounded);
7786 : 6512 : round_var(&rounded, 0);
7787 : :
7788 : : /* Check for zero input */
7789 : 6512 : strip_var(&rounded);
7790 : 6512 : ndigits = rounded.ndigits;
8446 tgl@sss.pgh.pa.us 7791 [ + + ]: 6512 : if (ndigits == 0)
7792 : : {
7793 : 331 : *result = 0;
4913 heikki.linnakangas@i 7794 : 331 : free_var(&rounded);
8446 tgl@sss.pgh.pa.us 7795 : 331 : return true;
7796 : : }
7797 : :
7798 : : /*
7799 : : * For input like 10000000000, we must treat stripped digits as real. So
7800 : : * the loop assumes there are weight+1 digits before the decimal point.
7801 : : */
4913 heikki.linnakangas@i 7802 : 6181 : weight = rounded.weight;
8310 bruce@momjian.us 7803 [ + - - + ]: 6181 : Assert(weight >= 0 && ndigits <= weight + 1);
7804 : :
7805 : : /*
7806 : : * Construct the result. To avoid issues with converting a value
7807 : : * corresponding to INT64_MIN (which can't be represented as a positive 64
7808 : : * bit two's complement integer), accumulate value as a negative number.
7809 : : */
4913 heikki.linnakangas@i 7810 : 6181 : digits = rounded.digits;
7811 : 6181 : neg = (rounded.sign == NUMERIC_NEG);
3066 andres@anarazel.de 7812 : 6181 : val = -digits[0];
8342 tgl@sss.pgh.pa.us 7813 [ + + ]: 8550 : for (i = 1; i <= weight; i++)
7814 : : {
3066 andres@anarazel.de 7815 [ + + ]: 2402 : if (unlikely(pg_mul_s64_overflow(val, NBASE, &val)))
7816 : : {
7817 : 21 : free_var(&rounded);
7818 : 21 : return false;
7819 : : }
7820 : :
7821 [ + + ]: 2381 : if (i < ndigits)
7822 : : {
7823 [ + + ]: 2174 : if (unlikely(pg_sub_s64_overflow(val, digits[i], &val)))
7824 : : {
4913 heikki.linnakangas@i 7825 : 12 : free_var(&rounded);
8446 tgl@sss.pgh.pa.us 7826 : 12 : return false;
7827 : : }
7828 : : }
7829 : : }
7830 : :
4913 heikki.linnakangas@i 7831 : 6148 : free_var(&rounded);
7832 : :
3066 andres@anarazel.de 7833 [ + + ]: 6148 : if (!neg)
7834 : : {
7835 [ + + ]: 5606 : if (unlikely(val == PG_INT64_MIN))
7836 : 16 : return false;
7837 : 5590 : val = -val;
7838 : : }
7839 : 6132 : *result = val;
7840 : :
8446 tgl@sss.pgh.pa.us 7841 : 6132 : return true;
7842 : : }
7843 : :
7844 : : /*
7845 : : * Convert int8 value to numeric.
7846 : : */
7847 : : static void
4064 andres@anarazel.de 7848 : 1261775 : int64_to_numericvar(int64 val, NumericVar *var)
7849 : : {
7850 : : uint64 uval,
7851 : : newuval;
7852 : : NumericDigit *ptr;
7853 : : int ndigits;
7854 : :
7855 : : /* int64 can require at most 19 decimal digits; add one for safety */
8310 bruce@momjian.us 7856 : 1261775 : alloc_var(var, 20 / DEC_DIGITS);
8446 tgl@sss.pgh.pa.us 7857 [ + + ]: 1261775 : if (val < 0)
7858 : : {
7859 : 1260 : var->sign = NUMERIC_NEG;
628 nathan@postgresql.or 7860 : 1260 : uval = pg_abs_s64(val);
7861 : : }
7862 : : else
7863 : : {
8446 tgl@sss.pgh.pa.us 7864 : 1260515 : var->sign = NUMERIC_POS;
7865 : 1260515 : uval = val;
7866 : : }
7867 : 1261775 : var->dscale = 0;
7868 [ + + ]: 1261775 : if (val == 0)
7869 : : {
7870 : 19393 : var->ndigits = 0;
7871 : 19393 : var->weight = 0;
7872 : 19393 : return;
7873 : : }
7874 : 1242382 : ptr = var->digits + var->ndigits;
7875 : 1242382 : ndigits = 0;
7876 : : do
7877 : : {
7878 : 1439485 : ptr--;
7879 : 1439485 : ndigits++;
7880 : 1439485 : newuval = uval / NBASE;
7881 : 1439485 : *ptr = uval - newuval * NBASE;
7882 : 1439485 : uval = newuval;
7883 [ + + ]: 1439485 : } while (uval);
7884 : 1242382 : var->digits = ptr;
7885 : 1242382 : var->ndigits = ndigits;
7886 : 1242382 : var->weight = ndigits - 1;
7887 : : }
7888 : :
7889 : : /*
7890 : : * Convert numeric to uint64, rounding if needed.
7891 : : *
7892 : : * If overflow, return false (no error is raised). Return true if okay.
7893 : : */
7894 : : static bool
2135 fujii@postgresql.org 7895 : 99 : numericvar_to_uint64(const NumericVar *var, uint64 *result)
7896 : : {
7897 : : NumericDigit *digits;
7898 : : int ndigits;
7899 : : int weight;
7900 : : int i;
7901 : : uint64 val;
7902 : : NumericVar rounded;
7903 : :
7904 : : /* Round to nearest integer */
7905 : 99 : init_var(&rounded);
7906 : 99 : set_var_from_var(var, &rounded);
7907 : 99 : round_var(&rounded, 0);
7908 : :
7909 : : /* Check for zero input */
7910 : 99 : strip_var(&rounded);
7911 : 99 : ndigits = rounded.ndigits;
7912 [ + + ]: 99 : if (ndigits == 0)
7913 : : {
7914 : 15 : *result = 0;
7915 : 15 : free_var(&rounded);
7916 : 15 : return true;
7917 : : }
7918 : :
7919 : : /* Check for negative input */
7920 [ + + ]: 84 : if (rounded.sign == NUMERIC_NEG)
7921 : : {
7922 : 8 : free_var(&rounded);
7923 : 8 : return false;
7924 : : }
7925 : :
7926 : : /*
7927 : : * For input like 10000000000, we must treat stripped digits as real. So
7928 : : * the loop assumes there are weight+1 digits before the decimal point.
7929 : : */
7930 : 76 : weight = rounded.weight;
7931 [ + - - + ]: 76 : Assert(weight >= 0 && ndigits <= weight + 1);
7932 : :
7933 : : /* Construct the result */
7934 : 76 : digits = rounded.digits;
7935 : 76 : val = digits[0];
7936 [ + + ]: 215 : for (i = 1; i <= weight; i++)
7937 : : {
7938 [ - + ]: 147 : if (unlikely(pg_mul_u64_overflow(val, NBASE, &val)))
7939 : : {
2135 fujii@postgresql.org 7940 :UBC 0 : free_var(&rounded);
7941 : 0 : return false;
7942 : : }
7943 : :
2135 fujii@postgresql.org 7944 [ + - ]:CBC 147 : if (i < ndigits)
7945 : : {
7946 [ + + ]: 147 : if (unlikely(pg_add_u64_overflow(val, digits[i], &val)))
7947 : : {
7948 : 8 : free_var(&rounded);
7949 : 8 : return false;
7950 : : }
7951 : : }
7952 : : }
7953 : :
7954 : 68 : free_var(&rounded);
7955 : :
7956 : 68 : *result = val;
7957 : :
7958 : 68 : return true;
7959 : : }
7960 : :
7961 : : /*
7962 : : * Convert 128 bit integer to numeric.
7963 : : */
7964 : : static void
271 dean.a.rasheed@gmail 7965 :GNC 6293 : int128_to_numericvar(INT128 val, NumericVar *var)
7966 : : {
7967 : : int sign;
7968 : : NumericDigit *ptr;
7969 : : int ndigits;
7970 : : int32 dig;
7971 : :
7972 : : /* int128 can require at most 39 decimal digits; add one for safety */
4064 andres@anarazel.de 7973 :CBC 6293 : alloc_var(var, 40 / DEC_DIGITS);
271 dean.a.rasheed@gmail 7974 :GNC 6293 : sign = int128_sign(val);
7975 : 6293 : var->sign = sign < 0 ? NUMERIC_NEG : NUMERIC_POS;
4064 andres@anarazel.de 7976 :CBC 6293 : var->dscale = 0;
271 dean.a.rasheed@gmail 7977 [ + + ]:GNC 6293 : if (sign == 0)
7978 : : {
4064 andres@anarazel.de 7979 :CBC 135 : var->ndigits = 0;
7980 : 135 : var->weight = 0;
7981 : 135 : return;
7982 : : }
7983 : 6158 : ptr = var->digits + var->ndigits;
7984 : 6158 : ndigits = 0;
7985 : : do
7986 : : {
7987 : 33064 : ptr--;
7988 : 33064 : ndigits++;
271 dean.a.rasheed@gmail 7989 :GNC 33064 : int128_div_mod_int32(&val, NBASE, &dig);
7990 : 33064 : *ptr = (NumericDigit) abs(dig);
7991 [ + + ]: 33064 : } while (!int128_is_zero(val));
4064 andres@anarazel.de 7992 :CBC 6158 : var->digits = ptr;
7993 : 6158 : var->ndigits = ndigits;
7994 : 6158 : var->weight = ndigits - 1;
7995 : : }
7996 : :
7997 : : /*
7998 : : * Convert a NumericVar to float8; if out of range, return +/- HUGE_VAL
7999 : : */
8000 : : static double
3159 8001 : 365 : numericvar_to_double_no_overflow(const NumericVar *var)
8002 : : {
8003 : : char *tmp;
8004 : : double val;
8005 : : char *endptr;
8006 : :
4913 heikki.linnakangas@i 8007 : 365 : tmp = get_str_from_var(var);
8008 : :
8009 : : /* unlike float8in, we ignore ERANGE from strtod */
8616 tgl@sss.pgh.pa.us 8010 : 365 : val = strtod(tmp, &endptr);
8011 [ - + ]: 365 : if (*endptr != '\0')
8012 : : {
8013 : : /* shouldn't happen ... */
8318 tgl@sss.pgh.pa.us 8014 [ # # ]:UBC 0 : ereport(ERROR,
8015 : : (errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
8016 : : errmsg("invalid input syntax for type %s: \"%s\"",
8017 : : "double precision", tmp)));
8018 : : }
8019 : :
8616 tgl@sss.pgh.pa.us 8020 :CBC 365 : pfree(tmp);
8021 : :
8022 : 365 : return val;
8023 : : }
8024 : :
8025 : :
8026 : : /*
8027 : : * cmp_var() -
8028 : : *
8029 : : * Compare two values on variable level. We assume zeroes have been
8030 : : * truncated to no digits.
8031 : : */
8032 : : static int
3159 andres@anarazel.de 8033 : 114439 : cmp_var(const NumericVar *var1, const NumericVar *var2)
8034 : : {
7392 bruce@momjian.us 8035 : 228878 : return cmp_var_common(var1->digits, var1->ndigits,
8036 : 114439 : var1->weight, var1->sign,
8037 : 114439 : var2->digits, var2->ndigits,
8038 : 114439 : var2->weight, var2->sign);
8039 : : }
8040 : :
8041 : : /*
8042 : : * cmp_var_common() -
8043 : : *
8044 : : * Main routine of cmp_var(). This function can be used by both
8045 : : * NumericVar and Numeric.
8046 : : */
8047 : : static int
8048 : 18808627 : cmp_var_common(const NumericDigit *var1digits, int var1ndigits,
8049 : : int var1weight, int var1sign,
8050 : : const NumericDigit *var2digits, int var2ndigits,
8051 : : int var2weight, int var2sign)
8052 : : {
8053 [ + + ]: 18808627 : if (var1ndigits == 0)
8054 : : {
8055 [ + + ]: 432181 : if (var2ndigits == 0)
9988 JanWieck@Yahoo.com 8056 : 341080 : return 0;
7392 bruce@momjian.us 8057 [ + + ]: 91101 : if (var2sign == NUMERIC_NEG)
9988 JanWieck@Yahoo.com 8058 : 2172 : return 1;
8059 : 88929 : return -1;
8060 : : }
7392 bruce@momjian.us 8061 [ + + ]: 18376446 : if (var2ndigits == 0)
8062 : : {
8063 [ + + ]: 66333 : if (var1sign == NUMERIC_POS)
9988 JanWieck@Yahoo.com 8064 : 62592 : return 1;
8065 : 3741 : return -1;
8066 : : }
8067 : :
7392 bruce@momjian.us 8068 [ + + ]: 18310113 : if (var1sign == NUMERIC_POS)
8069 : : {
8070 [ + + ]: 18259990 : if (var2sign == NUMERIC_NEG)
9988 JanWieck@Yahoo.com 8071 : 14424 : return 1;
7392 bruce@momjian.us 8072 : 18245566 : return cmp_abs_common(var1digits, var1ndigits, var1weight,
8073 : : var2digits, var2ndigits, var2weight);
8074 : : }
8075 : :
8076 [ + + ]: 50123 : if (var2sign == NUMERIC_POS)
9988 JanWieck@Yahoo.com 8077 : 14939 : return -1;
8078 : :
7392 bruce@momjian.us 8079 : 35184 : return cmp_abs_common(var2digits, var2ndigits, var2weight,
8080 : : var1digits, var1ndigits, var1weight);
8081 : : }
8082 : :
8083 : :
8084 : : /*
8085 : : * add_var() -
8086 : : *
8087 : : * Full version of add functionality on variable level (handling signs).
8088 : : * result might point to one of the operands too without danger.
8089 : : */
8090 : : static void
3159 andres@anarazel.de 8091 : 414485 : add_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
8092 : : {
8093 : : /*
8094 : : * Decide on the signs of the two variables what to do
8095 : : */
9988 JanWieck@Yahoo.com 8096 [ + + ]: 414485 : if (var1->sign == NUMERIC_POS)
8097 : : {
8098 [ + + ]: 413230 : if (var2->sign == NUMERIC_POS)
8099 : : {
8100 : : /*
8101 : : * Both are positive result = +(ABS(var1) + ABS(var2))
8102 : : */
8103 : 279629 : add_abs(var1, var2, result);
8104 : 279629 : result->sign = NUMERIC_POS;
8105 : : }
8106 : : else
8107 : : {
8108 : : /*
8109 : : * var1 is positive, var2 is negative Must compare absolute values
8110 : : */
8111 [ + + + - ]: 133601 : switch (cmp_abs(var1, var2))
8112 : : {
9423 tgl@sss.pgh.pa.us 8113 : 133 : case 0:
8114 : : /* ----------
8115 : : * ABS(var1) == ABS(var2)
8116 : : * result = ZERO
8117 : : * ----------
8118 : : */
9604 8119 : 133 : zero_var(result);
8842 bruce@momjian.us 8120 : 133 : result->dscale = Max(var1->dscale, var2->dscale);
9842 8121 : 133 : break;
8122 : :
9423 tgl@sss.pgh.pa.us 8123 : 124222 : case 1:
8124 : : /* ----------
8125 : : * ABS(var1) > ABS(var2)
8126 : : * result = +(ABS(var1) - ABS(var2))
8127 : : * ----------
8128 : : */
9842 bruce@momjian.us 8129 : 124222 : sub_abs(var1, var2, result);
8130 : 124222 : result->sign = NUMERIC_POS;
8131 : 124222 : break;
8132 : :
9423 tgl@sss.pgh.pa.us 8133 : 9246 : case -1:
8134 : : /* ----------
8135 : : * ABS(var1) < ABS(var2)
8136 : : * result = -(ABS(var2) - ABS(var1))
8137 : : * ----------
8138 : : */
9842 bruce@momjian.us 8139 : 9246 : sub_abs(var2, var1, result);
8140 : 9246 : result->sign = NUMERIC_NEG;
8141 : 9246 : break;
8142 : : }
8143 : : }
8144 : : }
8145 : : else
8146 : : {
9988 JanWieck@Yahoo.com 8147 [ + + ]: 1255 : if (var2->sign == NUMERIC_POS)
8148 : : {
8149 : : /* ----------
8150 : : * var1 is negative, var2 is positive
8151 : : * Must compare absolute values
8152 : : * ----------
8153 : : */
8154 [ + + + - ]: 318 : switch (cmp_abs(var1, var2))
8155 : : {
9423 tgl@sss.pgh.pa.us 8156 : 20 : case 0:
8157 : : /* ----------
8158 : : * ABS(var1) == ABS(var2)
8159 : : * result = ZERO
8160 : : * ----------
8161 : : */
9604 8162 : 20 : zero_var(result);
8842 bruce@momjian.us 8163 : 20 : result->dscale = Max(var1->dscale, var2->dscale);
9842 8164 : 20 : break;
8165 : :
9423 tgl@sss.pgh.pa.us 8166 : 197 : case 1:
8167 : : /* ----------
8168 : : * ABS(var1) > ABS(var2)
8169 : : * result = -(ABS(var1) - ABS(var2))
8170 : : * ----------
8171 : : */
9842 bruce@momjian.us 8172 : 197 : sub_abs(var1, var2, result);
8173 : 197 : result->sign = NUMERIC_NEG;
8174 : 197 : break;
8175 : :
9423 tgl@sss.pgh.pa.us 8176 : 101 : case -1:
8177 : : /* ----------
8178 : : * ABS(var1) < ABS(var2)
8179 : : * result = +(ABS(var2) - ABS(var1))
8180 : : * ----------
8181 : : */
9842 bruce@momjian.us 8182 : 101 : sub_abs(var2, var1, result);
8183 : 101 : result->sign = NUMERIC_POS;
8184 : 101 : break;
8185 : : }
8186 : : }
8187 : : else
8188 : : {
8189 : : /* ----------
8190 : : * Both are negative
8191 : : * result = -(ABS(var1) + ABS(var2))
8192 : : * ----------
8193 : : */
9988 JanWieck@Yahoo.com 8194 : 937 : add_abs(var1, var2, result);
8195 : 937 : result->sign = NUMERIC_NEG;
8196 : : }
8197 : : }
8198 : 414485 : }
8199 : :
8200 : :
8201 : : /*
8202 : : * sub_var() -
8203 : : *
8204 : : * Full version of sub functionality on variable level (handling signs).
8205 : : * result might point to one of the operands too without danger.
8206 : : */
8207 : : static void
3159 andres@anarazel.de 8208 : 351157 : sub_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
8209 : : {
8210 : : /*
8211 : : * Decide on the signs of the two variables what to do
8212 : : */
9988 JanWieck@Yahoo.com 8213 [ + + ]: 351157 : if (var1->sign == NUMERIC_POS)
8214 : : {
8215 [ + + ]: 350548 : if (var2->sign == NUMERIC_NEG)
8216 : : {
8217 : : /* ----------
8218 : : * var1 is positive, var2 is negative
8219 : : * result = +(ABS(var1) + ABS(var2))
8220 : : * ----------
8221 : : */
8222 : 18821 : add_abs(var1, var2, result);
8223 : 18821 : result->sign = NUMERIC_POS;
8224 : : }
8225 : : else
8226 : : {
8227 : : /* ----------
8228 : : * Both are positive
8229 : : * Must compare absolute values
8230 : : * ----------
8231 : : */
8232 [ + + + - ]: 331727 : switch (cmp_abs(var1, var2))
8233 : : {
9423 tgl@sss.pgh.pa.us 8234 : 29762 : case 0:
8235 : : /* ----------
8236 : : * ABS(var1) == ABS(var2)
8237 : : * result = ZERO
8238 : : * ----------
8239 : : */
9604 8240 : 29762 : zero_var(result);
8842 bruce@momjian.us 8241 : 29762 : result->dscale = Max(var1->dscale, var2->dscale);
9842 8242 : 29762 : break;
8243 : :
9423 tgl@sss.pgh.pa.us 8244 : 293333 : case 1:
8245 : : /* ----------
8246 : : * ABS(var1) > ABS(var2)
8247 : : * result = +(ABS(var1) - ABS(var2))
8248 : : * ----------
8249 : : */
9842 bruce@momjian.us 8250 : 293333 : sub_abs(var1, var2, result);
8251 : 293333 : result->sign = NUMERIC_POS;
8252 : 293333 : break;
8253 : :
9423 tgl@sss.pgh.pa.us 8254 : 8632 : case -1:
8255 : : /* ----------
8256 : : * ABS(var1) < ABS(var2)
8257 : : * result = -(ABS(var2) - ABS(var1))
8258 : : * ----------
8259 : : */
9842 bruce@momjian.us 8260 : 8632 : sub_abs(var2, var1, result);
8261 : 8632 : result->sign = NUMERIC_NEG;
8262 : 8632 : break;
8263 : : }
8264 : : }
8265 : : }
8266 : : else
8267 : : {
9988 JanWieck@Yahoo.com 8268 [ + + ]: 609 : if (var2->sign == NUMERIC_NEG)
8269 : : {
8270 : : /* ----------
8271 : : * Both are negative
8272 : : * Must compare absolute values
8273 : : * ----------
8274 : : */
8275 [ + + + - ]: 304 : switch (cmp_abs(var1, var2))
8276 : : {
9423 tgl@sss.pgh.pa.us 8277 : 110 : case 0:
8278 : : /* ----------
8279 : : * ABS(var1) == ABS(var2)
8280 : : * result = ZERO
8281 : : * ----------
8282 : : */
9604 8283 : 110 : zero_var(result);
8842 bruce@momjian.us 8284 : 110 : result->dscale = Max(var1->dscale, var2->dscale);
9842 8285 : 110 : break;
8286 : :
9423 tgl@sss.pgh.pa.us 8287 : 162 : case 1:
8288 : : /* ----------
8289 : : * ABS(var1) > ABS(var2)
8290 : : * result = -(ABS(var1) - ABS(var2))
8291 : : * ----------
8292 : : */
9842 bruce@momjian.us 8293 : 162 : sub_abs(var1, var2, result);
8294 : 162 : result->sign = NUMERIC_NEG;
8295 : 162 : break;
8296 : :
9423 tgl@sss.pgh.pa.us 8297 : 32 : case -1:
8298 : : /* ----------
8299 : : * ABS(var1) < ABS(var2)
8300 : : * result = +(ABS(var2) - ABS(var1))
8301 : : * ----------
8302 : : */
9842 bruce@momjian.us 8303 : 32 : sub_abs(var2, var1, result);
8304 : 32 : result->sign = NUMERIC_POS;
8305 : 32 : break;
8306 : : }
8307 : : }
8308 : : else
8309 : : {
8310 : : /* ----------
8311 : : * var1 is negative, var2 is positive
8312 : : * result = -(ABS(var1) + ABS(var2))
8313 : : * ----------
8314 : : */
9988 JanWieck@Yahoo.com 8315 : 305 : add_abs(var1, var2, result);
8316 : 305 : result->sign = NUMERIC_NEG;
8317 : : }
8318 : : }
8319 : 351157 : }
8320 : :
8321 : :
8322 : : /*
8323 : : * mul_var() -
8324 : : *
8325 : : * Multiplication on variable level. Product of var1 * var2 is stored
8326 : : * in result. Result is rounded to no more than rscale fractional digits.
8327 : : */
8328 : : static void
3159 andres@anarazel.de 8329 : 795493 : mul_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result,
8330 : : int rscale)
8331 : : {
8332 : : int res_ndigits;
8333 : : int res_ndigitpairs;
8334 : : int res_sign;
8335 : : int res_weight;
8336 : : int pair_offset;
8337 : : int maxdigits;
8338 : : int maxdigitpairs;
8339 : : uint64 *dig,
8340 : : *dig_i1_off;
8341 : : uint64 maxdig;
8342 : : uint64 carry;
8343 : : uint64 newdig;
8344 : : int var1ndigits;
8345 : : int var2ndigits;
8346 : : int var1ndigitpairs;
8347 : : int var2ndigitpairs;
8348 : : NumericDigit *var1digits;
8349 : : NumericDigit *var2digits;
8350 : : uint32 var1digitpair;
8351 : : uint32 *var2digitpairs;
8352 : : NumericDigit *res_digits;
8353 : : int i,
8354 : : i1,
8355 : : i2,
8356 : : i2limit;
8357 : :
8358 : : /*
8359 : : * Arrange for var1 to be the shorter of the two numbers. This improves
8360 : : * performance because the inner multiplication loop is much simpler than
8361 : : * the outer loop, so it's better to have a smaller number of iterations
8362 : : * of the outer loop. This also reduces the number of times that the
8363 : : * accumulator array needs to be normalized.
8364 : : */
3825 tgl@sss.pgh.pa.us 8365 [ + + ]: 795493 : if (var1->ndigits > var2->ndigits)
8366 : : {
3159 andres@anarazel.de 8367 : 10274 : const NumericVar *tmp = var1;
8368 : :
3825 tgl@sss.pgh.pa.us 8369 : 10274 : var1 = var2;
8370 : 10274 : var2 = tmp;
8371 : : }
8372 : :
8373 : : /* copy these values into local vars for speed in inner loop */
8374 : 795493 : var1ndigits = var1->ndigits;
8375 : 795493 : var2ndigits = var2->ndigits;
8376 : 795493 : var1digits = var1->digits;
8377 : 795493 : var2digits = var2->digits;
8378 : :
665 dean.a.rasheed@gmail 8379 [ + + ]: 795493 : if (var1ndigits == 0)
8380 : : {
8381 : : /* one or both inputs is zero; so is result */
8446 tgl@sss.pgh.pa.us 8382 : 1959 : zero_var(result);
8383 : 1959 : result->dscale = rscale;
8384 : 1959 : return;
8385 : : }
8386 : :
8387 : : /*
8388 : : * If var1 has 1-6 digits and the exact result was requested, delegate to
8389 : : * mul_var_short() which uses a faster direct multiplication algorithm.
8390 : : */
628 dean.a.rasheed@gmail 8391 [ + + + + ]: 793534 : if (var1ndigits <= 6 && rscale == var1->dscale + var2->dscale)
8392 : : {
665 8393 : 772865 : mul_var_short(var1, var2, result);
8394 : 772865 : return;
8395 : : }
8396 : :
8397 : : /* Determine result sign */
9988 JanWieck@Yahoo.com 8398 [ + + ]: 20669 : if (var1->sign == var2->sign)
8399 : 19390 : res_sign = NUMERIC_POS;
8400 : : else
8401 : 1279 : res_sign = NUMERIC_NEG;
8402 : :
8403 : : /*
8404 : : * Determine the number of result digits to compute and the (maximum
8405 : : * possible) result weight. If the exact result would have more than
8406 : : * rscale fractional digits, truncate the computation with
8407 : : * MUL_GUARD_DIGITS guard digits, i.e., ignore input digits that would
8408 : : * only contribute to the right of that. (This will give the exact
8409 : : * rounded-to-rscale answer unless carries out of the ignored positions
8410 : : * would have propagated through more than MUL_GUARD_DIGITS digits.)
8411 : : *
8412 : : * Note: an exact computation could not produce more than var1ndigits +
8413 : : * var2ndigits digits, but we allocate at least one extra output digit in
8414 : : * case rscale-driven rounding produces a carry out of the highest exact
8415 : : * digit.
8416 : : *
8417 : : * The computation itself is done using base-NBASE^2 arithmetic, so we
8418 : : * actually process the input digits in pairs, producing a base-NBASE^2
8419 : : * intermediate result. This significantly improves performance, since
8420 : : * schoolbook multiplication is O(N^2) in the number of input digits, and
8421 : : * working in base NBASE^2 effectively halves "N".
8422 : : *
8423 : : * Note: in a truncated computation, we must compute at least one extra
8424 : : * output digit to ensure that all the guard digits are fully computed.
8425 : : */
8426 : : /* digit pairs in each input */
628 dean.a.rasheed@gmail 8427 : 20669 : var1ndigitpairs = (var1ndigits + 1) / 2;
8428 : 20669 : var2ndigitpairs = (var2ndigits + 1) / 2;
8429 : :
8430 : : /* digits in exact result */
8431 : 20669 : res_ndigits = var1ndigits + var2ndigits;
8432 : :
8433 : : /* digit pairs in exact result with at least one extra output digit */
8434 : 20669 : res_ndigitpairs = res_ndigits / 2 + 1;
8435 : :
8436 : : /* pair offset to align result to end of dig[] */
8437 : 20669 : pair_offset = res_ndigitpairs - var1ndigitpairs - var2ndigitpairs + 1;
8438 : :
8439 : : /* maximum possible result weight (odd-length inputs shifted up below) */
8440 : 20669 : res_weight = var1->weight + var2->weight + 1 + 2 * res_ndigitpairs -
8441 : 20669 : res_ndigits - (var1ndigits & 1) - (var2ndigits & 1);
8442 : :
8443 : : /* rscale-based truncation with at least one extra output digit */
3825 tgl@sss.pgh.pa.us 8444 : 20669 : maxdigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS +
8445 : : MUL_GUARD_DIGITS;
628 dean.a.rasheed@gmail 8446 : 20669 : maxdigitpairs = maxdigits / 2 + 1;
8447 : :
8448 : 20669 : res_ndigitpairs = Min(res_ndigitpairs, maxdigitpairs);
8449 : 20669 : res_ndigits = 2 * res_ndigitpairs;
8450 : :
8451 : : /*
8452 : : * In the computation below, digit pair i1 of var1 and digit pair i2 of
8453 : : * var2 are multiplied and added to digit i1+i2+pair_offset of dig[]. Thus
8454 : : * input digit pairs with index >= res_ndigitpairs - pair_offset don't
8455 : : * contribute to the result, and can be ignored.
8456 : : */
8457 [ + + ]: 20669 : if (res_ndigitpairs <= pair_offset)
8458 : : {
8459 : : /* All input digits will be ignored; so result is zero */
3825 tgl@sss.pgh.pa.us 8460 : 10 : zero_var(result);
8461 : 10 : result->dscale = rscale;
8462 : 10 : return;
8463 : : }
628 dean.a.rasheed@gmail 8464 : 20659 : var1ndigitpairs = Min(var1ndigitpairs, res_ndigitpairs - pair_offset);
8465 : 20659 : var2ndigitpairs = Min(var2ndigitpairs, res_ndigitpairs - pair_offset);
8466 : :
8467 : : /*
8468 : : * We do the arithmetic in an array "dig[]" of unsigned 64-bit integers.
8469 : : * Since PG_UINT64_MAX is much larger than NBASE^4, this gives us a lot of
8470 : : * headroom to avoid normalizing carries immediately.
8471 : : *
8472 : : * maxdig tracks the maximum possible value of any dig[] entry; when this
8473 : : * threatens to exceed PG_UINT64_MAX, we take the time to propagate
8474 : : * carries. Furthermore, we need to ensure that overflow doesn't occur
8475 : : * during the carry propagation passes either. The carry values could be
8476 : : * as much as PG_UINT64_MAX / NBASE^2, so really we must normalize when
8477 : : * digits threaten to exceed PG_UINT64_MAX - PG_UINT64_MAX / NBASE^2.
8478 : : *
8479 : : * To avoid overflow in maxdig itself, it actually represents the maximum
8480 : : * possible value divided by NBASE^2-1, i.e., at the top of the loop it is
8481 : : * known that no dig[] entry exceeds maxdig * (NBASE^2-1).
8482 : : *
8483 : : * The conversion of var1 to base NBASE^2 is done on the fly, as each new
8484 : : * digit is required. The digits of var2 are converted upfront, and
8485 : : * stored at the end of dig[]. To avoid loss of precision, the input
8486 : : * digits are aligned with the start of digit pair array, effectively
8487 : : * shifting them up (multiplying by NBASE) if the inputs have an odd
8488 : : * number of NBASE digits.
8489 : : */
8490 : 20659 : dig = (uint64 *) palloc(res_ndigitpairs * sizeof(uint64) +
8491 : : var2ndigitpairs * sizeof(uint32));
8492 : :
8493 : : /* convert var2 to base NBASE^2, shifting up if its length is odd */
8494 : 20659 : var2digitpairs = (uint32 *) (dig + res_ndigitpairs);
8495 : :
8496 [ + + ]: 1048389 : for (i2 = 0; i2 < var2ndigitpairs - 1; i2++)
8497 : 1027730 : var2digitpairs[i2] = var2digits[2 * i2] * NBASE + var2digits[2 * i2 + 1];
8498 : :
8499 [ + + ]: 20659 : if (2 * i2 + 1 < var2ndigits)
8500 : 14659 : var2digitpairs[i2] = var2digits[2 * i2] * NBASE + var2digits[2 * i2 + 1];
8501 : : else
8502 : 6000 : var2digitpairs[i2] = var2digits[2 * i2] * NBASE;
8503 : :
8504 : : /*
8505 : : * Start by multiplying var2 by the least significant contributing digit
8506 : : * pair from var1, storing the results at the end of dig[], and filling
8507 : : * the leading digits with zeros.
8508 : : *
8509 : : * The loop here is the same as the inner loop below, except that we set
8510 : : * the results in dig[], rather than adding to them. This is the
8511 : : * performance bottleneck for multiplication, so we want to keep it simple
8512 : : * enough so that it can be auto-vectorized. Accordingly, process the
8513 : : * digits left-to-right even though schoolbook multiplication would
8514 : : * suggest right-to-left. Since we aren't propagating carries in this
8515 : : * loop, the order does not matter.
8516 : : */
8517 : 20659 : i1 = var1ndigitpairs - 1;
8518 [ + + ]: 20659 : if (2 * i1 + 1 < var1ndigits)
8519 : 9183 : var1digitpair = var1digits[2 * i1] * NBASE + var1digits[2 * i1 + 1];
8520 : : else
8521 : 11476 : var1digitpair = var1digits[2 * i1] * NBASE;
8522 : 20659 : maxdig = var1digitpair;
8523 : :
8524 : 20659 : i2limit = Min(var2ndigitpairs, res_ndigitpairs - i1 - pair_offset);
8525 : 20659 : dig_i1_off = &dig[i1 + pair_offset];
8526 : :
8527 : 20659 : memset(dig, 0, (i1 + pair_offset) * sizeof(uint64));
8528 [ + + ]: 930539 : for (i2 = 0; i2 < i2limit; i2++)
8529 : 909880 : dig_i1_off[i2] = (uint64) var1digitpair * var2digitpairs[i2];
8530 : :
8531 : : /*
8532 : : * Next, multiply var2 by the remaining digit pairs from var1, adding the
8533 : : * results to dig[] at the appropriate offsets, and normalizing whenever
8534 : : * there is a risk of any dig[] entry overflowing.
8535 : : */
8536 [ + + ]: 1012436 : for (i1 = i1 - 1; i1 >= 0; i1--)
8537 : : {
8538 : 991777 : var1digitpair = var1digits[2 * i1] * NBASE + var1digits[2 * i1 + 1];
8539 [ + + ]: 991777 : if (var1digitpair == 0)
8446 tgl@sss.pgh.pa.us 8540 : 786344 : continue;
8541 : :
8542 : : /* Time to normalize? */
628 dean.a.rasheed@gmail 8543 : 205433 : maxdig += var1digitpair;
8544 [ + + ]: 205433 : if (maxdig > (PG_UINT64_MAX - PG_UINT64_MAX / NBASE_SQR) / (NBASE_SQR - 1))
8545 : : {
8546 : : /* Yes, do it (to base NBASE^2) */
8446 tgl@sss.pgh.pa.us 8547 : 21 : carry = 0;
628 dean.a.rasheed@gmail 8548 [ + + ]: 84074 : for (i = res_ndigitpairs - 1; i >= 0; i--)
8549 : : {
8446 tgl@sss.pgh.pa.us 8550 : 84053 : newdig = dig[i] + carry;
628 dean.a.rasheed@gmail 8551 [ + + ]: 84053 : if (newdig >= NBASE_SQR)
8552 : : {
8553 : 80719 : carry = newdig / NBASE_SQR;
8554 : 80719 : newdig -= carry * NBASE_SQR;
8555 : : }
8556 : : else
8446 tgl@sss.pgh.pa.us 8557 : 3334 : carry = 0;
8558 : 84053 : dig[i] = newdig;
8559 : : }
8560 [ - + ]: 21 : Assert(carry == 0);
8561 : : /* Reset maxdig to indicate new worst-case */
628 dean.a.rasheed@gmail 8562 : 21 : maxdig = 1 + var1digitpair;
8563 : : }
8564 : :
8565 : : /* Multiply and add */
8566 : 205433 : i2limit = Min(var2ndigitpairs, res_ndigitpairs - i1 - pair_offset);
8567 : 205433 : dig_i1_off = &dig[i1 + pair_offset];
8568 : :
8569 [ + + ]: 87005259 : for (i2 = 0; i2 < i2limit; i2++)
8570 : 86799826 : dig_i1_off[i2] += (uint64) var1digitpair * var2digitpairs[i2];
8571 : : }
8572 : :
8573 : : /*
8574 : : * Now we do a final carry propagation pass to normalize back to base
8575 : : * NBASE^2, and construct the base-NBASE result digits. Note that this is
8576 : : * still done at full precision w/guard digits.
8577 : : */
8446 tgl@sss.pgh.pa.us 8578 : 20659 : alloc_var(result, res_ndigits);
8579 : 20659 : res_digits = result->digits;
8580 : 20659 : carry = 0;
628 dean.a.rasheed@gmail 8581 [ + + ]: 1946324 : for (i = res_ndigitpairs - 1; i >= 0; i--)
8582 : : {
8446 tgl@sss.pgh.pa.us 8583 : 1925665 : newdig = dig[i] + carry;
628 dean.a.rasheed@gmail 8584 [ + + ]: 1925665 : if (newdig >= NBASE_SQR)
8585 : : {
8586 : 290140 : carry = newdig / NBASE_SQR;
8587 : 290140 : newdig -= carry * NBASE_SQR;
8588 : : }
8589 : : else
8446 tgl@sss.pgh.pa.us 8590 : 1635525 : carry = 0;
628 dean.a.rasheed@gmail 8591 : 1925665 : res_digits[2 * i + 1] = (NumericDigit) ((uint32) newdig % NBASE);
8592 : 1925665 : res_digits[2 * i] = (NumericDigit) ((uint32) newdig / NBASE);
8593 : : }
8446 tgl@sss.pgh.pa.us 8594 [ - + ]: 20659 : Assert(carry == 0);
8595 : :
8596 : 20659 : pfree(dig);
8597 : :
8598 : : /*
8599 : : * Finally, round the result to the requested precision.
8600 : : */
9842 bruce@momjian.us 8601 : 20659 : result->weight = res_weight;
8602 : 20659 : result->sign = res_sign;
8603 : :
8604 : : /* Round to target rscale (and set result->dscale) */
8446 tgl@sss.pgh.pa.us 8605 : 20659 : round_var(result, rscale);
8606 : :
8607 : : /* Strip leading and trailing zeroes */
8608 : 20659 : strip_var(result);
8609 : : }
8610 : :
8611 : :
8612 : : /*
8613 : : * mul_var_short() -
8614 : : *
8615 : : * Special-case multiplication function used when var1 has 1-6 digits, var2
8616 : : * has at least as many digits as var1, and the exact product var1 * var2 is
8617 : : * requested.
8618 : : */
8619 : : static void
665 dean.a.rasheed@gmail 8620 : 772865 : mul_var_short(const NumericVar *var1, const NumericVar *var2,
8621 : : NumericVar *result)
8622 : : {
8623 : 772865 : int var1ndigits = var1->ndigits;
8624 : 772865 : int var2ndigits = var2->ndigits;
8625 : 772865 : NumericDigit *var1digits = var1->digits;
8626 : 772865 : NumericDigit *var2digits = var2->digits;
8627 : : int res_sign;
8628 : : int res_weight;
8629 : : int res_ndigits;
8630 : : NumericDigit *res_buf;
8631 : : NumericDigit *res_digits;
617 8632 : 772865 : uint32 carry = 0;
8633 : : uint32 term;
8634 : :
8635 : : /* Check preconditions */
665 8636 [ - + ]: 772865 : Assert(var1ndigits >= 1);
628 8637 [ - + ]: 772865 : Assert(var1ndigits <= 6);
665 8638 [ - + ]: 772865 : Assert(var2ndigits >= var1ndigits);
8639 : :
8640 : : /*
8641 : : * Determine the result sign, weight, and number of digits to calculate.
8642 : : * The weight figured here is correct if the product has no leading zero
8643 : : * digits; otherwise strip_var() will fix things up. Note that, unlike
8644 : : * mul_var(), we do not need to allocate an extra output digit, because we
8645 : : * are not rounding here.
8646 : : */
8647 [ + + ]: 772865 : if (var1->sign == var2->sign)
8648 : 772058 : res_sign = NUMERIC_POS;
8649 : : else
8650 : 807 : res_sign = NUMERIC_NEG;
8651 : 772865 : res_weight = var1->weight + var2->weight + 1;
8652 : 772865 : res_ndigits = var1ndigits + var2ndigits;
8653 : :
8654 : : /* Allocate result digit array */
8655 : 772865 : res_buf = digitbuf_alloc(res_ndigits + 1);
8656 : 772865 : res_buf[0] = 0; /* spare digit for later rounding */
8657 : 772865 : res_digits = res_buf + 1;
8658 : :
8659 : : /*
8660 : : * Compute the result digits in reverse, in one pass, propagating the
8661 : : * carry up as we go. The i'th result digit consists of the sum of the
8662 : : * products var1digits[i1] * var2digits[i2] for which i = i1 + i2 + 1.
8663 : : */
8664 : : #define PRODSUM1(v1,i1,v2,i2) ((v1)[(i1)] * (v2)[(i2)])
8665 : : #define PRODSUM2(v1,i1,v2,i2) (PRODSUM1(v1,i1,v2,i2) + (v1)[(i1)+1] * (v2)[(i2)-1])
8666 : : #define PRODSUM3(v1,i1,v2,i2) (PRODSUM2(v1,i1,v2,i2) + (v1)[(i1)+2] * (v2)[(i2)-2])
8667 : : #define PRODSUM4(v1,i1,v2,i2) (PRODSUM3(v1,i1,v2,i2) + (v1)[(i1)+3] * (v2)[(i2)-3])
8668 : : #define PRODSUM5(v1,i1,v2,i2) (PRODSUM4(v1,i1,v2,i2) + (v1)[(i1)+4] * (v2)[(i2)-4])
8669 : : #define PRODSUM6(v1,i1,v2,i2) (PRODSUM5(v1,i1,v2,i2) + (v1)[(i1)+5] * (v2)[(i2)-5])
8670 : :
8671 [ + + + + : 772865 : switch (var1ndigits)
+ + - ]
8672 : : {
8673 : 768720 : case 1:
8674 : : /* ---------
8675 : : * 1-digit case:
8676 : : * var1ndigits = 1
8677 : : * var2ndigits >= 1
8678 : : * res_ndigits = var2ndigits + 1
8679 : : * ----------
8680 : : */
628 8681 [ + + ]: 2405890 : for (int i = var2ndigits - 1; i >= 0; i--)
8682 : : {
8683 : 1637170 : term = PRODSUM1(var1digits, 0, var2digits, i) + carry;
665 8684 : 1637170 : res_digits[i + 1] = (NumericDigit) (term % NBASE);
8685 : 1637170 : carry = term / NBASE;
8686 : : }
8687 : 768720 : res_digits[0] = (NumericDigit) carry;
8688 : 768720 : break;
8689 : :
8690 : 519 : case 2:
8691 : : /* ---------
8692 : : * 2-digit case:
8693 : : * var1ndigits = 2
8694 : : * var2ndigits >= 2
8695 : : * res_ndigits = var2ndigits + 2
8696 : : * ----------
8697 : : */
8698 : : /* last result digit and carry */
628 8699 : 519 : term = PRODSUM1(var1digits, 1, var2digits, var2ndigits - 1);
665 8700 : 519 : res_digits[res_ndigits - 1] = (NumericDigit) (term % NBASE);
8701 : 519 : carry = term / NBASE;
8702 : :
8703 : : /* remaining digits, except for the first two */
628 8704 [ + + ]: 1573 : for (int i = var2ndigits - 1; i >= 1; i--)
8705 : : {
8706 : 1054 : term = PRODSUM2(var1digits, 0, var2digits, i) + carry;
665 8707 : 1054 : res_digits[i + 1] = (NumericDigit) (term % NBASE);
8708 : 1054 : carry = term / NBASE;
8709 : : }
8710 : 519 : break;
8711 : :
8712 : 146 : case 3:
8713 : : /* ---------
8714 : : * 3-digit case:
8715 : : * var1ndigits = 3
8716 : : * var2ndigits >= 3
8717 : : * res_ndigits = var2ndigits + 3
8718 : : * ----------
8719 : : */
8720 : : /* last two result digits */
628 8721 : 146 : term = PRODSUM1(var1digits, 2, var2digits, var2ndigits - 1);
665 8722 : 146 : res_digits[res_ndigits - 1] = (NumericDigit) (term % NBASE);
8723 : 146 : carry = term / NBASE;
8724 : :
628 8725 : 146 : term = PRODSUM2(var1digits, 1, var2digits, var2ndigits - 1) + carry;
665 8726 : 146 : res_digits[res_ndigits - 2] = (NumericDigit) (term % NBASE);
8727 : 146 : carry = term / NBASE;
8728 : :
8729 : : /* remaining digits, except for the first three */
628 8730 [ + + ]: 387 : for (int i = var2ndigits - 1; i >= 2; i--)
8731 : : {
8732 : 241 : term = PRODSUM3(var1digits, 0, var2digits, i) + carry;
665 8733 : 241 : res_digits[i + 1] = (NumericDigit) (term % NBASE);
8734 : 241 : carry = term / NBASE;
8735 : : }
8736 : 146 : break;
8737 : :
8738 : 2888 : case 4:
8739 : : /* ---------
8740 : : * 4-digit case:
8741 : : * var1ndigits = 4
8742 : : * var2ndigits >= 4
8743 : : * res_ndigits = var2ndigits + 4
8744 : : * ----------
8745 : : */
8746 : : /* last three result digits */
628 8747 : 2888 : term = PRODSUM1(var1digits, 3, var2digits, var2ndigits - 1);
665 8748 : 2888 : res_digits[res_ndigits - 1] = (NumericDigit) (term % NBASE);
8749 : 2888 : carry = term / NBASE;
8750 : :
628 8751 : 2888 : term = PRODSUM2(var1digits, 2, var2digits, var2ndigits - 1) + carry;
665 8752 : 2888 : res_digits[res_ndigits - 2] = (NumericDigit) (term % NBASE);
8753 : 2888 : carry = term / NBASE;
8754 : :
628 8755 : 2888 : term = PRODSUM3(var1digits, 1, var2digits, var2ndigits - 1) + carry;
665 8756 : 2888 : res_digits[res_ndigits - 3] = (NumericDigit) (term % NBASE);
8757 : 2888 : carry = term / NBASE;
8758 : :
8759 : : /* remaining digits, except for the first four */
628 8760 [ + + ]: 8058 : for (int i = var2ndigits - 1; i >= 3; i--)
8761 : : {
8762 : 5170 : term = PRODSUM4(var1digits, 0, var2digits, i) + carry;
665 8763 : 5170 : res_digits[i + 1] = (NumericDigit) (term % NBASE);
8764 : 5170 : carry = term / NBASE;
8765 : : }
628 8766 : 2888 : break;
8767 : :
8768 : 91 : case 5:
8769 : : /* ---------
8770 : : * 5-digit case:
8771 : : * var1ndigits = 5
8772 : : * var2ndigits >= 5
8773 : : * res_ndigits = var2ndigits + 5
8774 : : * ----------
8775 : : */
8776 : : /* last four result digits */
8777 : 91 : term = PRODSUM1(var1digits, 4, var2digits, var2ndigits - 1);
8778 : 91 : res_digits[res_ndigits - 1] = (NumericDigit) (term % NBASE);
665 8779 : 91 : carry = term / NBASE;
8780 : :
628 8781 : 91 : term = PRODSUM2(var1digits, 3, var2digits, var2ndigits - 1) + carry;
8782 : 91 : res_digits[res_ndigits - 2] = (NumericDigit) (term % NBASE);
8783 : 91 : carry = term / NBASE;
8784 : :
8785 : 91 : term = PRODSUM3(var1digits, 2, var2digits, var2ndigits - 1) + carry;
8786 : 91 : res_digits[res_ndigits - 3] = (NumericDigit) (term % NBASE);
665 8787 : 91 : carry = term / NBASE;
8788 : :
628 8789 : 91 : term = PRODSUM4(var1digits, 1, var2digits, var2ndigits - 1) + carry;
8790 : 91 : res_digits[res_ndigits - 4] = (NumericDigit) (term % NBASE);
8791 : 91 : carry = term / NBASE;
8792 : :
8793 : : /* remaining digits, except for the first five */
8794 [ + + ]: 242 : for (int i = var2ndigits - 1; i >= 4; i--)
8795 : : {
8796 : 151 : term = PRODSUM5(var1digits, 0, var2digits, i) + carry;
8797 : 151 : res_digits[i + 1] = (NumericDigit) (term % NBASE);
8798 : 151 : carry = term / NBASE;
8799 : : }
8800 : 91 : break;
8801 : :
8802 : 501 : case 6:
8803 : : /* ---------
8804 : : * 6-digit case:
8805 : : * var1ndigits = 6
8806 : : * var2ndigits >= 6
8807 : : * res_ndigits = var2ndigits + 6
8808 : : * ----------
8809 : : */
8810 : : /* last five result digits */
8811 : 501 : term = PRODSUM1(var1digits, 5, var2digits, var2ndigits - 1);
8812 : 501 : res_digits[res_ndigits - 1] = (NumericDigit) (term % NBASE);
8813 : 501 : carry = term / NBASE;
8814 : :
8815 : 501 : term = PRODSUM2(var1digits, 4, var2digits, var2ndigits - 1) + carry;
8816 : 501 : res_digits[res_ndigits - 2] = (NumericDigit) (term % NBASE);
8817 : 501 : carry = term / NBASE;
8818 : :
8819 : 501 : term = PRODSUM3(var1digits, 3, var2digits, var2ndigits - 1) + carry;
8820 : 501 : res_digits[res_ndigits - 3] = (NumericDigit) (term % NBASE);
8821 : 501 : carry = term / NBASE;
8822 : :
8823 : 501 : term = PRODSUM4(var1digits, 2, var2digits, var2ndigits - 1) + carry;
8824 : 501 : res_digits[res_ndigits - 4] = (NumericDigit) (term % NBASE);
8825 : 501 : carry = term / NBASE;
8826 : :
8827 : 501 : term = PRODSUM5(var1digits, 1, var2digits, var2ndigits - 1) + carry;
8828 : 501 : res_digits[res_ndigits - 5] = (NumericDigit) (term % NBASE);
8829 : 501 : carry = term / NBASE;
8830 : :
8831 : : /* remaining digits, except for the first six */
8832 [ + + ]: 1400 : for (int i = var2ndigits - 1; i >= 5; i--)
8833 : : {
8834 : 899 : term = PRODSUM6(var1digits, 0, var2digits, i) + carry;
8835 : 899 : res_digits[i + 1] = (NumericDigit) (term % NBASE);
8836 : 899 : carry = term / NBASE;
8837 : : }
8838 : 501 : break;
8839 : : }
8840 : :
8841 : : /*
8842 : : * Finally, for var1ndigits > 1, compute the remaining var1ndigits most
8843 : : * significant result digits.
8844 : : */
8845 [ + + + + : 772865 : switch (var1ndigits)
+ + ]
8846 : : {
8847 : 501 : case 6:
8848 : 501 : term = PRODSUM5(var1digits, 0, var2digits, 4) + carry;
8849 : 501 : res_digits[5] = (NumericDigit) (term % NBASE);
8850 : 501 : carry = term / NBASE;
8851 : : pg_fallthrough;
8852 : 592 : case 5:
8853 : 592 : term = PRODSUM4(var1digits, 0, var2digits, 3) + carry;
8854 : 592 : res_digits[4] = (NumericDigit) (term % NBASE);
8855 : 592 : carry = term / NBASE;
8856 : : pg_fallthrough;
8857 : 3480 : case 4:
8858 : 3480 : term = PRODSUM3(var1digits, 0, var2digits, 2) + carry;
8859 : 3480 : res_digits[3] = (NumericDigit) (term % NBASE);
8860 : 3480 : carry = term / NBASE;
8861 : : pg_fallthrough;
8862 : 3626 : case 3:
8863 : 3626 : term = PRODSUM2(var1digits, 0, var2digits, 1) + carry;
8864 : 3626 : res_digits[2] = (NumericDigit) (term % NBASE);
8865 : 3626 : carry = term / NBASE;
8866 : : pg_fallthrough;
8867 : 4145 : case 2:
8868 : 4145 : term = PRODSUM1(var1digits, 0, var2digits, 0) + carry;
665 8869 : 4145 : res_digits[1] = (NumericDigit) (term % NBASE);
8870 : 4145 : res_digits[0] = (NumericDigit) (term / NBASE);
8871 : 4145 : break;
8872 : : }
8873 : :
8874 : : /* Store the product in result */
8875 [ + + ]: 772865 : digitbuf_free(result->buf);
8876 : 772865 : result->ndigits = res_ndigits;
8877 : 772865 : result->buf = res_buf;
8878 : 772865 : result->digits = res_digits;
8879 : 772865 : result->weight = res_weight;
8880 : 772865 : result->sign = res_sign;
8881 : 772865 : result->dscale = var1->dscale + var2->dscale;
8882 : :
8883 : : /* Strip leading and trailing zeroes */
8884 : 772865 : strip_var(result);
8885 : 772865 : }
8886 : :
8887 : :
8888 : : /*
8889 : : * div_var() -
8890 : : *
8891 : : * Compute the quotient var1 / var2 to rscale fractional digits.
8892 : : *
8893 : : * If "round" is true, the result is rounded at the rscale'th digit; if
8894 : : * false, it is truncated (towards zero) at that digit.
8895 : : *
8896 : : * If "exact" is true, the exact result is computed to the specified rscale;
8897 : : * if false, successive quotient digits are approximated up to rscale plus
8898 : : * DIV_GUARD_DIGITS extra digits, ignoring all contributions from digits to
8899 : : * the right of that, before rounding or truncating to the specified rscale.
8900 : : * This can be significantly faster, and usually gives the same result as the
8901 : : * exact computation, but it may occasionally be off by one in the final
8902 : : * digit, if contributions from the ignored digits would have propagated
8903 : : * through the guard digits. This is good enough for the transcendental
8904 : : * functions, where small errors are acceptable.
8905 : : */
8906 : : static void
3159 andres@anarazel.de 8907 : 380269 : div_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result,
8908 : : int rscale, bool round, bool exact)
8909 : : {
578 dean.a.rasheed@gmail 8910 : 380269 : int var1ndigits = var1->ndigits;
8911 : 380269 : int var2ndigits = var2->ndigits;
8912 : : int res_sign;
8913 : : int res_weight;
8914 : : int res_ndigits;
8915 : : int var1ndigitpairs;
8916 : : int var2ndigitpairs;
8917 : : int res_ndigitpairs;
8918 : : int div_ndigitpairs;
8919 : : int64 *dividend;
8920 : : int32 *divisor;
8921 : : double fdivisor,
8922 : : fdivisorinverse,
8923 : : fdividend,
8924 : : fquotient;
8925 : : int64 maxdiv;
8926 : : int qi;
8927 : : int32 qdigit;
8928 : : int64 carry;
8929 : : int64 newdig;
8930 : : int64 *remainder;
8931 : : NumericDigit *res_digits;
8932 : : int i;
8933 : :
8934 : : /*
8935 : : * First of all division by zero check; we must not be handed an
8936 : : * unnormalized divisor.
8937 : : */
6605 tgl@sss.pgh.pa.us 8938 [ + + - + ]: 380269 : if (var2ndigits == 0 || var2->digits[0] == 0)
8939 [ + - ]: 8 : ereport(ERROR,
8940 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
8941 : : errmsg("division by zero")));
8942 : :
8943 : : /*
8944 : : * If the divisor has just one or two digits, delegate to div_var_int(),
8945 : : * which uses fast short division.
8946 : : *
8947 : : * Similarly, on platforms with 128-bit integer support, delegate to
8948 : : * div_var_int64() for divisors with three or four digits.
8949 : : */
1528 dean.a.rasheed@gmail 8950 [ + + ]: 380261 : if (var2ndigits <= 2)
8951 : : {
8952 : : int idivisor;
8953 : : int idivisor_weight;
8954 : :
8955 : 375909 : idivisor = var2->digits[0];
8956 : 375909 : idivisor_weight = var2->weight;
8957 [ + + ]: 375909 : if (var2ndigits == 2)
8958 : : {
8959 : 2109 : idivisor = idivisor * NBASE + var2->digits[1];
8960 : 2109 : idivisor_weight--;
8961 : : }
8962 [ + + ]: 375909 : if (var2->sign == NUMERIC_NEG)
8963 : 440 : idivisor = -idivisor;
8964 : :
8965 : 375909 : div_var_int(var1, idivisor, idivisor_weight, result, rscale, round);
8966 : 375909 : return;
8967 : : }
8968 : : #ifdef HAVE_INT128
1198 8969 [ + + ]: 4352 : if (var2ndigits <= 4)
8970 : : {
8971 : : int64 idivisor;
8972 : : int idivisor_weight;
8973 : :
8974 : 360 : idivisor = var2->digits[0];
8975 : 360 : idivisor_weight = var2->weight;
8976 [ + + ]: 1340 : for (i = 1; i < var2ndigits; i++)
8977 : : {
8978 : 980 : idivisor = idivisor * NBASE + var2->digits[i];
8979 : 980 : idivisor_weight--;
8980 : : }
8981 [ + + ]: 360 : if (var2->sign == NUMERIC_NEG)
8982 : 80 : idivisor = -idivisor;
8983 : :
8984 : 360 : div_var_int64(var1, idivisor, idivisor_weight, result, rscale, round);
8985 : 360 : return;
8986 : : }
8987 : : #endif
8988 : :
8989 : : /*
8990 : : * Otherwise, perform full long division.
8991 : : */
8992 : :
8993 : : /* Result zero check */
6605 tgl@sss.pgh.pa.us 8994 [ + + ]: 3992 : if (var1ndigits == 0)
8995 : : {
8996 : 24 : zero_var(result);
8997 : 24 : result->dscale = rscale;
8998 : 24 : return;
8999 : : }
9000 : :
9001 : : /*
9002 : : * The approximate computation can be significantly faster than the exact
9003 : : * one, since the working dividend is var2ndigitpairs base-NBASE^2 digits
9004 : : * shorter below. However, that comes with the tradeoff of computing
9005 : : * DIV_GUARD_DIGITS extra base-NBASE result digits. Ignoring all other
9006 : : * overheads, that suggests that, in theory, the approximate computation
9007 : : * will only be faster than the exact one when var2ndigits is greater than
9008 : : * 2 * (DIV_GUARD_DIGITS + 1), independent of the size of var1.
9009 : : *
9010 : : * Thus, we're better off doing an exact computation when var2 is shorter
9011 : : * than this. Empirically, it has been found that the exact threshold is
9012 : : * a little higher, due to other overheads in the outer division loop.
9013 : : */
578 dean.a.rasheed@gmail 9014 [ + + ]: 3968 : if (var2ndigits <= 2 * (DIV_GUARD_DIGITS + 2))
9015 : 2712 : exact = true;
9016 : :
9017 : : /*
9018 : : * Determine the result sign, weight and number of digits to calculate.
9019 : : * The weight figured here is correct if the emitted quotient has no
9020 : : * leading zero digits; otherwise strip_var() will fix things up.
9021 : : */
6605 tgl@sss.pgh.pa.us 9022 [ + + ]: 3968 : if (var1->sign == var2->sign)
9023 : 3866 : res_sign = NUMERIC_POS;
9024 : : else
9025 : 102 : res_sign = NUMERIC_NEG;
578 dean.a.rasheed@gmail 9026 : 3968 : res_weight = var1->weight - var2->weight + 1;
9027 : : /* The number of accurate result digits we need to produce: */
6605 tgl@sss.pgh.pa.us 9028 : 3968 : res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9029 : : /* ... but always at least 1 */
9030 : 3968 : res_ndigits = Max(res_ndigits, 1);
9031 : : /* If rounding needed, figure one more digit to ensure correct result */
9032 [ + + ]: 3968 : if (round)
9033 : 658 : res_ndigits++;
9034 : : /* Add guard digits for roundoff error when producing approx result */
578 dean.a.rasheed@gmail 9035 [ + + ]: 3968 : if (!exact)
9036 : 1246 : res_ndigits += DIV_GUARD_DIGITS;
9037 : :
9038 : : /*
9039 : : * The computation itself is done using base-NBASE^2 arithmetic, so we
9040 : : * actually process the input digits in pairs, producing a base-NBASE^2
9041 : : * intermediate result. This significantly improves performance, since
9042 : : * the computation is O(N^2) in the number of input digits, and working in
9043 : : * base NBASE^2 effectively halves "N".
9044 : : */
9045 : 3968 : var1ndigitpairs = (var1ndigits + 1) / 2;
9046 : 3968 : var2ndigitpairs = (var2ndigits + 1) / 2;
9047 : 3968 : res_ndigitpairs = (res_ndigits + 1) / 2;
9048 : 3968 : res_ndigits = 2 * res_ndigitpairs;
9049 : :
9050 : : /*
9051 : : * We do the arithmetic in an array "dividend[]" of signed 64-bit
9052 : : * integers. Since PG_INT64_MAX is much larger than NBASE^4, this gives
9053 : : * us a lot of headroom to avoid normalizing carries immediately.
9054 : : *
9055 : : * When performing an exact computation, the working dividend requires
9056 : : * res_ndigitpairs + var2ndigitpairs digits. If var1 is larger than that,
9057 : : * the extra digits do not contribute to the result, and are ignored.
9058 : : *
9059 : : * When performing an approximate computation, the working dividend only
9060 : : * requires res_ndigitpairs digits (which includes the extra guard
9061 : : * digits). All input digits beyond that are ignored.
9062 : : */
9063 [ + + ]: 3968 : if (exact)
9064 : : {
9065 : 2722 : div_ndigitpairs = res_ndigitpairs + var2ndigitpairs;
9066 : 2722 : var1ndigitpairs = Min(var1ndigitpairs, div_ndigitpairs);
9067 : : }
9068 : : else
9069 : : {
9070 : 1246 : div_ndigitpairs = res_ndigitpairs;
9071 : 1246 : var1ndigitpairs = Min(var1ndigitpairs, div_ndigitpairs);
9072 : 1246 : var2ndigitpairs = Min(var2ndigitpairs, div_ndigitpairs);
9073 : : }
9074 : :
9075 : : /*
9076 : : * Allocate room for the working dividend (div_ndigitpairs 64-bit digits)
9077 : : * plus the divisor (var2ndigitpairs 32-bit base-NBASE^2 digits).
9078 : : *
9079 : : * For convenience, we allocate one extra dividend digit, which is set to
9080 : : * zero and not counted in div_ndigitpairs, so that the main loop below
9081 : : * can safely read and write the (qi+1)'th digit in the approximate case.
9082 : : */
9083 : 3968 : dividend = (int64 *) palloc((div_ndigitpairs + 1) * sizeof(int64) +
9084 : : var2ndigitpairs * sizeof(int32));
9085 : 3968 : divisor = (int32 *) (dividend + div_ndigitpairs + 1);
9086 : :
9087 : : /* load var1 into dividend[0 .. var1ndigitpairs-1], zeroing the rest */
9088 [ + + ]: 37128 : for (i = 0; i < var1ndigitpairs - 1; i++)
9089 : 33160 : dividend[i] = var1->digits[2 * i] * NBASE + var1->digits[2 * i + 1];
9090 : :
9091 [ + + ]: 3968 : if (2 * i + 1 < var1ndigits)
9092 : 2341 : dividend[i] = var1->digits[2 * i] * NBASE + var1->digits[2 * i + 1];
9093 : : else
9094 : 1627 : dividend[i] = var1->digits[2 * i] * NBASE;
9095 : :
9096 : 3968 : memset(dividend + i + 1, 0, (div_ndigitpairs - i) * sizeof(int64));
9097 : :
9098 : : /* load var2 into divisor[0 .. var2ndigitpairs-1] */
9099 [ + + ]: 29424 : for (i = 0; i < var2ndigitpairs - 1; i++)
9100 : 25456 : divisor[i] = var2->digits[2 * i] * NBASE + var2->digits[2 * i + 1];
9101 : :
9102 [ + + ]: 3968 : if (2 * i + 1 < var2ndigits)
9103 : 2138 : divisor[i] = var2->digits[2 * i] * NBASE + var2->digits[2 * i + 1];
9104 : : else
9105 : 1830 : divisor[i] = var2->digits[2 * i] * NBASE;
9106 : :
9107 : : /*
9108 : : * We estimate each quotient digit using floating-point arithmetic, taking
9109 : : * the first 2 base-NBASE^2 digits of the (current) dividend and divisor.
9110 : : * This must be float to avoid overflow.
9111 : : *
9112 : : * Since the floating-point dividend and divisor use 4 base-NBASE input
9113 : : * digits, they include roughly 40-53 bits of information from their
9114 : : * respective inputs (assuming NBASE is 10000), which fits well in IEEE
9115 : : * double-precision variables. The relative error in the floating-point
9116 : : * quotient digit will then be less than around 2/NBASE^3, so the
9117 : : * estimated base-NBASE^2 quotient digit will typically be correct, and
9118 : : * should not be off by more than one from the correct value.
9119 : : */
9120 : 3968 : fdivisor = (double) divisor[0] * NBASE_SQR;
9121 [ + - ]: 3968 : if (var2ndigitpairs > 1)
9122 : 3968 : fdivisor += (double) divisor[1];
8446 tgl@sss.pgh.pa.us 9123 : 3968 : fdivisorinverse = 1.0 / fdivisor;
9124 : :
9125 : : /*
9126 : : * maxdiv tracks the maximum possible absolute value of any dividend[]
9127 : : * entry; when this threatens to exceed PG_INT64_MAX, we take the time to
9128 : : * propagate carries. Furthermore, we need to ensure that overflow
9129 : : * doesn't occur during the carry propagation passes either. The carry
9130 : : * values may have an absolute value as high as PG_INT64_MAX/NBASE^2 + 1,
9131 : : * so really we must normalize when digits threaten to exceed PG_INT64_MAX
9132 : : * - PG_INT64_MAX/NBASE^2 - 1.
9133 : : *
9134 : : * To avoid overflow in maxdiv itself, it represents the max absolute
9135 : : * value divided by NBASE^2-1, i.e., at the top of the loop it is known
9136 : : * that no dividend[] entry has an absolute value exceeding maxdiv *
9137 : : * (NBASE^2-1).
9138 : : *
9139 : : * Actually, though, that holds good only for dividend[] entries after
9140 : : * dividend[qi]; the adjustment done at the bottom of the loop may cause
9141 : : * dividend[qi + 1] to exceed the maxdiv limit, so that dividend[qi] in
9142 : : * the next iteration is beyond the limit. This does not cause problems,
9143 : : * as explained below.
9144 : : */
9145 : 3968 : maxdiv = 1;
9146 : :
9147 : : /*
9148 : : * Outer loop computes next quotient digit, which goes in dividend[qi].
9149 : : */
578 dean.a.rasheed@gmail 9150 [ + + ]: 36464 : for (qi = 0; qi < res_ndigitpairs; qi++)
9151 : : {
9152 : : /* Approximate the current dividend value */
9153 : 32496 : fdividend = (double) dividend[qi] * NBASE_SQR;
9154 : 32496 : fdividend += (double) dividend[qi + 1];
9155 : :
9156 : : /* Compute the (approximate) quotient digit */
8446 tgl@sss.pgh.pa.us 9157 : 32496 : fquotient = fdividend * fdivisorinverse;
578 dean.a.rasheed@gmail 9158 [ + + ]: 32496 : qdigit = (fquotient >= 0.0) ? ((int32) fquotient) :
9159 : 5 : (((int32) fquotient) - 1); /* truncate towards -infinity */
9160 : :
8446 tgl@sss.pgh.pa.us 9161 [ + + ]: 32496 : if (qdigit != 0)
9162 : : {
9163 : : /* Do we need to normalize now? */
578 dean.a.rasheed@gmail 9164 : 29863 : maxdiv += i64abs(qdigit);
9165 [ + + ]: 29863 : if (maxdiv > (PG_INT64_MAX - PG_INT64_MAX / NBASE_SQR - 1) / (NBASE_SQR - 1))
9166 : : {
9167 : : /*
9168 : : * Yes, do it. Note that if var2ndigitpairs is much smaller
9169 : : * than div_ndigitpairs, we can save a significant amount of
9170 : : * effort here by noting that we only need to normalise those
9171 : : * dividend[] entries touched where prior iterations
9172 : : * subtracted multiples of the divisor.
9173 : : */
8446 tgl@sss.pgh.pa.us 9174 : 5 : carry = 0;
578 dean.a.rasheed@gmail 9175 [ + + ]: 5625 : for (i = Min(qi + var2ndigitpairs - 2, div_ndigitpairs - 1); i > qi; i--)
9176 : : {
9177 : 5620 : newdig = dividend[i] + carry;
8446 tgl@sss.pgh.pa.us 9178 [ + - ]: 5620 : if (newdig < 0)
9179 : : {
578 dean.a.rasheed@gmail 9180 : 5620 : carry = -((-newdig - 1) / NBASE_SQR) - 1;
9181 : 5620 : newdig -= carry * NBASE_SQR;
9182 : : }
578 dean.a.rasheed@gmail 9183 [ # # ]:UBC 0 : else if (newdig >= NBASE_SQR)
9184 : : {
9185 : 0 : carry = newdig / NBASE_SQR;
9186 : 0 : newdig -= carry * NBASE_SQR;
9187 : : }
9188 : : else
8446 tgl@sss.pgh.pa.us 9189 : 0 : carry = 0;
578 dean.a.rasheed@gmail 9190 :CBC 5620 : dividend[i] = newdig;
9191 : : }
9192 : 5 : dividend[qi] += carry;
9193 : :
9194 : : /*
9195 : : * All the dividend[] digits except possibly dividend[qi] are
9196 : : * now in the range 0..NBASE^2-1. We do not need to consider
9197 : : * dividend[qi] in the maxdiv value anymore, so we can reset
9198 : : * maxdiv to 1.
9199 : : */
3814 tgl@sss.pgh.pa.us 9200 : 5 : maxdiv = 1;
9201 : :
9202 : : /*
9203 : : * Recompute the quotient digit since new info may have
9204 : : * propagated into the top two dividend digits.
9205 : : */
578 dean.a.rasheed@gmail 9206 : 5 : fdividend = (double) dividend[qi] * NBASE_SQR;
9207 : 5 : fdividend += (double) dividend[qi + 1];
8446 tgl@sss.pgh.pa.us 9208 : 5 : fquotient = fdividend * fdivisorinverse;
578 dean.a.rasheed@gmail 9209 [ + - ]: 5 : qdigit = (fquotient >= 0.0) ? ((int32) fquotient) :
578 dean.a.rasheed@gmail 9210 :UBC 0 : (((int32) fquotient) - 1); /* truncate towards -infinity */
9211 : :
578 dean.a.rasheed@gmail 9212 :CBC 5 : maxdiv += i64abs(qdigit);
9213 : : }
9214 : :
9215 : : /*
9216 : : * Subtract off the appropriate multiple of the divisor.
9217 : : *
9218 : : * The digits beyond dividend[qi] cannot overflow, because we know
9219 : : * they will fall within the maxdiv limit. As for dividend[qi]
9220 : : * itself, note that qdigit is approximately trunc(dividend[qi] /
9221 : : * divisor[0]), which would make the new value simply dividend[qi]
9222 : : * mod divisor[0]. The lower-order terms in qdigit can change
9223 : : * this result by not more than about twice PG_INT64_MAX/NBASE^2,
9224 : : * so overflow is impossible.
9225 : : *
9226 : : * This inner loop is the performance bottleneck for division, so
9227 : : * code it in the same way as the inner loop of mul_var() so that
9228 : : * it can be auto-vectorized.
9229 : : */
8446 tgl@sss.pgh.pa.us 9230 [ + - ]: 29863 : if (qdigit != 0)
9231 : : {
578 dean.a.rasheed@gmail 9232 : 29863 : int istop = Min(var2ndigitpairs, div_ndigitpairs - qi);
9233 : 29863 : int64 *dividend_qi = ÷nd[qi];
9234 : :
8446 tgl@sss.pgh.pa.us 9235 [ + + ]: 6518873 : for (i = 0; i < istop; i++)
578 dean.a.rasheed@gmail 9236 : 6489010 : dividend_qi[i] -= (int64) qdigit * divisor[i];
9237 : : }
9238 : : }
9239 : :
9240 : : /*
9241 : : * The dividend digit we are about to replace might still be nonzero.
9242 : : * Fold it into the next digit position.
9243 : : *
9244 : : * There is no risk of overflow here, although proving that requires
9245 : : * some care. Much as with the argument for dividend[qi] not
9246 : : * overflowing, if we consider the first two terms in the numerator
9247 : : * and denominator of qdigit, we can see that the final value of
9248 : : * dividend[qi + 1] will be approximately a remainder mod
9249 : : * (divisor[0]*NBASE^2 + divisor[1]). Accounting for the lower-order
9250 : : * terms is a bit complicated but ends up adding not much more than
9251 : : * PG_INT64_MAX/NBASE^2 to the possible range. Thus, dividend[qi + 1]
9252 : : * cannot overflow here, and in its role as dividend[qi] in the next
9253 : : * loop iteration, it can't be large enough to cause overflow in the
9254 : : * carry propagation step (if any), either.
9255 : : *
9256 : : * But having said that: dividend[qi] can be more than
9257 : : * PG_INT64_MAX/NBASE^2, as noted above, which means that the product
9258 : : * dividend[qi] * NBASE^2 *can* overflow. When that happens, adding
9259 : : * it to dividend[qi + 1] will always cause a canceling overflow so
9260 : : * that the end result is correct. We could avoid the intermediate
9261 : : * overflow by doing the multiplication and addition using unsigned
9262 : : * int64 arithmetic, which is modulo 2^64, but so far there appears no
9263 : : * need.
9264 : : */
9265 : 32496 : dividend[qi + 1] += dividend[qi] * NBASE_SQR;
9266 : :
9267 : 32496 : dividend[qi] = qdigit;
9268 : : }
9269 : :
9270 : : /*
9271 : : * If an exact result was requested, use the remainder to correct the
9272 : : * approximate quotient. The remainder is in dividend[], immediately
9273 : : * after the quotient digits. Note, however, that although the remainder
9274 : : * starts at dividend[qi = res_ndigitpairs], the first digit is the result
9275 : : * of folding two remainder digits into one above, and the remainder
9276 : : * currently only occupies var2ndigitpairs - 1 digits (the last digit of
9277 : : * the working dividend was untouched by the computation above). Thus we
9278 : : * expand the remainder down by one base-NBASE^2 digit when we normalize
9279 : : * it, so that it completely fills the last var2ndigitpairs digits of the
9280 : : * dividend array.
9281 : : */
9282 [ + + ]: 3968 : if (exact)
9283 : : {
9284 : : /* Normalize the remainder, expanding it down by one digit */
9285 : 2722 : remainder = ÷nd[qi];
9286 : 2722 : carry = 0;
9287 [ + + ]: 15518 : for (i = var2ndigitpairs - 2; i >= 0; i--)
9288 : : {
9289 : 12796 : newdig = remainder[i] + carry;
9290 [ + + ]: 12796 : if (newdig < 0)
9291 : : {
9292 : 10044 : carry = -((-newdig - 1) / NBASE_SQR) - 1;
9293 : 10044 : newdig -= carry * NBASE_SQR;
9294 : : }
9295 [ + + ]: 2752 : else if (newdig >= NBASE_SQR)
9296 : : {
9297 : 2696 : carry = newdig / NBASE_SQR;
9298 : 2696 : newdig -= carry * NBASE_SQR;
9299 : : }
9300 : : else
9301 : 56 : carry = 0;
9302 : 12796 : remainder[i + 1] = newdig;
9303 : : }
9304 : 2722 : remainder[0] = carry;
9305 : :
9306 [ + + ]: 2722 : if (remainder[0] < 0)
9307 : : {
9308 : : /*
9309 : : * The remainder is negative, so the approximate quotient is too
9310 : : * large. Correct by reducing the quotient by one and adding the
9311 : : * divisor to the remainder until the remainder is positive. We
9312 : : * expect the quotient to be off by at most one, which has been
9313 : : * borne out in all testing, but not conclusively proven, so we
9314 : : * allow for larger corrections, just in case.
9315 : : */
9316 : : do
9317 : : {
9318 : : /* Add the divisor to the remainder */
9319 : 5 : carry = 0;
9320 [ + + ]: 65 : for (i = var2ndigitpairs - 1; i > 0; i--)
9321 : : {
9322 : 60 : newdig = remainder[i] + divisor[i] + carry;
9323 [ - + ]: 60 : if (newdig >= NBASE_SQR)
9324 : : {
578 dean.a.rasheed@gmail 9325 :UBC 0 : remainder[i] = newdig - NBASE_SQR;
9326 : 0 : carry = 1;
9327 : : }
9328 : : else
9329 : : {
578 dean.a.rasheed@gmail 9330 :CBC 60 : remainder[i] = newdig;
9331 : 60 : carry = 0;
9332 : : }
9333 : : }
9334 : 5 : remainder[0] += divisor[0] + carry;
9335 : :
9336 : : /* Subtract 1 from the quotient (propagating carries later) */
9337 : 5 : dividend[qi - 1]--;
9338 : :
9339 [ - + ]: 5 : } while (remainder[0] < 0);
9340 : : }
9341 : : else
9342 : : {
9343 : : /*
9344 : : * The remainder is nonnegative. If it's greater than or equal to
9345 : : * the divisor, then the approximate quotient is too small and
9346 : : * must be corrected. As above, we don't expect to have to apply
9347 : : * more than one correction, but allow for it just in case.
9348 : : */
9349 : : while (true)
9350 : 5 : {
9351 : 2722 : bool less = false;
9352 : :
9353 : : /* Is remainder < divisor? */
9354 [ + + ]: 2737 : for (i = 0; i < var2ndigitpairs; i++)
9355 : : {
9356 [ + + ]: 2732 : if (remainder[i] < divisor[i])
9357 : : {
9358 : 2717 : less = true;
9359 : 2717 : break;
9360 : : }
9361 [ - + ]: 15 : if (remainder[i] > divisor[i])
578 dean.a.rasheed@gmail 9362 :UBC 0 : break; /* remainder > divisor */
9363 : : }
578 dean.a.rasheed@gmail 9364 [ + + ]:CBC 2722 : if (less)
9365 : 2717 : break; /* quotient is correct */
9366 : :
9367 : : /* Subtract the divisor from the remainder */
9368 : 5 : carry = 0;
9369 [ + + ]: 15 : for (i = var2ndigitpairs - 1; i > 0; i--)
9370 : : {
9371 : 10 : newdig = remainder[i] - divisor[i] + carry;
9372 [ - + ]: 10 : if (newdig < 0)
9373 : : {
578 dean.a.rasheed@gmail 9374 :UBC 0 : remainder[i] = newdig + NBASE_SQR;
9375 : 0 : carry = -1;
9376 : : }
9377 : : else
9378 : : {
578 dean.a.rasheed@gmail 9379 :CBC 10 : remainder[i] = newdig;
9380 : 10 : carry = 0;
9381 : : }
9382 : : }
9383 : 5 : remainder[0] = remainder[0] - divisor[0] + carry;
9384 : :
9385 : : /* Add 1 to the quotient (propagating carries later) */
9386 : 5 : dividend[qi - 1]++;
9387 : : }
9388 : : }
9389 : : }
9390 : :
9391 : : /*
9392 : : * Because the quotient digits were estimates that might have been off by
9393 : : * one (and we didn't bother propagating carries when adjusting the
9394 : : * quotient above), some quotient digits might be out of range, so do a
9395 : : * final carry propagation pass to normalize back to base NBASE^2, and
9396 : : * construct the base-NBASE result digits. Note that this is still done
9397 : : * at full precision w/guard digits.
9398 : : */
9399 : 3968 : alloc_var(result, res_ndigits);
8446 tgl@sss.pgh.pa.us 9400 : 3968 : res_digits = result->digits;
9401 : 3968 : carry = 0;
578 dean.a.rasheed@gmail 9402 [ + + ]: 36464 : for (i = res_ndigitpairs - 1; i >= 0; i--)
9403 : : {
9404 : 32496 : newdig = dividend[i] + carry;
8446 tgl@sss.pgh.pa.us 9405 [ + + ]: 32496 : if (newdig < 0)
9406 : : {
578 dean.a.rasheed@gmail 9407 : 5 : carry = -((-newdig - 1) / NBASE_SQR) - 1;
9408 : 5 : newdig -= carry * NBASE_SQR;
9409 : : }
9410 [ - + ]: 32491 : else if (newdig >= NBASE_SQR)
9411 : : {
578 dean.a.rasheed@gmail 9412 :UBC 0 : carry = newdig / NBASE_SQR;
9413 : 0 : newdig -= carry * NBASE_SQR;
9414 : : }
9415 : : else
8446 tgl@sss.pgh.pa.us 9416 :CBC 32491 : carry = 0;
578 dean.a.rasheed@gmail 9417 : 32496 : res_digits[2 * i + 1] = (NumericDigit) ((uint32) newdig % NBASE);
9418 : 32496 : res_digits[2 * i] = (NumericDigit) ((uint32) newdig / NBASE);
9419 : : }
8446 tgl@sss.pgh.pa.us 9420 [ - + ]: 3968 : Assert(carry == 0);
9421 : :
578 dean.a.rasheed@gmail 9422 : 3968 : pfree(dividend);
9423 : :
9424 : : /*
9425 : : * Finally, round or truncate the result to the requested precision.
9426 : : */
8446 tgl@sss.pgh.pa.us 9427 : 3968 : result->weight = res_weight;
9428 : 3968 : result->sign = res_sign;
9429 : :
9430 : : /* Round or truncate to target rscale (and set result->dscale) */
7640 bruce@momjian.us 9431 [ + + ]: 3968 : if (round)
9432 : 658 : round_var(result, rscale);
9433 : : else
9434 : 3310 : trunc_var(result, rscale);
9435 : :
9436 : : /* Strip leading and trailing zeroes */
8446 tgl@sss.pgh.pa.us 9437 : 3968 : strip_var(result);
9438 : : }
9439 : :
9440 : :
9441 : : /*
9442 : : * div_var_int() -
9443 : : *
9444 : : * Divide a numeric variable by a 32-bit integer with the specified weight.
9445 : : * The quotient var / (ival * NBASE^ival_weight) is stored in result.
9446 : : */
9447 : : static void
1528 dean.a.rasheed@gmail 9448 : 389667 : div_var_int(const NumericVar *var, int ival, int ival_weight,
9449 : : NumericVar *result, int rscale, bool round)
9450 : : {
9451 : 389667 : NumericDigit *var_digits = var->digits;
9452 : 389667 : int var_ndigits = var->ndigits;
9453 : : int res_sign;
9454 : : int res_weight;
9455 : : int res_ndigits;
9456 : : NumericDigit *res_buf;
9457 : : NumericDigit *res_digits;
9458 : : uint32 divisor;
9459 : : int i;
9460 : :
9461 : : /* Guard against division by zero */
9462 [ - + ]: 389667 : if (ival == 0)
1528 dean.a.rasheed@gmail 9463 [ # # ]:UBC 0 : ereport(ERROR,
9464 : : errcode(ERRCODE_DIVISION_BY_ZERO),
9465 : : errmsg("division by zero"));
9466 : :
9467 : : /* Result zero check */
1528 dean.a.rasheed@gmail 9468 [ + + ]:CBC 389667 : if (var_ndigits == 0)
9469 : : {
9470 : 1583 : zero_var(result);
9471 : 1583 : result->dscale = rscale;
9472 : 1583 : return;
9473 : : }
9474 : :
9475 : : /*
9476 : : * Determine the result sign, weight and number of digits to calculate.
9477 : : * The weight figured here is correct if the emitted quotient has no
9478 : : * leading zero digits; otherwise strip_var() will fix things up.
9479 : : */
9480 [ + + ]: 388084 : if (var->sign == NUMERIC_POS)
9481 [ + + ]: 385840 : res_sign = ival > 0 ? NUMERIC_POS : NUMERIC_NEG;
9482 : : else
9483 [ + + ]: 2244 : res_sign = ival > 0 ? NUMERIC_NEG : NUMERIC_POS;
9484 : 388084 : res_weight = var->weight - ival_weight;
9485 : : /* The number of accurate result digits we need to produce: */
9486 : 388084 : res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9487 : : /* ... but always at least 1 */
9488 : 388084 : res_ndigits = Max(res_ndigits, 1);
9489 : : /* If rounding needed, figure one more digit to ensure correct result */
9490 [ + + ]: 388084 : if (round)
9491 : 111699 : res_ndigits++;
9492 : :
9493 : 388084 : res_buf = digitbuf_alloc(res_ndigits + 1);
9494 : 388084 : res_buf[0] = 0; /* spare digit for later rounding */
9495 : 388084 : res_digits = res_buf + 1;
9496 : :
9497 : : /*
9498 : : * Now compute the quotient digits. This is the short division algorithm
9499 : : * described in Knuth volume 2, section 4.3.1 exercise 16, except that we
9500 : : * allow the divisor to exceed the internal base.
9501 : : *
9502 : : * In this algorithm, the carry from one digit to the next is at most
9503 : : * divisor - 1. Therefore, while processing the next digit, carry may
9504 : : * become as large as divisor * NBASE - 1, and so it requires a 64-bit
9505 : : * integer if this exceeds UINT_MAX.
9506 : : */
1306 peter@eisentraut.org 9507 : 388084 : divisor = abs(ival);
9508 : :
1528 dean.a.rasheed@gmail 9509 [ + + ]: 388084 : if (divisor <= UINT_MAX / NBASE)
9510 : : {
9511 : : /* carry cannot overflow 32 bits */
9512 : 386376 : uint32 carry = 0;
9513 : :
9514 [ + + ]: 1914264 : for (i = 0; i < res_ndigits; i++)
9515 : : {
9516 [ + + ]: 1527888 : carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9517 : 1527888 : res_digits[i] = (NumericDigit) (carry / divisor);
9518 : 1527888 : carry = carry % divisor;
9519 : : }
9520 : : }
9521 : : else
9522 : : {
9523 : : /* carry may exceed 32 bits */
9524 : 1708 : uint64 carry = 0;
9525 : :
9526 [ + + ]: 5573 : for (i = 0; i < res_ndigits; i++)
9527 : : {
9528 [ + + ]: 3865 : carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9529 : 3865 : res_digits[i] = (NumericDigit) (carry / divisor);
9530 : 3865 : carry = carry % divisor;
9531 : : }
9532 : : }
9533 : :
9534 : : /* Store the quotient in result */
9535 [ + + ]: 388084 : digitbuf_free(result->buf);
9536 : 388084 : result->ndigits = res_ndigits;
9537 : 388084 : result->buf = res_buf;
9538 : 388084 : result->digits = res_digits;
9539 : 388084 : result->weight = res_weight;
9540 : 388084 : result->sign = res_sign;
9541 : :
9542 : : /* Round or truncate to target rscale (and set result->dscale) */
9543 [ + + ]: 388084 : if (round)
9544 : 111699 : round_var(result, rscale);
9545 : : else
9546 : 276385 : trunc_var(result, rscale);
9547 : :
9548 : : /* Strip leading/trailing zeroes */
9549 : 388084 : strip_var(result);
9550 : : }
9551 : :
9552 : :
9553 : : #ifdef HAVE_INT128
9554 : : /*
9555 : : * div_var_int64() -
9556 : : *
9557 : : * Divide a numeric variable by a 64-bit integer with the specified weight.
9558 : : * The quotient var / (ival * NBASE^ival_weight) is stored in result.
9559 : : *
9560 : : * This duplicates the logic in div_var_int(), so any changes made there
9561 : : * should be made here too.
9562 : : */
9563 : : static void
1198 9564 : 360 : div_var_int64(const NumericVar *var, int64 ival, int ival_weight,
9565 : : NumericVar *result, int rscale, bool round)
9566 : : {
9567 : 360 : NumericDigit *var_digits = var->digits;
9568 : 360 : int var_ndigits = var->ndigits;
9569 : : int res_sign;
9570 : : int res_weight;
9571 : : int res_ndigits;
9572 : : NumericDigit *res_buf;
9573 : : NumericDigit *res_digits;
9574 : : uint64 divisor;
9575 : : int i;
9576 : :
9577 : : /* Guard against division by zero */
9578 [ - + ]: 360 : if (ival == 0)
1198 dean.a.rasheed@gmail 9579 [ # # ]:UBC 0 : ereport(ERROR,
9580 : : errcode(ERRCODE_DIVISION_BY_ZERO),
9581 : : errmsg("division by zero"));
9582 : :
9583 : : /* Result zero check */
1198 dean.a.rasheed@gmail 9584 [ + + ]:CBC 360 : if (var_ndigits == 0)
9585 : : {
9586 : 64 : zero_var(result);
9587 : 64 : result->dscale = rscale;
9588 : 64 : return;
9589 : : }
9590 : :
9591 : : /*
9592 : : * Determine the result sign, weight and number of digits to calculate.
9593 : : * The weight figured here is correct if the emitted quotient has no
9594 : : * leading zero digits; otherwise strip_var() will fix things up.
9595 : : */
9596 [ + + ]: 296 : if (var->sign == NUMERIC_POS)
9597 [ + + ]: 175 : res_sign = ival > 0 ? NUMERIC_POS : NUMERIC_NEG;
9598 : : else
9599 [ + + ]: 121 : res_sign = ival > 0 ? NUMERIC_NEG : NUMERIC_POS;
9600 : 296 : res_weight = var->weight - ival_weight;
9601 : : /* The number of accurate result digits we need to produce: */
9602 : 296 : res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9603 : : /* ... but always at least 1 */
9604 : 296 : res_ndigits = Max(res_ndigits, 1);
9605 : : /* If rounding needed, figure one more digit to ensure correct result */
9606 [ + + ]: 296 : if (round)
9607 : 291 : res_ndigits++;
9608 : :
9609 : 296 : res_buf = digitbuf_alloc(res_ndigits + 1);
9610 : 296 : res_buf[0] = 0; /* spare digit for later rounding */
9611 : 296 : res_digits = res_buf + 1;
9612 : :
9613 : : /*
9614 : : * Now compute the quotient digits. This is the short division algorithm
9615 : : * described in Knuth volume 2, section 4.3.1 exercise 16, except that we
9616 : : * allow the divisor to exceed the internal base.
9617 : : *
9618 : : * In this algorithm, the carry from one digit to the next is at most
9619 : : * divisor - 1. Therefore, while processing the next digit, carry may
9620 : : * become as large as divisor * NBASE - 1, and so it requires a 128-bit
9621 : : * integer if this exceeds PG_UINT64_MAX.
9622 : : */
9623 : 296 : divisor = i64abs(ival);
9624 : :
9625 [ + + ]: 296 : if (divisor <= PG_UINT64_MAX / NBASE)
9626 : : {
9627 : : /* carry cannot overflow 64 bits */
9628 : 232 : uint64 carry = 0;
9629 : :
9630 [ + + ]: 2361 : for (i = 0; i < res_ndigits; i++)
9631 : : {
9632 [ + + ]: 2129 : carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9633 : 2129 : res_digits[i] = (NumericDigit) (carry / divisor);
9634 : 2129 : carry = carry % divisor;
9635 : : }
9636 : : }
9637 : : else
9638 : : {
9639 : : /* carry may exceed 64 bits */
9640 : 64 : uint128 carry = 0;
9641 : :
9642 [ + + ]: 688 : for (i = 0; i < res_ndigits; i++)
9643 : : {
9644 [ + + ]: 624 : carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9645 : 624 : res_digits[i] = (NumericDigit) (carry / divisor);
9646 : 624 : carry = carry % divisor;
9647 : : }
9648 : : }
9649 : :
9650 : : /* Store the quotient in result */
9651 [ + + ]: 296 : digitbuf_free(result->buf);
9652 : 296 : result->ndigits = res_ndigits;
9653 : 296 : result->buf = res_buf;
9654 : 296 : result->digits = res_digits;
9655 : 296 : result->weight = res_weight;
9656 : 296 : result->sign = res_sign;
9657 : :
9658 : : /* Round or truncate to target rscale (and set result->dscale) */
9659 [ + + ]: 296 : if (round)
9660 : 291 : round_var(result, rscale);
9661 : : else
9662 : 5 : trunc_var(result, rscale);
9663 : :
9664 : : /* Strip leading/trailing zeroes */
9665 : 296 : strip_var(result);
9666 : : }
9667 : : #endif
9668 : :
9669 : :
9670 : : /*
9671 : : * Default scale selection for division
9672 : : *
9673 : : * Returns the appropriate result scale for the division result.
9674 : : */
9675 : : static int
3159 andres@anarazel.de 9676 : 99378 : select_div_scale(const NumericVar *var1, const NumericVar *var2)
9677 : : {
9678 : : int weight1,
9679 : : weight2,
9680 : : qweight,
9681 : : i;
9682 : : NumericDigit firstdigit1,
9683 : : firstdigit2;
9684 : : int rscale;
9685 : :
9686 : : /*
9687 : : * The result scale of a division isn't specified in any SQL standard. For
9688 : : * PostgreSQL we select a result scale that will give at least
9689 : : * NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a
9690 : : * result no less accurate than float8; but use a scale not less than
9691 : : * either input's display scale.
9692 : : */
9693 : :
9694 : : /* Get the actual (normalized) weight and first digit of each input */
9695 : :
8616 tgl@sss.pgh.pa.us 9696 : 99378 : weight1 = 0; /* values to use if var1 is zero */
9697 : 99378 : firstdigit1 = 0;
9698 [ + + ]: 99378 : for (i = 0; i < var1->ndigits; i++)
9699 : : {
9700 : 98245 : firstdigit1 = var1->digits[i];
9701 [ + - ]: 98245 : if (firstdigit1 != 0)
9702 : : {
9703 : 98245 : weight1 = var1->weight - i;
9704 : 98245 : break;
9705 : : }
9706 : : }
9707 : :
9708 : 99378 : weight2 = 0; /* values to use if var2 is zero */
9709 : 99378 : firstdigit2 = 0;
9710 [ + + ]: 99378 : for (i = 0; i < var2->ndigits; i++)
9711 : : {
9712 : 99345 : firstdigit2 = var2->digits[i];
9713 [ + - ]: 99345 : if (firstdigit2 != 0)
9714 : : {
9715 : 99345 : weight2 = var2->weight - i;
9716 : 99345 : break;
9717 : : }
9718 : : }
9719 : :
9720 : : /*
9721 : : * Estimate weight of quotient. If the two first digits are equal, we
9722 : : * can't be sure, but assume that var1 is less than var2.
9723 : : */
9724 : 99378 : qweight = weight1 - weight2;
9725 [ + + ]: 99378 : if (firstdigit1 <= firstdigit2)
9726 : 88547 : qweight--;
9727 : :
9728 : : /* Select result scale */
8446 9729 : 99378 : rscale = NUMERIC_MIN_SIG_DIGITS - qweight * DEC_DIGITS;
9730 : 99378 : rscale = Max(rscale, var1->dscale);
9731 : 99378 : rscale = Max(rscale, var2->dscale);
9732 : 99378 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
9733 : 99378 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
9734 : :
9735 : 99378 : return rscale;
9736 : : }
9737 : :
9738 : :
9739 : : /*
9740 : : * mod_var() -
9741 : : *
9742 : : * Calculate the modulo of two numerics at variable level
9743 : : */
9744 : : static void
3159 andres@anarazel.de 9745 : 275349 : mod_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
9746 : : {
9747 : : NumericVar tmp;
9748 : :
9988 JanWieck@Yahoo.com 9749 : 275349 : init_var(&tmp);
9750 : :
9751 : : /* ---------
9752 : : * We do this using the equation
9753 : : * mod(x,y) = x - trunc(x/y)*y
9754 : : * div_var can be persuaded to give us trunc(x/y) directly.
9755 : : * ----------
9756 : : */
578 dean.a.rasheed@gmail 9757 : 275349 : div_var(var1, var2, &tmp, 0, false, true);
9758 : :
6605 tgl@sss.pgh.pa.us 9759 : 275349 : mul_var(var2, &tmp, &tmp, var2->dscale);
9760 : :
9988 JanWieck@Yahoo.com 9761 : 275349 : sub_var(var1, &tmp, result);
9762 : :
9763 : 275349 : free_var(&tmp);
9764 : 275349 : }
9765 : :
9766 : :
9767 : : /*
9768 : : * div_mod_var() -
9769 : : *
9770 : : * Calculate the truncated integer quotient and numeric remainder of two
9771 : : * numeric variables. The remainder is precise to var2's dscale.
9772 : : */
9773 : : static void
2229 dean.a.rasheed@gmail 9774 : 3295 : div_mod_var(const NumericVar *var1, const NumericVar *var2,
9775 : : NumericVar *quot, NumericVar *rem)
9776 : : {
9777 : : NumericVar q;
9778 : : NumericVar r;
9779 : :
9780 : 3295 : init_var(&q);
9781 : 3295 : init_var(&r);
9782 : :
9783 : : /*
9784 : : * Use div_var() with exact = false to get an initial estimate for the
9785 : : * integer quotient (truncated towards zero). This might be slightly
9786 : : * inaccurate, but we correct it below.
9787 : : */
578 9788 : 3295 : div_var(var1, var2, &q, 0, false, false);
9789 : :
9790 : : /* Compute initial estimate of remainder using the quotient estimate. */
2229 9791 : 3295 : mul_var(var2, &q, &r, var2->dscale);
9792 : 3295 : sub_var(var1, &r, &r);
9793 : :
9794 : : /*
9795 : : * Adjust the results if necessary --- the remainder should have the same
9796 : : * sign as var1, and its absolute value should be less than the absolute
9797 : : * value of var2.
9798 : : */
9799 [ + - - + ]: 3295 : while (r.ndigits != 0 && r.sign != var1->sign)
9800 : : {
9801 : : /* The absolute value of the quotient is too large */
2229 dean.a.rasheed@gmail 9802 [ # # ]:UBC 0 : if (var1->sign == var2->sign)
9803 : : {
9804 : 0 : sub_var(&q, &const_one, &q);
9805 : 0 : add_var(&r, var2, &r);
9806 : : }
9807 : : else
9808 : : {
9809 : 0 : add_var(&q, &const_one, &q);
9810 : 0 : sub_var(&r, var2, &r);
9811 : : }
9812 : : }
9813 : :
2229 dean.a.rasheed@gmail 9814 [ - + ]:CBC 3295 : while (cmp_abs(&r, var2) >= 0)
9815 : : {
9816 : : /* The absolute value of the quotient is too small */
2229 dean.a.rasheed@gmail 9817 [ # # ]:UBC 0 : if (var1->sign == var2->sign)
9818 : : {
9819 : 0 : add_var(&q, &const_one, &q);
9820 : 0 : sub_var(&r, var2, &r);
9821 : : }
9822 : : else
9823 : : {
9824 : 0 : sub_var(&q, &const_one, &q);
9825 : 0 : add_var(&r, var2, &r);
9826 : : }
9827 : : }
9828 : :
2229 dean.a.rasheed@gmail 9829 :CBC 3295 : set_var_from_var(&q, quot);
9830 : 3295 : set_var_from_var(&r, rem);
9831 : :
9832 : 3295 : free_var(&q);
9833 : 3295 : free_var(&r);
9834 : 3295 : }
9835 : :
9836 : :
9837 : : /*
9838 : : * ceil_var() -
9839 : : *
9840 : : * Return the smallest integer greater than or equal to the argument
9841 : : * on variable level
9842 : : */
9843 : : static void
3159 andres@anarazel.de 9844 : 136 : ceil_var(const NumericVar *var, NumericVar *result)
9845 : : {
9846 : : NumericVar tmp;
9847 : :
9988 JanWieck@Yahoo.com 9848 : 136 : init_var(&tmp);
9849 : 136 : set_var_from_var(var, &tmp);
9850 : :
8446 tgl@sss.pgh.pa.us 9851 : 136 : trunc_var(&tmp, 0);
9852 : :
9853 [ + + + + ]: 136 : if (var->sign == NUMERIC_POS && cmp_var(var, &tmp) != 0)
9988 JanWieck@Yahoo.com 9854 : 40 : add_var(&tmp, &const_one, &tmp);
9855 : :
9856 : 136 : set_var_from_var(&tmp, result);
9857 : 136 : free_var(&tmp);
9858 : 136 : }
9859 : :
9860 : :
9861 : : /*
9862 : : * floor_var() -
9863 : : *
9864 : : * Return the largest integer equal to or less than the argument
9865 : : * on variable level
9866 : : */
9867 : : static void
3159 andres@anarazel.de 9868 : 72 : floor_var(const NumericVar *var, NumericVar *result)
9869 : : {
9870 : : NumericVar tmp;
9871 : :
9988 JanWieck@Yahoo.com 9872 : 72 : init_var(&tmp);
9873 : 72 : set_var_from_var(var, &tmp);
9874 : :
8446 tgl@sss.pgh.pa.us 9875 : 72 : trunc_var(&tmp, 0);
9876 : :
9877 [ + + + + ]: 72 : if (var->sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0)
9988 JanWieck@Yahoo.com 9878 : 20 : sub_var(&tmp, &const_one, &tmp);
9879 : :
9880 : 72 : set_var_from_var(&tmp, result);
9881 : 72 : free_var(&tmp);
9882 : 72 : }
9883 : :
9884 : :
9885 : : /*
9886 : : * gcd_var() -
9887 : : *
9888 : : * Calculate the greatest common divisor of two numerics at variable level
9889 : : */
9890 : : static void
2292 dean.a.rasheed@gmail 9891 : 148 : gcd_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
9892 : : {
9893 : : int res_dscale;
9894 : : int cmp;
9895 : : NumericVar tmp_arg;
9896 : : NumericVar mod;
9897 : :
9898 : 148 : res_dscale = Max(var1->dscale, var2->dscale);
9899 : :
9900 : : /*
9901 : : * Arrange for var1 to be the number with the greater absolute value.
9902 : : *
9903 : : * This would happen automatically in the loop below, but avoids an
9904 : : * expensive modulo operation.
9905 : : */
9906 : 148 : cmp = cmp_abs(var1, var2);
9907 [ + + ]: 148 : if (cmp < 0)
9908 : : {
9909 : 56 : const NumericVar *tmp = var1;
9910 : :
9911 : 56 : var1 = var2;
9912 : 56 : var2 = tmp;
9913 : : }
9914 : :
9915 : : /*
9916 : : * Also avoid the taking the modulo if the inputs have the same absolute
9917 : : * value, or if the smaller input is zero.
9918 : : */
9919 [ + + + + ]: 148 : if (cmp == 0 || var2->ndigits == 0)
9920 : : {
9921 : 48 : set_var_from_var(var1, result);
9922 : 48 : result->sign = NUMERIC_POS;
9923 : 48 : result->dscale = res_dscale;
9924 : 48 : return;
9925 : : }
9926 : :
9927 : 100 : init_var(&tmp_arg);
9928 : 100 : init_var(&mod);
9929 : :
9930 : : /* Use the Euclidean algorithm to find the GCD */
9931 : 100 : set_var_from_var(var1, &tmp_arg);
9932 : 100 : set_var_from_var(var2, result);
9933 : :
9934 : : for (;;)
9935 : : {
9936 : : /* this loop can take a while, so allow it to be interrupted */
9937 [ - + ]: 392 : CHECK_FOR_INTERRUPTS();
9938 : :
9939 : 392 : mod_var(&tmp_arg, result, &mod);
9940 [ + + ]: 392 : if (mod.ndigits == 0)
9941 : 100 : break;
9942 : 292 : set_var_from_var(result, &tmp_arg);
9943 : 292 : set_var_from_var(&mod, result);
9944 : : }
9945 : 100 : result->sign = NUMERIC_POS;
9946 : 100 : result->dscale = res_dscale;
9947 : :
9948 : 100 : free_var(&tmp_arg);
9949 : 100 : free_var(&mod);
9950 : : }
9951 : :
9952 : :
9953 : : /*
9954 : : * sqrt_var() -
9955 : : *
9956 : : * Compute the square root of x using the Karatsuba Square Root algorithm.
9957 : : * NOTE: we allow rscale < 0 here, implying rounding before the decimal
9958 : : * point.
9959 : : */
9960 : : static void
3159 andres@anarazel.de 9961 : 3048 : sqrt_var(const NumericVar *arg, NumericVar *result, int rscale)
9962 : : {
9963 : : int stat;
9964 : : int res_weight;
9965 : : int res_ndigits;
9966 : : int src_ndigits;
9967 : : int step;
9968 : : int ndigits[32];
9969 : : int blen;
9970 : : int64 arg_int64;
9971 : : int src_idx;
9972 : : int64 s_int64;
9973 : : int64 r_int64;
9974 : : NumericVar s_var;
9975 : : NumericVar r_var;
9976 : : NumericVar a0_var;
9977 : : NumericVar a1_var;
9978 : : NumericVar q_var;
9979 : : NumericVar u_var;
9980 : :
9988 JanWieck@Yahoo.com 9981 : 3048 : stat = cmp_var(arg, &const_zero);
9982 [ + + ]: 3048 : if (stat == 0)
9983 : : {
8446 tgl@sss.pgh.pa.us 9984 : 12 : zero_var(result);
9985 : 12 : result->dscale = rscale;
9988 JanWieck@Yahoo.com 9986 : 12 : return;
9987 : : }
9988 : :
9989 : : /*
9990 : : * SQL2003 defines sqrt() in terms of power, so we need to emit the right
9991 : : * SQLSTATE error code if the operand is negative.
9992 : : */
9993 [ + + ]: 3036 : if (stat < 0)
8318 tgl@sss.pgh.pa.us 9994 [ + - ]: 4 : ereport(ERROR,
9995 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
9996 : : errmsg("cannot take square root of a negative number")));
9997 : :
2229 dean.a.rasheed@gmail 9998 : 3032 : init_var(&s_var);
9999 : 3032 : init_var(&r_var);
10000 : 3032 : init_var(&a0_var);
10001 : 3032 : init_var(&a1_var);
10002 : 3032 : init_var(&q_var);
10003 : 3032 : init_var(&u_var);
10004 : :
10005 : : /*
10006 : : * The result weight is half the input weight, rounded towards minus
10007 : : * infinity --- res_weight = floor(arg->weight / 2).
10008 : : */
10009 [ + + ]: 3032 : if (arg->weight >= 0)
10010 : 2761 : res_weight = arg->weight / 2;
10011 : : else
10012 : 271 : res_weight = -((-arg->weight - 1) / 2 + 1);
10013 : :
10014 : : /*
10015 : : * Number of NBASE digits to compute. To ensure correct rounding, compute
10016 : : * at least 1 extra decimal digit. We explicitly allow rscale to be
10017 : : * negative here, but must always compute at least 1 NBASE digit. Thus
10018 : : * res_ndigits = res_weight + 1 + ceil((rscale + 1) / DEC_DIGITS) or 1.
10019 : : */
10020 [ + - ]: 3032 : if (rscale + 1 >= 0)
10021 : 3032 : res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS) / DEC_DIGITS;
10022 : : else
2229 dean.a.rasheed@gmail 10023 :UBC 0 : res_ndigits = res_weight + 1 - (-rscale - 1) / DEC_DIGITS;
2229 dean.a.rasheed@gmail 10024 :CBC 3032 : res_ndigits = Max(res_ndigits, 1);
10025 : :
10026 : : /*
10027 : : * Number of source NBASE digits logically required to produce a result
10028 : : * with this precision --- every digit before the decimal point, plus 2
10029 : : * for each result digit after the decimal point (or minus 2 for each
10030 : : * result digit we round before the decimal point).
10031 : : */
10032 : 3032 : src_ndigits = arg->weight + 1 + (res_ndigits - res_weight - 1) * 2;
10033 : 3032 : src_ndigits = Max(src_ndigits, 1);
10034 : :
10035 : : /* ----------
10036 : : * From this point on, we treat the input and the result as integers and
10037 : : * compute the integer square root and remainder using the Karatsuba
10038 : : * Square Root algorithm, which may be written recursively as follows:
10039 : : *
10040 : : * SqrtRem(n = a3*b^3 + a2*b^2 + a1*b + a0):
10041 : : * [ for some base b, and coefficients a0,a1,a2,a3 chosen so that
10042 : : * 0 <= a0,a1,a2 < b and a3 >= b/4 ]
10043 : : * Let (s,r) = SqrtRem(a3*b + a2)
10044 : : * Let (q,u) = DivRem(r*b + a1, 2*s)
10045 : : * Let s = s*b + q
10046 : : * Let r = u*b + a0 - q^2
10047 : : * If r < 0 Then
10048 : : * Let r = r + s
10049 : : * Let s = s - 1
10050 : : * Let r = r + s
10051 : : * Return (s,r)
10052 : : *
10053 : : * See "Karatsuba Square Root", Paul Zimmermann, INRIA Research Report
10054 : : * RR-3805, November 1999. At the time of writing this was available
10055 : : * on the net at <https://hal.inria.fr/inria-00072854>.
10056 : : *
10057 : : * The way to read the assumption "n = a3*b^3 + a2*b^2 + a1*b + a0" is
10058 : : * "choose a base b such that n requires at least four base-b digits to
10059 : : * express; then those digits are a3,a2,a1,a0, with a3 possibly larger
10060 : : * than b". For optimal performance, b should have approximately a
10061 : : * quarter the number of digits in the input, so that the outer square
10062 : : * root computes roughly twice as many digits as the inner one. For
10063 : : * simplicity, we choose b = NBASE^blen, an integer power of NBASE.
10064 : : *
10065 : : * We implement the algorithm iteratively rather than recursively, to
10066 : : * allow the working variables to be reused. With this approach, each
10067 : : * digit of the input is read precisely once --- src_idx tracks the number
10068 : : * of input digits used so far.
10069 : : *
10070 : : * The array ndigits[] holds the number of NBASE digits of the input that
10071 : : * will have been used at the end of each iteration, which roughly doubles
10072 : : * each time. Note that the array elements are stored in reverse order,
10073 : : * so if the final iteration requires src_ndigits = 37 input digits, the
10074 : : * array will contain [37,19,11,7,5,3], and we would start by computing
10075 : : * the square root of the 3 most significant NBASE digits.
10076 : : *
10077 : : * In each iteration, we choose blen to be the largest integer for which
10078 : : * the input number has a3 >= b/4, when written in the form above. In
10079 : : * general, this means blen = src_ndigits / 4 (truncated), but if
10080 : : * src_ndigits is a multiple of 4, that might lead to the coefficient a3
10081 : : * being less than b/4 (if the first input digit is less than NBASE/4), in
10082 : : * which case we choose blen = src_ndigits / 4 - 1. The number of digits
10083 : : * in the inner square root is then src_ndigits - 2*blen. So, for
10084 : : * example, if we have src_ndigits = 26 initially, the array ndigits[]
10085 : : * will be either [26,14,8,4] or [26,14,8,6,4], depending on the size of
10086 : : * the first input digit.
10087 : : *
10088 : : * Additionally, we can put an upper bound on the number of steps required
10089 : : * as follows --- suppose that the number of source digits is an n-bit
10090 : : * number in the range [2^(n-1), 2^n-1], then blen will be in the range
10091 : : * [2^(n-3)-1, 2^(n-2)-1] and the number of digits in the inner square
10092 : : * root will be in the range [2^(n-2), 2^(n-1)+1]. In the next step, blen
10093 : : * will be in the range [2^(n-4)-1, 2^(n-3)] and the number of digits in
10094 : : * the next inner square root will be in the range [2^(n-3), 2^(n-2)+1].
10095 : : * This pattern repeats, and in the worst case the array ndigits[] will
10096 : : * contain [2^n-1, 2^(n-1)+1, 2^(n-2)+1, ... 9, 5, 3], and the computation
10097 : : * will require n steps. Therefore, since all digit array sizes are
10098 : : * signed 32-bit integers, the number of steps required is guaranteed to
10099 : : * be less than 32.
10100 : : * ----------
10101 : : */
10102 : 3032 : step = 0;
10103 [ + + ]: 14531 : while ((ndigits[step] = src_ndigits) > 4)
10104 : : {
10105 : : /* Choose b so that a3 >= b/4, as described above */
10106 : 11499 : blen = src_ndigits / 4;
10107 [ + + + + ]: 11499 : if (blen * 4 == src_ndigits && arg->digits[0] < NBASE / 4)
10108 : 259 : blen--;
10109 : :
10110 : : /* Number of digits in the next step (inner square root) */
10111 : 11499 : src_ndigits -= 2 * blen;
10112 : 11499 : step++;
10113 : : }
10114 : :
10115 : : /*
10116 : : * First iteration (innermost square root and remainder):
10117 : : *
10118 : : * Here src_ndigits <= 4, and the input fits in an int64. Its square root
10119 : : * has at most 9 decimal digits, so estimate it using double precision
10120 : : * arithmetic, which will in fact almost certainly return the correct
10121 : : * result with no further correction required.
10122 : : */
10123 : 3032 : arg_int64 = arg->digits[0];
10124 [ + + ]: 9695 : for (src_idx = 1; src_idx < src_ndigits; src_idx++)
10125 : : {
10126 : 6663 : arg_int64 *= NBASE;
10127 [ + + ]: 6663 : if (src_idx < arg->ndigits)
10128 : 5647 : arg_int64 += arg->digits[src_idx];
10129 : : }
10130 : :
10131 : 3032 : s_int64 = (int64) sqrt((double) arg_int64);
10132 : 3032 : r_int64 = arg_int64 - s_int64 * s_int64;
10133 : :
10134 : : /*
10135 : : * Use Newton's method to correct the result, if necessary.
10136 : : *
10137 : : * This uses integer division with truncation to compute the truncated
10138 : : * integer square root by iterating using the formula x -> (x + n/x) / 2.
10139 : : * This is known to converge to isqrt(n), unless n+1 is a perfect square.
10140 : : * If n+1 is a perfect square, the sequence will oscillate between the two
10141 : : * values isqrt(n) and isqrt(n)+1, so we can be assured of convergence by
10142 : : * checking the remainder.
10143 : : */
10144 [ - + - + ]: 3032 : while (r_int64 < 0 || r_int64 > 2 * s_int64)
10145 : : {
2229 dean.a.rasheed@gmail 10146 :UBC 0 : s_int64 = (s_int64 + arg_int64 / s_int64) / 2;
10147 : 0 : r_int64 = arg_int64 - s_int64 * s_int64;
10148 : : }
10149 : :
10150 : : /*
10151 : : * Iterations with src_ndigits <= 8:
10152 : : *
10153 : : * The next 1 or 2 iterations compute larger (outer) square roots with
10154 : : * src_ndigits <= 8, so the result still fits in an int64 (even though the
10155 : : * input no longer does) and we can continue to compute using int64
10156 : : * variables to avoid more expensive numeric computations.
10157 : : *
10158 : : * It is fairly easy to see that there is no risk of the intermediate
10159 : : * values below overflowing 64-bit integers. In the worst case, the
10160 : : * previous iteration will have computed a 3-digit square root (of a
10161 : : * 6-digit input less than NBASE^6 / 4), so at the start of this
10162 : : * iteration, s will be less than NBASE^3 / 2 = 10^12 / 2, and r will be
10163 : : * less than 10^12. In this case, blen will be 1, so numer will be less
10164 : : * than 10^17, and denom will be less than 10^12 (and hence u will also be
10165 : : * less than 10^12). Finally, since q^2 = u*b + a0 - r, we can also be
10166 : : * sure that q^2 < 10^17. Therefore all these quantities fit comfortably
10167 : : * in 64-bit integers.
10168 : : */
2229 dean.a.rasheed@gmail 10169 :CBC 3032 : step--;
10170 [ + - + + ]: 7672 : while (step >= 0 && (src_ndigits = ndigits[step]) <= 8)
10171 : : {
10172 : : int b;
10173 : : int a0;
10174 : : int a1;
10175 : : int i;
10176 : : int64 numer;
10177 : : int64 denom;
10178 : : int64 q;
10179 : : int64 u;
10180 : :
10181 : 4640 : blen = (src_ndigits - src_idx) / 2;
10182 : :
10183 : : /* Extract a1 and a0, and compute b */
10184 : 4640 : a0 = 0;
10185 : 4640 : a1 = 0;
10186 : 4640 : b = 1;
10187 : :
10188 [ + + ]: 9399 : for (i = 0; i < blen; i++, src_idx++)
10189 : : {
10190 : 4759 : b *= NBASE;
10191 : 4759 : a1 *= NBASE;
10192 [ + + ]: 4759 : if (src_idx < arg->ndigits)
10193 : 3532 : a1 += arg->digits[src_idx];
10194 : : }
10195 : :
10196 [ + + ]: 9399 : for (i = 0; i < blen; i++, src_idx++)
10197 : : {
10198 : 4759 : a0 *= NBASE;
10199 [ + + ]: 4759 : if (src_idx < arg->ndigits)
10200 : 3420 : a0 += arg->digits[src_idx];
10201 : : }
10202 : :
10203 : : /* Compute (q,u) = DivRem(r*b + a1, 2*s) */
10204 : 4640 : numer = r_int64 * b + a1;
10205 : 4640 : denom = 2 * s_int64;
10206 : 4640 : q = numer / denom;
10207 : 4640 : u = numer - q * denom;
10208 : :
10209 : : /* Compute s = s*b + q and r = u*b + a0 - q^2 */
10210 : 4640 : s_int64 = s_int64 * b + q;
10211 : 4640 : r_int64 = u * b + a0 - q * q;
10212 : :
10213 [ + + ]: 4640 : if (r_int64 < 0)
10214 : : {
10215 : : /* s is too large by 1; set r += s, s--, r += s */
10216 : 161 : r_int64 += s_int64;
10217 : 161 : s_int64--;
10218 : 161 : r_int64 += s_int64;
10219 : : }
10220 : :
10221 [ - + ]: 4640 : Assert(src_idx == src_ndigits); /* All input digits consumed */
10222 : 4640 : step--;
10223 : : }
10224 : :
10225 : : /*
10226 : : * On platforms with 128-bit integer support, we can further delay the
10227 : : * need to use numeric variables.
10228 : : */
10229 : : #ifdef HAVE_INT128
10230 [ + - ]: 3032 : if (step >= 0)
10231 : : {
10232 : : int128 s_int128;
10233 : : int128 r_int128;
10234 : :
10235 : 3032 : s_int128 = s_int64;
10236 : 3032 : r_int128 = r_int64;
10237 : :
10238 : : /*
10239 : : * Iterations with src_ndigits <= 16:
10240 : : *
10241 : : * The result fits in an int128 (even though the input doesn't) so we
10242 : : * use int128 variables to avoid more expensive numeric computations.
10243 : : */
10244 [ + + + + ]: 6596 : while (step >= 0 && (src_ndigits = ndigits[step]) <= 16)
10245 : : {
10246 : : int64 b;
10247 : : int64 a0;
10248 : : int64 a1;
10249 : : int64 i;
10250 : : int128 numer;
10251 : : int128 denom;
10252 : : int128 q;
10253 : : int128 u;
10254 : :
10255 : 3564 : blen = (src_ndigits - src_idx) / 2;
10256 : :
10257 : : /* Extract a1 and a0, and compute b */
10258 : 3564 : a0 = 0;
10259 : 3564 : a1 = 0;
10260 : 3564 : b = 1;
10261 : :
10262 [ + + ]: 11796 : for (i = 0; i < blen; i++, src_idx++)
10263 : : {
10264 : 8232 : b *= NBASE;
10265 : 8232 : a1 *= NBASE;
10266 [ + + ]: 8232 : if (src_idx < arg->ndigits)
10267 : 4947 : a1 += arg->digits[src_idx];
10268 : : }
10269 : :
10270 [ + + ]: 11796 : for (i = 0; i < blen; i++, src_idx++)
10271 : : {
10272 : 8232 : a0 *= NBASE;
10273 [ + + ]: 8232 : if (src_idx < arg->ndigits)
10274 : 3407 : a0 += arg->digits[src_idx];
10275 : : }
10276 : :
10277 : : /* Compute (q,u) = DivRem(r*b + a1, 2*s) */
10278 : 3564 : numer = r_int128 * b + a1;
10279 : 3564 : denom = 2 * s_int128;
10280 : 3564 : q = numer / denom;
10281 : 3564 : u = numer - q * denom;
10282 : :
10283 : : /* Compute s = s*b + q and r = u*b + a0 - q^2 */
10284 : 3564 : s_int128 = s_int128 * b + q;
10285 : 3564 : r_int128 = u * b + a0 - q * q;
10286 : :
10287 [ + + ]: 3564 : if (r_int128 < 0)
10288 : : {
10289 : : /* s is too large by 1; set r += s, s--, r += s */
10290 : 146 : r_int128 += s_int128;
10291 : 146 : s_int128--;
10292 : 146 : r_int128 += s_int128;
10293 : : }
10294 : :
10295 [ - + ]: 3564 : Assert(src_idx == src_ndigits); /* All input digits consumed */
10296 : 3564 : step--;
10297 : : }
10298 : :
10299 : : /*
10300 : : * All remaining iterations require numeric variables. Convert the
10301 : : * integer values to NumericVar and continue. Note that in the final
10302 : : * iteration we don't need the remainder, so we can save a few cycles
10303 : : * there by not fully computing it.
10304 : : */
10305 : 3032 : int128_to_numericvar(s_int128, &s_var);
10306 [ + + ]: 3032 : if (step >= 0)
10307 : 2008 : int128_to_numericvar(r_int128, &r_var);
10308 : : }
10309 : : else
10310 : : {
2229 dean.a.rasheed@gmail 10311 :UBC 0 : int64_to_numericvar(s_int64, &s_var);
10312 : : /* step < 0, so we certainly don't need r */
10313 : : }
10314 : : #else /* !HAVE_INT128 */
10315 : : int64_to_numericvar(s_int64, &s_var);
10316 : : if (step >= 0)
10317 : : int64_to_numericvar(r_int64, &r_var);
10318 : : #endif /* HAVE_INT128 */
10319 : :
10320 : : /*
10321 : : * The remaining iterations with src_ndigits > 8 (or 16, if have int128)
10322 : : * use numeric variables.
10323 : : */
2229 dean.a.rasheed@gmail 10324 [ + + ]:CBC 6327 : while (step >= 0)
10325 : : {
10326 : : int tmp_len;
10327 : :
10328 : 3295 : src_ndigits = ndigits[step];
10329 : 3295 : blen = (src_ndigits - src_idx) / 2;
10330 : :
10331 : : /* Extract a1 and a0 */
10332 [ + + ]: 3295 : if (src_idx < arg->ndigits)
10333 : : {
10334 : 1088 : tmp_len = Min(blen, arg->ndigits - src_idx);
10335 : 1088 : alloc_var(&a1_var, tmp_len);
10336 : 1088 : memcpy(a1_var.digits, arg->digits + src_idx,
10337 : : tmp_len * sizeof(NumericDigit));
10338 : 1088 : a1_var.weight = blen - 1;
10339 : 1088 : a1_var.sign = NUMERIC_POS;
10340 : 1088 : a1_var.dscale = 0;
10341 : 1088 : strip_var(&a1_var);
10342 : : }
10343 : : else
10344 : : {
10345 : 2207 : zero_var(&a1_var);
10346 : 2207 : a1_var.dscale = 0;
10347 : : }
10348 : 3295 : src_idx += blen;
10349 : :
10350 [ + + ]: 3295 : if (src_idx < arg->ndigits)
10351 : : {
10352 : 1088 : tmp_len = Min(blen, arg->ndigits - src_idx);
10353 : 1088 : alloc_var(&a0_var, tmp_len);
10354 : 1088 : memcpy(a0_var.digits, arg->digits + src_idx,
10355 : : tmp_len * sizeof(NumericDigit));
10356 : 1088 : a0_var.weight = blen - 1;
10357 : 1088 : a0_var.sign = NUMERIC_POS;
10358 : 1088 : a0_var.dscale = 0;
10359 : 1088 : strip_var(&a0_var);
10360 : : }
10361 : : else
10362 : : {
10363 : 2207 : zero_var(&a0_var);
10364 : 2207 : a0_var.dscale = 0;
10365 : : }
10366 : 3295 : src_idx += blen;
10367 : :
10368 : : /* Compute (q,u) = DivRem(r*b + a1, 2*s) */
10369 : 3295 : set_var_from_var(&r_var, &q_var);
10370 : 3295 : q_var.weight += blen;
10371 : 3295 : add_var(&q_var, &a1_var, &q_var);
10372 : 3295 : add_var(&s_var, &s_var, &u_var);
10373 : 3295 : div_mod_var(&q_var, &u_var, &q_var, &u_var);
10374 : :
10375 : : /* Compute s = s*b + q */
10376 : 3295 : s_var.weight += blen;
10377 : 3295 : add_var(&s_var, &q_var, &s_var);
10378 : :
10379 : : /*
10380 : : * Compute r = u*b + a0 - q^2.
10381 : : *
10382 : : * In the final iteration, we don't actually need r; we just need to
10383 : : * know whether it is negative, so that we know whether to adjust s.
10384 : : * So instead of the final subtraction we can just compare.
10385 : : */
10386 : 3295 : u_var.weight += blen;
10387 : 3295 : add_var(&u_var, &a0_var, &u_var);
10388 : 3295 : mul_var(&q_var, &q_var, &q_var, 0);
10389 : :
10390 [ + + ]: 3295 : if (step > 0)
10391 : : {
10392 : : /* Need r for later iterations */
10393 : 1287 : sub_var(&u_var, &q_var, &r_var);
10394 [ + + ]: 1287 : if (r_var.sign == NUMERIC_NEG)
10395 : : {
10396 : : /* s is too large by 1; set r += s, s--, r += s */
10397 : 85 : add_var(&r_var, &s_var, &r_var);
10398 : 85 : sub_var(&s_var, &const_one, &s_var);
10399 : 85 : add_var(&r_var, &s_var, &r_var);
10400 : : }
10401 : : }
10402 : : else
10403 : : {
10404 : : /* Don't need r anymore, except to test if s is too large by 1 */
10405 [ + + ]: 2008 : if (cmp_var(&u_var, &q_var) < 0)
10406 : 27 : sub_var(&s_var, &const_one, &s_var);
10407 : : }
10408 : :
10409 [ - + ]: 3295 : Assert(src_idx == src_ndigits); /* All input digits consumed */
10410 : 3295 : step--;
10411 : : }
10412 : :
10413 : : /*
10414 : : * Construct the final result, rounding it to the requested precision.
10415 : : */
10416 : 3032 : set_var_from_var(&s_var, result);
10417 : 3032 : result->weight = res_weight;
10418 : 3032 : result->sign = NUMERIC_POS;
10419 : :
10420 : : /* Round to target rscale (and set result->dscale) */
8446 tgl@sss.pgh.pa.us 10421 : 3032 : round_var(result, rscale);
10422 : :
10423 : : /* Strip leading and trailing zeroes */
2229 dean.a.rasheed@gmail 10424 : 3032 : strip_var(result);
10425 : :
10426 : 3032 : free_var(&s_var);
10427 : 3032 : free_var(&r_var);
10428 : 3032 : free_var(&a0_var);
10429 : 3032 : free_var(&a1_var);
10430 : 3032 : free_var(&q_var);
10431 : 3032 : free_var(&u_var);
10432 : : }
10433 : :
10434 : :
10435 : : /*
10436 : : * exp_var() -
10437 : : *
10438 : : * Raise e to the power of x, computed to rscale fractional digits
10439 : : */
10440 : : static void
3159 andres@anarazel.de 10441 : 139 : exp_var(const NumericVar *arg, NumericVar *result, int rscale)
10442 : : {
10443 : : NumericVar x;
10444 : : NumericVar elem;
10445 : : int ni;
10446 : : double val;
10447 : : int dweight;
10448 : : int ndiv2;
10449 : : int sig_digits;
10450 : : int local_rscale;
10451 : :
9988 JanWieck@Yahoo.com 10452 : 139 : init_var(&x);
3825 tgl@sss.pgh.pa.us 10453 : 139 : init_var(&elem);
10454 : :
9988 JanWieck@Yahoo.com 10455 : 139 : set_var_from_var(arg, &x);
10456 : :
10457 : : /*
10458 : : * Estimate the dweight of the result using floating point arithmetic, so
10459 : : * that we can choose an appropriate local rscale for the calculation.
10460 : : */
3825 tgl@sss.pgh.pa.us 10461 : 139 : val = numericvar_to_double_no_overflow(&x);
10462 : :
10463 : : /* Guard against overflow/underflow */
10464 : : /* If you change this limit, see also power_var()'s limit */
1306 peter@eisentraut.org 10465 [ + + ]: 139 : if (fabs(val) >= NUMERIC_MAX_RESULT_SCALE * 3)
10466 : : {
1739 dean.a.rasheed@gmail 10467 [ - + ]: 5 : if (val > 0)
1739 dean.a.rasheed@gmail 10468 [ # # ]:UBC 0 : ereport(ERROR,
10469 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
10470 : : errmsg("value overflows numeric format")));
1739 dean.a.rasheed@gmail 10471 :CBC 5 : zero_var(result);
10472 : 5 : result->dscale = rscale;
10473 : 5 : return;
10474 : : }
10475 : :
10476 : : /* decimal weight = log10(e^x) = x * log10(e) */
3825 tgl@sss.pgh.pa.us 10477 : 134 : dweight = (int) (val * 0.434294481903252);
10478 : :
10479 : : /*
10480 : : * Reduce x to the range -0.01 <= x <= 0.01 (approximately) by dividing by
10481 : : * 2^ndiv2, to improve the convergence rate of the Taylor series.
10482 : : *
10483 : : * Note that the overflow check above ensures that fabs(x) < 6000, which
10484 : : * means that ndiv2 <= 20 here.
10485 : : */
1306 peter@eisentraut.org 10486 [ + + ]: 134 : if (fabs(val) > 0.01)
10487 : : {
3825 tgl@sss.pgh.pa.us 10488 : 110 : ndiv2 = 1;
10489 : 110 : val /= 2;
10490 : :
1306 peter@eisentraut.org 10491 [ + + ]: 1402 : while (fabs(val) > 0.01)
10492 : : {
3825 tgl@sss.pgh.pa.us 10493 : 1292 : ndiv2++;
10494 : 1292 : val /= 2;
10495 : : }
10496 : :
10497 : 110 : local_rscale = x.dscale + ndiv2;
1528 dean.a.rasheed@gmail 10498 : 110 : div_var_int(&x, 1 << ndiv2, 0, &x, local_rscale, true);
10499 : : }
10500 : : else
3825 tgl@sss.pgh.pa.us 10501 : 24 : ndiv2 = 0;
10502 : :
10503 : : /*
10504 : : * Set the scale for the Taylor series expansion. The final result has
10505 : : * (dweight + rscale + 1) significant digits. In addition, we have to
10506 : : * raise the Taylor series result to the power 2^ndiv2, which introduces
10507 : : * an error of up to around log10(2^ndiv2) digits, so work with this many
10508 : : * extra digits of precision (plus a few more for good measure).
10509 : : */
10510 : 134 : sig_digits = 1 + dweight + rscale + (int) (ndiv2 * 0.301029995663981);
10511 : 134 : sig_digits = Max(sig_digits, 0) + 8;
10512 : :
10513 : 134 : local_rscale = sig_digits - 1;
10514 : :
10515 : : /*
10516 : : * Use the Taylor series
10517 : : *
10518 : : * exp(x) = 1 + x + x^2/2! + x^3/3! + ...
10519 : : *
10520 : : * Given the limited range of x, this should converge reasonably quickly.
10521 : : * We run the series until the terms fall below the local_rscale limit.
10522 : : */
9988 JanWieck@Yahoo.com 10523 : 134 : add_var(&const_one, &x, result);
10524 : :
3825 tgl@sss.pgh.pa.us 10525 : 134 : mul_var(&x, &x, &elem, local_rscale);
1528 dean.a.rasheed@gmail 10526 : 134 : ni = 2;
10527 : 134 : div_var_int(&elem, ni, 0, &elem, local_rscale, true);
10528 : :
3825 tgl@sss.pgh.pa.us 10529 [ + + ]: 3639 : while (elem.ndigits != 0)
10530 : : {
9988 JanWieck@Yahoo.com 10531 : 3505 : add_var(result, &elem, result);
10532 : :
3825 tgl@sss.pgh.pa.us 10533 : 3505 : mul_var(&elem, &x, &elem, local_rscale);
1528 dean.a.rasheed@gmail 10534 : 3505 : ni++;
10535 : 3505 : div_var_int(&elem, ni, 0, &elem, local_rscale, true);
10536 : : }
10537 : :
10538 : : /*
10539 : : * Compensate for the argument range reduction. Since the weight of the
10540 : : * result doubles with each multiplication, we can reduce the local rscale
10541 : : * as we proceed.
10542 : : */
9988 JanWieck@Yahoo.com 10543 [ + + ]: 1536 : while (ndiv2-- > 0)
10544 : : {
3825 tgl@sss.pgh.pa.us 10545 : 1402 : local_rscale = sig_digits - result->weight * 2 * DEC_DIGITS;
10546 : 1402 : local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
8446 10547 : 1402 : mul_var(result, result, result, local_rscale);
10548 : : }
10549 : :
10550 : : /* Round to requested rscale */
3825 10551 : 134 : round_var(result, rscale);
10552 : :
9988 JanWieck@Yahoo.com 10553 : 134 : free_var(&x);
10554 : 134 : free_var(&elem);
10555 : : }
10556 : :
10557 : :
10558 : : /*
10559 : : * Estimate the dweight of the most significant decimal digit of the natural
10560 : : * logarithm of a number.
10561 : : *
10562 : : * Essentially, we're approximating log10(abs(ln(var))). This is used to
10563 : : * determine the appropriate rscale when computing natural logarithms.
10564 : : *
10565 : : * Note: many callers call this before range-checking the input. Therefore,
10566 : : * we must be robust against values that are invalid to apply ln() to.
10567 : : * We don't wish to throw an error here, so just return zero in such cases.
10568 : : */
10569 : : static int
3159 andres@anarazel.de 10570 : 534 : estimate_ln_dweight(const NumericVar *var)
10571 : : {
10572 : : int ln_dweight;
10573 : :
10574 : : /* Caller should fail on ln(negative), but for the moment return zero */
1524 tgl@sss.pgh.pa.us 10575 [ + + ]: 534 : if (var->sign != NUMERIC_POS)
10576 : 28 : return 0;
10577 : :
3825 10578 [ + + + + ]: 953 : if (cmp_var(var, &const_zero_point_nine) >= 0 &&
10579 : 447 : cmp_var(var, &const_one_point_one) <= 0)
10580 : 70 : {
10581 : : /*
10582 : : * 0.9 <= var <= 1.1
10583 : : *
10584 : : * ln(var) has a negative weight (possibly very large). To get a
10585 : : * reasonably accurate result, estimate it using ln(1+x) ~= x.
10586 : : */
10587 : : NumericVar x;
10588 : :
10589 : 70 : init_var(&x);
10590 : 70 : sub_var(var, &const_one, &x);
10591 : :
10592 [ + + ]: 70 : if (x.ndigits > 0)
10593 : : {
10594 : : /* Use weight of most significant decimal digit of x */
10595 : 35 : ln_dweight = x.weight * DEC_DIGITS + (int) log10(x.digits[0]);
10596 : : }
10597 : : else
10598 : : {
10599 : : /* x = 0. Since ln(1) = 0 exactly, we don't need extra digits */
10600 : 35 : ln_dweight = 0;
10601 : : }
10602 : :
10603 : 70 : free_var(&x);
10604 : : }
10605 : : else
10606 : : {
10607 : : /*
10608 : : * Estimate the logarithm using the first couple of digits from the
10609 : : * input number. This will give an accurate result whenever the input
10610 : : * is not too close to 1.
10611 : : */
10612 [ + + ]: 436 : if (var->ndigits > 0)
10613 : : {
10614 : : int digits;
10615 : : int dweight;
10616 : : double ln_var;
10617 : :
10618 : 408 : digits = var->digits[0];
10619 : 408 : dweight = var->weight * DEC_DIGITS;
10620 : :
10621 [ + + ]: 408 : if (var->ndigits > 1)
10622 : : {
10623 : 250 : digits = digits * NBASE + var->digits[1];
10624 : 250 : dweight -= DEC_DIGITS;
10625 : : }
10626 : :
10627 : : /*----------
10628 : : * We have var ~= digits * 10^dweight
10629 : : * so ln(var) ~= ln(digits) + dweight * ln(10)
10630 : : *----------
10631 : : */
10632 : 408 : ln_var = log((double) digits) + dweight * 2.302585092994046;
1306 peter@eisentraut.org 10633 : 408 : ln_dweight = (int) log10(fabs(ln_var));
10634 : : }
10635 : : else
10636 : : {
10637 : : /* Caller should fail on ln(0), but for the moment return zero */
3825 tgl@sss.pgh.pa.us 10638 : 28 : ln_dweight = 0;
10639 : : }
10640 : : }
10641 : :
10642 : 506 : return ln_dweight;
10643 : : }
10644 : :
10645 : :
10646 : : /*
10647 : : * ln_var() -
10648 : : *
10649 : : * Compute the natural log of x
10650 : : */
10651 : : static void
3159 andres@anarazel.de 10652 : 607 : ln_var(const NumericVar *arg, NumericVar *result, int rscale)
10653 : : {
10654 : : NumericVar x;
10655 : : NumericVar xx;
10656 : : int ni;
10657 : : NumericVar elem;
10658 : : NumericVar fact;
10659 : : int nsqrt;
10660 : : int local_rscale;
10661 : : int cmp;
10662 : :
8024 neilc@samurai.com 10663 : 607 : cmp = cmp_var(arg, &const_zero);
10664 [ + + ]: 607 : if (cmp == 0)
8318 tgl@sss.pgh.pa.us 10665 [ + - ]: 28 : ereport(ERROR,
10666 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
10667 : : errmsg("cannot take logarithm of zero")));
8024 neilc@samurai.com 10668 [ + + ]: 579 : else if (cmp < 0)
10669 [ + - ]: 24 : ereport(ERROR,
10670 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
10671 : : errmsg("cannot take logarithm of a negative number")));
10672 : :
9988 JanWieck@Yahoo.com 10673 : 555 : init_var(&x);
10674 : 555 : init_var(&xx);
10675 : 555 : init_var(&elem);
10676 : 555 : init_var(&fact);
10677 : :
10678 : 555 : set_var_from_var(arg, &x);
8446 tgl@sss.pgh.pa.us 10679 : 555 : set_var_from_var(&const_two, &fact);
10680 : :
10681 : : /*
10682 : : * Reduce input into range 0.9 < x < 1.1 with repeated sqrt() operations.
10683 : : *
10684 : : * The final logarithm will have up to around rscale+6 significant digits.
10685 : : * Each sqrt() will roughly halve the weight of x, so adjust the local
10686 : : * rscale as we work so that we keep this many significant digits at each
10687 : : * step (plus a few more for good measure).
10688 : : *
10689 : : * Note that we allow local_rscale < 0 during this input reduction
10690 : : * process, which implies rounding before the decimal point. sqrt_var()
10691 : : * explicitly supports this, and it significantly reduces the work
10692 : : * required to reduce very large inputs to the required range. Once the
10693 : : * input reduction is complete, x.weight will be 0 and its display scale
10694 : : * will be non-negative again.
10695 : : */
2256 dean.a.rasheed@gmail 10696 : 555 : nsqrt = 0;
8616 tgl@sss.pgh.pa.us 10697 [ + + ]: 826 : while (cmp_var(&x, &const_zero_point_nine) <= 0)
10698 : : {
3825 10699 : 271 : local_rscale = rscale - x.weight * DEC_DIGITS / 2 + 8;
8446 10700 : 271 : sqrt_var(&x, &x, local_rscale);
10701 : 271 : mul_var(&fact, &const_two, &fact, 0);
2256 dean.a.rasheed@gmail 10702 : 271 : nsqrt++;
10703 : : }
8616 tgl@sss.pgh.pa.us 10704 [ + + ]: 2984 : while (cmp_var(&x, &const_one_point_one) >= 0)
10705 : : {
3825 10706 : 2429 : local_rscale = rscale - x.weight * DEC_DIGITS / 2 + 8;
8446 10707 : 2429 : sqrt_var(&x, &x, local_rscale);
10708 : 2429 : mul_var(&fact, &const_two, &fact, 0);
2256 dean.a.rasheed@gmail 10709 : 2429 : nsqrt++;
10710 : : }
10711 : :
10712 : : /*
10713 : : * We use the Taylor series for 0.5 * ln((1+z)/(1-z)),
10714 : : *
10715 : : * z + z^3/3 + z^5/5 + ...
10716 : : *
10717 : : * where z = (x-1)/(x+1) is in the range (approximately) -0.053 .. 0.048
10718 : : * due to the above range-reduction of x.
10719 : : *
10720 : : * The convergence of this is not as fast as one would like, but is
10721 : : * tolerable given that z is small.
10722 : : *
10723 : : * The Taylor series result will be multiplied by 2^(nsqrt+1), which has a
10724 : : * decimal weight of (nsqrt+1) * log10(2), so work with this many extra
10725 : : * digits of precision (plus a few more for good measure).
10726 : : */
10727 : 555 : local_rscale = rscale + (int) ((nsqrt + 1) * 0.301029995663981) + 8;
10728 : :
9988 JanWieck@Yahoo.com 10729 : 555 : sub_var(&x, &const_one, result);
10730 : 555 : add_var(&x, &const_one, &elem);
578 dean.a.rasheed@gmail 10731 : 555 : div_var(result, &elem, result, local_rscale, true, false);
9988 JanWieck@Yahoo.com 10732 : 555 : set_var_from_var(result, &xx);
8446 tgl@sss.pgh.pa.us 10733 : 555 : mul_var(result, result, &x, local_rscale);
10734 : :
1528 dean.a.rasheed@gmail 10735 : 555 : ni = 1;
10736 : :
10737 : : for (;;)
10738 : : {
10739 : 10009 : ni += 2;
8446 tgl@sss.pgh.pa.us 10740 : 10009 : mul_var(&xx, &x, &xx, local_rscale);
1528 dean.a.rasheed@gmail 10741 : 10009 : div_var_int(&xx, ni, 0, &elem, local_rscale, true);
10742 : :
8616 tgl@sss.pgh.pa.us 10743 [ + + ]: 10009 : if (elem.ndigits == 0)
9988 JanWieck@Yahoo.com 10744 : 555 : break;
10745 : :
10746 : 9454 : add_var(result, &elem, result);
10747 : :
8310 bruce@momjian.us 10748 [ - + ]: 9454 : if (elem.weight < (result->weight - local_rscale * 2 / DEC_DIGITS))
8453 tgl@sss.pgh.pa.us 10749 :UBC 0 : break;
10750 : : }
10751 : :
10752 : : /* Compensate for argument range reduction, round to requested rscale */
8446 tgl@sss.pgh.pa.us 10753 :CBC 555 : mul_var(result, &fact, result, rscale);
10754 : :
9988 JanWieck@Yahoo.com 10755 : 555 : free_var(&x);
10756 : 555 : free_var(&xx);
10757 : 555 : free_var(&elem);
10758 : 555 : free_var(&fact);
10759 : 555 : }
10760 : :
10761 : :
10762 : : /*
10763 : : * log_var() -
10764 : : *
10765 : : * Compute the logarithm of num in a given base.
10766 : : *
10767 : : * Note: this routine chooses dscale of the result.
10768 : : */
10769 : : static void
3159 andres@anarazel.de 10770 : 156 : log_var(const NumericVar *base, const NumericVar *num, NumericVar *result)
10771 : : {
10772 : : NumericVar ln_base;
10773 : : NumericVar ln_num;
10774 : : int ln_base_dweight;
10775 : : int ln_num_dweight;
10776 : : int result_dweight;
10777 : : int rscale;
10778 : : int ln_base_rscale;
10779 : : int ln_num_rscale;
10780 : :
9988 JanWieck@Yahoo.com 10781 : 156 : init_var(&ln_base);
10782 : 156 : init_var(&ln_num);
10783 : :
10784 : : /* Estimated dweights of ln(base), ln(num) and the final result */
3825 tgl@sss.pgh.pa.us 10785 : 156 : ln_base_dweight = estimate_ln_dweight(base);
10786 : 156 : ln_num_dweight = estimate_ln_dweight(num);
10787 : 156 : result_dweight = ln_num_dweight - ln_base_dweight;
10788 : :
10789 : : /*
10790 : : * Select the scale of the result so that it will have at least
10791 : : * NUMERIC_MIN_SIG_DIGITS significant digits and is not less than either
10792 : : * input's display scale.
10793 : : */
10794 : 156 : rscale = NUMERIC_MIN_SIG_DIGITS - result_dweight;
8446 10795 : 156 : rscale = Max(rscale, base->dscale);
10796 : 156 : rscale = Max(rscale, num->dscale);
10797 : 156 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
10798 : 156 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
10799 : :
10800 : : /*
10801 : : * Set the scales for ln(base) and ln(num) so that they each have more
10802 : : * significant digits than the final result.
10803 : : */
3825 10804 : 156 : ln_base_rscale = rscale + result_dweight - ln_base_dweight + 8;
10805 : 156 : ln_base_rscale = Max(ln_base_rscale, NUMERIC_MIN_DISPLAY_SCALE);
10806 : :
10807 : 156 : ln_num_rscale = rscale + result_dweight - ln_num_dweight + 8;
10808 : 156 : ln_num_rscale = Max(ln_num_rscale, NUMERIC_MIN_DISPLAY_SCALE);
10809 : :
10810 : : /* Form natural logarithms */
10811 : 156 : ln_var(base, &ln_base, ln_base_rscale);
10812 : 140 : ln_var(num, &ln_num, ln_num_rscale);
10813 : :
10814 : : /* Divide and round to the required scale */
578 dean.a.rasheed@gmail 10815 : 120 : div_var(&ln_num, &ln_base, result, rscale, true, false);
10816 : :
9988 JanWieck@Yahoo.com 10817 : 116 : free_var(&ln_num);
10818 : 116 : free_var(&ln_base);
10819 : 116 : }
10820 : :
10821 : :
10822 : : /*
10823 : : * power_var() -
10824 : : *
10825 : : * Raise base to the power of exp
10826 : : *
10827 : : * Note: this routine chooses dscale of the result.
10828 : : */
10829 : : static void
3159 andres@anarazel.de 10830 : 968 : power_var(const NumericVar *base, const NumericVar *exp, NumericVar *result)
10831 : : {
10832 : : int res_sign;
10833 : : NumericVar abs_base;
10834 : : NumericVar ln_base;
10835 : : NumericVar ln_num;
10836 : : int ln_dweight;
10837 : : int rscale;
10838 : : int sig_digits;
10839 : : int local_rscale;
10840 : : double val;
10841 : :
10842 : : /* If exp can be represented as an integer, use power_var_int */
8446 tgl@sss.pgh.pa.us 10843 [ + + + + ]: 968 : if (exp->ndigits == 0 || exp->ndigits <= exp->weight + 1)
10844 : : {
10845 : : /* exact integer, but does it fit in int? */
10846 : : int64 expval64;
10847 : :
4064 andres@anarazel.de 10848 [ + + ]: 878 : if (numericvar_to_int64(exp, &expval64))
10849 : : {
1733 dean.a.rasheed@gmail 10850 [ + - + + ]: 873 : if (expval64 >= PG_INT32_MIN && expval64 <= PG_INT32_MAX)
10851 : : {
10852 : : /* Okay, use power_var_int */
1293 10853 : 848 : power_var_int(base, (int) expval64, exp->dscale, result);
8446 tgl@sss.pgh.pa.us 10854 : 840 : return;
10855 : : }
10856 : : }
10857 : : }
10858 : :
10859 : : /*
10860 : : * This avoids log(0) for cases of 0 raised to a non-integer. 0 ^ 0 is
10861 : : * handled by power_var_int().
10862 : : */
6571 bruce@momjian.us 10863 [ + + ]: 120 : if (cmp_var(base, &const_zero) == 0)
10864 : : {
10865 : 14 : set_var_from_var(&const_zero, result);
3240 tgl@sss.pgh.pa.us 10866 : 14 : result->dscale = NUMERIC_MIN_SIG_DIGITS; /* no need to round */
6571 bruce@momjian.us 10867 : 14 : return;
10868 : : }
10869 : :
1739 dean.a.rasheed@gmail 10870 : 106 : init_var(&abs_base);
9988 JanWieck@Yahoo.com 10871 : 106 : init_var(&ln_base);
10872 : 106 : init_var(&ln_num);
10873 : :
10874 : : /*
10875 : : * If base is negative, insist that exp be an integer. The result is then
10876 : : * positive if exp is even and negative if exp is odd.
10877 : : */
1739 dean.a.rasheed@gmail 10878 [ + + ]: 106 : if (base->sign == NUMERIC_NEG)
10879 : : {
10880 : : /*
10881 : : * Check that exp is an integer. This error code is defined by the
10882 : : * SQL standard, and matches other errors in numeric_power().
10883 : : */
10884 [ + - + + ]: 27 : if (exp->ndigits > 0 && exp->ndigits > exp->weight + 1)
10885 [ + - ]: 12 : ereport(ERROR,
10886 : : (errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
10887 : : errmsg("a negative number raised to a non-integer power yields a complex result")));
10888 : :
10889 : : /* Test if exp is odd or even */
10890 [ + - + + ]: 15 : if (exp->ndigits > 0 && exp->ndigits == exp->weight + 1 &&
10891 [ + + ]: 10 : (exp->digits[exp->ndigits - 1] & 1))
10892 : 5 : res_sign = NUMERIC_NEG;
10893 : : else
10894 : 10 : res_sign = NUMERIC_POS;
10895 : :
10896 : : /* Then work with abs(base) below */
10897 : 15 : set_var_from_var(base, &abs_base);
10898 : 15 : abs_base.sign = NUMERIC_POS;
10899 : 15 : base = &abs_base;
10900 : : }
10901 : : else
10902 : 79 : res_sign = NUMERIC_POS;
10903 : :
10904 : : /*----------
10905 : : * Decide on the scale for the ln() calculation. For this we need an
10906 : : * estimate of the weight of the result, which we obtain by doing an
10907 : : * initial low-precision calculation of exp * ln(base).
10908 : : *
10909 : : * We want result = e ^ (exp * ln(base))
10910 : : * so result dweight = log10(result) = exp * ln(base) * log10(e)
10911 : : *
10912 : : * We also perform a crude overflow test here so that we can exit early if
10913 : : * the full-precision result is sure to overflow, and to guard against
10914 : : * integer overflow when determining the scale for the real calculation.
10915 : : * exp_var() supports inputs up to NUMERIC_MAX_RESULT_SCALE * 3, so the
10916 : : * result will overflow if exp * ln(base) >= NUMERIC_MAX_RESULT_SCALE * 3.
10917 : : * Since the values here are only approximations, we apply a small fuzz
10918 : : * factor to this overflow test and let exp_var() determine the exact
10919 : : * overflow threshold so that it is consistent for all inputs.
10920 : : *----------
10921 : : */
3825 tgl@sss.pgh.pa.us 10922 : 94 : ln_dweight = estimate_ln_dweight(base);
10923 : :
10924 : : /*
10925 : : * Set the scale for the low-precision calculation, computing ln(base) to
10926 : : * around 8 significant digits. Note that ln_dweight may be as small as
10927 : : * -NUMERIC_DSCALE_MAX, so the scale may exceed NUMERIC_MAX_DISPLAY_SCALE
10928 : : * here.
10929 : : */
10930 : 94 : local_rscale = 8 - ln_dweight;
10931 : 94 : local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
10932 : :
8446 10933 : 94 : ln_var(base, &ln_base, local_rscale);
10934 : :
10935 : 94 : mul_var(&ln_base, exp, &ln_num, local_rscale);
10936 : :
8616 10937 : 94 : val = numericvar_to_double_no_overflow(&ln_num);
10938 : :
10939 : : /* initial overflow/underflow test with fuzz factor */
1306 peter@eisentraut.org 10940 [ + + ]: 94 : if (fabs(val) > NUMERIC_MAX_RESULT_SCALE * 3.01)
10941 : : {
1739 dean.a.rasheed@gmail 10942 [ - + ]: 5 : if (val > 0)
1739 dean.a.rasheed@gmail 10943 [ # # ]:UBC 0 : ereport(ERROR,
10944 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
10945 : : errmsg("value overflows numeric format")));
1739 dean.a.rasheed@gmail 10946 :CBC 5 : zero_var(result);
10947 : 5 : result->dscale = NUMERIC_MAX_DISPLAY_SCALE;
10948 : 5 : return;
10949 : : }
10950 : :
3652 10951 : 89 : val *= 0.434294481903252; /* approximate decimal result weight */
10952 : :
10953 : : /* choose the result scale */
8446 tgl@sss.pgh.pa.us 10954 : 89 : rscale = NUMERIC_MIN_SIG_DIGITS - (int) val;
10955 : 89 : rscale = Max(rscale, base->dscale);
10956 : 89 : rscale = Max(rscale, exp->dscale);
10957 : 89 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
10958 : 89 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
10959 : :
10960 : : /* significant digits required in the result */
1739 dean.a.rasheed@gmail 10961 : 89 : sig_digits = rscale + (int) val;
10962 : 89 : sig_digits = Max(sig_digits, 0);
10963 : :
10964 : : /* set the scale for the real exp * ln(base) calculation */
10965 : 89 : local_rscale = sig_digits - ln_dweight + 8;
3825 tgl@sss.pgh.pa.us 10966 : 89 : local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
10967 : :
10968 : : /* and do the real calculation */
10969 : :
10970 : 89 : ln_var(base, &ln_base, local_rscale);
10971 : :
10972 : 89 : mul_var(&ln_base, exp, &ln_num, local_rscale);
10973 : :
8446 10974 : 89 : exp_var(&ln_num, result, rscale);
10975 : :
1739 dean.a.rasheed@gmail 10976 [ + + + - ]: 89 : if (res_sign == NUMERIC_NEG && result->ndigits > 0)
10977 : 5 : result->sign = NUMERIC_NEG;
10978 : :
8446 tgl@sss.pgh.pa.us 10979 : 89 : free_var(&ln_num);
10980 : 89 : free_var(&ln_base);
1739 dean.a.rasheed@gmail 10981 : 89 : free_var(&abs_base);
10982 : : }
10983 : :
10984 : : /*
10985 : : * power_var_int() -
10986 : : *
10987 : : * Raise base to the power of exp, where exp is an integer.
10988 : : *
10989 : : * Note: this routine chooses dscale of the result.
10990 : : */
10991 : : static void
1293 10992 : 848 : power_var_int(const NumericVar *base, int exp, int exp_dscale,
10993 : : NumericVar *result)
10994 : : {
10995 : : double f;
10996 : : int p;
10997 : : int i;
10998 : : int rscale;
10999 : : int sig_digits;
11000 : : unsigned int mask;
11001 : : bool neg;
11002 : : NumericVar base_prod;
11003 : : int local_rscale;
11004 : :
11005 : : /*
11006 : : * Choose the result scale. For this we need an estimate of the decimal
11007 : : * weight of the result, which we obtain by approximating using double
11008 : : * precision arithmetic.
11009 : : *
11010 : : * We also perform crude overflow/underflow tests here so that we can exit
11011 : : * early if the result is sure to overflow/underflow, and to guard against
11012 : : * integer overflow when choosing the result scale.
11013 : : */
11014 [ + + ]: 848 : if (base->ndigits != 0)
11015 : : {
11016 : : /*----------
11017 : : * Choose f (double) and p (int) such that base ~= f * 10^p.
11018 : : * Then log10(result) = log10(base^exp) ~= exp * (log10(f) + p).
11019 : : *----------
11020 : : */
11021 : 826 : f = base->digits[0];
11022 : 826 : p = base->weight * DEC_DIGITS;
11023 : :
11024 [ + + + - ]: 891 : for (i = 1; i < base->ndigits && i * DEC_DIGITS < 16; i++)
11025 : : {
11026 : 65 : f = f * NBASE + base->digits[i];
11027 : 65 : p -= DEC_DIGITS;
11028 : : }
11029 : :
11030 : 826 : f = exp * (log10(f) + p); /* approximate decimal result weight */
11031 : : }
11032 : : else
11033 : 22 : f = 0; /* result is 0 or 1 (weight 0), or error */
11034 : :
11035 : : /* overflow/underflow tests with fuzz factors */
666 11036 [ + + ]: 848 : if (f > (NUMERIC_WEIGHT_MAX + 1) * DEC_DIGITS)
1293 11037 [ + - ]: 8 : ereport(ERROR,
11038 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
11039 : : errmsg("value overflows numeric format")));
11040 [ + + ]: 840 : if (f + 1 < -NUMERIC_MAX_DISPLAY_SCALE)
11041 : : {
11042 : 10 : zero_var(result);
11043 : 10 : result->dscale = NUMERIC_MAX_DISPLAY_SCALE;
11044 : 151 : return;
11045 : : }
11046 : :
11047 : : /*
11048 : : * Choose the result scale in the same way as power_var(), so it has at
11049 : : * least NUMERIC_MIN_SIG_DIGITS significant digits and is not less than
11050 : : * either input's display scale.
11051 : : */
11052 : 830 : rscale = NUMERIC_MIN_SIG_DIGITS - (int) f;
11053 : 830 : rscale = Max(rscale, base->dscale);
11054 : 830 : rscale = Max(rscale, exp_dscale);
11055 : 830 : rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
11056 : 830 : rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
11057 : :
11058 : : /* Handle some common special cases, as well as corner cases */
8446 tgl@sss.pgh.pa.us 11059 [ + + + + : 830 : switch (exp)
+ ]
11060 : : {
11061 : 52 : case 0:
11062 : :
11063 : : /*
11064 : : * While 0 ^ 0 can be either 1 or indeterminate (error), we treat
11065 : : * it as 1 because most programming languages do this. SQL:2003
11066 : : * also requires a return value of 1.
11067 : : * https://en.wikipedia.org/wiki/Exponentiation#Zero_to_the_zero_power
11068 : : */
11069 : 52 : set_var_from_var(&const_one, result);
8310 bruce@momjian.us 11070 : 52 : result->dscale = rscale; /* no need to round */
8446 tgl@sss.pgh.pa.us 11071 : 52 : return;
11072 : 32 : case 1:
11073 : 32 : set_var_from_var(base, result);
11074 : 32 : round_var(result, rscale);
11075 : 32 : return;
11076 : 21 : case -1:
578 dean.a.rasheed@gmail 11077 : 21 : div_var(&const_one, base, result, rscale, true, true);
8446 tgl@sss.pgh.pa.us 11078 : 21 : return;
11079 : 36 : case 2:
11080 : 36 : mul_var(base, base, result, rscale);
11081 : 36 : return;
11082 : 689 : default:
11083 : 689 : break;
11084 : : }
11085 : :
11086 : : /* Handle the special case where the base is zero */
3825 11087 [ - + ]: 689 : if (base->ndigits == 0)
11088 : : {
3825 tgl@sss.pgh.pa.us 11089 [ # # ]:UBC 0 : if (exp < 0)
11090 [ # # ]: 0 : ereport(ERROR,
11091 : : (errcode(ERRCODE_DIVISION_BY_ZERO),
11092 : : errmsg("division by zero")));
11093 : 0 : zero_var(result);
11094 : 0 : result->dscale = rscale;
11095 : 0 : return;
11096 : : }
11097 : :
11098 : : /*
11099 : : * The general case repeatedly multiplies base according to the bit
11100 : : * pattern of exp.
11101 : : *
11102 : : * The local rscale used for each multiplication is varied to keep a fixed
11103 : : * number of significant digits, sufficient to give the required result
11104 : : * scale.
11105 : : */
11106 : :
11107 : : /*
11108 : : * Approximate number of significant digits in the result. Note that the
11109 : : * underflow test above, together with the choice of rscale, ensures that
11110 : : * this approximation is necessarily > 0.
11111 : : */
3825 tgl@sss.pgh.pa.us 11112 :CBC 689 : sig_digits = 1 + rscale + (int) f;
11113 : :
11114 : : /*
11115 : : * The multiplications to produce the result may introduce an error of up
11116 : : * to around log10(abs(exp)) digits, so work with this many extra digits
11117 : : * of precision (plus a few more for good measure).
11118 : : */
1946 dean.a.rasheed@gmail 11119 : 689 : sig_digits += (int) log(fabs((double) exp)) + 8;
11120 : :
11121 : : /*
11122 : : * Now we can proceed with the multiplications.
11123 : : */
8446 tgl@sss.pgh.pa.us 11124 : 689 : neg = (exp < 0);
628 nathan@postgresql.or 11125 : 689 : mask = pg_abs_s32(exp);
11126 : :
8446 tgl@sss.pgh.pa.us 11127 : 689 : init_var(&base_prod);
11128 : 689 : set_var_from_var(base, &base_prod);
11129 : :
4254 11130 [ + + ]: 689 : if (mask & 1)
8446 11131 : 343 : set_var_from_var(base, result);
11132 : : else
11133 : 346 : set_var_from_var(&const_one, result);
11134 : :
4254 11135 [ + + ]: 3618 : while ((mask >>= 1) > 0)
11136 : : {
11137 : : /*
11138 : : * Do the multiplications using rscales large enough to hold the
11139 : : * results to the required number of significant digits, but don't
11140 : : * waste time by exceeding the scales of the numbers themselves.
11141 : : */
3825 11142 : 2929 : local_rscale = sig_digits - 2 * base_prod.weight * DEC_DIGITS;
11143 : 2929 : local_rscale = Min(local_rscale, 2 * base_prod.dscale);
11144 : 2929 : local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
11145 : :
8446 11146 : 2929 : mul_var(&base_prod, &base_prod, &base_prod, local_rscale);
11147 : :
4254 11148 [ + + ]: 2929 : if (mask & 1)
11149 : : {
3825 11150 : 1932 : local_rscale = sig_digits -
11151 : 1932 : (base_prod.weight + result->weight) * DEC_DIGITS;
11152 : 1932 : local_rscale = Min(local_rscale,
11153 : : base_prod.dscale + result->dscale);
11154 : 1932 : local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
11155 : :
8446 11156 : 1932 : mul_var(&base_prod, result, result, local_rscale);
11157 : : }
11158 : :
11159 : : /*
11160 : : * When abs(base) > 1, the number of digits to the left of the decimal
11161 : : * point in base_prod doubles at each iteration, so if exp is large we
11162 : : * could easily spend large amounts of time and memory space doing the
11163 : : * multiplications. But once the weight exceeds what will fit in
11164 : : * int16, the final result is guaranteed to overflow (or underflow, if
11165 : : * exp < 0), so we can give up before wasting too many cycles.
11166 : : */
666 dean.a.rasheed@gmail 11167 [ + - ]: 2929 : if (base_prod.weight > NUMERIC_WEIGHT_MAX ||
11168 [ - + ]: 2929 : result->weight > NUMERIC_WEIGHT_MAX)
11169 : : {
11170 : : /* overflow, unless neg, in which case result should be 0 */
4254 tgl@sss.pgh.pa.us 11171 [ # # ]:UBC 0 : if (!neg)
11172 [ # # ]: 0 : ereport(ERROR,
11173 : : (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
11174 : : errmsg("value overflows numeric format")));
11175 : 0 : zero_var(result);
11176 : 0 : neg = false;
11177 : 0 : break;
11178 : : }
11179 : : }
11180 : :
8446 tgl@sss.pgh.pa.us 11181 :CBC 689 : free_var(&base_prod);
11182 : :
11183 : : /* Compensate for input sign, and round to requested rscale */
11184 [ + + ]: 689 : if (neg)
578 dean.a.rasheed@gmail 11185 : 328 : div_var(&const_one, result, result, rscale, true, false);
11186 : : else
8446 tgl@sss.pgh.pa.us 11187 : 361 : round_var(result, rscale);
11188 : : }
11189 : :
11190 : : /*
11191 : : * power_ten_int() -
11192 : : *
11193 : : * Raise ten to the power of exp, where exp is an integer. Note that unlike
11194 : : * power_var_int(), this does no overflow/underflow checking or rounding.
11195 : : */
11196 : : static void
1734 dean.a.rasheed@gmail 11197 : 152 : power_ten_int(int exp, NumericVar *result)
11198 : : {
11199 : : /* Construct the result directly, starting from 10^0 = 1 */
11200 : 152 : set_var_from_var(&const_one, result);
11201 : :
11202 : : /* Scale needed to represent the result exactly */
11203 [ + + ]: 152 : result->dscale = exp < 0 ? -exp : 0;
11204 : :
11205 : : /* Base-NBASE weight of result and remaining exponent */
11206 [ + + ]: 152 : if (exp >= 0)
11207 : 108 : result->weight = exp / DEC_DIGITS;
11208 : : else
11209 : 44 : result->weight = (exp + 1) / DEC_DIGITS - 1;
11210 : :
11211 : 152 : exp -= result->weight * DEC_DIGITS;
11212 : :
11213 : : /* Final adjustment of the result's single NBASE digit */
11214 [ + + ]: 396 : while (exp-- > 0)
11215 : 244 : result->digits[0] *= 10;
11216 : 152 : }
11217 : :
11218 : : /*
11219 : : * random_var() - return a random value in the range [rmin, rmax].
11220 : : */
11221 : : static void
769 11222 : 22292 : random_var(pg_prng_state *state, const NumericVar *rmin,
11223 : : const NumericVar *rmax, NumericVar *result)
11224 : : {
11225 : : int rscale;
11226 : : NumericVar rlen;
11227 : : int res_ndigits;
11228 : : int n;
11229 : : int pow10;
11230 : : int i;
11231 : : uint64 rlen64;
11232 : : int rlen64_ndigits;
11233 : :
11234 : 22292 : rscale = Max(rmin->dscale, rmax->dscale);
11235 : :
11236 : : /* Compute rlen = rmax - rmin and check the range bounds */
11237 : 22292 : init_var(&rlen);
11238 : 22292 : sub_var(rmax, rmin, &rlen);
11239 : :
11240 [ + + ]: 22292 : if (rlen.sign == NUMERIC_NEG)
11241 [ + - ]: 4 : ereport(ERROR,
11242 : : errcode(ERRCODE_INVALID_PARAMETER_VALUE),
11243 : : errmsg("lower bound must be less than or equal to upper bound"));
11244 : :
11245 : : /* Special case for an empty range */
11246 [ + + ]: 22288 : if (rlen.ndigits == 0)
11247 : : {
11248 : 8 : set_var_from_var(rmin, result);
11249 : 8 : result->dscale = rscale;
11250 : 8 : free_var(&rlen);
11251 : 8 : return;
11252 : : }
11253 : :
11254 : : /*
11255 : : * Otherwise, select a random value in the range [0, rlen = rmax - rmin],
11256 : : * and shift it to the required range by adding rmin.
11257 : : */
11258 : :
11259 : : /* Required result digits */
11260 : 22280 : res_ndigits = rlen.weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
11261 : :
11262 : : /*
11263 : : * To get the required rscale, the final result digit must be a multiple
11264 : : * of pow10 = 10^n, where n = (-rscale) mod DEC_DIGITS.
11265 : : */
11266 : 22280 : n = ((rscale + DEC_DIGITS - 1) / DEC_DIGITS) * DEC_DIGITS - rscale;
11267 : 22280 : pow10 = 1;
11268 [ + + ]: 58600 : for (i = 0; i < n; i++)
11269 : 36320 : pow10 *= 10;
11270 : :
11271 : : /*
11272 : : * To choose a random value uniformly from the range [0, rlen], we choose
11273 : : * from the slightly larger range [0, rlen2], where rlen2 is formed from
11274 : : * rlen by copying the first 4 NBASE digits, and setting all remaining
11275 : : * decimal digits to "9".
11276 : : *
11277 : : * Without loss of generality, we can ignore the weight of rlen2 and treat
11278 : : * it as a pure integer for the purposes of this discussion. The process
11279 : : * above gives rlen2 + 1 = rlen64 * 10^N, for some integer N, where rlen64
11280 : : * is a 64-bit integer formed from the first 4 NBASE digits copied from
11281 : : * rlen. Since this trivially factors into smaller pieces that fit in
11282 : : * 64-bit integers, the task of choosing a random value uniformly from the
11283 : : * rlen2 + 1 possible values in [0, rlen2] is much simpler.
11284 : : *
11285 : : * If the random value selected is too large, it is rejected, and we try
11286 : : * again until we get a result <= rlen, ensuring that the overall result
11287 : : * is uniform (no particular value is any more likely than any other).
11288 : : *
11289 : : * Since rlen64 holds 4 NBASE digits from rlen, it contains at least
11290 : : * DEC_DIGITS * 3 + 1 decimal digits (i.e., at least 13 decimal digits,
11291 : : * when DEC_DIGITS is 4). Therefore the probability of needing to reject
11292 : : * the value chosen and retry is less than 1e-13.
11293 : : */
11294 : 22280 : rlen64 = (uint64) rlen.digits[0];
11295 : 22280 : rlen64_ndigits = 1;
11296 [ + + + + ]: 50808 : while (rlen64_ndigits < res_ndigits && rlen64_ndigits < 4)
11297 : : {
11298 : 28528 : rlen64 *= NBASE;
11299 [ + + ]: 28528 : if (rlen64_ndigits < rlen.ndigits)
11300 : 4408 : rlen64 += rlen.digits[rlen64_ndigits];
11301 : 28528 : rlen64_ndigits++;
11302 : : }
11303 : :
11304 : : /* Loop until we get a result <= rlen */
11305 : : do
11306 : : {
11307 : : NumericDigit *res_digits;
11308 : : uint64 rand;
11309 : : int whole_ndigits;
11310 : :
11311 : 22280 : alloc_var(result, res_ndigits);
11312 : 22280 : result->sign = NUMERIC_POS;
11313 : 22280 : result->weight = rlen.weight;
11314 : 22280 : result->dscale = rscale;
11315 : 22280 : res_digits = result->digits;
11316 : :
11317 : : /*
11318 : : * Set the first rlen64_ndigits using a random value in [0, rlen64].
11319 : : *
11320 : : * If this is the whole result, and rscale is not a multiple of
11321 : : * DEC_DIGITS (pow10 from above is not 1), then we need this to be a
11322 : : * multiple of pow10.
11323 : : */
11324 [ + + + + ]: 22280 : if (rlen64_ndigits == res_ndigits && pow10 != 1)
11325 : 14088 : rand = pg_prng_uint64_range(state, 0, rlen64 / pow10) * pow10;
11326 : : else
11327 : 8192 : rand = pg_prng_uint64_range(state, 0, rlen64);
11328 : :
11329 [ + + ]: 73088 : for (i = rlen64_ndigits - 1; i >= 0; i--)
11330 : : {
11331 : 50808 : res_digits[i] = (NumericDigit) (rand % NBASE);
11332 : 50808 : rand = rand / NBASE;
11333 : : }
11334 : :
11335 : : /*
11336 : : * Set the remaining digits to random values in range [0, NBASE),
11337 : : * noting that the last digit needs to be a multiple of pow10.
11338 : : */
11339 : 22280 : whole_ndigits = res_ndigits;
11340 [ + + ]: 22280 : if (pow10 != 1)
11341 : 22140 : whole_ndigits--;
11342 : :
11343 : : /* Set whole digits in groups of 4 for best performance */
11344 : 22280 : i = rlen64_ndigits;
11345 [ + + ]: 22320 : while (i < whole_ndigits - 3)
11346 : : {
11347 : 40 : rand = pg_prng_uint64_range(state, 0,
11348 : : (uint64) NBASE * NBASE * NBASE * NBASE - 1);
11349 : 40 : res_digits[i++] = (NumericDigit) (rand % NBASE);
11350 : 40 : rand = rand / NBASE;
11351 : 40 : res_digits[i++] = (NumericDigit) (rand % NBASE);
11352 : 40 : rand = rand / NBASE;
11353 : 40 : res_digits[i++] = (NumericDigit) (rand % NBASE);
11354 : 40 : rand = rand / NBASE;
11355 : 40 : res_digits[i++] = (NumericDigit) rand;
11356 : : }
11357 : :
11358 : : /* Remaining whole digits */
11359 [ + + ]: 22420 : while (i < whole_ndigits)
11360 : : {
11361 : 140 : rand = pg_prng_uint64_range(state, 0, NBASE - 1);
11362 : 140 : res_digits[i++] = (NumericDigit) rand;
11363 : : }
11364 : :
11365 : : /* Final partial digit (multiple of pow10) */
11366 [ + + ]: 22280 : if (i < res_ndigits)
11367 : : {
11368 : 8052 : rand = pg_prng_uint64_range(state, 0, NBASE / pow10 - 1) * pow10;
11369 : 8052 : res_digits[i] = (NumericDigit) rand;
11370 : : }
11371 : :
11372 : : /* Remove leading/trailing zeroes */
11373 : 22280 : strip_var(result);
11374 : :
11375 : : /* If result > rlen, try again */
11376 : :
11377 [ - + ]: 22280 : } while (cmp_var(result, &rlen) > 0);
11378 : :
11379 : : /* Offset the result to the required range */
11380 : 22280 : add_var(result, rmin, result);
11381 : :
11382 : 22280 : free_var(&rlen);
11383 : : }
11384 : :
11385 : :
11386 : : /* ----------------------------------------------------------------------
11387 : : *
11388 : : * Following are the lowest level functions that operate unsigned
11389 : : * on the variable level
11390 : : *
11391 : : * ----------------------------------------------------------------------
11392 : : */
11393 : :
11394 : :
11395 : : /* ----------
11396 : : * cmp_abs() -
11397 : : *
11398 : : * Compare the absolute values of var1 and var2
11399 : : * Returns: -1 for ABS(var1) < ABS(var2)
11400 : : * 0 for ABS(var1) == ABS(var2)
11401 : : * 1 for ABS(var1) > ABS(var2)
11402 : : * ----------
11403 : : */
11404 : : static int
3159 andres@anarazel.de 11405 : 469393 : cmp_abs(const NumericVar *var1, const NumericVar *var2)
11406 : : {
7392 bruce@momjian.us 11407 : 938786 : return cmp_abs_common(var1->digits, var1->ndigits, var1->weight,
11408 : 469393 : var2->digits, var2->ndigits, var2->weight);
11409 : : }
11410 : :
11411 : : /* ----------
11412 : : * cmp_abs_common() -
11413 : : *
11414 : : * Main routine of cmp_abs(). This function can be used by both
11415 : : * NumericVar and Numeric.
11416 : : * ----------
11417 : : */
11418 : : static int
11419 : 18750143 : cmp_abs_common(const NumericDigit *var1digits, int var1ndigits, int var1weight,
11420 : : const NumericDigit *var2digits, int var2ndigits, int var2weight)
11421 : : {
9842 11422 : 18750143 : int i1 = 0;
11423 : 18750143 : int i2 = 0;
11424 : :
11425 : : /* Check any digits before the first common digit */
11426 : :
7392 11427 [ + + + + ]: 18750143 : while (var1weight > var2weight && i1 < var1ndigits)
11428 : : {
8446 tgl@sss.pgh.pa.us 11429 [ + - ]: 17014 : if (var1digits[i1++] != 0)
9842 bruce@momjian.us 11430 : 17014 : return 1;
7392 bruce@momjian.us 11431 :UBC 0 : var1weight--;
11432 : : }
7392 bruce@momjian.us 11433 [ + + + + ]:CBC 18733129 : while (var2weight > var1weight && i2 < var2ndigits)
11434 : : {
8446 tgl@sss.pgh.pa.us 11435 [ + - ]: 99752 : if (var2digits[i2++] != 0)
9842 bruce@momjian.us 11436 : 99752 : return -1;
7392 bruce@momjian.us 11437 :UBC 0 : var2weight--;
11438 : : }
11439 : :
11440 : : /* At this point, either w1 == w2 or we've run out of digits */
11441 : :
7392 bruce@momjian.us 11442 [ + + ]:CBC 18633377 : if (var1weight == var2weight)
11443 : : {
11444 [ + + + + ]: 29350342 : while (i1 < var1ndigits && i2 < var2ndigits)
11445 : : {
8446 tgl@sss.pgh.pa.us 11446 : 19661383 : int stat = var1digits[i1++] - var2digits[i2++];
11447 : :
9983 JanWieck@Yahoo.com 11448 [ + + ]: 19661383 : if (stat)
11449 : : {
11450 [ + + ]: 8940188 : if (stat > 0)
11451 : 5272824 : return 1;
11452 : 3667364 : return -1;
11453 : : }
11454 : : }
11455 : : }
11456 : :
11457 : : /*
11458 : : * At this point, we've run out of digits on one side or the other; so any
11459 : : * remaining nonzero digits imply that side is larger
11460 : : */
7392 bruce@momjian.us 11461 [ + + ]: 9693379 : while (i1 < var1ndigits)
11462 : : {
8446 tgl@sss.pgh.pa.us 11463 [ + + ]: 6372 : if (var1digits[i1++] != 0)
9988 JanWieck@Yahoo.com 11464 : 6182 : return 1;
11465 : : }
7392 bruce@momjian.us 11466 [ + + ]: 9687169 : while (i2 < var2ndigits)
11467 : : {
8446 tgl@sss.pgh.pa.us 11468 [ + + ]: 781 : if (var2digits[i2++] != 0)
9988 JanWieck@Yahoo.com 11469 : 619 : return -1;
11470 : : }
11471 : :
11472 : 9686388 : return 0;
11473 : : }
11474 : :
11475 : :
11476 : : /*
11477 : : * add_abs() -
11478 : : *
11479 : : * Add the absolute values of two variables into result.
11480 : : * result might point to one of the operands without danger.
11481 : : */
11482 : : static void
3159 andres@anarazel.de 11483 : 299692 : add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
11484 : : {
11485 : : NumericDigit *res_buf;
11486 : : NumericDigit *res_digits;
11487 : : int res_ndigits;
11488 : : int res_weight;
11489 : : int res_rscale,
11490 : : rscale1,
11491 : : rscale2;
11492 : : int res_dscale;
11493 : : int i,
11494 : : i1,
11495 : : i2;
9842 bruce@momjian.us 11496 : 299692 : int carry = 0;
11497 : :
11498 : : /* copy these values into local vars for speed in inner loop */
9423 tgl@sss.pgh.pa.us 11499 : 299692 : int var1ndigits = var1->ndigits;
11500 : 299692 : int var2ndigits = var2->ndigits;
11501 : 299692 : NumericDigit *var1digits = var1->digits;
11502 : 299692 : NumericDigit *var2digits = var2->digits;
11503 : :
8842 bruce@momjian.us 11504 : 299692 : res_weight = Max(var1->weight, var2->weight) + 1;
11505 : :
11506 : 299692 : res_dscale = Max(var1->dscale, var2->dscale);
11507 : :
11508 : : /* Note: here we are figuring rscale in base-NBASE digits */
8446 tgl@sss.pgh.pa.us 11509 : 299692 : rscale1 = var1->ndigits - var1->weight - 1;
11510 : 299692 : rscale2 = var2->ndigits - var2->weight - 1;
11511 : 299692 : res_rscale = Max(rscale1, rscale2);
11512 : :
9988 JanWieck@Yahoo.com 11513 : 299692 : res_ndigits = res_rscale + res_weight + 1;
9604 tgl@sss.pgh.pa.us 11514 [ - + ]: 299692 : if (res_ndigits <= 0)
9604 tgl@sss.pgh.pa.us 11515 :UBC 0 : res_ndigits = 1;
11516 : :
8446 tgl@sss.pgh.pa.us 11517 :CBC 299692 : res_buf = digitbuf_alloc(res_ndigits + 1);
11518 : 299692 : res_buf[0] = 0; /* spare digit for later rounding */
11519 : 299692 : res_digits = res_buf + 1;
11520 : :
9988 JanWieck@Yahoo.com 11521 : 299692 : i1 = res_rscale + var1->weight + 1;
11522 : 299692 : i2 = res_rscale + var2->weight + 1;
11523 [ + + ]: 2480767 : for (i = res_ndigits - 1; i >= 0; i--)
11524 : : {
11525 : 2181075 : i1--;
11526 : 2181075 : i2--;
9423 tgl@sss.pgh.pa.us 11527 [ + + + + ]: 2181075 : if (i1 >= 0 && i1 < var1ndigits)
11528 : 988214 : carry += var1digits[i1];
11529 [ + + + + ]: 2181075 : if (i2 >= 0 && i2 < var2ndigits)
11530 : 780034 : carry += var2digits[i2];
11531 : :
8446 11532 [ + + ]: 2181075 : if (carry >= NBASE)
11533 : : {
11534 : 159523 : res_digits[i] = carry - NBASE;
9423 11535 : 159523 : carry = 1;
11536 : : }
11537 : : else
11538 : : {
11539 : 2021552 : res_digits[i] = carry;
11540 : 2021552 : carry = 0;
11541 : : }
11542 : : }
11543 : :
11544 [ - + ]: 299692 : Assert(carry == 0); /* else we failed to allow for carry out */
11545 : :
9988 JanWieck@Yahoo.com 11546 [ + + ]: 299692 : digitbuf_free(result->buf);
11547 : 299692 : result->ndigits = res_ndigits;
9842 bruce@momjian.us 11548 : 299692 : result->buf = res_buf;
11549 : 299692 : result->digits = res_digits;
11550 : 299692 : result->weight = res_weight;
11551 : 299692 : result->dscale = res_dscale;
11552 : :
11553 : : /* Remove leading/trailing zeroes */
8446 tgl@sss.pgh.pa.us 11554 : 299692 : strip_var(result);
9988 JanWieck@Yahoo.com 11555 : 299692 : }
11556 : :
11557 : :
11558 : : /*
11559 : : * sub_abs()
11560 : : *
11561 : : * Subtract the absolute value of var2 from the absolute value of var1
11562 : : * and store in result. result might point to one of the operands
11563 : : * without danger.
11564 : : *
11565 : : * ABS(var1) MUST BE GREATER OR EQUAL ABS(var2) !!!
11566 : : */
11567 : : static void
3159 andres@anarazel.de 11568 : 435925 : sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
11569 : : {
11570 : : NumericDigit *res_buf;
11571 : : NumericDigit *res_digits;
11572 : : int res_ndigits;
11573 : : int res_weight;
11574 : : int res_rscale,
11575 : : rscale1,
11576 : : rscale2;
11577 : : int res_dscale;
11578 : : int i,
11579 : : i1,
11580 : : i2;
9842 bruce@momjian.us 11581 : 435925 : int borrow = 0;
11582 : :
11583 : : /* copy these values into local vars for speed in inner loop */
9423 tgl@sss.pgh.pa.us 11584 : 435925 : int var1ndigits = var1->ndigits;
11585 : 435925 : int var2ndigits = var2->ndigits;
11586 : 435925 : NumericDigit *var1digits = var1->digits;
11587 : 435925 : NumericDigit *var2digits = var2->digits;
11588 : :
9988 JanWieck@Yahoo.com 11589 : 435925 : res_weight = var1->weight;
11590 : :
8842 bruce@momjian.us 11591 : 435925 : res_dscale = Max(var1->dscale, var2->dscale);
11592 : :
11593 : : /* Note: here we are figuring rscale in base-NBASE digits */
8446 tgl@sss.pgh.pa.us 11594 : 435925 : rscale1 = var1->ndigits - var1->weight - 1;
11595 : 435925 : rscale2 = var2->ndigits - var2->weight - 1;
11596 : 435925 : res_rscale = Max(rscale1, rscale2);
11597 : :
9988 JanWieck@Yahoo.com 11598 : 435925 : res_ndigits = res_rscale + res_weight + 1;
9604 tgl@sss.pgh.pa.us 11599 [ - + ]: 435925 : if (res_ndigits <= 0)
9604 tgl@sss.pgh.pa.us 11600 :UBC 0 : res_ndigits = 1;
11601 : :
8446 tgl@sss.pgh.pa.us 11602 :CBC 435925 : res_buf = digitbuf_alloc(res_ndigits + 1);
11603 : 435925 : res_buf[0] = 0; /* spare digit for later rounding */
11604 : 435925 : res_digits = res_buf + 1;
11605 : :
9988 JanWieck@Yahoo.com 11606 : 435925 : i1 = res_rscale + var1->weight + 1;
11607 : 435925 : i2 = res_rscale + var2->weight + 1;
11608 [ + + ]: 3488431 : for (i = res_ndigits - 1; i >= 0; i--)
11609 : : {
11610 : 3052506 : i1--;
11611 : 3052506 : i2--;
9423 tgl@sss.pgh.pa.us 11612 [ + - + + ]: 3052506 : if (i1 >= 0 && i1 < var1ndigits)
11613 : 2745544 : borrow += var1digits[i1];
11614 [ + + + + ]: 3052506 : if (i2 >= 0 && i2 < var2ndigits)
11615 : 2692433 : borrow -= var2digits[i2];
11616 : :
9988 JanWieck@Yahoo.com 11617 [ + + ]: 3052506 : if (borrow < 0)
11618 : : {
8446 tgl@sss.pgh.pa.us 11619 : 329423 : res_digits[i] = borrow + NBASE;
9988 JanWieck@Yahoo.com 11620 : 329423 : borrow = -1;
11621 : : }
11622 : : else
11623 : : {
11624 : 2723083 : res_digits[i] = borrow;
11625 : 2723083 : borrow = 0;
11626 : : }
11627 : : }
11628 : :
9423 tgl@sss.pgh.pa.us 11629 [ - + ]: 435925 : Assert(borrow == 0); /* else caller gave us var1 < var2 */
11630 : :
9988 JanWieck@Yahoo.com 11631 [ + + ]: 435925 : digitbuf_free(result->buf);
11632 : 435925 : result->ndigits = res_ndigits;
9842 bruce@momjian.us 11633 : 435925 : result->buf = res_buf;
11634 : 435925 : result->digits = res_digits;
11635 : 435925 : result->weight = res_weight;
11636 : 435925 : result->dscale = res_dscale;
11637 : :
11638 : : /* Remove leading/trailing zeroes */
8446 tgl@sss.pgh.pa.us 11639 : 435925 : strip_var(result);
11640 : 435925 : }
11641 : :
11642 : : /*
11643 : : * round_var
11644 : : *
11645 : : * Round the value of a variable to no more than rscale decimal digits
11646 : : * after the decimal point. NOTE: we allow rscale < 0 here, implying
11647 : : * rounding before the decimal point.
11648 : : */
11649 : : static void
11650 : 168131 : round_var(NumericVar *var, int rscale)
11651 : : {
8310 bruce@momjian.us 11652 : 168131 : NumericDigit *digits = var->digits;
11653 : : int di;
11654 : : int ndigits;
11655 : : int carry;
11656 : :
8446 tgl@sss.pgh.pa.us 11657 : 168131 : var->dscale = rscale;
11658 : :
11659 : : /* decimal digits wanted */
11660 : 168131 : di = (var->weight + 1) * DEC_DIGITS + rscale;
11661 : :
11662 : : /*
11663 : : * If di = 0, the value loses all digits, but could round up to 1 if its
11664 : : * first extra digit is >= 5. If di < 0 the result must be 0.
11665 : : */
11666 [ + + ]: 168131 : if (di < 0)
11667 : : {
11668 : 71 : var->ndigits = 0;
11669 : 71 : var->weight = 0;
11670 : 71 : var->sign = NUMERIC_POS;
11671 : : }
11672 : : else
11673 : : {
11674 : : /* NBASE digits wanted */
8310 bruce@momjian.us 11675 : 168060 : ndigits = (di + DEC_DIGITS - 1) / DEC_DIGITS;
11676 : :
11677 : : /* 0, or number of decimal digits to keep in last NBASE digit */
8446 tgl@sss.pgh.pa.us 11678 : 168060 : di %= DEC_DIGITS;
11679 : :
11680 [ + + ]: 168060 : if (ndigits < var->ndigits ||
11681 [ + + + + ]: 30529 : (ndigits == var->ndigits && di > 0))
11682 : : {
11683 : 140000 : var->ndigits = ndigits;
11684 : :
11685 : : #if DEC_DIGITS == 1
11686 : : /* di must be zero */
11687 : : carry = (digits[ndigits] >= HALF_NBASE) ? 1 : 0;
11688 : : #else
11689 [ + + ]: 140000 : if (di == 0)
11690 : 109929 : carry = (digits[ndigits] >= HALF_NBASE) ? 1 : 0;
11691 : : else
11692 : : {
11693 : : /* Must round within last NBASE digit */
11694 : : int extra,
11695 : : pow10;
11696 : :
11697 : : #if DEC_DIGITS == 4
11698 : 30071 : pow10 = round_powers[di];
11699 : : #elif DEC_DIGITS == 2
11700 : : pow10 = 10;
11701 : : #else
11702 : : #error unsupported NBASE
11703 : : #endif
11704 : 30071 : extra = digits[--ndigits] % pow10;
11705 : 30071 : digits[ndigits] -= extra;
11706 : 30071 : carry = 0;
8310 bruce@momjian.us 11707 [ + + ]: 30071 : if (extra >= pow10 / 2)
11708 : : {
8446 tgl@sss.pgh.pa.us 11709 : 14011 : pow10 += digits[ndigits];
11710 [ + + ]: 14011 : if (pow10 >= NBASE)
11711 : : {
11712 : 587 : pow10 -= NBASE;
11713 : 587 : carry = 1;
11714 : : }
11715 : 14011 : digits[ndigits] = pow10;
11716 : : }
11717 : : }
11718 : : #endif
11719 : :
11720 : : /* Propagate carry if needed */
11721 [ + + ]: 166918 : while (carry)
11722 : : {
11723 : 26918 : carry += digits[--ndigits];
11724 [ + + ]: 26918 : if (carry >= NBASE)
11725 : : {
11726 : 20520 : digits[ndigits] = carry - NBASE;
11727 : 20520 : carry = 1;
11728 : : }
11729 : : else
11730 : : {
11731 : 6398 : digits[ndigits] = carry;
11732 : 6398 : carry = 0;
11733 : : }
11734 : : }
11735 : :
11736 [ + + ]: 140000 : if (ndigits < 0)
11737 : : {
11738 [ - + ]: 65 : Assert(ndigits == -1); /* better not have added > 1 digit */
11739 [ - + ]: 65 : Assert(var->digits > var->buf);
11740 : 65 : var->digits--;
11741 : 65 : var->ndigits++;
11742 : 65 : var->weight++;
11743 : : }
11744 : : }
11745 : : }
11746 : 168131 : }
11747 : :
11748 : : /*
11749 : : * trunc_var
11750 : : *
11751 : : * Truncate (towards zero) the value of a variable at rscale decimal digits
11752 : : * after the decimal point. NOTE: we allow rscale < 0 here, implying
11753 : : * truncation before the decimal point.
11754 : : */
11755 : : static void
11756 : 280412 : trunc_var(NumericVar *var, int rscale)
11757 : : {
11758 : : int di;
11759 : : int ndigits;
11760 : :
11761 : 280412 : var->dscale = rscale;
11762 : :
11763 : : /* decimal digits wanted */
11764 : 280412 : di = (var->weight + 1) * DEC_DIGITS + rscale;
11765 : :
11766 : : /*
11767 : : * If di <= 0, the value loses all digits.
11768 : : */
11769 [ + + ]: 280412 : if (di <= 0)
11770 : : {
11771 : 66 : var->ndigits = 0;
11772 : 66 : var->weight = 0;
11773 : 66 : var->sign = NUMERIC_POS;
11774 : : }
11775 : : else
11776 : : {
11777 : : /* NBASE digits wanted */
8310 bruce@momjian.us 11778 : 280346 : ndigits = (di + DEC_DIGITS - 1) / DEC_DIGITS;
11779 : :
8446 tgl@sss.pgh.pa.us 11780 [ + + ]: 280346 : if (ndigits <= var->ndigits)
11781 : : {
11782 : 280158 : var->ndigits = ndigits;
11783 : :
11784 : : #if DEC_DIGITS == 1
11785 : : /* no within-digit stuff to worry about */
11786 : : #else
11787 : : /* 0, or number of decimal digits to keep in last NBASE digit */
11788 : 280158 : di %= DEC_DIGITS;
11789 : :
11790 [ + + ]: 280158 : if (di > 0)
11791 : : {
11792 : : /* Must truncate within last NBASE digit */
8310 bruce@momjian.us 11793 : 63 : NumericDigit *digits = var->digits;
11794 : : int extra,
11795 : : pow10;
11796 : :
11797 : : #if DEC_DIGITS == 4
8446 tgl@sss.pgh.pa.us 11798 : 63 : pow10 = round_powers[di];
11799 : : #elif DEC_DIGITS == 2
11800 : : pow10 = 10;
11801 : : #else
11802 : : #error unsupported NBASE
11803 : : #endif
11804 : 63 : extra = digits[--ndigits] % pow10;
11805 : 63 : digits[ndigits] -= extra;
11806 : : }
11807 : : #endif
11808 : : }
11809 : : }
11810 : 280412 : }
11811 : :
11812 : : /*
11813 : : * strip_var
11814 : : *
11815 : : * Strip any leading and trailing zeroes from a numeric variable
11816 : : */
11817 : : static void
11818 : 2189109 : strip_var(NumericVar *var)
11819 : : {
8310 bruce@momjian.us 11820 : 2189109 : NumericDigit *digits = var->digits;
8446 tgl@sss.pgh.pa.us 11821 : 2189109 : int ndigits = var->ndigits;
11822 : :
11823 : : /* Strip leading zeroes */
11824 [ + + + + ]: 3762804 : while (ndigits > 0 && *digits == 0)
11825 : : {
11826 : 1573695 : digits++;
11827 : 1573695 : var->weight--;
11828 : 1573695 : ndigits--;
11829 : : }
11830 : :
11831 : : /* Strip trailing zeroes */
11832 [ + + + + ]: 2641034 : while (ndigits > 0 && digits[ndigits - 1] == 0)
11833 : 451925 : ndigits--;
11834 : :
11835 : : /* If it's zero, normalize the sign and weight */
11836 [ + + ]: 2189109 : if (ndigits == 0)
11837 : : {
11838 : 33973 : var->sign = NUMERIC_POS;
11839 : 33973 : var->weight = 0;
11840 : : }
11841 : :
11842 : 2189109 : var->digits = digits;
11843 : 2189109 : var->ndigits = ndigits;
9988 JanWieck@Yahoo.com 11844 : 2189109 : }
11845 : :
11846 : :
11847 : : /* ----------------------------------------------------------------------
11848 : : *
11849 : : * Fast sum accumulator functions
11850 : : *
11851 : : * ----------------------------------------------------------------------
11852 : : */
11853 : :
11854 : : /*
11855 : : * Reset the accumulator's value to zero. The buffers to hold the digits
11856 : : * are not free'd.
11857 : : */
11858 : : static void
3532 heikki.linnakangas@i 11859 : 12 : accum_sum_reset(NumericSumAccum *accum)
11860 : : {
11861 : : int i;
11862 : :
11863 : 12 : accum->dscale = 0;
11864 [ + + ]: 44 : for (i = 0; i < accum->ndigits; i++)
11865 : : {
11866 : 32 : accum->pos_digits[i] = 0;
11867 : 32 : accum->neg_digits[i] = 0;
11868 : : }
11869 : 12 : }
11870 : :
11871 : : /*
11872 : : * Accumulate a new value.
11873 : : */
11874 : : static void
3159 andres@anarazel.de 11875 : 1570448 : accum_sum_add(NumericSumAccum *accum, const NumericVar *val)
11876 : : {
11877 : : int32 *accum_digits;
11878 : : int i,
11879 : : val_i;
11880 : : int val_ndigits;
11881 : : NumericDigit *val_digits;
11882 : :
11883 : : /*
11884 : : * If we have accumulated too many values since the last carry
11885 : : * propagation, do it now, to avoid overflowing. (We could allow more
11886 : : * than NBASE - 1, if we reserved two extra digits, rather than one, for
11887 : : * carry propagation. But even with NBASE - 1, this needs to be done so
11888 : : * seldom, that the performance difference is negligible.)
11889 : : */
3532 heikki.linnakangas@i 11890 [ + + ]: 1570448 : if (accum->num_uncarried == NBASE - 1)
11891 : 110 : accum_sum_carry(accum);
11892 : :
11893 : : /*
11894 : : * Adjust the weight or scale of the old value, so that it can accommodate
11895 : : * the new value.
11896 : : */
11897 : 1570448 : accum_sum_rescale(accum, val);
11898 : :
11899 : : /* */
11900 [ + + ]: 1570448 : if (val->sign == NUMERIC_POS)
11901 : 1169996 : accum_digits = accum->pos_digits;
11902 : : else
11903 : 400452 : accum_digits = accum->neg_digits;
11904 : :
11905 : : /* copy these values into local vars for speed in loop */
11906 : 1570448 : val_ndigits = val->ndigits;
11907 : 1570448 : val_digits = val->digits;
11908 : :
11909 : 1570448 : i = accum->weight - val->weight;
11910 [ + + ]: 7926592 : for (val_i = 0; val_i < val_ndigits; val_i++)
11911 : : {
11912 : 6356144 : accum_digits[i] += (int32) val_digits[val_i];
11913 : 6356144 : i++;
11914 : : }
11915 : :
11916 : 1570448 : accum->num_uncarried++;
11917 : 1570448 : }
11918 : :
11919 : : /*
11920 : : * Propagate carries.
11921 : : */
11922 : : static void
11923 : 115168 : accum_sum_carry(NumericSumAccum *accum)
11924 : : {
11925 : : int i;
11926 : : int ndigits;
11927 : : int32 *dig;
11928 : : int32 carry;
11929 : 115168 : int32 newdig = 0;
11930 : :
11931 : : /*
11932 : : * If no new values have been added since last carry propagation, nothing
11933 : : * to do.
11934 : : */
11935 [ + + ]: 115168 : if (accum->num_uncarried == 0)
11936 : 48 : return;
11937 : :
11938 : : /*
11939 : : * We maintain that the weight of the accumulator is always one larger
11940 : : * than needed to hold the current value, before carrying, to make sure
11941 : : * there is enough space for the possible extra digit when carry is
11942 : : * propagated. We cannot expand the buffer here, unless we require
11943 : : * callers of accum_sum_final() to switch to the right memory context.
11944 : : */
11945 [ + - - + ]: 115120 : Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0);
11946 : :
11947 : 115120 : ndigits = accum->ndigits;
11948 : :
11949 : : /* Propagate carry in the positive sum */
11950 : 115120 : dig = accum->pos_digits;
11951 : 115120 : carry = 0;
11952 [ + + ]: 1737020 : for (i = ndigits - 1; i >= 0; i--)
11953 : : {
11954 : 1621900 : newdig = dig[i] + carry;
11955 [ + + ]: 1621900 : if (newdig >= NBASE)
11956 : : {
11957 : 73884 : carry = newdig / NBASE;
11958 : 73884 : newdig -= carry * NBASE;
11959 : : }
11960 : : else
11961 : 1548016 : carry = 0;
11962 : 1621900 : dig[i] = newdig;
11963 : : }
11964 : : /* Did we use up the digit reserved for carry propagation? */
11965 [ + + ]: 115120 : if (newdig > 0)
11966 : 1760 : accum->have_carry_space = false;
11967 : :
11968 : : /* And the same for the negative sum */
11969 : 115120 : dig = accum->neg_digits;
11970 : 115120 : carry = 0;
11971 [ + + ]: 1737020 : for (i = ndigits - 1; i >= 0; i--)
11972 : : {
11973 : 1621900 : newdig = dig[i] + carry;
11974 [ + + ]: 1621900 : if (newdig >= NBASE)
11975 : : {
11976 : 132 : carry = newdig / NBASE;
11977 : 132 : newdig -= carry * NBASE;
11978 : : }
11979 : : else
11980 : 1621768 : carry = 0;
11981 : 1621900 : dig[i] = newdig;
11982 : : }
11983 [ + + ]: 115120 : if (newdig > 0)
11984 : 20 : accum->have_carry_space = false;
11985 : :
11986 : 115120 : accum->num_uncarried = 0;
11987 : : }
11988 : :
11989 : : /*
11990 : : * Re-scale accumulator to accommodate new value.
11991 : : *
11992 : : * If the new value has more digits than the current digit buffers in the
11993 : : * accumulator, enlarge the buffers.
11994 : : */
11995 : : static void
3159 andres@anarazel.de 11996 : 1570448 : accum_sum_rescale(NumericSumAccum *accum, const NumericVar *val)
11997 : : {
3532 heikki.linnakangas@i 11998 : 1570448 : int old_weight = accum->weight;
11999 : 1570448 : int old_ndigits = accum->ndigits;
12000 : : int accum_ndigits;
12001 : : int accum_weight;
12002 : : int accum_rscale;
12003 : : int val_rscale;
12004 : :
12005 : 1570448 : accum_weight = old_weight;
12006 : 1570448 : accum_ndigits = old_ndigits;
12007 : :
12008 : : /*
12009 : : * Does the new value have a larger weight? If so, enlarge the buffers,
12010 : : * and shift the existing value to the new weight, by adding leading
12011 : : * zeros.
12012 : : *
12013 : : * We enforce that the accumulator always has a weight one larger than
12014 : : * needed for the inputs, so that we have space for an extra digit at the
12015 : : * final carry-propagation phase, if necessary.
12016 : : */
12017 [ + + ]: 1570448 : if (val->weight >= accum_weight)
12018 : : {
12019 : 174806 : accum_weight = val->weight + 1;
12020 : 174806 : accum_ndigits = accum_ndigits + (accum_weight - old_weight);
12021 : : }
12022 : :
12023 : : /*
12024 : : * Even though the new value is small, we might've used up the space
12025 : : * reserved for the carry digit in the last call to accum_sum_carry(). If
12026 : : * so, enlarge to make room for another one.
12027 : : */
12028 [ + + ]: 1395642 : else if (!accum->have_carry_space)
12029 : : {
12030 : 62 : accum_weight++;
12031 : 62 : accum_ndigits++;
12032 : : }
12033 : :
12034 : : /* Is the new value wider on the right side? */
12035 : 1570448 : accum_rscale = accum_ndigits - accum_weight - 1;
12036 : 1570448 : val_rscale = val->ndigits - val->weight - 1;
12037 [ + + ]: 1570448 : if (val_rscale > accum_rscale)
12038 : 114822 : accum_ndigits = accum_ndigits + (val_rscale - accum_rscale);
12039 : :
12040 [ + + - + ]: 1570448 : if (accum_ndigits != old_ndigits ||
12041 : : accum_weight != old_weight)
12042 : : {
12043 : : int32 *new_pos_digits;
12044 : : int32 *new_neg_digits;
12045 : : int weightdiff;
12046 : :
12047 : 175068 : weightdiff = accum_weight - old_weight;
12048 : :
12049 : 175068 : new_pos_digits = palloc0(accum_ndigits * sizeof(int32));
12050 : 175068 : new_neg_digits = palloc0(accum_ndigits * sizeof(int32));
12051 : :
12052 [ + + ]: 175068 : if (accum->pos_digits)
12053 : : {
12054 : 60294 : memcpy(&new_pos_digits[weightdiff], accum->pos_digits,
12055 : : old_ndigits * sizeof(int32));
12056 : 60294 : pfree(accum->pos_digits);
12057 : :
12058 : 60294 : memcpy(&new_neg_digits[weightdiff], accum->neg_digits,
12059 : : old_ndigits * sizeof(int32));
12060 : 60294 : pfree(accum->neg_digits);
12061 : : }
12062 : :
12063 : 175068 : accum->pos_digits = new_pos_digits;
12064 : 175068 : accum->neg_digits = new_neg_digits;
12065 : :
12066 : 175068 : accum->weight = accum_weight;
12067 : 175068 : accum->ndigits = accum_ndigits;
12068 : :
12069 [ + - - + ]: 175068 : Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0);
12070 : 175068 : accum->have_carry_space = true;
12071 : : }
12072 : :
12073 [ + + ]: 1570448 : if (val->dscale > accum->dscale)
12074 : 200 : accum->dscale = val->dscale;
12075 : 1570448 : }
12076 : :
12077 : : /*
12078 : : * Return the current value of the accumulator. This perform final carry
12079 : : * propagation, and adds together the positive and negative sums.
12080 : : *
12081 : : * Unlike all the other routines, the caller is not required to switch to
12082 : : * the memory context that holds the accumulator.
12083 : : */
12084 : : static void
12085 : 115058 : accum_sum_final(NumericSumAccum *accum, NumericVar *result)
12086 : : {
12087 : : int i;
12088 : : NumericVar pos_var;
12089 : : NumericVar neg_var;
12090 : :
12091 [ - + ]: 115058 : if (accum->ndigits == 0)
12092 : : {
3532 heikki.linnakangas@i 12093 :UBC 0 : set_var_from_var(&const_zero, result);
12094 : 0 : return;
12095 : : }
12096 : :
12097 : : /* Perform final carry */
3532 heikki.linnakangas@i 12098 :CBC 115058 : accum_sum_carry(accum);
12099 : :
12100 : : /* Create NumericVars representing the positive and negative sums */
12101 : 115058 : init_var(&pos_var);
12102 : 115058 : init_var(&neg_var);
12103 : :
12104 : 115058 : pos_var.ndigits = neg_var.ndigits = accum->ndigits;
12105 : 115058 : pos_var.weight = neg_var.weight = accum->weight;
12106 : 115058 : pos_var.dscale = neg_var.dscale = accum->dscale;
12107 : 115058 : pos_var.sign = NUMERIC_POS;
12108 : 115058 : neg_var.sign = NUMERIC_NEG;
12109 : :
12110 : 115058 : pos_var.buf = pos_var.digits = digitbuf_alloc(accum->ndigits);
12111 : 115058 : neg_var.buf = neg_var.digits = digitbuf_alloc(accum->ndigits);
12112 : :
12113 [ + + ]: 1736712 : for (i = 0; i < accum->ndigits; i++)
12114 : : {
12115 [ - + ]: 1621654 : Assert(accum->pos_digits[i] < NBASE);
12116 : 1621654 : pos_var.digits[i] = (int16) accum->pos_digits[i];
12117 : :
12118 [ - + ]: 1621654 : Assert(accum->neg_digits[i] < NBASE);
12119 : 1621654 : neg_var.digits[i] = (int16) accum->neg_digits[i];
12120 : : }
12121 : :
12122 : : /* And add them together */
12123 : 115058 : add_var(&pos_var, &neg_var, result);
12124 : :
12125 : : /* Remove leading/trailing zeroes */
12126 : 115058 : strip_var(result);
12127 : : }
12128 : :
12129 : : /*
12130 : : * Copy an accumulator's state.
12131 : : *
12132 : : * 'dst' is assumed to be uninitialized beforehand. No attempt is made at
12133 : : * freeing old values.
12134 : : */
12135 : : static void
12136 : 28 : accum_sum_copy(NumericSumAccum *dst, NumericSumAccum *src)
12137 : : {
12138 : 28 : dst->pos_digits = palloc(src->ndigits * sizeof(int32));
12139 : 28 : dst->neg_digits = palloc(src->ndigits * sizeof(int32));
12140 : :
12141 : 28 : memcpy(dst->pos_digits, src->pos_digits, src->ndigits * sizeof(int32));
12142 : 28 : memcpy(dst->neg_digits, src->neg_digits, src->ndigits * sizeof(int32));
12143 : 28 : dst->num_uncarried = src->num_uncarried;
12144 : 28 : dst->ndigits = src->ndigits;
12145 : 28 : dst->weight = src->weight;
12146 : 28 : dst->dscale = src->dscale;
12147 : 28 : }
12148 : :
12149 : : /*
12150 : : * Add the current value of 'accum2' into 'accum'.
12151 : : */
12152 : : static void
12153 : 36 : accum_sum_combine(NumericSumAccum *accum, NumericSumAccum *accum2)
12154 : : {
12155 : : NumericVar tmp_var;
12156 : :
12157 : 36 : init_var(&tmp_var);
12158 : :
12159 : 36 : accum_sum_final(accum2, &tmp_var);
12160 : 36 : accum_sum_add(accum, &tmp_var);
12161 : :
12162 : 36 : free_var(&tmp_var);
12163 : 36 : }
|