PostgreSQL Source Code  git master
numeric.c File Reference
#include "postgres.h"
#include <ctype.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include "catalog/pg_type.h"
#include "common/hashfn.h"
#include "common/int.h"
#include "funcapi.h"
#include "lib/hyperloglog.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "nodes/supportnodes.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/guc.h"
#include "utils/numeric.h"
#include "utils/pg_lsn.h"
#include "utils/sortsupport.h"
Include dependency graph for numeric.c:

Go to the source code of this file.

Data Structures

struct  NumericShort
 
struct  NumericLong
 
union  NumericChoice
 
struct  NumericData
 
struct  NumericVar
 
struct  generate_series_numeric_fctx
 
struct  NumericSortSupport
 
struct  NumericSumAccum
 
struct  NumericAggState
 
struct  Int8TransTypeData
 

Macros

#define NBASE   10000
 
#define HALF_NBASE   5000
 
#define DEC_DIGITS   4 /* decimal digits per NBASE digit */
 
#define MUL_GUARD_DIGITS   2 /* these are measured in NBASE digits */
 
#define DIV_GUARD_DIGITS   4
 
#define NUMERIC_SIGN_MASK   0xC000
 
#define NUMERIC_POS   0x0000
 
#define NUMERIC_NEG   0x4000
 
#define NUMERIC_SHORT   0x8000
 
#define NUMERIC_SPECIAL   0xC000
 
#define NUMERIC_FLAGBITS(n)   ((n)->choice.n_header & NUMERIC_SIGN_MASK)
 
#define NUMERIC_IS_SHORT(n)   (NUMERIC_FLAGBITS(n) == NUMERIC_SHORT)
 
#define NUMERIC_IS_SPECIAL(n)   (NUMERIC_FLAGBITS(n) == NUMERIC_SPECIAL)
 
#define NUMERIC_HDRSZ   (VARHDRSZ + sizeof(uint16) + sizeof(int16))
 
#define NUMERIC_HDRSZ_SHORT   (VARHDRSZ + sizeof(uint16))
 
#define NUMERIC_HEADER_IS_SHORT(n)   (((n)->choice.n_header & 0x8000) != 0)
 
#define NUMERIC_HEADER_SIZE(n)
 
#define NUMERIC_EXT_SIGN_MASK   0xF000 /* high bits plus NaN/Inf flag bits */
 
#define NUMERIC_NAN   0xC000
 
#define NUMERIC_PINF   0xD000
 
#define NUMERIC_NINF   0xF000
 
#define NUMERIC_INF_SIGN_MASK   0x2000
 
#define NUMERIC_EXT_FLAGBITS(n)   ((n)->choice.n_header & NUMERIC_EXT_SIGN_MASK)
 
#define NUMERIC_IS_NAN(n)   ((n)->choice.n_header == NUMERIC_NAN)
 
#define NUMERIC_IS_PINF(n)   ((n)->choice.n_header == NUMERIC_PINF)
 
#define NUMERIC_IS_NINF(n)   ((n)->choice.n_header == NUMERIC_NINF)
 
#define NUMERIC_IS_INF(n)    (((n)->choice.n_header & ~NUMERIC_INF_SIGN_MASK) == NUMERIC_PINF)
 
#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_DSCALE_MAX   NUMERIC_DSCALE_MASK
 
#define NUMERIC_SIGN(n)
 
#define NUMERIC_DSCALE(n)
 
#define NUMERIC_WEIGHT(n)
 
#define NUMERIC_ABBREV_BITS   (SIZEOF_DATUM * BITS_PER_BYTE)
 
#define NumericAbbrevGetDatum(X)   ((Datum) (X))
 
#define DatumGetNumericAbbrev(X)   ((int32) (X))
 
#define NUMERIC_ABBREV_NAN   NumericAbbrevGetDatum(PG_INT32_MIN)
 
#define NUMERIC_ABBREV_PINF   NumericAbbrevGetDatum(-PG_INT32_MAX)
 
#define NUMERIC_ABBREV_NINF   NumericAbbrevGetDatum(PG_INT32_MAX)
 
#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)   memset(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)
 
#define NA_TOTAL_COUNT(na)    ((na)->N + (na)->NaNcount + (na)->pInfcount + (na)->nInfcount)
 
#define makePolyNumAggState   makeNumericAggState
 
#define makePolyNumAggStateCurrentContext   makeNumericAggStateCurrentContext
 

Typedefs

typedef int16 NumericDigit
 
typedef struct NumericVar NumericVar
 
typedef struct NumericSumAccum NumericSumAccum
 
typedef struct NumericAggState NumericAggState
 
typedef NumericAggState PolyNumAggState
 
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 bool set_var_from_str (const char *str, const char *cp, NumericVar *dest, const char **endptr, Node *escontext)
 
static bool set_var_from_non_decimal_integer_str (const char *str, const char *cp, int sign, int base, NumericVar *dest, const char **endptr, Node *escontext)
 
static void set_var_from_num (Numeric num, NumericVar *dest)
 
static void init_var_from_num (Numeric num, NumericVar *dest)
 
static void set_var_from_var (const NumericVar *value, NumericVar *dest)
 
static char * get_str_from_var (const NumericVar *var)
 
static char * get_str_from_var_sci (const NumericVar *var, int rscale)
 
static void numericvar_serialize (StringInfo buf, const NumericVar *var)
 
static void numericvar_deserialize (StringInfo buf, NumericVar *var)
 
static Numeric duplicate_numeric (Numeric num)
 
static Numeric make_result (const NumericVar *var)
 
static Numeric make_result_opt_error (const NumericVar *var, bool *have_error)
 
static bool apply_typmod (NumericVar *var, int32 typmod, Node *escontext)
 
static bool apply_typmod_special (Numeric num, int32 typmod, Node *escontext)
 
static bool numericvar_to_int32 (const NumericVar *var, int32 *result)
 
static bool numericvar_to_int64 (const NumericVar *var, int64 *result)
 
static void int64_to_numericvar (int64 val, NumericVar *var)
 
static bool numericvar_to_uint64 (const NumericVar *var, uint64 *result)
 
static double numericvar_to_double_no_overflow (const NumericVar *var)
 
static Datum numeric_abbrev_convert (Datum original_datum, SortSupport ssup)
 
static bool numeric_abbrev_abort (int memtupcount, SortSupport ssup)
 
static int numeric_fast_cmp (Datum x, Datum y, SortSupport ssup)
 
static int numeric_cmp_abbrev (Datum x, Datum y, SortSupport ssup)
 
static Datum numeric_abbrev_convert_var (const NumericVar *var, NumericSortSupport *nss)
 
static int cmp_numerics (Numeric num1, Numeric num2)
 
static int cmp_var (const NumericVar *var1, const 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 (const NumericVar *var1, const NumericVar *var2, NumericVar *result)
 
static void sub_var (const NumericVar *var1, const NumericVar *var2, NumericVar *result)
 
static void mul_var (const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale)
 
static void div_var (const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale, bool round)
 
static void div_var_fast (const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale, bool round)
 
static void div_var_int (const NumericVar *var, int ival, int ival_weight, NumericVar *result, int rscale, bool round)
 
static int select_div_scale (const NumericVar *var1, const NumericVar *var2)
 
static void mod_var (const NumericVar *var1, const NumericVar *var2, NumericVar *result)
 
static void div_mod_var (const NumericVar *var1, const NumericVar *var2, NumericVar *quot, NumericVar *rem)
 
static void ceil_var (const NumericVar *var, NumericVar *result)
 
static void floor_var (const NumericVar *var, NumericVar *result)
 
static void gcd_var (const NumericVar *var1, const NumericVar *var2, NumericVar *result)
 
static void sqrt_var (const NumericVar *arg, NumericVar *result, int rscale)
 
static void exp_var (const NumericVar *arg, NumericVar *result, int rscale)
 
static int estimate_ln_dweight (const NumericVar *var)
 
static void ln_var (const NumericVar *arg, NumericVar *result, int rscale)
 
static void log_var (const NumericVar *base, const NumericVar *num, NumericVar *result)
 
static void power_var (const NumericVar *base, const NumericVar *exp, NumericVar *result)
 
static void power_var_int (const NumericVar *base, int exp, int exp_dscale, NumericVar *result)
 
static void power_ten_int (int exp, NumericVar *result)
 
static int cmp_abs (const NumericVar *var1, const 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 (const NumericVar *var1, const NumericVar *var2, NumericVar *result)
 
static void sub_abs (const NumericVar *var1, const 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, const NumericVar *count_var, bool reversed_bounds, NumericVar *result_var)
 
static void accum_sum_add (NumericSumAccum *accum, const NumericVar *val)
 
static void accum_sum_rescale (NumericSumAccum *accum, const NumericVar *val)
 
static void accum_sum_carry (NumericSumAccum *accum)
 
static void accum_sum_reset (NumericSumAccum *accum)
 
static void accum_sum_final (NumericSumAccum *accum, NumericVar *result)
 
static void accum_sum_copy (NumericSumAccum *dst, NumericSumAccum *src)
 
static void accum_sum_combine (NumericSumAccum *accum, NumericSumAccum *accum2)
 
Datum numeric_in (PG_FUNCTION_ARGS)
 
Datum numeric_out (PG_FUNCTION_ARGS)
 
bool numeric_is_nan (Numeric num)
 
bool numeric_is_inf (Numeric num)
 
static bool numeric_is_integral (Numeric num)
 
static int32 make_numeric_typmod (int precision, int scale)
 
static bool is_valid_numeric_typmod (int32 typmod)
 
static int numeric_typmod_precision (int32 typmod)
 
static int numeric_typmod_scale (int32 typmod)
 
int32 numeric_maximum_size (int32 typmod)
 
char * numeric_out_sci (Numeric num, int scale)
 
char * numeric_normalize (Numeric num)
 
Datum numeric_recv (PG_FUNCTION_ARGS)
 
Datum numeric_send (PG_FUNCTION_ARGS)
 
Datum numeric_support (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)
 
static int numeric_sign_internal (Numeric num)
 
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 generate_series_numeric (PG_FUNCTION_ARGS)
 
Datum generate_series_step_numeric (PG_FUNCTION_ARGS)
 
Datum width_bucket_numeric (PG_FUNCTION_ARGS)
 
Datum numeric_sortsupport (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 in_range_numeric_numeric (PG_FUNCTION_ARGS)
 
Datum hash_numeric (PG_FUNCTION_ARGS)
 
Datum hash_numeric_extended (PG_FUNCTION_ARGS)
 
Datum numeric_add (PG_FUNCTION_ARGS)
 
Numeric numeric_add_opt_error (Numeric num1, Numeric num2, bool *have_error)
 
Datum numeric_sub (PG_FUNCTION_ARGS)
 
Numeric numeric_sub_opt_error (Numeric num1, Numeric num2, bool *have_error)
 
Datum numeric_mul (PG_FUNCTION_ARGS)
 
Numeric numeric_mul_opt_error (Numeric num1, Numeric num2, bool *have_error)
 
Datum numeric_div (PG_FUNCTION_ARGS)
 
Numeric numeric_div_opt_error (Numeric num1, Numeric num2, bool *have_error)
 
Datum numeric_div_trunc (PG_FUNCTION_ARGS)
 
Datum numeric_mod (PG_FUNCTION_ARGS)
 
Numeric numeric_mod_opt_error (Numeric num1, Numeric num2, bool *have_error)
 
Datum numeric_inc (PG_FUNCTION_ARGS)
 
Datum numeric_smaller (PG_FUNCTION_ARGS)
 
Datum numeric_larger (PG_FUNCTION_ARGS)
 
Datum numeric_gcd (PG_FUNCTION_ARGS)
 
Datum numeric_lcm (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 numeric_scale (PG_FUNCTION_ARGS)
 
static int get_min_scale (NumericVar *var)
 
Datum numeric_min_scale (PG_FUNCTION_ARGS)
 
Datum numeric_trim_scale (PG_FUNCTION_ARGS)
 
Numeric int64_to_numeric (int64 val)
 
Numeric int64_div_fast_to_numeric (int64 val1, int log10val2)
 
Datum int4_numeric (PG_FUNCTION_ARGS)
 
int32 numeric_int4_opt_error (Numeric num, bool *have_error)
 
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)
 
Datum numeric_pg_lsn (PG_FUNCTION_ARGS)
 
static NumericAggStatemakeNumericAggState (FunctionCallInfo fcinfo, bool calcSumX2)
 
static NumericAggStatemakeNumericAggStateCurrentContext (bool calcSumX2)
 
static void do_numeric_accum (NumericAggState *state, Numeric newval)
 
static bool do_numeric_discard (NumericAggState *state, Numeric newval)
 
Datum numeric_accum (PG_FUNCTION_ARGS)
 
Datum numeric_combine (PG_FUNCTION_ARGS)
 
Datum numeric_avg_accum (PG_FUNCTION_ARGS)
 
Datum numeric_avg_combine (PG_FUNCTION_ARGS)
 
Datum numeric_avg_serialize (PG_FUNCTION_ARGS)
 
Datum numeric_avg_deserialize (PG_FUNCTION_ARGS)
 
Datum numeric_serialize (PG_FUNCTION_ARGS)
 
Datum numeric_deserialize (PG_FUNCTION_ARGS)
 
Datum numeric_accum_inv (PG_FUNCTION_ARGS)
 
Datum int2_accum (PG_FUNCTION_ARGS)
 
Datum int4_accum (PG_FUNCTION_ARGS)
 
Datum int8_accum (PG_FUNCTION_ARGS)
 
Datum numeric_poly_combine (PG_FUNCTION_ARGS)
 
Datum numeric_poly_serialize (PG_FUNCTION_ARGS)
 
Datum numeric_poly_deserialize (PG_FUNCTION_ARGS)
 
Datum int8_avg_accum (PG_FUNCTION_ARGS)
 
Datum int8_avg_combine (PG_FUNCTION_ARGS)
 
Datum int8_avg_serialize (PG_FUNCTION_ARGS)
 
Datum int8_avg_deserialize (PG_FUNCTION_ARGS)
 
Datum int2_accum_inv (PG_FUNCTION_ARGS)
 
Datum int4_accum_inv (PG_FUNCTION_ARGS)
 
Datum int8_accum_inv (PG_FUNCTION_ARGS)
 
Datum int8_avg_accum_inv (PG_FUNCTION_ARGS)
 
Datum numeric_poly_sum (PG_FUNCTION_ARGS)
 
Datum numeric_poly_avg (PG_FUNCTION_ARGS)
 
Datum numeric_avg (PG_FUNCTION_ARGS)
 
Datum numeric_sum (PG_FUNCTION_ARGS)
 
static Numeric numeric_stddev_internal (NumericAggState *state, 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 numeric_poly_var_samp (PG_FUNCTION_ARGS)
 
Datum numeric_poly_stddev_samp (PG_FUNCTION_ARGS)
 
Datum numeric_poly_var_pop (PG_FUNCTION_ARGS)
 
Datum numeric_poly_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 int4_avg_combine (PG_FUNCTION_ARGS)
 
Datum int2_avg_accum_inv (PG_FUNCTION_ARGS)
 
Datum int4_avg_accum_inv (PG_FUNCTION_ARGS)
 
Datum int8_avg (PG_FUNCTION_ARGS)
 
Datum int2int4_sum (PG_FUNCTION_ARGS)
 
static int xdigit_value (char dig)
 

Variables

static const NumericDigit const_zero_data [1] = {0}
 
static const NumericVar const_zero
 
static const NumericDigit const_one_data [1] = {1}
 
static const NumericVar const_one
 
static const NumericVar const_minus_one
 
static const NumericDigit const_two_data [1] = {2}
 
static const NumericVar const_two
 
static const NumericDigit const_zero_point_nine_data [1] = {9000}
 
static const NumericVar const_zero_point_nine
 
static const NumericDigit const_one_point_one_data [2] = {1, 1000}
 
static const NumericVar const_one_point_one
 
static const NumericVar const_nan
 
static const NumericVar const_pinf
 
static const NumericVar const_ninf
 
static const int round_powers [4] = {0, 1000, 100, 10}
 

Macro Definition Documentation

◆ DatumGetNumericAbbrev

#define DatumGetNumericAbbrev (   X)    ((int32) (X))

Definition at line 404 of file numeric.c.

◆ DEC_DIGITS

#define DEC_DIGITS   4 /* decimal digits per NBASE digit */

Definition at line 98 of file numeric.c.

◆ digitbuf_alloc

#define digitbuf_alloc (   ndigits)     ((NumericDigit *) palloc((ndigits) * sizeof(NumericDigit)))

Definition at line 477 of file numeric.c.

◆ digitbuf_free

#define digitbuf_free (   buf)
Value:
do { \
if ((buf) != NULL) \
pfree(buf); \
} while (0)
static char * buf
Definition: pg_test_fsync.c:67

Definition at line 479 of file numeric.c.

◆ DIV_GUARD_DIGITS

#define DIV_GUARD_DIGITS   4

Definition at line 100 of file numeric.c.

◆ dump_numeric

#define dump_numeric (   s,
 
)

Definition at line 473 of file numeric.c.

◆ dump_var

#define dump_var (   s,
 
)

Definition at line 474 of file numeric.c.

◆ HALF_NBASE

#define HALF_NBASE   5000

Definition at line 97 of file numeric.c.

◆ init_var

#define init_var (   v)    memset(v, 0, sizeof(NumericVar))

Definition at line 485 of file numeric.c.

◆ makePolyNumAggState

#define makePolyNumAggState   makeNumericAggState

Definition at line 5471 of file numeric.c.

◆ makePolyNumAggStateCurrentContext

#define makePolyNumAggStateCurrentContext   makeNumericAggStateCurrentContext

Definition at line 5472 of file numeric.c.

◆ MUL_GUARD_DIGITS

#define MUL_GUARD_DIGITS   2 /* these are measured in NBASE digits */

Definition at line 99 of file numeric.c.

◆ NA_TOTAL_COUNT

#define NA_TOTAL_COUNT (   na)     ((na)->N + (na)->NaNcount + (na)->pInfcount + (na)->nInfcount)

Definition at line 4731 of file numeric.c.

◆ NBASE

#define NBASE   10000

Definition at line 96 of file numeric.c.

◆ NUMERIC_ABBREV_BITS

#define NUMERIC_ABBREV_BITS   (SIZEOF_DATUM * BITS_PER_BYTE)

Definition at line 395 of file numeric.c.

◆ NUMERIC_ABBREV_NAN

#define NUMERIC_ABBREV_NAN   NumericAbbrevGetDatum(PG_INT32_MIN)

Definition at line 405 of file numeric.c.

◆ NUMERIC_ABBREV_NINF

#define NUMERIC_ABBREV_NINF   NumericAbbrevGetDatum(PG_INT32_MAX)

Definition at line 407 of file numeric.c.

◆ NUMERIC_ABBREV_PINF

#define NUMERIC_ABBREV_PINF   NumericAbbrevGetDatum(-PG_INT32_MAX)

Definition at line 406 of file numeric.c.

◆ NUMERIC_CAN_BE_SHORT

#define NUMERIC_CAN_BE_SHORT (   scale,
  weight 
)
Value:
(weight) <= NUMERIC_SHORT_WEIGHT_MAX && \
#define NUMERIC_SHORT_DSCALE_MAX
Definition: numeric.c:217
#define NUMERIC_SHORT_WEIGHT_MIN
Definition: numeric.c:222
#define NUMERIC_SHORT_WEIGHT_MAX
Definition: numeric.c:221
int scale
Definition: pgbench.c:191

Definition at line 491 of file numeric.c.

◆ NUMERIC_DIGITS

#define NUMERIC_DIGITS (   num)
Value:
(num)->choice.n_short.n_data : (num)->choice.n_long.n_data)
#define NUMERIC_HEADER_IS_SHORT(n)
Definition: numeric.c:183

Definition at line 487 of file numeric.c.

◆ NUMERIC_DSCALE

#define NUMERIC_DSCALE (   n)
Value:
((n)->choice.n_short.n_header & NUMERIC_SHORT_DSCALE_MASK) \
: ((n)->choice.n_long.n_sign_dscale & NUMERIC_DSCALE_MASK))
#define NUMERIC_DSCALE_MASK
Definition: numeric.c:234
#define NUMERIC_SHORT_DSCALE_MASK
Definition: numeric.c:215
#define NUMERIC_SHORT_DSCALE_SHIFT
Definition: numeric.c:216

Definition at line 243 of file numeric.c.

◆ NUMERIC_DSCALE_MASK

#define NUMERIC_DSCALE_MASK   0x3FFF

Definition at line 234 of file numeric.c.

◆ NUMERIC_DSCALE_MAX

#define NUMERIC_DSCALE_MAX   NUMERIC_DSCALE_MASK

Definition at line 235 of file numeric.c.

◆ NUMERIC_EXT_FLAGBITS

#define NUMERIC_EXT_FLAGBITS (   n)    ((n)->choice.n_header & NUMERIC_EXT_SIGN_MASK)

Definition at line 203 of file numeric.c.

◆ NUMERIC_EXT_SIGN_MASK

#define NUMERIC_EXT_SIGN_MASK   0xF000 /* high bits plus NaN/Inf flag bits */

Definition at line 197 of file numeric.c.

◆ NUMERIC_FLAGBITS

#define NUMERIC_FLAGBITS (   n)    ((n)->choice.n_header & NUMERIC_SIGN_MASK)

Definition at line 171 of file numeric.c.

◆ NUMERIC_HDRSZ

#define NUMERIC_HDRSZ   (VARHDRSZ + sizeof(uint16) + sizeof(int16))

Definition at line 175 of file numeric.c.

◆ NUMERIC_HDRSZ_SHORT

#define NUMERIC_HDRSZ_SHORT   (VARHDRSZ + sizeof(uint16))

Definition at line 176 of file numeric.c.

◆ NUMERIC_HEADER_IS_SHORT

#define NUMERIC_HEADER_IS_SHORT (   n)    (((n)->choice.n_header & 0x8000) != 0)

