Refactor code into new JsonbValueAsText, and use it more
jsonb_object_field_text and jsonb_array_element_text both contained identical copies of this code, so extract that into new routine JsonbValueAsText. This can also be used in other places, to measurable performance benefit: the jsonb_each() and jsonb_array_elements() functions can use it for outputting text forms instead of their less efficient current implementation (because we no longer need to build intermediate a jsonb representation of each value). Author: Nikita Glukhov Discussion: https://postgr.es/m/7c417f90-f95f-247e-ba63-d95e39c0ad14@postgrespro.ru
This commit is contained in:
parent
e56cad84d5
commit
abb014a631
@ -349,6 +349,7 @@ static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text);
|
|||||||
static text *get_worker(text *json, char **tpath, int *ipath, int npath,
|
static text *get_worker(text *json, char **tpath, int *ipath, int npath,
|
||||||
bool normalize_results);
|
bool normalize_results);
|
||||||
static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text);
|
static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text);
|
||||||
|
static text *JsonbValueAsText(JsonbValue *v);
|
||||||
|
|
||||||
/* semantic action functions for json_array_length */
|
/* semantic action functions for json_array_length */
|
||||||
static void alen_object_start(void *state);
|
static void alen_object_start(void *state);
|
||||||
@ -761,39 +762,9 @@ jsonb_object_field_text(PG_FUNCTION_ARGS)
|
|||||||
VARDATA_ANY(key),
|
VARDATA_ANY(key),
|
||||||
VARSIZE_ANY_EXHDR(key));
|
VARSIZE_ANY_EXHDR(key));
|
||||||
|
|
||||||
if (v != NULL)
|
|
||||||
{
|
|
||||||
text *result = NULL;
|
|
||||||
|
|
||||||
switch (v->type)
|
if (v != NULL && v->type != jbvNull)
|
||||||
{
|
PG_RETURN_TEXT_P(JsonbValueAsText(v));
|
||||||
case jbvNull:
|
|
||||||
break;
|
|
||||||
case jbvBool:
|
|
||||||
result = cstring_to_text(v->val.boolean ? "true" : "false");
|
|
||||||
break;
|
|
||||||
case jbvString:
|
|
||||||
result = cstring_to_text_with_len(v->val.string.val, v->val.string.len);
|
|
||||||
break;
|
|
||||||
case jbvNumeric:
|
|
||||||
result = cstring_to_text(DatumGetCString(DirectFunctionCall1(numeric_out,
|
|
||||||
PointerGetDatum(v->val.numeric))));
|
|
||||||
break;
|
|
||||||
case jbvBinary:
|
|
||||||
{
|
|
||||||
StringInfo jtext = makeStringInfo();
|
|
||||||
|
|
||||||
(void) JsonbToCString(jtext, v->val.binary.data, -1);
|
|
||||||
result = cstring_to_text_with_len(jtext->data, jtext->len);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
PG_RETURN_TEXT_P(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
}
|
}
|
||||||
@ -878,39 +849,9 @@ jsonb_array_element_text(PG_FUNCTION_ARGS)
|
|||||||
}
|
}
|
||||||
|
|
||||||
v = getIthJsonbValueFromContainer(&jb->root, element);
|
v = getIthJsonbValueFromContainer(&jb->root, element);
|
||||||
if (v != NULL)
|
|
||||||
{
|
|
||||||
text *result = NULL;
|
|
||||||
|
|
||||||
switch (v->type)
|
if (v != NULL && v->type != jbvNull)
|
||||||
{
|
PG_RETURN_TEXT_P(JsonbValueAsText(v));
|
||||||
case jbvNull:
|
|
||||||
break;
|
|
||||||
case jbvBool:
|
|
||||||
result = cstring_to_text(v->val.boolean ? "true" : "false");
|
|
||||||
break;
|
|
||||||
case jbvString:
|
|
||||||
result = cstring_to_text_with_len(v->val.string.val, v->val.string.len);
|
|
||||||
break;
|
|
||||||
case jbvNumeric:
|
|
||||||
result = cstring_to_text(DatumGetCString(DirectFunctionCall1(numeric_out,
|
|
||||||
PointerGetDatum(v->val.numeric))));
|
|
||||||
break;
|
|
||||||
case jbvBinary:
|
|
||||||
{
|
|
||||||
StringInfo jtext = makeStringInfo();
|
|
||||||
|
|
||||||
(void) JsonbToCString(jtext, v->val.binary.data, -1);
|
|
||||||
result = cstring_to_text_with_len(jtext->data, jtext->len);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (result)
|
|
||||||
PG_RETURN_TEXT_P(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
PG_RETURN_NULL();
|
PG_RETURN_NULL();
|
||||||
}
|
}
|
||||||
@ -1548,6 +1489,53 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Return the text representation of the given JsonbValue.
|
||||||
|
*/
|
||||||
|
static text *
|
||||||
|
JsonbValueAsText(JsonbValue *v)
|
||||||
|
{
|
||||||
|
switch (v->type)
|
||||||
|
{
|
||||||
|
case jbvNull:
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
case jbvBool:
|
||||||
|
return v->val.boolean ?
|
||||||
|
cstring_to_text_with_len("true", 4) :
|
||||||
|
cstring_to_text_with_len("false", 5);
|
||||||
|
|
||||||
|
case jbvString:
|
||||||
|
return cstring_to_text_with_len(v->val.string.val,
|
||||||
|
v->val.string.len);
|
||||||
|
|
||||||
|
case jbvNumeric:
|
||||||
|
{
|
||||||
|
Datum cstr;
|
||||||
|
|
||||||
|
cstr = DirectFunctionCall1(numeric_out,
|
||||||
|
PointerGetDatum(v->val.numeric));
|
||||||
|
|
||||||
|
return cstring_to_text(DatumGetCString(cstr));
|
||||||
|
}
|
||||||
|
|
||||||
|
case jbvBinary:
|
||||||
|
{
|
||||||
|
StringInfoData jtext;
|
||||||
|
|
||||||
|
initStringInfo(&jtext);
|
||||||
|
(void) JsonbToCString(&jtext, v->val.binary.data,
|
||||||
|
v->val.binary.len);
|
||||||
|
|
||||||
|
return cstring_to_text_with_len(jtext.data, jtext.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* SQL function json_array_length(json) -> int
|
* SQL function json_array_length(json) -> int
|
||||||
*/
|
*/
|
||||||
@ -1758,26 +1746,7 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
|
|||||||
values[1] = (Datum) NULL;
|
values[1] = (Datum) NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
values[1] = PointerGetDatum(JsonbValueAsText(&v));
|
||||||
text *sv;
|
|
||||||
|
|
||||||
if (v.type == jbvString)
|
|
||||||
{
|
|
||||||
/* In text mode, scalar strings should be dequoted */
|
|
||||||
sv = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Turn anything else into a json string */
|
|
||||||
StringInfo jtext = makeStringInfo();
|
|
||||||
Jsonb *jb = JsonbValueToJsonb(&v);
|
|
||||||
|
|
||||||
(void) JsonbToCString(jtext, &jb->root, 0);
|
|
||||||
sv = cstring_to_text_with_len(jtext->data, jtext->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
values[1] = PointerGetDatum(sv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -2053,13 +2022,7 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
|
|||||||
/* use the tmp context so we can clean up after each tuple is done */
|
/* use the tmp context so we can clean up after each tuple is done */
|
||||||
old_cxt = MemoryContextSwitchTo(tmp_cxt);
|
old_cxt = MemoryContextSwitchTo(tmp_cxt);
|
||||||
|
|
||||||
if (!as_text)
|
if (as_text)
|
||||||
{
|
|
||||||
Jsonb *val = JsonbValueToJsonb(&v);
|
|
||||||
|
|
||||||
values[0] = PointerGetDatum(val);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
if (v.type == jbvNull)
|
if (v.type == jbvNull)
|
||||||
{
|
{
|
||||||
@ -2068,26 +2031,14 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
|
|||||||
values[0] = (Datum) NULL;
|
values[0] = (Datum) NULL;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
values[0] = PointerGetDatum(JsonbValueAsText(&v));
|
||||||
text *sv;
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Not in text mode, just return the Jsonb */
|
||||||
|
Jsonb *val = JsonbValueToJsonb(&v);
|
||||||
|
|
||||||
if (v.type == jbvString)
|
values[0] = PointerGetDatum(val);
|
||||||
{
|
|
||||||
/* in text mode scalar strings should be dequoted */
|
|
||||||
sv = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* turn anything else into a json string */
|
|
||||||
StringInfo jtext = makeStringInfo();
|
|
||||||
Jsonb *jb = JsonbValueToJsonb(&v);
|
|
||||||
|
|
||||||
(void) JsonbToCString(jtext, &jb->root, 0);
|
|
||||||
sv = cstring_to_text_with_len(jtext->data, jtext->len);
|
|
||||||
}
|
|
||||||
|
|
||||||
values[0] = PointerGetDatum(sv);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
tuple = heap_form_tuple(ret_tdesc, values, nulls);
|
tuple = heap_form_tuple(ret_tdesc, values, nulls);
|
||||||
@ -4430,7 +4381,6 @@ jsonb_delete_idx(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* SQL function jsonb_set(jsonb, text[], jsonb, boolean)
|
* SQL function jsonb_set(jsonb, text[], jsonb, boolean)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
jsonb_set(PG_FUNCTION_ARGS)
|
jsonb_set(PG_FUNCTION_ARGS)
|
||||||
@ -4522,7 +4472,6 @@ jsonb_delete_path(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* SQL function jsonb_insert(jsonb, text[], jsonb, boolean)
|
* SQL function jsonb_insert(jsonb, text[], jsonb, boolean)
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
Datum
|
Datum
|
||||||
jsonb_insert(PG_FUNCTION_ARGS)
|
jsonb_insert(PG_FUNCTION_ARGS)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user