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