LCOV - code coverage report
Current view: top level - contrib/hstore - hstore.h (source / functions) Coverage Total Hit
Test: PostgreSQL 20devel Lines: 100.0 % 4 4
Test Date: 2026-09-05 06:15:58 Functions: 100.0 % 1 1
Legend: Lines:     hit not hit

            Line data    Source code
       1              : /*
       2              :  * contrib/hstore/hstore.h
       3              :  */
       4              : #ifndef __HSTORE_H__
       5              : #define __HSTORE_H__
       6              : 
       7              : #include "fmgr.h"
       8              : #include "utils/array.h"
       9              : 
      10              : 
      11              : /*
      12              :  * HEntry: there is one of these for each key _and_ value in an hstore
      13              :  *
      14              :  * the position offset points to the _end_ so that we can get the length
      15              :  * by subtraction from the previous entry.  the ISFIRST flag lets us tell
      16              :  * whether there is a previous entry.
      17              :  */
      18              : typedef struct
      19              : {
      20              :     uint32      entry;
      21              : } HEntry;
      22              : 
      23              : #define HENTRY_ISFIRST 0x80000000
      24              : #define HENTRY_ISNULL  0x40000000
      25              : #define HENTRY_POSMASK 0x3FFFFFFF
      26              : 
      27              : /* note possible multiple evaluations, also access to prior array element */
      28              : #define HSE_ISFIRST(he_) (((he_).entry & HENTRY_ISFIRST) != 0)
      29              : #define HSE_ISNULL(he_) (((he_).entry & HENTRY_ISNULL) != 0)
      30              : #define HSE_ENDPOS(he_) ((he_).entry & HENTRY_POSMASK)
      31              : #define HSE_OFF(he_) (HSE_ISFIRST(he_) ? 0 : HSE_ENDPOS((&(he_))[-1]))
      32              : #define HSE_LEN(he_) (HSE_ISFIRST(he_)  \
      33              :                       ? HSE_ENDPOS(he_) \
      34              :                       : HSE_ENDPOS(he_) - HSE_ENDPOS((&(he_))[-1]))
      35              : 
      36              : /*
      37              :  * determined by the size of "endpos" (ie HENTRY_POSMASK), though this is a
      38              :  * bit academic since currently varlenas (and hence both the input and the
      39              :  * whole hstore) have the same limit
      40              :  */
      41              : #define HSTORE_MAX_KEY_LEN 0x3FFFFFFF
      42              : #define HSTORE_MAX_VALUE_LEN 0x3FFFFFFF
      43              : 
      44              : typedef struct
      45              : {
      46              :     int32       vl_len_;        /* varlena header (do not touch directly!) */
      47              :     uint32      size_;          /* flags and number of items in hstore */
      48              :     /* array of HEntry follows */
      49              : } HStore;
      50              : 
      51              : /*
      52              :  * It's not possible to get more than 2^28 items into an hstore, so we reserve
      53              :  * the top few bits of the size field.  See hstore_compat.c for one reason
      54              :  * why.  Some bits are left for future use here.  MaxAllocSize makes the
      55              :  * practical count limit slightly more than 2^28 / 3, or INT_MAX / 24, the
      56              :  * limit for an hstore full of 4-byte keys and null values.  Therefore, we
      57              :  * don't explicitly check the format-imposed limit.
      58              :  */
      59              : #define HS_FLAG_NEWVERSION 0x80000000
      60              : 
      61              : #define HS_COUNT(hsp_) ((hsp_)->size_ & 0x0FFFFFFF)
      62              : #define HS_SETCOUNT(hsp_,c_) ((hsp_)->size_ = (c_) | HS_FLAG_NEWVERSION)
      63              : 
      64              : 
      65              : #define HSHRDSIZE   (sizeof(HStore))
      66              : 
      67              : /*
      68              :  * "x" is a pair count, coming from an existing HS_COUNT() (as discussed, <=
      69              :  * INT_MAX/24) or a Pairs array length (due to MaxAllocSize, <= INT_MAX/40).
      70              :  * "lenstr" is no more than INT_MAX, that extreme case arising in
      71              :  * hstore_from_arrays().  Therefore, this calculation should be limited to
      72              :  * about INT_MAX / 5 + INT_MAX.
      73              :  */
      74              : static inline Size
      75         2648 : hstoreCalcDataSize(Size x, Size lenstr)
      76              : {
      77         2648 :     Size        entrysize = mul_size(x, 2 * sizeof(HEntry));
      78         2648 :     Size        total = add_size(HSHRDSIZE, lenstr);
      79              : 
      80         2648 :     return add_size(entrysize, total);
      81              : }
      82              : 
      83              : /* note multiple evaluations of x */
      84              : #define ARRPTR(x)       ( (HEntry*) ( (HStore*)(x) + 1 ) )
      85              : #define STRPTR(x)       ( (char*)(ARRPTR(x) + HS_COUNT((HStore*)(x)) * 2) )
      86              : 
      87              : /* note multiple/non evaluations */
      88              : #define HSTORE_KEY(arr_,str_,i_)    ((str_) + HSE_OFF((arr_)[2*(i_)]))
      89              : #define HSTORE_VAL(arr_,str_,i_)    ((str_) + HSE_OFF((arr_)[2*(i_)+1]))
      90              : #define HSTORE_KEYLEN(arr_,i_)      (HSE_LEN((arr_)[2*(i_)]))
      91              : #define HSTORE_VALLEN(arr_,i_)      (HSE_LEN((arr_)[2*(i_)+1]))
      92              : #define HSTORE_VALISNULL(arr_,i_)   (HSE_ISNULL((arr_)[2*(i_)+1]))
      93              : 
      94              : /*
      95              :  * currently, these following macros are the _only_ places that rely
      96              :  * on internal knowledge of HEntry. Everything else should be using
      97              :  * the above macros. Exception: the in-place upgrade in hstore_compat.c
      98              :  * messes with entries directly.
      99              :  */
     100              : 
     101              : /*
     102              :  * copy one key/value pair (which must be contiguous starting at
     103              :  * sptr_) into an under-construction hstore; dent_ is an HEntry*,
     104              :  * dbuf_ is the destination's string buffer, dptr_ is the current
     105              :  * position in the destination. lots of modification and multiple
     106              :  * evaluation here.
     107              :  */
     108              : #define HS_COPYITEM(dent_,dbuf_,dptr_,sptr_,klen_,vlen_,vnull_)         \
     109              :     do {                                                                \
     110              :         memcpy((dptr_), (sptr_), (klen_)+(vlen_));                      \
     111              :         (dptr_) += (klen_)+(vlen_);                                     \
     112              :         (dent_)++->entry = ((dptr_) - (dbuf_) - (vlen_)) & HENTRY_POSMASK; \
     113              :         (dent_)++->entry = ((((dptr_) - (dbuf_)) & HENTRY_POSMASK)       \
     114              :                              | ((vnull_) ? HENTRY_ISNULL : 0));         \
     115              :     } while(0)
     116              : 
     117              : /*
     118              :  * add one key/item pair, from a Pairs structure, into an
     119              :  * under-construction hstore
     120              :  */
     121              : #define HS_ADDITEM(dent_,dbuf_,dptr_,pair_)                             \
     122              :     do {                                                                \
     123              :         memcpy((dptr_), (pair_).key, (pair_).keylen);                   \
     124              :         (dptr_) += (pair_).keylen;                                      \
     125              :         (dent_)++->entry = ((dptr_) - (dbuf_)) & HENTRY_POSMASK;     \
     126              :         if ((pair_).isnull)                                             \
     127              :             (dent_)++->entry = ((((dptr_) - (dbuf_)) & HENTRY_POSMASK)   \
     128              :                                  | HENTRY_ISNULL);                      \
     129              :         else                                                            \
     130              :         {                                                               \
     131              :             memcpy((dptr_), (pair_).val, (pair_).vallen);               \
     132              :             (dptr_) += (pair_).vallen;                                  \
     133              :             (dent_)++->entry = ((dptr_) - (dbuf_)) & HENTRY_POSMASK; \
     134              :         }                                                               \
     135              :     } while (0)
     136              : 
     137              : /* finalize a newly-constructed hstore */
     138              : #define HS_FINALIZE(hsp_,count_,buf_,ptr_)                          \
     139              :     do {                                                            \
     140              :         Size _buflen = (ptr_) - (buf_);                             \
     141              :         if ((count_))                                               \
     142              :             ARRPTR(hsp_)[0].entry |= HENTRY_ISFIRST;                \
     143              :         if ((count_) != HS_COUNT((hsp_)))                           \
     144              :         {                                                           \
     145              :             HS_SETCOUNT((hsp_),(count_));                           \
     146              :             memmove(STRPTR(hsp_), (buf_), _buflen);                 \
     147              :         }                                                           \
     148              :         SET_VARSIZE((hsp_), hstoreCalcDataSize((count_), _buflen)); \
     149              :     } while (0)
     150              : 
     151              : /* ensure the varlena size of an existing hstore is correct */
     152              : #define HS_FIXSIZE(hsp_,count_)                                         \
     153              :     do {                                                                \
     154              :         Size bl = (count_) ? HSE_ENDPOS(ARRPTR(hsp_)[2*(count_)-1]) : 0; \
     155              :         SET_VARSIZE((hsp_), hstoreCalcDataSize((count_),bl));               \
     156              :     } while (0)
     157              : 
     158              : /* DatumGetHStoreP includes support for reading old-format hstore values */
     159              : extern PGDLLEXPORT HStore *hstoreUpgrade(Datum orig);
     160              : 
     161              : #define DatumGetHStoreP(d) hstoreUpgrade(d)
     162              : 
     163              : #define PG_GETARG_HSTORE_P(x) DatumGetHStoreP(PG_GETARG_DATUM(x))
     164              : 
     165              : 
     166              : /*
     167              :  * Pairs is a "decompressed" representation of one key/value pair.
     168              :  * The two strings are not necessarily null-terminated.
     169              :  */
     170              : typedef struct
     171              : {
     172              :     char       *key;
     173              :     char       *val;
     174              :     size_t      keylen;
     175              :     size_t      vallen;
     176              :     bool        isnull;         /* value is null? */
     177              :     bool        needfree;       /* need to pfree the value? */
     178              : } Pairs;
     179              : 
     180              : extern PGDLLEXPORT int hstoreUniquePairs(Pairs *a, int32 l, Size *buflen);
     181              : extern PGDLLEXPORT HStore *hstorePairs(Pairs *pairs, int32 pcount, Size buflen);
     182              : 
     183              : extern PGDLLEXPORT size_t hstoreCheckKeyLen(size_t len);
     184              : extern PGDLLEXPORT size_t hstoreCheckValLen(size_t len);
     185              : 
     186              : extern PGDLLEXPORT int hstoreFindKey(HStore *hs, int *lowbound, char *key, int keylen);
     187              : extern PGDLLEXPORT Pairs *hstoreArrayToPairs(ArrayType *a, int *npairs);
     188              : 
     189              : #define HStoreContainsStrategyNumber    7
     190              : #define HStoreExistsStrategyNumber      9
     191              : #define HStoreExistsAnyStrategyNumber   10
     192              : #define HStoreExistsAllStrategyNumber   11
     193              : #define HStoreOldContainsStrategyNumber 13  /* backwards compatibility */
     194              : 
     195              : /*
     196              :  * defining HSTORE_POLLUTE_NAMESPACE=0 will prevent use of old function names;
     197              :  * for now, we default to on for the benefit of people restoring old dumps
     198              :  */
     199              : #ifndef HSTORE_POLLUTE_NAMESPACE
     200              : #define HSTORE_POLLUTE_NAMESPACE 1
     201              : #endif
     202              : 
     203              : #if HSTORE_POLLUTE_NAMESPACE
     204              : #define HSTORE_POLLUTE(newname_,oldname_) \
     205              :     PG_FUNCTION_INFO_V1(oldname_);        \
     206              :     extern PGDLLEXPORT Datum newname_(PG_FUNCTION_ARGS);      \
     207              :     Datum oldname_(PG_FUNCTION_ARGS) { return newname_(fcinfo); } \
     208              :     extern int no_such_variable
     209              : #else
     210              : #define HSTORE_POLLUTE(newname_,oldname_) \
     211              :     extern int no_such_variable
     212              : #endif
     213              : 
     214              : #endif                          /* __HSTORE_H__ */
        

Generated by: LCOV version 2.0-1