numericvar_access.patch
text/x-patch
Filename: numericvar_access.patch
Type: text/x-patch
Part: 0
Message:
Re: access numeric data in module
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/backend/utils/adt/numeric.c | 8 | 142 |
| src/include/utils/numeric.h | 145 | 1 |
diff --git a/src/backend/utils/adt/numeric.c b/src/backend/utils/adt/numeric.c
index 40dcbc7b67..126b7dc452 100644
--- a/src/backend/utils/adt/numeric.c
+++ b/src/backend/utils/adt/numeric.c
@@ -50,60 +50,6 @@
#define NUMERIC_DEBUG
*/
-
-/* ----------
- * 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 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 0
-#define NBASE 10
-#define HALF_NBASE 5
-#define DEC_DIGITS 1 /* decimal digits per NBASE digit */
-#define MUL_GUARD_DIGITS 4 /* these are measured in NBASE digits */
-#define DIV_GUARD_DIGITS 8
-
-typedef signed char NumericDigit;
-#endif
-
-#if 0
-#define NBASE 100
-#define HALF_NBASE 50
-#define DEC_DIGITS 2 /* decimal digits per NBASE digit */
-#define MUL_GUARD_DIGITS 3 /* these are measured in NBASE digits */
-#define DIV_GUARD_DIGITS 6
-
-typedef signed char NumericDigit;
-#endif
-
-#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
-
-#define NBASE_SQR (NBASE * NBASE)
-
/*
* The Numeric type as stored on disk.
*
@@ -252,75 +198,6 @@ struct NumericData
| ((n)->choice.n_short.n_header & NUMERIC_SHORT_WEIGHT_MASK)) \
: ((n)->choice.n_long.n_weight))
-/*
- * Maximum weight of a stored Numeric value (based on the use of int16 for the
- * weight in NumericLong). Note that intermediate values held in NumericVar
- * and NumericSumAccum variables may have much larger weights.
- */
-#define NUMERIC_WEIGHT_MAX PG_INT16_MAX
-
-/* ----------
- * 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 palloc'd digit buffer for the
- * NumericVar. 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 NULL then the digit buffer isn't actually palloc'd and should
- * not be freed --- see the constants below for an example.
- *
- * dscale, or 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.
- * This is feasible because the digit buffer is separate from the variable.
- * ----------
- */
-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 palloc'd space for digits[] */
- NumericDigit *digits; /* base-NBASE digits */
-} NumericVar;
-
-
/* ----------
* Data for generate_series
* ----------
@@ -491,8 +368,6 @@ static void dump_var(const char *str, NumericVar *var);
pfree(buf); \
} while (0)
-#define init_var(v) memset(v, 0, sizeof(NumericVar))
-
#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) \
@@ -502,10 +377,6 @@ static void dump_var(const char *str, NumericVar *var);
(weight) <= NUMERIC_SHORT_WEIGHT_MAX && \
(weight) >= NUMERIC_SHORT_WEIGHT_MIN)
-static void alloc_var(NumericVar *var, int ndigits);
-static void free_var(NumericVar *var);
-static void zero_var(NumericVar *var);
-
static bool set_var_from_str(const char *str, const char *cp,
NumericVar *dest, const char **endptr,
Node *escontext);
@@ -514,9 +385,6 @@ static bool set_var_from_non_decimal_integer_str(const char *str,
int base, NumericVar *dest,
const char **endptr,
Node *escontext);
-static void set_var_from_num(Numeric num, NumericVar *dest);
-static void init_var_from_num(Numeric num, NumericVar *dest);
-static void set_var_from_var(const NumericVar *value, NumericVar *dest);
static char *get_str_from_var(const NumericVar *var);
static char *get_str_from_var_sci(const NumericVar *var, int rscale);
@@ -524,8 +392,6 @@ static void numericvar_serialize(StringInfo buf, const NumericVar *var);
static void numericvar_deserialize(StringInfo buf, NumericVar *var);
static Numeric duplicate_numeric(Numeric num);
-static Numeric make_result(const NumericVar *var);
-static Numeric make_result_opt_error(const NumericVar *var, bool *have_error);
static bool apply_typmod(NumericVar *var, int32 typmod, Node *escontext);
static bool apply_typmod_special(Numeric num, int32 typmod, Node *escontext);
@@ -7067,7 +6933,7 @@ dump_var(const char *str, NumericVar *var)
*
* Allocate a digit buffer of ndigits digits (plus a spare digit for rounding)
*/
-static void
+void
alloc_var(NumericVar *var, int ndigits)
{
digitbuf_free(var->buf);
@@ -7083,7 +6949,7 @@ alloc_var(NumericVar *var, int ndigits)
*
* Return the digit buffer of a variable to the free pool
*/
-static void
+void
free_var(NumericVar *var)
{
digitbuf_free(var->buf);
@@ -7099,7 +6965,7 @@ free_var(NumericVar *var)
* Set a variable to ZERO.
* Note: its dscale is not touched.
*/
-static void
+void
zero_var(NumericVar *var)
{
digitbuf_free(var->buf);
@@ -7534,7 +7400,7 @@ invalid_syntax:
*
* Convert the packed db format into a variable
*/
-static void
+void
set_var_from_num(Numeric num, NumericVar *dest)
{
int ndigits;
@@ -7565,7 +7431,7 @@ set_var_from_num(Numeric num, NumericVar *dest)
* propagate to the original Numeric! It's OK to use it as the destination
* argument of one of the calculational functions, though.
*/
-static void
+void
init_var_from_num(Numeric num, NumericVar *dest)
{
dest->ndigits = NUMERIC_NDIGITS(num);
@@ -7582,7 +7448,7 @@ init_var_from_num(Numeric num, NumericVar *dest)
*
* Copy one variable into another
*/
-static void
+void
set_var_from_var(const NumericVar *value, NumericVar *dest)
{
NumericDigit *newbuf;
@@ -7896,7 +7762,7 @@ duplicate_numeric(Numeric num)
* If "have_error" isn't NULL, on overflow *have_error is set to true and
* NULL is returned. This is helpful when caller needs to handle errors.
*/
-static Numeric
+Numeric
make_result_opt_error(const NumericVar *var, bool *have_error)
{
Numeric result;
@@ -8005,7 +7871,7 @@ make_result_opt_error(const NumericVar *var, bool *have_error)
*
* An interface to make_result_opt_error() without "have_error" argument.
*/
-static Numeric
+Numeric
make_result(const NumericVar *var)
{
return make_result_opt_error(var, NULL);
diff --git a/src/include/utils/numeric.h b/src/include/utils/numeric.h
index 9e79fc376c..32e77d2d13 100644
--- a/src/include/utils/numeric.h
+++ b/src/include/utils/numeric.h
@@ -42,6 +42,59 @@
#define NUMERIC_MAX_RESULT_SCALE (NUMERIC_MAX_PRECISION * 2)
+/* ----------
+ * 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 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 0
+#define NBASE 10
+#define HALF_NBASE 5
+#define DEC_DIGITS 1 /* decimal digits per NBASE digit */
+#define MUL_GUARD_DIGITS 4 /* these are measured in NBASE digits */
+#define DIV_GUARD_DIGITS 8
+
+typedef signed char NumericDigit;
+#endif
+
+#if 0
+#define NBASE 100
+#define HALF_NBASE 50
+#define DEC_DIGITS 2 /* decimal digits per NBASE digit */
+#define MUL_GUARD_DIGITS 3 /* these are measured in NBASE digits */
+#define DIV_GUARD_DIGITS 6
+
+typedef signed char NumericDigit;
+#endif
+
+#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
+
+#define NBASE_SQR (NBASE * NBASE)
+
/*
* For inherently inexact calculations such as division and square root,
* we try to get at least this many significant digits; the idea is to
@@ -49,8 +102,85 @@
*/
#define NUMERIC_MIN_SIG_DIGITS 16
+/*
+ * sign field of NumericVar
+ */
+
+#define NUMERIC_POS 0x0000
+#define NUMERIC_NEG 0x4000
+#define NUMERIC_NAN 0xC000
+#define NUMERIC_PINF 0xD000
+#define NUMERIC_NINF 0xF000
+
+/*
+ * Maximum weight of a stored Numeric value (based on the use of int16 for the
+ * weight in NumericLong). Note that intermediate values held in NumericVar
+ * and NumericSumAccum variables may have much larger weights.
+ */
+ #define NUMERIC_WEIGHT_MAX PG_INT16_MAX
+
+/* ----------
+ * 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 palloc'd digit buffer for the
+ * NumericVar. 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 NULL then the digit buffer isn't actually palloc'd and should
+ * not be freed --- see the constants below for an example.
+ *
+ * dscale, or 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.
+ * This is feasible because the digit buffer is separate from the variable.
+ * ----------
+ */
+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 palloc'd space for digits[] */
+ NumericDigit *digits; /* base-NBASE digits */
+} NumericVar;
+
/* The actual contents of Numeric are private to numeric.c */
-struct NumericData;
typedef struct NumericData *Numeric;
/*
@@ -79,9 +209,23 @@ NumericGetDatum(Numeric X)
#define PG_GETARG_NUMERIC_COPY(n) DatumGetNumericCopy(PG_GETARG_DATUM(n))
#define PG_RETURN_NUMERIC(x) return NumericGetDatum(x)
+#define init_var(v) memset(v, 0, sizeof(NumericVar))
+
/*
* Utility functions in numeric.c
*/
+
+extern void alloc_var(NumericVar *var, int ndigits);
+extern void free_var(NumericVar *var);
+extern void zero_var(NumericVar *var);
+
+extern void set_var_from_num(Numeric num, NumericVar *dest);
+extern void init_var_from_num(Numeric num, NumericVar *dest);
+extern void set_var_from_var(const NumericVar *value, NumericVar *dest);
+
+extern Numeric make_result(const NumericVar *var);
+extern Numeric make_result_opt_error(const NumericVar *var, bool *have_error);
+
extern bool numeric_is_nan(Numeric num);
extern bool numeric_is_inf(Numeric num);
extern int32 numeric_maximum_size(int32 typmod);