aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/common/heaptuple.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/common/heaptuple.c')
-rw-r--r--src/backend/access/common/heaptuple.c441
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);
}
/*