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

◆ makePolyNumAggStateCurrentContext

#define makePolyNumAggStateCurrentContext   makeNumericAggStateCurrentContext

Definition at line 5421 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 4680 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 5419 of file numeric.c.

Function Documentation

◆ accum_sum_add()

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

Definition at line 11626 of file numeric.c.

11627 {
11628  int32 *accum_digits;
11629  int i,
11630  val_i;
11631  int val_ndigits;
11632  NumericDigit *val_digits;
11633 
11634  /*
11635  * If we have accumulated too many values since the last carry
11636  * propagation, do it now, to avoid overflowing. (We could allow more
11637  * than NBASE - 1, if we reserved two extra digits, rather than one, for
11638  * carry propagation. But even with NBASE - 1, this needs to be done so
11639  * seldom, that the performance difference is negligible.)
11640  */
11641  if (accum->num_uncarried == NBASE - 1)
11642  accum_sum_carry(accum);
11643 
11644  /*
11645  * Adjust the weight or scale of the old value, so that it can accommodate
11646  * the new value.
11647  */
11648  accum_sum_rescale(accum, val);
11649 
11650  /* */
11651  if (val->sign == NUMERIC_POS)
11652  accum_digits = accum->pos_digits;
11653  else
11654  accum_digits = accum->neg_digits;
11655 
11656  /* copy these values into local vars for speed in loop */
11657  val_ndigits = val->ndigits;
11658  val_digits = val->digits;
11659 
11660  i = accum->weight - val->weight;
11661  for (val_i = 0; val_i < val_ndigits; val_i++)
11662  {
11663  accum_digits[i] += (int32) val_digits[val_i];
11664  i++;
11665  }
11666 
11667  accum->num_uncarried++;
11668 }
static void accum_sum_carry(NumericSumAccum *accum)
Definition: numeric.c:11674
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:11747
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 11674 of file numeric.c.

11675 {
11676  int i;
11677  int ndigits;
11678  int32 *dig;
11679  int32 carry;
11680  int32 newdig = 0;
11681 
11682  /*
11683  * If no new values have been added since last carry propagation, nothing
11684  * to do.
11685  */
11686  if (accum->num_uncarried == 0)
11687  return;
11688 
11689  /*
11690  * We maintain that the weight of the accumulator is always one larger
11691  * than needed to hold the current value, before carrying, to make sure
11692  * there is enough space for the possible extra digit when carry is
11693  * propagated. We cannot expand the buffer here, unless we require
11694  * callers of accum_sum_final() to switch to the right memory context.
11695  */
11696  Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0);
11697 
11698  ndigits = accum->ndigits;
11699 
11700  /* Propagate carry in the positive sum */
11701  dig = accum->pos_digits;
11702  carry = 0;
11703  for (i = ndigits - 1; i >= 0; i--)
11704  {
11705  newdig = dig[i] + carry;
11706  if (newdig >= NBASE)
11707  {
11708  carry = newdig / NBASE;
11709  newdig -= carry * NBASE;
11710  }
11711  else
11712  carry = 0;
11713  dig[i] = newdig;
11714  }
11715  /* Did we use up the digit reserved for carry propagation? */
11716  if (newdig > 0)
11717  accum->have_carry_space = false;
11718 
11719  /* And the same for the negative sum */
11720  dig = accum->neg_digits;
11721  carry = 0;
11722  for (i = ndigits - 1; i >= 0; i--)
11723  {
11724  newdig = dig[i] + carry;
11725  if (newdig >= NBASE)
11726  {
11727  carry = newdig / NBASE;
11728  newdig -= carry * NBASE;
11729  }
11730  else
11731  carry = 0;
11732  dig[i] = newdig;
11733  }
11734  if (newdig > 0)
11735  accum->have_carry_space = false;
11736 
11737  accum->num_uncarried = 0;
11738 }
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 11904 of file numeric.c.

11905 {
11906  NumericVar tmp_var;
11907 
11908  init_var(&tmp_var);
11909 
11910  accum_sum_final(accum2, &tmp_var);
11911  accum_sum_add(accum, &tmp_var);
11912 
11913  free_var(&tmp_var);
11914 }
static void accum_sum_final(NumericSumAccum *accum, NumericVar *result)
Definition: numeric.c:11836
static void free_var(NumericVar *var)
Definition: numeric.c:6848
static void accum_sum_add(NumericSumAccum *accum, const NumericVar *val)
Definition: numeric.c:11626
#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 11887 of file numeric.c.

11888 {
11889  dst->pos_digits = palloc(src->ndigits * sizeof(int32));
11890  dst->neg_digits = palloc(src->ndigits * sizeof(int32));
11891 
11892  memcpy(dst->pos_digits, src->pos_digits, src->ndigits * sizeof(int32));
11893  memcpy(dst->neg_digits, src->neg_digits, src->ndigits * sizeof(int32));
11894  dst->num_uncarried = src->num_uncarried;
11895  dst->ndigits = src->ndigits;
11896  dst->weight = src->weight;
11897  dst->dscale = src->dscale;
11898 }
void * palloc(Size size)
Definition: mcxt.c:1210

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

11837 {
11838  int i;
11839  NumericVar pos_var;
11840  NumericVar neg_var;
11841 
11842  if (accum->ndigits == 0)
11843  {
11844  set_var_from_var(&const_zero, result);
11845  return;
11846  }
11847 
11848  /* Perform final carry */
11849  accum_sum_carry(accum);
11850 
11851  /* Create NumericVars representing the positive and negative sums */
11852  init_var(&pos_var);
11853  init_var(&neg_var);
11854 
11855  pos_var.ndigits = neg_var.ndigits = accum->ndigits;
11856  pos_var.weight = neg_var.weight = accum->weight;
11857  pos_var.dscale = neg_var.dscale = accum->dscale;
11858  pos_var.sign = NUMERIC_POS;
11859  neg_var.sign = NUMERIC_NEG;
11860 
11861  pos_var.buf = pos_var.digits = digitbuf_alloc(accum->ndigits);
11862  neg_var.buf = neg_var.digits = digitbuf_alloc(accum->ndigits);
11863 
11864  for (i = 0; i < accum->ndigits; i++)
11865  {
11866  Assert(accum->pos_digits[i] < NBASE);
11867  pos_var.digits[i] = (int16) accum->pos_digits[i];
11868 
11869  Assert(accum->neg_digits[i] < NBASE);
11870  neg_var.digits[i] = (int16) accum->neg_digits[i];
11871  }
11872 
11873  /* And add them together */
11874  add_var(&pos_var, &neg_var, result);
11875 
11876  /* Remove leading/trailing zeroes */
11877  strip_var(result);
11878 }
static void add_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:8250
#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:7287
static void strip_var(NumericVar *var)
Definition: numeric.c:11569
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 11747 of file numeric.c.

11748 {
11749  int old_weight = accum->weight;
11750  int old_ndigits = accum->ndigits;
11751  int accum_ndigits;
11752  int accum_weight;
11753  int accum_rscale;
11754  int val_rscale;
11755 
11756  accum_weight = old_weight;
11757  accum_ndigits = old_ndigits;
11758 
11759  /*
11760  * Does the new value have a larger weight? If so, enlarge the buffers,
11761  * and shift the existing value to the new weight, by adding leading
11762  * zeros.
11763  *
11764  * We enforce that the accumulator always has a weight one larger than
11765  * needed for the inputs, so that we have space for an extra digit at the
11766  * final carry-propagation phase, if necessary.
11767  */
11768  if (val->weight >= accum_weight)
11769  {
11770  accum_weight = val->weight + 1;
11771  accum_ndigits = accum_ndigits + (accum_weight - old_weight);
11772  }
11773 
11774  /*
11775  * Even though the new value is small, we might've used up the space
11776  * reserved for the carry digit in the last call to accum_sum_carry(). If
11777  * so, enlarge to make room for another one.
11778  */
11779  else if (!accum->have_carry_space)
11780  {
11781  accum_weight++;
11782  accum_ndigits++;
11783  }
11784 
11785  /* Is the new value wider on the right side? */
11786  accum_rscale = accum_ndigits - accum_weight - 1;
11787  val_rscale = val->ndigits - val->weight - 1;
11788  if (val_rscale > accum_rscale)
11789  accum_ndigits = accum_ndigits + (val_rscale - accum_rscale);
11790 
11791  if (accum_ndigits != old_ndigits ||
11792  accum_weight != old_weight)
11793  {
11794  int32 *new_pos_digits;
11795  int32 *new_neg_digits;
11796  int weightdiff;
11797 
11798  weightdiff = accum_weight - old_weight;
11799 
11800  new_pos_digits = palloc0(accum_ndigits * sizeof(int32));
11801  new_neg_digits = palloc0(accum_ndigits * sizeof(int32));
11802 
11803  if (accum->pos_digits)
11804  {
11805  memcpy(&new_pos_digits[weightdiff], accum->pos_digits,
11806  old_ndigits * sizeof(int32));
11807  pfree(accum->pos_digits);
11808 
11809  memcpy(&new_neg_digits[weightdiff], accum->neg_digits,
11810  old_ndigits * sizeof(int32));
11811  pfree(accum->neg_digits);
11812  }
11813 
11814  accum->pos_digits = new_pos_digits;
11815  accum->neg_digits = new_neg_digits;
11816 
11817  accum->weight = accum_weight;
11818  accum->ndigits = accum_ndigits;
11819 
11820  Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0);
11821  accum->have_carry_space = true;
11822  }
11823 
11824  if (val->dscale > accum->dscale)
11825  accum->dscale = val->dscale;
11826 }
void pfree(void *pointer)
Definition: mcxt.c:1436
void * palloc0(Size size)
Definition: mcxt.c:1241

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

11611 {
11612  int i;
11613 
11614  accum->dscale = 0;
11615  for (i = 0; i < accum->ndigits; i++)
11616  {
11617  accum->pos_digits[i] = 0;
11618  accum->neg_digits[i] = 0;
11619  }
11620 }

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

11235 {
11236  NumericDigit *res_buf;
11237  NumericDigit *res_digits;
11238  int res_ndigits;
11239  int res_weight;
11240  int res_rscale,
11241  rscale1,
11242  rscale2;
11243  int res_dscale;
11244  int i,
11245  i1,
11246  i2;
11247  int carry = 0;
11248 
11249  /* copy these values into local vars for speed in inner loop */
11250  int var1ndigits = var1->ndigits;
11251  int var2ndigits = var2->ndigits;
11252  NumericDigit *var1digits = var1->digits;
11253  NumericDigit *var2digits = var2->digits;
11254 
11255  res_weight = Max(var1->weight, var2->weight) + 1;
11256 
11257  res_dscale = Max(var1->dscale, var2->dscale);
11258 
11259  /* Note: here we are figuring rscale in base-NBASE digits */
11260  rscale1 = var1->ndigits - var1->weight - 1;
11261  rscale2 = var2->ndigits - var2->weight - 1;
11262  res_rscale = Max(rscale1, rscale2);
11263 
11264  res_ndigits = res_rscale + res_weight + 1;
11265  if (res_ndigits <= 0)
11266  res_ndigits = 1;
11267 
11268  res_buf = digitbuf_alloc(res_ndigits + 1);
11269  res_buf[0] = 0; /* spare digit for later rounding */
11270  res_digits = res_buf + 1;
11271 
11272  i1 = res_rscale + var1->weight + 1;
11273  i2 = res_rscale + var2->weight + 1;
11274  for (i = res_ndigits - 1; i >= 0; i--)
11275  {
11276  i1--;
11277  i2--;
11278  if (i1 >= 0 && i1 < var1ndigits)
11279  carry += var1digits[i1];
11280  if (i2 >= 0 && i2 < var2ndigits)
11281  carry += var2digits[i2];
11282 
11283  if (carry >= NBASE)
11284  {
11285  res_digits[i] = carry - NBASE;
11286  carry = 1;
11287  }
11288  else
11289  {
11290  res_digits[i] = carry;
11291  carry = 0;
11292  }
11293  }
11294 
11295  Assert(carry == 0); /* else we failed to allow for carry out */
11296 
11297  digitbuf_free(result->buf);
11298  result->ndigits = res_ndigits;
11299  result->buf = res_buf;
11300  result->digits = res_digits;
11301  result->weight = res_weight;
11302  result->dscale = res_dscale;
11303 
11304  /* Remove leading/trailing zeroes */
11305  strip_var(result);
11306 }
#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 8250 of file numeric.c.

