/* * heap_compute_data_size * Determine size of the data area of a tuple to be constructed */ Size heap_compute_data_size(TupleDesc tupleDesc, Datum *values, bool *isnull) { Size data_length = 0; int i; int numberOfAttributes = tupleDesc->natts; Form_pg_attribute *att = tupleDesc->attrs; for (i = 0; i < numberOfAttributes; i++) { Datum val; Form_pg_attribute atti; if (isnull[i]) continue; val = values[i]; atti = att[i]; if (ATT_IS_PACKABLE(atti) && 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 if (atti->attlen == -1 && VARATT_IS_EXTERNAL_EXPANDED(DatumGetPointer(val))) { /* * we want to flatten the expanded value so that the constructed * tuple doesn't depend on it */ data_length = att_align_nominal(data_length, atti->attalign); data_length += EOH_get_flat_size(DatumGetEOHP(val)); } else { data_length = att_align_datum(data_length, atti->attalign, atti->attlen, val); data_length = att_addlength_datum(data_length, atti->attlen, val); } } return data_length; }
/* * heap_compute_data_size * Determine size of the data area of a tuple to be constructed */ Size heap_compute_data_size(TupleDesc tupleDesc, Datum *values, bool *isnull) { 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 (isnull[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 * * 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, 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 (isnull[i]) { *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(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(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(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); }
/* * Per-attribute helper for heap_fill_tuple and other routines building tuples. * * Fill in either a data value or a bit in the null bitmask */ static inline void fill_val(Form_pg_attribute att, bits8 **bit, int *bitmask, char **dataP, uint16 *infomask, Datum datum, bool isnull) { Size data_length; char *data = *dataP; /* * If we're building a null bitmap, set the appropriate bit for the * current column value here. */ if (bit != NULL) { if (*bitmask != HIGHBIT) *bitmask <<= 1; else { *bit += 1; **bit = 0x0; *bitmask = 1; } if (isnull) { *infomask |= HEAP_HASNULL; return; } **bit |= *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->attbyval) { /* pass-by-value */ data = (char *) att_align_nominal(data, att->attalign); store_att_byval(data, datum, att->attlen); data_length = att->attlen; } else if (att->attlen == -1) { /* varlena */ Pointer val = DatumGetPointer(datum); *infomask |= HEAP_HASVARWIDTH; if (VARATT_IS_EXTERNAL(val)) { if (VARATT_IS_EXTERNAL_EXPANDED(val)) { /* * we want to flatten the expanded value so that the * constructed tuple doesn't depend on it */ ExpandedObjectHeader *eoh = DatumGetEOHP(datum); data = (char *) att_align_nominal(data, att->attalign); data_length = EOH_get_flat_size(eoh); EOH_flatten_into(eoh, data, data_length); } else { *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) && 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(data, att->attalign); data_length = VARSIZE(val); memcpy(data, val, data_length); } } else if (att->attlen == -2) { /* cstring ... never needs alignment */ *infomask |= HEAP_HASVARWIDTH; Assert(att->attalign == 'c'); data_length = strlen(DatumGetCString(datum)) + 1; memcpy(data, DatumGetPointer(datum), data_length); } else { /* fixed-length pass-by-reference */ data = (char *) att_align_nominal(data, att->attalign); Assert(att->attlen > 0); data_length = att->attlen; memcpy(data, DatumGetPointer(datum), data_length); } data += data_length; *dataP = data; }