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 const char * set_var_from_str (const char *str, const char *cp, NumericVar *dest)
 
static void set_var_from_num (Numeric value, NumericVar *dest)
 
static void init_var_from_num (Numeric num, NumericVar *dest)
 
static void set_var_from_var (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 *error)
 
static void apply_typmod (NumericVar *var, int32 typmod)
 
static void apply_typmod_special (Numeric num, int32 typmod)
 
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, NumericVar *result, int rscale)
 
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 *var1)
 
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)
 

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

◆ makePolyNumAggStateCurrentContext

#define makePolyNumAggStateCurrentContext   makeNumericAggStateCurrentContext

Definition at line 5347 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 4606 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:194

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:440
signed short int16
Definition: c.h:428
#define VARHDRSZ
Definition: c.h:627

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

Function Documentation

◆ accum_sum_add()

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

Definition at line 11168 of file numeric.c.

11169 {
11170  int32 *accum_digits;
11171  int i,
11172  val_i;
11173  int val_ndigits;
11174  NumericDigit *val_digits;
11175 
11176  /*
11177  * If we have accumulated too many values since the last carry
11178  * propagation, do it now, to avoid overflowing. (We could allow more
11179  * than NBASE - 1, if we reserved two extra digits, rather than one, for
11180  * carry propagation. But even with NBASE - 1, this needs to be done so
11181  * seldom, that the performance difference is negligible.)
11182  */
11183  if (accum->num_uncarried == NBASE - 1)
11184  accum_sum_carry(accum);
11185 
11186  /*
11187  * Adjust the weight or scale of the old value, so that it can accommodate
11188  * the new value.
11189  */
11190  accum_sum_rescale(accum, val);
11191 
11192  /* */
11193  if (val->sign == NUMERIC_POS)
11194  accum_digits = accum->pos_digits;
11195  else
11196  accum_digits = accum->neg_digits;
11197 
11198  /* copy these values into local vars for speed in loop */
11199  val_ndigits = val->ndigits;
11200  val_digits = val->digits;
11201 
11202  i = accum->weight - val->weight;
11203  for (val_i = 0; val_i < val_ndigits; val_i++)
11204  {
11205  accum_digits[i] += (int32) val_digits[val_i];
11206  i++;
11207  }
11208 
11209  accum->num_uncarried++;
11210 }
static void accum_sum_carry(NumericSumAccum *accum)
Definition: numeric.c:11216
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:11289
signed int int32
Definition: c.h:429
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 11216 of file numeric.c.

11217 {
11218  int i;
11219  int ndigits;
11220  int32 *dig;
11221  int32 carry;
11222  int32 newdig = 0;
11223 
11224  /*
11225  * If no new values have been added since last carry propagation, nothing
11226  * to do.
11227  */
11228  if (accum->num_uncarried == 0)
11229  return;
11230 
11231  /*
11232  * We maintain that the weight of the accumulator is always one larger
11233  * than needed to hold the current value, before carrying, to make sure
11234  * there is enough space for the possible extra digit when carry is
11235  * propagated. We cannot expand the buffer here, unless we require
11236  * callers of accum_sum_final() to switch to the right memory context.
11237  */
11238  Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0);
11239 
11240  ndigits = accum->ndigits;
11241 
11242  /* Propagate carry in the positive sum */
11243  dig = accum->pos_digits;
11244  carry = 0;
11245  for (i = ndigits - 1; i >= 0; i--)
11246  {
11247  newdig = dig[i] + carry;
11248  if (newdig >= NBASE)
11249  {
11250  carry = newdig / NBASE;
11251  newdig -= carry * NBASE;
11252  }
11253  else
11254  carry = 0;
11255  dig[i] = newdig;
11256  }
11257  /* Did we use up the digit reserved for carry propagation? */
11258  if (newdig > 0)
11259  accum->have_carry_space = false;
11260 
11261  /* And the same for the negative sum */
11262  dig = accum->neg_digits;
11263  carry = 0;
11264  for (i = ndigits - 1; i >= 0; i--)
11265  {
11266  newdig = dig[i] + carry;
11267  if (newdig >= NBASE)
11268  {
11269  carry = newdig / NBASE;
11270  newdig -= carry * NBASE;
11271  }
11272  else
11273  carry = 0;
11274  dig[i] = newdig;
11275  }
11276  if (newdig > 0)
11277  accum->have_carry_space = false;
11278 
11279  accum->num_uncarried = 0;
11280 }
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 11446 of file numeric.c.

11447 {
11448  NumericVar tmp_var;
11449 
11450  init_var(&tmp_var);
11451 
11452  accum_sum_final(accum2, &tmp_var);
11453  accum_sum_add(accum, &tmp_var);
11454 
11455  free_var(&tmp_var);
11456 }
static void accum_sum_final(NumericSumAccum *accum, NumericVar *result)
Definition: numeric.c:11378
static void free_var(NumericVar *var)
Definition: numeric.c:6774
#define init_var(v)
Definition: numeric.c:485
static void accum_sum_add(NumericSumAccum *accum, const NumericVar *var1)
Definition: numeric.c:11168

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

11430 {
11431  dst->pos_digits = palloc(src->ndigits * sizeof(int32));
11432  dst->neg_digits = palloc(src->ndigits * sizeof(int32));
11433 
11434  memcpy(dst->pos_digits, src->pos_digits, src->ndigits * sizeof(int32));
11435  memcpy(dst->neg_digits, src->neg_digits, src->ndigits * sizeof(int32));
11436  dst->num_uncarried = src->num_uncarried;
11437  dst->ndigits = src->ndigits;
11438  dst->weight = src->weight;
11439  dst->dscale = src->dscale;
11440 }
void * palloc(Size size)
Definition: mcxt.c:1068

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

11379 {
11380  int i;
11381  NumericVar pos_var;
11382  NumericVar neg_var;
11383 
11384  if (accum->ndigits == 0)
11385  {
11386  set_var_from_var(&const_zero, result);
11387  return;
11388  }
11389 
11390  /* Perform final carry */
11391  accum_sum_carry(accum);
11392 
11393  /* Create NumericVars representing the positive and negative sums */
11394  init_var(&pos_var);
11395  init_var(&neg_var);
11396 
11397  pos_var.ndigits = neg_var.ndigits = accum->ndigits;
11398  pos_var.weight = neg_var.weight = accum->weight;
11399  pos_var.dscale = neg_var.dscale = accum->dscale;
11400  pos_var.sign = NUMERIC_POS;
11401  neg_var.sign = NUMERIC_NEG;
11402 
11403  pos_var.buf = pos_var.digits = digitbuf_alloc(accum->ndigits);
11404  neg_var.buf = neg_var.digits = digitbuf_alloc(accum->ndigits);
11405 
11406  for (i = 0; i < accum->ndigits; i++)
11407  {
11408  Assert(accum->pos_digits[i] < NBASE);
11409  pos_var.digits[i] = (int16) accum->pos_digits[i];
11410 
11411  Assert(accum->neg_digits[i] < NBASE);
11412  neg_var.digits[i] = (int16) accum->neg_digits[i];
11413  }
11414 
11415  /* And add them together */
11416  add_var(&pos_var, &neg_var, result);
11417 
11418  /* Remove leading/trailing zeroes */
11419  strip_var(result);
11420 }
static void add_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:7979
#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:7024
static void strip_var(NumericVar *var)
Definition: numeric.c:11111
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 11289 of file numeric.c.

11290 {
11291  int old_weight = accum->weight;
11292  int old_ndigits = accum->ndigits;
11293  int accum_ndigits;
11294  int accum_weight;
11295  int accum_rscale;
11296  int val_rscale;
11297 
11298  accum_weight = old_weight;
11299  accum_ndigits = old_ndigits;
11300 
11301  /*
11302  * Does the new value have a larger weight? If so, enlarge the buffers,
11303  * and shift the existing value to the new weight, by adding leading
11304  * zeros.
11305  *
11306  * We enforce that the accumulator always has a weight one larger than
11307  * needed for the inputs, so that we have space for an extra digit at the
11308  * final carry-propagation phase, if necessary.
11309  */
11310  if (val->weight >= accum_weight)
11311  {
11312  accum_weight = val->weight + 1;
11313  accum_ndigits = accum_ndigits + (accum_weight - old_weight);
11314  }
11315 
11316  /*
11317  * Even though the new value is small, we might've used up the space
11318  * reserved for the carry digit in the last call to accum_sum_carry(). If
11319  * so, enlarge to make room for another one.
11320  */
11321  else if (!accum->have_carry_space)
11322  {
11323  accum_weight++;
11324  accum_ndigits++;
11325  }
11326 
11327  /* Is the new value wider on the right side? */
11328  accum_rscale = accum_ndigits - accum_weight - 1;
11329  val_rscale = val->ndigits - val->weight - 1;
11330  if (val_rscale > accum_rscale)
11331  accum_ndigits = accum_ndigits + (val_rscale - accum_rscale);
11332 
11333  if (accum_ndigits != old_ndigits ||
11334  accum_weight != old_weight)
11335  {
11336  int32 *new_pos_digits;
11337  int32 *new_neg_digits;
11338  int weightdiff;
11339 
11340  weightdiff = accum_weight - old_weight;
11341 
11342  new_pos_digits = palloc0(accum_ndigits * sizeof(int32));
11343  new_neg_digits = palloc0(accum_ndigits * sizeof(int32));
11344 
11345  if (accum->pos_digits)
11346  {
11347  memcpy(&new_pos_digits[weightdiff], accum->pos_digits,
11348  old_ndigits * sizeof(int32));
11349  pfree(accum->pos_digits);
11350 
11351  memcpy(&new_neg_digits[weightdiff], accum->neg_digits,
11352  old_ndigits * sizeof(int32));
11353  pfree(accum->neg_digits);
11354  }
11355 
11356  accum->pos_digits = new_pos_digits;
11357  accum->neg_digits = new_neg_digits;
11358 
11359  accum->weight = accum_weight;
11360  accum->ndigits = accum_ndigits;
11361 
11362  Assert(accum->pos_digits[0] == 0 && accum->neg_digits[0] == 0);
11363  accum->have_carry_space = true;
11364  }
11365 
11366  if (val->dscale > accum->dscale)
11367  accum->dscale = val->dscale;
11368 }
void pfree(void *pointer)
Definition: mcxt.c:1175
void * palloc0(Size size)
Definition: mcxt.c:1099

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

11153 {
11154  int i;
11155 
11156  accum->dscale = 0;
11157  for (i = 0; i < accum->ndigits; i++)
11158  {
11159  accum->pos_digits[i] = 0;
11160  accum->neg_digits[i] = 0;
11161  }
11162 }

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

10777 {
10778  NumericDigit *res_buf;
10779  NumericDigit *res_digits;
10780  int res_ndigits;
10781  int res_weight;
10782  int res_rscale,
10783  rscale1,
10784  rscale2;
10785  int res_dscale;
10786  int i,
10787  i1,
10788  i2;
10789  int carry = 0;
10790 
10791  /* copy these values into local vars for speed in inner loop */
10792  int var1ndigits = var1->ndigits;
10793  int var2ndigits = var2->ndigits;
10794  NumericDigit *var1digits = var1->digits;
10795  NumericDigit *var2digits = var2->digits;
10796 
10797  res_weight = Max(var1->weight, var2->weight) + 1;
10798 
10799  res_dscale = Max(var1->dscale, var2->dscale);
10800 
10801  /* Note: here we are figuring rscale in base-NBASE digits */
10802  rscale1 = var1->ndigits - var1->weight - 1;
10803  rscale2 = var2->ndigits - var2->weight - 1;
10804  res_rscale = Max(rscale1, rscale2);
10805 
10806  res_ndigits = res_rscale + res_weight + 1;
10807  if (res_ndigits <= 0)
10808  res_ndigits = 1;
10809 
10810  res_buf = digitbuf_alloc(res_ndigits + 1);
10811  res_buf[0] = 0; /* spare digit for later rounding */
10812  res_digits = res_buf + 1;
10813 
10814  i1 = res_rscale + var1->weight + 1;
10815  i2 = res_rscale + var2->weight + 1;
10816  for (i = res_ndigits - 1; i >= 0; i--)
10817  {
10818  i1--;
10819  i2--;
10820  if (i1 >= 0 && i1 < var1ndigits)
10821  carry += var1digits[i1];
10822  if (i2 >= 0 && i2 < var2ndigits)
10823  carry += var2digits[i2];
10824 
10825  if (carry >= NBASE)
10826  {
10827  res_digits[i] = carry - NBASE;
10828  carry = 1;
10829  }
10830  else
10831  {
10832  res_digits[i] = carry;
10833  carry = 0;
10834  }
10835  }
10836 
10837  Assert(carry == 0); /* else we failed to allow for carry out */
10838 
10839  digitbuf_free(result->buf);
10840  result->ndigits = res_ndigits;
10841  result->buf = res_buf;
10842  result->digits = res_digits;
10843  result->weight = res_weight;
10844  result->dscale = res_dscale;
10845 
10846  /* Remove leading/trailing zeroes */
10847  strip_var(result);
10848 }
#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 7979 of file numeric.c.

7980 {
7981  /*
7982  * Decide on the signs of the two variables what to do
7983  */
7984  if (var1->sign == NUMERIC_POS)
7985  {
7986  if (var2->sign == NUMERIC_POS)
7987  {
7988  /*
7989  * Both are positive result = +(ABS(var1) + ABS(var2))
7990  */
7991  add_abs(var1, var2, result);
7992  result->sign = NUMERIC_POS;
7993  }
7994  else
7995  {
7996  /*
7997  * var1 is positive, var2 is negative Must compare absolute values
7998  */
7999  switch (cmp_abs(var1, var2))
8000  {
8001  case 0:
8002  /* ----------
8003  * ABS(var1) == ABS(var2)
8004  * result = ZERO
8005  * ----------
8006  */
8007  zero_var(result);
8008  result->dscale = Max(var1->dscale, var2->dscale);
8009  break;
8010 
8011  case 1:
8012  /* ----------
8013  * ABS(var1) > ABS(var2)
8014  * result = +(ABS(var1) - ABS(var2))
8015  * ----------
8016  */
8017  sub_abs(var1, var2, result);
8018  result->sign = NUMERIC_POS;
8019  break;
8020 
8021  case -1:
8022  /* ----------
8023  * ABS(var1) < ABS(var2)
8024  * result = -(ABS(var2) - ABS(var1))
8025  * ----------
8026  */
8027  sub_abs(var2, var1, result);
8028  result->sign = NUMERIC_NEG;
8029  break;
8030  }
8031  }
8032  }
8033  else
8034  {
8035  if (var2->sign == NUMERIC_POS)
8036  {
8037  /* ----------
8038  * var1 is negative, var2 is positive
8039  * Must compare absolute values
8040  * ----------
8041  */
8042  switch (cmp_abs(var1, var2))
8043  {
8044  case 0:
8045  /* ----------
8046  * ABS(var1) == ABS(var2)
8047  * result = ZERO
8048  * ----------
8049  */
8050  zero_var(result);
8051  result->dscale = Max(var1->dscale, var2->dscale);
8052  break;
8053 
8054  case 1:
8055  /* ----------
8056  * ABS(var1) > ABS(var2)
8057  * result = -(ABS(var1) - ABS(var2))
8058  * ----------
8059  */
8060  sub_abs(var1, var2, result);
8061  result->sign = NUMERIC_NEG;
8062  break;
8063 
8064  case -1:
8065  /* ----------
8066  * ABS(var1) < ABS(var2)
8067  * result = +(ABS(var2) - ABS(var1))
8068  * ----------
8069  */
8070  sub_abs(var2, var1, result);
8071  result->sign = NUMERIC_POS;
8072  break;
8073  }
8074  }
8075  else
8076  {
8077  /* ----------
8078  * Both are negative
8079  * result = -(ABS(var1) + ABS(var2))
8080  * ----------
8081  */
8082  add_abs(var1, var2, result);
8083  result->sign = NUMERIC_NEG;
8084  }
8085  }
8086 }
static void sub_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:10861
static void add_abs(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:10776
static void zero_var(NumericVar *var)
Definition: numeric.c:6790
static int cmp_abs(const NumericVar *var1, const NumericVar *var2)
Definition: numeric.c:10698

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(), sqrt_var(), and width_bucket_numeric().

◆ alloc_var()

static void alloc_var ( NumericVar var,
int  ndigits 
)
static

Definition at line 6758 of file numeric.c.

6759 {
6760  digitbuf_free(var->buf);
6761  var->buf = digitbuf_alloc(ndigits + 1);
6762  var->buf[0] = 0; /* spare digit for rounding */
6763  var->digits = var->buf + 1;
6764  var->ndigits = ndigits;
6765 }

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 void apply_typmod ( NumericVar var,
int32  typmod 
)
static

Definition at line 7460 of file numeric.c.

7461 {
7462  int precision;
7463  int scale;
7464  int maxdigits;
7465  int ddigits;
7466  int i;
7467 
7468  /* Do nothing if we have an invalid typmod */
7469  if (!is_valid_numeric_typmod(typmod))
7470  return;
7471 
7472  precision = numeric_typmod_precision(typmod);
7473  scale = numeric_typmod_scale(typmod);
7474  maxdigits = precision - scale;
7475 
7476  /* Round to target scale (and set var->dscale) */
7477  round_var(var, scale);
7478 
7479  /* but don't allow var->dscale to be negative */
7480  if (var->dscale < 0)
7481  var->dscale = 0;
7482 
7483  /*
7484  * Check for overflow - note we can't do this before rounding, because
7485  * rounding could raise the weight. Also note that the var's weight could
7486  * be inflated by leading zeroes, which will be stripped before storage
7487  * but perhaps might not have been yet. In any case, we must recognize a
7488  * true zero, whose weight doesn't mean anything.
7489  */
7490  ddigits = (var->weight + 1) * DEC_DIGITS;
7491  if (ddigits > maxdigits)
7492  {
7493  /* Determine true weight; and check for all-zero result */
7494  for (i = 0; i < var->ndigits; i++)
7495  {
7496  NumericDigit dig = var->digits[i];
7497 
7498  if (dig)
7499  {
7500  /* Adjust for any high-order decimal zero digits */
7501 #if DEC_DIGITS == 4
7502  if (dig < 10)
7503  ddigits -= 3;
7504  else if (dig < 100)
7505  ddigits -= 2;
7506  else if (dig < 1000)
7507  ddigits -= 1;
7508 #elif DEC_DIGITS == 2
7509  if (dig < 10)
7510  ddigits -= 1;
7511 #elif DEC_DIGITS == 1
7512  /* no adjustment */
7513 #else
7514 #error unsupported NBASE
7515 #endif
7516  if (ddigits > maxdigits)
7517  ereport(ERROR,
7518  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7519  errmsg("numeric field overflow"),
7520  errdetail("A field with precision %d, scale %d must round to an absolute value less than %s%d.",
7521  precision, scale,
7522  /* Display 10^0 as 1 */
7523  maxdigits ? "10^" : "",
7524  maxdigits ? maxdigits : 1
7525  )));
7526  break;
7527  }
7528  ddigits -= DEC_DIGITS;
7529  }
7530  }
7531 }
static bool is_valid_numeric_typmod(int32 typmod)
Definition: numeric.c:835
static int numeric_typmod_scale(int32 typmod)
Definition: numeric.c:861
static int numeric_typmod_precision(int32 typmod)
Definition: numeric.c:846
static void round_var(NumericVar *var, int rscale)
Definition: numeric.c:10943
#define DEC_DIGITS
Definition: numeric.c:98
int errdetail(const char *fmt,...)
Definition: elog.c:1037
int errcode(int sqlerrcode)
Definition: elog.c:693
int errmsg(const char *fmt,...)
Definition: elog.c:904
#define ERROR
Definition: elog.h:33
#define ereport(elevel,...)
Definition: elog.h:143
int maxdigits
Definition: informix.c:665

References DEC_DIGITS, NumericVar::digits, NumericVar::dscale, ereport, errcode(), errdetail(), errmsg(), ERROR, 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 void apply_typmod_special ( Numeric  num,
int32  typmod 
)
static

Definition at line 7540 of file numeric.c.

7541 {
7542  int precision;
7543  int scale;
7544 
7545  Assert(NUMERIC_IS_SPECIAL(num)); /* caller error if not */
7546 
7547  /*
7548  * NaN is allowed regardless of the typmod; that's rather dubious perhaps,
7549  * but it's a longstanding behavior. Inf is rejected if we have any
7550  * typmod restriction, since an infinity shouldn't be claimed to fit in
7551  * any finite number of digits.
7552  */
7553  if (NUMERIC_IS_NAN(num))
7554  return;
7555 
7556  /* Do nothing if we have a default typmod (-1) */
7557  if (!is_valid_numeric_typmod(typmod))
7558  return;
7559 
7560  precision = numeric_typmod_precision(typmod);
7561  scale = numeric_typmod_scale(typmod);
7562 
7563  ereport(ERROR,
7564  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
7565  errmsg("numeric field overflow"),
7566  errdetail("A field with precision %d, scale %d cannot hold an infinite value.",
7567  precision, scale)));
7568 }
#define NUMERIC_IS_NAN(n)
Definition: numeric.c:204

References Assert(), ereport, errcode(), errdetail(), errmsg(), ERROR, 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 9330 of file numeric.c.

9331 {
9332  NumericVar tmp;
9333 
9334  init_var(&tmp);
9335  set_var_from_var(var, &tmp);
9336 
9337  trunc_var(&tmp, 0);
9338 
9339  if (var->sign == NUMERIC_POS && cmp_var(var, &tmp) != 0)
9340  add_var(&tmp, &const_one, &tmp);
9341 
9342  set_var_from_var(&tmp, result);
9343  free_var(&tmp);
9344 }
static void trunc_var(NumericVar *var, int rscale)
Definition: numeric.c:11049
static int cmp_var(const NumericVar *var1, const NumericVar *var2)
Definition: numeric.c:7921
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 10698 of file numeric.c.

10699 {
10700  return cmp_abs_common(var1->digits, var1->ndigits, var1->weight,
10701  var2->digits, var2->ndigits, var2->weight);
10702 }
static int cmp_abs_common(const NumericDigit *var1digits, int var1ndigits, int var1weight, const NumericDigit *var2digits, int var2ndigits, int var2weight)
Definition: numeric.c:10712

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

10714 {
10715  int i1 = 0;
10716  int i2 = 0;
10717 
10718  /* Check any digits before the first common digit */
10719 
10720  while (var1weight > var2weight && i1 < var1ndigits)
10721  {
10722  if (var1digits[i1++] != 0)
10723  return 1;
10724  var1weight--;
10725  }
10726  while (var2weight > var1weight && i2 < var2ndigits)
10727  {
10728  if (var2digits[i2++] != 0)
10729  return -1;
10730  var2weight--;
10731  }
10732 
10733  /* At this point, either w1 == w2 or we've run out of digits */
10734 
10735  if (var1weight == var2weight)
10736  {
10737  while (i1 < var1ndigits && i2 < var2ndigits)
10738  {
10739  int stat = var1digits[i1++] - var2digits[i2++];
10740 
10741  if (stat)
10742  {
10743  if (stat > 0)
10744  return 1;
10745  return -1;
10746  }
10747  }
10748  }
10749 
10750  /*
10751  * At this point, we've run out of digits on one side or the other; so any
10752  * remaining nonzero digits imply that side is larger
10753  */
10754  while (i1 < var1ndigits)
10755  {
10756  if (var1digits[i1++] != 0)
10757  return 1;
10758  }
10759  while (i2 < var2ndigits)
10760  {
10761  if (var2digits[i2++] != 0)
10762  return -1;
10763  }
10764 
10765  return 0;
10766 }

Referenced by cmp_abs(), and cmp_var_common().

◆ cmp_numerics()

static int cmp_numerics ( Numeric  num1,
Numeric  num2 
)
static

Definition at line 2422 of file numeric.c.

2423 {
2424  int result;
2425 
2426  /*
2427  * We consider all NANs to be equal and larger than any non-NAN (including
2428  * Infinity). This is somewhat arbitrary; the important thing is to have
2429  * a consistent sort order.
2430  */
2431  if (NUMERIC_IS_SPECIAL(num1))
2432  {
2433  if (NUMERIC_IS_NAN(num1))
2434  {
2435  if (NUMERIC_IS_NAN(num2))
2436  result = 0; /* NAN = NAN */
2437  else
2438  result = 1; /* NAN > non-NAN */
2439  }
2440  else if (NUMERIC_IS_PINF(num1))
2441  {
2442  if (NUMERIC_IS_NAN(num2))
2443  result = -1; /* PINF < NAN */
2444  else if (NUMERIC_IS_PINF(num2))
2445  result = 0; /* PINF = PINF */
2446  else
2447  result = 1; /* PINF > anything else */
2448  }
2449  else /* num1 must be NINF */
2450  {
2451  if (NUMERIC_IS_NINF(num2))
2452  result = 0; /* NINF = NINF */
2453  else
2454  result = -1; /* NINF < anything else */
2455  }
2456  }
2457  else if (NUMERIC_IS_SPECIAL(num2))
2458  {
2459  if (NUMERIC_IS_NINF(num2))
2460  result = 1; /* normal > NINF */
2461  else
2462  result = -1; /* normal < NAN or PINF */
2463  }
2464  else
2465  {
2466  result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1),
2467  NUMERIC_WEIGHT(num1), NUMERIC_SIGN(num1),
2468  NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2),
2469  NUMERIC_WEIGHT(num2), NUMERIC_SIGN(num2));
2470  }
2471 
2472  return result;
2473 }
#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:7936

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

7940 {
7941  if (var1ndigits == 0)
7942  {
7943  if (var2ndigits == 0)
7944  return 0;
7945  if (var2sign == NUMERIC_NEG)
7946  return 1;
7947  return -1;
7948  }
7949  if (var2ndigits == 0)
7950  {
7951  if (var1sign == NUMERIC_POS)
7952  return 1;
7953  return -1;
7954  }
7955 
7956  if (var1sign == NUMERIC_POS)
7957  {
7958  if (var2sign == NUMERIC_NEG)
7959  return 1;
7960  return cmp_abs_common(var1digits, var1ndigits, var1weight,
7961  var2digits, var2ndigits, var2weight);
7962  }
7963 
7964  if (var2sign == NUMERIC_POS)
7965  return -1;
7966 
7967  return cmp_abs_common(var2digits, var2ndigits, var2weight,
7968  var1digits, var1ndigits, var1weight);
7969 }

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

1848 {
1849  NumericVar bound1_var;
1850  NumericVar bound2_var;
1851  NumericVar operand_var;
1852 
1853  init_var_from_num(bound1, &bound1_var);
1854  init_var_from_num(bound2, &bound2_var);
1855  init_var_from_num(operand, &operand_var);
1856 
1857  if (!reversed_bounds)
1858  {
1859  sub_var(&operand_var, &bound1_var, &operand_var);
1860  sub_var(&bound2_var, &bound1_var, &bound2_var);
1861  }
1862  else
1863  {
1864  sub_var(&bound1_var, &operand_var, &operand_var);
1865  sub_var(&bound1_var, &bound2_var, &bound2_var);
1866  }
1867 
1868  mul_var(&operand_var, count_var, &operand_var,
1869  operand_var.dscale + count_var->dscale);
1870  div_var(&operand_var, &bound2_var, result_var,
1871  select_div_scale(&operand_var, &bound2_var), true);
1872  add_var(result_var, &const_one, result_var);
1873  floor_var(result_var, result_var);
1874 
1875  free_var(&bound1_var);
1876  free_var(&bound2_var);
1877  free_var(&operand_var);
1878 }
static void sub_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:8096
static void floor_var(const NumericVar *var, NumericVar *result)
Definition: numeric.c:9354
static void init_var_from_num(Numeric num, NumericVar *dest)
Definition: numeric.c:7007
static void mul_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale)
Definition: numeric.c:8217
static int select_div_scale(const NumericVar *var1, const NumericVar *var2)
Definition: numeric.c:9162
static void div_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale, bool round)
Definition: numeric.c:8425

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

9262 {
9263  NumericVar q;
9264  NumericVar r;
9265 
9266  init_var(&q);
9267  init_var(&r);
9268 
9269  /*
9270  * Use div_var_fast() to get an initial estimate for the integer quotient.
9271  * This might be inaccurate (per the warning in div_var_fast's comments),
9272  * but we can correct it below.
9273  */
9274  div_var_fast(var1, var2, &q, 0, false);
9275 
9276  /* Compute initial estimate of remainder using the quotient estimate. */
9277  mul_var(var2, &q, &r, var2->dscale);
9278  sub_var(var1, &r, &r);
9279 
9280  /*
9281  * Adjust the results if necessary --- the remainder should have the same
9282  * sign as var1, and its absolute value should be less than the absolute
9283  * value of var2.
9284  */
9285  while (r.ndigits != 0 && r.sign != var1->sign)
9286  {
9287  /* The absolute value of the quotient is too large */
9288  if (var1->sign == var2->sign)
9289  {
9290  sub_var(&q, &const_one, &q);
9291  add_var(&r, var2, &r);
9292  }
9293  else
9294  {
9295  add_var(&q, &const_one, &q);
9296  sub_var(&r, var2, &r);
9297  }
9298  }
9299 
9300  while (cmp_abs(&r, var2) >= 0)
9301  {
9302  /* The absolute value of the quotient is too small */
9303  if (var1->sign == var2->sign)
9304  {
9305  add_var(&q, &const_one, &q);
9306  sub_var(&r, var2, &r);
9307  }
9308  else
9309  {
9310  sub_var(&q, &const_one, &q);
9311  add_var(&r, var2, &r);
9312  }
9313  }
9314 
9315  set_var_from_var(&q, quot);
9316  set_var_from_var(&r, rem);
9317 
9318  free_var(&q);
9319  free_var(&r);
9320 }
static void div_var_fast(const NumericVar *var1, const NumericVar *var2, NumericVar *result, int rscale, bool round)
Definition: numeric.c:8710

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