Definition at line 183 of file numeric.c.

◆ NUMERIC_HEADER_SIZE

#define NUMERIC_HEADER_SIZE (   n)
Value:
(VARHDRSZ + sizeof(uint16) + \
(NUMERIC_HEADER_IS_SHORT(n) ? 0 : sizeof(int16)))
unsigned short uint16
Definition: c.h:489
signed short int16
Definition: c.h:477
#define VARHDRSZ
Definition: c.h:676

Definition at line 184 of file numeric.c.

◆ NUMERIC_INF_SIGN_MASK

#define NUMERIC_INF_SIGN_MASK   0x2000

Definition at line 201 of file numeric.c.

◆ NUMERIC_IS_INF

#define NUMERIC_IS_INF (   n)     (((n)->choice.n_header & ~NUMERIC_INF_SIGN_MASK) == NUMERIC_PINF)

Definition at line 207 of file numeric.c.

◆ NUMERIC_IS_NAN

#define NUMERIC_IS_NAN (   n)    ((n)->choice.n_header == NUMERIC_NAN)

Definition at line 204 of file numeric.c.

◆ NUMERIC_IS_NINF

#define NUMERIC_IS_NINF (   n)    ((n)->choice.n_header == NUMERIC_NINF)

Definition at line 206 of file numeric.c.

◆ NUMERIC_IS_PINF

#define NUMERIC_IS_PINF (   n)    ((n)->choice.n_header == NUMERIC_PINF)

Definition at line 205 of file numeric.c.

◆ NUMERIC_IS_SHORT

#define NUMERIC_IS_SHORT (   n)    (NUMERIC_FLAGBITS(n) == NUMERIC_SHORT)

Definition at line 172 of file numeric.c.

◆ NUMERIC_IS_SPECIAL

#define NUMERIC_IS_SPECIAL (   n)    (NUMERIC_FLAGBITS(n) == NUMERIC_SPECIAL)

Definition at line 173 of file numeric.c.

◆ NUMERIC_NAN

#define NUMERIC_NAN   0xC000

Definition at line 198 of file numeric.c.

◆ NUMERIC_NDIGITS

#define NUMERIC_NDIGITS (   num)     ((VARSIZE(num) - NUMERIC_HEADER_SIZE(num)) / sizeof(NumericDigit))

Definition at line 489 of file numeric.c.

◆ NUMERIC_NEG

#define NUMERIC_NEG   0x4000

Definition at line 167 of file numeric.c.

◆ NUMERIC_NINF

#define NUMERIC_NINF   0xF000

Definition at line 200 of file numeric.c.

◆ NUMERIC_PINF

#define NUMERIC_PINF   0xD000

Definition at line 199 of file numeric.c.

◆ NUMERIC_POS

#define NUMERIC_POS   0x0000

Definition at line 166 of file numeric.c.

◆ NUMERIC_SHORT

#define NUMERIC_SHORT   0x8000

Definition at line 168 of file numeric.c.

◆ NUMERIC_SHORT_DSCALE_MASK

#define NUMERIC_SHORT_DSCALE_MASK   0x1F80

Definition at line 215 of file numeric.c.

◆ NUMERIC_SHORT_DSCALE_MAX

#define NUMERIC_SHORT_DSCALE_MAX    (NUMERIC_SHORT_DSCALE_MASK >> NUMERIC_SHORT_DSCALE_SHIFT)

Definition at line 217 of file numeric.c.

◆ NUMERIC_SHORT_DSCALE_SHIFT

#define NUMERIC_SHORT_DSCALE_SHIFT   7

Definition at line 216 of file numeric.c.

◆ NUMERIC_SHORT_SIGN_MASK

#define NUMERIC_SHORT_SIGN_MASK   0x2000

Definition at line 214 of file numeric.c.

◆ NUMERIC_SHORT_WEIGHT_MASK

#define NUMERIC_SHORT_WEIGHT_MASK   0x003F

Definition at line 220 of file numeric.c.

◆ NUMERIC_SHORT_WEIGHT_MAX

#define NUMERIC_SHORT_WEIGHT_MAX   NUMERIC_SHORT_WEIGHT_MASK

Definition at line 221 of file numeric.c.

◆ NUMERIC_SHORT_WEIGHT_MIN

#define NUMERIC_SHORT_WEIGHT_MIN   (-(NUMERIC_SHORT_WEIGHT_MASK+1))

Definition at line 222 of file numeric.c.

◆ NUMERIC_SHORT_WEIGHT_SIGN_MASK

#define NUMERIC_SHORT_WEIGHT_SIGN_MASK   0x0040

Definition at line 219 of file numeric.c.

◆ NUMERIC_SIGN

#define NUMERIC_SIGN (   n)
Value:
(((n)->choice.n_short.n_header & NUMERIC_SHORT_SIGN_MASK) ? \
NUMERIC_NEG : NUMERIC_POS) : \
NUMERIC_EXT_FLAGBITS(n) : NUMERIC_FLAGBITS(n)))
#define NUMERIC_IS_SPECIAL(n)
Definition: numeric.c:173
#define NUMERIC_FLAGBITS(n)
Definition: numeric.c:171
#define NUMERIC_SHORT_SIGN_MASK
Definition: numeric.c:214
#define NUMERIC_IS_SHORT(n)
Definition: numeric.c:172
#define NUMERIC_POS
Definition: numeric.c:166

Definition at line 237 of file numeric.c.

◆ NUMERIC_SIGN_MASK

#define NUMERIC_SIGN_MASK   0xC000

Definition at line 165 of file numeric.c.

◆ NUMERIC_SPECIAL

#define NUMERIC_SPECIAL   0xC000

Definition at line 169 of file numeric.c.

◆ NUMERIC_WEIGHT

#define NUMERIC_WEIGHT (   n)
Value:
(((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_SIGN_MASK ? \
| ((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \
: ((n)->choice.n_long.n_weight))
#define NUMERIC_SHORT_WEIGHT_MASK
Definition: numeric.c:220
#define NUMERIC_SHORT_WEIGHT_SIGN_MASK
Definition: numeric.c:219

Definition at line 247 of file numeric.c.

◆ NumericAbbrevGetDatum

#define NumericAbbrevGetDatum (   X)    ((Datum) (X))

Definition at line 403 of file numeric.c.

Typedef Documentation

◆ Int8TransTypeData

◆ NumericAggState

◆ NumericDigit

Definition at line 102 of file numeric.c.

◆ NumericSumAccum

◆ NumericVar

typedef struct NumericVar NumericVar

◆ PolyNumAggState

Definition at line 5470 of file numeric.c.

Function Documentation

◆ accum_sum_add()

static void accum_sum_add ( NumericSumAccum accum,
const NumericVar val 
)
static

Definition at line 11737 of file numeric.c.

11738 {
11739  int32 *accum_digits;
11740  int i,
11741  val_i;
11742  int val_ndigits;
11743  NumericDigit *val_digits;
11744 
11745  /*
11746  * If we have accumulated too many values since the last carry
11747  * propagation, do it now, to avoid overflowing. (We could allow more
11748  * than NBASE - 1, if we reserved two extra digits, rather than one, for
11749  * carry propagation. But even with NBASE - 1, this needs to be done so
11750  * seldom, that the performance difference is negligible.)
11751  */
11752  if (accum->num_uncarried == NBASE - 1)
11753  accum_sum_carry(accum);
11754 
11755  /*
11756  * Adjust the weight or scale of the old value, so that it can accommodate
11757  * the new value.
11758  */
11759  accum_sum_rescale(accum, val);
11760 
11761  /* */
11762  if (val->sign == NUMERIC_POS)
11763  accum_digits = accum->pos_digits;
11764  else
11765  accum_digits = accum->neg_digits;
11766 
11767  /* copy these values into local vars for speed in loop */
11768  val_ndigits = val->ndigits;
11769  val_digits = val->digits;
11770 
11771  i = accum->weight - val->weight;
11772  for (val_i = 0; val_i < val_ndigits; val_i++)
11773  {
11774  accum_digits[i] += (int32) val_digits[val_i];
11775  i++;
11776  }
11777 
11778  accum->num_uncarried++;
11779 }
static void accum_sum_carry(NumericSumAccum *accum)
Definition: numeric.c:11785
int16 NumericDigit
Definition: numeric.c:102
#define NBASE
Definition: numeric.c:96
static void accum_sum_rescale(NumericSumAccum *accum, const NumericVar *val)
Definition: numeric.c:11858
signed int int32
Definition: c.h:478
long val
Definition: informix.c:664
int i
Definition: isn.c:73
int32 * pos_digits
Definition: numeric.c:378
int num_uncarried
Definition: numeric.c:376
int32 * neg_digits
Definition: numeric.c:379

References accum_sum_carry(), accum_sum_rescale(), i, NBASE, NumericSumAccum::neg_digits, NumericSumAccum::num_uncarried, NUMERIC_POS, NumericSumAccum::pos_digits, val, and NumericSumAccum::weight.

Referenced by accum_sum_combine(), do_numeric_accum(), do_numeric_discard(), int8_avg_deserialize(), numeric_avg_deserialize(), numeric_deserialize(), and numeric_poly_deserialize().

◆ accum_sum_carry()

static void accum_sum_carry ( NumericSumAccum accum)
static

Definition at line 11785 of file numeric.c.

11786 {
11787  int i;
11788  int ndigits;
11789  int32 *dig;
11790  int32 carry;
11791  int32 newdig = 0;
11792 
11793  /*
11794  * If no new values have been added since last carry propagation, nothing
11795  * to do.
11796  */
11797  if (accum->num_uncarried == 0)
11798  return;
11799 
11800  /*
11801  * We maintain that the weight of the accumulator is always one larger
11802  * than needed to hold the current value, before carrying, to make sure
11803  * there is enough space for the possible extra digit when carry is
11804  * propagated. We cannot expand the buffer here, unless we require
11805  * callers of accum_sum_final() to switch to the right memory context.
11806  */
11807  Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0);
11808 
11809  ndigits = accum->ndigits;
11810 
11811  /* Propagate carry in the positive sum */
11812  dig = accum->pos_digits;
11813  carry = 0;
11814  for (i = ndigits - 1; i >= 0; i--)
11815  {
11816  newdig = dig[i] + carry;
11817  if (newdig >= NBASE)
11818  {
11819  carry = newdig / NBASE;
11820  newdig -= carry * NBASE;
11821  }
11822  else
11823  carry = 0;
11824  dig[i] = newdig;
11825  }
11826  /* Did we use up the digit reserved for carry propagation? */
11827  if (newdig > 0)
11828  accum->have_carry_space = false;
11829 
11830  /* And the same for the negative sum */
11831  dig = accum->neg_digits;
11832  carry = 0;
11833  for (i = ndigits - 1; i >= 0; i--)
11834  {
11835  newdig = dig[i] + carry;
11836  if (newdig >= NBASE)
11837  {
11838  carry = newdig / NBASE;
11839  newdig -= carry * NBASE;
11840  }
11841  else
11842  carry = 0;
11843  dig[i] = newdig;
11844  }
11845  if (newdig > 0)
11846  accum->have_carry_space = false;
11847 
11848  accum->num_uncarried = 0;
11849 }
Assert(fmt[strlen(fmt) - 1] !='\n')
bool have_carry_space
Definition: numeric.c:377

References Assert(), NumericSumAccum::have_carry_space, i, NBASE, NumericSumAccum::ndigits, NumericSumAccum::neg_digits, NumericSumAccum::num_uncarried, and NumericSumAccum::pos_digits.

Referenced by accum_sum_add(), and accum_sum_final().

◆ accum_sum_combine()

static void accum_sum_combine ( NumericSumAccum accum,
NumericSumAccum accum2 
)
static

Definition at line 12015 of file numeric.c.

12016 {
12017  NumericVar tmp_var;
12018 
12019  init_var(&tmp_var);
12020 
12021  accum_sum_final(accum2, &tmp_var);
12022  accum_sum_add(accum, &tmp_var);
12023 
12024  free_var(&tmp_var);
12025 }
static void accum_sum_final(NumericSumAccum *accum, NumericVar *result)
Definition: numeric.c:11947
static void free_var(NumericVar *var)
Definition: numeric.c:6899
static void accum_sum_add(NumericSumAccum *accum, const NumericVar *val)
Definition: numeric.c:11737
#define init_var(v)
Definition: numeric.c:485

References accum_sum_add(), accum_sum_final(), free_var(), and init_var.

Referenced by int8_avg_combine(), numeric_avg_combine(), numeric_combine(), and numeric_poly_combine().

◆ accum_sum_copy()

static void accum_sum_copy ( NumericSumAccum dst,
NumericSumAccum src 
)
static

Definition at line 11998 of file numeric.c.

11999 {
12000  dst->pos_digits = palloc(src->ndigits * sizeof(int32));
12001  dst->neg_digits = palloc(src->ndigits * sizeof(int32));
12002 
12003  memcpy(dst->pos_digits, src->pos_digits, src->ndigits * sizeof(int32));
12004  memcpy(dst->neg_digits, src->neg_digits, src->ndigits * sizeof(int32));
12005  dst->num_uncarried = src->num_uncarried;
12006  dst->ndigits = src->ndigits;
12007  dst->weight = src->weight;
12008  dst->dscale = src->dscale;
12009 }
void * palloc(Size size)
Definition: mcxt.c:1226

References NumericSumAccum::dscale, NumericSumAccum::ndigits, NumericSumAccum::neg_digits, NumericSumAccum::num_uncarried, palloc(), NumericSumAccum::pos_digits, and NumericSumAccum::weight.

Referenced by int8_avg_combine(), numeric_avg_combine(), numeric_combine(), and numeric_poly_combine().

◆ accum_sum_final()

static void accum_sum_final ( NumericSumAccum accum,
NumericVar result 
)
static

Definition at line 11947 of file numeric.c.

11948 {
11949  int i;
11950  NumericVar pos_var;
11951  NumericVar neg_var;
11952 
11953  if (accum->ndigits == 0)
11954  {
11955  set_var_from_var(&const_zero, result);
11956  return;
11957  }
11958 
11959  /* Perform final carry */
11960  accum_sum_carry(accum);
11961 
11962  /* Create NumericVars representing the positive and negative sums */
11963  init_var(&pos_var);
11964  init_var(&neg_var);
11965 
11966  pos_var.ndigits = neg_var.ndigits = accum->ndigits;
11967  pos_var.weight = neg_var.weight = accum->weight;
11968  pos_var.dscale = neg_var.dscale = accum->dscale;
11969  pos_var.sign = NUMERIC_POS;
11970  neg_var.sign = NUMERIC_NEG;
11971 
11972  pos_var.buf = pos_var.digits = digitbuf_alloc(accum->ndigits);
11973  neg_var.buf = neg_var.digits = digitbuf_alloc(accum->ndigits);
11974 
11975  for (i = 0; i < accum->ndigits; i++)
11976  {
11977  Assert(accum->pos_digits[i] < NBASE);
11978  pos_var.digits[i] = (int16) accum->pos_digits[i];
11979 
11980  Assert(accum->neg_digits[i] < NBASE);
11981  neg_var.digits[i] = (int16) accum->neg_digits[i];
11982  }
11983 
11984  /* And add them together */
11985  add_var(&pos_var, &neg_var, result);
11986 
11987  /* Remove leading/trailing zeroes */
11988  strip_var(result);
11989 }
static void add_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:8361
#define NUMERIC_NEG
Definition: numeric.c:167
#define digitbuf_alloc(ndigits)
Definition: numeric.c:477
static const NumericVar const_zero
Definition: numeric.c:416
static void set_var_from_var(const NumericVar *value, NumericVar *dest)
Definition: numeric.c:7398
static void strip_var(NumericVar *var)
Definition: numeric.c:11680
int ndigits
Definition: numeric.c:306
NumericDigit * digits
Definition: numeric.c:311
int dscale
Definition: numeric.c:309
int sign
Definition: numeric.c:308
NumericDigit * buf
Definition: numeric.c:310
int weight
Definition: numeric.c:307

References accum_sum_carry(), add_var(), Assert(), NumericVar::buf, const_zero, digitbuf_alloc, NumericVar::digits, NumericVar::dscale, NumericSumAccum::dscale, i, init_var, NBASE, NumericVar::ndigits, NumericSumAccum::ndigits, NumericSumAccum::neg_digits, NUMERIC_NEG, NUMERIC_POS, NumericSumAccum::pos_digits, set_var_from_var(), NumericVar::sign, strip_var(), NumericVar::weight, and NumericSumAccum::weight.

Referenced by accum_sum_combine(), int8_avg_serialize(), numeric_avg(), numeric_avg_serialize(), numeric_poly_serialize(), numeric_serialize(), numeric_stddev_internal(), and numeric_sum().

◆ accum_sum_rescale()

static void accum_sum_rescale ( NumericSumAccum accum,
const NumericVar val 
)
static

Definition at line 11858 of file numeric.c.

11859 {
11860  int old_weight = accum->weight;
11861  int old_ndigits = accum->ndigits;
11862  int accum_ndigits;
11863  int accum_weight;
11864  int accum_rscale;
11865  int val_rscale;
11866 
11867  accum_weight = old_weight;
11868  accum_ndigits = old_ndigits;
11869 
11870  /*
11871  * Does the new value have a larger weight? If so, enlarge the buffers,
11872  * and shift the existing value to the new weight, by adding leading
11873  * zeros.
11874  *
11875  * We enforce that the accumulator always has a weight one larger than
11876  * needed for the inputs, so that we have space for an extra digit at the
11877  * final carry-propagation phase, if necessary.
11878  */
11879  if (val->weight >= accum_weight)
11880  {
11881  accum_weight = val->weight + 1;
11882  accum_ndigits = accum_ndigits + (accum_weight - old_weight);
11883  }
11884 
11885  /*
11886  * Even though the new value is small, we might've used up the space
11887  * reserved for the carry digit in the last call to accum_sum_carry(). If
11888  * so, enlarge to make room for another one.
11889  */
11890  else if (!accum->have_carry_space)
11891  {
11892  accum_weight++;
11893  accum_ndigits++;
11894  }
11895 
11896  /* Is the new value wider on the right side? */
11897  accum_rscale = accum_ndigits - accum_weight - 1;
11898  val_rscale = val->ndigits - val->weight - 1;
11899  if (val_rscale > accum_rscale)
11900  accum_ndigits = accum_ndigits + (val_rscale - accum_rscale);
11901 
11902  if (accum_ndigits != old_ndigits ||
11903  accum_weight != old_weight)
11904  {
11905  int32 *new_pos_digits;
11906  int32 *new_neg_digits;
11907  int weightdiff;
11908 
11909  weightdiff = accum_weight - old_weight;
11910 
11911  new_pos_digits = palloc0(accum_ndigits * sizeof(int32));
11912  new_neg_digits = palloc0(accum_ndigits * sizeof(int32));
11913 
11914  if (accum->pos_digits)
11915  {
11916  memcpy(&new_pos_digits[weightdiff], accum->pos_digits,
11917  old_ndigits * sizeof(int32));
11918  pfree(accum->pos_digits);
11919 
11920  memcpy(&new_neg_digits[weightdiff], accum->neg_digits,
11921  old_ndigits * sizeof(int32));
11922  pfree(accum->neg_digits);
11923  }
11924 
11925  accum->pos_digits = new_pos_digits;
11926  accum->neg_digits = new_neg_digits;
11927 
11928  accum->weight = accum_weight;
11929  accum->ndigits = accum_ndigits;
11930 
11931  Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0);
11932  accum->have_carry_space = true;
11933  }
11934 
11935  if (val->dscale > accum->dscale)
11936  accum->dscale = val->dscale;
11937 }
void pfree(void *pointer)
Definition: mcxt.c:1456
void * palloc0(Size size)
Definition: mcxt.c:1257

References Assert(), NumericSumAccum::dscale, NumericSumAccum::have_carry_space, NumericSumAccum::ndigits, NumericSumAccum::neg_digits, palloc0(), pfree(), NumericSumAccum::pos_digits, val, and NumericSumAccum::weight.

Referenced by accum_sum_add().

◆ accum_sum_reset()

static void accum_sum_reset ( NumericSumAccum accum)
static

Definition at line 11721 of file numeric.c.

11722 {
11723  int i;
11724 
11725  accum->dscale = 0;
11726  for (i = 0; i < accum->ndigits; i++)
11727  {
11728  accum->pos_digits[i] = 0;
11729  accum->neg_digits[i] = 0;
11730  }
11731 }

References NumericSumAccum::dscale, i, NumericSumAccum::ndigits, NumericSumAccum::neg_digits, and NumericSumAccum::pos_digits.

Referenced by do_numeric_discard().

◆ add_abs()

static void add_abs ( const NumericVar var1,
const NumericVar var2,
NumericVar result 
)
static

Definition at line 11345 of file numeric.c.

11346 {
11347  NumericDigit *res_buf;
11348  NumericDigit *res_digits;
11349  int res_ndigits;
11350  int res_weight;
11351  int res_rscale,
11352  rscale1,
11353  rscale2;
11354  int res_dscale;
11355  int i,
11356  i1,
11357  i2;
11358  int carry = 0;
11359 
11360  /* copy these values into local vars for speed in inner loop */
11361  int var1ndigits = var1->ndigits;
11362  int var2ndigits = var2->ndigits;
11363  NumericDigit *var1digits = var1->digits;
11364  NumericDigit *var2digits = var2->digits;
11365 
11366  res_weight = Max(var1->weight, var2->weight) + 1;
11367 
11368  res_dscale = Max(var1->dscale, var2->dscale);
11369 
11370  /* Note: here we are figuring rscale in base-NBASE digits */
11371  rscale1 = var1->ndigits - var1->weight - 1;
11372  rscale2 = var2->ndigits - var2->weight - 1;
11373  res_rscale = Max(rscale1, rscale2);
11374 
11375  res_ndigits = res_rscale + res_weight + 1;
11376  if (res_ndigits <= 0)
11377  res_ndigits = 1;
11378 
11379  res_buf = digitbuf_alloc(res_ndigits + 1);
11380  res_buf[0] = 0; /* spare digit for later rounding */
11381  res_digits = res_buf + 1;
11382 
11383  i1 = res_rscale + var1->weight + 1;
11384  i2 = res_rscale + var2->weight + 1;
11385  for (i = res_ndigits - 1; i >= 0; i--)
11386  {
11387  i1--;
11388  i2--;
11389  if (i1 >= 0 && i1 < var1ndigits)
11390  carry += var1digits[i1];
11391  if (i2 >= 0 && i2 < var2ndigits)
11392  carry += var2digits[i2];
11393 
11394  if (carry >= NBASE)
11395  {
11396  res_digits[i] = carry - NBASE;
11397  carry = 1;
11398  }
11399  else
11400  {
11401  res_digits[i] = carry;
11402  carry = 0;
11403  }
11404  }
11405 
11406  Assert(carry == 0); /* else we failed to allow for carry out */
11407 
11408  digitbuf_free(result->buf);
11409  result->ndigits = res_ndigits;
11410  result->buf = res_buf;
11411  result->digits = res_digits;
11412  result->weight = res_weight;
11413  result->dscale = res_dscale;
11414 
11415  /* Remove leading/trailing zeroes */
11416  strip_var(result);
11417 }
#define digitbuf_free(buf)
Definition: numeric.c:479
#define Max(x, y)
Definition: numeric.c:13

References Assert(), NumericVar::buf, digitbuf_alloc, digitbuf_free, NumericVar::digits, NumericVar::dscale, i, Max, NBASE, NumericVar::ndigits, strip_var(), and NumericVar::weight.

Referenced by add_var(), and sub_var().

◆ add_var()

static void add_var ( const NumericVar var1,
const NumericVar var2,
NumericVar result 
)
static

Definition at line 8361 of file numeric.c.

8362 {
8363  /*
8364  * Decide on the signs of the two variables what to do
8365  */
8366  if (var1->sign == NUMERIC_POS)
8367  {
8368  if (var2->sign == NUMERIC_POS)
8369  {
8370  /*
8371  * Both are positive result = +(ABS(var1) + ABS(var2))
8372  */
8373  add_abs(var1, var2, result);
8374  result->sign = NUMERIC_POS;
8375  }
8376  else
8377  {
8378  /*
8379  * var1 is positive, var2 is negative Must compare absolute values
8380  */
8381  switch (cmp_abs(var1, var2))
8382  {
8383  case 0:
8384  /* ----------
8385  * ABS(var1) == ABS(var2)
8386  * result = ZERO
8387  * ----------
8388  */
8389  zero_var(result);
8390  result->dscale = Max(var1->dscale, var2->dscale);
8391  break;
8392 
8393  case 1:
8394  /* ----------
8395  * ABS(var1) > ABS(var2)
8396  * result = +(ABS(var1) - ABS(var2))
8397  * ----------
8398  */
8399  sub_abs(var1, var2, result);
8400  result->sign = NUMERIC_POS;
8401  break;
8402 
8403  case -1:
8404  /* ----------
8405  * ABS(var1) < ABS(var2)
8406  * result = -(ABS(var2) - ABS(var1))
8407  * ----------
8408  */
8409  sub_abs(var2, var1, result);
8410  result->sign = NUMERIC_NEG;
8411  break;
8412  }
8413  }
8414  }
8415  else
8416  {
8417  if (var2->sign == NUMERIC_POS)
8418  {
8419  /* ----------
8420  * var1 is negative, var2 is positive
8421  * Must compare absolute values
8422  * ----------
8423  */
8424  switch (cmp_abs(var1, var2))
8425  {
8426  case 0:
8427  /* ----------
8428  * ABS(var1) == ABS(var2)
8429  * result = ZERO
8430  * ----------
8431  */
8432  zero_var(result);
8433  result->dscale = Max(var1->dscale, var2->dscale);
8434  break;
8435 
8436  case 1:
8437  /* ----------
8438  * ABS(var1) > ABS(var2)
8439  * result = -(ABS(var1) - ABS(var2))
8440  * ----------
8441  */
8442  sub_abs(var1, var2, result);
8443  result->sign = NUMERIC_NEG;
8444  break;
8445 
8446  case -1:
8447  /* ----------
8448  * ABS(var1) < ABS(var2)
8449  * result = +(ABS(var2) - ABS(var1))
8450  * ----------
8451  */
8452  sub_abs(var2, var1, result);
8453  result->sign = NUMERIC_POS;
8454  break;
8455  }
8456  }
8457  else
8458  {
8459  /* ----------
8460  * Both are negative
8461  * result = -(ABS(var1) + ABS(var2))
8462  * ----------
8463  */
8464  add_abs(var1, var2, result);
8465  result->sign = NUMERIC_NEG;
8466  }
8467  }
8468 }
static void sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:11430
static void add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:11345
static void zero_var(NumericVar *var)
Definition: numeric.c:6915
static int cmp_abs(const NumericVar *var1, const NumericVar *var2)
Definition: numeric.c:11267

References add_abs(), cmp_abs(), NumericVar::dscale, Max, NUMERIC_NEG, NUMERIC_POS, NumericVar::sign, sub_abs(), and zero_var().

Referenced by accum_sum_final(), ceil_var(), compute_bucket(), div_mod_var(), exp_var(), generate_series_step_numeric(), in_range_numeric_numeric(), ln_var(), numeric_add_opt_error(), numeric_inc(), set_var_from_non_decimal_integer_str(), sqrt_var(), and width_bucket_numeric().

◆ alloc_var()

static void alloc_var ( NumericVar var,
int  ndigits 
)
static

Definition at line 6883 of file numeric.c.

6884 {
6885  digitbuf_free(var->buf);
6886  var->buf = digitbuf_alloc(ndigits + 1);
6887  var->buf[0] = 0; /* spare digit for rounding */
6888  var->digits = var->buf + 1;
6889  var->ndigits = ndigits;
6890 }

References NumericVar::buf, digitbuf_alloc, digitbuf_free, NumericVar::digits, and NumericVar::ndigits.

Referenced by div_var(), div_var_fast(), int64_to_numericvar(), mul_var(), numeric_recv(), numericvar_deserialize(), set_var_from_num(), set_var_from_str(), and sqrt_var().

◆ apply_typmod()

static bool apply_typmod ( NumericVar var,
int32  typmod,
Node escontext 
)
static

Definition at line 7837 of file numeric.c.

7838 {
7839  int precision;
7840  int scale;
7841  int maxdigits;
7842  int ddigits;
7843  int i;
7844 
7845  /* Do nothing if we have an invalid typmod */
7846  if (!is_valid_numeric_typmod(typmod))
7847  return true;
7848 
7849  precision = numeric_typmod_precision(typmod);
7850  scale = numeric_typmod_scale(typmod);
7851  maxdigits = precision - scale;
7852 
7853  /* Round to target scale (and set var->dscale) */
7854  round_var(var, scale);
7855 
7856  /* but don't allow var->dscale to be negative */
7857  if (var->dscale < 0)
7858  var->dscale = 0;
7859 
7860  /*
7861  * Check for overflow - note we can't do this before rounding, because
7862  * rounding could raise the weight. Also note that the var's weight could
7863  * be inflated by leading zeroes, which will be stripped before storage
7864  * but perhaps might not have been yet. In any case, we must recognize a
7865  * true zero, whose weight doesn't mean anything.
7866  */
7867  ddigits = (var->weight + 1) * DEC_DIGITS;
7868  if (ddigits > maxdigits)
7869  {
7870  /* Determine true weight; and check for all-zero result */
7871  for (i = 0; i < var->ndigits; i++)
7872  {
7873  NumericDigit dig = var->digits[i];
7874 
7875  if (dig)
7876  {
7877  /* Adjust for any high-order decimal zero digits */
7878 #if DEC_DIGITS == 4
7879  if (dig < 10)
7880  ddigits -= 3;
7881  else if (dig < 100)
7882  ddigits -= 2;
7883  else if (dig < 1000)
7884  ddigits -= 1;
7885 #elif DEC_DIGITS == 2
7886  if (dig < 10)
7887  ddigits -= 1;
7888 #elif DEC_DIGITS == 1
7889  /* no adjustment */
7890 #else
7891 #error unsupported NBASE
7892 #endif
7893  if (ddigits > maxdigits)
7894  ereturn(escontext, false,
7895  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7896  errmsg("numeric field overflow"),
7897  errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.",
7898  precision, scale,
7899  /* Display 10^0 as 1 */
7900  maxdigits ? "10^" : "",
7901  maxdigits ? maxdigits : 1
7902  )));
7903  break;
7904  }
7905  ddigits -= DEC_DIGITS;
7906  }
7907  }
7908 
7909  return true;
7910 }
static bool is_valid_numeric_typmod(int32 typmod)
Definition: numeric.c:906
static int numeric_typmod_scale(int32 typmod)
Definition: numeric.c:932
static int numeric_typmod_precision(int32 typmod)
Definition: numeric.c:917
static void round_var(NumericVar *var, int rscale)
Definition: numeric.c:11512
#define DEC_DIGITS
Definition: numeric.c:98
int errdetail(const char *fmt,...)
Definition: elog.c:1202
int errcode(int sqlerrcode)
Definition: elog.c:858
int errmsg(const char *fmt,...)
Definition: elog.c:1069
#define ereturn(context, dummy_value,...)
Definition: elog.h:276
int maxdigits
Definition: informix.c:665

