aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_expr.c
diff options
context:
space:
mode:
authorAndrew Dunstan <andrew@dunslane.net>2022-09-01 17:07:14 -0400
committerAndrew Dunstan <andrew@dunslane.net>2022-09-01 17:07:14 -0400
commit2f2b18bd3f554e96a8cc885b177211be12288e4a (patch)
tree344a5d33738de735f68b98361a54eb5944726f8f /src/backend/parser/parse_expr.c
parent90247e742f849794d061a0444071647728054b45 (diff)
downloadpostgresql-2f2b18bd3f554e96a8cc885b177211be12288e4a.tar.gz
postgresql-2f2b18bd3f554e96a8cc885b177211be12288e4a.zip
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
Diffstat (limited to 'src/backend/parser/parse_expr.c')
-rw-r--r--src/backend/parser/parse_expr.c1503
1 files changed, 0 insertions, 1503 deletions
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index fabb5f72076..7aaf1c673f8 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -15,8 +15,6 @@
#include "postgres.h"
-#include "catalog/pg_aggregate.h"
-#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "miscadmin.h"
@@ -36,7 +34,6 @@
#include "parser/parse_type.h"
#include "utils/builtins.h"
#include "utils/date.h"
-#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/timestamp.h"
#include "utils/xml.h"
@@ -77,21 +74,6 @@ static Node *transformWholeRowRef(ParseState *pstate,
static Node *transformIndirection(ParseState *pstate, A_Indirection *ind);
static Node *transformTypeCast(ParseState *pstate, TypeCast *tc);
static Node *transformCollateClause(ParseState *pstate, CollateClause *c);
-static Node *transformJsonObjectConstructor(ParseState *pstate,
- JsonObjectConstructor *ctor);
-static Node *transformJsonArrayConstructor(ParseState *pstate,
- JsonArrayConstructor *ctor);
-static Node *transformJsonArrayQueryConstructor(ParseState *pstate,
- JsonArrayQueryConstructor *ctor);
-static Node *transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg);
-static Node *transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg);
-static Node *transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *p);
-static Node *transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *p);
-static Node *transformJsonValueExpr(ParseState *pstate, JsonValueExpr *jve);
-static Node *transformJsonParseExpr(ParseState *pstate, JsonParseExpr *expr);
-static Node *transformJsonScalarExpr(ParseState *pstate, JsonScalarExpr *expr);
-static Node *transformJsonSerializeExpr(ParseState *pstate,
- JsonSerializeExpr *expr);
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
List *largs, List *rargs, int location);
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
@@ -319,50 +301,6 @@ transformExprRecurse(ParseState *pstate, Node *expr)
break;
}
- case T_JsonObjectConstructor:
- result = transformJsonObjectConstructor(pstate, (JsonObjectConstructor *) expr);
- break;
-
- case T_JsonArrayConstructor:
- result = transformJsonArrayConstructor(pstate, (JsonArrayConstructor *) expr);
- break;
-
- case T_JsonArrayQueryConstructor:
- result = transformJsonArrayQueryConstructor(pstate, (JsonArrayQueryConstructor *) expr);
- break;
-
- case T_JsonObjectAgg:
- result = transformJsonObjectAgg(pstate, (JsonObjectAgg *) expr);
- break;
-
- case T_JsonArrayAgg:
- result = transformJsonArrayAgg(pstate, (JsonArrayAgg *) expr);
- break;
-
- case T_JsonIsPredicate:
- result = transformJsonIsPredicate(pstate, (JsonIsPredicate *) expr);
- break;
-
- case T_JsonFuncExpr:
- result = transformJsonFuncExpr(pstate, (JsonFuncExpr *) expr);
- break;
-
- case T_JsonValueExpr:
- result = transformJsonValueExpr(pstate, (JsonValueExpr *) expr);
- break;
-
- case T_JsonParseExpr:
- result = transformJsonParseExpr(pstate, (JsonParseExpr *) expr);
- break;
-
- case T_JsonScalarExpr:
- result = transformJsonScalarExpr(pstate, (JsonScalarExpr *) expr);
- break;
-
- case T_JsonSerializeExpr:
- result = transformJsonSerializeExpr(pstate, (JsonSerializeExpr *) expr);
- break;
-
default:
/* should not reach here */
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -3163,1444 +3101,3 @@ ParseExprKindName(ParseExprKind exprKind)
}
return "unrecognized expression kind";
}
-
-/*
- * Make string Const node from JSON encoding name.
- *
- * UTF8 is default encoding.
- */
-static Const *
-getJsonEncodingConst(JsonFormat *format)
-{
- JsonEncoding encoding;
- const char *enc;
- Name encname = palloc(sizeof(NameData));
-
- if (!format ||
- format->format_type == JS_FORMAT_DEFAULT ||
- format->encoding == JS_ENC_DEFAULT)
- encoding = JS_ENC_UTF8;
- else
- encoding = format->encoding;
-
- switch (encoding)
- {
- case JS_ENC_UTF16:
- enc = "UTF16";
- break;
- case JS_ENC_UTF32:
- enc = "UTF32";
- break;
- case JS_ENC_UTF8:
- enc = "UTF8";
- break;
- default:
- elog(ERROR, "invalid JSON encoding: %d", encoding);
- break;
- }
-
- namestrcpy(encname, enc);
-
- return makeConst(NAMEOID, -1, InvalidOid, NAMEDATALEN,
- NameGetDatum(encname), false, false);
-}
-
-/*
- * Make bytea => text conversion using specified JSON format encoding.
- */
-static Node *
-makeJsonByteaToTextConversion(Node *expr, JsonFormat *format, int location)
-{
- Const *encoding = getJsonEncodingConst(format);
- FuncExpr *fexpr = makeFuncExpr(F_CONVERT_FROM, TEXTOID,
- list_make2(expr, encoding),
- InvalidOid, InvalidOid,
- COERCE_EXPLICIT_CALL);
-
- fexpr->location = location;
-
- return (Node *) fexpr;
-}
-
-/*
- * Make CaseTestExpr node.
- */
-static Node *
-makeCaseTestExpr(Node *expr)
-{
- CaseTestExpr *placeholder = makeNode(CaseTestExpr);
-
- placeholder->typeId = exprType(expr);
- placeholder->typeMod = exprTypmod(expr);
- placeholder->collation = exprCollation(expr);
-
- return (Node *) placeholder;
-}
-
-/*
- * Transform JSON value expression using specified input JSON format or
- * default format otherwise.
- */
-static Node *
-transformJsonValueExprExt(ParseState *pstate, JsonValueExpr *ve,
- JsonFormatType default_format, bool isarg,
- Oid targettype)
-{
- Node *expr = transformExprRecurse(pstate, (Node *) ve->raw_expr);
- Node *rawexpr;
- JsonFormatType format;
- Oid exprtype;
- int location;
- char typcategory;
- bool typispreferred;
-
- if (exprType(expr) == UNKNOWNOID)
- expr = coerce_to_specific_type(pstate, expr, TEXTOID, "JSON_VALUE_EXPR");
-
- rawexpr = expr;
- exprtype = exprType(expr);
- location = exprLocation(expr);
-
- get_type_category_preferred(exprtype, &typcategory, &typispreferred);
-
- rawexpr = expr;
-
- if (ve->format->format_type != JS_FORMAT_DEFAULT)
- {
- if (ve->format->encoding != JS_ENC_DEFAULT && exprtype != BYTEAOID)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("JSON ENCODING clause is only allowed for bytea input type"),
- parser_errposition(pstate, ve->format->location)));
-
- if (exprtype == JSONOID || exprtype == JSONBOID)
- {
- format = JS_FORMAT_DEFAULT; /* do not format json[b] types */
- ereport(WARNING,
- (errmsg("FORMAT JSON has no effect for json and jsonb types"),
- parser_errposition(pstate, ve->format->location)));
- }
- else
- format = ve->format->format_type;
- }
- else if (isarg)
- {
- /* Pass SQL/JSON item types directly without conversion to json[b]. */
- switch (exprtype)
- {
- case TEXTOID:
- case NUMERICOID:
- case BOOLOID:
- case INT2OID:
- case INT4OID:
- case INT8OID:
- case FLOAT4OID:
- case FLOAT8OID:
- case DATEOID:
- case TIMEOID:
- case TIMETZOID:
- case TIMESTAMPOID:
- case TIMESTAMPTZOID:
- return expr;
-
- default:
- if (typcategory == TYPCATEGORY_STRING)
- return coerce_to_specific_type(pstate, expr, TEXTOID,
- "JSON_VALUE_EXPR");
- /* else convert argument to json[b] type */
- break;
- }
-
- format = default_format;
- }
- else if (exprtype == JSONOID || exprtype == JSONBOID)
- format = JS_FORMAT_DEFAULT; /* do not format json[b] types */
- else
- format = default_format;
-
- if (format == JS_FORMAT_DEFAULT &&
- (!OidIsValid(targettype) || exprtype == targettype))
- expr = rawexpr;
- else
- {
- Node *orig = makeCaseTestExpr(expr);
- Node *coerced;
- bool cast_is_needed = OidIsValid(targettype);
-
- if (!isarg && !cast_is_needed &&
- exprtype != BYTEAOID && typcategory != TYPCATEGORY_STRING)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg(ve->format->format_type == JS_FORMAT_DEFAULT ?
- "cannot use non-string types with implicit FORMAT JSON clause" :
- "cannot use non-string types with explicit FORMAT JSON clause"),
- parser_errposition(pstate, ve->format->location >= 0 ?
- ve->format->location : location)));
-
- expr = orig;
-
- /* Convert encoded JSON text from bytea. */
- if (format == JS_FORMAT_JSON && exprtype == BYTEAOID)
- {
- expr = makeJsonByteaToTextConversion(expr, ve->format, location);
- exprtype = TEXTOID;
- }
-
- if (!OidIsValid(targettype))
- targettype = format == JS_FORMAT_JSONB ? JSONBOID : JSONOID;
-
- /* Try to coerce to the target type. */
- coerced = coerce_to_target_type(pstate, expr, exprtype,
- targettype, -1,
- COERCION_EXPLICIT,
- COERCE_EXPLICIT_CAST,
- location);
-
- if (!coerced)
- {
- /* If coercion failed, use to_json()/to_jsonb() functions. */
- FuncExpr *fexpr;
- Oid fnoid;
-
- if (cast_is_needed) /* only CAST is allowed */
- ereport(ERROR,
- (errcode(ERRCODE_CANNOT_COERCE),
- errmsg("cannot cast type %s to %s",
- format_type_be(exprtype),
- format_type_be(targettype)),
- parser_errposition(pstate, location)));
-
- fnoid = targettype == JSONOID ? F_TO_JSON : F_TO_JSONB;
- fexpr = makeFuncExpr(fnoid, targettype, list_make1(expr),
- InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
-
- fexpr->location = location;
-
- coerced = (Node *) fexpr;
- }
-
- if (coerced == orig)
- expr = rawexpr;
- else
- {
- ve = copyObject(ve);
- ve->raw_expr = (Expr *) rawexpr;
- ve->formatted_expr = (Expr *) coerced;
-
- expr = (Node *) ve;
- }
- }
-
- return expr;
-}
-
-/*
- * Transform JSON value expression using FORMAT JSON by default.
- */
-static Node *
-transformJsonValueExpr(ParseState *pstate, JsonValueExpr *jve)
-{
- return transformJsonValueExprExt(pstate, jve, JS_FORMAT_JSON, false,
- InvalidOid);
-}
-
-/*
- * Transform JSON value expression using unspecified format by default.
- */
-static Node *
-transformJsonValueExprDefault(ParseState *pstate, JsonValueExpr *jve)
-{
- return transformJsonValueExprExt(pstate, jve, JS_FORMAT_DEFAULT, false,
- InvalidOid);
-}
-
-/*
- * Checks specified output format for its applicability to the target type.
- */
-static void
-checkJsonOutputFormat(ParseState *pstate, const JsonFormat *format,
- Oid targettype, bool allow_format_for_non_strings)
-{
- if (!allow_format_for_non_strings &&
- format->format_type != JS_FORMAT_DEFAULT &&
- (targettype != BYTEAOID &&
- targettype != JSONOID &&
- targettype != JSONBOID))
- {
- char typcategory;
- bool typispreferred;
-
- get_type_category_preferred(targettype, &typcategory, &typispreferred);
-
- if (typcategory != TYPCATEGORY_STRING)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- parser_errposition(pstate, format->location),
- errmsg("cannot use JSON format with non-string output types")));
- }
-
- if (format->format_type == JS_FORMAT_JSON)
- {
- JsonEncoding enc = format->encoding != JS_ENC_DEFAULT ?
- format->encoding : JS_ENC_UTF8;
-
- if (targettype != BYTEAOID &&
- format->encoding != JS_ENC_DEFAULT)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- parser_errposition(pstate, format->location),
- errmsg("cannot set JSON encoding for non-bytea output types")));
-
- if (enc != JS_ENC_UTF8)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("unsupported JSON encoding"),
- errhint("Only UTF8 JSON encoding is supported."),
- parser_errposition(pstate, format->location)));
- }
-}
-
-/*
- * Transform JSON output clause.
- *
- * Assigns target type oid and modifier.
- * Assigns default format or checks specified format for its applicability to
- * the target type.
- */
-static JsonReturning *
-transformJsonOutput(ParseState *pstate, const JsonOutput *output,
- bool allow_format)
-{
- JsonReturning *ret;
-
- /* if output clause is not specified, make default clause value */
- if (!output)
- {
- ret = makeNode(JsonReturning);
-
- ret->format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
- ret->typid = InvalidOid;
- ret->typmod = -1;
-
- return ret;
- }
-
- ret = copyObject(output->returning);
-
- typenameTypeIdAndMod(pstate, output->typeName, &ret->typid, &ret->typmod);
-
- if (output->typeName->setof)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("returning SETOF types is not supported in SQL/JSON functions")));
-
- if (ret->format->format_type == JS_FORMAT_DEFAULT)
- /* assign JSONB format when returning jsonb, or JSON format otherwise */
- ret->format->format_type =
- ret->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON;
- else
- checkJsonOutputFormat(pstate, ret->format, ret->typid, allow_format);
-
- return ret;
-}
-
-/*
- * Transform JSON output clause of JSON constructor functions.
- *
- * Derive RETURNING type, if not specified, from argument types.
- */
-static JsonReturning *
-transformJsonConstructorOutput(ParseState *pstate, JsonOutput *output,
- List *args)
-{
- JsonReturning *returning = transformJsonOutput(pstate, output, true);
-
- if (!OidIsValid(returning->typid))
- {
- ListCell *lc;
- bool have_jsonb = false;
-
- foreach(lc, args)
- {
- Node *expr = lfirst(lc);
- Oid typid = exprType(expr);
-
- have_jsonb |= typid == JSONBOID;
-
- if (have_jsonb)
- break;
- }
-
- if (have_jsonb)
- {
- returning->typid = JSONBOID;
- returning->format->format_type = JS_FORMAT_JSONB;
- }
- else
- {
- /* XXX TEXT is default by the standard, but we return JSON */
- returning->typid = JSONOID;
- returning->format->format_type = JS_FORMAT_JSON;
- }
-
- returning->typmod = -1;
- }
-
- return returning;
-}
-
-/*
- * Coerce json[b]-valued function expression to the output type.
- */
-static Node *
-coerceJsonFuncExpr(ParseState *pstate, Node *expr,
- const JsonReturning *returning, bool report_error)
-{
- Node *res;
- int location;
- Oid exprtype = exprType(expr);
-
- /* if output type is not specified or equals to function type, return */
- if (!OidIsValid(returning->typid) || returning->typid == exprtype)
- return expr;
-
- location = exprLocation(expr);
-
- if (location < 0)
- location = returning->format->location;
-
- /* special case for RETURNING bytea FORMAT json */
- if (returning->format->format_type == JS_FORMAT_JSON &&
- returning->typid == BYTEAOID)
- {
- /* encode json text into bytea using pg_convert_to() */
- Node *texpr = coerce_to_specific_type(pstate, expr, TEXTOID,
- "JSON_FUNCTION");
- Const *enc = getJsonEncodingConst(returning->format);
- FuncExpr *fexpr = makeFuncExpr(F_CONVERT_TO, BYTEAOID,
- list_make2(texpr, enc),
- InvalidOid, InvalidOid,
- COERCE_EXPLICIT_CALL);
-
- fexpr->location = location;
-
- return (Node *) fexpr;
- }
-
- /* try to coerce expression to the output type */
- res = coerce_to_target_type(pstate, expr, exprtype,
- returning->typid, returning->typmod,
- /* XXX throwing errors when casting to char(N) */
- COERCION_EXPLICIT,
- COERCE_EXPLICIT_CAST,
- location);
-
- if (!res && report_error)
- ereport(ERROR,
- (errcode(ERRCODE_CANNOT_COERCE),
- errmsg("cannot cast type %s to %s",
- format_type_be(exprtype),
- format_type_be(returning->typid)),
- parser_coercion_errposition(pstate, location, expr)));
-
- return res;
-}
-
-static Node *
-makeJsonConstructorExpr(ParseState *pstate, JsonConstructorType type,
- List *args, Expr *fexpr, JsonReturning *returning,
- bool unique, bool absent_on_null, int location)
-{
- JsonConstructorExpr *jsctor = makeNode(JsonConstructorExpr);
- Node *placeholder;
- Node *coercion;
- Oid intermediate_typid =
- returning->format->format_type == JS_FORMAT_JSONB ? JSONBOID : JSONOID;
-
- jsctor->args = args;
- jsctor->func = fexpr;
- jsctor->type = type;
- jsctor->returning = returning;
- jsctor->unique = unique;
- jsctor->absent_on_null = absent_on_null;
- jsctor->location = location;
-
- if (fexpr)
- placeholder = makeCaseTestExpr((Node *) fexpr);
- else
- {
- CaseTestExpr *cte = makeNode(CaseTestExpr);
-
- cte->typeId = intermediate_typid;
- cte->typeMod = -1;
- cte->collation = InvalidOid;
-
- placeholder = (Node *) cte;
- }
-
- coercion = coerceJsonFuncExpr(pstate, placeholder, returning, true);
-
- if (coercion != placeholder)
- jsctor->coercion = (Expr *) coercion;
-
- return (Node *) jsctor;
-}
-
-/*
- * Transform JSON_OBJECT() constructor.
- *
- * JSON_OBJECT() is transformed into json[b]_build_object[_ext]() call
- * depending on the output JSON format. The first two arguments of
- * json[b]_build_object_ext() are absent_on_null and check_key_uniqueness.
- *
- * Then function call result is coerced to the target type.
- */
-static Node *
-transformJsonObjectConstructor(ParseState *pstate, JsonObjectConstructor *ctor)
-{
- JsonReturning *returning;
- List *args = NIL;
-
- /* transform key-value pairs, if any */
- if (ctor->exprs)
- {
- ListCell *lc;
-
- /* transform and append key-value arguments */
- foreach(lc, ctor->exprs)
- {
- JsonKeyValue *kv = castNode(JsonKeyValue, lfirst(lc));
- Node *key = transformExprRecurse(pstate, (Node *) kv->key);
- Node *val = transformJsonValueExprDefault(pstate, kv->value);
-
- args = lappend(args, key);
- args = lappend(args, val);
- }
- }
-
- returning = transformJsonConstructorOutput(pstate, ctor->output, args);
-
- return makeJsonConstructorExpr(pstate, JSCTOR_JSON_OBJECT, args, NULL,
- returning, ctor->unique,
- ctor->absent_on_null, ctor->location);
-}
-
-/*
- * Transform JSON_ARRAY(query [FORMAT] [RETURNING] [ON NULL]) into
- * (SELECT JSON_ARRAYAGG(a [FORMAT] [RETURNING] [ON NULL]) FROM (query) q(a))
- */
-static Node *
-transformJsonArrayQueryConstructor(ParseState *pstate,
- JsonArrayQueryConstructor *ctor)
-{
- SubLink *sublink = makeNode(SubLink);
- SelectStmt *select = makeNode(SelectStmt);
- RangeSubselect *range = makeNode(RangeSubselect);
- Alias *alias = makeNode(Alias);
- ResTarget *target = makeNode(ResTarget);
- JsonArrayAgg *agg = makeNode(JsonArrayAgg);
- ColumnRef *colref = makeNode(ColumnRef);
- Query *query;
- ParseState *qpstate;
-
- /* Transform query only for counting target list entries. */
- qpstate = make_parsestate(pstate);
-
- query = transformStmt(qpstate, ctor->query);
-
- if (count_nonjunk_tlist_entries(query->targetList) != 1)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("subquery must return only one column"),
- parser_errposition(pstate, ctor->location)));
-
- free_parsestate(qpstate);
-
- colref->fields = list_make2(makeString(pstrdup("q")),
- makeString(pstrdup("a")));
- colref->location = ctor->location;
-
- agg->arg = makeJsonValueExpr((Expr *) colref, ctor->format);
- agg->absent_on_null = ctor->absent_on_null;
- agg->constructor = makeNode(JsonAggConstructor);
- agg->constructor->agg_order = NIL;
- agg->constructor->output = ctor->output;
- agg->constructor->location = ctor->location;
-
- target->name = NULL;
- target->indirection = NIL;
- target->val = (Node *) agg;
- target->location = ctor->location;
-
- alias->aliasname = pstrdup("q");
- alias->colnames = list_make1(makeString(pstrdup("a")));
-
- range->lateral = false;
- range->subquery = ctor->query;
- range->alias = alias;
-
- select->targetList = list_make1(target);
- select->fromClause = list_make1(range);
-
- sublink->subLinkType = EXPR_SUBLINK;
- sublink->subLinkId = 0;
- sublink->testexpr = NULL;
- sublink->operName = NIL;
- sublink->subselect = (Node *) select;
- sublink->location = ctor->location;
-
- return transformExprRecurse(pstate, (Node *) sublink);
-}
-
-/*
- * Common code for JSON_OBJECTAGG and JSON_ARRAYAGG transformation.
- */
-static Node *
-transformJsonAggConstructor(ParseState *pstate, JsonAggConstructor *agg_ctor,
- JsonReturning *returning, List *args,
- const char *aggfn, Oid aggtype,
- JsonConstructorType ctor_type,
- bool unique, bool absent_on_null)
-{
- Oid aggfnoid;
- Node *node;
- Expr *aggfilter = agg_ctor->agg_filter ? (Expr *)
- transformWhereClause(pstate, agg_ctor->agg_filter,
- EXPR_KIND_FILTER, "FILTER") : NULL;
-
- aggfnoid = DatumGetInt32(DirectFunctionCall1(regprocin,
- CStringGetDatum(aggfn)));
-
- if (agg_ctor->over)
- {
- /* window function */
- WindowFunc *wfunc = makeNode(WindowFunc);
-
- wfunc->winfnoid = aggfnoid;
- wfunc->wintype = aggtype;
- /* wincollid and inputcollid will be set by parse_collate.c */
- wfunc->args = args;
- /* winref will be set by transformWindowFuncCall */
- wfunc->winstar = false;
- wfunc->winagg = true;
- wfunc->aggfilter = aggfilter;
- wfunc->location = agg_ctor->location;
-
- /*
- * ordered aggs not allowed in windows yet
- */
- if (agg_ctor->agg_order != NIL)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("aggregate ORDER BY is not implemented for window functions"),
- parser_errposition(pstate, agg_ctor->location)));
-
- /* parse_agg.c does additional window-func-specific processing */
- transformWindowFuncCall(pstate, wfunc, agg_ctor->over);
-
- node = (Node *) wfunc;
- }
- else
- {
- Aggref *aggref = makeNode(Aggref);
-
- aggref->aggfnoid = aggfnoid;
- aggref->aggtype = aggtype;
-
- /* aggcollid and inputcollid will be set by parse_collate.c */
- aggref->aggtranstype = InvalidOid; /* will be set by planner */
- /* aggargtypes will be set by transformAggregateCall */
- /* aggdirectargs and args will be set by transformAggregateCall */
- /* aggorder and aggdistinct will be set by transformAggregateCall */
- aggref->aggfilter = aggfilter;
- aggref->aggstar = false;
- aggref->aggvariadic = false;
- aggref->aggkind = AGGKIND_NORMAL;
- aggref->aggpresorted = false;
- /* agglevelsup will be set by transformAggregateCall */
- aggref->aggsplit = AGGSPLIT_SIMPLE; /* planner might change this */
- aggref->location = agg_ctor->location;
-
- transformAggregateCall(pstate, aggref, args, agg_ctor->agg_order, false);
-
- node = (Node *) aggref;
- }
-
- return makeJsonConstructorExpr(pstate, ctor_type, NIL, (Expr *) node,
- returning, unique, absent_on_null,
- agg_ctor->location);
-}
-
-/*
- * Transform JSON_OBJECTAGG() aggregate function.
- *
- * JSON_OBJECTAGG() is transformed into
- * json[b]_objectagg(key, value, absent_on_null, check_unique) call depending on
- * the output JSON format. Then the function call result is coerced to the
- * target output type.
- */
-static Node *
-transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg)
-{
- JsonReturning *returning;
- Node *key;
- Node *val;
- List *args;
- const char *aggfnname;
- Oid aggtype;
-
- key = transformExprRecurse(pstate, (Node *) agg->arg->key);
- val = transformJsonValueExprDefault(pstate, agg->arg->value);
- args = list_make2(key, val);
-
- returning = transformJsonConstructorOutput(pstate, agg->constructor->output,
- args);
-
- if (returning->format->format_type == JS_FORMAT_JSONB)
- {
- if (agg->absent_on_null)
- if (agg->unique)
- aggfnname = "pg_catalog.jsonb_object_agg_unique_strict"; /* F_JSONB_OBJECT_AGG_UNIQUE_STRICT */
- else
- aggfnname = "pg_catalog.jsonb_object_agg_strict"; /* F_JSONB_OBJECT_AGG_STRICT */
- else if (agg->unique)
- aggfnname = "pg_catalog.jsonb_object_agg_unique"; /* F_JSONB_OBJECT_AGG_UNIQUE */
- else
- aggfnname = "pg_catalog.jsonb_object_agg"; /* F_JSONB_OBJECT_AGG */
-
- aggtype = JSONBOID;
- }
- else
- {
- if (agg->absent_on_null)
- if (agg->unique)
- aggfnname = "pg_catalog.json_object_agg_unique_strict"; /* F_JSON_OBJECT_AGG_UNIQUE_STRICT */
- else
- aggfnname = "pg_catalog.json_object_agg_strict"; /* F_JSON_OBJECT_AGG_STRICT */
- else if (agg->unique)
- aggfnname = "pg_catalog.json_object_agg_unique"; /* F_JSON_OBJECT_AGG_UNIQUE */
- else
- aggfnname = "pg_catalog.json_object_agg"; /* F_JSON_OBJECT_AGG */
-
- aggtype = JSONOID;
- }
-
- return transformJsonAggConstructor(pstate, agg->constructor, returning,
- args, aggfnname, aggtype,
- JSCTOR_JSON_OBJECTAGG,
- agg->unique, agg->absent_on_null);
-}
-
-/*
- * Transform JSON_ARRAYAGG() aggregate function.
- *
- * JSON_ARRAYAGG() is transformed into json[b]_agg[_strict]() call depending
- * on the output JSON format and absent_on_null. Then the function call result
- * is coerced to the target output type.
- */
-static Node *
-transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg)
-{
- JsonReturning *returning;
- Node *arg;
- const char *aggfnname;
- Oid aggtype;
-
- arg = transformJsonValueExprDefault(pstate, agg->arg);
-
- returning = transformJsonConstructorOutput(pstate, agg->constructor->output,
- list_make1(arg));
-
- if (returning->format->format_type == JS_FORMAT_JSONB)
- {
- aggfnname = agg->absent_on_null ?
- "pg_catalog.jsonb_agg_strict" : "pg_catalog.jsonb_agg";
- aggtype = JSONBOID;
- }
- else
- {
- aggfnname = agg->absent_on_null ?
- "pg_catalog.json_agg_strict" : "pg_catalog.json_agg";
- aggtype = JSONOID;
- }
-
- return transformJsonAggConstructor(pstate, agg->constructor, returning,
- list_make1(arg), aggfnname, aggtype,
- JSCTOR_JSON_ARRAYAGG,
- false, agg->absent_on_null);
-}
-
-/*
- * Transform JSON_ARRAY() constructor.
- *
- * JSON_ARRAY() is transformed into json[b]_build_array[_ext]() call
- * depending on the output JSON format. The first argument of
- * json[b]_build_array_ext() is absent_on_null.
- *
- * Then function call result is coerced to the target type.
- */
-static Node *
-transformJsonArrayConstructor(ParseState *pstate, JsonArrayConstructor *ctor)
-{
- JsonReturning *returning;
- List *args = NIL;
-
- /* transform element expressions, if any */
- if (ctor->exprs)
- {
- ListCell *lc;
-
- /* transform and append element arguments */
- foreach(lc, ctor->exprs)
- {
- JsonValueExpr *jsval = castNode(JsonValueExpr, lfirst(lc));
- Node *val = transformJsonValueExprDefault(pstate, jsval);
-
- args = lappend(args, val);
- }
- }
-
- returning = transformJsonConstructorOutput(pstate, ctor->output, args);
-
- return makeJsonConstructorExpr(pstate, JSCTOR_JSON_ARRAY, args, NULL,
- returning, false, ctor->absent_on_null,
- ctor->location);
-}
-
-static Node *
-transformJsonParseArg(ParseState *pstate, Node *jsexpr, JsonFormat *format,
- Oid *exprtype)
-{
- Node *raw_expr = transformExprRecurse(pstate, jsexpr);
- Node *expr = raw_expr;
-
- *exprtype = exprType(expr);
-
- /* prepare input document */
- if (*exprtype == BYTEAOID)
- {
- JsonValueExpr *jve;
-
- expr = makeCaseTestExpr(raw_expr);
- expr = makeJsonByteaToTextConversion(expr, format, exprLocation(expr));
- *exprtype = TEXTOID;
-
- jve = makeJsonValueExpr((Expr *) raw_expr, format);
-
- jve->formatted_expr = (Expr *) expr;
- expr = (Node *) jve;
- }
- else
- {
- char typcategory;
- bool typispreferred;
-
- get_type_category_preferred(*exprtype, &typcategory, &typispreferred);
-
- if (*exprtype == UNKNOWNOID || typcategory == TYPCATEGORY_STRING)
- {
- expr = coerce_to_target_type(pstate, (Node *) expr, *exprtype,
- TEXTOID, -1,
- COERCION_IMPLICIT,
- COERCE_IMPLICIT_CAST, -1);
- *exprtype = TEXTOID;
- }
-
- if (format->encoding != JS_ENC_DEFAULT)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- parser_errposition(pstate, format->location),
- errmsg("cannot use JSON FORMAT ENCODING clause for non-bytea input types")));
- }
-
- return expr;
-}
-
-/*
- * Transform IS JSON predicate.
- */
-static Node *
-transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *pred)
-{
- Oid exprtype;
- Node *expr = transformJsonParseArg(pstate, pred->expr, pred->format,
- &exprtype);
-
- /* make resulting expression */
- if (exprtype != TEXTOID && exprtype != JSONOID && exprtype != JSONBOID)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("cannot use type %s in IS JSON predicate",
- format_type_be(exprtype))));
-
- /* This intentionally(?) drops the format clause. */
- return makeJsonIsPredicate(expr, NULL, pred->item_type,
- pred->unique_keys, pred->location);
-}
-
-/*
- * Transform a JSON PASSING clause.
- */
-static void
-transformJsonPassingArgs(ParseState *pstate, JsonFormatType format, List *args,
- List **passing_values, List **passing_names)
-{
- ListCell *lc;
-
- *passing_values = NIL;
- *passing_names = NIL;
-
- foreach(lc, args)
- {
- JsonArgument *arg = castNode(JsonArgument, lfirst(lc));
- Node *expr = transformJsonValueExprExt(pstate, arg->val,
- format, true, InvalidOid);
-
- assign_expr_collations(pstate, expr);
-
- *passing_values = lappend(*passing_values, expr);
- *passing_names = lappend(*passing_names, makeString(arg->name));
- }
-}
-
-/*
- * Transform a JSON BEHAVIOR clause.
- */
-static JsonBehavior *
-transformJsonBehavior(ParseState *pstate, JsonBehavior *behavior,
- JsonBehaviorType default_behavior)
-{
- JsonBehaviorType behavior_type = default_behavior;
- Node *default_expr = NULL;
-
- if (behavior)
- {
- behavior_type = behavior->btype;
- if (behavior_type == JSON_BEHAVIOR_DEFAULT)
- default_expr = transformExprRecurse(pstate, behavior->default_expr);
- }
- return makeJsonBehavior(behavior_type, default_expr);
-}
-
-/*
- * Common code for JSON_VALUE, JSON_QUERY, JSON_EXISTS transformation
- * into a JsonExpr node.
- */
-static JsonExpr *
-transformJsonExprCommon(ParseState *pstate, JsonFuncExpr *func)
-{
- JsonExpr *jsexpr = makeNode(JsonExpr);
- Node *pathspec;
- JsonFormatType format;
-
- if (func->common->pathname && func->op != JSON_TABLE_OP)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("JSON_TABLE path name is not allowed here"),
- parser_errposition(pstate, func->location)));
-
- jsexpr->location = func->location;
- jsexpr->op = func->op;
- jsexpr->formatted_expr = transformJsonValueExpr(pstate, func->common->expr);
-
- assign_expr_collations(pstate, jsexpr->formatted_expr);
-
- /* format is determined by context item type */
- format = exprType(jsexpr->formatted_expr) == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON;
-
- jsexpr->result_coercion = NULL;
- jsexpr->omit_quotes = false;
-
- jsexpr->format = func->common->expr->format;
-
- pathspec = transformExprRecurse(pstate, func->common->pathspec);
-
- jsexpr->path_spec =
- coerce_to_target_type(pstate, pathspec, exprType(pathspec),
- JSONPATHOID, -1,
- COERCION_EXPLICIT, COERCE_IMPLICIT_CAST,
- exprLocation(pathspec));
- if (!jsexpr->path_spec)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("JSON path expression must be type %s, not type %s",
- "jsonpath", format_type_be(exprType(pathspec))),
- parser_errposition(pstate, exprLocation(pathspec))));
-
- /* transform and coerce to json[b] passing arguments */
- transformJsonPassingArgs(pstate, format, func->common->passing,
- &jsexpr->passing_values, &jsexpr->passing_names);
-
- if (func->op != JSON_EXISTS_OP && func->op != JSON_TABLE_OP)
- jsexpr->on_empty = transformJsonBehavior(pstate, func->on_empty,
- JSON_BEHAVIOR_NULL);
-
- if (func->op == JSON_EXISTS_OP)
- jsexpr->on_error = transformJsonBehavior(pstate, func->on_error,
- JSON_BEHAVIOR_FALSE);
- else if (func->op == JSON_TABLE_OP)
- jsexpr->on_error = transformJsonBehavior(pstate, func->on_error,
- JSON_BEHAVIOR_EMPTY);
- else
- jsexpr->on_error = transformJsonBehavior(pstate, func->on_error,
- JSON_BEHAVIOR_NULL);
-
- return jsexpr;
-}
-
-/*
- * Assign default JSON returning type from the specified format or from
- * the context item type.
- */
-static void
-assignDefaultJsonReturningType(Node *context_item, JsonFormat *context_format,
- JsonReturning *ret)
-{
- bool is_jsonb;
-
- ret->format = copyObject(context_format);
-
- if (ret->format->format_type == JS_FORMAT_DEFAULT)
- is_jsonb = exprType(context_item) == JSONBOID;
- else
- is_jsonb = ret->format->format_type == JS_FORMAT_JSONB;
-
- ret->typid = is_jsonb ? JSONBOID : JSONOID;
- ret->typmod = -1;
-}
-
-/*
- * Try to coerce expression to the output type or
- * use json_populate_type() for composite, array and domain types or
- * use coercion via I/O.
- */
-static JsonCoercion *
-coerceJsonExpr(ParseState *pstate, Node *expr, const JsonReturning *returning)
-{
- char typtype;
- JsonCoercion *coercion = makeNode(JsonCoercion);
-
- coercion->expr = coerceJsonFuncExpr(pstate, expr, returning, false);
-
- if (coercion->expr)
- {
- if (coercion->expr == expr)
- coercion->expr = NULL;
-
- return coercion;
- }
-
- typtype = get_typtype(returning->typid);
-
- if (returning->typid == RECORDOID ||
- typtype == TYPTYPE_COMPOSITE ||
- typtype == TYPTYPE_DOMAIN ||
- type_is_array(returning->typid))
- coercion->via_populate = true;
- else
- coercion->via_io = true;
-
- return coercion;
-}
-
-/*
- * Transform a JSON output clause of JSON_VALUE and JSON_QUERY.
- */
-static void
-transformJsonFuncExprOutput(ParseState *pstate, JsonFuncExpr *func,
- JsonExpr *jsexpr)
-{
- Node *expr = jsexpr->formatted_expr;
-
- jsexpr->returning = transformJsonOutput(pstate, func->output, false);
-
- /* JSON_VALUE returns text by default */
- if (func->op == JSON_VALUE_OP && !OidIsValid(jsexpr->returning->typid))
- {
- jsexpr->returning->typid = TEXTOID;
- jsexpr->returning->typmod = -1;
- }
-
- if (OidIsValid(jsexpr->returning->typid))
- {
- JsonReturning ret;
-
- if (func->op == JSON_VALUE_OP &&
- jsexpr->returning->typid != JSONOID &&
- jsexpr->returning->typid != JSONBOID)
- {
- /* Forced coercion via I/O for JSON_VALUE for non-JSON types */
- jsexpr->result_coercion = makeNode(JsonCoercion);
- jsexpr->result_coercion->expr = NULL;
- jsexpr->result_coercion->via_io = true;
- return;
- }
-
- assignDefaultJsonReturningType(jsexpr->formatted_expr, jsexpr->format, &ret);
-
- if (ret.typid != jsexpr->returning->typid ||
- ret.typmod != jsexpr->returning->typmod)
- {
- Node *placeholder = makeCaseTestExpr(expr);
-
- Assert(((CaseTestExpr *) placeholder)->typeId == ret.typid);
- Assert(((CaseTestExpr *) placeholder)->typeMod == ret.typmod);
-
- jsexpr->result_coercion = coerceJsonExpr(pstate, placeholder,
- jsexpr->returning);
- }
- }
- else
- assignDefaultJsonReturningType(jsexpr->formatted_expr, jsexpr->format,
- jsexpr->returning);
-}
-
-/*
- * Coerce an expression in JSON DEFAULT behavior to the target output type.
- */
-static Node *
-coerceDefaultJsonExpr(ParseState *pstate, JsonExpr *jsexpr, Node *defexpr)
-{
- int location;
- Oid exprtype;
-
- if (!defexpr)
- return NULL;
-
- exprtype = exprType(defexpr);
- location = exprLocation(defexpr);
-
- if (location < 0)
- location = jsexpr->location;
-
- defexpr = coerce_to_target_type(pstate,
- defexpr,
- exprtype,
- jsexpr->returning->typid,
- jsexpr->returning->typmod,
- COERCION_EXPLICIT,
- COERCE_IMPLICIT_CAST,
- location);
-
- if (!defexpr)
- ereport(ERROR,
- (errcode(ERRCODE_CANNOT_COERCE),
- errmsg("cannot cast DEFAULT expression type %s to %s",
- format_type_be(exprtype),
- format_type_be(jsexpr->returning->typid)),
- parser_errposition(pstate, location)));
-
- return defexpr;
-}
-
-/*
- * Initialize SQL/JSON item coercion from the SQL type "typid" to the target
- * "returning" type.
- */
-static JsonCoercion *
-initJsonItemCoercion(ParseState *pstate, Oid typid,
- const JsonReturning *returning)
-{
- Node *expr;
-
- if (typid == UNKNOWNOID)
- {
- expr = (Node *) makeNullConst(UNKNOWNOID, -1, InvalidOid);
- }
- else
- {
- CaseTestExpr *placeholder = makeNode(CaseTestExpr);
-
- placeholder->typeId = typid;
- placeholder->typeMod = -1;
- placeholder->collation = InvalidOid;
-
- expr = (Node *) placeholder;
- }
-
- return coerceJsonExpr(pstate, expr, returning);
-}
-
-static void
-initJsonItemCoercions(ParseState *pstate, JsonItemCoercions *coercions,
- const JsonReturning *returning, Oid contextItemTypeId)
-{
- struct
- {
- JsonCoercion **coercion;
- Oid typid;
- } *p,
- coercionTypids[] =
- {
- {&coercions->null, UNKNOWNOID},
- {&coercions->string, TEXTOID},
- {&coercions->numeric, NUMERICOID},
- {&coercions->boolean, BOOLOID},
- {&coercions->date, DATEOID},
- {&coercions->time, TIMEOID},
- {&coercions->timetz, TIMETZOID},
- {&coercions->timestamp, TIMESTAMPOID},
- {&coercions->timestamptz, TIMESTAMPTZOID},
- {&coercions->composite, contextItemTypeId},
- {NULL, InvalidOid}
- };
-
- for (p = coercionTypids; p->coercion; p++)
- *p->coercion = initJsonItemCoercion(pstate, p->typid, returning);
-}
-
-/*
- * Transform JSON_VALUE, JSON_QUERY, JSON_EXISTS functions into a JsonExpr node.
- */
-static Node *
-transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
-{
- JsonExpr *jsexpr = transformJsonExprCommon(pstate, func);
- const char *func_name = NULL;
- Node *contextItemExpr = jsexpr->formatted_expr;
-
- switch (func->op)
- {
- case JSON_VALUE_OP:
- func_name = "JSON_VALUE";
-
- transformJsonFuncExprOutput(pstate, func, jsexpr);
-
- jsexpr->returning->format->format_type = JS_FORMAT_DEFAULT;
- jsexpr->returning->format->encoding = JS_ENC_DEFAULT;
-
- jsexpr->on_empty->default_expr =
- coerceDefaultJsonExpr(pstate, jsexpr,
- jsexpr->on_empty->default_expr);
-
- jsexpr->on_error->default_expr =
- coerceDefaultJsonExpr(pstate, jsexpr,
- jsexpr->on_error->default_expr);
-
- jsexpr->coercions = makeNode(JsonItemCoercions);
- initJsonItemCoercions(pstate, jsexpr->coercions, jsexpr->returning,
- exprType(contextItemExpr));
-
- break;
-
- case JSON_QUERY_OP:
- func_name = "JSON_QUERY";
-
- transformJsonFuncExprOutput(pstate, func, jsexpr);
-
- jsexpr->on_empty->default_expr =
- coerceDefaultJsonExpr(pstate, jsexpr,
- jsexpr->on_empty->default_expr);
-
- jsexpr->on_error->default_expr =
- coerceDefaultJsonExpr(pstate, jsexpr,
- jsexpr->on_error->default_expr);
-
- jsexpr->wrapper = func->wrapper;
- jsexpr->omit_quotes = func->omit_quotes;
-
- break;
-
- case JSON_EXISTS_OP:
- func_name = "JSON_EXISTS";
-
- jsexpr->returning = transformJsonOutput(pstate, func->output, false);
-
- jsexpr->returning->format->format_type = JS_FORMAT_DEFAULT;
- jsexpr->returning->format->encoding = JS_ENC_DEFAULT;
-
- if (!OidIsValid(jsexpr->returning->typid))
- {
- jsexpr->returning->typid = BOOLOID;
- jsexpr->returning->typmod = -1;
- }
- else if (jsexpr->returning->typid != BOOLOID)
- {
- CaseTestExpr *placeholder = makeNode(CaseTestExpr);
- int location = exprLocation((Node *) jsexpr);
-
- placeholder->typeId = BOOLOID;
- placeholder->typeMod = -1;
- placeholder->collation = InvalidOid;
-
- jsexpr->result_coercion = makeNode(JsonCoercion);
- jsexpr->result_coercion->expr =
- coerce_to_target_type(pstate, (Node *) placeholder, BOOLOID,
- jsexpr->returning->typid,
- jsexpr->returning->typmod,
- COERCION_EXPLICIT,
- COERCE_IMPLICIT_CAST,
- location);
-
- if (!jsexpr->result_coercion->expr)
- ereport(ERROR,
- (errcode(ERRCODE_CANNOT_COERCE),
- errmsg("cannot cast type %s to %s",
- format_type_be(BOOLOID),
- format_type_be(jsexpr->returning->typid)),
- parser_coercion_errposition(pstate, location, (Node *) jsexpr)));
-
- if (jsexpr->result_coercion->expr == (Node *) placeholder)
- jsexpr->result_coercion->expr = NULL;
- }
- break;
-
- case JSON_TABLE_OP:
- jsexpr->returning = makeNode(JsonReturning);
- jsexpr->returning->format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
- jsexpr->returning->typid = exprType(contextItemExpr);
- jsexpr->returning->typmod = -1;
-
- if (jsexpr->returning->typid != JSONBOID)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("JSON_TABLE() is not yet implemented for the json type"),
- errhint("Try casting the argument to jsonb"),
- parser_errposition(pstate, func->location)));
-
- break;
- }
-
- if (exprType(contextItemExpr) != JSONBOID)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("%s() is not yet implemented for the json type", func_name),
- errhint("Try casting the argument to jsonb"),
- parser_errposition(pstate, func->location)));
-
- return (Node *) jsexpr;
-}
-
-static JsonReturning *
-transformJsonConstructorRet(ParseState *pstate, JsonOutput *output, const char *fname)
-{
- JsonReturning *returning;
-
- if (output)
- {
- returning = transformJsonOutput(pstate, output, false);
-
- Assert(OidIsValid(returning->typid));
-
- if (returning->typid != JSONOID && returning->typid != JSONBOID)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("cannot use RETURNING type %s in %s",
- format_type_be(returning->typid), fname),
- parser_errposition(pstate, output->typeName->location)));
- }
- else
- {
- Oid targettype = JSONOID;
- JsonFormatType format = JS_FORMAT_JSON;
-
- returning = makeNode(JsonReturning);
- returning->format = makeJsonFormat(format, JS_ENC_DEFAULT, -1);
- returning->typid = targettype;
- returning->typmod = -1;
- }
-
- return returning;
-}
-
-/*
- * Transform a JSON() expression.
- */
-static Node *
-transformJsonParseExpr(ParseState *pstate, JsonParseExpr *jsexpr)
-{
- JsonReturning *returning = transformJsonConstructorRet(pstate, jsexpr->output,
- "JSON()");
- Node *arg;
-
- if (jsexpr->unique_keys)
- {
- /*
- * Coerce string argument to text and then to json[b] in the executor
- * node with key uniqueness check.
- */
- JsonValueExpr *jve = jsexpr->expr;
- Oid arg_type;
-
- arg = transformJsonParseArg(pstate, (Node *) jve->raw_expr, jve->format,
- &arg_type);
-
- if (arg_type != TEXTOID)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("cannot use non-string types with WITH UNIQUE KEYS clause"),
- parser_errposition(pstate, jsexpr->location)));
- }
- else
- {
- /*
- * Coerce argument to target type using CAST for compatibility with PG
- * function-like CASTs.
- */
- arg = transformJsonValueExprExt(pstate, jsexpr->expr, JS_FORMAT_JSON,
- false, returning->typid);
- }
-
- return makeJsonConstructorExpr(pstate, JSCTOR_JSON_PARSE, list_make1(arg), NULL,
- returning, jsexpr->unique_keys, false,
- jsexpr->location);
-}
-
-/*
- * Transform a JSON_SCALAR() expression.
- */
-static Node *
-transformJsonScalarExpr(ParseState *pstate, JsonScalarExpr *jsexpr)
-{
- Node *arg = transformExprRecurse(pstate, (Node *) jsexpr->expr);
- JsonReturning *returning = transformJsonConstructorRet(pstate, jsexpr->output,
- "JSON_SCALAR()");
-
- if (exprType(arg) == UNKNOWNOID)
- arg = coerce_to_specific_type(pstate, arg, TEXTOID, "JSON_SCALAR");
-
- return makeJsonConstructorExpr(pstate, JSCTOR_JSON_SCALAR, list_make1(arg), NULL,
- returning, false, false, jsexpr->location);
-}
-
-/*
- * Transform a JSON_SERIALIZE() expression.
- */
-static Node *
-transformJsonSerializeExpr(ParseState *pstate, JsonSerializeExpr *expr)
-{
- Node *arg = transformJsonValueExpr(pstate, expr->expr);
- JsonReturning *returning;
-
- if (expr->output)
- {
- returning = transformJsonOutput(pstate, expr->output, true);
-
- if (returning->typid != BYTEAOID)
- {
- char typcategory;
- bool typispreferred;
-
- get_type_category_preferred(returning->typid, &typcategory,
- &typispreferred);
- if (typcategory != TYPCATEGORY_STRING)
- ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("cannot use RETURNING type %s in %s",
- format_type_be(returning->typid),
- "JSON_SERIALIZE()"),
- errhint("Try returning a string type or bytea.")));
- }
- }
- else
- {
- /* RETURNING TEXT FORMAT JSON is by default */
- returning = makeNode(JsonReturning);
- returning->format = makeJsonFormat(JS_FORMAT_JSON, JS_ENC_DEFAULT, -1);
- returning->typid = TEXTOID;
- returning->typmod = -1;
- }
-
- return makeJsonConstructorExpr(pstate, JSCTOR_JSON_SERIALIZE, list_make1(arg),
- NULL, returning, false, false, expr->location);
-}