diff --git a/src/backend/access/common/heaptuple.c b/src/backend/access/common/heaptuple.c index 4355c0df4c704b744daca974b92f3c445dbbfaef..266cf3bdcc2178a641f59555e1a50fa9c59ea9bb 100644 --- a/src/backend/access/common/heaptuple.c +++ b/src/backend/access/common/heaptuple.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.90 2004/04/01 21:28:43 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/heaptuple.c,v 1.91 2004/06/04 20:35:21 tgl Exp $ * * NOTES * The old interface functions have been converted to macros @@ -37,10 +37,10 @@ */ Size ComputeDataSize(TupleDesc tupleDesc, - Datum *value, + Datum *values, char *nulls) { - uint32 data_length = 0; + Size data_length = 0; int i; int numberOfAttributes = tupleDesc->natts; Form_pg_attribute *att = tupleDesc->attrs; @@ -51,7 +51,7 @@ ComputeDataSize(TupleDesc tupleDesc, continue; data_length = att_align(data_length, att[i]->attalign); - data_length = att_addlength(data_length, att[i]->attlen, value[i]); + data_length = att_addlength(data_length, att[i]->attlen, values[i]); } return data_length; @@ -59,19 +59,20 @@ ComputeDataSize(TupleDesc tupleDesc, /* ---------------- * DataFill + * + * Load data portion of a tuple from values/nulls arrays * ---------------- */ void DataFill(char *data, TupleDesc tupleDesc, - Datum *value, + Datum *values, char *nulls, uint16 *infomask, bits8 *bit) { - bits8 *bitP = 0; - int bitmask = 0; - Size data_length; + bits8 *bitP; + int bitmask; int i; int numberOfAttributes = tupleDesc->natts; Form_pg_attribute *att = tupleDesc->attrs; @@ -81,11 +82,19 @@ DataFill(char *data, bitP = &bit[-1]; bitmask = CSIGNBIT; } + else + { + /* just to keep compiler quiet */ + bitP = NULL; + bitmask = 0; + } *infomask &= ~(HEAP_HASNULL | HEAP_HASVARWIDTH | HEAP_HASEXTENDED); for (i = 0; i < numberOfAttributes; i++) { + Size data_length; + if (bit != NULL) { if (bitmask != CSIGNBIT) @@ -112,33 +121,33 @@ DataFill(char *data, if (att[i]->attbyval) { /* pass-by-value */ - store_att_byval(data, value[i], att[i]->attlen); + store_att_byval(data, values[i], att[i]->attlen); data_length = att[i]->attlen; } else if (att[i]->attlen == -1) { /* varlena */ *infomask |= HEAP_HASVARWIDTH; - if (VARATT_IS_EXTERNAL(value[i])) + if (VARATT_IS_EXTERNAL(values[i])) *infomask |= HEAP_HASEXTERNAL; - if (VARATT_IS_COMPRESSED(value[i])) + if (VARATT_IS_COMPRESSED(values[i])) *infomask |= HEAP_HASCOMPRESSED; - data_length = VARATT_SIZE(DatumGetPointer(value[i])); - memcpy(data, DatumGetPointer(value[i]), data_length); + data_length = VARATT_SIZE(DatumGetPointer(values[i])); + memcpy(data, DatumGetPointer(values[i]), data_length); } else if (att[i]->attlen == -2) { /* cstring */ *infomask |= HEAP_HASVARWIDTH; - data_length = strlen(DatumGetCString(value[i])) + 1; - memcpy(data, DatumGetPointer(value[i]), data_length); + data_length = strlen(DatumGetCString(values[i])) + 1; + memcpy(data, DatumGetPointer(values[i]), data_length); } else { /* fixed-length pass-by-reference */ Assert(att[i]->attlen > 0); data_length = att[i]->attlen; - memcpy(data, DatumGetPointer(value[i]), data_length); + memcpy(data, DatumGetPointer(values[i]), data_length); } data += data_length; @@ -160,27 +169,28 @@ heap_attisnull(HeapTuple tup, int attnum) if (attnum > (int) tup->t_data->t_natts) return 1; - if (HeapTupleNoNulls(tup)) - return 0; - if (attnum > 0) + { + if (HeapTupleNoNulls(tup)) + return 0; return att_isnull(attnum - 1, tup->t_data->t_bits); - else - switch (attnum) - { - case TableOidAttributeNumber: - case SelfItemPointerAttributeNumber: - case ObjectIdAttributeNumber: - case MinTransactionIdAttributeNumber: - case MinCommandIdAttributeNumber: - case MaxTransactionIdAttributeNumber: - case MaxCommandIdAttributeNumber: - /* these are never null */ - break; - - default: - elog(ERROR, "invalid attnum: %d", attnum); - } + } + + switch (attnum) + { + case TableOidAttributeNumber: + case SelfItemPointerAttributeNumber: + case ObjectIdAttributeNumber: + case MinTransactionIdAttributeNumber: + case MinCommandIdAttributeNumber: + case MaxTransactionIdAttributeNumber: + case MaxCommandIdAttributeNumber: + /* these are never null */ + break; + + default: + elog(ERROR, "invalid attnum: %d", attnum); + } return 0; } @@ -202,6 +212,8 @@ heap_attisnull(HeapTuple tup, int attnum) * perform well for queries which hit large #'s of tuples. After * you cache the offsets once, examining all the other tuples using * the same attribute descriptor will go much quicker. -cim 5/4/91 + * + * NOTE: if you need to change this code, see also heap_deformtuple. * ---------------- */ Datum @@ -536,53 +548,18 @@ heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest) memcpy((char *) dest->t_data, (char *) src->t_data, src->t_len); } -#ifdef NOT_USED -/* ---------------- - * heap_deformtuple - * - * the inverse of heap_formtuple (see below) - * ---------------- - */ -void -heap_deformtuple(HeapTuple tuple, - TupleDesc tdesc, - Datum *values, - char *nulls) -{ - int i; - int natts; - - Assert(HeapTupleIsValid(tuple)); - - natts = tuple->t_natts; - for (i = 0; i < natts; i++) - { - bool isnull; - - values[i] = heap_getattr(tuple, - i + 1, - tdesc, - &isnull); - if (isnull) - nulls[i] = 'n'; - else - nulls[i] = ' '; - } -} -#endif - /* ---------------- * heap_formtuple * - * constructs a tuple from the given *value and *nulls arrays + * construct a tuple from the given values[] and nulls[] arrays * * Null attributes are indicated by a 'n' in the appropriate byte - * of *nulls. Non-null attributes are indicated by a ' ' (space). + * of nulls[]. Non-null attributes are indicated by a ' ' (space). * ---------------- */ HeapTuple heap_formtuple(TupleDesc tupleDescriptor, - Datum *value, + Datum *values, char *nulls) { HeapTuple tuple; /* return tuple */ @@ -621,7 +598,7 @@ heap_formtuple(TupleDesc tupleDescriptor, hoff = len = MAXALIGN(len); /* align user data safely */ - len += ComputeDataSize(tupleDescriptor, value, nulls); + len += ComputeDataSize(tupleDescriptor, values, nulls); /* * Allocate and zero the space needed. Note that the tuple body and @@ -651,7 +628,7 @@ heap_formtuple(TupleDesc tupleDescriptor, DataFill((char *) td + hoff, tupleDescriptor, - value, + values, nulls, &td->t_infomask, (hasnull ? td->t_bits : NULL)); @@ -664,68 +641,59 @@ heap_formtuple(TupleDesc tupleDescriptor, * * forms a new tuple from an old tuple and a set of replacement values. * returns a new palloc'ed tuple. + * + * XXX it is misdesign that this is passed a Relation and not just a + * TupleDesc to describe the tuple structure. * ---------------- */ HeapTuple heap_modifytuple(HeapTuple tuple, Relation relation, - Datum *replValue, - char *replNull, - char *repl) + Datum *replValues, + char *replNulls, + char *replActions) { + TupleDesc tupleDesc = RelationGetDescr(relation); + int numberOfAttributes = tupleDesc->natts; int attoff; - int numberOfAttributes; - Datum *value; + Datum *values; char *nulls; - bool isNull; HeapTuple newTuple; /* - * sanity checks - */ - Assert(HeapTupleIsValid(tuple)); - Assert(RelationIsValid(relation)); - Assert(PointerIsValid(replValue)); - Assert(PointerIsValid(replNull)); - Assert(PointerIsValid(repl)); - - numberOfAttributes = RelationGetForm(relation)->relnatts; - - /* - * allocate and fill *value and *nulls arrays from either the tuple or + * 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. */ - value = (Datum *) palloc(numberOfAttributes * sizeof(Datum)); + values = (Datum *) palloc(numberOfAttributes * sizeof(Datum)); nulls = (char *) palloc(numberOfAttributes * sizeof(char)); + heap_deformtuple(tuple, tupleDesc, values, nulls); + for (attoff = 0; attoff < numberOfAttributes; attoff++) { - if (repl[attoff] == ' ') + if (replActions[attoff] == 'r') { - value[attoff] = heap_getattr(tuple, - AttrOffsetGetAttrNumber(attoff), - RelationGetDescr(relation), - &isNull); - nulls[attoff] = (isNull) ? 'n' : ' '; - + values[attoff] = replValues[attoff]; + nulls[attoff] = replNulls[attoff]; } - else if (repl[attoff] == 'r') - { - value[attoff] = replValue[attoff]; - nulls[attoff] = replNull[attoff]; - } - else - elog(ERROR, "unrecognized replace flag: %d", (int) repl[attoff]); + else if (replActions[attoff] != ' ') + elog(ERROR, "unrecognized replace flag: %d", + (int) replActions[attoff]); } /* - * create a new tuple from the *values and *nulls arrays + * create a new tuple from the values and nulls arrays */ - newTuple = heap_formtuple(RelationGetDescr(relation), - value, - nulls); + newTuple = heap_formtuple(tupleDesc, values, nulls); - pfree(value); + pfree(values); pfree(nulls); /* @@ -735,12 +703,96 @@ heap_modifytuple(HeapTuple tuple, newTuple->t_data->t_ctid = tuple->t_data->t_ctid; newTuple->t_self = tuple->t_self; newTuple->t_tableOid = tuple->t_tableOid; - if (relation->rd_rel->relhasoids) + if (tupleDesc->tdhasoid) HeapTupleSetOid(newTuple, HeapTupleGetOid(tuple)); return newTuple; } +/* ---------------- + * heap_deformtuple + * + * Given a tuple, extract data into values/nulls arrays; this is + * the inverse of heap_formtuple. + * + * Storage for the values/nulls arrays is provided by the caller; + * it should be sized according to tupleDesc->natts not tuple->t_natts. + * + * Note that for pass-by-reference datatypes, the pointer placed + * in the Datum will point into the given tuple. + * + * When all or most of a tuple's fields need to be extracted, + * this routine will be significantly quicker than a loop around + * heap_getattr; the loop will become O(N^2) as soon as any + * noncacheable attribute offsets are involved. + * ---------------- + */ +void +heap_deformtuple(HeapTuple tuple, + TupleDesc tupleDesc, + Datum *values, + char *nulls) +{ + HeapTupleHeader tup = tuple->t_data; + Form_pg_attribute *att = tupleDesc->attrs; + int tdesc_natts = tupleDesc->natts; + int natts; /* number of atts to extract */ + int attnum; + char *tp; /* ptr to tuple data */ + long off; /* offset in tuple data */ + bits8 *bp = tup->t_bits; /* ptr to null bitmask in tuple */ + bool slow = false; /* can we use/set attcacheoff? */ + + natts = tup->t_natts; + /* This min() operation is pure paranoia */ + natts = Min(natts, tdesc_natts); + + tp = (char *) tup + tup->t_hoff; + + off = 0; + + for (attnum = 0; attnum < natts; attnum++) + { + if (HeapTupleHasNulls(tuple) && att_isnull(attnum, bp)) + { + values[attnum] = (Datum) 0; + nulls[attnum] = 'n'; + slow = true; /* can't use attcacheoff anymore */ + continue; + } + + nulls[attnum] = ' '; + + if (!slow && att[attnum]->attcacheoff >= 0) + { + off = att[attnum]->attcacheoff; + } + else + { + off = att_align(off, att[attnum]->attalign); + + if (!slow) + att[attnum]->attcacheoff = off; + } + + values[attnum] = fetchatt(att[attnum], tp + off); + + off = att_addlength(off, att[attnum]->attlen, tp + off); + + if (att[attnum]->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'; + } +} /* ---------------- * heap_freetuple diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index eb05c994b465784e43a478f9cf7dcce5c927cd76..fc0b8d9e7ace99cde4834cbac01b40e97a99079e 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -9,7 +9,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.81 2004/05/26 04:41:03 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.82 2004/06/04 20:35:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -65,6 +65,8 @@ typedef struct TupleDesc attrinfo; /* The attr info we are set up for */ int nattrs; PrinttupAttrInfo *myinfo; /* Cached info about each attr */ + Datum *values; /* preallocated space for deformtuple */ + char *nulls; } DR_printtup; /* ---------------- @@ -103,6 +105,8 @@ printtup_create_DR(CommandDest dest, Portal portal) self->attrinfo = NULL; self->nattrs = 0; self->myinfo = NULL; + self->values = NULL; + self->nulls = NULL; return (DestReceiver *) self; } @@ -243,15 +247,27 @@ printtup_prepare_info(DR_printtup *myState, TupleDesc typeinfo, int numAttrs) int16 *formats = myState->portal->formats; int i; + /* get rid of any old data */ if (myState->myinfo) - pfree(myState->myinfo); /* get rid of any old data */ + pfree(myState->myinfo); myState->myinfo = NULL; + if (myState->values) + pfree(myState->values); + myState->values = NULL; + if (myState->nulls) + pfree(myState->nulls); + myState->nulls = NULL; + myState->attrinfo = typeinfo; myState->nattrs = numAttrs; if (numAttrs <= 0) return; + myState->myinfo = (PrinttupAttrInfo *) palloc0(numAttrs * sizeof(PrinttupAttrInfo)); + myState->values = (Datum *) palloc(numAttrs * sizeof(Datum)); + myState->nulls = (char *) palloc(numAttrs * sizeof(char)); + for (i = 0; i < numAttrs; i++) { PrinttupAttrInfo *thisState = myState->myinfo + i; @@ -297,6 +313,11 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) if (myState->attrinfo != typeinfo || myState->nattrs != natts) printtup_prepare_info(myState, typeinfo, natts); + /* + * deconstruct the tuple (faster than a heap_getattr loop) + */ + heap_deformtuple(tuple, typeinfo, myState->values, myState->nulls); + /* * Prepare a DataRow message */ @@ -310,12 +331,10 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) for (i = 0; i < natts; ++i) { PrinttupAttrInfo *thisState = myState->myinfo + i; - Datum origattr, + Datum origattr = myState->values[i], attr; - bool isnull; - origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull); - if (isnull) + if (myState->nulls[i] == 'n') { pq_sendint(&buf, -1, 4); continue; @@ -383,6 +402,11 @@ printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) if (myState->attrinfo != typeinfo || myState->nattrs != natts) printtup_prepare_info(myState, typeinfo, natts); + /* + * deconstruct the tuple (faster than a heap_getattr loop) + */ + heap_deformtuple(tuple, typeinfo, myState->values, myState->nulls); + /* * tell the frontend to expect new tuple data (in ASCII style) */ @@ -395,7 +419,7 @@ printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) k = 1 << 7; for (i = 0; i < natts; ++i) { - if (!heap_attisnull(tuple, i + 1)) + if (myState->nulls[i] != 'n') j |= k; /* set bit if not null */ k >>= 1; if (k == 0) /* end of byte? */ @@ -414,13 +438,11 @@ printtup_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) for (i = 0; i < natts; ++i) { PrinttupAttrInfo *thisState = myState->myinfo + i; - Datum origattr, + Datum origattr = myState->values[i], attr; - bool isnull; char *outputstr; - origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull); - if (isnull) + if (myState->nulls[i] == 'n') continue; Assert(thisState->format == 0); @@ -461,6 +483,13 @@ printtup_shutdown(DestReceiver *self) if (myState->myinfo) pfree(myState->myinfo); myState->myinfo = NULL; + if (myState->values) + pfree(myState->values); + myState->values = NULL; + if (myState->nulls) + pfree(myState->nulls); + myState->nulls = NULL; + myState->attrinfo = NULL; } @@ -587,6 +616,11 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) if (myState->attrinfo != typeinfo || myState->nattrs != natts) printtup_prepare_info(myState, typeinfo, natts); + /* + * deconstruct the tuple (faster than a heap_getattr loop) + */ + heap_deformtuple(tuple, typeinfo, myState->values, myState->nulls); + /* * tell the frontend to expect new tuple data (in binary style) */ @@ -599,7 +633,7 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) k = 1 << 7; for (i = 0; i < natts; ++i) { - if (!heap_attisnull(tuple, i + 1)) + if (myState->nulls[i] != 'n') j |= k; /* set bit if not null */ k >>= 1; if (k == 0) /* end of byte? */ @@ -618,13 +652,11 @@ printtup_internal_20(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) for (i = 0; i < natts; ++i) { PrinttupAttrInfo *thisState = myState->myinfo + i; - Datum origattr, + Datum origattr = myState->values[i], attr; - bool isnull; bytea *outputbytes; - origattr = heap_getattr(tuple, i + 1, typeinfo, &isnull); - if (isnull) + if (myState->nulls[i] == 'n') continue; Assert(thisState->format == 1); diff --git a/src/backend/access/heap/tuptoaster.c b/src/backend/access/heap/tuptoaster.c index ae4b2c0aa888c07db76e719e9f28c4dee178ca3e..f206a3f28eb5475abad83767dca9341739f41c3c 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.41 2003/11/29 19:51:40 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/access/heap/tuptoaster.c,v 1.42 2004/06/04 20:35:21 tgl Exp $ * * * INTERFACE ROUTINES @@ -281,15 +281,26 @@ toast_delete(Relation rel, HeapTuple oldtup) Form_pg_attribute *att; int numAttrs; int i; - Datum value; - bool isnull; + Datum toast_values[MaxHeapAttributeNumber]; + char toast_nulls[MaxHeapAttributeNumber]; /* - * Get the tuple descriptor, the number of and attribute descriptors. + * Get the tuple descriptor and break down the tuple into fields. + * + * NOTE: it's debatable whether to use heap_deformtuple() here or + * just heap_getattr() only the varlena columns. The latter could + * win if there are few varlena columns and many non-varlena ones. + * However, heap_deformtuple costs only O(N) while the heap_getattr + * way would cost O(N^2) if there are many varlena columns, so it + * seems better to err on the side of linear cost. (We won't even + * be here unless there's at least one varlena column, by the way.) */ tupleDesc = rel->rd_att; - numAttrs = tupleDesc->natts; att = tupleDesc->attrs; + numAttrs = tupleDesc->natts; + + Assert(numAttrs <= MaxHeapAttributeNumber); + heap_deformtuple(oldtup, tupleDesc, toast_values, toast_nulls); /* * Check for external stored attributes and delete them from the @@ -299,8 +310,9 @@ toast_delete(Relation rel, HeapTuple oldtup) { if (att[i]->attlen == -1) { - value = heap_getattr(oldtup, i + 1, tupleDesc, &isnull); - if (!isnull && VARATT_IS_EXTERNAL(value)) + Datum value = toast_values[i]; + + if (toast_nulls[i] != 'n' && VARATT_IS_EXTERNAL(value)) toast_delete_datum(rel, value); } } @@ -321,8 +333,6 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup) Form_pg_attribute *att; int numAttrs; int i; - bool old_isnull; - bool new_isnull; bool need_change = false; bool need_free = false; @@ -333,18 +343,24 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup) char toast_action[MaxHeapAttributeNumber]; char toast_nulls[MaxHeapAttributeNumber]; + char toast_oldnulls[MaxHeapAttributeNumber]; Datum toast_values[MaxHeapAttributeNumber]; + Datum toast_oldvalues[MaxHeapAttributeNumber]; int32 toast_sizes[MaxHeapAttributeNumber]; bool toast_free[MaxHeapAttributeNumber]; bool toast_delold[MaxHeapAttributeNumber]; /* - * Get the tuple descriptor, the number of and attribute descriptors - * and the location of the tuple values. + * Get the tuple descriptor and break down the tuple(s) into fields. */ tupleDesc = rel->rd_att; - numAttrs = tupleDesc->natts; att = tupleDesc->attrs; + numAttrs = tupleDesc->natts; + + Assert(numAttrs <= MaxHeapAttributeNumber); + heap_deformtuple(newtup, tupleDesc, toast_values, toast_nulls); + if (oldtup != NULL) + heap_deformtuple(oldtup, tupleDesc, toast_oldvalues, toast_oldnulls); /* ---------- * Then collect information about the values given @@ -353,12 +369,15 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup) * ' ' default handling * 'p' already processed --- don't touch it * 'x' incompressible, but OK to move off + * + * NOTE: toast_sizes[i] is only made valid for varlena attributes with + * toast_action[i] different from 'p'. * ---------- */ memset(toast_action, ' ', numAttrs * sizeof(char)); - memset(toast_nulls, ' ', numAttrs * sizeof(char)); memset(toast_free, 0, numAttrs * sizeof(bool)); memset(toast_delold, 0, numAttrs * sizeof(bool)); + for (i = 0; i < numAttrs; i++) { varattrib *old_value; @@ -369,27 +388,24 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup) /* * For UPDATE get the old and new values of this attribute */ - old_value = (varattrib *) DatumGetPointer( - heap_getattr(oldtup, i + 1, tupleDesc, &old_isnull)); - toast_values[i] = - heap_getattr(newtup, i + 1, tupleDesc, &new_isnull); + old_value = (varattrib *) DatumGetPointer(toast_oldvalues[i]); new_value = (varattrib *) DatumGetPointer(toast_values[i]); /* * If the old value is an external stored one, check if it has * changed so we have to delete it later. */ - if (!old_isnull && att[i]->attlen == -1 && + if (att[i]->attlen == -1 && toast_oldnulls[i] != 'n' && VARATT_IS_EXTERNAL(old_value)) { - if (new_isnull || !VARATT_IS_EXTERNAL(new_value) || + if (toast_nulls[i] == 'n' || !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) { /* - * The old external store value isn't needed any more + * The old external stored value isn't needed any more * after the update */ toast_delold[i] = true; @@ -413,23 +429,21 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup) /* * For INSERT simply get the new value */ - toast_values[i] = - heap_getattr(newtup, i + 1, tupleDesc, &new_isnull); + new_value = (varattrib *) DatumGetPointer(toast_values[i]); } /* * Handle NULL attributes */ - if (new_isnull) + if (toast_nulls[i] == 'n') { toast_action[i] = 'p'; - toast_nulls[i] = 'n'; has_nulls = true; continue; } /* - * Now look at varsize attributes + * Now look at varlena attributes */ if (att[i]->attlen == -1) { @@ -461,10 +475,9 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup) else { /* - * Not a variable size attribute, plain storage always + * Not a varlena attribute, plain storage always */ toast_action[i] = 'p'; - toast_sizes[i] = att[i]->attlen; } } @@ -768,8 +781,7 @@ toast_insert_or_update(Relation rel, HeapTuple newtup, HeapTuple oldtup) if (need_delold) for (i = 0; i < numAttrs; i++) if (toast_delold[i]) - toast_delete_datum(rel, - heap_getattr(oldtup, i + 1, tupleDesc, &old_isnull)); + toast_delete_datum(rel, toast_oldvalues[i]); } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 71f5ad0c00173143228e11ece7e27f0f0ed5f0fc..492532363a579c99f2d3eefeaced2a9db9d0bd82 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.109 2004/06/02 21:01:08 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.110 2004/06/04 20:35:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -2342,10 +2342,10 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) newslot = MakeTupleTableSlot(); ExecSetSlotDescriptor(newslot, newTupDesc, false); - /* Preallocate values/nulls arrays (+1 in case natts==0) */ + /* Preallocate values/nulls arrays */ i = Max(newTupDesc->natts, oldTupDesc->natts); - values = (Datum *) palloc(i * sizeof(Datum) + 1); - nulls = (char *) palloc(i * sizeof(char) + 1); + values = (Datum *) palloc(i * sizeof(Datum)); + nulls = (char *) palloc(i * sizeof(char)); memset(values, 0, i * sizeof(Datum)); memset(nulls, 'n', i * sizeof(char)); @@ -2363,24 +2363,14 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) * Extract data from old tuple. We can force to null any * columns that are deleted according to the new tuple. */ - int natts = oldTupDesc->natts; - bool isNull; + int natts = newTupDesc->natts; + + heap_deformtuple(tuple, oldTupDesc, values, nulls); for (i = 0; i < natts; i++) { if (newTupDesc->attrs[i]->attisdropped) nulls[i] = 'n'; - else - { - values[i] = heap_getattr(tuple, - i + 1, - oldTupDesc, - &isNull); - if (isNull) - nulls[i] = 'n'; - else - nulls[i] = ' '; - } } /* @@ -2393,6 +2383,7 @@ ATRewriteTable(AlteredTableInfo *tab, Oid OIDNewHeap) foreach(l, tab->newvals) { NewColumnValue *ex = lfirst(l); + bool isNull; values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate, econtext, diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index d8a2a5b20f5d91c7dfc32d48ae7edc8c80357857..439ad91cc37e7d91eb9fe56cfcfc7c998f06c825 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.57 2004/05/26 04:41:12 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.58 2004/06/04 20:35:21 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -1329,12 +1329,8 @@ AlterDomainNotNull(List *names, bool notNull) for (i = 0; i < rtc->natts; i++) { int attnum = rtc->atts[i]; - Datum d; - bool isNull; - d = heap_getattr(tuple, attnum, tupdesc, &isNull); - - if (isNull) + if (heap_attisnull(tuple, attnum)) ereport(ERROR, (errcode(ERRCODE_NOT_NULL_VIOLATION), errmsg("column \"%s\" of table \"%s\" contains null values", diff --git a/src/backend/executor/execJunk.c b/src/backend/executor/execJunk.c index 20c385134b272d95ec8c3afb91c2d1e8d6cef512..8c693ddc98c7062b889122c1891b8254ab334c7f 100644 --- a/src/backend/executor/execJunk.c +++ b/src/backend/executor/execJunk.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.40 2004/05/26 04:41:14 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execJunk.c,v 1.41 2004/06/04 20:35:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -246,12 +246,15 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot) TupleDesc cleanTupType; TupleDesc tupType; int cleanLength; - bool isNull; int i; Datum *values; char *nulls; + Datum *old_values; + char *old_nulls; Datum values_array[64]; + Datum old_values_array[64]; char nulls_array[64]; + char old_nulls_array[64]; /* * get info from the slot and the junk filter @@ -265,11 +268,15 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot) /* * Create the arrays that will hold the attribute values and the null - * information for the new "clean" tuple. + * information for the old tuple and new "clean" tuple. * * Note: we use memory on the stack to optimize things when we are * dealing with a small number of attributes. for large tuples we just * use palloc. + * + * Note: we could use just one set of arrays if we were willing to + * assume that the resno mapping is monotonic... I think it is, but + * won't take the risk of breaking things right now. */ if (cleanLength > 64) { @@ -281,36 +288,52 @@ ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot) values = values_array; nulls = nulls_array; } + if (tupType->natts > 64) + { + old_values = (Datum *) palloc(tupType->natts * sizeof(Datum)); + old_nulls = (char *) palloc(tupType->natts * sizeof(char)); + } + else + { + old_values = old_values_array; + old_nulls = old_nulls_array; + } /* - * Exctract one by one all the values of the "clean" tuple. + * Extract all the values of the old tuple. + */ + heap_deformtuple(tuple, tupType, old_values, old_nulls); + + /* + * Transpose into proper fields of the new tuple. */ for (i = 0; i < cleanLength; i++) { - values[i] = heap_getattr(tuple, cleanMap[i], tupType, &isNull); + int j = cleanMap[i] - 1; - if (isNull) - nulls[i] = 'n'; - else - nulls[i] = ' '; + values[i] = old_values[j]; + nulls[i] = old_nulls[j]; } /* * Now form the new tuple. */ - cleanTuple = heap_formtuple(cleanTupType, - values, - nulls); + cleanTuple = heap_formtuple(cleanTupType, values, nulls); /* * We are done. Free any space allocated for 'values' and 'nulls' and * return the new tuple. */ - if (cleanLength > 64) + if (values != values_array) { pfree(values); pfree(nulls); } + if (old_values != old_values_array) + { + pfree(old_values); + pfree(old_nulls); + } return cleanTuple; } diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 6ec4d810a8e3c0cfcde9d694636b560a60dbfda4..047b8fa2aae66d687427cf97e14283543c5e09d3 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.115 2004/05/30 23:40:26 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.116 2004/06/04 20:35:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -427,7 +427,6 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, int numberOfAttributes; Datum *v; char *n; - bool isnull; int i; if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL) @@ -448,11 +447,7 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, n = (char *) palloc(numberOfAttributes * sizeof(char)); /* fetch old values and nulls */ - for (i = 0; i < numberOfAttributes; i++) - { - v[i] = heap_getattr(tuple, i + 1, rel->rd_att, &isnull); - n[i] = (isnull) ? 'n' : ' '; - } + heap_deformtuple(tuple, rel->rd_att, v, n); /* replace values and nulls */ for (i = 0; i < natts; i++) @@ -474,7 +469,7 @@ SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, mtuple->t_data->t_ctid = tuple->t_data->t_ctid; mtuple->t_self = tuple->t_self; mtuple->t_tableOid = tuple->t_tableOid; - if (rel->rd_rel->relhasoids) + if (rel->rd_att->tdhasoid) HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple)); } else diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 9f138524155560fd4190eea1c4ce90230b1c8879..5fa50d28e1e8b69bd232fdf96b71cde36edc2656 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.89 2004/04/21 18:24:26 tgl Exp $ + * $PostgreSQL: pgsql/src/include/access/heapam.h,v 1.90 2004/06/04 20:35:21 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -184,9 +184,9 @@ extern XLogRecPtr log_heap_move(Relation reln, Buffer oldbuf, Buffer newbuf, HeapTuple newtup); /* in common/heaptuple.c */ -extern Size ComputeDataSize(TupleDesc tupleDesc, Datum *value, char *nulls); +extern Size ComputeDataSize(TupleDesc tupleDesc, Datum *values, char *nulls); extern void DataFill(char *data, TupleDesc tupleDesc, - Datum *value, char *nulls, uint16 *infomask, + Datum *values, char *nulls, uint16 *infomask, bits8 *bit); extern int heap_attisnull(HeapTuple tup, int attnum); extern Datum nocachegetattr(HeapTuple tup, int attnum, @@ -194,9 +194,14 @@ extern Datum nocachegetattr(HeapTuple tup, int attnum, extern HeapTuple heap_copytuple(HeapTuple tuple); extern void heap_copytuple_with_tuple(HeapTuple src, HeapTuple dest); extern HeapTuple heap_formtuple(TupleDesc tupleDescriptor, - Datum *value, char *nulls); + Datum *values, char *nulls); extern HeapTuple heap_modifytuple(HeapTuple tuple, - Relation relation, Datum *replValue, char *replNull, char *repl); + Relation relation, + Datum *replValues, + char *replNulls, + char *replActions); +extern void heap_deformtuple(HeapTuple tuple, TupleDesc tupleDesc, + Datum *values, char *nulls); extern void heap_freetuple(HeapTuple tuple); extern HeapTuple heap_addheader(int natts, bool withoid, Size structlen, void *structure);