References DEC_DIGITS, NumericVar::digits, NumericVar::dscale, ereturn, errcode(), errdetail(), errmsg(), i, is_valid_numeric_typmod(), maxdigits, NumericVar::ndigits, numeric_typmod_precision(), numeric_typmod_scale(), round_var(), scale, and NumericVar::weight.

Referenced by numeric(), numeric_in(), and numeric_recv().

◆ apply_typmod_special()

static bool apply_typmod_special ( Numeric  num,
int32  typmod,
Node escontext 
)
static

Definition at line 7922 of file numeric.c.

7923 {
7924  int precision;
7925  int scale;
7926 
7927  Assert(NUMERIC_IS_SPECIAL(num)); /* caller error if not */
7928 
7929  /*
7930  * NaN is allowed regardless of the typmod; that's rather dubious perhaps,
7931  * but it's a longstanding behavior. Inf is rejected if we have any
7932  * typmod restriction, since an infinity shouldn't be claimed to fit in
7933  * any finite number of digits.
7934  */
7935  if (NUMERIC_IS_NAN(num))
7936  return true;
7937 
7938  /* Do nothing if we have a default typmod (-1) */
7939  if (!is_valid_numeric_typmod(typmod))
7940  return true;
7941 
7942  precision = numeric_typmod_precision(typmod);
7943  scale = numeric_typmod_scale(typmod);
7944 
7945  ereturn(escontext, false,
7946  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7947  errmsg("numeric field overflow"),
7948  errdetail("A field with precision %d, scale %d cannot hold an infinite value.",
7949  precision, scale)));
7950 }
#define NUMERIC_IS_NAN(n)
Definition: numeric.c:204

References Assert(), ereturn, errcode(), errdetail(), errmsg(), is_valid_numeric_typmod(), NUMERIC_IS_NAN, NUMERIC_IS_SPECIAL, numeric_typmod_precision(), numeric_typmod_scale(), and scale.

Referenced by numeric(), numeric_in(), and numeric_recv().

◆ ceil_var()

static void ceil_var ( const NumericVar var,
NumericVar result 
)
static

Definition at line 9875 of file numeric.c.

9876 {
9877  NumericVar tmp;
9878 
9879  init_var(&tmp);
9880  set_var_from_var(var, &tmp);
9881 
9882  trunc_var(&tmp, 0);
9883 
9884  if (var->sign == NUMERIC_POS && cmp_var(var, &tmp) != 0)
9885  add_var(&tmp, &const_one, &tmp);
9886 
9887  set_var_from_var(&tmp, result);
9888  free_var(&tmp);
9889 }
static void trunc_var(NumericVar *var, int rscale)
Definition: numeric.c:11618
static int cmp_var(const NumericVar *var1, const NumericVar *var2)
Definition: numeric.c:8303
static const NumericVar const_one
Definition: numeric.c:420

References add_var(), cmp_var(), const_one, free_var(), init_var, NUMERIC_POS, set_var_from_var(), NumericVar::sign, and trunc_var().

Referenced by numeric_ceil().

◆ cmp_abs()

static int cmp_abs ( const NumericVar var1,
const NumericVar var2 
)
static

Definition at line 11267 of file numeric.c.

11268 {
11269  return cmp_abs_common(var1->digits, var1->ndigits, var1->weight,
11270  var2->digits, var2->ndigits, var2->weight);
11271 }
static int cmp_abs_common(const NumericDigit *var1digits, int var1ndigits, int var1weight, const NumericDigit *var2digits, int var2ndigits, int var2weight)
Definition: numeric.c:11281

References cmp_abs_common(), NumericVar::digits, NumericVar::ndigits, and NumericVar::weight.

Referenced by add_var(), div_mod_var(), gcd_var(), and sub_var().

◆ cmp_abs_common()

static int cmp_abs_common ( const NumericDigit var1digits,
int  var1ndigits,
int  var1weight,
const NumericDigit var2digits,
int  var2ndigits,
int  var2weight 
)
static

Definition at line 11281 of file numeric.c.

11283 {
11284  int i1 = 0;
11285  int i2 = 0;
11286 
11287  /* Check any digits before the first common digit */
11288 
11289  while (var1weight > var2weight && i1 < var1ndigits)
11290  {
11291  if (var1digits[i1++] != 0)
11292  return 1;
11293  var1weight--;
11294  }
11295  while (var2weight > var1weight && i2 < var2ndigits)
11296  {
11297  if (var2digits[i2++] != 0)
11298  return -1;
11299  var2weight--;
11300  }
11301 
11302  /* At this point, either w1 == w2 or we've run out of digits */
11303 
11304  if (var1weight == var2weight)
11305  {
11306  while (i1 < var1ndigits && i2 < var2ndigits)
11307  {
11308  int stat = var1digits[i1++] - var2digits[i2++];
11309 
11310  if (stat)
11311  {
11312  if (stat > 0)
11313  return 1;
11314  return -1;
11315  }
11316  }
11317  }
11318 
11319  /*
11320  * At this point, we've run out of digits on one side or the other; so any
11321  * remaining nonzero digits imply that side is larger
11322  */
11323  while (i1 < var1ndigits)
11324  {
11325  if (var1digits[i1++] != 0)
11326  return 1;
11327  }
11328  while (i2 < var2ndigits)
11329  {
11330  if (var2digits[i2++] != 0)
11331  return -1;
11332  }
11333 
11334  return 0;
11335 }

Referenced by cmp_abs(), and cmp_var_common().

◆ cmp_numerics()

static int cmp_numerics ( Numeric  num1,
Numeric  num2 
)
static

Definition at line 2504 of file numeric.c.

2505 {
2506  int result;
2507 
2508  /*
2509  * We consider all NANs to be equal and larger than any non-NAN (including
2510  * Infinity). This is somewhat arbitrary; the important thing is to have
2511  * a consistent sort order.
2512  */
2513  if (NUMERIC_IS_SPECIAL(num1))
2514  {
2515  if (NUMERIC_IS_NAN(num1))
2516  {
2517  if (NUMERIC_IS_NAN(num2))
2518  result = 0; /* NAN = NAN */
2519  else
2520  result = 1; /* NAN > non-NAN */
2521  }
2522  else if (NUMERIC_IS_PINF(num1))
2523  {
2524  if (NUMERIC_IS_NAN(num2))
2525  result = -1; /* PINF < NAN */
2526  else if (NUMERIC_IS_PINF(num2))
2527  result = 0; /* PINF = PINF */
2528  else
2529  result = 1; /* PINF > anything else */
2530  }
2531  else /* num1 must be NINF */
2532  {
2533  if (NUMERIC_IS_NINF(num2))
2534  result = 0; /* NINF = NINF */
2535  else
2536  result = -1; /* NINF < anything else */
2537  }
2538  }
2539  else if (NUMERIC_IS_SPECIAL(num2))
2540  {
2541  if (NUMERIC_IS_NINF(num2))
2542  result = 1; /* normal > NINF */
2543  else
2544  result = -1; /* normal < NAN or PINF */
2545  }
2546  else
2547  {
2548  result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1),
2549  NUMERIC_WEIGHT(num1), NUMERIC_SIGN(num1),
2550  NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2),
2551  NUMERIC_WEIGHT(num2), NUMERIC_SIGN(num2));
2552  }
2553 
2554  return result;
2555 }
#define NUMERIC_SIGN(n)
Definition: numeric.c:237
#define NUMERIC_IS_PINF(n)
Definition: numeric.c:205
#define NUMERIC_IS_NINF(n)
Definition: numeric.c:206
#define NUMERIC_WEIGHT(n)
Definition: numeric.c:247
#define NUMERIC_DIGITS(num)
Definition: numeric.c:487
#define NUMERIC_NDIGITS(num)
Definition: numeric.c:489
static int cmp_var_common(const NumericDigit *var1digits, int var1ndigits, int var1weight, int var1sign, const NumericDigit *var2digits, int var2ndigits, int var2weight, int var2sign)
Definition: numeric.c:8318

References cmp_var_common(), NUMERIC_DIGITS, NUMERIC_IS_NAN, NUMERIC_IS_NINF, NUMERIC_IS_PINF, NUMERIC_IS_SPECIAL, NUMERIC_NDIGITS, NUMERIC_SIGN, and NUMERIC_WEIGHT.

Referenced by numeric_cmp(), numeric_eq(), numeric_fast_cmp(), numeric_ge(), numeric_gt(), numeric_larger(), numeric_le(), numeric_lt(), numeric_ne(), numeric_smaller(), and width_bucket_numeric().

◆ cmp_var()

static int cmp_var ( const NumericVar var1,
const NumericVar var2 
)
static

◆ cmp_var_common()

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

8322 {
8323  if (var1ndigits == 0)
8324  {
8325  if (var2ndigits == 0)
8326  return 0;
8327  if (var2sign == NUMERIC_NEG)
8328  return 1;
8329  return -1;
8330  }
8331  if (var2ndigits == 0)
8332  {
8333  if (var1sign == NUMERIC_POS)
8334  return 1;
8335  return -1;
8336  }
8337 
8338  if (var1sign == NUMERIC_POS)
8339  {
8340  if (var2sign == NUMERIC_NEG)
8341  return 1;
8342  return cmp_abs_common(var1digits, var1ndigits, var1weight,
8343  var2digits, var2ndigits, var2weight);
8344  }
8345 
8346  if (var2sign == NUMERIC_POS)
8347  return -1;
8348 
8349  return cmp_abs_common(var2digits, var2ndigits, var2weight,
8350  var1digits, var1ndigits, var1weight);
8351 }

References cmp_abs_common(), NUMERIC_NEG, and NUMERIC_POS.

Referenced by cmp_numerics(), and cmp_var().

◆ compute_bucket()

static void compute_bucket ( Numeric  operand,
Numeric  bound1,
Numeric  bound2,
const NumericVar count_var,
bool  reversed_bounds,
NumericVar result_var 
)
static

Definition at line 1916 of file numeric.c.

1919 {
1920  NumericVar bound1_var;
1921  NumericVar bound2_var;
1922  NumericVar operand_var;
1923 
1924  init_var_from_num(bound1, &bound1_var);
1925  init_var_from_num(bound2, &bound2_var);
1926  init_var_from_num(operand, &operand_var);
1927 
1928  if (!reversed_bounds)
1929  {
1930  sub_var(&operand_var, &bound1_var, &operand_var);
1931  sub_var(&bound2_var, &bound1_var, &bound2_var);
1932  }
1933  else
1934  {
1935  sub_var(&bound1_var, &operand_var, &operand_var);
1936  sub_var(&bound1_var, &bound2_var, &bound2_var);
1937  }
1938 
1939  mul_var(&operand_var, count_var, &operand_var,
1940  operand_var.dscale + count_var->dscale);
1941  div_var(&operand_var, &bound2_var, result_var,
1942  select_div_scale(&operand_var, &bound2_var), true);
1943 
1944  /*
1945  * Roundoff in the division could give us a quotient exactly equal to
1946  * "count", which is too large. Clamp so that we do not emit a result
1947  * larger than "count".
1948  */
1949  if (cmp_var(result_var, count_var) >= 0)
1950  set_var_from_var(count_var, result_var);
1951  else
1952  {
1953  add_var(result_var, &const_one, result_var);
1954  floor_var(result_var, result_var);
1955  }
1956 
1957  free_var(&bound1_var);
1958  free_var(&bound2_var);
1959  free_var(&operand_var);
1960 }
static void sub_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:8478
static void floor_var(const NumericVar *var, NumericVar *result)
Definition: numeric.c:9899
static void init_var_from_num(Numeric num, NumericVar *dest)
Definition: numeric.c:7381
static void mul_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale)
Definition: numeric.c:8599
static int select_div_scale(const NumericVar *var1, const NumericVar *var2)
Definition: numeric.c:9707
static void div_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale, bool round)
Definition: numeric.c:8807

References add_var(), cmp_var(), const_one, div_var(), NumericVar::dscale, floor_var(), free_var(), init_var_from_num(), mul_var(), select_div_scale(), set_var_from_var(), and sub_var().

Referenced by width_bucket_numeric().

◆ div_mod_var()

static void div_mod_var ( const NumericVar var1,
const NumericVar var2,
NumericVar quot,
NumericVar rem 
)
static

Definition at line 9805 of file numeric.c.

