/* ---------- * heap_tuple_untoast_attr - * * Public entry point to get back a toasted value from compression * or external storage. * ---------- */ varattrib * heap_tuple_untoast_attr(varattrib *attr) { varattrib *result; if (VARATT_IS_EXTERNAL(attr)) { if (VARATT_IS_COMPRESSED(attr)) { /* ---------- * This is an external stored compressed value * Fetch it from the toast heap and decompress. * ---------- */ varattrib *tmp; tmp = toast_fetch_datum(attr); result = (varattrib *) palloc(attr->va_content.va_external.va_rawsize + VARHDRSZ); VARATT_SIZEP(result) = attr->va_content.va_external.va_rawsize + VARHDRSZ; pglz_decompress((PGLZ_Header *) tmp, VARATT_DATA(result)); pfree(tmp); } else { /* * This is an external stored plain value */ result = toast_fetch_datum(attr); } } else if (VARATT_IS_COMPRESSED(attr)) { /* * This is a compressed value inside of the main tuple */ result = (varattrib *) palloc(attr->va_content.va_compressed.va_rawsize + VARHDRSZ); VARATT_SIZEP(result) = attr->va_content.va_compressed.va_rawsize + VARHDRSZ; pglz_decompress((PGLZ_Header *) attr, VARATT_DATA(result)); } else /* * This is a plain value inside of the main tuple - why am I * called? */ return attr; return result; }
/* ---------- * heap_tuple_untoast_attr_slice - * * Public entry point to get back part of a toasted value * from compression or external storage. * ---------- */ varattrib * heap_tuple_untoast_attr_slice(varattrib *attr, int32 sliceoffset, int32 slicelength) { varattrib *preslice; varattrib *result; int32 attrsize; if (VARATT_IS_COMPRESSED(attr)) { varattrib *tmp; if (VARATT_IS_EXTERNAL(attr)) tmp = toast_fetch_datum(attr); else { tmp = attr; /* compressed in main tuple */ } preslice = (varattrib *) palloc(attr->va_content.va_external.va_rawsize + VARHDRSZ); VARATT_SIZEP(preslice) = attr->va_content.va_external.va_rawsize + VARHDRSZ; pglz_decompress((PGLZ_Header *) tmp, VARATT_DATA(preslice)); if (tmp != attr) pfree(tmp); } else { /* Plain value */ if (VARATT_IS_EXTERNAL(attr)) { /* fast path */ return (toast_fetch_datum_slice(attr, sliceoffset, slicelength)); } else preslice = attr; } /* slicing of datum for compressed cases and plain value */ attrsize = VARSIZE(preslice) - VARHDRSZ; if (sliceoffset >= attrsize) { sliceoffset = 0; slicelength = 0; } if (((sliceoffset + slicelength) > attrsize) || slicelength < 0) slicelength = attrsize - sliceoffset; result = (varattrib *) palloc(slicelength + VARHDRSZ); VARATT_SIZEP(result) = slicelength + VARHDRSZ; memcpy(VARDATA(result), VARDATA(preslice) + sliceoffset, slicelength); if (preslice != attr) pfree(preslice); return result; }
/** * If this function is changed then update varattrib_untoast_len as well */ void varattrib_untoast_ptr_len(Datum d, char **datastart, int *len, void **tofree) { if (DatumGetPointer(d) == NULL) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg(" Unable to detoast datum "), errprintstack(true))); } struct varlena *va = (struct varlena *) DatumGetPointer(d); varattrib *attr = (varattrib *) va; *len = -1; *tofree = NULL; if(VARATT_IS_EXTENDED(attr)) { if(VARATT_IS_EXTERNAL(attr)) { attr = (varattrib *)toast_fetch_datum((struct varlena *)attr); /* toast_fetch_datum will palloc, so set it up for free */ *tofree = attr; } if(VARATT_IS_COMPRESSED(attr)) { PGLZ_Header *tmp = (PGLZ_Header *) attr; attr = (varattrib *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); SET_VARSIZE(attr, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); pglz_decompress(tmp, VARDATA(attr)); /* If tofree is set, that is, we get it from toast_fetch_datum. * We need to free it here */ if(*tofree) pfree(*tofree); *tofree = attr; } else if(VARATT_IS_SHORT(attr)) { /* Warning! Return unaligned pointer! */ *len = VARSIZE_SHORT(attr) - VARHDRSZ_SHORT; *datastart = VARDATA_SHORT(attr); attr = NULL; } } if(*len == -1) { *datastart = VARDATA(attr); *len = VARSIZE(attr) - VARHDRSZ; } Assert(*len >= 0); }
/* ---------- * heap_tuple_untoast_attr - * * Public entry point to get back a toasted value from compression * or external storage. * ---------- */ struct varlena * heap_tuple_untoast_attr(struct varlena * attr) { if (VARATT_IS_EXTERNAL(attr)) { /* * This is an externally stored datum --- fetch it back from there */ attr = toast_fetch_datum(attr); /* If it's compressed, decompress it */ if (VARATT_IS_COMPRESSED(attr)) { PGLZ_Header *tmp = (PGLZ_Header *) attr; attr = (struct varlena *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); SET_VARSIZE(attr, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); pglz_decompress(tmp, VARDATA(attr)); pfree(tmp); } } else if (VARATT_IS_COMPRESSED(attr)) { /* * This is a compressed value inside of the main tuple */ PGLZ_Header *tmp = (PGLZ_Header *) attr; attr = (struct varlena *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); SET_VARSIZE(attr, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); pglz_decompress(tmp, VARDATA(attr)); } else if (VARATT_IS_SHORT(attr)) { /* * This is a short-header varlena --- convert to 4-byte header format */ Size data_size = VARSIZE_SHORT(attr) - VARHDRSZ_SHORT; Size new_size = data_size + VARHDRSZ; struct varlena *new_attr; new_attr = (struct varlena *) palloc(new_size); SET_VARSIZE(new_attr, new_size); memcpy(VARDATA(new_attr), VARDATA_SHORT(attr), data_size); attr = new_attr; } return attr; }
/** * If this function is changed then update varattrib_untoast_ptr_len as well */ int varattrib_untoast_len(Datum d) { if (DatumGetPointer(d) == NULL) { ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg(" Unable to detoast datum "), errprintstack(true))); } struct varlena *va = (struct varlena *) DatumGetPointer(d); varattrib *attr = (varattrib *) va; int len = -1; void *toFree = NULL; if(VARATT_IS_EXTENDED(attr)) { if(VARATT_IS_EXTERNAL(attr)) { attr = (varattrib *)toast_fetch_datum((struct varlena *)attr); /* toast_fetch_datum will palloc, so set it up for free */ toFree = attr; } if(VARATT_IS_COMPRESSED(attr)) { PGLZ_Header *tmp = (PGLZ_Header *) attr; len = PGLZ_RAW_SIZE(tmp); } else if(VARATT_IS_SHORT(attr)) { len = VARSIZE_SHORT(attr) - VARHDRSZ_SHORT; } } if(len == -1) { len = VARSIZE(attr) - VARHDRSZ; } if ( toFree) pfree(toFree); Assert(len >= 0); return len; }
/* ---------- * heap_tuple_untoast_attr - * * Public entry point to get back a toasted value from compression * or external storage. * ---------- */ struct varlena * heap_tuple_untoast_attr(struct varlena *attr) { if (VARATT_IS_EXTERNAL(attr)) { /* * This is an externally stored datum --- fetch it back from there */ attr = toast_fetch_datum(attr); /* fall through to IS_COMPRESSED if it's a compressed external datum */ } if (VARATT_IS_COMPRESSED(attr)) { /* * This is a compressed value inside of the main tuple */ PGLZ_Header *tmp = (PGLZ_Header *) attr; attr = (struct varlena *) palloc(PGLZ_RAW_SIZE(tmp) + VARHDRSZ); SET_VARSIZE(attr, PGLZ_RAW_SIZE(tmp) + VARHDRSZ); pglz_decompress(tmp, VARDATA(attr)); } else if (VARATT_IS_SHORT(attr)) { /* * This is a short-header varlena --- convert to 4-byte header format */ Size data_size = VARSIZE_SHORT(attr); Size new_size = data_size - VARHDRSZ_SHORT + VARHDRSZ; varattrib *tmp = (varattrib *)attr; /* This is a "short" varlena header but is otherwise a normal varlena */ attr = (struct varlena *) palloc(new_size); SET_VARSIZE(attr, new_size); memcpy(VARDATA(attr), VARDATA_SHORT(tmp), data_size - VARHDRSZ_SHORT); } return attr; }
/* ---------- * heap_tuple_fetch_attr - * * Public entry point to get back a toasted value from * external storage (possibly still in compressed format). * * This will return a datum that contains all the data internally, ie, not * relying on external storage, but it can still be compressed or have a short * header. ---------- */ struct varlena * heap_tuple_fetch_attr(struct varlena * attr) { struct varlena *result; if (VARATT_IS_EXTERNAL(attr)) { /* * This is an external stored plain value */ result = toast_fetch_datum(attr); } else { /* * This is a plain value inside of the main tuple - why am I called? */ result = attr; } return result; }
/* ---------- * heap_tuple_untoast_attr_slice - * * Public entry point to get back part of a toasted value * from compression or external storage. * ---------- */ struct varlena * heap_tuple_untoast_attr_slice(struct varlena * attr, int32 sliceoffset, int32 slicelength) { struct varlena *preslice; struct varlena *result; char *attrdata; int32 attrsize; if (VARATT_IS_EXTERNAL(attr)) { struct varatt_external toast_pointer; VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr); /* fast path for non-compressed external datums */ if (!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer)) return toast_fetch_datum_slice(attr, sliceoffset, slicelength); /* fetch it back (compressed marker will get set automatically) */ preslice = toast_fetch_datum(attr); } else preslice = attr; if (VARATT_IS_COMPRESSED(preslice)) { PGLZ_Header *tmp = (PGLZ_Header *) preslice; Size size = PGLZ_RAW_SIZE(tmp) + VARHDRSZ; preslice = (struct varlena *) palloc(size); SET_VARSIZE(preslice, size); pglz_decompress(tmp, VARDATA(preslice)); if (tmp != (PGLZ_Header *) attr) pfree(tmp); } if (VARATT_IS_SHORT(preslice)) { attrdata = VARDATA_SHORT(preslice); attrsize = VARSIZE_SHORT(preslice) - VARHDRSZ_SHORT; } else { attrdata = VARDATA(preslice); attrsize = VARSIZE(preslice) - VARHDRSZ; } /* slicing of datum for compressed cases and plain value */ if (sliceoffset >= attrsize) { sliceoffset = 0; slicelength = 0; } if (((sliceoffset + slicelength) > attrsize) || slicelength < 0) slicelength = attrsize - sliceoffset; result = (struct varlena *) palloc(slicelength + VARHDRSZ); SET_VARSIZE(result, slicelength + VARHDRSZ); memcpy(VARDATA(result), attrdata + sliceoffset, slicelength); if (preslice != attr) pfree(preslice); return result; }
/* ---------- * heap_tuple_untoast_attr_slice - * * Public entry point to get back part of a toasted value * from compression or external storage. * ---------- */ struct varlena * heap_tuple_untoast_attr_slice(struct varlena * attr, int32 sliceoffset, int32 slicelength) { varattrib *preslice; varattrib *result; char *attrdata; int32 attrsize; if (VARATT_IS_EXTERNAL(attr)) { /* fast path for non-compressed external datums */ if (!VARATT_EXTERNAL_IS_COMPRESSED(attr)) return toast_fetch_datum_slice(attr, sliceoffset, slicelength); /* this automatically sets the compressed flag if appropriate */ preslice = (varattrib *)toast_fetch_datum(attr); } else preslice = (varattrib *)attr; if (VARATT_IS_COMPRESSED(preslice)) { unsigned size; PGLZ_Header *tmp; tmp = (PGLZ_Header *) preslice; size = PGLZ_RAW_SIZE(tmp) + VARHDRSZ; preslice = (varattrib *) palloc(size); SET_VARSIZE(preslice, size); pglz_decompress(tmp, VARDATA(preslice)); if (tmp != (PGLZ_Header *) attr) pfree(tmp); } if (VARATT_IS_SHORT(preslice)) { attrdata = VARDATA_SHORT(preslice); attrsize = VARSIZE_SHORT(preslice) - VARHDRSZ_SHORT; } else { attrdata = VARDATA(preslice); attrsize = VARSIZE(preslice) - VARHDRSZ; } /* slicing of datum for compressed cases and plain value */ if (sliceoffset >= attrsize) { sliceoffset = 0; slicelength = 0; } if (((sliceoffset + slicelength) > attrsize) || slicelength < 0) slicelength = attrsize - sliceoffset; result = (varattrib *) palloc(slicelength + VARHDRSZ); SET_VARSIZE(result, slicelength + VARHDRSZ); memcpy(VARDATA(result), attrdata + sliceoffset, slicelength); if ((struct varlena *)preslice != (struct varlena *)attr) pfree(preslice); return (struct varlena *)result; }