Unify JSON categorize type API and export for external use
This essentially removes the JsonbTypeCategory enum and jsonb_categorize_type() and integrates any jsonb-specific logic that was in jsonb_categorize_type() into json_categorize_type(), now moved to jsonfuncs.c. The remaining JsonTypeCategory enum and json_categorize_type() cover the needs of the callers in both json.c and jsonb.c. json_categorize_type() has grown a new parameter named is_jsonb for callers to engage the jsonb-specific behavior of json_categorize_type(). One notable change in the now exported API of json_categorize_type() is that it now always returns *outfuncoid even though a caller may have no need currently to see one. This is in preparation of later commits to implement additional SQL/JSON functions. Co-authored-by: Álvaro Herrera <alvherre@alvh.no-ip.org> Reviewed-by: Álvaro Herrera <alvherre@alvh.no-ip.org> Discussion: https://postgr.es/m/CA+HiwqE4XTdfb1nW=Ojoy_tQSRhYt-q_kb6i5d4xcKyrLC1Nbg@mail.gmail.com
This commit is contained in:
parent
2a990abd79
commit
3c152a27b0
@ -19,7 +19,6 @@
|
|||||||
#include "funcapi.h"
|
#include "funcapi.h"
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "parser/parse_coerce.h"
|
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/date.h"
|
#include "utils/date.h"
|
||||||
@ -29,21 +28,6 @@
|
|||||||
#include "utils/lsyscache.h"
|
#include "utils/lsyscache.h"
|
||||||
#include "utils/typcache.h"
|
#include "utils/typcache.h"
|
||||||
|
|
||||||
typedef enum /* type categories for datum_to_json */
|
|
||||||
{
|
|
||||||
JSONTYPE_NULL, /* null, so we didn't bother to identify */
|
|
||||||
JSONTYPE_BOOL, /* boolean (built-in types only) */
|
|
||||||
JSONTYPE_NUMERIC, /* numeric (ditto) */
|
|
||||||
JSONTYPE_DATE, /* we use special formatting for datetimes */
|
|
||||||
JSONTYPE_TIMESTAMP,
|
|
||||||
JSONTYPE_TIMESTAMPTZ,
|
|
||||||
JSONTYPE_JSON, /* JSON itself (and JSONB) */
|
|
||||||
JSONTYPE_ARRAY, /* array */
|
|
||||||
JSONTYPE_COMPOSITE, /* composite */
|
|
||||||
JSONTYPE_CAST, /* something with an explicit cast to JSON */
|
|
||||||
JSONTYPE_OTHER /* all else */
|
|
||||||
} JsonTypeCategory;
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Support for fast key uniqueness checking.
|
* Support for fast key uniqueness checking.
|
||||||
@ -107,9 +91,6 @@ static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims,
|
|||||||
bool use_line_feeds);
|
bool use_line_feeds);
|
||||||
static void array_to_json_internal(Datum array, StringInfo result,
|
static void array_to_json_internal(Datum array, StringInfo result,
|
||||||
bool use_line_feeds);
|
bool use_line_feeds);
|
||||||
static void json_categorize_type(Oid typoid,
|
|
||||||
JsonTypeCategory *tcategory,
|
|
||||||
Oid *outfuncoid);
|
|
||||||
static void datum_to_json(Datum val, bool is_null, StringInfo result,
|
static void datum_to_json(Datum val, bool is_null, StringInfo result,
|
||||||
JsonTypeCategory tcategory, Oid outfuncoid,
|
JsonTypeCategory tcategory, Oid outfuncoid,
|
||||||
bool key_scalar);
|
bool key_scalar);
|
||||||
@ -182,106 +163,6 @@ json_recv(PG_FUNCTION_ARGS)
|
|||||||
PG_RETURN_TEXT_P(cstring_to_text_with_len(str, nbytes));
|
PG_RETURN_TEXT_P(cstring_to_text_with_len(str, nbytes));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine how we want to print values of a given type in datum_to_json.
|
|
||||||
*
|
|
||||||
* 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.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
json_categorize_type(Oid typoid,
|
|
||||||
JsonTypeCategory *tcategory,
|
|
||||||
Oid *outfuncoid)
|
|
||||||
{
|
|
||||||
bool typisvarlena;
|
|
||||||
|
|
||||||
/* Look through any domain */
|
|
||||||
typoid = getBaseType(typoid);
|
|
||||||
|
|
||||||
*outfuncoid = InvalidOid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We need to get the output function for everything except date and
|
|
||||||
* timestamp types, array and composite types, booleans, and non-builtin
|
|
||||||
* types where there's a cast to json.
|
|
||||||
*/
|
|
||||||
|
|
||||||
switch (typoid)
|
|
||||||
{
|
|
||||||
case BOOLOID:
|
|
||||||
*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:
|
|
||||||
*tcategory = JSONTYPE_DATE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMESTAMPOID:
|
|
||||||
*tcategory = JSONTYPE_TIMESTAMP;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMESTAMPTZOID:
|
|
||||||
*tcategory = JSONTYPE_TIMESTAMPTZ;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JSONOID:
|
|
||||||
case JSONBOID:
|
|
||||||
getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
|
|
||||||
*tcategory = JSONTYPE_JSON;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* Check for arrays and composites */
|
|
||||||
if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
|
|
||||||
|| typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
|
|
||||||
*tcategory = JSONTYPE_ARRAY;
|
|
||||||
else if (type_is_rowtype(typoid)) /* includes RECORDOID */
|
|
||||||
*tcategory = JSONTYPE_COMPOSITE;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* It's probably the general case ... */
|
|
||||||
*tcategory = JSONTYPE_OTHER;
|
|
||||||
/* but let's look for a cast to json, if it's not built-in */
|
|
||||||
if (typoid >= FirstNormalObjectId)
|
|
||||||
{
|
|
||||||
Oid castfunc;
|
|
||||||
CoercionPathType ctype;
|
|
||||||
|
|
||||||
ctype = find_coercion_pathway(JSONOID, typoid,
|
|
||||||
COERCION_EXPLICIT,
|
|
||||||
&castfunc);
|
|
||||||
if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
|
|
||||||
{
|
|
||||||
*tcategory = JSONTYPE_CAST;
|
|
||||||
*outfuncoid = castfunc;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* non builtin type with no cast */
|
|
||||||
getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* any other builtin type */
|
|
||||||
getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Turn a Datum into JSON text, appending the string to "result".
|
* Turn a Datum into JSON text, appending the string to "result".
|
||||||
*
|
*
|
||||||
@ -591,7 +472,7 @@ array_to_json_internal(Datum array, StringInfo result, bool use_line_feeds)
|
|||||||
get_typlenbyvalalign(element_type,
|
get_typlenbyvalalign(element_type,
|
||||||
&typlen, &typbyval, &typalign);
|
&typlen, &typbyval, &typalign);
|
||||||
|
|
||||||
json_categorize_type(element_type,
|
json_categorize_type(element_type, false,
|
||||||
&tcategory, &outfuncoid);
|
&tcategory, &outfuncoid);
|
||||||
|
|
||||||
deconstruct_array(v, element_type, typlen, typbyval,
|
deconstruct_array(v, element_type, typlen, typbyval,
|
||||||
@ -665,7 +546,8 @@ composite_to_json(Datum composite, StringInfo result, bool use_line_feeds)
|
|||||||
outfuncoid = InvalidOid;
|
outfuncoid = InvalidOid;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
json_categorize_type(att->atttypid, &tcategory, &outfuncoid);
|
json_categorize_type(att->atttypid, false, &tcategory,
|
||||||
|
&outfuncoid);
|
||||||
|
|
||||||
datum_to_json(val, isnull, result, tcategory, outfuncoid, false);
|
datum_to_json(val, isnull, result, tcategory, outfuncoid, false);
|
||||||
}
|
}
|
||||||
@ -699,7 +581,7 @@ add_json(Datum val, bool is_null, StringInfo result,
|
|||||||
outfuncoid = InvalidOid;
|
outfuncoid = InvalidOid;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
json_categorize_type(val_type,
|
json_categorize_type(val_type, false,
|
||||||
&tcategory, &outfuncoid);
|
&tcategory, &outfuncoid);
|
||||||
|
|
||||||
datum_to_json(val, is_null, result, tcategory, outfuncoid, key_scalar);
|
datum_to_json(val, is_null, result, tcategory, outfuncoid, key_scalar);
|
||||||
@ -784,12 +666,13 @@ to_json_is_immutable(Oid typoid)
|
|||||||
JsonTypeCategory tcategory;
|
JsonTypeCategory tcategory;
|
||||||
Oid outfuncoid;
|
Oid outfuncoid;
|
||||||
|
|
||||||
json_categorize_type(typoid, &tcategory, &outfuncoid);
|
json_categorize_type(typoid, false, &tcategory, &outfuncoid);
|
||||||
|
|
||||||
switch (tcategory)
|
switch (tcategory)
|
||||||
{
|
{
|
||||||
case JSONTYPE_BOOL:
|
case JSONTYPE_BOOL:
|
||||||
case JSONTYPE_JSON:
|
case JSONTYPE_JSON:
|
||||||
|
case JSONTYPE_JSONB:
|
||||||
case JSONTYPE_NULL:
|
case JSONTYPE_NULL:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -830,7 +713,7 @@ to_json(PG_FUNCTION_ARGS)
|
|||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("could not determine input data type")));
|
errmsg("could not determine input data type")));
|
||||||
|
|
||||||
json_categorize_type(val_type,
|
json_categorize_type(val_type, false,
|
||||||
&tcategory, &outfuncoid);
|
&tcategory, &outfuncoid);
|
||||||
|
|
||||||
result = makeStringInfo();
|
result = makeStringInfo();
|
||||||
@ -880,7 +763,7 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
|
|||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
appendStringInfoChar(state->str, '[');
|
appendStringInfoChar(state->str, '[');
|
||||||
json_categorize_type(arg_type, &state->val_category,
|
json_categorize_type(arg_type, false, &state->val_category,
|
||||||
&state->val_output_func);
|
&state->val_output_func);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1112,7 +995,7 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
|
|||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("could not determine data type for argument %d", 1)));
|
errmsg("could not determine data type for argument %d", 1)));
|
||||||
|
|
||||||
json_categorize_type(arg_type, &state->key_category,
|
json_categorize_type(arg_type, false, &state->key_category,
|
||||||
&state->key_output_func);
|
&state->key_output_func);
|
||||||
|
|
||||||
arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
|
arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
|
||||||
@ -1122,7 +1005,7 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
|
|||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("could not determine data type for argument %d", 2)));
|
errmsg("could not determine data type for argument %d", 2)));
|
||||||
|
|
||||||
json_categorize_type(arg_type, &state->val_category,
|
json_categorize_type(arg_type, false, &state->val_category,
|
||||||
&state->val_output_func);
|
&state->val_output_func);
|
||||||
|
|
||||||
appendStringInfoString(state->str, "{ ");
|
appendStringInfoString(state->str, "{ ");
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
#include "funcapi.h"
|
#include "funcapi.h"
|
||||||
#include "libpq/pqformat.h"
|
#include "libpq/pqformat.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "parser/parse_coerce.h"
|
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/date.h"
|
#include "utils/date.h"
|
||||||
#include "utils/datetime.h"
|
#include "utils/datetime.h"
|
||||||
@ -37,29 +36,12 @@ typedef struct JsonbInState
|
|||||||
Node *escontext;
|
Node *escontext;
|
||||||
} JsonbInState;
|
} JsonbInState;
|
||||||
|
|
||||||
/* unlike with json categories, we need to treat json and jsonb differently */
|
|
||||||
typedef enum /* type categories for datum_to_jsonb */
|
|
||||||
{
|
|
||||||
JSONBTYPE_NULL, /* null, so we didn't bother to identify */
|
|
||||||
JSONBTYPE_BOOL, /* boolean (built-in types only) */
|
|
||||||
JSONBTYPE_NUMERIC, /* numeric (ditto) */
|
|
||||||
JSONBTYPE_DATE, /* we use special formatting for datetimes */
|
|
||||||
JSONBTYPE_TIMESTAMP, /* we use special formatting for timestamp */
|
|
||||||
JSONBTYPE_TIMESTAMPTZ, /* ... and timestamptz */
|
|
||||||
JSONBTYPE_JSON, /* JSON */
|
|
||||||
JSONBTYPE_JSONB, /* JSONB */
|
|
||||||
JSONBTYPE_ARRAY, /* array */
|
|
||||||
JSONBTYPE_COMPOSITE, /* composite */
|
|
||||||
JSONBTYPE_JSONCAST, /* something with an explicit cast to JSON */
|
|
||||||
JSONBTYPE_OTHER /* all else */
|
|
||||||
} JsonbTypeCategory;
|
|
||||||
|
|
||||||
typedef struct JsonbAggState
|
typedef struct JsonbAggState
|
||||||
{
|
{
|
||||||
JsonbInState *res;
|
JsonbInState *res;
|
||||||
JsonbTypeCategory key_category;
|
JsonTypeCategory key_category;
|
||||||
Oid key_output_func;
|
Oid key_output_func;
|
||||||
JsonbTypeCategory val_category;
|
JsonTypeCategory val_category;
|
||||||
Oid val_output_func;
|
Oid val_output_func;
|
||||||
} JsonbAggState;
|
} JsonbAggState;
|
||||||
|
|
||||||
@ -72,19 +54,13 @@ static JsonParseErrorType jsonb_in_array_end(void *pstate);
|
|||||||
static JsonParseErrorType jsonb_in_object_field_start(void *pstate, char *fname, bool isnull);
|
static JsonParseErrorType jsonb_in_object_field_start(void *pstate, char *fname, bool isnull);
|
||||||
static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal);
|
static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal);
|
||||||
static JsonParseErrorType jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype);
|
static JsonParseErrorType jsonb_in_scalar(void *pstate, char *token, JsonTokenType tokentype);
|
||||||
static void jsonb_categorize_type(Oid typoid,
|
|
||||||
JsonbTypeCategory *tcategory,
|
|
||||||
Oid *outfuncoid);
|
|
||||||
static void composite_to_jsonb(Datum composite, JsonbInState *result);
|
static void composite_to_jsonb(Datum composite, JsonbInState *result);
|
||||||
static void array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims,
|
static void array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims,
|
||||||
Datum *vals, bool *nulls, int *valcount,
|
Datum *vals, bool *nulls, int *valcount,
|
||||||
JsonbTypeCategory tcategory, Oid outfuncoid);
|
JsonTypeCategory tcategory, Oid outfuncoid);
|
||||||
static void array_to_jsonb_internal(Datum array, JsonbInState *result);
|
static void array_to_jsonb_internal(Datum array, JsonbInState *result);
|
||||||
static void jsonb_categorize_type(Oid typoid,
|
|
||||||
JsonbTypeCategory *tcategory,
|
|
||||||
Oid *outfuncoid);
|
|
||||||
static void datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
static void datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
||||||
JsonbTypeCategory tcategory, Oid outfuncoid,
|
JsonTypeCategory tcategory, Oid outfuncoid,
|
||||||
bool key_scalar);
|
bool key_scalar);
|
||||||
static void add_jsonb(Datum val, bool is_null, JsonbInState *result,
|
static void add_jsonb(Datum val, bool is_null, JsonbInState *result,
|
||||||
Oid val_type, bool key_scalar);
|
Oid val_type, bool key_scalar);
|
||||||
@ -633,112 +609,6 @@ add_indent(StringInfo out, bool indent, int level)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Determine how we want to render values of a given type in datum_to_jsonb.
|
|
||||||
*
|
|
||||||
* Given the datatype OID, return its JsonbTypeCategory, as well as the type's
|
|
||||||
* output function OID. If the returned category is JSONBTYPE_JSONCAST,
|
|
||||||
* we return the OID of the relevant cast function instead.
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
jsonb_categorize_type(Oid typoid,
|
|
||||||
JsonbTypeCategory *tcategory,
|
|
||||||
Oid *outfuncoid)
|
|
||||||
{
|
|
||||||
bool typisvarlena;
|
|
||||||
|
|
||||||
/* Look through any domain */
|
|
||||||
typoid = getBaseType(typoid);
|
|
||||||
|
|
||||||
*outfuncoid = InvalidOid;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We need to get the output function for everything except date and
|
|
||||||
* timestamp types, booleans, array and composite types, json and jsonb,
|
|
||||||
* and non-builtin types where there's a cast to json. In this last case
|
|
||||||
* we return the oid of the cast function instead.
|
|
||||||
*/
|
|
||||||
|
|
||||||
switch (typoid)
|
|
||||||
{
|
|
||||||
case BOOLOID:
|
|
||||||
*tcategory = JSONBTYPE_BOOL;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case INT2OID:
|
|
||||||
case INT4OID:
|
|
||||||
case INT8OID:
|
|
||||||
case FLOAT4OID:
|
|
||||||
case FLOAT8OID:
|
|
||||||
case NUMERICOID:
|
|
||||||
getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
|
|
||||||
*tcategory = JSONBTYPE_NUMERIC;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DATEOID:
|
|
||||||
*tcategory = JSONBTYPE_DATE;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMESTAMPOID:
|
|
||||||
*tcategory = JSONBTYPE_TIMESTAMP;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case TIMESTAMPTZOID:
|
|
||||||
*tcategory = JSONBTYPE_TIMESTAMPTZ;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JSONBOID:
|
|
||||||
*tcategory = JSONBTYPE_JSONB;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case JSONOID:
|
|
||||||
*tcategory = JSONBTYPE_JSON;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
/* Check for arrays and composites */
|
|
||||||
if (OidIsValid(get_element_type(typoid)) || typoid == ANYARRAYOID
|
|
||||||
|| typoid == ANYCOMPATIBLEARRAYOID || typoid == RECORDARRAYOID)
|
|
||||||
*tcategory = JSONBTYPE_ARRAY;
|
|
||||||
else if (type_is_rowtype(typoid)) /* includes RECORDOID */
|
|
||||||
*tcategory = JSONBTYPE_COMPOSITE;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* It's probably the general case ... */
|
|
||||||
*tcategory = JSONBTYPE_OTHER;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* but first let's look for a cast to json (note: not to
|
|
||||||
* jsonb) if it's not built-in.
|
|
||||||
*/
|
|
||||||
if (typoid >= FirstNormalObjectId)
|
|
||||||
{
|
|
||||||
Oid castfunc;
|
|
||||||
CoercionPathType ctype;
|
|
||||||
|
|
||||||
ctype = find_coercion_pathway(JSONOID, typoid,
|
|
||||||
COERCION_EXPLICIT, &castfunc);
|
|
||||||
if (ctype == COERCION_PATH_FUNC && OidIsValid(castfunc))
|
|
||||||
{
|
|
||||||
*tcategory = JSONBTYPE_JSONCAST;
|
|
||||||
*outfuncoid = castfunc;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* not a cast type, so just get the usual output func */
|
|
||||||
getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* any other builtin type */
|
|
||||||
getTypeOutputInfo(typoid, outfuncoid, &typisvarlena);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Turn a Datum into jsonb, adding it to the result JsonbInState.
|
* Turn a Datum into jsonb, adding it to the result JsonbInState.
|
||||||
*
|
*
|
||||||
@ -753,7 +623,7 @@ jsonb_categorize_type(Oid typoid,
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
||||||
JsonbTypeCategory tcategory, Oid outfuncoid,
|
JsonTypeCategory tcategory, Oid outfuncoid,
|
||||||
bool key_scalar)
|
bool key_scalar)
|
||||||
{
|
{
|
||||||
char *outputstr;
|
char *outputstr;
|
||||||
@ -770,11 +640,11 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
jb.type = jbvNull;
|
jb.type = jbvNull;
|
||||||
}
|
}
|
||||||
else if (key_scalar &&
|
else if (key_scalar &&
|
||||||
(tcategory == JSONBTYPE_ARRAY ||
|
(tcategory == JSONTYPE_ARRAY ||
|
||||||
tcategory == JSONBTYPE_COMPOSITE ||
|
tcategory == JSONTYPE_COMPOSITE ||
|
||||||
tcategory == JSONBTYPE_JSON ||
|
tcategory == JSONTYPE_JSON ||
|
||||||
tcategory == JSONBTYPE_JSONB ||
|
tcategory == JSONTYPE_JSONB ||
|
||||||
tcategory == JSONBTYPE_JSONCAST))
|
tcategory == JSONTYPE_JSON))
|
||||||
{
|
{
|
||||||
ereport(ERROR,
|
ereport(ERROR,
|
||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
@ -782,18 +652,18 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (tcategory == JSONBTYPE_JSONCAST)
|
if (tcategory == JSONTYPE_CAST)
|
||||||
val = OidFunctionCall1(outfuncoid, val);
|
val = OidFunctionCall1(outfuncoid, val);
|
||||||
|
|
||||||
switch (tcategory)
|
switch (tcategory)
|
||||||
{
|
{
|
||||||
case JSONBTYPE_ARRAY:
|
case JSONTYPE_ARRAY:
|
||||||
array_to_jsonb_internal(val, result);
|
array_to_jsonb_internal(val, result);
|
||||||
break;
|
break;
|
||||||
case JSONBTYPE_COMPOSITE:
|
case JSONTYPE_COMPOSITE:
|
||||||
composite_to_jsonb(val, result);
|
composite_to_jsonb(val, result);
|
||||||
break;
|
break;
|
||||||
case JSONBTYPE_BOOL:
|
case JSONTYPE_BOOL:
|
||||||
if (key_scalar)
|
if (key_scalar)
|
||||||
{
|
{
|
||||||
outputstr = DatumGetBool(val) ? "true" : "false";
|
outputstr = DatumGetBool(val) ? "true" : "false";
|
||||||
@ -807,7 +677,7 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
jb.val.boolean = DatumGetBool(val);
|
jb.val.boolean = DatumGetBool(val);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case JSONBTYPE_NUMERIC:
|
case JSONTYPE_NUMERIC:
|
||||||
outputstr = OidOutputFunctionCall(outfuncoid, val);
|
outputstr = OidOutputFunctionCall(outfuncoid, val);
|
||||||
if (key_scalar)
|
if (key_scalar)
|
||||||
{
|
{
|
||||||
@ -845,26 +715,26 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case JSONBTYPE_DATE:
|
case JSONTYPE_DATE:
|
||||||
jb.type = jbvString;
|
jb.type = jbvString;
|
||||||
jb.val.string.val = JsonEncodeDateTime(NULL, val,
|
jb.val.string.val = JsonEncodeDateTime(NULL, val,
|
||||||
DATEOID, NULL);
|
DATEOID, NULL);
|
||||||
jb.val.string.len = strlen(jb.val.string.val);
|
jb.val.string.len = strlen(jb.val.string.val);
|
||||||
break;
|
break;
|
||||||
case JSONBTYPE_TIMESTAMP:
|
case JSONTYPE_TIMESTAMP:
|
||||||
jb.type = jbvString;
|
jb.type = jbvString;
|
||||||
jb.val.string.val = JsonEncodeDateTime(NULL, val,
|
jb.val.string.val = JsonEncodeDateTime(NULL, val,
|
||||||
TIMESTAMPOID, NULL);
|
TIMESTAMPOID, NULL);
|
||||||
jb.val.string.len = strlen(jb.val.string.val);
|
jb.val.string.len = strlen(jb.val.string.val);
|
||||||
break;
|
break;
|
||||||
case JSONBTYPE_TIMESTAMPTZ:
|
case JSONTYPE_TIMESTAMPTZ:
|
||||||
jb.type = jbvString;
|
jb.type = jbvString;
|
||||||
jb.val.string.val = JsonEncodeDateTime(NULL, val,
|
jb.val.string.val = JsonEncodeDateTime(NULL, val,
|
||||||
TIMESTAMPTZOID, NULL);
|
TIMESTAMPTZOID, NULL);
|
||||||
jb.val.string.len = strlen(jb.val.string.val);
|
jb.val.string.len = strlen(jb.val.string.val);
|
||||||
break;
|
break;
|
||||||
case JSONBTYPE_JSONCAST:
|
case JSONTYPE_CAST:
|
||||||
case JSONBTYPE_JSON:
|
case JSONTYPE_JSON:
|
||||||
{
|
{
|
||||||
/* parse the json right into the existing result object */
|
/* parse the json right into the existing result object */
|
||||||
JsonLexContext *lex;
|
JsonLexContext *lex;
|
||||||
@ -887,7 +757,7 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
pg_parse_json_or_ereport(lex, &sem);
|
pg_parse_json_or_ereport(lex, &sem);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case JSONBTYPE_JSONB:
|
case JSONTYPE_JSONB:
|
||||||
{
|
{
|
||||||
Jsonb *jsonb = DatumGetJsonbP(val);
|
Jsonb *jsonb = DatumGetJsonbP(val);
|
||||||
JsonbIterator *it;
|
JsonbIterator *it;
|
||||||
@ -931,7 +801,7 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
|
|
||||||
/* Now insert jb into result, unless we did it recursively */
|
/* Now insert jb into result, unless we did it recursively */
|
||||||
if (!is_null && !scalar_jsonb &&
|
if (!is_null && !scalar_jsonb &&
|
||||||
tcategory >= JSONBTYPE_JSON && tcategory <= JSONBTYPE_JSONCAST)
|
tcategory >= JSONTYPE_JSON && tcategory <= JSONTYPE_CAST)
|
||||||
{
|
{
|
||||||
/* work has been done recursively */
|
/* work has been done recursively */
|
||||||
return;
|
return;
|
||||||
@ -976,7 +846,7 @@ datum_to_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, Datum *vals,
|
array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims, Datum *vals,
|
||||||
bool *nulls, int *valcount, JsonbTypeCategory tcategory,
|
bool *nulls, int *valcount, JsonTypeCategory tcategory,
|
||||||
Oid outfuncoid)
|
Oid outfuncoid)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
@ -1020,7 +890,7 @@ array_to_jsonb_internal(Datum array, JsonbInState *result)
|
|||||||
int16 typlen;
|
int16 typlen;
|
||||||
bool typbyval;
|
bool typbyval;
|
||||||
char typalign;
|
char typalign;
|
||||||
JsonbTypeCategory tcategory;
|
JsonTypeCategory tcategory;
|
||||||
Oid outfuncoid;
|
Oid outfuncoid;
|
||||||
|
|
||||||
ndim = ARR_NDIM(v);
|
ndim = ARR_NDIM(v);
|
||||||
@ -1037,8 +907,8 @@ array_to_jsonb_internal(Datum array, JsonbInState *result)
|
|||||||
get_typlenbyvalalign(element_type,
|
get_typlenbyvalalign(element_type,
|
||||||
&typlen, &typbyval, &typalign);
|
&typlen, &typbyval, &typalign);
|
||||||
|
|
||||||
jsonb_categorize_type(element_type,
|
json_categorize_type(element_type, true,
|
||||||
&tcategory, &outfuncoid);
|
&tcategory, &outfuncoid);
|
||||||
|
|
||||||
deconstruct_array(v, element_type, typlen, typbyval,
|
deconstruct_array(v, element_type, typlen, typbyval,
|
||||||
typalign, &elements, &nulls,
|
typalign, &elements, &nulls,
|
||||||
@ -1084,7 +954,7 @@ composite_to_jsonb(Datum composite, JsonbInState *result)
|
|||||||
Datum val;
|
Datum val;
|
||||||
bool isnull;
|
bool isnull;
|
||||||
char *attname;
|
char *attname;
|
||||||
JsonbTypeCategory tcategory;
|
JsonTypeCategory tcategory;
|
||||||
Oid outfuncoid;
|
Oid outfuncoid;
|
||||||
JsonbValue v;
|
JsonbValue v;
|
||||||
Form_pg_attribute att = TupleDescAttr(tupdesc, i);
|
Form_pg_attribute att = TupleDescAttr(tupdesc, i);
|
||||||
@ -1105,11 +975,12 @@ composite_to_jsonb(Datum composite, JsonbInState *result)
|
|||||||
|
|
||||||
if (isnull)
|
if (isnull)
|
||||||
{
|
{
|
||||||
tcategory = JSONBTYPE_NULL;
|
tcategory = JSONTYPE_NULL;
|
||||||
outfuncoid = InvalidOid;
|
outfuncoid = InvalidOid;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
jsonb_categorize_type(att->atttypid, &tcategory, &outfuncoid);
|
json_categorize_type(att->atttypid, true, &tcategory,
|
||||||
|
&outfuncoid);
|
||||||
|
|
||||||
datum_to_jsonb(val, isnull, result, tcategory, outfuncoid, false);
|
datum_to_jsonb(val, isnull, result, tcategory, outfuncoid, false);
|
||||||
}
|
}
|
||||||
@ -1122,7 +993,7 @@ composite_to_jsonb(Datum composite, JsonbInState *result)
|
|||||||
* Append JSON text for "val" to "result".
|
* Append JSON text for "val" to "result".
|
||||||
*
|
*
|
||||||
* This is just a thin wrapper around datum_to_jsonb. If the same type will be
|
* This is just a thin wrapper around datum_to_jsonb. If the same type will be
|
||||||
* printed many times, avoid using this; better to do the jsonb_categorize_type
|
* printed many times, avoid using this; better to do the json_categorize_type
|
||||||
* lookups only once.
|
* lookups only once.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -1130,7 +1001,7 @@ static void
|
|||||||
add_jsonb(Datum val, bool is_null, JsonbInState *result,
|
add_jsonb(Datum val, bool is_null, JsonbInState *result,
|
||||||
Oid val_type, bool key_scalar)
|
Oid val_type, bool key_scalar)
|
||||||
{
|
{
|
||||||
JsonbTypeCategory tcategory;
|
JsonTypeCategory tcategory;
|
||||||
Oid outfuncoid;
|
Oid outfuncoid;
|
||||||
|
|
||||||
if (val_type == InvalidOid)
|
if (val_type == InvalidOid)
|
||||||
@ -1140,12 +1011,12 @@ add_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
|
|
||||||
if (is_null)
|
if (is_null)
|
||||||
{
|
{
|
||||||
tcategory = JSONBTYPE_NULL;
|
tcategory = JSONTYPE_NULL;
|
||||||
outfuncoid = InvalidOid;
|
outfuncoid = InvalidOid;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
jsonb_categorize_type(val_type,
|
json_categorize_type(val_type, true,
|
||||||
&tcategory, &outfuncoid);
|
&tcategory, &outfuncoid);
|
||||||
|
|
||||||
datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar);
|
datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar);
|
||||||
}
|
}
|
||||||
@ -1160,33 +1031,33 @@ add_jsonb(Datum val, bool is_null, JsonbInState *result,
|
|||||||
bool
|
bool
|
||||||
to_jsonb_is_immutable(Oid typoid)
|
to_jsonb_is_immutable(Oid typoid)
|
||||||
{
|
{
|
||||||
JsonbTypeCategory tcategory;
|
JsonTypeCategory tcategory;
|
||||||
Oid outfuncoid;
|
Oid outfuncoid;
|
||||||
|
|
||||||
jsonb_categorize_type(typoid, &tcategory, &outfuncoid);
|
json_categorize_type(typoid, true, &tcategory, &outfuncoid);
|
||||||
|
|
||||||
switch (tcategory)
|
switch (tcategory)
|
||||||
{
|
{
|
||||||
case JSONBTYPE_NULL:
|
case JSONTYPE_NULL:
|
||||||
case JSONBTYPE_BOOL:
|
case JSONTYPE_BOOL:
|
||||||
case JSONBTYPE_JSON:
|
case JSONTYPE_JSON:
|
||||||
case JSONBTYPE_JSONB:
|
case JSONTYPE_JSONB:
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case JSONBTYPE_DATE:
|
case JSONTYPE_DATE:
|
||||||
case JSONBTYPE_TIMESTAMP:
|
case JSONTYPE_TIMESTAMP:
|
||||||
case JSONBTYPE_TIMESTAMPTZ:
|
case JSONTYPE_TIMESTAMPTZ:
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
case JSONBTYPE_ARRAY:
|
case JSONTYPE_ARRAY:
|
||||||
return false; /* TODO recurse into elements */
|
return false; /* TODO recurse into elements */
|
||||||
|
|
||||||
case JSONBTYPE_COMPOSITE:
|
case JSONTYPE_COMPOSITE:
|
||||||
return false; /* TODO recurse into fields */
|
return false; /* TODO recurse into fields */
|
||||||
|
|
||||||
case JSONBTYPE_NUMERIC:
|
case JSONTYPE_NUMERIC:
|
||||||
case JSONBTYPE_JSONCAST:
|
case JSONTYPE_CAST:
|
||||||
case JSONBTYPE_OTHER:
|
case JSONTYPE_OTHER:
|
||||||
return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE;
|
return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1202,7 +1073,7 @@ to_jsonb(PG_FUNCTION_ARGS)
|
|||||||
Datum val = PG_GETARG_DATUM(0);
|
Datum val = PG_GETARG_DATUM(0);
|
||||||
Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
|
||||||
JsonbInState result;
|
JsonbInState result;
|
||||||
JsonbTypeCategory tcategory;
|
JsonTypeCategory tcategory;
|
||||||
Oid outfuncoid;
|
Oid outfuncoid;
|
||||||
|
|
||||||
if (val_type == InvalidOid)
|
if (val_type == InvalidOid)
|
||||||
@ -1210,8 +1081,8 @@ to_jsonb(PG_FUNCTION_ARGS)
|
|||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("could not determine input data type")));
|
errmsg("could not determine input data type")));
|
||||||
|
|
||||||
jsonb_categorize_type(val_type,
|
json_categorize_type(val_type, true,
|
||||||
&tcategory, &outfuncoid);
|
&tcategory, &outfuncoid);
|
||||||
|
|
||||||
memset(&result, 0, sizeof(JsonbInState));
|
memset(&result, 0, sizeof(JsonbInState));
|
||||||
|
|
||||||
@ -1636,8 +1507,8 @@ jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
|
|||||||
WJB_BEGIN_ARRAY, NULL);
|
WJB_BEGIN_ARRAY, NULL);
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
jsonb_categorize_type(arg_type, &state->val_category,
|
json_categorize_type(arg_type, true, &state->val_category,
|
||||||
&state->val_output_func);
|
&state->val_output_func);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1816,8 +1687,8 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
|
|||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("could not determine input data type")));
|
errmsg("could not determine input data type")));
|
||||||
|
|
||||||
jsonb_categorize_type(arg_type, &state->key_category,
|
json_categorize_type(arg_type, true, &state->key_category,
|
||||||
&state->key_output_func);
|
&state->key_output_func);
|
||||||
|
|
||||||
arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
|
arg_type = get_fn_expr_argtype(fcinfo->flinfo, 2);
|
||||||
|
|
||||||
@ -1826,8 +1697,8 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
|
|||||||
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
||||||
errmsg("could not determine input data type")));
|
errmsg("could not determine input data type")));
|
||||||
|
|
||||||
jsonb_categorize_type(arg_type, &state->val_category,
|
json_categorize_type(arg_type, true, &state->val_category,
|
||||||
&state->val_output_func);
|
&state->val_output_func);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "miscadmin.h"
|
#include "miscadmin.h"
|
||||||
#include "nodes/miscnodes.h"
|
#include "nodes/miscnodes.h"
|
||||||
|
#include "parser/parse_coerce.h"
|
||||||
#include "utils/array.h"
|
#include "utils/array.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
#include "utils/fmgroids.h"
|
#include "utils/fmgroids.h"
|
||||||
@ -5685,3 +5686,113 @@ json_get_first_token(text *json, bool throw_error)
|
|||||||
|
|
||||||
return JSON_TOKEN_INVALID; /* invalid json */
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -63,4 +63,24 @@ extern Jsonb *transform_jsonb_string_values(Jsonb *jsonb, void *action_state,
|
|||||||
extern text *transform_json_string_values(text *json, void *action_state,
|
extern text *transform_json_string_values(text *json, void *action_state,
|
||||||
JsonTransformStringValuesAction transform_action);
|
JsonTransformStringValuesAction transform_action);
|
||||||
|
|
||||||
|
/* Type categories returned by json_categorize_type */
|
||||||
|
typedef enum
|
||||||
|
{
|
||||||
|
JSONTYPE_NULL, /* null, so we didn't bother to identify */
|
||||||
|
JSONTYPE_BOOL, /* boolean (built-in types only) */
|
||||||
|
JSONTYPE_NUMERIC, /* numeric (ditto) */
|
||||||
|
JSONTYPE_DATE, /* we use special formatting for datetimes */
|
||||||
|
JSONTYPE_TIMESTAMP,
|
||||||
|
JSONTYPE_TIMESTAMPTZ,
|
||||||
|
JSONTYPE_JSON, /* JSON (and JSONB, if not is_jsonb) */
|
||||||
|
JSONTYPE_JSONB, /* JSONB (if is_jsonb) */
|
||||||
|
JSONTYPE_ARRAY, /* array */
|
||||||
|
JSONTYPE_COMPOSITE, /* composite */
|
||||||
|
JSONTYPE_CAST, /* something with an explicit cast to JSON */
|
||||||
|
JSONTYPE_OTHER, /* all else */
|
||||||
|
} JsonTypeCategory;
|
||||||
|
|
||||||
|
extern void json_categorize_type(Oid typoid, bool is_jsonb,
|
||||||
|
JsonTypeCategory *tcategory, Oid *outfuncoid);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1318,7 +1318,6 @@ JsonbIteratorToken
|
|||||||
JsonbPair
|
JsonbPair
|
||||||
JsonbParseState
|
JsonbParseState
|
||||||
JsonbSubWorkspace
|
JsonbSubWorkspace
|
||||||
JsonbTypeCategory
|
|
||||||
JsonbValue
|
JsonbValue
|
||||||
JumbleState
|
JumbleState
|
||||||
JunkFilter
|
JunkFilter
|
||||||
|
Loading…
x
Reference in New Issue
Block a user