9807 {
9808  NumericVar q;
9809  NumericVar r;
9810 
9811  init_var(&q);
9812  init_var(&r);
9813 
9814  /*
9815  * Use div_var_fast() to get an initial estimate for the integer quotient.
9816  * This might be inaccurate (per the warning in div_var_fast's comments),
9817  * but we can correct it below.
9818  */
9819  div_var_fast(var1, var2, &q, 0, false);
9820 
9821  /* Compute initial estimate of remainder using the quotient estimate. */
9822  mul_var(var2, &q, &r, var2->dscale);
9823  sub_var(var1, &r, &r);
9824 
9825  /*
9826  * Adjust the results if necessary --- the remainder should have the same
9827  * sign as var1, and its absolute value should be less than the absolute
9828  * value of var2.
9829  */
9830  while (r.ndigits != 0 && r.sign != var1->sign)
9831  {
9832  /* The absolute value of the quotient is too large */
9833  if (var1->sign == var2->sign)
9834  {
9835  sub_var(&q, &const_one, &q);
9836  add_var(&r, var2, &r);
9837  }
9838  else
9839  {
9840  add_var(&q, &const_one, &q);
9841  sub_var(&r, var2, &r);
9842  }
9843  }
9844 
9845  while (cmp_abs(&r, var2) >= 0)
9846  {
9847  /* The absolute value of the quotient is too small */
9848  if (var1->sign == var2->sign)
9849  {
9850  add_var(&q, &const_one, &q);
9851  sub_var(&r, var2, &r);
9852  }
9853  else
9854  {
9855  sub_var(&q, &const_one, &q);
9856  add_var(&r, var2, &r);
9857  }
9858  }
9859 
9860  set_var_from_var(&q, quot);
9861  set_var_from_var(&r, rem);
9862 
9863  free_var(&q);
9864  free_var(&r);
9865 }
static void div_var_fast(const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale, bool round)
Definition: numeric.c:9115

References add_var(), cmp_abs(), const_one, div_var_fast(), NumericVar::dscale, free_var(), init_var, mul_var(), NumericVar::ndigits, set_var_from_var(), NumericVar::sign, and sub_var().

Referenced by sqrt_var().

◆ div_var()

static void div_var ( const NumericVar var1,
const NumericVar var2,
NumericVar result,
int  rscale,
bool  round 
)
static

Definition at line 8807 of file numeric.c.

8809 {
8810  int div_ndigits;
8811  int res_ndigits;
8812  int res_sign;
8813  int res_weight;
8814  int carry;
8815  int borrow;
8816  int divisor1;
8817  int divisor2;
8818  NumericDigit *dividend;
8819  NumericDigit *divisor;
8820  NumericDigit *res_digits;
8821  int i;
8822  int j;
8823 
8824  /* copy these values into local vars for speed in inner loop */
8825  int var1ndigits = var1->ndigits;
8826  int var2ndigits = var2->ndigits;
8827 
8828  /*
8829  * First of all division by zero check; we must not be handed an
8830  * unnormalized divisor.
8831  */
8832  if (var2ndigits == 0 || var2->digits[0] == 0)
8833  ereport(ERROR,
8834  (errcode(ERRCODE_DIVISION_BY_ZERO),
8835  errmsg("division by zero")));
8836 
8837  /*
8838  * If the divisor has just one or two digits, delegate to div_var_int(),
8839  * which uses fast short division.
8840  *
8841  * Similarly, on platforms with 128-bit integer support, delegate to
8842  * div_var_int64() for divisors with three or four digits.
8843  */
8844  if (var2ndigits <= 2)
8845  {
8846  int idivisor;
8847  int idivisor_weight;
8848 
8849  idivisor = var2->digits[0];
8850  idivisor_weight = var2->weight;
8851  if (var2ndigits == 2)
8852  {
8853  idivisor = idivisor * NBASE + var2->digits[1];
8854  idivisor_weight--;
8855  }
8856  if (var2->sign == NUMERIC_NEG)
8857  idivisor = -idivisor;
8858 
8859  div_var_int(var1, idivisor, idivisor_weight, result, rscale, round);
8860  return;
8861  }
8862 #ifdef HAVE_INT128
8863  if (var2ndigits <= 4)
8864  {
8865  int64 idivisor;
8866  int idivisor_weight;
8867 
8868  idivisor = var2->digits[0];
8869  idivisor_weight = var2->weight;
8870  for (i = 1; i < var2ndigits; i++)
8871  {
8872  idivisor = idivisor * NBASE + var2->digits[i];
8873  idivisor_weight--;
8874  }
8875  if (var2->sign == NUMERIC_NEG)
8876  idivisor = -idivisor;
8877 
8878  div_var_int64(var1, idivisor, idivisor_weight, result, rscale, round);
8879  return;
8880  }
8881 #endif
8882 
8883  /*
8884  * Otherwise, perform full long division.
8885  */
8886 
8887  /* Result zero check */
8888  if (var1ndigits == 0)
8889  {
8890  zero_var(result);
8891  result->dscale = rscale;
8892  return;
8893  }
8894 
8895  /*
8896  * Determine the result sign, weight and number of digits to calculate.
8897  * The weight figured here is correct if the emitted quotient has no
8898  * leading zero digits; otherwise strip_var() will fix things up.
8899  */
8900  if (var1->sign == var2->sign)
8901  res_sign = NUMERIC_POS;
8902  else
8903  res_sign = NUMERIC_NEG;
8904  res_weight = var1->weight - var2->weight;
8905  /* The number of accurate result digits we need to produce: */
8906  res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
8907  /* ... but always at least 1 */
8908  res_ndigits = Max(res_ndigits, 1);
8909  /* If rounding needed, figure one more digit to ensure correct result */
8910  if (round)
8911  res_ndigits++;
8912 
8913  /*
8914  * The working dividend normally requires res_ndigits + var2ndigits
8915  * digits, but make it at least var1ndigits so we can load all of var1
8916  * into it. (There will be an additional digit dividend[0] in the
8917  * dividend space, but for consistency with Knuth's notation we don't
8918  * count that in div_ndigits.)
8919  */
8920  div_ndigits = res_ndigits + var2ndigits;
8921  div_ndigits = Max(div_ndigits, var1ndigits);
8922 
8923  /*
8924  * We need a workspace with room for the working dividend (div_ndigits+1
8925  * digits) plus room for the possibly-normalized divisor (var2ndigits
8926  * digits). It is convenient also to have a zero at divisor[0] with the
8927  * actual divisor data in divisor[1 .. var2ndigits]. Transferring the
8928  * digits into the workspace also allows us to realloc the result (which
8929  * might be the same as either input var) before we begin the main loop.
8930  * Note that we use palloc0 to ensure that divisor[0], dividend[0], and
8931  * any additional dividend positions beyond var1ndigits, start out 0.
8932  */
8933  dividend = (NumericDigit *)
8934  palloc0((div_ndigits + var2ndigits + 2) * sizeof(NumericDigit));
8935  divisor = dividend + (div_ndigits + 1);
8936  memcpy(dividend + 1, var1->digits, var1ndigits * sizeof(NumericDigit));
8937  memcpy(divisor + 1, var2->digits, var2ndigits * sizeof(NumericDigit));
8938 
8939  /*
8940  * Now we can realloc the result to hold the generated quotient digits.
8941  */
8942  alloc_var(result, res_ndigits);
8943  res_digits = result->digits;
8944 
8945  /*
8946  * The full multiple-place algorithm is taken from Knuth volume 2,
8947  * Algorithm 4.3.1D.
8948  *
8949  * We need the first divisor digit to be >= NBASE/2. If it isn't, make it
8950  * so by scaling up both the divisor and dividend by the factor "d". (The
8951  * reason for allocating dividend[0] above is to leave room for possible
8952  * carry here.)
8953  */
8954  if (divisor[1] < HALF_NBASE)
8955  {
8956  int d = NBASE / (divisor[1] + 1);
8957 
8958  carry = 0;
8959  for (i = var2ndigits; i > 0; i--)
8960  {
8961  carry += divisor[i] * d;
8962  divisor[i] = carry % NBASE;
8963  carry = carry / NBASE;
8964  }
8965  Assert(carry == 0);
8966  carry = 0;
8967  /* at this point only var1ndigits of dividend can be nonzero */
8968  for (i = var1ndigits; i >= 0; i--)
8969  {
8970  carry += dividend[i] * d;
8971  dividend[i] = carry % NBASE;
8972  carry = carry / NBASE;
8973  }
8974  Assert(carry == 0);
8975  Assert(divisor[1] >= HALF_NBASE);
8976  }
8977  /* First 2 divisor digits are used repeatedly in main loop */
8978  divisor1 = divisor[1];
8979  divisor2 = divisor[2];
8980 
8981  /*
8982  * Begin the main loop. Each iteration of this loop produces the j'th
8983  * quotient digit by dividing dividend[j .. j + var2ndigits] by the
8984  * divisor; this is essentially the same as the common manual procedure
8985  * for long division.
8986  */
8987  for (j = 0; j < res_ndigits; j++)
8988  {
8989  /* Estimate quotient digit from the first two dividend digits */
8990  int next2digits = dividend[j] * NBASE + dividend[j + 1];
8991  int qhat;
8992 
8993  /*
8994  * If next2digits are 0, then quotient digit must be 0 and there's no
8995  * need to adjust the working dividend. It's worth testing here to
8996  * fall out ASAP when processing trailing zeroes in a dividend.
8997  */
8998  if (next2digits == 0)
8999  {
9000  res_digits[j] = 0;
9001  continue;
9002  }
9003 
9004  if (dividend[j] == divisor1)
9005  qhat = NBASE - 1;
9006  else
9007  qhat = next2digits / divisor1;
9008 
9009  /*
9010  * Adjust quotient digit if it's too large. Knuth proves that after
9011  * this step, the quotient digit will be either correct or just one
9012  * too large. (Note: it's OK to use dividend[j+2] here because we
9013  * know the divisor length is at least 2.)
9014  */
9015  while (divisor2 * qhat >
9016  (next2digits - qhat * divisor1) * NBASE + dividend[j + 2])
9017  qhat--;
9018 
9019  /* As above, need do nothing more when quotient digit is 0 */
9020  if (qhat > 0)
9021  {
9022  NumericDigit *dividend_j = &dividend[j];
9023 
9024  /*
9025  * Multiply the divisor by qhat, and subtract that from the
9026  * working dividend. The multiplication and subtraction are
9027  * folded together here, noting that qhat <= NBASE (since it might
9028  * be one too large), and so the intermediate result "tmp_result"
9029  * is in the range [-NBASE^2, NBASE - 1], and "borrow" is in the
9030  * range [0, NBASE].
9031  */
9032  borrow = 0;
9033  for (i = var2ndigits; i >= 0; i--)
9034  {
9035  int tmp_result;
9036 
9037  tmp_result = dividend_j[i] - borrow - divisor[i] * qhat;
9038  borrow = (NBASE - 1 - tmp_result) / NBASE;
9039  dividend_j[i] = tmp_result + borrow * NBASE;
9040  }
9041 
9042  /*
9043  * If we got a borrow out of the top dividend digit, then indeed
9044  * qhat was one too large. Fix it, and add back the divisor to
9045  * correct the working dividend. (Knuth proves that this will
9046  * occur only about 3/NBASE of the time; hence, it's a good idea
9047  * to test this code with small NBASE to be sure this section gets
9048  * exercised.)
9049  */
9050  if (borrow)
9051  {
9052  qhat--;
9053  carry = 0;
9054  for (i = var2ndigits; i >= 0; i--)
9055  {
9056  carry += dividend_j[i] + divisor[i];
9057  if (carry >= NBASE)
9058  {
9059  dividend_j[i] = carry - NBASE;
9060  carry = 1;
9061  }
9062  else
9063  {
9064  dividend_j[i] = carry;
9065  carry = 0;
9066  }
9067  }
9068  /* A carry should occur here to cancel the borrow above */
9069  Assert(carry == 1);
9070  }
9071  }
9072 
9073  /* And we're done with this quotient digit */
9074  res_digits[j] = qhat;
9075  }
9076 
9077  pfree(dividend);
9078 
9079  /*
9080  * Finally, round or truncate the result to the requested precision.
9081  */
9082  result->weight = res_weight;
9083  result->sign = res_sign;
9084 
9085  /* Round or truncate to target rscale (and set result->dscale) */
9086  if (round)
9087  round_var(result, rscale);
9088  else
9089  trunc_var(result, rscale);
9090 
9091  /* Strip leading and trailing zeroes */
9092  strip_var(result);
9093 }
static void div_var_int(const NumericVar *var, int ival, int ival_weight, NumericVar *result, int rscale, bool round)
Definition: numeric.c:9479
static void alloc_var(NumericVar *var, int ndigits)
Definition: numeric.c:6883
#define HALF_NBASE
Definition: numeric.c:97
#define ERROR
Definition: elog.h:39
#define ereport(elevel,...)
Definition: elog.h:149
int j
Definition: isn.c:74

References alloc_var(), Assert(), DEC_DIGITS, NumericVar::digits, div_var_int(), NumericVar::dscale, ereport, errcode(), errmsg(), ERROR, HALF_NBASE, i, j, Max, NBASE, NumericVar::ndigits, NUMERIC_NEG, NUMERIC_POS, 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_opt_error(), numeric_div_trunc(), numeric_lcm(), numeric_stddev_internal(), and power_var_int().

◆ div_var_fast()

static void div_var_fast ( const NumericVar var1,
const NumericVar var2,
NumericVar result,
int  rscale,
bool  round 
)
static

Definition at line 9115 of file numeric.c.

9117 {
9118  int div_ndigits;
9119  int load_ndigits;
9120  int res_sign;
9121  int res_weight;
9122  int *div;
9123  int qdigit;
9124  int carry;
9125  int maxdiv;
9126  int newdig;
9127  NumericDigit *res_digits;
9128  double fdividend,
9129  fdivisor,
9130  fdivisorinverse,
9131  fquotient;
9132  int qi;
9133  int i;
9134 
9135  /* copy these values into local vars for speed in inner loop */
9136  int var1ndigits = var1->ndigits;
9137  int var2ndigits = var2->ndigits;
9138  NumericDigit *var1digits = var1->digits;
9139  NumericDigit *var2digits = var2->digits;
9140 
9141  /*
9142  * First of all division by zero check; we must not be handed an
9143  * unnormalized divisor.
9144  */
9145  if (var2ndigits == 0 || var2digits[0] == 0)
9146  ereport(ERROR,
9147  (errcode(ERRCODE_DIVISION_BY_ZERO),
9148  errmsg("division by zero")));
9149 
9150  /*
9151  * If the divisor has just one or two digits, delegate to div_var_int(),
9152  * which uses fast short division.
9153  *
9154  * Similarly, on platforms with 128-bit integer support, delegate to
9155  * div_var_int64() for divisors with three or four digits.
9156  */
9157  if (var2ndigits <= 2)
9158  {
9159  int idivisor;
9160  int idivisor_weight;
9161 
9162  idivisor = var2->digits[0];
9163  idivisor_weight = var2->weight;
9164  if (var2ndigits == 2)
9165  {
9166  idivisor = idivisor * NBASE + var2->digits[1];
9167  idivisor_weight--;
9168  }
9169  if (var2->sign == NUMERIC_NEG)
9170  idivisor = -idivisor;
9171 
9172  div_var_int(var1, idivisor, idivisor_weight, result, rscale, round);
9173  return;
9174  }
9175 #ifdef HAVE_INT128
9176  if (var2ndigits <= 4)
9177  {
9178  int64 idivisor;
9179  int idivisor_weight;
9180 
9181  idivisor = var2->digits[0];
9182  idivisor_weight = var2->weight;
9183  for (i = 1; i < var2ndigits; i++)
9184  {
9185  idivisor = idivisor * NBASE + var2->digits[i];
9186  idivisor_weight--;
9187  }
9188  if (var2->sign == NUMERIC_NEG)
9189  idivisor = -idivisor;
9190 
9191  div_var_int64(var1, idivisor, idivisor_weight, result, rscale, round);
9192  return;
9193  }
9194 #endif
9195 
9196  /*
9197  * Otherwise, perform full long division.
9198  */
9199 
9200  /* Result zero check */
9201  if (var1ndigits == 0)
9202  {
9203  zero_var(result);
9204  result->dscale = rscale;
9205  return;
9206  }
9207 
9208  /*
9209  * Determine the result sign, weight and number of digits to calculate
9210  */
9211  if (var1->sign == var2->sign)
9212  res_sign = NUMERIC_POS;
9213  else
9214  res_sign = NUMERIC_NEG;
9215  res_weight = var1->weight - var2->weight + 1;
9216  /* The number of accurate result digits we need to produce: */
9217  div_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9218  /* Add guard digits for roundoff error */
9219  div_ndigits += DIV_GUARD_DIGITS;
9220  if (div_ndigits < DIV_GUARD_DIGITS)
9221  div_ndigits = DIV_GUARD_DIGITS;
9222 
9223  /*
9224  * We do the arithmetic in an array "div[]" of signed int's. Since
9225  * INT_MAX is noticeably larger than NBASE*NBASE, this gives us headroom
9226  * to avoid normalizing carries immediately.
9227  *
9228  * We start with div[] containing one zero digit followed by the
9229  * dividend's digits (plus appended zeroes to reach the desired precision
9230  * including guard digits). Each step of the main loop computes an
9231  * (approximate) quotient digit and stores it into div[], removing one
9232  * position of dividend space. A final pass of carry propagation takes
9233  * care of any mistaken quotient digits.
9234  *
9235  * Note that div[] doesn't necessarily contain all of the digits from the
9236  * dividend --- the desired precision plus guard digits might be less than
9237  * the dividend's precision. This happens, for example, in the square
9238  * root algorithm, where we typically divide a 2N-digit number by an
9239  * N-digit number, and only require a result with N digits of precision.
9240  */
9241  div = (int *) palloc0((div_ndigits + 1) * sizeof(int));
9242  load_ndigits = Min(div_ndigits, var1ndigits);
9243  for (i = 0; i < load_ndigits; i++)
9244  div[i + 1] = var1digits[i];
9245 
9246  /*
9247  * We estimate each quotient digit using floating-point arithmetic, taking
9248  * the first four digits of the (current) dividend and divisor. This must
9249  * be float to avoid overflow. The quotient digits will generally be off
9250  * by no more than one from the exact answer.
9251  */
9252  fdivisor = (double) var2digits[0];
9253  for (i = 1; i < 4; i++)
9254  {
9255  fdivisor *= NBASE;
9256  if (i < var2ndigits)
9257  fdivisor += (double) var2digits[i];
9258  }
9259  fdivisorinverse = 1.0 / fdivisor;
9260 
9261  /*
9262  * maxdiv tracks the maximum possible absolute value of any div[] entry;
9263  * when this threatens to exceed INT_MAX, we take the time to propagate
9264  * carries. Furthermore, we need to ensure that overflow doesn't occur
9265  * during the carry propagation passes either. The carry values may have
9266  * an absolute value as high as INT_MAX/NBASE + 1, so really we must
9267  * normalize when digits threaten to exceed INT_MAX - INT_MAX/NBASE - 1.
9268  *
9269  * To avoid overflow in maxdiv itself, it represents the max absolute
9270  * value divided by NBASE-1, ie, at the top of the loop it is known that
9271  * no div[] entry has an absolute value exceeding maxdiv * (NBASE-1).
9272  *
9273  * Actually, though, that holds good only for div[] entries after div[qi];
9274  * the adjustment done at the bottom of the loop may cause div[qi + 1] to
9275  * exceed the maxdiv limit, so that div[qi] in the next iteration is
9276  * beyond the limit. This does not cause problems, as explained below.
9277  */
9278  maxdiv = 1;
9279 
9280  /*
9281  * Outer loop computes next quotient digit, which will go into div[qi]
9282  */
9283  for (qi = 0; qi < div_ndigits; qi++)
9284  {
9285  /* Approximate the current dividend value */
9286  fdividend = (double) div[qi];
9287  for (i = 1; i < 4; i++)
9288  {
9289  fdividend *= NBASE;
9290  if (qi + i <= div_ndigits)
9291  fdividend += (double) div[qi + i];
9292  }
9293  /* Compute the (approximate) quotient digit */
9294  fquotient = fdividend * fdivisorinverse;
9295  qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
9296  (((int) fquotient) - 1); /* truncate towards -infinity */
9297 
9298  if (qdigit != 0)
9299  {
9300  /* Do we need to normalize now? */
9301  maxdiv += abs(qdigit);
9302  if (maxdiv > (INT_MAX - INT_MAX / NBASE - 1) / (NBASE - 1))
9303  {
9304  /*
9305  * Yes, do it. Note that if var2ndigits is much smaller than
9306  * div_ndigits, we can save a significant amount of effort
9307  * here by noting that we only need to normalise those div[]
9308  * entries touched where prior iterations subtracted multiples
9309  * of the divisor.
9310  */
9311  carry = 0;
9312  for (i = Min(qi + var2ndigits - 2, div_ndigits); i > qi; i--)
9313  {
9314  newdig = div[i] + carry;
9315  if (newdig < 0)
9316  {
9317  carry = -((-newdig - 1) / NBASE) - 1;
9318  newdig -= carry * NBASE;
9319  }
9320  else if (newdig >= NBASE)
9321  {
9322  carry = newdig / NBASE;
9323  newdig -= carry * NBASE;
9324  }
9325  else
9326  carry = 0;
9327  div[i] = newdig;
9328  }
9329  newdig = div[qi] + carry;
9330  div[qi] = newdig;
9331 
9332  /*
9333  * All the div[] digits except possibly div[qi] are now in the
9334  * range 0..NBASE-1. We do not need to consider div[qi] in
9335  * the maxdiv value anymore, so we can reset maxdiv to 1.
9336  */
9337  maxdiv = 1;
9338 
9339  /*
9340  * Recompute the quotient digit since new info may have
9341  * propagated into the top four dividend digits
9342  */
9343  fdividend = (double) div[qi];
9344  for (i = 1; i < 4; i++)
9345  {
9346  fdividend *= NBASE;
9347  if (qi + i <= div_ndigits)
9348  fdividend += (double) div[qi + i];
9349  }
9350  /* Compute the (approximate) quotient digit */
9351  fquotient = fdividend * fdivisorinverse;
9352  qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
9353  (((int) fquotient) - 1); /* truncate towards -infinity */
9354  maxdiv += abs(qdigit);
9355  }
9356 
9357  /*
9358  * Subtract off the appropriate multiple of the divisor.
9359  *
9360  * The digits beyond div[qi] cannot overflow, because we know they
9361  * will fall within the maxdiv limit. As for div[qi] itself, note
9362  * that qdigit is approximately trunc(div[qi] / vardigits[0]),
9363  * which would make the new value simply div[qi] mod vardigits[0].
9364  * The lower-order terms in qdigit can change this result by not
9365  * more than about twice INT_MAX/NBASE, so overflow is impossible.
9366  *
9367  * This inner loop is the performance bottleneck for division, so
9368  * code it in the same way as the inner loop of mul_var() so that
9369  * it can be auto-vectorized. We cast qdigit to NumericDigit
9370  * before multiplying to allow the compiler to generate more
9371  * efficient code (using 16-bit multiplication), which is safe
9372  * since we know that the quotient digit is off by at most one, so
9373  * there is no overflow risk.
9374  */
9375  if (qdigit != 0)
9376  {
9377  int istop = Min(var2ndigits, div_ndigits - qi + 1);
9378  int *div_qi = &div[qi];
9379 
9380  for (i = 0; i < istop; i++)
9381  div_qi[i] -= ((NumericDigit) qdigit) * var2digits[i];
9382  }
9383  }
9384 
9385  /*
9386  * The dividend digit we are about to replace might still be nonzero.
9387  * Fold it into the next digit position.
9388  *
9389  * There is no risk of overflow here, although proving that requires
9390  * some care. Much as with the argument for div[qi] not overflowing,
9391  * if we consider the first two terms in the numerator and denominator
9392  * of qdigit, we can see that the final value of div[qi + 1] will be
9393  * approximately a remainder mod (vardigits[0]*NBASE + vardigits[1]).
9394  * Accounting for the lower-order terms is a bit complicated but ends
9395  * up adding not much more than INT_MAX/NBASE to the possible range.
9396  * Thus, div[qi + 1] cannot overflow here, and in its role as div[qi]
9397  * in the next loop iteration, it can't be large enough to cause
9398  * overflow in the carry propagation step (if any), either.
9399  *
9400  * But having said that: div[qi] can be more than INT_MAX/NBASE, as
9401  * noted above, which means that the product div[qi] * NBASE *can*
9402  * overflow. When that happens, adding it to div[qi + 1] will always
9403  * cause a canceling overflow so that the end result is correct. We
9404  * could avoid the intermediate overflow by doing the multiplication
9405  * and addition in int64 arithmetic, but so far there appears no need.
9406  */
9407  div[qi + 1] += div[qi] * NBASE;
9408 
9409  div[qi] = qdigit;
9410  }
9411 
9412  /*
9413  * Approximate and store the last quotient digit (div[div_ndigits])
9414  */
9415  fdividend = (double) div[qi];
9416  for (i = 1; i < 4; i++)
9417  fdividend *= NBASE;
9418  fquotient = fdividend * fdivisorinverse;
9419  qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
9420  (((int) fquotient) - 1); /* truncate towards -infinity */
9421  div[qi] = qdigit;
9422 
9423  /*
9424  * Because the quotient digits might be off by one, some of them might be
9425  * -1 or NBASE at this point. The represented value is correct in a
9426  * mathematical sense, but it doesn't look right. We do a final carry
9427  * propagation pass to normalize the digits, which we combine with storing
9428  * the result digits into the output. Note that this is still done at
9429  * full precision w/guard digits.
9430  */
9431  alloc_var(result, div_ndigits + 1);
9432  res_digits = result->digits;
9433  carry = 0;
9434  for (i = div_ndigits; i >= 0; i--)
9435  {
9436  newdig = div[i] + carry;
9437  if (newdig < 0)
9438  {
9439  carry = -((-newdig - 1) / NBASE) - 1;
9440  newdig -= carry * NBASE;
9441  }
9442  else if (newdig >= NBASE)
9443  {
9444  carry = newdig / NBASE;
9445  newdig -= carry * NBASE;
9446  }
9447  else
9448  carry = 0;
9449  res_digits[i] = newdig;
9450  }
9451  Assert(carry == 0);
9452 
9453  pfree(div);
9454 
9455  /*
9456  * Finally, round the result to the requested precision.
9457  */
9458  result->weight = res_weight;
9459  result->sign = res_sign;
9460 
9461  /* Round to target rscale (and set result->dscale) */
9462  if (round)
9463  round_var(result, rscale);
9464  else
9465  trunc_var(result, rscale);
9466 
9467  /* Strip leading and trailing zeroes */
9468  strip_var(result);
9469 }
#define DIV_GUARD_DIGITS
Definition: numeric.c:100
#define Min(x, y)
Definition: numeric.c:14

