/* * contrib/hstore/hstore.h */ #ifndef __HSTORE_H__ #define __HSTORE_H__ #include "fmgr.h" #include "securec_check.h" #include "utils/array.h" /* * HEntry: there is one of these for each key _and_ value in an hstore * * the position offset points to the _end_ so that we can get the length * by subtraction from the previous entry. the ISFIRST flag lets us tell * whether there is a previous entry. */ typedef struct { uint32 entry; } HEntry; #define HENTRY_ISFIRST 0x80000000 #define HENTRY_ISNULL 0x40000000 #define HENTRY_POSMASK 0x3FFFFFFF /* note possible multiple evaluations, also access to prior array element */ #define HSE_ISFIRST(he_) (((he_).entry & HENTRY_ISFIRST) != 0) #define HSE_ISNULL(he_) (((he_).entry & HENTRY_ISNULL) != 0) #define HSE_ENDPOS(he_) ((he_).entry & HENTRY_POSMASK) #define HSE_OFF(he_) (HSE_ISFIRST(he_) ? 0 : HSE_ENDPOS((&(he_))[-1])) #define HSE_LEN(he_) (HSE_ISFIRST(he_) ? HSE_ENDPOS(he_) : HSE_ENDPOS(he_) - HSE_ENDPOS((&(he_))[-1])) /* * determined by the size of "endpos" (ie HENTRY_POSMASK), though this is a * bit academic since currently varlenas (and hence both the input and the * whole hstore) have the same limit */ #define HSTORE_MAX_KEY_LEN 0x3FFFFFFF #define HSTORE_MAX_VALUE_LEN 0x3FFFFFFF typedef struct { int32 vl_len_; /* varlena header (do not touch directly!) */ uint32 size_; /* flags and number of items in hstore */ /* array of HEntry follows */ } HStore; /* * It's not possible to get more than 2^28 items into an hstore, so we reserve * the top few bits of the size field. See hstore_compat.c for one reason * why. Some bits are left for future use here. MaxAllocSize makes the * practical count limit slightly more than 2^28 / 3, or INT_MAX / 24, the * limit for an hstore full of 4-byte keys and null values. Therefore, we * don't explicitly check the format-imposed limit. */ #define HS_FLAG_NEWVERSION 0x80000000 #define HS_COUNT(hsp_) ((hsp_)->size_ & 0x0FFFFFFF) #define HS_SETCOUNT(hsp_, c_) ((hsp_)->size_ = (c_) | HS_FLAG_NEWVERSION) /* * "x" comes from an existing HS_COUNT() (as discussed, <= INT_MAX/24) or a * Pairs array length (due to MaxAllocSize, <= INT_MAX/40). "lenstr" is no * more than INT_MAX, that extreme case arising in hstore_from_arrays(). * Therefore, this calculation is limited to about INT_MAX / 5 + INT_MAX. */ #define HSHRDSIZE (sizeof(HStore)) #define CALCDATASIZE(x, lenstr) ((x)*2 * sizeof(HEntry) + HSHRDSIZE + (lenstr)) /* note multiple evaluations of x */ #define ARRPTR(x) ((HEntry*)((HStore*)(x) + 1)) #define STRPTR(x) ((char*)(ARRPTR(x) + HS_COUNT((HStore*)(x)) * 2)) /* note multiple/non evaluations */ #define HS_KEY(arr_, str_, i_) ((str_) + HSE_OFF((arr_)[2 * (i_)])) #define HS_VAL(arr_, str_, i_) ((str_) + HSE_OFF((arr_)[2 * (i_) + 1])) #define HS_KEYLEN(arr_, i_) (HSE_LEN((arr_)[2 * (i_)])) #define HS_VALLEN(arr_, i_) (HSE_LEN((arr_)[2 * (i_) + 1])) #define HS_VALISNULL(arr_, i_) (HSE_ISNULL((arr_)[2 * (i_) + 1])) /* * currently, these following macros are the _only_ places that rely * on internal knowledge of HEntry. Everything else should be using * the above macros. Exception: the in-place upgrade in hstore_compat.c * messes with entries directly. */ /* * copy one key/value pair (which must be contiguous starting at * sptr_) into an under-construction hstore; dent_ is an HEntry*, * dbuf_ is the destination's string buffer, dptr_ is the current * position in the destination. lots of modification and multiple * evaluation here. */ #define HS_COPYITEM(dent_, dbuf_, dptr_, dlen_, sptr_, klen_, vlen_, vnull_) \ do { \ errno_t errorno = EOK; \ errorno = memcpy_s((dptr_), (dlen_), (sptr_), (klen_) + (vlen_)); \ securec_check(errorno, "\0", "\0"); \ (dptr_) += (klen_) + (vlen_); \ (dlen_) = (dlen_) - (klen_) - (vlen_); \ (dent_)++->entry = ((dptr_) - (dbuf_) - (vlen_)) & HENTRY_POSMASK; \ (dent_)++->entry = ((((dptr_) - (dbuf_)) & HENTRY_POSMASK) | ((vnull_) ? HENTRY_ISNULL : 0)); \ } while (0) /* * add one key/item pair, from a Pairs structure, into an * under-construction hstore */ #define HS_ADDITEM(dent_, dbuf_, dptr_, pair_, len) \ do { \ errno_t errorno = EOK; \ errorno = memcpy_s((dptr_), len, (pair_).key, (pair_).keylen); \ securec_check(errorno, "\0", "\0"); \ (dptr_) += (pair_).keylen; \ (len) = (len) - (pair_).keylen; \ (dent_)++->entry = ((dptr_) - (dbuf_)) & HENTRY_POSMASK; \ if ((pair_).isnull) \ (dent_)++->entry = ((((dptr_) - (dbuf_)) & HENTRY_POSMASK) | HENTRY_ISNULL); \ else { \ errorno = memcpy_s((dptr_), len, (pair_).val, (pair_).vallen); \ securec_check(errorno, "\0", "\0"); \ (dptr_) += (pair_).vallen; \ (len) = (len) - (pair_).vallen; \ (dent_)++->entry = ((dptr_) - (dbuf_)) & HENTRY_POSMASK; \ } \ } while (0) /* finalize a newly-constructed hstore */ #define HS_FINALIZE(hsp_, len_, count_, buf_, ptr_) \ do { \ int buflen = (ptr_) - (buf_); \ if ((count_)) \ ARRPTR(hsp_)[0].entry |= HENTRY_ISFIRST; \ if ((count_) != HS_COUNT((hsp_))) { \ HS_SETCOUNT((hsp_), (count_)); \ errno_t errorno = EOK; \ errorno = memmove_s(STRPTR(hsp_), len_, (buf_), buflen); \ securec_check(errorno, "\0", "\0"); \ } \ SET_VARSIZE((hsp_), CALCDATASIZE((count_), buflen)); \ } while (0) /* ensure the varlena size of an existing hstore is correct */ #define HS_FIXSIZE(hsp_, count_) \ do { \ int bl = (count_) ? HSE_ENDPOS(ARRPTR(hsp_)[2 * (count_)-1]) : 0; \ SET_VARSIZE((hsp_), CALCDATASIZE((count_), bl)); \ } while (0) /* DatumGetHStoreP includes support for reading old-format hstore values */ extern HStore* hstoreUpgrade(Datum orig); #define DatumGetHStoreP(d) (d) ? (hstoreUpgrade(d)) : ((HStore*)NULL) #define PG_GETARG_HS(x) DatumGetHStoreP(PG_GETARG_DATUM(x)) #define NOT_NULL_HS(x) \ do { \ if (unlikely(x == NULL)) { \ ereport(ERROR, \ (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), \ errmsg("NULL HStore is invalid"))); \ } \ }while(0) /* * Pairs is a "decompressed" representation of one key/value pair. * The two strings are not necessarily null-terminated. */ typedef struct { char* key; char* val; size_t keylen; size_t vallen; bool isnull; /* value is null? */ bool needfree; /* need to pfree the value? */ } Pairs; extern int hstoreUniquePairs(Pairs* a, int4 l, int4* buflen); extern HStore* hstorePairs(Pairs* pairs, int4 pcount, int4 buflen); extern size_t hstoreCheckKeyLen(size_t len); extern size_t hstoreCheckValLen(size_t len); extern int hstoreFindKey(HStore* hs, int* lowbound, const char* key, uint32 keylen); extern Pairs* hstoreArrayToPairs(ArrayType* a, int* npairs); #define HStoreContainsStrategyNumber 7 #define HStoreExistsStrategyNumber 9 #define HStoreExistsAnyStrategyNumber 10 #define HStoreExistsAllStrategyNumber 11 #define HStoreOldContainsStrategyNumber 13 /* backwards compatibility */ /* * defining HSTORE_POLLUTE_NAMESPACE=0 will prevent use of old function names; * for now, we default to on for the benefit of people restoring old dumps */ #ifndef HSTORE_POLLUTE_NAMESPACE #define HSTORE_POLLUTE_NAMESPACE 1 #endif #if HSTORE_POLLUTE_NAMESPACE #define HSTORE_POLLUTE(newname_, oldname_) \ PG_FUNCTION_INFO_V1(oldname_); \ extern "C" Datum oldname_(PG_FUNCTION_ARGS); \ extern "C" Datum newname_(PG_FUNCTION_ARGS); \ Datum oldname_(PG_FUNCTION_ARGS) \ { \ return newname_(fcinfo); \ } \ extern int no_such_variable #else #define HSTORE_POLLUTE(newname_, oldname_) extern int no_such_variable #endif #endif /* __HSTORE_H__ */