diff options
Diffstat (limited to 'src/include/utils/jsonb.h')
-rw-r--r-- | src/include/utils/jsonb.h | 320 |
1 files changed, 320 insertions, 0 deletions
diff --git a/src/include/utils/jsonb.h b/src/include/utils/jsonb.h new file mode 100644 index 00000000000..a70cbd59400 --- /dev/null +++ b/src/include/utils/jsonb.h @@ -0,0 +1,320 @@ +/*------------------------------------------------------------------------- + * + * jsonb.h + * Declarations for jsonb data type support. + * + * Copyright (c) 1996-2014, PostgreSQL Global Development Group + * + * src/include/utils/jsonb.h + * + *------------------------------------------------------------------------- + */ +#ifndef __JSONB_H__ +#define __JSONB_H__ + +#include "lib/stringinfo.h" +#include "utils/array.h" +#include "utils/numeric.h" + +/* + * JB_CMASK is used to extract count of items + * + * It's not possible to get more than 2^28 items into an Jsonb. + */ +#define JB_CMASK 0x0FFFFFFF + +#define JB_FSCALAR 0x10000000 +#define JB_FOBJECT 0x20000000 +#define JB_FARRAY 0x40000000 + +/* Get information on varlena Jsonb */ +#define JB_ROOT_COUNT(jbp_) ( *(uint32*) VARDATA(jbp_) & JB_CMASK) +#define JB_ROOT_IS_SCALAR(jbp_) ( *(uint32*) VARDATA(jbp_) & JB_FSCALAR) +#define JB_ROOT_IS_OBJECT(jbp_) ( *(uint32*) VARDATA(jbp_) & JB_FOBJECT) +#define JB_ROOT_IS_ARRAY(jbp_) ( *(uint32*) VARDATA(jbp_) & JB_FARRAY) + +/* Jentry macros */ +#define JENTRY_POSMASK 0x0FFFFFFF +#define JENTRY_ISFIRST 0x80000000 +#define JENTRY_TYPEMASK (~(JENTRY_POSMASK | JENTRY_ISFIRST)) +#define JENTRY_ISSTRING 0x00000000 +#define JENTRY_ISNUMERIC 0x10000000 +#define JENTRY_ISNEST 0x20000000 +#define JENTRY_ISNULL 0x40000000 +#define JENTRY_ISBOOL (JENTRY_ISNUMERIC | JENTRY_ISNEST) +#define JENTRY_ISFALSE JENTRY_ISBOOL +#define JENTRY_ISTRUE (JENTRY_ISBOOL | 0x40000000) +/* Note possible multiple evaluations, also access to prior array element */ +#define JBE_ISFIRST(je_) (((je_).header & JENTRY_ISFIRST) != 0) +#define JBE_ISSTRING(je_) (((je_).header & JENTRY_TYPEMASK) == JENTRY_ISSTRING) +#define JBE_ISNUMERIC(je_) (((je_).header & JENTRY_TYPEMASK) == JENTRY_ISNUMERIC) +#define JBE_ISNEST(je_) (((je_).header & JENTRY_TYPEMASK) == JENTRY_ISNEST) +#define JBE_ISNULL(je_) (((je_).header & JENTRY_TYPEMASK) == JENTRY_ISNULL) +#define JBE_ISBOOL(je_) (((je_).header & JENTRY_TYPEMASK & JENTRY_ISBOOL) == JENTRY_ISBOOL) +#define JBE_ISBOOL_TRUE(je_) (((je_).header & JENTRY_TYPEMASK) == JENTRY_ISTRUE) +#define JBE_ISBOOL_FALSE(je_) (JBE_ISBOOL(je_) && !JBE_ISBOOL_TRUE(je_)) + +/* Get offset for Jentry */ +#define JBE_ENDPOS(je_) ((je_).header & JENTRY_POSMASK) +#define JBE_OFF(je_) (JBE_ISFIRST(je_) ? 0 : JBE_ENDPOS((&(je_))[-1])) +#define JBE_LEN(je_) (JBE_ISFIRST(je_) ? \ + JBE_ENDPOS(je_) \ + : JBE_ENDPOS(je_) - JBE_ENDPOS((&(je_))[-1])) + +/* Flags indicating a stage of sequential Jsonb processing */ +#define WJB_DONE 0x000 +#define WJB_KEY 0x001 +#define WJB_VALUE 0x002 +#define WJB_ELEM 0x004 +#define WJB_BEGIN_ARRAY 0x008 +#define WJB_END_ARRAY 0x010 +#define WJB_BEGIN_OBJECT 0x020 +#define WJB_END_OBJECT 0x040 + +/* + * When using a GIN index for jsonb, we choose to index both keys and values. + * The storage format is text, with K, or V prepended to the string to indicate + * key/element or value/element. + * + * Jsonb Keys and string array elements are treated equivalently when + * serialized to text index storage. One day we may wish to create an opclass + * that only indexes values, but for now keys and values are stored in GIN + * indexes in a way that doesn't really consider their relationship to each + * other. + */ +#define JKEYELEM 'K' +#define JVAL 'V' + +#define JsonbContainsStrategyNumber 7 +#define JsonbExistsStrategyNumber 9 +#define JsonbExistsAnyStrategyNumber 10 +#define JsonbExistsAllStrategyNumber 11 + +/* Convenience macros */ +#define DatumGetJsonb(d) ((Jsonb *) PG_DETOAST_DATUM(d)) +#define JsonbGetDatum(p) PointerGetDatum(p) +#define PG_GETARG_JSONB(x) DatumGetJsonb(PG_GETARG_DATUM(x)) +#define PG_RETURN_JSONB(x) PG_RETURN_POINTER(x) + +typedef struct JsonbPair JsonbPair; +typedef struct JsonbValue JsonbValue; +typedef char* JsonbSuperHeader; + +/* + * Jsonbs are varlena objects, so must meet the varlena convention that the + * first int32 of the object contains the total object size in bytes. Be sure + * to use VARSIZE() and SET_VARSIZE() to access it, though! + * + * Jsonb is the on-disk representation, in contrast to the in-memory JsonbValue + * representation. Often, JsonbValues are just shims through which a Jsonb + * buffer is accessed, but they can also be deep copied and passed around. + * + * We have an abstraction called a "superheader". This is a pointer that + * conventionally points to the first item after our 4-byte uncompressed + * varlena header, from which we can read flags using bitwise operations. + * + * Frequently, we pass a superheader reference to a function, and it doesn't + * matter if it points to just after the start of a Jsonb, or to a temp buffer. + */ +typedef struct +{ + int32 vl_len_; /* varlena header (do not touch directly!) */ + uint32 superheader; + /* (array of JEntry follows, size determined using uint32 superheader) */ +} Jsonb; + +/* + * JEntry: there is one of these for each key _and_ value for objects. Arrays + * have one per element. + * + * The position offset points to the _end_ so that we can get the length by + * subtraction from the previous entry. The JENTRY_ISFIRST flag indicates if + * there is a previous entry. + */ +typedef struct +{ + uint32 header; /* Shares some flags with superheader */ +} JEntry; + +#define IsAJsonbScalar(jsonbval) ((jsonbval)->type >= jbvNull && \ + (jsonbval)->type <= jbvBool) + +/* + * JsonbValue: In-memory representation of Jsonb. This is a convenient + * deserialized representation, that can easily support using the anonymous + * union across underlying types during manipulation. The Jsonb on-disk + * representation has various alignment considerations. + */ +struct JsonbValue +{ + enum + { + /* Scalar types */ + jbvNull = 0x0, + jbvString, + jbvNumeric, + jbvBool, + /* Composite types */ + jbvArray = 0x10, + jbvObject, + /* Binary (i.e. struct Jsonb) jbvArray/jbvObject */ + jbvBinary + } type; /* Influences sort order */ + + int estSize; /* Estimated size of node (including + * subnodes) */ + + union + { + Numeric numeric; + bool boolean; + struct + { + int len; + char *val; /* Not necessarily null-terminated */ + } string; /* String primitive type */ + + struct + { + int nElems; + JsonbValue *elems; + bool rawScalar; /* Top-level "raw scalar" array? */ + } array; /* Array container type */ + + struct + { + int nPairs; /* 1 pair, 2 elements */ + JsonbPair *pairs; + } object; /* Associative container type */ + + struct + { + int len; + char *data; + } binary; + }; +}; + +/* + * Pair within an Object. + * + * Pairs with duplicate keys are de-duplicated. We store the order for the + * benefit of doing so in a well-defined way with respect to the original + * observed order (which is "last observed wins"). This is only used briefly + * when originally constructing a Jsonb. + */ +struct JsonbPair +{ + JsonbValue key; /* Must be a jbvString */ + JsonbValue value; /* May be of any type */ + uint32 order; /* preserves order of pairs with equal keys */ +}; + +/* Conversion state used when parsing Jsonb from text, or for type coercion */ +typedef struct JsonbParseState +{ + JsonbValue contVal; + Size size; + struct JsonbParseState *next; +} JsonbParseState; + +/* + * JsonbIterator holds details of the type for each iteration. It also stores a + * Jsonb varlena buffer, which can be directly accessed in some contexts. + */ +typedef enum +{ + jbi_start = 0x0, + jbi_key, + jbi_value, + jbi_elem +} JsonbIterState; + +typedef struct JsonbIterator +{ + /* Jsonb varlena buffer (may or may not be root) */ + char *buffer; + + /* Current value */ + uint32 containerType; /* Never of value JB_FSCALAR, since + * scalars will appear in pseudo-arrays */ + uint32 nElems; /* Number of elements in metaArray + * (will be nPairs for objects) */ + bool isScalar; /* Pseudo-array scalar value? */ + JEntry *meta; + + /* Current item in buffer (up to nElems, but must * 2 for objects) */ + int i; + + /* + * Data proper. Note that this points just past end of "meta" array. We + * use its metadata (Jentrys) with JBE_OFF() macro to find appropriate + * offsets into this array. + */ + char *dataProper; + + /* Private state */ + JsonbIterState state; + + struct JsonbIterator *parent; +} JsonbIterator; + +/* I/O routines */ +extern Datum jsonb_in(PG_FUNCTION_ARGS); +extern Datum jsonb_out(PG_FUNCTION_ARGS); +extern Datum jsonb_recv(PG_FUNCTION_ARGS); +extern Datum jsonb_send(PG_FUNCTION_ARGS); +extern Datum jsonb_typeof(PG_FUNCTION_ARGS); + +/* Indexing-related ops */ +extern Datum jsonb_exists(PG_FUNCTION_ARGS); +extern Datum jsonb_exists_any(PG_FUNCTION_ARGS); +extern Datum jsonb_exists_all(PG_FUNCTION_ARGS); +extern Datum jsonb_contains(PG_FUNCTION_ARGS); +extern Datum jsonb_contained(PG_FUNCTION_ARGS); +extern Datum jsonb_ne(PG_FUNCTION_ARGS); +extern Datum jsonb_lt(PG_FUNCTION_ARGS); +extern Datum jsonb_gt(PG_FUNCTION_ARGS); +extern Datum jsonb_le(PG_FUNCTION_ARGS); +extern Datum jsonb_ge(PG_FUNCTION_ARGS); +extern Datum jsonb_eq(PG_FUNCTION_ARGS); +extern Datum jsonb_cmp(PG_FUNCTION_ARGS); +extern Datum jsonb_hash(PG_FUNCTION_ARGS); + +/* GIN support functions */ +extern Datum gin_compare_jsonb(PG_FUNCTION_ARGS); +extern Datum gin_extract_jsonb(PG_FUNCTION_ARGS); +extern Datum gin_extract_jsonb_query(PG_FUNCTION_ARGS); +extern Datum gin_consistent_jsonb(PG_FUNCTION_ARGS); +extern Datum gin_triconsistent_jsonb(PG_FUNCTION_ARGS); +/* GIN hash opclass functions */ +extern Datum gin_extract_jsonb_hash(PG_FUNCTION_ARGS); +extern Datum gin_extract_jsonb_query_hash(PG_FUNCTION_ARGS); +extern Datum gin_consistent_jsonb_hash(PG_FUNCTION_ARGS); +extern Datum gin_triconsistent_jsonb_hash(PG_FUNCTION_ARGS); + +/* Support functions */ +extern int compareJsonbSuperHeaderValue(JsonbSuperHeader a, + JsonbSuperHeader b); +extern JsonbValue *findJsonbValueFromSuperHeader(JsonbSuperHeader sheader, + uint32 flags, + uint32 *lowbound, + JsonbValue *key); +extern JsonbValue *getIthJsonbValueFromSuperHeader(JsonbSuperHeader sheader, + uint32 i); +extern JsonbValue *pushJsonbValue(JsonbParseState ** pstate, int seq, + JsonbValue *scalarVal); +extern JsonbIterator *JsonbIteratorInit(JsonbSuperHeader buffer); +extern int JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, + bool skipNested); +extern Jsonb *JsonbValueToJsonb(JsonbValue *val); +extern bool JsonbDeepContains(JsonbIterator ** val, + JsonbIterator ** mContained); +extern JsonbValue *arrayToJsonbSortedArray(ArrayType *a); +extern void JsonbHashScalarValue(const JsonbValue * scalarVal, uint32 * hash); + +/* jsonb.c support function */ +extern char *JsonbToCString(StringInfo out, JsonbSuperHeader in, + int estimated_len); + +#endif /* __JSONB_H__ */ |