References alloc_var(), Assert(), DEC_DIGITS, NumericVar::digits, DIV_GUARD_DIGITS, div_var_int(), NumericVar::dscale, ereport, errcode(), errmsg(), ERROR, i, Min, NBASE, NumericVar::ndigits, NUMERIC_NEG, NUMERIC_POS, palloc0(), pfree(), round_var(), NumericVar::sign, strip_var(), trunc_var(), NumericVar::weight, and zero_var().

Referenced by div_mod_var(), ln_var(), log_var(), and power_var_int().

◆ div_var_int()

static void div_var_int ( const NumericVar var,
int  ival,
int  ival_weight,
NumericVar result,
int  rscale,
bool  round 
)
static

Definition at line 9479 of file numeric.c.

9481 {
9482  NumericDigit *var_digits = var->digits;
9483  int var_ndigits = var->ndigits;
9484  int res_sign;
9485  int res_weight;
9486  int res_ndigits;
9487  NumericDigit *res_buf;
9488  NumericDigit *res_digits;
9489  uint32 divisor;
9490  int i;
9491 
9492  /* Guard against division by zero */
9493  if (ival == 0)
9494  ereport(ERROR,
9495  errcode(ERRCODE_DIVISION_BY_ZERO),
9496  errmsg("division by zero"));
9497 
9498  /* Result zero check */
9499  if (var_ndigits == 0)
9500  {
9501  zero_var(result);
9502  result->dscale = rscale;
9503  return;
9504  }
9505 
9506  /*
9507  * Determine the result sign, weight and number of digits to calculate.
9508  * The weight figured here is correct if the emitted quotient has no
9509  * leading zero digits; otherwise strip_var() will fix things up.
9510  */
9511  if (var->sign == NUMERIC_POS)
9512  res_sign = ival > 0 ? NUMERIC_POS : NUMERIC_NEG;
9513  else
9514  res_sign = ival > 0 ? NUMERIC_NEG : NUMERIC_POS;
9515  res_weight = var->weight - ival_weight;
9516  /* The number of accurate result digits we need to produce: */
9517  res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9518  /* ... but always at least 1 */
9519  res_ndigits = Max(res_ndigits, 1);
9520  /* If rounding needed, figure one more digit to ensure correct result */
9521  if (round)
9522  res_ndigits++;
9523 
9524  res_buf = digitbuf_alloc(res_ndigits + 1);
9525  res_buf[0] = 0; /* spare digit for later rounding */
9526  res_digits = res_buf + 1;
9527 
9528  /*
9529  * Now compute the quotient digits. This is the short division algorithm
9530  * described in Knuth volume 2, section 4.3.1 exercise 16, except that we
9531  * allow the divisor to exceed the internal base.
9532  *
9533  * In this algorithm, the carry from one digit to the next is at most
9534  * divisor - 1. Therefore, while processing the next digit, carry may
9535  * become as large as divisor * NBASE - 1, and so it requires a 64-bit
9536  * integer if this exceeds UINT_MAX.
9537  */
9538  divisor = abs(ival);
9539 
9540  if (divisor <= UINT_MAX / NBASE)
9541  {
9542  /* carry cannot overflow 32 bits */
9543  uint32 carry = 0;
9544 
9545  for (i = 0; i < res_ndigits; i++)
9546  {
9547  carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9548  res_digits[i] = (NumericDigit) (carry / divisor);
9549  carry = carry % divisor;
9550  }
9551  }
9552  else
9553  {
9554  /* carry may exceed 32 bits */
9555  uint64 carry = 0;
9556 
9557  for (i = 0; i < res_ndigits; i++)
9558  {
9559  carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9560  res_digits[i] = (NumericDigit) (carry / divisor);
9561  carry = carry % divisor;
9562  }
9563  }
9564 
9565  /* Store the quotient in result */
9566  digitbuf_free(result->buf);
9567  result->ndigits = res_ndigits;
9568  result->buf = res_buf;
9569  result->digits = res_digits;
9570  result->weight = res_weight;
9571  result->sign = res_sign;
9572 
9573  /* Round or truncate to target rscale (and set result->dscale) */
9574  if (round)
9575  round_var(result, rscale);
9576  else
9577  trunc_var(result, rscale);
9578 
9579  /* Strip leading/trailing zeroes */
9580  strip_var(result);
9581 }
unsigned int uint32
Definition: c.h:490

References NumericVar::buf, DEC_DIGITS, digitbuf_alloc, digitbuf_free, NumericVar::digits, NumericVar::dscale, ereport, errcode(), errmsg(), ERROR, i, Max, NBASE, NumericVar::ndigits, NUMERIC_NEG, NUMERIC_POS, round_var(), NumericVar::sign, strip_var(), trunc_var(), NumericVar::weight, and zero_var().

Referenced by div_var(), div_var_fast(), exp_var(), and ln_var().

◆ do_numeric_accum()

static void do_numeric_accum ( NumericAggState state,
Numeric  newval 
)
static

Definition at line 4779 of file numeric.c.

4780 {
4781  NumericVar X;
4782  NumericVar X2;
4783  MemoryContext old_context;
4784 
4785  /* Count NaN/infinity inputs separately from all else */
4787  {
4788  if (NUMERIC_IS_PINF(newval))
4789  state->pInfcount++;
4790  else if (NUMERIC_IS_NINF(newval))
4791  state->nInfcount++;
4792  else
4793  state->NaNcount++;
4794  return;
4795  }
4796 
4797  /* load processed number in short-lived context */
4799 
4800  /*
4801  * Track the highest input dscale that we've seen, to support inverse
4802  * transitions (see do_numeric_discard).
4803  */
4804  if (X.dscale > state->maxScale)
4805  {
4806  state->maxScale = X.dscale;
4807  state->maxScaleCount = 1;
4808  }
4809  else if (X.dscale == state->maxScale)
4810  state->maxScaleCount++;
4811 
4812  /* if we need X^2, calculate that in short-lived context */
4813  if (state->calcSumX2)
4814  {
4815  init_var(&X2);
4816  mul_var(&X, &X, &X2, X.dscale * 2);
4817  }
4818 
4819  /* The rest of this needs to work in the aggregate context */
4820  old_context = MemoryContextSwitchTo(state->agg_context);
4821 
4822  state->N++;
4823 
4824  /* Accumulate sums */
4825  accum_sum_add(&(state->sumX), &X);
4826 
4827  if (state->calcSumX2)
4828  accum_sum_add(&(state->sumX2), &X2);
4829 
4830  MemoryContextSwitchTo(old_context);
4831 }
#define newval
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
Definition: regguts.h:323

References accum_sum_add(), NumericVar::dscale, init_var, init_var_from_num(), MemoryContextSwitchTo(), mul_var(), newval, NUMERIC_IS_NINF, NUMERIC_IS_PINF, and NUMERIC_IS_SPECIAL.

Referenced by int2_accum(), int4_accum(), int8_accum(), int8_avg_accum(), numeric_accum(), and numeric_avg_accum().

◆ do_numeric_discard()

static bool do_numeric_discard ( NumericAggState state,
Numeric  newval 
)
static

Definition at line 4849 of file numeric.c.

4850 {
4851  NumericVar X;
4852  NumericVar X2;
4853  MemoryContext old_context;
4854 
4855  /* Count NaN/infinity inputs separately from all else */
4857  {
4858  if (NUMERIC_IS_PINF(newval))
4859  state->pInfcount--;
4860  else if (NUMERIC_IS_NINF(newval))
4861  state->nInfcount--;
4862  else
4863  state->NaNcount--;
4864  return true;
4865  }
4866 
4867  /* load processed number in short-lived context */
4869 
4870  /*
4871  * state->sumX's dscale is the maximum dscale of any of the inputs.
4872  * Removing the last input with that dscale would require us to recompute
4873  * the maximum dscale of the *remaining* inputs, which we cannot do unless
4874  * no more non-NaN inputs remain at all. So we report a failure instead,
4875  * and force the aggregation to be redone from scratch.
4876  */
4877  if (X.dscale == state->maxScale)
4878  {
4879  if (state->maxScaleCount > 1 || state->maxScale == 0)
4880  {
4881  /*
4882  * Some remaining inputs have same dscale, or dscale hasn't gotten
4883  * above zero anyway
4884  */
4885  state->maxScaleCount--;
4886  }
4887  else if (state->N == 1)
4888  {
4889  /* No remaining non-NaN inputs at all, so reset maxScale */
4890  state->maxScale = 0;
4891  state->maxScaleCount = 0;
4892  }
4893  else
4894  {
4895  /* Correct new maxScale is uncertain, must fail */
4896  return false;
4897  }
4898  }
4899 
4900  /* if we need X^2, calculate that in short-lived context */
4901  if (state->calcSumX2)
4902  {
4903  init_var(&X2);
4904  mul_var(&X, &X, &X2, X.dscale * 2);
4905  }
4906 
4907  /* The rest of this needs to work in the aggregate context */
4908  old_context = MemoryContextSwitchTo(state->agg_context);
4909 
4910  if (state->N-- > 1)
4911  {
4912  /* Negate X, to subtract it from the sum */
4913  X.sign = (X.sign == NUMERIC_POS ? NUMERIC_NEG : NUMERIC_POS);
4914  accum_sum_add(&(state->sumX), &X);
4915 
4916  if (state->calcSumX2)
4917  {
4918  /* Negate X^2. X^2 is always positive */
4919  X2.sign = NUMERIC_NEG;
4920  accum_sum_add(&(state->sumX2), &X2);
4921  }
4922  }
4923  else
4924  {
4925  /* Zero the sums */
4926  Assert(state->N == 0);
4927 
4928  accum_sum_reset(&state->sumX);
4929  if (state->calcSumX2)
4930  accum_sum_reset(&state->sumX2);
4931  }
4932 
4933  MemoryContextSwitchTo(old_context);
4934 
4935  return true;
4936 }
static void accum_sum_reset(NumericSumAccum *accum)
Definition: numeric.c:11721

References accum_sum_add(), accum_sum_reset(), Assert(), NumericVar::dscale, init_var, init_var_from_num(), MemoryContextSwitchTo(), mul_var(), newval, NUMERIC_IS_NINF, NUMERIC_IS_PINF, NUMERIC_IS_SPECIAL, NUMERIC_NEG, NUMERIC_POS, and NumericVar::sign.

Referenced by int2_accum_inv(), int4_accum_inv(), int8_accum_inv(), int8_avg_accum_inv(), and numeric_accum_inv().

◆ duplicate_numeric()

static Numeric duplicate_numeric ( Numeric  num)
static

Definition at line 7693 of file numeric.c.

7694 {
7695  Numeric res;
7696 
7697  res = (Numeric) palloc(VARSIZE(num));
7698  memcpy(res, num, VARSIZE(num));
7699  return res;
7700 }
struct NumericData * Numeric
Definition: numeric.h:53
#define VARSIZE(PTR)
Definition: varatt.h:279

References palloc(), res, and VARSIZE.

Referenced by numeric(), numeric_abs(), numeric_ceil(), numeric_exp(), numeric_floor(), numeric_inc(), numeric_ln(), numeric_mod_opt_error(), numeric_round(), numeric_sqrt(), numeric_trim_scale(), numeric_trunc(), numeric_uminus(), and numeric_uplus().

◆ estimate_ln_dweight()

static int estimate_ln_dweight ( const NumericVar var)
static

Definition at line 10601 of file numeric.c.

10602 {
10603  int ln_dweight;
10604 
10605  /* Caller should fail on ln(negative), but for the moment return zero */
10606  if (var->sign != NUMERIC_POS)
10607  return 0;
10608 
10609  if (cmp_var(var, &const_zero_point_nine) >= 0 &&
10610  cmp_var(var, &const_one_point_one) <= 0)
10611  {
10612  /*
10613  * 0.9 <= var <= 1.1
10614  *
10615  * ln(var) has a negative weight (possibly very large). To get a
10616  * reasonably accurate result, estimate it using ln(1+x) ~= x.
10617  */
10618  NumericVar x;
10619 
10620  init_var(&x);
10621  sub_var(var, &const_one, &x);
10622 
10623  if (x.ndigits > 0)
10624  {
10625  /* Use weight of most significant decimal digit of x */
10626  ln_dweight = x.weight * DEC_DIGITS + (int) log10(x.digits[0]);
10627  }
10628  else
10629  {
10630  /* x = 0. Since ln(1) = 0 exactly, we don't need extra digits */
10631  ln_dweight = 0;
10632  }
10633 
10634  free_var(&x);
10635  }
10636  else
10637  {
10638  /*
10639  * Estimate the logarithm using the first couple of digits from the
10640  * input number. This will give an accurate result whenever the input
10641  * is not too close to 1.
10642  */
10643  if (var->ndigits > 0)
10644  {
10645  int digits;
10646  int dweight;
10647  double ln_var;
10648 
10649  digits = var->digits[0];
10650  dweight = var->weight * DEC_DIGITS;
10651 
10652  if (var->ndigits > 1)
10653  {
10654  digits = digits * NBASE + var->digits[1];
10655  dweight -= DEC_DIGITS;
10656  }
10657 
10658  /*----------
10659  * We have var ~= digits * 10^dweight
10660  * so ln(var) ~= ln(digits) + dweight * ln(10)
10661  *----------
10662  */
10663  ln_var = log((double) digits) + dweight * 2.302585092994046;
10664  ln_dweight = (int) log10(fabs(ln_var));
10665  }
10666  else
10667  {
10668  /* Caller should fail on ln(0), but for the moment return zero */
10669  ln_dweight = 0;
10670  }
10671  }
10672 
10673  return ln_dweight;
10674 }
static const NumericVar const_zero_point_nine
Definition: numeric.c:437
static const NumericVar const_one_point_one
Definition: numeric.c:447
static void ln_var(const NumericVar *arg, NumericVar *result, int rscale)
Definition: numeric.c:10683
int digits
Definition: informix.c:666
int x
Definition: isn.c:71

References cmp_var(), const_one, const_one_point_one, const_zero_point_nine, DEC_DIGITS, NumericVar::digits, digits, free_var(), init_var, ln_var(), NBASE, NumericVar::ndigits, NUMERIC_POS, NumericVar::sign, sub_var(), NumericVar::weight, and x.

Referenced by log_var(), numeric_ln(), and power_var().

◆ exp_var()

static void exp_var ( const NumericVar arg,
NumericVar result,
int  rscale 
)
static

Definition at line 10472 of file numeric.c.

10473 {
10474  NumericVar x;
10475  NumericVar elem;
10476  int ni;
10477  double val;
10478  int dweight;
10479  int ndiv2;
10480  int sig_digits;
10481  int local_rscale;
10482 
10483  init_var(&x);
10484  init_var(&elem);
10485 
10486  set_var_from_var(arg, &x);
10487 
10488  /*
10489  * Estimate the dweight of the result using floating point arithmetic, so
10490  * that we can choose an appropriate local rscale for the calculation.
10491  */
10493 
10494  /* Guard against overflow/underflow */
10495  /* If you change this limit, see also power_var()'s limit */
10496  if (fabs(val) >= NUMERIC_MAX_RESULT_SCALE * 3)
10497  {
10498  if (val > 0)
10499  ereport(ERROR,
10500  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
10501  errmsg("value overflows numeric format")));
10502  zero_var(result);
10503  result->dscale = rscale;
10504  return;
10505  }
10506 
10507  /* decimal weight = log10(e^x) = x * log10(e) */
10508  dweight = (int) (val * 0.434294481903252);
10509 
10510  /*
10511  * Reduce x to the range -0.01 <= x <= 0.01 (approximately) by dividing by
10512  * 2^ndiv2, to improve the convergence rate of the Taylor series.
10513  *
10514  * Note that the overflow check above ensures that fabs(x) < 6000, which
10515  * means that ndiv2 <= 20 here.
10516  */
10517  if (fabs(val) > 0.01)
10518  {
10519  ndiv2 = 1;
10520  val /= 2;
10521 
10522  while (fabs(val) > 0.01)
10523  {
10524  ndiv2++;
10525  val /= 2;
10526  }
10527 
10528  local_rscale = x.dscale + ndiv2;
10529  div_var_int(&x, 1 << ndiv2, 0, &x, local_rscale, true);
10530  }
10531  else
10532  ndiv2 = 0;
10533 
10534  /*
10535  * Set the scale for the Taylor series expansion. The final result has
10536  * (dweight + rscale + 1) significant digits. In addition, we have to
10537  * raise the Taylor series result to the power 2^ndiv2, which introduces
10538  * an error of up to around log10(2^ndiv2) digits, so work with this many
10539  * extra digits of precision (plus a few more for good measure).
10540  */
10541  sig_digits = 1 + dweight + rscale + (int) (ndiv2 * 0.301029995663981);
10542  sig_digits = Max(sig_digits, 0) + 8;
10543 
10544  local_rscale = sig_digits - 1;
10545 
10546  /*
10547  * Use the Taylor series
10548  *
10549  * exp(x) = 1 + x + x^2/2! + x^3/3! + ...
10550  *
10551  * Given the limited range of x, this should converge reasonably quickly.
10552  * We run the series until the terms fall below the local_rscale limit.
10553  */
10554  add_var(&const_one, &x, result);
10555 
10556  mul_var(&x, &x, &elem, local_rscale);
10557  ni = 2;
10558  div_var_int(&elem, ni, 0, &elem, local_rscale, true);
10559 
10560  while (elem.ndigits != 0)
10561  {
10562  add_var(result, &elem, result);
10563 
10564  mul_var(&elem, &x, &elem, local_rscale);
10565  ni++;
10566  div_var_int(&elem, ni, 0, &elem, local_rscale, true);
10567  }
10568 
10569  /*
10570  * Compensate for the argument range reduction. Since the weight of the
10571  * result doubles with each multiplication, we can reduce the local rscale
10572  * as we proceed.
10573  */
10574  while (ndiv2-- > 0)
10575  {
10576  local_rscale = sig_digits - result->weight * 2 * DEC_DIGITS;
10577  local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
10578  mul_var(result, result, result, local_rscale);
10579  }
10580 
10581  /* Round to requested rscale */
10582  round_var(result, rscale);
10583 
10584  free_var(&x);
10585  free_var(&elem);
10586 }
static double numericvar_to_double_no_overflow(const NumericVar *var)
Definition: numeric.c:8271
#define NUMERIC_MAX_RESULT_SCALE
Definition: numeric.h:42
#define NUMERIC_MIN_DISPLAY_SCALE
Definition: numeric.h:40
void * arg

