diff options
Diffstat (limited to 'src/backend/access/common/detoast.c')
-rw-r--r-- | src/backend/access/common/detoast.c | 77 |
1 files changed, 44 insertions, 33 deletions
diff --git a/src/backend/access/common/detoast.c b/src/backend/access/common/detoast.c index d1cdbaf6486..2fef40c2e9a 100644 --- a/src/backend/access/common/detoast.c +++ b/src/backend/access/common/detoast.c @@ -240,14 +240,20 @@ detoast_attr_slice(struct varlena *attr, */ if (slicelimit >= 0) { - int32 max_size; + int32 max_size = VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer); /* * Determine maximum amount of compressed data needed for a prefix * of a given length (after decompression). + * + * At least for now, if it's LZ4 data, we'll have to fetch the + * whole thing, because there doesn't seem to be an API call to + * determine how much compressed data we need to be sure of being + * able to decompress the required slice. */ - max_size = pglz_maximum_compressed_size(slicelimit, - toast_pointer.va_extsize); + if (VARATT_EXTERNAL_GET_COMPRESSION(toast_pointer) == + TOAST_PGLZ_COMPRESSION_ID) + max_size = pglz_maximum_compressed_size(slicelimit, max_size); /* * Fetch enough compressed slices (compressed marker will get set @@ -347,7 +353,7 @@ toast_fetch_datum(struct varlena *attr) /* Must copy to access aligned fields */ VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr); - attrsize = toast_pointer.va_extsize; + attrsize = VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer); result = (struct varlena *) palloc(attrsize + VARHDRSZ); @@ -408,7 +414,7 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, */ Assert(!VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) || 0 == sliceoffset); - attrsize = toast_pointer.va_extsize; + attrsize = VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer); if (sliceoffset >= attrsize) { @@ -418,8 +424,8 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, /* * When fetching a prefix of a compressed external datum, account for the - * rawsize tracking amount of raw data, which is stored at the beginning - * as an int32 value). + * space required by va_tcinfo, which is stored at the beginning as an + * int32 value. */ if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer) && slicelength > 0) slicelength = slicelength + sizeof(int32); @@ -464,21 +470,24 @@ toast_fetch_datum_slice(struct varlena *attr, int32 sliceoffset, static struct varlena * toast_decompress_datum(struct varlena *attr) { - struct varlena *result; + ToastCompressionId cmid; Assert(VARATT_IS_COMPRESSED(attr)); - result = (struct varlena *) - palloc(TOAST_COMPRESS_RAWSIZE(attr) + VARHDRSZ); - SET_VARSIZE(result, TOAST_COMPRESS_RAWSIZE(attr) + VARHDRSZ); - - if (pglz_decompress(TOAST_COMPRESS_RAWDATA(attr), - TOAST_COMPRESS_SIZE(attr), - VARDATA(result), - TOAST_COMPRESS_RAWSIZE(attr), true) < 0) - elog(ERROR, "compressed data is corrupted"); - - return result; + /* + * Fetch the compression method id stored in the compression header and + * decompress the data using the appropriate decompression routine. + */ + cmid = TOAST_COMPRESS_METHOD(attr); + switch (cmid) + { + case TOAST_PGLZ_COMPRESSION_ID: + return pglz_decompress_datum(attr); + case TOAST_LZ4_COMPRESSION_ID: + return lz4_decompress_datum(attr); + default: + elog(ERROR, "invalid compression method id %d", cmid); + } } @@ -492,22 +501,24 @@ toast_decompress_datum(struct varlena *attr) static struct varlena * toast_decompress_datum_slice(struct varlena *attr, int32 slicelength) { - struct varlena *result; - int32 rawsize; + ToastCompressionId cmid; Assert(VARATT_IS_COMPRESSED(attr)); - result = (struct varlena *) palloc(slicelength + VARHDRSZ); - - rawsize = pglz_decompress(TOAST_COMPRESS_RAWDATA(attr), - VARSIZE(attr) - TOAST_COMPRESS_HDRSZ, - VARDATA(result), - slicelength, false); - if (rawsize < 0) - elog(ERROR, "compressed data is corrupted"); - - SET_VARSIZE(result, rawsize + VARHDRSZ); - return result; + /* + * Fetch the compression method id stored in the compression header and + * decompress the data slice using the appropriate decompression routine. + */ + cmid = TOAST_COMPRESS_METHOD(attr); + switch (cmid) + { + case TOAST_PGLZ_COMPRESSION_ID: + return pglz_decompress_datum_slice(attr, slicelength); + case TOAST_LZ4_COMPRESSION_ID: + return lz4_decompress_datum_slice(attr, slicelength); + default: + elog(ERROR, "invalid compression method id %d", cmid); + } } /* ---------- @@ -589,7 +600,7 @@ toast_datum_size(Datum value) struct varatt_external toast_pointer; VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr); - result = toast_pointer.va_extsize; + result = VARATT_EXTERNAL_GET_EXTSIZE(toast_pointer); } else if (VARATT_IS_EXTERNAL_INDIRECT(attr)) { |