Commit abb014a6 authored by Alvaro Herrera's avatar Alvaro Herrera

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
parent e56cad84
...@@ -349,6 +349,7 @@ static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text); ...@@ -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) ...@@ -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)
{
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); if (v != NULL && v->type != jbvNull)
result = cstring_to_text_with_len(jtext->data, jtext->len); PG_RETURN_TEXT_P(JsonbValueAsText(v));
}
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) ...@@ -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)
{
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) if (v != NULL && v->type != jbvNull)
PG_RETURN_TEXT_P(result); PG_RETURN_TEXT_P(JsonbValueAsText(v));
}
PG_RETURN_NULL(); PG_RETURN_NULL();
} }
...@@ -1548,6 +1489,53 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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;
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 else
{ {
/* turn anything else into a json string */ /* Not in text mode, just return the Jsonb */
StringInfo jtext = makeStringInfo(); Jsonb *val = JsonbValueToJsonb(&v);
Jsonb *jb = JsonbValueToJsonb(&v);
(void) JsonbToCString(jtext, &jb->root, 0);
sv = cstring_to_text_with_len(jtext->data, jtext->len);
}
values[0] = PointerGetDatum(sv); values[0] = PointerGetDatum(val);
}
} }
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) ...@@ -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) ...@@ -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)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment