1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-19 13:42:17 +03:00

Revert SQL/JSON features

The reverts the following and makes some associated cleanups:

    commit f79b803dc: Common SQL/JSON clauses
    commit f4fb45d15: SQL/JSON constructors
    commit 5f0adec25: Make STRING an unreserved_keyword.
    commit 33a377608: IS JSON predicate
    commit 1a36bc9db: SQL/JSON query functions
    commit 606948b05: SQL JSON functions
    commit 49082c2cc: RETURNING clause for JSON() and JSON_SCALAR()
    commit 4e34747c8: JSON_TABLE
    commit fadb48b00: PLAN clauses for JSON_TABLE
    commit 2ef6f11b0: Reduce running time of jsonb_sqljson test
    commit 14d3f24fa: Further improve jsonb_sqljson parallel test
    commit a6baa4bad: Documentation for SQL/JSON features
    commit b46bcf7a4: Improve readability of SQL/JSON documentation.
    commit 112fdb352: Fix finalization for json_objectagg and friends
    commit fcdb35c32: Fix transformJsonBehavior
    commit 4cd8717af: Improve a couple of sql/json error messages
    commit f7a605f63: Small cleanups in SQL/JSON code
    commit 9c3d25e17: Fix JSON_OBJECTAGG uniquefying bug
    commit a79153b7a: Claim SQL standard compliance for SQL/JSON features
    commit a1e7616d6: Rework SQL/JSON documentation
    commit 8d9f9634e: Fix errors in copyfuncs/equalfuncs support for JSON node types.
    commit 3c633f32b: Only allow returning string types or bytea from json_serialize
    commit 67b26703b: expression eval: Fix EEOP_JSON_CONSTRUCTOR and EEOP_JSONEXPR size.

The release notes are also adjusted.

Backpatch to release 15.

Discussion: https://postgr.es/m/40d2c882-bcac-19a9-754d-4299e1d87ac7@postgresql.org
This commit is contained in:
Andrew Dunstan
2022-09-01 17:07:14 -04:00
parent 90247e742f
commit 2f2b18bd3f
60 changed files with 348 additions and 14893 deletions

View File

@@ -14,7 +14,6 @@
#include "access/htup_details.h"
#include "access/transam.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
@@ -34,9 +33,25 @@ typedef struct JsonbInState
{
JsonbParseState *parseState;
JsonbValue *res;
bool unique_keys;
} 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
{
JsonbInState *res;
@@ -46,7 +61,7 @@ typedef struct JsonbAggState
Oid val_output_func;
} JsonbAggState;
static inline Datum jsonb_from_cstring(char *json, int len, bool unique_keys);
static inline Datum jsonb_from_cstring(char *json, int len);
static size_t checkStringLen(size_t len);
static void jsonb_in_object_start(void *pstate);
static void jsonb_in_object_end(void *pstate);
@@ -55,11 +70,17 @@ static void jsonb_in_array_end(void *pstate);
static void jsonb_in_object_field_start(void *pstate, char *fname, bool isnull);
static void jsonb_put_escaped_value(StringInfo out, JsonbValue *scalarVal);
static void 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 array_dim_to_jsonb(JsonbInState *result, int dim, int ndims, int *dims,
Datum *vals, bool *nulls, int *valcount,
JsonbTypeCategory tcategory, Oid outfuncoid);
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,
JsonbTypeCategory tcategory, Oid outfuncoid,
bool key_scalar);
@@ -77,7 +98,7 @@ jsonb_in(PG_FUNCTION_ARGS)
{
char *json = PG_GETARG_CSTRING(0);
return jsonb_from_cstring(json, strlen(json), false);
return jsonb_from_cstring(json, strlen(json));
}
/*
@@ -101,7 +122,7 @@ jsonb_recv(PG_FUNCTION_ARGS)
else
elog(ERROR, "unsupported jsonb version number %d", version);
return jsonb_from_cstring(str, nbytes, false);
return jsonb_from_cstring(str, nbytes);
}
/*
@@ -142,14 +163,6 @@ jsonb_send(PG_FUNCTION_ARGS)
PG_RETURN_BYTEA_P(pq_endtypsend(&buf));
}
Datum
jsonb_from_text(text *js, bool unique_keys)
{
return jsonb_from_cstring(VARDATA_ANY(js),
VARSIZE_ANY_EXHDR(js),
unique_keys);
}
/*
* Get the type name of a jsonb container.
*/
@@ -240,7 +253,7 @@ jsonb_typeof(PG_FUNCTION_ARGS)
* Uses the json parser (with hooks) to construct a jsonb.
*/
static inline Datum
jsonb_from_cstring(char *json, int len, bool unique_keys)
jsonb_from_cstring(char *json, int len)
{
JsonLexContext *lex;
JsonbInState state;
@@ -250,8 +263,6 @@ jsonb_from_cstring(char *json, int len, bool unique_keys)
memset(&sem, 0, sizeof(sem));
lex = makeJsonLexContextCstringLen(json, len, GetDatabaseEncoding(), true);
state.unique_keys = unique_keys;
sem.semstate = (void *) &state;
sem.object_start = jsonb_in_object_start;
@@ -286,7 +297,6 @@ jsonb_in_object_start(void *pstate)
JsonbInState *_state = (JsonbInState *) pstate;
_state->res = pushJsonbValue(&_state->parseState, WJB_BEGIN_OBJECT, NULL);
_state->parseState->unique_keys = _state->unique_keys;
}
static void
@@ -609,7 +619,7 @@ add_indent(StringInfo out, bool indent, int level)
* output function OID. If the returned category is JSONBTYPE_JSONCAST,
* we return the OID of the relevant cast function instead.
*/
void
static void
jsonb_categorize_type(Oid typoid,
JsonbTypeCategory *tcategory,
Oid *outfuncoid)
@@ -1115,51 +1125,6 @@ add_jsonb(Datum val, bool is_null, JsonbInState *result,
datum_to_jsonb(val, is_null, result, tcategory, outfuncoid, key_scalar);
}
Datum
to_jsonb_worker(Datum val, JsonbTypeCategory tcategory, Oid outfuncoid)
{
JsonbInState result;
memset(&result, 0, sizeof(JsonbInState));
datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false);
return JsonbPGetDatum(JsonbValueToJsonb(result.res));
}
bool
to_jsonb_is_immutable(Oid typoid)
{
JsonbTypeCategory tcategory;
Oid outfuncoid;
jsonb_categorize_type(typoid, &tcategory, &outfuncoid);
switch (tcategory)
{
case JSONBTYPE_BOOL:
case JSONBTYPE_JSON:
case JSONBTYPE_JSONB:
return true;
case JSONBTYPE_DATE:
case JSONBTYPE_TIMESTAMP:
case JSONBTYPE_TIMESTAMPTZ:
return false;
case JSONBTYPE_ARRAY:
return false; /* TODO recurse into elements */
case JSONBTYPE_COMPOSITE:
return false; /* TODO recurse into fields */
case JSONBTYPE_NUMERIC:
case JSONBTYPE_JSONCAST:
default:
return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE;
}
}
/*
* SQL function to_jsonb(anyvalue)
*/
@@ -1168,6 +1133,7 @@ to_jsonb(PG_FUNCTION_ARGS)
{
Datum val = PG_GETARG_DATUM(0);
Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
JsonbInState result;
JsonbTypeCategory tcategory;
Oid outfuncoid;
@@ -1179,15 +1145,31 @@ to_jsonb(PG_FUNCTION_ARGS)
jsonb_categorize_type(val_type,
&tcategory, &outfuncoid);
PG_RETURN_DATUM(to_jsonb_worker(val, tcategory, outfuncoid));
memset(&result, 0, sizeof(JsonbInState));
datum_to_jsonb(val, false, &result, tcategory, outfuncoid, false);
PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
}
/*
* SQL function jsonb_build_object(variadic "any")
*/
Datum
jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
bool absent_on_null, bool unique_keys)
jsonb_build_object(PG_FUNCTION_ARGS)
{
int nargs;
int i;
JsonbInState result;
Datum *args;
bool *nulls;
Oid *types;
/* build argument values to build the object */
nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
if (nargs < 0)
PG_RETURN_NULL();
if (nargs % 2 != 0)
ereport(ERROR,
@@ -1200,26 +1182,15 @@ jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
memset(&result, 0, sizeof(JsonbInState));
result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_OBJECT, NULL);
result.parseState->unique_keys = unique_keys;
result.parseState->skip_nulls = absent_on_null;
for (i = 0; i < nargs; i += 2)
{
/* process key */
bool skip;
if (nulls[i])
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("argument %d: key must not be null", i + 1)));
/* skip null values if absent_on_null */
skip = absent_on_null && nulls[i + 1];
/* we need to save skipped keys for the key uniqueness check */
if (skip && !unique_keys)
continue;
add_jsonb(args[i], false, &result, types[i], true);
/* process value */
@@ -1228,27 +1199,7 @@ jsonb_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
result.res = pushJsonbValue(&result.parseState, WJB_END_OBJECT, NULL);
return JsonbPGetDatum(JsonbValueToJsonb(result.res));
}
/*
* SQL function jsonb_build_object(variadic "any")
*/
Datum
jsonb_build_object(PG_FUNCTION_ARGS)
{
Datum *args;
bool *nulls;
Oid *types;
/* build argument values to build the object */
int nargs = extract_variadic_args(fcinfo, 0, true,
&args, &types, &nulls);
if (nargs < 0)
PG_RETURN_NULL();
PG_RETURN_DATUM(jsonb_build_object_worker(nargs, args, nulls, types, false, false));
PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
}
/*
@@ -1267,50 +1218,36 @@ jsonb_build_object_noargs(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
}
Datum
jsonb_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types,
bool absent_on_null)
{
int i;
JsonbInState result;
memset(&result, 0, sizeof(JsonbInState));
result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
for (i = 0; i < nargs; i++)
{
if (absent_on_null && nulls[i])
continue;
add_jsonb(args[i], nulls[i], &result, types[i], false);
}
result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
return JsonbPGetDatum(JsonbValueToJsonb(result.res));
}
/*
* SQL function jsonb_build_array(variadic "any")
*/
Datum
jsonb_build_array(PG_FUNCTION_ARGS)
{
int nargs;
int i;
JsonbInState result;
Datum *args;
bool *nulls;
Oid *types;
/* build argument values to build the object */
int nargs = extract_variadic_args(fcinfo, 0, true,
&args, &types, &nulls);
/* build argument values to build the array */
nargs = extract_variadic_args(fcinfo, 0, true, &args, &types, &nulls);
if (nargs < 0)
PG_RETURN_NULL();
PG_RETURN_DATUM(jsonb_build_array_worker(nargs, args, nulls, types, false));
}
memset(&result, 0, sizeof(JsonbInState));
result.res = pushJsonbValue(&result.parseState, WJB_BEGIN_ARRAY, NULL);
for (i = 0; i < nargs; i++)
add_jsonb(args[i], nulls[i], &result, types[i], false);
result.res = pushJsonbValue(&result.parseState, WJB_END_ARRAY, NULL);
PG_RETURN_POINTER(JsonbValueToJsonb(result.res));
}
/*
* degenerate case of jsonb_build_array where it gets 0 arguments.
@@ -1545,8 +1482,6 @@ clone_parse_state(JsonbParseState *state)
{
ocursor->contVal = icursor->contVal;
ocursor->size = icursor->size;
ocursor->unique_keys = icursor->unique_keys;
ocursor->skip_nulls = icursor->skip_nulls;
icursor = icursor->next;
if (icursor == NULL)
break;
@@ -1558,8 +1493,12 @@ clone_parse_state(JsonbParseState *state)
return result;
}
static Datum
jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
/*
* jsonb_agg aggregate function
*/
Datum
jsonb_agg_transfn(PG_FUNCTION_ARGS)
{
MemoryContext oldcontext,
aggcontext;
@@ -1607,9 +1546,6 @@ jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
result = state->res;
}
if (absent_on_null && PG_ARGISNULL(1))
PG_RETURN_POINTER(state);
/* turn the argument into jsonb in the normal function context */
val = PG_ARGISNULL(1) ? (Datum) 0 : PG_GETARG_DATUM(1);
@@ -1679,24 +1615,6 @@ jsonb_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
PG_RETURN_POINTER(state);
}
/*
* jsonb_agg aggregate function
*/
Datum
jsonb_agg_transfn(PG_FUNCTION_ARGS)
{
return jsonb_agg_transfn_worker(fcinfo, false);
}
/*
* jsonb_agg_strict aggregate function
*/
Datum
jsonb_agg_strict_transfn(PG_FUNCTION_ARGS)
{
return jsonb_agg_transfn_worker(fcinfo, true);
}
Datum
jsonb_agg_finalfn(PG_FUNCTION_ARGS)
{
@@ -1729,9 +1647,11 @@ jsonb_agg_finalfn(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(out);
}
static Datum
jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
bool absent_on_null, bool unique_keys)
/*
* jsonb_object_agg aggregate function
*/
Datum
jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
{
MemoryContext oldcontext,
aggcontext;
@@ -1745,7 +1665,6 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
*jbval;
JsonbValue v;
JsonbIteratorToken type;
bool skip;
if (!AggCheckCallContext(fcinfo, &aggcontext))
{
@@ -1765,9 +1684,6 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
state->res = result;
result->res = pushJsonbValue(&result->parseState,
WJB_BEGIN_OBJECT, NULL);
result->parseState->unique_keys = unique_keys;
result->parseState->skip_nulls = absent_on_null;
MemoryContextSwitchTo(oldcontext);
arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
@@ -1803,15 +1719,6 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("field name must not be null")));
/*
* Skip null values if absent_on_null unless key uniqueness check is
* needed (because we must save keys in this case).
*/
skip = absent_on_null && PG_ARGISNULL(2);
if (skip && !unique_keys)
PG_RETURN_POINTER(state);
val = PG_GETARG_DATUM(1);
memset(&elem, 0, sizeof(JsonbInState));
@@ -1867,16 +1774,6 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
}
result->res = pushJsonbValue(&result->parseState,
WJB_KEY, &v);
if (skip)
{
v.type = jbvNull;
result->res = pushJsonbValue(&result->parseState,
WJB_VALUE, &v);
MemoryContextSwitchTo(oldcontext);
PG_RETURN_POINTER(state);
}
break;
case WJB_END_ARRAY:
break;
@@ -1949,43 +1846,6 @@ jsonb_object_agg_transfn_worker(FunctionCallInfo fcinfo,
PG_RETURN_POINTER(state);
}
/*
* jsonb_object_agg aggregate function
*/
Datum
jsonb_object_agg_transfn(PG_FUNCTION_ARGS)
{
return jsonb_object_agg_transfn_worker(fcinfo, false, false);
}
/*
* jsonb_object_agg_strict aggregate function
*/
Datum
jsonb_object_agg_strict_transfn(PG_FUNCTION_ARGS)
{
return jsonb_object_agg_transfn_worker(fcinfo, true, false);
}
/*
* jsonb_object_agg_unique aggregate function
*/
Datum
jsonb_object_agg_unique_transfn(PG_FUNCTION_ARGS)
{
return jsonb_object_agg_transfn_worker(fcinfo, false, true);
}
/*
* jsonb_object_agg_unique_strict aggregate function
*/
Datum
jsonb_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS)
{
return jsonb_object_agg_transfn_worker(fcinfo, true, true);
}
Datum
jsonb_object_agg_finalfn(PG_FUNCTION_ARGS)
{
@@ -2217,65 +2077,3 @@ jsonb_float8(PG_FUNCTION_ARGS)
PG_RETURN_DATUM(retValue);
}
/*
* Construct an empty array jsonb.
*/
Jsonb *
JsonbMakeEmptyArray(void)
{
JsonbValue jbv;
jbv.type = jbvArray;
jbv.val.array.elems = NULL;
jbv.val.array.nElems = 0;
jbv.val.array.rawScalar = false;
return JsonbValueToJsonb(&jbv);
}
/*
* Construct an empty object jsonb.
*/
Jsonb *
JsonbMakeEmptyObject(void)
{
JsonbValue jbv;
jbv.type = jbvObject;
jbv.val.object.pairs = NULL;
jbv.val.object.nPairs = 0;
return JsonbValueToJsonb(&jbv);
}
/*
* Convert jsonb to a C-string stripping quotes from scalar strings.
*/
char *
JsonbUnquote(Jsonb *jb)
{
if (JB_ROOT_IS_SCALAR(jb))
{
JsonbValue v;
(void) JsonbExtractScalar(&jb->root, &v);
if (v.type == jbvString)
return pnstrdup(v.val.string.val, v.val.string.len);
else if (v.type == jbvBool)
return pstrdup(v.val.boolean ? "true" : "false");
else if (v.type == jbvNumeric)
return DatumGetCString(DirectFunctionCall1(numeric_out,
PointerGetDatum(v.val.numeric)));
else if (v.type == jbvNull)
return pstrdup("null");
else
{
elog(ERROR, "unrecognized jsonb value type %d", v.type);
return NULL;
}
}
else
return JsonbToCString(NULL, &jb->root, VARSIZE(jb));
}