mirror of
https://github.com/postgres/postgres.git
synced 2025-07-24 14:22:24 +03:00
Improve the efficiency of certain jsonb get operations.
Instead of iterating over jsonb structures, use the inbuilt functions findJsonbValueFromContainerLen() and getIthJsonbValueFromContainer() to extract values directly. These functions use algorithms that are O(n log n) and O(1) respectively, whereas iterating is O(n), so we should see considerable speedup here. Teodor Sigaev.
This commit is contained in:
@ -466,12 +466,8 @@ Datum
|
|||||||
jsonb_object_field(PG_FUNCTION_ARGS)
|
jsonb_object_field(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||||
char *key = text_to_cstring(PG_GETARG_TEXT_P(1));
|
text *key = PG_GETARG_TEXT_PP(1);
|
||||||
int klen = strlen(key);
|
JsonbValue *v;
|
||||||
JsonbIterator *it;
|
|
||||||
JsonbValue v;
|
|
||||||
int r;
|
|
||||||
bool skipNested = false;
|
|
||||||
|
|
||||||
if (JB_ROOT_IS_SCALAR(jb))
|
if (JB_ROOT_IS_SCALAR(jb))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -484,25 +480,11 @@ jsonb_object_field(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
Assert(JB_ROOT_IS_OBJECT(jb));
|
Assert(JB_ROOT_IS_OBJECT(jb));
|
||||||
|
|
||||||
it = JsonbIteratorInit(&jb->root);
|
v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT,
|
||||||
|
VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
|
||||||
|
|
||||||
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
|
if (v != NULL)
|
||||||
{
|
PG_RETURN_JSONB(JsonbValueToJsonb(v));
|
||||||
skipNested = true;
|
|
||||||
|
|
||||||
if (r == WJB_KEY)
|
|
||||||
{
|
|
||||||
if (klen == v.val.string.len && strncmp(key, v.val.string.val, klen) == 0)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* The next thing the iterator fetches should be the value, no
|
|
||||||
* matter what shape it is.
|
|
||||||
*/
|
|
||||||
(void) JsonbIteratorNext(&it, &v, skipNested);
|
|
||||||
PG_RETURN_JSONB(JsonbValueToJsonb(&v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
}
|
}
|
||||||
@ -527,12 +509,8 @@ Datum
|
|||||||
jsonb_object_field_text(PG_FUNCTION_ARGS)
|
jsonb_object_field_text(PG_FUNCTION_ARGS)
|
||||||
{
|
{
|
||||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||||
char *key = text_to_cstring(PG_GETARG_TEXT_P(1));
|
text *key = PG_GETARG_TEXT_PP(1);
|
||||||
int klen = strlen(key);
|
JsonbValue *v;
|
||||||
JsonbIterator *it;
|
|
||||||
JsonbValue v;
|
|
||||||
int r;
|
|
||||||
bool skipNested = false;
|
|
||||||
|
|
||||||
if (JB_ROOT_IS_SCALAR(jb))
|
if (JB_ROOT_IS_SCALAR(jb))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -545,48 +523,42 @@ jsonb_object_field_text(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
Assert(JB_ROOT_IS_OBJECT(jb));
|
Assert(JB_ROOT_IS_OBJECT(jb));
|
||||||
|
|
||||||
it = JsonbIteratorInit(&jb->root);
|
v = findJsonbValueFromContainerLen(&jb->root, JB_FOBJECT,
|
||||||
|
VARDATA_ANY(key), VARSIZE_ANY_EXHDR(key));
|
||||||
|
|
||||||
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
|
if (v != NULL)
|
||||||
{
|
{
|
||||||
skipNested = true;
|
text *result = NULL;
|
||||||
|
|
||||||
if (r == WJB_KEY)
|
switch(v->type)
|
||||||
{
|
{
|
||||||
if (klen == v.val.string.len && strncmp(key, v.val.string.val, klen) == 0)
|
case jbvNull:
|
||||||
{
|
break;
|
||||||
text *result;
|
case jbvBool:
|
||||||
|
result = cstring_to_text(v->val.boolean ? "true" : "false");
|
||||||
/*
|
break;
|
||||||
* The next thing the iterator fetches should be the value, no
|
case jbvString:
|
||||||
* matter what shape it is.
|
result = cstring_to_text_with_len(v->val.string.val, v->val.string.len);
|
||||||
*/
|
break;
|
||||||
r = JsonbIteratorNext(&it, &v, skipNested);
|
case jbvNumeric:
|
||||||
|
result = cstring_to_text(DatumGetCString(DirectFunctionCall1(numeric_out,
|
||||||
/*
|
PointerGetDatum(v->val.numeric))));
|
||||||
* if it's a scalar string it needs to be de-escaped,
|
break;
|
||||||
* otherwise just return the text
|
case jbvBinary:
|
||||||
*/
|
|
||||||
if (v.type == jbvString)
|
|
||||||
{
|
|
||||||
result = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
|
|
||||||
}
|
|
||||||
else if (v.type == jbvNull)
|
|
||||||
{
|
|
||||||
PG_RETURN_NULL();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
StringInfo jtext = makeStringInfo();
|
StringInfo jtext = makeStringInfo();
|
||||||
Jsonb *tjb = JsonbValueToJsonb(&v);
|
|
||||||
|
|
||||||
(void) JsonbToCString(jtext, &tjb->root , -1);
|
(void) JsonbToCString(jtext, v->val.binary.data, -1);
|
||||||
result = cstring_to_text_with_len(jtext->data, jtext->len);
|
result = cstring_to_text_with_len(jtext->data, jtext->len);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "Wrong jsonb type: %d", v->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
PG_RETURN_TEXT_P(result);
|
PG_RETURN_TEXT_P(result);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
}
|
}
|
||||||
@ -611,11 +583,7 @@ jsonb_array_element(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||||
int element = PG_GETARG_INT32(1);
|
int element = PG_GETARG_INT32(1);
|
||||||
JsonbIterator *it;
|
JsonbValue *v;
|
||||||
JsonbValue v;
|
|
||||||
int r;
|
|
||||||
bool skipNested = false;
|
|
||||||
int element_number = 0;
|
|
||||||
|
|
||||||
if (JB_ROOT_IS_SCALAR(jb))
|
if (JB_ROOT_IS_SCALAR(jb))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -628,18 +596,9 @@ jsonb_array_element(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
Assert(JB_ROOT_IS_ARRAY(jb));
|
Assert(JB_ROOT_IS_ARRAY(jb));
|
||||||
|
|
||||||
it = JsonbIteratorInit(&jb->root);
|
v = getIthJsonbValueFromContainer(&jb->root, element);
|
||||||
|
if (v != NULL)
|
||||||
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
|
PG_RETURN_JSONB(JsonbValueToJsonb(v));
|
||||||
{
|
|
||||||
skipNested = true;
|
|
||||||
|
|
||||||
if (r == WJB_ELEM)
|
|
||||||
{
|
|
||||||
if (element_number++ == element)
|
|
||||||
PG_RETURN_JSONB(JsonbValueToJsonb(&v));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
}
|
}
|
||||||
@ -664,12 +623,7 @@ jsonb_array_element_text(PG_FUNCTION_ARGS)
|
|||||||
{
|
{
|
||||||
Jsonb *jb = PG_GETARG_JSONB(0);
|
Jsonb *jb = PG_GETARG_JSONB(0);
|
||||||
int element = PG_GETARG_INT32(1);
|
int element = PG_GETARG_INT32(1);
|
||||||
JsonbIterator *it;
|
JsonbValue *v;
|
||||||
JsonbValue v;
|
|
||||||
int r;
|
|
||||||
bool skipNested = false;
|
|
||||||
int element_number = 0;
|
|
||||||
|
|
||||||
|
|
||||||
if (JB_ROOT_IS_SCALAR(jb))
|
if (JB_ROOT_IS_SCALAR(jb))
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
@ -682,42 +636,40 @@ jsonb_array_element_text(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
Assert(JB_ROOT_IS_ARRAY(jb));
|
Assert(JB_ROOT_IS_ARRAY(jb));
|
||||||
|
|
||||||
it = JsonbIteratorInit(&jb->root);
|
v = getIthJsonbValueFromContainer(&jb->root, element);
|
||||||
|
if (v != NULL)
|
||||||
|
{
|
||||||
|
text *result = NULL;
|
||||||
|
|
||||||
while ((r = JsonbIteratorNext(&it, &v, skipNested)) != WJB_DONE)
|
switch(v->type)
|
||||||
{
|
{
|
||||||
skipNested = true;
|
case jbvNull:
|
||||||
|
break;
|
||||||
if (r == WJB_ELEM)
|
case jbvBool:
|
||||||
{
|
result = cstring_to_text(v->val.boolean ? "true" : "false");
|
||||||
if (element_number++ == element)
|
break;
|
||||||
{
|
case jbvString:
|
||||||
/*
|
result = cstring_to_text_with_len(v->val.string.val, v->val.string.len);
|
||||||
* if it's a scalar string it needs to be de-escaped,
|
break;
|
||||||
* otherwise just return the text
|
case jbvNumeric:
|
||||||
*/
|
result = cstring_to_text(DatumGetCString(DirectFunctionCall1(numeric_out,
|
||||||
text *result;
|
PointerGetDatum(v->val.numeric))));
|
||||||
|
break;
|
||||||
if (v.type == jbvString)
|
case jbvBinary:
|
||||||
{
|
|
||||||
result = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
|
|
||||||
}
|
|
||||||
else if (v.type == jbvNull)
|
|
||||||
{
|
|
||||||
PG_RETURN_NULL();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
StringInfo jtext = makeStringInfo();
|
StringInfo jtext = makeStringInfo();
|
||||||
Jsonb *tjb = JsonbValueToJsonb(&v);
|
|
||||||
|
|
||||||
(void) JsonbToCString(jtext, &tjb->root, -1);
|
(void) JsonbToCString(jtext, v->val.binary.data, -1);
|
||||||
result = cstring_to_text_with_len(jtext->data, jtext->len);
|
result = cstring_to_text_with_len(jtext->data, jtext->len);
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
elog(ERROR, "Wrong jsonb type: %d", v->type);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result)
|
||||||
PG_RETURN_TEXT_P(result);
|
PG_RETURN_TEXT_P(result);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user