8427 {
8428  int div_ndigits;
8429  int res_ndigits;
8430  int res_sign;
8431  int res_weight;
8432  int carry;
8433  int borrow;
8434  int divisor1;
8435  int divisor2;
8436  NumericDigit *dividend;
8437  NumericDigit *divisor;
8438  NumericDigit *res_digits;
8439  int i;
8440  int j;
8441 
8442  /* copy these values into local vars for speed in inner loop */
8443  int var1ndigits = var1->ndigits;
8444  int var2ndigits = var2->ndigits;
8445 
8446  /*
8447  * First of all division by zero check; we must not be handed an
8448  * unnormalized divisor.
8449  */
8450  if (var2ndigits == 0 || var2->digits[0] == 0)
8451  ereport(ERROR,
8452  (errcode(ERRCODE_DIVISION_BY_ZERO),
8453  errmsg("division by zero")));
8454 
8455  /*
8456  * If the divisor has just one or two digits, delegate to div_var_int(),
8457  * which uses fast short division.
8458  */
8459  if (var2ndigits <= 2)
8460  {
8461  int idivisor;
8462  int idivisor_weight;
8463 
8464  idivisor = var2->digits[0];
8465  idivisor_weight = var2->weight;
8466  if (var2ndigits == 2)
8467  {
8468  idivisor = idivisor * NBASE + var2->digits[1];
8469  idivisor_weight--;
8470  }
8471  if (var2->sign == NUMERIC_NEG)
8472  idivisor = -idivisor;
8473 
8474  div_var_int(var1, idivisor, idivisor_weight, result, rscale, round);
8475  return;
8476  }
8477 
8478  /*
8479  * Otherwise, perform full long division.
8480  */
8481 
8482  /* Result zero check */
8483  if (var1ndigits == 0)
8484  {
8485  zero_var(result);
8486  result->dscale = rscale;
8487  return;
8488  }
8489 
8490  /*
8491  * Determine the result sign, weight and number of digits to calculate.
8492  * The weight figured here is correct if the emitted quotient has no
8493  * leading zero digits; otherwise strip_var() will fix things up.
8494  */
8495  if (var1->sign == var2->sign)
8496  res_sign = NUMERIC_POS;
8497  else
8498  res_sign = NUMERIC_NEG;
8499  res_weight = var1->weight - var2->weight;
8500  /* The number of accurate result digits we need to produce: */
8501  res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
8502  /* ... but always at least 1 */
8503  res_ndigits = Max(res_ndigits, 1);
8504  /* If rounding needed, figure one more digit to ensure correct result */
8505  if (round)
8506  res_ndigits++;
8507 
8508  /*
8509  * The working dividend normally requires res_ndigits + var2ndigits
8510  * digits, but make it at least var1ndigits so we can load all of var1
8511  * into it. (There will be an additional digit dividend[0] in the
8512  * dividend space, but for consistency with Knuth's notation we don't
8513  * count that in div_ndigits.)
8514  */
8515  div_ndigits = res_ndigits + var2ndigits;
8516  div_ndigits = Max(div_ndigits, var1ndigits);
8517 
8518  /*
8519  * We need a workspace with room for the working dividend (div_ndigits+1
8520  * digits) plus room for the possibly-normalized divisor (var2ndigits
8521  * digits). It is convenient also to have a zero at divisor[0] with the
8522  * actual divisor data in divisor[1 .. var2ndigits]. Transferring the
8523  * digits into the workspace also allows us to realloc the result (which
8524  * might be the same as either input var) before we begin the main loop.
8525  * Note that we use palloc0 to ensure that divisor[0], dividend[0], and
8526  * any additional dividend positions beyond var1ndigits, start out 0.
8527  */
8528  dividend = (NumericDigit *)
8529  palloc0((div_ndigits + var2ndigits + 2) * sizeof(NumericDigit));
8530  divisor = dividend + (div_ndigits + 1);
8531  memcpy(dividend + 1, var1->digits, var1ndigits * sizeof(NumericDigit));
8532  memcpy(divisor + 1, var2->digits, var2ndigits * sizeof(NumericDigit));
8533 
8534  /*
8535  * Now we can realloc the result to hold the generated quotient digits.
8536  */
8537  alloc_var(result, res_ndigits);
8538  res_digits = result->digits;
8539 
8540  /*
8541  * The full multiple-place algorithm is taken from Knuth volume 2,
8542  * Algorithm 4.3.1D.
8543  *
8544  * We need the first divisor digit to be >= NBASE/2. If it isn't, make it
8545  * so by scaling up both the divisor and dividend by the factor "d". (The
8546  * reason for allocating dividend[0] above is to leave room for possible
8547  * carry here.)
8548  */
8549  if (divisor[1] < HALF_NBASE)
8550  {
8551  int d = NBASE / (divisor[1] + 1);
8552 
8553  carry = 0;
8554  for (i = var2ndigits; i > 0; i--)
8555  {
8556  carry += divisor[i] * d;
8557  divisor[i] = carry % NBASE;
8558  carry = carry / NBASE;
8559  }
8560  Assert(carry == 0);
8561  carry = 0;
8562  /* at this point only var1ndigits of dividend can be nonzero */
8563  for (i = var1ndigits; i >= 0; i--)
8564  {
8565  carry += dividend[i] * d;
8566  dividend[i] = carry % NBASE;
8567  carry = carry / NBASE;
8568  }
8569  Assert(carry == 0);
8570  Assert(divisor[1] >= HALF_NBASE);
8571  }
8572  /* First 2 divisor digits are used repeatedly in main loop */
8573  divisor1 = divisor[1];
8574  divisor2 = divisor[2];
8575 
8576  /*
8577  * Begin the main loop. Each iteration of this loop produces the j'th
8578  * quotient digit by dividing dividend[j .. j + var2ndigits] by the
8579  * divisor; this is essentially the same as the common manual procedure
8580  * for long division.
8581  */
8582  for (j = 0; j < res_ndigits; j++)
8583  {
8584  /* Estimate quotient digit from the first two dividend digits */
8585  int next2digits = dividend[j] * NBASE + dividend[j + 1];
8586  int qhat;
8587 
8588  /*
8589  * If next2digits are 0, then quotient digit must be 0 and there's no
8590  * need to adjust the working dividend. It's worth testing here to
8591  * fall out ASAP when processing trailing zeroes in a dividend.
8592  */
8593  if (next2digits == 0)
8594  {
8595  res_digits[j] = 0;
8596  continue;
8597  }
8598 
8599  if (dividend[j] == divisor1)
8600  qhat = NBASE - 1;
8601  else
8602  qhat = next2digits / divisor1;
8603 
8604  /*
8605  * Adjust quotient digit if it's too large. Knuth proves that after
8606  * this step, the quotient digit will be either correct or just one
8607  * too large. (Note: it's OK to use dividend[j+2] here because we
8608  * know the divisor length is at least 2.)
8609  */
8610  while (divisor2 * qhat >
8611  (next2digits - qhat * divisor1) * NBASE + dividend[j + 2])
8612  qhat--;
8613 
8614  /* As above, need do nothing more when quotient digit is 0 */
8615  if (qhat > 0)
8616  {
8617  NumericDigit *dividend_j = &dividend[j];
8618 
8619  /*
8620  * Multiply the divisor by qhat, and subtract that from the
8621  * working dividend. The multiplication and subtraction are
8622  * folded together here, noting that qhat <= NBASE (since it might
8623  * be one too large), and so the intermediate result "tmp_result"
8624  * is in the range [-NBASE^2, NBASE - 1], and "borrow" is in the
8625  * range [0, NBASE].
8626  */
8627  borrow = 0;
8628  for (i = var2ndigits; i >= 0; i--)
8629  {
8630  int tmp_result;
8631 
8632  tmp_result = dividend_j[i] - borrow - divisor[i] * qhat;
8633  borrow = (NBASE - 1 - tmp_result) / NBASE;
8634  dividend_j[i] = tmp_result + borrow * NBASE;
8635  }
8636 
8637  /*
8638  * If we got a borrow out of the top dividend digit, then indeed
8639  * qhat was one too large. Fix it, and add back the divisor to
8640  * correct the working dividend. (Knuth proves that this will
8641  * occur only about 3/NBASE of the time; hence, it's a good idea
8642  * to test this code with small NBASE to be sure this section gets
8643  * exercised.)
8644  */
8645  if (borrow)
8646  {
8647  qhat--;
8648  carry = 0;
8649  for (i = var2ndigits; i >= 0; i--)
8650  {
8651  carry += dividend_j[i] + divisor[i];
8652  if (carry >= NBASE)
8653  {
8654  dividend_j[i] = carry - NBASE;
8655  carry = 1;
8656  }
8657  else
8658  {
8659  dividend_j[i] = carry;
8660  carry = 0;
8661  }
8662  }
8663  /* A carry should occur here to cancel the borrow above */
8664  Assert(carry == 1);
8665  }
8666  }
8667 
8668  /* And we're done with this quotient digit */
8669  res_digits[j] = qhat;
8670  }
8671 
8672  pfree(dividend);
8673 
8674  /*
8675  * Finally, round or truncate the result to the requested precision.
8676  */
8677  result->weight = res_weight;
8678  result->sign = res_sign;
8679 
8680  /* Round or truncate to target rscale (and set result->dscale) */
8681  if (round)
8682  round_var(result, rscale);
8683  else
8684  trunc_var(result, rscale);
8685 
8686  /* Strip leading and trailing zeroes */
8687  strip_var(result);
8688 }
static void div_var_int(const NumericVar *var, int ival, int ival_weight, NumericVar *result, int rscale, bool round)
Definition: numeric.c:9051
static void alloc_var(NumericVar *var, int ndigits)
Definition: numeric.c:6758
#define HALF_NBASE
Definition: numeric.c:97
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 8710 of file numeric.c.

