*
*
* 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
*/
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;
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;
/* ----------------
* 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;
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)
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;
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;
}
* 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
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 */
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
DataFill((char *) td + hoff,
tupleDescriptor,
- value,
+ values,
nulls,
&td->t_infomask,
(hasnull ? td->t_bits : NULL));
*
* 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);
/*
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
* 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 $
*
*-------------------------------------------------------------------------
*/
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;
/* ----------------
self->attrinfo = NULL;
self->nattrs = 0;
self->myinfo = NULL;
+ self->values = NULL;
+ self->nulls = NULL;
return (DestReceiver *) self;
}
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;
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
*/
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;
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)
*/
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? */
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);
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;
}
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)
*/
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? */
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);
*
*
* 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
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
{
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);
}
}
Form_pg_attribute *att;
int numAttrs;
int i;
- bool old_isnull;
- bool new_isnull;
bool need_change = false;
bool need_free = false;
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
* ' ' 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;
/*
* 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;
/*
* 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)
{
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;
}
}
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]);
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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));
* 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] = ' ';
- }
}
/*
foreach(l, tab->newvals)
{
NewColumnValue *ex = lfirst(l);
+ bool isNull;
values[ex->attnum - 1] = ExecEvalExpr(ex->exprstate,
econtext,
*
*
* 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
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",
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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
/*
* 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)
{
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;
}
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
int numberOfAttributes;
Datum *v;
char *n;
- bool isnull;
int i;
if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
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++)
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
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
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);