8251 {
8252  /*
8253  * Decide on the signs of the two variables what to do
8254  */
8255  if (var1->sign == NUMERIC_POS)
8256  {
8257  if (var2->sign == NUMERIC_POS)
8258  {
8259  /*
8260  * Both are positive result = +(ABS(var1) + ABS(var2))
8261  */
8262  add_abs(var1, var2, result);
8263  result->sign = NUMERIC_POS;
8264  }
8265  else
8266  {
8267  /*
8268  * var1 is positive, var2 is negative Must compare absolute values
8269  */
8270  switch (cmp_abs(var1, var2))
8271  {
8272  case 0:
8273  /* ----------
8274  * ABS(var1) == ABS(var2)
8275  * result = ZERO
8276  * ----------
8277  */
8278  zero_var(result);
8279  result->dscale = Max(var1->dscale, var2->dscale);
8280  break;
8281 
8282  case 1:
8283  /* ----------
8284  * ABS(var1) > ABS(var2)
8285  * result = +(ABS(var1) - ABS(var2))
8286  * ----------
8287  */
8288  sub_abs(var1, var2, result);
8289  result->sign = NUMERIC_POS;
8290  break;
8291 
8292  case -1:
8293  /* ----------
8294  * ABS(var1) < ABS(var2)
8295  * result = -(ABS(var2) - ABS(var1))
8296  * ----------
8297  */
8298  sub_abs(var2, var1, result);
8299  result->sign = NUMERIC_NEG;
8300  break;
8301  }
8302  }
8303  }
8304  else
8305  {
8306  if (var2->sign == NUMERIC_POS)
8307  {
8308  /* ----------
8309  * var1 is negative, var2 is positive
8310  * Must compare absolute values
8311  * ----------
8312  */
8313  switch (cmp_abs(var1, var2))
8314  {
8315  case 0:
8316  /* ----------
8317  * ABS(var1) == ABS(var2)
8318  * result = ZERO
8319  * ----------
8320  */
8321  zero_var(result);
8322  result->dscale = Max(var1->dscale, var2->dscale);
8323  break;
8324 
8325  case 1:
8326  /* ----------
8327  * ABS(var1) > ABS(var2)
8328  * result = -(ABS(var1) - ABS(var2))
8329  * ----------
8330  */
8331  sub_abs(var1, var2, result);
8332  result->sign = NUMERIC_NEG;
8333  break;
8334 
8335  case -1:
8336  /* ----------
8337  * ABS(var1) < ABS(var2)
8338  * result = +(ABS(var2) - ABS(var1))
8339  * ----------
8340  */
8341  sub_abs(var2, var1, result);
8342  result->sign = NUMERIC_POS;
8343  break;
8344  }
8345  }
8346  else
8347  {
8348  /* ----------
8349  * Both are negative
8350  * result = -(ABS(var1) + ABS(var2))
8351  * ----------
8352  */
8353  add_abs(var1, var2, result);
8354  result->sign = NUMERIC_NEG;
8355  }
8356  }
8357 }
static void sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:11319
static void add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:11234
static void zero_var(NumericVar *var)
Definition: numeric.c:6864
static int cmp_abs(const NumericVar *var1, const NumericVar *var2)
Definition: numeric.c:11156

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

6833 {
6834  digitbuf_free(var->buf);
6835  var->buf = digitbuf_alloc(ndigits + 1);
6836  var->buf[0] = 0; /* spare digit for rounding */
6837  var->digits = var->buf + 1;
6838  var->ndigits = ndigits;
6839 }

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

7727 {
7728  int precision;
7729  int scale;
7730  int maxdigits;
7731  int ddigits;
7732  int i;
7733 
7734  /* Do nothing if we have an invalid typmod */
7735  if (!is_valid_numeric_typmod(typmod))
7736  return true;
7737 
7738  precision = numeric_typmod_precision(typmod);
7739  scale = numeric_typmod_scale(typmod);
7740  maxdigits = precision - scale;
7741 
7742  /* Round to target scale (and set var->dscale) */
7743  round_var(var, scale);
7744 
7745  /* but don't allow var->dscale to be negative */
7746  if (var->dscale < 0)
7747  var->dscale = 0;
7748 
7749  /*
7750  * Check for overflow - note we can't do this before rounding, because
7751  * rounding could raise the weight. Also note that the var's weight could
7752  * be inflated by leading zeroes, which will be stripped before storage
7753  * but perhaps might not have been yet. In any case, we must recognize a
7754  * true zero, whose weight doesn't mean anything.
7755  */
7756  ddigits = (var->weight + 1) * DEC_DIGITS;
7757  if (ddigits > maxdigits)
7758  {
7759  /* Determine true weight; and check for all-zero result */
7760  for (i = 0; i < var->ndigits; i++)
7761  {
7762  NumericDigit dig = var->digits[i];
7763 
7764  if (dig)
7765  {
7766  /* Adjust for any high-order decimal zero digits */
7767 #if DEC_DIGITS == 4
7768  if (dig < 10)
7769  ddigits -= 3;
7770  else if (dig < 100)
7771  ddigits -= 2;
7772  else if (dig < 1000)
7773  ddigits -= 1;
7774 #elif DEC_DIGITS == 2
7775  if (dig < 10)
7776  ddigits -= 1;
7777 #elif DEC_DIGITS == 1
7778  /* no adjustment */
7779 #else
7780 #error unsupported NBASE
7781 #endif
7782  if (ddigits > maxdigits)
7783  ereturn(escontext, false,
7784  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7785  errmsg("numeric field overflow"),
7786  errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.",
7787  precision, scale,
7788  /* Display 10^0 as 1 */
7789  maxdigits ? "10^" : "",
7790  maxdigits ? maxdigits : 1
7791  )));
7792  break;
7793  }
7794  ddigits -= DEC_DIGITS;
7795  }
7796  }
7797 
7798  return true;
7799 }
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:11401
#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 7811 of file numeric.c.

7812 {
7813  int precision;
7814  int scale;
7815 
7816  Assert(NUMERIC_IS_SPECIAL(num)); /* caller error if not */
7817 
7818  /*
7819  * NaN is allowed regardless of the typmod; that's rather dubious perhaps,
7820  * but it's a longstanding behavior. Inf is rejected if we have any
7821  * typmod restriction, since an infinity shouldn't be claimed to fit in
7822  * any finite number of digits.
7823  */
7824  if (NUMERIC_IS_NAN(num))
7825  return true;
7826 
7827  /* Do nothing if we have a default typmod (-1) */
7828  if (!is_valid_numeric_typmod(typmod))
7829  return true;
7830 
7831  precision = numeric_typmod_precision(typmod);
7832  scale = numeric_typmod_scale(typmod);
7833 
7834  ereturn(escontext, false,
7835  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7836  errmsg("numeric field overflow"),
7837  errdetail("A field with precision %d, scale %d cannot hold an infinite value.",
7838  precision, scale)));
7839 }
#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 9764 of file numeric.c.

9765 {
9766  NumericVar tmp;
9767 
9768  init_var(&tmp);
9769  set_var_from_var(var, &tmp);
9770 
9771  trunc_var(&tmp, 0);
9772 
9773  if (var->sign == NUMERIC_POS && cmp_var(var, &tmp) != 0)
9774  add_var(&tmp, &const_one, &tmp);
9775 
9776  set_var_from_var(&tmp, result);
9777  free_var(&tmp);
9778 }
static void trunc_var(NumericVar *var, int rscale)
Definition: numeric.c:11507
static int cmp_var(const NumericVar *var1, const NumericVar *var2)
Definition: numeric.c:8192
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 11156 of file numeric.c.

11157 {
11158  return cmp_abs_common(var1->digits, var1->ndigits, var1->weight,
11159  var2->digits, var2->ndigits, var2->weight);
11160 }
static int cmp_abs_common(const NumericDigit *var1digits, int var1ndigits, int var1weight, const NumericDigit *var2digits, int var2ndigits, int var2weight)
Definition: numeric.c:11170

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

11172 {
11173  int i1 = 0;
11174  int i2 = 0;
11175 
11176  /* Check any digits before the first common digit */
11177 
11178  while (var1weight > var2weight && i1 < var1ndigits)
11179  {
11180  if (var1digits[i1++] != 0)
11181  return 1;
11182  var1weight--;
11183  }
11184  while (var2weight > var1weight && i2 < var2ndigits)
11185  {
11186  if (var2digits[i2++] != 0)
11187  return -1;
11188  var2weight--;
11189  }
11190 
11191  /* At this point, either w1 == w2 or we've run out of digits */
11192 
11193  if (var1weight == var2weight)
11194  {
11195  while (i1 < var1ndigits && i2 < var2ndigits)
11196  {
11197  int stat = var1digits[i1++] - var2digits[i2++];
11198 
11199  if (stat)
11200  {
11201  if (stat > 0)
11202  return 1;
11203  return -1;
11204  }
11205  }
11206  }
11207 
11208  /*
11209  * At this point, we've run out of digits on one side or the other; so any
11210  * remaining nonzero digits imply that side is larger
11211  */
11212  while (i1 < var1ndigits)
11213  {
11214  if (var1digits[i1++] != 0)
11215  return 1;
11216  }
11217  while (i2 < var2ndigits)
11218  {
11219  if (var2digits[i2++] != 0)
11220  return -1;
11221  }
11222 
11223  return 0;
11224 }

Referenced by cmp_abs(), and cmp_var_common().

◆ cmp_numerics()

static int cmp_numerics ( Numeric  num1,
Numeric  num2 
)
static

Definition at line 2493 of file numeric.c.

2494 {
2495  int result;
2496 
2497  /*
2498  * We consider all NANs to be equal and larger than any non-NAN (including
2499  * Infinity). This is somewhat arbitrary; the important thing is to have
2500  * a consistent sort order.
2501  */
2502  if (NUMERIC_IS_SPECIAL(num1))
2503  {
2504  if (NUMERIC_IS_NAN(num1))
2505  {
2506  if (NUMERIC_IS_NAN(num2))
2507  result = 0; /* NAN = NAN */
2508  else
2509  result = 1; /* NAN > non-NAN */
2510  }
2511  else if (NUMERIC_IS_PINF(num1))
2512  {
2513  if (NUMERIC_IS_NAN(num2))
2514  result = -1; /* PINF < NAN */
2515  else if (NUMERIC_IS_PINF(num2))
2516  result = 0; /* PINF = PINF */
2517  else
2518  result = 1; /* PINF > anything else */
2519  }
2520  else /* num1 must be NINF */
2521  {
2522  if (NUMERIC_IS_NINF(num2))
2523  result = 0; /* NINF = NINF */
2524  else
2525  result = -1; /* NINF < anything else */
2526  }
2527  }
2528  else if (NUMERIC_IS_SPECIAL(num2))
2529  {
2530  if (NUMERIC_IS_NINF(num2))
2531  result = 1; /* normal > NINF */
2532  else
2533  result = -1; /* normal < NAN or PINF */
2534  }
2535  else
2536  {
2537  result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1),
2538  NUMERIC_WEIGHT(num1), NUMERIC_SIGN(num1),
2539  NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2),
2540  NUMERIC_WEIGHT(num2), NUMERIC_SIGN(num2));
2541  }
2542 
2543  return result;
2544 }
#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:8207

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

