Now we're into 8.2devel mode, its time to submit the previously
discussed patch that:
- reduces Numeric storage format by 2 bytes
- limits scale to +/- 508 decimal places
This is sufficient to allow Numeric to continue to be used as the
default numeric representation for all numbers in the parser.
Passes: make check on cvstip, as well as some tests not in there.
Code comments explain the new format and consequences.
As previously agreed, reviewing this is a 2 stage process:
1. review/possibly agree OK to commit
2. check with everybody on GENERAL that the restriction to 508 is
acceptable
Figure there's no point doing (2) until we agree the proposal/code is
workable.
As Atsushi-san point out, there is also come CPU optimization to be done
on Numeric comparison, and also on other areas such as aggregation. I've
not done this yet.
Best Regards, Simon Riggs
Index: src/backend/utils/adt/numeric.c
===================================================================
RCS file: /projects/cvsroot/pgsql/src/backend/utils/adt/numeric.c,v
retrieving revision 1.86
diff -c -r1.86 numeric.c
*** src/backend/utils/adt/numeric.c 15 Oct 2005 02:49:29 -0000 1.86
--- src/backend/utils/adt/numeric.c 16 Nov 2005 17:00:51 -0000
***************
*** 84,92 ****
#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,
--- 84,112 ----
#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,
***************
*** 130,137 ****
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 */
--- 150,157 ----
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 */
***************
*** 199,205 ****
{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};
--- 219,225 ----
{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};
***************
*** 368,373 ****
--- 388,399 ----
*
* 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)
***************
*** 394,413 ****
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")));
--- 420,456 ----
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")));
***************
*** 424,429 ****
--- 467,474 ----
/*
* 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)
***************
*** 438,443 ****
--- 483,493 ----
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));
***************
*** 501,513 ****
* 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(num->varlen);
memcpy(new, num, num->varlen);
! new->n_sign_dscale = NUMERIC_SIGN(new) |
! ((uint16) scale & NUMERIC_DSCALE_MASK);
PG_RETURN_NUMERIC(new);
}
--- 551,563 ----
* 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(num->varlen);
memcpy(new, num, num->varlen);
! new->n_dscale8bits = (uint8) scale;
!
PG_RETURN_NUMERIC(new);
}
***************
*** 539,544 ****
--- 589,595 ----
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
+ NumericDigit *resdigits;
/*
* Handle NaN
***************
*** 551,558 ****
*/
res = (Numeric) palloc(num->varlen);
memcpy(res, num, num->varlen);
- res->n_sign_dscale = NUMERIC_POS | NUMERIC_DSCALE(num);
PG_RETURN_NUMERIC(res);
}
--- 602,611 ----
*/
res = (Numeric) palloc(num->varlen);
memcpy(res, num, num->varlen);
+ resdigits = (NumericDigit *) res->n_data;
+
+ resdigits[0] &= NUMERIC_ABS_MASK;
PG_RETURN_NUMERIC(res);
}
***************
*** 563,568 ****
--- 616,622 ----
{
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
+ NumericDigit *resdigits;
/*
* Handle NaN
***************
*** 574,593 ****
* Do it the easy way directly on the packed format
*/
res = (Numeric) palloc(num->varlen);
memcpy(res, num, num->varlen);
/*
! * 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 (num->varlen != 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);
--- 628,654 ----
* Do it the easy way directly on the packed format
*/
res = (Numeric) palloc(num->varlen);
+
memcpy(res, num, num->varlen);
+ 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);
***************
*** 618,623 ****
--- 679,685 ----
Numeric num = PG_GETARG_NUMERIC(0);
Numeric res;
NumericVar result;
+ NumericDigit *digits = (NumericDigit *) num->n_data;
/*
* Handle NaN
***************
*** 627,647 ****
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 (num->varlen == 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);
--- 689,705 ----
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);
***************
*** 2157,2162 ****
--- 2215,2221 ----
int ndatums;
Numeric N,
sumX;
+ NumericDigit *digits;
/* We assume the input is array of numeric */
deconstruct_array(transarray,
***************
*** 2168,2178 ****
sumX = DatumGetNumeric(transdatums[1]);
/* ignore sumX2 */
/* SQL92 defines AVG of no values to be NULL */
/* N is zero iff no digits (cf. numeric_uminus) */
! if (N->varlen == NUMERIC_HDRSZ)
PG_RETURN_NULL();
PG_RETURN_DATUM(DirectFunctionCall2(numeric_div,
NumericGetDatum(sumX),
NumericGetDatum(N)));
--- 2227,2241 ----
sumX = DatumGetNumeric(transdatums[1]);
/* ignore sumX2 */
+ 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,
NumericGetDatum(sumX),
NumericGetDatum(N)));
***************
*** 2589,2601 ****
dump_numeric(const char *str, Numeric num)
{
NumericDigit *digits = (NumericDigit *) num->n_data;
int ndigits;
int i;
ndigits = (num->varlen - NUMERIC_HDRSZ) / sizeof(NumericDigit);
! printf("%s: NUMERIC w=%d d=%d ", str, num->n_weight, NUMERIC_DSCALE(num));
! switch (NUMERIC_SIGN(num))
{
case NUMERIC_POS:
printf("POS");
--- 2652,2672 ----
dump_numeric(const char *str, Numeric num)
{
NumericDigit *digits = (NumericDigit *) num->n_data;
+ int scale;
int ndigits;
int i;
ndigits = (num->varlen - NUMERIC_HDRSZ) / sizeof(NumericDigit);
! 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");
***************
*** 2603,2622 ****
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
*/
--- 2674,2690 ----
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
*/
***************
*** 2626,2631 ****
--- 2694,2703 ----
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:
***************
*** 2634,2644 ****
case NUMERIC_NEG:
printf("NEG");
break;
- case NUMERIC_NAN:
- printf("NaN");
- break;
default:
- printf("SIGN=0x%x", var->sign);
break;
}
--- 2706,2712 ----
***************
*** 2688,2694 ****
digitbuf_free(var->buf);
var->buf = NULL;
var->digits = NULL;
! var->sign = NUMERIC_NAN;
}
--- 2756,2763 ----
digitbuf_free(var->buf);
var->buf = NULL;
var->digits = NULL;
! var->weight = NUMERIC_NAN;
! var->sign = NUMERIC_POS;
}
***************
*** 2896,2906 ****
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));
}
--- 2965,2986 ----
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;
}
***************
*** 3082,3098 ****
Numeric result;
NumericDigit *digits = var->digits;
int weight = var->weight;
! int sign = var->sign;
int n;
Size len;
! if (sign == NUMERIC_NAN)
{
result = (Numeric) palloc(NUMERIC_HDRSZ);
result->varlen = NUMERIC_HDRSZ;
! result->n_weight = 0;
! result->n_sign_dscale = NUMERIC_NAN;
dump_numeric("make_result()", result);
return result;
--- 3162,3179 ----
Numeric result;
NumericDigit *digits = var->digits;
int weight = var->weight;
! int sign = var->sign;
int n;
Size len;
+ bool setfirst = false;
! if (weight == NUMERIC_NAN)
{
result = (Numeric) palloc(NUMERIC_HDRSZ);
result->varlen = NUMERIC_HDRSZ;
! result->n_weight = NUMERIC_NAN;
! result->n_dscale8bits = 0;
dump_numeric("make_result()", result);
return result;
***************
*** 3111,3135 ****
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 */
len = NUMERIC_HDRSZ + n * sizeof(NumericDigit);
result = (Numeric) palloc(len);
result->varlen = 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")));
--- 3192,3236 ----
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 */
len = NUMERIC_HDRSZ + n * sizeof(NumericDigit);
result = (Numeric) palloc(len);
result->varlen = 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")));
***************
*** 3154,3159 ****
--- 3255,3271 ----
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;
***************
*** 3166,3171 ****
--- 3278,3284 ----
/* 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
***************
*** 3396,3401 ****
--- 3509,3515 ----
return 1;
return -1;
}
+
if (var2->ndigits == 0)
{
if (var1->sign == NUMERIC_POS)
Index: src/include/utils/numeric.h
===================================================================
RCS file: /projects/cvsroot/pgsql/src/include/utils/numeric.h,v
retrieving revision 1.20
diff -c -r1.20 numeric.h
*** src/include/utils/numeric.h 1 Jan 2005 05:43:09 -0000 1.20
--- src/include/utils/numeric.h 16 Nov 2005 17:00:53 -0000
***************
*** 15,24 ****
#define _PG_NUMERIC_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
--- 15,23 ----
#define _PG_NUMERIC_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
***************
*** 39,53 ****
/*
* 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)
/*
--- 38,64 ----
/*
* 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) ((n)->varlen != NUMERIC_HDRSZ)
/*
***************
*** 61,75 ****
typedef struct NumericData
{
int32 varlen; /* Variable size (std varlena header) */
! 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 (sizeof(int32) + sizeof(int16) + sizeof(uint16))
!
/*
* fmgr interface macros
--- 72,85 ----
typedef struct NumericData
{
int32 varlen; /* Variable size (std varlena header) */
! 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 (sizeof(int32) + sizeof(int8) + sizeof(uint8))
/*
* fmgr interface macros
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster