aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/access/common/detoast.c11
-rw-r--r--src/include/access/toast_internals.h2
2 files changed, 13 insertions, 0 deletions
diff --git a/src/backend/access/common/detoast.c b/src/backend/access/common/detoast.c
index a7f7a474782..545a6b8867a 100644
--- a/src/backend/access/common/detoast.c
+++ b/src/backend/access/common/detoast.c
@@ -507,6 +507,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 bf118f04829..1c28b07c4dd 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)