aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/jsonfuncs.c
diff options
context:
space:
mode:
authorHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-05-07 23:16:19 +0300
committerHeikki Linnakangas <heikki.linnakangas@iki.fi>2014-05-07 23:16:19 +0300
commit364ddc3e5cbd01c93a39896b5260509129a9883e (patch)
tree88b49bb7ade35e082ce176d76a5d404cf1c9a85e /src/backend/utils/adt/jsonfuncs.c
parent4d155d8b08fe08c1a1649fdbad61c6dcf4a8671f (diff)
downloadpostgresql-364ddc3e5cbd01c93a39896b5260509129a9883e.tar.gz
postgresql-364ddc3e5cbd01c93a39896b5260509129a9883e.zip
Clean up jsonb code.
The main target of this cleanup is the convertJsonb() function, but I also touched a lot of other things that I spotted into in the process. The new convertToJsonb() function uses an output buffer that's resized on demand, so the code to estimate of the size of JsonbValue is removed. The on-disk format was not changed, even though I refactored the structs used to handle it. The term "superheader" is replaced with "container". The jsonb_exists_any and jsonb_exists_all functions no longer sort the input array. That was a premature optimization, the idea being that if there are duplicates in the input array, you only need to check them once. Also, sorting the array saves some effort in the binary search used to find a key within an object. But there were drawbacks too: the sorting and deduplicating obviously isn't free, and in the typical case there are no duplicates to remove, and the gain in the binary search was minimal. Remove all that, which makes the code simpler too. This includes a bug-fix; the total length of the elements in a jsonb array or object mustn't exceed 2^28. That is now checked.
Diffstat (limited to 'src/backend/utils/adt/jsonfuncs.c')
-rw-r--r--src/backend/utils/adt/jsonfuncs.c64
1 files changed, 32 insertions, 32 deletions
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 6b1ce9b3a9f..b67eb6555c1 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -106,7 +106,7 @@ static inline Datum populate_recordset_worker(FunctionCallInfo fcinfo,
bool have_record_arg);
/* Worker that takes care of common setup for us */
-static JsonbValue *findJsonbValueFromSuperHeaderLen(JsonbSuperHeader sheader,
+static JsonbValue *findJsonbValueFromContainerLen(JsonbContainer *container,
uint32 flags,
char *key,
uint32 keylen);
@@ -286,7 +286,7 @@ jsonb_object_keys(PG_FUNCTION_ARGS)
state->sent_count = 0;
state->result = palloc(state->result_size * sizeof(char *));
- it = JsonbIteratorInit(VARDATA_ANY(jb));
+ it = JsonbIteratorInit(&jb->root);
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
{
@@ -484,7 +484,7 @@ jsonb_object_field(PG_FUNCTION_ARGS)
Assert(JB_ROOT_IS_OBJECT(jb));
- it = JsonbIteratorInit(VARDATA_ANY(jb));
+ it = JsonbIteratorInit(&jb->root);
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
{
@@ -545,7 +545,7 @@ jsonb_object_field_text(PG_FUNCTION_ARGS)
Assert(JB_ROOT_IS_OBJECT(jb));
- it = JsonbIteratorInit(VARDATA_ANY(jb));
+ it = JsonbIteratorInit(&jb->root);
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
{
@@ -580,7 +580,7 @@ jsonb_object_field_text(PG_FUNCTION_ARGS)
StringInfo jtext = makeStringInfo();
Jsonb *tjb = JsonbValueToJsonb(&v);
- (void) JsonbToCString(jtext, VARDATA(tjb), -1);
+ (void) JsonbToCString(jtext, &tjb->root , -1);
result = cstring_to_text_with_len(jtext->data, jtext->len);
}
PG_RETURN_TEXT_P(result);
@@ -628,7 +628,7 @@ jsonb_array_element(PG_FUNCTION_ARGS)
Assert(JB_ROOT_IS_ARRAY(jb));
- it = JsonbIteratorInit(VARDATA_ANY(jb));
+ it = JsonbIteratorInit(&jb->root);
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
{
@@ -682,7 +682,7 @@ jsonb_array_element_text(PG_FUNCTION_ARGS)
Assert(JB_ROOT_IS_ARRAY(jb));
- it = JsonbIteratorInit(VARDATA_ANY(jb));
+ it = JsonbIteratorInit(&jb->root);
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
{
@@ -711,7 +711,7 @@ jsonb_array_element_text(PG_FUNCTION_ARGS)
StringInfo jtext = makeStringInfo();
Jsonb *tjb = JsonbValueToJsonb(&v);
- (void) JsonbToCString(jtext, VARDATA(tjb), -1);
+ (void) JsonbToCString(jtext, &tjb->root, -1);
result = cstring_to_text_with_len(jtext->data, jtext->len);
}
PG_RETURN_TEXT_P(result);
@@ -1155,7 +1155,7 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
have_array = false;
JsonbValue *jbvp = NULL;
JsonbValue tv;
- JsonbSuperHeader superHeader;
+ JsonbContainer *container;
if (array_contains_nulls(path))
ereport(ERROR,
@@ -1170,15 +1170,15 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
else if (JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb))
have_array = true;
- superHeader = (JsonbSuperHeader) VARDATA(jb);
+ container = &jb->root;
for (i = 0; i < npath; i++)
{
if (have_object)
{
- jbvp = findJsonbValueFromSuperHeaderLen(superHeader,
- JB_FOBJECT,
- VARDATA_ANY(pathtext[i]),
+ jbvp = findJsonbValueFromContainerLen(container,
+ JB_FOBJECT,
+ VARDATA_ANY(pathtext[i]),
VARSIZE_ANY_EXHDR(pathtext[i]));
}
else if (have_array)
@@ -1192,7 +1192,7 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
if (*endptr != '\0' || lindex > INT_MAX || lindex < 0)
PG_RETURN_NULL();
index = (uint32) lindex;
- jbvp = getIthJsonbValueFromSuperHeader(superHeader, index);
+ jbvp = getIthJsonbValueFromContainer(container, index);
}
else
{
@@ -1210,11 +1210,11 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
if (jbvp->type == jbvBinary)
{
- JsonbIterator *it = JsonbIteratorInit(jbvp->val.binary.data);
+ JsonbIterator *it = JsonbIteratorInit((JsonbContainer *) jbvp->val.binary.data);
int r;
r = JsonbIteratorNext(&it, &tv, true);
- superHeader = (JsonbSuperHeader) jbvp->val.binary.data;
+ container = (JsonbContainer *) jbvp->val.binary.data;
have_object = r == WJB_BEGIN_OBJECT;
have_array = r == WJB_BEGIN_ARRAY;
}
@@ -1238,7 +1238,7 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
if (as_text)
{
PG_RETURN_TEXT_P(cstring_to_text(JsonbToCString(NULL,
- VARDATA(res),
+ &res->root,
VARSIZE(res))));
}
else
@@ -1428,7 +1428,7 @@ each_worker_jsonb(FunctionCallInfo fcinfo, bool as_text)
ALLOCSET_DEFAULT_MAXSIZE);
- it = JsonbIteratorInit(VARDATA_ANY(jb));
+ it = JsonbIteratorInit(&jb->root);
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
{
@@ -1477,7 +1477,7 @@ each_worker_jsonb(FunctionCallInfo fcinfo, bool as_text)
StringInfo jtext = makeStringInfo();
Jsonb *jb = JsonbValueToJsonb(&v);
- (void) JsonbToCString(jtext, VARDATA(jb), 2 * v.estSize);
+ (void) JsonbToCString(jtext, &jb->root, 0);
sv = cstring_to_text_with_len(jtext->data, jtext->len);
}
@@ -1753,7 +1753,7 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, bool as_text)
ALLOCSET_DEFAULT_MAXSIZE);
- it = JsonbIteratorInit(VARDATA_ANY(jb));
+ it = JsonbIteratorInit(&jb->root);
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
{
@@ -1797,7 +1797,7 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, bool as_text)
StringInfo jtext = makeStringInfo();
Jsonb *jb = JsonbValueToJsonb(&v);
- (void) JsonbToCString(jtext, VARDATA(jb), 2 * v.estSize);
+ (void) JsonbToCString(jtext, &jb->root, 0);
sv = cstring_to_text_with_len(jtext->data, jtext->len);
}
@@ -2219,8 +2219,8 @@ populate_record_worker(FunctionCallInfo fcinfo, bool have_record_arg)
{
char *key = NameStr(tupdesc->attrs[i]->attname);
- v = findJsonbValueFromSuperHeaderLen(VARDATA(jb), JB_FOBJECT, key,
- strlen(key));
+ v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT, key,
+ strlen(key));
}
/*
@@ -2282,7 +2282,7 @@ populate_record_worker(FunctionCallInfo fcinfo, bool have_record_arg)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot populate with a nested object unless use_json_as_text is true")));
else if (v->type == jbvBinary)
- s = JsonbToCString(NULL, v->val.binary.data, v->val.binary.len);
+ s = JsonbToCString(NULL, (JsonbContainer *) v->val.binary.data, v->val.binary.len);
else
elog(ERROR, "invalid jsonb type");
}
@@ -2529,8 +2529,8 @@ make_row_from_rec_and_jsonb(Jsonb *element, PopulateRecordsetState *state)
key = NameStr(tupdesc->attrs[i]->attname);
- v = findJsonbValueFromSuperHeaderLen(VARDATA(element), JB_FOBJECT,
- key, strlen(key));
+ v = findJsonbValueFromContainerLen(&element->root, JB_FOBJECT,
+ key, strlen(key));
/*
* We can't just skip here if the key wasn't found since we might have
@@ -2582,7 +2582,7 @@ make_row_from_rec_and_jsonb(Jsonb *element, PopulateRecordsetState *state)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot populate with a nested object unless use_json_as_text is true")));
else if (v->type == jbvBinary)
- s = JsonbToCString(NULL, v->val.binary.data, v->val.binary.len);
+ s = JsonbToCString(NULL, (JsonbContainer *) v->val.binary.data, v->val.binary.len);
else
elog(ERROR, "invalid jsonb type");
@@ -2750,7 +2750,7 @@ populate_recordset_worker(FunctionCallInfo fcinfo, bool have_record_arg)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("cannot call jsonb_populate_recordset on non-array")));
- it = JsonbIteratorInit(VARDATA_ANY(jb));
+ it = JsonbIteratorInit(&jb->root);
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
{
@@ -3019,11 +3019,11 @@ populate_recordset_object_field_end(void *state, char *fname, bool isnull)
}
/*
- * findJsonbValueFromSuperHeader() wrapper that sets up JsonbValue key string.
+ * findJsonbValueFromContainer() wrapper that sets up JsonbValue key string.
*/
static JsonbValue *
-findJsonbValueFromSuperHeaderLen(JsonbSuperHeader sheader, uint32 flags,
- char *key, uint32 keylen)
+findJsonbValueFromContainerLen(JsonbContainer *container, uint32 flags,
+ char *key, uint32 keylen)
{
JsonbValue k;
@@ -3031,5 +3031,5 @@ findJsonbValueFromSuperHeaderLen(JsonbSuperHeader sheader, uint32 flags,
k.val.string.val = key;
k.val.string.len = keylen;
- return findJsonbValueFromSuperHeader(sheader, flags, NULL, &k);
+ return findJsonbValueFromContainer(container, flags, &k);
}