Skip to content

Commit abb014a

Browse files
committed
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
1 parent e56cad8 commit abb014a

File tree

1 file changed

+61
-112
lines changed

1 file changed

+61
-112
lines changed

src/backend/utils/adt/jsonfuncs.c

Lines changed: 61 additions & 112 deletions
Original file line numberDiff line numberDiff line change
@@ -349,6 +349,7 @@ static Datum get_path_all(FunctionCallInfo fcinfo, bool as_text);
349349
static text *get_worker(text *json, char **tpath, int *ipath, int npath,
350350
bool normalize_results);
351351
static Datum get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text);
352+
static text *JsonbValueAsText(JsonbValue *v);
352353

353354
/* semantic action functions for json_array_length */
354355
static void alen_object_start(void *state);
@@ -761,39 +762,9 @@ jsonb_object_field_text(PG_FUNCTION_ARGS)
761762
VARDATA_ANY(key),
762763
VARSIZE_ANY_EXHDR(key));
763764

764-
if (v != NULL)
765-
{
766-
text *result = NULL;
767765

768-
switch (v->type)
769-
{
770-
case jbvNull:
771-
break;
772-
case jbvBool:
773-
result = cstring_to_text(v->val.boolean ? "true" : "false");
774-
break;
775-
case jbvString:
776-
result = cstring_to_text_with_len(v->val.string.val, v->val.string.len);
777-
break;
778-
case jbvNumeric:
779-
result = cstring_to_text(DatumGetCString(DirectFunctionCall1(numeric_out,
780-
PointerGetDatum(v->val.numeric))));
781-
break;
782-
case jbvBinary:
783-
{
784-
StringInfo jtext = makeStringInfo();
785-
786-
(void) JsonbToCString(jtext, v->val.binary.data, -1);
787-
result = cstring_to_text_with_len(jtext->data, jtext->len);
788-
}
789-
break;
790-
default:
791-
elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
792-
}
793-
794-
if (result)
795-
PG_RETURN_TEXT_P(result);
796-
}
766+
if (v != NULL && v->type != jbvNull)
767+
PG_RETURN_TEXT_P(JsonbValueAsText(v));
797768

798769
PG_RETURN_NULL();
799770
}
@@ -878,39 +849,9 @@ jsonb_array_element_text(PG_FUNCTION_ARGS)
878849
}
879850

880851
v = getIthJsonbValueFromContainer(&jb->root, element);
881-
if (v != NULL)
882-
{
883-
text *result = NULL;
884-
885-
switch (v->type)
886-
{
887-
case jbvNull:
888-
break;
889-
case jbvBool:
890-
result = cstring_to_text(v->val.boolean ? "true" : "false");
891-
break;
892-
case jbvString:
893-
result = cstring_to_text_with_len(v->val.string.val, v->val.string.len);
894-
break;
895-
case jbvNumeric:
896-
result = cstring_to_text(DatumGetCString(DirectFunctionCall1(numeric_out,
897-
PointerGetDatum(v->val.numeric))));
898-
break;
899-
case jbvBinary:
900-
{
901-
StringInfo jtext = makeStringInfo();
902852

903-
(void) JsonbToCString(jtext, v->val.binary.data, -1);
904-
result = cstring_to_text_with_len(jtext->data, jtext->len);
905-
}
906-
break;
907-
default:
908-
elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
909-
}
910-
911-
if (result)
912-
PG_RETURN_TEXT_P(result);
913-
}
853+
if (v != NULL && v->type != jbvNull)
854+
PG_RETURN_TEXT_P(JsonbValueAsText(v));
914855

915856
PG_RETURN_NULL();
916857
}
@@ -1548,6 +1489,53 @@ get_jsonb_path_all(FunctionCallInfo fcinfo, bool as_text)
15481489
}
15491490
}
15501491

