LCOV - differential code coverage report
Current view: top level - src/backend/access/common - toast_compression.c (source / functions) Coverage Total Hit LBC UBC GBC GNC CBC EUB ECB DCB
Current: bed3ffbf9d952be6c7d739d068cdce44c046dfb7 vs 574581b50ac9c63dd9e4abebb731a3b67e5b50f6 Lines: 89.4 % 85 76 1 8 2 19 55 5 19
Current Date: 2026-05-05 10:23:31 +0900 Functions: 100.0 % 9 9 7 2 7
Baseline: lcov-20260505-025707-baseline Branches: 53.1 % 49 26 2 21 3 23 20 12
Baseline Date: 2026-05-05 10:27:06 +0900 Line coverage date bins:
Legend: Lines:     hit not hit
Branches: + taken - not taken # not executed
(30,360] days: 100.0 % 19 19 19
(360..) days: 86.4 % 66 57 1 8 2 55 5
Function coverage date bins:
(30,360] days: 100.0 % 7 7 7
(360..) days: 100.0 % 2 2 2
Branch coverage date bins:
(360..) days: 32.1 % 81 26 2 21 3 23 20 12

 Age         Owner                    Branch data    TLA  Line data    Source code
                                  1                 :                : /*-------------------------------------------------------------------------
                                  2                 :                :  *
                                  3                 :                :  * toast_compression.c
                                  4                 :                :  *    Functions for toast compression.
                                  5                 :                :  *
                                  6                 :                :  * Copyright (c) 2021-2026, PostgreSQL Global Development Group
                                  7                 :                :  *
                                  8                 :                :  *
                                  9                 :                :  * IDENTIFICATION
                                 10                 :                :  *    src/backend/access/common/toast_compression.c
                                 11                 :                :  *
                                 12                 :                :  *-------------------------------------------------------------------------
                                 13                 :                :  */
                                 14                 :                : #include "postgres.h"
                                 15                 :                : 
                                 16                 :                : #ifdef USE_LZ4
                                 17                 :                : #include <lz4.h>
                                 18                 :                : #endif
                                 19                 :                : 
                                 20                 :                : #include "access/detoast.h"
                                 21                 :                : #include "access/toast_compression.h"
                                 22                 :                : #include "common/pg_lzcompress.h"
                                 23                 :                : #include "varatt.h"
                                 24                 :                : 
                                 25                 :                : /* GUC */
                                 26                 :                : int         default_toast_compression = DEFAULT_TOAST_COMPRESSION;
                                 27                 :                : 
                                 28                 :                : #define NO_COMPRESSION_SUPPORT(method) \
                                 29                 :                :     ereport(ERROR, \
                                 30                 :                :             (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
                                 31                 :                :              errmsg("compression method %s not supported", method), \
                                 32                 :                :              errdetail("This functionality requires the server to be built with %s support.", method)))
                                 33                 :                : 
                                 34                 :                : /*
                                 35                 :                :  * Compress a varlena using PGLZ.
                                 36                 :                :  *
                                 37                 :                :  * Returns the compressed varlena, or NULL if compression fails.
                                 38                 :                :  */
                                 39                 :                : varlena *
   83 michael@paquier.xyz        40                 :GNC         166 : pglz_compress_datum(const varlena *value)
                                 41                 :                : {
                                 42                 :                :     int32       valsize,
                                 43                 :                :                 len;
                                 44                 :            166 :     varlena    *tmp = NULL;
                                 45                 :                : 
 1346 peter@eisentraut.org       46   [ -  +  -  -  :CBC         166 :     valsize = VARSIZE_ANY_EXHDR(value);
                                     -  -  -  -  +  
                                                 + ]
                                 47                 :                : 
                                 48                 :                :     /*
                                 49                 :                :      * No point in wasting a palloc cycle if value size is outside the allowed
                                 50                 :                :      * range for compression.
                                 51                 :                :      */
 1873 rhaas@postgresql.org       52         [ +  - ]:            166 :     if (valsize < PGLZ_strategy_default->min_input_size ||
                                 53         [ -  + ]:            166 :         valsize > PGLZ_strategy_default->max_input_size)
 1873 rhaas@postgresql.org       54                 :LBC       (474) :         return NULL;
                                 55                 :                : 
                                 56                 :                :     /*
                                 57                 :                :      * Figure out the maximum possible size of the pglz output, add the bytes
                                 58                 :                :      * that will be needed for varlena overhead, and allocate that amount.
                                 59                 :                :      */
   83 michael@paquier.xyz        60                 :GNC         166 :     tmp = (varlena *) palloc(PGLZ_MAX_OUTPUT(valsize) +
                                 61                 :                :                              VARHDRSZ_COMPRESSED);
                                 62                 :                : 
 1873 rhaas@postgresql.org       63         [ +  + ]:CBC         166 :     len = pglz_compress(VARDATA_ANY(value),
                                 64                 :                :                         valsize,
                                 65                 :                :                         (char *) tmp + VARHDRSZ_COMPRESSED,
                                 66                 :                :                         NULL);
                                 67         [ +  + ]:            166 :     if (len < 0)
                                 68                 :                :     {
                                 69                 :             58 :         pfree(tmp);
                                 70                 :             58 :         return NULL;
                                 71                 :                :     }
                                 72                 :                : 
 1870 tgl@sss.pgh.pa.us          73                 :            108 :     SET_VARSIZE_COMPRESSED(tmp, len + VARHDRSZ_COMPRESSED);
                                 74                 :                : 
 1873 rhaas@postgresql.org       75                 :            108 :     return tmp;
                                 76                 :                : }
                                 77                 :                : 
                                 78                 :                : /*
                                 79                 :                :  * Decompress a varlena that was compressed using PGLZ.
                                 80                 :                :  */
                                 81                 :                : varlena *
   83 michael@paquier.xyz        82                 :GNC         373 : pglz_decompress_datum(const varlena *value)
                                 83                 :                : {
                                 84                 :                :     varlena    *result;
                                 85                 :                :     int32       rawsize;
                                 86                 :                : 
                                 87                 :                :     /* allocate memory for the uncompressed data */
                                 88                 :            373 :     result = (varlena *) palloc(VARDATA_COMPRESSED_GET_EXTSIZE(value) + VARHDRSZ);
                                 89                 :                : 
                                 90                 :                :     /* decompress the data */
   99 peter@eisentraut.org       91                 :            373 :     rawsize = pglz_decompress((const char *) value + VARHDRSZ_COMPRESSED,
 1870 tgl@sss.pgh.pa.us          92                 :CBC         373 :                               VARSIZE(value) - VARHDRSZ_COMPRESSED,
 1873 rhaas@postgresql.org       93                 :ECB     (76852) :                               VARDATA(result),
 1870 tgl@sss.pgh.pa.us          94                 :CBC         373 :                               VARDATA_COMPRESSED_GET_EXTSIZE(value), true);
 1873 rhaas@postgresql.org       95         [ -  + ]:            373 :     if (rawsize < 0)
 1873 rhaas@postgresql.org       96         [ #  # ]:UBC           0 :         ereport(ERROR,
                                 97                 :                :                 (errcode(ERRCODE_DATA_CORRUPTED),
                                 98                 :                :                  errmsg_internal("compressed pglz data is corrupt")));
                                 99                 :                : 
 1873 rhaas@postgresql.org      100                 :CBC         373 :     SET_VARSIZE(result, rawsize + VARHDRSZ);
                                101                 :                : 
                                102                 :            373 :     return result;
                                103                 :                : }
                                104                 :                : 
                                105                 :                : /*
                                106                 :                :  * Decompress part of a varlena that was compressed using PGLZ.
                                107                 :                :  */
                                108                 :                : varlena *
   83 michael@paquier.xyz       109                 :GNC          24 : pglz_decompress_datum_slice(const varlena *value,
                                110                 :                :                             int32 slicelength)
                                111                 :                : {
                                112                 :                :     varlena    *result;
                                113                 :                :     int32       rawsize;
                                114                 :                : 
                                115                 :                :     /* allocate memory for the uncompressed data */
                                116                 :             24 :     result = (varlena *) palloc(slicelength + VARHDRSZ);
                                117                 :                : 
                                118                 :                :     /* decompress the data */
   99 peter@eisentraut.org      119                 :             24 :     rawsize = pglz_decompress((const char *) value + VARHDRSZ_COMPRESSED,
 1870 tgl@sss.pgh.pa.us         120                 :CBC          24 :                               VARSIZE(value) - VARHDRSZ_COMPRESSED,
 1873 rhaas@postgresql.org      121                 :ECB        (36) :                               VARDATA(result),
                                122                 :                :                               slicelength, false);
 1873 rhaas@postgresql.org      123         [ -  + ]:CBC          24 :     if (rawsize < 0)
 1873 rhaas@postgresql.org      124         [ #  # ]:UBC           0 :         ereport(ERROR,
                                125                 :                :                 (errcode(ERRCODE_DATA_CORRUPTED),
                                126                 :                :                  errmsg_internal("compressed pglz data is corrupt")));
                                127                 :                : 
 1873 rhaas@postgresql.org      128                 :CBC          24 :     SET_VARSIZE(result, rawsize + VARHDRSZ);
                                129                 :                : 
                                130                 :             24 :     return result;
                                131                 :                : }
                                132                 :                : 
                                133                 :                : /*
                                134                 :                :  * Compress a varlena using LZ4.
                                135                 :                :  *
                                136                 :                :  * Returns the compressed varlena, or NULL if compression fails.
                                137                 :                :  */
                                138                 :                : varlena *
   83 michael@paquier.xyz       139                 :GNC       32175 : lz4_compress_datum(const varlena *value)
                                140                 :                : {
                                141                 :                : #ifndef USE_LZ4
                                142                 :                :     NO_COMPRESSION_SUPPORT("lz4");
                                143                 :                :     return NULL;                /* keep compiler quiet */
                                144                 :                : #else
                                145                 :                :     int32       valsize;
                                146                 :                :     int32       len;
                                147                 :                :     int32       max_size;
                                148                 :          32175 :     varlena    *tmp = NULL;
                                149                 :                : 
 1873 rhaas@postgresql.org      150   [ -  +  -  -  :CBC       32175 :     valsize = VARSIZE_ANY_EXHDR(value);
                                     -  -  -  -  -  
                                                 + ]
                                151                 :                : 
                                152                 :                :     /*
                                153                 :                :      * Figure out the maximum possible size of the LZ4 output, add the bytes
                                154                 :                :      * that will be needed for varlena overhead, and allocate that amount.
                                155                 :                :      */
                                156                 :          32175 :     max_size = LZ4_compressBound(valsize);
   83 michael@paquier.xyz       157                 :GNC       32175 :     tmp = (varlena *) palloc(max_size + VARHDRSZ_COMPRESSED);
                                158                 :                : 
 1873 rhaas@postgresql.org      159         [ -  + ]:CBC       32175 :     len = LZ4_compress_default(VARDATA_ANY(value),
                                160                 :                :                                (char *) tmp + VARHDRSZ_COMPRESSED,
                                161                 :                :                                valsize, max_size);
                                162         [ -  + ]:          32175 :     if (len <= 0)
 1873 rhaas@postgresql.org      163         [ #  # ]:UBC           0 :         elog(ERROR, "lz4 compression failed");
                                164                 :                : 
                                165                 :                :     /* data is incompressible so just free the memory and return NULL */
 1873 rhaas@postgresql.org      166         [ +  + ]:CBC       32175 :     if (len > valsize)
                                167                 :                :     {
 1873 rhaas@postgresql.org      168                 :GBC         410 :         pfree(tmp);
                                169                 :            410 :         return NULL;
                                170                 :                :     }
                                171                 :                : 
 1870 tgl@sss.pgh.pa.us         172                 :CBC       31765 :     SET_VARSIZE_COMPRESSED(tmp, len + VARHDRSZ_COMPRESSED);
                                173                 :                : 
 1873 rhaas@postgresql.org      174                 :          31765 :     return tmp;
                                175                 :                : #endif
                                176                 :                : }
                                177                 :                : 
                                178                 :                : /*
                                179                 :                :  * Decompress a varlena that was compressed using LZ4.
                                180                 :                :  */
                                181                 :                : varlena *
   83 michael@paquier.xyz       182                 :GNC      101777 : lz4_decompress_datum(const varlena *value)
                                183                 :                : {
                                184                 :                : #ifndef USE_LZ4
                                185                 :                :     NO_COMPRESSION_SUPPORT("lz4");
                                186                 :                :     return NULL;                /* keep compiler quiet */
                                187                 :                : #else
                                188                 :                :     int32       rawsize;
                                189                 :                :     varlena    *result;
                                190                 :                : 
                                191                 :                :     /* allocate memory for the uncompressed data */
                                192                 :         101777 :     result = (varlena *) palloc(VARDATA_COMPRESSED_GET_EXTSIZE(value) + VARHDRSZ);
                                193                 :                : 
                                194                 :                :     /* decompress the data */
   99 peter@eisentraut.org      195                 :         101777 :     rawsize = LZ4_decompress_safe((const char *) value + VARHDRSZ_COMPRESSED,
 1873 rhaas@postgresql.org      196                 :ECB        (50) :                                   VARDATA(result),
 1870 tgl@sss.pgh.pa.us         197                 :CBC      101777 :                                   VARSIZE(value) - VARHDRSZ_COMPRESSED,
                                198                 :         101777 :                                   VARDATA_COMPRESSED_GET_EXTSIZE(value));
 1873 rhaas@postgresql.org      199         [ -  + ]:         101777 :     if (rawsize < 0)
 1873 rhaas@postgresql.org      200         [ #  # ]:UBC           0 :         ereport(ERROR,
                                201                 :                :                 (errcode(ERRCODE_DATA_CORRUPTED),
                                202                 :                :                  errmsg_internal("compressed lz4 data is corrupt")));
                                203                 :                : 
                                204                 :                : 
 1873 rhaas@postgresql.org      205                 :CBC      101777 :     SET_VARSIZE(result, rawsize + VARHDRSZ);
                                206                 :                : 
                                207                 :         101777 :     return result;
                                208                 :                : #endif
                                209                 :                : }
                                210                 :                : 
                                211                 :                : /*
                                212                 :                :  * Decompress part of a varlena that was compressed using LZ4.
                                213                 :                :  */
                                214                 :                : varlena *
   83 michael@paquier.xyz       215                 :GNC         148 : lz4_decompress_datum_slice(const varlena *value, int32 slicelength)
                                216                 :                : {
                                217                 :                : #ifndef USE_LZ4
                                218                 :                :     NO_COMPRESSION_SUPPORT("lz4");
                                219                 :                :     return NULL;                /* keep compiler quiet */
                                220                 :                : #else
                                221                 :                :     int32       rawsize;
                                222                 :                :     varlena    *result;
                                223                 :                : 
                                224                 :                :     /* slice decompression not supported prior to 1.8.3 */
 1873 rhaas@postgresql.org      225         [ -  + ]:CBC         148 :     if (LZ4_versionNumber() < 10803)
 1873 rhaas@postgresql.org      226                 :UBC           0 :         return lz4_decompress_datum(value);
                                227                 :                : 
                                228                 :                :     /* allocate memory for the uncompressed data */
   83 michael@paquier.xyz       229                 :GNC         148 :     result = (varlena *) palloc(slicelength + VARHDRSZ);
                                230                 :                : 
                                231                 :                :     /* decompress the data */
   99 peter@eisentraut.org      232                 :            148 :     rawsize = LZ4_decompress_safe_partial((const char *) value + VARHDRSZ_COMPRESSED,
 1873 rhaas@postgresql.org      233                 :ECB         (9) :                                           VARDATA(result),
 1870 tgl@sss.pgh.pa.us         234                 :CBC         148 :                                           VARSIZE(value) - VARHDRSZ_COMPRESSED,
                                235                 :                :                                           slicelength,
                                236                 :                :                                           slicelength);
 1873 rhaas@postgresql.org      237         [ -  + ]:            148 :     if (rawsize < 0)
 1873 rhaas@postgresql.org      238         [ #  # ]:UBC           0 :         ereport(ERROR,
                                239                 :                :                 (errcode(ERRCODE_DATA_CORRUPTED),
                                240                 :                :                  errmsg_internal("compressed lz4 data is corrupt")));
                                241                 :                : 
 1873 rhaas@postgresql.org      242                 :CBC         148 :     SET_VARSIZE(result, rawsize + VARHDRSZ);
                                243                 :                : 
                                244                 :            148 :     return result;
                                245                 :                : #endif
                                246                 :                : }
                                247                 :                : 
                                248                 :                : /*
                                249                 :                :  * Extract compression ID from a varlena.
                                250                 :                :  *
                                251                 :                :  * Returns TOAST_INVALID_COMPRESSION_ID if the varlena is not compressed.
                                252                 :                :  */
                                253                 :                : ToastCompressionId
   83 michael@paquier.xyz       254                 :GNC         128 : toast_get_compression_id(varlena *attr)
                                255                 :                : {
 1819 tgl@sss.pgh.pa.us         256                 :CBC         128 :     ToastCompressionId cmid = TOAST_INVALID_COMPRESSION_ID;
                                257                 :                : 
                                258                 :                :     /*
                                259                 :                :      * If it is stored externally then fetch the compression method id from
                                260                 :                :      * the external toast pointer.  If compressed inline, fetch it from the
                                261                 :                :      * toast compression header.
                                262                 :                :      */
 1873 rhaas@postgresql.org      263   [ +  +  +  - ]:            128 :     if (VARATT_IS_EXTERNAL_ONDISK(attr))
 1873 rhaas@postgresql.org      264                 :ECB        (12) :     {
                                265                 :                :         varatt_external toast_pointer;
                                266                 :                : 
 1873 rhaas@postgresql.org      267   [ -  +  -  +  :CBC          32 :         VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr);
                                     +  -  -  +  -  
                                                 + ]
                                268                 :                : 
                                269         [ +  + ]:             32 :         if (VARATT_EXTERNAL_IS_COMPRESSED(toast_pointer))
 1870 tgl@sss.pgh.pa.us         270                 :             12 :             cmid = VARATT_EXTERNAL_GET_COMPRESS_METHOD(toast_pointer);
                                271                 :                :     }
 1873 rhaas@postgresql.org      272         [ +  + ]:             96 :     else if (VARATT_IS_COMPRESSED(attr))
 1870 tgl@sss.pgh.pa.us         273                 :             88 :         cmid = VARDATA_COMPRESSED_GET_COMPRESS_METHOD(attr);
                                274                 :                : 
 1873 rhaas@postgresql.org      275                 :            128 :     return cmid;
                                276                 :                : }
                                277                 :                : 
                                278                 :                : /*
                                279                 :                :  * CompressionNameToMethod - Get compression method from compression name
                                280                 :                :  *
                                281                 :                :  * Search in the available built-in methods.  If the compression not found
                                282                 :                :  * in the built-in methods then return InvalidCompressionMethod.
                                283                 :                :  */
                                284                 :                : char
 1868                           285                 :            135 : CompressionNameToMethod(const char *compression)
                                286                 :                : {
                                287         [ +  + ]:            135 :     if (strcmp(compression, "pglz") == 0)
                                288                 :             84 :         return TOAST_PGLZ_COMPRESSION;
                                289         [ +  + ]:             51 :     else if (strcmp(compression, "lz4") == 0)
                                290                 :                :     {
                                291                 :                : #ifndef USE_LZ4
                                292                 :                :         NO_COMPRESSION_SUPPORT("lz4");
                                293                 :                : #endif
                                294                 :             43 :         return TOAST_LZ4_COMPRESSION;
                                295                 :                :     }
                                296                 :                : 
                                297                 :              8 :     return InvalidCompressionMethod;
                                298                 :                : }
                                299                 :                : 
                                300                 :                : /*
                                301                 :                :  * GetCompressionMethodName - Get compression method name
                                302                 :                :  */
                                303                 :                : const char *
                                304                 :             40 : GetCompressionMethodName(char method)
                                305                 :                : {
                                306      [ +  +  - ]:             40 :     switch (method)
                                307                 :                :     {
                                308                 :             28 :         case TOAST_PGLZ_COMPRESSION:
                                309                 :             28 :             return "pglz";
                                310                 :             12 :         case TOAST_LZ4_COMPRESSION:
                                311                 :             12 :             return "lz4";
 1868 rhaas@postgresql.org      312                 :UBC           0 :         default:
                                313         [ #  # ]:              0 :             elog(ERROR, "invalid compression method %c", method);
                                314                 :                :             return NULL;        /* keep compiler quiet */
                                315                 :                :     }
                                316                 :                : }
        

Generated by: LCOV version 2.5.0-beta