References add_var(), arg, const_one, DEC_DIGITS, div_var_int(), NumericVar::dscale, ereport, errcode(), errmsg(), ERROR, free_var(), init_var, Max, mul_var(), NumericVar::ndigits, NUMERIC_MAX_RESULT_SCALE, NUMERIC_MIN_DISPLAY_SCALE, numericvar_to_double_no_overflow(), round_var(), set_var_from_var(), val, NumericVar::weight, x, and zero_var().

Referenced by numeric_exp(), and power_var().

◆ float4_numeric()

Datum float4_numeric ( PG_FUNCTION_ARGS  )

Definition at line 4609 of file numeric.c.

4610 {
4612  Numeric res;
4613  NumericVar result;
4614  char buf[FLT_DIG + 100];
4615  const char *endptr;
4616 
4617  if (isnan(val))
4619 
4620  if (isinf(val))
4621  {
4622  if (val < 0)
4624  else
4626  }
4627 
4628  snprintf(buf, sizeof(buf), "%.*g", FLT_DIG, val);
4629 
4630  init_var(&result);
4631 
4632  /* Assume we need not worry about leading/trailing spaces */
4633  (void) set_var_from_str(buf, buf, &result, &endptr, NULL);
4634 
4635  res = make_result(&result);
4636 
4637  free_var(&result);
4638 
4640 }
static const NumericVar const_pinf
Definition: numeric.c:453
static const NumericVar const_ninf
Definition: numeric.c:456
static bool set_var_from_str(const char *str, const char *cp, NumericVar *dest, const char **endptr, Node *escontext)
Definition: numeric.c:6942
static Numeric make_result(const NumericVar *var)
Definition: numeric.c:7821
static const NumericVar const_nan
Definition: numeric.c:450
float float4
Definition: c.h:613
#define PG_GETARG_FLOAT4(n)
Definition: fmgr.h:281
#define PG_RETURN_NUMERIC(x)
Definition: numeric.h:79
#define snprintf
Definition: port.h:238

References buf, const_nan, const_ninf, const_pinf, free_var(), init_var, make_result(), PG_GETARG_FLOAT4, PG_RETURN_NUMERIC, res, set_var_from_str(), snprintf, and val.

◆ float8_numeric()

Datum float8_numeric ( PG_FUNCTION_ARGS  )

Definition at line 4515 of file numeric.c.

4516 {
4518  Numeric res;
4519  NumericVar result;
4520  char buf[DBL_DIG + 100];
4521  const char *endptr;
4522 
4523  if (isnan(val))
4525 
4526  if (isinf(val))
4527  {
4528  if (val < 0)
4530  else
4532  }
4533 
4534  snprintf(buf, sizeof(buf), "%.*g", DBL_DIG, val);
4535 
4536  init_var(&result);
4537 
4538  /* Assume we need not worry about leading/trailing spaces */
4539  (void) set_var_from_str(buf, buf, &result, &endptr, NULL);
4540 
4541  res = make_result(&result);
4542 
4543  free_var(&result);
4544 
4546 }
double float8
Definition: c.h:614
#define PG_GETARG_FLOAT8(n)
Definition: fmgr.h:282

References buf, const_nan, const_ninf, const_pinf, free_var(), init_var, make_result(), PG_GETARG_FLOAT8, PG_RETURN_NUMERIC, res, set_var_from_str(), snprintf, and val.

Referenced by executeItemOptUnwrapTarget(), and SV_to_JsonbValue().

◆ floor_var()

static void floor_var ( const NumericVar var,
NumericVar result 
)
static

Definition at line 9899 of file numeric.c.

9900 {
9901  NumericVar tmp;
9902 
9903  init_var(&tmp);
9904  set_var_from_var(var, &tmp);
9905 
9906  trunc_var(&tmp, 0);
9907 
9908  if (var->sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0)
9909  sub_var(&tmp, &const_one, &tmp);
9910 
9911  set_var_from_var(&tmp, result);
9912  free_var(&tmp);
9913 }

References cmp_var(), const_one, free_var(), init_var, NUMERIC_NEG, set_var_from_var(), NumericVar::sign, sub_var(), and trunc_var().

Referenced by compute_bucket(), and numeric_floor().

◆ free_var()

static void free_var ( NumericVar var)
static

Definition at line 6899 of file numeric.c.

6900 {
6901  digitbuf_free(var->buf);
6902  var->buf = NULL;
6903  var->digits = NULL;
6904  var->sign = NUMERIC_NAN;
6905 }
#define NUMERIC_NAN
Definition: numeric.c:198

References NumericVar::buf, digitbuf_free, NumericVar::digits, NUMERIC_NAN, and NumericVar::sign.

Referenced by accum_sum_combine(), ceil_var(), compute_bucket(), div_mod_var(), estimate_ln_dweight(), exp_var(), float4_numeric(), float8_numeric(), floor_var(), gcd_var(), get_str_from_var_sci(), in_range_numeric_numeric(), int64_div_fast_to_numeric(), int64_to_numeric(), int8_avg_deserialize(), int8_avg_serialize(), ln_var(), log_var(), mod_var(), numeric(), numeric_add_opt_error(), numeric_avg(), numeric_avg_deserialize(), numeric_avg_serialize(), numeric_ceil(), numeric_deserialize(), numeric_div_opt_error(), numeric_div_trunc(), numeric_exp(), numeric_fac(), numeric_floor(), numeric_gcd(), numeric_in(), numeric_inc(), numeric_lcm(), numeric_ln(), numeric_log(), numeric_min_scale(), numeric_mod_opt_error(), numeric_mul_opt_error(), numeric_poly_avg(), numeric_poly_deserialize(), numeric_poly_serialize(), numeric_poly_sum(), numeric_power(), numeric_recv(), numeric_round(), numeric_serialize(), numeric_sqrt(), numeric_stddev_internal(), numeric_sub_opt_error(), numeric_sum(), numeric_trim_scale(), numeric_trunc(), numericvar_to_int64(), numericvar_to_uint64(), power_var(), power_var_int(), set_var_from_non_decimal_integer_str(), sqrt_var(), and width_bucket_numeric().

◆ gcd_var()

static void gcd_var ( const NumericVar var1,
const NumericVar var2,
NumericVar result 
)
static

Definition at line 9922 of file numeric.c.

9923 {
9924  int res_dscale;
9925  int cmp;
9926  NumericVar tmp_arg;
9927  NumericVar mod;
9928 
9929  res_dscale = Max(var1->dscale, var2->dscale);
9930 
9931  /*
9932  * Arrange for var1 to be the number with the greater absolute value.
9933  *
9934  * This would happen automatically in the loop below, but avoids an
9935  * expensive modulo operation.
9936  */
9937  cmp = cmp_abs(var1, var2);
9938  if (cmp < 0)
9939  {
9940  const NumericVar *tmp = var1;
9941 
9942  var1 = var2;
9943  var2 = tmp;
9944  }
9945 
9946  /*
9947  * Also avoid the taking the modulo if the inputs have the same absolute
9948  * value, or if the smaller input is zero.
9949  */
9950  if (cmp == 0 || var2->ndigits == 0)
9951  {
9952  set_var_from_var(var1, result);
9953  result->sign = NUMERIC_POS;
9954  result->dscale = res_dscale;
9955  return;
9956  }
9957 
9958  init_var(&tmp_arg);
9959  init_var(&mod);
9960 
9961  /* Use the Euclidean algorithm to find the GCD */
9962  set_var_from_var(var1, &tmp_arg);
9963  set_var_from_var(var2, result);
9964 
9965  for (;;)
9966  {
9967  /* this loop can take a while, so allow it to be interrupted */
9969 
9970  mod_var(&tmp_arg, result, &mod);
9971  if (mod.ndigits == 0)
9972  break;
9973  set_var_from_var(result, &tmp_arg);
9974  set_var_from_var(&mod, result);
9975  }
9976  result->sign = NUMERIC_POS;
9977  result->dscale = res_dscale;
9978 
9979  free_var(&tmp_arg);
9980  free_var(&mod);
9981 }
static void mod_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:9776
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:743

References CHECK_FOR_INTERRUPTS, cmp(), cmp_abs(), NumericVar::dscale, free_var(), init_var, Max, mod_var(), NumericVar::ndigits, NUMERIC_POS, set_var_from_var(), and NumericVar::sign.

Referenced by numeric_gcd(), and numeric_lcm().

◆ generate_series_numeric()

Datum generate_series_numeric ( PG_FUNCTION_ARGS  )

Definition at line 1685 of file numeric.c.

1686 {
1687  return generate_series_step_numeric(fcinfo);
1688 }
Datum generate_series_step_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:1691

References generate_series_step_numeric().

◆ generate_series_step_numeric()

Datum generate_series_step_numeric ( PG_FUNCTION_ARGS  )

Definition at line 1691 of file numeric.c.

1692 {
1694  FuncCallContext *funcctx;
1695  MemoryContext oldcontext;
1696 
1697  if (SRF_IS_FIRSTCALL())
1698  {
1699  Numeric start_num = PG_GETARG_NUMERIC(0);
1700  Numeric stop_num = PG_GETARG_NUMERIC(1);
1701  NumericVar steploc = const_one;
1702 
1703  /* Reject NaN and infinities in start and stop values */
1704  if (NUMERIC_IS_SPECIAL(start_num))
1705  {
1706  if (NUMERIC_IS_NAN(start_num))
1707  ereport(ERROR,
1708  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1709  errmsg("start value cannot be NaN")));
1710  else
1711  ereport(ERROR,
1712  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1713  errmsg("start value cannot be infinity")));
1714  }
1715  if (NUMERIC_IS_SPECIAL(stop_num))
1716  {
1717  if (NUMERIC_IS_NAN(stop_num))
1718  ereport(ERROR,
1719  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1720  errmsg("stop value cannot be NaN")));
1721  else
1722  ereport(ERROR,
1723  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1724  errmsg("stop value cannot be infinity")));
1725  }
1726 
1727  /* see if we were given an explicit step size */
1728  if (PG_NARGS() == 3)
1729  {
1730  Numeric step_num = PG_GETARG_NUMERIC(2);
1731 
1732  if (NUMERIC_IS_SPECIAL(step_num))
1733  {
1734  if (NUMERIC_IS_NAN(step_num))
1735  ereport(ERROR,
1736  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1737  errmsg("step size cannot be NaN")));
1738  else
1739  ereport(ERROR,
1740  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1741  errmsg("step size cannot be infinity")));
1742  }
1743 
1744  init_var_from_num(step_num, &steploc);
1745 
1746  if (cmp_var(&steploc, &const_zero) == 0)
1747  ereport(ERROR,
1748  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1749  errmsg("step size cannot equal zero")));
1750  }
1751 
1752  /* create a function context for cross-call persistence */
1753  funcctx = SRF_FIRSTCALL_INIT();
1754 
1755  /*
1756  * Switch to memory context appropriate for multiple function calls.
1757  */
1758  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1759 
1760  /* allocate memory for user context */
1761  fctx = (generate_series_numeric_fctx *)
1763 
1764  /*
1765  * Use fctx to keep state from call to call. Seed current with the
1766  * original start value. We must copy the start_num and stop_num
1767  * values rather than pointing to them, since we may have detoasted
1768  * them in the per-call context.
1769  */
1770  init_var(&fctx->current);
1771  init_var(&fctx->stop);
1772  init_var(&fctx->step);
1773 
1774  set_var_from_num(start_num, &fctx->current);
1775  set_var_from_num(stop_num, &fctx->stop);
1776  set_var_from_var(&steploc, &fctx->step);
1777 
1778  funcctx->user_fctx = fctx;
1779  MemoryContextSwitchTo(oldcontext);
1780  }
1781 
1782  /* stuff done on every call of the function */
1783  funcctx = SRF_PERCALL_SETUP();
1784 
1785  /*
1786  * Get the saved state and use current state as the result of this
1787  * iteration.
1788  */
1789  fctx = funcctx->user_fctx;
1790 
1791  if ((fctx->step.sign == NUMERIC_POS &&
1792  cmp_var(&fctx->current, &fctx->stop) <= 0) ||
1793  (fctx->step.sign == NUMERIC_NEG &&
1794  cmp_var(&fctx->current, &fctx->stop) >= 0))
1795  {
1796  Numeric result = make_result(&fctx->current);
1797 
1798  /* switch to memory context appropriate for iteration calculation */
1799  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1800 
1801  /* increment current in preparation for next iteration */
1802  add_var(&fctx->current, &fctx->step, &fctx->current);
1803  MemoryContextSwitchTo(oldcontext);
1804 
1805  /* do when there is more left to send */
1806  SRF_RETURN_NEXT(funcctx, NumericGetDatum(result));
1807  }
1808  else
1809  /* do when there is no more left */
1810  SRF_RETURN_DONE(funcctx);
1811 }
static void set_var_from_num(Numeric num, NumericVar *dest)
Definition: numeric.c:7350
#define PG_NARGS()
Definition: fmgr.h:203
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:77
static Datum NumericGetDatum(Numeric X)
Definition: numeric.h:72
void * user_fctx
Definition: funcapi.h:82
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101

References add_var(), cmp_var(), const_one, const_zero, generate_series_numeric_fctx::current, ereport, errcode(), errmsg(), ERROR, init_var, init_var_from_num(), make_result(), MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, NUMERIC_IS_NAN, NUMERIC_IS_SPECIAL, NUMERIC_NEG, NUMERIC_POS, NumericGetDatum(), palloc(), PG_GETARG_NUMERIC, PG_NARGS, set_var_from_num(), set_var_from_var(), NumericVar::sign, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, generate_series_numeric_fctx::step, generate_series_numeric_fctx::stop, and FuncCallContext::user_fctx.

Referenced by generate_series_numeric().

◆ get_min_scale()

static int get_min_scale ( NumericVar var)
static

Definition at line 4135 of file numeric.c.

4136 {
4137  int min_scale;
4138  int last_digit_pos;
4139 
4140  /*
4141  * Ordinarily, the input value will be "stripped" so that the last
4142  * NumericDigit is nonzero. But we don't want to get into an infinite
4143  * loop if it isn't, so explicitly find the last nonzero digit.
4144  */
4145  last_digit_pos = var->ndigits - 1;
4146  while (last_digit_pos >= 0 &&
4147  var->digits[last_digit_pos] == 0)
4148  last_digit_pos--;
4149 
4150  if (last_digit_pos >= 0)
4151  {
4152  /* compute min_scale assuming that last ndigit has no zeroes */
4153  min_scale = (last_digit_pos - var->weight) * DEC_DIGITS;
4154 
4155  /*
4156  * We could get a negative result if there are no digits after the
4157  * decimal point. In this case the min_scale must be zero.
4158  */
4159  if (min_scale > 0)
4160  {
4161  /*
4162  * Reduce min_scale if trailing digit(s) in last NumericDigit are
4163  * zero.
4164  */
4165  NumericDigit last_digit = var->digits[last_digit_pos];
4166 
4167  while (last_digit % 10 == 0)
4168  {
4169  min_scale--;
4170  last_digit /= 10;
4171  }
4172  }
4173  else
4174  min_scale = 0;
4175  }
4176  else
4177  min_scale = 0; /* result if input is zero */
4178 
4179  return min_scale;
4180 }

References DEC_DIGITS, NumericVar::digits, NumericVar::ndigits, and NumericVar::weight.

Referenced by numeric_min_scale(), and numeric_trim_scale().

◆ get_str_from_var()

static char * get_str_from_var ( const NumericVar var)
static

Definition at line 7424 of file numeric.c.

7425 {
7426  int dscale;
7427  char *str;
7428  char *cp;
7429  char *endcp;
7430  int i;
7431  int d;
7432  NumericDigit dig;
7433 
7434 #if DEC_DIGITS > 1
7435  NumericDigit d1;
7436 #endif
7437 
7438  dscale = var->dscale;
7439 
7440  /*
7441  * Allocate space for the result.
7442  *
7443  * i is set to the # of decimal digits before decimal point. dscale is the
7444  * # of decimal digits we will print after decimal point. We may generate
7445  * as many as DEC_DIGITS-1 excess digits at the end, and in addition we
7446  * need room for sign, decimal point, null terminator.
7447  */
7448  i = (var->weight + 1) * DEC_DIGITS;
7449  if (i <= 0)
7450  i = 1;
7451 
7452  str = palloc(i + dscale + DEC_DIGITS + 2);
7453  cp = str;
7454 
7455  /*
7456  * Output a dash for negative values
7457  */
7458  if (var->sign == NUMERIC_NEG)
7459  *cp++ = '-';
7460 
7461  /*
7462  * Output all digits before the decimal point
7463  */
7464  if (var->weight < 0)
7465  {
7466  d = var->weight + 1;
7467  *cp++ = '0';
7468  }
7469  else
7470  {
7471  for (d = 0; d <= var->weight; d++)
7472  {
7473  dig = (d < var->ndigits) ? var->digits[d] : 0;
7474  /* In the first digit, suppress extra leading decimal zeroes */
7475 #if DEC_DIGITS == 4
7476  {
7477  bool putit = (d > 0);
7478 
7479  d1 = dig / 1000;
7480  dig -= d1 * 1000;
7481  putit |= (d1 > 0);
7482  if (putit)
7483  *cp++ = d1 + '0';
7484  d1 = dig / 100;
7485  dig -= d1 * 100;
7486  putit |= (d1 > 0);
7487  if (putit)
7488  *cp++ = d1 + '0';
7489  d1 = dig / 10;
7490  dig -= d1 * 10;
7491  putit |= (d1 > 0);
7492  if (putit)
7493  *cp++ = d1 + '0';
7494  *cp++ = dig + '0';
7495  }
7496 #elif DEC_DIGITS == 2
7497  d1 = dig / 10;
7498  dig -= d1 * 10;
7499  if (d1 > 0 || d > 0)
7500  *cp++ = d1 + '0';
7501  *cp++ = dig + '0';
7502 #elif DEC_DIGITS == 1
7503  *cp++ = dig + '0';
7504 #else
7505 #error unsupported NBASE
7506 #endif
7507  }
7508  }
7509 
7510  /*
7511  * If requested, output a decimal point and all the digits that follow it.
7512  * We initially put out a multiple of DEC_DIGITS digits, then truncate if
7513  * needed.
7514  */
7515  if (dscale > 0)
7516  {
7517  *cp++ = '.';
7518  endcp = cp + dscale;
7519  for (i = 0; i < dscale; d++, i += DEC_DIGITS)
7520  {
7521  dig = (d >= 0 && d < var->ndigits) ? var->digits[d] : 0;
7522 #if DEC_DIGITS == 4
7523  d1 = dig / 1000;
7524  dig -= d1 * 1000;
7525  *cp++ = d1 + '0';
7526  d1 = dig / 100;
7527  dig -= d1 * 100;
7528  *cp++ = d1 + '0';
7529  d1 = dig / 10;
7530  dig -= d1 * 10;
7531  *cp++ = d1 + '0';
7532  *cp++ = dig + '0';
7533 #elif DEC_DIGITS == 2
7534  d1 = dig / 10;
7535  dig -= d1 * 10;
7536  *cp++ = d1 + '0';
7537  *cp++ = dig + '0';
7538 #elif DEC_DIGITS == 1
7539  *cp++ = dig + '0';
7540 #else
7541 #error unsupported NBASE
7542 #endif
7543  }
7544  cp = endcp;
7545  }
7546 
7547  /*
7548  * terminate the string and return it
7549  */
7550  *cp = '\0';
7551  return str;
7552 }
static void error(void)
Definition: sql-dyntest.c:147

References DEC_DIGITS, NumericVar::digits, NumericVar::dscale, i, NumericVar::ndigits, NUMERIC_NEG, palloc(), NumericVar::sign, generate_unaccent_rules::str, and NumericVar::weight.

Referenced by get_str_from_var_sci(), numeric_normalize(), numeric_out(), and numericvar_to_double_no_overflow().

◆ get_str_from_var_sci()

static char * get_str_from_var_sci ( const NumericVar var,
int  rscale 
)
static

Definition at line 7577 of file numeric.c.

