/* * heap_form_minimal_tuple * construct a MinimalTuple from the given values[] and isnull[] arrays, * which are of the length indicated by tupleDescriptor->natts * * This is exactly like heap_form_tuple() except that the result is a * "minimal" tuple lacking a HeapTupleData header as well as room for system * columns. * * The result is allocated in the current memory context. */ MinimalTuple heap_form_minimal_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull) { MinimalTuple tuple; /* return tuple */ Size len, data_len; int hoff; bool hasnull = false; Form_pg_attribute *att = tupleDescriptor->attrs; int numberOfAttributes = tupleDescriptor->natts; 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 (isnull[i]) hasnull = true; else if (att[i]->attlen == -1 && att[i]->attalign == 'd' && att[i]->attndims == 0 && !VARATT_IS_EXTENDED(values[i])) { values[i] = toast_flatten_tuple_attribute(values[i], att[i]->atttypid, att[i]->atttypmod); } } /* * Determine total space needed */ len = offsetof(MinimalTupleData, t_bits); if (hasnull) len += BITMAPLEN(numberOfAttributes); if (tupleDescriptor->tdhasoid) len += sizeof(Oid); hoff = len = MAXALIGN(len); /* align user data safely */ data_len = heap_compute_data_size(tupleDescriptor, values, isnull); len += data_len; /* * Allocate and zero the space needed. */ tuple = (MinimalTuple) palloc0(len); /* * And fill in the information. */ tuple->t_len = len; HeapTupleHeaderSetNatts(tuple, numberOfAttributes); tuple->t_hoff = hoff + MINIMAL_TUPLE_OFFSET; if (tupleDescriptor->tdhasoid) /* else leave infomask = 0 */ tuple->t_infomask = HEAP_HASOID; heap_fill_tuple(tupleDescriptor, values, isnull, (char *) tuple + hoff, data_len, &tuple->t_infomask, (hasnull ? tuple->t_bits : NULL)); return tuple; }
/* * heap_formtuple * * 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). * * 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, Datum *values, 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; 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(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); if (hasnull) len += BITMAPLEN(numberOfAttributes); if (tupleDescriptor->tdhasoid) len += sizeof(Oid); 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)); 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; heap_fill_tuple(tupleDescriptor, values, nulls, (char *) td + hoff, data_len, &td->t_infomask, (hasnull ? td->t_bits : NULL)); return tuple; }
/* * heap_form_tuple * construct a tuple from the given values[] and isnull[] arrays, * which are of the length indicated by tupleDescriptor->natts * * The result is allocated in the current memory context. */ HeapTuple heaptuple_form_to(TupleDesc tupleDescriptor, Datum *values, bool *isnull, HeapTuple dst, uint32 *dstlen) { HeapTuple tuple; /* return tuple */ HeapTupleHeader td; /* tuple data */ unsigned long len, predicted_len, actual_len; int hoff; bool hasnull = false; Form_pg_attribute *att = tupleDescriptor->attrs; int numberOfAttributes = tupleDescriptor->natts; 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 (isnull[i]) hasnull = true; else if (att[i]->attlen == -1 && att[i]->attalign == 'd' && att[i]->attndims == 0 && !VARATT_IS_EXTENDED_D(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); if (hasnull) len += BITMAPLEN(numberOfAttributes); if (tupleDescriptor->tdhasoid) len += sizeof(Oid); hoff = len = MAXALIGN(len); /* align user data safely */ predicted_len = heap_compute_data_size(tupleDescriptor, values, isnull); len += predicted_len; if(dstlen && (*dstlen) < (HEAPTUPLESIZE + len)) { *dstlen = HEAPTUPLESIZE + len; return NULL; } if(dstlen) { *dstlen = HEAPTUPLESIZE + len; tuple = dst; } else tuple = (HeapTuple) palloc(HEAPTUPLESIZE + len); /* * Allocate and zero the space needed. Note that the tuple body and * HeapTupleData management structure are allocated in one chunk. */ 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)); /* * The following 3 calls will setup the first 12 bytes of td (tuple->t_data) */ HeapTupleHeaderSetDatumLength(td, len); HeapTupleHeaderSetTypeId(td, tupleDescriptor->tdtypeid); HeapTupleHeaderSetTypMod(td, tupleDescriptor->tdtypmod); /* t_ctid does not matter */ /* num of attrs are stored in t_infomask2. Clear the other flags first */ td->t_infomask2 = 0; HeapTupleHeaderSetNatts(td, numberOfAttributes); /* * Set up t_hoff. This need to be done before set up t_infomask * because HeapTupleHeaderSetOid will use t_hoff */ td->t_hoff = hoff; if (tupleDescriptor->tdhasoid) { td->t_infomask = HEAP_HASOID; HeapTupleHeaderSetOid(td, InvalidOid); } else td->t_infomask = 0; /* Really fill in the data. */ actual_len = heap_fill_tuple(tupleDescriptor, values, isnull, (char *) td + hoff, &td->t_infomask, (hasnull ? td->t_bits : NULL)); Assert(predicted_len == actual_len); Assert(!is_heaptuple_memtuple(tuple)); return tuple; }