8211 {
8212  if (var1ndigits == 0)
8213  {
8214  if (var2ndigits == 0)
8215  return 0;
8216  if (var2sign == NUMERIC_NEG)
8217  return 1;
8218  return -1;
8219  }
8220  if (var2ndigits == 0)
8221  {
8222  if (var1sign == NUMERIC_POS)
8223  return 1;
8224  return -1;
8225  }
8226 
8227  if (var1sign == NUMERIC_POS)
8228  {
8229  if (var2sign == NUMERIC_NEG)
8230  return 1;
8231  return cmp_abs_common(var1digits, var1ndigits, var1weight,
8232  var2digits, var2ndigits, var2weight);
8233  }
8234 
8235  if (var2sign == NUMERIC_POS)
8236  return -1;
8237 
8238  return cmp_abs_common(var2digits, var2ndigits, var2weight,
8239  var1digits, var1ndigits, var1weight);
8240 }

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  add_var(result_var, &const_one, result_var);
1944  floor_var(result_var, result_var);
1945 
1946  free_var(&bound1_var);
1947  free_var(&bound2_var);
1948  free_var(&operand_var);
1949 }
static void sub_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:8367
static void floor_var(const NumericVar *var, NumericVar *result)
Definition: numeric.c:9788
static void init_var_from_num(Numeric num, NumericVar *dest)
Definition: numeric.c:7270
static void mul_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale)
Definition: numeric.c:8488
static int select_div_scale(const NumericVar *var1, const NumericVar *var2)
Definition: numeric.c:9596
static void div_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale, bool round)
Definition: numeric.c:8696

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

Referenced by width_bucket_numeric().

◆ div_mod_var()

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

Definition at line 9694 of file numeric.c.

9696 {
9697  NumericVar q;
9698  NumericVar r;
9699 
9700  init_var(&q);
9701  init_var(&r);
9702 
9703  /*
9704  * Use div_var_fast() to get an initial estimate for the integer quotient.
9705  * This might be inaccurate (per the warning in div_var_fast's comments),
9706  * but we can correct it below.
9707  */
9708  div_var_fast(var1, var2, &q, 0, false);
9709 
9710  /* Compute initial estimate of remainder using the quotient estimate. */
9711  mul_var(var2, &q, &r, var2->dscale);
9712  sub_var(var1, &r, &r);
9713 
9714  /*
9715  * Adjust the results if necessary --- the remainder should have the same
9716  * sign as var1, and its absolute value should be less than the absolute
9717  * value of var2.
9718  */
9719  while (r.ndigits != 0 && r.sign != var1->sign)
9720  {
9721  /* The absolute value of the quotient is too large */
9722  if (var1->sign == var2->sign)
9723  {
9724  sub_var(&q, &const_one, &q);
9725  add_var(&r, var2, &r);
9726  }
9727  else
9728  {
9729  add_var(&q, &const_one, &q);
9730  sub_var(&r, var2, &r);
9731  }
9732  }
9733 
9734  while (cmp_abs(&r, var2) >= 0)
9735  {
9736  /* The absolute value of the quotient is too small */
9737  if (var1->sign == var2->sign)
9738  {
9739  add_var(&q, &const_one, &q);
9740  sub_var(&r, var2, &r);
9741  }
9742  else
9743  {
9744  sub_var(&q, &const_one, &q);
9745  add_var(&r, var2, &r);
9746  }
9747  }
9748 
9749  set_var_from_var(&q, quot);
9750  set_var_from_var(&r, rem);
9751 
9752  free_var(&q);
9753  free_var(&r);
9754 }
static void div_var_fast(const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale, bool round)
Definition: numeric.c:9004

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

8698 {
8699  int div_ndigits;
8700  int res_ndigits;
8701  int res_sign;
8702  int res_weight;
8703  int carry;
8704  int borrow;
8705  int divisor1;
8706  int divisor2;
8707  NumericDigit *dividend;
8708  NumericDigit *divisor;
8709  NumericDigit *res_digits;
8710  int i;
8711  int j;
8712 
8713  /* copy these values into local vars for speed in inner loop */
8714  int var1ndigits = var1->ndigits;
8715  int var2ndigits = var2->ndigits;
8716 
8717  /*
8718  * First of all division by zero check; we must not be handed an
8719  * unnormalized divisor.
8720  */
8721  if (var2ndigits == 0 || var2->digits[0] == 0)
8722  ereport(ERROR,
8723  (errcode(ERRCODE_DIVISION_BY_ZERO),
8724  errmsg("division by zero")));
8725 
8726  /*
8727  * If the divisor has just one or two digits, delegate to div_var_int(),
8728  * which uses fast short division.
8729  *
8730  * Similarly, on platforms with 128-bit integer support, delegate to
8731  * div_var_int64() for divisors with three or four digits.
8732  */
8733  if (var2ndigits <= 2)
8734  {
8735  int idivisor;
8736  int idivisor_weight;
8737 
8738  idivisor = var2->digits[0];
8739  idivisor_weight = var2->weight;
8740  if (var2ndigits == 2)
8741  {
8742  idivisor = idivisor * NBASE + var2->digits[1];
8743  idivisor_weight--;
8744  }
8745  if (var2->sign == NUMERIC_NEG)
8746  idivisor = -idivisor;
8747 
8748  div_var_int(var1, idivisor, idivisor_weight, result, rscale, round);
8749  return;
8750  }
8751 #ifdef HAVE_INT128
8752  if (var2ndigits <= 4)
8753  {
8754  int64 idivisor;
8755  int idivisor_weight;
8756 
8757  idivisor = var2->digits[0];
8758  idivisor_weight = var2->weight;
8759  for (i = 1; i < var2ndigits; i++)
8760  {
8761  idivisor = idivisor * NBASE + var2->digits[i];
8762  idivisor_weight--;
8763  }
8764  if (var2->sign == NUMERIC_NEG)
8765  idivisor = -idivisor;
8766 
8767  div_var_int64(var1, idivisor, idivisor_weight, result, rscale, round);
8768  return;
8769  }
8770 #endif
8771 
8772  /*
8773  * Otherwise, perform full long division.
8774  */
8775 
8776  /* Result zero check */
8777  if (var1ndigits == 0)
8778  {
8779  zero_var(result);
8780  result->dscale = rscale;
8781  return;
8782  }
8783 
8784  /*
8785  * Determine the result sign, weight and number of digits to calculate.
8786  * The weight figured here is correct if the emitted quotient has no
8787  * leading zero digits; otherwise strip_var() will fix things up.
8788  */
8789  if (var1->sign == var2->sign)
8790  res_sign = NUMERIC_POS;
8791  else
8792  res_sign = NUMERIC_NEG;
8793  res_weight = var1->weight - var2->weight;
8794  /* The number of accurate result digits we need to produce: */
8795  res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
8796  /* ... but always at least 1 */
8797  res_ndigits = Max(res_ndigits, 1);
8798  /* If rounding needed, figure one more digit to ensure correct result */
8799  if (round)
8800  res_ndigits++;
8801 
8802  /*
8803  * The working dividend normally requires res_ndigits + var2ndigits
8804  * digits, but make it at least var1ndigits so we can load all of var1
8805  * into it. (There will be an additional digit dividend[0] in the
8806  * dividend space, but for consistency with Knuth's notation we don't
8807  * count that in div_ndigits.)
8808  */
8809  div_ndigits = res_ndigits + var2ndigits;
8810  div_ndigits = Max(div_ndigits, var1ndigits);
8811 
8812  /*
8813  * We need a workspace with room for the working dividend (div_ndigits+1
8814  * digits) plus room for the possibly-normalized divisor (var2ndigits
8815  * digits). It is convenient also to have a zero at divisor[0] with the
8816  * actual divisor data in divisor[1 .. var2ndigits]. Transferring the
8817  * digits into the workspace also allows us to realloc the result (which
8818  * might be the same as either input var) before we begin the main loop.
8819  * Note that we use palloc0 to ensure that divisor[0], dividend[0], and
8820  * any additional dividend positions beyond var1ndigits, start out 0.
8821  */
8822  dividend = (NumericDigit *)
8823  palloc0((div_ndigits + var2ndigits + 2) * sizeof(NumericDigit));
8824  divisor = dividend + (div_ndigits + 1);
8825  memcpy(dividend + 1, var1->digits, var1ndigits * sizeof(NumericDigit));
8826  memcpy(divisor + 1, var2->digits, var2ndigits * sizeof(NumericDigit));
8827 
8828  /*
8829  * Now we can realloc the result to hold the generated quotient digits.
8830  */
8831  alloc_var(result, res_ndigits);
8832  res_digits = result->digits;
8833 
8834  /*
8835  * The full multiple-place algorithm is taken from Knuth volume 2,
8836  * Algorithm 4.3.1D.
8837  *
8838  * We need the first divisor digit to be >= NBASE/2. If it isn't, make it
8839  * so by scaling up both the divisor and dividend by the factor "d". (The
8840  * reason for allocating dividend[0] above is to leave room for possible
8841  * carry here.)
8842  */
8843  if (divisor[1] < HALF_NBASE)
8844  {
8845  int d = NBASE / (divisor[1] + 1);
8846 
8847  carry = 0;
8848  for (i = var2ndigits; i > 0; i--)
8849  {
8850  carry += divisor[i] * d;
8851  divisor[i] = carry % NBASE;
8852  carry = carry / NBASE;
8853  }
8854  Assert(carry == 0);
8855  carry = 0;
8856  /* at this point only var1ndigits of dividend can be nonzero */
8857  for (i = var1ndigits; i >= 0; i--)
8858  {
8859  carry += dividend[i] * d;
8860  dividend[i] = carry % NBASE;
8861  carry = carry / NBASE;
8862  }
8863  Assert(carry == 0);
8864  Assert(divisor[1] >= HALF_NBASE);
8865  }
8866  /* First 2 divisor digits are used repeatedly in main loop */
8867  divisor1 = divisor[1];
8868  divisor2 = divisor[2];
8869 
8870  /*
8871  * Begin the main loop. Each iteration of this loop produces the j'th
8872  * quotient digit by dividing dividend[j .. j + var2ndigits] by the
8873  * divisor; this is essentially the same as the common manual procedure
8874  * for long division.
8875  */
8876  for (j = 0; j < res_ndigits; j++)
8877  {
8878  /* Estimate quotient digit from the first two dividend digits */
8879  int next2digits = dividend[j] * NBASE + dividend[j + 1];
8880  int qhat;
8881 
8882  /*
8883  * If next2digits are 0, then quotient digit must be 0 and there's no
8884  * need to adjust the working dividend. It's worth testing here to
8885  * fall out ASAP when processing trailing zeroes in a dividend.
8886  */
8887  if (next2digits == 0)
8888  {
8889  res_digits[j] = 0;
8890  continue;
8891  }
8892 
8893  if (dividend[j] == divisor1)
8894  qhat = NBASE - 1;
8895  else
8896  qhat = next2digits / divisor1;
8897 
8898  /*
8899  * Adjust quotient digit if it's too large. Knuth proves that after
8900  * this step, the quotient digit will be either correct or just one
8901  * too large. (Note: it's OK to use dividend[j+2] here because we
8902  * know the divisor length is at least 2.)
8903  */
8904  while (divisor2 * qhat >
8905  (next2digits - qhat * divisor1) * NBASE + dividend[j + 2])
8906  qhat--;
8907 
8908  /* As above, need do nothing more when quotient digit is 0 */
8909  if (qhat > 0)
8910  {
8911  NumericDigit *dividend_j = &dividend[j];
8912 
8913  /*
8914  * Multiply the divisor by qhat, and subtract that from the
8915  * working dividend. The multiplication and subtraction are
8916  * folded together here, noting that qhat <= NBASE (since it might
8917  * be one too large), and so the intermediate result "tmp_result"
8918  * is in the range [-NBASE^2, NBASE - 1], and "borrow" is in the
8919  * range [0, NBASE].
8920  */
8921  borrow = 0;
8922  for (i = var2ndigits; i >= 0; i--)
8923  {
8924  int tmp_result;
8925 
8926  tmp_result = dividend_j[i] - borrow - divisor[i] * qhat;
8927  borrow = (NBASE - 1 - tmp_result) / NBASE;
8928  dividend_j[i] = tmp_result + borrow * NBASE;
8929  }
8930 
8931  /*
8932  * If we got a borrow out of the top dividend digit, then indeed
8933  * qhat was one too large. Fix it, and add back the divisor to
8934  * correct the working dividend. (Knuth proves that this will
8935  * occur only about 3/NBASE of the time; hence, it's a good idea
8936  * to test this code with small NBASE to be sure this section gets
8937  * exercised.)
8938  */
8939  if (borrow)
8940  {
8941  qhat--;
8942  carry = 0;
8943  for (i = var2ndigits; i >= 0; i--)
8944  {
8945  carry += dividend_j[i] + divisor[i];
8946  if (carry >= NBASE)
8947  {
8948  dividend_j[i] = carry - NBASE;
8949  carry = 1;
8950  }
8951  else
8952  {
8953  dividend_j[i] = carry;
8954  carry = 0;
8955  }
8956  }
8957  /* A carry should occur here to cancel the borrow above */
8958  Assert(carry == 1);
8959  }
8960  }
8961 
8962  /* And we're done with this quotient digit */
8963  res_digits[j] = qhat;
8964  }
8965 
8966  pfree(dividend);
8967 
8968  /*
8969  * Finally, round or truncate the result to the requested precision.
8970  */
8971  result->weight = res_weight;
8972  result->sign = res_sign;
8973 
8974  /* Round or truncate to target rscale (and set result->dscale) */
8975  if (round)
8976  round_var(result, rscale);
8977  else
8978  trunc_var(result, rscale);
8979 
8980  /* Strip leading and trailing zeroes */
8981  strip_var(result);
8982 }
static void div_var_int(const NumericVar *var, int ival, int ival_weight, NumericVar *result, int rscale, bool round)
Definition: numeric.c:9368
static void alloc_var(NumericVar *var, int ndigits)
Definition: numeric.c:6832
#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 9004 of file numeric.c.

