aboutsummaryrefslogtreecommitdiff
path: root/src/backend/utils/adt/jsonfuncs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/utils/adt/jsonfuncs.c')
-rw-r--r--src/backend/utils/adt/jsonfuncs.c111
1 files changed, 111 insertions, 0 deletions
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 70cb922e6b7..a4bfa5e4040 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -26,6 +26,7 @@
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "nodes/miscnodes.h"
+#include "parser/parse_coerce.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
@@ -5685,3 +5686,113 @@ json_get_first_token(text *json, bool throw_error)
return JSON_TOKEN_INVALID; /* invalid json */
}
+
+/*
+ * Determine how we want to print values of a given type in datum_to_json(b).
+ *
+ * Given the datatype OID, return its JsonTypeCategory, as well as the type's
+ * output function OID. If the returned category is JSONTYPE_CAST, we return
+ * the OID of the type->JSON cast function instead.
+ */
+void
+json_categorize_type(Oid typoid, bool is_jsonb,
+ JsonTypeCategory *tcategory, Oid *outfuncoid)
+{
+ bool typisvarlena;
+
+ /* Look through any domain */
+ typoid = getBaseType(typoid);
+
+ *outfuncoid = InvalidOid;
+
+ switch (typoid)
+ {
+ case BOOLOID:
+ *outfuncoid = F_BOOLOUT;
+ *tcategory = JSONTYPE_BOOL;
+ break;
+
+ case INT2OID:
+ case INT4OID:
+ case INT8OID:
+ case FLOAT4OID:
+ case FLOAT8OID:
+ case NUMERICOID:
+ getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
+ *tcategory = JSONTYPE_NUMERIC;
+ break;
+
+ case DATEOID:
+ *outfuncoid = F_DATE_OUT;
+ *tcategory = JSONTYPE_DATE;
+ break;
+
+ case TIMESTAMPOID:
+ *outfuncoid = F_TIMESTAMP_OUT;
+ *tcategory = JSONTYPE_TIMESTAMP;
+ break;
+
+ case TIMESTAMPTZOID:
+ *outfuncoid = F_TIMESTAMPTZ_OUT;
+ *tcategory = JSONTYPE_TIMESTAMPTZ;
+ break;
+
+ case JSONOID:
+ getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
+ *tcategory = JSONTYPE_JSON;
+ break;
+
+ case JSONBOID:
+ getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
+ *tcategory = is_jsonb ? JSONTYPE_JSONB : JSONTYPE_JSON;
+ break;
+
+ default:
+ /* Check for arrays and composites */
+ if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
+ || typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
+ {
+ *outfuncoid = F_ARRAY_OUT;
+ *tcategory = JSONTYPE_ARRAY;
+ }
+ else if (type_is_rowtype(typoid)) /* includes RECORDOID */
+ {
+ *outfuncoid = F_RECORD_OUT;
+ *tcategory = JSONTYPE_COMPOSITE;
+ }
+ else
+ {
+ /*
+ * It's probably the general case. But let's look for a cast
+ * to json (note: not to jsonb even if is_jsonb is true), if
+ * it's not built-in.
+ */
+ *tcategory = JSONTYPE_OTHER;
+ if (typoid >= FirstNormalObjectId)
+ {
+ Oid castfunc;
+ CoercionPathType ctype;
+
+ ctype = find_coercion_pathway(JSONOID, typoid,
+ COERCION_EXPLICIT,
+ &castfunc);
+ if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
+ {
+ *outfuncoid = castfunc;
+ *tcategory = JSONTYPE_CAST;
+ }
+ else
+ {
+ /* non builtin type with no cast */
+ getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
+ }
+ }
+ else
+ {
+ /* any other builtin type */
+ getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
+ }
+ }
+ break;
+ }
+}