8712 {
8713  int div_ndigits;
8714  int load_ndigits;
8715  int res_sign;
8716  int res_weight;
8717  int *div;
8718  int qdigit;
8719  int carry;
8720  int maxdiv;
8721  int newdig;
8722  NumericDigit *res_digits;
8723  double fdividend,
8724  fdivisor,
8725  fdivisorinverse,
8726  fquotient;
8727  int qi;
8728  int i;
8729 
8730  /* copy these values into local vars for speed in inner loop */
8731  int var1ndigits = var1->ndigits;
8732  int var2ndigits = var2->ndigits;
8733  NumericDigit *var1digits = var1->digits;
8734  NumericDigit *var2digits = var2->digits;
8735 
8736  /*
8737  * First of all division by zero check; we must not be handed an
8738  * unnormalized divisor.
8739  */
8740  if (var2ndigits == 0 || var2digits[0] == 0)
8741  ereport(ERROR,
8742  (errcode(ERRCODE_DIVISION_BY_ZERO),
8743  errmsg("division by zero")));
8744 
8745  /*
8746  * If the divisor has just one or two digits, delegate to div_var_int(),
8747  * which uses fast short division.
8748  */
8749  if (var2ndigits <= 2)
8750  {
8751  int idivisor;
8752  int idivisor_weight;
8753 
8754  idivisor = var2->digits[0];
8755  idivisor_weight = var2->weight;
8756  if (var2ndigits == 2)
8757  {
8758  idivisor = idivisor * NBASE + var2->digits[1];
8759  idivisor_weight--;
8760  }
8761  if (var2->sign == NUMERIC_NEG)
8762  idivisor = -idivisor;
8763 
8764  div_var_int(var1, idivisor, idivisor_weight, result, rscale, round);
8765  return;
8766  }
8767 
8768  /*
8769  * Otherwise, perform full long division.
8770  */
8771 
8772  /* Result zero check */
8773  if (var1ndigits == 0)
8774  {
8775  zero_var(result);
8776  result->dscale = rscale;
8777  return;
8778  }
8779 
8780  /*
8781  * Determine the result sign, weight and number of digits to calculate
8782  */
8783  if (var1->sign == var2->sign)
8784  res_sign = NUMERIC_POS;
8785  else
8786  res_sign = NUMERIC_NEG;
8787  res_weight = var1->weight - var2->weight + 1;
8788  /* The number of accurate result digits we need to produce: */
8789  div_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
8790  /* Add guard digits for roundoff error */
8791  div_ndigits += DIV_GUARD_DIGITS;
8792  if (div_ndigits < DIV_GUARD_DIGITS)
8793  div_ndigits = DIV_GUARD_DIGITS;
8794 
8795  /*
8796  * We do the arithmetic in an array "div[]" of signed int's. Since
8797  * INT_MAX is noticeably larger than NBASE*NBASE, this gives us headroom
8798  * to avoid normalizing carries immediately.
8799  *
8800  * We start with div[] containing one zero digit followed by the
8801  * dividend's digits (plus appended zeroes to reach the desired precision
8802  * including guard digits). Each step of the main loop computes an
8803  * (approximate) quotient digit and stores it into div[], removing one
8804  * position of dividend space. A final pass of carry propagation takes
8805  * care of any mistaken quotient digits.
8806  *
8807  * Note that div[] doesn't necessarily contain all of the digits from the
8808  * dividend --- the desired precision plus guard digits might be less than
8809  * the dividend's precision. This happens, for example, in the square
8810  * root algorithm, where we typically divide a 2N-digit number by an
8811  * N-digit number, and only require a result with N digits of precision.
8812  */
8813  div = (int *) palloc0((div_ndigits + 1) * sizeof(int));
8814  load_ndigits = Min(div_ndigits, var1ndigits);
8815  for (i = 0; i < load_ndigits; i++)
8816  div[i + 1] = var1digits[i];
8817 
8818  /*
8819  * We estimate each quotient digit using floating-point arithmetic, taking
8820  * the first four digits of the (current) dividend and divisor. This must
8821  * be float to avoid overflow. The quotient digits will generally be off
8822  * by no more than one from the exact answer.
8823  */
8824  fdivisor = (double) var2digits[0];
8825  for (i = 1; i < 4; i++)
8826  {
8827  fdivisor *= NBASE;
8828  if (i < var2ndigits)
8829  fdivisor += (double) var2digits[i];
8830  }
8831  fdivisorinverse = 1.0 / fdivisor;
8832 
8833  /*
8834  * maxdiv tracks the maximum possible absolute value of any div[] entry;
8835  * when this threatens to exceed INT_MAX, we take the time to propagate
8836  * carries. Furthermore, we need to ensure that overflow doesn't occur
8837  * during the carry propagation passes either. The carry values may have
8838  * an absolute value as high as INT_MAX/NBASE + 1, so really we must
8839  * normalize when digits threaten to exceed INT_MAX - INT_MAX/NBASE - 1.
8840  *
8841  * To avoid overflow in maxdiv itself, it represents the max absolute
8842  * value divided by NBASE-1, ie, at the top of the loop it is known that
8843  * no div[] entry has an absolute value exceeding maxdiv * (NBASE-1).
8844  *
8845  * Actually, though, that holds good only for div[] entries after div[qi];
8846  * the adjustment done at the bottom of the loop may cause div[qi + 1] to
8847  * exceed the maxdiv limit, so that div[qi] in the next iteration is
8848  * beyond the limit. This does not cause problems, as explained below.
8849  */
8850  maxdiv = 1;
8851 
8852  /*
8853  * Outer loop computes next quotient digit, which will go into div[qi]
8854  */
8855  for (qi = 0; qi < div_ndigits; qi++)
8856  {
8857  /* Approximate the current dividend value */
8858  fdividend = (double) div[qi];
8859  for (i = 1; i < 4; i++)
8860  {
8861  fdividend *= NBASE;
8862  if (qi + i <= div_ndigits)
8863  fdividend += (double) div[qi + i];
8864  }
8865  /* Compute the (approximate) quotient digit */
8866  fquotient = fdividend * fdivisorinverse;
8867  qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
8868  (((int) fquotient) - 1); /* truncate towards -infinity */
8869 
8870  if (qdigit != 0)
8871  {
8872  /* Do we need to normalize now? */
8873  maxdiv += Abs(qdigit);
8874  if (maxdiv > (INT_MAX - INT_MAX / NBASE - 1) / (NBASE - 1))
8875  {
8876  /*
8877  * Yes, do it. Note that if var2ndigits is much smaller than
8878  * div_ndigits, we can save a significant amount of effort
8879  * here by noting that we only need to normalise those div[]
8880  * entries touched where prior iterations subtracted multiples
8881  * of the divisor.
8882  */
8883  carry = 0;
8884  for (i = Min(qi + var2ndigits - 2, div_ndigits); i > qi; i--)
8885  {
8886  newdig = div[i] + carry;
8887  if (newdig < 0)
8888  {
8889  carry = -((-newdig - 1) / NBASE) - 1;
8890  newdig -= carry * NBASE;
8891  }
8892  else if (newdig >= NBASE)
8893  {
8894  carry = newdig / NBASE;
8895  newdig -= carry * NBASE;
8896  }
8897  else
8898  carry = 0;
8899  div[i] = newdig;
8900  }
8901  newdig = div[qi] + carry;
8902  div[qi] = newdig;
8903 
8904  /*
8905  * All the div[] digits except possibly div[qi] are now in the
8906  * range 0..NBASE-1. We do not need to consider div[qi] in
8907  * the maxdiv value anymore, so we can reset maxdiv to 1.
8908  */
8909  maxdiv = 1;
8910 
8911  /*
8912  * Recompute the quotient digit since new info may have
8913  * propagated into the top four dividend digits
8914  */
8915  fdividend = (double) div[qi];
8916  for (i = 1; i < 4; i++)
8917  {
8918  fdividend *= NBASE;
8919  if (qi + i <= div_ndigits)
8920  fdividend += (double) div[qi + i];
8921  }
8922  /* Compute the (approximate) quotient digit */
8923  fquotient = fdividend * fdivisorinverse;
8924  qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
8925  (((int) fquotient) - 1); /* truncate towards -infinity */
8926  maxdiv += Abs(qdigit);
8927  }
8928 
8929  /*
8930  * Subtract off the appropriate multiple of the divisor.
8931  *
8932  * The digits beyond div[qi] cannot overflow, because we know they
8933  * will fall within the maxdiv limit. As for div[qi] itself, note
8934  * that qdigit is approximately trunc(div[qi] / vardigits[0]),
8935  * which would make the new value simply div[qi] mod vardigits[0].
8936  * The lower-order terms in qdigit can change this result by not
8937  * more than about twice INT_MAX/NBASE, so overflow is impossible.
8938  *
8939  * This inner loop is the performance bottleneck for division, so
8940  * code it in the same way as the inner loop of mul_var() so that
8941  * it can be auto-vectorized. We cast qdigit to NumericDigit
8942  * before multiplying to allow the compiler to generate more
8943  * efficient code (using 16-bit multiplication), which is safe
8944  * since we know that the quotient digit is off by at most one, so
8945  * there is no overflow risk.
8946  */
8947  if (qdigit != 0)
8948  {
8949  int istop = Min(var2ndigits, div_ndigits - qi + 1);
8950  int *div_qi = &div[qi];
8951 
8952  for (i = 0; i < istop; i++)
8953  div_qi[i] -= ((NumericDigit) qdigit) * var2digits[i];
8954  }
8955  }
8956 
8957  /*
8958  * The dividend digit we are about to replace might still be nonzero.
8959  * Fold it into the next digit position.
8960  *
8961  * There is no risk of overflow here, although proving that requires
8962  * some care. Much as with the argument for div[qi] not overflowing,
8963  * if we consider the first two terms in the numerator and denominator
8964  * of qdigit, we can see that the final value of div[qi + 1] will be
8965  * approximately a remainder mod (vardigits[0]*NBASE + vardigits[1]).
8966  * Accounting for the lower-order terms is a bit complicated but ends
8967  * up adding not much more than INT_MAX/NBASE to the possible range.
8968  * Thus, div[qi + 1] cannot overflow here, and in its role as div[qi]
8969  * in the next loop iteration, it can't be large enough to cause
8970  * overflow in the carry propagation step (if any), either.
8971  *
8972  * But having said that: div[qi] can be more than INT_MAX/NBASE, as
8973  * noted above, which means that the product div[qi] * NBASE *can*
8974  * overflow. When that happens, adding it to div[qi + 1] will always
8975  * cause a canceling overflow so that the end result is correct. We
8976  * could avoid the intermediate overflow by doing the multiplication
8977  * and addition in int64 arithmetic, but so far there appears no need.
8978  */
8979  div[qi + 1] += div[qi] * NBASE;
8980 
8981  div[qi] = qdigit;
8982  }
8983 
8984  /*
8985  * Approximate and store the last quotient digit (div[div_ndigits])
8986  */
8987  fdividend = (double) div[qi];
8988  for (i = 1; i < 4; i++)
8989  fdividend *= NBASE;
8990  fquotient = fdividend * fdivisorinverse;
8991  qdigit = (fquotient >= 0.0) ? ((int) fquotient) :
8992  (((int) fquotient) - 1); /* truncate towards -infinity */
8993  div[qi] = qdigit;
8994 
8995  /*
8996  * Because the quotient digits might be off by one, some of them might be
8997  * -1 or NBASE at this point. The represented value is correct in a
8998  * mathematical sense, but it doesn't look right. We do a final carry
8999  * propagation pass to normalize the digits, which we combine with storing
9000  * the result digits into the output. Note that this is still done at
9001  * full precision w/guard digits.
9002  */
9003  alloc_var(result, div_ndigits + 1);
9004  res_digits = result->digits;
9005  carry = 0;
9006  for (i = div_ndigits; i >= 0; i--)
9007  {
9008  newdig = div[i] + carry;
9009  if (newdig < 0)
9010  {
9011  carry = -((-newdig - 1) / NBASE) - 1;
9012  newdig -= carry * NBASE;
9013  }
9014  else if (newdig >= NBASE)
9015  {
9016  carry = newdig / NBASE;
9017  newdig -= carry * NBASE;
9018  }
9019  else
9020  carry = 0;
9021  res_digits[i] = newdig;
9022  }
9023  Assert(carry == 0);
9024 
9025  pfree(div);
9026 
9027  /*
9028  * Finally, round the result to the requested precision.
9029  */
9030  result->weight = res_weight;
9031  result->sign = res_sign;
9032 
9033  /* Round to target rscale (and set result->dscale) */
9034  if (round)
9035  round_var(result, rscale);
9036  else
9037  trunc_var(result, rscale);
9038 
9039  /* Strip leading and trailing zeroes */
9040  strip_var(result);
9041 }
#define DIV_GUARD_DIGITS
Definition: numeric.c:100
#define Abs(x)
Definition: c.h:992
#define Min(x, y)
Definition: numeric.c:14

References Abs, 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 9051 of file numeric.c.

9053 {
9054  NumericDigit *var_digits = var->digits;
9055  int var_ndigits = var->ndigits;
9056  int res_sign;
9057  int res_weight;
9058  int res_ndigits;
9059  NumericDigit *res_buf;
9060  NumericDigit *res_digits;
9061  uint32 divisor;
9062  int i;
9063 
9064  /* Guard against division by zero */
9065  if (ival == 0)
9066  ereport(ERROR,
9067  errcode(ERRCODE_DIVISION_BY_ZERO),
9068  errmsg("division by zero"));
9069 
9070  /* Result zero check */
9071  if (var_ndigits == 0)
9072  {
9073  zero_var(result);
9074  result->dscale = rscale;
9075  return;
9076  }
9077 
9078  /*
9079  * Determine the result sign, weight and number of digits to calculate.
9080  * The weight figured here is correct if the emitted quotient has no
9081  * leading zero digits; otherwise strip_var() will fix things up.
9082  */
9083  if (var->sign == NUMERIC_POS)
9084  res_sign = ival > 0 ? NUMERIC_POS : NUMERIC_NEG;
9085  else
9086  res_sign = ival > 0 ? NUMERIC_NEG : NUMERIC_POS;
9087  res_weight = var->weight - ival_weight;
9088  /* The number of accurate result digits we need to produce: */
9089  res_ndigits = res_weight + 1 + (rscale + DEC_DIGITS - 1) / DEC_DIGITS;
9090  /* ... but always at least 1 */
9091  res_ndigits = Max(res_ndigits, 1);
9092  /* If rounding needed, figure one more digit to ensure correct result */
9093  if (round)
9094  res_ndigits++;
9095 
9096  res_buf = digitbuf_alloc(res_ndigits + 1);
9097  res_buf[0] = 0; /* spare digit for later rounding */
9098  res_digits = res_buf + 1;
9099 
9100  /*
9101  * Now compute the quotient digits. This is the short division algorithm
9102  * described in Knuth volume 2, section 4.3.1 exercise 16, except that we
9103  * allow the divisor to exceed the internal base.
9104  *
9105  * In this algorithm, the carry from one digit to the next is at most
9106  * divisor - 1. Therefore, while processing the next digit, carry may
9107  * become as large as divisor * NBASE - 1, and so it requires a 64-bit
9108  * integer if this exceeds UINT_MAX.
9109  */
9110  divisor = Abs(ival);
9111 
9112  if (divisor <= UINT_MAX / NBASE)
9113  {
9114  /* carry cannot overflow 32 bits */
9115  uint32 carry = 0;
9116 
9117  for (i = 0; i < res_ndigits; i++)
9118  {
9119  carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9120  res_digits[i] = (NumericDigit) (carry / divisor);
9121  carry = carry % divisor;
9122  }
9123  }
9124  else
9125  {
9126  /* carry may exceed 32 bits */
9127  uint64 carry = 0;
9128 
9129  for (i = 0; i < res_ndigits; i++)
9130  {
9131  carry = carry * NBASE + (i < var_ndigits ? var_digits[i] : 0);
9132  res_digits[i] = (NumericDigit) (carry / divisor);
9133  carry = carry % divisor;
9134  }
9135  }
9136 
9137  /* Store the quotient in result */
9138  digitbuf_free(result->buf);
9139  result->ndigits = res_ndigits;
9140  result->buf = res_buf;
9141  result->digits = res_digits;
9142  result->weight = res_weight;
9143  result->sign = res_sign;
9144 
9145  /* Round or truncate to target rscale (and set result->dscale) */
9146  if (round)
9147  round_var(result, rscale);
9148  else
9149  trunc_var(result, rscale);
9150 
9151  /* Strip leading/trailing zeroes */
9152  strip_var(result);
9153 }
unsigned int uint32
Definition: c.h:441

References Abs, 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 4654 of file numeric.c.

4655 {
4656  NumericVar X;
4657  NumericVar X2;
4658  MemoryContext old_context;
4659 
4660  /* Count NaN/infinity inputs separately from all else */
4662  {
4663  if (NUMERIC_IS_PINF(newval))
4664  state->pInfcount++;
4665  else if (NUMERIC_IS_NINF(newval))
4666  state->nInfcount++;
4667  else
4668  state->NaNcount++;
4669  return;
4670  }
4671 
4672  /* load processed number in short-lived context */
4674 
4675  /*
4676  * Track the highest input dscale that we've seen, to support inverse
4677  * transitions (see do_numeric_discard).
4678  */
4679  if (X.dscale > state->maxScale)
4680  {
4681  state->maxScale = X.dscale;
4682  state->maxScaleCount = 1;
4683  }
4684  else if (X.dscale == state->maxScale)
4685  state->maxScaleCount++;
4686 
4687  /* if we need X^2, calculate that in short-lived context */
4688  if (state->calcSumX2)
4689  {
4690  init_var(&X2);
4691  mul_var(&X, &X, &X2, X.dscale * 2);
4692  }
4693 
4694  /* The rest of this needs to work in the aggregate context */
4695  old_context = MemoryContextSwitchTo(state->agg_context);
4696 
4697  state->N++;
4698 
4699  /* Accumulate sums */
4700  accum_sum_add(&(state->sumX), &X);
4701 
4702  if (state->calcSumX2)
4703  accum_sum_add(&(state->sumX2), &X2);
4704 
4705  MemoryContextSwitchTo(old_context);
4706 }
#define newval
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
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 4724 of file numeric.c.