7578 {
7579  int32 exponent;
7580  NumericVar tmp_var;
7581  size_t len;
7582  char *str;
7583  char *sig_out;
7584 
7585  if (rscale < 0)
7586  rscale = 0;
7587 
7588  /*
7589  * Determine the exponent of this number in normalised form.
7590  *
7591  * This is the exponent required to represent the number with only one
7592  * significant digit before the decimal place.
7593  */
7594  if (var->ndigits > 0)
7595  {
7596  exponent = (var->weight + 1) * DEC_DIGITS;
7597 
7598  /*
7599  * Compensate for leading decimal zeroes in the first numeric digit by
7600  * decrementing the exponent.
7601  */
7602  exponent -= DEC_DIGITS - (int) log10(var->digits[0]);
7603  }
7604  else
7605  {
7606  /*
7607  * If var has no digits, then it must be zero.
7608  *
7609  * Zero doesn't technically have a meaningful exponent in normalised
7610  * notation, but we just display the exponent as zero for consistency
7611  * of output.
7612  */
7613  exponent = 0;
7614  }
7615 
7616  /*
7617  * Divide var by 10^exponent to get the significand, rounding to rscale
7618  * decimal digits in the process.
7619  */
7620  init_var(&tmp_var);
7621 
7622  power_ten_int(exponent, &tmp_var);
7623  div_var(var, &tmp_var, &tmp_var, rscale, true);
7624  sig_out = get_str_from_var(&tmp_var);
7625 
7626  free_var(&tmp_var);
7627 
7628  /*
7629  * Allocate space for the result.
7630  *
7631  * In addition to the significand, we need room for the exponent
7632  * decoration ("e"), the sign of the exponent, up to 10 digits for the
7633  * exponent itself, and of course the null terminator.
7634  */
7635  len = strlen(sig_out) + 13;
7636  str = palloc(len);
7637  snprintf(str, len, "%se%+03d", sig_out, exponent);
7638 
7639  pfree(sig_out);
7640 
7641  return str;
7642 }
static char * get_str_from_var(const NumericVar *var)
Definition: numeric.c:7424
static void power_ten_int(int exp, NumericVar *result)
Definition: numeric.c:11226
const void size_t len

References DEC_DIGITS, NumericVar::digits, div_var(), free_var(), get_str_from_var(), init_var, len, NumericVar::ndigits, palloc(), pfree(), power_ten_int(), snprintf, generate_unaccent_rules::str, and NumericVar::weight.

Referenced by numeric_out_sci().

◆ hash_numeric()

Datum hash_numeric ( PG_FUNCTION_ARGS  )

Definition at line 2696 of file numeric.c.

2697 {
2699  Datum digit_hash;
2700  Datum result;
2701  int weight;
2702  int start_offset;
2703  int end_offset;
2704  int i;
2705  int hash_len;
2707 
2708  /* If it's NaN or infinity, don't try to hash the rest of the fields */
2709  if (NUMERIC_IS_SPECIAL(key))
2710  PG_RETURN_UINT32(0);
2711 
2712  weight = NUMERIC_WEIGHT(key);
2713  start_offset = 0;
2714  end_offset = 0;
2715 
2716  /*
2717  * Omit any leading or trailing zeros from the input to the hash. The
2718  * numeric implementation *should* guarantee that leading and trailing
2719  * zeros are suppressed, but we're paranoid. Note that we measure the
2720  * starting and ending offsets in units of NumericDigits, not bytes.
2721  */
2723  for (i = 0; i < NUMERIC_NDIGITS(key); i++)
2724  {
2725  if (digits[i] != (NumericDigit) 0)
2726  break;
2727 
2728  start_offset++;
2729 
2730  /*
2731  * The weight is effectively the # of digits before the decimal point,
2732  * so decrement it for each leading zero we skip.
2733  */
2734  weight--;
2735  }
2736 
2737  /*
2738  * If there are no non-zero digits, then the value of the number is zero,
2739  * regardless of any other fields.
2740  */
2741  if (NUMERIC_NDIGITS(key) == start_offset)
2742  PG_RETURN_UINT32(-1);
2743 
2744  for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)
2745  {
2746  if (digits[i] != (NumericDigit) 0)
2747  break;
2748 
2749  end_offset++;
2750  }
2751 
2752  /* If we get here, there should be at least one non-zero digit */
2753  Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));
2754 
2755  /*
2756  * Note that we don't hash on the Numeric's scale, since two numerics can
2757  * compare equal but have different scales. We also don't hash on the
2758  * sign, although we could: since a sign difference implies inequality,
2759  * this shouldn't affect correctness.
2760  */
2761  hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;
2762  digit_hash = hash_any((unsigned char *) (NUMERIC_DIGITS(key) + start_offset),
2763  hash_len * sizeof(NumericDigit));
2764 
2765  /* Mix in the weight, via XOR */
2766  result = digit_hash ^ weight;
2767 
2768  PG_RETURN_DATUM(result);
2769 }
#define PG_RETURN_UINT32(x)
Definition: fmgr.h:355
#define PG_RETURN_DATUM(x)
Definition: fmgr.h:353
static Datum hash_any(const unsigned char *k, int keylen)
Definition: hashfn.h:31
uintptr_t Datum
Definition: postgres.h:64

References Assert(), digits, hash_any(), i, sort-test::key, NUMERIC_DIGITS, NUMERIC_IS_SPECIAL, NUMERIC_NDIGITS, NUMERIC_WEIGHT, PG_GETARG_NUMERIC, PG_RETURN_DATUM, and PG_RETURN_UINT32.

Referenced by JsonbHashScalarValue().

◆ hash_numeric_extended()

Datum hash_numeric_extended ( PG_FUNCTION_ARGS  )

Definition at line 2776 of file numeric.c.

2777 {
2779  uint64 seed = PG_GETARG_INT64(1);
2780  Datum digit_hash;
2781  Datum result;
2782  int weight;
2783  int start_offset;
2784  int end_offset;
2785  int i;
2786  int hash_len;
2788 
2789  /* If it's NaN or infinity, don't try to hash the rest of the fields */
2790  if (NUMERIC_IS_SPECIAL(key))
2791  PG_RETURN_UINT64(seed);
2792 
2793  weight = NUMERIC_WEIGHT(key);
2794  start_offset = 0;
2795  end_offset = 0;
2796 
2798  for (i = 0; i < NUMERIC_NDIGITS(key); i++)
2799  {
2800  if (digits[i] != (NumericDigit) 0)
2801  break;
2802 
2803  start_offset++;
2804 
2805  weight--;
2806  }
2807 
2808  if (NUMERIC_NDIGITS(key) == start_offset)
2809  PG_RETURN_UINT64(seed - 1);
2810 
2811  for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)
2812  {
2813  if (digits[i] != (NumericDigit) 0)
2814  break;
2815 
2816  end_offset++;
2817  }
2818 
2819  Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));
2820 
2821  hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;
2822  digit_hash = hash_any_extended((unsigned char *) (NUMERIC_DIGITS(key)
2823  + start_offset),
2824  hash_len * sizeof(NumericDigit),
2825  seed);
2826 
2827  result = UInt64GetDatum(DatumGetUInt64(digit_hash) ^ weight);
2828 
2829  PG_RETURN_DATUM(result);
2830 }
#define PG_GETARG_INT64(n)
Definition: fmgr.h:283
#define PG_RETURN_UINT64(x)
Definition: fmgr.h:369
static Datum hash_any_extended(const unsigned char *k, int keylen, uint64 seed)
Definition: hashfn.h:37
static uint64 DatumGetUInt64(Datum X)
Definition: postgres.h:419
static Datum UInt64GetDatum(uint64 X)
Definition: postgres.h:436

References Assert(), DatumGetUInt64(), digits, hash_any_extended(), i, sort-test::key, NUMERIC_DIGITS, NUMERIC_IS_SPECIAL, NUMERIC_NDIGITS, NUMERIC_WEIGHT, PG_GETARG_INT64, PG_GETARG_NUMERIC, PG_RETURN_DATUM, PG_RETURN_UINT64, and UInt64GetDatum().

Referenced by JsonbHashScalarValueExtended().

◆ in_range_numeric_numeric()

Datum in_range_numeric_numeric ( PG_FUNCTION_ARGS  )

Definition at line 2561 of file numeric.c.

2562 {
2564  Numeric base = PG_GETARG_NUMERIC(1);
2565  Numeric offset = PG_GETARG_NUMERIC(2);
2566  bool sub = PG_GETARG_BOOL(3);
2567  bool less = PG_GETARG_BOOL(4);
2568  bool result;
2569 
2570  /*
2571  * Reject negative (including -Inf) or NaN offset. Negative is per spec,
2572  * and NaN is because appropriate semantics for that seem non-obvious.
2573  */
2574  if (NUMERIC_IS_NAN(offset) ||
2575  NUMERIC_IS_NINF(offset) ||
2576  NUMERIC_SIGN(offset) == NUMERIC_NEG)
2577  ereport(ERROR,
2578  (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2579  errmsg("invalid preceding or following size in window function")));
2580 
2581  /*
2582  * Deal with cases where val and/or base is NaN, following the rule that
2583  * NaN sorts after non-NaN (cf cmp_numerics). The offset cannot affect
2584  * the conclusion.
2585  */
2586  if (NUMERIC_IS_NAN(val))
2587  {
2588  if (NUMERIC_IS_NAN(base))
2589  result = true; /* NAN = NAN */
2590  else
2591  result = !less; /* NAN > non-NAN */
2592  }
2593  else if (NUMERIC_IS_NAN(base))
2594  {
2595  result = less; /* non-NAN < NAN */
2596  }
2597 
2598  /*
2599  * Deal with infinite offset (necessarily +Inf, at this point).
2600  */
2601  else if (NUMERIC_IS_SPECIAL(offset))
2602  {
2603  Assert(NUMERIC_IS_PINF(offset));
2604  if (sub ? NUMERIC_IS_PINF(base) : NUMERIC_IS_NINF(base))
2605  {
2606  /*
2607  * base +/- offset would produce NaN, so return true for any val
2608  * (see in_range_float8_float8() for reasoning).
2609  */
2610  result = true;
2611  }
2612  else if (sub)
2613  {
2614  /* base - offset must be -inf */
2615  if (less)
2616  result = NUMERIC_IS_NINF(val); /* only -inf is <= sum */
2617  else
2618  result = true; /* any val is >= sum */
2619  }
2620  else
2621  {
2622  /* base + offset must be +inf */
2623  if (less)
2624  result = true; /* any val is <= sum */
2625  else
2626  result = NUMERIC_IS_PINF(val); /* only +inf is >= sum */
2627  }
2628  }
2629 
2630  /*
2631  * Deal with cases where val and/or base is infinite. The offset, being
2632  * now known finite, cannot affect the conclusion.
2633  */
2634  else if (NUMERIC_IS_SPECIAL(val))
2635  {
2636  if (NUMERIC_IS_PINF(val))
2637  {
2638  if (NUMERIC_IS_PINF(base))
2639  result = true; /* PINF = PINF */
2640  else
2641  result = !less; /* PINF > any other non-NAN */
2642  }
2643  else /* val must be NINF */
2644  {
2645  if (NUMERIC_IS_NINF(base))
2646  result = true; /* NINF = NINF */
2647  else
2648  result = less; /* NINF < anything else */
2649  }
2650  }
2651  else if (NUMERIC_IS_SPECIAL(base))
2652  {
2653  if (NUMERIC_IS_NINF(base))
2654  result = !less; /* normal > NINF */
2655  else
2656  result = less; /* normal < PINF */
2657  }
2658  else
2659  {
2660  /*
2661  * Otherwise go ahead and compute base +/- offset. While it's
2662  * possible for this to overflow the numeric format, it's unlikely
2663  * enough that we don't take measures to prevent it.
2664  */
2665  NumericVar valv;
2666  NumericVar basev;
2667  NumericVar offsetv;
2668  NumericVar sum;
2669 
2670  init_var_from_num(val, &valv);
2671  init_var_from_num(base, &basev);
2672  init_var_from_num(offset, &offsetv);
2673  init_var(&sum);
2674 
2675  if (sub)
2676  sub_var(&basev, &offsetv, &sum);
2677  else
2678  add_var(&basev, &offsetv, &sum);
2679 
2680  if (less)
2681  result = (cmp_var(&valv, &sum) <= 0);
2682  else
2683  result = (cmp_var(&valv, &sum) >= 0);
2684 
2685  free_var(&sum);
2686  }
2687 
2688  PG_FREE_IF_COPY(val, 0);
2689  PG_FREE_IF_COPY(base, 1);
2690  PG_FREE_IF_COPY(offset, 2);
2691 
2692  PG_RETURN_BOOL(result);
2693 }
#define PG_FREE_IF_COPY(ptr, n)
Definition: fmgr.h:260
#define PG_GETARG_BOOL(n)
Definition: fmgr.h:274
#define PG_RETURN_BOOL(x)
Definition: fmgr.h:359

References add_var(), Assert(), cmp_var(), ereport, errcode(), errmsg(), ERROR, free_var(), init_var, init_var_from_num(), NUMERIC_IS_NAN, NUMERIC_IS_NINF, NUMERIC_IS_PINF, NUMERIC_IS_SPECIAL, NUMERIC_NEG, NUMERIC_SIGN, PG_FREE_IF_COPY, PG_GETARG_BOOL, PG_GETARG_NUMERIC, PG_RETURN_BOOL, sub_var(), and val.

◆ init_var_from_num()

◆ int2_accum()

Datum int2_accum ( PG_FUNCTION_ARGS  )

Definition at line 5476 of file numeric.c.

5477 {
5479 
5480  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5481 
5482  /* Create the state data on the first call */
5483  if (state == NULL)
5484  state = makePolyNumAggState(fcinfo, true);
5485 
5486  if (!PG_ARGISNULL(1))
5487  {
5488 #ifdef HAVE_INT128
5489  do_int128_accum(state, (int128) PG_GETARG_INT16(1));
5490 #else
5492 #endif
5493  }
5494 
5496 }
#define makePolyNumAggState
Definition: numeric.c:5471
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4232
static void do_numeric_accum(NumericAggState *state, Numeric newval)
Definition: numeric.c:4779
#define PG_GETARG_POINTER(n)
Definition: fmgr.h:276
#define PG_ARGISNULL(n)
Definition: fmgr.h:209
#define PG_RETURN_POINTER(x)
Definition: fmgr.h:361
#define PG_GETARG_INT16(n)
Definition: fmgr.h:271

References do_numeric_accum(), int64_to_numeric(), makePolyNumAggState, PG_ARGISNULL, PG_GETARG_INT16, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ int2_accum_inv()

Datum int2_accum_inv ( PG_FUNCTION_ARGS  )

Definition at line 5904 of file numeric.c.

5905 {
5907 
5908  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5909 
5910  /* Should not get here with no state */
5911  if (state == NULL)
5912  elog(ERROR, "int2_accum_inv called with NULL state");
5913 
5914  if (!PG_ARGISNULL(1))
5915  {
5916 #ifdef HAVE_INT128
5917  do_int128_discard(state, (int128) PG_GETARG_INT16(1));
5918 #else
5919  /* Should never fail, all inputs have dscale 0 */
5921  elog(ERROR, "do_numeric_discard failed unexpectedly");
5922 #endif
5923  }
5924 
5926 }
static bool do_numeric_discard(NumericAggState *state, Numeric newval)
Definition: numeric.c:4849

References do_numeric_discard(), elog(), ERROR, int64_to_numeric(), PG_ARGISNULL, PG_GETARG_INT16, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ int2_avg_accum()

Datum int2_avg_accum ( PG_FUNCTION_ARGS  )

Definition at line 6587 of file numeric.c.

6588 {
6589  ArrayType *transarray;
6591  Int8TransTypeData *transdata;
6592 
6593  /*
6594  * If we're invoked as an aggregate, we can cheat and modify our first
6595  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6596  * a copy of it before scribbling on it.
6597  */
6598  if (AggCheckCallContext(fcinfo, NULL))
6599  transarray = PG_GETARG_ARRAYTYPE_P(0);
6600  else
6601  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6602 
6603  if (ARR_HASNULL(transarray) ||
6604  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6605  elog(ERROR, "expected 2-element int8 array");
6606 
6607  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6608  transdata->count++;
6609  transdata->sum += newval;
6610 
6611  PG_RETURN_ARRAYTYPE_P(transarray);
6612 }
#define PG_GETARG_ARRAYTYPE_P_COPY(n)
Definition: array.h:257
#define PG_GETARG_ARRAYTYPE_P(n)
Definition: array.h:256
#define ARR_DATA_PTR(a)
Definition: array.h:315
#define PG_RETURN_ARRAYTYPE_P(x)
Definition: array.h:258
#define ARR_SIZE(a)
Definition: array.h:282
#define ARR_OVERHEAD_NONULLS(ndims)
Definition: array.h:303
#define ARR_HASNULL(a)
Definition: array.h:284
int AggCheckCallContext(FunctionCallInfo fcinfo, MemoryContext *aggcontext)
Definition: nodeAgg.c:4522

References AggCheckCallContext(), ARR_DATA_PTR, ARR_HASNULL, ARR_OVERHEAD_NONULLS, ARR_SIZE, Int8TransTypeData::count, elog(), ERROR, newval, PG_GETARG_ARRAYTYPE_P, PG_GETARG_ARRAYTYPE_P_COPY, PG_GETARG_INT16, PG_RETURN_ARRAYTYPE_P, and Int8TransTypeData::sum.

◆ int2_avg_accum_inv()

Datum int2_avg_accum_inv ( PG_FUNCTION_ARGS  )

Definition at line 6674 of file numeric.c.

6675 {
6676  ArrayType *transarray;
6678  Int8TransTypeData *transdata;
6679 
6680  /*
6681  * If we're invoked as an aggregate, we can cheat and modify our first
6682  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6683  * a copy of it before scribbling on it.
6684  */
6685  if (AggCheckCallContext(fcinfo, NULL))
6686  transarray = PG_GETARG_ARRAYTYPE_P(0);
6687  else
6688  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6689 
6690  if (ARR_HASNULL(transarray) ||
6691  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6692  elog(ERROR, "expected 2-element int8 array");
6693 
6694  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6695  transdata->count--;
6696  transdata->sum -= newval;
6697 
6698  PG_RETURN_ARRAYTYPE_P(transarray);
6699 }

References AggCheckCallContext(), ARR_DATA_PTR, ARR_HASNULL, ARR_OVERHEAD_NONULLS, ARR_SIZE, Int8TransTypeData::count, elog(), ERROR, newval, PG_GETARG_ARRAYTYPE_P, PG_GETARG_ARRAYTYPE_P_COPY, PG_GETARG_INT16, PG_RETURN_ARRAYTYPE_P, and Int8TransTypeData::sum.

◆ int2_numeric()

Datum int2_numeric ( PG_FUNCTION_ARGS  )

Definition at line 4466 of file numeric.c.

4467 {
4468  int16 val = PG_GETARG_INT16(0);
4469 
4471 }

References int64_to_numeric(), PG_GETARG_INT16, PG_RETURN_NUMERIC, and val.

◆ int2_sum()

Datum int2_sum ( PG_FUNCTION_ARGS  )

Definition at line 6438 of file numeric.c.

6439 {
6440  int64 newval;
6441 
6442  if (PG_ARGISNULL(0))
6443  {
6444  /* No non-null input seen so far... */
6445  if (PG_ARGISNULL(1))
6446  PG_RETURN_NULL(); /* still no non-null */
6447  /* This is the first non-null input. */
6448  newval = (int64) PG_GETARG_INT16(1);
6450  }
6451 
6452  /*
6453  * If we're invoked as an aggregate, we can cheat and modify our first
6454  * parameter in-place to avoid palloc overhead. If not, we need to return
6455  * the new value of the transition variable. (If int8 is pass-by-value,
6456  * then of course this is useless as well as incorrect, so just ifdef it
6457  * out.)
6458  */
6459 #ifndef USE_FLOAT8_BYVAL /* controls int8 too */
6460  if (AggCheckCallContext(fcinfo, NULL))
6461  {
6462  int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
6463 
6464  /* Leave the running sum unchanged in the new input is null */
6465  if (!PG_ARGISNULL(1))
6466  *oldsum = *oldsum + (int64) PG_GETARG_INT16(1);
6467 
6468  PG_RETURN_POINTER(oldsum);
6469  }
6470  else
6471 #endif
6472  {
6473  int64 oldsum = PG_GETARG_INT64(0);
6474 
6475  /* Leave sum unchanged if new input is null. */
6476  if (PG_ARGISNULL(1))
6477  PG_RETURN_INT64(oldsum);
6478 
6479  /* OK to do the addition. */
6480  newval = oldsum + (int64) PG_GETARG_INT16(1);
6481 
6483  }
6484 }
#define PG_RETURN_INT64(x)
Definition: fmgr.h:368
#define PG_RETURN_NULL()
Definition: fmgr.h:345

References AggCheckCallContext(), newval, PG_ARGISNULL, PG_GETARG_INT16, PG_GETARG_INT64, PG_GETARG_POINTER, PG_RETURN_INT64, PG_RETURN_NULL, and PG_RETURN_POINTER.

◆ int2int4_sum()

Datum int2int4_sum ( PG_FUNCTION_ARGS  )

Definition at line 6757 of file numeric.c.

6758 {
6759  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
6760  Int8TransTypeData *transdata;
6761 
6762  if (ARR_HASNULL(transarray) ||
6763  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6764  elog(ERROR, "expected 2-element int8 array");
6765  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6766 
6767  /* SQL defines SUM of no values to be NULL */
6768  if (transdata->count == 0)
6769  PG_RETURN_NULL();
6770 
6771  PG_RETURN_DATUM(Int64GetDatumFast(transdata->sum));
6772 }
#define Int64GetDatumFast(X)
Definition: postgres.h:554

References ARR_DATA_PTR, ARR_HASNULL, ARR_OVERHEAD_NONULLS, ARR_SIZE, Int8TransTypeData::count, elog(), ERROR, Int64GetDatumFast, PG_GETARG_ARRAYTYPE_P, PG_RETURN_DATUM, PG_RETURN_NULL, and Int8TransTypeData::sum.

◆ int4_accum()

Datum int4_accum ( PG_FUNCTION_ARGS  )

Definition at line 5499 of file numeric.c.

5500 {
5502 
5503  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5504 
5505  /* Create the state data on the first call */
5506  if (state == NULL)
5507  state = makePolyNumAggState(fcinfo, true);
5508 
5509  if (!PG_ARGISNULL(1))
5510  {
5511 #ifdef HAVE_INT128
5512  do_int128_accum(state, (int128) PG_GETARG_INT32(1));
5513 #else
5515 #endif
5516  }
5517 
5519 }
#define PG_GETARG_INT32(n)
Definition: fmgr.h:269

References do_numeric_accum(), int64_to_numeric(), makePolyNumAggState, PG_ARGISNULL, PG_GETARG_INT32, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ int4_accum_inv()

Datum int4_accum_inv ( PG_FUNCTION_ARGS  )

Definition at line 5929 of file numeric.c.

5930 {
5932 
5933  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5934 
5935  /* Should not get here with no state */
5936  if (state == NULL)
5937  elog(ERROR, "int4_accum_inv called with NULL state");
5938 
5939  if (!PG_ARGISNULL(1))
5940  {
5941 #ifdef HAVE_INT128
5942  do_int128_discard(state, (int128) PG_GETARG_INT32(1));
5943 #else
5944  /* Should never fail, all inputs have dscale 0 */
5946  elog(ERROR, "do_numeric_discard failed unexpectedly");
5947 #endif
5948  }
5949 
5951 }

References do_numeric_discard(), elog(), ERROR, int64_to_numeric(), PG_ARGISNULL, PG_GETARG_INT32, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ int4_avg_accum()

Datum int4_avg_accum ( PG_FUNCTION_ARGS  )

Definition at line 6615 of file numeric.c.

6616 {
6617  ArrayType *transarray;
6619  Int8TransTypeData *transdata;
6620 
6621  /*
6622  * If we're invoked as an aggregate, we can cheat and modify our first
6623  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6624  * a copy of it before scribbling on it.
6625  */
6626  if (AggCheckCallContext(fcinfo, NULL))
6627  transarray = PG_GETARG_ARRAYTYPE_P(0);
6628  else
6629  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6630 
6631  if (ARR_HASNULL(transarray) ||
6632  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6633  elog(ERROR, "expected 2-element int8 array");
6634 
6635  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6636  transdata->count++;
6637  transdata->sum += newval;
6638 
6639  PG_RETURN_ARRAYTYPE_P(transarray);
6640 }

References AggCheckCallContext(), ARR_DATA_PTR, ARR_HASNULL, ARR_OVERHEAD_NONULLS, ARR_SIZE, Int8TransTypeData::count, elog(), ERROR, newval, PG_GETARG_ARRAYTYPE_P, PG_GETARG_ARRAYTYPE_P_COPY, PG_GETARG_INT32, PG_RETURN_ARRAYTYPE_P, and Int8TransTypeData::sum.

◆ int4_avg_accum_inv()

Datum int4_avg_accum_inv ( PG_FUNCTION_ARGS  )

Definition at line 6702 of file numeric.c.

6703 {
6704  ArrayType *transarray;
6706  Int8TransTypeData *transdata;
6707 
6708  /*
6709  * If we're invoked as an aggregate, we can cheat and modify our first
6710  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6711  * a copy of it before scribbling on it.
6712  */
6713  if (AggCheckCallContext(fcinfo, NULL))
6714  transarray = PG_GETARG_ARRAYTYPE_P(0);
6715  else
6716  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6717 
6718  if (ARR_HASNULL(transarray) ||
6719  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6720  elog(ERROR, "expected 2-element int8 array");
6721 
6722  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6723  transdata->count--;
6724  transdata->sum -= newval;
6725 
6726  PG_RETURN_ARRAYTYPE_P(transarray);
6727 }

References AggCheckCallContext(), ARR_DATA_PTR, ARR_HASNULL, ARR_OVERHEAD_NONULLS, ARR_SIZE, Int8TransTypeData::count, elog(), ERROR, newval, PG_GETARG_ARRAYTYPE_P, PG_GETARG_ARRAYTYPE_P_COPY, PG_GETARG_INT32, PG_RETURN_ARRAYTYPE_P, and Int8TransTypeData::sum.

◆ int4_avg_combine()

Datum int4_avg_combine ( PG_FUNCTION_ARGS  )

Definition at line 6643 of file numeric.c.

6644 {
6645  ArrayType *transarray1;
6646  ArrayType *transarray2;
6647  Int8TransTypeData *state1;
6648  Int8TransTypeData *state2;
6649 
6650  if (!AggCheckCallContext(fcinfo, NULL))
6651  elog(ERROR, "aggregate function called in non-aggregate context");
6652 
6653  transarray1 = PG_GETARG_ARRAYTYPE_P(0);
6654  transarray2 = PG_GETARG_ARRAYTYPE_P(1);
6655 
6656  if (ARR_HASNULL(transarray1) ||
6657  ARR_SIZE(transarray1) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6658  elog(ERROR, "expected 2-element int8 array");
6659 
6660  if (ARR_HASNULL(transarray2) ||
6661  ARR_SIZE(transarray2) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6662  elog(ERROR, "expected 2-element int8 array");
6663 
6664  state1 = (Int8TransTypeData *) ARR_DATA_PTR(transarray1);
6665  state2 = (Int8TransTypeData *) ARR_DATA_PTR(transarray2);
6666 
6667  state1->count += state2->count;
6668  state1->sum += state2->sum;
6669 
6670  PG_RETURN_ARRAYTYPE_P(transarray1);
6671 }

References AggCheckCallContext(), ARR_DATA_PTR, ARR_HASNULL, ARR_OVERHEAD_NONULLS, ARR_SIZE, Int8TransTypeData::count, elog(), ERROR, PG_GETARG_ARRAYTYPE_P, PG_RETURN_ARRAYTYPE_P, and Int8TransTypeData::sum.

◆ int4_numeric()

Datum int4_numeric ( PG_FUNCTION_ARGS  )

Definition at line 4338 of file numeric.c.

4339 {
4340  int32 val = PG_GETARG_INT32(0);
4341 
4343 }

References int64_to_numeric(), PG_GETARG_INT32, PG_RETURN_NUMERIC, and val.

◆ int4_sum()

Datum int4_sum ( PG_FUNCTION_ARGS  )

Definition at line 6487 of file numeric.c.

6488 {
6489  int64 newval;
6490 
6491  if (PG_ARGISNULL(0))
6492  {
6493  /* No non-null input seen so far... */
6494  if (PG_ARGISNULL(1))
6495  PG_RETURN_NULL(); /* still no non-null */
6496  /* This is the first non-null input. */
6497  newval = (int64) PG_GETARG_INT32(1);
6499  }
6500 
6501  /*
6502  * If we're invoked as an aggregate, we can cheat and modify our first
6503  * parameter in-place to avoid palloc overhead. If not, we need to return
6504  * the new value of the transition variable. (If int8 is pass-by-value,
6505  * then of course this is useless as well as incorrect, so just ifdef it
6506  * out.)
6507  */
6508 #ifndef USE_FLOAT8_BYVAL /* controls int8 too */
6509  if (AggCheckCallContext(fcinfo, NULL))
6510  {
6511  int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
6512 
6513  /* Leave the running sum unchanged in the new input is null */
6514  if (!PG_ARGISNULL(1))
6515  *oldsum = *oldsum + (int64) PG_GETARG_INT32(1);
6516 
6517  PG_RETURN_POINTER(oldsum);
6518  }
6519  else
6520 #endif
6521  {
6522  int64 oldsum = PG_GETARG_INT64(0);
6523 
6524  /* Leave sum unchanged if new input is null. */
6525  if (PG_ARGISNULL(1))
6526  PG_RETURN_INT64(oldsum);
6527 
6528  /* OK to do the addition. */
6529  newval = oldsum + (int64) PG_GETARG_INT32(1);
6530 
6532  }
6533 }

References AggCheckCallContext(), newval, PG_ARGISNULL, PG_GETARG_INT32, PG_GETARG_INT64, PG_GETARG_POINTER, PG_RETURN_INT64, PG_RETURN_NULL, and PG_RETURN_POINTER.

◆ int64_div_fast_to_numeric()

Numeric int64_div_fast_to_numeric ( int64  val1,
int  log10val2 
)

Definition at line 4253 of file numeric.c.

4254 {
4255  Numeric res;
4256  NumericVar result;
4257  int rscale;
4258  int w;
4259  int m;
4260 
4261  init_var(&result);
4262 
4263  /* result scale */
4264  rscale = log10val2 < 0 ? 0 : log10val2;
4265 
4266  /* how much to decrease the weight by */
4267  w = log10val2 / DEC_DIGITS;
4268  /* how much is left to divide by */
4269  m = log10val2 % DEC_DIGITS;
4270  if (m < 0)
4271  {
4272  m += DEC_DIGITS;
4273  w--;
4274  }
4275 
4276  /*
4277  * If there is anything left to divide by (10^m with 0 < m < DEC_DIGITS),
4278  * multiply the dividend by 10^(DEC_DIGITS - m), and shift the weight by
4279  * one more.
4280  */
4281  if (m > 0)
4282  {
4283 #if DEC_DIGITS == 4
4284  static const int pow10[] = {1, 10, 100, 1000};
4285 #elif DEC_DIGITS == 2
4286  static const int pow10[] = {1, 10};
4287 #elif DEC_DIGITS == 1
4288  static const int pow10[] = {1};
4289 #else
4290 #error unsupported NBASE
4291 #endif
4292  int64 factor = pow10[DEC_DIGITS - m];
4293  int64 new_val1;
4294 
4295  StaticAssertDecl(lengthof(pow10) == DEC_DIGITS, "mismatch with DEC_DIGITS");
4296 
4297  if (unlikely(pg_mul_s64_overflow(val1, factor, &new_val1)))
4298  {
4299 #ifdef HAVE_INT128
4300  /* do the multiplication using 128-bit integers */
4301  int128 tmp;
4302 
4303  tmp = (int128) val1 * (int128) factor;
4304 
4305  int128_to_numericvar(tmp, &result);
4306 #else
4307  /* do the multiplication using numerics */
4308  NumericVar tmp;
4309 
4310  init_var(&tmp);
4311 
4312  int64_to_numericvar(val1, &result);
4313  int64_to_numericvar(factor, &tmp);
4314  mul_var(&result, &tmp, &result, 0);
4315 
4316  free_var(&tmp);
4317 #endif
4318  }
4319  else
4320  int64_to_numericvar(new_val1, &result);
4321 
4322  w++;
4323  }
4324  else
4325  int64_to_numericvar(val1, &result);
4326 
4327  result.weight -= w;
4328  result.dscale = rscale;
4329 
4330  res = make_result(&result);
4331 
4332  free_var(&result);
4333 
4334  return res;
4335 }
static void int64_to_numericvar(int64 val, NumericVar *var)
Definition: numeric.c:8034
#define unlikely(x)
Definition: c.h:295
#define lengthof(array)
Definition: c.h:772
#define StaticAssertDecl(condition, errmessage)
Definition: c.h:920
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:215

References DEC_DIGITS, NumericVar::dscale, free_var(), init_var, int64_to_numericvar(), lengthof, make_result(), mul_var(), pg_mul_s64_overflow(), res, StaticAssertDecl, unlikely, and NumericVar::weight.

Referenced by interval_part_common(), time_part_common(), timestamp_part_common(), timestamptz_part_common(), and timetz_part_common().

◆ int64_to_numeric()

◆ int64_to_numericvar()

static void int64_to_numericvar ( int64  val,
NumericVar var 
)
static

Definition at line 8034 of file numeric.c.

8035 {
8036  uint64 uval,
8037  newuval;
8038  NumericDigit *ptr;
8039  int ndigits;
8040 
8041  /* int64 can require at most 19 decimal digits; add one for safety */
8042  alloc_var(var, 20 / DEC_DIGITS);
8043  if (val < 0)
8044  {
8045  var->sign = NUMERIC_NEG;
8046  uval = -val;
8047  }
8048  else
8049  {
8050  var->sign = NUMERIC_POS;
8051  uval = val;
8052  }
8053  var->dscale = 0;
8054  if (val == 0)
8055  {
8056  var->ndigits = 0;
8057  var->weight = 0;
8058  return;
8059  }
8060  ptr = var->digits + var->ndigits;
8061  ndigits = 0;
8062  do
8063  {
8064  ptr--;
8065  ndigits++;
8066  newuval = uval / NBASE;
8067  *ptr = uval - newuval * NBASE;
8068  uval = newuval;
8069  } while (uval);
8070  var->digits = ptr;
8071  var->ndigits = ndigits;
8072  var->weight = ndigits - 1;
8073 }

References alloc_var(), DEC_DIGITS, NumericVar::digits, NumericVar::dscale, NBASE, NumericVar::ndigits, NUMERIC_NEG, NUMERIC_POS, NumericVar::sign, val, and NumericVar::weight.

Referenced by int64_div_fast_to_numeric(), int64_to_numeric(), numeric_fac(), numeric_stddev_internal(), set_var_from_non_decimal_integer_str(), sqrt_var(), and width_bucket_numeric().

◆ int8_accum()

Datum int8_accum ( PG_FUNCTION_ARGS  )

Definition at line 5522 of file numeric.c.

5523 {
5525 
5526  state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5527 
5528  /* Create the state data on the first call */
5529  if (state == NULL)
5530  state = makeNumericAggState(fcinfo, true);
5531 
5532  if (!PG_ARGISNULL(1))
5534 
5536 }
static NumericAggState * makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
Definition: numeric.c:4739

References do_numeric_accum(), int64_to_numeric(), makeNumericAggState(), PG_ARGISNULL, PG_GETARG_INT64, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ int8_accum_inv()

Datum int8_accum_inv ( PG_FUNCTION_ARGS  )

Definition at line 5954 of file numeric.c.

5955 {
5957 
5958  state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5959 
5960  /* Should not get here with no state */
5961  if (state == NULL)
5962  elog(ERROR, "int8_accum_inv called with NULL state");
5963 
5964  if (!PG_ARGISNULL(1))
5965  {
5966  /* Should never fail, all inputs have dscale 0 */
5968  elog(ERROR, "do_numeric_discard failed unexpectedly");
5969  }
5970 
5972 }

References do_numeric_discard(), elog(), ERROR, int64_to_numeric(), PG_ARGISNULL, PG_GETARG_INT64, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ int8_avg()

Datum int8_avg ( PG_FUNCTION_ARGS  )

Definition at line 6730 of file numeric.c.

6731 {
6732  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
6733  Int8TransTypeData *transdata;
6734  Datum countd,
6735  sumd;
6736 
6737  if (ARR_HASNULL(transarray) ||
6738  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6739  elog(ERROR, "expected 2-element int8 array");
6740  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6741 
6742  /* SQL defines AVG of no values to be NULL */
6743  if (transdata->count == 0)
6744  PG_RETURN_NULL();
6745 
6746  countd = NumericGetDatum(int64_to_numeric(transdata->count));
6747  sumd = NumericGetDatum(int64_to_numeric(transdata->sum));
6748 
6750 }
Datum numeric_div(PG_FUNCTION_ARGS)
Definition: numeric.c:3123
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644

References ARR_DATA_PTR, ARR_HASNULL, ARR_OVERHEAD_NONULLS, ARR_SIZE, Int8TransTypeData::count, DirectFunctionCall2, elog(), ERROR, int64_to_numeric(), numeric_div(), NumericGetDatum(), PG_GETARG_ARRAYTYPE_P, PG_RETURN_DATUM, PG_RETURN_NULL, and Int8TransTypeData::sum.

◆ int8_avg_accum()

Datum int8_avg_accum ( PG_FUNCTION_ARGS  )

Definition at line 5720 of file numeric.c.

5721 {
5723 
5724  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5725 
5726  /* Create the state data on the first call */
5727  if (state == NULL)
5728  state = makePolyNumAggState(fcinfo, false);
5729 
5730  if (!PG_ARGISNULL(1))
5731  {
5732 #ifdef HAVE_INT128
5733  do_int128_accum(state, (int128) PG_GETARG_INT64(1));
5734 #else
5736 #endif
5737  }
5738 
5740 }

References do_numeric_accum(), int64_to_numeric(), makePolyNumAggState, PG_ARGISNULL, PG_GETARG_INT64, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ int8_avg_accum_inv()

Datum int8_avg_accum_inv ( PG_FUNCTION_ARGS  )

Definition at line 5975 of file numeric.c.

5976 {
5978 
5979  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5980 
5981  /* Should not get here with no state */
5982  if (state == NULL)
5983  elog(ERROR, "int8_avg_accum_inv called with NULL state");
5984 
5985  if (!PG_ARGISNULL(1))
5986  {
5987 #ifdef HAVE_INT128
5988  do_int128_discard(state, (int128) PG_GETARG_INT64(1));
5989 #else
5990  /* Should never fail, all inputs have dscale 0 */
5992  elog(ERROR, "do_numeric_discard failed unexpectedly");
5993 #endif
5994  }
5995 
5997 }

References do_numeric_discard(), elog(), ERROR, int64_to_numeric(), PG_ARGISNULL, PG_GETARG_INT64, PG_GETARG_POINTER, and PG_RETURN_POINTER.

◆ int8_avg_combine()

Datum int8_avg_combine ( PG_FUNCTION_ARGS  )

Definition at line 5747 of file numeric.c.

5748 {
5749  PolyNumAggState *state1;
5750  PolyNumAggState *state2;
5751  MemoryContext agg_context;
5752  MemoryContext old_context;
5753 
5754  if (!AggCheckCallContext(fcinfo, &agg_context))
5755  elog(ERROR, "aggregate function called in non-aggregate context");
5756 
5757  state1 = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5758  state2 = PG_ARGISNULL(1) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(1);
5759 
5760  if (state2 == NULL)
5761  PG_RETURN_POINTER(state1);
5762 
5763  /* manually copy all fields from state2 to state1 */
5764  if (state1 == NULL)
5765  {
5766  old_context = MemoryContextSwitchTo(agg_context);
5767 
5768  state1 = makePolyNumAggState(fcinfo, false);
5769  state1->N = state2->N;
5770 
5771 #ifdef HAVE_INT128
5772  state1->sumX = state2->sumX;
5773 #else
5774  accum_sum_copy(&state1->sumX, &state2->sumX);
5775 #endif
5776  MemoryContextSwitchTo(old_context);
5777 
5778  PG_RETURN_POINTER(state1);
5779  }
5780 
5781  if (state2->N > 0)
5782  {
5783  state1->N += state2->N;
5784 
5785 #ifdef HAVE_INT128
5786  state1->sumX += state2->sumX;
5787 #else
5788  /* The rest of this needs to work in the aggregate context */
5789  old_context = MemoryContextSwitchTo(agg_context);
5790 
5791  /* Accumulate sums */
5792  accum_sum_combine(&state1->sumX, &state2->sumX);
5793 
5794  MemoryContextSwitchTo(old_context);
5795 #endif
5796 
5797  }
5798  PG_RETURN_POINTER(state1);
5799 }
static void accum_sum_combine(NumericSumAccum *accum, NumericSumAccum *accum2)
Definition: numeric.c:12015
static void accum_sum_copy(NumericSumAccum *dst, NumericSumAccum *src)
Definition: numeric.c:11998
NumericSumAccum sumX
Definition: numeric.c:4721

References accum_sum_combine(), accum_sum_copy(), AggCheckCallContext(), elog(), ERROR, makePolyNumAggState, MemoryContextSwitchTo(), NumericAggState::N, PG_ARGISNULL, PG_GETARG_POINTER, PG_RETURN_POINTER, and NumericAggState::sumX.

◆ int8_avg_deserialize()

Datum int8_avg_deserialize ( PG_FUNCTION_ARGS  )

Definition at line 5856 of file numeric.c.

5857 {
5858  bytea *sstate;
5859  PolyNumAggState *result;
5861  NumericVar tmp_var;
5862 
5863  if (!AggCheckCallContext(fcinfo, NULL))
5864  elog(ERROR, "aggregate function called in non-aggregate context");
5865 
5866  sstate = PG_GETARG_BYTEA_PP(0);
5867 
5868  init_var(&tmp_var);
5869 
5870  /*
5871  * Copy the bytea into a StringInfo so that we can "receive" it using the
5872  * standard recv-function infrastructure.
5873  */
5874  initStringInfo(&buf);
5876  VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
5877 
5878  result = makePolyNumAggStateCurrentContext(false);
5879 
5880  /* N */
5881  result->N = pq_getmsgint64(&buf);
5882 
5883  /* sumX */
5884  numericvar_deserialize(&buf, &tmp_var);
5885 #ifdef HAVE_INT128
5886  numericvar_to_int128(&tmp_var, &result->sumX);
5887 #else
5888  accum_sum_add(&result->sumX, &tmp_var);
5889 #endif
5890 
5891  pq_getmsgend(&buf);
5892  pfree(buf.data);
5893 
5894  free_var(&tmp_var);
5895 
5896  PG_RETURN_POINTER(result);
5897 }
static void numericvar_deserialize(StringInfo buf, NumericVar *var)
Definition: numeric.c:7670
#define makePolyNumAggStateCurrentContext
Definition: numeric.c:5472
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:308
void pq_getmsgend(StringInfo msg)
Definition: pqformat.c:638
int64 pq_getmsgint64(StringInfo msg)
Definition: pqformat.c:456
void appendBinaryStringInfo(StringInfo str, const void *data, int datalen)
Definition: stringinfo.c:227
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Definition: c.h:671
#define VARDATA_ANY(PTR)
Definition: varatt.h:324
#define VARSIZE_ANY_EXHDR(PTR)
Definition: varatt.h:317

References accum_sum_add(), AggCheckCallContext(), appendBinaryStringInfo(), buf, elog(), ERROR, free_var(), init_var, initStringInfo(), makePolyNumAggStateCurrentContext, NumericAggState::N, numericvar_deserialize(), pfree(), PG_GETARG_BYTEA_PP, PG_RETURN_POINTER, pq_getmsgend(), pq_getmsgint64(), NumericAggState::sumX, VARDATA_ANY, and VARSIZE_ANY_EXHDR.