9006 {
9007  int div_ndigits;
9008  int load_ndigits;
9009  int res_sign;
9010  int res_weight;
9011  int *div;
9012  int qdigit;
9013  int carry;
9014  int maxdiv;
9015  int newdig;
9016  NumericDigit *res_digits;
9017  double fdividend,
9018  fdivisor,
9019  fdivisorinverse,
9020  fquotient;
9021  int qi;
9022  int i;
9023 
9024  /* copy these values into local vars for speed in inner loop */
9025  int var1ndigits = var1->ndigits;
9026  int var2ndigits = var2->ndigits;
9027  NumericDigit *var1digits = var1->digits;
9028  NumericDigit *var2digits = var2->digits;
9029 
9030  /*
9031  * First of all division by zero check; we must not be handed an
9032  * unnormalized divisor.
9033  */
9034  if (var2ndigits == 0 || var2digits[0] == 0)
9035  ereport(ERROR,
9036  (errcode(ERRCODE_DIVISION_BY_ZERO),
9037  errmsg("division by zero")));
9038 
9039  /*
9040  * If the divisor has just one or two digits, delegate to div_var_int(),
9041  * which uses fast short division.
9042  *
9043  * Similarly, on platforms with 128-bit integer support, delegate to
9044  * div_var_int64() for divisors with three or four digits.
9045  */
9046  if (var2ndigits <= 2)
9047  {
9048  int idivisor;
9049  int idivisor_weight;
9050 
9051  idivisor = var2->digits[0];
9052  idivisor_weight = var2->weight;
9053  if (var2ndigits == 2)
9054  {
9055  idivisor = idivisor * NBASE + var2->digits[1];
9056  idivisor_weight--;
9057  }
9058  if (var2->sign == NUMERIC_NEG)
9059  idivisor = -idivisor;
9060 
9061  div_var_int(var1, idivisor, idivisor_weight, result, rscale, round);
9062  return;
9063  }
9064 #ifdef HAVE_INT128
9065  if (var2ndigits <= 4)
9066  {
9067  int64 idivisor;
9068  int idivisor_weight;
9069 
9070  idivisor = var2->digits[0];
9071  idivisor_weight = var2->weight;
9072  for (i = 1; i < var2ndigits; i++)
9073  {
9074  idivisor = idivisor * NBASE + var2->digits[i];
9075  idivisor_weight--;
9076  }
9077  if (var2->sign == NUMERIC_NEG)
9078  idivisor = -idivisor;
9079 
9080  div_var_int64(var1, idivisor, idivisor_weight, result, rscale, round);
9081  return;
9082  }
9083 #endif
9084 
9085  /*
9086  * Otherwise, perform full long division.
9087  */
9088 
9089  /* Result zero check */
9090  if (var1ndigits == 0)
9091  {
9092  zero_var(result);
9093  result->dscale = rscale;
9094  return;
9095  }
9096 
9097  /*
9098  * Determine the result sign, weight and number of digits to calculate
9099  */
9100  if (var1->sign == var2->sign)
9101  res_sign = NUMERIC_POS;
9102  else
9103  res_sign = NUMERIC_NEG;
9104  res_weight = var1->weight - var2->weight + 1;
9105  /* The number of accurate result digits we need to produce: */
9106  div_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9107  /* Add guard digits for roundoff error */
9108  div_ndigits += DIV_GUARD_DIGITS;
9109  if (div_ndigits < DIV_GUARD_DIGITS)
9110  div_ndigits = DIV_GUARD_DIGITS;
9111 
9112  /*
9113  * We do the arithmetic in an array "div[]" of signed int's. Since
9114  * INT_MAX is noticeably larger than NBASE*NBASE, this gives us headroom
9115  * to avoid normalizing carries immediately.
9116  *
9117  * We start with div[] containing one zero digit followed by the
9118  * dividend's digits (plus appended zeroes to reach the desired precision
9119  * including guard digits). Each step of the main loop computes an
9120  * (approximate) quotient digit and stores it into div[], removing one
9121  * position of dividend space. A final pass of carry propagation takes
9122  * care of any mistaken quotient digits.
9123  *
9124  * Note that div[] doesn't necessarily contain all of the digits from the
9125  * dividend --- the desired precision plus guard digits might be less than
9126  * the dividend's precision. This happens, for example, in the square
9127  * root algorithm, where we typically divide a 2N-digit number by an
9128  * N-digit number, and only require a result with N digits of precision.
9129  */
9130  div = (int *) palloc0((div_ndigits + 1) * sizeof(int));
9131  load_ndigits = Min(div_ndigits, var1ndigits);
9132  for (i = 0; i < load_ndigits; i++)
9133  div[i + 1] = var1digits[i];
9134 
9135  /*
9136  * We estimate each quotient digit using floating-point arithmetic, taking
9137  * the first four digits of the (current) dividend and divisor. This must
9138  * be float to avoid overflow. The quotient digits will generally be off
9139  * by no more than one from the exact answer.
9140  */
9141  fdivisor = (double) var2digits[0];
9142  for (i = 1; i < 4; i++)
9143  {
9144  fdivisor *= NBASE;
9145  if (i < var2ndigits)
9146  fdivisor += (double) var2digits[i];
9147  }
9148  fdivisorinverse = 1.0 / fdivisor;
9149 
9150  /*
9151  * maxdiv tracks the maximum possible absolute value of any div[] entry;
9152  * when this threatens to exceed INT_MAX, we take the time to propagate
9153  * carries. Furthermore, we need to ensure that overflow doesn't occur
9154  * during the carry propagation passes either. The carry values may have
9155  * an absolute value as high as INT_MAX/NBASE + 1, so really we must
9156  * normalize when digits threaten to exceed INT_MAX - INT_MAX/NBASE - 1.
9157  *
9158  * To avoid overflow in maxdiv itself, it represents the max absolute
9159  * value divided by NBASE-1, ie, at the top of the loop it is known that
9160  * no div[] entry has an absolute value exceeding maxdiv * (NBASE-1).
9161  *
9162  * Actually, though, that holds good only for div[] entries after div[qi];
9163  * the adjustment done at the bottom of the loop may cause div[qi + 1] to
9164  * exceed the maxdiv limit, so that div[qi] in the next iteration is
9165  * beyond the limit. This does not cause problems, as explained below.
9166  */
9167  maxdiv = 1;
9168 
9169  /*
9170  * Outer loop computes next quotient digit, which will go into div[qi]
9171  */
9172  for (qi = 0; qi < div_ndigits; qi++)
9173  {
9174  /* Approximate the current dividend value */
9175  fdividend = (double) div[qi];
9176  for (i = 1; i < 4; i++)
9177  {
9178  fdividend *= NBASE;
9179  if (qi + i <= div_ndigits)
9180  fdividend += (double) div[qi + i];
9181  }
9182  /* Compute the (approximate) quotient digit */
9183  fquotient = fdividend * fdivisorinverse;
9184  qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
9185  (((int) fquotient) - 1); /* truncate towards -infinity */
9186 
9187  if (qdigit != 0)
9188  {
9189  /* Do we need to normalize now? */
9190  maxdiv += abs(qdigit);
9191  if (maxdiv > (INT_MAX - INT_MAX / NBASE - 1) / (NBASE - 1))
9192  {
9193  /*
9194  * Yes, do it. Note that if var2ndigits is much smaller than
9195  * div_ndigits, we can save a significant amount of effort
9196  * here by noting that we only need to normalise those div[]
9197  * entries touched where prior iterations subtracted multiples
9198  * of the divisor.
9199  */
9200  carry = 0;
9201  for (i = Min(qi + var2ndigits - 2, div_ndigits); i > qi; i--)
9202  {
9203  newdig = div[i] + carry;
9204  if (newdig < 0)
9205  {
9206  carry = -((-newdig - 1) / NBASE) - 1;
9207  newdig -= carry * NBASE;
9208  }
9209  else if (newdig >= NBASE)
9210  {
9211  carry = newdig / NBASE;
9212  newdig -= carry * NBASE;
9213  }
9214  else
9215  carry = 0;
9216  div[i] = newdig;
9217  }
9218  newdig = div[qi] + carry;
9219  div[qi] = newdig;
9220 
9221  /*
9222  * All the div[] digits except possibly div[qi] are now in the
9223  * range 0..NBASE-1. We do not need to consider div[qi] in
9224  * the maxdiv value anymore, so we can reset maxdiv to 1.
9225  */
9226  maxdiv = 1;
9227 
9228  /*
9229  * Recompute the quotient digit since new info may have
9230  * propagated into the top four dividend digits
9231  */
9232  fdividend = (double) div[qi];
9233  for (i = 1; i < 4; i++)
9234  {
9235  fdividend *= NBASE;
9236  if (qi + i <= div_ndigits)
9237  fdividend += (double) div[qi + i];
9238  }
9239  /* Compute the (approximate) quotient digit */
9240  fquotient = fdividend * fdivisorinverse;
9241  qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
9242  (((int) fquotient) - 1); /* truncate towards -infinity */
9243  maxdiv += abs(qdigit);
9244  }
9245 
9246  /*
9247  * Subtract off the appropriate multiple of the divisor.
9248  *
9249  * The digits beyond div[qi] cannot overflow, because we know they
9250  * will fall within the maxdiv limit. As for div[qi] itself, note
9251  * that qdigit is approximately trunc(div[qi] / vardigits[0]),
9252  * which would make the new value simply div[qi] mod vardigits[0].
9253  * The lower-order terms in qdigit can change this result by not
9254  * more than about twice INT_MAX/NBASE, so overflow is impossible.
9255  *
9256  * This inner loop is the performance bottleneck for division, so
9257  * code it in the same way as the inner loop of mul_var() so that
9258  * it can be auto-vectorized. We cast qdigit to NumericDigit
9259  * before multiplying to allow the compiler to generate more
9260  * efficient code (using 16-bit multiplication), which is safe
9261  * since we know that the quotient digit is off by at most one, so
9262  * there is no overflow risk.
9263  */
9264  if (qdigit != 0)
9265  {
9266  int istop = Min(var2ndigits, div_ndigits - qi + 1);
9267  int *div_qi = &div[qi];
9268 
9269  for (i = 0; i < istop; i++)
9270  div_qi[i] -= ((NumericDigit) qdigit) * var2digits[i];
9271  }
9272  }
9273 
9274  /*
9275  * The dividend digit we are about to replace might still be nonzero.
9276  * Fold it into the next digit position.
9277  *
9278  * There is no risk of overflow here, although proving that requires
9279  * some care. Much as with the argument for div[qi] not overflowing,
9280  * if we consider the first two terms in the numerator and denominator
9281  * of qdigit, we can see that the final value of div[qi + 1] will be
9282  * approximately a remainder mod (vardigits[0]*NBASE + vardigits[1]).
9283  * Accounting for the lower-order terms is a bit complicated but ends
9284  * up adding not much more than INT_MAX/NBASE to the possible range.
9285  * Thus, div[qi + 1] cannot overflow here, and in its role as div[qi]
9286  * in the next loop iteration, it can't be large enough to cause
9287  * overflow in the carry propagation step (if any), either.
9288  *
9289  * But having said that: div[qi] can be more than INT_MAX/NBASE, as
9290  * noted above, which means that the product div[qi] * NBASE *can*
9291  * overflow. When that happens, adding it to div[qi + 1] will always
9292  * cause a canceling overflow so that the end result is correct. We
9293  * could avoid the intermediate overflow by doing the multiplication
9294  * and addition in int64 arithmetic, but so far there appears no need.
9295  */
9296  div[qi + 1] += div[qi] * NBASE;
9297 
9298  div[qi] = qdigit;
9299  }
9300 
9301  /*
9302  * Approximate and store the last quotient digit (div[div_ndigits])
9303  */
9304  fdividend = (double) div[qi];
9305  for (i = 1; i < 4; i++)
9306  fdividend *= NBASE;
9307  fquotient = fdividend * fdivisorinverse;
9308  qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
9309  (((int) fquotient) - 1); /* truncate towards -infinity */
9310  div[qi] = qdigit;
9311 
9312  /*
9313  * Because the quotient digits might be off by one, some of them might be
9314  * -1 or NBASE at this point. The represented value is correct in a
9315  * mathematical sense, but it doesn't look right. We do a final carry
9316  * propagation pass to normalize the digits, which we combine with storing
9317  * the result digits into the output. Note that this is still done at
9318  * full precision w/guard digits.
9319  */
9320  alloc_var(result, div_ndigits + 1);
9321  res_digits = result->digits;
9322  carry = 0;
9323  for (i = div_ndigits; i >= 0; i--)
9324  {
9325  newdig = div[i] + carry;
9326  if (newdig < 0)
9327  {
9328  carry = -((-newdig - 1) / NBASE) - 1;
9329  newdig -= carry * NBASE;
9330  }
9331  else if (newdig >= NBASE)
9332  {
9333  carry = newdig / NBASE;
9334  newdig -= carry * NBASE;
9335  }
9336  else
9337  carry = 0;
9338  res_digits[i] = newdig;
9339  }
9340  Assert(carry == 0);
9341 
9342  pfree(div);
9343 
9344  /*
9345  * Finally, round the result to the requested precision.
9346  */
9347  result->weight = res_weight;
9348  result->sign = res_sign;
9349 
9350  /* Round to target rscale (and set result->dscale) */
9351  if (round)
9352  round_var(result, rscale);
9353  else
9354  trunc_var(result, rscale);
9355 
9356  /* Strip leading and trailing zeroes */
9357  strip_var(result);
9358 }
#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 9368 of file numeric.c.