4725 {
4726  NumericVar X;
4727  NumericVar X2;
4728  MemoryContext old_context;
4729 
4730  /* Count NaN/infinity inputs separately from all else */
4732  {
4733  if (NUMERIC_IS_PINF(newval))
4734  state->pInfcount--;
4735  else if (NUMERIC_IS_NINF(newval))
4736  state->nInfcount--;
4737  else
4738  state->NaNcount--;
4739  return true;
4740  }
4741 
4742  /* load processed number in short-lived context */
4744 
4745  /*
4746  * state->sumX's dscale is the maximum dscale of any of the inputs.
4747  * Removing the last input with that dscale would require us to recompute
4748  * the maximum dscale of the *remaining* inputs, which we cannot do unless
4749  * no more non-NaN inputs remain at all. So we report a failure instead,
4750  * and force the aggregation to be redone from scratch.
4751  */
4752  if (X.dscale == state->maxScale)
4753  {
4754  if (state->maxScaleCount > 1 || state->maxScale == 0)
4755  {
4756  /*
4757  * Some remaining inputs have same dscale, or dscale hasn't gotten
4758  * above zero anyway
4759  */
4760  state->maxScaleCount--;
4761  }
4762  else if (state->N == 1)
4763  {
4764  /* No remaining non-NaN inputs at all, so reset maxScale */
4765  state->maxScale = 0;
4766  state->maxScaleCount = 0;
4767  }
4768  else
4769  {
4770  /* Correct new maxScale is uncertain, must fail */
4771  return false;
4772  }
4773  }
4774 
4775  /* if we need X^2, calculate that in short-lived context */
4776  if (state->calcSumX2)
4777  {
4778  init_var(&X2);
4779  mul_var(&X, &X, &X2, X.dscale * 2);
4780  }
4781 
4782  /* The rest of this needs to work in the aggregate context */
4783  old_context = MemoryContextSwitchTo(state->agg_context);
4784 
4785  if (state->N-- > 1)
4786  {
4787  /* Negate X, to subtract it from the sum */
4788  X.sign = (X.sign == NUMERIC_POS ? NUMERIC_NEG : NUMERIC_POS);
4789  accum_sum_add(&(state->sumX), &X);
4790 
4791  if (state->calcSumX2)
4792  {
4793  /* Negate X^2. X^2 is always positive */
4794  X2.sign = NUMERIC_NEG;
4795  accum_sum_add(&(state->sumX2), &X2);
4796  }
4797  }
4798  else
4799  {
4800  /* Zero the sums */
4801  Assert(state->N == 0);
4802 
4803  accum_sum_reset(&state->sumX);
4804  if (state->calcSumX2)
4805  accum_sum_reset(&state->sumX2);
4806  }
4807 
4808  MemoryContextSwitchTo(old_context);
4809 
4810  return true;
4811 }
static void accum_sum_reset(NumericSumAccum *accum)
Definition: numeric.c:11152

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

7320 {
7321  Numeric res;
7322 
7323  res = (Numeric) palloc(VARSIZE(num));
7324  memcpy(res, num, VARSIZE(num));
7325  return res;
7326 }
struct NumericData * Numeric
Definition: numeric.h:53
#define VARSIZE(PTR)
Definition: postgres.h:316

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

10057 {
10058  int ln_dweight;
10059 
10060  /* Caller should fail on ln(negative), but for the moment return zero */
10061  if (var->sign != NUMERIC_POS)
10062  return 0;
10063 
10064  if (cmp_var(var, &const_zero_point_nine) >= 0 &&
10065  cmp_var(var, &const_one_point_one) <= 0)
10066  {
10067  /*
10068  * 0.9 <= var <= 1.1
10069  *
10070  * ln(var) has a negative weight (possibly very large). To get a
10071  * reasonably accurate result, estimate it using ln(1+x) ~= x.
10072  */
10073  NumericVar x;
10074 
10075  init_var(&x);
10076  sub_var(var, &const_one, &x);
10077 
10078  if (x.ndigits > 0)
10079  {
10080  /* Use weight of most significant decimal digit of x */
10081  ln_dweight = x.weight * DEC_DIGITS + (int) log10(x.digits[0]);
10082  }
10083  else
10084  {
10085  /* x = 0. Since ln(1) = 0 exactly, we don't need extra digits */
10086  ln_dweight = 0;
10087  }
10088 
10089  free_var(&x);
10090  }
10091  else
10092  {
10093  /*
10094  * Estimate the logarithm using the first couple of digits from the
10095  * input number. This will give an accurate result whenever the input
10096  * is not too close to 1.
10097  */
10098  if (var->ndigits > 0)
10099  {
10100  int digits;
10101  int dweight;
10102  double ln_var;
10103 
10104  digits = var->digits[0];
10105  dweight = var->weight * DEC_DIGITS;
10106 
10107  if (var->ndigits > 1)
10108  {
10109  digits = digits * NBASE + var->digits[1];
10110  dweight -= DEC_DIGITS;
10111  }
10112 
10113  /*----------
10114  * We have var ~= digits * 10^dweight
10115  * so ln(var) ~= ln(digits) + dweight * ln(10)
10116  *----------
10117  */
10118  ln_var = log((double) digits) + dweight * 2.302585092994046;
10119  ln_dweight = (int) log10(Abs(ln_var));
10120  }
10121  else
10122  {
10123  /* Caller should fail on ln(0), but for the moment return zero */
10124  ln_dweight = 0;
10125  }
10126  }
10127 
10128  return ln_dweight;
10129 }
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:10138
int digits
Definition: informix.c:666
int x
Definition: isn.c:71

References Abs, 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 9927 of file numeric.c.

9928 {
9929  NumericVar x;
9930  NumericVar elem;
9931  int ni;
9932  double val;
9933  int dweight;
9934  int ndiv2;
9935  int sig_digits;
9936  int local_rscale;
9937 
9938  init_var(&x);
9939  init_var(&elem);
9940 
9941  set_var_from_var(arg, &x);
9942 
9943  /*
9944  * Estimate the dweight of the result using floating point arithmetic, so
9945  * that we can choose an appropriate local rscale for the calculation.
9946  */
9948 
9949  /* Guard against overflow/underflow */
9950  /* If you change this limit, see also power_var()'s limit */
9951  if (Abs(val) >= NUMERIC_MAX_RESULT_SCALE * 3)
9952  {
9953  if (val > 0)
9954  ereport(ERROR,
9955  (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
9956  errmsg("value overflows numeric format")));
9957  zero_var(result);
9958  result->dscale = rscale;
9959  return;
9960  }
9961 
9962  /* decimal weight = log10(e^x) = x * log10(e) */
9963  dweight = (int) (val * 0.434294481903252);
9964 
9965  /*
9966  * Reduce x to the range -0.01 <= x <= 0.01 (approximately) by dividing by
9967  * 2^ndiv2, to improve the convergence rate of the Taylor series.
9968  *
9969  * Note that the overflow check above ensures that Abs(x) < 6000, which
9970  * means that ndiv2 <= 20 here.
9971  */
9972  if (Abs(val) > 0.01)
9973  {
9974  ndiv2 = 1;
9975  val /= 2;
9976 
9977  while (Abs(val) > 0.01)
9978  {
9979  ndiv2++;
9980  val /= 2;
9981  }
9982 
9983  local_rscale = x.dscale + ndiv2;
9984  div_var_int(&x, 1 << ndiv2, 0, &x, local_rscale, true);
9985  }
9986  else
9987  ndiv2 = 0;
9988 
9989  /*
9990  * Set the scale for the Taylor series expansion. The final result has
9991  * (dweight + rscale + 1) significant digits. In addition, we have to
9992  * raise the Taylor series result to the power 2^ndiv2, which introduces
9993  * an error of up to around log10(2^ndiv2) digits, so work with this many
9994  * extra digits of precision (plus a few more for good measure).
9995  */
9996  sig_digits = 1 + dweight + rscale + (int) (ndiv2 * 0.301029995663981);
9997  sig_digits = Max(sig_digits, 0) + 8;
9998 
9999  local_rscale = sig_digits - 1;
10000 
10001  /*
10002  * Use the Taylor series
10003  *
10004  * exp(x) = 1 + x + x^2/2! + x^3/3! + ...
10005  *
10006  * Given the limited range of x, this should converge reasonably quickly.
10007  * We run the series until the terms fall below the local_rscale limit.
10008  */
10009  add_var(&const_one, &x, result);
10010 
10011  mul_var(&x, &x, &elem, local_rscale);
10012  ni = 2;
10013  div_var_int(&elem, ni, 0, &elem, local_rscale, true);
10014 
10015  while (elem.ndigits != 0)
10016  {
10017  add_var(result, &elem, result);
10018 
10019  mul_var(&elem, &x, &elem, local_rscale);
10020  ni++;
10021  div_var_int(&elem, ni, 0, &elem, local_rscale, true);
10022  }
10023 
10024  /*
10025  * Compensate for the argument range reduction. Since the weight of the
10026  * result doubles with each multiplication, we can reduce the local rscale
10027  * as we proceed.
10028  */
10029  while (ndiv2-- > 0)
10030  {
10031  local_rscale = sig_digits - result->weight * 2 * DEC_DIGITS;
10032  local_rscale = Max(local_rscale, NUMERIC_MIN_DISPLAY_SCALE);
10033  mul_var(result, result, result, local_rscale);
10034  }
10035 
10036  /* Round to requested rscale */
10037  round_var(result, rscale);
10038 
10039  free_var(&x);
10040  free_var(&elem);
10041 }
static double numericvar_to_double_no_overflow(const NumericVar *var)
Definition: numeric.c:7889
#define NUMERIC_MAX_RESULT_SCALE
Definition: numeric.h:42
#define NUMERIC_MIN_DISPLAY_SCALE
Definition: numeric.h:40
void * arg

References Abs, 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 4485 of file numeric.c.

4486 {
4488  Numeric res;
4489  NumericVar result;
4490  char buf[FLT_DIG + 100];
4491 
4492  if (isnan(val))
4494 
4495  if (isinf(val))
4496  {
4497  if (val < 0)
4499  else
4501  }
4502 
4503  snprintf(buf, sizeof(buf), "%.*g", FLT_DIG, val);
4504 
4505  init_var(&result);
4506 
4507  /* Assume we need not worry about leading/trailing spaces */
4508  (void) set_var_from_str(buf, buf, &result);
4509 
4510  res = make_result(&result);
4511 
4512  free_var(&result);
4513 
4515 }
static const NumericVar const_pinf
Definition: numeric.c:453
static const NumericVar const_ninf
Definition: numeric.c:456
static const char * set_var_from_str(const char *str, const char *cp, NumericVar *dest)
Definition: numeric.c:6814
static Numeric make_result(const NumericVar *var)
Definition: numeric.c:7447
static const NumericVar const_nan
Definition: numeric.c:450
float float4
Definition: c.h:564
#define PG_GETARG_FLOAT4(n)
Definition: fmgr.h:281
#define PG_RETURN_NUMERIC(x)
Definition: numeric.h:64
#define snprintf
Definition: port.h:225

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.

Referenced by JsonItemFromDatum().

◆ float8_numeric()

Datum float8_numeric ( PG_FUNCTION_ARGS  )

Definition at line 4392 of file numeric.c.

4393 {
4395  Numeric res;
4396  NumericVar result;
4397  char buf[DBL_DIG + 100];
4398 
4399  if (isnan(val))
4401 
4402  if (isinf(val))
4403  {
4404  if (val < 0)
4406  else
4408  }
4409 
4410  snprintf(buf, sizeof(buf), "%.*g", DBL_DIG, val);
4411 
4412  init_var(&result);
4413 
4414  /* Assume we need not worry about leading/trailing spaces */
4415  (void) set_var_from_str(buf, buf, &result);
4416 
4417  res = make_result(&result);
4418 
4419  free_var(&result);
4420 
4422 }
double float8
Definition: c.h:565
#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(), JsonItemFromDatum(), and SV_to_JsonbValue().

◆ floor_var()

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

Definition at line 9354 of file numeric.c.

9355 {
9356  NumericVar tmp;
9357 
9358  init_var(&tmp);
9359  set_var_from_var(var, &tmp);
9360 
9361  trunc_var(&tmp, 0);
9362 
9363  if (var->sign == NUMERIC_NEG && cmp_var(var, &tmp) != 0)
9364  sub_var(&tmp, &const_one, &tmp);
9365 
9366  set_var_from_var(&tmp, result);
9367  free_var(&tmp);
9368 }

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

◆ gcd_var()

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

Definition at line 9377 of file numeric.c.

9378 {
9379  int res_dscale;
9380  int cmp;
9381  NumericVar tmp_arg;
9382  NumericVar mod;
9383 
9384  res_dscale = Max(var1->dscale, var2->dscale);
9385 
9386  /*
9387  * Arrange for var1 to be the number with the greater absolute value.
9388  *
9389  * This would happen automatically in the loop below, but avoids an
9390  * expensive modulo operation.
9391  */
9392  cmp = cmp_abs(var1, var2);
9393  if (cmp < 0)
9394  {
9395  const NumericVar *tmp = var1;
9396 
9397  var1 = var2;
9398  var2 = tmp;
9399  }
9400 
9401  /*
9402  * Also avoid the taking the modulo if the inputs have the same absolute
9403  * value, or if the smaller input is zero.
9404  */
9405  if (cmp == 0 || var2->ndigits == 0)
9406  {
9407  set_var_from_var(var1, result);
9408  result->sign = NUMERIC_POS;
9409  result->dscale = res_dscale;
9410  return;
9411  }
9412 
9413  init_var(&tmp_arg);
9414  init_var(&mod);
9415 
9416  /* Use the Euclidean algorithm to find the GCD */
9417  set_var_from_var(var1, &tmp_arg);
9418  set_var_from_var(var2, result);
9419 
9420  for (;;)
9421  {
9422  /* this loop can take a while, so allow it to be interrupted */
9424 
9425  mod_var(&tmp_arg, result, &mod);
9426  if (mod.ndigits == 0)
9427  break;
9428  set_var_from_var(result, &tmp_arg);
9429  set_var_from_var(&mod, result);
9430  }
9431  result->sign = NUMERIC_POS;
9432  result->dscale = res_dscale;
9433 
9434  free_var(&tmp_arg);
9435  free_var(&mod);
9436 }
static void mod_var(const NumericVar *var1, const NumericVar *var2, NumericVar *result)
Definition: numeric.c:9231
#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 1614 of file numeric.c.

1615 {
1616  return generate_series_step_numeric(fcinfo);
1617 }
Datum generate_series_step_numeric(PG_FUNCTION_ARGS)
Definition: numeric.c:1620

References generate_series_step_numeric().

◆ generate_series_step_numeric()

Datum generate_series_step_numeric ( PG_FUNCTION_ARGS  )

Definition at line 1620 of file numeric.c.

