diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-11-02 01:45:28 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-11-02 01:45:28 +0000 |
commit | 902d1cb35f69464e1e13015b9e05abdb76a7444d (patch) | |
tree | 995e1ec29c8a937a3890956065a31c1ab9d7c6bd /src/backend/access/common/heaptuple.c | |
parent | 492059dabae9643f097fcd0a4f8860366563843d (diff) | |
download | postgresql-902d1cb35f69464e1e13015b9e05abdb76a7444d.tar.gz postgresql-902d1cb35f69464e1e13015b9e05abdb76a7444d.zip |
Remove all uses of the deprecated functions heap_formtuple, heap_modifytuple,
and heap_deformtuple in favor of the newer functions heap_form_tuple et al
(which do the same things but use bool control flags instead of arbitrary
char values). Eliminate the former duplicate coding of these functions,
reducing the deprecated functions to mere wrappers around the newer ones.
We can't get rid of them entirely because add-on modules probably still
contain many instances of the old coding style.
Kris Jurka
Diffstat (limited to 'src/backend/access/common/heaptuple.c')
-rw-r--r-- | src/backend/access/common/heaptuple.c | 441 |
1 files changed, 34 insertions, 407 deletions
diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index db557f900bd..201a3878bc6 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -4,13 +4,6 @@ * This file contains heap tuple accessor and mutator routines, as well * as various tuple utilities. * - * NOTE: there is massive duplication of code in this module to - * support both the convention that a null is marked by a bool TRUE, - * and the convention that a null is marked by a char 'n'. The latter - * convention is deprecated but it'll probably be a long time before - * 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 @@ -24,8 +17,8 @@ * 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. + * conversion is performed directly in heap_form_tuple, without invoking + * tuptoaster.c. * * 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 @@ -57,7 +50,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.122 2008/05/12 00:00:43 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.123 2008/11/02 01:45:26 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -128,54 +121,6 @@ heap_compute_data_size(TupleDesc tupleDesc, return data_length; } -/* ---------------- - * ComputeDataSize - * - * Determine size of the data area of a tuple to be constructed - * - * OLD API with char 'n'/' ' convention for indicating nulls - * ---------------- - */ -static Size -ComputeDataSize(TupleDesc tupleDesc, - Datum *values, - char *nulls) -{ - Size data_length = 0; - int i; - int numberOfAttributes = tupleDesc->natts; - Form_pg_attribute *att = tupleDesc->attrs; - - for (i = 0; i < numberOfAttributes; i++) - { - Datum val; - - if (nulls[i] != ' ') - continue; - - 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; -} - /* * heap_fill_tuple * Load data portion of a tuple from values/isnull arrays @@ -310,138 +255,6 @@ heap_fill_tuple(TupleDesc tupleDesc, Assert((data - start) == data_size); } -/* ---------------- - * DataFill - * - * Load data portion of a tuple from values/nulls arrays - * - * OLD API with char 'n'/' ' convention for indicating nulls - * ---------------- - */ -static void -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) - { - bitP = &bit[-1]; - bitmask = HIGHBIT; - } - else - { - /* just to keep compiler quiet */ - bitP = NULL; - bitmask = 0; - } - - *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTERNAL); - - for (i = 0; i < numberOfAttributes; i++) - { - Size data_length; - - if (bit != NULL) - { - if (bitmask != HIGHBIT) - bitmask <<= 1; - else - { - bitP += 1; - *bitP = 0x0; - bitmask = 1; - } - - if (nulls[i] == 'n') - { - *infomask |= HEAP_HASNULL; - continue; - } - - *bitP |= bitmask; - } - - /* - * 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(val)) - { - *infomask |= HEAP_HASEXTERNAL; - /* 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 ... 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); - } - - data += data_length; - } - - Assert((data - start) == data_size); -} /* ---------------------------------------------------------------- * heap tuple interface @@ -952,7 +765,7 @@ heap_form_tuple(TupleDesc tupleDescriptor, return tuple; } -/* ---------------- +/* * heap_formtuple * * construct a tuple from the given values[] and nulls[] arrays @@ -960,8 +773,9 @@ heap_form_tuple(TupleDesc tupleDescriptor, * Null attributes are indicated by a 'n' in the appropriate byte * of nulls[]. Non-null attributes are indicated by a ' ' (space). * - * OLD API with char 'n'/' ' convention for indicating nulls - * ---------------- + * OLD API with char 'n'/' ' convention for indicating nulls. + * This is deprecated and should not be used in new code, but we keep it + * around for use by old add-on modules. */ HeapTuple heap_formtuple(TupleDesc tupleDescriptor, @@ -969,96 +783,16 @@ heap_formtuple(TupleDesc tupleDescriptor, char *nulls) { HeapTuple tuple; /* return tuple */ - HeapTupleHeader td; /* tuple data */ - Size len, - data_len; - int hoff; - bool hasnull = false; - Form_pg_attribute *att = tupleDescriptor->attrs; int numberOfAttributes = tupleDescriptor->natts; + bool *boolNulls = (bool *) palloc(numberOfAttributes * sizeof(bool)); int i; - if (numberOfAttributes > MaxTupleAttributeNumber) - ereport(ERROR, - (errcode(ERRCODE_TOO_MANY_COLUMNS), - errmsg("number of columns (%d) exceeds limit (%d)", - numberOfAttributes, MaxTupleAttributeNumber))); - - /* - * Check for nulls and embedded tuples; expand any toasted attributes in - * embedded tuples. This preserves the invariant that toasting can only - * go one level deep. - * - * We can skip calling toast_flatten_tuple_attribute() if the attribute - * couldn't possibly be of composite type. All composite datums are - * varlena and have alignment 'd'; furthermore they aren't arrays. Also, - * if an attribute is already toasted, it must have been sent to disk - * already and so cannot contain toasted attributes. - */ for (i = 0; i < numberOfAttributes; i++) - { - if (nulls[i] != ' ') - hasnull = true; - else if (att[i]->attlen == -1 && - att[i]->attalign == 'd' && - att[i]->attndims == 0 && - !VARATT_IS_EXTENDED(DatumGetPointer(values[i]))) - { - values[i] = toast_flatten_tuple_attribute(values[i], - att[i]->atttypid, - att[i]->atttypmod); - } - } - - /* - * Determine total space needed - */ - len = offsetof(HeapTupleHeaderData, t_bits); + boolNulls[i] = (nulls[i] == 'n'); - if (hasnull) - len += BITMAPLEN(numberOfAttributes); - - if (tupleDescriptor->tdhasoid) - len += sizeof(Oid); + tuple = heap_form_tuple(tupleDescriptor, values, boolNulls); - hoff = len = MAXALIGN(len); /* align user data safely */ - - data_len = ComputeDataSize(tupleDescriptor, values, nulls); - - len += data_len; - - /* - * Allocate and zero the space needed. Note that the tuple body and - * HeapTupleData management structure are allocated in one chunk. - */ - tuple = (HeapTuple) palloc0(HEAPTUPLESIZE + len); - tuple->t_data = td = (HeapTupleHeader) ((char *) tuple + HEAPTUPLESIZE); - - /* - * And fill in the information. Note we fill the Datum fields even though - * this tuple may never become a Datum. - */ - tuple->t_len = len; - ItemPointerSetInvalid(&(tuple->t_self)); - tuple->t_tableOid = InvalidOid; - - HeapTupleHeaderSetDatumLength(td, len); - HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid); - HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod); - - HeapTupleHeaderSetNatts(td, numberOfAttributes); - td->t_hoff = hoff; - - if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ - td->t_infomask = HEAP_HASOID; - - DataFill(tupleDescriptor, - values, - nulls, - (char *) td + hoff, - data_len, - &td->t_infomask, - (hasnull ? td->t_bits : NULL)); + pfree(boolNulls); return tuple; } @@ -1134,7 +868,7 @@ heap_modify_tuple(HeapTuple tuple, return newTuple; } -/* ---------------- +/* * heap_modifytuple * * forms a new tuple from an old tuple and a set of replacement values. @@ -1142,7 +876,8 @@ heap_modify_tuple(HeapTuple tuple, * * OLD API with char 'n'/' ' convention for indicating nulls, and * char 'r'/' ' convention for indicating whether to replace columns. - * ---------------- + * This is deprecated and should not be used in new code, but we keep it + * around for use by old add-on modules. */ HeapTuple heap_modifytuple(HeapTuple tuple, @@ -1151,59 +886,24 @@ heap_modifytuple(HeapTuple tuple, char *replNulls, char *replActions) { + HeapTuple result; int numberOfAttributes = tupleDesc->natts; - int attoff; - Datum *values; - char *nulls; - HeapTuple newTuple; - - /* - * allocate and fill values and nulls arrays from either the tuple or the - * repl information, as appropriate. - * - * NOTE: it's debatable whether to use heap_deformtuple() here or just - * heap_getattr() only the non-replaced colums. The latter could win if - * there are many replaced columns and few non-replaced ones. However, - * heap_deformtuple costs only O(N) while the heap_getattr way would cost - * O(N^2) if there are many non-replaced columns, so it seems better to - * err on the side of linear cost. - */ - values = (Datum *) palloc(numberOfAttributes * sizeof(Datum)); - nulls = (char *) palloc(numberOfAttributes * sizeof(char)); - - heap_deformtuple(tuple, tupleDesc, values, nulls); + bool *boolNulls = (bool *) palloc(numberOfAttributes * sizeof(bool)); + bool *boolActions = (bool *) palloc(numberOfAttributes * sizeof(bool)); + int attnum; - for (attoff = 0; attoff < numberOfAttributes; attoff++) + for (attnum = 0; attnum < numberOfAttributes; attnum++) { - if (replActions[attoff] == 'r') - { - values[attoff] = replValues[attoff]; - nulls[attoff] = replNulls[attoff]; - } - else if (replActions[attoff] != ' ') - elog(ERROR, "unrecognized replace flag: %d", - (int) replActions[attoff]); + boolNulls[attnum] = (replNulls[attnum] == 'n'); + boolActions[attnum] = (replActions[attnum] == 'r'); } - /* - * create a new tuple from the values and nulls arrays - */ - newTuple = heap_formtuple(tupleDesc, values, nulls); + result = heap_modify_tuple(tuple, tupleDesc, replValues, boolNulls, boolActions); - pfree(values); - pfree(nulls); + pfree(boolNulls); + pfree(boolActions); - /* - * copy the identification info of the old tuple: t_ctid, t_self, and OID - * (if any) - */ - newTuple->t_data->t_ctid = tuple->t_data->t_ctid; - newTuple->t_self = tuple->t_self; - newTuple->t_tableOid = tuple->t_tableOid; - if (tupleDesc->tdhasoid) - HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple)); - - return newTuple; + return result; } /* @@ -1312,7 +1012,7 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, } } -/* ---------------- +/* * heap_deformtuple * * Given a tuple, extract data into values/nulls arrays; this is @@ -1329,8 +1029,9 @@ heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, * heap_getattr; the loop will become O(N^2) as soon as any * noncacheable attribute offsets are involved. * - * OLD API with char 'n'/' ' convention for indicating nulls - * ---------------- + * OLD API with char 'n'/' ' convention for indicating nulls. + * This is deprecated and should not be used in new code, but we keep it + * around for use by old add-on modules. */ void heap_deformtuple(HeapTuple tuple, @@ -1338,90 +1039,16 @@ heap_deformtuple(HeapTuple tuple, Datum *values, char *nulls) { - HeapTupleHeader tup = tuple->t_data; - bool hasnulls = HeapTupleHasNulls(tuple); - Form_pg_attribute *att = tupleDesc->attrs; - int tdesc_natts = tupleDesc->natts; - int natts; /* number of atts to extract */ + int natts = tupleDesc->natts; + bool *boolNulls = (bool *) palloc(natts * sizeof(bool)); int attnum; - char *tp; /* ptr to tuple data */ - long off; /* offset in tuple data */ - bits8 *bp = tup->t_bits; /* ptr to null bitmap in tuple */ - bool slow = false; /* can we use/set attcacheoff? */ - natts = HeapTupleHeaderGetNatts(tup); - - /* - * In inheritance situations, it is possible that the given tuple actually - * has more fields than the caller is expecting. Don't run off the end of - * the caller's arrays. - */ - natts = Min(natts, tdesc_natts); - - tp = (char *) tup + tup->t_hoff; - - off = 0; + heap_deform_tuple(tuple, tupleDesc, values, boolNulls); for (attnum = 0; attnum < natts; attnum++) - { - Form_pg_attribute thisatt = att[attnum]; - - if (hasnulls && att_isnull(attnum, bp)) - { - values[attnum] = (Datum) 0; - nulls[attnum] = 'n'; - slow = true; /* can't use attcacheoff anymore */ - continue; - } - - nulls[attnum] = ' '; + nulls[attnum] = (boolNulls[attnum] ? 'n' : ' '); - 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 - { - /* not varlena, so safe to use att_align_nominal */ - off = att_align_nominal(off, thisatt->attalign); - - if (!slow) - thisatt->attcacheoff = off; - } - - values[attnum] = fetchatt(thisatt, tp + off); - - off = att_addlength_pointer(off, thisatt->attlen, tp + off); - - if (thisatt->attlen <= 0) - slow = true; /* can't use attcacheoff anymore */ - } - - /* - * If tuple doesn't have all the atts indicated by tupleDesc, read the - * rest as null - */ - for (; attnum < tdesc_natts; attnum++) - { - values[attnum] = (Datum) 0; - nulls[attnum] = 'n'; - } + pfree(boolNulls); } /* |