/* * contrib/hstore/hstore.h */ #ifndef __HSTORE_H__ #define __HSTORE_H__ #include "fmgr.h" #include "lib/stringinfo.h" #include "utils/array.h" #include "utils/numeric.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_ISSTRING (0x00000000) /* keep binary compatibility */ #define HENTRY_ISNUMERIC (0x10000000) #define HENTRY_ISNEST (0x20000000) #define HENTRY_ISNULL (0x40000000) /* keep binary compatibility */ #define HENTRY_ISBOOL (0x10000000 | 0x20000000) #define HENTRY_ISFALSE HENTRY_ISBOOL #define HENTRY_ISTRUE (0x10000000 | 0x20000000 | 0x40000000) /* HENTRY_ISHASH, HENTRY_ISARRAY and HENTRY_ISSCALAR is only used in send/recv */ #define HENTRY_ISHASH (0x20000000) #define HENTRY_ISARRAY (0x20000000 | 0x40000000) #define HENTRY_ISSCALAR (0x10000000 | 0x40000000) #define HENTRY_POSMASK 0x0FFFFFFF #define HENTRY_TYPEMASK (~(HENTRY_POSMASK | HENTRY_ISFIRST)) /* note possible multiple evaluations, also access to prior array element */ #define HSE_ISFIRST(he_) (((he_).entry & HENTRY_ISFIRST) != 0) #define HSE_ISSTRING(he_) (((he_).entry & HENTRY_TYPEMASK) == \ HENTRY_ISSTRING) #define HSE_ISNUMERIC(he_) (((he_).entry & HENTRY_TYPEMASK) == \ HENTRY_ISNUMERIC) #define HSE_ISNEST(he_) (((he_).entry & HENTRY_TYPEMASK) == \ HENTRY_ISNEST) #define HSE_ISNULL(he_) (((he_).entry & HENTRY_TYPEMASK) == \ HENTRY_ISNULL) #define HSE_ISBOOL(he_) (((he_).entry & HENTRY_ISBOOL) == \ HENTRY_ISBOOL) #define HSE_ISBOOL_TRUE(he_) (((he_).entry & HENTRY_TYPEMASK) == \ HENTRY_ISTRUE) #define HSE_ISBOOL_FALSE(he_) (HSE_ISBOOL(he_) && !HSE_ISBOOL_TRUE(he_)) #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) */ #define HSTORE_MAX_KEY_LEN HENTRY_POSMASK #define HSTORE_MAX_VALUE_LEN HENTRY_POSMASK typedef struct { int32 vl_len_; /* varlena header (do not touch directly!) */ /* header of hash or array hstore type */ /* 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_FLAG_ARRAY 0x40000000 #define HS_FLAG_HSTORE 0x20000000 #define HS_FLAG_SCALAR 0x10000000 #define HS_COUNT_MASK 0x0FFFFFFF #define HS_ISEMPTY(hsp_) (VARSIZE(hsp_) <= VARHDRSZ) #define HS_ROOT_COUNT(hsp_) (HS_ISEMPTY(hsp_) ? 0 : \ ( *(uint32*)VARDATA(hsp_) & HS_COUNT_MASK)) #define HS_ROOT_IS_HASH(hsp_) (HS_ISEMPTY(hsp_) ? 0 : \ ( *(uint32*)VARDATA(hsp_) & HS_FLAG_HSTORE)) #define HS_ROOT_IS_ARRAY(hsp_) (HS_ISEMPTY(hsp_) ? 0 : \ ( *(uint32*)VARDATA(hsp_) & HS_FLAG_ARRAY)) #define HS_ROOT_IS_SCALAR(hsp_) (HS_ISEMPTY(hsp_) ? 0 : \ ( *(uint32*)VARDATA(hsp_) & HS_FLAG_SCALAR)) /* DatumGetHStoreP includes support for reading old-format hstore values */ extern HStore *hstoreUpgrade(Datum orig); #define DatumGetHStoreP(d) hstoreUpgrade(d) #define PG_GETARG_HS(x) DatumGetHStoreP(PG_GETARG_DATUM(x)) typedef struct HStorePair HStorePair; typedef struct HStoreValue HStoreValue; struct HStoreValue { enum { hsvNull, hsvString, hsvNumeric, hsvBool, hsvArray, hsvHash, hsvBinary /* binary form of hsvArray/hsvHash */ } type; uint32 size; /* estimation size of node (including subnodes) */ union { Numeric numeric; bool boolean; struct { uint32 len; char *val; /* could be not null-terminated */ } string; struct { int nelems; HStoreValue *elems; /* * scalar actually shares representation with array */ bool scalar; } array; struct { int npairs; HStorePair *pairs; } hash; struct { uint32 len; char *data; } binary; }; }; struct HStorePair { HStoreValue key; HStoreValue value; uint32 order; /* to keep order of pairs with equal key */ }; extern HStoreValue* parseHStore(const char *str, int len, bool json); /* * hstore support functios */ #define WHS_KEY (0x001) #define WHS_VALUE (0x002) #define WHS_ELEM (0x004) #define WHS_BEGIN_ARRAY (0x008) #define WHS_END_ARRAY (0x010) #define WHS_BEGIN_HASH (0x020) #define WHS_END_HASH (0x040) typedef void (*walk_hstore_cb)(void* /*arg*/, HStoreValue* /* value */, uint32 /* flags */, uint32 /* level */); extern void walkUncompressedHStore(HStoreValue *v, walk_hstore_cb cb, void *cb_arg); extern int compareHStoreStringValue(const void *a, const void *b, void *arg); extern int compareHStorePair(const void *a, const void *b, void *arg); extern int compareHStoreBinaryValue(char *a, char *b); extern int compareHStoreValue(HStoreValue *a, HStoreValue *b); extern HStoreValue* findUncompressedHStoreValueByValue(char *buffer, uint32 flags, uint32 *lowbound, HStoreValue* key); extern HStoreValue* findUncompressedHStoreValue(char *buffer, uint32 flags, uint32 *lowbound, char *key, uint32 keylen); extern HStoreValue* getHStoreValue(char *buffer, uint32 flags, int32 i); extern bool stringIsNumber(char *string, int len, bool jsonNumber); typedef enum HStoreOutputKind { JsonOutput = 0x01, LooseOutput = 0x02, ArrayCurlyBraces = 0x04, RootHashDecorated = 0x08, PrettyPrint = 0x10 } HStoreOutputKind; extern char* hstoreToCString(StringInfo out, char *in, int len /* just estimation */, HStoreOutputKind kind); extern text* HStoreValueToText(HStoreValue *v); typedef struct ToHStoreState { HStoreValue v; uint32 size; struct ToHStoreState *next; } ToHStoreState; extern HStoreValue* pushHStoreValue(ToHStoreState **state, int r /* WHS_* */, HStoreValue *v); extern void uniqueHStoreValue(HStoreValue *v); extern uint32 compressHStore(HStoreValue *v, char *buffer); typedef struct HStoreIterator { uint32 type; uint32 nelems; HEntry *array; bool isScalar; char *data; char *buffer; /* unparsed buffer */ int i; /* * enum members should be freely OR'ed with HS_FLAG_ARRAY/HS_FLAG_HSTORE * with possiblity of decoding. See optimization in HStoreIteratorGet() */ enum { hsi_start = 0x00, hsi_key = 0x01, hsi_value = 0x02, hsi_elem = 0x04 } state; struct HStoreIterator *next; } HStoreIterator; extern HStoreIterator* HStoreIteratorInit(char *buffer); extern int /* WHS_* */ HStoreIteratorGet(HStoreIterator **it, HStoreValue *v, bool skipNested); #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_); \ Datum oldname_(PG_FUNCTION_ARGS); \ 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 /* * When using a GIN/GiST index for hstore, we choose to index both keys and values. * The storage format is "text" values, with K, V, E or N prepended to the string * to indicate key, value, element or null values. (As of 9.1 it might be better to * store null values as nulls, but we'll keep it this way for on-disk * compatibility.) Before nested hstore GIN indexes used KV notation, so there is * no problem with upgrade, but GiST indexes should be rebuilded. */ #define ELEMFLAG 'E' #define KEYFLAG 'K' #define VALFLAG 'V' #define NULLFLAG 'N' #endif /* __HSTORE_H__ */