codestyle
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -1,15 +1,15 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
/* -------------------------------------------------------------------------
|
||||
*
|
||||
* jsonb.c
|
||||
* jsonb.cpp
|
||||
* I/O routines for jsonb type
|
||||
*
|
||||
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
* Portions Copyright (c) 2021 Huawei Technologies Co.,Ltd.
|
||||
* Copyright (c) 2014, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/backend/utils/adt/jsonb.c
|
||||
* src/common/backend/utils/adt/jsonb.cpp
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
@ -19,8 +19,7 @@
|
||||
#include "utils/jsonapi.h"
|
||||
#include "utils/jsonb.h"
|
||||
|
||||
typedef struct JsonbInState
|
||||
{
|
||||
typedef struct JsonbInState {
|
||||
JsonbParseState *parseState;
|
||||
JsonbValue *res;
|
||||
} JsonbInState;
|
||||
@ -32,17 +31,16 @@ static void jsonb_in_object_end(void *pstate);
|
||||
static void jsonb_in_array_start(void *pstate);
|
||||
static void jsonb_in_array_end(void *pstate);
|
||||
static void jsonb_in_object_field_start(void *pstate, char *fname, bool isnull);
|
||||
static void jsonb_put_escaped_value(StringInfo out, JsonbValue * scalarVal);
|
||||
static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal);
|
||||
static void jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype);
|
||||
char *JsonbToCString(StringInfo out, char *in, int estimated_len);
|
||||
|
||||
/*
|
||||
* jsonb type input function
|
||||
*/
|
||||
Datum
|
||||
jsonb_in(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_in(PG_FUNCTION_ARGS)
|
||||
{
|
||||
char *json = PG_GETARG_CSTRING(0);
|
||||
char *json = PG_GETARG_CSTRING(0);
|
||||
json = json == NULL ? pstrdup("") : json;
|
||||
|
||||
return jsonb_from_cstring(json, strlen(json));
|
||||
@ -56,8 +54,7 @@ jsonb_in(PG_FUNCTION_ARGS)
|
||||
* can change the binary format sent in future if necessary. For now,
|
||||
* only version 1 is supported.
|
||||
*/
|
||||
Datum
|
||||
jsonb_recv(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_recv(PG_FUNCTION_ARGS)
|
||||
{
|
||||
StringInfo buf = (StringInfo) PG_GETARG_POINTER(0);
|
||||
int version = pq_getmsgint(buf, 1);
|
||||
@ -75,8 +72,7 @@ jsonb_recv(PG_FUNCTION_ARGS)
|
||||
/*
|
||||
* jsonb type output function
|
||||
*/
|
||||
Datum
|
||||
jsonb_out(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_out(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||
char *out = NULL;
|
||||
@ -91,8 +87,7 @@ jsonb_out(PG_FUNCTION_ARGS)
|
||||
*
|
||||
* Just send jsonb as a version number, then a string of text
|
||||
*/
|
||||
Datum
|
||||
jsonb_send(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_send(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||
StringInfoData buf;
|
||||
@ -116,8 +111,7 @@ jsonb_send(PG_FUNCTION_ARGS)
|
||||
* This function is here because the analog json function is in json.c, since
|
||||
* it uses the json parser internals not exposed elsewhere.
|
||||
*/
|
||||
Datum
|
||||
jsonb_typeof(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_typeof(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *in = PG_GETARG_JSONB(0);
|
||||
JsonbIterator *it = NULL;
|
||||
@ -130,9 +124,7 @@ jsonb_typeof(PG_FUNCTION_ARGS)
|
||||
result = "array";
|
||||
} else {
|
||||
Assert(JB_ROOT_IS_SCALAR(in));
|
||||
|
||||
it = JsonbIteratorInit(VARDATA_ANY(in));
|
||||
|
||||
/*
|
||||
* A root scalar is stored as an array of one element, so we get the
|
||||
* array and then its first (and only) member.
|
||||
@ -168,8 +160,7 @@ jsonb_typeof(PG_FUNCTION_ARGS)
|
||||
*
|
||||
* Uses the json parser (with hooks) to construct a jsonb.
|
||||
*/
|
||||
static inline Datum
|
||||
jsonb_from_cstring(char *json, int len)
|
||||
static inline Datum jsonb_from_cstring(char *json, int len)
|
||||
{
|
||||
JsonLexContext *lex = NULL;
|
||||
JsonbInState state;
|
||||
@ -182,7 +173,6 @@ jsonb_from_cstring(char *json, int len)
|
||||
lex = makeJsonLexContextCstringLen(json, len, true);
|
||||
|
||||
sem.semstate = (void *) &state;
|
||||
|
||||
sem.object_start = jsonb_in_object_start;
|
||||
sem.array_start = jsonb_in_array_start;
|
||||
sem.object_end = jsonb_in_object_end;
|
||||
@ -196,8 +186,7 @@ jsonb_from_cstring(char *json, int len)
|
||||
PG_RETURN_POINTER(JsonbValueToJsonb(state.res));
|
||||
}
|
||||
|
||||
static size_t
|
||||
checkStringLen(size_t len)
|
||||
static size_t checkStringLen(size_t len)
|
||||
{
|
||||
if (len > JENTRY_POSMASK) {
|
||||
ereport(ERROR,
|
||||
@ -210,40 +199,31 @@ checkStringLen(size_t len)
|
||||
return len;
|
||||
}
|
||||
|
||||
static void
|
||||
jsonb_in_object_start(void *pstate)
|
||||
static void jsonb_in_object_start(void *pstate)
|
||||
{
|
||||
JsonbInState *_state = (JsonbInState *) pstate;
|
||||
|
||||
_state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_OBJECT, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
jsonb_in_object_end(void *pstate)
|
||||
static void jsonb_in_object_end(void *pstate)
|
||||
{
|
||||
JsonbInState *_state = (JsonbInState *) pstate;
|
||||
|
||||
_state->res = pushJsonbValue(&_state->parseState, WJB_END_OBJECT, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
jsonb_in_array_start(void *pstate)
|
||||
static void jsonb_in_array_start(void *pstate)
|
||||
{
|
||||
JsonbInState *_state = (JsonbInState *) pstate;
|
||||
|
||||
_state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_ARRAY, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
jsonb_in_array_end(void *pstate)
|
||||
static void jsonb_in_array_end(void *pstate)
|
||||
{
|
||||
JsonbInState *_state = (JsonbInState *) pstate;
|
||||
|
||||
_state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
|
||||
static void jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
|
||||
{
|
||||
JsonbInState *_state = (JsonbInState *) pstate;
|
||||
JsonbValue v;
|
||||
@ -257,8 +237,7 @@ jsonb_in_object_field_start(void *pstate, char *fname, bool isnull)
|
||||
_state->res = pushJsonbValue(&_state->parseState, WJB_KEY, &v);
|
||||
}
|
||||
|
||||
static void
|
||||
jsonb_put_escaped_value(StringInfo out, JsonbValue * scalarVal)
|
||||
static void jsonb_put_escaped_value(StringInfo out, JsonbValue * scalarVal)
|
||||
{
|
||||
switch (scalarVal->type) {
|
||||
case jbvNull:
|
||||
@ -286,16 +265,13 @@ jsonb_put_escaped_value(StringInfo out, JsonbValue * scalarVal)
|
||||
/*
|
||||
* For jsonb we always want the de-escaped value - that's what's in token
|
||||
*/
|
||||
static void
|
||||
jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
|
||||
static void jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
|
||||
{
|
||||
JsonbInState *_state = (JsonbInState *) pstate;
|
||||
JsonbValue v;
|
||||
|
||||
v.estSize = sizeof(JEntry);
|
||||
|
||||
switch (tokentype) {
|
||||
|
||||
case JSON_TOKEN_STRING:
|
||||
Assert (token != NULL);
|
||||
v.type = jbvString;
|
||||
@ -311,7 +287,7 @@ jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
|
||||
Assert (token != NULL);
|
||||
v.type = jbvNumeric;
|
||||
v.numeric = DatumGetNumeric(DirectFunctionCall3(numeric_in, CStringGetDatum(token), 0, -1));
|
||||
v.estSize += VARSIZE_ANY(v.numeric) + sizeof(JEntry) /* alignment */ ;
|
||||
v.estSize += VARSIZE_ANY(v.numeric) + sizeof(JEntry); /* alignment */
|
||||
break;
|
||||
case JSON_TOKEN_TRUE:
|
||||
v.type = jbvBool;
|
||||
@ -343,7 +319,6 @@ jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
|
||||
_state->res = pushJsonbValue(&_state->parseState, WJB_END_ARRAY, NULL);
|
||||
} else {
|
||||
JsonbValue *o = &_state->parseState->contVal;
|
||||
|
||||
switch (o->type) {
|
||||
case jbvArray:
|
||||
_state->res = pushJsonbValue(&_state->parseState, WJB_ELEM, &v);
|
||||
@ -368,8 +343,7 @@ jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype)
|
||||
* caller wants access to the len attribute without having to call strlen, e.g.
|
||||
* if they are converting it to a text* object.
|
||||
*/
|
||||
char *
|
||||
JsonbToCString(StringInfo out, JsonbSuperHeader in, int estimated_len)
|
||||
char *JsonbToCString(StringInfo out, JsonbSuperHeader in, int estimated_len)
|
||||
{
|
||||
bool first = true;
|
||||
JsonbIterator *it = NULL;
|
||||
@ -382,11 +356,9 @@ JsonbToCString(StringInfo out, JsonbSuperHeader in, int estimated_len)
|
||||
out = makeStringInfo();
|
||||
|
||||
enlargeStringInfo(out, (estimated_len >= 0) ? estimated_len : 64);
|
||||
|
||||
it = JsonbIteratorInit(in);
|
||||
|
||||
while (redo_switch ||
|
||||
((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)) {
|
||||
while (redo_switch || ((type = JsonbIteratorNext(&it, &v, false)) != WJB_DONE)) {
|
||||
redo_switch = false;
|
||||
switch (type) {
|
||||
case WJB_BEGIN_ARRAY:
|
||||
@ -421,7 +393,6 @@ JsonbToCString(StringInfo out, JsonbSuperHeader in, int estimated_len)
|
||||
jsonb_put_escaped_value(out, &v);
|
||||
} else {
|
||||
Assert(type == WJB_BEGIN_OBJECT || type == WJB_BEGIN_ARRAY);
|
||||
|
||||
/*
|
||||
* We need to rerun the current switch() since we need to
|
||||
* output the object which we just got from the iterator
|
||||
@ -435,7 +406,6 @@ JsonbToCString(StringInfo out, JsonbSuperHeader in, int estimated_len)
|
||||
appendBinaryStringInfo(out, ", ", 2);
|
||||
else
|
||||
first = false;
|
||||
|
||||
jsonb_put_escaped_value(out, &v);
|
||||
break;
|
||||
case WJB_END_ARRAY:
|
||||
@ -453,8 +423,6 @@ JsonbToCString(StringInfo out, JsonbSuperHeader in, int estimated_len)
|
||||
elog(ERROR, "unknown flag of jsonb iterator");
|
||||
}
|
||||
}
|
||||
|
||||
Assert(level == 0);
|
||||
|
||||
return out->data;
|
||||
}
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
/* -------------------------------------------------------------------------
|
||||
*
|
||||
* jsonb_gin.c
|
||||
* jsonb_gin.cpp
|
||||
* GIN support functions for jsonb
|
||||
*
|
||||
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
* Portions Copyright (c) 2021 Huawei Technologies Co.,Ltd.
|
||||
* Copyright (c) 2014, PostgreSQL Global Development Group
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/backend/utils/adt/jsonb_gin.c
|
||||
* src/common/backend/utils/adt/jsonb_gin.cpp
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "access/gin.h"
|
||||
#include "access/skey.h"
|
||||
#include "catalog/pg_collation.h"
|
||||
@ -21,22 +20,20 @@
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/jsonb.h"
|
||||
|
||||
typedef struct PathHashStack
|
||||
{
|
||||
typedef struct PathHashStack {
|
||||
uint32 hash;
|
||||
struct PathHashStack *parent;
|
||||
} PathHashStack;
|
||||
|
||||
static text *make_text_key(const char *str, int len, char flag);
|
||||
static text *make_scalar_key(const JsonbValue * scalarVal, char flag);
|
||||
static text *make_scalar_key(const JsonbValue *scalarVal, char flag);
|
||||
|
||||
/*
|
||||
*
|
||||
* jsonb_ops GIN opclass support functions
|
||||
*
|
||||
*/
|
||||
Datum
|
||||
gin_compare_jsonb(PG_FUNCTION_ARGS)
|
||||
Datum gin_compare_jsonb(PG_FUNCTION_ARGS)
|
||||
{
|
||||
text *arg1 = PG_GETARG_TEXT_PP(0);
|
||||
text *arg2 = PG_GETARG_TEXT_PP(1);
|
||||
@ -48,21 +45,18 @@ gin_compare_jsonb(PG_FUNCTION_ARGS)
|
||||
|
||||
a1p = VARDATA_ANY(arg1);
|
||||
a2p = VARDATA_ANY(arg2);
|
||||
|
||||
len1 = VARSIZE_ANY_EXHDR(arg1);
|
||||
len2 = VARSIZE_ANY_EXHDR(arg2);
|
||||
|
||||
/* Compare text as bttextcmp does, but always using C collation */
|
||||
result = varstr_cmp(a1p, len1, a2p, len2, C_COLLATION_OID);
|
||||
|
||||
PG_FREE_IF_COPY(arg1, 0);
|
||||
PG_FREE_IF_COPY(arg2, 1);
|
||||
|
||||
PG_RETURN_INT32(result);
|
||||
}
|
||||
|
||||
Datum
|
||||
gin_extract_jsonb(PG_FUNCTION_ARGS)
|
||||
Datum gin_extract_jsonb(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jb = (Jsonb *) PG_GETARG_JSONB(0);
|
||||
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
|
||||
@ -79,9 +73,7 @@ gin_extract_jsonb(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
entries = (Datum *) palloc(sizeof(Datum) * total);
|
||||
|
||||
it = JsonbIteratorInit(VARDATA(jb));
|
||||
|
||||
while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) {
|
||||
if (i >= total) {
|
||||
total *= 2;
|
||||
@ -141,12 +133,10 @@ gin_extract_jsonb(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
*nentries = i;
|
||||
|
||||
PG_RETURN_POINTER(entries);
|
||||
}
|
||||
|
||||
Datum
|
||||
gin_extract_jsonb_query(PG_FUNCTION_ARGS)
|
||||
Datum gin_extract_jsonb_query(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(2);
|
||||
@ -156,9 +146,7 @@ gin_extract_jsonb_query(PG_FUNCTION_ARGS)
|
||||
if (strategy == JsonbContainsStrategyNumber) {
|
||||
/* Query is a jsonb, so just apply gin_extract_jsonb... */
|
||||
entries = (Datum *)
|
||||
DatumGetPointer(DirectFunctionCall2(gin_extract_jsonb,
|
||||
PG_GETARG_DATUM(0),
|
||||
PointerGetDatum(nentries)));
|
||||
DatumGetPointer(DirectFunctionCall2(gin_extract_jsonb, PG_GETARG_DATUM(0), PointerGetDatum(nentries)));
|
||||
/* ...although "contains {}" requires a full index scan */
|
||||
if (entries == NULL) {
|
||||
*searchMode = GIN_SEARCH_MODE_ALL;
|
||||
@ -169,11 +157,9 @@ gin_extract_jsonb_query(PG_FUNCTION_ARGS)
|
||||
|
||||
*nentries = 1;
|
||||
entries = (Datum *) palloc(sizeof(Datum));
|
||||
item = make_text_key(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query),
|
||||
JKEYELEM);
|
||||
item = make_text_key(VARDATA_ANY(query), VARSIZE_ANY_EXHDR(query), JKEYELEM);
|
||||
entries[0] = PointerGetDatum(item);
|
||||
} else if (strategy == JsonbExistsAnyStrategyNumber ||
|
||||
strategy == JsonbExistsAllStrategyNumber) {
|
||||
} else if (strategy == JsonbExistsAnyStrategyNumber || strategy == JsonbExistsAllStrategyNumber) {
|
||||
ArrayType *query = PG_GETARG_ARRAYTYPE_P(0);
|
||||
Datum *key_datums = NULL;
|
||||
bool *key_nulls = NULL;
|
||||
@ -181,11 +167,7 @@ gin_extract_jsonb_query(PG_FUNCTION_ARGS)
|
||||
int i,
|
||||
j;
|
||||
text *item = NULL;
|
||||
|
||||
deconstruct_array(query,
|
||||
TEXTOID, -1, false, 'i',
|
||||
&key_datums, &key_nulls, &key_count);
|
||||
|
||||
deconstruct_array(query, TEXTOID, -1, false, 'i', &key_datums, &key_nulls, &key_count);
|
||||
entries = (Datum *) palloc(sizeof(Datum) * key_count);
|
||||
|
||||
for (i = 0, j = 0; i < key_count; ++i) {
|
||||
@ -193,9 +175,7 @@ gin_extract_jsonb_query(PG_FUNCTION_ARGS)
|
||||
if (key_nulls[i]) {
|
||||
continue;
|
||||
}
|
||||
item = make_text_key(VARDATA(key_datums[i]),
|
||||
VARSIZE(key_datums[i]) - VARHDRSZ,
|
||||
JKEYELEM);
|
||||
item = make_text_key(VARDATA(key_datums[i]), VARSIZE(key_datums[i]) - VARHDRSZ, JKEYELEM);
|
||||
entries[j++] = PointerGetDatum(item);
|
||||
}
|
||||
|
||||
@ -212,16 +192,13 @@ gin_extract_jsonb_query(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_POINTER(entries);
|
||||
}
|
||||
|
||||
Datum
|
||||
gin_consistent_jsonb(PG_FUNCTION_ARGS)
|
||||
Datum gin_consistent_jsonb(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bool *check = (bool *) PG_GETARG_POINTER(0);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
|
||||
/* Jsonb *query = PG_GETARG_JSONB(2); */
|
||||
/* example: Jsonb *query = PG_GETARG_JSONB(2); */
|
||||
int32 nkeys = PG_GETARG_INT32(3);
|
||||
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
/* example: Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
bool *recheck = (bool *) PG_GETARG_POINTER(5);
|
||||
bool res = true;
|
||||
int32 i;
|
||||
@ -267,21 +244,16 @@ gin_consistent_jsonb(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
gin_triconsistent_jsonb(PG_FUNCTION_ARGS)
|
||||
Datum gin_triconsistent_jsonb(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GinLogicValue *check = (GinLogicValue *) PG_GETARG_POINTER(0);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
/* Jsonb *query = PG_GETARG_JSONB(2); */
|
||||
int32 nkeys = PG_GETARG_INT32(3);
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
GinLogicValue res = GIN_TRUE;
|
||||
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
int32 nkeys = PG_GETARG_INT32(3);
|
||||
GinLogicValue res = GIN_TRUE;
|
||||
int32 i;
|
||||
|
||||
if (strategy == JsonbContainsStrategyNumber) {
|
||||
bool has_maybe = false;
|
||||
|
||||
/*
|
||||
* All extracted keys must be present. Combination of GIN_MAYBE and
|
||||
* GIN_TRUE gives GIN_MAYBE result because then all keys may be
|
||||
@ -307,8 +279,7 @@ gin_triconsistent_jsonb(PG_FUNCTION_ARGS)
|
||||
if (!has_maybe && res == GIN_TRUE) {
|
||||
res = GIN_MAYBE;
|
||||
}
|
||||
} else if (strategy == JsonbExistsStrategyNumber ||
|
||||
strategy == JsonbExistsAnyStrategyNumber) {
|
||||
} else if (strategy == JsonbExistsStrategyNumber || strategy == JsonbExistsAnyStrategyNumber) {
|
||||
/* Existence of key guaranteed in default search mode */
|
||||
res = GIN_FALSE;
|
||||
for (i = 0; i < nkeys; i++) {
|
||||
@ -339,21 +310,16 @@ gin_triconsistent_jsonb(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
/*
|
||||
*
|
||||
* jsonb_hash_ops GIN opclass support functions
|
||||
*
|
||||
*/
|
||||
Datum
|
||||
gin_consistent_jsonb_hash(PG_FUNCTION_ARGS)
|
||||
Datum gin_consistent_jsonb_hash(PG_FUNCTION_ARGS)
|
||||
{
|
||||
bool *check = (bool *) PG_GETARG_POINTER(0);
|
||||
bool *check = (bool *) PG_GETARG_POINTER(0);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
/* Jsonb *query = PG_GETARG_JSONB(2); */
|
||||
int32 nkeys = PG_GETARG_INT32(3);
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
bool *recheck = (bool *) PG_GETARG_POINTER(5);
|
||||
bool res = true;
|
||||
int32 i;
|
||||
int32 nkeys = PG_GETARG_INT32(3);
|
||||
bool *recheck = (bool *) PG_GETARG_POINTER(5);
|
||||
bool res = true;
|
||||
int32 i;
|
||||
|
||||
if (strategy != JsonbContainsStrategyNumber) {
|
||||
elog(ERROR, "unrecognized strategy number: %d", strategy);
|
||||
@ -379,17 +345,14 @@ gin_consistent_jsonb_hash(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
gin_triconsistent_jsonb_hash(PG_FUNCTION_ARGS)
|
||||
Datum gin_triconsistent_jsonb_hash(PG_FUNCTION_ARGS)
|
||||
{
|
||||
GinLogicValue *check = (GinLogicValue *) PG_GETARG_POINTER(0);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
/* Jsonb *query = PG_GETARG_JSONB(2); */
|
||||
int32 nkeys = PG_GETARG_INT32(3);
|
||||
/* Pointer *extra_data = (Pointer *) PG_GETARG_POINTER(4); */
|
||||
GinLogicValue res = GIN_TRUE;
|
||||
int32 i;
|
||||
bool has_maybe = false;
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(1);
|
||||
int32 nkeys = PG_GETARG_INT32(3);
|
||||
GinLogicValue res = GIN_TRUE;
|
||||
int32 i;
|
||||
bool has_maybe = false;
|
||||
|
||||
if (strategy != JsonbContainsStrategyNumber) {
|
||||
elog(ERROR, "unrecognized strategy number: %d", strategy);
|
||||
@ -425,8 +388,7 @@ gin_triconsistent_jsonb_hash(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_GIN_LOGIC_VALUE(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
gin_extract_jsonb_hash(PG_FUNCTION_ARGS)
|
||||
Datum gin_extract_jsonb_hash(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
|
||||
@ -445,16 +407,13 @@ gin_extract_jsonb_hash(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
entries = (Datum *) palloc(sizeof(Datum) * total);
|
||||
|
||||
it = JsonbIteratorInit(VARDATA(jb));
|
||||
|
||||
tail.parent = NULL;
|
||||
tail.hash = 0;
|
||||
stack = &tail;
|
||||
|
||||
while ((r = JsonbIteratorNext(&it, &v, false)) != WJB_DONE) {
|
||||
PathHashStack *tmp = NULL;
|
||||
|
||||
if (i >= total) {
|
||||
total *= 2;
|
||||
entries = (Datum *) repalloc(entries, sizeof(Datum) * total);
|
||||
@ -516,12 +475,10 @@ gin_extract_jsonb_hash(PG_FUNCTION_ARGS)
|
||||
}
|
||||
|
||||
*nentries = i;
|
||||
|
||||
PG_RETURN_POINTER(entries);
|
||||
}
|
||||
|
||||
Datum
|
||||
gin_extract_jsonb_query_hash(PG_FUNCTION_ARGS)
|
||||
Datum gin_extract_jsonb_query_hash(PG_FUNCTION_ARGS)
|
||||
{
|
||||
int32 *nentries = (int32 *) PG_GETARG_POINTER(1);
|
||||
StrategyNumber strategy = PG_GETARG_UINT16(2);
|
||||
@ -550,29 +507,26 @@ gin_extract_jsonb_query_hash(PG_FUNCTION_ARGS)
|
||||
* Build a text value from a cstring and flag suitable for storage as a key
|
||||
* value
|
||||
*/
|
||||
static text *
|
||||
make_text_key(const char *str, int len, char flag)
|
||||
static text *make_text_key(const char *str, int len, char flag)
|
||||
{
|
||||
text *item = NULL;
|
||||
text *item = NULL;
|
||||
|
||||
item = (text *) palloc(VARHDRSZ + len + 1);
|
||||
item = (text *)palloc(VARHDRSZ + len + 1);
|
||||
SET_VARSIZE(item, VARHDRSZ + len + 1);
|
||||
|
||||
*VARDATA(item) = flag;
|
||||
|
||||
memcpy(VARDATA(item) + 1, str, len);
|
||||
|
||||
errno_t rc = memcpy_s(VARDATA(item) + 1, len, str, len);
|
||||
securec_check(rc, "\0", "\0");
|
||||
return item;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a textual representation of a jsonbValue for GIN storage.
|
||||
*/
|
||||
static text *
|
||||
make_scalar_key(const JsonbValue * scalarVal, char flag)
|
||||
static text *make_scalar_key(const JsonbValue *scalarVal, char flag)
|
||||
{
|
||||
text *item = NULL;
|
||||
char *cstr = NULL;
|
||||
text *item = NULL;
|
||||
char *cstr = NULL;
|
||||
|
||||
switch (scalarVal->type) {
|
||||
case jbvNull:
|
||||
@ -596,8 +550,7 @@ make_scalar_key(const JsonbValue * scalarVal, char flag)
|
||||
pfree(cstr);
|
||||
break;
|
||||
case jbvString:
|
||||
item = make_text_key(scalarVal->string.val, scalarVal->string.len,
|
||||
flag);
|
||||
item = make_text_key(scalarVal->string.val, scalarVal->string.len, flag);
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "invalid jsonb scalar type");
|
||||
|
||||
@ -1,24 +1,23 @@
|
||||
/*-------------------------------------------------------------------------
|
||||
/* -------------------------------------------------------------------------
|
||||
*
|
||||
* jsonb_op.c
|
||||
* jsonb_op.cpp
|
||||
* Special operators for jsonb only, used by various index access methods
|
||||
*
|
||||
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
* Portions Copyright (c) 2021 Huawei Technologies Co.,Ltd.
|
||||
* Copyright (c) 2014, PostgreSQL Global Development Group
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* src/backend/utils/adt/jsonb_op.c
|
||||
* src/common/backend/utils/adt/jsonb_op.cpp
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
* -------------------------------------------------------------------------
|
||||
*/
|
||||
#include "postgres.h"
|
||||
|
||||
#include "miscadmin.h"
|
||||
#include "utils/jsonb.h"
|
||||
|
||||
Datum
|
||||
jsonb_exists(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_exists(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||
text *key = PG_GETARG_TEXT_PP(1);
|
||||
@ -35,22 +34,18 @@ jsonb_exists(PG_FUNCTION_ARGS)
|
||||
kval.string.val = VARDATA_ANY(key);
|
||||
kval.string.len = VARSIZE_ANY_EXHDR(key);
|
||||
|
||||
v = findJsonbValueFromSuperHeader(VARDATA(jb),
|
||||
JB_FOBJECT | JB_FARRAY,
|
||||
NULL,
|
||||
&kval);
|
||||
v = findJsonbValueFromSuperHeader(VARDATA(jb), JB_FOBJECT | JB_FARRAY, NULL, &kval);
|
||||
|
||||
PG_RETURN_BOOL(v != NULL);
|
||||
}
|
||||
|
||||
Datum
|
||||
jsonb_exists_any(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_exists_any(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||
ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
|
||||
JsonbValue *arrKey = arrayToJsonbSortedArray(keys);
|
||||
uint32 *plowbound = NULL,
|
||||
lowbound = 0;
|
||||
uint32 *plowbound = NULL;
|
||||
uint32 lowbound = 0;
|
||||
int i;
|
||||
|
||||
if (arrKey == NULL || arrKey->object.nPairs == 0) {
|
||||
@ -68,10 +63,8 @@ jsonb_exists_any(PG_FUNCTION_ARGS)
|
||||
* the lower bound of the last search.
|
||||
*/
|
||||
for (i = 0; i < arrKey->array.nElems; i++) {
|
||||
if (findJsonbValueFromSuperHeader(VARDATA(jb),
|
||||
JB_FOBJECT | JB_FARRAY,
|
||||
plowbound,
|
||||
arrKey->array.elems + i) != NULL) {
|
||||
if (findJsonbValueFromSuperHeader(VARDATA(jb), JB_FOBJECT | JB_FARRAY,
|
||||
plowbound, arrKey->array.elems + i) != NULL) {
|
||||
PG_RETURN_BOOL(true);
|
||||
}
|
||||
}
|
||||
@ -79,8 +72,7 @@ jsonb_exists_any(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(false);
|
||||
}
|
||||
|
||||
Datum
|
||||
jsonb_exists_all(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_exists_all(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||
ArrayType *keys = PG_GETARG_ARRAYTYPE_P(1);
|
||||
@ -104,10 +96,8 @@ jsonb_exists_all(PG_FUNCTION_ARGS)
|
||||
* the lower bound of the last search.
|
||||
*/
|
||||
for (i = 0; i < arrKey->array.nElems; i++) {
|
||||
if (findJsonbValueFromSuperHeader(VARDATA(jb),
|
||||
JB_FOBJECT | JB_FARRAY,
|
||||
plowbound,
|
||||
arrKey->array.elems + i) == NULL) {
|
||||
if (findJsonbValueFromSuperHeader(VARDATA(jb), JB_FOBJECT | JB_FARRAY,
|
||||
plowbound, arrKey->array.elems + i) == NULL) {
|
||||
PG_RETURN_BOOL(false);
|
||||
}
|
||||
}
|
||||
@ -115,11 +105,10 @@ jsonb_exists_all(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(true);
|
||||
}
|
||||
|
||||
Datum
|
||||
jsonb_contains(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_contains(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *val = PG_GETARG_JSONB(0);
|
||||
Jsonb *tmpl = PG_GETARG_JSONB(1);
|
||||
Jsonb *val = PG_GETARG_JSONB(0);
|
||||
Jsonb *tmpl = PG_GETARG_JSONB(1);
|
||||
|
||||
JsonbIterator *it1 = NULL;
|
||||
JsonbIterator *it2 = NULL;
|
||||
@ -134,12 +123,11 @@ jsonb_contains(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
|
||||
}
|
||||
|
||||
Datum
|
||||
jsonb_contained(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_contained(PG_FUNCTION_ARGS)
|
||||
{
|
||||
/* Commutator of "contains" */
|
||||
Jsonb *tmpl = PG_GETARG_JSONB(0);
|
||||
Jsonb *val = PG_GETARG_JSONB(1);
|
||||
Jsonb *tmpl = PG_GETARG_JSONB(0);
|
||||
Jsonb *val = PG_GETARG_JSONB(1);
|
||||
|
||||
JsonbIterator *it1 = NULL;
|
||||
JsonbIterator *it2 = NULL;
|
||||
@ -154,12 +142,11 @@ jsonb_contained(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(JsonbDeepContains(&it1, &it2));
|
||||
}
|
||||
|
||||
Datum
|
||||
jsonb_ne(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_ne(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res;
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res = false;
|
||||
|
||||
res = (compareJsonbSuperHeaderValue(VARDATA(jba), VARDATA(jbb)) != 0);
|
||||
|
||||
@ -171,12 +158,11 @@ jsonb_ne(PG_FUNCTION_ARGS)
|
||||
/*
|
||||
* B-Tree operator class operators, support function
|
||||
*/
|
||||
Datum
|
||||
jsonb_lt(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_lt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res;
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res = false;
|
||||
|
||||
res = (compareJsonbSuperHeaderValue(VARDATA(jba), VARDATA(jbb)) < 0);
|
||||
|
||||
@ -185,12 +171,11 @@ jsonb_lt(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
jsonb_gt(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_gt(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res;
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res = false;
|
||||
|
||||
res = (compareJsonbSuperHeaderValue(VARDATA(jba), VARDATA(jbb)) > 0);
|
||||
|
||||
@ -199,12 +184,11 @@ jsonb_gt(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
jsonb_le(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_le(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res;
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res = false;
|
||||
|
||||
res = (compareJsonbSuperHeaderValue(VARDATA(jba), VARDATA(jbb)) <= 0);
|
||||
|
||||
@ -213,13 +197,11 @@ jsonb_le(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
jsonb_ge(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_ge(PG_FUNCTION_ARGS)
|
||||
{
|
||||
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res;
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res = false;
|
||||
|
||||
res = (compareJsonbSuperHeaderValue(VARDATA(jba), VARDATA(jbb)) >= 0);
|
||||
|
||||
@ -228,12 +210,11 @@ jsonb_ge(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
jsonb_eq(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_eq(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res;
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
bool res = false;
|
||||
|
||||
res = (compareJsonbSuperHeaderValue(VARDATA(jba), VARDATA(jbb)) == 0);
|
||||
|
||||
@ -242,12 +223,11 @@ jsonb_eq(PG_FUNCTION_ARGS)
|
||||
PG_RETURN_BOOL(res);
|
||||
}
|
||||
|
||||
Datum
|
||||
jsonb_cmp(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_cmp(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
int res;
|
||||
Jsonb *jba = PG_GETARG_JSONB(0);
|
||||
Jsonb *jbb = PG_GETARG_JSONB(1);
|
||||
int res = false;
|
||||
|
||||
res = compareJsonbSuperHeaderValue(VARDATA(jba), VARDATA(jbb));
|
||||
|
||||
@ -259,8 +239,7 @@ jsonb_cmp(PG_FUNCTION_ARGS)
|
||||
/*
|
||||
* Hash operator class jsonb hashing function
|
||||
*/
|
||||
Datum
|
||||
jsonb_hash(PG_FUNCTION_ARGS)
|
||||
Datum jsonb_hash(PG_FUNCTION_ARGS)
|
||||
{
|
||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||
JsonbIterator *it = NULL;
|
||||
|
||||
@ -3,7 +3,7 @@
|
||||
* jsonb_util.c
|
||||
* Utilities for jsonb datatype
|
||||
*
|
||||
* Portions Copyright (c) 2020 Huawei Technologies Co.,Ltd.
|
||||
* Portions Copyright (c) 2021 Huawei Technologies Co.,Ltd.
|
||||
* Copyright (c) 2014, PostgreSQL Global Development Group
|
||||
*
|
||||
*
|
||||
@ -35,8 +35,7 @@
|
||||
* object.
|
||||
*/
|
||||
#define JSONB_MAX_ELEMS (Min(MaxAllocSize / sizeof(JsonbValue), JENTRY_POSMASK))
|
||||
#define JSONB_MAX_PAIRS (Min(MaxAllocSize / sizeof(JsonbPair), \
|
||||
JENTRY_POSMASK))
|
||||
#define JSONB_MAX_PAIRS (Min(MaxAllocSize / sizeof(JsonbPair), JENTRY_POSMASK))
|
||||
|
||||
/*
|
||||
* State used while converting an arbitrary JsonbValue into a Jsonb value
|
||||
@ -44,8 +43,7 @@
|
||||
*
|
||||
* ConvertLevel: Bookkeeping around particular level when converting.
|
||||
*/
|
||||
typedef struct convertLevel
|
||||
{
|
||||
typedef struct convertLevel {
|
||||
uint32 i; /* Iterates once per element, or once per pair */
|
||||
uint32 *header; /* Pointer to current container header */
|
||||
JEntry *meta; /* This level's metadata */
|
||||
@ -55,44 +53,39 @@ typedef struct convertLevel
|
||||
/*
|
||||
* convertState: Overall bookkeeping state for conversion
|
||||
*/
|
||||
typedef struct convertState
|
||||
{
|
||||
typedef struct convertState {
|
||||
/* Preallocated buffer in which to form varlena/Jsonb value */
|
||||
Jsonb *buffer;
|
||||
/* Pointer into buffer */
|
||||
char *ptr;
|
||||
|
||||
/* State for */
|
||||
convertLevel *allState, /* Overall state array */
|
||||
*contPtr; /* Cur container pointer (in allState) */
|
||||
convertLevel *allState; /* Overall state array */
|
||||
convertLevel *contPtr; /* Cur container pointer (in allState) */
|
||||
|
||||
/* Current size of buffer containing allState array */
|
||||
Size levelSz;
|
||||
|
||||
} convertState;
|
||||
|
||||
static int compareJsonbScalarValue(JsonbValue * a, JsonbValue * b);
|
||||
static int lexicalCompareJsonbStringValue(const void *a, const void *b);
|
||||
static Size convertJsonb(JsonbValue * val, Jsonb* buffer);
|
||||
static inline short addPaddingInt(convertState * cstate);
|
||||
static void walkJsonbValueConversion(JsonbValue * val, convertState * cstate,
|
||||
uint32 nestlevel);
|
||||
static void putJsonbValueConversion(convertState * cstate, JsonbValue * val,
|
||||
uint32 flags, uint32 level);
|
||||
static void putScalarConversion(convertState * cstate, JsonbValue * scalarVal,
|
||||
uint32 level, uint32 i);
|
||||
static void iteratorFromContainerBuf(JsonbIterator * it, char *buffer);
|
||||
static bool formIterIsContainer(JsonbIterator ** it, JsonbValue * val,
|
||||
JEntry * ent, bool skipNested);
|
||||
static JsonbIterator *freeAndGetParent(JsonbIterator * it);
|
||||
static JsonbParseState *pushState(JsonbParseState ** pstate);
|
||||
static void appendKey(JsonbParseState * pstate, JsonbValue * scalarVal);
|
||||
static void appendValue(JsonbParseState * pstate, JsonbValue * scalarVal);
|
||||
static void appendElement(JsonbParseState * pstate, JsonbValue * scalarVal);
|
||||
static int lengthCompareJsonbStringValue(const void *a, const void *b, void *arg);
|
||||
static int lengthCompareJsonbPair(const void *a, const void *b, void *arg);
|
||||
static void uniqueifyJsonbObject(JsonbValue * object);
|
||||
static void uniqueifyJsonbArray(JsonbValue * array);
|
||||
static int compareJsonbScalarValue(JsonbValue* a, JsonbValue* b);
|
||||
static int lexicalCompareJsonbStringValue(const void* a, const void* b);
|
||||
static Size convertJsonb(JsonbValue* val, Jsonb* buffer);
|
||||
static inline short addPaddingInt(convertState* cstate);
|
||||
static void walkJsonbValueConversion(JsonbValue* val, convertState* cstate, uint32 nestlevel);
|
||||
static void putJsonbValueConversion(convertState* cstate, JsonbValue* val, uint32 flags, uint32 level);
|
||||
static void putScalarConversion(convertState* cstate, JsonbValue* scalarVal, uint32 level, uint32 i);
|
||||
static void iteratorFromContainerBuf(JsonbIterator* it, char* buffer);
|
||||
static bool formIterIsContainer(JsonbIterator** it, JsonbValue* val, JEntry* ent, bool skipNested);
|
||||
static JsonbIterator* freeAndGetParent(JsonbIterator* it);
|
||||
static JsonbParseState* pushState(JsonbParseState** pstate);
|
||||
static void appendKey(JsonbParseState* pstate, JsonbValue* scalarVal);
|
||||
static void appendValue(JsonbParseState* pstate, JsonbValue* scalarVal);
|
||||
static void appendElement(JsonbParseState* pstate, JsonbValue* scalarVal);
|
||||
static int lengthCompareJsonbStringValue(const void* a, const void* b, void* binequal);
|
||||
static int lengthCompareJsonbPair(const void* a, const void* b, void* binequal);
|
||||
static void uniqueifyJsonbObject(JsonbValue* object);
|
||||
static void uniqueifyJsonbArray(JsonbValue* array);
|
||||
|
||||
/*
|
||||
* Turn an in-memory JsonbValue into a Jsonb for on-disk storage.
|
||||
@ -107,11 +100,10 @@ static void uniqueifyJsonbArray(JsonbValue * array);
|
||||
* values, or simple containers of scalar values, where it would be
|
||||
* inconvenient to deal with a great amount of other state.
|
||||
*/
|
||||
Jsonb *
|
||||
JsonbValueToJsonb(JsonbValue * val)
|
||||
Jsonb* JsonbValueToJsonb(JsonbValue *val)
|
||||
{
|
||||
Jsonb *out = NULL;
|
||||
Size sz;
|
||||
Jsonb *out = NULL;
|
||||
Size sz;
|
||||
|
||||
if (IsAJsonbScalar(val)) {
|
||||
/* Scalar value */
|
||||
@ -131,7 +123,7 @@ JsonbValueToJsonb(JsonbValue * val)
|
||||
sz = convertJsonb(res, out);
|
||||
Assert(sz <= (uint)res->estSize);
|
||||
SET_VARSIZE(out, sz + VARHDRSZ);
|
||||
} else if (val->type == jbvObject || val->type == jbvArray){
|
||||
} else if (val->type == jbvObject || val->type == jbvArray) {
|
||||
out = (Jsonb*)palloc(VARHDRSZ + val->estSize);
|
||||
sz = convertJsonb(val, out);
|
||||
Assert(sz <= (uint)val->estSize);
|
||||
@ -140,7 +132,7 @@ JsonbValueToJsonb(JsonbValue * val)
|
||||
Assert(val->type == jbvBinary);
|
||||
out = (Jsonb*)palloc(VARHDRSZ + val->binary.len);
|
||||
SET_VARSIZE(out, VARHDRSZ + val->binary.len);
|
||||
|
||||
|
||||
errno_t rc = memcpy_s(VARDATA(out), VARHDRSZ + val->binary.len, val->binary.data, val->binary.len);
|
||||
securec_check(rc, "\0", "\0");
|
||||
}
|
||||
@ -158,8 +150,7 @@ JsonbValueToJsonb(JsonbValue * val)
|
||||
* called from B-Tree support function 1, we're careful about not leaking
|
||||
* memory here.
|
||||
*/
|
||||
int
|
||||
compareJsonbSuperHeaderValue(JsonbSuperHeader a, JsonbSuperHeader b)
|
||||
int compareJsonbSuperHeaderValue(JsonbSuperHeader a, JsonbSuperHeader b)
|
||||
{
|
||||
JsonbIterator *ita = NULL;
|
||||
JsonbIterator *itb = NULL;
|
||||
@ -190,13 +181,13 @@ compareJsonbSuperHeaderValue(JsonbSuperHeader a, JsonbSuperHeader b)
|
||||
break;
|
||||
}
|
||||
if (ra == WJB_END_ARRAY || ra == WJB_END_OBJECT) {
|
||||
/*
|
||||
* There is no array or object to compare at this stage of
|
||||
* processing. jbvArray/jbvObject values are compared
|
||||
* initially, at the WJB_BEGIN_ARRAY and WJB_BEGIN_OBJECT
|
||||
* tokens.
|
||||
*/
|
||||
continue;
|
||||
/*
|
||||
* There is no array or object to compare at this stage of
|
||||
* processing. jbvArray/jbvObject values are compared
|
||||
* initially, at the WJB_BEGIN_ARRAY and WJB_BEGIN_OBJECT
|
||||
* tokens.
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
if (va.type == vb.type) {
|
||||
@ -215,7 +206,7 @@ compareJsonbSuperHeaderValue(JsonbSuperHeader a, JsonbSuperHeader b)
|
||||
* special case here though, since we still want the
|
||||
* general type-based comparisons to apply, and as far
|
||||
* as we're concerned a pseudo array is just a scalar.
|
||||
*/
|
||||
*/
|
||||
if (va.array.rawScalar != vb.array.rawScalar) {
|
||||
res = (va.array.rawScalar) ? -1 : 1;
|
||||
} else if (va.array.nElems != vb.array.nElems) {
|
||||
@ -311,23 +302,21 @@ compareJsonbSuperHeaderValue(JsonbSuperHeader a, JsonbSuperHeader b)
|
||||
* presumably anyone exploiting this is only interested in matching Object keys
|
||||
* with a String. lowbound is given in units of pairs, not underlying values.
|
||||
*/
|
||||
JsonbValue *
|
||||
findJsonbValueFromSuperHeader(JsonbSuperHeader sheader, uint32 flags,
|
||||
uint32 *lowbound, JsonbValue * key)
|
||||
JsonbValue *findJsonbValueFromSuperHeader(JsonbSuperHeader sheader, uint32 flags, uint32 *lowbound, JsonbValue *key)
|
||||
{
|
||||
uint32 superheader = *(uint32 *) sheader;
|
||||
JEntry *array = (JEntry *) (sheader + sizeof(uint32));
|
||||
uint count = (superheader & JB_CMASK);
|
||||
JsonbValue *result = (JsonbValue*)palloc(sizeof(JsonbValue));
|
||||
uint32 superheader = *(uint32 *)sheader;
|
||||
JEntry *array = (JEntry *)(sheader + sizeof(uint32));
|
||||
uint count = (superheader & JB_CMASK);
|
||||
JsonbValue *result = (JsonbValue*)palloc(sizeof(JsonbValue));
|
||||
|
||||
Assert((flags & ~(JB_FARRAY | JB_FOBJECT)) == 0);
|
||||
|
||||
if (flags & JB_FARRAY & superheader) {
|
||||
char *data = (char *) (array + (superheader & JB_CMASK));
|
||||
uint i;
|
||||
char *data = (char *)(array + (superheader & JB_CMASK));
|
||||
uint i;
|
||||
|
||||
for (i = 0; i < count; i++) {
|
||||
JEntry *e = array + i;
|
||||
JEntry *e = array + i;
|
||||
|
||||
if (JBE_ISNULL(*e) && key->type == jbvNull) {
|
||||
result->type = jbvNull;
|
||||
@ -446,8 +435,7 @@ findJsonbValueFromSuperHeader(JsonbSuperHeader sheader, uint32 flags,
|
||||
*
|
||||
* Returns palloc()'d copy of value.
|
||||
*/
|
||||
JsonbValue *
|
||||
getIthJsonbValueFromSuperHeader(JsonbSuperHeader sheader, uint32 i)
|
||||
JsonbValue *getIthJsonbValueFromSuperHeader(JsonbSuperHeader sheader, uint32 i)
|
||||
{
|
||||
uint32 superheader = *(uint32 *) sheader;
|
||||
JsonbValue *result = NULL;
|
||||
@ -509,8 +497,7 @@ getIthJsonbValueFromSuperHeader(JsonbSuperHeader sheader, uint32 i)
|
||||
* JsonbValue. There is one exception -- WJB_BEGIN_ARRAY callers may pass a
|
||||
* "raw scalar" pseudo array to append that.
|
||||
*/
|
||||
JsonbValue *
|
||||
pushJsonbValue(JsonbParseState ** pstate, int seq, JsonbValue * scalarVal)
|
||||
JsonbValue *pushJsonbValue(JsonbParseState **pstate, int seq, JsonbValue *scalarVal)
|
||||
{
|
||||
JsonbValue *result = NULL;
|
||||
|
||||
@ -531,8 +518,7 @@ pushJsonbValue(JsonbParseState ** pstate, int seq, JsonbValue * scalarVal)
|
||||
} else {
|
||||
(*pstate)->size = 4;
|
||||
}
|
||||
(*pstate)->contVal.array.elems = (JsonbValue*)palloc(sizeof(JsonbValue) *
|
||||
(*pstate)->size);
|
||||
(*pstate)->contVal.array.elems = (JsonbValue*)palloc(sizeof(JsonbValue) * (*pstate)->size);
|
||||
break;
|
||||
case WJB_BEGIN_OBJECT:
|
||||
Assert(!scalarVal);
|
||||
@ -542,21 +528,18 @@ pushJsonbValue(JsonbParseState ** pstate, int seq, JsonbValue * scalarVal)
|
||||
(*pstate)->contVal.estSize = 3 * sizeof(JEntry);
|
||||
(*pstate)->contVal.object.nPairs = 0;
|
||||
(*pstate)->size = 4;
|
||||
(*pstate)->contVal.object.pairs = (JsonbPair*)palloc(sizeof(JsonbPair) *
|
||||
(*pstate)->size);
|
||||
(*pstate)->contVal.object.pairs = (JsonbPair*)palloc(sizeof(JsonbPair) * (*pstate)->size);
|
||||
break;
|
||||
case WJB_KEY:
|
||||
Assert(scalarVal->type == jbvString);
|
||||
appendKey(*pstate, scalarVal);
|
||||
break;
|
||||
case WJB_VALUE:
|
||||
Assert(IsAJsonbScalar(scalarVal) ||
|
||||
scalarVal->type == jbvBinary);
|
||||
Assert(IsAJsonbScalar(scalarVal) || scalarVal->type == jbvBinary);
|
||||
appendValue(*pstate, scalarVal);
|
||||
break;
|
||||
case WJB_ELEM:
|
||||
Assert(IsAJsonbScalar(scalarVal) ||
|
||||
scalarVal->type == jbvBinary);
|
||||
Assert(IsAJsonbScalar(scalarVal) || scalarVal->type == jbvBinary);
|
||||
appendElement(*pstate, scalarVal);
|
||||
break;
|
||||
case WJB_END_OBJECT:
|
||||
@ -597,8 +580,7 @@ pushJsonbValue(JsonbParseState ** pstate, int seq, JsonbValue * scalarVal)
|
||||
*
|
||||
* See JsonbIteratorNext() for notes on memory management.
|
||||
*/
|
||||
JsonbIterator *
|
||||
JsonbIteratorInit(JsonbSuperHeader sheader)
|
||||
JsonbIterator *JsonbIteratorInit(JsonbSuperHeader sheader)
|
||||
{
|
||||
JsonbIterator *it = (JsonbIterator*)palloc(sizeof(JsonbIterator));
|
||||
|
||||
@ -636,8 +618,7 @@ JsonbIteratorInit(JsonbSuperHeader sheader)
|
||||
* or Object element/pair buffers, since their element/pair pointers are
|
||||
* garbage.
|
||||
*/
|
||||
int
|
||||
JsonbIteratorNext(JsonbIterator ** it, JsonbValue * val, bool skipNested)
|
||||
int JsonbIteratorNext(JsonbIterator **it, JsonbValue *val, bool skipNested)
|
||||
{
|
||||
JsonbIterState state;
|
||||
|
||||
@ -675,8 +656,7 @@ JsonbIteratorNext(JsonbIterator ** it, JsonbValue * val, bool skipNested)
|
||||
*/
|
||||
*it = freeAndGetParent(*it);
|
||||
return WJB_END_ARRAY;
|
||||
} else if (formIterIsContainer(it, val, &(*it)->meta[(*it)->i++],
|
||||
skipNested)) {
|
||||
} else if (formIterIsContainer(it, val, &(*it)->meta[(*it)->i++], skipNested)) {
|
||||
/*
|
||||
* New child iterator acquired within formIterIsContainer.
|
||||
* Recurse into container. Don't directly return jbvBinary
|
||||
@ -736,8 +716,7 @@ JsonbIteratorNext(JsonbIterator ** it, JsonbValue * val, bool skipNested)
|
||||
* child iterator. If it is, don't bother !skipNested callers with
|
||||
* dealing with the jbvBinary representation.
|
||||
*/
|
||||
if (formIterIsContainer(it, val, &(*it)->meta[((*it)->i++) * 2 + 1],
|
||||
skipNested)) {
|
||||
if (formIterIsContainer(it, val, &(*it)->meta[((*it)->i++) * 2 + 1], skipNested)) {
|
||||
return JsonbIteratorNext(it, val, skipNested);
|
||||
} else {
|
||||
return WJB_VALUE;
|
||||
@ -761,8 +740,7 @@ JsonbIteratorNext(JsonbIterator ** it, JsonbValue * val, bool skipNested)
|
||||
* "val" is lhs Jsonb, and mContained is rhs Jsonb when called from top level.
|
||||
* We determine if mContained is contained within val.
|
||||
*/
|
||||
bool
|
||||
JsonbDeepContains(JsonbIterator ** val, JsonbIterator ** mContained)
|
||||
bool JsonbDeepContains(JsonbIterator **val, JsonbIterator **mContained)
|
||||
{
|
||||
uint32 rval,
|
||||
rcont;
|
||||
@ -810,10 +788,7 @@ JsonbDeepContains(JsonbIterator ** val, JsonbIterator ** mContained)
|
||||
Assert(rcont == WJB_KEY);
|
||||
|
||||
/* First, find value by key... */
|
||||
lhsVal = findJsonbValueFromSuperHeader((*val)->buffer,
|
||||
JB_FOBJECT,
|
||||
NULL,
|
||||
&vcontained);
|
||||
lhsVal = findJsonbValueFromSuperHeader((*val)->buffer, JB_FOBJECT, NULL, &vcontained);
|
||||
|
||||
if (!lhsVal) {
|
||||
return false;
|
||||
@ -907,10 +882,7 @@ JsonbDeepContains(JsonbIterator ** val, JsonbIterator ** mContained)
|
||||
Assert(rcont == WJB_ELEM);
|
||||
|
||||
if (IsAJsonbScalar(&vcontained)) {
|
||||
if (!findJsonbValueFromSuperHeader((*val)->buffer,
|
||||
JB_FARRAY,
|
||||
NULL,
|
||||
&vcontained)) {
|
||||
if (!findJsonbValueFromSuperHeader((*val)->buffer, JB_FARRAY, NULL, &vcontained)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
@ -927,7 +899,7 @@ JsonbDeepContains(JsonbIterator ** val, JsonbIterator ** mContained)
|
||||
lhsConts = (JsonbValue*)palloc(sizeof(JsonbValue) * nLhsElems);
|
||||
|
||||
for (i = 0; i < nLhsElems; i++) {
|
||||
/* Store all lhs elements in temp array*/
|
||||
/* Store all lhs elements in temp array */
|
||||
rcont = JsonbIteratorNext(val, &vval, true);
|
||||
Assert(rcont == WJB_ELEM);
|
||||
|
||||
@ -991,8 +963,7 @@ JsonbDeepContains(JsonbIterator ** val, JsonbIterator ** mContained)
|
||||
* in the array, so we enforce that the number of strings cannot exceed
|
||||
* JSONB_MAX_PAIRS.
|
||||
*/
|
||||
JsonbValue *
|
||||
arrayToJsonbSortedArray(ArrayType *array)
|
||||
JsonbValue *arrayToJsonbSortedArray(ArrayType *array)
|
||||
{
|
||||
Datum *key_datums = NULL;
|
||||
bool *key_nulls = NULL;
|
||||
@ -1002,8 +973,7 @@ arrayToJsonbSortedArray(ArrayType *array)
|
||||
j;
|
||||
|
||||
/* Extract data for sorting */
|
||||
deconstruct_array(array, TEXTOID, -1, false, 'i', &key_datums, &key_nulls,
|
||||
&elem_count);
|
||||
deconstruct_array(array, TEXTOID, -1, false, 'i', &key_datums, &key_nulls, &elem_count);
|
||||
|
||||
if (elem_count == 0) {
|
||||
return NULL;
|
||||
@ -1049,8 +1019,7 @@ arrayToJsonbSortedArray(ArrayType *array)
|
||||
* Some callers may wish to independently XOR in JB_FOBJECT and JB_FARRAY
|
||||
* flags.
|
||||
*/
|
||||
void
|
||||
JsonbHashScalarValue(const JsonbValue * scalarVal, uint32 * hash)
|
||||
void JsonbHashScalarValue(const JsonbValue * scalarVal, uint32 * hash)
|
||||
{
|
||||
int tmp;
|
||||
|
||||
@ -1065,14 +1034,12 @@ JsonbHashScalarValue(const JsonbValue * scalarVal, uint32 * hash)
|
||||
*hash ^= 0x01;
|
||||
return;
|
||||
case jbvString:
|
||||
tmp = hash_any((unsigned char *) scalarVal->string.val,
|
||||
scalarVal->string.len);
|
||||
tmp = hash_any((unsigned char *) scalarVal->string.val, scalarVal->string.len);
|
||||
*hash ^= tmp;
|
||||
return;
|
||||
case jbvNumeric:
|
||||
/* Must be unaffected by trailing zeroes */
|
||||
tmp = DatumGetInt32(DirectFunctionCall1(hash_numeric,
|
||||
NumericGetDatum(scalarVal->numeric)));
|
||||
tmp = DatumGetInt32(DirectFunctionCall1(hash_numeric, NumericGetDatum(scalarVal->numeric)));
|
||||
*hash ^= tmp;
|
||||
return;
|
||||
case jbvBool:
|
||||
@ -1090,8 +1057,7 @@ JsonbHashScalarValue(const JsonbValue * scalarVal, uint32 * hash)
|
||||
* never be used against Strings for anything other than searching for values
|
||||
* within a single jsonb.
|
||||
*/
|
||||
static int
|
||||
compareJsonbScalarValue(JsonbValue * aScalar, JsonbValue * bScalar)
|
||||
static int compareJsonbScalarValue(JsonbValue * aScalar, JsonbValue * bScalar)
|
||||
{
|
||||
if (aScalar->type == bScalar->type) {
|
||||
switch (aScalar->type) {
|
||||
@ -1123,8 +1089,7 @@ compareJsonbScalarValue(JsonbValue * aScalar, JsonbValue * bScalar)
|
||||
* Sorts strings lexically, using the default database collation. Used by
|
||||
* B-Tree operators, where a lexical sort order is generally expected.
|
||||
*/
|
||||
static int
|
||||
lexicalCompareJsonbStringValue(const void *a, const void *b)
|
||||
static int lexicalCompareJsonbStringValue(const void *a, const void *b)
|
||||
{
|
||||
const JsonbValue *va = (const JsonbValue *) a;
|
||||
const JsonbValue *vb = (const JsonbValue *) b;
|
||||
@ -1132,16 +1097,14 @@ lexicalCompareJsonbStringValue(const void *a, const void *b)
|
||||
Assert(va->type == jbvString);
|
||||
Assert(vb->type == jbvString);
|
||||
|
||||
return varstr_cmp(va->string.val, va->string.len, vb->string.val,
|
||||
vb->string.len, DEFAULT_COLLATION_OID);
|
||||
return varstr_cmp(va->string.val, va->string.len, vb->string.val, vb->string.len, DEFAULT_COLLATION_OID);
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a JsonbValue, convert to Jsonb and store in preallocated Jsonb buffer
|
||||
* sufficiently large to fit the value
|
||||
*/
|
||||
static Size
|
||||
convertJsonb(JsonbValue * val, Jsonb *buffer)
|
||||
static Size convertJsonb(JsonbValue * val, Jsonb *buffer)
|
||||
{
|
||||
convertState state;
|
||||
Size len;
|
||||
@ -1171,12 +1134,9 @@ convertJsonb(JsonbValue * val, Jsonb *buffer)
|
||||
* the top level calls putJsonbValueConversion once per sequential processing
|
||||
* token (in a manner similar to generic iteration).
|
||||
*/
|
||||
static void
|
||||
walkJsonbValueConversion(JsonbValue * val, convertState * cstate,
|
||||
uint32 nestlevel)
|
||||
static void walkJsonbValueConversion(JsonbValue * val, convertState * cstate, uint32 nestlevel)
|
||||
{
|
||||
int i;
|
||||
|
||||
check_stack_depth();
|
||||
|
||||
if (!val)
|
||||
@ -1184,40 +1144,29 @@ walkJsonbValueConversion(JsonbValue * val, convertState * cstate,
|
||||
|
||||
switch (val->type) {
|
||||
case jbvArray:
|
||||
|
||||
putJsonbValueConversion(cstate, val, WJB_BEGIN_ARRAY, nestlevel);
|
||||
for (i = 0; i < val->array.nElems; i++) {
|
||||
if (IsAJsonbScalar(&val->array.elems[i]) ||
|
||||
val->array.elems[i].type == jbvBinary) {
|
||||
putJsonbValueConversion(cstate, val->array.elems + i,
|
||||
WJB_ELEM, nestlevel);
|
||||
putJsonbValueConversion(cstate, val->array.elems + i, WJB_ELEM, nestlevel);
|
||||
} else {
|
||||
walkJsonbValueConversion(val->array.elems + i, cstate,
|
||||
nestlevel + 1);
|
||||
walkJsonbValueConversion(val->array.elems + i, cstate, nestlevel + 1);
|
||||
}
|
||||
}
|
||||
putJsonbValueConversion(cstate, val, WJB_END_ARRAY, nestlevel);
|
||||
|
||||
break;
|
||||
case jbvObject:
|
||||
|
||||
putJsonbValueConversion(cstate, val, WJB_BEGIN_OBJECT, nestlevel);
|
||||
for (i = 0; i < val->object.nPairs; i++) {
|
||||
putJsonbValueConversion(cstate, &val->object.pairs[i].key,
|
||||
WJB_KEY, nestlevel);
|
||||
|
||||
putJsonbValueConversion(cstate, &val->object.pairs[i].key, WJB_KEY, nestlevel);
|
||||
if (IsAJsonbScalar(&val->object.pairs[i].value) ||
|
||||
val->object.pairs[i].value.type == jbvBinary) {
|
||||
putJsonbValueConversion(cstate,
|
||||
&val->object.pairs[i].value,
|
||||
WJB_VALUE, nestlevel);
|
||||
putJsonbValueConversion(cstate, &val->object.pairs[i].value, WJB_VALUE, nestlevel);
|
||||
} else {
|
||||
walkJsonbValueConversion(&val->object.pairs[i].value,
|
||||
cstate, nestlevel + 1);
|
||||
walkJsonbValueConversion(&val->object.pairs[i].value, cstate, nestlevel + 1);
|
||||
}
|
||||
}
|
||||
putJsonbValueConversion(cstate, val, WJB_END_OBJECT, nestlevel);
|
||||
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unknown type of jsonb container");
|
||||
@ -1228,13 +1177,11 @@ walkJsonbValueConversion(JsonbValue * val, convertState * cstate,
|
||||
* walkJsonbValueConversion() worker. Add padding sufficient to int-align our
|
||||
* access to conversion buffer.
|
||||
*/
|
||||
static inline
|
||||
short addPaddingInt(convertState * cstate)
|
||||
static inline short addPaddingInt(convertState *cstate)
|
||||
{
|
||||
short padlen, p;
|
||||
|
||||
padlen = INTALIGN(cstate->ptr - VARDATA(cstate->buffer)) -
|
||||
(cstate->ptr - VARDATA(cstate->buffer));
|
||||
padlen = INTALIGN(cstate->ptr - VARDATA(cstate->buffer)) - (cstate->ptr - VARDATA(cstate->buffer));
|
||||
|
||||
for (p = padlen; p > 0; p--) {
|
||||
*cstate->ptr = '\0';
|
||||
@ -1257,14 +1204,11 @@ short addPaddingInt(convertState * cstate)
|
||||
* rather, the function is called as required for the start of an Object/Array,
|
||||
* and the end (i.e. there is one call per sequential processing WJB_* token).
|
||||
*/
|
||||
static void
|
||||
putJsonbValueConversion(convertState * cstate, JsonbValue * val, uint32 flags,
|
||||
uint32 level)
|
||||
static void putJsonbValueConversion(convertState *cstate, JsonbValue *val, uint32 flags, uint32 level)
|
||||
{
|
||||
if (level == cstate->levelSz) {
|
||||
cstate->levelSz *= 2;
|
||||
cstate->allState = (convertLevel*)repalloc(cstate->allState,
|
||||
sizeof(convertLevel) * cstate->levelSz);
|
||||
cstate->allState = (convertLevel*)repalloc(cstate->allState, sizeof(convertLevel) * cstate->levelSz);
|
||||
}
|
||||
|
||||
cstate->contPtr = cstate->allState + level;
|
||||
@ -1303,7 +1247,6 @@ putJsonbValueConversion(convertState * cstate, JsonbValue * val, uint32 flags,
|
||||
cstate->contPtr->i++;
|
||||
} else if (flags & WJB_KEY) {
|
||||
Assert(val->type == jbvString);
|
||||
|
||||
putScalarConversion(cstate, val, level, cstate->contPtr->i * 2);
|
||||
} else if (flags & WJB_VALUE) {
|
||||
putScalarConversion(cstate, val, level, cstate->contPtr->i * 2 + 1);
|
||||
@ -1321,27 +1264,23 @@ putJsonbValueConversion(convertState * cstate, JsonbValue * val, uint32 flags,
|
||||
}
|
||||
|
||||
len = cstate->ptr - (char *) cstate->contPtr->begin;
|
||||
|
||||
prevPtr = cstate->contPtr - 1;
|
||||
|
||||
if (*prevPtr->header & JB_FARRAY) {
|
||||
i = prevPtr->i;
|
||||
|
||||
prevPtr->meta[i].header = JENTRY_ISNEST;
|
||||
|
||||
if (i == 0) {
|
||||
prevPtr->meta[0].header |= JENTRY_ISFIRST | len;
|
||||
} else {
|
||||
prevPtr->meta[i].header |=
|
||||
(prevPtr->meta[i - 1].header & JENTRY_POSMASK) + len;
|
||||
prevPtr->meta[i].header |= (prevPtr->meta[i - 1].header & JENTRY_POSMASK) + len;
|
||||
}
|
||||
} else if (*prevPtr->header & JB_FOBJECT) {
|
||||
i = 2 * prevPtr->i + 1; /* Value, not key */
|
||||
|
||||
prevPtr->meta[i].header = JENTRY_ISNEST;
|
||||
|
||||
prevPtr->meta[i].header |=
|
||||
(prevPtr->meta[i - 1].header & JENTRY_POSMASK) + len;
|
||||
prevPtr->meta[i].header |= (prevPtr->meta[i - 1].header & JENTRY_POSMASK) + len;
|
||||
} else {
|
||||
elog(ERROR, "invalid jsonb container type");
|
||||
}
|
||||
@ -1361,14 +1300,12 @@ putJsonbValueConversion(convertState * cstate, JsonbValue * val, uint32 flags,
|
||||
* walkJsonbValueConversion()). It handles the details with regard to Jentry
|
||||
* metadata peculiar to each scalar type.
|
||||
*/
|
||||
static void
|
||||
putScalarConversion(convertState * cstate, JsonbValue * scalarVal, uint32 level,
|
||||
uint32 i)
|
||||
static void putScalarConversion(convertState *cstate, JsonbValue *scalarVal, uint32 level, uint32 i)
|
||||
{
|
||||
int strlen;
|
||||
int numlen;
|
||||
short padlen;
|
||||
errno_t rc = 0;
|
||||
int strlen;
|
||||
int numlen;
|
||||
short padlen;
|
||||
errno_t rc = 0;
|
||||
|
||||
cstate->contPtr = cstate->allState + level;
|
||||
|
||||
@ -1388,7 +1325,7 @@ putScalarConversion(convertState * cstate, JsonbValue * scalarVal, uint32 level,
|
||||
}
|
||||
break;
|
||||
case jbvString:
|
||||
strlen = scalarVal->string.len > 0 ? scalarVal->string.len : 1;
|
||||
strlen = scalarVal->string.len > 0 ? scalarVal->string.len : 1;
|
||||
rc = memcpy_s(cstate->ptr, strlen, scalarVal->string.val, strlen);
|
||||
securec_check(rc, "\0", "\0");
|
||||
cstate->ptr += scalarVal->string.len;
|
||||
@ -1397,8 +1334,7 @@ putScalarConversion(convertState * cstate, JsonbValue * scalarVal, uint32 level,
|
||||
cstate->contPtr->meta[0].header |= scalarVal->string.len;
|
||||
} else {
|
||||
cstate->contPtr->meta[i].header |=
|
||||
(cstate->contPtr->meta[i - 1].header & JENTRY_POSMASK) +
|
||||
scalarVal->string.len;
|
||||
(cstate->contPtr->meta[i - 1].header & JENTRY_POSMASK) + scalarVal->string.len;
|
||||
}
|
||||
break;
|
||||
case jbvNumeric:
|
||||
@ -1414,17 +1350,14 @@ putScalarConversion(convertState * cstate, JsonbValue * scalarVal, uint32 level,
|
||||
cstate->contPtr->meta[0].header |= padlen + numlen;
|
||||
} else {
|
||||
cstate->contPtr->meta[i].header |=
|
||||
(cstate->contPtr->meta[i - 1].header & JENTRY_POSMASK)
|
||||
+ padlen + numlen;
|
||||
(cstate->contPtr->meta[i - 1].header & JENTRY_POSMASK) + padlen + numlen;
|
||||
}
|
||||
break;
|
||||
case jbvBool:
|
||||
cstate->contPtr->meta[i].header |= (scalarVal->boolean) ?
|
||||
JENTRY_ISTRUE : JENTRY_ISFALSE;
|
||||
cstate->contPtr->meta[i].header |= (scalarVal->boolean) ? JENTRY_ISTRUE : JENTRY_ISFALSE;
|
||||
|
||||
if (i > 0) {
|
||||
cstate->contPtr->meta[i].header |=
|
||||
cstate->contPtr->meta[i - 1].header & JENTRY_POSMASK;
|
||||
cstate->contPtr->meta[i].header |= cstate->contPtr->meta[i - 1].header & JENTRY_POSMASK;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -1436,8 +1369,7 @@ putScalarConversion(convertState * cstate, JsonbValue * scalarVal, uint32 level,
|
||||
* Given superheader pointer into buffer, initialize iterator. Must be a
|
||||
* container type.
|
||||
*/
|
||||
static void
|
||||
iteratorFromContainerBuf(JsonbIterator * it, JsonbSuperHeader sheader)
|
||||
static void iteratorFromContainerBuf(JsonbIterator *it, JsonbSuperHeader sheader)
|
||||
{
|
||||
uint32 superheader = *(uint32 *) sheader;
|
||||
|
||||
@ -1462,8 +1394,7 @@ iteratorFromContainerBuf(JsonbIterator * it, JsonbSuperHeader sheader)
|
||||
* Offset reflects that nElems indicates JsonbPairs in an object.
|
||||
* Each key and each value contain Jentry metadata just the same.
|
||||
*/
|
||||
it->dataProper =
|
||||
(char *) it->meta + it->nElems * sizeof(JEntry) * 2;
|
||||
it->dataProper = (char *) it->meta + it->nElems * sizeof(JEntry) * 2;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unknown type of jsonb container");
|
||||
@ -1488,40 +1419,33 @@ iteratorFromContainerBuf(JsonbIterator * it, JsonbSuperHeader sheader)
|
||||
* to do this. The point is that our JsonbValues scalars can be passed around
|
||||
* anywhere).
|
||||
*/
|
||||
static bool
|
||||
formIterIsContainer(JsonbIterator ** it, JsonbValue * val, JEntry * ent,
|
||||
bool skipNested)
|
||||
static bool formIterIsContainer(JsonbIterator **it, JsonbValue *val, JEntry *ent, bool skipNested)
|
||||
{
|
||||
if (JBE_ISNULL(*ent)) {
|
||||
val->type = jbvNull;
|
||||
val->estSize = sizeof(JEntry);
|
||||
|
||||
return false;
|
||||
} else if (JBE_ISSTRING(*ent)) {
|
||||
val->type = jbvString;
|
||||
val->string.val = (*it)->dataProper + JBE_OFF(*ent);
|
||||
val->string.len = JBE_LEN(*ent);
|
||||
val->estSize = sizeof(JEntry) + val->string.len;
|
||||
|
||||
return false;
|
||||
} else if (JBE_ISNUMERIC(*ent)) {
|
||||
val->type = jbvNumeric;
|
||||
val->numeric = (Numeric) ((*it)->dataProper + INTALIGN(JBE_OFF(*ent)));
|
||||
val->estSize = 2 * sizeof(JEntry) + VARSIZE_ANY(val->numeric);
|
||||
|
||||
return false;
|
||||
} else if (JBE_ISBOOL(*ent)) {
|
||||
val->type = jbvBool;
|
||||
val->boolean = JBE_ISBOOL_TRUE(*ent) != 0;
|
||||
val->estSize = sizeof(JEntry);
|
||||
|
||||
return false;
|
||||
} else if (skipNested) {
|
||||
val->type = jbvBinary;
|
||||
val->binary.data = (*it)->dataProper + INTALIGN(JBE_OFF(*ent));
|
||||
val->binary.len = JBE_LEN(*ent) - (INTALIGN(JBE_OFF(*ent)) - JBE_OFF(*ent));
|
||||
val->estSize = val->binary.len + 2 * sizeof(JEntry);
|
||||
|
||||
return false;
|
||||
} else {
|
||||
/*
|
||||
@ -1531,13 +1455,9 @@ formIterIsContainer(JsonbIterator ** it, JsonbValue * val, JEntry * ent,
|
||||
* Get child iterator.
|
||||
*/
|
||||
JsonbIterator *child = (JsonbIterator*)palloc(sizeof(JsonbIterator));
|
||||
|
||||
iteratorFromContainerBuf(child,
|
||||
(*it)->dataProper + INTALIGN(JBE_OFF(*ent)));
|
||||
|
||||
iteratorFromContainerBuf(child, (*it)->dataProper + INTALIGN(JBE_OFF(*ent)));
|
||||
child->parent = *it;
|
||||
*it = child;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@ -1546,8 +1466,7 @@ formIterIsContainer(JsonbIterator ** it, JsonbValue * val, JEntry * ent,
|
||||
* JsonbIteratorNext() worker: Return parent, while freeing memory for current
|
||||
* iterator
|
||||
*/
|
||||
static JsonbIterator *
|
||||
freeAndGetParent(JsonbIterator * it)
|
||||
static JsonbIterator *freeAndGetParent(JsonbIterator *it)
|
||||
{
|
||||
JsonbIterator *v = it->parent;
|
||||
|
||||
@ -1558,8 +1477,7 @@ freeAndGetParent(JsonbIterator * it)
|
||||
/*
|
||||
* pushJsonbValue() worker: Iteration-like forming of Jsonb
|
||||
*/
|
||||
static JsonbParseState *
|
||||
pushState(JsonbParseState ** pstate)
|
||||
static JsonbParseState *pushState(JsonbParseState **pstate)
|
||||
{
|
||||
JsonbParseState *ns = (JsonbParseState*)palloc(sizeof(JsonbParseState));
|
||||
|
||||
@ -1570,8 +1488,7 @@ pushState(JsonbParseState ** pstate)
|
||||
/*
|
||||
* pushJsonbValue() worker: Append a pair key to state when generating a Jsonb
|
||||
*/
|
||||
static void
|
||||
appendKey(JsonbParseState * pstate, JsonbValue * string)
|
||||
static void appendKey(JsonbParseState *pstate, JsonbValue *string)
|
||||
{
|
||||
JsonbValue *object = &pstate->contVal;
|
||||
|
||||
@ -1587,8 +1504,7 @@ appendKey(JsonbParseState * pstate, JsonbValue * string)
|
||||
|
||||
if ((uint)object->object.nPairs >= pstate->size) {
|
||||
pstate->size *= 2;
|
||||
object->object.pairs = (JsonbPair*)repalloc(object->object.pairs,
|
||||
sizeof(JsonbPair) * pstate->size);
|
||||
object->object.pairs = (JsonbPair*)repalloc(object->object.pairs, sizeof(JsonbPair) * pstate->size);
|
||||
}
|
||||
|
||||
object->object.pairs[object->object.nPairs].key = *string;
|
||||
@ -1601,8 +1517,7 @@ appendKey(JsonbParseState * pstate, JsonbValue * string)
|
||||
* pushJsonbValue() worker: Append a pair value to state when generating a
|
||||
* Jsonb
|
||||
*/
|
||||
static void
|
||||
appendValue(JsonbParseState * pstate, JsonbValue * scalarVal)
|
||||
static void appendValue(JsonbParseState *pstate, JsonbValue *scalarVal)
|
||||
{
|
||||
JsonbValue *object = &pstate->contVal;
|
||||
|
||||
@ -1615,8 +1530,7 @@ appendValue(JsonbParseState * pstate, JsonbValue * scalarVal)
|
||||
/*
|
||||
* pushJsonbValue() worker: Append an element to state when generating a Jsonb
|
||||
*/
|
||||
static void
|
||||
appendElement(JsonbParseState * pstate, JsonbValue * scalarVal)
|
||||
static void appendElement(JsonbParseState *pstate, JsonbValue *scalarVal)
|
||||
{
|
||||
JsonbValue *array = &pstate->contVal;
|
||||
|
||||
@ -1631,8 +1545,7 @@ appendElement(JsonbParseState * pstate, JsonbValue * scalarVal)
|
||||
|
||||
if ((uint)array->array.nElems >= pstate->size) {
|
||||
pstate->size *= 2;
|
||||
array->array.elems = (JsonbValue*)repalloc(array->array.elems,
|
||||
sizeof(JsonbValue) * pstate->size);
|
||||
array->array.elems = (JsonbValue*)repalloc(array->array.elems, sizeof(JsonbValue) * pstate->size);
|
||||
}
|
||||
|
||||
array->array.elems[array->array.nElems++] = *scalarVal;
|
||||
@ -1655,8 +1568,7 @@ appendElement(JsonbParseState * pstate, JsonbValue * scalarVal)
|
||||
* to true iff a and b have full binary equality, since some callers have an
|
||||
* interest in whether the two values are equal or merely equivalent.
|
||||
*/
|
||||
static int
|
||||
lengthCompareJsonbStringValue(const void *a, const void *b, void *binequal)
|
||||
static int lengthCompareJsonbStringValue(const void *a, const void *b, void *binequal)
|
||||
{
|
||||
const JsonbValue *va = (const JsonbValue *) a;
|
||||
const JsonbValue *vb = (const JsonbValue *) b;
|
||||
@ -1688,12 +1600,11 @@ lengthCompareJsonbStringValue(const void *a, const void *b, void *binequal)
|
||||
*
|
||||
* Pairs with equals keys are ordered such that the order field is respected.
|
||||
*/
|
||||
static int
|
||||
lengthCompareJsonbPair(const void *a, const void *b, void *binequal)
|
||||
static int lengthCompareJsonbPair(const void *a, const void *b, void *binequal)
|
||||
{
|
||||
const JsonbPair *pa = (const JsonbPair *) a;
|
||||
const JsonbPair *pb = (const JsonbPair *) b;
|
||||
int res;
|
||||
int res;
|
||||
|
||||
res = lengthCompareJsonbStringValue(&pa->key, &pb->key, binequal);
|
||||
|
||||
@ -1711,16 +1622,14 @@ lengthCompareJsonbPair(const void *a, const void *b, void *binequal)
|
||||
/*
|
||||
* Sort and unique-ify pairs in JsonbValue object
|
||||
*/
|
||||
static void
|
||||
uniqueifyJsonbObject(JsonbValue * object)
|
||||
static void uniqueifyJsonbObject(JsonbValue * object)
|
||||
{
|
||||
bool hasNonUniq = false;
|
||||
bool hasNonUniq = false;
|
||||
|
||||
Assert(object->type == jbvObject);
|
||||
|
||||
if (object->object.nPairs > 1) {
|
||||
qsort_arg(object->object.pairs, object->object.nPairs, sizeof(JsonbPair),
|
||||
lengthCompareJsonbPair, &hasNonUniq);
|
||||
qsort_arg(object->object.pairs, object->object.nPairs, sizeof(JsonbPair), lengthCompareJsonbPair, &hasNonUniq);
|
||||
}
|
||||
|
||||
if (hasNonUniq) {
|
||||
@ -1750,8 +1659,7 @@ uniqueifyJsonbObject(JsonbValue * object)
|
||||
*
|
||||
* Sorting uses internal ordering.
|
||||
*/
|
||||
static void
|
||||
uniqueifyJsonbArray(JsonbValue * array)
|
||||
static void uniqueifyJsonbArray(JsonbValue *array)
|
||||
{
|
||||
bool hasNonUniq = false;
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -454,37 +454,32 @@ char* numeric_out_sci(Numeric num, int scale)
|
||||
*
|
||||
* Output function for numeric data type without trailing zeroes.
|
||||
*/
|
||||
char *
|
||||
numeric_normalize(Numeric num)
|
||||
char *numeric_normalize(Numeric num)
|
||||
{
|
||||
NumericVar x;
|
||||
char *str;
|
||||
int orig, last;
|
||||
NumericVar x;
|
||||
char *str = NULL;
|
||||
int orig, last;
|
||||
|
||||
/*
|
||||
* Handle NaN
|
||||
*/
|
||||
if (NUMERIC_IS_NAN(num))
|
||||
return pstrdup("NaN");
|
||||
/*
|
||||
* Handle NaN
|
||||
*/
|
||||
if (NUMERIC_IS_NAN(num)) {
|
||||
return pstrdup("NaN");
|
||||
}
|
||||
init_var_from_num(num, &x);
|
||||
str = get_str_from_var(&x);
|
||||
orig = last = strlen(str) - 1;
|
||||
|
||||
init_var_from_num(num, &x);
|
||||
|
||||
str = get_str_from_var(&x);
|
||||
|
||||
orig = last = strlen(str) - 1;
|
||||
|
||||
for (;;)
|
||||
{
|
||||
if (last == 0 || str[last] != '0')
|
||||
break;
|
||||
|
||||
last--;
|
||||
}
|
||||
|
||||
if (last > 0 && last != orig)
|
||||
str[last] = '\0';
|
||||
|
||||
return str;
|
||||
for (;;) {
|
||||
if (last == 0 || str[last] != '0') {
|
||||
break;
|
||||
}
|
||||
last--;
|
||||
}
|
||||
if (last > 0 && last != orig) {
|
||||
str[last] = '\0';
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -2331,8 +2331,8 @@ bool pgxc_is_internal_agg_final_func(Oid funcid)
|
||||
case TIMESTAMPTZLISTAGGNOARG2FUNCOID: // timestamptz_listagg_noarg2_finalfn
|
||||
case INTERVALLISTAGGFUNCOID: // interval_listagg_finalfn
|
||||
case INTERVALLISTAGGNOARG2FUNCOID: // interval_listagg_noarg2_finalfn
|
||||
case JSONAGGFUNCOID: //json_agg_finalfn
|
||||
case JSONOBJECTAGGFUNCOID: //json_object_agg_finalfn
|
||||
case JSONAGGFUNCOID: // json_agg_finalfn
|
||||
case JSONOBJECTAGGFUNCOID: // json_object_agg_finalfn
|
||||
is_internal_func = false;
|
||||
break;
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user