diff --git a/src/backend/access/common/detoast.c b/src/backend/access/common/detoast.c index a7f7a47478..545a6b8867 100644 --- a/src/backend/access/common/detoast.c +++ b/src/backend/access/common/detoast.c @@ -506,6 +506,17 @@ toast_decompress_datum_slice(struct varlena *attr, int32 slicelength) Assert(VARATT_IS_COMPRESSED(attr)); + /* + * Some callers may pass a slicelength that's more than the actual + * decompressed size. If so, just decompress normally. This avoids + * possibly allocating a larger-than-necessary result object, and may be + * faster and/or more robust as well. Notably, some versions of liblz4 + * have been seen to give wrong results if passed an output size that is + * more than the data's true decompressed size. + */ + if ((uint32) slicelength >= TOAST_COMPRESS_EXTSIZE(attr)) + return toast_decompress_datum(attr); + /* * Fetch the compression method id stored in the compression header and * decompress the data slice using the appropriate decompression routine. diff --git a/src/include/access/toast_internals.h b/src/include/access/toast_internals.h index bf118f0482..1c28b07c4d 100644 --- a/src/include/access/toast_internals.h +++ b/src/include/access/toast_internals.h @@ -31,6 +31,8 @@ typedef struct toast_compress_header * Utilities for manipulation of header information for compressed * toast entries. */ +#define TOAST_COMPRESS_EXTSIZE(ptr) \ + (((toast_compress_header *) (ptr))->tcinfo & VARLENA_EXTSIZE_MASK) #define TOAST_COMPRESS_METHOD(ptr) \ (((toast_compress_header *) (ptr))->tcinfo >> VARLENA_EXTSIZE_BITS)