Some refactoring to export json(b) conversion functions
authorAmit Langote <[email protected]>
Fri, 21 Jul 2023 02:46:56 +0000 (11:46 +0900)
committerAmit Langote <[email protected]>
Wed, 26 Jul 2023 08:06:03 +0000 (17:06 +0900)
This is to export datum_to_json(), datum_to_jsonb(), and
jsonb_from_cstring(), though the last one is exported as
jsonb_from_text().

A subsequent commit to add new SQL/JSON constructor functions will
need them for calling from the executor.

Discussion: https://postgr.es/m/20230720160252.ldk7jy6jqclxfxkq%40alvherre.pgsql

src/backend/utils/adt/json.c
src/backend/utils/adt/jsonb.c
src/include/utils/jsonfuncs.h

index f6bef9c1484be731f4206ccda002c8304d7f275c..e405791f5d836f9ee1b2efa33f2011c38b39859f 100644 (file)
@@ -91,9 +91,9 @@ static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims,
                              bool use_line_feeds);
 static void array_to_json_internal(Datum array, StringInfo result,
                                   bool use_line_feeds);
-static void datum_to_json(Datum val, bool is_null, StringInfo result,
-                         JsonTypeCategory tcategory, Oid outfuncoid,
-                         bool key_scalar);
+static void datum_to_json_internal(Datum val, bool is_null, StringInfo result,
+                                  JsonTypeCategory tcategory, Oid outfuncoid,
+                                  bool key_scalar);
 static void add_json(Datum val, bool is_null, StringInfo result,
                     Oid val_type, bool key_scalar);
 static text *catenate_stringinfo_string(StringInfo buffer, const char *addon);
@@ -173,9 +173,9 @@ json_recv(PG_FUNCTION_ARGS)
  * it's of an acceptable type, and force it to be quoted.
  */
 static void
-datum_to_json(Datum val, bool is_null, StringInfo result,
-             JsonTypeCategory tcategory, Oid outfuncoid,
-             bool key_scalar)
+datum_to_json_internal(Datum val, bool is_null, StringInfo result,
+                      JsonTypeCategory tcategory, Oid outfuncoid,
+                      bool key_scalar)
 {
    char       *outputstr;
    text       *jsontext;
@@ -421,8 +421,9 @@ array_dim_to_json(StringInfo result, int dim, int ndims, int *dims, Datum *vals,
 
        if (dim + 1 == ndims)
        {
-           datum_to_json(vals[*valcount], nulls[*valcount], result, tcategory,
-                         outfuncoid, false);
+           datum_to_json_internal(vals[*valcount], nulls[*valcount],
+                                  result, tcategory,
+                                  outfuncoid, false);
            (*valcount)++;
        }
        else
@@ -549,7 +550,8 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
            json_categorize_type(att->atttypid, false, &tcategory,
                                 &outfuncoid);
 
-       datum_to_json(val, isnull, result, tcategory, outfuncoid, false);
+       datum_to_json_internal(val, isnull, result, tcategory, outfuncoid,
+                              false);
    }
 
    appendStringInfoChar(result, '}');
@@ -584,7 +586,8 @@ add_json(Datum val, bool is_null, StringInfo result,
        json_categorize_type(val_type, false,
                             &tcategory, &outfuncoid);
 
-   datum_to_json(val, is_null, result, tcategory, outfuncoid, key_scalar);
+   datum_to_json_internal(val, is_null, result, tcategory, outfuncoid,
+                          key_scalar);
 }
 
 /*
@@ -704,7 +707,6 @@ to_json(PG_FUNCTION_ARGS)
 {
    Datum       val = PG_GETARG_DATUM(0);
    Oid         val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
-   StringInfo  result;
    JsonTypeCategory tcategory;
    Oid         outfuncoid;
 
@@ -716,11 +718,23 @@ to_json(PG_FUNCTION_ARGS)
    json_categorize_type(val_type, false,
                         &tcategory, &outfuncoid);
 
-   result = makeStringInfo();
+   PG_RETURN_DATUM(datum_to_json(val, tcategory, outfuncoid));
+}
 
-   datum_to_json(val, false, result, tcategory, outfuncoid, false);
+/*
+ * Turn a Datum into JSON text.
+ *
+ * tcategory and outfuncoid are from a previous call to json_categorize_type.
+ */
+Datum
+datum_to_json(Datum val, JsonTypeCategory tcategory, Oid outfuncoid)
+{
+   StringInfo  result = makeStringInfo();
 
-   PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
+   datum_to_json_internal(val, false, result, tcategory, outfuncoid,
+                          false);
+
+   return PointerGetDatum(cstring_to_text_with_len(result->data, result->len));
 }
 
 /*
@@ -780,8 +794,8 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
    /* fast path for NULLs */
    if (PG_ARGISNULL(1))
    {
-       datum_to_json((Datum) 0, true, state->str, JSONTYPE_NULL,
-                     InvalidOid, false);
+       datum_to_json_internal((Datum) 0, true, state->str, JSONTYPE_NULL,
+                              InvalidOid, false);
        PG_RETURN_POINTER(state);
    }
 
@@ -795,8 +809,8 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
        appendStringInfoString(state->str, "\n ");
    }
 