1621 {
1623  FuncCallContext *funcctx;
1624  MemoryContext oldcontext;
1625 
1626  if (SRF_IS_FIRSTCALL())
1627  {
1628  Numeric start_num = PG_GETARG_NUMERIC(0);
1629  Numeric stop_num = PG_GETARG_NUMERIC(1);
1630  NumericVar steploc = const_one;
1631 
1632  /* Reject NaN and infinities in start and stop values */
1633  if (NUMERIC_IS_SPECIAL(start_num))
1634  {
1635  if (NUMERIC_IS_NAN(start_num))
1636  ereport(ERROR,
1637  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1638  errmsg("start value cannot be NaN")));
1639  else
1640  ereport(ERROR,
1641  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1642  errmsg("start value cannot be infinity")));
1643  }
1644  if (NUMERIC_IS_SPECIAL(stop_num))
1645  {
1646  if (NUMERIC_IS_NAN(stop_num))
1647  ereport(ERROR,
1648  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1649  errmsg("stop value cannot be NaN")));
1650  else
1651  ereport(ERROR,
1652  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1653  errmsg("stop value cannot be infinity")));
1654  }
1655 
1656  /* see if we were given an explicit step size */
1657  if (PG_NARGS() == 3)
1658  {
1659  Numeric step_num = PG_GETARG_NUMERIC(2);
1660 
1661  if (NUMERIC_IS_SPECIAL(step_num))
1662  {
1663  if (NUMERIC_IS_NAN(step_num))
1664  ereport(ERROR,
1665  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1666  errmsg("step size cannot be NaN")));
1667  else
1668  ereport(ERROR,
1669  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1670  errmsg("step size cannot be infinity")));
1671  }
1672 
1673  init_var_from_num(step_num, &steploc);
1674 
1675  if (cmp_var(&steploc, &const_zero) == 0)
1676  ereport(ERROR,
1677  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1678  errmsg("step size cannot equal zero")));
1679  }
1680 
1681  /* create a function context for cross-call persistence */
1682  funcctx = SRF_FIRSTCALL_INIT();
1683 
1684  /*
1685  * Switch to memory context appropriate for multiple function calls.
1686  */
1687  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1688 
1689  /* allocate memory for user context */
1690  fctx = (generate_series_numeric_fctx *)
1692 
1693  /*
1694  * Use fctx to keep state from call to call. Seed current with the
1695  * original start value. We must copy the start_num and stop_num
1696  * values rather than pointing to them, since we may have detoasted
1697  * them in the per-call context.
1698  */
1699  init_var(&fctx->current);
1700  init_var(&fctx->stop);
1701  init_var(&fctx->step);
1702 
1703  set_var_from_num(start_num, &fctx->current);
1704  set_var_from_num(stop_num, &fctx->stop);
1705  set_var_from_var(&steploc, &fctx->step);
1706 
1707  funcctx->user_fctx = fctx;
1708  MemoryContextSwitchTo(oldcontext);
1709  }
1710 
1711  /* stuff done on every call of the function */
1712  funcctx = SRF_PERCALL_SETUP();
1713 
1714  /*
1715  * Get the saved state and use current state as the result of this
1716  * iteration.
1717  */
1718  fctx = funcctx->user_fctx;
1719 
1720  if ((fctx->step.sign == NUMERIC_POS &&
1721  cmp_var(&fctx->current, &fctx->stop) <= 0) ||
1722  (fctx->step.sign == NUMERIC_NEG &&
1723  cmp_var(&fctx->current, &fctx->stop) >= 0))
1724  {
1725  Numeric result = make_result(&fctx->current);
1726 
1727  /* switch to memory context appropriate for iteration calculation */
1728  oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
1729 
1730  /* increment current in preparation for next iteration */
1731  add_var(&fctx->current, &fctx->step, &fctx->current);
1732  MemoryContextSwitchTo(oldcontext);
1733 
1734  /* do when there is more left to send */
1735  SRF_RETURN_NEXT(funcctx, NumericGetDatum(result));
1736  }
1737  else
1738  /* do when there is no more left */
1739  SRF_RETURN_DONE(funcctx);
1740 }
static void set_var_from_num(Numeric value, NumericVar *dest)
Definition: numeric.c:6976
#define PG_NARGS()
Definition: fmgr.h:203
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:299
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:303
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:305
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:301
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:323
#define NumericGetDatum(X)
Definition: numeric.h:61
#define PG_GETARG_NUMERIC(n)
Definition: numeric.h:62
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 4040 of file numeric.c.

4041 {
4042  int min_scale;
4043  int last_digit_pos;
4044 
4045  /*
4046  * Ordinarily, the input value will be "stripped" so that the last
4047  * NumericDigit is nonzero. But we don't want to get into an infinite
4048  * loop if it isn't, so explicitly find the last nonzero digit.
4049  */
4050  last_digit_pos = var->ndigits - 1;
4051  while (last_digit_pos >= 0 &&
4052  var->digits[last_digit_pos] == 0)
4053  last_digit_pos--;
4054 
4055  if (last_digit_pos >= 0)
4056  {
4057  /* compute min_scale assuming that last ndigit has no zeroes */
4058  min_scale = (last_digit_pos - var->weight) * DEC_DIGITS;
4059 
4060  /*
4061  * We could get a negative result if there are no digits after the
4062  * decimal point. In this case the min_scale must be zero.
4063  */
4064  if (min_scale > 0)
4065  {
4066  /*
4067  * Reduce min_scale if trailing digit(s) in last NumericDigit are
4068  * zero.
4069  */
4070  NumericDigit last_digit = var->digits[last_digit_pos];
4071 
4072  while (last_digit % 10 == 0)
4073  {
4074  min_scale--;
4075  last_digit /= 10;
4076  }
4077  }
4078  else
4079  min_scale = 0;
4080  }
4081  else
4082  min_scale = 0; /* result if input is zero */
4083 
4084  return min_scale;
4085 }

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

7051 {
7052  int dscale;
7053  char *str;
7054  char *cp;
7055  char *endcp;
7056  int i;
7057  int d;
7058  NumericDigit dig;
7059 
7060 #if DEC_DIGITS > 1
7061  NumericDigit d1;
7062 #endif
7063 
7064  dscale = var->dscale;
7065 
7066  /*
7067  * Allocate space for the result.
7068  *
7069  * i is set to the # of decimal digits before decimal point. dscale is the
7070  * # of decimal digits we will print after decimal point. We may generate
7071  * as many as DEC_DIGITS-1 excess digits at the end, and in addition we
7072  * need room for sign, decimal point, null terminator.
7073  */
7074  i = (var->weight + 1) * DEC_DIGITS;
7075  if (i <= 0)
7076  i = 1;
7077 
7078  str = palloc(i + dscale + DEC_DIGITS + 2);
7079  cp = str;
7080 
7081  /*
7082  * Output a dash for negative values
7083  */
7084  if (var->sign == NUMERIC_NEG)
7085  *cp++ = '-';
7086 
7087  /*
7088  * Output all digits before the decimal point
7089  */
7090  if (var->weight < 0)
7091  {
7092  d = var->weight + 1;
7093  *cp++ = '0';
7094  }
7095  else
7096  {
7097  for (d = 0; d <= var->weight; d++)
7098  {
7099  dig = (d < var->ndigits) ? var->digits[d] : 0;
7100  /* In the first digit, suppress extra leading decimal zeroes */
7101 #if DEC_DIGITS == 4
7102  {
7103  bool putit = (d > 0);
7104 
7105  d1 = dig / 1000;
7106  dig -= d1 * 1000;
7107  putit |= (d1 > 0);
7108  if (putit)
7109  *cp++ = d1 + '0';
7110  d1 = dig / 100;
7111  dig -= d1 * 100;
7112  putit |= (d1 > 0);
7113  if (putit)
7114  *cp++ = d1 + '0';
7115  d1 = dig / 10;
7116  dig -= d1 * 10;
7117  putit |= (d1 > 0);
7118  if (putit)
7119  *cp++ = d1 + '0';
7120  *cp++ = dig + '0';
7121  }
7122 #elif DEC_DIGITS == 2
7123  d1 = dig / 10;
7124  dig -= d1 * 10;
7125  if (d1 > 0 || d > 0)
7126  *cp++ = d1 + '0';
7127  *cp++ = dig + '0';
7128 #elif DEC_DIGITS == 1
7129  *cp++ = dig + '0';
7130 #else
7131 #error unsupported NBASE
7132 #endif
7133  }
7134  }
7135 
7136  /*
7137  * If requested, output a decimal point and all the digits that follow it.
7138  * We initially put out a multiple of DEC_DIGITS digits, then truncate if
7139  * needed.
7140  */
7141  if (dscale > 0)
7142  {
7143  *cp++ = '.';
7144  endcp = cp + dscale;
7145  for (i = 0; i < dscale; d++, i += DEC_DIGITS)
7146  {
7147  dig = (d >= 0 && d < var->ndigits) ? var->digits[d] : 0;
7148 #if DEC_DIGITS == 4
7149  d1 = dig / 1000;
7150  dig -= d1 * 1000;
7151  *cp++ = d1 + '0';
7152  d1 = dig / 100;
7153  dig -= d1 * 100;
7154  *cp++ = d1 + '0';
7155  d1 = dig / 10;
7156  dig -= d1 * 10;
7157  *cp++ = d1 + '0';
7158  *cp++ = dig + '0';
7159 #elif DEC_DIGITS == 2
7160  d1 = dig / 10;
7161  dig -= d1 * 10;
7162  *cp++ = d1 + '0';
7163  *cp++ = dig + '0';
7164 #elif DEC_DIGITS == 1
7165  *cp++ = dig + '0';
7166 #else
7167 #error unsupported NBASE
7168 #endif
7169  }
7170  cp = endcp;
7171  }
7172 
7173  /*
7174  * terminate the string and return it
7175  */
7176  *cp = '\0';
7177  return str;
7178 }
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 7203 of file numeric.c.

7204 {
7205  int32 exponent;
7206  NumericVar tmp_var;
7207  size_t len;
7208  char *str;
7209  char *sig_out;
7210 
7211  if (rscale < 0)
7212  rscale = 0;
7213 
7214  /*
7215  * Determine the exponent of this number in normalised form.
7216  *
7217  * This is the exponent required to represent the number with only one
7218  * significant digit before the decimal place.
7219  */
7220  if (var->ndigits > 0)
7221  {
7222  exponent = (var->weight + 1) * DEC_DIGITS;
7223 
7224  /*
7225  * Compensate for leading decimal zeroes in the first numeric digit by
7226  * decrementing the exponent.
7227  */
7228  exponent -= DEC_DIGITS - (int) log10(var->digits[0]);
7229  }
7230  else
7231  {
7232  /*
7233  * If var has no digits, then it must be zero.
7234  *
7235  * Zero doesn't technically have a meaningful exponent in normalised
7236  * notation, but we just display the exponent as zero for consistency
7237  * of output.
7238  */
7239  exponent = 0;
7240  }
7241 
7242  /*
7243  * Divide var by 10^exponent to get the significand, rounding to rscale
7244  * decimal digits in the process.
7245  */
7246  init_var(&tmp_var);
7247 
7248  power_ten_int(exponent, &tmp_var);
7249  div_var(var, &tmp_var, &tmp_var, rscale, true);
7250  sig_out = get_str_from_var(&tmp_var);
7251 
7252  free_var(&tmp_var);
7253 
7254  /*
7255  * Allocate space for the result.
7256  *
7257  * In addition to the significand, we need room for the exponent
7258  * decoration ("e"), the sign of the exponent, up to 10 digits for the
7259  * exponent itself, and of course the null terminator.
7260  */
7261  len = strlen(sig_out) + 13;
7262  str = palloc(len);
7263  snprintf(str, len, "%se%+03d", sig_out, exponent);
7264 
7265  pfree(sig_out);
7266 
7267  return str;
7268 }
static char * get_str_from_var(const NumericVar *var)
Definition: numeric.c:7050
static void power_ten_int(int exp, NumericVar *result)
Definition: numeric.c:10657
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 2614 of file numeric.c.

2615 {
2617  Datum digit_hash;
2618  Datum result;
2619  int weight;
2620  int start_offset;
2621  int end_offset;
2622  int i;
2623  int hash_len;
2625 
2626  /* If it's NaN or infinity, don't try to hash the rest of the fields */
2627  if (NUMERIC_IS_SPECIAL(key))
2628  PG_RETURN_UINT32(0);
2629 
2630  weight = NUMERIC_WEIGHT(key);
2631  start_offset = 0;
2632  end_offset = 0;
2633 
2634  /*
2635  * Omit any leading or trailing zeros from the input to the hash. The
2636  * numeric implementation *should* guarantee that leading and trailing
2637  * zeros are suppressed, but we're paranoid. Note that we measure the
2638  * starting and ending offsets in units of NumericDigits, not bytes.
2639  */
2641  for (i = 0; i < NUMERIC_NDIGITS(key); i++)
2642  {
2643  if (digits[i] != (NumericDigit) 0)
2644  break;
2645 
2646  start_offset++;
2647 
2648  /*
2649  * The weight is effectively the # of digits before the decimal point,
2650  * so decrement it for each leading zero we skip.
2651  */
2652  weight--;
2653  }
2654 
2655  /*
2656  * If there are no non-zero digits, then the value of the number is zero,
2657  * regardless of any other fields.
2658  */
2659  if (NUMERIC_NDIGITS(key) == start_offset)
2660  PG_RETURN_UINT32(-1);
2661 
2662  for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)
2663  {
2664  if (digits[i] != (NumericDigit) 0)
2665  break;
2666 
2667  end_offset++;
2668  }
2669 
2670  /* If we get here, there should be at least one non-zero digit */
2671  Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));
2672 
2673  /*
2674  * Note that we don't hash on the Numeric's scale, since two numerics can
2675  * compare equal but have different scales. We also don't hash on the
2676  * sign, although we could: since a sign difference implies inequality,
2677  * this shouldn't affect correctness.
2678  */
2679  hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;
2680  digit_hash = hash_any((unsigned char *) (NUMERIC_DIGITS(key) + start_offset),
2681  hash_len * sizeof(NumericDigit));
2682 
2683  /* Mix in the weight, via XOR */
2684  result = digit_hash ^ weight;
2685 
2686  PG_RETURN_DATUM(result);
2687 }
#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:411

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

2695 {
2697  uint64 seed = PG_GETARG_INT64(1);
2698  Datum digit_hash;
2699  Datum result;
2700  int weight;
2701  int start_offset;
2702  int end_offset;
2703  int i;
2704  int hash_len;
2706 
2707  /* If it's NaN or infinity, don't try to hash the rest of the fields */
2708  if (NUMERIC_IS_SPECIAL(key))
2709  PG_RETURN_UINT64(seed);
2710 
2711  weight = NUMERIC_WEIGHT(key);
2712  start_offset = 0;
2713  end_offset = 0;
2714 
2716  for (i = 0; i < NUMERIC_NDIGITS(key); i++)
2717  {
2718  if (digits[i] != (NumericDigit) 0)
2719  break;
2720 
2721  start_offset++;
2722 
2723  weight--;
2724  }
2725 
2726  if (NUMERIC_NDIGITS(key) == start_offset)
2727  PG_RETURN_UINT64(seed - 1);
2728 
2729  for (i = NUMERIC_NDIGITS(key) - 1; i >= 0; i--)
2730  {
2731  if (digits[i] != (NumericDigit) 0)
2732  break;
2733 
2734  end_offset++;
2735  }
2736 
2737  Assert(start_offset + end_offset < NUMERIC_NDIGITS(key));
2738 
2739  hash_len = NUMERIC_NDIGITS(key) - start_offset - end_offset;
2740  digit_hash = hash_any_extended((unsigned char *) (NUMERIC_DIGITS(key)
2741  + start_offset),
2742  hash_len * sizeof(NumericDigit),
2743  seed);
2744 
2745  result = UInt64GetDatum(DatumGetUInt64(digit_hash) ^ weight);
2746 
2747  PG_RETURN_DATUM(result);
2748 }
#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
#define DatumGetUInt64(X)
Definition: postgres.h:678
#define UInt64GetDatum(X)
Definition: postgres.h:692

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

