| /*------------------------------------------------------------------------- |
| * |
| * numeric.h |
| * Definitions for the exact numeric data type of Postgres |
| * |
| * Original coding 1998, Jan Wieck. Heavily revised 2003, Tom Lane. |
| * |
| * Copyright (c) 1998-2021, PostgreSQL Global Development Group |
| * |
| * src/include/utils/numeric.h |
| * |
| *------------------------------------------------------------------------- |
| */ |
| #ifndef _PG_NUMERIC_H_ |
| #define _PG_NUMERIC_H_ |
| |
| #include "fmgr.h" |
| |
| /* |
| * Limit on the precision (and hence scale) specifiable in a NUMERIC typmod. |
| * Note that the implementation limit on the length of a numeric value is |
| * much larger --- beware of what you use this for! |
| */ |
| #define NUMERIC_MAX_PRECISION 1000 |
| |
| /* |
| * Internal limits on the scales chosen for calculation results |
| */ |
| #define NUMERIC_MAX_DISPLAY_SCALE NUMERIC_MAX_PRECISION |
| #define NUMERIC_MIN_DISPLAY_SCALE 0 |
| |
| #define NUMERIC_MAX_RESULT_SCALE (NUMERIC_MAX_PRECISION * 2) |
| |
| /* |
| * For inherently inexact calculations such as division and square root, |
| * we try to get at least this many significant digits; the idea is to |
| * deliver a result no worse than float8 would. |
| */ |
| #define NUMERIC_MIN_SIG_DIGITS 16 |
| |
| |
| /* ---------- |
| * Local data types |
| * |
| * Numeric values are represented in a base-NBASE floating point format. |
| * Each "digit" ranges from 0 to NBASE-1. The type NumericDigit is signed |
| * and wide enough to store a digit. We assume that NBASE*NBASE can fit in |
| * an int. Although the purely calculational routines could handle any even |
| * NBASE that's less than sqrt(INT_MAX), in practice we are only interested |
| * in NBASE a power of ten, so that I/O conversions and decimal rounding |
| * are easy. Also, it's actually more efficient if NBASE is rather less than |
| * sqrt(INT_MAX), so that there is "headroom" for mul_var and div_var_fast to |
| * postpone processing carries. |
| * |
| * Values of NBASE other than 10000 are considered of historical interest only |
| * and are no longer supported in any sense; no mechanism exists for the client |
| * to discover the base, so every client supporting binary mode expects the |
| * base-10000 format. If you plan to change this, also note the numeric |
| * abbreviation code, which assumes NBASE=10000. |
| * ---------- |
| */ |
| |
| |
| #if 1 |
| #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 |
| |
| typedef int16 NumericDigit; |
| #endif |
| |
| /* |
| * The Numeric type as stored on disk. |
| * |
| * If the high bits of the first word of a NumericChoice (n_header, or |
| * n_short.n_header, or n_long.n_sign_dscale) are NUMERIC_SHORT, then the |
| * numeric follows the NumericShort format; if they are NUMERIC_POS or |
| * NUMERIC_NEG, it follows the NumericLong format. If they are NUMERIC_SPECIAL, |
| * the value is a NaN or Infinity. We currently always store SPECIAL values |
| * using just two bytes (i.e. only n_header), but previous releases used only |
| * the NumericLong format, so we might find 4-byte NaNs (though not infinities) |
| * on disk if a database has been migrated using pg_upgrade. In either case, |
| * the low-order bits of a special value's header are reserved and currently |
| * should always be set to zero. |
| * |
| * In the NumericShort format, the remaining 14 bits of the header word |
| * (n_short.n_header) are allocated as follows: 1 for sign (positive or |
| * negative), 6 for dynamic scale, and 7 for weight. In practice, most |
| * commonly-encountered values can be represented this way. |
| * |
| * In the NumericLong format, the remaining 14 bits of the header word |
| * (n_long.n_sign_dscale) represent the display scale; and the weight is |
| * stored separately in n_weight. |
| * |
| * NOTE: by convention, values in the packed form have been stripped of |
| * all leading and trailing zero digits (where a "digit" is of base NBASE). |
| * In particular, if the value is zero, there will be no digits at all! |
| * The weight is arbitrary in that case, but we normally set it to zero. |
| */ |
| |
| struct NumericShort |
| { |
| uint16 n_header; /* Sign + display scale + weight */ |
| NumericDigit n_data[FLEXIBLE_ARRAY_MEMBER]; /* Digits */ |
| }; |
| |
| struct NumericLong |
| { |
| uint16 n_sign_dscale; /* Sign + display scale */ |
| int16 n_weight; /* Weight of 1st digit */ |
| NumericDigit n_data[FLEXIBLE_ARRAY_MEMBER]; /* Digits */ |
| }; |
| |
| union NumericChoice |
| { |
| uint16 n_header; /* Header word */ |
| struct NumericLong n_long; /* Long form (4-byte header) */ |
| struct NumericShort n_short; /* Short form (2-byte header) */ |
| }; |
| |
| struct NumericData |
| { |
| int32 vl_len_; /* varlena header (do not touch directly!) */ |
| union NumericChoice choice; /* choice of format */ |
| }; |
| typedef struct NumericData *Numeric; |
| |
| /* |
| * Interpretation of high bits. |
| */ |
| |
| #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)) |
| |
| /* |
| * If the flag bits are NUMERIC_SHORT or NUMERIC_SPECIAL, we want the short |
| * header; otherwise, we want the long one. Instead of testing against each |
| * value, we can just look at the high bit, for a slight efficiency gain. |
| */ |
| #define NUMERIC_HEADER_IS_SHORT(n) (((n)->choice.n_header & 0x8000) != 0) |
| #define NUMERIC_HEADER_SIZE(n) \ |
| (VARHDRSZ + sizeof(uint16) + \ |
| (NUMERIC_HEADER_IS_SHORT(n) ? 0 : sizeof(int16))) |
| |
| /* |
| * Definitions for special values (NaN, positive infinity, negative infinity). |
| * |
| * The two bits after the NUMERIC_SPECIAL bits are 00 for NaN, 01 for positive |
| * infinity, 11 for negative infinity. (This makes the sign bit match where |
| * it is in a short-format value, though we make no use of that at present.) |
| * We could mask off the remaining bits before testing the active bits, but |
| * currently those bits must be zeroes, so masking would just add cycles. |
| */ |
| #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) |
| |
| /* |
| * Short format definitions. |
| */ |
| |
| #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)) |
| |
| /* |
| * Extract sign, display scale, weight. These macros extract field values |
| * suitable for the NumericVar format from the Numeric (on-disk) format. |
| * |
| * Note that we don't trouble to ensure that dscale and weight read as zero |
| * for an infinity; however, that doesn't matter since we never convert |
| * "special" numerics to NumericVar form. Only the constants defined below |
| * (const_nan, etc) ever represent a non-finite value as a NumericVar. |
| */ |
| |
| #define NUMERIC_DSCALE_MASK 0x3FFF |
| #define NUMERIC_DSCALE_MAX NUMERIC_DSCALE_MASK |
| |
| #define NUMERIC_SIGN(n) \ |
| (NUMERIC_IS_SHORT(n) ? \ |
| (((n)->choice.n_short.n_header & NUMERIC_SHORT_SIGN_MASK) ? \ |
| NUMERIC_NEG : NUMERIC_POS) : \ |
| (NUMERIC_IS_SPECIAL(n) ? \ |
| NUMERIC_EXT_FLAGBITS(n) : NUMERIC_FLAGBITS(n))) |
| #define NUMERIC_DSCALE(n) (NUMERIC_HEADER_IS_SHORT((n)) ? \ |
| ((n)->choice.n_short.n_header & NUMERIC_SHORT_DSCALE_MASK) \ |
| >> NUMERIC_SHORT_DSCALE_SHIFT \ |
| : ((n)->choice.n_long.n_sign_dscale & NUMERIC_DSCALE_MASK)) |
| #define NUMERIC_WEIGHT(n) (NUMERIC_HEADER_IS_SHORT((n)) ? \ |
| (((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_SIGN_MASK ? \ |
| ~NUMERIC_SHORT_WEIGHT_MASK : 0) \ |
| | ((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \ |
| : ((n)->choice.n_long.n_weight)) |
| #define NUMERIC_DIGITS(num) (NUMERIC_HEADER_IS_SHORT(num) ? \ |
| (num)->choice.n_short.n_data : (num)->choice.n_long.n_data) |
| #define NUMERIC_NDIGITS(num) \ |
| ((VARSIZE(num) - NUMERIC_HEADER_SIZE(num)) / sizeof(NumericDigit)) |
| |
| /* ---------- |
| * NumericVar is the format we use for arithmetic. The digit-array part |
| * is the same as the NumericData storage format, but the header is more |
| * complex. |
| * |
| * The value represented by a NumericVar is determined by the sign, weight, |
| * ndigits, and digits[] array. If it is a "special" value (NaN or Inf) |
| * then only the sign field matters; ndigits should be zero, and the weight |
| * and dscale fields are ignored. |
| * |
| * Note: the first digit of a NumericVar's value is assumed to be multiplied |
| * by NBASE ** weight. Another way to say it is that there are weight+1 |
| * digits before the decimal point. It is possible to have weight < 0. |
| * |
| * buf: points at the physical start of the digit buffer for the NumericVar. |
| * This is either the local buffer (ndb) or a palloc'd buffer. |
| * |
| * digits: points at the first digit in actual use (the one with the |
| * specified weight). We normally leave an unused digit or two |
| * (preset to zeroes) between buf and digits, so that there is room to store |
| * a carry out of the top digit without reallocating space. We just need to |
| * decrement digits (and increment weight) to make room for the carry digit. |
| * (There is no such extra space in a numeric value stored in the database, |
| * only in a NumericVar in memory.) |
| * |
| * If buf is set to ndb, then the digit buffer isn't actually palloc'd and |
| * should not be freed --- see the constants below for an example. |
| * |
| * dscale: display scale, is the nominal precision expressed as number |
| * of digits after the decimal point (it must always be >= 0 at present). |
| * dscale may be more than the number of physically stored fractional digits, |
| * implying that we have suppressed storage of significant trailing zeroes. |
| * It should never be less than the number of stored digits, since that would |
| * imply hiding digits that are present. NOTE that dscale is always expressed |
| * in *decimal* digits, and so it may correspond to a fractional number of |
| * base-NBASE digits --- divide by DEC_DIGITS to convert to NBASE digits. |
| * |
| * rscale, or result scale, is the target precision for a computation. |
| * Like dscale it is expressed as number of *decimal* digits after the decimal |
| * point, and is always >= 0 at present. |
| * Note that rscale is not stored in variables --- it's figured on-the-fly |
| * from the dscales of the inputs. |
| * |
| * While we consistently use "weight" to refer to the base-NBASE weight of |
| * a numeric value, it is convenient in some scale-related calculations to |
| * make use of the base-10 weight (ie, the approximate log10 of the value). |
| * To avoid confusion, such a decimal-units weight is called a "dweight". |
| * |
| * NB: All the variable-level functions are written in a style that makes it |
| * possible to give one and the same variable as argument and destination. |
| * |
| * ---------- |
| */ |
| #define NUMERIC_LOCAL_NDIG 36 /* number of 'digits' in local digits[] */ |
| #define NUMERIC_LOCAL_NMAX (NUMERIC_LOCAL_NDIG - 2) |
| #define NUMERIC_LOCAL_DTXT 128 /* number of char in local text */ |
| #define NUMERIC_LOCAL_DMAX (NUMERIC_LOCAL_DTXT - 2) |
| |
| typedef struct NumericVar |
| { |
| int ndigits; /* # of digits in digits[] - can be 0! */ |
| int weight; /* weight of first digit */ |
| int sign; /* NUMERIC_POS, _NEG, _NAN, _PINF, or _NINF */ |
| int dscale; /* display scale */ |
| NumericDigit *buf; /* start of space for digits[] */ |
| NumericDigit *digits; /* base-NBASE digits */ |
| NumericDigit ndb[NUMERIC_LOCAL_NDIG]; /* local space for digits[] */ |
| } NumericVar; |
| |
| #define NUMERIC_LOCAL_HSIZ \ |
| (sizeof(NumericVar) - (sizeof(NumericDigit) * NUMERIC_LOCAL_NDIG)) |
| |
| |
| /* |
| * NumericVar interface macros |
| * used to build a Numeric by NumericVar |
| */ |
| |
| extern void init_numeric_var(NumericVar *var); |
| extern void free_numeric_var(NumericVar *var); |
| |
| extern void alloc_numeric_var(NumericVar *var, int ndigits); |
| extern void zero_numeric_var(NumericVar *var); |
| extern const char *init_var_from_str(const char *str, const char *cp, NumericVar *dest); |
| extern void init_var_from_var(const NumericVar *value, NumericVar *dest); |
| extern void init_ro_var_from_var(const NumericVar *value, NumericVar *dest); |
| extern void set_var_from_num(Numeric value, NumericVar *dest); |
| extern void init_var_from_num(Numeric value, NumericVar *dest); |
| extern void set_var_from_var(const NumericVar *value, NumericVar *dest); |
| extern char *get_str_from_var(const NumericVar *var); |
| extern char *get_str_from_var_sci(const NumericVar *var, int rscale); |
| |
| extern Numeric make_numeric_result(const NumericVar *var); |
| |
| extern Numeric make_zero_numeric_result(void); |
| extern Numeric make_one_numeric_result(void); |
| extern Numeric make_minus_one_numeric_result(void); |
| |
| extern Numeric make_nan_numeric_result(void); |
| extern Numeric make_pinf_numeric_result(void); |
| extern Numeric make_ninf_numeric_result(void); |
| |
| /* |
| * fmgr interface macros |
| */ |
| |
| #define DatumGetNumeric(X) ((Numeric) PG_DETOAST_DATUM(X)) |
| #define DatumGetNumericCopy(X) ((Numeric) PG_DETOAST_DATUM_COPY(X)) |
| #define NumericGetDatum(X) PointerGetDatum(X) |
| #define PG_GETARG_NUMERIC(n) DatumGetNumeric(PG_GETARG_DATUM(n)) |
| #define PG_GETARG_NUMERIC_COPY(n) DatumGetNumericCopy(PG_GETARG_DATUM(n)) |
| #define PG_RETURN_NUMERIC(x) return NumericGetDatum(x) |
| extern double numeric_to_double_no_overflow(Numeric num); |
| extern int cmp_numerics(Numeric num1, Numeric num2); |
| extern float8 numeric_li_fraction(Numeric x, Numeric x0, Numeric x1, |
| bool *eq_bounds, bool *eq_abscissas); |
| extern Numeric numeric_li_value(float8 f, Numeric y0, Numeric y1); |
| |
| /* |
| * Some of utility functions. which have same definition as the macro, |
| * but some of extension will these function rather than use the marco |
| * like `pgrx`. |
| */ |
| extern int16 *numeric_digits(Numeric num); |
| extern int numeric_len(Numeric num); |
| extern bool numeric_is_nan(Numeric num); |
| extern bool numeric_is_inf(Numeric num); |
| |
| /* |
| * Utility functions in numeric.c |
| */ |
| int32 numeric_maximum_size(int32 typmod); |
| extern char *numeric_out_sci(Numeric num, int scale); |
| extern char *numeric_normalize(Numeric num); |
| |
| extern Numeric int64_to_numeric(int64 val); |
| extern Numeric int64_div_fast_to_numeric(int64 val1, int log10val2); |
| |
| extern Numeric numeric_add_opt_error(Numeric num1, Numeric num2, |
| bool *have_error); |
| extern Numeric numeric_sub_opt_error(Numeric num1, Numeric num2, |
| bool *have_error); |
| extern Numeric numeric_mul_opt_error(Numeric num1, Numeric num2, |
| bool *have_error); |
| extern Numeric numeric_div_opt_error(Numeric num1, Numeric num2, |
| bool *have_error); |
| extern Numeric numeric_mod_opt_error(Numeric num1, Numeric num2, |
| bool *have_error); |
| extern int32 numeric_int4_opt_error(Numeric num, bool *error); |
| |
| #endif /* _PG_NUMERIC_H_ */ |