9370 {
9371  NumericDigit *var_digits = var->digits;
9372  int var_ndigits = var->ndigits;
9373  int res_sign;
9374  int res_weight;
9375  int res_ndigits;
9376  NumericDigit *res_buf;
9377  NumericDigit *res_digits;
9378  uint32 divisor;
9379  int i;
9380 
9381  /* Guard against division by zero */
9382  if (ival == 0)
9383  ereport(ERROR,
9384  errcode(ERRCODE_DIVISION_BY_ZERO),
9385  errmsg("division by zero"));
9386 
9387  /* Result zero check */
9388  if (var_ndigits == 0)
9389  {
9390  zero_var(result);
9391  result->dscale = rscale;
9392  return;
9393  }
9394 
9395  /*
9396  * Determine the result sign, weight and number of digits to calculate.
9397  * The weight figured here is correct if the emitted quotient has no
9398  * leading zero digits; otherwise strip_var() will fix things up.
9399  */
9400  if (var->sign == NUMERIC_POS)
9401  res_sign = ival > 0 ? NUMERIC_POS : NUMERIC_NEG;
9402  else
9403  res_sign = ival > 0 ? NUMERIC_NEG : NUMERIC_POS;
9404  res_weight = var->weight - ival_weight;
9405  /* The number of accurate result digits we need to produce: */
9406  res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9407  /* ... but always at least 1 */
9408  res_ndigits = Max(res_ndigits, 1);
9409  /* If rounding needed, figure one more digit to ensure correct result */
9410  if (round)
9411  res_ndigits++;
9412 
9413  res_buf = digitbuf_alloc(res_ndigits + 1);
9414  res_buf[0] = 0; /* spare digit for later rounding */
9415  res_digits = res_buf + 1;
9416 
9417  /*
9418  * Now compute the quotient digits. This is the short division algorithm
9419  * described in Knuth volume 2, section 4.3.1 exercise 16, except that we
9420  * allow the divisor to exceed the internal base.
9421  *
9422  * In this algorithm, the carry from one digit to the next is at most
9423  * divisor - 1. Therefore, while processing the next digit, carry may
9424  * become as large as divisor * NBASE - 1, and so it requires a 64-bit
9425  * integer if this exceeds UINT_MAX.
9426  */
9427  divisor = abs(ival);
9428 
9429  if (divisor <= UINT_MAX / NBASE)
9430  {
9431  /* carry cannot overflow 32 bits */
9432  uint32 carry = 0;
9433 
9434  for (i = 0; i < res_ndigits; i++)
9435  {
9436  carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9437  res_digits[i] = (NumericDigit) (carry / divisor);
9438  carry = carry % divisor;
9439  }
9440  }
9441  else
9442  {
9443  /* carry may exceed 32 bits */
9444  uint64 carry = 0;
9445 
9446  for (i = 0; i < res_ndigits; i++)
9447  {
9448  carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9449  res_digits[i] = (NumericDigit) (carry / divisor);
9450  carry = carry % divisor;
9451  }
9452  }
9453 
9454  /* Store the quotient in result */
9455  digitbuf_free(result->buf);
9456  result->ndigits = res_ndigits;
9457  result->buf = res_buf;
9458  result->digits = res_digits;
9459  result->weight = res_weight;
9460  result->sign = res_sign;
9461 
9462  /* Round or truncate to target rscale (and set result->dscale) */
9463  if (round)
9464  round_var(result, rscale);
9465  else
9466  trunc_var(result, rscale);
9467 
9468  /* Strip leading/trailing zeroes */
9469  strip_var(result);
9470 }
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 4728 of file numeric.c.

4729 {
4730  NumericVar X;
4731  NumericVar X2;
4732  MemoryContext old_context;
4733 
4734  /* Count NaN/infinity inputs separately from all else */
4736  {
4737  if (NUMERIC_IS_PINF(newval))
4738  state->pInfcount++;
4739  else if (NUMERIC_IS_NINF(newval))
4740  state->nInfcount++;
4741  else
4742  state->NaNcount++;
4743  return;
4744  }
4745 
4746  /* load processed number in short-lived context */
4748 
4749  /*
4750  * Track the highest input dscale that we've seen, to support inverse
4751  * transitions (see do_numeric_discard).
4752  */
4753  if (X.dscale > state->maxScale)
4754  {
4755  state->maxScale = X.dscale;
4756  state->maxScaleCount = 1;
4757  }
4758  else if (X.dscale == state->maxScale)
4759  state->maxScaleCount++;
4760 
4761  /* if we need X^2, calculate that in short-lived context */
4762  if (state->calcSumX2)
4763  {
4764  init_var(&X2);
4765  mul_var(&X, &X, &X2, X.dscale * 2);
4766  }
4767 
4768  /* The rest of this needs to work in the aggregate context */
4769  old_context = MemoryContextSwitchTo(state->agg_context);
4770 
4771  state->N++;
4772 
4773  /* Accumulate sums */
4774  accum_sum_add(&(state->sumX), &X);
4775 
4776  if (state->calcSumX2)
4777  accum_sum_add(&(state->sumX2), &X2);
4778 
4779  MemoryContextSwitchTo(old_context);
4780 }
#define newval
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
Definition: regguts.h:318

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

4799 {
4800  NumericVar X;
4801  NumericVar X2;
4802  MemoryContext old_context;
4803 
4804  /* Count NaN/infinity inputs separately from all else */
4806  {
4807  if (NUMERIC_IS_PINF(newval))
4808  state->pInfcount--;
4809  else if (NUMERIC_IS_NINF(newval))
4810  state->nInfcount--;
4811  else
4812  state->NaNcount--;
4813  return true;
4814  }
4815 
4816  /* load processed number in short-lived context */
4818 
4819  /*
4820  * state->sumX's dscale is the maximum dscale of any of the inputs.
4821  * Removing the last input with that dscale would require us to recompute
4822  * the maximum dscale of the *remaining* inputs, which we cannot do unless
4823  * no more non-NaN inputs remain at all. So we report a failure instead,
4824  * and force the aggregation to be redone from scratch.
4825  */
4826  if (X.dscale == state->maxScale)
4827  {
4828  if (state->maxScaleCount > 1 || state->maxScale == 0)
4829  {
4830  /*
4831  * Some remaining inputs have same dscale, or dscale hasn't gotten
4832  * above zero anyway
4833  */
4834  state->maxScaleCount--;
4835  }
4836  else if (state->N == 1)
4837  {
4838  /* No remaining non-NaN inputs at all, so reset maxScale */
4839  state->maxScale = 0;
4840  state->maxScaleCount = 0;
4841  }
4842  else
4843  {
4844  /* Correct new maxScale is uncertain, must fail */
4845  return false;
4846  }
4847  }
4848 
4849  /* if we need X^2, calculate that in short-lived context */
4850  if (state->calcSumX2)
4851  {
4852  init_var(&X2);
4853  mul_var(&X, &X, &X2, X.dscale * 2);
4854  }
4855 
4856  /* The rest of this needs to work in the aggregate context */
4857  old_context = MemoryContextSwitchTo(state->agg_context);
4858 
4859  if (state->N-- > 1)
4860  {
4861  /* Negate X, to subtract it from the sum */
4862  X.sign = (X.sign == NUMERIC_POS ? NUMERIC_NEG : NUMERIC_POS);
4863  accum_sum_add(&(state->sumX), &X);
4864 
4865  if (state->calcSumX2)
4866  {
4867  /* Negate X^2. X^2 is always positive */
4868  X2.sign = NUMERIC_NEG;
4869  accum_sum_add(&(state->sumX2), &X2);
4870  }
4871  }
4872  else
4873  {
4874  /* Zero the sums */
4875  Assert(state->N == 0);
4876 
4877  accum_sum_reset(&state->sumX);
4878  if (state->calcSumX2)
4879  accum_sum_reset(&state->sumX2);
4880  }
4881 
4882  MemoryContextSwitchTo(old_context);
4883 
4884  return true;
4885 }
static void accum_sum_reset(NumericSumAccum *accum)
Definition: numeric.c:11610

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

7583 {
7584  Numeric res;
7585 
7586  res = (Numeric) palloc(VARSIZE(num));
7587  memcpy(res, num, VARSIZE(num));
7588  return res;
7589 }
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 10490 of file numeric.c.