-   datum_to_json(val, false, state->str, state->val_category,
-                 state->val_output_func, false);
+   datum_to_json_internal(val, false, state->str, state->val_category,
+                          state->val_output_func, false);
 
    /*
     * The transition type for json_agg() is declared to be "internal", which
@@ -1059,8 +1073,8 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
 
    key_offset = out->len;
 
-   datum_to_json(arg, false, out, state->key_category,
-                 state->key_output_func, true);
+   datum_to_json_internal(arg, false, out, state->key_category,
+                          state->key_output_func, true);
 
    if (unique_keys)
    {
@@ -1082,8 +1096,9 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
    else
        arg = PG_GETARG_DATUM(2);
 
-   datum_to_json(arg, PG_ARGISNULL(2), state->str, state->val_category,
-                 state->val_output_func, false);
+   datum_to_json_internal(arg, PG_ARGISNULL(2), state->str,
+                          state->val_category,
+                          state->val_output_func, false);
 
    PG_RETURN_POINTER(state);
 }
index fc64f5686826415a7ff085d8fcef480bfb06c13d..5ea582a8884cea104fc11d3989bc6148795924d3 100644 (file)
@@ -59,9 +59,9 @@ static void array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *di
                               Datum *vals, bool *nulls, int *valcount,
                               JsonTypeCategory tcategory, Oid outfuncoid);
 static void array_to_jsonb_internal(Datum array, JsonbInState *result);
-static void datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
-                          JsonTypeCategory tcategory, Oid outfuncoid,
-                          bool key_scalar);
+static void datum_to_jsonb_internal(Datum val, bool is_null, JsonbInState *result,
+                                   JsonTypeCategory tcategory, Oid outfuncoid,
+                                   bool key_scalar);
 static void add_jsonb(Datum val, bool is_null, JsonbInState *result,
                      Oid val_type, bool key_scalar);
 static JsonbParseState *clone_parse_state(JsonbParseState *state);
@@ -141,6 +141,19 @@ jsonb_send(PG_FUNCTION_ARGS)
    PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
 }
 
+/*
+ * jsonb_from_text
+ *
+ * Turns json text string into a jsonb Datum.
+ */
+Datum
+jsonb_from_text(text *js)
+{
+   return jsonb_from_cstring(VARDATA_ANY(js),
+                             VARSIZE_ANY_EXHDR(js),
+                             NULL);
+}
+
 /*
  * Get the type name of a jsonb container.
  */
@@ -622,9 +635,9 @@ add_indent(StringInfo out, bool indent, int level)
  * will be thrown.
  */
 static void
-datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
-              JsonTypeCategory tcategory, Oid outfuncoid,
-              bool key_scalar)
+datum_to_jsonb_internal(Datum val, bool is_null, JsonbInState *result,
+                       JsonTypeCategory tcategory, Oid outfuncoid,
+                       bool key_scalar)
 {
    char       *outputstr;
    bool        numeric_error;
@@ -859,8 +872,8 @@ array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, Datum *v
    {
        if (dim + 1 == ndims)
        {
-           datum_to_jsonb(vals[*valcount], nulls[*valcount], result, tcategory,
-                          outfuncoid, false);
+           datum_to_jsonb_internal(vals[*valcount], nulls[*valcount], result, tcategory,
+                                   outfuncoid, false);
            (*valcount)++;
        }
        else
@@ -982,7 +995,8 @@ composite_to_jsonb(Datum composite, JsonbInState *result)
            json_categorize_type(att->atttypid, true, &tcategory,
                                 &outfuncoid);
 
-       datum_to_jsonb(val, isnull, result, tcategory, outfuncoid, false);
+       datum_to_jsonb_internal(val, isnull, result, tcategory, outfuncoid,
+                               false);
    }
 
    result->res = pushJsonbValue(&result->parseState, WJB_END_OBJECT, NULL);
@@ -1018,9 +1032,11 @@ add_jsonb(Datum val, bool is_null, JsonbInState *result,
        json_categorize_type(val_type, true,
                             &tcategory, &outfuncoid);
 
-   datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar);
+   datum_to_jsonb_internal(val, is_null, result, tcategory, outfuncoid,
+                           key_scalar);
 }
 
+
 /*
  * Is the given type immutable when coming out of a JSONB context?
  *
@@ -1072,7 +1088,6 @@ to_jsonb(PG_FUNCTION_ARGS)
 {
    Datum       val = PG_GETARG_DATUM(0);
    Oid         val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
-   JsonbInState result;
    JsonTypeCategory tcategory;
    Oid         outfuncoid;
 
@@ -1084,11 +1099,25 @@ to_jsonb(PG_FUNCTION_ARGS)
    json_categorize_type(val_type, true,
                         &tcategory, &outfuncoid);
 
+   PG_RETURN_DATUM(datum_to_jsonb(val, tcategory, outfuncoid));
+}
+
+/*
+ * Turn a Datum into jsonb.
+ *
+ * tcategory and outfuncoid are from a previous call to json_categorize_type.
+ */
+Datum
+datum_to_jsonb(Datum val, JsonTypeCategory tcategory, Oid outfuncoid)
+{
+   JsonbInState result;
+
    memset(&result, 0, sizeof(JsonbInState));
 
-   datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false);
+   datum_to_jsonb_internal(val, false, &result, tcategory, outfuncoid,
+                           false);
 
-   PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
+   return JsonbPGetDatum(JsonbValueToJsonb(result.res));
 }
 
 Datum
@@ -1525,8 +1554,8 @@ jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
 
    memset(&elem, 0, sizeof(JsonbInState));
 
-   datum_to_jsonb(val, PG_ARGISNULL(1), &elem, state->val_category,
-                  state->val_output_func, false);
+   datum_to_jsonb_internal(val, PG_ARGISNULL(1), &elem, state->val_category,
+                           state->val_output_func, false);
 
    jbelem = JsonbValueToJsonb(elem.res);
 
@@ -1726,8 +1755,8 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
 
    memset(&elem, 0, sizeof(JsonbInState));
 
-   datum_to_jsonb(val, false, &elem, state->key_category,
-                  state->key_output_func, true);
+   datum_to_jsonb_internal(val, false, &elem, state->key_category,
+                           state->key_output_func, true);
 
    jbkey = JsonbValueToJsonb(elem.res);
 
@@ -1735,8 +1764,8 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
 
    memset(&elem, 0, sizeof(JsonbInState));
 
-   datum_to_jsonb(val, PG_ARGISNULL(2), &elem, state->val_category,
-                  state->val_output_func, false);
+   datum_to_jsonb_internal(val, PG_ARGISNULL(2), &elem, state->val_category,
+                           state->val_output_func, false);
 
    jbval = JsonbValueToJsonb(elem.res);
 
index 121dfd5d2480a6a0db86582066521c997bae39fa..2ad648d1b8b2c7b8ec248914abe926ab0a343d19 100644 (file)
@@ -82,5 +82,10 @@ typedef enum
 
 extern void json_categorize_type(Oid typoid, bool is_jsonb,
                                 JsonTypeCategory *tcategory, Oid *outfuncoid);
+extern Datum datum_to_json(Datum val, JsonTypeCategory tcategory,
+                          Oid outfuncoid);
+extern Datum datum_to_jsonb(Datum val, JsonTypeCategory tcategory,
+                           Oid outfuncoid);
+extern Datum jsonb_from_text(text *js);
 
 #endif