2480 {
2482  Numeric base = PG_GETARG_NUMERIC(1);
2483  Numeric offset = PG_GETARG_NUMERIC(2);
2484  bool sub = PG_GETARG_BOOL(3);
2485  bool less = PG_GETARG_BOOL(4);
2486  bool result;
2487 
2488  /*
2489  * Reject negative (including -Inf) or NaN offset. Negative is per spec,
2490  * and NaN is because appropriate semantics for that seem non-obvious.
2491  */
2492  if (NUMERIC_IS_NAN(offset) ||
2493  NUMERIC_IS_NINF(offset) ||
2494  NUMERIC_SIGN(offset) == NUMERIC_NEG)
2495  ereport(ERROR,
2496  (errcode(ERRCODE_INVALID_PRECEDING_OR_FOLLOWING_SIZE),
2497  errmsg("invalid preceding or following size in window function")));
2498 
2499  /*
2500  * Deal with cases where val and/or base is NaN, following the rule that
2501  * NaN sorts after non-NaN (cf cmp_numerics). The offset cannot affect
2502  * the conclusion.
2503  */
2504  if (NUMERIC_IS_NAN(val))
2505  {
2506  if (NUMERIC_IS_NAN(base))
2507  result = true; /* NAN = NAN */
2508  else
2509  result = !less; /* NAN > non-NAN */
2510  }
2511  else if (NUMERIC_IS_NAN(base))
2512  {
2513  result = less; /* non-NAN < NAN */
2514  }
2515 
2516  /*
2517  * Deal with infinite offset (necessarily +Inf, at this point).
2518  */
2519  else if (NUMERIC_IS_SPECIAL(offset))
2520  {
2521  Assert(NUMERIC_IS_PINF(offset));
2522  if (sub ? NUMERIC_IS_PINF(base) : NUMERIC_IS_NINF(base))
2523  {
2524  /*
2525  * base +/- offset would produce NaN, so return true for any val
2526  * (see in_range_float8_float8() for reasoning).
2527  */
2528  result = true;
2529  }
2530  else if (sub)
2531  {
2532  /* base - offset must be -inf */
2533  if (less)
2534  result = NUMERIC_IS_NINF(val); /* only -inf is <= sum */
2535  else
2536  result = true; /* any val is >= sum */
2537  }
2538  else
2539  {
2540  /* base + offset must be +inf */
2541  if (less)
2542  result = true; /* any val is <= sum */
2543  else
2544  result = NUMERIC_IS_PINF(val); /* only +inf is >= sum */
2545  }
2546  }
2547 
2548  /*
2549  * Deal with cases where val and/or base is infinite. The offset, being
2550  * now known finite, cannot affect the conclusion.
2551  */
2552  else if (NUMERIC_IS_SPECIAL(val))
2553  {
2554  if (NUMERIC_IS_PINF(val))
2555  {
2556  if (NUMERIC_IS_PINF(base))
2557  result = true; /* PINF = PINF */
2558  else
2559  result = !less; /* PINF > any other non-NAN */
2560  }
2561  else /* val must be NINF */
2562  {
2563  if (NUMERIC_IS_NINF(base))
2564  result = true; /* NINF = NINF */
2565  else
2566  result = less; /* NINF < anything else */
2567  }
2568  }
2569  else if (NUMERIC_IS_SPECIAL(base))
2570  {
2571  if (NUMERIC_IS_NINF(base))
2572  result = !less; /* normal > NINF */
2573  else
2574  result = less; /* normal < PINF */
2575  }
2576  else
2577  {
2578  /*
2579  * Otherwise go ahead and compute base +/- offset. While it's
2580  * possible for this to overflow the numeric format, it's unlikely
2581  * enough that we don't take measures to prevent it.
2582  */
2583  NumericVar valv;
2584  NumericVar basev;
2585  NumericVar offsetv;
2586  NumericVar sum;
2587 
2588  init_var_from_num(val, &valv);
2589  init_var_from_num(base, &basev);
2590  init_var_from_num(offset, &offsetv);
2591  init_var(&sum);
2592 
2593  if (sub)
2594  sub_var(&basev, &offsetv, &sum);
2595  else
2596  add_var(&basev, &offsetv, &sum);
2597 
2598  if (less)
2599  result = (cmp_var(&valv, &sum) <= 0);
2600  else
2601  result = (cmp_var(&valv, &sum) >= 0);
2602 
2603  free_var(&sum);
2604  }
2605 
2606  PG_FREE_IF_COPY(val, 0);
2607  PG_FREE_IF_COPY(base, 1);
2608  PG_FREE_IF_COPY(offset, 2);
2609 
2610  PG_RETURN_BOOL(result);
2611 }
#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 5351 of file numeric.c.

5352 {
5354 
5355  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5356 
5357  /* Create the state data on the first call */
5358  if (state == NULL)
5359  state = makePolyNumAggState(fcinfo, true);
5360 
5361  if (!PG_ARGISNULL(1))
5362  {
5363 #ifdef HAVE_INT128
5364  do_int128_accum(state, (int128) PG_GETARG_INT16(1));
5365 #else
5367 #endif
5368  }
5369 
5371 }
#define makePolyNumAggState
Definition: numeric.c:5346
Numeric int64_to_numeric(int64 val)
Definition: numeric.c:4137
static void do_numeric_accum(NumericAggState *state, Numeric newval)
Definition: numeric.c:4654
#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 5779 of file numeric.c.

5780 {
5782 
5783  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5784 
5785  /* Should not get here with no state */
5786  if (state == NULL)
5787  elog(ERROR, "int2_accum_inv called with NULL state");
5788 
5789  if (!PG_ARGISNULL(1))
5790  {
5791 #ifdef HAVE_INT128
5792  do_int128_discard(state, (int128) PG_GETARG_INT16(1));
5793 #else
5794  /* Should never fail, all inputs have dscale 0 */
5796  elog(ERROR, "do_numeric_discard failed unexpectedly");
5797 #endif
5798  }
5799 
5801 }
static bool do_numeric_discard(NumericAggState *state, Numeric newval)
Definition: numeric.c:4724
#define elog(elevel,...)
Definition: elog.h:218

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

