#include "postgres.h"#include <ctype.h>#include <float.h>#include <limits.h>#include <math.h>#include "access/hash.h"#include "catalog/pg_type.h"#include "libpq/pqformat.h"#include "miscadmin.h"#include "nodes/nodeFuncs.h"#include "utils/array.h"#include "utils/builtins.h"#include "utils/int8.h"#include "utils/numeric.h"
Go to the source code of this file.
Data Structures | |
| struct | NumericShort |
| struct | NumericLong |
| union | NumericChoice |
| struct | NumericData |
| struct | NumericVar |
| struct | Int8TransTypeData |
Defines | |
| #define | NBASE 10000 |
| #define | HALF_NBASE 5000 |
| #define | DEC_DIGITS 4 |
| #define | MUL_GUARD_DIGITS 2 |
| #define | DIV_GUARD_DIGITS 4 |
| #define | NUMERIC_SIGN_MASK 0xC000 |
| #define | NUMERIC_POS 0x0000 |
| #define | NUMERIC_NEG 0x4000 |
| #define | NUMERIC_SHORT 0x8000 |
| #define | NUMERIC_NAN 0xC000 |
| #define | NUMERIC_FLAGBITS(n) ((n)->choice.n_header & NUMERIC_SIGN_MASK) |
| #define | NUMERIC_IS_NAN(n) (NUMERIC_FLAGBITS(n) == NUMERIC_NAN) |
| #define | NUMERIC_IS_SHORT(n) (NUMERIC_FLAGBITS(n) == NUMERIC_SHORT) |
| #define | NUMERIC_HDRSZ (VARHDRSZ + sizeof(uint16) + sizeof(int16)) |
| #define | NUMERIC_HDRSZ_SHORT (VARHDRSZ + sizeof(uint16)) |
| #define | NUMERIC_HEADER_SIZE(n) |
| #define | NUMERIC_SHORT_SIGN_MASK 0x2000 |
| #define | NUMERIC_SHORT_DSCALE_MASK 0x1F80 |
| #define | NUMERIC_SHORT_DSCALE_SHIFT 7 |
| #define | NUMERIC_SHORT_DSCALE_MAX (NUMERIC_SHORT_DSCALE_MASK >> NUMERIC_SHORT_DSCALE_SHIFT) |
| #define | NUMERIC_SHORT_WEIGHT_SIGN_MASK 0x0040 |
| #define | NUMERIC_SHORT_WEIGHT_MASK 0x003F |
| #define | NUMERIC_SHORT_WEIGHT_MAX NUMERIC_SHORT_WEIGHT_MASK |
| #define | NUMERIC_SHORT_WEIGHT_MIN (-(NUMERIC_SHORT_WEIGHT_MASK+1)) |
| #define | NUMERIC_DSCALE_MASK 0x3FFF |
| #define | NUMERIC_SIGN(n) |
| #define | NUMERIC_DSCALE(n) |
| #define | NUMERIC_WEIGHT(n) |
| #define | dump_numeric(s, n) |
| #define | dump_var(s, v) |
| #define | digitbuf_alloc(ndigits) ((NumericDigit *) palloc((ndigits) * sizeof(NumericDigit))) |
| #define | digitbuf_free(buf) |
| #define | init_var(v) MemSetAligned(v, 0, sizeof(NumericVar)) |
| #define | NUMERIC_DIGITS(num) |
| #define | NUMERIC_NDIGITS(num) ((VARSIZE(num) - NUMERIC_HEADER_SIZE(num)) / sizeof(NumericDigit)) |
| #define | NUMERIC_CAN_BE_SHORT(scale, weight) |
Typedefs | |
| typedef int16 | NumericDigit |
| typedef struct NumericVar | NumericVar |
| typedef struct Int8TransTypeData | Int8TransTypeData |
Functions | |
| static void | alloc_var (NumericVar *var, int ndigits) |
| static void | free_var (NumericVar *var) |
| static void | zero_var (NumericVar *var) |
| static const char * | set_var_from_str (const char *str, const char *cp, NumericVar *dest) |
| static void | set_var_from_num (Numeric value, NumericVar *dest) |
| static void | init_var_from_num (Numeric num, NumericVar *dest) |
| static void | set_var_from_var (NumericVar *value, NumericVar *dest) |
| static char * | get_str_from_var (NumericVar *var) |
| static char * | get_str_from_var_sci (NumericVar *var, int rscale) |
| static Numeric | make_result (NumericVar *var) |
| static void | apply_typmod (NumericVar *var, int32 typmod) |
| static int32 | numericvar_to_int4 (NumericVar *var) |
| static bool | numericvar_to_int8 (NumericVar *var, int64 *result) |
| static void | int8_to_numericvar (int64 val, NumericVar *var) |
| static double | numeric_to_double_no_overflow (Numeric num) |
| static double | numericvar_to_double_no_overflow (NumericVar *var) |
| static int | cmp_numerics (Numeric num1, Numeric num2) |
| static int | cmp_var (NumericVar *var1, NumericVar *var2) |
| static int | cmp_var_common (const NumericDigit *var1digits, int var1ndigits, int var1weight, int var1sign, const NumericDigit *var2digits, int var2ndigits, int var2weight, int var2sign) |
| static void | add_var (NumericVar *var1, NumericVar *var2, NumericVar *result) |
| static void | sub_var (NumericVar *var1, NumericVar *var2, NumericVar *result) |
| static void | mul_var (NumericVar *var1, NumericVar *var2, NumericVar *result, int rscale) |
| static void | div_var (NumericVar *var1, NumericVar *var2, NumericVar *result, int rscale, bool round) |
| static void | div_var_fast (NumericVar *var1, NumericVar *var2, NumericVar *result, int rscale, bool round) |
| static int | select_div_scale (NumericVar *var1, NumericVar *var2) |
| static void | mod_var (NumericVar *var1, NumericVar *var2, NumericVar *result) |
| static void | ceil_var (NumericVar *var, NumericVar *result) |
| static void | floor_var (NumericVar *var, NumericVar *result) |
| static void | sqrt_var (NumericVar *arg, NumericVar *result, int rscale) |
| static void | exp_var (NumericVar *arg, NumericVar *result, int rscale) |
| static void | exp_var_internal (NumericVar *arg, NumericVar *result, int rscale) |
| static void | ln_var (NumericVar *arg, NumericVar *result, int rscale) |
| static void | log_var (NumericVar *base, NumericVar *num, NumericVar *result) |
| static void | power_var (NumericVar *base, NumericVar *exp, NumericVar *result) |
| static void | power_var_int (NumericVar *base, int exp, NumericVar *result, int rscale) |
| static int | cmp_abs (NumericVar *var1, NumericVar *var2) |
| static int | cmp_abs_common (const NumericDigit *var1digits, int var1ndigits, int var1weight, const NumericDigit *var2digits, int var2ndigits, int var2weight) |
| static void | add_abs (NumericVar *var1, NumericVar *var2, NumericVar *result) |
| static void | sub_abs (NumericVar *var1, NumericVar *var2, NumericVar *result) |
| static void | round_var (NumericVar *var, int rscale) |
| static void | trunc_var (NumericVar *var, int rscale) |
| static void | strip_var (NumericVar *var) |
| static void | compute_bucket (Numeric operand, Numeric bound1, Numeric bound2, NumericVar *count_var, NumericVar *result_var) |
| Datum | numeric_in (PG_FUNCTION_ARGS) |
| Datum | numeric_out (PG_FUNCTION_ARGS) |
| bool | numeric_is_nan (Numeric num) |
| int32 | numeric_maximum_size (int32 typmod) |
| char * | numeric_out_sci (Numeric num, int scale) |
| Datum | numeric_recv (PG_FUNCTION_ARGS) |
| Datum | numeric_send (PG_FUNCTION_ARGS) |
| Datum | numeric_transform (PG_FUNCTION_ARGS) |
| Datum | numeric (PG_FUNCTION_ARGS) |
| Datum | numerictypmodin (PG_FUNCTION_ARGS) |
| Datum | numerictypmodout (PG_FUNCTION_ARGS) |
| Datum | numeric_abs (PG_FUNCTION_ARGS) |
| Datum | numeric_uminus (PG_FUNCTION_ARGS) |
| Datum | numeric_uplus (PG_FUNCTION_ARGS) |
| Datum | numeric_sign (PG_FUNCTION_ARGS) |
| Datum | numeric_round (PG_FUNCTION_ARGS) |
| Datum | numeric_trunc (PG_FUNCTION_ARGS) |
| Datum | numeric_ceil (PG_FUNCTION_ARGS) |
| Datum | numeric_floor (PG_FUNCTION_ARGS) |
| Datum | width_bucket_numeric (PG_FUNCTION_ARGS) |
| Datum | numeric_cmp (PG_FUNCTION_ARGS) |
| Datum | numeric_eq (PG_FUNCTION_ARGS) |
| Datum | numeric_ne (PG_FUNCTION_ARGS) |
| Datum | numeric_gt (PG_FUNCTION_ARGS) |
| Datum | numeric_ge (PG_FUNCTION_ARGS) |
| Datum | numeric_lt (PG_FUNCTION_ARGS) |
| Datum | numeric_le (PG_FUNCTION_ARGS) |
| Datum | hash_numeric (PG_FUNCTION_ARGS) |
| Datum | numeric_add (PG_FUNCTION_ARGS) |
| Datum | numeric_sub (PG_FUNCTION_ARGS) |
| Datum | numeric_mul (PG_FUNCTION_ARGS) |
| Datum | numeric_div (PG_FUNCTION_ARGS) |
| Datum | numeric_div_trunc (PG_FUNCTION_ARGS) |
| Datum | numeric_mod (PG_FUNCTION_ARGS) |
| Datum | numeric_inc (PG_FUNCTION_ARGS) |
| Datum | numeric_smaller (PG_FUNCTION_ARGS) |
| Datum | numeric_larger (PG_FUNCTION_ARGS) |
| Datum | numeric_fac (PG_FUNCTION_ARGS) |
| Datum | numeric_sqrt (PG_FUNCTION_ARGS) |
| Datum | numeric_exp (PG_FUNCTION_ARGS) |
| Datum | numeric_ln (PG_FUNCTION_ARGS) |
| Datum | numeric_log (PG_FUNCTION_ARGS) |
| Datum | numeric_power (PG_FUNCTION_ARGS) |
| Datum | int4_numeric (PG_FUNCTION_ARGS) |
| Datum | numeric_int4 (PG_FUNCTION_ARGS) |
| Datum | int8_numeric (PG_FUNCTION_ARGS) |
| Datum | numeric_int8 (PG_FUNCTION_ARGS) |
| Datum | int2_numeric (PG_FUNCTION_ARGS) |
| Datum | numeric_int2 (PG_FUNCTION_ARGS) |
| Datum | float8_numeric (PG_FUNCTION_ARGS) |
| Datum | numeric_float8 (PG_FUNCTION_ARGS) |
| Datum | numeric_float8_no_overflow (PG_FUNCTION_ARGS) |
| Datum | float4_numeric (PG_FUNCTION_ARGS) |
| Datum | numeric_float4 (PG_FUNCTION_ARGS) |
| static ArrayType * | do_numeric_accum (ArrayType *transarray, Numeric newval) |
| static ArrayType * | do_numeric_avg_accum (ArrayType *transarray, Numeric newval) |
| Datum | numeric_accum (PG_FUNCTION_ARGS) |
| Datum | numeric_avg_accum (PG_FUNCTION_ARGS) |
| Datum | int2_accum (PG_FUNCTION_ARGS) |
| Datum | int4_accum (PG_FUNCTION_ARGS) |
| Datum | int8_accum (PG_FUNCTION_ARGS) |
| Datum | int8_avg_accum (PG_FUNCTION_ARGS) |
| Datum | numeric_avg (PG_FUNCTION_ARGS) |
| static Numeric | numeric_stddev_internal (ArrayType *transarray, bool variance, bool sample, bool *is_null) |
| Datum | numeric_var_samp (PG_FUNCTION_ARGS) |
| Datum | numeric_stddev_samp (PG_FUNCTION_ARGS) |
| Datum | numeric_var_pop (PG_FUNCTION_ARGS) |
| Datum | numeric_stddev_pop (PG_FUNCTION_ARGS) |
| Datum | int2_sum (PG_FUNCTION_ARGS) |
| Datum | int4_sum (PG_FUNCTION_ARGS) |
| Datum | int8_sum (PG_FUNCTION_ARGS) |
| Datum | int2_avg_accum (PG_FUNCTION_ARGS) |
| Datum | int4_avg_accum (PG_FUNCTION_ARGS) |
| Datum | int8_avg (PG_FUNCTION_ARGS) |
Variables | |
| static NumericDigit | const_zero_data [1] = {0} |
| static NumericVar | const_zero |
| static NumericDigit | const_one_data [1] = {1} |
| static NumericVar | const_one |
| static NumericDigit | const_two_data [1] = {2} |
| static NumericVar | const_two |
| static NumericDigit | const_ten_data [1] = {10} |
| static NumericVar | const_ten |
| static NumericDigit | const_zero_point_five_data [1] = {5000} |
| static NumericVar | const_zero_point_five |
| static NumericDigit | const_zero_point_nine_data [1] = {9000} |
| static NumericVar | const_zero_point_nine |
| static NumericDigit | const_zero_point_01_data [1] = {100} |
| static NumericVar | const_zero_point_01 |
| static NumericDigit | const_one_point_one_data [2] = {1, 1000} |
| static NumericVar | const_one_point_one |
| static NumericVar | const_nan |
| static const int | round_powers [4] = {0, 1000, 100, 10} |
| #define DEC_DIGITS 4 |
Definition at line 85 of file numeric.c.
Referenced by apply_typmod(), div_var(), div_var_fast(), get_str_from_var(), get_str_from_var_sci(), int8_to_numericvar(), ln_var(), log_var(), numeric(), numeric_ln(), numeric_maximum_size(), numeric_sqrt(), power_var(), round_var(), set_var_from_str(), and trunc_var().
| #define digitbuf_alloc | ( | ndigits | ) | ((NumericDigit *) palloc((ndigits) * sizeof(NumericDigit))) |
Definition at line 354 of file numeric.c.
Referenced by add_abs(), alloc_var(), set_var_from_var(), and sub_abs().
| #define digitbuf_free | ( | buf | ) |
Definition at line 356 of file numeric.c.
Referenced by add_abs(), alloc_var(), free_var(), set_var_from_var(), sub_abs(), and zero_var().
| #define DIV_GUARD_DIGITS 4 |
Definition at line 87 of file numeric.c.
Referenced by div_var_fast().
| #define dump_numeric | ( | s, | ||
| n | ||||
| ) |
Definition at line 350 of file numeric.c.
Referenced by make_result().
| #define init_var | ( | v | ) | MemSetAligned(v, 0, sizeof(NumericVar)) |
Definition at line 362 of file numeric.c.
Referenced by ceil_var(), exp_var(), exp_var_internal(), float4_numeric(), float8_numeric(), floor_var(), get_str_from_var_sci(), int2_numeric(), int4_numeric(), int8_numeric(), ln_var(), log_var(), mod_var(), numeric(), numeric_add(), numeric_div(), numeric_div_trunc(), numeric_exp(), numeric_fac(), numeric_in(), numeric_ln(), numeric_log(), numeric_mod(), numeric_mul(), numeric_power(), numeric_recv(), numeric_round(), numeric_sign(), numeric_sqrt(), numeric_stddev_internal(), numeric_sub(), numeric_trunc(), numericvar_to_int8(), power_var(), power_var_int(), sqrt_var(), and width_bucket_numeric().
| #define MUL_GUARD_DIGITS 2 |
Definition at line 86 of file numeric.c.
Referenced by exp_var(), mul_var(), and power_var_int().
| #define NBASE 10000 |
Definition at line 83 of file numeric.c.
Referenced by add_abs(), div_var(), div_var_fast(), mul_var(), numeric_recv(), numericvar_to_int8(), and round_var().
| #define NUMERIC_CAN_BE_SHORT | ( | scale, | ||
| weight | ||||
| ) |
((scale) <= NUMERIC_SHORT_DSCALE_MAX && \ (weight) <= NUMERIC_SHORT_WEIGHT_MAX && \ (weight) >= NUMERIC_SHORT_WEIGHT_MIN)
Definition at line 368 of file numeric.c.
Referenced by make_result(), and numeric().
| #define NUMERIC_DIGITS | ( | num | ) |
(NUMERIC_IS_SHORT(num) ? \ (num)->choice.n_short.n_data : (num)->choice.n_long.n_data)
Definition at line 364 of file numeric.c.
Referenced by cmp_numerics(), hash_numeric(), init_var_from_num(), make_result(), and set_var_from_num().
| #define NUMERIC_DSCALE | ( | n | ) |
(NUMERIC_IS_SHORT((n)) ? \ ((n)->choice.n_short.n_header & NUMERIC_SHORT_DSCALE_MASK) \ >> NUMERIC_SHORT_DSCALE_SHIFT \ : ((n)->choice.n_long.n_sign_dscale & NUMERIC_DSCALE_MASK))
Definition at line 199 of file numeric.c.
Referenced by init_var_from_num(), make_result(), numeric(), numeric_abs(), numeric_uminus(), and set_var_from_num().
| #define NUMERIC_DSCALE_MASK 0x3FFF |
| #define NUMERIC_FLAGBITS | ( | n | ) | ((n)->choice.n_header & NUMERIC_SIGN_MASK) |
Definition at line 163 of file numeric.c.
Referenced by make_result(), and numeric_maximum_size().
| #define NUMERIC_HDRSZ_SHORT (VARHDRSZ + sizeof(uint16)) |
Definition at line 164 of file numeric.c.
Referenced by make_result().
| #define NUMERIC_HEADER_SIZE | ( | n | ) |
(VARHDRSZ + sizeof(uint16) + \ (((NUMERIC_FLAGBITS(n) & 0x8000) == 0) ? sizeof(int16) : 0))
| #define NUMERIC_IS_NAN | ( | n | ) | (NUMERIC_FLAGBITS(n) == NUMERIC_NAN) |
Definition at line 160 of file numeric.c.
Referenced by cmp_numerics(), hash_numeric(), numeric(), numeric_abs(), numeric_add(), numeric_ceil(), numeric_div(), numeric_div_trunc(), numeric_exp(), numeric_float4(), numeric_float8(), numeric_float8_no_overflow(), numeric_floor(), numeric_inc(), numeric_int2(), numeric_int4(), numeric_int8(), numeric_is_nan(), numeric_ln(), numeric_log(), numeric_mod(), numeric_mul(), numeric_out(), numeric_out_sci(), numeric_power(), numeric_round(), numeric_sign(), numeric_sqrt(), numeric_stddev_internal(), numeric_sub(), numeric_trunc(), numeric_uminus(), and width_bucket_numeric().
| #define NUMERIC_IS_SHORT | ( | n | ) | (NUMERIC_FLAGBITS(n) == NUMERIC_SHORT) |
Definition at line 161 of file numeric.c.
Referenced by numeric(), numeric_abs(), and numeric_uminus().
| #define NUMERIC_NAN 0xC000 |
Definition at line 157 of file numeric.c.
Referenced by get_str_from_var(), main(), make_result(), and numeric_recv().
| #define NUMERIC_NDIGITS | ( | num | ) | ((VARSIZE(num) - NUMERIC_HEADER_SIZE(num)) / sizeof(NumericDigit)) |
Definition at line 366 of file numeric.c.
Referenced by cmp_numerics(), hash_numeric(), init_var_from_num(), make_result(), numeric_avg(), numeric_sign(), numeric_uminus(), and set_var_from_num().
| #define NUMERIC_NEG 0x4000 |
Definition at line 155 of file numeric.c.
Referenced by cmp_var_common(), exp_var(), floor_var(), get_str_from_var(), make_result(), numeric_recv(), numeric_uminus(), PGTYPESnumeric_cmp(), PGTYPESnumeric_sub(), and sub_var().
| #define NUMERIC_POS 0x0000 |
Definition at line 154 of file numeric.c.
Referenced by add_var(), ceil_var(), cmp_var_common(), exp_var_internal(), numeric_abs(), numeric_recv(), numeric_uminus(), PGTYPESnumeric_add(), PGTYPESnumeric_cmp(), PGTYPESnumeric_sub(), and sub_var().
| #define NUMERIC_SHORT 0x8000 |
Definition at line 156 of file numeric.c.
Referenced by make_result().
| #define NUMERIC_SHORT_DSCALE_MAX (NUMERIC_SHORT_DSCALE_MASK >> NUMERIC_SHORT_DSCALE_SHIFT) |
| #define NUMERIC_SHORT_DSCALE_SHIFT 7 |
| #define NUMERIC_SHORT_WEIGHT_MAX NUMERIC_SHORT_WEIGHT_MASK |
| #define NUMERIC_SHORT_WEIGHT_MIN (-(NUMERIC_SHORT_WEIGHT_MASK+1)) |
| #define NUMERIC_SHORT_WEIGHT_SIGN_MASK 0x0040 |
Definition at line 184 of file numeric.c.
Referenced by make_result().
| #define NUMERIC_SIGN | ( | n | ) |
(NUMERIC_IS_SHORT(n) ? \ (((n)->choice.n_short.n_header & NUMERIC_SHORT_SIGN_MASK) ? \ NUMERIC_NEG : NUMERIC_POS) : NUMERIC_FLAGBITS(n))
Definition at line 195 of file numeric.c.
Referenced by cmp_numerics(), init_var_from_num(), numeric(), numeric_sign(), numeric_uminus(), and set_var_from_num().
| #define NUMERIC_WEIGHT | ( | n | ) |
(NUMERIC_IS_SHORT((n)) ? \ (((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_SIGN_MASK ? \ ~NUMERIC_SHORT_WEIGHT_MASK : 0) \ | ((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \ : ((n)->choice.n_long.n_weight))
Definition at line 203 of file numeric.c.
Referenced by cmp_numerics(), hash_numeric(), init_var_from_num(), make_result(), numeric(), and set_var_from_num().
| typedef struct Int8TransTypeData Int8TransTypeData |
| typedef int16 NumericDigit |
| typedef struct NumericVar NumericVar |
| static void add_abs | ( | NumericVar * | var1, | |
| NumericVar * | var2, | |||
| NumericVar * | result | |||
| ) | [static] |
Definition at line 5811 of file numeric.c.
References Assert, NumericVar::buf, digitbuf_alloc, digitbuf_free, NumericVar::digits, NumericVar::dscale, Max, NBASE, NumericVar::ndigits, strip_var(), and NumericVar::weight.
Referenced by add_var(), and sub_var().
{
NumericDigit *res_buf;
NumericDigit *res_digits;
int res_ndigits;
int res_weight;
int res_rscale,
rscale1,
rscale2;
int res_dscale;
int i,
i1,
i2;
int carry = 0;
/* copy these values into local vars for speed in inner loop */
int var1ndigits = var1->ndigits;
int var2ndigits = var2->ndigits;
NumericDigit *var1digits = var1->digits;
NumericDigit *var2digits = var2->digits;
res_weight = Max(var1->weight, var2->weight) + 1;
res_dscale = Max(var1->dscale, var2->dscale);
/* Note: here we are figuring rscale in base-NBASE digits */
rscale1 = var1->ndigits - var1->weight - 1;
rscale2 = var2->ndigits - var2->weight - 1;
res_rscale = Max(rscale1, rscale2);
res_ndigits = res_rscale + res_weight + 1;
if (res_ndigits <= 0)
res_ndigits = 1;
res_buf = digitbuf_alloc(res_ndigits + 1);
res_buf[0] = 0; /* spare digit for later rounding */
res_digits = res_buf + 1;
i1 = res_rscale + var1->weight + 1;
i2 = res_rscale + var2->weight + 1;
for (i = res_ndigits - 1; i >= 0; i--)
{
i1--;
i2--;
if (i1 >= 0 && i1 < var1ndigits)
carry += var1digits[i1];
if (i2 >= 0 && i2 < var2ndigits)
carry += var2digits[i2];
if (carry >= NBASE)
{
res_digits[i] = carry - NBASE;
carry = 1;
}
else
{
res_digits[i] = carry;
carry = 0;
}
}
Assert(carry == 0); /* else we failed to allow for carry out */
digitbuf_free(result->buf);
result->ndigits = res_ndigits;
result->buf = res_buf;
result->digits = res_digits;
result->weight = res_weight;
result->dscale = res_dscale;
/* Remove leading/trailing zeroes */
strip_var(result);
}
| static void add_var | ( | NumericVar * | var1, | |
| NumericVar * | var2, | |||
| NumericVar * | result | |||
| ) | [static] |
Definition at line 4073 of file numeric.c.
References add_abs(), cmp_abs(), NumericVar::dscale, Max, NUMERIC_POS, NumericVar::sign, sub_abs(), and zero_var().
Referenced by ceil_var(), compute_bucket(), exp_var_internal(), ln_var(), numeric_add(), numeric_inc(), sqrt_var(), and width_bucket_numeric().
{
/*
* Decide on the signs of the two variables what to do
*/
if (var1->sign == NUMERIC_POS)
{
if (var2->sign == NUMERIC_POS)
{
/*
* Both are positive result = +(ABS(var1) + ABS(var2))
*/
add_abs(var1, var2, result);
result->sign = NUMERIC_POS;
}
else
{
/*
* var1 is positive, var2 is negative Must compare absolute values
*/
switch (cmp_abs(var1, var2))
{
case 0:
/* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
zero_var(result);
result->dscale = Max(var1->dscale, var2->dscale);
break;
case 1:
/* ----------
* ABS(var1) > ABS(var2)
* result = +(ABS(var1) - ABS(var2))
* ----------
*/
sub_abs(var1, var2, result);
result->sign = NUMERIC_POS;
break;
case -1:
/* ----------
* ABS(var1) < ABS(var2)
* result = -(ABS(var2) - ABS(var1))
* ----------
*/
sub_abs(var2, var1, result);
result->sign = NUMERIC_NEG;
break;
}
}
}
else
{
if (var2->sign == NUMERIC_POS)
{
/* ----------
* var1 is negative, var2 is positive
* Must compare absolute values
* ----------
*/
switch (cmp_abs(var1, var2))
{
case 0:
/* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
zero_var(result);
result->dscale = Max(var1->dscale, var2->dscale);
break;
case 1:
/* ----------
* ABS(var1) > ABS(var2)
* result = -(ABS(var1) - ABS(var2))
* ----------
*/
sub_abs(var1, var2, result);
result->sign = NUMERIC_NEG;
break;
case -1:
/* ----------
* ABS(var1) < ABS(var2)
* result = +(ABS(var2) - ABS(var1))
* ----------
*/
sub_abs(var2, var1, result);
result->sign = NUMERIC_POS;
break;
}
}
else
{
/* ----------
* Both are negative
* result = -(ABS(var1) + ABS(var2))
* ----------
*/
add_abs(var1, var2, result);
result->sign = NUMERIC_NEG;
}
}
}
| static void alloc_var | ( | NumericVar * | var, | |
| int | ndigits | |||
| ) | [static] |
Definition at line 3157 of file numeric.c.
References NumericVar::buf, digitbuf_alloc, digitbuf_free, NumericVar::digits, and NumericVar::ndigits.
Referenced by div_var(), div_var_fast(), int8_to_numericvar(), mul_var(), numeric_recv(), set_var_from_num(), set_var_from_str(), and sqrt_var().
{
digitbuf_free(var->buf);
var->buf = digitbuf_alloc(ndigits + 1);
var->buf[0] = 0; /* spare digit for rounding */
var->digits = var->buf + 1;
var->ndigits = ndigits;
}
| static void apply_typmod | ( | NumericVar * | var, | |
| int32 | typmod | |||
| ) | [static] |
Definition at line 3764 of file numeric.c.
References DEC_DIGITS, NumericVar::digits, ereport, errcode(), errdetail(), errmsg(), ERROR, maxdigits, NumericVar::ndigits, round_var(), scale, VARHDRSZ, and NumericVar::weight.
Referenced by numeric(), numeric_in(), and numeric_recv().
{
int precision;
int scale;
int maxdigits;
int ddigits;
int i;
/* Do nothing if we have a default typmod (-1) */
if (typmod < (int32) (VARHDRSZ))
return;
typmod -= VARHDRSZ;
precision = (typmod >> 16) & 0xffff;
scale = typmod & 0xffff;
maxdigits = precision - scale;
/* Round to target scale (and set var->dscale) */
round_var(var, scale);
/*
* Check for overflow - note we can't do this before rounding, because
* rounding could raise the weight. Also note that the var's weight could
* be inflated by leading zeroes, which will be stripped before storage
* but perhaps might not have been yet. In any case, we must recognize a
* true zero, whose weight doesn't mean anything.
*/
ddigits = (var->weight + 1) * DEC_DIGITS;
if (ddigits > maxdigits)
{
/* Determine true weight; and check for all-zero result */
for (i = 0; i < var->ndigits; i++)
{
NumericDigit dig = var->digits[i];
if (dig)
{
/* Adjust for any high-order decimal zero digits */
#if DEC_DIGITS == 4
if (dig < 10)
ddigits -= 3;
else if (dig < 100)
ddigits -= 2;
else if (dig < 1000)
ddigits -= 1;
#elif DEC_DIGITS == 2
if (dig < 10)
ddigits -= 1;
#elif DEC_DIGITS == 1
/* no adjustment */
#else
#error unsupported NBASE
#endif
if (ddigits > maxdigits)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("numeric field overflow"),
errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.",
precision, scale,
/* Display 10^0 as 1 */
maxdigits ? "10^" : "",
maxdigits ? maxdigits : 1
)));
break;
}
ddigits -= DEC_DIGITS;
}
}
}
| static void ceil_var | ( | NumericVar * | var, | |
| NumericVar * | result | |||
| ) | [static] |
Definition at line 5114 of file numeric.c.
References add_var(), cmp_var(), free_var(), init_var, NUMERIC_POS, set_var_from_var(), NumericVar::sign, and trunc_var().
Referenced by numeric_ceil().
{
NumericVar tmp;
init_var(&tmp);
set_var_from_var(var, &tmp);
trunc_var(&tmp, 0);
if (var->sign == NUMERIC_POS && cmp_var(var, &tmp) != 0)
add_var(&tmp, &const_one, &tmp);
set_var_from_var(&tmp, result);
free_var(&tmp);
}
| static int cmp_abs | ( | NumericVar * | var1, | |
| NumericVar * | var2 | |||
| ) | [static] |
Definition at line 5733 of file numeric.c.
References cmp_abs_common(), NumericVar::digits, NumericVar::ndigits, and NumericVar::weight.
| static int cmp_abs_common | ( | const NumericDigit * | var1digits, | |
| int | var1ndigits, | |||
| int | var1weight, | |||
| const NumericDigit * | var2digits, | |||
| int | var2ndigits, | |||
| int | var2weight | |||
| ) | [static] |
Definition at line 5747 of file numeric.c.
Referenced by cmp_abs(), and cmp_var_common().
{
int i1 = 0;
int i2 = 0;
/* Check any digits before the first common digit */
while (var1weight > var2weight && i1 < var1ndigits)
{
if (var1digits[i1++] != 0)
return 1;
var1weight--;
}
while (var2weight > var1weight && i2 < var2ndigits)
{
if (var2digits[i2++] != 0)
return -1;
var2weight--;
}
/* At this point, either w1 == w2 or we've run out of digits */
if (var1weight == var2weight)
{
while (i1 < var1ndigits && i2 < var2ndigits)
{
int stat = var1digits[i1++] - var2digits[i2++];
if (stat)
{
if (stat > 0)
return 1;
return -1;
}
}
}
/*
* At this point, we've run out of digits on one side or the other; so any
* remaining nonzero digits imply that side is larger
*/
while (i1 < var1ndigits)
{
if (var1digits[i1++] != 0)
return 1;
}
while (i2 < var2ndigits)
{
if (var2digits[i2++] != 0)
return -1;
}
return 0;
}
Definition at line 1426 of file numeric.c.
References cmp_var_common(), NUMERIC_DIGITS, NUMERIC_IS_NAN, NUMERIC_NDIGITS, NUMERIC_SIGN, and NUMERIC_WEIGHT.
Referenced by numeric_cmp(), numeric_eq(), numeric_ge(), numeric_gt(), numeric_larger(), numeric_le(), numeric_lt(), numeric_ne(), numeric_smaller(), and width_bucket_numeric().
{
int result;
/*
* We consider all NANs to be equal and larger than any non-NAN. This is
* somewhat arbitrary; the important thing is to have a consistent sort
* order.
*/
if (NUMERIC_IS_NAN(num1))
{
if (NUMERIC_IS_NAN(num2))
result = 0; /* NAN = NAN */
else
result = 1; /* NAN > non-NAN */
}
else if (NUMERIC_IS_NAN(num2))
{
result = -1; /* non-NAN < NAN */
}
else
{
result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1),
NUMERIC_WEIGHT(num1), NUMERIC_SIGN(num1),
NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2),
NUMERIC_WEIGHT(num2), NUMERIC_SIGN(num2));
}
return result;
}
| static int cmp_var | ( | NumericVar * | var1, | |
| NumericVar * | var2 | |||
| ) | [static] |
Definition at line 4015 of file numeric.c.
References cmp_var_common(), NumericVar::digits, NumericVar::ndigits, NumericVar::sign, and NumericVar::weight.
Referenced by ceil_var(), compute_bucket(), exp_var_internal(), floor_var(), ln_var(), numeric_power(), numeric_stddev_internal(), power_var(), and sqrt_var().
| static int cmp_var_common | ( | const NumericDigit * | var1digits, | |
| int | var1ndigits, | |||
| int | var1weight, | |||
| int | var1sign, | |||
| const NumericDigit * | var2digits, | |||
| int | var2ndigits, | |||
| int | var2weight, | |||
| int | var2sign | |||
| ) | [static] |
Definition at line 4030 of file numeric.c.
References cmp_abs_common(), NUMERIC_NEG, and NUMERIC_POS.
Referenced by cmp_numerics(), and cmp_var().
{
if (var1ndigits == 0)
{
if (var2ndigits == 0)
return 0;
if (var2sign == NUMERIC_NEG)
return 1;
return -1;
}
if (var2ndigits == 0)
{
if (var1sign == NUMERIC_POS)
return 1;
return -1;
}
if (var1sign == NUMERIC_POS)
{
if (var2sign == NUMERIC_NEG)
return 1;
return cmp_abs_common(var1digits, var1ndigits, var1weight,
var2digits, var2ndigits, var2weight);
}
if (var2sign == NUMERIC_POS)
return -1;
return cmp_abs_common(var2digits, var2ndigits, var2weight,
var1digits, var1ndigits, var1weight);
}
| static void compute_bucket | ( | Numeric | operand, | |
| Numeric | bound1, | |||
| Numeric | bound2, | |||
| NumericVar * | count_var, | |||
| NumericVar * | result_var | |||
| ) | [static] |
Definition at line 1272 of file numeric.c.
References add_var(), cmp_var(), div_var(), NumericVar::dscale, floor_var(), free_var(), init_var_from_num(), mul_var(), select_div_scale(), and sub_var().
Referenced by width_bucket_numeric().
{
NumericVar bound1_var;
NumericVar bound2_var;
NumericVar operand_var;
init_var_from_num(bound1, &bound1_var);
init_var_from_num(bound2, &bound2_var);
init_var_from_num(operand, &operand_var);
if (cmp_var(&bound1_var, &bound2_var) < 0)
{
sub_var(&operand_var, &bound1_var, &operand_var);
sub_var(&bound2_var, &bound1_var, &bound2_var);
div_var(&operand_var, &bound2_var, result_var,
select_div_scale(&operand_var, &bound2_var), true);
}
else
{
sub_var(&bound1_var, &operand_var, &operand_var);
sub_var(&bound1_var, &bound2_var, &bound1_var);
div_var(&operand_var, &bound1_var, result_var,
select_div_scale(&operand_var, &bound1_var), true);
}
mul_var(result_var, count_var, result_var,
result_var->dscale + count_var->dscale);
add_var(result_var, &const_one, result_var);
floor_var(result_var, result_var);
free_var(&bound1_var);
free_var(&bound2_var);
free_var(&operand_var);
}
| static void div_var | ( | NumericVar * | var1, | |
| NumericVar * | var2, | |||
| NumericVar * | result, | |||
| int | rscale, | |||
| bool | round | |||
| ) | [static] |
Definition at line 4482 of file numeric.c.
References alloc_var(), Assert, DEC_DIGITS, NumericVar::digits, NumericVar::dscale, ereport, errcode(), errmsg(), ERROR, HALF_NBASE, Max, NBASE, NumericVar::ndigits, palloc0(), pfree(), round_var(), NumericVar::sign, strip_var(), trunc_var(), NumericVar::weight, and zero_var().
Referenced by compute_bucket(), get_str_from_var_sci(), mod_var(), numeric_div(), numeric_div_trunc(), numeric_stddev_internal(), and power_var_int().
{
int div_ndigits;
int res_ndigits;
int res_sign;
int res_weight;
int carry;
int borrow;
int divisor1;
int divisor2;
NumericDigit *dividend;
NumericDigit *divisor;
NumericDigit *res_digits;
int i;
int j;
/* copy these values into local vars for speed in inner loop */
int var1ndigits = var1->ndigits;
int var2ndigits = var2->ndigits;
/*
* First of all division by zero check; we must not be handed an
* unnormalized divisor.
*/
if (var2ndigits == 0 || var2->digits[0] == 0)
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
/*
* Now result zero check
*/
if (var1ndigits == 0)
{
zero_var(result);
result->dscale = rscale;
return;
}
/*
* Determine the result sign, weight and number of digits to calculate.
* The weight figured here is correct if the emitted quotient has no
* leading zero digits; otherwise strip_var() will fix things up.
*/
if (var1->sign == var2->sign)
res_sign = NUMERIC_POS;
else
res_sign = NUMERIC_NEG;
res_weight = var1->weight - var2->weight;
/* The number of accurate result digits we need to produce: */
res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
/* ... but always at least 1 */
res_ndigits = Max(res_ndigits, 1);
/* If rounding needed, figure one more digit to ensure correct result */
if (round)
res_ndigits++;
/*
* The working dividend normally requires res_ndigits + var2ndigits
* digits, but make it at least var1ndigits so we can load all of var1
* into it. (There will be an additional digit dividend[0] in the
* dividend space, but for consistency with Knuth's notation we don't
* count that in div_ndigits.)
*/
div_ndigits = res_ndigits + var2ndigits;
div_ndigits = Max(div_ndigits, var1ndigits);
/*
* We need a workspace with room for the working dividend (div_ndigits+1
* digits) plus room for the possibly-normalized divisor (var2ndigits
* digits). It is convenient also to have a zero at divisor[0] with the
* actual divisor data in divisor[1 .. var2ndigits]. Transferring the
* digits into the workspace also allows us to realloc the result (which
* might be the same as either input var) before we begin the main loop.
* Note that we use palloc0 to ensure that divisor[0], dividend[0], and
* any additional dividend positions beyond var1ndigits, start out 0.
*/
dividend = (NumericDigit *)
palloc0((div_ndigits + var2ndigits + 2) * sizeof(NumericDigit));
divisor = dividend + (div_ndigits + 1);
memcpy(dividend + 1, var1->digits, var1ndigits * sizeof(NumericDigit));
memcpy(divisor + 1, var2->digits, var2ndigits * sizeof(NumericDigit));
/*
* Now we can realloc the result to hold the generated quotient digits.
*/
alloc_var(result, res_ndigits);
res_digits = result->digits;
if (var2ndigits == 1)
{
/*
* If there's only a single divisor digit, we can use a fast path (cf.
* Knuth section 4.3.1 exercise 16).
*/
divisor1 = divisor[1];
carry = 0;
for (i = 0; i < res_ndigits; i++)
{
carry = carry * NBASE + dividend[i + 1];
res_digits[i] = carry / divisor1;
carry = carry % divisor1;
}
}
else
{
/*
* The full multiple-place algorithm is taken from Knuth volume 2,
* Algorithm 4.3.1D.
*
* We need the first divisor digit to be >= NBASE/2. If it isn't,
* make it so by scaling up both the divisor and dividend by the
* factor "d". (The reason for allocating dividend[0] above is to
* leave room for possible carry here.)
*/
if (divisor[1] < HALF_NBASE)
{
int d = NBASE / (divisor[1] + 1);
carry = 0;
for (i = var2ndigits; i > 0; i--)
{
carry += divisor[i] * d;
divisor[i] = carry % NBASE;
carry = carry / NBASE;
}
Assert(carry == 0);
carry = 0;
/* at this point only var1ndigits of dividend can be nonzero */
for (i = var1ndigits; i >= 0; i--)
{
carry += dividend[i] * d;
dividend[i] = carry % NBASE;
carry = carry / NBASE;
}
Assert(carry == 0);
Assert(divisor[1] >= HALF_NBASE);
}
/* First 2 divisor digits are used repeatedly in main loop */
divisor1 = divisor[1];
divisor2 = divisor[2];
/*
* Begin the main loop. Each iteration of this loop produces the j'th
* quotient digit by dividing dividend[j .. j + var2ndigits] by the
* divisor; this is essentially the same as the common manual
* procedure for long division.
*/
for (j = 0; j < res_ndigits; j++)
{
/* Estimate quotient digit from the first two dividend digits */
int next2digits = dividend[j] * NBASE + dividend[j + 1];
int qhat;
/*
* If next2digits are 0, then quotient digit must be 0 and there's
* no need to adjust the working dividend. It's worth testing
* here to fall out ASAP when processing trailing zeroes in a
* dividend.
*/
if (next2digits == 0)
{
res_digits[j] = 0;
continue;
}
if (dividend[j] == divisor1)
qhat = NBASE - 1;
else
qhat = next2digits / divisor1;
/*
* Adjust quotient digit if it's too large. Knuth proves that
* after this step, the quotient digit will be either correct or
* just one too large. (Note: it's OK to use dividend[j+2] here
* because we know the divisor length is at least 2.)
*/
while (divisor2 * qhat >
(next2digits - qhat * divisor1) * NBASE + dividend[j + 2])
qhat--;
/* As above, need do nothing more when quotient digit is 0 */
if (qhat > 0)
{
/*
* Multiply the divisor by qhat, and subtract that from the
* working dividend. "carry" tracks the multiplication,
* "borrow" the subtraction (could we fold these together?)
*/
carry = 0;
borrow = 0;
for (i = var2ndigits; i >= 0; i--)
{
carry += divisor[i] * qhat;
borrow -= carry % NBASE;
carry = carry / NBASE;
borrow += dividend[j + i];
if (borrow < 0)
{
dividend[j + i] = borrow + NBASE;
borrow = -1;
}
else
{
dividend[j + i] = borrow;
borrow = 0;
}
}
Assert(carry == 0);
/*
* If we got a borrow out of the top dividend digit, then
* indeed qhat was one too large. Fix it, and add back the
* divisor to correct the working dividend. (Knuth proves
* that this will occur only about 3/NBASE of the time; hence,
* it's a good idea to test this code with small NBASE to be
* sure this section gets exercised.)
*/
if (borrow)
{
qhat--;
carry = 0;
for (i = var2ndigits; i >= 0; i--)
{
carry += dividend[j + i] + divisor[i];
if (carry >= NBASE)
{
dividend[j + i] = carry - NBASE;
carry = 1;
}
else
{
dividend[j + i] = carry;
carry = 0;
}
}
/* A carry should occur here to cancel the borrow above */
Assert(carry == 1);
}
}
/* And we're done with this quotient digit */
res_digits[j] = qhat;
}
}
pfree(dividend);
/*
* Finally, round or truncate the result to the requested precision.
*/
result->weight = res_weight;
result->sign = res_sign;
/* Round or truncate to target rscale (and set result->dscale) */
if (round)
round_var(result, rscale);
else
trunc_var(result, rscale);
/* Strip leading and trailing zeroes */
strip_var(result);
}
| static void div_var_fast | ( | NumericVar * | var1, | |
| NumericVar * | var2, | |||
| NumericVar * | result, | |||
| int | rscale, | |||
| bool | round | |||
| ) | [static] |
Definition at line 4761 of file numeric.c.
References Abs, alloc_var(), Assert, DEC_DIGITS, NumericVar::digits, DIV_GUARD_DIGITS, NumericVar::dscale, ereport, errcode(), errmsg(), ERROR, Max, Min, NBASE, NumericVar::ndigits, palloc0(), pfree(), round_var(), NumericVar::sign, strip_var(), trunc_var(), NumericVar::weight, and zero_var().
Referenced by exp_var(), exp_var_internal(), ln_var(), log_var(), power_var_int(), and sqrt_var().
{
int div_ndigits;
int res_sign;
int res_weight;
int *div;
int qdigit;
int carry;
int maxdiv;
int newdig;
NumericDigit *res_digits;
double fdividend,
fdivisor,
fdivisorinverse,
fquotient;
int qi;
int i;
/* copy these values into local vars for speed in inner loop */
int var1ndigits = var1->ndigits;
int var2ndigits = var2->ndigits;
NumericDigit *var1digits = var1->digits;
NumericDigit *var2digits = var2->digits;
/*
* First of all division by zero check; we must not be handed an
* unnormalized divisor.
*/
if (var2ndigits == 0 || var2digits[0] == 0)
ereport(ERROR,
(errcode(ERRCODE_DIVISION_BY_ZERO),
errmsg("division by zero")));
/*
* Now result zero check
*/
if (var1ndigits == 0)
{
zero_var(result);
result->dscale = rscale;
return;
}
/*
* Determine the result sign, weight and number of digits to calculate
*/
if (var1->sign == var2->sign)
res_sign = NUMERIC_POS;
else
res_sign = NUMERIC_NEG;
res_weight = var1->weight - var2->weight + 1;
/* The number of accurate result digits we need to produce: */
div_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
/* Add guard digits for roundoff error */
div_ndigits += DIV_GUARD_DIGITS;
if (div_ndigits < DIV_GUARD_DIGITS)
div_ndigits = DIV_GUARD_DIGITS;
/* Must be at least var1ndigits, too, to simplify data-loading loop */
if (div_ndigits < var1ndigits)
div_ndigits = var1ndigits;
/*
* We do the arithmetic in an array "div[]" of signed int's. Since
* INT_MAX is noticeably larger than NBASE*NBASE, this gives us headroom
* to avoid normalizing carries immediately.
*
* We start with div[] containing one zero digit followed by the
* dividend's digits (plus appended zeroes to reach the desired precision
* including guard digits). Each step of the main loop computes an
* (approximate) quotient digit and stores it into div[], removing one
* position of dividend space. A final pass of carry propagation takes
* care of any mistaken quotient digits.
*/
div = (int *) palloc0((div_ndigits + 1) * sizeof(int));
for (i = 0; i < var1ndigits; i++)
div[i + 1] = var1digits[i];
/*
* We estimate each quotient digit using floating-point arithmetic, taking
* the first four digits of the (current) dividend and divisor. This must
* be float to avoid overflow.
*/
fdivisor = (double) var2digits[0];
for (i = 1; i < 4; i++)
{
fdivisor *= NBASE;
if (i < var2ndigits)
fdivisor += (double) var2digits[i];
}
fdivisorinverse = 1.0 / fdivisor;
/*
* maxdiv tracks the maximum possible absolute value of any div[] entry;
* when this threatens to exceed INT_MAX, we take the time to propagate
* carries. To avoid overflow in maxdiv itself, it actually represents
* the max possible abs. value divided by NBASE-1.
*/
maxdiv = 1;
/*
* Outer loop computes next quotient digit, which will go into div[qi]
*/
for (qi = 0; qi < div_ndigits; qi++)
{
/* Approximate the current dividend value */
fdividend = (double) div[qi];
for (i = 1; i < 4; i++)
{
fdividend *= NBASE;
if (qi + i <= div_ndigits)
fdividend += (double) div[qi + i];
}
/* Compute the (approximate) quotient digit */
fquotient = fdividend * fdivisorinverse;
qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
(((int) fquotient) - 1); /* truncate towards -infinity */
if (qdigit != 0)
{
/* Do we need to normalize now? */
maxdiv += Abs(qdigit);
if (maxdiv > INT_MAX / (NBASE - 1))
{
/* Yes, do it */
carry = 0;
for (i = div_ndigits; i > qi; i--)
{
newdig = div[i] + carry;
if (newdig < 0)
{
carry = -((-newdig - 1) / NBASE) - 1;
newdig -= carry * NBASE;
}
else if (newdig >= NBASE)
{
carry = newdig / NBASE;
newdig -= carry * NBASE;
}
else
carry = 0;
div[i] = newdig;
}
newdig = div[qi] + carry;
div[qi] = newdig;
/*
* All the div[] digits except possibly div[qi] are now in the
* range 0..NBASE-1.
*/
maxdiv = Abs(newdig) / (NBASE - 1);
maxdiv = Max(maxdiv, 1);
/*
* Recompute the quotient digit since new info may have
* propagated into the top four dividend digits
*/
fdividend = (double) div[qi];
for (i = 1; i < 4; i++)
{
fdividend *= NBASE;
if (qi + i <= div_ndigits)
fdividend += (double) div[qi + i];
}
/* Compute the (approximate) quotient digit */
fquotient = fdividend * fdivisorinverse;
qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
(((int) fquotient) - 1); /* truncate towards -infinity */
maxdiv += Abs(qdigit);
}
/* Subtract off the appropriate multiple of the divisor */
if (qdigit != 0)
{
int istop = Min(var2ndigits, div_ndigits - qi + 1);
for (i = 0; i < istop; i++)
div[qi + i] -= qdigit * var2digits[i];
}
}
/*
* The dividend digit we are about to replace might still be nonzero.
* Fold it into the next digit position. We don't need to worry about
* overflow here since this should nearly cancel with the subtraction
* of the divisor.
*/
div[qi + 1] += div[qi] * NBASE;
div[qi] = qdigit;
}
/*
* Approximate and store the last quotient digit (div[div_ndigits])
*/
fdividend = (double) div[qi];
for (i = 1; i < 4; i++)
fdividend *= NBASE;
fquotient = fdividend * fdivisorinverse;
qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
(((int) fquotient) - 1); /* truncate towards -infinity */
div[qi] = qdigit;
/*
* Now we do a final carry propagation pass to normalize the result, which
* we combine with storing the result digits into the output. Note that
* this is still done at full precision w/guard digits.
*/
alloc_var(result, div_ndigits + 1);
res_digits = result->digits;
carry = 0;
for (i = div_ndigits; i >= 0; i--)
{
newdig = div[i] + carry;
if (newdig < 0)
{
carry = -((-newdig - 1) / NBASE) - 1;
newdig -= carry * NBASE;
}
else if (newdig >= NBASE)
{
carry = newdig / NBASE;
newdig -= carry * NBASE;
}
else
carry = 0;
res_digits[i] = newdig;
}
Assert(carry == 0);
pfree(div);
/*
* Finally, round the result to the requested precision.
*/
result->weight = res_weight;
result->sign = res_sign;
/* Round to target rscale (and set result->dscale) */
if (round)
round_var(result, rscale);
else
trunc_var(result, rscale);
/* Strip leading and trailing zeroes */
strip_var(result);
}
Definition at line 2477 of file numeric.c.
References construct_array(), deconstruct_array(), DirectFunctionCall1, DirectFunctionCall2, elog, ERROR, NULL, numeric_add(), numeric_inc(), numeric_mul(), NumericGetDatum, and NUMERICOID.
Referenced by int2_accum(), int4_accum(), int8_accum(), and numeric_accum().
{
Datum *transdatums;
int ndatums;
Datum N,
sumX,
sumX2;
ArrayType *result;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
NUMERICOID, -1, false, 'i',
&transdatums, NULL, &ndatums);
if (ndatums != 3)
elog(ERROR, "expected 3-element numeric array");
N = transdatums[0];
sumX = transdatums[1];
sumX2 = transdatums[2];
N = DirectFunctionCall1(numeric_inc, N);
sumX = DirectFunctionCall2(numeric_add, sumX,
NumericGetDatum(newval));
sumX2 = DirectFunctionCall2(numeric_add, sumX2,
DirectFunctionCall2(numeric_mul,
NumericGetDatum(newval),
NumericGetDatum(newval)));
transdatums[0] = N;
transdatums[1] = sumX;
transdatums[2] = sumX2;
result = construct_array(transdatums, 3,
NUMERICOID, -1, false, 'i');
return result;
}
Definition at line 2518 of file numeric.c.
References construct_array(), deconstruct_array(), DirectFunctionCall1, DirectFunctionCall2, elog, ERROR, NULL, numeric_add(), numeric_inc(), NumericGetDatum, and NUMERICOID.
Referenced by int8_avg_accum(), and numeric_avg_accum().
{
Datum *transdatums;
int ndatums;
Datum N,
sumX;
ArrayType *result;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
NUMERICOID, -1, false, 'i',
&transdatums, NULL, &ndatums);
if (ndatums != 2)
elog(ERROR, "expected 2-element numeric array");
N = transdatums[0];
sumX = transdatums[1];
N = DirectFunctionCall1(numeric_inc, N);
sumX = DirectFunctionCall2(numeric_add, sumX,
NumericGetDatum(newval));
transdatums[0] = N;
transdatums[1] = sumX;
result = construct_array(transdatums, 2,
NUMERICOID, -1, false, 'i');
return result;
}
| static void exp_var | ( | NumericVar * | arg, | |
| NumericVar * | result, | |||
| int | rscale | |||
| ) | [static] |
Definition at line 5234 of file numeric.c.
References NumericVar::digits, div_var_fast(), ereport, errcode(), errmsg(), ERROR, exp_var_internal(), free_var(), init_var, MUL_GUARD_DIGITS, mul_var(), NumericVar::ndigits, NUMERIC_MAX_RESULT_SCALE, NUMERIC_NEG, power_var_int(), round_var(), set_var_from_var(), NumericVar::sign, and NumericVar::weight.
Referenced by numeric_exp(), and power_var().
{
NumericVar x;
int xintval;
bool xneg = FALSE;
int local_rscale;
/*----------
* We separate the integral and fraction parts of x, then compute
* e^x = e^xint * e^xfrac
* where e = exp(1) and e^xfrac = exp(xfrac) are computed by
* exp_var_internal; the limited range of inputs allows that routine
* to do a good job with a simple Taylor series. Raising e^xint is
* done by repeated multiplications in power_var_int.
*----------
*/
init_var(&x);
set_var_from_var(arg, &x);
if (x.sign == NUMERIC_NEG)
{
xneg = TRUE;
x.sign = NUMERIC_POS;
}
/* Extract the integer part, remove it from x */
xintval = 0;
while (x.weight >= 0)
{
xintval *= NBASE;
if (x.ndigits > 0)
{
xintval += x.digits[0];
x.digits++;
x.ndigits--;
}
x.weight--;
/* Guard against overflow */
if (xintval >= NUMERIC_MAX_RESULT_SCALE * 3)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("argument for function \"exp\" too big")));
}
/* Select an appropriate scale for internal calculation */
local_rscale = rscale + MUL_GUARD_DIGITS * 2;
/* Compute e^xfrac */
exp_var_internal(&x, result, local_rscale);
/* If there's an integer part, multiply by e^xint */
if (xintval > 0)
{
NumericVar e;
init_var(&e);
exp_var_internal(&const_one, &e, local_rscale);
power_var_int(&e, xintval, &e, local_rscale);
mul_var(&e, result, result, local_rscale);
free_var(&e);
}
/* Compensate for input sign, and round to requested rscale */
if (xneg)
div_var_fast(&const_one, result, result, rscale, true);
else
round_var(result, rscale);
free_var(&x);
}
| static void exp_var_internal | ( | NumericVar * | arg, | |
| NumericVar * | result, | |||
| int | rscale | |||
| ) | [static] |
Definition at line 5316 of file numeric.c.
References add_var(), Assert, cmp_var(), div_var_fast(), NumericVar::dscale, free_var(), init_var, mul_var(), NumericVar::ndigits, NUMERIC_POS, set_var_from_var(), and NumericVar::sign.
Referenced by exp_var().
{
NumericVar x;
NumericVar xpow;
NumericVar ifac;
NumericVar elem;
NumericVar ni;
int ndiv2 = 0;
int local_rscale;
init_var(&x);
init_var(&xpow);
init_var(&ifac);
init_var(&elem);
init_var(&ni);
set_var_from_var(arg, &x);
Assert(x.sign == NUMERIC_POS);
local_rscale = rscale + 8;
/* Reduce input into range 0 <= x <= 0.01 */
while (cmp_var(&x, &const_zero_point_01) > 0)
{
ndiv2++;
local_rscale++;
mul_var(&x, &const_zero_point_five, &x, x.dscale + 1);
}
/*
* Use the Taylor series
*
* exp(x) = 1 + x + x^2/2! + x^3/3! + ...
*
* Given the limited range of x, this should converge reasonably quickly.
* We run the series until the terms fall below the local_rscale limit.
*/
add_var(&const_one, &x, result);
set_var_from_var(&x, &xpow);
set_var_from_var(&const_one, &ifac);
set_var_from_var(&const_one, &ni);
for (;;)
{
add_var(&ni, &const_one, &ni);
mul_var(&xpow, &x, &xpow, local_rscale);
mul_var(&ifac, &ni, &ifac, 0);
div_var_fast(&xpow, &ifac, &elem, local_rscale, true);
if (elem.ndigits == 0)
break;
add_var(result, &elem, result);
}
/* Compensate for argument range reduction */
while (ndiv2-- > 0)
mul_var(result, result, result, local_rscale);
free_var(&x);
free_var(&xpow);
free_var(&ifac);
free_var(&elem);
free_var(&ni);
}
| Datum float4_numeric | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2417 of file numeric.c.
References buf, free_var(), init_var, make_result(), PG_GETARG_FLOAT4, PG_RETURN_NUMERIC, set_var_from_str(), and val.
{
float4 val = PG_GETARG_FLOAT4(0);
Numeric res;
NumericVar result;
char buf[FLT_DIG + 100];
if (isnan(val))
PG_RETURN_NUMERIC(make_result(&const_nan));
sprintf(buf, "%.*g", FLT_DIG, val);
init_var(&result);
/* Assume we need not worry about leading/trailing spaces */
(void) set_var_from_str(buf, buf, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum float8_numeric | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2355 of file numeric.c.
References buf, free_var(), init_var, make_result(), PG_GETARG_FLOAT8, PG_RETURN_NUMERIC, set_var_from_str(), and val.
{
float8 val = PG_GETARG_FLOAT8(0);
Numeric res;
NumericVar result;
char buf[DBL_DIG + 100];
if (isnan(val))
PG_RETURN_NUMERIC(make_result(&const_nan));
sprintf(buf, "%.*g", DBL_DIG, val);
init_var(&result);
/* Assume we need not worry about leading/trailing spaces */
(void) set_var_from_str(buf, buf, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| static void floor_var | ( | NumericVar * | var, | |
| NumericVar * | result | |||
| ) | [static] |
Definition at line 5138 of file numeric.c.
References cmp_var(), free_var(), init_var, NUMERIC_NEG, set_var_from_var(), NumericVar::sign, sub_var(), and trunc_var().
Referenced by compute_bucket(), and numeric_floor().
{
NumericVar tmp;
init_var(&tmp);
set_var_from_var(var, &tmp);
trunc_var(&tmp, 0);
if (var->sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0)
sub_var(&tmp, &const_one, &tmp);
set_var_from_var(&tmp, result);
free_var(&tmp);
}
| static void free_var | ( | NumericVar * | var | ) | [static] |
Definition at line 3173 of file numeric.c.
References NumericVar::buf, digitbuf_free, NumericVar::digits, and NumericVar::sign.
Referenced by ceil_var(), compute_bucket(), exp_var(), exp_var_internal(), float4_numeric(), float8_numeric(), floor_var(), get_str_from_var_sci(), int2_numeric(), int4_numeric(), int8_numeric(), ln_var(), log_var(), mod_var(), numeric(), numeric_add(), numeric_ceil(), numeric_div(), numeric_div_trunc(), numeric_exp(), numeric_fac(), numeric_floor(), numeric_in(), numeric_inc(), numeric_ln(), numeric_log(), numeric_mod(), numeric_mul(), numeric_power(), numeric_recv(), numeric_round(), numeric_sign(), numeric_sqrt(), numeric_stddev_internal(), numeric_sub(), numeric_trunc(), numericvar_to_int8(), power_var(), power_var_int(), sqrt_var(), and width_bucket_numeric().
{
digitbuf_free(var->buf);
var->buf = NULL;
var->digits = NULL;
var->sign = NUMERIC_NAN;
}
| static char * get_str_from_var | ( | NumericVar * | var | ) | [static] |
Definition at line 3439 of file numeric.c.
References DEC_DIGITS, NumericVar::digits, NumericVar::dscale, NumericVar::ndigits, NUMERIC_NEG, palloc(), NumericVar::sign, and NumericVar::weight.
Referenced by get_str_from_var_sci(), numeric_out(), and numericvar_to_double_no_overflow().
{
int dscale;
char *str;
char *cp;
char *endcp;
int i;
int d;
NumericDigit dig;
#if DEC_DIGITS > 1
NumericDigit d1;
#endif
dscale = var->dscale;
/*
* Allocate space for the result.
*
* i is set to the # of decimal digits before decimal point. dscale is the
* # of decimal digits we will print after decimal point. We may generate
* as many as DEC_DIGITS-1 excess digits at the end, and in addition we
* need room for sign, decimal point, null terminator.
*/
i = (var->weight + 1) * DEC_DIGITS;
if (i <= 0)
i = 1;
str = palloc(i + dscale + DEC_DIGITS + 2);
cp = str;
/*
* Output a dash for negative values
*/
if (var->sign == NUMERIC_NEG)
*cp++ = '-';
/*
* Output all digits before the decimal point
*/
if (var->weight < 0)
{
d = var->weight + 1;
*cp++ = '0';
}
else
{
for (d = 0; d <= var->weight; d++)
{
dig = (d < var->ndigits) ? var->digits[d] : 0;
/* In the first digit, suppress extra leading decimal zeroes */
#if DEC_DIGITS == 4
{
bool putit = (d > 0);
d1 = dig / 1000;
dig -= d1 * 1000;
putit |= (d1 > 0);
if (putit)
*cp++ = d1 + '0';
d1 = dig / 100;
dig -= d1 * 100;
putit |= (d1 > 0);
if (putit)
*cp++ = d1 + '0';
d1 = dig / 10;
dig -= d1 * 10;
putit |= (d1 > 0);
if (putit)
*cp++ = d1 + '0';
*cp++ = dig + '0';
}
#elif DEC_DIGITS == 2
d1 = dig / 10;
dig -= d1 * 10;
if (d1 > 0 || d > 0)
*cp++ = d1 + '0';
*cp++ = dig + '0';
#elif DEC_DIGITS == 1
*cp++ = dig + '0';
#else
#error unsupported NBASE
#endif
}
}
/*
* If requested, output a decimal point and all the digits that follow it.
* We initially put out a multiple of DEC_DIGITS digits, then truncate if
* needed.
*/
if (dscale > 0)
{
*cp++ = '.';
endcp = cp + dscale;
for (i = 0; i < dscale; d++, i += DEC_DIGITS)
{
dig = (d >= 0 && d < var->ndigits) ? var->digits[d] : 0;
#if DEC_DIGITS == 4
d1 = dig / 1000;
dig -= d1 * 1000;
*cp++ = d1 + '0';
d1 = dig / 100;
dig -= d1 * 100;
*cp++ = d1 + '0';
d1 = dig / 10;
dig -= d1 * 10;
*cp++ = d1 + '0';
*cp++ = dig + '0';
#elif DEC_DIGITS == 2
d1 = dig / 10;
dig -= d1 * 10;
*cp++ = d1 + '0';
*cp++ = dig + '0';
#elif DEC_DIGITS == 1
*cp++ = dig + '0';
#else
#error unsupported NBASE
#endif
}
cp = endcp;
}
/*
* terminate the string and return it
*/
*cp = '\0';
return str;
}
| static char * get_str_from_var_sci | ( | NumericVar * | var, | |
| int | rscale | |||
| ) | [static] |
Definition at line 3592 of file numeric.c.
References DEC_DIGITS, NumericVar::digits, div_var(), free_var(), get_str_from_var(), init_var, NumericVar::ndigits, palloc(), pfree(), power_var_int(), snprintf(), and NumericVar::weight.
Referenced by numeric_out_sci().
{
int32 exponent;
NumericVar denominator;
NumericVar significand;
int denom_scale;
size_t len;
char *str;
char *sig_out;
if (rscale < 0)
rscale = 0;
/*
* Determine the exponent of this number in normalised form.
*
* This is the exponent required to represent the number with only one
* significant digit before the decimal place.
*/
if (var->ndigits > 0)
{
exponent = (var->weight + 1) * DEC_DIGITS;
/*
* Compensate for leading decimal zeroes in the first numeric digit by
* decrementing the exponent.
*/
exponent -= DEC_DIGITS - (int) log10(var->digits[0]);
}
else
{
/*
* If var has no digits, then it must be zero.
*
* Zero doesn't technically have a meaningful exponent in normalised
* notation, but we just display the exponent as zero for consistency
* of output.
*/
exponent = 0;
}
/*
* The denominator is set to 10 raised to the power of the exponent.
*
* We then divide var by the denominator to get the significand, rounding
* to rscale decimal digits in the process.
*/
if (exponent < 0)
denom_scale = -exponent;
else
denom_scale = 0;
init_var(&denominator);
init_var(&significand);
power_var_int(&const_ten, exponent, &denominator, denom_scale);
div_var(var, &denominator, &significand, rscale, true);
sig_out = get_str_from_var(&significand);
free_var(&denominator);
free_var(&significand);
/*
* Allocate space for the result.
*
* In addition to the significand, we need room for the exponent
* decoration ("e"), the sign of the exponent, up to 10 digits for the
* exponent itself, and of course the null terminator.
*/
len = strlen(sig_out) + 13;
str = palloc(len);
snprintf(str, len, "%se%+03d", sig_out, exponent);
pfree(sig_out);
return str;
}
| Datum hash_numeric | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1458 of file numeric.c.
References Assert, digits, hash_any(), i, NUMERIC_DIGITS, NUMERIC_IS_NAN, NUMERIC_NDIGITS, NUMERIC_WEIGHT, PG_GETARG_NUMERIC, PG_RETURN_DATUM, and PG_RETURN_UINT32.
{
Numeric key = PG_GETARG_NUMERIC(0);
Datum digit_hash;
Datum result;
int weight;
int start_offset;
int end_offset;
int i;
int hash_len;
NumericDigit *digits;
/* If it's NaN, don't try to hash the rest of the fields */
if (NUMERIC_IS_NAN(key))
PG_RETURN_UINT32(0);
weight = NUMERIC_WEIGHT(key);
start_offset = 0;
end_offset = 0;
/*
* Omit any leading or trailing zeros from the input to the hash. The
* numeric implementation *should* guarantee that leading and trailing
* zeros are suppressed, but we're paranoid. Note that we measure the
* starting and ending offsets in units of NumericDigits, not bytes.
*/
digits = NUMERIC_DIGITS(key);
for (i = 0; i < NUMERIC_NDIGITS(key); i++)
{
if (digits[i] != (NumericDigit) 0)
break;
start_offset++;
/*
* The weight is effectively the # of digits before the decimal point,
* so decrement it for each leading zero we skip.
*/
weight--;
}
/*
* If there are no non-zero digits, then the value of the number is zero,
* regardless of any other fields.
*/
if (NUMERIC_NDIGITS(key) == start_offset)
PG_RETURN_UINT32(-1);
for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)
{
if (digits[i] != (NumericDigit) 0)
break;
end_offset++;
}
/* If we get here, there should be at least one non-zero digit */
Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));
/*
* Note that we don't hash on the Numeric's scale, since two numerics can
* compare equal but have different scales. We also don't hash on the
* sign, although we could: since a sign difference implies inequality,
* this shouldn't affect correctness.
*/
hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;
digit_hash = hash_any((unsigned char *) (NUMERIC_DIGITS(key) + start_offset),
hash_len * sizeof(NumericDigit));
/* Mix in the weight, via XOR */
result = digit_hash ^ weight;
PG_RETURN_DATUM(result);
}
| static void init_var_from_num | ( | Numeric | num, | |
| NumericVar * | dest | |||
| ) | [static] |
Definition at line 3398 of file numeric.c.
References NumericVar::buf, NumericVar::digits, NumericVar::dscale, NumericVar::ndigits, NUMERIC_DIGITS, NUMERIC_DSCALE, NUMERIC_NDIGITS, NUMERIC_SIGN, NUMERIC_WEIGHT, NumericVar::sign, and NumericVar::weight.
Referenced by compute_bucket(), numeric_add(), numeric_ceil(), numeric_div(), numeric_div_trunc(), numeric_exp(), numeric_floor(), numeric_inc(), numeric_int2(), numeric_int4(), numeric_int8(), numeric_ln(), numeric_log(), numeric_mod(), numeric_mul(), numeric_out(), numeric_out_sci(), numeric_power(), numeric_send(), numeric_sqrt(), numeric_stddev_internal(), and numeric_sub().
{
dest->ndigits = NUMERIC_NDIGITS(num);
dest->weight = NUMERIC_WEIGHT(num);
dest->sign = NUMERIC_SIGN(num);
dest->dscale = NUMERIC_DSCALE(num);
dest->digits = NUMERIC_DIGITS(num);
dest->buf = NULL; /* digits array is not palloc'd */
}
| Datum int2_accum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2579 of file numeric.c.
References DatumGetNumeric, DirectFunctionCall1, do_numeric_accum(), int2_numeric(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, and PG_RETURN_ARRAYTYPE_P.
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum newval2 = PG_GETARG_DATUM(1);
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int2_numeric, newval2));
PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
| Datum int2_avg_accum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2981 of file numeric.c.
References AggCheckCallContext(), ARR_DATA_PTR, ARR_HASNULL, ARR_OVERHEAD_NONULLS, ARR_SIZE, Int8TransTypeData::count, elog, ERROR, NULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_ARRAYTYPE_P_COPY, PG_GETARG_INT16, PG_RETURN_ARRAYTYPE_P, and Int8TransTypeData::sum.
{
ArrayType *transarray;
int16 newval = PG_GETARG_INT16(1);
Int8TransTypeData *transdata;
/*
* If we're invoked as an aggregate, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we need to make
* a copy of it before scribbling on it.
*/
if (AggCheckCallContext(fcinfo, NULL))
transarray = PG_GETARG_ARRAYTYPE_P(0);
else
transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
if (ARR_HASNULL(transarray) ||
ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
elog(ERROR, "expected 2-element int8 array");
transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
transdata->count++;
transdata->sum += newval;
PG_RETURN_ARRAYTYPE_P(transarray);
}
| Datum int2_numeric | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2301 of file numeric.c.
References free_var(), init_var, int8_to_numericvar(), make_result(), PG_GETARG_INT16, PG_RETURN_NUMERIC, and val.
Referenced by int2_accum().
{
int16 val = PG_GETARG_INT16(0);
Numeric res;
NumericVar result;
init_var(&result);
int8_to_numericvar((int64) val, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum int2_sum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2836 of file numeric.c.
References AggCheckCallContext(), NULL, PG_ARGISNULL, PG_GETARG_INT16, PG_GETARG_INT64, PG_GETARG_POINTER, PG_RETURN_INT64, PG_RETURN_NULL, and PG_RETURN_POINTER.
{
int64 newval;
if (PG_ARGISNULL(0))
{
/* No non-null input seen so far... */
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* still no non-null */
/* This is the first non-null input. */
newval = (int64) PG_GETARG_INT16(1);
PG_RETURN_INT64(newval);
}
/*
* If we're invoked as an aggregate, we can cheat and modify our first
* parameter in-place to avoid palloc overhead. If not, we need to return
* the new value of the transition variable. (If int8 is pass-by-value,
* then of course this is useless as well as incorrect, so just ifdef it
* out.)
*/
#ifndef USE_FLOAT8_BYVAL /* controls int8 too */
if (AggCheckCallContext(fcinfo, NULL))
{
int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
/* Leave the running sum unchanged in the new input is null */
if (!PG_ARGISNULL(1))
*oldsum = *oldsum + (int64) PG_GETARG_INT16(1);
PG_RETURN_POINTER(oldsum);
}
else
#endif
{
int64 oldsum = PG_GETARG_INT64(0);
/* Leave sum unchanged if new input is null. */
if (PG_ARGISNULL(1))
PG_RETURN_INT64(oldsum);
/* OK to do the addition. */
newval = oldsum + (int64) PG_GETARG_INT16(1);
PG_RETURN_INT64(newval);
}
}
| Datum int4_accum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2591 of file numeric.c.
References DatumGetNumeric, DirectFunctionCall1, do_numeric_accum(), int4_numeric(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, and PG_RETURN_ARRAYTYPE_P.
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum newval4 = PG_GETARG_DATUM(1);
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int4_numeric, newval4));
PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
| Datum int4_avg_accum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3009 of file numeric.c.
References AggCheckCallContext(), ARR_DATA_PTR, ARR_HASNULL, ARR_OVERHEAD_NONULLS, ARR_SIZE, Int8TransTypeData::count, elog, ERROR, NULL, PG_GETARG_ARRAYTYPE_P, PG_GETARG_ARRAYTYPE_P_COPY, PG_GETARG_INT32, PG_RETURN_ARRAYTYPE_P, and Int8TransTypeData::sum.
{
ArrayType *transarray;
int32 newval = PG_GETARG_INT32(1);
Int8TransTypeData *transdata;
/*
* If we're invoked as an aggregate, we can cheat and modify our first
* parameter in-place to reduce palloc overhead. Otherwise we need to make
* a copy of it before scribbling on it.
*/
if (AggCheckCallContext(fcinfo, NULL))
transarray = PG_GETARG_ARRAYTYPE_P(0);
else
transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
if (ARR_HASNULL(transarray) ||
ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
elog(ERROR, "expected 2-element int8 array");
transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
transdata->count++;
transdata->sum += newval;
PG_RETURN_ARRAYTYPE_P(transarray);
}
| Datum int4_numeric | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2191 of file numeric.c.
References free_var(), init_var, int8_to_numericvar(), make_result(), PG_GETARG_INT32, PG_RETURN_NUMERIC, and val.
Referenced by gbt_numeric_penalty(), int4_accum(), and numeric_to_char().
{
int32 val = PG_GETARG_INT32(0);
Numeric res;
NumericVar result;
init_var(&result);
int8_to_numericvar((int64) val, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum int4_sum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2885 of file numeric.c.
References AggCheckCallContext(), NULL, PG_ARGISNULL, PG_GETARG_INT32, PG_GETARG_INT64, PG_GETARG_POINTER, PG_RETURN_INT64, PG_RETURN_NULL, and PG_RETURN_POINTER.
{
int64 newval;
if (PG_ARGISNULL(0))
{
/* No non-null input seen so far... */
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* still no non-null */
/* This is the first non-null input. */
newval = (int64) PG_GETARG_INT32(1);
PG_RETURN_INT64(newval);
}
/*
* If we're invoked as an aggregate, we can cheat and modify our first
* parameter in-place to avoid palloc overhead. If not, we need to return
* the new value of the transition variable. (If int8 is pass-by-value,
* then of course this is useless as well as incorrect, so just ifdef it
* out.)
*/
#ifndef USE_FLOAT8_BYVAL /* controls int8 too */
if (AggCheckCallContext(fcinfo, NULL))
{
int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
/* Leave the running sum unchanged in the new input is null */
if (!PG_ARGISNULL(1))
*oldsum = *oldsum + (int64) PG_GETARG_INT32(1);
PG_RETURN_POINTER(oldsum);
}
else
#endif
{
int64 oldsum = PG_GETARG_INT64(0);
/* Leave sum unchanged if new input is null. */
if (PG_ARGISNULL(1))
PG_RETURN_INT64(oldsum);
/* OK to do the addition. */
newval = oldsum + (int64) PG_GETARG_INT32(1);
PG_RETURN_INT64(newval);
}
}
| Datum int8_accum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2603 of file numeric.c.
References DatumGetNumeric, DirectFunctionCall1, do_numeric_accum(), int8_numeric(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, and PG_RETURN_ARRAYTYPE_P.
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum newval8 = PG_GETARG_DATUM(1);
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
| Datum int8_avg | ( | PG_FUNCTION_ARGS | ) |
Definition at line 3037 of file numeric.c.
References ARR_DATA_PTR, ARR_HASNULL, ARR_OVERHEAD_NONULLS, ARR_SIZE, Int8TransTypeData::count, DirectFunctionCall1, DirectFunctionCall2, elog, ERROR, Int64GetDatumFast, int8_numeric(), numeric_div(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_DATUM, PG_RETURN_NULL, and Int8TransTypeData::sum.
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Int8TransTypeData *transdata;
Datum countd,
sumd;
if (ARR_HASNULL(transarray) ||
ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
elog(ERROR, "expected 2-element int8 array");
transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
/* SQL defines AVG of no values to be NULL */
if (transdata->count == 0)
PG_RETURN_NULL();
countd = DirectFunctionCall1(int8_numeric,
Int64GetDatumFast(transdata->count));
sumd = DirectFunctionCall1(int8_numeric,
Int64GetDatumFast(transdata->sum));
PG_RETURN_DATUM(DirectFunctionCall2(numeric_div, sumd, countd));
}
| Datum int8_avg_accum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2618 of file numeric.c.
References DatumGetNumeric, DirectFunctionCall1, do_numeric_avg_accum(), int8_numeric(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_DATUM, and PG_RETURN_ARRAYTYPE_P.
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum newval8 = PG_GETARG_DATUM(1);
Numeric newval;
newval = DatumGetNumeric(DirectFunctionCall1(int8_numeric, newval8));
PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
}
| Datum int8_numeric | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2257 of file numeric.c.
References free_var(), init_var, int8_to_numericvar(), make_result(), PG_GETARG_INT64, PG_RETURN_NUMERIC, and val.
Referenced by cash_numeric(), int64_to_numeric(), int8_accum(), int8_avg(), int8_avg_accum(), int8_sum(), int8_to_char(), numeric_cash(), numeric_plus_one_over_two(), numeric_shift_right(), and pg_xlog_location_diff().
{
int64 val = PG_GETARG_INT64(0);
Numeric res;
NumericVar result;
init_var(&result);
int8_to_numericvar(val, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum int8_sum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2934 of file numeric.c.
References DirectFunctionCall1, DirectFunctionCall2, int8_numeric(), numeric_add(), NumericGetDatum, PG_ARGISNULL, PG_GETARG_DATUM, PG_GETARG_NUMERIC, PG_RETURN_DATUM, PG_RETURN_NULL, and PG_RETURN_NUMERIC.
{
Numeric oldsum;
Datum newval;
if (PG_ARGISNULL(0))
{
/* No non-null input seen so far... */
if (PG_ARGISNULL(1))
PG_RETURN_NULL(); /* still no non-null */
/* This is the first non-null input. */
newval = DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(1));
PG_RETURN_DATUM(newval);
}
/*
* Note that we cannot special-case the aggregate case here, as we do for
* int2_sum and int4_sum: numeric is of variable size, so we cannot modify
* our first parameter in-place.
*/
oldsum = PG_GETARG_NUMERIC(0);
/* Leave sum unchanged if new input is null. */
if (PG_ARGISNULL(1))
PG_RETURN_NUMERIC(oldsum);
/* OK to do the addition. */
newval = DirectFunctionCall1(int8_numeric, PG_GETARG_DATUM(1));
PG_RETURN_DATUM(DirectFunctionCall2(numeric_add,
NumericGetDatum(oldsum), newval));
}
| static void int8_to_numericvar | ( | int64 | val, | |
| NumericVar * | var | |||
| ) | [static] |
Definition at line 3911 of file numeric.c.
References alloc_var(), DEC_DIGITS, NumericVar::digits, NumericVar::dscale, NumericVar::ndigits, NumericVar::sign, and NumericVar::weight.
Referenced by int2_numeric(), int4_numeric(), int8_numeric(), numeric_fac(), and width_bucket_numeric().
{
uint64 uval,
newuval;
NumericDigit *ptr;
int ndigits;
/* int8 can require at most 19 decimal digits; add one for safety */
alloc_var(var, 20 / DEC_DIGITS);
if (val < 0)
{
var->sign = NUMERIC_NEG;
uval = -val;
}
else
{
var->sign = NUMERIC_POS;
uval = val;
}
var->dscale = 0;
if (val == 0)
{
var->ndigits = 0;
var->weight = 0;
return;
}
ptr = var->digits + var->ndigits;
ndigits = 0;
do
{
ptr--;
ndigits++;
newuval = uval / NBASE;
*ptr = uval - newuval * NBASE;
uval = newuval;
} while (uval);
var->digits = ptr;
var->ndigits = ndigits;
var->weight = ndigits - 1;
}
| static void ln_var | ( | NumericVar * | arg, | |
| NumericVar * | result, | |||
| int | rscale | |||
| ) | [static] |
Definition at line 5390 of file numeric.c.
References add_var(), cmp_var(), DEC_DIGITS, div_var_fast(), ereport, errcode(), errmsg(), ERROR, free_var(), init_var, mul_var(), NumericVar::ndigits, set_var_from_var(), sqrt_var(), sub_var(), and NumericVar::weight.
Referenced by log_var(), numeric_ln(), and power_var().
{
NumericVar x;
NumericVar xx;
NumericVar ni;
NumericVar elem;
NumericVar fact;
int local_rscale;
int cmp;
cmp = cmp_var(arg, &const_zero);
if (cmp == 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
errmsg("cannot take logarithm of zero")));
else if (cmp < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_LOG),
errmsg("cannot take logarithm of a negative number")));
local_rscale = rscale + 8;
init_var(&x);
init_var(&xx);
init_var(&ni);
init_var(&elem);
init_var(&fact);
set_var_from_var(arg, &x);
set_var_from_var(&const_two, &fact);
/* Reduce input into range 0.9 < x < 1.1 */
while (cmp_var(&x, &const_zero_point_nine) <= 0)
{
local_rscale++;
sqrt_var(&x, &x, local_rscale);
mul_var(&fact, &const_two, &fact, 0);
}
while (cmp_var(&x, &const_one_point_one) >= 0)
{
local_rscale++;
sqrt_var(&x, &x, local_rscale);
mul_var(&fact, &const_two, &fact, 0);
}
/*
* We use the Taylor series for 0.5 * ln((1+z)/(1-z)),
*
* z + z^3/3 + z^5/5 + ...
*
* where z = (x-1)/(x+1) is in the range (approximately) -0.053 .. 0.048
* due to the above range-reduction of x.
*
* The convergence of this is not as fast as one would like, but is
* tolerable given that z is small.
*/
sub_var(&x, &const_one, result);
add_var(&x, &const_one, &elem);
div_var_fast(result, &elem, result, local_rscale, true);
set_var_from_var(result, &xx);
mul_var(result, result, &x, local_rscale);
set_var_from_var(&const_one, &ni);
for (;;)
{
add_var(&ni, &const_two, &ni);
mul_var(&xx, &x, &xx, local_rscale);
div_var_fast(&xx, &ni, &elem, local_rscale, true);
if (elem.ndigits == 0)
break;
add_var(result, &elem, result);
if (elem.weight < (result->weight - local_rscale * 2 / DEC_DIGITS))
break;
}
/* Compensate for argument range reduction, round to requested rscale */
mul_var(result, &fact, result, rscale);
free_var(&x);
free_var(&xx);
free_var(&ni);
free_var(&elem);
free_var(&fact);
}
| static void log_var | ( | NumericVar * | base, | |
| NumericVar * | num, | |||
| NumericVar * | result | |||
| ) | [static] |
Definition at line 5488 of file numeric.c.
References DEC_DIGITS, div_var_fast(), NumericVar::dscale, free_var(), init_var, ln_var(), Max, Min, NUMERIC_MAX_DISPLAY_SCALE, NUMERIC_MIN_DISPLAY_SCALE, NUMERIC_MIN_SIG_DIGITS, select_div_scale(), and NumericVar::weight.
Referenced by numeric_log().
{
NumericVar ln_base;
NumericVar ln_num;
int dec_digits;
int rscale;
int local_rscale;
init_var(&ln_base);
init_var(&ln_num);
/* Set scale for ln() calculations --- compare numeric_ln() */
/* Approx decimal digits before decimal point */
dec_digits = (num->weight + 1) * DEC_DIGITS;
if (dec_digits > 1)
rscale = NUMERIC_MIN_SIG_DIGITS - (int) log10(dec_digits - 1);
else if (dec_digits < 1)
rscale = NUMERIC_MIN_SIG_DIGITS - (int) log10(1 - dec_digits);
else
rscale = NUMERIC_MIN_SIG_DIGITS;
rscale = Max(rscale, base->dscale);
rscale = Max(rscale, num->dscale);
rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
local_rscale = rscale + 8;
/* Form natural logarithms */
ln_var(base, &ln_base, local_rscale);
ln_var(num, &ln_num, local_rscale);
ln_base.dscale = rscale;
ln_num.dscale = rscale;
/* Select scale for division result */
rscale = select_div_scale(&ln_num, &ln_base);
div_var_fast(&ln_num, &ln_base, result, rscale, true);
free_var(&ln_num);
free_var(&ln_base);
}
| static Numeric make_result | ( | NumericVar * | var | ) | [static] |
Definition at line 3678 of file numeric.c.
References Assert, NumericData::choice, NumericVar::digits, NumericVar::dscale, dump_numeric, ereport, errcode(), errmsg(), ERROR, NumericChoice::n_header, NumericVar::ndigits, NUMERIC_CAN_BE_SHORT, NUMERIC_DIGITS, NUMERIC_DSCALE, NUMERIC_HDRSZ, NUMERIC_HDRSZ_SHORT, NUMERIC_NAN, NUMERIC_NDIGITS, NUMERIC_NEG, NUMERIC_SHORT, NUMERIC_SHORT_WEIGHT_SIGN_MASK, NUMERIC_WEIGHT, palloc(), SET_VARSIZE, NumericVar::sign, sign, and NumericVar::weight.
{
Numeric result;
NumericDigit *digits = var->digits;
int weight = var->weight;
int sign = var->sign;
int n;
Size len;
if (sign == NUMERIC_NAN)
{
result = (Numeric) palloc(NUMERIC_HDRSZ_SHORT);
SET_VARSIZE(result, NUMERIC_HDRSZ_SHORT);
result->choice.n_header = NUMERIC_NAN;
/* the header word is all we need */
dump_numeric("make_result()", result);
return result;
}
n = var->ndigits;
/* truncate leading zeroes */
while (n > 0 && *digits == 0)
{
digits++;
weight--;
n--;
}
/* truncate trailing zeroes */
while (n > 0 && digits[n - 1] == 0)
n--;
/* If zero result, force to weight=0 and positive sign */
if (n == 0)
{
weight = 0;
sign = NUMERIC_POS;
}
/* Build the result */
if (NUMERIC_CAN_BE_SHORT(var->dscale, weight))
{
len = NUMERIC_HDRSZ_SHORT + n * sizeof(NumericDigit);
result = (Numeric) palloc(len);
SET_VARSIZE(result, len);
result->choice.n_short.n_header =
(sign == NUMERIC_NEG ? (NUMERIC_SHORT | NUMERIC_SHORT_SIGN_MASK)
: NUMERIC_SHORT)
| (var->dscale << NUMERIC_SHORT_DSCALE_SHIFT)
| (weight < 0 ? NUMERIC_SHORT_WEIGHT_SIGN_MASK : 0)
| (weight & NUMERIC_SHORT_WEIGHT_MASK);
}
else
{
len = NUMERIC_HDRSZ + n * sizeof(NumericDigit);
result = (Numeric) palloc(len);
SET_VARSIZE(result, len);
result->choice.n_long.n_sign_dscale =
sign | (var->dscale & NUMERIC_DSCALE_MASK);
result->choice.n_long.n_weight = weight;
}
memcpy(NUMERIC_DIGITS(result), digits, n * sizeof(NumericDigit));
Assert(NUMERIC_NDIGITS(result) == n);
/* Check for overflow of int16 fields */
if (NUMERIC_WEIGHT(result) != weight ||
NUMERIC_DSCALE(result) != var->dscale)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value overflows numeric format")));
dump_numeric("make_result()", result);
return result;
}
| static void mod_var | ( | NumericVar * | var1, | |
| NumericVar * | var2, | |||
| NumericVar * | result | |||
| ) | [static] |
Definition at line 5085 of file numeric.c.
References div_var(), NumericVar::dscale, free_var(), init_var, mul_var(), and sub_var().
Referenced by numeric_mod().
{
NumericVar tmp;
init_var(&tmp);
/* ---------
* We do this using the equation
* mod(x,y) = x - trunc(x/y)*y
* div_var can be persuaded to give us trunc(x/y) directly.
* ----------
*/
div_var(var1, var2, &tmp, 0, false);
mul_var(var2, &tmp, &tmp, var2->dscale);
sub_var(var1, &tmp, result);
free_var(&tmp);
}
| static void mul_var | ( | NumericVar * | var1, | |
| NumericVar * | var2, | |||
| NumericVar * | result, | |||
| int | rscale | |||
| ) | [static] |
Definition at line 4311 of file numeric.c.
References alloc_var(), Assert, NumericVar::digits, NumericVar::dscale, maxdigits, MUL_GUARD_DIGITS, NBASE, NumericVar::ndigits, palloc0(), pfree(), round_var(), NumericVar::sign, strip_var(), NumericVar::weight, and zero_var().
Referenced by compute_bucket(), exp_var(), exp_var_internal(), ln_var(), mod_var(), numeric_fac(), numeric_mul(), numeric_stddev_internal(), power_var(), power_var_int(), and sqrt_var().
{
int res_ndigits;
int res_sign;
int res_weight;
int maxdigits;
int *dig;
int carry;
int maxdig;
int newdig;
NumericDigit *res_digits;
int i,
ri,
i1,
i2;
/* copy these values into local vars for speed in inner loop */
int var1ndigits = var1->ndigits;
int var2ndigits = var2->ndigits;
NumericDigit *var1digits = var1->digits;
NumericDigit *var2digits = var2->digits;
if (var1ndigits == 0 || var2ndigits == 0)
{
/* one or both inputs is zero; so is result */
zero_var(result);
result->dscale = rscale;
return;
}
/* Determine result sign and (maximum possible) weight */
if (var1->sign == var2->sign)
res_sign = NUMERIC_POS;
else
res_sign = NUMERIC_NEG;
res_weight = var1->weight + var2->weight + 2;
/*
* Determine number of result digits to compute. If the exact result
* would have more than rscale fractional digits, truncate the computation
* with MUL_GUARD_DIGITS guard digits. We do that by pretending that one
* or both inputs have fewer digits than they really do.
*/
res_ndigits = var1ndigits + var2ndigits + 1;
maxdigits = res_weight + 1 + (rscale * DEC_DIGITS) + MUL_GUARD_DIGITS;
if (res_ndigits > maxdigits)
{
if (maxdigits < 3)
{
/* no useful precision at all in the result... */
zero_var(result);
result->dscale = rscale;
return;
}
/* force maxdigits odd so that input ndigits can be equal */
if ((maxdigits & 1) == 0)
maxdigits++;
if (var1ndigits > var2ndigits)
{
var1ndigits -= res_ndigits - maxdigits;
if (var1ndigits < var2ndigits)
var1ndigits = var2ndigits = (var1ndigits + var2ndigits) / 2;
}
else
{
var2ndigits -= res_ndigits - maxdigits;
if (var2ndigits < var1ndigits)
var1ndigits = var2ndigits = (var1ndigits + var2ndigits) / 2;
}
res_ndigits = maxdigits;
Assert(res_ndigits == var1ndigits + var2ndigits + 1);
}
/*
* We do the arithmetic in an array "dig[]" of signed int's. Since
* INT_MAX is noticeably larger than NBASE*NBASE, this gives us headroom
* to avoid normalizing carries immediately.
*
* maxdig tracks the maximum possible value of any dig[] entry; when this
* threatens to exceed INT_MAX, we take the time to propagate carries. To
* avoid overflow in maxdig itself, it actually represents the max
* possible value divided by NBASE-1.
*/
dig = (int *) palloc0(res_ndigits * sizeof(int));
maxdig = 0;
ri = res_ndigits - 1;
for (i1 = var1ndigits - 1; i1 >= 0; ri--, i1--)
{
int var1digit = var1digits[i1];
if (var1digit == 0)
continue;
/* Time to normalize? */
maxdig += var1digit;
if (maxdig > INT_MAX / (NBASE - 1))
{
/* Yes, do it */
carry = 0;
for (i = res_ndigits - 1; i >= 0; i--)
{
newdig = dig[i] + carry;
if (newdig >= NBASE)
{
carry = newdig / NBASE;
newdig -= carry * NBASE;
}
else
carry = 0;
dig[i] = newdig;
}
Assert(carry == 0);
/* Reset maxdig to indicate new worst-case */
maxdig = 1 + var1digit;
}
/* Add appropriate multiple of var2 into the accumulator */
i = ri;
for (i2 = var2ndigits - 1; i2 >= 0; i2--)
dig[i--] += var1digit * var2digits[i2];
}
/*
* Now we do a final carry propagation pass to normalize the result, which
* we combine with storing the result digits into the output. Note that
* this is still done at full precision w/guard digits.
*/
alloc_var(result, res_ndigits);
res_digits = result->digits;
carry = 0;
for (i = res_ndigits - 1; i >= 0; i--)
{
newdig = dig[i] + carry;
if (newdig >= NBASE)
{
carry = newdig / NBASE;
newdig -= carry * NBASE;
}
else
carry = 0;
res_digits[i] = newdig;
}
Assert(carry == 0);
pfree(dig);
/*
* Finally, round the result to the requested precision.
*/
result->weight = res_weight;
result->sign = res_sign;
/* Round to target rscale (and set result->dscale) */
round_var(result, rscale);
/* Strip leading and trailing zeroes */
strip_var(result);
}
Definition at line 768 of file numeric.c.
References apply_typmod(), NumericData::choice, DEC_DIGITS, free_var(), init_var, make_result(), maxdigits, NumericShort::n_header, NumericChoice::n_short, NUMERIC_CAN_BE_SHORT, NUMERIC_DSCALE, NUMERIC_DSCALE_MASK, NUMERIC_IS_NAN, NUMERIC_IS_SHORT, NUMERIC_SHORT_DSCALE_SHIFT, NUMERIC_SIGN, NUMERIC_WEIGHT, palloc(), PG_GETARG_INT32, PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, scale, set_var_from_num(), VARHDRSZ, and VARSIZE.
{
Numeric num = PG_GETARG_NUMERIC(0);
int32 typmod = PG_GETARG_INT32(1);
Numeric new;
int32 tmp_typmod;
int precision;
int scale;
int ddigits;
int maxdigits;
NumericVar var;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* If the value isn't a valid type modifier, simply return a copy of the
* input value
*/
if (typmod < (int32) (VARHDRSZ))
{
new = (Numeric) palloc(VARSIZE(num));
memcpy(new, num, VARSIZE(num));
PG_RETURN_NUMERIC(new);
}
/*
* Get the precision and scale out of the typmod value
*/
tmp_typmod = typmod - VARHDRSZ;
precision = (tmp_typmod >> 16) & 0xffff;
scale = tmp_typmod & 0xffff;
maxdigits = precision - scale;
/*
* If the number is certainly in bounds and due to the target scale no
* rounding could be necessary, just make a copy of the input and modify
* its scale fields, unless the larger scale forces us to abandon the
* short representation. (Note we assume the existing dscale is
* honest...)
*/
ddigits = (NUMERIC_WEIGHT(num) + 1) * DEC_DIGITS;
if (ddigits <= maxdigits && scale >= NUMERIC_DSCALE(num)
&& (NUMERIC_CAN_BE_SHORT(scale, NUMERIC_WEIGHT(num))
|| !NUMERIC_IS_SHORT(num)))
{
new = (Numeric) palloc(VARSIZE(num));
memcpy(new, num, VARSIZE(num));
if (NUMERIC_IS_SHORT(num))
new->choice.n_short.n_header =
(num->choice.n_short.n_header & ~NUMERIC_SHORT_DSCALE_MASK)
| (scale << NUMERIC_SHORT_DSCALE_SHIFT);
else
new->choice.n_long.n_sign_dscale = NUMERIC_SIGN(new) |
((uint16) scale & NUMERIC_DSCALE_MASK);
PG_RETURN_NUMERIC(new);
}
/*
* We really need to fiddle with things - unpack the number into a
* variable and let apply_typmod() do it.
*/
init_var(&var);
set_var_from_num(num, &var);
apply_typmod(&var, typmod);
new = make_result(&var);
free_var(&var);
PG_RETURN_NUMERIC(new);
}
| Datum numeric_abs | ( | PG_FUNCTION_ARGS | ) |
Definition at line 914 of file numeric.c.
References NumericData::choice, make_result(), NumericShort::n_header, NumericChoice::n_long, NumericChoice::n_short, NumericLong::n_sign_dscale, NUMERIC_DSCALE, NUMERIC_IS_NAN, NUMERIC_IS_SHORT, NUMERIC_POS, palloc(), PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, and VARSIZE.
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Do it the easy way directly on the packed format
*/
res = (Numeric) palloc(VARSIZE(num));
memcpy(res, num, VARSIZE(num));
if (NUMERIC_IS_SHORT(num))
res->choice.n_short.n_header =
num->choice.n_short.n_header & ~NUMERIC_SHORT_SIGN_MASK;
else
res->choice.n_long.n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_accum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2549 of file numeric.c.
References do_numeric_accum(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_NUMERIC, and PG_RETURN_ARRAYTYPE_P.
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Numeric newval = PG_GETARG_NUMERIC(1);
PG_RETURN_ARRAYTYPE_P(do_numeric_accum(transarray, newval));
}
| Datum numeric_add | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1548 of file numeric.c.
References add_var(), free_var(), init_var, init_var_from_num(), make_result(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, and PG_RETURN_NUMERIC.
Referenced by do_numeric_accum(), do_numeric_avg_accum(), int8_sum(), and numeric_plus_one_over_two().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
NumericVar arg1;
NumericVar arg2;
NumericVar result;
Numeric res;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Unpack the values, let add_var() compute the result and return it.
*/
init_var_from_num(num1, &arg1);
init_var_from_num(num2, &arg2);
init_var(&result);
add_var(&arg1, &arg2, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_avg | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2631 of file numeric.c.
References DatumGetNumeric, deconstruct_array(), DirectFunctionCall2, elog, ERROR, NULL, numeric_div(), NUMERIC_NDIGITS, NumericGetDatum, NUMERICOID, PG_GETARG_ARRAYTYPE_P, PG_RETURN_DATUM, and PG_RETURN_NULL.
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Datum *transdatums;
int ndatums;
Numeric N,
sumX;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
NUMERICOID, -1, false, 'i',
&transdatums, NULL, &ndatums);
if (ndatums != 2)
elog(ERROR, "expected 2-element numeric array");
N = DatumGetNumeric(transdatums[0]);
sumX = DatumGetNumeric(transdatums[1]);
/* SQL defines AVG of no values to be NULL */
/* N is zero iff no digits (cf. numeric_uminus) */
if (NUMERIC_NDIGITS(N) == 0)
PG_RETURN_NULL();
PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
NumericGetDatum(sumX),
NumericGetDatum(N)));
}
| Datum numeric_avg_accum | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2561 of file numeric.c.
References do_numeric_avg_accum(), PG_GETARG_ARRAYTYPE_P, PG_GETARG_NUMERIC, and PG_RETURN_ARRAYTYPE_P.
{
ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
Numeric newval = PG_GETARG_NUMERIC(1);
PG_RETURN_ARRAYTYPE_P(do_numeric_avg_accum(transarray, newval));
}
| Datum numeric_ceil | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1142 of file numeric.c.
References ceil_var(), free_var(), init_var_from_num(), make_result(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, and PG_RETURN_NUMERIC.
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
NumericVar result;
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
init_var_from_num(num, &result);
ceil_var(&result, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_cmp | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1320 of file numeric.c.
References cmp_numerics(), PG_FREE_IF_COPY, PG_GETARG_NUMERIC, and PG_RETURN_INT32.
Referenced by gbt_numeric_cmp(), and gin_numeric_cmp().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
int result;
result = cmp_numerics(num1, num2);
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
PG_RETURN_INT32(result);
}
| Datum numeric_div | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1666 of file numeric.c.
References div_var(), free_var(), init_var, init_var_from_num(), make_result(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, and select_div_scale().
Referenced by cash_numeric(), gbt_numeric_penalty(), int8_avg(), and numeric_avg().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
NumericVar arg1;
NumericVar arg2;
NumericVar result;
Numeric res;
int rscale;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Unpack the arguments
*/
init_var_from_num(num1, &arg1);
init_var_from_num(num2, &arg2);
init_var(&result);
/*
* Select scale for division result
*/
rscale = select_div_scale(&arg1, &arg2);
/*
* Do the divide and return the result
*/
div_var(&arg1, &arg2, &result, rscale, true);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_div_trunc | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1714 of file numeric.c.
References div_var(), free_var(), init_var, init_var_from_num(), make_result(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, and PG_RETURN_NUMERIC.
Referenced by numeric_plus_one_over_two(), and numeric_shift_right().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
NumericVar arg1;
NumericVar arg2;
NumericVar result;
Numeric res;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Unpack the arguments
*/
init_var_from_num(num1, &arg1);
init_var_from_num(num2, &arg2);
init_var(&result);
/*
* Do the divide and return the result
*/
div_var(&arg1, &arg2, &result, 0, false);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_eq | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1336 of file numeric.c.
References cmp_numerics(), PG_FREE_IF_COPY, PG_GETARG_NUMERIC, and PG_RETURN_BOOL.
Referenced by gbt_numeric_eq().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
result = cmp_numerics(num1, num2) == 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
PG_RETURN_BOOL(result);
}
| Datum numeric_exp | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1972 of file numeric.c.
References arg, NumericVar::dscale, exp_var(), free_var(), init_var, init_var_from_num(), make_result(), Max, Min, NUMERIC_IS_NAN, NUMERIC_MAX_DISPLAY_SCALE, NUMERIC_MAX_RESULT_SCALE, NUMERIC_MIN_DISPLAY_SCALE, NUMERIC_MIN_SIG_DIGITS, numericvar_to_double_no_overflow(), PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, and val.
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
NumericVar arg;
NumericVar result;
int rscale;
double val;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Unpack the argument and determine the result scale. We choose a scale
* to give at least NUMERIC_MIN_SIG_DIGITS significant digits; but in any
* case not less than the input's dscale.
*/
init_var_from_num(num, &arg);
init_var(&result);
/* convert input to float8, ignoring overflow */
val = numericvar_to_double_no_overflow(&arg);
/*
* log10(result) = num * log10(e), so this is approximately the decimal
* weight of the result:
*/
val *= 0.434294481903252;
/* limit to something that won't cause integer overflow */
val = Max(val, -NUMERIC_MAX_RESULT_SCALE);
val = Min(val, NUMERIC_MAX_RESULT_SCALE);
rscale = NUMERIC_MIN_SIG_DIGITS - (int) val;
rscale = Max(rscale, arg.dscale);
rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
/*
* Let exp_var() do the calculation and return the result.
*/
exp_var(&arg, &result, rscale);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_fac | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1873 of file numeric.c.
References CHECK_FOR_INTERRUPTS, ereport, errcode(), errmsg(), ERROR, free_var(), init_var, int8_to_numericvar(), make_result(), mul_var(), PG_GETARG_INT64, and PG_RETURN_NUMERIC.
{
int64 num = PG_GETARG_INT64(0);
Numeric res;
NumericVar fact;
NumericVar result;
if (num <= 1)
{
res = make_result(&const_one);
PG_RETURN_NUMERIC(res);
}
/* Fail immediately if the result would overflow */
if (num > 32177)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value overflows numeric format")));
init_var(&fact);
init_var(&result);
int8_to_numericvar(num, &result);
for (num = num - 1; num > 1; num--)
{
/* this loop can take awhile, so allow it to be interrupted */
CHECK_FOR_INTERRUPTS();
int8_to_numericvar(num, &fact);
mul_var(&result, &fact, &result, 0);
}
res = make_result(&result);
free_var(&fact);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_float4 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2443 of file numeric.c.
References CStringGetDatum, DatumGetCString, DirectFunctionCall1, float4in(), get_float4_nan(), NUMERIC_IS_NAN, numeric_out(), NumericGetDatum, pfree(), PG_GETARG_NUMERIC, PG_RETURN_DATUM, and PG_RETURN_FLOAT4.
{
Numeric num = PG_GETARG_NUMERIC(0);
char *tmp;
Datum result;
if (NUMERIC_IS_NAN(num))
PG_RETURN_FLOAT4(get_float4_nan());
tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(num)));
result = DirectFunctionCall1(float4in, CStringGetDatum(tmp));
pfree(tmp);
PG_RETURN_DATUM(result);
}
| Datum numeric_float8 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2381 of file numeric.c.
References CStringGetDatum, DatumGetCString, DirectFunctionCall1, float8in(), get_float8_nan(), NUMERIC_IS_NAN, numeric_out(), NumericGetDatum, pfree(), PG_GETARG_NUMERIC, PG_RETURN_DATUM, and PG_RETURN_FLOAT8.
Referenced by numrange_subdiff(), and PLyFloat_FromNumeric().
{
Numeric num = PG_GETARG_NUMERIC(0);
char *tmp;
Datum result;
if (NUMERIC_IS_NAN(num))
PG_RETURN_FLOAT8(get_float8_nan());
tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(num)));
result = DirectFunctionCall1(float8in, CStringGetDatum(tmp));
pfree(tmp);
PG_RETURN_DATUM(result);
}
| Datum numeric_float8_no_overflow | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2403 of file numeric.c.
References get_float8_nan(), NUMERIC_IS_NAN, numeric_to_double_no_overflow(), PG_GETARG_NUMERIC, PG_RETURN_FLOAT8, and val.
Referenced by convert_numeric_to_scalar(), and gbt_numeric_penalty().
{
Numeric num = PG_GETARG_NUMERIC(0);
double val;
if (NUMERIC_IS_NAN(num))
PG_RETURN_FLOAT8(get_float8_nan());
val = numeric_to_double_no_overflow(num);
PG_RETURN_FLOAT8(val);
}
| Datum numeric_floor | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1167 of file numeric.c.
References floor_var(), free_var(), init_var_from_num(), make_result(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, and PG_RETURN_NUMERIC.
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
NumericVar result;
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
init_var_from_num(num, &result);
floor_var(&result, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_ge | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1381 of file numeric.c.
References cmp_numerics(), PG_FREE_IF_COPY, PG_GETARG_NUMERIC, and PG_RETURN_BOOL.
Referenced by gbt_numeric_ge().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
result = cmp_numerics(num1, num2) >= 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
PG_RETURN_BOOL(result);
}
| Datum numeric_gt | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1366 of file numeric.c.
References cmp_numerics(), PG_FREE_IF_COPY, PG_GETARG_NUMERIC, and PG_RETURN_BOOL.
Referenced by gbt_numeric_gt(), and gbt_numeric_penalty().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
result = cmp_numerics(num1, num2) > 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
PG_RETURN_BOOL(result);
}
| Datum numeric_in | ( | PG_FUNCTION_ARGS | ) |
Definition at line 451 of file numeric.c.
References apply_typmod(), ereport, errcode(), errmsg(), ERROR, free_var(), init_var, make_result(), PG_GETARG_CSTRING, PG_GETARG_INT32, PG_GETARG_OID, PG_RETURN_NUMERIC, pg_strncasecmp(), set_var_from_str(), and value.
Referenced by make_const(), numeric_to_number(), and ssl_client_serial().
{
char *str = PG_GETARG_CSTRING(0);
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 typmod = PG_GETARG_INT32(2);
Numeric res;
const char *cp;
/* Skip leading spaces */
cp = str;
while (*cp)
{
if (!isspace((unsigned char) *cp))
break;
cp++;
}
/*
* Check for NaN
*/
if (pg_strncasecmp(cp, "NaN", 3) == 0)
{
res = make_result(&const_nan);
/* Should be nothing left but spaces */
cp += 3;
while (*cp)
{
if (!isspace((unsigned char) *cp))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type numeric: \"%s\"",
str)));
cp++;
}
}
else
{
/*
* Use set_var_from_str() to parse a normal numeric value
*/
NumericVar value;
init_var(&value);
cp = set_var_from_str(str, cp, &value);
/*
* We duplicate a few lines of code here because we would like to
* throw any trailing-junk syntax error before any semantic error
* resulting from apply_typmod. We can't easily fold the two cases
* together because we mustn't apply apply_typmod to a NaN.
*/
while (*cp)
{
if (!isspace((unsigned char) *cp))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type numeric: \"%s\"",
str)));
cp++;
}
apply_typmod(&value, typmod);
res = make_result(&value);
free_var(&value);
}
PG_RETURN_NUMERIC(res);
}
| Datum numeric_inc | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1789 of file numeric.c.
References add_var(), arg, free_var(), init_var_from_num(), make_result(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, and PG_RETURN_NUMERIC.
Referenced by do_numeric_accum(), and do_numeric_avg_accum().
{
Numeric num = PG_GETARG_NUMERIC(0);
NumericVar arg;
Numeric res;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Compute the result and return it
*/
init_var_from_num(num, &arg);
add_var(&arg, &const_one, &arg);
res = make_result(&arg);
free_var(&arg);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_int2 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2320 of file numeric.c.
References ereport, errcode(), errmsg(), ERROR, init_var_from_num(), NUMERIC_IS_NAN, numericvar_to_int8(), PG_GETARG_NUMERIC, PG_RETURN_INT16, and val.
{
Numeric num = PG_GETARG_NUMERIC(0);
NumericVar x;
int64 val;
int16 result;
/* XXX would it be better to return NULL? */
if (NUMERIC_IS_NAN(num))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert NaN to smallint")));
/* Convert to variable format and thence to int8 */
init_var_from_num(num, &x);
if (!numericvar_to_int8(&x, &val))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
/* Down-convert to int2 */
result = (int16) val;
/* Test for overflow by reverse-conversion. */
if ((int64) result != val)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("smallint out of range")));
PG_RETURN_INT16(result);
}
| Datum numeric_int4 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2210 of file numeric.c.
References ereport, errcode(), errmsg(), ERROR, init_var_from_num(), NUMERIC_IS_NAN, numericvar_to_int4(), PG_GETARG_NUMERIC, and PG_RETURN_INT32.
Referenced by numeric_to_char().
{
Numeric num = PG_GETARG_NUMERIC(0);
NumericVar x;
int32 result;
/* XXX would it be better to return NULL? */
if (NUMERIC_IS_NAN(num))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert NaN to integer")));
/* Convert to variable format, then convert to int4 */
init_var_from_num(num, &x);
result = numericvar_to_int4(&x);
PG_RETURN_INT32(result);
}
| Datum numeric_int8 | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2276 of file numeric.c.
References ereport, errcode(), errmsg(), ERROR, init_var_from_num(), NUMERIC_IS_NAN, numericvar_to_int8(), PG_GETARG_NUMERIC, and PG_RETURN_INT64.
Referenced by numeric_cash().
{
Numeric num = PG_GETARG_NUMERIC(0);
NumericVar x;
int64 result;
/* XXX would it be better to return NULL? */
if (NUMERIC_IS_NAN(num))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot convert NaN to bigint")));
/* Convert to variable format and thence to int8 */
init_var_from_num(num, &x);
if (!numericvar_to_int8(&x, &result))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("bigint out of range")));
PG_RETURN_INT64(result);
}
Definition at line 561 of file numeric.c.
References NUMERIC_IS_NAN.
Referenced by gbt_numeric_penalty().
{
return NUMERIC_IS_NAN(num);
}
| Datum numeric_larger | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1844 of file numeric.c.
References cmp_numerics(), PG_GETARG_NUMERIC, and PG_RETURN_NUMERIC.
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
/*
* Use cmp_numerics so that this will agree with the comparison operators,
* particularly as regards comparisons involving NaN.
*/
if (cmp_numerics(num1, num2) > 0)
PG_RETURN_NUMERIC(num1);
else
PG_RETURN_NUMERIC(num2);
}
| Datum numeric_le | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1411 of file numeric.c.
References cmp_numerics(), PG_FREE_IF_COPY, PG_GETARG_NUMERIC, and PG_RETURN_BOOL.
Referenced by gbt_numeric_le().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
result = cmp_numerics(num1, num2) <= 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
PG_RETURN_BOOL(result);
}
| Datum numeric_ln | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2033 of file numeric.c.
References arg, DEC_DIGITS, NumericVar::dscale, free_var(), init_var, init_var_from_num(), ln_var(), make_result(), Max, Min, NUMERIC_IS_NAN, NUMERIC_MAX_DISPLAY_SCALE, NUMERIC_MIN_DISPLAY_SCALE, NUMERIC_MIN_SIG_DIGITS, PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, and NumericVar::weight.
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
NumericVar arg;
NumericVar result;
int dec_digits;
int rscale;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
init_var_from_num(num, &arg);
init_var(&result);
/* Approx decimal digits before decimal point */
dec_digits = (arg.weight + 1) * DEC_DIGITS;
if (dec_digits > 1)
rscale = NUMERIC_MIN_SIG_DIGITS - (int) log10(dec_digits - 1);
else if (dec_digits < 1)
rscale = NUMERIC_MIN_SIG_DIGITS - (int) log10(1 - dec_digits);
else
rscale = NUMERIC_MIN_SIG_DIGITS;
rscale = Max(rscale, arg.dscale);
rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
ln_var(&arg, &result, rscale);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_log | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2081 of file numeric.c.
References free_var(), init_var, init_var_from_num(), log_var(), make_result(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, and PG_RETURN_NUMERIC.
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
NumericVar arg1;
NumericVar arg2;
NumericVar result;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Initialize things
*/
init_var_from_num(num1, &arg1);
init_var_from_num(num2, &arg2);
init_var(&result);
/*
* Call log_var() to compute and return the result; note it handles scale
* selection itself.
*/
log_var(&arg1, &arg2, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_lt | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1396 of file numeric.c.
References cmp_numerics(), PG_FREE_IF_COPY, PG_GETARG_NUMERIC, and PG_RETURN_BOOL.
Referenced by gbt_numeric_lt(), and numeric_is_less().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
result = cmp_numerics(num1, num2) < 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
PG_RETURN_BOOL(result);
}
Definition at line 572 of file numeric.c.
References DEC_DIGITS, NUMERIC_HDRSZ, and VARHDRSZ.
Referenced by type_maximum_size().
{
int precision;
int numeric_digits;
if (typmod < (int32) (VARHDRSZ))
return -1;
/* precision (ie, max # of digits) is in upper bits of typmod */
precision = ((typmod - VARHDRSZ) >> 16) & 0xffff;
/*
* This formula computes the maximum number of NumericDigits we could need
* in order to store the specified number of decimal digits. Because the
* weight is stored as a number of NumericDigits rather than a number of
* decimal digits, it's possible that the first NumericDigit will contain
* only a single decimal digit. Thus, the first two decimal digits can
* require two NumericDigits to store, but it isn't until we reach
* DEC_DIGITS + 2 decimal digits that we potentially need a third
* NumericDigit.
*/
numeric_digits = (precision + 2 * (DEC_DIGITS - 1)) / DEC_DIGITS;
/*
* In most cases, the size of a numeric will be smaller than the value
* computed below, because the varlena header will typically get toasted
* down to a single byte before being stored on disk, and it may also be
* possible to use a short numeric header. But our job here is to compute
* the worst case.
*/
return NUMERIC_HDRSZ + (numeric_digits * sizeof(NumericDigit));
}
| Datum numeric_mod | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1756 of file numeric.c.
References free_var(), init_var, init_var_from_num(), make_result(), mod_var(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, and PG_RETURN_NUMERIC.
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
NumericVar arg1;
NumericVar arg2;
NumericVar result;
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
init_var_from_num(num1, &arg1);
init_var_from_num(num2, &arg2);
init_var(&result);
mod_var(&arg1, &arg2, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_mul | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1624 of file numeric.c.
References NumericVar::dscale, free_var(), init_var, init_var_from_num(), make_result(), mul_var(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, and PG_RETURN_NUMERIC.
Referenced by do_numeric_accum(), numeric_cash(), and numeric_to_char().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
NumericVar arg1;
NumericVar arg2;
NumericVar result;
Numeric res;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Unpack the values, let mul_var() compute the result and return it.
* Unlike add_var() and sub_var(), mul_var() will round its result. In the
* case of numeric_mul(), which is invoked for the * operator on numerics,
* we request exact representation for the product (rscale = sum(dscale of
* arg1, dscale of arg2)).
*/
init_var_from_num(num1, &arg1);
init_var_from_num(num2, &arg2);
init_var(&result);
mul_var(&arg1, &arg2, &result, arg1.dscale + arg2.dscale);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_ne | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1351 of file numeric.c.
References cmp_numerics(), PG_FREE_IF_COPY, PG_GETARG_NUMERIC, and PG_RETURN_BOOL.
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
bool result;
result = cmp_numerics(num1, num2) != 0;
PG_FREE_IF_COPY(num1, 0);
PG_FREE_IF_COPY(num2, 1);
PG_RETURN_BOOL(result);
}
| Datum numeric_out | ( | PG_FUNCTION_ARGS | ) |
Definition at line 533 of file numeric.c.
References get_str_from_var(), init_var_from_num(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, PG_RETURN_CSTRING, and pstrdup().
Referenced by numeric_float4(), numeric_float8(), numeric_to_char(), numeric_to_cstring(), and numeric_to_double_no_overflow().
{
Numeric num = PG_GETARG_NUMERIC(0);
NumericVar x;
char *str;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_CSTRING(pstrdup("NaN"));
/*
* Get the number in the variable format.
*/
init_var_from_num(num, &x);
str = get_str_from_var(&x);
PG_RETURN_CSTRING(str);
}
| char* numeric_out_sci | ( | Numeric | num, | |
| int | scale | |||
| ) |
Definition at line 611 of file numeric.c.
References get_str_from_var_sci(), init_var_from_num(), NUMERIC_IS_NAN, and pstrdup().
Referenced by int8_to_char(), and numeric_to_char().
{
NumericVar x;
char *str;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
return pstrdup("NaN");
init_var_from_num(num, &x);
str = get_str_from_var_sci(&x, scale);
return str;
}
| Datum numeric_power | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2123 of file numeric.c.
References cmp_var(), ereport, errcode(), errmsg(), ERROR, free_var(), init_var, init_var_from_num(), make_result(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, power_var(), set_var_from_var(), and trunc_var().
Referenced by numeric_to_char().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
Numeric res;
NumericVar arg1;
NumericVar arg2;
NumericVar arg2_trunc;
NumericVar result;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Initialize things
*/
init_var(&arg2_trunc);
init_var(&result);
init_var_from_num(num1, &arg1);
init_var_from_num(num2, &arg2);
set_var_from_var(&arg2, &arg2_trunc);
trunc_var(&arg2_trunc, 0);
/*
* The SQL spec requires that we emit a particular SQLSTATE error code for
* certain error conditions. Specifically, we don't return a
* divide-by-zero error code for 0 ^ -1.
*/
if (cmp_var(&arg1, &const_zero) == 0 &&
cmp_var(&arg2, &const_zero) < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
errmsg("zero raised to a negative power is undefined")));
if (cmp_var(&arg1, &const_zero) < 0 &&
cmp_var(&arg2, &arg2_trunc) != 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
errmsg("a negative number raised to a non-integer power yields a complex result")));
/*
* Call power_var() to compute and return the result; note it handles
* scale selection itself.
*/
power_var(&arg1, &arg2, &result);
res = make_result(&result);
free_var(&result);
free_var(&arg2_trunc);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_recv | ( | PG_FUNCTION_ARGS | ) |
Definition at line 636 of file numeric.c.
References alloc_var(), apply_typmod(), buf, NumericVar::digits, NumericVar::dscale, ereport, errcode(), errmsg(), ERROR, free_var(), i, init_var, make_result(), NBASE, NUMERIC_MAX_PRECISION, NUMERIC_MAX_RESULT_SCALE, NUMERIC_NAN, NUMERIC_NEG, NUMERIC_POS, PG_GETARG_INT32, PG_GETARG_OID, PG_GETARG_POINTER, PG_RETURN_NUMERIC, pq_getmsgint(), NumericVar::sign, value, and NumericVar::weight.
{
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
#ifdef NOT_USED
Oid typelem = PG_GETARG_OID(1);
#endif
int32 typmod = PG_GETARG_INT32(2);
NumericVar value;
Numeric res;
int len,
i;
init_var(&value);
len = (uint16) pq_getmsgint(buf, sizeof(uint16));
if (len < 0 || len > NUMERIC_MAX_PRECISION + NUMERIC_MAX_RESULT_SCALE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid length in external \"numeric\" value")));
alloc_var(&value, len);
value.weight = (int16) pq_getmsgint(buf, sizeof(int16));
value.sign = (uint16) pq_getmsgint(buf, sizeof(uint16));
if (!(value.sign == NUMERIC_POS ||
value.sign == NUMERIC_NEG ||
value.sign == NUMERIC_NAN))
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid sign in external \"numeric\" value")));
value.dscale = (uint16) pq_getmsgint(buf, sizeof(uint16));
for (i = 0; i < len; i++)
{
NumericDigit d = pq_getmsgint(buf, sizeof(NumericDigit));
if (d < 0 || d >= NBASE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid digit in external \"numeric\" value")));
value.digits[i] = d;
}
apply_typmod(&value, typmod);
res = make_result(&value);
free_var(&value);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_round | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1046 of file numeric.c.
References arg, NumericVar::dscale, free_var(), init_var, make_result(), Max, Min, NUMERIC_IS_NAN, NUMERIC_MAX_RESULT_SCALE, PG_GETARG_INT32, PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, round_var(), scale, and set_var_from_num().
Referenced by cash_numeric(), and numeric_to_char().
{
Numeric num = PG_GETARG_NUMERIC(0);
int32 scale = PG_GETARG_INT32(1);
Numeric res;
NumericVar arg;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Limit the scale value to avoid possible overflow in calculations
*/
scale = Max(scale, -NUMERIC_MAX_RESULT_SCALE);
scale = Min(scale, NUMERIC_MAX_RESULT_SCALE);
/*
* Unpack the argument and round it at the proper digit position
*/
init_var(&arg);
set_var_from_num(num, &arg);
round_var(&arg, scale);
/* We don't allow negative output dscale */
if (scale < 0)
arg.dscale = 0;
/*
* Return the rounded result
*/
res = make_result(&arg);
free_var(&arg);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_send | ( | PG_FUNCTION_ARGS | ) |
Definition at line 692 of file numeric.c.
References buf, NumericVar::digits, NumericVar::dscale, i, init_var_from_num(), NumericVar::ndigits, PG_GETARG_NUMERIC, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), pq_sendint(), NumericVar::sign, and NumericVar::weight.
{
Numeric num = PG_GETARG_NUMERIC(0);
NumericVar x;
StringInfoData buf;
int i;
init_var_from_num(num, &x);
pq_begintypsend(&buf);
pq_sendint(&buf, x.ndigits, sizeof(int16));
pq_sendint(&buf, x.weight, sizeof(int16));
pq_sendint(&buf, x.sign, sizeof(int16));
pq_sendint(&buf, x.dscale, sizeof(int16));
for (i = 0; i < x.ndigits; i++)
pq_sendint(&buf, x.digits[i], sizeof(NumericDigit));
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
| Datum numeric_sign | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1001 of file numeric.c.
References free_var(), init_var, make_result(), NUMERIC_IS_NAN, NUMERIC_NDIGITS, NUMERIC_SIGN, PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, set_var_from_var(), and NumericVar::sign.
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
NumericVar result;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
init_var(&result);
/*
* The packed format is known to be totally zero digit trimmed always. So
* we can identify a ZERO by the fact that there are no digits at all.
*/
if (NUMERIC_NDIGITS(num) == 0)
set_var_from_var(&const_zero, &result);
else
{
/*
* And if there are some, we return a copy of ONE with the sign of our
* argument
*/
set_var_from_var(&const_one, &result);
result.sign = NUMERIC_SIGN(num);
}
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_smaller | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1822 of file numeric.c.
References cmp_numerics(), PG_GETARG_NUMERIC, and PG_RETURN_NUMERIC.
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
/*
* Use cmp_numerics so that this will agree with the comparison operators,
* particularly as regards comparisons involving NaN.
*/
if (cmp_numerics(num1, num2) < 0)
PG_RETURN_NUMERIC(num1);
else
PG_RETURN_NUMERIC(num2);
}
| Datum numeric_sqrt | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1921 of file numeric.c.
References arg, DEC_DIGITS, NumericVar::dscale, free_var(), init_var, init_var_from_num(), make_result(), Max, Min, NUMERIC_IS_NAN, NUMERIC_MAX_DISPLAY_SCALE, NUMERIC_MIN_DISPLAY_SCALE, NUMERIC_MIN_SIG_DIGITS, PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, sqrt_var(), and NumericVar::weight.
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
NumericVar arg;
NumericVar result;
int sweight;
int rscale;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Unpack the argument and determine the result scale. We choose a scale
* to give at least NUMERIC_MIN_SIG_DIGITS significant digits; but in any
* case not less than the input's dscale.
*/
init_var_from_num(num, &arg);
init_var(&result);
/* Assume the input was normalized, so arg.weight is accurate */
sweight = (arg.weight + 1) * DEC_DIGITS / 2 - 1;
rscale = NUMERIC_MIN_SIG_DIGITS - sweight;
rscale = Max(rscale, arg.dscale);
rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
/*
* Let sqrt_var() do the calculation and return the result.
*/
sqrt_var(&arg, &result, rscale);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| static Numeric numeric_stddev_internal | ( | ArrayType * | transarray, | |
| bool | variance, | |||
| bool | sample, | |||
| bool * | is_null | |||
| ) | [static] |
Definition at line 2670 of file numeric.c.
References cmp_var(), DatumGetNumeric, deconstruct_array(), div_var(), NumericVar::dscale, elog, ERROR, free_var(), init_var, init_var_from_num(), make_result(), mul_var(), NULL, NUMERIC_IS_NAN, NUMERICOID, select_div_scale(), sqrt_var(), and sub_var().
Referenced by numeric_stddev_pop(), numeric_stddev_samp(), numeric_var_pop(), and numeric_var_samp().
{
Datum *transdatums;
int ndatums;
Numeric N,
sumX,
sumX2,
res;
NumericVar vN,
vsumX,
vsumX2,
vNminus1;
NumericVar *comp;
int rscale;
*is_null = false;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
NUMERICOID, -1, false, 'i',
&transdatums, NULL, &ndatums);
if (ndatums != 3)
elog(ERROR, "expected 3-element numeric array");
N = DatumGetNumeric(transdatums[0]);
sumX = DatumGetNumeric(transdatums[1]);
sumX2 = DatumGetNumeric(transdatums[2]);
if (NUMERIC_IS_NAN(N) || NUMERIC_IS_NAN(sumX) || NUMERIC_IS_NAN(sumX2))
return make_result(&const_nan);
init_var_from_num(N, &vN);
/*
* Sample stddev and variance are undefined when N <= 1; population stddev
* is undefined when N == 0. Return NULL in either case.
*/
if (sample)
comp = &const_one;
else
comp = &const_zero;
if (cmp_var(&vN, comp) <= 0)
{
*is_null = true;
return NULL;
}
init_var(&vNminus1);
sub_var(&vN, &const_one, &vNminus1);
init_var_from_num(sumX, &vsumX);
init_var_from_num(sumX2, &vsumX2);
/* compute rscale for mul_var calls */
rscale = vsumX.dscale * 2;
mul_var(&vsumX, &vsumX, &vsumX, rscale); /* vsumX = sumX * sumX */
mul_var(&vN, &vsumX2, &vsumX2, rscale); /* vsumX2 = N * sumX2 */
sub_var(&vsumX2, &vsumX, &vsumX2); /* N * sumX2 - sumX * sumX */
if (cmp_var(&vsumX2, &const_zero) <= 0)
{
/* Watch out for roundoff error producing a negative numerator */
res = make_result(&const_zero);
}
else
{
if (sample)
mul_var(&vN, &vNminus1, &vNminus1, 0); /* N * (N - 1) */
else
mul_var(&vN, &vN, &vNminus1, 0); /* N * N */
rscale = select_div_scale(&vsumX2, &vNminus1);
div_var(&vsumX2, &vNminus1, &vsumX, rscale, true); /* variance */
if (!variance)
sqrt_var(&vsumX, &vsumX, rscale); /* stddev */
res = make_result(&vsumX);
}
free_var(&vNminus1);
free_var(&vsumX);
free_var(&vsumX2);
return res;
}
| Datum numeric_stddev_pop | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2804 of file numeric.c.
References numeric_stddev_internal(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_NULL, and PG_RETURN_NUMERIC.
{
Numeric res;
bool is_null;
res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
false, false, &is_null);
if (is_null)
PG_RETURN_NULL();
else
PG_RETURN_NUMERIC(res);
}
| Datum numeric_stddev_samp | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2774 of file numeric.c.
References numeric_stddev_internal(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_NULL, and PG_RETURN_NUMERIC.
{
Numeric res;
bool is_null;
res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
false, true, &is_null);
if (is_null)
PG_RETURN_NULL();
else
PG_RETURN_NUMERIC(res);
}
| Datum numeric_sub | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1586 of file numeric.c.
References free_var(), init_var, init_var_from_num(), make_result(), NUMERIC_IS_NAN, PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, and sub_var().
Referenced by gbt_numeric_penalty(), numrange_subdiff(), and pg_xlog_location_diff().
{
Numeric num1 = PG_GETARG_NUMERIC(0);
Numeric num2 = PG_GETARG_NUMERIC(1);
NumericVar arg1;
NumericVar arg2;
NumericVar result;
Numeric res;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num1) || NUMERIC_IS_NAN(num2))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Unpack the values, let sub_var() compute the result and return it.
*/
init_var_from_num(num1, &arg1);
init_var_from_num(num2, &arg2);
init_var(&result);
sub_var(&arg1, &arg2, &result);
res = make_result(&result);
free_var(&result);
PG_RETURN_NUMERIC(res);
}
| static double numeric_to_double_no_overflow | ( | Numeric | num | ) | [static] |
Definition at line 3956 of file numeric.c.
References DatumGetCString, DirectFunctionCall1, ereport, errcode(), errmsg(), ERROR, numeric_out(), NumericGetDatum, pfree(), and val.
Referenced by numeric_float8_no_overflow().
{
char *tmp;
double val;
char *endptr;
tmp = DatumGetCString(DirectFunctionCall1(numeric_out,
NumericGetDatum(num)));
/* unlike float8in, we ignore ERANGE from strtod */
val = strtod(tmp, &endptr);
if (*endptr != '\0')
{
/* shouldn't happen ... */
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type double precision: \"%s\"",
tmp)));
}
pfree(tmp);
return val;
}
| Datum numeric_transform | ( | PG_FUNCTION_ARGS | ) |
Definition at line 724 of file numeric.c.
References FuncExpr::args, Assert, DatumGetInt32, exprTypmod(), IsA, linitial, list_length(), lsecond, PG_GETARG_POINTER, PG_RETURN_POINTER, relabel_to_typmod(), and VARHDRSZ.
{
FuncExpr *expr = (FuncExpr *) PG_GETARG_POINTER(0);
Node *ret = NULL;
Node *typmod;
Assert(IsA(expr, FuncExpr));
Assert(list_length(expr->args) >= 2);
typmod = (Node *) lsecond(expr->args);
if (IsA(typmod, Const) &&!((Const *) typmod)->constisnull)
{
Node *source = (Node *) linitial(expr->args);
int32 old_typmod = exprTypmod(source);
int32 new_typmod = DatumGetInt32(((Const *) typmod)->constvalue);
int32 old_scale = (old_typmod - VARHDRSZ) & 0xffff;
int32 new_scale = (new_typmod - VARHDRSZ) & 0xffff;
int32 old_precision = (old_typmod - VARHDRSZ) >> 16 & 0xffff;
int32 new_precision = (new_typmod - VARHDRSZ) >> 16 & 0xffff;
/*
* If new_typmod < VARHDRSZ, the destination is unconstrained; that's
* always OK. If old_typmod >= VARHDRSZ, the source is constrained,
* and we're OK if the scale is unchanged and the precision is not
* decreasing. See further notes in function header comment.
*/
if (new_typmod < (int32) VARHDRSZ ||
(old_typmod >= (int32) VARHDRSZ &&
new_scale == old_scale && new_precision >= old_precision))
ret = relabel_to_typmod(source, new_typmod);
}
PG_RETURN_POINTER(ret);
}
| Datum numeric_trunc | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1095 of file numeric.c.
References arg, NumericVar::dscale, free_var(), init_var, make_result(), Max, Min, NUMERIC_IS_NAN, NUMERIC_MAX_RESULT_SCALE, PG_GETARG_INT32, PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, scale, set_var_from_num(), and trunc_var().
{
Numeric num = PG_GETARG_NUMERIC(0);
int32 scale = PG_GETARG_INT32(1);
Numeric res;
NumericVar arg;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Limit the scale value to avoid possible overflow in calculations
*/
scale = Max(scale, -NUMERIC_MAX_RESULT_SCALE);
scale = Min(scale, NUMERIC_MAX_RESULT_SCALE);
/*
* Unpack the argument and truncate it at the proper digit position
*/
init_var(&arg);
set_var_from_num(num, &arg);
trunc_var(&arg, scale);
/* We don't allow negative output dscale */
if (scale < 0)
arg.dscale = 0;
/*
* Return the truncated result
*/
res = make_result(&arg);
free_var(&arg);
PG_RETURN_NUMERIC(res);
}
| Datum numeric_uminus | ( | PG_FUNCTION_ARGS | ) |
Definition at line 942 of file numeric.c.
References NumericData::choice, make_result(), NumericShort::n_header, NumericChoice::n_long, NumericChoice::n_short, NumericLong::n_sign_dscale, NUMERIC_DSCALE, NUMERIC_IS_NAN, NUMERIC_IS_SHORT, NUMERIC_NDIGITS, NUMERIC_NEG, NUMERIC_POS, NUMERIC_SIGN, palloc(), PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, and VARSIZE.
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
/*
* Handle NaN
*/
if (NUMERIC_IS_NAN(num))
PG_RETURN_NUMERIC(make_result(&const_nan));
/*
* Do it the easy way directly on the packed format
*/
res = (Numeric) palloc(VARSIZE(num));
memcpy(res, num, VARSIZE(num));
/*
* The packed format is known to be totally zero digit trimmed always. So
* we can identify a ZERO by the fact that there are no digits at all. Do
* nothing to a zero.
*/
if (NUMERIC_NDIGITS(num) != 0)
{
/* Else, flip the sign */
if (NUMERIC_IS_SHORT(num))
res->choice.n_short.n_header =
num->choice.n_short.n_header ^ NUMERIC_SHORT_SIGN_MASK;
else if (NUMERIC_SIGN(num) == NUMERIC_POS)
res->choice.n_long.n_sign_dscale =
NUMERIC_NEG | NUMERIC_DSCALE(num);
else
res->choice.n_long.n_sign_dscale =
NUMERIC_POS | NUMERIC_DSCALE(num);
}
PG_RETURN_NUMERIC(res);
}
| Datum numeric_uplus | ( | PG_FUNCTION_ARGS | ) |
Definition at line 983 of file numeric.c.
References palloc(), PG_GETARG_NUMERIC, PG_RETURN_NUMERIC, and VARSIZE.
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
res = (Numeric) palloc(VARSIZE(num));
memcpy(res, num, VARSIZE(num));
PG_RETURN_NUMERIC(res);
}
| Datum numeric_var_pop | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2789 of file numeric.c.
References numeric_stddev_internal(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_NULL, and PG_RETURN_NUMERIC.
{
Numeric res;
bool is_null;
res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
true, false, &is_null);
if (is_null)
PG_RETURN_NULL();
else
PG_RETURN_NUMERIC(res);
}
| Datum numeric_var_samp | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2759 of file numeric.c.
References numeric_stddev_internal(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_NULL, and PG_RETURN_NUMERIC.
{
Numeric res;
bool is_null;
res = numeric_stddev_internal(PG_GETARG_ARRAYTYPE_P(0),
true, true, &is_null);
if (is_null)
PG_RETURN_NULL();
else
PG_RETURN_NUMERIC(res);
}
| Datum numerictypmodin | ( | PG_FUNCTION_ARGS | ) |
Definition at line 845 of file numeric.c.
References ArrayGetIntegerTypmods(), ereport, errcode(), errmsg(), ERROR, NUMERIC_MAX_PRECISION, PG_GETARG_ARRAYTYPE_P, PG_RETURN_INT32, and VARHDRSZ.
{
ArrayType *ta = PG_GETARG_ARRAYTYPE_P(0);
int32 *tl;
int n;
int32 typmod;
tl = ArrayGetIntegerTypmods(ta, &n);
if (n == 2)
{
if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("NUMERIC precision %d must be between 1 and %d",
tl[0], NUMERIC_MAX_PRECISION)));
if (tl[1] < 0 || tl[1] > tl[0])
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("NUMERIC scale %d must be between 0 and precision %d",
tl[1], tl[0])));
typmod = ((tl[0] << 16) | tl[1]) + VARHDRSZ;
}
else if (n == 1)
{
if (tl[0] < 1 || tl[0] > NUMERIC_MAX_PRECISION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("NUMERIC precision %d must be between 1 and %d",
tl[0], NUMERIC_MAX_PRECISION)));
/* scale defaults to zero */
typmod = (tl[0] << 16) + VARHDRSZ;
}
else
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("invalid NUMERIC type modifier")));
typmod = 0; /* keep compiler quiet */
}
PG_RETURN_INT32(typmod);
}
| Datum numerictypmodout | ( | PG_FUNCTION_ARGS | ) |
Definition at line 890 of file numeric.c.
References palloc(), PG_GETARG_INT32, PG_RETURN_CSTRING, snprintf(), and VARHDRSZ.
{
int32 typmod = PG_GETARG_INT32(0);
char *res = (char *) palloc(64);
if (typmod >= 0)
snprintf(res, 64, "(%d,%d)",
((typmod - VARHDRSZ) >> 16) & 0xffff,
(typmod - VARHDRSZ) & 0xffff);
else
*res = '\0';
PG_RETURN_CSTRING(res);
}
| static double numericvar_to_double_no_overflow | ( | NumericVar * | var | ) | [static] |
Definition at line 3983 of file numeric.c.
References ereport, errcode(), errmsg(), ERROR, get_str_from_var(), pfree(), and val.
Referenced by numeric_exp(), and power_var().
{
char *tmp;
double val;
char *endptr;
tmp = get_str_from_var(var);
/* unlike float8in, we ignore ERANGE from strtod */
val = strtod(tmp, &endptr);
if (*endptr != '\0')
{
/* shouldn't happen ... */
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type double precision: \"%s\"",
tmp)));
}
pfree(tmp);
return val;
}
| static int32 numericvar_to_int4 | ( | NumericVar * | var | ) | [static] |
Definition at line 2234 of file numeric.c.
References ereport, errcode(), errmsg(), ERROR, numericvar_to_int8(), and val.
Referenced by numeric_int4(), and width_bucket_numeric().
{
int32 result;
int64 val;
if (!numericvar_to_int8(var, &val))
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
/* Down-convert to int4 */
result = (int32) val;
/* Test for overflow by reverse-conversion. */
if ((int64) result != val)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("integer out of range")));
return result;
}
| static bool numericvar_to_int8 | ( | NumericVar * | var, | |
| int64 * | result | |||
| ) | [static] |
Definition at line 3840 of file numeric.c.
References Assert, NumericVar::digits, free_var(), init_var, NBASE, NumericVar::ndigits, round_var(), set_var_from_var(), NumericVar::sign, strip_var(), val, and NumericVar::weight.
Referenced by numeric_int2(), numeric_int8(), numericvar_to_int4(), and power_var().
{
NumericDigit *digits;
int ndigits;
int weight;
int i;
int64 val,
oldval;
bool neg;
NumericVar rounded;
/* Round to nearest integer */
init_var(&rounded);
set_var_from_var(var, &rounded);
round_var(&rounded, 0);
/* Check for zero input */
strip_var(&rounded);
ndigits = rounded.ndigits;
if (ndigits == 0)
{
*result = 0;
free_var(&rounded);
return true;
}
/*
* For input like 10000000000, we must treat stripped digits as real. So
* the loop assumes there are weight+1 digits before the decimal point.
*/
weight = rounded.weight;
Assert(weight >= 0 && ndigits <= weight + 1);
/* Construct the result */
digits = rounded.digits;
neg = (rounded.sign == NUMERIC_NEG);
val = digits[0];
for (i = 1; i <= weight; i++)
{
oldval = val;
val *= NBASE;
if (i < ndigits)
val += digits[i];
/*
* The overflow check is a bit tricky because we want to accept
* INT64_MIN, which will overflow the positive accumulator. We can
* detect this case easily though because INT64_MIN is the only
* nonzero value for which -val == val (on a two's complement machine,
* anyway).
*/
if ((val / NBASE) != oldval) /* possible overflow? */
{
if (!neg || (-val) != val || val == 0 || oldval < 0)
{
free_var(&rounded);
return false;
}
}
}
free_var(&rounded);
*result = neg ? -val : val;
return true;
}
| static void power_var | ( | NumericVar * | base, | |
| NumericVar * | exp, | |||
| NumericVar * | result | |||
| ) | [static] |
Definition at line 5543 of file numeric.c.
References cmp_var(), DEC_DIGITS, NumericVar::dscale, exp_var(), free_var(), init_var, ln_var(), Max, Min, mul_var(), NumericVar::ndigits, NUMERIC_MAX_DISPLAY_SCALE, NUMERIC_MAX_RESULT_SCALE, NUMERIC_MIN_DISPLAY_SCALE, NUMERIC_MIN_SIG_DIGITS, numericvar_to_double_no_overflow(), numericvar_to_int8(), power_var_int(), set_var_from_var(), val, and NumericVar::weight.
Referenced by numeric_power().
{
NumericVar ln_base;
NumericVar ln_num;
int dec_digits;
int rscale;
int local_rscale;
double val;
/* If exp can be represented as an integer, use power_var_int */
if (exp->ndigits == 0 || exp->ndigits <= exp->weight + 1)
{
/* exact integer, but does it fit in int? */
int64 expval64;
if (numericvar_to_int8(exp, &expval64))
{
int expval = (int) expval64;
/* Test for overflow by reverse-conversion. */
if ((int64) expval == expval64)
{
/* Okay, select rscale */
rscale = NUMERIC_MIN_SIG_DIGITS;
rscale = Max(rscale, base->dscale);
rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
power_var_int(base, expval, result, rscale);
return;
}
}
}
/*
* This avoids log(0) for cases of 0 raised to a non-integer. 0 ^ 0
* handled by power_var_int().
*/
if (cmp_var(base, &const_zero) == 0)
{
set_var_from_var(&const_zero, result);
result->dscale = NUMERIC_MIN_SIG_DIGITS; /* no need to round */
return;
}
init_var(&ln_base);
init_var(&ln_num);
/* Set scale for ln() calculation --- need extra accuracy here */
/* Approx decimal digits before decimal point */
dec_digits = (base->weight + 1) * DEC_DIGITS;
if (dec_digits > 1)
rscale = NUMERIC_MIN_SIG_DIGITS * 2 - (int) log10(dec_digits - 1);
else if (dec_digits < 1)
rscale = NUMERIC_MIN_SIG_DIGITS * 2 - (int) log10(1 - dec_digits);
else
rscale = NUMERIC_MIN_SIG_DIGITS * 2;
rscale = Max(rscale, base->dscale * 2);
rscale = Max(rscale, exp->dscale * 2);
rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE * 2);
rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE * 2);
local_rscale = rscale + 8;
ln_var(base, &ln_base, local_rscale);
mul_var(&ln_base, exp, &ln_num, local_rscale);
/* Set scale for exp() -- compare numeric_exp() */
/* convert input to float8, ignoring overflow */
val = numericvar_to_double_no_overflow(&ln_num);
/*
* log10(result) = num * log10(e), so this is approximately the weight:
*/
val *= 0.434294481903252;
/* limit to something that won't cause integer overflow */
val = Max(val, -NUMERIC_MAX_RESULT_SCALE);
val = Min(val, NUMERIC_MAX_RESULT_SCALE);
rscale = NUMERIC_MIN_SIG_DIGITS - (int) val;
rscale = Max(rscale, base->dscale);
rscale = Max(rscale, exp->dscale);
rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
exp_var(&ln_num, result, rscale);
free_var(&ln_num);
free_var(&ln_base);
}
| static void power_var_int | ( | NumericVar * | base, | |
| int | exp, | |||
| NumericVar * | result, | |||
| int | rscale | |||
| ) | [static] |
Definition at line 5646 of file numeric.c.
References Abs, div_var(), div_var_fast(), NumericVar::dscale, free_var(), init_var, MUL_GUARD_DIGITS, mul_var(), round_var(), and set_var_from_var().
Referenced by exp_var(), get_str_from_var_sci(), and power_var().
{
bool neg;
NumericVar base_prod;
int local_rscale;
switch (exp)
{
case 0:
/*
* While 0 ^ 0 can be either 1 or indeterminate (error), we treat
* it as 1 because most programming languages do this. SQL:2003
* also requires a return value of 1.
* http://en.wikipedia.org/wiki/Exponentiation#Zero_to_the_zero_pow
* er
*/
set_var_from_var(&const_one, result);
result->dscale = rscale; /* no need to round */
return;
case 1:
set_var_from_var(base, result);
round_var(result, rscale);
return;
case -1:
div_var(&const_one, base, result, rscale, true);
return;
case 2:
mul_var(base, base, result, rscale);
return;
default:
break;
}
/*
* The general case repeatedly multiplies base according to the bit
* pattern of exp. We do the multiplications with some extra precision.
*/
neg = (exp < 0);
exp = Abs(exp);
local_rscale = rscale + MUL_GUARD_DIGITS * 2;
init_var(&base_prod);
set_var_from_var(base, &base_prod);
if (exp & 1)
set_var_from_var(base, result);
else
set_var_from_var(&const_one, result);
while ((exp >>= 1) > 0)
{
mul_var(&base_prod, &base_prod, &base_prod, local_rscale);
if (exp & 1)
mul_var(&base_prod, result, result, local_rscale);
}
free_var(&base_prod);
/* Compensate for input sign, and round to requested rscale */
if (neg)
div_var_fast(&const_one, result, result, rscale, true);
else
round_var(result, rscale);
}
| static void round_var | ( | NumericVar * | var, | |
| int | rscale | |||
| ) | [static] |
Definition at line 5978 of file numeric.c.
References Assert, NumericVar::buf, DEC_DIGITS, NumericVar::digits, NumericVar::dscale, NBASE, NumericVar::ndigits, round_powers, NumericVar::sign, and NumericVar::weight.
Referenced by apply_typmod(), div_var(), div_var_fast(), exp_var(), mul_var(), numeric_round(), numericvar_to_int8(), power_var_int(), and sqrt_var().
{
NumericDigit *digits = var->digits;
int di;
int ndigits;
int carry;
var->dscale = rscale;
/* decimal digits wanted */
di = (var->weight + 1) * DEC_DIGITS + rscale;
/*
* If di = 0, the value loses all digits, but could round up to 1 if its
* first extra digit is >= 5. If di < 0 the result must be 0.
*/
if (di < 0)
{
var->ndigits = 0;
var->weight = 0;
var->sign = NUMERIC_POS;
}
else
{
/* NBASE digits wanted */
ndigits = (di + DEC_DIGITS - 1) / DEC_DIGITS;
/* 0, or number of decimal digits to keep in last NBASE digit */
di %= DEC_DIGITS;
if (ndigits < var->ndigits ||
(ndigits == var->ndigits && di > 0))
{
var->ndigits = ndigits;
#if DEC_DIGITS == 1
/* di must be zero */
carry = (digits[ndigits] >= HALF_NBASE) ? 1 : 0;
#else
if (di == 0)
carry = (digits[ndigits] >= HALF_NBASE) ? 1 : 0;
else
{
/* Must round within last NBASE digit */
int extra,
pow10;
#if DEC_DIGITS == 4
pow10 = round_powers[di];
#elif DEC_DIGITS == 2
pow10 = 10;
#else
#error unsupported NBASE
#endif
extra = digits[--ndigits] % pow10;
digits[ndigits] -= extra;
carry = 0;
if (extra >= pow10 / 2)
{
pow10 += digits[ndigits];
if (pow10 >= NBASE)
{
pow10 -= NBASE;
carry = 1;
}
digits[ndigits] = pow10;
}
}
#endif
/* Propagate carry if needed */
while (carry)
{
carry += digits[--ndigits];
if (carry >= NBASE)
{
digits[ndigits] = carry - NBASE;
carry = 1;
}
else
{
digits[ndigits] = carry;
carry = 0;
}
}
if (ndigits < 0)
{
Assert(ndigits == -1); /* better not have added > 1 digit */
Assert(var->digits > var->buf);
var->digits--;
var->ndigits++;
var->weight++;
}
}
}
}
| static int select_div_scale | ( | NumericVar * | var1, | |
| NumericVar * | var2 | |||
| ) | [static] |
Definition at line 5016 of file numeric.c.
References NumericVar::digits, NumericVar::dscale, Max, Min, NumericVar::ndigits, NUMERIC_MAX_DISPLAY_SCALE, NUMERIC_MIN_DISPLAY_SCALE, NUMERIC_MIN_SIG_DIGITS, and NumericVar::weight.
Referenced by compute_bucket(), log_var(), numeric_div(), and numeric_stddev_internal().
{
int weight1,
weight2,
qweight,
i;
NumericDigit firstdigit1,
firstdigit2;
int rscale;
/*
* The result scale of a division isn't specified in any SQL standard. For
* PostgreSQL we select a result scale that will give at least
* NUMERIC_MIN_SIG_DIGITS significant digits, so that numeric gives a
* result no less accurate than float8; but use a scale not less than
* either input's display scale.
*/
/* Get the actual (normalized) weight and first digit of each input */
weight1 = 0; /* values to use if var1 is zero */
firstdigit1 = 0;
for (i = 0; i < var1->ndigits; i++)
{
firstdigit1 = var1->digits[i];
if (firstdigit1 != 0)
{
weight1 = var1->weight - i;
break;
}
}
weight2 = 0; /* values to use if var2 is zero */
firstdigit2 = 0;
for (i = 0; i < var2->ndigits; i++)
{
firstdigit2 = var2->digits[i];
if (firstdigit2 != 0)
{
weight2 = var2->weight - i;
break;
}
}
/*
* Estimate weight of quotient. If the two first digits are equal, we
* can't be sure, but assume that var1 is less than var2.
*/
qweight = weight1 - weight2;
if (firstdigit1 <= firstdigit2)
qweight--;
/* Select result scale */
rscale = NUMERIC_MIN_SIG_DIGITS - qweight * DEC_DIGITS;
rscale = Max(rscale, var1->dscale);
rscale = Max(rscale, var2->dscale);
rscale = Max(rscale, NUMERIC_MIN_DISPLAY_SCALE);
rscale = Min(rscale, NUMERIC_MAX_DISPLAY_SCALE);
return rscale;
}
| static void set_var_from_num | ( | Numeric | value, | |
| NumericVar * | dest | |||
| ) | [static] |
Definition at line 3367 of file numeric.c.
References alloc_var(), NumericVar::digits, NumericVar::dscale, NUMERIC_DIGITS, NUMERIC_DSCALE, NUMERIC_NDIGITS, NUMERIC_SIGN, NUMERIC_WEIGHT, NumericVar::sign, and NumericVar::weight.
Referenced by numeric(), numeric_round(), and numeric_trunc().
{
int ndigits;
ndigits = NUMERIC_NDIGITS(num);
alloc_var(dest, ndigits);
dest->weight = NUMERIC_WEIGHT(num);
dest->sign = NUMERIC_SIGN(num);
dest->dscale = NUMERIC_DSCALE(num);
memcpy(dest->digits, NUMERIC_DIGITS(num), ndigits * sizeof(NumericDigit));
}
| static const char * set_var_from_str | ( | const char * | str, | |
| const char * | cp, | |||
| NumericVar * | dest | |||
| ) | [static] |
Definition at line 3213 of file numeric.c.
References alloc_var(), DEC_DIGITS, NumericVar::digits, NumericVar::dscale, ereport, errcode(), errmsg(), ERROR, NUMERIC_MAX_PRECISION, palloc(), pfree(), NumericVar::sign, sign, strip_var(), and NumericVar::weight.
Referenced by float4_numeric(), float8_numeric(), and numeric_in().
{
bool have_dp = FALSE;
int i;
unsigned char *decdigits;
int sign = NUMERIC_POS;
int dweight = -1;
int ddigits;
int dscale = 0;
int weight;
int ndigits;
int offset;
NumericDigit *digits;
/*
* We first parse the string to extract decimal digits and determine the
* correct decimal weight. Then convert to NBASE representation.
*/
switch (*cp)
{
case '+':
sign = NUMERIC_POS;
cp++;
break;
case '-':
sign = NUMERIC_NEG;
cp++;
break;
}
if (*cp == '.')
{
have_dp = TRUE;
cp++;
}
if (!isdigit((unsigned char) *cp))
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type numeric: \"%s\"", str)));
decdigits = (unsigned char *) palloc(strlen(cp) + DEC_DIGITS * 2);
/* leading padding for digit alignment later */
memset(decdigits, 0, DEC_DIGITS);
i = DEC_DIGITS;
while (*cp)
{
if (isdigit((unsigned char) *cp))
{
decdigits[i++] = *cp++ - '0';
if (!have_dp)
dweight++;
else
dscale++;
}
else if (*cp == '.')
{
if (have_dp)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type numeric: \"%s\"",
str)));
have_dp = TRUE;
cp++;
}
else
break;
}
ddigits = i - DEC_DIGITS;
/* trailing padding for digit alignment later */
memset(decdigits + i, 0, DEC_DIGITS - 1);
/* Handle exponent, if any */
if (*cp == 'e' || *cp == 'E')
{
long exponent;
char *endptr;
cp++;
exponent = strtol(cp, &endptr, 10);
if (endptr == cp)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type numeric: \"%s\"",
str)));
cp = endptr;
if (exponent > NUMERIC_MAX_PRECISION ||
exponent < -NUMERIC_MAX_PRECISION)
ereport(ERROR,
(errcode(ERRCODE_INVALID_TEXT_REPRESENTATION),
errmsg("invalid input syntax for type numeric: \"%s\"",
str)));
dweight += (int) exponent;
dscale -= (int) exponent;
if (dscale < 0)
dscale = 0;
}
/*
* Okay, convert pure-decimal representation to base NBASE. First we need
* to determine the converted weight and ndigits. offset is the number of
* decimal zeroes to insert before the first given digit to have a
* correctly aligned first NBASE digit.
*/
if (dweight >= 0)
weight = (dweight + 1 + DEC_DIGITS - 1) / DEC_DIGITS - 1;
else
weight = -((-dweight - 1) / DEC_DIGITS + 1);
offset = (weight + 1) * DEC_DIGITS - (dweight + 1);
ndigits = (ddigits + offset + DEC_DIGITS - 1) / DEC_DIGITS;
alloc_var(dest, ndigits);
dest->sign = sign;
dest->weight = weight;
dest->dscale = dscale;
i = DEC_DIGITS - offset;
digits = dest->digits;
while (ndigits-- > 0)
{
#if DEC_DIGITS == 4
*digits++ = ((decdigits[i] * 10 + decdigits[i + 1]) * 10 +
decdigits[i + 2]) * 10 + decdigits[i + 3];
#elif DEC_DIGITS == 2
*digits++ = decdigits[i] * 10 + decdigits[i + 1];
#elif DEC_DIGITS == 1
*digits++ = decdigits[i];
#else
#error unsupported NBASE
#endif
i += DEC_DIGITS;
}
pfree(decdigits);
/* Strip any leading/trailing zeroes, and normalize weight if zero */
strip_var(dest);
/* Return end+1 position for caller */
return cp;
}
| static void set_var_from_var | ( | NumericVar * | value, | |
| NumericVar * | dest | |||
| ) | [static] |
Definition at line 3415 of file numeric.c.
References NumericVar::buf, digitbuf_alloc, digitbuf_free, NumericVar::digits, memmove, and NumericVar::ndigits.
Referenced by ceil_var(), exp_var(), exp_var_internal(), floor_var(), ln_var(), numeric_power(), numeric_sign(), numericvar_to_int8(), power_var(), power_var_int(), sqrt_var(), and width_bucket_numeric().
{
NumericDigit *newbuf;
newbuf = digitbuf_alloc(value->ndigits + 1);
newbuf[0] = 0; /* spare digit for rounding */
memcpy(newbuf + 1, value->digits, value->ndigits * sizeof(NumericDigit));
digitbuf_free(dest->buf);
memmove(dest, value, sizeof(NumericVar));
dest->buf = newbuf;
dest->digits = newbuf + 1;
}
| static void sqrt_var | ( | NumericVar * | arg, | |
| NumericVar * | result, | |||
| int | rscale | |||
| ) | [static] |
Definition at line 5161 of file numeric.c.
References add_var(), alloc_var(), cmp_var(), NumericVar::digits, div_var_fast(), NumericVar::dscale, ereport, errcode(), errmsg(), ERROR, free_var(), init_var, mul_var(), round_var(), set_var_from_var(), NumericVar::sign, NumericVar::weight, and zero_var().
Referenced by ln_var(), numeric_sqrt(), and numeric_stddev_internal().
{
NumericVar tmp_arg;
NumericVar tmp_val;
NumericVar last_val;
int local_rscale;
int stat;
local_rscale = rscale + 8;
stat = cmp_var(arg, &const_zero);
if (stat == 0)
{
zero_var(result);
result->dscale = rscale;
return;
}
/*
* SQL2003 defines sqrt() in terms of power, so we need to emit the right
* SQLSTATE error code if the operand is negative.
*/
if (stat < 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_POWER_FUNCTION),
errmsg("cannot take square root of a negative number")));
init_var(&tmp_arg);
init_var(&tmp_val);
init_var(&last_val);
/* Copy arg in case it is the same var as result */
set_var_from_var(arg, &tmp_arg);
/*
* Initialize the result to the first guess
*/
alloc_var(result, 1);
result->digits[0] = tmp_arg.digits[0] / 2;
if (result->digits[0] == 0)
result->digits[0] = 1;
result->weight = tmp_arg.weight / 2;
result->sign = NUMERIC_POS;
set_var_from_var(result, &last_val);
for (;;)
{
div_var_fast(&tmp_arg, result, &tmp_val, local_rscale, true);
add_var(result, &tmp_val, result);
mul_var(result, &const_zero_point_five, result, local_rscale);
if (cmp_var(&last_val, result) == 0)
break;
set_var_from_var(result, &last_val);
}
free_var(&last_val);
free_var(&tmp_val);
free_var(&tmp_arg);
/* Round to requested precision */
round_var(result, rscale);
}
| static void strip_var | ( | NumericVar * | var | ) | [static] |
Definition at line 6146 of file numeric.c.
References NumericVar::digits, NumericVar::ndigits, NumericVar::sign, and NumericVar::weight.
Referenced by add_abs(), div_var(), div_var_fast(), mul_var(), numericvar_to_int8(), set_var_from_str(), and sub_abs().
{
NumericDigit *digits = var->digits;
int ndigits = var->ndigits;
/* Strip leading zeroes */
while (ndigits > 0 && *digits == 0)
{
digits++;
var->weight--;
ndigits--;
}
/* Strip trailing zeroes */
while (ndigits > 0 && digits[ndigits - 1] == 0)
ndigits--;
/* If it's zero, normalize the sign and weight */
if (ndigits == 0)
{
var->sign = NUMERIC_POS;
var->weight = 0;
}
var->digits = digits;
var->ndigits = ndigits;
}
| static void sub_abs | ( | NumericVar * | var1, | |
| NumericVar * | var2, | |||
| NumericVar * | result | |||
| ) | [static] |
Definition at line 5896 of file numeric.c.
References Assert, NumericVar::buf, digitbuf_alloc, digitbuf_free, NumericVar::digits, NumericVar::dscale, Max, NumericVar::ndigits, strip_var(), and NumericVar::weight.
Referenced by add_var(), and sub_var().
{
NumericDigit *res_buf;
NumericDigit *res_digits;
int res_ndigits;
int res_weight;
int res_rscale,
rscale1,
rscale2;
int res_dscale;
int i,
i1,
i2;
int borrow = 0;
/* copy these values into local vars for speed in inner loop */
int var1ndigits = var1->ndigits;
int var2ndigits = var2->ndigits;
NumericDigit *var1digits = var1->digits;
NumericDigit *var2digits = var2->digits;
res_weight = var1->weight;
res_dscale = Max(var1->dscale, var2->dscale);
/* Note: here we are figuring rscale in base-NBASE digits */
rscale1 = var1->ndigits - var1->weight - 1;
rscale2 = var2->ndigits - var2->weight - 1;
res_rscale = Max(rscale1, rscale2);
res_ndigits = res_rscale + res_weight + 1;
if (res_ndigits <= 0)
res_ndigits = 1;
res_buf = digitbuf_alloc(res_ndigits + 1);
res_buf[0] = 0; /* spare digit for later rounding */
res_digits = res_buf + 1;
i1 = res_rscale + var1->weight + 1;
i2 = res_rscale + var2->weight + 1;
for (i = res_ndigits - 1; i >= 0; i--)
{
i1--;
i2--;
if (i1 >= 0 && i1 < var1ndigits)
borrow += var1digits[i1];
if (i2 >= 0 && i2 < var2ndigits)
borrow -= var2digits[i2];
if (borrow < 0)
{
res_digits[i] = borrow + NBASE;
borrow = -1;
}
else
{
res_digits[i] = borrow;
borrow = 0;
}
}
Assert(borrow == 0); /* else caller gave us var1 < var2 */
digitbuf_free(result->buf);
result->ndigits = res_ndigits;
result->buf = res_buf;
result->digits = res_digits;
result->weight = res_weight;
result->dscale = res_dscale;
/* Remove leading/trailing zeroes */
strip_var(result);
}
| static void sub_var | ( | NumericVar * | var1, | |
| NumericVar * | var2, | |||
| NumericVar * | result | |||
| ) | [static] |
Definition at line 4190 of file numeric.c.
References add_abs(), cmp_abs(), NumericVar::dscale, Max, NUMERIC_NEG, NUMERIC_POS, NumericVar::sign, sub_abs(), and zero_var().
Referenced by compute_bucket(), floor_var(), ln_var(), mod_var(), numeric_stddev_internal(), and numeric_sub().
{
/*
* Decide on the signs of the two variables what to do
*/
if (var1->sign == NUMERIC_POS)
{
if (var2->sign == NUMERIC_NEG)
{
/* ----------
* var1 is positive, var2 is negative
* result = +(ABS(var1) + ABS(var2))
* ----------
*/
add_abs(var1, var2, result);
result->sign = NUMERIC_POS;
}
else
{
/* ----------
* Both are positive
* Must compare absolute values
* ----------
*/
switch (cmp_abs(var1, var2))
{
case 0:
/* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
zero_var(result);
result->dscale = Max(var1->dscale, var2->dscale);
break;
case 1:
/* ----------
* ABS(var1) > ABS(var2)
* result = +(ABS(var1) - ABS(var2))
* ----------
*/
sub_abs(var1, var2, result);
result->sign = NUMERIC_POS;
break;
case -1:
/* ----------
* ABS(var1) < ABS(var2)
* result = -(ABS(var2) - ABS(var1))
* ----------
*/
sub_abs(var2, var1, result);
result->sign = NUMERIC_NEG;
break;
}
}
}
else
{
if (var2->sign == NUMERIC_NEG)
{
/* ----------
* Both are negative
* Must compare absolute values
* ----------
*/
switch (cmp_abs(var1, var2))
{
case 0:
/* ----------
* ABS(var1) == ABS(var2)
* result = ZERO
* ----------
*/
zero_var(result);
result->dscale = Max(var1->dscale, var2->dscale);
break;
case 1:
/* ----------
* ABS(var1) > ABS(var2)
* result = -(ABS(var1) - ABS(var2))
* ----------
*/
sub_abs(var1, var2, result);
result->sign = NUMERIC_NEG;
break;
case -1:
/* ----------
* ABS(var1) < ABS(var2)
* result = +(ABS(var2) - ABS(var1))
* ----------
*/
sub_abs(var2, var1, result);
result->sign = NUMERIC_POS;
break;
}
}
else
{
/* ----------
* var1 is negative, var2 is positive
* result = -(ABS(var1) + ABS(var2))
* ----------
*/
add_abs(var1, var2, result);
result->sign = NUMERIC_NEG;
}
}
}
| static void trunc_var | ( | NumericVar * | var, | |
| int | rscale | |||
| ) | [static] |
Definition at line 6084 of file numeric.c.
References DEC_DIGITS, NumericVar::digits, NumericVar::dscale, NumericVar::ndigits, round_powers, NumericVar::sign, and NumericVar::weight.
Referenced by ceil_var(), div_var(), div_var_fast(), floor_var(), numeric_power(), and numeric_trunc().
{
int di;
int ndigits;
var->dscale = rscale;
/* decimal digits wanted */
di = (var->weight + 1) * DEC_DIGITS + rscale;
/*
* If di <= 0, the value loses all digits.
*/
if (di <= 0)
{
var->ndigits = 0;
var->weight = 0;
var->sign = NUMERIC_POS;
}
else
{
/* NBASE digits wanted */
ndigits = (di + DEC_DIGITS - 1) / DEC_DIGITS;
if (ndigits <= var->ndigits)
{
var->ndigits = ndigits;
#if DEC_DIGITS == 1
/* no within-digit stuff to worry about */
#else
/* 0, or number of decimal digits to keep in last NBASE digit */
di %= DEC_DIGITS;
if (di > 0)
{
/* Must truncate within last NBASE digit */
NumericDigit *digits = var->digits;
int extra,
pow10;
#if DEC_DIGITS == 4
pow10 = round_powers[di];
#elif DEC_DIGITS == 2
pow10 = 10;
#else
#error unsupported NBASE
#endif
extra = digits[--ndigits] % pow10;
digits[ndigits] -= extra;
}
#endif
}
}
}
| Datum width_bucket_numeric | ( | PG_FUNCTION_ARGS | ) |
Definition at line 1199 of file numeric.c.
References add_var(), cmp_numerics(), compute_bucket(), ereport, errcode(), errmsg(), ERROR, free_var(), init_var, int8_to_numericvar(), NUMERIC_IS_NAN, numericvar_to_int4(), PG_GETARG_INT32, PG_GETARG_NUMERIC, PG_RETURN_INT32, and set_var_from_var().
{
Numeric operand = PG_GETARG_NUMERIC(0);
Numeric bound1 = PG_GETARG_NUMERIC(1);
Numeric bound2 = PG_GETARG_NUMERIC(2);
int32 count = PG_GETARG_INT32(3);
NumericVar count_var;
NumericVar result_var;
int32 result;
if (count <= 0)
ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
errmsg("count must be greater than zero")));
if (NUMERIC_IS_NAN(operand) ||
NUMERIC_IS_NAN(bound1) ||
NUMERIC_IS_NAN(bound2))
ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
errmsg("operand, lower bound, and upper bound cannot be NaN")));
init_var(&result_var);
init_var(&count_var);
/* Convert 'count' to a numeric, for ease of use later */
int8_to_numericvar((int64) count, &count_var);
switch (cmp_numerics(bound1, bound2))
{
case 0:
ereport(ERROR,
(errcode(ERRCODE_INVALID_ARGUMENT_FOR_WIDTH_BUCKET_FUNCTION),
errmsg("lower bound cannot equal upper bound")));
/* bound1 < bound2 */
case -1:
if (cmp_numerics(operand, bound1) < 0)
set_var_from_var(&const_zero, &result_var);
else if (cmp_numerics(operand, bound2) >= 0)
add_var(&count_var, &const_one, &result_var);
else
compute_bucket(operand, bound1, bound2,
&count_var, &result_var);
break;
/* bound1 > bound2 */
case 1:
if (cmp_numerics(operand, bound1) > 0)
set_var_from_var(&const_zero, &result_var);
else if (cmp_numerics(operand, bound2) <= 0)
add_var(&count_var, &const_one, &result_var);
else
compute_bucket(operand, bound1, bound2,
&count_var, &result_var);
break;
}
/* if result exceeds the range of a legal int4, we ereport here */
result = numericvar_to_int4(&result_var);
free_var(&count_var);
free_var(&result_var);
PG_RETURN_INT32(result);
}
| static void zero_var | ( | NumericVar * | var | ) | [static] |
Definition at line 3189 of file numeric.c.
References NumericVar::buf, digitbuf_free, NumericVar::digits, NumericVar::ndigits, NumericVar::sign, and NumericVar::weight.
Referenced by add_var(), div_var(), div_var_fast(), mul_var(), sqrt_var(), and sub_var().
NumericVar const_nan [static] |
NumericVar const_one [static] |
{1, 0, NUMERIC_POS, 0, NULL, const_one_data}
NumericDigit const_one_data[1] = {1} [static] |
NumericVar const_one_point_one [static] |
{2, 0, NUMERIC_POS, 1, NULL, const_one_point_one_data}
NumericDigit const_one_point_one_data[2] = {1, 1000} [static] |
NumericVar const_ten [static] |
{1, 0, NUMERIC_POS, 0, NULL, const_ten_data}
NumericDigit const_ten_data[1] = {10} [static] |
NumericVar const_two [static] |
{1, 0, NUMERIC_POS, 0, NULL, const_two_data}
NumericDigit const_two_data[1] = {2} [static] |
NumericVar const_zero [static] |
{0, 0, NUMERIC_POS, 0, NULL, const_zero_data}
NumericDigit const_zero_data[1] = {0} [static] |
NumericVar const_zero_point_01 [static] |
{1, -1, NUMERIC_POS, 2, NULL, const_zero_point_01_data}
NumericDigit const_zero_point_01_data[1] = {100} [static] |
NumericVar const_zero_point_five [static] |
{1, -1, NUMERIC_POS, 1, NULL, const_zero_point_five_data}
NumericDigit const_zero_point_five_data[1] = {5000} [static] |
NumericVar const_zero_point_nine [static] |
{1, -1, NUMERIC_POS, 1, NULL, const_zero_point_nine_data}
NumericDigit const_zero_point_nine_data[1] = {9000} [static] |
const int round_powers[4] = {0, 1000, 100, 10} [static] |
Definition at line 337 of file numeric.c.
Referenced by round_var(), and trunc_var().
1.7.1