See -hackers thread for discussion.
Updated version of num508, against current CVS HEAD.
--
Simon Riggs
EnterpriseDB http://www.enterprisedb.com
Index: src/backend/utils/adt/numeric.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/numeric.c,v
retrieving revision 1.105
diff -c -r1.105 numeric.c
*** src/backend/utils/adt/numeric.c 15 Jun 2007 20:56:50 -0000 1.105
--- src/backend/utils/adt/numeric.c 17 Jun 2007 20:30:43 -0000
***************
*** 85,93 ****
#define MUL_GUARD_DIGITS 2 /* these are measured in NBASE digits */
#define DIV_GUARD_DIGITS 4
! typedef int16 NumericDigit;
#endif
/* ----------
* The value represented by a NumericVar is determined by the sign, weight,
--- 85,113 ----
#define MUL_GUARD_DIGITS 2 /* these are measured in NBASE digits */
#define DIV_GUARD_DIGITS 4
! typedef uint16 NumericDigit;
#endif
+ /* ---------
+ * The storage format for NUMERIC is
+ *
+ * numeric header
+ * int32 varlen is the standard variable length header
+ * weight 8 bits in int8 so +/-127; -128 is reserved for NUMERIC_NAN
+ * scale 9 bits
+ * first 8 bits in uint8
+ * 9th bit is the high order bit of first digit
+ * sign is the second highest bit of first digit
+ *
+ * numeric digits
+ * an array of NumericDigits, each element storing NBASE
+ * digits. All trailing and leading zeros are not stored,
+ * apart from when the value is Zero AND the scale > 255
+ * in which case we store a single zero digit, with the
+ * sign set to NUMERIC_POS so the actual stored value
+ * is equal to NUMERIC_DSCALE9_1
+ *----------
+ */
/* ----------
* The value represented by a NumericVar is determined by the sign, weight,
***************
*** 131,138 ****
typedef struct NumericVar
{
int ndigits; /* # of digits in digits[] - can be 0! */
! int weight; /* weight of first digit */
! int sign; /* NUMERIC_POS, NUMERIC_NEG, or NUMERIC_NAN */
int dscale; /* display scale */
NumericDigit *buf; /* start of palloc'd space for digits[] */
NumericDigit *digits; /* base-NBASE digits */
--- 151,158 ----
typedef struct NumericVar
{
int ndigits; /* # of digits in digits[] - can be 0! */
! int weight; /* weight of first digit, or NUMERIC_NAN */
! int sign; /* NUMERIC_POS, NUMERIC_NEG */
int dscale; /* display scale */
NumericDigit *buf; /* start of palloc'd space for digits[] */
NumericDigit *digits; /* base-NBASE digits */
***************
*** 200,206 ****
{2, 0, NUMERIC_POS, 1, NULL, const_one_point_one_data};
static NumericVar const_nan =
! {0, 0, NUMERIC_NAN, 0, NULL, NULL};
#if DEC_DIGITS == 4
static const int round_powers[4] = {0, 1000, 100, 10};
--- 220,226 ----
{2, 0, NUMERIC_POS, 1, NULL, const_one_point_one_data};
static NumericVar const_nan =
! {0, NUMERIC_NAN, 0, 0, NULL, NULL};
#if DEC_DIGITS == 4
static const int round_powers[4] = {0, 1000, 100, 10};
***************
*** 381,386 ****
--- 401,412 ----
*
* External format is a sequence of int16's:
* ndigits, weight, sign, dscale, NumericDigits.
+ *
+ * Note that the internal format is now different to the external format
+ * for the representation of NaN. In the external format, a value of
+ * NUMERIC_NAN_EXTERNAL in the sign field indicates NaN, which is converted
+ * into a NUMERIC_NAN in the weight field for the internal storage format and
+ * var formats. Sending data reverses this.
*/
Datum
numeric_recv(PG_FUNCTION_ARGS)
***************
*** 407,426 ****
alloc_var(&value, len);
value.weight = (int16) pq_getmsgint(buf, sizeof(int16));
value.sign = (uint16) pq_getmsgint(buf, sizeof(uint16));
if (!(value.sign == NUMERIC_POS ||
value.sign == NUMERIC_NEG ||
! value.sign == NUMERIC_NAN))
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid sign in external \"numeric\" value")));
value.dscale = (uint16) pq_getmsgint(buf, sizeof(uint16));
for (i = 0; i < len; i++)
{
NumericDigit d = pq_getmsgint(buf, sizeof(NumericDigit));
! if (d < 0 || d >= NBASE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid digit in external \"numeric\" value")));
--- 433,469 ----
alloc_var(&value, len);
value.weight = (int16) pq_getmsgint(buf, sizeof(int16));
+ if (!(value.weight > NUMERIC_NAN ||
+ value.weight < NUMERIC_WEIGHT_MAX))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("invalid weight in external \"numeric\" value")));
+
value.sign = (uint16) pq_getmsgint(buf, sizeof(uint16));
if (!(value.sign == NUMERIC_POS ||
value.sign == NUMERIC_NEG ||
! value.sign == NUMERIC_NAN_EXTERNAL))
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid sign in external \"numeric\" value")));
+ if (value.sign == NUMERIC_NAN_EXTERNAL)
+ {
+ value.sign = NUMERIC_POS;
+ value.weight = NUMERIC_NAN;
+ }
value.dscale = (uint16) pq_getmsgint(buf, sizeof(uint16));
+ if (!(value.dscale > 0 ||
+ value.dscale <= NUMERIC_MAX_PRECISION))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
+ errmsg("invalid scale in external \"numeric\" value")));
+
for (i = 0; i < len; i++)
{
NumericDigit d = pq_getmsgint(buf, sizeof(NumericDigit));
! if (d >= NBASE)
ereport(ERROR,
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
errmsg("invalid digit in external \"numeric\" value")));
***************
*** 437,442 ****
--- 480,487 ----
/*
* numeric_send - converts numeric to binary format
+ *
+ * See comment for numeric_recv to explain conversion to NUMERIC_NAN_EXTERNAL
*/
Datum
numeric_send(PG_FUNCTION_ARGS)
***************
*** 451,456 ****
--- 496,506 ----
pq_begintypsend(&buf);
+ if (x.weight == NUMERIC_NAN)
+ {
+ x.weight = NUMERIC_POS;
+ x.sign = NUMERIC_NAN_EXTERNAL;
+ }
pq_sendint(&buf, x.ndigits, sizeof(int16));
pq_sendint(&buf, x.weight, sizeof(int16));
pq_sendint(&buf, x.sign, sizeof(int16));
***************
*** 514,526 ****
* rounding could be necessary, just make a copy of the input and modify
* its scale fields. (Note we assume the existing dscale is honest...)
*/
! ddigits = (num->n_weight + 1) * DEC_DIGITS;
! if (ddigits <= maxdigits && scale >= NUMERIC_DSCALE(num))
{
new = (Numeric) palloc(VARSIZE(num));
memcpy(new, num, VARSIZE(num));
! new->n_sign_dscale = NUMERIC_SIGN(new) |
! ((uint16) scale & NUMERIC_DSCALE_MASK);
PG_RETURN_NUMERIC(new);
}
--- 564,575 ----
* rounding could be necessary, just make a copy of the input and modify
* its scale fields. (Note we assume the existing dscale is honest...)
*/
! ddigits = (NUMERIC_WEIGHT(num) + 1) * DEC_DIGITS;
! if (ddigits <= maxdigits && scale >= num->n_dscale8bits && scale < 256)
{
new = (Numeric) palloc(VARSIZE(num));
memcpy(new, num, VARSIZE(num));
! new->n_dscale8bits = (uint8) scale;
PG_RETURN_NUMERIC(new);
}
***************
*** 613,618 ****
--- 662,668 ----
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
+ NumericDigit *resdigits;
/*
* Handle NaN
***************
*** 625,632 ****
*/
res = (Numeric) palloc(VARSIZE(num));
memcpy(res, num, VARSIZE(num));
!
! res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
PG_RETURN_NUMERIC(res);
}
--- 675,682 ----
*/
res = (Numeric) palloc(VARSIZE(num));
memcpy(res, num, VARSIZE(num));
! resdigits = (NumericDigit *) res->n_data;
! resdigits[0] &= NUMERIC_ABS_MASK;
PG_RETURN_NUMERIC(res);
}
***************
*** 637,642 ****
--- 687,693 ----
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
+ NumericDigit *resdigits;
/*
* Handle NaN
***************
*** 649,667 ****
*/
res = (Numeric) palloc(VARSIZE(num));
memcpy(res, num, VARSIZE(num));
!
/*
! * The packed format is known to be totally zero digit trimmed always. So
! * we can identify a ZERO by the fact that there are no digits at all. Do
! * nothing to a zero.
! */
! if (VARSIZE(num) != NUMERIC_HDRSZ)
! {
! /* Else, flip the sign */
! if (NUMERIC_SIGN(num) == NUMERIC_POS)
! res->n_sign_dscale = NUMERIC_NEG | NUMERIC_DSCALE(num);
else
! res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
}
PG_RETURN_NUMERIC(res);
--- 700,723 ----
*/
res = (Numeric) palloc(VARSIZE(num));
memcpy(res, num, VARSIZE(num));
! resdigits = (NumericDigit *) res->n_data;
/*
! * Do nothing to a zero.
! */
! if (NUMERIC_HAS_DIGITS(res))
! {
! /* flip the sign */
! if ((resdigits[0] & NUMERIC_SIGN_MASK) == NUMERIC_POS)
! {
! /*
! * unless the first digit is a zero with scale > 255
! * in which case we should maintain the sign as NUMERIC_POS
! */
! if (resdigits[0] != NUMERIC_DSCALE9_MASK)
! resdigits[0] |= NUMERIC_NEG;
! }
else
! resdigits[0] &= NUMERIC_ABS_MASK;
}
PG_RETURN_NUMERIC(res);
***************
*** 692,697 ****
--- 748,754 ----
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
NumericVar result;
+ NumericDigit *digits = (NumericDigit *) num->n_data;
/*
* Handle NaN
***************
*** 701,721 ****
init_var(&result);
! /*
! * The packed format is known to be totally zero digit trimmed always. So
! * we can identify a ZERO by the fact that there are no digits at all.
! */
! if (VARSIZE(num) == NUMERIC_HDRSZ)
! set_var_from_var(&const_zero, &result);
! else
{
/*
* And if there are some, we return a copy of ONE with the sign of our
* argument
*/
set_var_from_var(&const_one, &result);
! result.sign = NUMERIC_SIGN(num);
}
res = make_result(&result);
free_var(&result);
--- 758,774 ----
init_var(&result);
! if (NUMERIC_HAS_DIGITS(num))
{
/*
* And if there are some, we return a copy of ONE with the sign of our
* argument
*/
set_var_from_var(&const_one, &result);
! result.sign = (digits[0] & NUMERIC_SIGN_MASK);
}
+ else
+ set_var_from_var(&const_zero, &result);
res = make_result(&result);
free_var(&result);
***************
*** 1123,1128 ****
--- 1176,1183 ----
cmp_numerics(Numeric num1, Numeric num2)
{
int result;
+ NumericDigit *digits1 = (NumericDigit *) num1->n_data;
+ NumericDigit *digits2 = (NumericDigit *) num2->n_data;
/*
* We consider all NANs to be equal and larger than any non-NAN. This is
***************
*** 1140,1151 ****
{
result = -1; /* non-NAN < NAN */
}
else
{
result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1),
! num1->n_weight, NUMERIC_SIGN(num1),
! NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2),
! num2->n_weight, NUMERIC_SIGN(num2));
}
return result;
--- 1195,1225 ----
{
result = -1; /* non-NAN < NAN */
}
+ else if (!NUMERIC_HAS_DIGITS(num1))
+ {
+ if (!NUMERIC_HAS_DIGITS(num2))
+ result = 0; /* 0 = 0 */
+ else
+ {
+ if ((digits2[0] & NUMERIC_SIGN_MASK) == NUMERIC_POS)
+ result = -1;
+ else
+ result = 1;
+ }
+ }
+ else if (!NUMERIC_HAS_DIGITS(num2))
+ {
+ if ((digits1[0] & NUMERIC_SIGN_MASK) == NUMERIC_POS)
+ result = 1;
+ else
+ result = -1;
+ }
else
{
result = cmp_var_common(NUMERIC_DIGITS(num1), NUMERIC_NDIGITS(num1),
! num1->n_weight, digits1[0] & NUMERIC_SIGN_MASK,
! NUMERIC_DIGITS(num2), NUMERIC_NDIGITS(num2),
! num2->n_weight, digits2[0] & NUMERIC_SIGN_MASK);
}
return result;
***************
*** 2330,2335 ****
--- 2404,2410 ----
int ndatums;
Numeric N,
sumX;
+ NumericDigit *digits;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
***************
*** 2340,2348 ****
N = DatumGetNumeric(transdatums[0]);
sumX = DatumGetNumeric(transdatums[1]);
/* SQL92 defines AVG of no values to be NULL */
/* N is zero iff no digits (cf. numeric_uminus) */
! if (VARSIZE(N) == NUMERIC_HDRSZ)
PG_RETURN_NULL();
PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
--- 2415,2426 ----
N = DatumGetNumeric(transdatums[0]);
sumX = DatumGetNumeric(transdatums[1]);
+ digits = (NumericDigit *) N->n_data;
+
/* SQL92 defines AVG of no values to be NULL */
/* N is zero iff no digits (cf. numeric_uminus) */
! /* Check to see whether we are zero, but with scale > 255 */
! if ((!NUMERIC_HAS_DIGITS(N)) || (digits[0] == NUMERIC_DSCALE9_MASK))
PG_RETURN_NULL();
PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
***************
*** 2772,2784 ****
dump_numeric(const char *str, Numeric num)
{
NumericDigit *digits = NUMERIC_DIGITS(num);
int ndigits;
int i;
ndigits = NUMERIC_NDIGITS(num);
! printf("%s: NUMERIC w=%d d=%d ", str, num->n_weight, NUMERIC_DSCALE(num));
! switch (NUMERIC_SIGN(num))
{
case NUMERIC_POS:
printf("POS");
--- 2850,2870 ----
dump_numeric(const char *str, Numeric num)
{
NumericDigit *digits = NUMERIC_DIGITS(num);
+ int scale;
int ndigits;
int i;
ndigits = NUMERIC_NDIGITS(num);
! scale = num->n_dscale8bits;
! if ((digits[0] & NUMERIC_DSCALE9_MASK) == NUMERIC_DSCALE9_1)
! scale += 256;
!
! printf("%s: NUMERIC w=%d d=%u ", str, NUMERIC_WEIGHT(num), scale);
! if (NUMERIC_IS_NAN(num))
! printf("NaN ");
!
! switch (digits[0] & NUMERIC_SIGN_MASK)
{
case NUMERIC_POS:
printf("POS");
***************
*** 2786,2805 ****
case NUMERIC_NEG:
printf("NEG");
break;
- case NUMERIC_NAN:
- printf("NaN");
- break;
default:
- printf("SIGN=0x%x", NUMERIC_SIGN(num));
break;
}
for (i = 0; i < ndigits; i++)
! printf(" %0*d", DEC_DIGITS, digits[i]);
printf("\n");
}
-
/*
* dump_var() - Dump a value in the variable format for debugging
*/
--- 2872,2888 ----
case NUMERIC_NEG:
printf("NEG");
break;
default:
break;
}
for (i = 0; i < ndigits; i++)
! printf(" %0*d(%X) ", DEC_DIGITS, digits[i] & NUMERIC_DIGIT_MASK,
! digits[i]);
!
printf("\n");
}
/*
* dump_var() - Dump a value in the variable format for debugging
*/
***************
*** 2809,2814 ****
--- 2892,2901 ----
int i;
printf("%s: VAR w=%d d=%d ", str, var->weight, var->dscale);
+
+ if (var->weight == NUMERIC_NAN)
+ printf("NaN");
+
switch (var->sign)
{
case NUMERIC_POS:
***************
*** 2817,2827 ****
case NUMERIC_NEG:
printf("NEG");
break;
- case NUMERIC_NAN:
- printf("NaN");
- break;
default:
- printf("SIGN=0x%x", var->sign);
break;
}
--- 2904,2910 ----
***************
*** 2871,2877 ****
digitbuf_free(var->buf);
var->buf = NULL;
var->digits = NULL;
! var->sign = NUMERIC_NAN;
}
--- 2954,2961 ----
digitbuf_free(var->buf);
var->buf = NULL;
var->digits = NULL;
! var->weight = NUMERIC_NAN;
! var->sign = NUMERIC_POS;
}
***************
*** 3079,3089 ****
alloc_var(dest, ndigits);
! dest->weight = num->n_weight;
! dest->sign = NUMERIC_SIGN(num);
! dest->dscale = NUMERIC_DSCALE(num);
! memcpy(dest->digits, num->n_data, ndigits * sizeof(NumericDigit));
}
--- 3163,3184 ----
alloc_var(dest, ndigits);
! dest->weight = NUMERIC_WEIGHT(num);
! dest->dscale = num->n_dscale8bits;
!
! if (ndigits > 0)
! {
! memcpy(dest->digits, num->n_data, ndigits * sizeof(NumericDigit));
! if ((dest->digits[0] & NUMERIC_DSCALE9_MASK) == NUMERIC_DSCALE9_1)
! dest->dscale += 256;
!
! dest->sign = dest->digits[0] & NUMERIC_SIGN_MASK;
!
! dest->digits[0] = dest->digits[0] & NUMERIC_DIGIT_MASK;
! }
! else
! dest->sign = NUMERIC_POS;
}
***************
*** 3268,3281 ****
int sign = var->sign;
int n;
Size len;
! if (sign == NUMERIC_NAN)
{
result = (Numeric) palloc(NUMERIC_HDRSZ);
SET_VARSIZE(result, NUMERIC_HDRSZ);
! result->n_weight = 0;
! result->n_sign_dscale = NUMERIC_NAN;
dump_numeric("make_result()", result);
return result;
--- 3363,3377 ----
int sign = var->sign;
int n;
Size len;
+ bool setfirst = false;
! if (weight == NUMERIC_NAN)
{
result = (Numeric) palloc(NUMERIC_HDRSZ);
SET_VARSIZE(result, NUMERIC_HDRSZ);
! result->n_weight = NUMERIC_NAN;
! result->n_dscale8bits = 0;
dump_numeric("make_result()", result);
return result;
***************
*** 3294,3304 ****
while (n > 0 && digits[n - 1] == 0)
n--;
! /* If zero result, force to weight=0 and positive sign */
! if (n == 0)
{
! weight = 0;
! sign = NUMERIC_POS;
}
/* Build the result */
--- 3390,3404 ----
while (n > 0 && digits[n - 1] == 0)
n--;
! /*
! * Zero is stored as no digits, unless we have a very large scale,
! * in which case we store a single zero digit with its dscale9 bit set
! * If we pass this test, digits[0] is already known as zero from above
! */
! if (n == 0 && var->dscale > 255)
{
! n = 1;
! setfirst = true;
}
/* Build the result */
***************
*** 3306,3318 ****
result = (Numeric) palloc(len);
SET_VARSIZE(result, len);
result->n_weight = weight;
! result->n_sign_dscale = sign | (var->dscale & NUMERIC_DSCALE_MASK);
memcpy(result->n_data, digits, n * sizeof(NumericDigit));
! /* Check for overflow of int16 fields */
if (result->n_weight != weight ||
! NUMERIC_DSCALE(result) != var->dscale)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value overflows numeric format")));
--- 3406,3433 ----
result = (Numeric) palloc(len);
SET_VARSIZE(result, len);
result->n_weight = weight;
!
! if (var->dscale > 255)
! {
! result->n_dscale8bits = (uint8) (var->dscale - 256);
! /* We will always have a digits[0] if scale > 255 */
! if (setfirst)
! digits[0] = 0;
! digits[0] |= NUMERIC_DSCALE9_1 | sign;
! }
! else
! {
! result->n_dscale8bits = (uint8) var->dscale;
! if (n > 0)
! digits[0] |= NUMERIC_DSCALE9_0 | sign;
! }
memcpy(result->n_data, digits, n * sizeof(NumericDigit));
! /* Check for overflow or underflow */
if (result->n_weight != weight ||
! var->dscale < 0 ||
! var->dscale > NUMERIC_MAX_PRECISION)
ereport(ERROR,
(errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
errmsg("value overflows numeric format")));
***************
*** 3337,3342 ****
--- 3452,3468 ----
int ddigits;
int i;
+ /*
+ * If we get here, var cannot be NUMERIC_NAN. Since we store NUMERIC_NAN
+ * in the weight field, then weight must be checked to be within
+ * bounds so that we do not overflow the weight to become NUMERIC_NAN
+ */
+ if (var->weight <= NUMERIC_NAN)
+ ereport(ERROR,
+ (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE),
+ errmsg("value overflows numeric format")));
+
+
/* Do nothing if we have a default typmod (-1) */
if (typmod < (int32) (VARHDRSZ))
return;
***************
*** 3349,3354 ****
--- 3475,3481 ----
/* Round to target scale (and set var->dscale) */
round_var(var, scale);
+
/*
* Check for overflow - note we can't do this before rounding, because
* rounding could raise the weight. Also note that the var's weight could
Index: src/include/utils/numeric.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/numeric.h,v
retrieving revision 1.24
diff -c -r1.24 numeric.h
*** src/include/utils/numeric.h 27 Feb 2007 23:48:10 -0000 1.24
--- src/include/utils/numeric.h 17 Jun 2007 20:30:43 -0000
***************
*** 17,26 ****
#include "fmgr.h"
/*
! * Hardcoded precision limit - arbitrary, but must be small enough that
! * dscale values will fit in 14 bits.
*/
! #define NUMERIC_MAX_PRECISION 1000
/*
* Internal limits on the scales chosen for calculation results
--- 17,25 ----
#include "fmgr.h"
/*
! * Hardcoded precision limit - maximum that can fit in Numeric storage
*/
! #define NUMERIC_MAX_PRECISION 508
/*
* Internal limits on the scales chosen for calculation results
***************
*** 41,55 ****
/*
* Sign values and macros to deal with packing/unpacking n_sign_dscale
*/
! #define NUMERIC_SIGN_MASK 0xC000
! #define NUMERIC_POS 0x0000
! #define NUMERIC_NEG 0x4000
! #define NUMERIC_NAN 0xC000
! #define NUMERIC_DSCALE_MASK 0x3FFF
! #define NUMERIC_SIGN(n) ((n)->n_sign_dscale & NUMERIC_SIGN_MASK)
! #define NUMERIC_DSCALE(n) ((n)->n_sign_dscale & NUMERIC_DSCALE_MASK)
! #define NUMERIC_IS_NAN(n) (NUMERIC_SIGN(n) != NUMERIC_POS && \
! NUMERIC_SIGN(n) != NUMERIC_NEG)
/*
--- 40,66 ----
/*
* Sign values and macros to deal with packing/unpacking n_sign_dscale
*/
! #define NUMERIC_SIGN_MASK 0x4000
! #define NUMERIC_POS 0x0000
! #define NUMERIC_NEG 0x4000
!
! #define NUMERIC_ABS_MASK 0xBFFF
!
! #define NUMERIC_DSCALE9_MASK 0x8000
! #define NUMERIC_DSCALE9_1 0x8000
! #define NUMERIC_DSCALE9_0 0x0000
!
! #define NUMERIC_DIGIT_MASK 0x3FFF
!
! #define NUMERIC_NAN -128
! /* See numeric.c for explanation of these two values */
! #define NUMERIC_NAN_EXTERNAL 0xC000
!
! #define NUMERIC_WEIGHT(n) ((n)->n_weight)
! #define NUMERIC_WEIGHT_MAX 127
!
! #define NUMERIC_IS_NAN(n) ((n)->n_weight == NUMERIC_NAN)
! #define NUMERIC_HAS_DIGITS(n) (VARSIZE(n) != NUMERIC_HDRSZ)
/*
***************
*** 63,76 ****
typedef struct NumericData
{
int32 vl_len_; /* varlena header (do not touch directly!) */
! int16 n_weight; /* Weight of 1st digit */
! uint16 n_sign_dscale; /* Sign + display scale */
char n_data[1]; /* Digits (really array of NumericDigit) */
} NumericData;
typedef NumericData *Numeric;
! #define NUMERIC_HDRSZ (VARHDRSZ + sizeof(int16) + sizeof(uint16))
/*
--- 74,87 ----
typedef struct NumericData
{
int32 vl_len_; /* varlena header (do not touch directly!) */
! int8 n_weight; /* Weight of 1st digit */
! uint8 n_dscale8bits; /* First 8 bits of display scale */
char n_data[1]; /* Digits (really array of NumericDigit) */
} NumericData;
typedef NumericData *Numeric;
! #define NUMERIC_HDRSZ (VARHDRSZ + sizeof(int8) + sizeof(uint8))
/*
---------------------------(end of broadcast)---------------------------
TIP 4: Have you searched our list archives?
http://archives.postgresql.org