1492+
/*
1493+
* Return the text representation of the given JsonbValue.
1494+
*/
1495+
static text *
1496+
JsonbValueAsText(JsonbValue *v)
1497+
{
1498+
switch (v->type)
1499+
{
1500+
case jbvNull:
1501+
return NULL;
1502+
1503+
case jbvBool:
1504+
return v->val.boolean ?
1505+
cstring_to_text_with_len("true", 4) :
1506+
cstring_to_text_with_len("false", 5);
1507+
1508+
case jbvString:
1509+
return cstring_to_text_with_len(v->val.string.val,
1510+
v->val.string.len);
1511+
1512+
case jbvNumeric:
1513+
{
1514+
Datum cstr;
1515+
1516+
cstr = DirectFunctionCall1(numeric_out,
1517+
PointerGetDatum(v->val.numeric));
1518+
1519+
return cstring_to_text(DatumGetCString(cstr));
1520+
}
1521+
1522+
case jbvBinary:
1523+
{
1524+
StringInfoData jtext;
1525+
1526+
initStringInfo(&jtext);
1527+
(void) JsonbToCString(&jtext, v->val.binary.data,
1528+
v->val.binary.len);
1529+
1530+
return cstring_to_text_with_len(jtext.data, jtext.len);
1531+
}
1532+
1533+
default:
1534+
elog(ERROR, "unrecognized jsonb type: %d", (int) v->type);
1535+
return NULL;
1536+
}
1537+
}
1538+
15511539
/*
15521540
* SQL function json_array_length(json) -> int
15531541
*/
@@ -1758,26 +1746,7 @@ each_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname, bool as_text)
17581746
values[1] = (Datum) NULL;
17591747
}
17601748
else
1761-
{
1762-
text *sv;
1763-
1764-
if (v.type == jbvString)
1765-
{
1766-
/* In text mode, scalar strings should be dequoted */
1767-
sv = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
1768-
}
1769-
else
1770-
{
1771-
/* Turn anything else into a json string */
1772-
StringInfo jtext = makeStringInfo();
1773-
Jsonb *jb = JsonbValueToJsonb(&v);
1774-
1775-
(void) JsonbToCString(jtext, &jb->root, 0);
1776-
sv = cstring_to_text_with_len(jtext->data, jtext->len);
1777-
}
1778-
1779-
values[1] = PointerGetDatum(sv);
1780-
}
1749+
values[1] = PointerGetDatum(JsonbValueAsText(&v));
17811750
}
17821751
else
17831752
{
@@ -2053,13 +2022,7 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
20532022
/* use the tmp context so we can clean up after each tuple is done */
20542023
old_cxt = MemoryContextSwitchTo(tmp_cxt);
20552024

2056-
if (!as_text)
2057-
{
2058-
Jsonb *val = JsonbValueToJsonb(&v);
2059-
2060-
values[0] = PointerGetDatum(val);
2061-
}
2062-
else
2025+
if (as_text)
20632026
{
20642027
if (v.type == jbvNull)
20652028
{
@@ -2068,26 +2031,14 @@ elements_worker_jsonb(FunctionCallInfo fcinfo, const char *funcname,
20682031
values[0] = (Datum) NULL;
20692032
}
20702033
else
2071-
{
2072-
text *sv;
2073-
2074-
if (v.type == jbvString)
2075-
{
2076-
/* in text mode scalar strings should be dequoted */
2077-
sv = cstring_to_text_with_len(v.val.string.val, v.val.string.len);
2078-
}
2079-
else
2080-
{
2081-
/* turn anything else into a json string */
2082-
StringInfo jtext = makeStringInfo();
2083-
Jsonb *jb = JsonbValueToJsonb(&v);
2084-
2085-
(void) JsonbToCString(jtext, &jb->root, 0);
2086-
sv = cstring_to_text_with_len(jtext->data, jtext->len);
2087-
}
2034+
values[0] = PointerGetDatum(JsonbValueAsText(&v));
2035+
}
2036+
else
2037+
{
2038+
/* Not in text mode, just return the Jsonb */
2039+
Jsonb *val = JsonbValueToJsonb(&v);
20882040

2089-
values[0] = PointerGetDatum(sv);
2090-
}
2041+
values[0] = PointerGetDatum(val);
20912042
}
20922043

20932044
tuple = heap_form_tuple(ret_tdesc, values, nulls);
@@ -4430,7 +4381,6 @@ jsonb_delete_idx(PG_FUNCTION_ARGS)
44304381

44314382
/*
44324383
* SQL function jsonb_set(jsonb, text[], jsonb, boolean)
4433-
*
44344384
*/
44354385
Datum
44364386
jsonb_set(PG_FUNCTION_ARGS)
@@ -4522,7 +4472,6 @@ jsonb_delete_path(PG_FUNCTION_ARGS)
45224472

45234473
/*
45244474
* SQL function jsonb_insert(jsonb, text[], jsonb, boolean)
4525-
*
45264475
*/
45274476
Datum
45284477
jsonb_insert(PG_FUNCTION_ARGS)

0 commit comments

Comments
 (0)