10491 {
10492  int ln_dweight;
10493 
10494  /* Caller should fail on ln(negative), but for the moment return zero */
10495  if (var->sign != NUMERIC_POS)
10496  return 0;
10497 
10498  if (cmp_var(var, &const_zero_point_nine) >= 0 &&
10499  cmp_var(var, &const_one_point_one) <= 0)
10500  {
10501  /*
10502  * 0.9 <= var <= 1.1
10503  *
10504  * ln(var) has a negative weight (possibly very large). To get a
10505  * reasonably accurate result, estimate it using ln(1+x) ~= x.
10506  */
10507  NumericVar x;
10508 
10509  init_var(&x);
10510  sub_var(var, &const_one, &x);
10511 
10512  if (x.ndigits > 0)
10513  {
10514  /* Use weight of most significant decimal digit of x */
10515  ln_dweight = x.weight * DEC_DIGITS + (int) log10(x.digits[0]);
10516  }
10517  else
10518  {
10519  /* x = 0. Since ln(1) = 0 exactly, we don't need extra digits */
10520  ln_dweight = 0;
10521  }
10522 
10523  free_var(&x);
10524  }
10525  else
10526  {
10527  /*
10528  * Estimate the logarithm using the first couple of digits from the
10529  * input number. This will give an accurate result whenever the input
10530  * is not too close to 1.
10531  */
10532  if (var->ndigits > 0)
10533  {
10534  int digits;
10535  int dweight;
10536  double ln_var;
10537 
10538  digits = var->digits[0];
10539  dweight = var->weight * DEC_DIGITS;
10540 
10541  if (var->ndigits > 1)
10542  {
10543  digits = digits * NBASE + var->digits[1];
10544  dweight -= DEC_DIGITS;
10545  }
10546 
10547  /*----------
10548  * We have var ~= digits * 10^dweight
10549  * so ln(var) ~= ln(digits) + dweight * ln(10)
10550  *----------
10551  */
10552  ln_var = log((double) digits) + dweight * 2.302585092994046;
10553  ln_dweight = (int) log10(fabs(ln_var));
10554  }
10555  else
10556  {
10557  /* Caller should fail on ln(0), but for the moment return zero */
10558  ln_dweight = 0;
10559  }
10560  }
10561 
10562  return ln_dweight;
10563 }
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:10572
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 10361 of file numeric.c.

10362 {
10363  NumericVar x;
10364  NumericVar elem;
10365  int ni;
10366  double val;
10367  int dweight;
10368  int ndiv2;
10369  int sig_digits;
10370  int local_rscale;
10371 
10372  init_var(&x);
10373  init_var(&elem);
10374 
10375  set_var_from_var(arg, &x);
10376 
10377  /*
10378  * Estimate the dweight of the result using floating point arithmetic, so
10379  * that we can choose an appropriate local rscale for the calculation.
10380  */
10382 
10383  /* Guard against overflow/underflow */
10384  /* If you change this limit, see also power_var()'s limit */
10385  if (fabs(val) >= NUMERIC_MAX_RESULT_SCALE * 3)
10386  {
10387  if (val > 0)
10388  ereport(ERROR,
10389  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
10390  errmsg("value overflows numeric format")));
10391  zero_var(result);
10392  result->dscale = rscale;
10393  return;
10394  }
10395 
10396  /* decimal weight = log10(e^x) = x * log10(e) */
10397  dweight = (int) (val * 0.434294481903252);
10398 
10399  /*
10400  * Reduce x to the range -0.01 <= x <= 0.01 (approximately) by dividing by
10401  * 2^ndiv2, to improve the convergence rate of the Taylor series.
10402  *
10403  * Note that the overflow check above ensures that fabs(x) < 6000, which
10404  * means that ndiv2 <= 20 here.
10405  */
10406  if (fabs(val) > 0.01)
10407  {
10408  ndiv2 = 1;
10409  val /= 2;
10410 
10411  while (fabs(val) > 0.01)
10412  {
10413  ndiv2++;
10414  val /= 2;
10415  }
10416 
10417  local_rscale = x.dscale + ndiv2;
10418  div_var_int(&x, 1 << ndiv2, 0, &x, local_rscale, true);
10419  }
10420  else
10421  ndiv2 = 0;
10422 
10423  /*
10424  * Set the scale for the Taylor series expansion. The final result has
10425  * (dweight + rscale + 1) significant digits. In addition, we have to
10426  * raise the Taylor series result to the power 2^ndiv2, which introduces
10427  * an error of up to around log10(2^ndiv2) digits, so work with this many
10428  * extra digits of precision (plus a few more for good measure).
10429  */
10430  sig_digits = 1 + dweight + rscale + (int) (ndiv2 * 0.301029995663981);
10431  sig_digits = Max(sig_digits, 0) + 8;
10432 
10433  local_rscale = sig_digits - 1;
10434 
10435  /*
10436  * Use the Taylor series
10437  *
10438  * exp(x) = 1 + x + x^2/2! + x^3/3! + ...
10439  *
10440  * Given the limited range of x, this should converge reasonably quickly.
10441  * We run the series until the terms fall below the local_rscale limit.
10442  */
10443  add_var(&const_one, &x, result);
10444 
10445  mul_var(&x, &x, &elem, local_rscale);
10446  ni = 2;
10447  div_var_int(&elem, ni, 0, &elem, local_rscale, true);
10448 
10449  while (elem.ndigits != 0)
10450  {
10451  add_var(result, &elem, result);
10452 
10453  mul_var(&elem, &x, &elem, local_rscale);
10454  ni++;
10455  div_var_int(&elem, ni, 0, &elem, local_rscale, true);
10456  }
10457 
10458  /*
10459  * Compensate for the argument range reduction. Since the weight of the
10460  * result doubles with each multiplication, we can reduce the local rscale
10461  * as we proceed.
10462  */
10463  while (ndiv2-- > 0)
10464  {
10465  local_rscale = sig_digits - result->weight * 2 * DEC_DIGITS;
10466  local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
10467  mul_var(result, result, result, local_rscale);
10468  }
10469 
10470  /* Round to requested rscale */
10471  round_var(result, rscale);
10472 
10473  free_var(&x);
10474  free_var(&elem);
10475 }
static double numericvar_to_double_no_overflow(const NumericVar *var)
Definition: numeric.c:8160
#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 4558 of file numeric.c.

4559 {
4561  Numeric res;
4562  NumericVar result;
4563  char buf[FLT_DIG + 100];
4564  const char *endptr;
4565 
4566  if (isnan(val))
4568 
4569  if (isinf(val))
4570  {
4571  if (val < 0)
4573  else
4575  }
4576 
4577  snprintf(buf, sizeof(buf), "%.*g", FLT_DIG, val);
4578 
4579  init_var(&result);
4580 
4581  /* Assume we need not worry about leading/trailing spaces */
4582  (void) set_var_from_str(buf, buf, &result, &endptr, NULL);
4583 
4584  res = make_result(&result);
4585 
4586  free_var(&result);
4587 
4589 }
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:6891
static Numeric make_result(const NumericVar *var)
Definition: numeric.c:7710
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 4464 of file numeric.c.

4465 {
4467  Numeric res;
4468  NumericVar result;
4469  char buf[DBL_DIG + 100];
4470  const char *endptr;
4471 
4472  if (isnan(val))
4474 
4475  if (isinf(val))
4476  {
4477  if (val < 0)
4479  else
4481  }
4482 
4483  snprintf(buf, sizeof(buf), "%.*g", DBL_DIG, val);
4484 
4485  init_var(&result);
4486 
4487  /* Assume we need not worry about leading/trailing spaces */
4488  (void) set_var_from_str(buf, buf, &result, &endptr, NULL);
4489 
4490  res = make_result(&result);
4491 
4492  free_var(&result);
4493 
4495 }
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 9788 of file numeric.c.

9789 {
9790  NumericVar tmp;
9791 
9792  init_var(&tmp);
9793  set_var_from_var(var, &tmp);
9794 
9795  trunc_var(&tmp, 0);
9796 
9797  if (var->sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0)
9798  sub_var(&tmp, &const_one, &tmp);
9799 
9800  set_var_from_var(&tmp, result);
9801  free_var(&tmp);
9802 }

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

6849 {
6850  digitbuf_free(var->buf);
6851  var->buf = NULL;
6852  var->digits = NULL;
6853  var->sign = NUMERIC_NAN;
6854 }
#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 9811 of file numeric.c.

9812 {
9813  int res_dscale;
9814  int cmp;
9815  NumericVar tmp_arg;
9816  NumericVar mod;
9817 
9818  res_dscale = Max(var1->dscale, var2->dscale);
9819 
9820  /*
9821  * Arrange for var1 to be the number with the greater absolute value.
9822  *
9823  * This would happen automatically in the loop below, but avoids an
9824  * expensive modulo operation.
9825  */
9826  cmp = cmp_abs(var1, var2);
9827  if (cmp < 0)
9828  {
9829  const NumericVar *tmp = var1;
9830 
9831  var1 = var2;
9832  var2 = tmp;
9833  }
9834 
9835  /*
9836  * Also avoid the taking the modulo if the inputs have the same absolute
9837  * value, or if the smaller input is zero.
9838  */
9839  if (cmp == 0 || var2->ndigits == 0)
9840  {
9841  set_var_from_var(var1, result);
9842  result->sign = NUMERIC_POS;
9843  result->dscale = res_dscale;
9844  return;
9845  }
9846 
9847  init_var(&tmp_arg);
9848  init_var(&mod);
9849 
9850  /* Use the Euclidean algorithm to find the GCD */
9851  set_var_from_var(var1, &tmp_arg);
9852  set_var_from_var(var2, result);
9853 
9854  for (;;)
9855  {
9856  /* this loop can take a while, so allow it to be interrupted */
9858 
9859  mod_var(&tmp_arg, result, &mod);
9860  if (mod.ndigits == 0)
9861  break;
9862  set_var_from_var(result, &tmp_arg);
9863  set_var_from_var(&mod, result);
9864  }
9865  result->sign = NUMERIC_POS;
9866  result->dscale = res_dscale;
9867 
9868  free_var(&tmp_arg);
9869  free_var(&mod);
9870 }
static void mod_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:9665
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:121
static int cmp(const chr *x, const chr *y, size_t len)
Definition: regc_locale.c:747

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:7239
#define PG_NARGS()
Definition: fmgr.h:203
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:303
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:307
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:309
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:305
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:327
#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 4111 of file numeric.c.

4112 {
4113  int min_scale;
4114  int last_digit_pos;
4115 
4116  /*
4117  * Ordinarily, the input value will be "stripped" so that the last
4118  * NumericDigit is nonzero. But we don't want to get into an infinite
4119  * loop if it isn't, so explicitly find the last nonzero digit.
4120  */
4121  last_digit_pos = var->ndigits - 1;
4122  while (last_digit_pos >= 0 &&
4123  var->digits[last_digit_pos] == 0)
4124  last_digit_pos--;
4125 
4126  if (last_digit_pos >= 0)
4127  {
4128  /* compute min_scale assuming that last ndigit has no zeroes */
4129  min_scale = (last_digit_pos - var->weight) * DEC_DIGITS;
4130 
4131  /*
4132  * We could get a negative result if there are no digits after the
4133  * decimal point. In this case the min_scale must be zero.
4134  */
4135  if (min_scale > 0)
4136  {
4137  /*
4138  * Reduce min_scale if trailing digit(s) in last NumericDigit are
4139  * zero.
4140  */
4141  NumericDigit last_digit = var->digits[last_digit_pos];
4142 
4143  while (last_digit % 10 == 0)
4144  {
4145  min_scale--;
4146  last_digit /= 10;
4147  }
4148  }
4149  else
4150  min_scale = 0;
4151  }
4152  else
4153  min_scale = 0; /* result if input is zero */
4154 
4155  return min_scale;
4156 }

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

7314 {
7315  int dscale;
7316  char *str;
7317  char *cp;
7318  char *endcp;
7319  int i;
7320  int d;
7321  NumericDigit dig;
7322 
7323 #if DEC_DIGITS > 1
7324  NumericDigit d1;
7325 #endif
7326 
7327  dscale = var->dscale;
7328 
7329  /*
7330  * Allocate space for the result.
7331  *
7332  * i is set to the # of decimal digits before decimal point. dscale is the
7333  * # of decimal digits we will print after decimal point. We may generate
7334  * as many as DEC_DIGITS-1 excess digits at the end, and in addition we
7335  * need room for sign, decimal point, null terminator.
7336  */
7337  i = (var->weight + 1) * DEC_DIGITS;
7338  if (i <= 0)
7339  i = 1;
7340 
7341  str = palloc(i + dscale + DEC_DIGITS + 2);
7342  cp = str;
7343 
7344  /*
7345  * Output a dash for negative values
7346  */
7347  if (var->sign == NUMERIC_NEG)
7348  *cp++ = '-';
7349 
7350  /*
7351  * Output all digits before the decimal point
7352  */
7353  if (var->weight < 0)
7354  {
7355  d = var->weight + 1;
7356  *cp++ = '0';
7357  }
7358  else
7359  {
7360  for (d = 0; d <= var->weight; d++)
7361  {
7362  dig = (d < var->ndigits) ? var->digits[d] : 0;
7363  /* In the first digit, suppress extra leading decimal zeroes */
7364 #if DEC_DIGITS == 4
7365  {
7366  bool putit = (d > 0);
7367 
7368  d1 = dig / 1000;
7369  dig -= d1 * 1000;
7370  putit |= (d1 > 0);
7371  if (putit)
7372  *cp++ = d1 + '0';
7373  d1 = dig / 100;
7374  dig -= d1 * 100;
7375  putit |= (d1 > 0);
7376  if (putit)
7377  *cp++ = d1 + '0';
7378  d1 = dig / 10;
7379  dig -= d1 * 10;
7380  putit |= (d1 > 0);
7381  if (putit)
7382  *cp++ = d1 + '0';
7383  *cp++ = dig + '0';
7384  }
7385 #elif DEC_DIGITS == 2
7386  d1 = dig / 10;
7387  dig -= d1 * 10;
7388  if (d1 > 0 || d > 0)
7389  *cp++ = d1 + '0';
7390  *cp++ = dig + '0';
7391 #elif DEC_DIGITS == 1
7392  *cp++ = dig + '0';
7393 #else
7394 #error unsupported NBASE
7395 #endif
7396  }
7397  }
7398 
7399  /*
7400  * If requested, output a decimal point and all the digits that follow it.
7401  * We initially put out a multiple of DEC_DIGITS digits, then truncate if
7402  * needed.
7403  */
7404  if (dscale > 0)
7405  {
7406  *cp++ = '.';
7407  endcp = cp + dscale;
7408  for (i = 0; i < dscale; d++, i += DEC_DIGITS)
7409  {
7410  dig = (d >= 0 && d < var->ndigits) ? var->digits[d] : 0;
7411 #if DEC_DIGITS == 4
7412  d1 = dig / 1000;
7413  dig -= d1 * 1000;
7414  *cp++ = d1 + '0';
7415  d1 = dig / 100;
7416  dig -= d1 * 100;
7417  *cp++ = d1 + '0';
7418  d1 = dig / 10;
7419  dig -= d1 * 10;
7420  *cp++ = d1 + '0';
7421  *cp++ = dig + '0';
7422 #elif DEC_DIGITS == 2
7423  d1 = dig / 10;
7424  dig -= d1 * 10;
7425  *cp++ = d1 + '0';
7426  *cp++ = dig + '0';
7427 #elif DEC_DIGITS == 1
7428  *cp++ = dig + '0';
7429 #else
7430 #error unsupported NBASE
7431 #endif
7432  }
7433  cp = endcp;
7434  }
7435 
7436  /*
7437  * terminate the string and return it
7438  */
7439  *cp = '\0';
7440  return str;
7441 }
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 7466 of file numeric.c.

7467 {
7468  int32 exponent;
7469  NumericVar tmp_var;
7470  size_t len;
7471  char *str;
7472  char *sig_out;
7473 
7474  if (rscale < 0)
7475  rscale = 0;
7476 
7477  /*
7478  * Determine the exponent of this number in normalised form.
7479  *
7480  * This is the exponent required to represent the number with only one
7481  * significant digit before the decimal place.
7482  */
7483  if (var->ndigits > 0)
7484  {
7485  exponent = (var->weight + 1) * DEC_DIGITS;
7486 
7487  /*
7488  * Compensate for leading decimal zeroes in the first numeric digit by
7489  * decrementing the exponent.
7490  */
7491  exponent -= DEC_DIGITS - (int) log10(var->digits[0]);
7492  }
7493  else
7494  {
7495  /*
7496  * If var has no digits, then it must be zero.
7497  *
7498  * Zero doesn't technically have a meaningful exponent in normalised
7499  * notation, but we just display the exponent as zero for consistency
7500  * of output.
7501  */
7502  exponent = 0;
7503  }
7504 
7505  /*
7506  * Divide var by 10^exponent to get the significand, rounding to rscale
7507  * decimal digits in the process.
7508  */
7509  init_var(&tmp_var);
7510 
7511  power_ten_int(exponent, &tmp_var);
7512  div_var(var, &tmp_var, &tmp_var, rscale, true);
7513  sig_out = get_str_from_var(&tmp_var);
7514 
7515  free_var(&tmp_var);
7516 
7517  /*
7518  * Allocate space for the result.
7519  *
7520  * In addition to the significand, we need room for the exponent
7521  * decoration ("e"), the sign of the exponent, up to 10 digits for the
7522  * exponent itself, and of course the null terminator.
7523  */
7524  len = strlen(sig_out) + 13;
7525  str = palloc(len);
7526  snprintf(str, len, "%se%+03d", sig_out, exponent);
7527 
7528  pfree(sig_out);
7529 
7530  return str;
7531 }
static char * get_str_from_var(const NumericVar *var)
Definition: numeric.c:7313
static void power_ten_int(int exp, NumericVar *result)
Definition: numeric.c:11115
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 2685 of file numeric.c.

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

2766 {
2768  uint64 seed = PG_GETARG_INT64(1);
2769  Datum digit_hash;
2770  Datum result;
2771  int weight;
2772  int start_offset;
2773  int end_offset;
2774  int i;
2775  int hash_len;
2777 
2778  /* If it's NaN or infinity, don't try to hash the rest of the fields */
2779  if (NUMERIC_IS_SPECIAL(key))
2780  PG_RETURN_UINT64(seed);
2781 
2782  weight = NUMERIC_WEIGHT(key);
2783  start_offset = 0;
2784  end_offset = 0;
2785 
2787  for (i = 0; i < NUMERIC_NDIGITS(key); i++)
2788  {
2789  if (digits[i] != (NumericDigit) 0)
2790  break;
2791 
2792  start_offset++;
2793 
2794  weight--;
2795  }
2796 
2797  if (NUMERIC_NDIGITS(key) == start_offset)
2798  PG_RETURN_UINT64(seed - 1);
2799 
2800  for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)
2801  {
2802  if (digits[i] != (NumericDigit) 0)
2803  break;
2804 
2805  end_offset++;
2806  }
2807 
2808  Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));
2809 
2810  hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;
2811  digit_hash = hash_any_extended((unsigned char *) (NUMERIC_DIGITS(key)
2812  + start_offset),
2813  hash_len * sizeof(NumericDigit),
2814  seed);
2815 
2816  result = UInt64GetDatum(DatumGetUInt64(digit_hash) ^ weight);
2817 
2818  PG_RETURN_DATUM(result);
2819 }
#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 2550 of file numeric.c.

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

5426 {
5428 
5429  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5430 
5431  /* Create the state data on the first call */
5432  if (state == NULL)
5433  state = makePolyNumAggState(fcinfo, true);
5434 
5435  if (!PG_ARGISNULL(1))
5436  {
5437 #ifdef HAVE_INT128
5438  do_int128_accum(state, (int128) PG_GETARG_INT16(1));
5439 #else
5441 #endif
5442  }
5443 
5445 }
#define makePolyNumAggState
Definition: numeric.c:5420
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4208
static void do_numeric_accum(NumericAggState *state, Numeric newval)
Definition: numeric.c:4728
#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 5853 of file numeric.c.

5854 {
5856 
5857  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5858 
5859  /* Should not get here with no state */
5860  if (state == NULL)
5861  elog(ERROR, "int2_accum_inv called with NULL state");
5862 
5863  if (!PG_ARGISNULL(1))
5864  {
5865 #ifdef HAVE_INT128
5866  do_int128_discard(state, (int128) PG_GETARG_INT16(1));
5867 #else
5868  /* Should never fail, all inputs have dscale 0 */
5870  elog(ERROR, "do_numeric_discard failed unexpectedly");
5871 #endif
5872  }
5873 
5875 }
static bool do_numeric_discard(NumericAggState *state, Numeric newval)
Definition: numeric.c:4798

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

