diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2007-04-06 04:21:44 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2007-04-06 04:21:44 +0000 |
commit | 3e23b68dac006e8deb0afa327e855258df8de064 (patch) | |
tree | f5a555955dd954265dea1107e08dadd917714551 /src/backend | |
parent | d44163953c2ce74d6db9d9807e030a0a3b725da5 (diff) | |
download | postgresql-3e23b68dac006e8deb0afa327e855258df8de064.tar.gz postgresql-3e23b68dac006e8deb0afa327e855258df8de064.zip |
Support varlena fields with single-byte headers and unaligned storage.
This commit breaks any code that assumes that the mere act of forming a tuple
(without writing it to disk) does not "toast" any fields. While all available
regression tests pass, I'm not totally sure that we've fixed every nook and
cranny, especially in contrib.
Greg Stark with some help from Tom Lane
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/access/common/heaptuple.c | 447 | ||||
-rw-r--r-- | src/backend/access/common/indextuple.c | 142 | ||||
-rw-r--r-- | src/backend/access/heap/tuptoaster.c | 496 | ||||
-rw-r--r-- | src/backend/catalog/toasting.c | 4 | ||||
-rw-r--r-- | src/backend/commands/analyze.c | 6 | ||||
-rw-r--r-- | src/backend/executor/execQual.c | 6 | ||||
-rw-r--r-- | src/backend/storage/large_object/inv_api.c | 10 | ||||
-rw-r--r-- | src/backend/utils/adt/arrayfuncs.c | 84 | ||||
-rw-r--r-- | src/backend/utils/adt/datum.c | 6 | ||||
-rw-r--r-- | src/backend/utils/adt/network.c | 104 | ||||
-rw-r--r-- | src/backend/utils/adt/pg_lzcompress.c | 4 | ||||
-rw-r--r-- | src/backend/utils/adt/varchar.c | 160 | ||||
-rw-r--r-- | src/backend/utils/adt/varlena.c | 280 | ||||
-rw-r--r-- | src/backend/utils/adt/xml.c | 6 | ||||
-rw-r--r-- | src/backend/utils/fmgr/fmgr.c | 17 | ||||
-rw-r--r-- | src/backend/utils/init/flatfiles.c | 6 |
16 files changed, 1100 insertions, 678 deletions
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 0c83262c3b8..f1a80d6feee 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -11,12 +11,53 @@ * we can get rid of it entirely. * * + * Some notes about varlenas and this code: + * + * Before Postgres 8.3 varlenas always had a 4-byte length header, and + * therefore always needed 4-byte alignment (at least). This wasted space + * for short varlenas, for example CHAR(1) took 5 bytes and could need up to + * 3 additional padding bytes for alignment. + * + * Now, a short varlena (up to 126 data bytes) is reduced to a 1-byte header + * and we don't align it. To hide this from datatype-specific functions that + * don't want to deal with it, such a datum is considered "toasted" and will + * be expanded back to the normal 4-byte-header format by pg_detoast_datum. + * (In performance-critical code paths we can use pg_detoast_datum_packed + * and the appropriate access macros to avoid that overhead.) Note that this + * conversion is performed directly in heap_form_tuple (or heap_formtuple), + * without explicitly invoking the toaster. + * + * This change will break any code that assumes it needn't detoast values + * that have been put into a tuple but never sent to disk. Hopefully there + * are few such places. + * + * Varlenas still have alignment 'i' (or 'd') in pg_type/pg_attribute, since + * that's the normal requirement for the untoasted format. But we ignore that + * for the 1-byte-header format. This means that the actual start position + * of a varlena datum may vary depending on which format it has. To determine + * what is stored, we have to require that alignment padding bytes be zero. + * (Postgres actually has always zeroed them, but now it's required!) Since + * the first byte of a 1-byte-header varlena can never be zero, we can examine + * the first byte after the previous datum to tell if it's a pad byte or the + * start of a 1-byte-header varlena. + * + * Note that while formerly we could rely on the first varlena column of a + * system catalog to be at the offset suggested by the C struct for the + * catalog, this is now risky: it's only safe if the preceding field is + * word-aligned, so that there will never be any padding. + * + * We don't pack varlenas whose attstorage is 'p', since the data type + * isn't expecting to have to detoast values. This is used in particular + * by oidvector and int2vector, which are used in the system catalogs + * and we'd like to still refer to them via C struct offsets. + * + * * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.116 2007/02/27 23:48:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.117 2007/04/06 04:21:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -28,11 +69,20 @@ #include "executor/tuptable.h" +/* Does att's datatype allow packing into the 1-byte-header varlena format? */ +#define ATT_IS_PACKABLE(att) \ + ((att)->attlen == -1 && (att)->attstorage != 'p') +/* Use this if it's already known varlena */ +#define VARLENA_ATT_IS_PACKABLE(att) \ + ((att)->attstorage != 'p') + + /* ---------------------------------------------------------------- * misc support routines * ---------------------------------------------------------------- */ + /* * heap_compute_data_size * Determine size of the data area of a tuple to be constructed @@ -49,11 +99,29 @@ heap_compute_data_size(TupleDesc tupleDesc, for (i = 0; i < numberOfAttributes; i++) { + Datum val; + if (isnull[i]) continue; - data_length = att_align(data_length, att[i]->attalign); - data_length = att_addlength(data_length, att[i]->attlen, values[i]); + val = values[i]; + + if (ATT_IS_PACKABLE(att[i]) && + VARATT_CAN_MAKE_SHORT(DatumGetPointer(val))) + { + /* + * we're anticipating converting to a short varlena header, + * so adjust length and don't count any alignment + */ + data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val)); + } + else + { + data_length = att_align_datum(data_length, att[i]->attalign, + att[i]->attlen, val); + data_length = att_addlength_datum(data_length, att[i]->attlen, + val); + } } return data_length; @@ -79,11 +147,29 @@ ComputeDataSize(TupleDesc tupleDesc, for (i = 0; i < numberOfAttributes; i++) { + Datum val; + if (nulls[i] != ' ') continue; - data_length = att_align(data_length, att[i]->attalign); - data_length = att_addlength(data_length, att[i]->attlen, values[i]); + val = values[i]; + + if (ATT_IS_PACKABLE(att[i]) && + VARATT_CAN_MAKE_SHORT(DatumGetPointer(val))) + { + /* + * we're anticipating converting to a short varlena header, + * so adjust length and don't count any alignment + */ + data_length += VARATT_CONVERTED_SHORT_SIZE(DatumGetPointer(val)); + } + else + { + data_length = att_align_datum(data_length, att[i]->attalign, + att[i]->attlen, val); + data_length = att_addlength_datum(data_length, att[i]->attlen, + val); + } } return data_length; @@ -95,17 +181,23 @@ ComputeDataSize(TupleDesc tupleDesc, * * We also fill the null bitmap (if any) and set the infomask bits * that reflect the tuple's data contents. + * + * NOTE: it is now REQUIRED that the caller have pre-zeroed the data area. */ void heap_fill_tuple(TupleDesc tupleDesc, Datum *values, bool *isnull, - char *data, uint16 *infomask, bits8 *bit) + char *data, Size data_size, + uint16 *infomask, bits8 *bit) { bits8 *bitP; int bitmask; int i; int numberOfAttributes = tupleDesc->natts; Form_pg_attribute *att = tupleDesc->attrs; +#ifdef USE_ASSERT_CHECKING + char *start = data; +#endif if (bit != NULL) { @@ -119,7 +211,7 @@ heap_fill_tuple(TupleDesc tupleDesc, bitmask = 0; } - *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTENDED); + *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL); for (i = 0; i < numberOfAttributes; i++) { @@ -145,36 +237,66 @@ heap_fill_tuple(TupleDesc tupleDesc, *bitP |= bitmask; } - /* XXX we are aligning the pointer itself, not the offset */ - data = (char *) att_align((long) data, att[i]->attalign); + /* + * XXX we use the att_align macros on the pointer value itself, + * not on an offset. This is a bit of a hack. + */ if (att[i]->attbyval) { /* pass-by-value */ + data = (char *) att_align_nominal((long) data, att[i]->attalign); store_att_byval(data, values[i], att[i]->attlen); data_length = att[i]->attlen; } else if (att[i]->attlen == -1) { /* varlena */ + Pointer val = DatumGetPointer(values[i]); + *infomask |= HEAP_HASVARWIDTH; - if (VARATT_IS_EXTERNAL(values[i])) + if (VARATT_IS_EXTERNAL(val)) + { *infomask |= HEAP_HASEXTERNAL; - if (VARATT_IS_COMPRESSED(values[i])) - *infomask |= HEAP_HASCOMPRESSED; - data_length = VARSIZE(DatumGetPointer(values[i])); - memcpy(data, DatumGetPointer(values[i]), data_length); + /* no alignment, since it's short by definition */ + data_length = VARSIZE_EXTERNAL(val); + memcpy(data, val, data_length); + } + else if (VARATT_IS_SHORT(val)) + { + /* no alignment for short varlenas */ + data_length = VARSIZE_SHORT(val); + memcpy(data, val, data_length); + } + else if (VARLENA_ATT_IS_PACKABLE(att[i]) && + VARATT_CAN_MAKE_SHORT(val)) + { + /* convert to short varlena -- no alignment */ + data_length = VARATT_CONVERTED_SHORT_SIZE(val); + SET_VARSIZE_SHORT(data, data_length); + memcpy(data + 1, VARDATA(val), data_length - 1); + } + else + { + /* full 4-byte header varlena */ + data = (char *) att_align_nominal((long) data, + att[i]->attalign); + data_length = VARSIZE(val); + memcpy(data, val, data_length); + } } else if (att[i]->attlen == -2) { - /* cstring */ + /* cstring ... never needs alignment */ *infomask |= HEAP_HASVARWIDTH; + Assert(att[i]->attalign == 'c'); data_length = strlen(DatumGetCString(values[i])) + 1; memcpy(data, DatumGetPointer(values[i]), data_length); } else { /* fixed-length pass-by-reference */ + data = (char *) att_align_nominal((long) data, att[i]->attalign); Assert(att[i]->attlen > 0); data_length = att[i]->attlen; memcpy(data, DatumGetPointer(values[i]), data_length); @@ -182,6 +304,8 @@ heap_fill_tuple(TupleDesc tupleDesc, data += data_length; } + + Assert((data - start) == data_size); } /* ---------------- @@ -193,18 +317,19 @@ heap_fill_tuple(TupleDesc tupleDesc, * ---------------- */ static void -DataFill(char *data, - TupleDesc tupleDesc, - Datum *values, - char *nulls, - uint16 *infomask, - bits8 *bit) +DataFill(TupleDesc tupleDesc, + Datum *values, char *nulls, + char *data, Size data_size, + uint16 *infomask, bits8 *bit) { bits8 *bitP; int bitmask; int i; int numberOfAttributes = tupleDesc->natts; Form_pg_attribute *att = tupleDesc->attrs; +#ifdef USE_ASSERT_CHECKING + char *start = data; +#endif if (bit != NULL) { @@ -218,7 +343,7 @@ DataFill(char *data, bitmask = 0; } - *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTENDED); + *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL); for (i = 0; i < numberOfAttributes; i++) { @@ -244,36 +369,66 @@ DataFill(char *data, *bitP |= bitmask; } - /* XXX we are aligning the pointer itself, not the offset */ - data = (char *) att_align((long) data, att[i]->attalign); + /* + * XXX we use the att_align macros on the pointer value itself, + * not on an offset. This is a bit of a hack. + */ if (att[i]->attbyval) { /* pass-by-value */ + data = (char *) att_align_nominal((long) data, att[i]->attalign); store_att_byval(data, values[i], att[i]->attlen); data_length = att[i]->attlen; } else if (att[i]->attlen == -1) { /* varlena */ + Pointer val = DatumGetPointer(values[i]); + *infomask |= HEAP_HASVARWIDTH; - if (VARATT_IS_EXTERNAL(values[i])) + if (VARATT_IS_EXTERNAL(val)) + { *infomask |= HEAP_HASEXTERNAL; - if (VARATT_IS_COMPRESSED(values[i])) - *infomask |= HEAP_HASCOMPRESSED; - data_length = VARSIZE(DatumGetPointer(values[i])); - memcpy(data, DatumGetPointer(values[i]), data_length); + /* no alignment, since it's short by definition */ + data_length = VARSIZE_EXTERNAL(val); + memcpy(data, val, data_length); + } + else if (VARATT_IS_SHORT(val)) + { + /* no alignment for short varlenas */ + data_length = VARSIZE_SHORT(val); + memcpy(data, val, data_length); + } + else if (VARLENA_ATT_IS_PACKABLE(att[i]) && + VARATT_CAN_MAKE_SHORT(val)) + { + /* convert to short varlena -- no alignment */ + data_length = VARATT_CONVERTED_SHORT_SIZE(val); + SET_VARSIZE_SHORT(data, data_length); + memcpy(data + 1, VARDATA(val), data_length - 1); + } + else + { + /* full 4-byte header varlena */ + data = (char *) att_align_nominal((long) data, + att[i]->attalign); + data_length = VARSIZE(val); + memcpy(data, val, data_length); + } } else if (att[i]->attlen == -2) { - /* cstring */ + /* cstring ... never needs alignment */ *infomask |= HEAP_HASVARWIDTH; + Assert(att[i]->attalign == 'c'); data_length = strlen(DatumGetCString(values[i])) + 1; memcpy(data, DatumGetPointer(values[i]), data_length); } else { /* fixed-length pass-by-reference */ + data = (char *) att_align_nominal((long) data, att[i]->attalign); Assert(att[i]->attlen > 0); data_length = att[i]->attlen; memcpy(data, DatumGetPointer(values[i]), data_length); @@ -281,6 +436,8 @@ DataFill(char *data, data += data_length; } + + Assert((data - start) == data_size); } /* ---------------------------------------------------------------- @@ -343,6 +500,8 @@ heap_attisnull(HeapTuple tup, int attnum) * the same attribute descriptor will go much quicker. -cim 5/4/91 * * NOTE: if you need to change this code, see also heap_deform_tuple. + * Also see nocache_index_getattr, which is the same code for index + * tuples. * ---------------- */ Datum @@ -353,20 +512,12 @@ nocachegetattr(HeapTuple tuple, { HeapTupleHeader tup = tuple->t_data; Form_pg_attribute *att = tupleDesc->attrs; - char *tp; /* ptr to att in tuple */ + char *tp; /* ptr to data part of tuple */ bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */ - bool slow = false; /* do we have to walk nulls? */ + bool slow = false; /* do we have to walk attrs? */ + int off; /* current offset within data */ (void) isnull; /* not used */ -#ifdef IN_MACRO -/* This is handled in the macro */ - Assert(attnum > 0); - - if (isnull) - *isnull = false; -#endif - - attnum--; /* ---------------- * Three cases: @@ -377,11 +528,21 @@ nocachegetattr(HeapTuple tuple, * ---------------- */ +#ifdef IN_MACRO +/* This is handled in the macro */ + Assert(attnum > 0); + + if (isnull) + *isnull = false; +#endif + + attnum--; + if (HeapTupleNoNulls(tuple)) { #ifdef IN_MACRO /* This is handled in the macro */ - if (att[attnum]->attcacheoff != -1) + if (att[attnum]->attcacheoff >= 0) { return fetchatt(att[attnum], (char *) tup + tup->t_hoff + @@ -436,24 +597,27 @@ nocachegetattr(HeapTuple tuple, tp = (char *) tup + tup->t_hoff; - /* - * now check for any non-fixed length attrs before our attribute - */ if (!slow) { - if (att[attnum]->attcacheoff != -1) + /* + * If we get here, there are no nulls up to and including the target + * attribute. If we have a cached offset, we can use it. + */ + if (att[attnum]->attcacheoff >= 0) { return fetchatt(att[attnum], tp + att[attnum]->attcacheoff); } - else if (HeapTupleHasVarWidth(tuple)) + + /* + * Otherwise, check for non-fixed-length attrs up to and including + * target. If there aren't any, it's safe to cheaply initialize + * the cached offsets for these attrs. + */ + if (HeapTupleHasVarWidth(tuple)) { int j; - /* - * In for(), we test <= and not < because we want to see if we can - * go past it in initializing offsets. - */ for (j = 0; j <= attnum; j++) { if (att[j]->attlen <= 0) @@ -465,89 +629,109 @@ nocachegetattr(HeapTuple tuple, } } - /* - * If slow is false, and we got here, we know that we have a tuple with no - * nulls or var-widths before the target attribute. If possible, we also - * want to initialize the remainder of the attribute cached offset values. - */ if (!slow) { + int natts = tupleDesc->natts; int j = 1; - long off; - int natts = HeapTupleHeaderGetNatts(tup); /* - * need to set cache for some atts + * If we get here, we have a tuple with no nulls or var-widths up to + * and including the target attribute, so we can use the cached offset + * ... only we don't have it yet, or we'd not have got here. Since + * it's cheap to compute offsets for fixed-width columns, we take the + * opportunity to initialize the cached offsets for *all* the leading + * fixed-width columns, in hope of avoiding future visits to this + * routine. */ - att[0]->attcacheoff = 0; - while (j < attnum && att[j]->attcacheoff > 0) + /* we might have set some offsets in the slow path previously */ + while (j < natts && att[j]->attcacheoff > 0) j++; off = att[j - 1]->attcacheoff + att[j - 1]->attlen; - for (; j <= attnum || - /* Can we compute more? We will probably need them */ - (j < natts && - att[j]->attcacheoff == -1 && - (HeapTupleNoNulls(tuple) || !att_isnull(j, bp)) && - (HeapTupleAllFixed(tuple) || att[j]->attlen > 0)); j++) + for (; j < natts; j++) { - off = att_align(off, att[j]->attalign); + if (att[j]->attlen <= 0) + break; + + off = att_align_nominal(off, att[j]->attalign); att[j]->attcacheoff = off; - off = att_addlength(off, att[j]->attlen, tp + off); + off += att[j]->attlen; } - return fetchatt(att[attnum], tp + att[attnum]->attcacheoff); + Assert(j > attnum); + + off = att[attnum]->attcacheoff; } else { bool usecache = true; - int off = 0; int i; /* - * Now we know that we have to walk the tuple CAREFULLY. + * Now we know that we have to walk the tuple CAREFULLY. But we + * still might be able to cache some offsets for next time. * * Note - This loop is a little tricky. For each non-null attribute, * we have to first account for alignment padding before the attr, * then advance over the attr based on its length. Nulls have no * storage and no alignment padding either. We can use/set - * attcacheoff until we pass either a null or a var-width attribute. + * attcacheoff until we reach either a null or a var-width attribute. */ - - for (i = 0; i < attnum; i++) + off = 0; + for (i = 0; ; i++) /* loop exit is at "break" */ { if (HeapTupleHasNulls(tuple) && att_isnull(i, bp)) { usecache = false; - continue; + continue; /* this cannot be the target att */ } - /* If we know the next offset, we can skip the alignment calc */ - if (usecache && att[i]->attcacheoff != -1) + /* If we know the next offset, we can skip the rest */ + if (usecache && att[i]->attcacheoff >= 0) off = att[i]->attcacheoff; + else if (att[i]->attlen == -1) + { + /* + * We can only cache the offset for a varlena attribute + * if the offset is already suitably aligned, so that there + * would be no pad bytes in any case: then the offset will + * be valid for either an aligned or unaligned value. + */ + if (usecache && + off == att_align_nominal(off, att[i]->attalign)) + att[i]->attcacheoff = off; + else + { + off = att_align_pointer(off, att[i]->attalign, -1, + tp + off); + usecache = false; + } + } else { - off = att_align(off, att[i]->attalign); + /* not varlena, so safe to use att_align_nominal */ + off = att_align_nominal(off, att[i]->attalign); if (usecache) att[i]->attcacheoff = off; } - off = att_addlength(off, att[i]->attlen, tp + off); + if (i == attnum) + break; + + off = att_addlength_pointer(off, att[i]->attlen, tp + off); if (usecache && att[i]->attlen <= 0) usecache = false; } - - off = att_align(off, att[attnum]->attalign); - - return fetchatt(att[attnum], tp + off); } + + return fetchatt(att[attnum], tp + off); } /* ---------------- @@ -671,7 +855,7 @@ heap_form_tuple(TupleDesc tupleDescriptor, { HeapTuple tuple; /* return tuple */ HeapTupleHeader td; /* tuple data */ - unsigned long len; + Size len, data_len; int hoff; bool hasnull = false; Form_pg_attribute *att = tupleDescriptor->attrs; @@ -723,7 +907,9 @@ heap_form_tuple(TupleDesc tupleDescriptor, hoff = len = MAXALIGN(len); /* align user data safely */ - len += heap_compute_data_size(tupleDescriptor, values, isnull); + data_len = heap_compute_data_size(tupleDescriptor, values, isnull); + + len += data_len; /* * Allocate and zero the space needed. Note that the tuple body and @@ -754,6 +940,7 @@ heap_form_tuple(TupleDesc tupleDescriptor, values, isnull, (char *) td + hoff, + data_len, &td->t_infomask, (hasnull ? td->t_bits : NULL)); @@ -778,7 +965,7 @@ heap_formtuple(TupleDesc tupleDescriptor, { HeapTuple tuple; /* return tuple */ HeapTupleHeader td; /* tuple data */ - unsigned long len; + Size len, data_len; int hoff; bool hasnull = false; Form_pg_attribute *att = tupleDescriptor->attrs; @@ -830,7 +1017,9 @@ heap_formtuple(TupleDesc tupleDescriptor, hoff = len = MAXALIGN(len); /* align user data safely */ - len += ComputeDataSize(tupleDescriptor, values, nulls); + data_len = ComputeDataSize(tupleDescriptor, values, nulls); + + len += data_len; /* * Allocate and zero the space needed. Note that the tuple body and @@ -857,16 +1046,18 @@ heap_formtuple(TupleDesc tupleDescriptor, if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ td->t_infomask = HEAP_HASOID; - DataFill((char *) td + hoff, - tupleDescriptor, + DataFill(tupleDescriptor, values, nulls, + (char *) td + hoff, + data_len, &td->t_infomask, (hasnull ? td->t_bits : NULL)); return tuple; } + /* * heap_modify_tuple * form a new tuple from an old tuple and a set of replacement values. @@ -1069,9 +1260,28 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, if (!slow && thisatt->attcacheoff >= 0) off = thisatt->attcacheoff; + else if (thisatt->attlen == -1) + { + /* + * We can only cache the offset for a varlena attribute + * if the offset is already suitably aligned, so that there + * would be no pad bytes in any case: then the offset will + * be valid for either an aligned or unaligned value. + */ + if (!slow && + off == att_align_nominal(off, thisatt->attalign)) + thisatt->attcacheoff = off; + else + { + off = att_align_pointer(off, thisatt->attalign, -1, + tp + off); + slow = true; + } + } else { - off = att_align(off, thisatt->attalign); + /* not varlena, so safe to use att_align_nominal */ + off = att_align_nominal(off, thisatt->attalign); if (!slow) thisatt->attcacheoff = off; @@ -1079,7 +1289,7 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, values[attnum] = fetchatt(thisatt, tp + off); - off = att_addlength(off, thisatt->attlen, tp + off); + off = att_addlength_pointer(off, thisatt->attlen, tp + off); if (thisatt->attlen <= 0) slow = true; /* can't use attcacheoff anymore */ @@ -1162,9 +1372,28 @@ heap_deformtuple(HeapTuple tuple, if (!slow && thisatt->attcacheoff >= 0) off = thisatt->attcacheoff; + else if (thisatt->attlen == -1) + { + /* + * We can only cache the offset for a varlena attribute + * if the offset is already suitably aligned, so that there + * would be no pad bytes in any case: then the offset will + * be valid for either an aligned or unaligned value. + */ + if (!slow && + off == att_align_nominal(off, thisatt->attalign)) + thisatt->attcacheoff = off; + else + { + off = att_align_pointer(off, thisatt->attalign, -1, + tp + off); + slow = true; + } + } else { - off = att_align(off, thisatt->attalign); + /* not varlena, so safe to use att_align_nominal */ + off = att_align_nominal(off, thisatt->attalign); if (!slow) thisatt->attcacheoff = off; @@ -1172,7 +1401,7 @@ heap_deformtuple(HeapTuple tuple, values[attnum] = fetchatt(thisatt, tp + off); - off = att_addlength(off, thisatt->attlen, tp + off); + off = att_addlength_pointer(off, thisatt->attlen, tp + off); if (thisatt->attlen <= 0) slow = true; /* can't use attcacheoff anymore */ @@ -1252,9 +1481,28 @@ slot_deform_tuple(TupleTableSlot *slot, int natts) if (!slow && thisatt->attcacheoff >= 0) off = thisatt->attcacheoff; + else if (thisatt->attlen == -1) + { + /* + * We can only cache the offset for a varlena attribute + * if the offset is already suitably aligned, so that there + * would be no pad bytes in any case: then the offset will + * be valid for either an aligned or unaligned value. + */ + if (!slow && + off == att_align_nominal(off, thisatt->attalign)) + thisatt->attcacheoff = off; + else + { + off = att_align_pointer(off, thisatt->attalign, -1, + tp + off); + slow = true; + } + } else { - off = att_align(off, thisatt->attalign); + /* not varlena, so safe to use att_align_nominal */ + off = att_align_nominal(off, thisatt->attalign); if (!slow) thisatt->attcacheoff = off; @@ -1262,7 +1510,7 @@ slot_deform_tuple(TupleTableSlot *slot, int natts) values[attnum] = fetchatt(thisatt, tp + off); - off = att_addlength(off, thisatt->attlen, tp + off); + off = att_addlength_pointer(off, thisatt->attlen, tp + off); if (thisatt->attlen <= 0) slow = true; /* can't use attcacheoff anymore */ @@ -1543,7 +1791,7 @@ heap_form_minimal_tuple(TupleDesc tupleDescriptor, bool *isnull) { MinimalTuple tuple; /* return tuple */ - unsigned long len; + Size len, data_len; int hoff; bool hasnull = false; Form_pg_attribute *att = tupleDescriptor->attrs; @@ -1595,7 +1843,9 @@ heap_form_minimal_tuple(TupleDesc tupleDescriptor, hoff = len = MAXALIGN(len); /* align user data safely */ - len += heap_compute_data_size(tupleDescriptor, values, isnull); + data_len = heap_compute_data_size(tupleDescriptor, values, isnull); + + len += data_len; /* * Allocate and zero the space needed. @@ -1616,6 +1866,7 @@ heap_form_minimal_tuple(TupleDesc tupleDescriptor, values, isnull, (char *) tuple + hoff, + data_len, &tuple->t_infomask, (hasnull ? tuple->t_bits : NULL)); diff --git a/src/backend/access/common/indextuple.c b/src/backend/access/common/indextuple.c index c83e34834ca..471d28c28c4 100644 --- a/src/backend/access/common/indextuple.c +++ b/src/backend/access/common/indextuple.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/indextuple.c,v 1.81 2007/02/27 23:48:06 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/indextuple.c,v 1.82 2007/04/06 04:21:41 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -38,6 +38,7 @@ index_form_tuple(TupleDesc tupleDescriptor, char *tp; /* tuple pointer */ IndexTuple tuple; /* return tuple */ Size size, + data_size, hoff; int i; unsigned short infomask = 0; @@ -74,9 +75,9 @@ index_form_tuple(TupleDesc tupleDescriptor, */ if (VARATT_IS_EXTERNAL(values[i])) { - untoasted_values[i] = PointerGetDatum( - heap_tuple_fetch_attr( - (varattrib *) DatumGetPointer(values[i]))); + untoasted_values[i] = + PointerGetDatum(heap_tuple_fetch_attr((struct varlena *) + DatumGetPointer(values[i]))); untoasted_free[i] = true; } @@ -84,8 +85,8 @@ index_form_tuple(TupleDesc tupleDescriptor, * If value is above size target, and is of a compressible datatype, * try to compress it in-line. */ - if (VARSIZE(untoasted_values[i]) > TOAST_INDEX_TARGET && - !VARATT_IS_EXTENDED(untoasted_values[i]) && + if (!VARATT_IS_EXTENDED(untoasted_values[i]) && + VARSIZE(untoasted_values[i]) > TOAST_INDEX_TARGET && (att->attstorage == 'x' || att->attstorage == 'm')) { Datum cvalue = toast_compress_datum(untoasted_values[i]); @@ -116,12 +117,13 @@ index_form_tuple(TupleDesc tupleDescriptor, hoff = IndexInfoFindDataOffset(infomask); #ifdef TOAST_INDEX_HACK - size = hoff + heap_compute_data_size(tupleDescriptor, - untoasted_values, isnull); + data_size = heap_compute_data_size(tupleDescriptor, + untoasted_values, isnull); #else - size = hoff + heap_compute_data_size(tupleDescriptor, - values, isnull); + data_size = heap_compute_data_size(tupleDescriptor, + values, isnull); #endif + size = hoff + data_size; size = MAXALIGN(size); /* be conservative */ tp = (char *) palloc0(size); @@ -135,6 +137,7 @@ index_form_tuple(TupleDesc tupleDescriptor, #endif isnull, (char *) tp + hoff, + data_size, &tupmask, (hasnull ? (bits8 *) tp + sizeof(IndexTupleData) : NULL)); @@ -201,17 +204,14 @@ nocache_index_getattr(IndexTuple tup, bool *isnull) { Form_pg_attribute *att = tupleDesc->attrs; - char *tp; /* ptr to att in tuple */ - bits8 *bp = NULL; /* ptr to null bitmask in tuple */ - bool slow = false; /* do we have to walk nulls? */ + char *tp; /* ptr to data part of tuple */ + bits8 *bp = NULL; /* ptr to null bitmap in tuple */ + bool slow = false; /* do we have to walk attrs? */ int data_off; /* tuple data offset */ + int off; /* current offset within data */ (void) isnull; /* not used */ - /* - * sanity checks - */ - /* ---------------- * Three cases: * @@ -237,7 +237,7 @@ nocache_index_getattr(IndexTuple tup, { #ifdef IN_MACRO /* This is handled in the macro */ - if (att[attnum]->attcacheoff != -1) + if (att[attnum]->attcacheoff >= 0) { return fetchatt(att[attnum], (char *) tup + data_off + @@ -295,21 +295,28 @@ nocache_index_getattr(IndexTuple tup, tp = (char *) tup + data_off; - /* - * now check for any non-fixed length attrs before our attribute - */ if (!slow) { - if (att[attnum]->attcacheoff != -1) + /* + * If we get here, there are no nulls up to and including the target + * attribute. If we have a cached offset, we can use it. + */ + if (att[attnum]->attcacheoff >= 0) { return fetchatt(att[attnum], tp + att[attnum]->attcacheoff); } - else if (IndexTupleHasVarwidths(tup)) + + /* + * Otherwise, check for non-fixed-length attrs up to and including + * target. If there aren't any, it's safe to cheaply initialize + * the cached offsets for these attrs. + */ + if (IndexTupleHasVarwidths(tup)) { int j; - for (j = 0; j < attnum; j++) + for (j = 0; j <= attnum; j++) { if (att[j]->attlen <= 0) { @@ -320,80 +327,109 @@ nocache_index_getattr(IndexTuple tup, } } - /* - * If slow is false, and we got here, we know that we have a tuple with no - * nulls or var-widths before the target attribute. If possible, we also - * want to initialize the remainder of the attribute cached offset values. - */ if (!slow) { + int natts = tupleDesc->natts; int j = 1; - long off; /* - * need to set cache for some atts + * If we get here, we have a tuple with no nulls or var-widths up to + * and including the target attribute, so we can use the cached offset + * ... only we don't have it yet, or we'd not have got here. Since + * it's cheap to compute offsets for fixed-width columns, we take the + * opportunity to initialize the cached offsets for *all* the leading + * fixed-width columns, in hope of avoiding future visits to this + * routine. */ - att[0]->attcacheoff = 0; - while (j < attnum && att[j]->attcacheoff > 0) + /* we might have set some offsets in the slow path previously */ + while (j < natts && att[j]->attcacheoff > 0) j++; off = att[j - 1]->attcacheoff + att[j - 1]->attlen; - for (; j <= attnum; j++) + for (; j < natts; j++) { - off = att_align(off, att[j]->attalign); + if (att[j]->attlen <= 0) + break; + + off = att_align_nominal(off, att[j]->attalign); att[j]->attcacheoff = off; off += att[j]->attlen; } - return fetchatt(att[attnum], tp + att[attnum]->attcacheoff); + Assert(j > attnum); + + off = att[attnum]->attcacheoff; } else { bool usecache = true; - int off = 0; int i; /* - * Now we know that we have to walk the tuple CAREFULLY. + * Now we know that we have to walk the tuple CAREFULLY. But we + * still might be able to cache some offsets for next time. + * + * Note - This loop is a little tricky. For each non-null attribute, + * we have to first account for alignment padding before the attr, + * then advance over the attr based on its length. Nulls have no + * storage and no alignment padding either. We can use/set + * attcacheoff until we reach either a null or a var-width attribute. */ - - for (i = 0; i < attnum; i++) + off = 0; + for (i = 0; ; i++) /* loop exit is at "break" */ { - if (IndexTupleHasNulls(tup)) + if (IndexTupleHasNulls(tup) && att_isnull(i, bp)) { - if (att_isnull(i, bp)) - { - usecache = false; - continue; - } + usecache = false; + continue; /* this cannot be the target att */ } /* If we know the next offset, we can skip the rest */ - if (usecache && att[i]->attcacheoff != -1) + if (usecache && att[i]->attcacheoff >= 0) off = att[i]->attcacheoff; + else if (att[i]->attlen == -1) + { + /* + * We can only cache the offset for a varlena attribute + * if the offset is already suitably aligned, so that there + * would be no pad bytes in any case: then the offset will + * be valid for either an aligned or unaligned value. + */ + if (usecache && + off == att_align_nominal(off, att[i]->attalign)) + att[i]->attcacheoff = off; + else + { + off = att_align_pointer(off, att[i]->attalign, -1, + tp + off); + usecache = false; + } + } else { - off = att_align(off, att[i]->attalign); + /* not varlena, so safe to use att_align_nominal */ + off = att_align_nominal(off, att[i]->attalign); if (usecache) att[i]->attcacheoff = off; } - off = att_addlength(off, att[i]->attlen, tp + off); + if (i == attnum) + break; + + off = att_addlength_pointer(off, att[i]->attlen, tp + off); if (usecache && att[i]->attlen <= 0) usecache = false; } - - off = att_align(off, att[attnum]->attalign); - - return fetchatt(att[attnum], tp + off); } + + return fetchatt(att[attnum], tp + off); } /* diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index 334d6700423..1a3c01bcac9 100644 --- a/src/backend/access/heap/tuptoaster.c +++ b/src/backend/access/heap/tuptoaster.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.73 2007/04/03 04:14:26 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.74 2007/04/06 04:21:41 tgl Exp $ * * * INTERFACE ROUTINES @@ -42,25 +42,39 @@ #undef TOAST_DEBUG +/* + * Testing whether an externally-stored value is compressed now requires + * comparing extsize (the actual length of the external data) to rawsize + * (the original uncompressed datum's size). The latter includes VARHDRSZ + * overhead, the former doesn't. We never use compression unless it actually + * saves space, so we expect either equality or less-than. + */ +#define VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) \ + ((toast_pointer).va_extsize < (toast_pointer).va_rawsize - VARHDRSZ) + static void toast_delete_datum(Relation rel, Datum value); static Datum toast_save_datum(Relation rel, Datum value, bool use_wal, bool use_fsm); -static varattrib *toast_fetch_datum(varattrib *attr); -static varattrib *toast_fetch_datum_slice(varattrib *attr, +static struct varlena *toast_fetch_datum(struct varlena *attr); +static struct varlena *toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, int32 length); /* ---------- * heap_tuple_fetch_attr - * - * Public entry point to get back a toasted value + * Public entry point to get back a toasted value from * external storage (possibly still in compressed format). - * ---------- + * + * This will return a datum that contains all the data internally, ie, not + * relying on external storage, but it can still be compressed or have a short + * header. + ---------- */ -varattrib * -heap_tuple_fetch_attr(varattrib *attr) +struct varlena * +heap_tuple_fetch_attr(struct varlena *attr) { - varattrib *result; + struct varlena *result; if (VARATT_IS_EXTERNAL(attr)) { @@ -88,35 +102,25 @@ heap_tuple_fetch_attr(varattrib *attr) * or external storage. * ---------- */ -varattrib * -heap_tuple_untoast_attr(varattrib *attr) +struct varlena * +heap_tuple_untoast_attr(struct varlena *attr) { - varattrib *result; - if (VARATT_IS_EXTERNAL(attr)) { + /* + * This is an externally stored datum --- fetch it back from there + */ + attr = toast_fetch_datum(attr); + /* If it's compressed, decompress it */ if (VARATT_IS_COMPRESSED(attr)) { - /* ---------- - * This is an external stored compressed value - * Fetch it from the toast heap and decompress. - * ---------- - */ - PGLZ_Header *tmp; + PGLZ_Header *tmp = (PGLZ_Header *) attr; - tmp = (PGLZ_Header *) toast_fetch_datum(attr); - result = (varattrib *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); - SET_VARSIZE(result, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); - pglz_decompress(tmp, VARDATA(result)); + attr = (struct varlena *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); + SET_VARSIZE(attr, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); + pglz_decompress(tmp, VARDATA(attr)); pfree(tmp); } - else - { - /* - * This is an external stored plain value - */ - result = toast_fetch_datum(attr); - } } else if (VARATT_IS_COMPRESSED(attr)) { @@ -125,18 +129,26 @@ heap_tuple_untoast_attr(varattrib *attr) */ PGLZ_Header *tmp = (PGLZ_Header *) attr; - result = (varattrib *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); - SET_VARSIZE(result, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); - pglz_decompress(tmp, VARDATA(result)); + attr = (struct varlena *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); + SET_VARSIZE(attr, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); + pglz_decompress(tmp, VARDATA(attr)); } - else - + else if (VARATT_IS_SHORT(attr)) + { /* - * This is a plain value inside of the main tuple - why am I called? + * This is a short-header varlena --- convert to 4-byte header format */ - return attr; + Size data_size = VARSIZE_SHORT(attr) - VARHDRSZ_SHORT; + Size new_size = data_size + VARHDRSZ; + struct varlena *new_attr; + + new_attr = (struct varlena *) palloc(new_size); + SET_VARSIZE(new_attr, new_size); + memcpy(VARDATA(new_attr), VARDATA_SHORT(attr), data_size); + attr = new_attr; + } - return result; + return attr; } @@ -147,44 +159,57 @@ heap_tuple_untoast_attr(varattrib *attr) * from compression or external storage. * ---------- */ -varattrib * -heap_tuple_untoast_attr_slice(varattrib *attr, int32 sliceoffset, int32 slicelength) +struct varlena * +heap_tuple_untoast_attr_slice(struct varlena *attr, + int32 sliceoffset, int32 slicelength) { - varattrib *preslice; - varattrib *result; + struct varlena *preslice; + struct varlena *result; + char *attrdata; int32 attrsize; - if (VARATT_IS_COMPRESSED(attr)) + if (VARATT_IS_EXTERNAL(attr)) { - PGLZ_Header *tmp; + struct varatt_external toast_pointer; - if (VARATT_IS_EXTERNAL(attr)) - tmp = (PGLZ_Header *) toast_fetch_datum(attr); - else - tmp = (PGLZ_Header *) attr; /* compressed in main tuple */ + memcpy(&toast_pointer, VARDATA_SHORT(attr), sizeof(toast_pointer)); + + /* fast path for non-compressed external datums */ + if (!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)) + return toast_fetch_datum_slice(attr, sliceoffset, slicelength); - preslice = (varattrib *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); - SET_VARSIZE(preslice, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); + /* fetch it back (compressed marker will get set automatically) */ + preslice = toast_fetch_datum(attr); + } + else + preslice = attr; + + if (VARATT_IS_COMPRESSED(preslice)) + { + PGLZ_Header *tmp = (PGLZ_Header *) preslice; + Size size = PGLZ_RAW_SIZE(tmp) + VARHDRSZ; + + preslice = (struct varlena *) palloc(size); + SET_VARSIZE(preslice, size); pglz_decompress(tmp, VARDATA(preslice)); if (tmp != (PGLZ_Header *) attr) pfree(tmp); } + + if (VARATT_IS_SHORT(preslice)) + { + attrdata = VARDATA_SHORT(preslice); + attrsize = VARSIZE_SHORT(preslice) - VARHDRSZ_SHORT; + } else { - /* Plain value */ - if (VARATT_IS_EXTERNAL(attr)) - { - /* fast path */ - return toast_fetch_datum_slice(attr, sliceoffset, slicelength); - } - else - preslice = attr; + attrdata = VARDATA(preslice); + attrsize = VARSIZE(preslice) - VARHDRSZ; } /* slicing of datum for compressed cases and plain value */ - attrsize = VARSIZE(preslice) - VARHDRSZ; if (sliceoffset >= attrsize) { sliceoffset = 0; @@ -194,10 +219,10 @@ heap_tuple_untoast_attr_slice(varattrib *attr, int32 sliceoffset, int32 slicelen if (((sliceoffset + slicelength) > attrsize) || slicelength < 0) slicelength = attrsize - sliceoffset; - result = (varattrib *) palloc(slicelength + VARHDRSZ); + result = (struct varlena *) palloc(slicelength + VARHDRSZ); SET_VARSIZE(result, slicelength + VARHDRSZ); - memcpy(VARDATA(result), VARDATA(preslice) + sliceoffset, slicelength); + memcpy(VARDATA(result), attrdata + sliceoffset, slicelength); if (preslice != attr) pfree(preslice); @@ -210,29 +235,35 @@ heap_tuple_untoast_attr_slice(varattrib *attr, int32 sliceoffset, int32 slicelen * toast_raw_datum_size - * * Return the raw (detoasted) size of a varlena datum + * (including the VARHDRSZ header) * ---------- */ Size toast_raw_datum_size(Datum value) { - varattrib *attr = (varattrib *) DatumGetPointer(value); + struct varlena *attr = (struct varlena *) DatumGetPointer(value); Size result; - if (VARATT_IS_COMPRESSED(attr)) + if (VARATT_IS_EXTERNAL(attr)) { - /* - * va_rawsize shows the original data size, whether the datum is - * external or not. - */ - result = attr->va_content.va_compressed.va_rawsize + VARHDRSZ; + /* va_rawsize is the size of the original datum -- including header */ + struct varatt_external toast_pointer; + + memcpy(&toast_pointer, VARDATA_SHORT(attr), sizeof(toast_pointer)); + result = toast_pointer.va_rawsize; } - else if (VARATT_IS_EXTERNAL(attr)) + else if (VARATT_IS_COMPRESSED(attr)) + { + /* here, va_rawsize is just the payload size */ + result = VARRAWSIZE_4B_C(attr) + VARHDRSZ; + } + else if (VARATT_IS_SHORT(attr)) { /* - * an uncompressed external attribute has rawsize including the header - * (not too consistent!) + * we have to normalize the header length to VARHDRSZ or else the + * callers of this function will be confused. */ - result = attr->va_content.va_external.va_rawsize; + result = VARSIZE_SHORT(attr) - VARHDRSZ_SHORT + VARHDRSZ; } else { @@ -251,7 +282,7 @@ toast_raw_datum_size(Datum value) Size toast_datum_size(Datum value) { - varattrib *attr = (varattrib *) DatumGetPointer(value); + struct varlena *attr = (struct varlena *) DatumGetPointer(value); Size result; if (VARATT_IS_EXTERNAL(attr)) @@ -261,7 +292,14 @@ toast_datum_size(Datum value) * compressed or not. We do not count the size of the toast pointer * ... should we? */ - result = attr->va_content.va_external.va_extsize; + struct varatt_external toast_pointer; + + memcpy(&toast_pointer, VARDATA_SHORT(attr), sizeof(toast_pointer)); + result = toast_pointer.va_extsize; + } + else if (VARATT_IS_SHORT(attr)) + { + result = VARSIZE_SHORT(attr); } else { @@ -413,16 +451,16 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, for (i = 0; i < numAttrs; i++) { - varattrib *old_value; - varattrib *new_value; + struct varlena *old_value; + struct varlena *new_value; if (oldtup != NULL) { /* * For UPDATE get the old and new values of this attribute */ - old_value = (varattrib *) DatumGetPointer(toast_oldvalues[i]); - new_value = (varattrib *) DatumGetPointer(toast_values[i]); + old_value = (struct varlena *) DatumGetPointer(toast_oldvalues[i]); + new_value = (struct varlena *) DatumGetPointer(toast_values[i]); /* * If the old value is an external stored one, check if it has @@ -432,10 +470,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, VARATT_IS_EXTERNAL(old_value)) { if (toast_isnull[i] || !VARATT_IS_EXTERNAL(new_value) || - old_value->va_content.va_external.va_valueid != - new_value->va_content.va_external.va_valueid || - old_value->va_content.va_external.va_toastrelid != - new_value->va_content.va_external.va_toastrelid) + memcmp(VARDATA_SHORT(old_value), + VARDATA_SHORT(new_value), + sizeof(struct varatt_external)) != 0) { /* * The old external stored value isn't needed any more @@ -452,7 +489,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, * tuple. */ toast_action[i] = 'p'; - toast_sizes[i] = VARSIZE(toast_values[i]); continue; } } @@ -462,7 +498,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, /* * For INSERT simply get the new value */ - new_value = (varattrib *) DatumGetPointer(toast_values[i]); + new_value = (struct varlena *) DatumGetPointer(toast_values[i]); } /* @@ -503,7 +539,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, /* * Remember the size of this attribute */ - toast_sizes[i] = VARSIZE(new_value); + toast_sizes[i] = VARSIZE_ANY(new_value); } else { @@ -542,7 +578,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, toast_values, toast_isnull) > maxDataLen) { int biggest_attno = -1; - int32 biggest_size = MAXALIGN(sizeof(varattrib)); + int32 biggest_size = MAXALIGN(sizeof(varattrib_pointer)); Datum old_value; Datum new_value; @@ -553,7 +589,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, { if (toast_action[i] != ' ') continue; - if (VARATT_IS_EXTENDED(toast_values[i])) + if (VARATT_IS_EXTERNAL(toast_values[i])) + continue; + if (VARATT_IS_COMPRESSED(toast_values[i])) continue; if (att[i]->attstorage != 'x') continue; @@ -603,7 +641,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, rel->rd_rel->reltoastrelid != InvalidOid) { int biggest_attno = -1; - int32 biggest_size = MAXALIGN(sizeof(varattrib)); + int32 biggest_size = MAXALIGN(sizeof(varattrib_pointer)); Datum old_value; /*------ @@ -639,9 +677,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, use_wal, use_fsm); if (toast_free[i]) pfree(DatumGetPointer(old_value)); - toast_free[i] = true; - toast_sizes[i] = VARSIZE(toast_values[i]); need_change = true; need_free = true; @@ -655,7 +691,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, toast_values, toast_isnull) > maxDataLen) { int biggest_attno = -1; - int32 biggest_size = MAXALIGN(sizeof(varattrib)); + int32 biggest_size = MAXALIGN(sizeof(varattrib_pointer)); Datum old_value; Datum new_value; @@ -666,7 +702,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, { if (toast_action[i] != ' ') continue; - if (VARATT_IS_EXTENDED(toast_values[i])) + if (VARATT_IS_EXTERNAL(toast_values[i])) + continue; + if (VARATT_IS_COMPRESSED(toast_values[i])) continue; if (att[i]->attstorage != 'm') continue; @@ -715,7 +753,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, rel->rd_rel->reltoastrelid != InvalidOid) { int biggest_attno = -1; - int32 biggest_size = MAXALIGN(sizeof(varattrib)); + int32 biggest_size = MAXALIGN(sizeof(varattrib_pointer)); Datum old_value; /*-------- @@ -768,6 +806,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, HeapTupleHeader olddata = newtup->t_data; HeapTupleHeader new_data; int32 new_len; + int32 new_data_len; /* * Calculate the new size of the tuple. Header size should not @@ -780,8 +819,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, new_len += sizeof(Oid); new_len = MAXALIGN(new_len); Assert(new_len == olddata->t_hoff); - new_len += heap_compute_data_size(tupleDesc, - toast_values, toast_isnull); + new_data_len = heap_compute_data_size(tupleDesc, + toast_values, toast_isnull); + new_len += new_data_len; /* * Allocate and zero the space needed, and fill HeapTupleData fields. @@ -802,6 +842,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, toast_values, toast_isnull, (char *) new_data + olddata->t_hoff, + new_data_len, &(new_data->t_infomask), has_nulls ? new_data->t_bits : NULL); } @@ -835,6 +876,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup, * This must be invoked on any potentially-composite field that is to be * inserted into a tuple. Doing this preserves the invariant that toasting * goes only one level deep in a tuple. + * + * Note that flattening does not mean expansion of short-header varlenas, + * so in one sense toasting is allowed within composite datums. * ---------- */ Datum @@ -845,6 +889,7 @@ toast_flatten_tuple_attribute(Datum value, HeapTupleHeader olddata; HeapTupleHeader new_data; int32 new_len; + int32 new_data_len; HeapTupleData tmptup; Form_pg_attribute *att; int numAttrs; @@ -891,10 +936,11 @@ toast_flatten_tuple_attribute(Datum value, has_nulls = true; else if (att[i]->attlen == -1) { - varattrib *new_value; + struct varlena *new_value; - new_value = (varattrib *) DatumGetPointer(toast_values[i]); - if (VARATT_IS_EXTENDED(new_value)) + new_value = (struct varlena *) DatumGetPointer(toast_values[i]); + if (VARATT_IS_EXTERNAL(new_value) || + VARATT_IS_COMPRESSED(new_value)) { new_value = heap_tuple_untoast_attr(new_value); toast_values[i] = PointerGetDatum(new_value); @@ -924,7 +970,9 @@ toast_flatten_tuple_attribute(Datum value, new_len += sizeof(Oid); new_len = MAXALIGN(new_len); Assert(new_len == olddata->t_hoff); - new_len += heap_compute_data_size(tupleDesc, toast_values, toast_isnull); + new_data_len = heap_compute_data_size(tupleDesc, + toast_values, toast_isnull); + new_len += new_data_len; new_data = (HeapTupleHeader) palloc0(new_len); @@ -939,6 +987,7 @@ toast_flatten_tuple_attribute(Datum value, toast_values, toast_isnull, (char *) new_data + olddata->t_hoff, + new_data_len, &(new_data->t_infomask), has_nulls ? new_data->t_bits : NULL); @@ -962,21 +1011,26 @@ toast_flatten_tuple_attribute(Datum value, * If we fail (ie, compressed result is actually bigger than original) * then return NULL. We must not use compressed data if it'd expand * the tuple! + * + * We use VAR{SIZE,DATA}_ANY so we can handle short varlenas here without + * copying them. But we can't handle external or compressed datums. * ---------- */ Datum toast_compress_datum(Datum value) { - varattrib *tmp; - int32 valsize = VARSIZE(value) - VARHDRSZ; + struct varlena *tmp; + int32 valsize = VARSIZE_ANY_EXHDR(value); - tmp = (varattrib *) palloc(PGLZ_MAX_OUTPUT(valsize)); - if (pglz_compress(VARDATA(value), valsize, + Assert(!VARATT_IS_EXTERNAL(value)); + Assert(!VARATT_IS_COMPRESSED(value)); + + tmp = (struct varlena *) palloc(PGLZ_MAX_OUTPUT(valsize)); + if (pglz_compress(VARDATA_ANY(value), valsize, (PGLZ_Header *) tmp, PGLZ_strategy_default) && - VARSIZE(tmp) < VARSIZE(value)) + VARSIZE(tmp) < VARSIZE_ANY(value)) { /* successful compression */ - VARATT_SIZEP_DEPRECATED(tmp) |= VARATT_FLAG_COMPRESSED; return PointerGetDatum(tmp); } else @@ -992,7 +1046,7 @@ toast_compress_datum(Datum value) * toast_save_datum - * * Save one single datum into the secondary relation and return - * a varattrib reference for it. + * a Datum reference for it. * ---------- */ static Datum @@ -1006,7 +1060,8 @@ toast_save_datum(Relation rel, Datum value, Datum t_values[3]; bool t_isnull[3]; CommandId mycid = GetCurrentCommandId(); - varattrib *result; + struct varlena *result; + struct varatt_external toast_pointer; struct { struct varlena hdr; @@ -1027,44 +1082,51 @@ toast_save_datum(Relation rel, Datum value, toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock); /* - * Create the varattrib reference + * Get the data pointer and length, and compute va_rawsize and va_extsize. + * + * va_rawsize is the size of the equivalent fully uncompressed datum, + * so we have to adjust for short headers. + * + * va_extsize is the actual size of the data payload in the toast records. */ - result = (varattrib *) palloc(sizeof(varattrib)); - - SET_VARSIZE(result, sizeof(varattrib)); - VARATT_SIZEP_DEPRECATED(result) |= VARATT_FLAG_EXTERNAL; - if (VARATT_IS_COMPRESSED(value)) + if (VARATT_IS_SHORT(value)) + { + data_p = VARDATA_SHORT(value); + data_todo = VARSIZE_SHORT(value) - VARHDRSZ_SHORT; + toast_pointer.va_rawsize = data_todo + VARHDRSZ; /* as if not short */ + toast_pointer.va_extsize = data_todo; + } + else if (VARATT_IS_COMPRESSED(value)) { - VARATT_SIZEP_DEPRECATED(result) |= VARATT_FLAG_COMPRESSED; - result->va_content.va_external.va_rawsize = - ((varattrib *) value)->va_content.va_compressed.va_rawsize; + data_p = VARDATA(value); + data_todo = VARSIZE(value) - VARHDRSZ; + /* rawsize in a compressed datum is just the size of the payload */ + toast_pointer.va_rawsize = VARRAWSIZE_4B_C(value) + VARHDRSZ; + toast_pointer.va_extsize = data_todo; + /* Assert that the numbers look like it's compressed */ + Assert(VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)); } else - result->va_content.va_external.va_rawsize = VARSIZE(value); + { + data_p = VARDATA(value); + data_todo = VARSIZE(value) - VARHDRSZ; + toast_pointer.va_rawsize = VARSIZE(value); + toast_pointer.va_extsize = data_todo; + } - result->va_content.va_external.va_extsize = - VARSIZE(value) - VARHDRSZ; - result->va_content.va_external.va_valueid = - GetNewOidWithIndex(toastrel, toastidx); - result->va_content.va_external.va_toastrelid = - rel->rd_rel->reltoastrelid; + toast_pointer.va_valueid = GetNewOidWithIndex(toastrel, toastidx); + toast_pointer.va_toastrelid = rel->rd_rel->reltoastrelid; /* * Initialize constant parts of the tuple data */ - t_values[0] = ObjectIdGetDatum(result->va_content.va_external.va_valueid); + t_values[0] = ObjectIdGetDatum(toast_pointer.va_valueid); t_values[2] = PointerGetDatum(&chunk_data); t_isnull[0] = false; t_isnull[1] = false; t_isnull[2] = false; /* - * Get the data to process - */ - data_p = VARDATA(value); - data_todo = VARSIZE(value) - VARHDRSZ; - - /* * Split up the item into chunks */ while (data_todo > 0) @@ -1111,11 +1173,18 @@ toast_save_datum(Relation rel, Datum value, } /* - * Done - close toast relation and return the reference + * Done - close toast relation */ index_close(toastidx, RowExclusiveLock); heap_close(toastrel, RowExclusiveLock); + /* + * Create the TOAST pointer value that we'll return + */ + result = (struct varlena *) palloc(sizeof(varattrib_pointer)); + SET_VARSIZE_EXTERNAL(result); + memcpy(VARDATA_SHORT(result), &toast_pointer, sizeof(toast_pointer)); + return PointerGetDatum(result); } @@ -1129,7 +1198,8 @@ toast_save_datum(Relation rel, Datum value, static void toast_delete_datum(Relation rel, Datum value) { - varattrib *attr = (varattrib *) DatumGetPointer(value); + struct varlena *attr = (struct varlena *) DatumGetPointer(value); + struct varatt_external toast_pointer; Relation toastrel; Relation toastidx; ScanKeyData toastkey; @@ -1139,11 +1209,14 @@ toast_delete_datum(Relation rel, Datum value) if (!VARATT_IS_EXTERNAL(attr)) return; + /* Must copy to access aligned fields */ + memcpy(&toast_pointer, VARDATA_SHORT(attr), + sizeof(struct varatt_external)); + /* * Open the toast relation and its index */ - toastrel = heap_open(attr->va_content.va_external.va_toastrelid, - RowExclusiveLock); + toastrel = heap_open(toast_pointer.va_toastrelid, RowExclusiveLock); toastidx = index_open(toastrel->rd_rel->reltoastidxid, RowExclusiveLock); /* @@ -1153,7 +1226,7 @@ toast_delete_datum(Relation rel, Datum value) ScanKeyInit(&toastkey, (AttrNumber) 1, BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(attr->va_content.va_external.va_valueid)); + ObjectIdGetDatum(toast_pointer.va_valueid)); /* * Find the chunks by index @@ -1180,12 +1253,12 @@ toast_delete_datum(Relation rel, Datum value) /* ---------- * toast_fetch_datum - * - * Reconstruct an in memory varattrib from the chunks saved + * Reconstruct an in memory Datum from the chunks saved * in the toast relation * ---------- */ -static varattrib * -toast_fetch_datum(varattrib *attr) +static struct varlena * +toast_fetch_datum(struct varlena *attr) { Relation toastrel; Relation toastidx; @@ -1193,28 +1266,35 @@ toast_fetch_datum(varattrib *attr) IndexScanDesc toastscan; HeapTuple ttup; TupleDesc toasttupDesc; - varattrib *result; + struct varlena *result; + struct varatt_external toast_pointer; int32 ressize; int32 residx, nextidx; int32 numchunks; Pointer chunk; bool isnull; + char *chunkdata; int32 chunksize; - ressize = attr->va_content.va_external.va_extsize; + /* Must copy to access aligned fields */ + memcpy(&toast_pointer, VARDATA_SHORT(attr), + sizeof(struct varatt_external)); + + ressize = toast_pointer.va_extsize; numchunks = ((ressize - 1) / TOAST_MAX_CHUNK_SIZE) + 1; - result = (varattrib *) palloc(ressize + VARHDRSZ); - SET_VARSIZE(result, ressize + VARHDRSZ); - if (VARATT_IS_COMPRESSED(attr)) - VARATT_SIZEP_DEPRECATED(result) |= VARATT_FLAG_COMPRESSED; + result = (struct varlena *) palloc(ressize + VARHDRSZ); + + if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)) + SET_VARSIZE_COMPRESSED(result, ressize + VARHDRSZ); + else + SET_VARSIZE(result, ressize + VARHDRSZ); /* * Open the toast relation and its index */ - toastrel = heap_open(attr->va_content.va_external.va_toastrelid, - AccessShareLock); + toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock); toasttupDesc = toastrel->rd_att; toastidx = index_open(toastrel->rd_rel->reltoastidxid, AccessShareLock); @@ -1224,7 +1304,7 @@ toast_fetch_datum(varattrib *attr) ScanKeyInit(&toastkey, (AttrNumber) 1, BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(attr->va_content.va_external.va_valueid)); + ObjectIdGetDatum(toast_pointer.va_valueid)); /* * Read the chunks by index @@ -1246,7 +1326,24 @@ toast_fetch_datum(varattrib *attr) Assert(!isnull); chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull)); Assert(!isnull); - chunksize = VARSIZE(chunk) - VARHDRSZ; + if (!VARATT_IS_EXTENDED(chunk)) + { + chunksize = VARSIZE(chunk) - VARHDRSZ; + chunkdata = VARDATA(chunk); + } + else if (VARATT_IS_SHORT(chunk)) + { + /* could happen due to heap_form_tuple doing its thing */ + chunksize = VARSIZE_SHORT(chunk) - VARHDRSZ_SHORT; + chunkdata = VARDATA_SHORT(chunk); + } + else + { + /* should never happen */ + elog(ERROR, "found toasted toast chunk"); + chunksize = 0; /* keep compiler quiet */ + chunkdata = NULL; + } /* * Some checks on the data we've found @@ -1254,31 +1351,35 @@ toast_fetch_datum(varattrib *attr) if (residx != nextidx) elog(ERROR, "unexpected chunk number %d (expected %d) for toast value %u", residx, nextidx, - attr->va_content.va_external.va_valueid); + toast_pointer.va_valueid); if (residx < numchunks - 1) { if (chunksize != TOAST_MAX_CHUNK_SIZE) - elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u", - chunksize, residx, - attr->va_content.va_external.va_valueid); + elog(ERROR, "unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u", + chunksize, (int) TOAST_MAX_CHUNK_SIZE, + residx, numchunks, + toast_pointer.va_valueid); } - else if (residx < numchunks) + else if (residx == numchunks-1) { if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != ressize) - elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u", - chunksize, residx, - attr->va_content.va_external.va_valueid); + elog(ERROR, "unexpected chunk size %d (expected %d) in final chunk %d for toast value %u", + chunksize, + (int) (ressize - residx*TOAST_MAX_CHUNK_SIZE), + residx, + toast_pointer.va_valueid); } else - elog(ERROR, "unexpected chunk number %d for toast value %u", + elog(ERROR, "unexpected chunk number %d for toast value %u (out of range %d..%d)", residx, - attr->va_content.va_external.va_valueid); + toast_pointer.va_valueid, + 0, numchunks-1); /* * Copy the data into proper place in our result */ memcpy(VARDATA(result) + residx * TOAST_MAX_CHUNK_SIZE, - VARDATA(chunk), + chunkdata, chunksize); nextidx++; @@ -1290,7 +1391,7 @@ toast_fetch_datum(varattrib *attr) if (nextidx != numchunks) elog(ERROR, "missing chunk number %d for toast value %u", nextidx, - attr->va_content.va_external.va_valueid); + toast_pointer.va_valueid); /* * End scan and close relations @@ -1305,12 +1406,12 @@ toast_fetch_datum(varattrib *attr) /* ---------- * toast_fetch_datum_slice - * - * Reconstruct a segment of a varattrib from the chunks saved + * Reconstruct a segment of a Datum from the chunks saved * in the toast relation * ---------- */ -static varattrib * -toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) +static struct varlena * +toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, int32 length) { Relation toastrel; Relation toastidx; @@ -1319,7 +1420,8 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) IndexScanDesc toastscan; HeapTuple ttup; TupleDesc toasttupDesc; - varattrib *result; + struct varlena *result; + struct varatt_external toast_pointer; int32 attrsize; int32 residx; int32 nextidx; @@ -1331,11 +1433,16 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) int totalchunks; Pointer chunk; bool isnull; + char *chunkdata; int32 chunksize; int32 chcpystrt; int32 chcpyend; - attrsize = attr->va_content.va_external.va_extsize; + /* Must copy to access aligned fields */ + memcpy(&toast_pointer, VARDATA_SHORT(attr), + sizeof(struct varatt_external)); + + attrsize = toast_pointer.va_extsize; totalchunks = ((attrsize - 1) / TOAST_MAX_CHUNK_SIZE) + 1; if (sliceoffset >= attrsize) @@ -1347,11 +1454,12 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) if (((sliceoffset + length) > attrsize) || length < 0) length = attrsize - sliceoffset; - result = (varattrib *) palloc(length + VARHDRSZ); - SET_VARSIZE(result, length + VARHDRSZ); + result = (struct varlena *) palloc(length + VARHDRSZ); - if (VARATT_IS_COMPRESSED(attr)) - VARATT_SIZEP_DEPRECATED(result) |= VARATT_FLAG_COMPRESSED; + if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)) + SET_VARSIZE_COMPRESSED(result, length + VARHDRSZ); + else + SET_VARSIZE(result, length + VARHDRSZ); if (length == 0) return result; /* Can save a lot of work at this point! */ @@ -1366,8 +1474,7 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) /* * Open the toast relation and its index */ - toastrel = heap_open(attr->va_content.va_external.va_toastrelid, - AccessShareLock); + toastrel = heap_open(toast_pointer.va_toastrelid, AccessShareLock); toasttupDesc = toastrel->rd_att; toastidx = index_open(toastrel->rd_rel->reltoastidxid, AccessShareLock); @@ -1378,7 +1485,7 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) ScanKeyInit(&toastkey[0], (AttrNumber) 1, BTEqualStrategyNumber, F_OIDEQ, - ObjectIdGetDatum(attr->va_content.va_external.va_valueid)); + ObjectIdGetDatum(toast_pointer.va_valueid)); /* * Use equality condition for one chunk, a range condition otherwise: @@ -1421,7 +1528,24 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) Assert(!isnull); chunk = DatumGetPointer(fastgetattr(ttup, 3, toasttupDesc, &isnull)); Assert(!isnull); - chunksize = VARSIZE(chunk) - VARHDRSZ; + if (!VARATT_IS_EXTENDED(chunk)) + { + chunksize = VARSIZE(chunk) - VARHDRSZ; + chunkdata = VARDATA(chunk); + } + else if (VARATT_IS_SHORT(chunk)) + { + /* could happen due to heap_form_tuple doing its thing */ + chunksize = VARSIZE_SHORT(chunk) - VARHDRSZ_SHORT; + chunkdata = VARDATA_SHORT(chunk); + } + else + { + /* should never happen */ + elog(ERROR, "found toasted toast chunk"); + chunksize = 0; /* keep compiler quiet */ + chunkdata = NULL; + } /* * Some checks on the data we've found @@ -1429,21 +1553,29 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) if ((residx != nextidx) || (residx > endchunk) || (residx < startchunk)) elog(ERROR, "unexpected chunk number %d (expected %d) for toast value %u", residx, nextidx, - attr->va_content.va_external.va_valueid); + toast_pointer.va_valueid); if (residx < totalchunks - 1) { if (chunksize != TOAST_MAX_CHUNK_SIZE) - elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u", - chunksize, residx, - attr->va_content.va_external.va_valueid); + elog(ERROR, "unexpected chunk size %d (expected %d) in chunk %d of %d for toast value %u when fetching slice", + chunksize, (int) TOAST_MAX_CHUNK_SIZE, + residx, totalchunks, + toast_pointer.va_valueid); } - else + else if (residx == totalchunks-1) { if ((residx * TOAST_MAX_CHUNK_SIZE + chunksize) != attrsize) - elog(ERROR, "unexpected chunk size %d in chunk %d for toast value %u", - chunksize, residx, - attr->va_content.va_external.va_valueid); + elog(ERROR, "unexpected chunk size %d (expected %d) in final chunk %d for toast value %u when fetching slice", + chunksize, + (int) (attrsize - residx * TOAST_MAX_CHUNK_SIZE), + residx, + toast_pointer.va_valueid); } + else + elog(ERROR, "unexpected chunk number %d for toast value %u (out of range %d..%d)", + residx, + toast_pointer.va_valueid, + 0, totalchunks-1); /* * Copy the data into proper place in our result @@ -1457,7 +1589,7 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) memcpy(VARDATA(result) + (residx * TOAST_MAX_CHUNK_SIZE - sliceoffset) + chcpystrt, - VARDATA(chunk) + chcpystrt, + chunkdata + chcpystrt, (chcpyend - chcpystrt) + 1); nextidx++; @@ -1469,7 +1601,7 @@ toast_fetch_datum_slice(varattrib *attr, int32 sliceoffset, int32 length) if (nextidx != (endchunk + 1)) elog(ERROR, "missing chunk number %d for toast value %u", nextidx, - attr->va_content.va_external.va_valueid); + toast_pointer.va_valueid); /* * End scan and close relations diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 47f5e25fd20..463f038c0f7 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -8,7 +8,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.5 2007/01/09 02:14:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.6 2007/04/06 04:21:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -314,7 +314,7 @@ needs_toast_table(Relation rel) { if (att[i]->attisdropped) continue; - data_length = att_align(data_length, att[i]->attalign); + data_length = att_align_nominal(data_length, att[i]->attalign); if (att[i]->attlen > 0) { /* Fixed-length types are never toastable */ diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index c568f04284c..44e743363ad 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.103 2007/01/09 02:14:11 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/analyze.c,v 1.104 2007/04/06 04:21:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1478,7 +1478,7 @@ compute_minimal_stats(VacAttrStatsP stats, */ if (is_varlena) { - total_width += VARSIZE(DatumGetPointer(value)); + total_width += VARSIZE_ANY(DatumGetPointer(value)); /* * If the value is toasted, we want to detoast it just once to @@ -1792,7 +1792,7 @@ compute_scalar_stats(VacAttrStatsP stats, */ if (is_varlena) { - total_width += VARSIZE(DatumGetPointer(value)); + total_width += VARSIZE_ANY(DatumGetPointer(value)); /* * If the value is toasted, we want to detoast it just once to diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index 94e6829f544..50ab3ada237 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.216 2007/03/27 23:21:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.217 2007/04/06 04:21:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1896,8 +1896,8 @@ ExecEvalScalarArrayOp(ScalarArrayOpExprState *sstate, else { elt = fetch_att(s, typbyval, typlen); - s = att_addlength(s, typlen, PointerGetDatum(s)); - s = (char *) att_align(s, typalign); + s = att_addlength_pointer(s, typlen, s); + s = (char *) att_align_nominal(s, typalign); fcinfo.arg[1] = elt; fcinfo.argnull[1] = false; } diff --git a/src/backend/storage/large_object/inv_api.c b/src/backend/storage/large_object/inv_api.c index 7becf160b49..ea98ab29520 100644 --- a/src/backend/storage/large_object/inv_api.c +++ b/src/backend/storage/large_object/inv_api.c @@ -17,7 +17,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.123 2007/03/03 19:52:46 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/storage/large_object/inv_api.c,v 1.124 2007/04/06 04:21:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -336,7 +336,7 @@ inv_getsize(LargeObjectDesc *obj_desc) if (VARATT_IS_EXTENDED(datafield)) { datafield = (bytea *) - heap_tuple_untoast_attr((varattrib *) datafield); + heap_tuple_untoast_attr((struct varlena *) datafield); pfreeit = true; } lastbyte = data->pageno * LOBLKSIZE + getbytealen(datafield); @@ -462,7 +462,7 @@ inv_read(LargeObjectDesc *obj_desc, char *buf, int nbytes) if (VARATT_IS_EXTENDED(datafield)) { datafield = (bytea *) - heap_tuple_untoast_attr((varattrib *) datafield); + heap_tuple_untoast_attr((struct varlena *) datafield); pfreeit = true; } len = getbytealen(datafield); @@ -580,7 +580,7 @@ inv_write(LargeObjectDesc *obj_desc, const char *buf, int nbytes) if (VARATT_IS_EXTENDED(datafield)) { datafield = (bytea *) - heap_tuple_untoast_attr((varattrib *) datafield); + heap_tuple_untoast_attr((struct varlena *) datafield); pfreeit = true; } len = getbytealen(datafield); @@ -756,7 +756,7 @@ inv_truncate(LargeObjectDesc *obj_desc, int len) if (VARATT_IS_EXTENDED(datafield)) { datafield = (bytea *) - heap_tuple_untoast_attr((varattrib *) datafield); + heap_tuple_untoast_attr((struct varlena *) datafield); pfreeit = true; } pagelen = getbytealen(datafield); diff --git a/src/backend/utils/adt/arrayfuncs.c b/src/backend/utils/adt/arrayfuncs.c index 38a86452e3f..991c7a46f7c 100644 --- a/src/backend/utils/adt/arrayfuncs.c +++ b/src/backend/utils/adt/arrayfuncs.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.138 2007/03/27 23:21:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/arrayfuncs.c,v 1.139 2007/04/06 04:21:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -805,8 +805,8 @@ ReadArrayStr(char *arrayStr, /* let's just make sure data is not toasted */ if (typlen == -1) values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i])); - totbytes = att_addlength(totbytes, typlen, values[i]); - totbytes = att_align(totbytes, typalign); + totbytes = att_addlength_datum(totbytes, typlen, values[i]); + totbytes = att_align_nominal(totbytes, typalign); /* check for overflow of total request */ if (!AllocSizeIsValid(totbytes)) ereport(ERROR, @@ -1011,8 +1011,8 @@ array_out(PG_FUNCTION_ARGS) itemvalue = fetch_att(p, typbyval, typlen); values[i] = OutputFunctionCall(&my_extra->proc, itemvalue); - p = att_addlength(p, typlen, PointerGetDatum(p)); - p = (char *) att_align(p, typalign); + p = att_addlength_pointer(p, typlen, p); + p = (char *) att_align_nominal(p, typalign); /* count data plus backslashes; detect chars needing quotes */ if (values[i][0] == '\0') @@ -1399,8 +1399,8 @@ ReadArrayBinary(StringInfo buf, /* let's just make sure data is not toasted */ if (typlen == -1) values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i])); - totbytes = att_addlength(totbytes, typlen, values[i]); - totbytes = att_align(totbytes, typalign); + totbytes = att_addlength_datum(totbytes, typlen, values[i]); + totbytes = att_align_nominal(totbytes, typalign); /* check for overflow of total request */ if (!AllocSizeIsValid(totbytes)) ereport(ERROR, @@ -1512,8 +1512,8 @@ array_send(PG_FUNCTION_ARGS) VARSIZE(outputbytes) - VARHDRSZ); pfree(outputbytes); - p = att_addlength(p, typlen, PointerGetDatum(p)); - p = (char *) att_align(p, typalign); + p = att_addlength_pointer(p, typlen, p); + p = (char *) att_align_nominal(p, typalign); } /* advance bitmap pointer if any */ @@ -2108,8 +2108,8 @@ array_set(ArrayType *array, olditemlen = 0; else { - olditemlen = att_addlength(0, elmlen, PointerGetDatum(elt_ptr)); - olditemlen = att_align(olditemlen, elmalign); + olditemlen = att_addlength_pointer(0, elmlen, elt_ptr); + olditemlen = att_align_nominal(olditemlen, elmalign); } lenafter = (int) (olddatasize - lenbefore - olditemlen); } @@ -2118,8 +2118,8 @@ array_set(ArrayType *array, newitemlen = 0; else { - newitemlen = att_addlength(0, elmlen, dataValue); - newitemlen = att_align(newitemlen, elmalign); + newitemlen = att_addlength_datum(0, elmlen, dataValue); + newitemlen = att_align_nominal(newitemlen, elmalign); } newsize = overheadlen + lenbefore + newitemlen + lenafter; @@ -2639,8 +2639,8 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType, else { elt = fetch_att(s, inp_typbyval, inp_typlen); - s = att_addlength(s, inp_typlen, elt); - s = (char *) att_align(s, inp_typalign); + s = att_addlength_datum(s, inp_typlen, elt); + s = (char *) att_align_nominal(s, inp_typalign); fcinfo->arg[0] = elt; fcinfo->argnull[0] = false; } @@ -2679,8 +2679,8 @@ array_map(FunctionCallInfo fcinfo, Oid inpType, Oid retType, if (typlen == -1) values[i] = PointerGetDatum(PG_DETOAST_DATUM(values[i])); /* Update total result size */ - nbytes = att_addlength(nbytes, typlen, values[i]); - nbytes = att_align(nbytes, typalign); + nbytes = att_addlength_datum(nbytes, typlen, values[i]); + nbytes = att_align_nominal(nbytes, typalign); /* check for overflow of total request */ if (!AllocSizeIsValid(nbytes)) ereport(ERROR, @@ -2827,8 +2827,8 @@ construct_md_array(Datum *elems, /* make sure data is not toasted */ if (elmlen == -1) elems[i] = PointerGetDatum(PG_DETOAST_DATUM(elems[i])); - nbytes = att_addlength(nbytes, elmlen, elems[i]); - nbytes = att_align(nbytes, elmalign); + nbytes = att_addlength_datum(nbytes, elmlen, elems[i]); + nbytes = att_align_nominal(nbytes, elmalign); /* check for overflow of total request */ if (!AllocSizeIsValid(nbytes)) ereport(ERROR, @@ -2947,8 +2947,8 @@ deconstruct_array(ArrayType *array, elems[i] = fetch_att(p, elmbyval, elmlen); if (nulls) nulls[i] = false; - p = att_addlength(p, elmlen, PointerGetDatum(p)); - p = (char *) att_align(p, elmalign); + p = att_addlength_pointer(p, elmlen, p); + p = (char *) att_align_nominal(p, elmalign); } /* advance bitmap pointer if any */ @@ -3064,8 +3064,8 @@ array_eq(PG_FUNCTION_ARGS) { isnull1 = false; elt1 = fetch_att(ptr1, typbyval, typlen); - ptr1 = att_addlength(ptr1, typlen, PointerGetDatum(ptr1)); - ptr1 = (char *) att_align(ptr1, typalign); + ptr1 = att_addlength_pointer(ptr1, typlen, ptr1); + ptr1 = (char *) att_align_nominal(ptr1, typalign); } if (bitmap2 && (*bitmap2 & bitmask) == 0) @@ -3077,8 +3077,8 @@ array_eq(PG_FUNCTION_ARGS) { isnull2 = false; elt2 = fetch_att(ptr2, typbyval, typlen); - ptr2 = att_addlength(ptr2, typlen, PointerGetDatum(ptr2)); - ptr2 = (char *) att_align(ptr2, typalign); + ptr2 = att_addlength_pointer(ptr2, typlen, ptr2); + ptr2 = (char *) att_align_nominal(ptr2, typalign); } /* advance bitmap pointers if any */ @@ -3265,8 +3265,8 @@ array_cmp(FunctionCallInfo fcinfo) { isnull1 = false; elt1 = fetch_att(ptr1, typbyval, typlen); - ptr1 = att_addlength(ptr1, typlen, PointerGetDatum(ptr1)); - ptr1 = (char *) att_align(ptr1, typalign); + ptr1 = att_addlength_pointer(ptr1, typlen, ptr1); + ptr1 = (char *) att_align_nominal(ptr1, typalign); } if (bitmap2 && (*bitmap2 & bitmask) == 0) @@ -3278,8 +3278,8 @@ array_cmp(FunctionCallInfo fcinfo) { isnull2 = false; elt2 = fetch_att(ptr2, typbyval, typlen); - ptr2 = att_addlength(ptr2, typlen, PointerGetDatum(ptr2)); - ptr2 = (char *) att_align(ptr2, typalign); + ptr2 = att_addlength_pointer(ptr2, typlen, ptr2); + ptr2 = (char *) att_align_nominal(ptr2, typalign); } /* advance bitmap pointers if any */ @@ -3468,8 +3468,8 @@ array_contain_compare(ArrayType *array1, ArrayType *array2, bool matchall, { isnull1 = false; elt1 = fetch_att(ptr1, typbyval, typlen); - ptr1 = att_addlength(ptr1, typlen, PointerGetDatum(ptr1)); - ptr1 = (char *) att_align(ptr1, typalign); + ptr1 = att_addlength_pointer(ptr1, typlen, ptr1); + ptr1 = (char *) att_align_nominal(ptr1, typalign); } /* advance bitmap pointer if any */ @@ -3667,14 +3667,14 @@ ArrayCastAndSet(Datum src, store_att_byval(dest, src, typlen); else memmove(dest, DatumGetPointer(src), typlen); - inc = att_align(typlen, typalign); + inc = att_align_nominal(typlen, typalign); } else { Assert(!typbyval); - inc = att_addlength(0, typlen, src); + inc = att_addlength_datum(0, typlen, src); memmove(dest, DatumGetPointer(src), inc); - inc = att_align(inc, typalign); + inc = att_align_nominal(inc, typalign); } return inc; @@ -3700,7 +3700,7 @@ array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, /* easy if fixed-size elements and no NULLs */ if (typlen > 0 && !nullbitmap) - return ptr + nitems * ((Size) att_align(typlen, typalign)); + return ptr + nitems * ((Size) att_align_nominal(typlen, typalign)); /* seems worth having separate loops for NULL and no-NULLs cases */ if (nullbitmap) @@ -3712,8 +3712,8 @@ array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, { if (*nullbitmap & bitmask) { - ptr = att_addlength(ptr, typlen, PointerGetDatum(ptr)); - ptr = (char *) att_align(ptr, typalign); + ptr = att_addlength_pointer(ptr, typlen, ptr); + ptr = (char *) att_align_nominal(ptr, typalign); } bitmask <<= 1; if (bitmask == 0x100) @@ -3727,8 +3727,8 @@ array_seek(char *ptr, int offset, bits8 *nullbitmap, int nitems, { for (i = 0; i < nitems; i++) { - ptr = att_addlength(ptr, typlen, PointerGetDatum(ptr)); - ptr = (char *) att_align(ptr, typalign); + ptr = att_addlength_pointer(ptr, typlen, ptr); + ptr = (char *) att_align_nominal(ptr, typalign); } } return ptr; @@ -3883,7 +3883,7 @@ array_slice_size(char *arraydataptr, bits8 *arraynullsptr, /* Pretty easy for fixed element length without nulls ... */ if (typlen > 0 && !arraynullsptr) - return ArrayGetNItems(ndim, span) * att_align(typlen, typalign); + return ArrayGetNItems(ndim, span) * att_align_nominal(typlen, typalign); /* Else gotta do it the hard way */ src_offset = ArrayGetOffset(ndim, dim, lb, st); @@ -3904,8 +3904,8 @@ array_slice_size(char *arraydataptr, bits8 *arraynullsptr, } if (!array_get_isnull(arraynullsptr, src_offset)) { - inc = att_addlength(0, typlen, PointerGetDatum(ptr)); - inc = att_align(inc, typalign); + inc = att_addlength_pointer(0, typlen, ptr); + inc = att_align_nominal(inc, typalign); ptr += inc; count += inc; } diff --git a/src/backend/utils/adt/datum.c b/src/backend/utils/adt/datum.c index 21e7cc55412..c025de61f74 100644 --- a/src/backend/utils/adt/datum.c +++ b/src/backend/utils/adt/datum.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/datum.c,v 1.34 2007/02/27 23:48:07 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/datum.c,v 1.35 2007/04/06 04:21:42 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -47,7 +47,7 @@ * Find the "real" size of a datum, given the datum value, * whether it is a "by value", and the declared type length. * - * This is essentially an out-of-line version of the att_addlength() + * This is essentially an out-of-line version of the att_addlength_datum() * macro in access/tupmacs.h. We do a tad more error checking though. *------------------------------------------------------------------------- */ @@ -79,7 +79,7 @@ datumGetSize(Datum value, bool typByVal, int typLen) (errcode(ERRCODE_DATA_EXCEPTION), errmsg("invalid Datum pointer"))); - size = (Size) VARSIZE(s); + size = (Size) VARSIZE_ANY(s); } else if (typLen == -2) { diff --git a/src/backend/utils/adt/network.c b/src/backend/utils/adt/network.c index 88fa427450f..c1dadfbcc1b 100644 --- a/src/backend/utils/adt/network.c +++ b/src/backend/utils/adt/network.c @@ -1,7 +1,7 @@ /* * PostgreSQL type definitions for the INET and CIDR types. * - * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.68 2007/02/27 23:48:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/network.c,v 1.69 2007/04/06 04:21:43 tgl Exp $ * * Jon Postel RIP 16 Oct 1998 */ @@ -30,23 +30,38 @@ static int ip_addrsize(inet *inetptr); static inet *internal_inetpl(inet *ip, int64 addend); /* - * Access macros. + * Access macros. We use VARDATA_ANY so that we can process short-header + * varlena values without detoasting them. This requires a trick: + * VARDATA_ANY assumes the varlena header is already filled in, which is + * not the case when constructing a new value (until SET_INET_VARSIZE is + * called, which we typically can't do till the end). Therefore, we + * always initialize the newly-allocated value to zeroes (using palloc0). + * A zero length word will look like the not-1-byte case to VARDATA_ANY, + * and so we correctly construct an uncompressed value. + * + * Note that ip_maxbits() and SET_INET_VARSIZE() require + * the family field to be set correctly. */ #define ip_family(inetptr) \ - (((inet_struct *)VARDATA(inetptr))->family) + (((inet_struct *) VARDATA_ANY(inetptr))->family) #define ip_bits(inetptr) \ - (((inet_struct *)VARDATA(inetptr))->bits) + (((inet_struct *) VARDATA_ANY(inetptr))->bits) #define ip_addr(inetptr) \ - (((inet_struct *)VARDATA(inetptr))->ipaddr) + (((inet_struct *) VARDATA_ANY(inetptr))->ipaddr) #define ip_maxbits(inetptr) \ (ip_family(inetptr) == PGSQL_AF_INET ? 32 : 128) +#define SET_INET_VARSIZE(dst) \ + SET_VARSIZE(dst, VARHDRSZ + offsetof(inet_struct, ipaddr) + \ + ip_addrsize(dst)) + + /* - * Return the number of bytes of storage needed for this data type. + * Return the number of bytes of address storage needed for this data type. */ static int ip_addrsize(inet *inetptr) @@ -71,7 +86,7 @@ network_in(char *src, bool is_cidr) int bits; inet *dst; - dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + dst = (inet *) palloc0(sizeof(inet)); /* * First, check to see if this is an IPv6 or IPv4 address. IPv6 addresses @@ -105,10 +120,8 @@ network_in(char *src, bool is_cidr) errdetail("Value has bits set to right of mask."))); } - SET_VARSIZE(dst, VARHDRSZ + - ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + - ip_addrsize(dst)); ip_bits(dst) = bits; + SET_INET_VARSIZE(dst); return dst; } @@ -194,7 +207,7 @@ network_recv(StringInfo buf, bool is_cidr) i; /* make sure any unused bits in a CIDR value are zeroed */ - addr = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + addr = (inet *) palloc0(sizeof(inet)); ip_family(addr) = pq_getmsgbyte(buf); if (ip_family(addr) != PGSQL_AF_INET && @@ -220,9 +233,6 @@ network_recv(StringInfo buf, bool is_cidr) /* translator: %s is inet or cidr */ errmsg("invalid length in external \"%s\" value", is_cidr ? "cidr" : "inet"))); - SET_VARSIZE(addr, VARHDRSZ + - ((char *) ip_addr(addr) - (char *) VARDATA(addr)) + - ip_addrsize(addr)); addrptr = (char *) ip_addr(addr); for (i = 0; i < nb; i++) @@ -240,6 +250,8 @@ network_recv(StringInfo buf, bool is_cidr) errdetail("Value has bits set to right of mask."))); } + SET_INET_VARSIZE(addr); + return addr; } @@ -348,8 +360,8 @@ inet_to_cidr(PG_FUNCTION_ARGS) elog(ERROR, "invalid inet bit length: %d", bits); /* clone the original data */ - dst = (inet *) palloc(VARSIZE(src)); - memcpy(dst, src, VARSIZE(src)); + dst = (inet *) palloc(VARSIZE_ANY(src)); + memcpy(dst, src, VARSIZE_ANY(src)); /* zero out any bits to the right of the netmask */ byte = bits / 8; @@ -387,8 +399,8 @@ inet_set_masklen(PG_FUNCTION_ARGS) errmsg("invalid mask length: %d", bits))); /* clone the original data */ - dst = (inet *) palloc(VARSIZE(src)); - memcpy(dst, src, VARSIZE(src)); + dst = (inet *) palloc(VARSIZE_ANY(src)); + memcpy(dst, src, VARSIZE_ANY(src)); ip_bits(dst) = bits; @@ -414,8 +426,8 @@ cidr_set_masklen(PG_FUNCTION_ARGS) errmsg("invalid mask length: %d", bits))); /* clone the original data */ - dst = (inet *) palloc(VARSIZE(src)); - memcpy(dst, src, VARSIZE(src)); + dst = (inet *) palloc(VARSIZE_ANY(src)); + memcpy(dst, src, VARSIZE_ANY(src)); ip_bits(dst) = bits; @@ -546,7 +558,7 @@ hashinet(PG_FUNCTION_ARGS) int addrsize = ip_addrsize(addr); /* XXX this assumes there are no pad bytes in the data structure */ - return hash_any((unsigned char *) VARDATA(addr), addrsize + 2); + return hash_any((unsigned char *) VARDATA_ANY(addr), addrsize + 2); } /* @@ -762,7 +774,7 @@ network_broadcast(PG_FUNCTION_ARGS) *b; /* make sure any unused bits are zeroed */ - dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + dst = (inet *) palloc0(sizeof(inet)); if (ip_family(ip) == PGSQL_AF_INET) maxbytes = 4; @@ -793,9 +805,7 @@ network_broadcast(PG_FUNCTION_ARGS) ip_family(dst) = ip_family(ip); ip_bits(dst) = ip_bits(ip); - SET_VARSIZE(dst, VARHDRSZ + - ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + - ip_addrsize(dst)); + SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } @@ -812,7 +822,7 @@ network_network(PG_FUNCTION_ARGS) *b; /* make sure any unused bits are zeroed */ - dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + dst = (inet *) palloc0(sizeof(inet)); bits = ip_bits(ip); a = ip_addr(ip); @@ -838,9 +848,7 @@ network_network(PG_FUNCTION_ARGS) ip_family(dst) = ip_family(ip); ip_bits(dst) = ip_bits(ip); - SET_VARSIZE(dst, VARHDRSZ + - ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + - ip_addrsize(dst)); + SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } @@ -856,7 +864,7 @@ network_netmask(PG_FUNCTION_ARGS) unsigned char *b; /* make sure any unused bits are zeroed */ - dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + dst = (inet *) palloc0(sizeof(inet)); bits = ip_bits(ip); b = ip_addr(dst); @@ -881,9 +889,7 @@ network_netmask(PG_FUNCTION_ARGS) ip_family(dst) = ip_family(ip); ip_bits(dst) = ip_maxbits(ip); - SET_VARSIZE(dst, VARHDRSZ + - ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + - ip_addrsize(dst)); + SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } @@ -900,7 +906,7 @@ network_hostmask(PG_FUNCTION_ARGS) unsigned char *b; /* make sure any unused bits are zeroed */ - dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + dst = (inet *) palloc0(sizeof(inet)); if (ip_family(ip) == PGSQL_AF_INET) maxbytes = 4; @@ -930,9 +936,7 @@ network_hostmask(PG_FUNCTION_ARGS) ip_family(dst) = ip_family(ip); ip_bits(dst) = ip_maxbits(ip); - SET_VARSIZE(dst, VARHDRSZ + - ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + - ip_addrsize(dst)); + SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } @@ -1259,7 +1263,7 @@ inetnot(PG_FUNCTION_ARGS) inet *ip = PG_GETARG_INET_P(0); inet *dst; - dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + dst = (inet *) palloc0(sizeof(inet)); { int nb = ip_addrsize(ip); @@ -1272,9 +1276,7 @@ inetnot(PG_FUNCTION_ARGS) ip_bits(dst) = ip_bits(ip); ip_family(dst) = ip_family(ip); - SET_VARSIZE(dst, VARHDRSZ + - ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + - ip_addrsize(dst)); + SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } @@ -1287,7 +1289,7 @@ inetand(PG_FUNCTION_ARGS) inet *ip2 = PG_GETARG_INET_P(1); inet *dst; - dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + dst = (inet *) palloc0(sizeof(inet)); if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, @@ -1306,9 +1308,7 @@ inetand(PG_FUNCTION_ARGS) ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2)); ip_family(dst) = ip_family(ip); - SET_VARSIZE(dst, VARHDRSZ + - ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + - ip_addrsize(dst)); + SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } @@ -1321,7 +1321,7 @@ inetor(PG_FUNCTION_ARGS) inet *ip2 = PG_GETARG_INET_P(1); inet *dst; - dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + dst = (inet *) palloc0(sizeof(inet)); if (ip_family(ip) != ip_family(ip2)) ereport(ERROR, @@ -1340,9 +1340,7 @@ inetor(PG_FUNCTION_ARGS) ip_bits(dst) = Max(ip_bits(ip), ip_bits(ip2)); ip_family(dst) = ip_family(ip); - SET_VARSIZE(dst, VARHDRSZ + - ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + - ip_addrsize(dst)); + SET_INET_VARSIZE(dst); PG_RETURN_INET_P(dst); } @@ -1353,7 +1351,7 @@ internal_inetpl(inet *ip, int64 addend) { inet *dst; - dst = (inet *) palloc0(VARHDRSZ + sizeof(inet_struct)); + dst = (inet *) palloc0(sizeof(inet)); { int nb = ip_addrsize(ip); @@ -1391,12 +1389,10 @@ internal_inetpl(inet *ip, int64 addend) (errcode(ERRCODE_NUMERIC_VALUE_OUT_OF_RANGE), errmsg("result is out of range"))); } - ip_bits(dst) = ip_bits(ip); + ip_bits(dst) = ip_bits(ip); ip_family(dst) = ip_family(ip); - SET_VARSIZE(dst, VARHDRSZ + - ((char *) ip_addr(dst) - (char *) VARDATA(dst)) + - ip_addrsize(dst)); + SET_INET_VARSIZE(dst); return dst; } diff --git a/src/backend/utils/adt/pg_lzcompress.c b/src/backend/utils/adt/pg_lzcompress.c index c756e5707a5..085bc63e0dd 100644 --- a/src/backend/utils/adt/pg_lzcompress.c +++ b/src/backend/utils/adt/pg_lzcompress.c @@ -166,7 +166,7 @@ * * Copyright (c) 1999-2007, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.25 2007/02/27 23:48:08 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/pg_lzcompress.c,v 1.26 2007/04/06 04:21:43 tgl Exp $ * ---------- */ #include "postgres.h" @@ -618,7 +618,7 @@ pglz_compress(const char *source, int32 slen, PGLZ_Header *dest, /* * Success - need only fill in the actual length of the compressed datum. */ - SET_VARSIZE(dest, result_size + sizeof(PGLZ_Header)); + SET_VARSIZE_COMPRESSED(dest, result_size + sizeof(PGLZ_Header)); return true; } diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c index 371a8a605d6..77a6ab9c4fc 100644 --- a/src/backend/utils/adt/varchar.c +++ b/src/backend/utils/adt/varchar.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.122 2007/02/27 23:48:09 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/varchar.c,v 1.123 2007/04/06 04:21:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -16,6 +16,7 @@ #include "access/hash.h" +#include "access/tuptoaster.h" #include "libpq/pqformat.h" #include "utils/array.h" #include "utils/builtins.h" @@ -206,14 +207,14 @@ bpcharin(PG_FUNCTION_ARGS) Datum bpcharout(PG_FUNCTION_ARGS) { - BpChar *s = PG_GETARG_BPCHAR_P(0); + BpChar *s = PG_GETARG_BPCHAR_PP(0); char *result; int len; /* copy and add null term */ - len = VARSIZE(s) - VARHDRSZ; + len = VARSIZE_ANY_EXHDR(s); result = (char *) palloc(len + 1); - memcpy(result, VARDATA(s), len); + memcpy(result, VARDATA_ANY(s), len); result[len] = '\0'; PG_RETURN_CSTRING(result); @@ -267,7 +268,7 @@ bpcharsend(PG_FUNCTION_ARGS) Datum bpchar(PG_FUNCTION_ARGS) { - BpChar *source = PG_GETARG_BPCHAR_P(0); + BpChar *source = PG_GETARG_BPCHAR_PP(0); int32 maxlen = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); BpChar *result; @@ -282,9 +283,12 @@ bpchar(PG_FUNCTION_ARGS) if (maxlen < (int32) VARHDRSZ) PG_RETURN_BPCHAR_P(source); - len = VARSIZE(source); + maxlen -= VARHDRSZ; - charlen = pg_mbstrlen_with_len(VARDATA(source), len - VARHDRSZ) + VARHDRSZ; + len = VARSIZE_ANY_EXHDR(source); + s = VARDATA_ANY(source); + + charlen = pg_mbstrlen_with_len(s, len); /* No work if supplied data matches typmod already */ if (charlen == maxlen) @@ -295,23 +299,22 @@ bpchar(PG_FUNCTION_ARGS) /* Verify that extra characters are spaces, and clip them off */ size_t maxmblen; - maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ, - maxlen - VARHDRSZ) + VARHDRSZ; + maxmblen = pg_mbcharcliplen(s, len, maxlen); if (!isExplicit) { - for (i = maxmblen - VARHDRSZ; i < len - VARHDRSZ; i++) - if (*(VARDATA(source) + i) != ' ') + for (i = maxmblen; i < len; i++) + if (s[i] != ' ') ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), errmsg("value too long for type character(%d)", - maxlen - VARHDRSZ))); + maxlen))); } len = maxmblen; /* - * XXX: at this point, maxlen is the necessary byte length+VARHDRSZ, + * At this point, maxlen is the necessary byte length, * not the number of CHARACTERS! */ maxlen = len; @@ -319,23 +322,23 @@ bpchar(PG_FUNCTION_ARGS) else { /* - * XXX: at this point, maxlen is the necessary byte length+VARHDRSZ, + * At this point, maxlen is the necessary byte length, * not the number of CHARACTERS! */ maxlen = len + (maxlen - charlen); } - s = VARDATA(source); + Assert(maxlen >= len); - result = palloc(maxlen); - SET_VARSIZE(result, maxlen); + result = palloc(maxlen+VARHDRSZ); + SET_VARSIZE(result, maxlen+VARHDRSZ); r = VARDATA(result); - memcpy(r, s, len - VARHDRSZ); + memcpy(r, s, len); /* blank pad the string if necessary */ if (maxlen > len) - memset(r + len - VARHDRSZ, ' ', maxlen - len); + memset(r + len, ' ', maxlen - len); PG_RETURN_BPCHAR_P(result); } @@ -365,11 +368,13 @@ char_bpchar(PG_FUNCTION_ARGS) Datum bpchar_name(PG_FUNCTION_ARGS) { - BpChar *s = PG_GETARG_BPCHAR_P(0); + BpChar *s = PG_GETARG_BPCHAR_PP(0); + char *s_data; Name result; int len; - len = VARSIZE(s) - VARHDRSZ; + len = VARSIZE_ANY_EXHDR(s); + s_data = VARDATA_ANY(s); /* Truncate to max length for a Name */ if (len >= NAMEDATALEN) @@ -378,13 +383,13 @@ bpchar_name(PG_FUNCTION_ARGS) /* Remove trailing blanks */ while (len > 0) { - if (*(VARDATA(s) + len - 1) != ' ') + if (s_data[len - 1] != ' ') break; len--; } result = (NameData *) palloc(NAMEDATALEN); - memcpy(NameStr(*result), VARDATA(s), len); + memcpy(NameStr(*result), s_data, len); /* Now null pad to full length... */ while (len < NAMEDATALEN) @@ -509,14 +514,14 @@ varcharin(PG_FUNCTION_ARGS) Datum varcharout(PG_FUNCTION_ARGS) { - VarChar *s = PG_GETARG_VARCHAR_P(0); + VarChar *s = PG_GETARG_VARCHAR_PP(0); char *result; int32 len; /* copy and add null term */ - len = VARSIZE(s) - VARHDRSZ; + len = VARSIZE_ANY_EXHDR(s); result = palloc(len + 1); - memcpy(result, VARDATA(s), len); + memcpy(result, VARDATA_ANY(s), len); result[len] = '\0'; PG_RETURN_CSTRING(result); @@ -570,39 +575,41 @@ varcharsend(PG_FUNCTION_ARGS) Datum varchar(PG_FUNCTION_ARGS) { - VarChar *source = PG_GETARG_VARCHAR_P(0); - int32 maxlen = PG_GETARG_INT32(1); + VarChar *source = PG_GETARG_VARCHAR_PP(0); + int32 typmod = PG_GETARG_INT32(1); bool isExplicit = PG_GETARG_BOOL(2); VarChar *result; - int32 len; + int32 len, maxlen; size_t maxmblen; int i; + char *s_data; + + len = VARSIZE_ANY_EXHDR(source); + s_data = VARDATA_ANY(source); + maxlen = typmod - VARHDRSZ; - len = VARSIZE(source); /* No work if typmod is invalid or supplied data fits it already */ - if (maxlen < (int32) VARHDRSZ || len <= maxlen) + if (maxlen < 0 || len <= maxlen) PG_RETURN_VARCHAR_P(source); /* only reach here if string is too long... */ /* truncate multibyte string preserving multibyte boundary */ - maxmblen = pg_mbcharcliplen(VARDATA(source), len - VARHDRSZ, - maxlen - VARHDRSZ); + maxmblen = pg_mbcharcliplen(s_data, len, maxlen); if (!isExplicit) { - for (i = maxmblen; i < len - VARHDRSZ; i++) - if (*(VARDATA(source) + i) != ' ') + for (i = maxmblen; i < len; i++) + if (s_data[i] != ' ') ereport(ERROR, (errcode(ERRCODE_STRING_DATA_RIGHT_TRUNCATION), - errmsg("value too long for type character varying(%d)", - maxlen - VARHDRSZ))); + errmsg("value too long for type character varying(%d)", + maxlen))); } - len = maxmblen + VARHDRSZ; - result = palloc(len); - SET_VARSIZE(result, len); - memcpy(VARDATA(result), VARDATA(source), len - VARHDRSZ); + result = palloc(maxmblen + VARHDRSZ); + SET_VARSIZE(result, maxmblen + VARHDRSZ); + memcpy(VARDATA(result), s_data, maxmblen); PG_RETURN_VARCHAR_P(result); } @@ -632,11 +639,11 @@ varchartypmodout(PG_FUNCTION_ARGS) static int bcTruelen(BpChar *arg) { - char *s = VARDATA(arg); + char *s = VARDATA_ANY(arg); int i; int len; - len = VARSIZE(arg) - VARHDRSZ; + len = VARSIZE_ANY_EXHDR(arg); for (i = len - 1; i >= 0; i--) { if (s[i] != ' ') @@ -648,7 +655,7 @@ bcTruelen(BpChar *arg) Datum bpcharlen(PG_FUNCTION_ARGS) { - BpChar *arg = PG_GETARG_BPCHAR_P(0); + BpChar *arg = PG_GETARG_BPCHAR_PP(0); int len; /* get number of bytes, ignoring trailing spaces */ @@ -656,7 +663,7 @@ bpcharlen(PG_FUNCTION_ARGS) /* in multibyte encoding, convert to number of characters */ if (pg_database_encoding_max_length() != 1) - len = pg_mbstrlen_with_len(VARDATA(arg), len); + len = pg_mbstrlen_with_len(VARDATA_ANY(arg), len); PG_RETURN_INT32(len); } @@ -664,9 +671,10 @@ bpcharlen(PG_FUNCTION_ARGS) Datum bpcharoctetlen(PG_FUNCTION_ARGS) { - BpChar *arg = PG_GETARG_BPCHAR_P(0); + Datum arg = PG_GETARG_DATUM(0); - PG_RETURN_INT32(VARSIZE(arg) - VARHDRSZ); + /* We need not detoast the input at all */ + PG_RETURN_INT32(toast_raw_datum_size(arg) - VARHDRSZ); } @@ -681,8 +689,8 @@ bpcharoctetlen(PG_FUNCTION_ARGS) Datum bpchareq(PG_FUNCTION_ARGS) { - BpChar *arg1 = PG_GETARG_BPCHAR_P(0); - BpChar *arg2 = PG_GETARG_BPCHAR_P(1); + BpChar *arg1 = PG_GETARG_BPCHAR_PP(0); + BpChar *arg2 = PG_GETARG_BPCHAR_PP(1); int len1, len2; bool result; @@ -697,7 +705,7 @@ bpchareq(PG_FUNCTION_ARGS) if (len1 != len2) result = false; else - result = (strncmp(VARDATA(arg1), VARDATA(arg2), len1) == 0); + result = (strncmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) == 0); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -708,8 +716,8 @@ bpchareq(PG_FUNCTION_ARGS) Datum bpcharne(PG_FUNCTION_ARGS) { - BpChar *arg1 = PG_GETARG_BPCHAR_P(0); - BpChar *arg2 = PG_GETARG_BPCHAR_P(1); + BpChar *arg1 = PG_GETARG_BPCHAR_PP(0); + BpChar *arg2 = PG_GETARG_BPCHAR_PP(1); int len1, len2; bool result; @@ -724,7 +732,7 @@ bpcharne(PG_FUNCTION_ARGS) if (len1 != len2) result = true; else - result = (strncmp(VARDATA(arg1), VARDATA(arg2), len1) != 0); + result = (strncmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) != 0); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -735,8 +743,8 @@ bpcharne(PG_FUNCTION_ARGS) Datum bpcharlt(PG_FUNCTION_ARGS) { - BpChar *arg1 = PG_GETARG_BPCHAR_P(0); - BpChar *arg2 = PG_GETARG_BPCHAR_P(1); + BpChar *arg1 = PG_GETARG_BPCHAR_PP(0); + BpChar *arg2 = PG_GETARG_BPCHAR_PP(1); int len1, len2; int cmp; @@ -744,7 +752,7 @@ bpcharlt(PG_FUNCTION_ARGS) len1 = bcTruelen(arg1); len2 = bcTruelen(arg2); - cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2); + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -755,8 +763,8 @@ bpcharlt(PG_FUNCTION_ARGS) Datum bpcharle(PG_FUNCTION_ARGS) { - BpChar *arg1 = PG_GETARG_BPCHAR_P(0); - BpChar *arg2 = PG_GETARG_BPCHAR_P(1); + BpChar *arg1 = PG_GETARG_BPCHAR_PP(0); + BpChar *arg2 = PG_GETARG_BPCHAR_PP(1); int len1, len2; int cmp; @@ -764,7 +772,7 @@ bpcharle(PG_FUNCTION_ARGS) len1 = bcTruelen(arg1); len2 = bcTruelen(arg2); - cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2); + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -775,8 +783,8 @@ bpcharle(PG_FUNCTION_ARGS) Datum bpchargt(PG_FUNCTION_ARGS) { - BpChar *arg1 = PG_GETARG_BPCHAR_P(0); - BpChar *arg2 = PG_GETARG_BPCHAR_P(1); + BpChar *arg1 = PG_GETARG_BPCHAR_PP(0); + BpChar *arg2 = PG_GETARG_BPCHAR_PP(1); int len1, len2; int cmp; @@ -784,7 +792,7 @@ bpchargt(PG_FUNCTION_ARGS) len1 = bcTruelen(arg1); len2 = bcTruelen(arg2); - cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2); + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -795,8 +803,8 @@ bpchargt(PG_FUNCTION_ARGS) Datum bpcharge(PG_FUNCTION_ARGS) { - BpChar *arg1 = PG_GETARG_BPCHAR_P(0); - BpChar *arg2 = PG_GETARG_BPCHAR_P(1); + BpChar *arg1 = PG_GETARG_BPCHAR_PP(0); + BpChar *arg2 = PG_GETARG_BPCHAR_PP(1); int len1, len2; int cmp; @@ -804,7 +812,7 @@ bpcharge(PG_FUNCTION_ARGS) len1 = bcTruelen(arg1); len2 = bcTruelen(arg2); - cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2); + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -815,8 +823,8 @@ bpcharge(PG_FUNCTION_ARGS) Datum bpcharcmp(PG_FUNCTION_ARGS) { - BpChar *arg1 = PG_GETARG_BPCHAR_P(0); - BpChar *arg2 = PG_GETARG_BPCHAR_P(1); + BpChar *arg1 = PG_GETARG_BPCHAR_PP(0); + BpChar *arg2 = PG_GETARG_BPCHAR_PP(1); int len1, len2; int cmp; @@ -824,7 +832,7 @@ bpcharcmp(PG_FUNCTION_ARGS) len1 = bcTruelen(arg1); len2 = bcTruelen(arg2); - cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2); + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -835,8 +843,8 @@ bpcharcmp(PG_FUNCTION_ARGS) Datum bpchar_larger(PG_FUNCTION_ARGS) { - BpChar *arg1 = PG_GETARG_BPCHAR_P(0); - BpChar *arg2 = PG_GETARG_BPCHAR_P(1); + BpChar *arg1 = PG_GETARG_BPCHAR_PP(0); + BpChar *arg2 = PG_GETARG_BPCHAR_PP(1); int len1, len2; int cmp; @@ -844,7 +852,7 @@ bpchar_larger(PG_FUNCTION_ARGS) len1 = bcTruelen(arg1); len2 = bcTruelen(arg2); - cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2); + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2); PG_RETURN_BPCHAR_P((cmp >= 0) ? arg1 : arg2); } @@ -852,8 +860,8 @@ bpchar_larger(PG_FUNCTION_ARGS) Datum bpchar_smaller(PG_FUNCTION_ARGS) { - BpChar *arg1 = PG_GETARG_BPCHAR_P(0); - BpChar *arg2 = PG_GETARG_BPCHAR_P(1); + BpChar *arg1 = PG_GETARG_BPCHAR_PP(0); + BpChar *arg2 = PG_GETARG_BPCHAR_PP(1); int len1, len2; int cmp; @@ -861,7 +869,7 @@ bpchar_smaller(PG_FUNCTION_ARGS) len1 = bcTruelen(arg1); len2 = bcTruelen(arg2); - cmp = varstr_cmp(VARDATA(arg1), len1, VARDATA(arg2), len2); + cmp = varstr_cmp(VARDATA_ANY(arg1), len1, VARDATA_ANY(arg2), len2); PG_RETURN_BPCHAR_P((cmp <= 0) ? arg1 : arg2); } @@ -878,12 +886,12 @@ bpchar_smaller(PG_FUNCTION_ARGS) Datum hashbpchar(PG_FUNCTION_ARGS) { - BpChar *key = PG_GETARG_BPCHAR_P(0); + BpChar *key = PG_GETARG_BPCHAR_PP(0); char *keydata; int keylen; Datum result; - keydata = VARDATA(key); + keydata = VARDATA_ANY(key); keylen = bcTruelen(key); result = hash_any((unsigned char *) keydata, keylen); diff --git a/src/backend/utils/adt/varlena.c b/src/backend/utils/adt/varlena.c index 51130efd79b..0b5b4fd16a4 100644 --- a/src/backend/utils/adt/varlena.c +++ b/src/backend/utils/adt/varlena.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.155 2007/02/27 23:48:09 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/varlena.c,v 1.156 2007/04/06 04:21:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -175,7 +175,7 @@ byteain(PG_FUNCTION_ARGS) Datum byteaout(PG_FUNCTION_ARGS) { - bytea *vlena = PG_GETARG_BYTEA_P(0); + bytea *vlena = PG_GETARG_BYTEA_PP(0); char *result; char *vp; char *rp; @@ -184,8 +184,8 @@ byteaout(PG_FUNCTION_ARGS) int len; len = 1; /* empty string has 1 char */ - vp = VARDATA(vlena); - for (i = VARSIZE(vlena) - VARHDRSZ; i != 0; i--, vp++) + vp = VARDATA_ANY(vlena); + for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++) { if (*vp == '\\') len += 2; @@ -195,8 +195,8 @@ byteaout(PG_FUNCTION_ARGS) len++; } rp = result = (char *) palloc(len); - vp = VARDATA(vlena); - for (i = VARSIZE(vlena) - VARHDRSZ; i != 0; i--, vp++) + vp = VARDATA_ANY(vlena); + for (i = VARSIZE_ANY_EXHDR(vlena); i != 0; i--, vp++) { if (*vp == '\\') { @@ -277,13 +277,13 @@ textin(PG_FUNCTION_ARGS) Datum textout(PG_FUNCTION_ARGS) { - text *t = PG_GETARG_TEXT_P(0); + text *t = PG_GETARG_TEXT_PP(0); int len; char *result; - len = VARSIZE(t) - VARHDRSZ; + len = VARSIZE_ANY_EXHDR(t); result = (char *) palloc(len + 1); - memcpy(result, VARDATA(t), len); + memcpy(result, VARDATA_ANY(t), len); result[len] = '\0'; PG_RETURN_CSTRING(result); @@ -315,11 +315,11 @@ textrecv(PG_FUNCTION_ARGS) Datum textsend(PG_FUNCTION_ARGS) { - text *t = PG_GETARG_TEXT_P(0); + text *t = PG_GETARG_TEXT_PP(0); StringInfoData buf; pq_begintypsend(&buf); - pq_sendtext(&buf, VARDATA(t), VARSIZE(t) - VARHDRSZ); + pq_sendtext(&buf, VARDATA_ANY(t), VARSIZE_ANY_EXHDR(t)); PG_RETURN_BYTEA_P(pq_endtypsend(&buf)); } @@ -412,10 +412,10 @@ text_length(Datum str) PG_RETURN_INT32(toast_raw_datum_size(str) - VARHDRSZ); else { - text *t = DatumGetTextP(str); + text *t = DatumGetTextPP(str); - PG_RETURN_INT32(pg_mbstrlen_with_len(VARDATA(t), - VARSIZE(t) - VARHDRSZ)); + PG_RETURN_INT32(pg_mbstrlen_with_len(VARDATA_ANY(t), + VARSIZE_ANY_EXHDR(t))); } } @@ -446,19 +446,19 @@ textoctetlen(PG_FUNCTION_ARGS) Datum textcat(PG_FUNCTION_ARGS) { - text *t1 = PG_GETARG_TEXT_P(0); - text *t2 = PG_GETARG_TEXT_P(1); + text *t1 = PG_GETARG_TEXT_PP(0); + text *t2 = PG_GETARG_TEXT_PP(1); int len1, len2, len; text *result; char *ptr; - len1 = VARSIZE(t1) - VARHDRSZ; + len1 = VARSIZE_ANY_EXHDR(t1); if (len1 < 0) len1 = 0; - len2 = VARSIZE(t2) - VARHDRSZ; + len2 = VARSIZE_ANY_EXHDR(t2); if (len2 < 0) len2 = 0; @@ -471,9 +471,9 @@ textcat(PG_FUNCTION_ARGS) /* Fill data field of result string... */ ptr = VARDATA(result); if (len1 > 0) - memcpy(ptr, VARDATA(t1), len1); + memcpy(ptr, VARDATA_ANY(t1), len1); if (len2 > 0) - memcpy(ptr + len1, VARDATA(t2), len2); + memcpy(ptr + len1, VARDATA_ANY(t2), len2); PG_RETURN_TEXT_P(result); } @@ -1058,12 +1058,12 @@ text_cmp(text *arg1, text *arg2) int len1, len2; - a1p = VARDATA(arg1); - a2p = VARDATA(arg2); - - len1 = VARSIZE(arg1) - VARHDRSZ; - len2 = VARSIZE(arg2) - VARHDRSZ; + a1p = VARDATA_ANY(arg1); + a2p = VARDATA_ANY(arg2); + len1 = VARSIZE_ANY_EXHDR(arg1); + len2 = VARSIZE_ANY_EXHDR(arg2); + return varstr_cmp(a1p, len1, a2p, len2); } @@ -1078,19 +1078,19 @@ text_cmp(text *arg1, text *arg2) Datum texteq(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); bool result; /* * Since we only care about equality or not-equality, we can avoid all the * expense of strcoll() here, and just do bitwise comparison. */ - if (VARSIZE(arg1) != VARSIZE(arg2)) + if (VARSIZE_ANY_EXHDR(arg1) != VARSIZE_ANY_EXHDR(arg2)) result = false; else - result = (strncmp(VARDATA(arg1), VARDATA(arg2), - VARSIZE(arg1) - VARHDRSZ) == 0); + result = (strncmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), + VARSIZE_ANY_EXHDR(arg1)) == 0); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -1101,19 +1101,19 @@ texteq(PG_FUNCTION_ARGS) Datum textne(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); bool result; /* * Since we only care about equality or not-equality, we can avoid all the * expense of strcoll() here, and just do bitwise comparison. */ - if (VARSIZE(arg1) != VARSIZE(arg2)) + if (VARSIZE_ANY_EXHDR(arg1) != VARSIZE_ANY_EXHDR(arg2)) result = true; else - result = (strncmp(VARDATA(arg1), VARDATA(arg2), - VARSIZE(arg1) - VARHDRSZ) != 0); + result = (strncmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), + VARSIZE_ANY_EXHDR(arg1)) != 0); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -1124,8 +1124,8 @@ textne(PG_FUNCTION_ARGS) Datum text_lt(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); bool result; result = (text_cmp(arg1, arg2) < 0); @@ -1139,8 +1139,8 @@ text_lt(PG_FUNCTION_ARGS) Datum text_le(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); bool result; result = (text_cmp(arg1, arg2) <= 0); @@ -1154,8 +1154,8 @@ text_le(PG_FUNCTION_ARGS) Datum text_gt(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); bool result; result = (text_cmp(arg1, arg2) > 0); @@ -1169,8 +1169,8 @@ text_gt(PG_FUNCTION_ARGS) Datum text_ge(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); bool result; result = (text_cmp(arg1, arg2) >= 0); @@ -1184,8 +1184,8 @@ text_ge(PG_FUNCTION_ARGS) Datum bttextcmp(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); int32 result; result = text_cmp(arg1, arg2); @@ -1200,8 +1200,8 @@ bttextcmp(PG_FUNCTION_ARGS) Datum text_larger(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); text *result; result = ((text_cmp(arg1, arg2) > 0) ? arg1 : arg2); @@ -1212,8 +1212,8 @@ text_larger(PG_FUNCTION_ARGS) Datum text_smaller(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); text *result; result = ((text_cmp(arg1, arg2) < 0) ? arg1 : arg2); @@ -1233,13 +1233,13 @@ internal_text_pattern_compare(text *arg1, text *arg2) { int result; - result = memcmp(VARDATA(arg1), VARDATA(arg2), - Min(VARSIZE(arg1), VARSIZE(arg2)) - VARHDRSZ); + result = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), + Min(VARSIZE_ANY_EXHDR(arg1), VARSIZE_ANY_EXHDR(arg2))); if (result != 0) return result; - else if (VARSIZE(arg1) < VARSIZE(arg2)) + else if (VARSIZE_ANY_EXHDR(arg1) < VARSIZE_ANY_EXHDR(arg2)) return -1; - else if (VARSIZE(arg1) > VARSIZE(arg2)) + else if (VARSIZE_ANY_EXHDR(arg1) > VARSIZE_ANY_EXHDR(arg2)) return 1; else return 0; @@ -1249,8 +1249,8 @@ internal_text_pattern_compare(text *arg1, text *arg2) Datum text_pattern_lt(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); int result; result = internal_text_pattern_compare(arg1, arg2); @@ -1265,8 +1265,8 @@ text_pattern_lt(PG_FUNCTION_ARGS) Datum text_pattern_le(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); int result; result = internal_text_pattern_compare(arg1, arg2); @@ -1281,11 +1281,11 @@ text_pattern_le(PG_FUNCTION_ARGS) Datum text_pattern_eq(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); int result; - if (VARSIZE(arg1) != VARSIZE(arg2)) + if (VARSIZE_ANY_EXHDR(arg1) != VARSIZE_ANY_EXHDR(arg2)) result = 1; else result = internal_text_pattern_compare(arg1, arg2); @@ -1300,8 +1300,8 @@ text_pattern_eq(PG_FUNCTION_ARGS) Datum text_pattern_ge(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); int result; result = internal_text_pattern_compare(arg1, arg2); @@ -1316,8 +1316,8 @@ text_pattern_ge(PG_FUNCTION_ARGS) Datum text_pattern_gt(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); int result; result = internal_text_pattern_compare(arg1, arg2); @@ -1332,11 +1332,11 @@ text_pattern_gt(PG_FUNCTION_ARGS) Datum text_pattern_ne(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); int result; - if (VARSIZE(arg1) != VARSIZE(arg2)) + if (VARSIZE_ANY_EXHDR(arg1) != VARSIZE_ANY_EXHDR(arg2)) result = 1; else result = internal_text_pattern_compare(arg1, arg2); @@ -1351,8 +1351,8 @@ text_pattern_ne(PG_FUNCTION_ARGS) Datum bttext_pattern_cmp(PG_FUNCTION_ARGS) { - text *arg1 = PG_GETARG_TEXT_P(0); - text *arg2 = PG_GETARG_TEXT_P(1); + text *arg1 = PG_GETARG_TEXT_PP(0); + text *arg2 = PG_GETARG_TEXT_PP(1); int result; result = internal_text_pattern_compare(arg1, arg2); @@ -1389,19 +1389,19 @@ byteaoctetlen(PG_FUNCTION_ARGS) Datum byteacat(PG_FUNCTION_ARGS) { - bytea *t1 = PG_GETARG_BYTEA_P(0); - bytea *t2 = PG_GETARG_BYTEA_P(1); + bytea *t1 = PG_GETARG_BYTEA_PP(0); + bytea *t2 = PG_GETARG_BYTEA_PP(1); int len1, len2, len; bytea *result; char *ptr; - len1 = VARSIZE(t1) - VARHDRSZ; + len1 = VARSIZE_ANY_EXHDR(t1); if (len1 < 0) len1 = 0; - len2 = VARSIZE(t2) - VARHDRSZ; + len2 = VARSIZE_ANY_EXHDR(t2); if (len2 < 0) len2 = 0; @@ -1414,9 +1414,9 @@ byteacat(PG_FUNCTION_ARGS) /* Fill data field of result string... */ ptr = VARDATA(result); if (len1 > 0) - memcpy(ptr, VARDATA(t1), len1); + memcpy(ptr, VARDATA_ANY(t1), len1); if (len2 > 0) - memcpy(ptr + len1, VARDATA(t2), len2); + memcpy(ptr + len1, VARDATA_ANY(t2), len2); PG_RETURN_BYTEA_P(result); } @@ -1509,8 +1509,8 @@ bytea_substr_no_len(PG_FUNCTION_ARGS) Datum byteapos(PG_FUNCTION_ARGS) { - bytea *t1 = PG_GETARG_BYTEA_P(0); - bytea *t2 = PG_GETARG_BYTEA_P(1); + bytea *t1 = PG_GETARG_BYTEA_PP(0); + bytea *t2 = PG_GETARG_BYTEA_PP(1); int pos; int px, p; @@ -1519,14 +1519,14 @@ byteapos(PG_FUNCTION_ARGS) char *p1, *p2; - if (VARSIZE(t2) <= VARHDRSZ) - PG_RETURN_INT32(1); /* result for empty pattern */ + len1 = VARSIZE_ANY_EXHDR(t1); + len2 = VARSIZE_ANY_EXHDR(t2); - len1 = VARSIZE(t1) - VARHDRSZ; - len2 = VARSIZE(t2) - VARHDRSZ; + if (len2 <= 0) + PG_RETURN_INT32(1); /* result for empty pattern */ - p1 = VARDATA(t1); - p2 = VARDATA(t2); + p1 = VARDATA_ANY(t1); + p2 = VARDATA_ANY(t2); pos = 0; px = (len1 - len2); @@ -1553,12 +1553,12 @@ byteapos(PG_FUNCTION_ARGS) Datum byteaGetByte(PG_FUNCTION_ARGS) { - bytea *v = PG_GETARG_BYTEA_P(0); + bytea *v = PG_GETARG_BYTEA_PP(0); int32 n = PG_GETARG_INT32(1); int len; int byte; - len = VARSIZE(v) - VARHDRSZ; + len = VARSIZE_ANY_EXHDR(v); if (n < 0 || n >= len) ereport(ERROR, @@ -1566,7 +1566,7 @@ byteaGetByte(PG_FUNCTION_ARGS) errmsg("index %d out of valid range, 0..%d", n, len - 1))); - byte = ((unsigned char *) VARDATA(v))[n]; + byte = ((unsigned char *) VARDATA_ANY(v))[n]; PG_RETURN_INT32(byte); } @@ -1582,14 +1582,14 @@ byteaGetByte(PG_FUNCTION_ARGS) Datum byteaGetBit(PG_FUNCTION_ARGS) { - bytea *v = PG_GETARG_BYTEA_P(0); + bytea *v = PG_GETARG_BYTEA_PP(0); int32 n = PG_GETARG_INT32(1); int byteNo, bitNo; int len; int byte; - len = VARSIZE(v) - VARHDRSZ; + len = VARSIZE_ANY_EXHDR(v); if (n < 0 || n >= len * 8) ereport(ERROR, @@ -1600,7 +1600,7 @@ byteaGetBit(PG_FUNCTION_ARGS) byteNo = n / 8; bitNo = n % 8; - byte = ((unsigned char *) VARDATA(v))[byteNo]; + byte = ((unsigned char *) VARDATA_ANY(v))[byteNo]; if (byte & (1 << bitNo)) PG_RETURN_INT32(1); @@ -1715,23 +1715,18 @@ byteaSetBit(PG_FUNCTION_ARGS) Datum text_name(PG_FUNCTION_ARGS) { - text *s = PG_GETARG_TEXT_P(0); + text *s = PG_GETARG_TEXT_PP(0); Name result; int len; - len = VARSIZE(s) - VARHDRSZ; + len = VARSIZE_ANY_EXHDR(s); /* Truncate oversize input */ if (len >= NAMEDATALEN) len = NAMEDATALEN - 1; -#ifdef STRINGDEBUG - printf("text- convert string length %d (%d) ->%d\n", - VARSIZE(s) - VARHDRSZ, VARSIZE(s), len); -#endif - result = (Name) palloc(NAMEDATALEN); - memcpy(NameStr(*result), VARDATA(s), len); + memcpy(NameStr(*result), VARDATA_ANY(s), len); /* now null pad to full length... */ while (len < NAMEDATALEN) @@ -1755,11 +1750,6 @@ name_text(PG_FUNCTION_ARGS) len = strlen(NameStr(*s)); -#ifdef STRINGDEBUG - printf("text- convert string length %d (%d) ->%d\n", - VARSIZE(s) - VARHDRSZ, VARSIZE(s), len); -#endif - result = palloc(VARHDRSZ + len); SET_VARSIZE(result, VARHDRSZ + len); memcpy(VARDATA(result), NameStr(*s), len); @@ -1948,20 +1938,20 @@ SplitIdentifierString(char *rawstring, char separator, Datum byteaeq(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_P(0); - bytea *arg2 = PG_GETARG_BYTEA_P(1); + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); int len1, len2; bool result; - len1 = VARSIZE(arg1) - VARHDRSZ; - len2 = VARSIZE(arg2) - VARHDRSZ; + len1 = VARSIZE_ANY_EXHDR(arg1); + len2 = VARSIZE_ANY_EXHDR(arg2); /* fast path for different-length inputs */ if (len1 != len2) result = false; else - result = (memcmp(VARDATA(arg1), VARDATA(arg2), len1) == 0); + result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) == 0); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -1972,20 +1962,20 @@ byteaeq(PG_FUNCTION_ARGS) Datum byteane(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_P(0); - bytea *arg2 = PG_GETARG_BYTEA_P(1); + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); int len1, len2; bool result; - len1 = VARSIZE(arg1) - VARHDRSZ; - len2 = VARSIZE(arg2) - VARHDRSZ; + len1 = VARSIZE_ANY_EXHDR(arg1); + len2 = VARSIZE_ANY_EXHDR(arg2); /* fast path for different-length inputs */ if (len1 != len2) result = true; else - result = (memcmp(VARDATA(arg1), VARDATA(arg2), len1) != 0); + result = (memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), len1) != 0); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -1996,16 +1986,16 @@ byteane(PG_FUNCTION_ARGS) Datum bytealt(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_P(0); - bytea *arg2 = PG_GETARG_BYTEA_P(1); + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); int len1, len2; int cmp; - len1 = VARSIZE(arg1) - VARHDRSZ; - len2 = VARSIZE(arg2) - VARHDRSZ; + len1 = VARSIZE_ANY_EXHDR(arg1); + len2 = VARSIZE_ANY_EXHDR(arg2); - cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); + cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2)); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -2016,16 +2006,16 @@ bytealt(PG_FUNCTION_ARGS) Datum byteale(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_P(0); - bytea *arg2 = PG_GETARG_BYTEA_P(1); + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); int len1, len2; int cmp; - len1 = VARSIZE(arg1) - VARHDRSZ; - len2 = VARSIZE(arg2) - VARHDRSZ; + len1 = VARSIZE_ANY_EXHDR(arg1); + len2 = VARSIZE_ANY_EXHDR(arg2); - cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); + cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2)); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -2036,16 +2026,16 @@ byteale(PG_FUNCTION_ARGS) Datum byteagt(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_P(0); - bytea *arg2 = PG_GETARG_BYTEA_P(1); + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); int len1, len2; int cmp; - len1 = VARSIZE(arg1) - VARHDRSZ; - len2 = VARSIZE(arg2) - VARHDRSZ; + len1 = VARSIZE_ANY_EXHDR(arg1); + len2 = VARSIZE_ANY_EXHDR(arg2); - cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); + cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2)); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -2056,16 +2046,16 @@ byteagt(PG_FUNCTION_ARGS) Datum byteage(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_P(0); - bytea *arg2 = PG_GETARG_BYTEA_P(1); + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); int len1, len2; int cmp; - len1 = VARSIZE(arg1) - VARHDRSZ; - len2 = VARSIZE(arg2) - VARHDRSZ; + len1 = VARSIZE_ANY_EXHDR(arg1); + len2 = VARSIZE_ANY_EXHDR(arg2); - cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); + cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2)); PG_FREE_IF_COPY(arg1, 0); PG_FREE_IF_COPY(arg2, 1); @@ -2076,16 +2066,16 @@ byteage(PG_FUNCTION_ARGS) Datum byteacmp(PG_FUNCTION_ARGS) { - bytea *arg1 = PG_GETARG_BYTEA_P(0); - bytea *arg2 = PG_GETARG_BYTEA_P(1); + bytea *arg1 = PG_GETARG_BYTEA_PP(0); + bytea *arg2 = PG_GETARG_BYTEA_PP(1); int len1, len2; int cmp; - len1 = VARSIZE(arg1) - VARHDRSZ; - len2 = VARSIZE(arg2) - VARHDRSZ; + len1 = VARSIZE_ANY_EXHDR(arg1); + len2 = VARSIZE_ANY_EXHDR(arg2); - cmp = memcmp(VARDATA(arg1), VARDATA(arg2), Min(len1, len2)); + cmp = memcmp(VARDATA_ANY(arg1), VARDATA_ANY(arg2), Min(len1, len2)); if ((cmp == 0) && (len1 != len2)) cmp = (len1 < len2) ? -1 : 1; @@ -2713,8 +2703,8 @@ array_to_text(PG_FUNCTION_ARGS) appendStringInfoString(&buf, value); printed = true; - p = att_addlength(p, typlen, PointerGetDatum(p)); - p = (char *) att_align(p, typalign); + p = att_addlength_pointer(p, typlen, p); + p = (char *) att_align_nominal(p, typalign); } /* advance bitmap pointer if any */ @@ -2795,16 +2785,16 @@ to_hex64(PG_FUNCTION_ARGS) Datum md5_text(PG_FUNCTION_ARGS) { - text *in_text = PG_GETARG_TEXT_P(0); + text *in_text = PG_GETARG_TEXT_PP(0); size_t len; char hexsum[MD5_HASH_LEN + 1]; text *result_text; /* Calculate the length of the buffer using varlena metadata */ - len = VARSIZE(in_text) - VARHDRSZ; + len = VARSIZE_ANY_EXHDR(in_text); /* get the hash result */ - if (pg_md5_hash(VARDATA(in_text), len, hexsum) == false) + if (pg_md5_hash(VARDATA_ANY(in_text), len, hexsum) == false) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); @@ -2821,13 +2811,13 @@ md5_text(PG_FUNCTION_ARGS) Datum md5_bytea(PG_FUNCTION_ARGS) { - bytea *in = PG_GETARG_BYTEA_P(0); + bytea *in = PG_GETARG_BYTEA_PP(0); size_t len; char hexsum[MD5_HASH_LEN + 1]; text *result_text; - len = VARSIZE(in) - VARHDRSZ; - if (pg_md5_hash(VARDATA(in), len, hexsum) == false) + len = VARSIZE_ANY_EXHDR(in); + if (pg_md5_hash(VARDATA_ANY(in), len, hexsum) == false) ereport(ERROR, (errcode(ERRCODE_OUT_OF_MEMORY), errmsg("out of memory"))); diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index f039bba21e0..e873264e3a1 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.41 2007/04/05 13:53:23 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.42 2007/04/06 04:21:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -3071,8 +3071,8 @@ xmlpath(PG_FUNCTION_ARGS) else ns_uris[i - ns_count] = DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(ptr))); - ptr = att_addlength(ptr, typlen, PointerGetDatum(ptr)); - ptr = (char *) att_align(ptr, typalign); + ptr = att_addlength_pointer(ptr, typlen, ptr); + ptr = (char *) att_align_nominal(ptr, typalign); } /* advance bitmap pointer if any */ diff --git a/src/backend/utils/fmgr/fmgr.c b/src/backend/utils/fmgr/fmgr.c index a28acdc2ad8..5a67a84cf88 100644 --- a/src/backend/utils/fmgr/fmgr.c +++ b/src/backend/utils/fmgr/fmgr.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.105 2007/03/27 23:21:10 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/fmgr/fmgr.c,v 1.106 2007/04/06 04:21:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1962,7 +1962,7 @@ struct varlena * pg_detoast_datum(struct varlena * datum) { if (VARATT_IS_EXTENDED(datum)) - return (struct varlena *) heap_tuple_untoast_attr((varattrib *) datum); + return heap_tuple_untoast_attr(datum); else return datum; } @@ -1971,7 +1971,7 @@ struct varlena * pg_detoast_datum_copy(struct varlena * datum) { if (VARATT_IS_EXTENDED(datum)) - return (struct varlena *) heap_tuple_untoast_attr((varattrib *) datum); + return heap_tuple_untoast_attr(datum); else { /* Make a modifiable copy of the varlena object */ @@ -1987,7 +1987,16 @@ struct varlena * pg_detoast_datum_slice(struct varlena * datum, int32 first, int32 count) { /* Only get the specified portion from the toast rel */ - return (struct varlena *) heap_tuple_untoast_attr_slice((varattrib *) datum, first, count); + return heap_tuple_untoast_attr_slice(datum, first, count); +} + +struct varlena * +pg_detoast_datum_packed(struct varlena * datum) +{ + if (VARATT_IS_COMPRESSED(datum) || VARATT_IS_EXTERNAL(datum)) + return heap_tuple_untoast_attr(datum); + else + return datum; } /*------------------------------------------------------------------------- diff --git a/src/backend/utils/init/flatfiles.c b/src/backend/utils/init/flatfiles.c index 1699979c3d0..e388d1edfdc 100644 --- a/src/backend/utils/init/flatfiles.c +++ b/src/backend/utils/init/flatfiles.c @@ -23,7 +23,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.24 2007/01/05 22:19:43 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/init/flatfiles.c,v 1.25 2007/04/06 04:21:43 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -467,7 +467,7 @@ write_auth_file(Relation rel_authid, Relation rel_authmem) auth_info[curr_role].rolpassword = DatumGetCString(DirectFunctionCall1(textout, datum)); /* assume passwd has attlen -1 */ - off = att_addlength(off, -1, tp + off); + off = att_addlength_pointer(off, -1, tp + off); } if (HeapTupleHasNulls(tuple) && @@ -482,7 +482,7 @@ write_auth_file(Relation rel_authid, Relation rel_authmem) * rolvaliduntil is timestamptz, which we assume is double * alignment and pass-by-reference. */ - off = att_align(off, 'd'); + off = att_align_nominal(off, 'd'); datum = PointerGetDatum(tp + off); auth_info[curr_role].rolvaliduntil = DatumGetCString(DirectFunctionCall1(timestamptz_out, datum)); } |