6463 {
6464  ArrayType *transarray;
6466  Int8TransTypeData *transdata;
6467 
6468  /*
6469  * If we're invoked as an aggregate, we can cheat and modify our first
6470  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6471  * a copy of it before scribbling on it.
6472  */
6473  if (AggCheckCallContext(fcinfo, NULL))
6474  transarray = PG_GETARG_ARRAYTYPE_P(0);
6475  else
6476  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6477 
6478  if (ARR_HASNULL(transarray) ||
6479  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6480  elog(ERROR, "expected 2-element int8 array");
6481 
6482  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6483  transdata->count++;
6484  transdata->sum += newval;
6485 
6486  PG_RETURN_ARRAYTYPE_P(transarray);
6487 }
#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:4487

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

6550 {
6551  ArrayType *transarray;
6553  Int8TransTypeData *transdata;
6554 
6555  /*
6556  * If we're invoked as an aggregate, we can cheat and modify our first
6557  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6558  * a copy of it before scribbling on it.
6559  */
6560  if (AggCheckCallContext(fcinfo, NULL))
6561  transarray = PG_GETARG_ARRAYTYPE_P(0);
6562  else
6563  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6564 
6565  if (ARR_HASNULL(transarray) ||
6566  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6567  elog(ERROR, "expected 2-element int8 array");
6568 
6569  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6570  transdata->count--;
6571  transdata->sum -= newval;
6572 
6573  PG_RETURN_ARRAYTYPE_P(transarray);
6574 }

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

4344 {
4345  int16 val = PG_GETARG_INT16(0);
4346 
4348 }

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

Referenced by JsonItemFromDatum().

◆ int2_sum()

Datum int2_sum ( PG_FUNCTION_ARGS  )

Definition at line 6313 of file numeric.c.

6314 {
6315  int64 newval;
6316 
6317  if (PG_ARGISNULL(0))
6318  {
6319  /* No non-null input seen so far... */
6320  if (PG_ARGISNULL(1))
6321  PG_RETURN_NULL(); /* still no non-null */
6322  /* This is the first non-null input. */
6323  newval = (int64) PG_GETARG_INT16(1);
6325  }
6326 
6327  /*
6328  * If we're invoked as an aggregate, we can cheat and modify our first
6329  * parameter in-place to avoid palloc overhead. If not, we need to return
6330  * the new value of the transition variable. (If int8 is pass-by-value,
6331  * then of course this is useless as well as incorrect, so just ifdef it
6332  * out.)
6333  */
6334 #ifndef USE_FLOAT8_BYVAL /* controls int8 too */
6335  if (AggCheckCallContext(fcinfo, NULL))
6336  {
6337  int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
6338 
6339  /* Leave the running sum unchanged in the new input is null */
6340  if (!PG_ARGISNULL(1))
6341  *oldsum = *oldsum + (int64) PG_GETARG_INT16(1);
6342 
6343  PG_RETURN_POINTER(oldsum);
6344  }
6345  else
6346 #endif
6347  {
6348  int64 oldsum = PG_GETARG_INT64(0);
6349 
6350  /* Leave sum unchanged if new input is null. */
6351  if (PG_ARGISNULL(1))
6352  PG_RETURN_INT64(oldsum);
6353 
6354  /* OK to do the addition. */
6355  newval = oldsum + (int64) PG_GETARG_INT16(1);
6356 
6358  }
6359 }
#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 6632 of file numeric.c.

6633 {
6634  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
6635  Int8TransTypeData *transdata;
6636 
6637  if (ARR_HASNULL(transarray) ||
6638  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6639  elog(ERROR, "expected 2-element int8 array");
6640  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6641 
6642  /* SQL defines SUM of no values to be NULL */
6643  if (transdata->count == 0)
6644  PG_RETURN_NULL();
6645 
6646  PG_RETURN_DATUM(Int64GetDatumFast(transdata->sum));
6647 }
#define Int64GetDatumFast(X)
Definition: postgres.h:804

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

5375 {
5377 
5378  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5379 
5380  /* Create the state data on the first call */
5381  if (state == NULL)
5382  state = makePolyNumAggState(fcinfo, true);
5383 
5384  if (!PG_ARGISNULL(1))
5385  {
5386 #ifdef HAVE_INT128
5387  do_int128_accum(state, (int128) PG_GETARG_INT32(1));
5388 #else
5390 #endif
5391  }
5392 
5394 }
#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 5804 of file numeric.c.

5805 {
5807 
5808  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5809 
5810  /* Should not get here with no state */
5811  if (state == NULL)
5812  elog(ERROR, "int4_accum_inv called with NULL state");
5813 
5814  if (!PG_ARGISNULL(1))
5815  {
5816 #ifdef HAVE_INT128
5817  do_int128_discard(state, (int128) PG_GETARG_INT32(1));
5818 #else
5819  /* Should never fail, all inputs have dscale 0 */
5821  elog(ERROR, "do_numeric_discard failed unexpectedly");
5822 #endif
5823  }
5824 
5826 }

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

6491 {
6492  ArrayType *transarray;
6494  Int8TransTypeData *transdata;
6495 
6496  /*
6497  * If we're invoked as an aggregate, we can cheat and modify our first
6498  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6499  * a copy of it before scribbling on it.
6500  */
6501  if (AggCheckCallContext(fcinfo, NULL))
6502  transarray = PG_GETARG_ARRAYTYPE_P(0);
6503  else
6504  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6505 
6506  if (ARR_HASNULL(transarray) ||
6507  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6508  elog(ERROR, "expected 2-element int8 array");
6509 
6510  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6511  transdata->count++;
6512  transdata->sum += newval;
6513 
6514  PG_RETURN_ARRAYTYPE_P(transarray);
6515 }

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

6578 {
6579  ArrayType *transarray;
6581  Int8TransTypeData *transdata;
6582 
6583  /*
6584  * If we're invoked as an aggregate, we can cheat and modify our first
6585  * parameter in-place to reduce palloc overhead. Otherwise we need to make
6586  * a copy of it before scribbling on it.
6587  */
6588  if (AggCheckCallContext(fcinfo, NULL))
6589  transarray = PG_GETARG_ARRAYTYPE_P(0);
6590  else
6591  transarray = PG_GETARG_ARRAYTYPE_P_COPY(0);
6592 
6593  if (ARR_HASNULL(transarray) ||
6594  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6595  elog(ERROR, "expected 2-element int8 array");
6596 
6597  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6598  transdata->count--;
6599  transdata->sum -= newval;
6600 
6601  PG_RETURN_ARRAYTYPE_P(transarray);
6602 }

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

6519 {
6520  ArrayType *transarray1;
6521  ArrayType *transarray2;
6522  Int8TransTypeData *state1;
6523  Int8TransTypeData *state2;
6524 
6525  if (!AggCheckCallContext(fcinfo, NULL))
6526  elog(ERROR, "aggregate function called in non-aggregate context");
6527 
6528  transarray1 = PG_GETARG_ARRAYTYPE_P(0);
6529  transarray2 = PG_GETARG_ARRAYTYPE_P(1);
6530 
6531  if (ARR_HASNULL(transarray1) ||
6532  ARR_SIZE(transarray1) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6533  elog(ERROR, "expected 2-element int8 array");
6534 
6535  if (ARR_HASNULL(transarray2) ||
6536  ARR_SIZE(transarray2) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6537  elog(ERROR, "expected 2-element int8 array");
6538 
6539  state1 = (Int8TransTypeData *) ARR_DATA_PTR(transarray1);
6540  state2 = (Int8TransTypeData *) ARR_DATA_PTR(transarray2);
6541 
6542  state1->count += state2->count;
6543  state1->sum += state2->sum;
6544 
6545  PG_RETURN_ARRAYTYPE_P(transarray1);
6546 }

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

4216 {
4217  int32 val = PG_GETARG_INT32(0);
4218 
4220 }

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

Referenced by JsonItemFromDatum().

◆ int4_sum()

Datum int4_sum ( PG_FUNCTION_ARGS  )

Definition at line 6362 of file numeric.c.

6363 {
6364  int64 newval;
6365 
6366  if (PG_ARGISNULL(0))
6367  {
6368  /* No non-null input seen so far... */
6369  if (PG_ARGISNULL(1))
6370  PG_RETURN_NULL(); /* still no non-null */
6371  /* This is the first non-null input. */
6372  newval = (int64) PG_GETARG_INT32(1);
6374  }
6375 
6376  /*
6377  * If we're invoked as an aggregate, we can cheat and modify our first
6378  * parameter in-place to avoid palloc overhead. If not, we need to return
6379  * the new value of the transition variable. (If int8 is pass-by-value,
6380  * then of course this is useless as well as incorrect, so just ifdef it
6381  * out.)
6382  */
6383 #ifndef USE_FLOAT8_BYVAL /* controls int8 too */
6384  if (AggCheckCallContext(fcinfo, NULL))
6385  {
6386  int64 *oldsum = (int64 *) PG_GETARG_POINTER(0);
6387 
6388  /* Leave the running sum unchanged in the new input is null */
6389  if (!PG_ARGISNULL(1))
6390  *oldsum = *oldsum + (int64) PG_GETARG_INT32(1);
6391 
6392  PG_RETURN_POINTER(oldsum);
6393  }
6394  else
6395 #endif
6396  {
6397  int64 oldsum = PG_GETARG_INT64(0);
6398 
6399  /* Leave sum unchanged if new input is null. */
6400  if (PG_ARGISNULL(1))
6401  PG_RETURN_INT64(oldsum);
6402 
6403  /* OK to do the addition. */
6404  newval = oldsum + (int64) PG_GETARG_INT32(1);
6405 
6407  }
6408 }

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

4159 {
4160  Numeric res;
4161  NumericVar result;
4162  int64 saved_val1 = val1;
4163  int w;
4164  int m;
4165 
4166  /* how much to decrease the weight by */
4167  w = log10val2 / DEC_DIGITS;
4168  /* how much is left */
4169  m = log10val2 % DEC_DIGITS;
4170 
4171  /*
4172  * If there is anything left, multiply the dividend by what's left, then
4173  * shift the weight by one more.
4174  */
4175  if (m > 0)
4176  {
4177  static int pow10[] = {1, 10, 100, 1000};
4178 
4179  StaticAssertStmt(lengthof(pow10) == DEC_DIGITS, "mismatch with DEC_DIGITS");
4180  if (unlikely(pg_mul_s64_overflow(val1, pow10[DEC_DIGITS - m], &val1)))
4181  {
4182  /*
4183  * If it doesn't fit, do the whole computation in numeric the slow
4184  * way. Note that va1l may have been overwritten, so use
4185  * saved_val1 instead.
4186  */
4187  int val2 = 1;
4188 
4189  for (int i = 0; i < log10val2; i++)
4190  val2 *= 10;
4191  res = numeric_div_opt_error(int64_to_numeric(saved_val1), int64_to_numeric(val2), NULL);
4194  Int32GetDatum(log10val2)));
4195  return res;
4196  }
4197  w++;
4198  }
4199 
4200  init_var(&result);
4201 
4202  int64_to_numericvar(val1, &result);
4203 
4204  result.weight -= w;
4205  result.dscale += w * DEC_DIGITS - (DEC_DIGITS - m);
4206 
4207  res = make_result(&result);
4208 
4209  free_var(&result);
4210 
4211  return res;
4212 }
Datum numeric_round(PG_FUNCTION_ARGS)
Definition: numeric.c:1462
Numeric numeric_div_opt_error(Numeric num1, Numeric num2, bool *have_error)
Definition: numeric.c:3061
static void int64_to_numericvar(int64 val, NumericVar *var)
Definition: numeric.c:7652
#define unlikely(x)
Definition: c.h:273
#define lengthof(array)
Definition: c.h:734
#define StaticAssertStmt(condition, errmessage)
Definition: c.h:918
#define DirectFunctionCall2(func, arg1, arg2)
Definition: fmgr.h:633
static bool pg_mul_s64_overflow(int64 a, int64 b, int64 *result)
Definition: int.h:215
#define DatumGetNumeric(X)
Definition: numeric.h:59
#define Int32GetDatum(X)
Definition: postgres.h:523

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, StaticAssertStmt, 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 7652 of file numeric.c.

7653 {
7654  uint64 uval,
7655  newuval;
7656  NumericDigit *ptr;
7657  int ndigits;
7658 
7659  /* int64 can require at most 19 decimal digits; add one for safety */
7660  alloc_var(var, 20 / DEC_DIGITS);
7661  if (val < 0)
7662  {
7663  var->sign = NUMERIC_NEG;
7664  uval = -val;
7665  }
7666  else
7667  {
7668  var->sign = NUMERIC_POS;
7669  uval = val;
7670  }
7671  var->dscale = 0;
7672  if (val == 0)
7673  {
7674  var->ndigits = 0;
7675  var->weight = 0;
7676  return;
7677  }
7678  ptr = var->digits + var->ndigits;
7679  ndigits = 0;
7680  do
7681  {
7682  ptr--;
7683  ndigits++;
7684  newuval = uval / NBASE;
7685  *ptr = uval - newuval * NBASE;
7686  uval = newuval;
7687  } while (uval);
7688  var->digits = ptr;
7689  var->ndigits = ndigits;
7690  var->weight = ndigits - 1;
7691 }

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(), sqrt_var(), and width_bucket_numeric().

◆ int8_accum()

Datum int8_accum ( PG_FUNCTION_ARGS  )

Definition at line 5397 of file numeric.c.

5398 {
5400 
5401  state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5402 
5403  /* Create the state data on the first call */
5404  if (state == NULL)
5405  state = makeNumericAggState(fcinfo, true);
5406 
5407  if (!PG_ARGISNULL(1))
5409 
5411 }
static NumericAggState * makeNumericAggState(FunctionCallInfo fcinfo, bool calcSumX2)
Definition: numeric.c:4614

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

5830 {
5832 
5833  state = PG_ARGISNULL(0) ? NULL : (NumericAggState *) PG_GETARG_POINTER(0);
5834 
5835  /* Should not get here with no state */
5836  if (state == NULL)
5837  elog(ERROR, "int8_accum_inv called with NULL state");
5838 
5839  if (!PG_ARGISNULL(1))
5840  {
5841  /* Should never fail, all inputs have dscale 0 */
5843  elog(ERROR, "do_numeric_discard failed unexpectedly");
5844  }
5845 
5847 }

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

6606 {
6607  ArrayType *transarray = PG_GETARG_ARRAYTYPE_P(0);
6608  Int8TransTypeData *transdata;
6609  Datum countd,
6610  sumd;
6611 
6612  if (ARR_HASNULL(transarray) ||
6613  ARR_SIZE(transarray) != ARR_OVERHEAD_NONULLS(1) + sizeof(Int8TransTypeData))
6614  elog(ERROR, "expected 2-element int8 array");
6615  transdata = (Int8TransTypeData *) ARR_DATA_PTR(transarray);
6616 
6617  /* SQL defines AVG of no values to be NULL */
6618  if (transdata->count == 0)
6619  PG_RETURN_NULL();
6620 
6621  countd = NumericGetDatum(int64_to_numeric(transdata->count));
6622  sumd = NumericGetDatum(int64_to_numeric(transdata->sum));
6623 
6625 }
Datum numeric_div(PG_FUNCTION_ARGS)
Definition: numeric.c:3041

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

5596 {
5598 
5599  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5600 
5601  /* Create the state data on the first call */
5602  if (state == NULL)
5603  state = makePolyNumAggState(fcinfo, false);
5604 
5605  if (!PG_ARGISNULL(1))
5606  {
5607 #ifdef HAVE_INT128
5608  do_int128_accum(state, (int128) PG_GETARG_INT64(1));
5609 #else
5611 #endif
5612  }
5613 
5615 }

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

5851 {
5853 
5854  state = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5855 
5856  /* Should not get here with no state */
5857  if (state == NULL)
5858  elog(ERROR, "int8_avg_accum_inv called with NULL state");
5859 
5860  if (!PG_ARGISNULL(1))
5861  {
5862 #ifdef HAVE_INT128
5863  do_int128_discard(state, (int128) PG_GETARG_INT64(1));
5864 #else
5865  /* Should never fail, all inputs have dscale 0 */
5867  elog(ERROR, "do_numeric_discard failed unexpectedly");
5868 #endif
5869  }
5870 
5872 }

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

5623 {
5624  PolyNumAggState *state1;
5625  PolyNumAggState *state2;
5626  MemoryContext agg_context;
5627  MemoryContext old_context;
5628 
5629  if (!AggCheckCallContext(fcinfo, &agg_context))
5630  elog(ERROR, "aggregate function called in non-aggregate context");
5631 
5632  state1 = PG_ARGISNULL(0) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(0);
5633  state2 = PG_ARGISNULL(1) ? NULL : (PolyNumAggState *) PG_GETARG_POINTER(1);
5634 
5635  if (state2 == NULL)
5636  PG_RETURN_POINTER(state1);
5637 
5638  /* manually copy all fields from state2 to state1 */
5639  if (state1 == NULL)
5640  {
5641  old_context = MemoryContextSwitchTo(agg_context);
5642 
5643  state1 = makePolyNumAggState(fcinfo, false);
5644  state1->N = state2->N;
5645 
5646 #ifdef HAVE_INT128
5647  state1->sumX = state2->sumX;
5648 #else
5649  accum_sum_copy(&state1->sumX, &state2->sumX);
5650 #endif
5651  MemoryContextSwitchTo(old_context);
5652 
5653  PG_RETURN_POINTER(state1);
5654  }
5655 
5656  if (state2->N > 0)
5657  {
5658  state1->N += state2->N;
5659 
5660 #ifdef HAVE_INT128
5661  state1->sumX += state2->sumX;
5662 #else
5663  /* The rest of this needs to work in the aggregate context */
5664  old_context = MemoryContextSwitchTo(agg_context);
5665 
5666  /* Accumulate sums */
5667  accum_sum_combine(&state1->sumX, &state2->sumX);
5668 
5669  MemoryContextSwitchTo(old_context);
5670 #endif
5671 
5672  }
5673  PG_RETURN_POINTER(state1);
5674 }
static void accum_sum_combine(NumericSumAccum *accum, NumericSumAccum *accum2)
Definition: numeric.c:11446
static void accum_sum_copy(NumericSumAccum *dst, NumericSumAccum *src)
Definition: numeric.c:11429
NumericSumAccum sumX
Definition: numeric.c:4596

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

5732 {
5733  bytea *sstate;
5734  PolyNumAggState *result;
5736  NumericVar tmp_var;
5737 
5738  if (!AggCheckCallContext(fcinfo, NULL))
5739  elog(ERROR, "aggregate function called in non-aggregate context");
5740 
5741  sstate = PG_GETARG_BYTEA_PP(0);
5742 
5743  init_var(&tmp_var);
5744 
5745  /*
5746  * Copy the bytea into a StringInfo so that we can "receive" it using the
5747  * standard recv-function infrastructure.
5748  */
5749  initStringInfo(&buf);
5751  VARDATA_ANY(sstate), VARSIZE_ANY_EXHDR(sstate));
5752 
5753  result = makePolyNumAggStateCurrentContext(false);
5754 
5755  /* N */
5756  result->N = pq_getmsgint64(&buf);
5757 
5758  /* sumX */
5759  numericvar_deserialize(&buf, &tmp_var);
5760 #ifdef HAVE_INT128
5761  numericvar_to_int128(&tmp_var, &result->sumX);
5762 #else
5763  accum_sum_add(&result->sumX, &tmp_var);
5764 #endif
5765 
5766  pq_getmsgend(&buf);
5767  pfree(buf.data);
5768 
5769  free_var(&tmp_var);
5770 
5771  PG_RETURN_POINTER(result);
5772 }
static void numericvar_deserialize(StringInfo buf, NumericVar *var)
Definition: numeric.c:7296
#define makePolyNumAggStateCurrentContext
Definition: numeric.c:5347
#define PG_GETARG_BYTEA_PP(n)
Definition: fmgr.h:308
#define VARDATA_ANY(PTR)
Definition: postgres.h:361
#define VARSIZE_ANY_EXHDR(PTR)
Definition: postgres.h:354
void pq_getmsgend(StringInfo msg)
Definition: pqformat.c:637
int64 pq_getmsgint64(StringInfo msg)
Definition: pqformat.c:455
void appendBinaryStringInfo(StringInfo str, const char *data, int datalen)
Definition: stringinfo.c:227
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59
Definition: c.h:622

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

5683 {
5686  bytea *result;
5687  NumericVar tmp_var;
5688 
5689  /* Ensure we disallow calling when not in aggregate context */
5690  if (!AggCheckCallContext(fcinfo, NULL))
5691  elog(ERROR, "aggregate function called in non-aggregate context");
5692 
5694 
5695  /*
5696  * If the platform supports int128 then sumX will be a 128 integer type.
5697  * Here we'll convert that into a numeric type so that the combine state
5698  * is in the same format for both int128 enabled machines and machines
5699  * which don't support that type. The logic here is that one day we might
5700  * like to send these over to another server for further processing and we
5701  * want a standard format to work with.
5702  */
5703 
5704  init_var(&tmp_var);
5705 
5706  pq_begintypsend(&buf);
5707 
5708  /* N */
5709  pq_sendint64(&buf, state->N);
5710 
5711  /* sumX */
5712 #ifdef HAVE_INT128
5713  int128_to_numericvar(state->sumX, &tmp_var);
5714 #else
5715  accum_sum_final(&state->sumX, &tmp_var);
5716 #endif
5717  numericvar_serialize(&buf, &tmp_var);
5718 
5719  result = pq_endtypsend(&buf);
5720 
5721  free_var(&tmp_var);
5722 
5723  PG_RETURN_BYTEA_P(result);
5724 }
static void numericvar_serialize(StringInfo buf, const NumericVar *var)
Definition: numeric.c:7280
#define PG_RETURN_BYTEA_P(x)
Definition: fmgr.h:371
void pq_begintypsend(StringInfo buf)
Definition: pqformat.c:328
bytea * pq_endtypsend(StringInfo buf)
Definition: pqformat.c:348
static void pq_sendint64(StringInfo buf, uint64 i)
Definition: pqformat.h:153

References accum_sum_final(), AggCheckCallContext(), buf, elog, ERROR, free_var(), init_var, numericvar_serialize(), PG_GETARG_POINTER, PG_RETURN_BYTEA_P, pq_begintypsend(), pq_endtypsend(), and pq_sendint64().

◆ int8_numeric()

Datum int8_numeric ( PG_FUNCTION_ARGS  )

Definition at line 4303 of file numeric.c.

4304 {
4305  int64