6537 {
6538  ArrayType *transarray;
6540  Int8TransTypeData *transdata;
6541 
6542  /*
6543  * If we're invoked as an aggregate, we can cheat and modify our first
6544  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6545  * a copy of it before scribbling on it.
6546  */
6547  if (AggCheckCallContext(fcinfo, NULL))
6548  transarray = PG_GETARG_ARRAYTYPE_P(0);
6549  else
6550  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6551 
6552  if (ARR_HASNULL(transarray) ||
6553  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6554  elog(ERROR, "expected 2-element int8 array");
6555 
6556  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6557  transdata->count++;
6558  transdata->sum += newval;
6559 
6560  PG_RETURN_ARRAYTYPE_P(transarray);
6561 }
#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:4513

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

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

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

4416 {
4417  int16 val = PG_GETARG_INT16(0);
4418 
4420 }

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

◆ int2_sum()

Datum int2_sum ( PG_FUNCTION_ARGS  )

Definition at line 6387 of file numeric.c.

6388 {
6389  int64 newval;
6390 
6391  if (PG_ARGISNULL(0))
6392  {
6393  /* No non-null input seen so far... */
6394  if (PG_ARGISNULL(1))
6395  PG_RETURN_NULL(); /* still no non-null */
6396  /* This is the first non-null input. */
6397  newval = (int64) PG_GETARG_INT16(1);
6399  }
6400 
6401  /*
6402  * If we're invoked as an aggregate, we can cheat and modify our first
6403  * parameter in-place to avoid palloc overhead. If not, we need to return
6404  * the new value of the transition variable. (If int8 is pass-by-value,
6405  * then of course this is useless as well as incorrect, so just ifdef it
6406  * out.)
6407  */
6408 #ifndef USE_FLOAT8_BYVAL /* controls int8 too */
6409  if (AggCheckCallContext(fcinfo, NULL))
6410  {
6411  int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
6412 
6413  /* Leave the running sum unchanged in the new input is null */
6414  if (!PG_ARGISNULL(1))
6415  *oldsum = *oldsum + (int64) PG_GETARG_INT16(1);
6416 
6417  PG_RETURN_POINTER(oldsum);
6418  }
6419  else
6420 #endif
6421  {
6422  int64 oldsum = PG_GETARG_INT64(0);
6423 
6424  /* Leave sum unchanged if new input is null. */
6425  if (PG_ARGISNULL(1))
6426  PG_RETURN_INT64(oldsum);
6427 
6428  /* OK to do the addition. */
6429  newval = oldsum + (int64) PG_GETARG_INT16(1);
6430 
6432  }
6433 }
#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 6706 of file numeric.c.

6707 {
6708  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
6709  Int8TransTypeData *transdata;
6710 
6711  if (ARR_HASNULL(transarray) ||
6712  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6713  elog(ERROR, "expected 2-element int8 array");
6714  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6715 
6716  /* SQL defines SUM of no values to be NULL */
6717  if (transdata->count == 0)
6718  PG_RETURN_NULL();
6719 
6720  PG_RETURN_DATUM(Int64GetDatumFast(transdata->sum));
6721 }
#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 5448 of file numeric.c.

5449 {
5451 
5452  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5453 
5454  /* Create the state data on the first call */
5455  if (state == NULL)
5456  state = makePolyNumAggState(fcinfo, true);
5457 
5458  if (!PG_ARGISNULL(1))
5459  {
5460 #ifdef HAVE_INT128
5461  do_int128_accum(state, (int128) PG_GETARG_INT32(1));
5462 #else
5464 #endif
5465  }
5466 
5468 }
#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 5878 of file numeric.c.

5879 {
5881 
5882  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5883 
5884  /* Should not get here with no state */
5885  if (state == NULL)
5886  elog(ERROR, "int4_accum_inv called with NULL state");
5887 
5888  if (!PG_ARGISNULL(1))
5889  {
5890 #ifdef HAVE_INT128
5891  do_int128_discard(state, (int128) PG_GETARG_INT32(1));
5892 #else
5893  /* Should never fail, all inputs have dscale 0 */
5895  elog(ERROR, "do_numeric_discard failed unexpectedly");
5896 #endif
5897  }
5898 
5900 }

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

6565 {
6566  ArrayType *transarray;
6568  Int8TransTypeData *transdata;
6569 
6570  /*
6571  * If we're invoked as an aggregate, we can cheat and modify our first
6572  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6573  * a copy of it before scribbling on it.
6574  */
6575  if (AggCheckCallContext(fcinfo, NULL))
6576  transarray = PG_GETARG_ARRAYTYPE_P(0);
6577  else
6578  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6579 
6580  if (ARR_HASNULL(transarray) ||
6581  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6582  elog(ERROR, "expected 2-element int8 array");
6583 
6584  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6585  transdata->count++;
6586  transdata->sum += newval;
6587 
6588  PG_RETURN_ARRAYTYPE_P(transarray);
6589 }

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

6652 {
6653  ArrayType *transarray;
6655  Int8TransTypeData *transdata;
6656 
6657  /*
6658  * If we're invoked as an aggregate, we can cheat and modify our first
6659  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6660  * a copy of it before scribbling on it.
6661  */
6662  if (AggCheckCallContext(fcinfo, NULL))
6663  transarray = PG_GETARG_ARRAYTYPE_P(0);
6664  else
6665  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6666 
6667  if (ARR_HASNULL(transarray) ||
6668  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6669  elog(ERROR, "expected 2-element int8 array");
6670 
6671  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6672  transdata->count--;
6673  transdata->sum -= newval;
6674 
6675  PG_RETURN_ARRAYTYPE_P(transarray);
6676 }

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

6593 {
6594  ArrayType *transarray1;
6595  ArrayType *transarray2;
6596  Int8TransTypeData *state1;
6597  Int8TransTypeData *state2;
6598 
6599  if (!AggCheckCallContext(fcinfo, NULL))
6600  elog(ERROR, "aggregate function called in non-aggregate context");
6601 
6602  transarray1 = PG_GETARG_ARRAYTYPE_P(0);
6603  transarray2 = PG_GETARG_ARRAYTYPE_P(1);
6604 
6605  if (ARR_HASNULL(transarray1) ||
6606  ARR_SIZE(transarray1) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6607  elog(ERROR, "expected 2-element int8 array");
6608 
6609  if (ARR_HASNULL(transarray2) ||
6610  ARR_SIZE(transarray2) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6611  elog(ERROR, "expected 2-element int8 array");
6612 
6613  state1 = (Int8TransTypeData *) ARR_DATA_PTR(transarray1);
6614  state2 = (Int8TransTypeData *) ARR_DATA_PTR(transarray2);
6615 
6616  state1->count += state2->count;
6617  state1->sum += state2->sum;
6618 
6619  PG_RETURN_ARRAYTYPE_P(transarray1);
6620 }

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

4288 {
4289  int32 val = PG_GETARG_INT32(0);
4290 
4292 }

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

◆ int4_sum()

Datum int4_sum ( PG_FUNCTION_ARGS  )

Definition at line 6436 of file numeric.c.

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

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

4230 {
4231  Numeric res;
4232  NumericVar result;
4233  int64 saved_val1 = val1;
4234  int w;
4235  int m;
4236 
4237  /* how much to decrease the weight by */
4238  w = log10val2 / DEC_DIGITS;
4239  /* how much is left */
4240  m = log10val2 % DEC_DIGITS;
4241 
4242  /*
4243  * If there is anything left, multiply the dividend by what's left, then
4244  * shift the weight by one more.
4245  */
4246  if (m > 0)
4247  {
4248  static int pow10[] = {1, 10, 100, 1000};
4249 
4250  StaticAssertDecl(lengthof(pow10) == DEC_DIGITS, "mismatch with DEC_DIGITS");
4251 
4252  if (unlikely(pg_mul_s64_overflow(val1, pow10[DEC_DIGITS - m], &val1)))
4253  {
4254  /*
4255  * If it doesn't fit, do the whole computation in numeric the slow
4256  * way. Note that va1l may have been overwritten, so use
4257  * saved_val1 instead.
4258  */
4259  int val2 = 1;
4260 
4261  for (int i = 0; i < log10val2; i++)
4262  val2 *= 10;
4263  res = numeric_div_opt_error(int64_to_numeric(saved_val1), int64_to_numeric(val2), NULL);
4266  Int32GetDatum(log10val2)));
4267  return res;
4268  }
4269  w++;
4270  }
4271 
4272  init_var(&result);
4273 
4274  int64_to_numericvar(val1, &result);
4275 
4276  result.weight -= w;
4277  result.dscale += w * DEC_DIGITS - (DEC_DIGITS - m);
4278 
4279  res = make_result(&result);
4280 
4281  free_var(&result);
4282 
4283  return res;
4284 }
Datum numeric_round(PG_FUNCTION_ARGS)
Definition: numeric.c:1533
Numeric numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:3132
static void int64_to_numericvar(int64 val, NumericVar *var)
Definition: numeric.c:7923
#define unlikely(x)
Definition: c.h:295
#define lengthof(array)
Definition: c.h:772
#define StaticAssertDecl(condition, errmessage)
Definition: c.h:920
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:644
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:215
static Numeric DatumGetNumeric(Datum X)
Definition: numeric.h:60
static Datum Int32GetDatum(int32 X)
Definition: postgres.h:212

References DatumGetNumeric(), DEC_DIGITS, DirectFunctionCall2, NumericVar::dscale, free_var(), i, init_var, Int32GetDatum(), int64_to_numeric(), int64_to_numericvar(), lengthof, make_result(), numeric_div_opt_error(), numeric_round(), NumericGetDatum(), 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 7923 of file numeric.c.

7924 {
7925  uint64 uval,
7926  newuval;
7927  NumericDigit *ptr;
7928  int ndigits;
7929 
7930  /* int64 can require at most 19 decimal digits; add one for safety */
7931  alloc_var(var, 20 / DEC_DIGITS);
7932  if (val < 0)
7933  {
7934  var->sign = NUMERIC_NEG;
7935  uval = -val;
7936  }
7937  else
7938  {
7939  var->sign = NUMERIC_POS;
7940  uval = val;
7941  }
7942  var->dscale = 0;
7943  if (val == 0)
7944  {
7945  var->ndigits = 0;
7946  var->weight = 0;
7947  return;
7948  }
7949  ptr = var->digits + var->ndigits;
7950  ndigits = 0;
7951  do
7952  {
7953  ptr--;
7954  ndigits++;
7955  newuval = uval / NBASE;
7956  *ptr = uval - newuval * NBASE;
7957  uval = newuval;
7958  } while (uval);
7959  var->digits = ptr;
7960  var->ndigits = ndigits;
7961  var->weight = ndigits - 1;
7962 }

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

5472 {
5474 
5475  state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5476 
5477  /* Create the state data on the first call */
5478  if (state == NULL)
5479  state = makeNumericAggState(fcinfo, true);
5480 
5481  if (!PG_ARGISNULL(1))
5483 
5485 }
static NumericAggState * makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
Definition: numeric.c:4688

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

5904 {
5906 
5907  state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5908 
5909  /* Should not get here with no state */
5910  if (state == NULL)
5911  elog(ERROR, "int8_accum_inv called with NULL state");
5912 
5913  if (!PG_ARGISNULL(1))
5914  {
5915  /* Should never fail, all inputs have dscale 0 */
5917  elog(ERROR, "do_numeric_discard failed unexpectedly");
5918  }
5919 
5921 }

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

6680 {
6681  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
6682  Int8TransTypeData *transdata;
6683  Datum countd,
6684  sumd;
6685 
6686  if (ARR_HASNULL(transarray) ||
6687  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6688  elog(ERROR, "expected 2-element int8 array");
6689  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6690 
6691  /* SQL defines AVG of no values to be NULL */
6692  if (transdata->count == 0)
6693  PG_RETURN_NULL();
6694 
6695  countd = NumericGetDatum(int64_to_numeric(transdata->count));
6696  sumd = NumericGetDatum(int64_to_numeric(transdata->sum));
6697 
6699 }
Datum numeric_div(PG_FUNCTION_ARGS)
Definition: numeric.c:3112

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

5670 {
5672 
5673  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5674 
5675  /* Create the state data on the first call */
5676  if (state == NULL)
5677  state = makePolyNumAggState(fcinfo, false);
5678 
5679  if (!PG_ARGISNULL(1))
5680  {
5681 #ifdef HAVE_INT128
5682  do_int128_accum(state, (int128) PG_GETARG_INT64(1));
5683 #else
5685 #endif
5686  }
5687 
5689 }

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

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

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

5697 {
5698  PolyNumAggState *state1;
5699  PolyNumAggState *state2;
5700  MemoryContext agg_context;
5701  MemoryContext old_context;
5702 
5703  if (!AggCheckCallContext(fcinfo, &agg_context))
5704  elog(ERROR, "aggregate function called in non-aggregate context");
5705 
5706  state1 = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5707  state2 = PG_ARGISNULL(1) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(1);
5708 
5709  if (state2 == NULL)
5710  PG_RETURN_POINTER(state1);
5711 
5712  /* manually copy all fields from state2 to state1 */
5713  if (state1 == NULL)
5714  {
5715  old_context = MemoryContextSwitchTo(agg_context);
5716 
5717  state1 = makePolyNumAggState(fcinfo, false);
5718  state1->N = state2->N;
5719 
5720 #ifdef HAVE_INT128
5721  state1->sumX = state2->sumX;
5722 #else
5723  accum_sum_copy(&state1->sumX, &state2->sumX);
5724 #endif
5725  MemoryContextSwitchTo(old_context);
5726 
5727  PG_RETURN_POINTER(state1);
5728  }
5729 
5730  if (state2->N > 0)
5731  {
5732  state1->N += state2->N;
5733 
5734 #ifdef HAVE_INT128
5735  state1->sumX += state2->sumX;
5736 #else
5737  /* The rest of this needs to work in the aggregate context */
5738  old_context = MemoryContextSwitchTo(agg_context);
5739 
5740  /* Accumulate sums */
5741  accum_sum_combine(&state1->sumX, &state2->sumX);
5742 
5743  MemoryContextSwitchTo(old_context);
5744 #endif
5745 
5746  }
5747  PG_RETURN_POINTER(state1);
5748 }
static void accum_sum_combine(NumericSumAccum *accum, NumericSumAccum *accum2)
Definition: numeric.c:11904
static void accum_sum_copy(NumericSumAccum *dst, NumericSumAccum *src)
Definition: numeric.c:11887
NumericSumAccum sumX
Definition: numeric.c:4670

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

5806 {
5807  bytea *sstate;
5808  PolyNumAggState *result;
5810  NumericVar tmp_var;
5811 
5812  if (!AggCheckCallContext(fcinfo, NULL))
5813  elog(ERROR, "aggregate function called in non-aggregate context");
5814 
5815  sstate = PG_GETARG_BYTEA_PP(0);
5816 
5817  init_var(&tmp_var);
5818 
5819  /*
5820  * Copy the bytea into a StringInfo so that we can "receive" it using the
5821  * standard recv-function infrastructure.
5822  */
5823  initStringInfo(&buf);
5825  VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
5826 
5827  result = makePolyNumAggStateCurrentContext(false);
5828 
5829  /* N */
5830  result->N = pq_getmsgint64(&buf);
5831 
5832  /* sumX */
5833  numericvar_deserialize(&buf, &tmp_var);
5834 #ifdef HAVE_INT128
5835  numericvar_to_int128(&tmp_var, &result->sumX);
5836 #else
5837  accum_sum_add(&result->sumX, &tmp_var);
5838 #endif
5839 
5840  pq_getmsgend(&buf);
5841  pfree(buf.data);
5842 
5843  free_var(&tmp_var);
5844 
5845  PG_RETURN_POINTER(result);
5846 }
static void numericvar_deserialize(StringInfo buf, NumericVar *var)
Definition: numeric.c:7559
#define makePolyNumAggStateCurrentContext
Definition: numeric.c:5421
#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.

◆ int8_avg_serialize()

Datum int8_avg_serialize ( PG_FUNCTION_ARGS  )

Definition at line 5756 of file numeric.c.

5757 {
5760  bytea *result;
5761  NumericVar tmp_var;
5762 
5763  /* Ensure we disallow calling when not in aggregate context */
5764  if (!