summaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/sql_features.txt30
-rw-r--r--src/backend/commands/explain.c8
-rw-r--r--src/backend/executor/execExpr.c359
-rw-r--r--src/backend/executor/execExprInterp.c743
-rw-r--r--src/backend/executor/nodeTableFuncscan.c23
-rw-r--r--src/backend/jit/llvm/llvmjit_expr.c18
-rw-r--r--src/backend/jit/llvm/llvmjit_types.c3
-rw-r--r--src/backend/nodes/makefuncs.c122
-rw-r--r--src/backend/nodes/nodeFuncs.c486
-rw-r--r--src/backend/optimizer/path/costsize.c3
-rw-r--r--src/backend/optimizer/util/clauses.c78
-rw-r--r--src/backend/parser/Makefile1
-rw-r--r--src/backend/parser/gram.y1115
-rw-r--r--src/backend/parser/parse_clause.c12
-rw-r--r--src/backend/parser/parse_collate.c7
-rw-r--r--src/backend/parser/parse_expr.c1503
-rw-r--r--src/backend/parser/parse_jsontable.c732
-rw-r--r--src/backend/parser/parse_relation.c7
-rw-r--r--src/backend/parser/parse_target.c40
-rw-r--r--src/backend/parser/parser.c16
-rw-r--r--src/backend/utils/adt/format_type.c4
-rw-r--r--src/backend/utils/adt/formatting.c45
-rw-r--r--src/backend/utils/adt/json.c553
-rw-r--r--src/backend/utils/adt/jsonb.c352
-rw-r--r--src/backend/utils/adt/jsonb_util.c39
-rw-r--r--src/backend/utils/adt/jsonfuncs.c71
-rw-r--r--src/backend/utils/adt/jsonpath.c257
-rw-r--r--src/backend/utils/adt/jsonpath_exec.c844
-rw-r--r--src/backend/utils/adt/ruleutils.c719
-rw-r--r--src/backend/utils/misc/queryjumble.c72
30 files changed, 335 insertions, 7927 deletions
diff --git a/src/backend/catalog/sql_features.txt b/src/backend/catalog/sql_features.txt
index 0a9c7df4f4..da7c9c772e 100644
--- a/src/backend/catalog/sql_features.txt
+++ b/src/backend/catalog/sql_features.txt
@@ -527,20 +527,20 @@ T652 SQL-dynamic statements in SQL routines NO
T653 SQL-schema statements in external routines YES
T654 SQL-dynamic statements in external routines NO
T655 Cyclically dependent routines YES
-T811 Basic SQL/JSON constructor functions YES
-T812 SQL/JSON: JSON_OBJECTAGG YES
-T813 SQL/JSON: JSON_ARRAYAGG with ORDER BY YES
-T814 Colon in JSON_OBJECT or JSON_OBJECTAGG YES
-T821 Basic SQL/JSON query operators YES
-T822 SQL/JSON: IS JSON WITH UNIQUE KEYS predicate YES
-T823 SQL/JSON: PASSING clause YES
-T824 JSON_TABLE: specific PLAN clause YES
-T825 SQL/JSON: ON EMPTY and ON ERROR clauses YES
-T826 General value expression in ON ERROR or ON EMPTY clauses YES
-T827 JSON_TABLE: sibling NESTED COLUMNS clauses YES
-T828 JSON_QUERY YES
-T829 JSON_QUERY: array wrapper options YES
-T830 Enforcing unique keys in SQL/JSON constructor functions YES
+T811 Basic SQL/JSON constructor functions NO
+T812 SQL/JSON: JSON_OBJECTAGG NO
+T813 SQL/JSON: JSON_ARRAYAGG with ORDER BY NO
+T814 Colon in JSON_OBJECT or JSON_OBJECTAGG NO
+T821 Basic SQL/JSON query operators NO
+T822 SQL/JSON: IS JSON WITH UNIQUE KEYS predicate NO
+T823 SQL/JSON: PASSING clause NO
+T824 JSON_TABLE: specific PLAN clause NO
+T825 SQL/JSON: ON EMPTY and ON ERROR clauses NO
+T826 General value expression in ON ERROR or ON EMPTY clauses NO
+T827 JSON_TABLE: sibling NESTED COLUMNS clauses NO
+T828 JSON_QUERY NO
+T829 JSON_QUERY: array wrapper options NO
+T830 Enforcing unique keys in SQL/JSON constructor functions NO
T831 SQL/JSON path language: strict mode YES
T832 SQL/JSON path language: item method YES
T833 SQL/JSON path language: multiple subscripts YES
@@ -548,7 +548,7 @@ T834 SQL/JSON path language: wildcard member accessor YES
T835 SQL/JSON path language: filter expressions YES
T836 SQL/JSON path language: starts with predicate YES
T837 SQL/JSON path language: regex_like predicate YES
-T838 JSON_TABLE: PLAN DEFAULT clause YES
+T838 JSON_TABLE: PLAN DEFAULT clause NO
T839 Formatted cast of datetimes to/from character strings NO
M001 Datalinks NO
M002 Datalinks via SQL/CLI NO
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index e078456b19..053d2ca5ae 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -3851,13 +3851,7 @@ ExplainTargetRel(Plan *plan, Index rti, ExplainState *es)
break;
case T_TableFuncScan:
Assert(rte->rtekind == RTE_TABLEFUNC);
- if (rte->tablefunc)
- if (rte->tablefunc->functype == TFT_XMLTABLE)
- objectname = "xmltable";
- else /* Must be TFT_JSON_TABLE */
- objectname = "json_table";
- else
- objectname = NULL;
+ objectname = "xmltable";
objecttag = "Table Function Name";
break;
case T_ValuesScan:
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index d0a57c7aae..25a94bbaaa 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -47,9 +47,6 @@
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/datum.h"
-#include "utils/json.h"
-#include "utils/jsonb.h"
-#include "utils/jsonpath.h"
#include "utils/lsyscache.h"
#include "utils/typcache.h"
@@ -88,40 +85,6 @@ static void ExecBuildAggTransCall(ExprState *state, AggState *aggstate,
bool nullcheck);
-static ExprState *
-ExecInitExprInternal(Expr *node, PlanState *parent, ParamListInfo ext_params,
- Datum *caseval, bool *casenull)
-{
- ExprState *state;
- ExprEvalStep scratch = {0};
-
- /* Special case: NULL expression produces a NULL ExprState pointer */
- if (node == NULL)
- return NULL;
-
- /* Initialize ExprState with empty step list */
- state = makeNode(ExprState);
- state->expr = node;
- state->parent = parent;
- state->ext_params = ext_params;
- state->innermost_caseval = caseval;
- state->innermost_casenull = casenull;
-
- /* Insert EEOP_*_FETCHSOME steps as needed */
- ExecInitExprSlots(state, (Node *) node);
-
- /* Compile the expression proper */
- ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
-
- /* Finally, append a DONE step */
- scratch.opcode = EEOP_DONE;
- ExprEvalPushStep(state, &scratch);
-
- ExecReadyExpr(state);
-
- return state;
-}
-
/*
* ExecInitExpr: prepare an expression tree for execution
*
@@ -159,7 +122,32 @@ ExecInitExprInternal(Expr *node, PlanState *parent, ParamListInfo ext_params,
ExprState *
ExecInitExpr(Expr *node, PlanState *parent)
{
- return ExecInitExprInternal(node, parent, NULL, NULL, NULL);
+ ExprState *state;
+ ExprEvalStep scratch = {0};
+
+ /* Special case: NULL expression produces a NULL ExprState pointer */
+ if (node == NULL)
+ return NULL;
+
+ /* Initialize ExprState with empty step list */
+ state = makeNode(ExprState);
+ state->expr = node;
+ state->parent = parent;
+ state->ext_params = NULL;
+
+ /* Insert EEOP_*_FETCHSOME steps as needed */
+ ExecInitExprSlots(state, (Node *) node);
+
+ /* Compile the expression proper */
+ ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
+
+ /* Finally, append a DONE step */
+ scratch.opcode = EEOP_DONE;
+ ExprEvalPushStep(state, &scratch);
+
+ ExecReadyExpr(state);
+
+ return state;
}
/*
@@ -171,20 +159,32 @@ ExecInitExpr(Expr *node, PlanState *parent)
ExprState *
ExecInitExprWithParams(Expr *node, ParamListInfo ext_params)
{
- return ExecInitExprInternal(node, NULL, ext_params, NULL, NULL);
-}
+ ExprState *state;
+ ExprEvalStep scratch = {0};
-/*
- * ExecInitExprWithCaseValue: prepare an expression tree for execution
- *
- * This is the same as ExecInitExpr, except that a pointer to the value for
- * CasTestExpr is passed here.
- */
-ExprState *
-ExecInitExprWithCaseValue(Expr *node, PlanState *parent,
- Datum *caseval, bool *casenull)
-{
- return ExecInitExprInternal(node, parent, NULL, caseval, casenull);
+ /* Special case: NULL expression produces a NULL ExprState pointer */
+ if (node == NULL)
+ return NULL;
+
+ /* Initialize ExprState with empty step list */
+ state = makeNode(ExprState);
+ state->expr = node;
+ state->parent = NULL;
+ state->ext_params = ext_params;
+
+ /* Insert EEOP_*_FETCHSOME steps as needed */
+ ExecInitExprSlots(state, (Node *) node);
+
+ /* Compile the expression proper */
+ ExecInitExprRec(node, state, &state->resvalue, &state->resnull);
+
+ /* Finally, append a DONE step */
+ scratch.opcode = EEOP_DONE;
+ ExprEvalPushStep(state, &scratch);
+
+ ExecReadyExpr(state);
+
+ return state;
}
/*
@@ -2411,263 +2411,6 @@ ExecInitExprRec(Expr *node, ExprState *state,
break;
}
- case T_JsonValueExpr:
- {
- JsonValueExpr *jve = (JsonValueExpr *) node;
-
- ExecInitExprRec(jve->raw_expr, state, resv, resnull);
-
- if (jve->formatted_expr)
- {
- Datum *innermost_caseval = state->innermost_caseval;
- bool *innermost_isnull = state->innermost_casenull;
-
- state->innermost_caseval = resv;
- state->innermost_casenull = resnull;
-
- ExecInitExprRec(jve->formatted_expr, state, resv, resnull);
-
- state->innermost_caseval = innermost_caseval;
- state->innermost_casenull = innermost_isnull;
- }
- break;
- }
-
- case T_JsonConstructorExpr:
- {
- JsonConstructorExpr *ctor = (JsonConstructorExpr *) node;
- List *args = ctor->args;
- ListCell *lc;
- int nargs = list_length(args);
- int argno = 0;
-
- if (ctor->func)
- {
- ExecInitExprRec(ctor->func, state, resv, resnull);
- }
- else if ((ctor->type == JSCTOR_JSON_PARSE && !ctor->unique) ||
- ctor->type == JSCTOR_JSON_SERIALIZE)
- {
- /* Use the value of the first argument as a result */
- ExecInitExprRec(linitial(args), state, resv, resnull);
- }
- else
- {
- JsonConstructorExprState *jcstate;
-
- jcstate = palloc0(sizeof(JsonConstructorExprState));
-
- scratch.opcode = EEOP_JSON_CONSTRUCTOR;
- scratch.d.json_constructor.jcstate = jcstate;
-
- jcstate->constructor = ctor;
- jcstate->arg_values = palloc(sizeof(Datum) * nargs);
- jcstate->arg_nulls = palloc(sizeof(bool) * nargs);
- jcstate->arg_types = palloc(sizeof(Oid) * nargs);
- jcstate->nargs = nargs;
-
- foreach(lc, args)
- {
- Expr *arg = (Expr *) lfirst(lc);
-
- jcstate->arg_types[argno] = exprType((Node *) arg);
-
- if (IsA(arg, Const))
- {
- /* Don't evaluate const arguments every round */
- Const *con = (Const *) arg;
-
- jcstate->arg_values[argno] = con->constvalue;
- jcstate->arg_nulls[argno] = con->constisnull;
- }
- else
- {
- ExecInitExprRec(arg, state,
- &jcstate->arg_values[argno],
- &jcstate->arg_nulls[argno]);
- }
- argno++;
- }
-
- /* prepare type cache for datum_to_json[b]() */
- if (ctor->type == JSCTOR_JSON_SCALAR)
- {
- bool is_jsonb =
- ctor->returning->format->format_type == JS_FORMAT_JSONB;
-
- jcstate->arg_type_cache =
- palloc(sizeof(*jcstate->arg_type_cache) * nargs);
-
- for (int i = 0; i < nargs; i++)
- {
- int category;
- Oid outfuncid;
- Oid typid = jcstate->arg_types[i];
-
- if (is_jsonb)
- {
- JsonbTypeCategory jbcat;
-
- jsonb_categorize_type(typid, &jbcat, &outfuncid);
-
- category = (int) jbcat;
- }
- else
- {
- JsonTypeCategory jscat;
-
- json_categorize_type(typid, &jscat, &outfuncid);
-
- category = (int) jscat;
- }
-
- jcstate->arg_type_cache[i].outfuncid = outfuncid;
- jcstate->arg_type_cache[i].category = category;
- }
- }
-
- ExprEvalPushStep(state, &scratch);
- }
-
- if (ctor->coercion)
- {
- Datum *innermost_caseval = state->innermost_caseval;
- bool *innermost_isnull = state->innermost_casenull;
-
- state->innermost_caseval = resv;
- state->innermost_casenull = resnull;
-
- ExecInitExprRec(ctor->coercion, state, resv, resnull);
-
- state->innermost_caseval = innermost_caseval;
- state->innermost_casenull = innermost_isnull;
- }
- }
- break;
-
- case T_JsonIsPredicate:
- {
- JsonIsPredicate *pred = (JsonIsPredicate *) node;
-
- ExecInitExprRec((Expr *) pred->expr, state, resv, resnull);
-
- scratch.opcode = EEOP_IS_JSON;
- scratch.d.is_json.pred = pred;
-
- ExprEvalPushStep(state, &scratch);
- break;
- }
-
- case T_JsonExpr:
- {
- JsonExpr *jexpr = castNode(JsonExpr, node);
- JsonExprState *jsestate = palloc0(sizeof(JsonExprState));
- ListCell *argexprlc;
- ListCell *argnamelc;
-
- scratch.opcode = EEOP_JSONEXPR;
- scratch.d.jsonexpr.jsestate = jsestate;
-
- jsestate->jsexpr = jexpr;
-
- jsestate->formatted_expr =
- palloc(sizeof(*jsestate->formatted_expr));
-
- ExecInitExprRec((Expr *) jexpr->formatted_expr, state,
- &jsestate->formatted_expr->value,
- &jsestate->formatted_expr->isnull);
-
- jsestate->pathspec =
- palloc(sizeof(*jsestate->pathspec));
-
- ExecInitExprRec((Expr *) jexpr->path_spec, state,
- &jsestate->pathspec->value,
- &jsestate->pathspec->isnull);
-
- jsestate->res_expr =
- palloc(sizeof(*jsestate->res_expr));
-
- jsestate->result_expr = jexpr->result_coercion
- ? ExecInitExprWithCaseValue((Expr *) jexpr->result_coercion->expr,
- state->parent,
- &jsestate->res_expr->value,
- &jsestate->res_expr->isnull)
- : NULL;
-
- jsestate->default_on_empty = !jexpr->on_empty ? NULL :
- ExecInitExpr((Expr *) jexpr->on_empty->default_expr,
- state->parent);
-
- jsestate->default_on_error =
- ExecInitExpr((Expr *) jexpr->on_error->default_expr,
- state->parent);
-
- if (jexpr->omit_quotes ||
- (jexpr->result_coercion && jexpr->result_coercion->via_io))
- {
- Oid typinput;
-
- /* lookup the result type's input function */
- getTypeInputInfo(jexpr->returning->typid, &typinput,
- &jsestate->input.typioparam);
- fmgr_info(typinput, &jsestate->input.func);
- }
-
- jsestate->args = NIL;
-
- forboth(argexprlc, jexpr->passing_values,
- argnamelc, jexpr->passing_names)
- {
- Expr *argexpr = (Expr *) lfirst(argexprlc);
- String *argname = lfirst_node(String, argnamelc);
- JsonPathVariableEvalContext *var = palloc(sizeof(*var));
-
- var->name = pstrdup(argname->sval);
- var->typid = exprType((Node *) argexpr);
- var->typmod = exprTypmod((Node *) argexpr);
- var->estate = ExecInitExpr(argexpr, state->parent);
- var->econtext = NULL;
- var->mcxt = NULL;
- var->evaluated = false;
- var->value = (Datum) 0;
- var->isnull = true;
-
- jsestate->args =
- lappend(jsestate->args, var);
- }
-
- jsestate->cache = NULL;
-
- if (jexpr->coercions)
- {
- JsonCoercion **coercion;
- struct JsonCoercionState *cstate;
- Datum *caseval;
- bool *casenull;
-
- jsestate->coercion_expr =
- palloc(sizeof(*jsestate->coercion_expr));
-
- caseval = &jsestate->coercion_expr->value;
- casenull = &jsestate->coercion_expr->isnull;
-
- for (cstate = &jsestate->coercions.null,
- coercion = &jexpr->coercions->null;
- coercion <= &jexpr->coercions->composite;
- coercion++, cstate++)
- {
- cstate->coercion = *coercion;
- cstate->estate = *coercion ?
- ExecInitExprWithCaseValue((Expr *) (*coercion)->expr,
- state->parent,
- caseval, casenull) : NULL;
- }
- }
-
- ExprEvalPushStep(state, &scratch);
- break;
- }
-
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(node));
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 636794ca6f..9b9bbf00a9 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -57,31 +57,22 @@
#include "postgres.h"
#include "access/heaptoast.h"
-#include "access/xact.h"
-#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
#include "commands/sequence.h"
#include "executor/execExpr.h"
#include "executor/nodeSubplan.h"
#include "funcapi.h"
#include "miscadmin.h"
-#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
-#include "parser/parse_expr.h"
#include "pgstat.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/date.h"
#include "utils/datum.h"
#include "utils/expandedrecord.h"
-#include "utils/json.h"
-#include "utils/jsonb.h"
-#include "utils/jsonfuncs.h"
-#include "utils/jsonpath.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
-#include "utils/resowner.h"
#include "utils/timestamp.h"
#include "utils/typcache.h"
#include "utils/xml.h"
@@ -488,9 +479,6 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
&&CASE_EEOP_GROUPING_FUNC,
&&CASE_EEOP_WINDOW_FUNC,
&&CASE_EEOP_SUBPLAN,
- &&CASE_EEOP_JSON_CONSTRUCTOR,
- &&CASE_EEOP_IS_JSON,
- &&CASE_EEOP_JSONEXPR,
&&CASE_EEOP_AGG_STRICT_DESERIALIZE,
&&CASE_EEOP_AGG_DESERIALIZE,
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
@@ -1824,27 +1812,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
{
/* too complex for an inline implementation */
ExecEvalAggOrderedTransTuple(state, op, econtext);
- EEO_NEXT();
- }
-
- EEO_CASE(EEOP_JSON_CONSTRUCTOR)
- {
- /* too complex for an inline implementation */
- ExecEvalJsonConstructor(state, op, econtext);
- EEO_NEXT();
- }
-
- EEO_CASE(EEOP_IS_JSON)
- {
- /* too complex for an inline implementation */
- ExecEvalJsonIsPredicate(state, op);
- EEO_NEXT();
- }
- EEO_CASE(EEOP_JSONEXPR)
- {
- /* too complex for an inline implementation */
- ExecEvalJson(state, op, econtext);
EEO_NEXT();
}
@@ -3972,91 +3940,6 @@ ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
}
}
-void
-ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op)
-{
- JsonIsPredicate *pred = op->d.is_json.pred;
- Datum js = *op->resvalue;
- Oid exprtype;
- bool res;
-
- if (*op->resnull)
- {
- *op->resvalue = BoolGetDatum(false);
- return;
- }
-
- exprtype = exprType(pred->expr);
-
- if (exprtype == TEXTOID || exprtype == JSONOID)
- {
- text *json = DatumGetTextP(js);
-
- if (pred->item_type == JS_TYPE_ANY)
- res = true;
- else
- {
- switch (json_get_first_token(json, false))
- {
- case JSON_TOKEN_OBJECT_START:
- res = pred->item_type == JS_TYPE_OBJECT;
- break;
- case JSON_TOKEN_ARRAY_START:
- res = pred->item_type == JS_TYPE_ARRAY;
- break;
- case JSON_TOKEN_STRING:
- case JSON_TOKEN_NUMBER:
- case JSON_TOKEN_TRUE:
- case JSON_TOKEN_FALSE:
- case JSON_TOKEN_NULL:
- res = pred->item_type == JS_TYPE_SCALAR;
- break;
- default:
- res = false;
- break;
- }
- }
-
- /*
- * Do full parsing pass only for uniqueness check or for JSON text
- * validation.
- */
- if (res && (pred->unique_keys || exprtype == TEXTOID))
- res = json_validate(json, pred->unique_keys, false);
- }
- else if (exprtype == JSONBOID)
- {
- if (pred->item_type == JS_TYPE_ANY)
- res = true;
- else
- {
- Jsonb *jb = DatumGetJsonbP(js);
-
- switch (pred->item_type)
- {
- case JS_TYPE_OBJECT:
- res = JB_ROOT_IS_OBJECT(jb);
- break;
- case JS_TYPE_ARRAY:
- res = JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb);
- break;
- case JS_TYPE_SCALAR:
- res = JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb);
- break;
- default:
- res = false;
- break;
- }
- }
-
- /* Key uniqueness check is redundant for jsonb */
- }
- else
- res = false;
-
- *op->resvalue = BoolGetDatum(res);
-}
-
/*
* ExecEvalGroupingFunc
*
@@ -4619,629 +4502,3 @@ ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
MemoryContextSwitchTo(oldContext);
}
-
-/*
- * Evaluate a JSON constructor expression.
- */
-void
-ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
- ExprContext *econtext)
-{
- Datum res;
- JsonConstructorExprState *jcstate = op->d.json_constructor.jcstate;
- JsonConstructorExpr *ctor = jcstate->constructor;
- bool is_jsonb = ctor->returning->format->format_type == JS_FORMAT_JSONB;
- bool isnull = false;
-
- if (ctor->type == JSCTOR_JSON_ARRAY)
- res = (is_jsonb ?
- jsonb_build_array_worker :
- json_build_array_worker) (jcstate->nargs,
- jcstate->arg_values,
- jcstate->arg_nulls,
- jcstate->arg_types,
- ctor->absent_on_null);
- else if (ctor->type == JSCTOR_JSON_OBJECT)
- res = (is_jsonb ?
- jsonb_build_object_worker :
- json_build_object_worker) (jcstate->nargs,
- jcstate->arg_values,
- jcstate->arg_nulls,
- jcstate->arg_types,
- ctor->absent_on_null,
- ctor->unique);
- else if (ctor->type == JSCTOR_JSON_SCALAR)
- {
- if (jcstate->arg_nulls[0])
- {
- res = (Datum) 0;
- isnull = true;
- }
- else
- {
- Datum value = jcstate->arg_values[0];
- int category = jcstate->arg_type_cache[0].category;
- Oid outfuncid = jcstate->arg_type_cache[0].outfuncid;
-
- if (is_jsonb)
- res = to_jsonb_worker(value, category, outfuncid);
- else
- res = to_json_worker(value, category, outfuncid);
- }
- }
- else if (ctor->type == JSCTOR_JSON_PARSE)
- {
- if (jcstate->arg_nulls[0])
- {
- res = (Datum) 0;
- isnull = true;
- }
- else
- {
- Datum value = jcstate->arg_values[0];
- text *js = DatumGetTextP(value);
-
- if (is_jsonb)
- res = jsonb_from_text(js, true);
- else
- {
- (void) json_validate(js, true, true);
- res = value;
- }
- }
- }
- else
- {
- res = (Datum) 0;
- elog(ERROR, "invalid JsonConstructorExpr type %d", ctor->type);
- }
-
- *op->resvalue = res;
- *op->resnull = isnull;
-}
-
-/*
- * Evaluate a JSON error/empty behavior result.
- */
-static Datum
-ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
- ExprState *default_estate, bool *is_null)
-{
- *is_null = false;
-
- switch (behavior->btype)
- {
- case JSON_BEHAVIOR_EMPTY_ARRAY:
- return JsonbPGetDatum(JsonbMakeEmptyArray());
-
- case JSON_BEHAVIOR_EMPTY_OBJECT:
- return JsonbPGetDatum(JsonbMakeEmptyObject());
-
- case JSON_BEHAVIOR_TRUE:
- return BoolGetDatum(true);
-
- case JSON_BEHAVIOR_FALSE:
- return BoolGetDatum(false);
-
- case JSON_BEHAVIOR_NULL:
- case JSON_BEHAVIOR_UNKNOWN:
- case JSON_BEHAVIOR_EMPTY:
- *is_null = true;
- return (Datum) 0;
-
- case JSON_BEHAVIOR_DEFAULT:
- return ExecEvalExpr(default_estate, econtext, is_null);
-
- default:
- elog(ERROR, "unrecognized SQL/JSON behavior %d", behavior->btype);
- return (Datum) 0;
- }
-}
-
-/*
- * Evaluate a coercion of a JSON item to the target type.
- */
-static Datum
-ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
- Datum res, bool *isNull, void *p, bool *error)
-{
- ExprState *estate = p;
- JsonExprState *jsestate;
-
- if (estate) /* coerce using specified expression */
- return ExecEvalExpr(estate, econtext, isNull);
-
- jsestate = op->d.jsonexpr.jsestate;
-
- if (jsestate->jsexpr->op != JSON_EXISTS_OP)
- {
- JsonCoercion *coercion = jsestate->jsexpr->result_coercion;
- JsonExpr *jexpr = jsestate->jsexpr;
- Jsonb *jb = *isNull ? NULL : DatumGetJsonbP(res);
-
- if ((coercion && coercion->via_io) ||
- (jexpr->omit_quotes && !*isNull &&
- JB_ROOT_IS_SCALAR(jb)))
- {
- /* strip quotes and call typinput function */
- char *str = *isNull ? NULL : JsonbUnquote(jb);
-
- return InputFunctionCall(&jsestate->input.func, str,
- jsestate->input.typioparam,
- jexpr->returning->typmod);
- }
- else if (coercion && coercion->via_populate)
- return json_populate_type(res, JSONBOID,
- jexpr->returning->typid,
- jexpr->returning->typmod,
- &jsestate->cache,
- econtext->ecxt_per_query_memory,
- isNull);
- }
-
- if (jsestate->result_expr)
- {
- jsestate->res_expr->value = res;
- jsestate->res_expr->isnull = *isNull;
-
- res = ExecEvalExpr(jsestate->result_expr, econtext, isNull);
- }
-
- return res;
-}
-
-/*
- * Evaluate a JSON path variable caching computed value.
- */
-int
-EvalJsonPathVar(void *cxt, char *varName, int varNameLen,
- JsonbValue *val, JsonbValue *baseObject)
-{
- JsonPathVariableEvalContext *var = NULL;
- List *vars = cxt;
- ListCell *lc;
- int id = 1;
-
- if (!varName)
- return list_length(vars);
-
- foreach(lc, vars)
- {
- var = lfirst(lc);
-
- if (!strncmp(var->name, varName, varNameLen))
- break;
-
- var = NULL;
- id++;
- }
-
- if (!var)
- return -1;
-
- if (!var->evaluated)
- {
- MemoryContext oldcxt = var->mcxt ?
- MemoryContextSwitchTo(var->mcxt) : NULL;
-
- var->value = ExecEvalExpr(var->estate, var->econtext, &var->isnull);
- var->evaluated = true;
-
- if (oldcxt)
- MemoryContextSwitchTo(oldcxt);
- }
-
- if (var->isnull)
- {
- val->type = jbvNull;
- return 0;
- }
-
- JsonItemFromDatum(var->value, var->typid, var->typmod, val);
-
- *baseObject = *val;
- return id;
-}
-
-/*
- * Prepare SQL/JSON item coercion to the output type. Returned a datum of the
- * corresponding SQL type and a pointer to the coercion state.
- */
-Datum
-ExecPrepareJsonItemCoercion(JsonbValue *item,
- JsonReturning *returning,
- struct JsonCoercionsState *coercions,
- struct JsonCoercionState **pcoercion)
-{
- struct JsonCoercionState *coercion;
- Datum res;
- JsonbValue buf;
-
- if (item->type == jbvBinary &&
- JsonContainerIsScalar(item->val.binary.data))
- {
- bool res PG_USED_FOR_ASSERTS_ONLY;
-
- res = JsonbExtractScalar(item->val.binary.data, &buf);
- item = &buf;
- Assert(res);
- }
-
- /* get coercion state reference and datum of the corresponding SQL type */
- switch (item->type)
- {
- case jbvNull:
- coercion = &coercions->null;
- res = (Datum) 0;
- break;
-
- case jbvString:
- coercion = &coercions->string;
- res = PointerGetDatum(cstring_to_text_with_len(item->val.string.val,
- item->val.string.len));
- break;
-
- case jbvNumeric:
- coercion = &coercions->numeric;
- res = NumericGetDatum(item->val.numeric);
- break;
-
- case jbvBool:
- coercion = &coercions->boolean;
- res = BoolGetDatum(item->val.boolean);
- break;
-
- case jbvDatetime:
- res = item->val.datetime.value;
- switch (item->val.datetime.typid)
- {
- case DATEOID:
- coercion = &coercions->date;
- break;
- case TIMEOID:
- coercion = &coercions->time;
- break;
- case TIMETZOID:
- coercion = &coercions->timetz;
- break;
- case TIMESTAMPOID:
- coercion = &coercions->timestamp;
- break;
- case TIMESTAMPTZOID:
- coercion = &coercions->timestamptz;
- break;
- default:
- elog(ERROR, "unexpected jsonb datetime type oid %u",
- item->val.datetime.typid);
- return (Datum) 0;
- }
- break;
-
- case jbvArray:
- case jbvObject:
- case jbvBinary:
- coercion = &coercions->composite;
- res = JsonbPGetDatum(JsonbValueToJsonb(item));
- break;
-
- default:
- elog(ERROR, "unexpected jsonb value type %d", item->type);
- return (Datum) 0;
- }
-
- *pcoercion = coercion;
-
- return res;
-}
-
-typedef Datum (*JsonFunc) (ExprEvalStep *op, ExprContext *econtext,
- Datum item, bool *resnull, void *p, bool *error);
-
-static Datum
-ExecEvalJsonExprSubtrans(JsonFunc func, ExprEvalStep *op,
- ExprContext *econtext,
- Datum res, bool *resnull,
- void *p, bool *error, bool subtrans)
-{
- MemoryContext oldcontext;
- ResourceOwner oldowner;
-
- if (!subtrans)
- /* No need to use subtransactions. */
- return func(op, econtext, res, resnull, p, error);
-
- /*
- * We should catch exceptions of category ERRCODE_DATA_EXCEPTION and
- * execute the corresponding ON ERROR behavior then.
- */
- oldcontext = CurrentMemoryContext;
- oldowner = CurrentResourceOwner;
-
- Assert(error);
-
- BeginInternalSubTransaction(NULL);
- /* Want to execute expressions inside function's memory context */
- MemoryContextSwitchTo(oldcontext);
-
- PG_TRY();
- {
- res = func(op, econtext, res, resnull, p, error);
-
- /* Commit the inner transaction, return to outer xact context */
- ReleaseCurrentSubTransaction();
- MemoryContextSwitchTo(oldcontext);
- CurrentResourceOwner = oldowner;
- }
- PG_CATCH();
- {
- ErrorData *edata;
- int ecategory;
-
- /* Save error info in oldcontext */
- MemoryContextSwitchTo(oldcontext);
- edata = CopyErrorData();
- FlushErrorState();
-
- /* Abort the inner transaction */
- RollbackAndReleaseCurrentSubTransaction();
- MemoryContextSwitchTo(oldcontext);
- CurrentResourceOwner = oldowner;
-
- ecategory = ERRCODE_TO_CATEGORY(edata->sqlerrcode);
-
- if (ecategory != ERRCODE_DATA_EXCEPTION && /* jsonpath and other data
- * errors */
- ecategory != ERRCODE_INTEGRITY_CONSTRAINT_VIOLATION) /* domain errors */
- ReThrowError(edata);
-
- res = (Datum) 0;
- *error = true;
- }
- PG_END_TRY();
-
- return res;
-}
-
-
-typedef struct
-{
- JsonPath *path;
- bool *error;
- bool coercionInSubtrans;
-} ExecEvalJsonExprContext;
-
-static Datum
-ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
- Datum item, bool *resnull, void *pcxt,
- bool *error)
-{
- ExecEvalJsonExprContext *cxt = pcxt;
- JsonPath *path = cxt->path;
- JsonExprState *jsestate = op->d.jsonexpr.jsestate;
- JsonExpr *jexpr = jsestate->jsexpr;
- ExprState *estate = NULL;
- bool empty = false;
- Datum res = (Datum) 0;
-
- switch (jexpr->op)
- {
- case JSON_QUERY_OP:
- res = JsonPathQuery(item, path, jexpr->wrapper, &empty, error,
- jsestate->args);
- if (error && *error)
- {
- *resnull = true;
- return (Datum) 0;
- }
- *resnull = !DatumGetPointer(res);
- break;
-
- case JSON_VALUE_OP:
- {
- struct JsonCoercionState *jcstate;
- JsonbValue *jbv = JsonPathValue(item, path, &empty, error,
- jsestate->args);
-
- if (error && *error)
- return (Datum) 0;
-
- if (!jbv) /* NULL or empty */
- break;
-
- Assert(!empty);
-
- *resnull = false;
-
- /* coerce scalar item to the output type */
- if (jexpr->returning->typid == JSONOID ||
- jexpr->returning->typid == JSONBOID)
- {
- /* Use result coercion from json[b] to the output type */
- res = JsonbPGetDatum(JsonbValueToJsonb(jbv));
- break;
- }
-
- /* Use coercion from SQL/JSON item type to the output type */
- res = ExecPrepareJsonItemCoercion(jbv,
- jsestate->jsexpr->returning,
- &jsestate->coercions,
- &jcstate);
-
- if (jcstate->coercion &&
- (jcstate->coercion->via_io ||
- jcstate->coercion->via_populate))
- {
- if (error)
- {
- *error = true;
- return (Datum) 0;
- }
-
- /*
- * Coercion via I/O means here that the cast to the target
- * type simply does not exist.
- */
- ereport(ERROR,
- (errcode(ERRCODE_SQL_JSON_ITEM_CANNOT_BE_CAST_TO_TARGET_TYPE),
- errmsg("SQL/JSON item cannot be cast to target type")));
- }
- else if (!jcstate->estate)
- return res; /* no coercion */
-
- /* coerce using specific expression */
- estate = jcstate->estate;
- jsestate->coercion_expr->value = res;
- jsestate->coercion_expr->isnull = *resnull;
- break;
- }
-
- case JSON_EXISTS_OP:
- {
- bool exists = JsonPathExists(item, path,
- jsestate->args,
- error);
-
- *resnull = error && *error;
- res = BoolGetDatum(exists);
-
- if (!jsestate->result_expr)
- return res;
-
- /* coerce using result expression */
- estate = jsestate->result_expr;
- jsestate->res_expr->value = res;
- jsestate->res_expr->isnull = *resnull;
- break;
- }
-
- case JSON_TABLE_OP:
- *resnull = false;
- return item;
-
- default:
- elog(ERROR, "unrecognized SQL/JSON expression op %d", jexpr->op);
- return (Datum) 0;
- }
-
- if (empty)
- {
- Assert(jexpr->on_empty); /* it is not JSON_EXISTS */
-
- if (jexpr->on_empty->btype == JSON_BEHAVIOR_ERROR)
- {
- if (error)
- {
- *error = true;
- return (Datum) 0;
- }
-
- ereport(ERROR,
- (errcode(ERRCODE_NO_SQL_JSON_ITEM),
- errmsg("no SQL/JSON item")));
- }
-
- if (jexpr->on_empty->btype == JSON_BEHAVIOR_DEFAULT)
-
- /*
- * Execute DEFAULT expression as a coercion expression, because
- * its result is already coerced to the target type.
- */
- estate = jsestate->default_on_empty;
- else
- /* Execute ON EMPTY behavior */
- res = ExecEvalJsonBehavior(econtext, jexpr->on_empty,
- jsestate->default_on_empty,
- resnull);
- }
-
- return ExecEvalJsonExprSubtrans(ExecEvalJsonExprCoercion, op, econtext,
- res, resnull, estate, error,
- cxt->coercionInSubtrans);
-}
-
-bool
-ExecEvalJsonNeedsSubTransaction(JsonExpr *jsexpr,
- struct JsonCoercionsState *coercions)
-{
- if (jsexpr->on_error->btype == JSON_BEHAVIOR_ERROR)
- return false;
-
- if (jsexpr->op == JSON_EXISTS_OP && !jsexpr->result_coercion)
- return false;
-
- if (!coercions)
- return true;
-
- return false;
-}
-
-/* ----------------------------------------------------------------
- * ExecEvalJson
- * ----------------------------------------------------------------
- */
-void
-ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
-{
- ExecEvalJsonExprContext cxt;
- JsonExprState *jsestate = op->d.jsonexpr.jsestate;
- JsonExpr *jexpr = jsestate->jsexpr;
- Datum item;
- Datum res = (Datum) 0;
- JsonPath *path;
- ListCell *lc;
- bool error = false;
- bool needSubtrans;
- bool throwErrors = jexpr->on_error->btype == JSON_BEHAVIOR_ERROR;
-
- *op->resnull = true; /* until we get a result */
- *op->resvalue = (Datum) 0;
-
- if (jsestate->formatted_expr->isnull || jsestate->pathspec->isnull)
- {
- /* execute domain checks for NULLs */
- (void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
- NULL, NULL);
-
- Assert(*op->resnull);
- return;
- }
-
- item = jsestate->formatted_expr->value;
- path = DatumGetJsonPathP(jsestate->pathspec->value);
-
- /* reset JSON path variable contexts */
- foreach(lc, jsestate->args)
- {
- JsonPathVariableEvalContext *var = lfirst(lc);
-
- var->econtext = econtext;
- var->evaluated = false;
- }
-
- needSubtrans = ExecEvalJsonNeedsSubTransaction(jexpr, &jsestate->coercions);
-
- cxt.path = path;
- cxt.error = throwErrors ? NULL : &error;
- cxt.coercionInSubtrans = !needSubtrans && !throwErrors;
- Assert(!needSubtrans || cxt.error);
-
- res = ExecEvalJsonExprSubtrans(ExecEvalJsonExpr, op, econtext, item,
- op->resnull, &cxt, cxt.error,
- needSubtrans);
-
- if (error)
- {
- /* Execute ON ERROR behavior */
- res = ExecEvalJsonBehavior(econtext, jexpr->on_error,
- jsestate->default_on_error,
- op->resnull);
-
- /* result is already coerced in DEFAULT behavior case */
- if (jexpr->on_error->btype != JSON_BEHAVIOR_DEFAULT)
- res = ExecEvalJsonExprCoercion(op, econtext, res,
- op->resnull,
- NULL, NULL);
- }
-
- *op->resvalue = res;
-}
diff --git a/src/backend/executor/nodeTableFuncscan.c b/src/backend/executor/nodeTableFuncscan.c
index 691c3e28ce..0db4ed0c2f 100644
--- a/src/backend/executor/nodeTableFuncscan.c
+++ b/src/backend/executor/nodeTableFuncscan.c
@@ -28,7 +28,6 @@
#include "miscadmin.h"
#include "nodes/execnodes.h"
#include "utils/builtins.h"
-#include "utils/jsonpath.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/xml.h"
@@ -162,9 +161,8 @@ ExecInitTableFuncScan(TableFuncScan *node, EState *estate, int eflags)
scanstate->ss.ps.qual =
ExecInitQual(node->scan.plan.qual, &scanstate->ss.ps);
- /* Only XMLTABLE and JSON_TABLE are supported currently */
- scanstate->routine =
- tf->functype == TFT_XMLTABLE ? &XmlTableRoutine : &JsonbTableRoutine;
+ /* Only XMLTABLE is supported currently */
+ scanstate->routine = &XmlTableRoutine;
scanstate->perTableCxt =
AllocSetContextCreate(CurrentMemoryContext,
@@ -383,17 +381,14 @@ tfuncInitialize(TableFuncScanState *tstate, ExprContext *econtext, Datum doc)
routine->SetNamespace(tstate, ns_name, ns_uri);
}
- if (routine->SetRowFilter)
- {
- /* Install the row filter expression into the table builder context */
- value = ExecEvalExpr(tstate->rowexpr, econtext, &isnull);
- if (isnull)
- ereport(ERROR,
- (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
- errmsg("row filter expression must not be null")));
+ /* Install the row filter expression into the table builder context */
+ value = ExecEvalExpr(tstate->rowexpr, econtext, &isnull);
+ if (isnull)
+ ereport(ERROR,
+ (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+ errmsg("row filter expression must not be null")));
- routine->SetRowFilter(tstate, TextDatumGetCString(value));
- }
+ routine->SetRowFilter(tstate, TextDatumGetCString(value));
/*
* Install the column filter expressions into the table builder context.
diff --git a/src/backend/jit/llvm/llvmjit_expr.c b/src/backend/jit/llvm/llvmjit_expr.c
index bd3965143d..95d0807bdd 100644
--- a/src/backend/jit/llvm/llvmjit_expr.c
+++ b/src/backend/jit/llvm/llvmjit_expr.c
@@ -2395,24 +2395,6 @@ llvm_compile_expr(ExprState *state)
LLVMBuildBr(b, opblocks[opno + 1]);
break;
- case EEOP_JSON_CONSTRUCTOR:
- build_EvalXFunc(b, mod, "ExecEvalJsonConstructor",
- v_state, op, v_econtext);
- LLVMBuildBr(b, opblocks[opno + 1]);
- break;
-
- case EEOP_IS_JSON:
- build_EvalXFunc(b, mod, "ExecEvalJsonIsPredicate",
- v_state, op);
- LLVMBuildBr(b, opblocks[opno + 1]);
- break;
-
- case EEOP_JSONEXPR:
- build_EvalXFunc(b, mod, "ExecEvalJson",
- v_state, op, v_econtext);
- LLVMBuildBr(b, opblocks[opno + 1]);
- break;
-
case EEOP_LAST:
Assert(false);
break;
diff --git a/src/backend/jit/llvm/llvmjit_types.c b/src/backend/jit/llvm/llvmjit_types.c
index 373471ad27..90ac6b83b5 100644
--- a/src/backend/jit/llvm/llvmjit_types.c
+++ b/src/backend/jit/llvm/llvmjit_types.c
@@ -133,9 +133,6 @@ void *referenced_functions[] =
ExecEvalSysVar,
ExecEvalWholeRowVar,
ExecEvalXmlExpr,
- ExecEvalJsonConstructor,
- ExecEvalJsonIsPredicate,
- ExecEvalJson,
MakeExpandedObjectReadOnlyInternal,
slot_getmissingattrs,
slot_getsomeattrs_int,
diff --git a/src/backend/nodes/makefuncs.c b/src/backend/nodes/makefuncs.c
index 28288dcfc1..c85d8fe975 100644
--- a/src/backend/nodes/makefuncs.c
+++ b/src/backend/nodes/makefuncs.c
@@ -19,7 +19,6 @@
#include "catalog/pg_type.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
-#include "utils/errcodes.h"
#include "utils/lsyscache.h"
@@ -819,124 +818,3 @@ makeVacuumRelation(RangeVar *relation, Oid oid, List *va_cols)
v->va_cols = va_cols;
return v;
}
-
-/*
- * makeJsonFormat -
- * creates a JsonFormat node
- */
-JsonFormat *
-makeJsonFormat(JsonFormatType type, JsonEncoding encoding, int location)
-{
- JsonFormat *jf = makeNode(JsonFormat);
-
- jf->format_type = type;
- jf->encoding = encoding;
- jf->location = location;
-
- return jf;
-}
-
-/*
- * makeJsonValueExpr -
- * creates a JsonValueExpr node
- */
-JsonValueExpr *
-makeJsonValueExpr(Expr *expr, JsonFormat *format)
-{
- JsonValueExpr *jve = makeNode(JsonValueExpr);
-
- jve->raw_expr = expr;
- jve->formatted_expr = NULL;
- jve->format = format;
-
- return jve;
-}
-
-/*
- * makeJsonBehavior -
- * creates a JsonBehavior node
- */
-JsonBehavior *
-makeJsonBehavior(JsonBehaviorType type, Node *default_expr)
-{
- JsonBehavior *behavior = makeNode(JsonBehavior);
-
- behavior->btype = type;
- behavior->default_expr = default_expr;
-
- return behavior;
-}
-
-/*
- * makeJsonTableJoinedPlan -
- * creates a joined JsonTablePlan node
- */
-Node *
-makeJsonTableJoinedPlan(JsonTablePlanJoinType type, Node *plan1, Node *plan2,
- int location)
-{
- JsonTablePlan *n = makeNode(JsonTablePlan);
-
- n->plan_type = JSTP_JOINED;
- n->join_type = type;
- n->plan1 = castNode(JsonTablePlan, plan1);
- n->plan2 = castNode(JsonTablePlan, plan2);
- n->location = location;
-
- return (Node *) n;
-}
-
-/*
- * makeJsonEncoding -
- * converts JSON encoding name to enum JsonEncoding
- */
-JsonEncoding
-makeJsonEncoding(char *name)
-{
- if (!pg_strcasecmp(name, "utf8"))
- return JS_ENC_UTF8;
- if (!pg_strcasecmp(name, "utf16"))
- return JS_ENC_UTF16;
- if (!pg_strcasecmp(name, "utf32"))
- return JS_ENC_UTF32;
-
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("unrecognized JSON encoding: %s", name)));
-
- return JS_ENC_DEFAULT;
-}
-
-/*
- * makeJsonKeyValue -
- * creates a JsonKeyValue node
- */
-Node *
-makeJsonKeyValue(Node *key, Node *value)
-{
- JsonKeyValue *n = makeNode(JsonKeyValue);
-
- n->key = (Expr *) key;
- n->value = castNode(JsonValueExpr, value);
-
- return (Node *) n;
-}
-
-/*
- * makeJsonIsPredicate -
- * creates a JsonIsPredicate node
- */
-Node *
-makeJsonIsPredicate(Node *expr, JsonFormat *format, JsonValueType item_type,
- bool unique_keys, int location)
-{
- JsonIsPredicate *n = makeNode(JsonIsPredicate);
-
- n->expr = expr;
- n->format = format;
- n->item_type = item_type;
- n->unique_keys = unique_keys;
- n->location = location;
-
- return (Node *) n;
-}
diff --git a/src/backend/nodes/nodeFuncs.c b/src/backend/nodes/nodeFuncs.c
index c334daae39..3bac350bf5 100644
--- a/src/backend/nodes/nodeFuncs.c
+++ b/src/backend/nodes/nodeFuncs.c
@@ -250,25 +250,6 @@ exprType(const Node *expr)
case T_PlaceHolderVar:
type = exprType((Node *) ((const PlaceHolderVar *) expr)->phexpr);
break;
- case T_JsonValueExpr:
- {
- const JsonValueExpr *jve = (const JsonValueExpr *) expr;
-
- type = exprType((Node *) (jve->formatted_expr ? jve->formatted_expr : jve->raw_expr));
- }
- break;
- case T_JsonConstructorExpr:
- type = ((const JsonConstructorExpr *) expr)->returning->typid;
- break;
- case T_JsonIsPredicate:
- type = BOOLOID;
- break;
- case T_JsonExpr:
- type = ((const JsonExpr *) expr)->returning->typid;
- break;
- case T_JsonCoercion:
- type = exprType(((const JsonCoercion *) expr)->expr);
- break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
type = InvalidOid; /* keep compiler quiet */
@@ -501,14 +482,6 @@ exprTypmod(const Node *expr)
return ((const SetToDefault *) expr)->typeMod;
case T_PlaceHolderVar:
return exprTypmod((Node *) ((const PlaceHolderVar *) expr)->phexpr);
- case T_JsonValueExpr:
- return exprTypmod((Node *) ((const JsonValueExpr *) expr)->formatted_expr);
- case T_JsonConstructorExpr:
- return ((const JsonConstructorExpr *) expr)->returning->typmod;
- case T_JsonExpr:
- return ((JsonExpr *) expr)->returning->typmod;
- case T_JsonCoercion:
- return exprTypmod(((const JsonCoercion *) expr)->expr);
default:
break;
}
@@ -991,37 +964,6 @@ exprCollation(const Node *expr)
case T_PlaceHolderVar:
coll = exprCollation((Node *) ((const PlaceHolderVar *) expr)->phexpr);
break;
- case T_JsonValueExpr:
- coll = exprCollation((Node *) ((const JsonValueExpr *) expr)->formatted_expr);
- break;
- case T_JsonConstructorExpr:
- {
- const JsonConstructorExpr *ctor = (const JsonConstructorExpr *) expr;
-
- if (ctor->coercion)
- coll = exprCollation((Node *) ctor->coercion);
- else
- coll = InvalidOid;
- }
- break;
- case T_JsonIsPredicate:
- coll = InvalidOid; /* result is always an boolean type */
- break;
- case T_JsonExpr:
- {
- JsonExpr *jexpr = (JsonExpr *) expr;
- JsonCoercion *coercion = jexpr->result_coercion;
-
- if (!coercion)
- coll = InvalidOid;
- else if (coercion->expr)
- coll = exprCollation(coercion->expr);
- else if (coercion->via_io || coercion->via_populate)
- coll = coercion->collation;
- else
- coll = InvalidOid;
- }
- break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
coll = InvalidOid; /* keep compiler quiet */
@@ -1234,39 +1176,6 @@ exprSetCollation(Node *expr, Oid collation)
/* NextValueExpr's result is an integer type ... */
Assert(!OidIsValid(collation)); /* ... so never set a collation */
break;
- case T_JsonValueExpr:
- exprSetCollation((Node *) ((JsonValueExpr *) expr)->formatted_expr,
- collation);
- break;
- case T_JsonConstructorExpr:
- {
- JsonConstructorExpr *ctor = (JsonConstructorExpr *) expr;
-
- if (ctor->coercion)
- exprSetCollation((Node *) ctor->coercion, collation);
- else
- Assert(!OidIsValid(collation)); /* result is always a
- * json[b] type */
- }
- break;
- case T_JsonIsPredicate:
- Assert(!OidIsValid(collation)); /* result is always boolean */
- break;
- case T_JsonExpr:
- {
- JsonExpr *jexpr = (JsonExpr *) expr;
- JsonCoercion *coercion = jexpr->result_coercion;
-
- if (!coercion)
- Assert(!OidIsValid(collation));
- else if (coercion->expr)
- exprSetCollation(coercion->expr, collation);
- else if (coercion->via_io || coercion->via_populate)
- coercion->collation = collation;
- else
- Assert(!OidIsValid(collation));
- }
- break;
default:
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
break;
@@ -1713,24 +1622,6 @@ exprLocation(const Node *expr)
case T_PartitionRangeDatum:
loc = ((const PartitionRangeDatum *) expr)->location;
break;
- case T_JsonValueExpr:
- loc = exprLocation((Node *) ((const JsonValueExpr *) expr)->raw_expr);
- break;
- case T_JsonConstructorExpr:
- loc = ((const JsonConstructorExpr *) expr)->location;
- break;
- case T_JsonIsPredicate:
- loc = ((const JsonIsPredicate *) expr)->location;
- break;
- case T_JsonExpr:
- {
- const JsonExpr *jsexpr = (const JsonExpr *) expr;
-
- /* consider both function name and leftmost arg */
- loc = leftmostLoc(jsexpr->location,
- exprLocation(jsexpr->formatted_expr));
- }
- break;
default:
/* for any other node type it's just unknown... */
loc = -1;
@@ -2473,80 +2364,6 @@ expression_tree_walker(Node *node,
return true;
if (walker(tf->coldefexprs, context))
return true;
- if (walker(tf->colvalexprs, context))
- return true;
- }
- break;
- case T_JsonValueExpr:
- {
- JsonValueExpr *jve = (JsonValueExpr *) node;
-
- if (walker(jve->raw_expr, context))
- return true;
- if (walker(jve->formatted_expr, context))
- return true;
- }
- break;
- case T_JsonConstructorExpr:
- {
- JsonConstructorExpr *ctor = (JsonConstructorExpr *) node;
-
- if (walker(ctor->args, context))
- return true;
- if (walker(ctor->func, context))
- return true;
- if (walker(ctor->coercion, context))
- return true;
- }
- break;
- case T_JsonIsPredicate:
- return walker(((JsonIsPredicate *) node)->expr, context);
- case T_JsonExpr:
- {
- JsonExpr *jexpr = (JsonExpr *) node;
-
- if (walker(jexpr->formatted_expr, context))
- return true;
- if (walker(jexpr->result_coercion, context))
- return true;
- if (walker(jexpr->passing_values, context))
- return true;
- /* we assume walker doesn't care about passing_names */
- if (jexpr->on_empty &&
- walker(jexpr->on_empty->default_expr, context))
- return true;
- if (walker(jexpr->on_error->default_expr, context))
- return true;
- if (walker(jexpr->coercions, context))
- return true;
- }
- break;
- case T_JsonCoercion:
- return walker(((JsonCoercion *) node)->expr, context);
- case T_JsonItemCoercions:
- {
- JsonItemCoercions *coercions = (JsonItemCoercions *) node;
-
- if (walker(coercions->null, context))
- return true;
- if (walker(coercions->string, context))
- return true;
- if (walker(coercions->numeric, context))
- return true;
- if (walker(coercions->boolean, context))
- return true;
- if (walker(coercions->date, context))
- return true;
- if (walker(coercions->time, context))
- return true;
- if (walker(coercions->timetz, context))
- return true;
- if (walker(coercions->timestamp, context))
- return true;
- if (walker(coercions->timestamptz, context))
- return true;
- if (walker(coercions->composite, context))
- return true;
}
break;
default:
@@ -2876,7 +2693,6 @@ expression_tree_mutator(Node *node,
case T_RangeTblRef:
case T_SortGroupClause:
case T_CTESearchClause:
- case T_JsonFormat:
return (Node *) copyObject(node);
case T_WithCheckOption:
{
@@ -3517,102 +3333,6 @@ expression_tree_mutator(Node *node,
MUTATE(newnode->rowexpr, tf->rowexpr, Node *);
MUTATE(newnode->colexprs, tf->colexprs, List *);
MUTATE(newnode->coldefexprs, tf->coldefexprs, List *);
- MUTATE(newnode->colvalexprs, tf->colvalexprs, List *);
- return (Node *) newnode;
- }
- break;
- case T_JsonReturning:
- {
- JsonReturning *jr = (JsonReturning *) node;
- JsonReturning *newnode;
-
- FLATCOPY(newnode, jr, JsonReturning);
- MUTATE(newnode->format, jr->format, JsonFormat *);
-
- return (Node *) newnode;
- }
- case T_JsonValueExpr:
- {
- JsonValueExpr *jve = (JsonValueExpr *) node;
- JsonValueExpr *newnode;
-
- FLATCOPY(newnode, jve, JsonValueExpr);
- MUTATE(newnode->raw_expr, jve->raw_expr, Expr *);
- MUTATE(newnode->formatted_expr, jve->formatted_expr, Expr *);
- MUTATE(newnode->format, jve->format, JsonFormat *);
-
- return (Node *) newnode;
- }
- case T_JsonConstructorExpr:
- {
- JsonConstructorExpr *jve = (JsonConstructorExpr *) node;
- JsonConstructorExpr *newnode;
-
- FLATCOPY(newnode, jve, JsonConstructorExpr);
- MUTATE(newnode->args, jve->args, List *);
- MUTATE(newnode->func, jve->func, Expr *);
- MUTATE(newnode->coercion, jve->coercion, Expr *);
- MUTATE(newnode->returning, jve->returning, JsonReturning *);
-
- return (Node *) newnode;
- }
- break;
- case T_JsonIsPredicate:
- {
- JsonIsPredicate *pred = (JsonIsPredicate *) node;
- JsonIsPredicate *newnode;
-
- FLATCOPY(newnode, pred, JsonIsPredicate);
- MUTATE(newnode->expr, pred->expr, Node *);
-
- return (Node *) newnode;
- }
- break;
- case T_JsonExpr:
- {
- JsonExpr *jexpr = (JsonExpr *) node;
- JsonExpr *newnode;
-
- FLATCOPY(newnode, jexpr, JsonExpr);
- MUTATE(newnode->path_spec, jexpr->path_spec, Node *);
- MUTATE(newnode->formatted_expr, jexpr->formatted_expr, Node *);
- MUTATE(newnode->result_coercion, jexpr->result_coercion, JsonCoercion *);
- MUTATE(newnode->passing_values, jexpr->passing_values, List *);
- /* assume mutator does not care about passing_names */
- if (newnode->on_empty)
- MUTATE(newnode->on_empty->default_expr,
- jexpr->on_empty->default_expr, Node *);
- MUTATE(newnode->on_error->default_expr,
- jexpr->on_error->default_expr, Node *);
- return (Node *) newnode;
- }
- break;
- case T_JsonCoercion:
- {
- JsonCoercion *coercion = (JsonCoercion *) node;
- JsonCoercion *newnode;
-
- FLATCOPY(newnode, coercion, JsonCoercion);
- MUTATE(newnode->expr, coercion->expr, Node *);
- return (Node *) newnode;
- }
- break;
- case T_JsonItemCoercions:
- {
- JsonItemCoercions *coercions = (JsonItemCoercions *) node;
- JsonItemCoercions *newnode;
-
- FLATCOPY(newnode, coercions, JsonItemCoercions);
- MUTATE(newnode->null, coercions->null, JsonCoercion *);
- MUTATE(newnode->string, coercions->string, JsonCoercion *);
- MUTATE(newnode->numeric, coercions->numeric, JsonCoercion *);
- MUTATE(newnode->boolean, coercions->boolean, JsonCoercion *);
- MUTATE(newnode->date, coercions->date, JsonCoercion *);
- MUTATE(newnode->time, coercions->time, JsonCoercion *);
- MUTATE(newnode->timetz, coercions->timetz, JsonCoercion *);
- MUTATE(newnode->timestamp, coercions->timestamp, JsonCoercion *);
- MUTATE(newnode->timestamptz, coercions->timestamptz, JsonCoercion *);
- MUTATE(newnode->composite, coercions->composite, JsonCoercion *);
return (Node *) newnode;
}
break;
@@ -3888,7 +3608,6 @@ raw_expression_tree_walker(Node *node,
case T_ParamRef:
case T_A_Const:
case T_A_Star:
- case T_JsonFormat:
/* primitive node types with no subnodes */
break;
case T_Alias:
@@ -4351,211 +4070,6 @@ raw_expression_tree_walker(Node *node,
case T_CommonTableExpr:
/* search_clause and cycle_clause are not interesting here */
return walker(((CommonTableExpr *) node)->ctequery, context);
- case T_JsonReturning:
- return walker(((JsonReturning *) node)->format, context);
- case T_JsonValueExpr:
- {
- JsonValueExpr *jve = (JsonValueExpr *) node;
-
- if (walker(jve->raw_expr, context))
- return true;
- if (walker(jve->formatted_expr, context))
- return true;
- if (walker(jve->format, context))
- return true;
- }
- break;
- case T_JsonParseExpr:
- {
- JsonParseExpr *jpe = (JsonParseExpr *) node;
-
- if (walker(jpe->expr, context))
- return true;
- if (walker(jpe->output, context))
- return true;
- }
- break;
- case T_JsonScalarExpr:
- {
- JsonScalarExpr *jse = (JsonScalarExpr *) node;
-
- if (walker(jse->expr, context))
- return true;
- if (walker(jse->output, context))
- return true;
- }
- break;
- case T_JsonSerializeExpr:
- {
- JsonSerializeExpr *jse = (JsonSerializeExpr *) node;
-
- if (walker(jse->expr, context))
- return true;
- if (walker(jse->output, context))
- return true;
- }
- break;
- case T_JsonConstructorExpr:
- {
- JsonConstructorExpr *ctor = (JsonConstructorExpr *) node;
-
- if (walker(ctor->args, context))
- return true;
- if (walker(ctor->func, context))
- return true;
- if (walker(ctor->coercion, context))
- return true;
- if (walker(ctor->returning, context))
- return true;
- }
- break;
- case T_JsonOutput:
- {
- JsonOutput *out = (JsonOutput *) node;
-
- if (walker(out->typeName, context))
- return true;
- if (walker(out->returning, context))
- return true;
- }
- break;
- case T_JsonKeyValue:
- {
- JsonKeyValue *jkv = (JsonKeyValue *) node;
-
- if (walker(jkv->key, context))
- return true;
- if (walker(jkv->value, context))
- return true;
- }
- break;
- case T_JsonObjectConstructor:
- {
- JsonObjectConstructor *joc = (JsonObjectConstructor *) node;
-
- if (walker(joc->output, context))
- return true;
- if (walker(joc->exprs, context))
- return true;
- }
- break;
- case T_JsonArrayConstructor:
- {
- JsonArrayConstructor *jac = (JsonArrayConstructor *) node;
-
- if (walker(jac->output, context))
- return true;
- if (walker(jac->exprs, context))
- return true;
- }
- break;
- case T_JsonAggConstructor:
- {
- JsonAggConstructor *ctor = (JsonAggConstructor *) node;
-
- if (walker(ctor->output, context))
- return true;
- if (walker(ctor->agg_order, context))
- return true;
- if (walker(ctor->agg_filter, context))
- return true;
- if (walker(ctor->over, context))
- return true;
- }
- break;
- case T_JsonObjectAgg:
- {
- JsonObjectAgg *joa = (JsonObjectAgg *) node;
-
- if (walker(joa->constructor, context))
- return true;
- if (walker(joa->arg, context))
- return true;
- }
- break;
- case T_JsonArrayAgg:
- {
- JsonArrayAgg *jaa = (JsonArrayAgg *) node;
-
- if (walker(jaa->constructor, context))
- return true;
- if (walker(jaa->arg, context))
- return true;
- }
- break;
- case T_JsonArrayQueryConstructor:
- {
- JsonArrayQueryConstructor *jaqc = (JsonArrayQueryConstructor *) node;
-
- if (walker(jaqc->output, context))
- return true;
- if (walker(jaqc->query, context))
- return true;
- }
- break;
- case T_JsonIsPredicate:
- return walker(((JsonIsPredicate *) node)->expr, context);
- case T_JsonArgument:
- return walker(((JsonArgument *) node)->val, context);
- case T_JsonCommon:
- {
- JsonCommon *jc = (JsonCommon *) node;
-
- if (walker(jc->expr, context))
- return true;
- if (walker(jc->pathspec, context))
- return true;
- if (walker(jc->passing, context))
- return true;
- }
- break;
- case T_JsonBehavior:
- {
- JsonBehavior *jb = (JsonBehavior *) node;
-
- if (jb->btype == JSON_BEHAVIOR_DEFAULT &&
- walker(jb->default_expr, context))
- return true;
- }
- break;
- case T_JsonFuncExpr:
- {
- JsonFuncExpr *jfe = (JsonFuncExpr *) node;
-
- if (walker(jfe->common, context))
- return true;
- if (jfe->output && walker(jfe->output, context))
- return true;
- if (walker(jfe->on_empty, context))
- return true;
- if (walker(jfe->on_error, context))
- return true;
- }
- break;
- case T_JsonTable:
- {
- JsonTable *jt = (JsonTable *) node;
-
- if (walker(jt->common, context))
- return true;
- if (walker(jt->columns, context))
- return true;
- }
- break;
- case T_JsonTableColumn:
- {
- JsonTableColumn *jtc = (JsonTableColumn *) node;
-
- if (walker(jtc->typeName, context))
- return true;
- if (walker(jtc->on_empty, context))
- return true;
- if (walker(jtc->on_error, context))
- return true;
- if (jtc->coltype == JTC_NESTED && walker(jtc->columns, context))
- return true;
- }
- break;
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(node));
diff --git a/src/backend/optimizer/path/costsize.c b/src/backend/optimizer/path/costsize.c
index 75acea149c..f486d42441 100644
--- a/src/backend/optimizer/path/costsize.c
+++ b/src/backend/optimizer/path/costsize.c
@@ -4923,8 +4923,7 @@ cost_qual_eval_walker(Node *node, cost_qual_eval_context *context)
IsA(node, SQLValueFunction) ||
IsA(node, XmlExpr) ||
IsA(node, CoerceToDomain) ||
- IsA(node, NextValueExpr) ||
- IsA(node, JsonExpr))
+ IsA(node, NextValueExpr))
{
/* Treat all these as having cost 1 */
context->total.per_tuple += cpu_operator_cost;
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 533df86ff7..5c54171fee 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -28,7 +28,6 @@
#include "catalog/pg_type.h"
#include "executor/executor.h"
#include "executor/functions.h"
-#include "executor/execExpr.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
@@ -51,9 +50,6 @@
#include "utils/builtins.h"
#include "utils/datum.h"
#include "utils/fmgroids.h"
-#include "utils/json.h"
-#include "utils/jsonb.h"
-#include "utils/jsonpath.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/syscache.h"
@@ -386,45 +382,6 @@ contain_mutable_functions_walker(Node *node, void *context)
context))
return true;
- if (IsA(node, JsonConstructorExpr))
- {
- const JsonConstructorExpr *ctor = (JsonConstructorExpr *) node;
- ListCell *lc;
- bool is_jsonb =
- ctor->returning->format->format_type == JS_FORMAT_JSONB;
-
- /* Check argument_type => json[b] conversions */
- foreach(lc, ctor->args)
- {
- Oid typid = exprType(lfirst(lc));
-
- if (is_jsonb ?
- !to_jsonb_is_immutable(typid) :
- !to_json_is_immutable(typid))
- return true;
- }
-
- /* Check all subnodes */
- }
-
- if (IsA(node, JsonExpr))
- {
- JsonExpr *jexpr = castNode(JsonExpr, node);
- Const *cnst;
-
- if (!IsA(jexpr->path_spec, Const))
- return true;
-
- cnst = castNode(Const, jexpr->path_spec);
-
- Assert(cnst->consttype == JSONPATHOID);
- if (cnst->constisnull)
- return false;
-
- return jspIsMutable(DatumGetJsonPathP(cnst->constvalue),
- jexpr->passing_names, jexpr->passing_values);
- }
-
if (IsA(node, SQLValueFunction))
{
/* all variants of SQLValueFunction are stable */
@@ -896,18 +853,6 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
context, 0);
}
- /* JsonExpr is parallel-unsafe if subtransactions can be used. */
- else if (IsA(node, JsonExpr))
- {
- JsonExpr *jsexpr = (JsonExpr *) node;
-
- if (ExecEvalJsonNeedsSubTransaction(jsexpr, NULL))
- {
- context->max_hazard = PROPARALLEL_UNSAFE;
- return true;
- }
- }
-
/* Recurse to check arguments */
return expression_tree_walker(node,
max_parallel_hazard_walker,
@@ -3567,29 +3512,6 @@ eval_const_expressions_mutator(Node *node,
return ece_evaluate_expr((Node *) newcre);
return (Node *) newcre;
}
- case T_JsonValueExpr:
- {
- JsonValueExpr *jve = (JsonValueExpr *) node;
- Node *raw = eval_const_expressions_mutator((Node *) jve->raw_expr,
- context);
-
- if (raw && IsA(raw, Const))
- {
- Node *formatted;
- Node *save_case_val = context->case_val;
-
- context->case_val = raw;
-
- formatted = eval_const_expressions_mutator((Node *) jve->formatted_expr,
- context);
-
- context->case_val = save_case_val;
-
- if (formatted && IsA(formatted, Const))
- return formatted;
- }
- break;
- }
default:
break;
}
diff --git a/src/backend/parser/Makefile b/src/backend/parser/Makefile
index f4c0cc7f10..9f1c4022bb 100644
--- a/src/backend/parser/Makefile
+++ b/src/backend/parser/Makefile
@@ -23,7 +23,6 @@ OBJS = \
parse_enr.o \
parse_expr.o \
parse_func.o \
- parse_jsontable.o \
parse_merge.o \
parse_node.o \
parse_oper.o \
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index b5ab9d9c9a..0492ff9a66 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -281,13 +281,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
MergeWhenClause *mergewhen;
struct KeyActions *keyactions;
struct KeyAction *keyaction;
- JsonBehavior *jsbehavior;
- struct
- {
- JsonBehavior *on_empty;
- JsonBehavior *on_error;
- } on_behavior;
- JsonQuotes js_quotes;
}
%type <node> stmt toplevel_stmt schema_stmt routine_body_stmt
@@ -576,7 +569,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <list> copy_options
%type <typnam> Typename SimpleTypename ConstTypename
- GenericType Numeric opt_float JsonType
+ GenericType Numeric opt_float
Character ConstCharacter
CharacterWithLength CharacterWithoutLength
ConstDatetime ConstInterval
@@ -656,101 +649,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
%type <defelt> hash_partbound_elem
-%type <node> json_format_clause_opt
- json_representation
- json_value_expr
- json_func_expr
- json_value_func_expr
- json_query_expr
- json_exists_predicate
- json_parse_expr
- json_scalar_expr
- json_serialize_expr
- json_api_common_syntax
- json_context_item
- json_argument
- json_output_clause_opt
- json_returning_clause_opt
- json_value_constructor
- json_object_constructor
- json_object_constructor_args
- json_object_constructor_args_opt
- json_object_args
- json_object_func_args
- json_array_constructor
- json_name_and_value
- json_aggregate_func
- json_object_aggregate_constructor
- json_array_aggregate_constructor
- json_path_specification
- json_table
- json_table_column_definition
- json_table_ordinality_column_definition
- json_table_regular_column_definition
- json_table_formatted_column_definition
- json_table_exists_column_definition
- json_table_nested_columns
- json_table_plan_clause_opt
- json_table_specific_plan
- json_table_plan
- json_table_plan_simple
- json_table_plan_parent_child
- json_table_plan_outer
- json_table_plan_inner
- json_table_plan_sibling
- json_table_plan_union
- json_table_plan_cross
- json_table_plan_primary
- json_table_default_plan
-
-%type <list> json_name_and_value_list
- json_value_expr_list
- json_array_aggregate_order_by_clause_opt
- json_arguments
- json_passing_clause_opt
- json_table_columns_clause
- json_table_column_definition_list
-
-%type <str> json_table_path_name
- json_as_path_name_clause_opt
- json_table_column_path_specification_clause_opt
-
-%type <ival> json_encoding
- json_encoding_clause_opt
- json_table_default_plan_choices
- json_table_default_plan_inner_outer
- json_table_default_plan_union_cross
- json_wrapper_clause_opt
- json_wrapper_behavior
- json_conditional_or_unconditional_opt
- json_predicate_type_constraint_opt
-
-%type <jsbehavior> json_behavior_error
- json_behavior_null
- json_behavior_true
- json_behavior_false
- json_behavior_unknown
- json_behavior_empty
- json_behavior_empty_array
- json_behavior_empty_object
- json_behavior_default
- json_value_behavior
- json_query_behavior
- json_exists_error_behavior
- json_exists_error_clause_opt
- json_table_error_behavior
- json_table_error_clause_opt
-
-%type <on_behavior> json_value_on_behavior_clause_opt
- json_query_on_behavior_clause_opt
-
-%type <js_quotes> json_quotes_behavior
- json_quotes_clause_opt
-
-%type <boolean> json_key_uniqueness_constraint_opt
- json_object_constructor_null_clause_opt
- json_array_constructor_null_clause_opt
-
/*
* Non-keyword token types. These are hard-wired into the "flex" lexer.
* They must be listed first so that their numeric codes do not depend on
@@ -776,7 +674,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
*/
/* ordinary key words in alphabetical order */
-%token <keyword> ABORT_P ABSENT ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
+%token <keyword> ABORT_P ABSOLUTE_P ACCESS ACTION ADD_P ADMIN AFTER
AGGREGATE ALL ALSO ALTER ALWAYS ANALYSE ANALYZE AND ANY ARRAY AS ASC
ASENSITIVE ASSERTION ASSIGNMENT ASYMMETRIC ATOMIC AT ATTACH ATTRIBUTE AUTHORIZATION
@@ -786,7 +684,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
CACHE CALL CALLED CASCADE CASCADED CASE CAST CATALOG_P CHAIN CHAR_P
CHARACTER CHARACTERISTICS CHECK CHECKPOINT CLASS CLOSE
CLUSTER COALESCE COLLATE COLLATION COLUMN COLUMNS COMMENT COMMENTS COMMIT
- COMMITTED COMPRESSION CONCURRENTLY CONDITIONAL CONFIGURATION CONFLICT
+ COMMITTED COMPRESSION CONCURRENTLY CONFIGURATION CONFLICT
CONNECTION CONSTRAINT CONSTRAINTS CONTENT_P CONTINUE_P CONVERSION_P COPY
COST CREATE CROSS CSV CUBE CURRENT_P
CURRENT_CATALOG CURRENT_DATE CURRENT_ROLE CURRENT_SCHEMA
@@ -797,12 +695,12 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
DETACH DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P
DOUBLE_P DROP
- EACH ELSE EMPTY_P ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ERROR_P ESCAPE
- EVENT EXCEPT EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION
+ EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT
+ EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN EXPRESSION
EXTENSION EXTERNAL EXTRACT
FALSE_P FAMILY FETCH FILTER FINALIZE FIRST_P FLOAT_P FOLLOWING FOR
- FORCE FOREIGN FORMAT FORWARD FREEZE FROM FULL FUNCTION FUNCTIONS
+ FORCE FOREIGN FORWARD FREEZE FROM FULL FUNCTION FUNCTIONS
GENERATED GLOBAL GRANT GRANTED GREATEST GROUP_P GROUPING GROUPS
@@ -813,10 +711,9 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
INNER_P INOUT INPUT_P INSENSITIVE INSERT INSTEAD INT_P INTEGER
INTERSECT INTERVAL INTO INVOKER IS ISNULL ISOLATION
- JOIN JSON JSON_ARRAY JSON_ARRAYAGG JSON_EXISTS JSON_OBJECT JSON_OBJECTAGG
- JSON_QUERY JSON_SCALAR JSON_SERIALIZE JSON_TABLE JSON_VALUE
+ JOIN
- KEY KEYS KEEP
+ KEY
LABEL LANGUAGE LARGE_P LAST_P LATERAL_P
LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL
@@ -825,31 +722,31 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
MAPPING MATCH MATCHED MATERIALIZED MAXVALUE MERGE METHOD
MINUTE_P MINVALUE MODE MONTH_P MOVE
- NAME_P NAMES NATIONAL NATURAL NCHAR NESTED NEW NEXT NFC NFD NFKC NFKD NO
- NONE NORMALIZE NORMALIZED
+ NAME_P NAMES NATIONAL NATURAL NCHAR NEW NEXT NFC NFD NFKC NFKD NO NONE
+ NORMALIZE NORMALIZED
NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF
NULLS_P NUMERIC
- OBJECT_P OF OFF OFFSET OIDS OLD OMIT ON ONLY OPERATOR OPTION OPTIONS OR
+ OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR
ORDER ORDINALITY OTHERS OUT_P OUTER_P
OVER OVERLAPS OVERLAY OVERRIDING OWNED OWNER
- PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD PATH
- PLACING PLAN PLANS POLICY
+ PARALLEL PARAMETER PARSER PARTIAL PARTITION PASSING PASSWORD
+ PLACING PLANS POLICY
POSITION PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
PRIOR PRIVILEGES PROCEDURAL PROCEDURE PROCEDURES PROGRAM PUBLICATION
- QUOTE QUOTES
+ QUOTE
RANGE READ REAL REASSIGN RECHECK RECURSIVE REF REFERENCES REFERENCING
REFRESH REINDEX RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA
RESET RESTART RESTRICT RETURN RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROLLUP
ROUTINE ROUTINES ROW ROWS RULE
- SAVEPOINT SCALAR SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT
- SEQUENCE SEQUENCES SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF
- SHARE SHOW SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P
- START STATEMENT STATISTICS STDIN STDOUT STORAGE STORED STRICT_P STRING STRIP_P
+ SAVEPOINT SCHEMA SCHEMAS SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES
+ SERIALIZABLE SERVER SESSION SESSION_USER SET SETS SETOF SHARE SHOW
+ SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME SQL_P STABLE STANDALONE_P
+ START STATEMENT STATISTICS STDIN STDOUT STORAGE STORED STRICT_P STRIP_P
SUBSCRIPTION SUBSTRING SUPPORT SYMMETRIC SYSID SYSTEM_P
TABLE TABLES TABLESAMPLE TABLESPACE TEMP TEMPLATE TEMPORARY TEXT_P THEN
@@ -857,7 +754,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
TREAT TRIGGER TRIM TRUE_P
TRUNCATE TRUSTED TYPE_P TYPES_P
- UESCAPE UNBOUNDED UNCONDITIONAL UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN
+ UESCAPE UNBOUNDED UNCOMMITTED UNENCRYPTED UNION UNIQUE UNKNOWN
UNLISTEN UNLOGGED UNTIL UPDATE USER USING
VACUUM VALID VALIDATE VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
@@ -882,7 +779,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
* as NOT, at least with respect to their left-hand subexpression.
* NULLS_LA and WITH_LA are needed to make the grammar LALR(1).
*/
-%token NOT_LA NULLS_LA WITH_LA WITH_LA_UNIQUE WITHOUT_LA
+%token NOT_LA NULLS_LA WITH_LA
/*
* The grammar likewise thinks these tokens are keywords, but they are never
@@ -900,7 +797,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
/* Precedence: lowest to highest */
%nonassoc SET /* see relation_expr_opt_alias */
-%right FORMAT
%left UNION EXCEPT
%left INTERSECT
%left OR
@@ -936,15 +832,11 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
* Using the same precedence as IDENT seems right for the reasons given above.
*/
%nonassoc UNBOUNDED /* ideally would have same precedence as IDENT */
-%nonassoc ERROR_P EMPTY_P DEFAULT ABSENT /* JSON error/empty behavior */
-%nonassoc FALSE_P KEEP OMIT PASSING TRUE_P UNKNOWN UNIQUE JSON COLUMNS
%nonassoc IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
%left Op OPERATOR /* multi-character ops and user-defined operators */
%left '+' '-'
%left '*' '/' '%'
%left '^'
-%left KEYS /* UNIQUE [ KEYS ] */
-%left OBJECT_P SCALAR VALUE_P /* JSON [ OBJECT | SCALAR | VALUE ] */
/* Unary Operators */
%left AT /* sets precedence for AT TIME ZONE */
%left COLLATE
@@ -962,13 +854,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
*/
%left JOIN CROSS LEFT FULL RIGHT INNER_P NATURAL
-%nonassoc json_table_column
-%nonassoc NESTED
-%left PATH
-
-%nonassoc empty_json_unique
-%left WITHOUT WITH_LA_UNIQUE
-
%%
/*
@@ -13407,21 +13292,6 @@ table_ref: relation_expr opt_alias_clause
$2->alias = $4;
$$ = (Node *) $2;
}
- | json_table opt_alias_clause
- {
- JsonTable *jt = castNode(JsonTable, $1);
-
- jt->alias = $2;
- $$ = (Node *) jt;
- }
- | LATERAL_P json_table opt_alias_clause
- {
- JsonTable *jt = castNode(JsonTable, $2);
-
- jt->alias = $3;
- jt->lateral = true;
- $$ = (Node *) jt;
- }
;
@@ -13989,8 +13859,6 @@ xmltable_column_option_el:
{ $$ = makeDefElem("is_not_null", (Node *) makeBoolean(true), @1); }
| NULL_P
{ $$ = makeDefElem("is_not_null", (Node *) makeBoolean(false), @1); }
- | PATH b_expr
- { $$ = makeDefElem("path", $2, @1); }
;
xml_namespace_list:
@@ -14091,7 +13959,6 @@ SimpleTypename:
$$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1),
makeIntConst($3, @3));
}
- | JsonType { $$ = $1; }
;
/* We have a separate ConstTypename to allow defaulting fixed-length
@@ -14110,7 +13977,6 @@ ConstTypename:
| ConstBit { $$ = $1; }
| ConstCharacter { $$ = $1; }
| ConstDatetime { $$ = $1; }
- | JsonType { $$ = $1; }
;
/*
@@ -14404,7 +14270,7 @@ ConstInterval:
opt_timezone:
WITH_LA TIME ZONE { $$ = true; }
- | WITHOUT_LA TIME ZONE { $$ = false; }
+ | WITHOUT TIME ZONE { $$ = false; }
| /*EMPTY*/ { $$ = false; }
;
@@ -14479,13 +14345,6 @@ interval_second:
}
;
-JsonType:
- JSON
- {
- $$ = SystemTypeName("json");
- $$->location = @1;
- }
- ;
/*****************************************************************************
*
@@ -14956,47 +14815,6 @@ a_expr: c_expr { $$ = $1; }
@2),
@2);
}
- | a_expr
- IS json_predicate_type_constraint_opt
- json_key_uniqueness_constraint_opt %prec IS
- {
- JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
- $$ = makeJsonIsPredicate($1, format, $3, $4, @1);
- }
- /*
- * Required by standard, but it would conflict with expressions
- * like: 'str' || format(...)
- | a_expr
- FORMAT json_representation
- IS json_predicate_type_constraint_opt
- json_key_uniqueness_constraint_opt %prec FORMAT
- {
- $3.location = @2;
- $$ = makeJsonIsPredicate($1, $3, $5, $6, @1);
- }
- */
- | a_expr
- IS NOT
- json_predicate_type_constraint_opt
- json_key_uniqueness_constraint_opt %prec IS
- {
- JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
-
- $$ = makeNotExpr(makeJsonIsPredicate($1, format, $4, $5, @1), @1);
- }
- /*
- * Required by standard, but it would conflict with expressions
- * like: 'str' || format(...)
- | a_expr
- FORMAT json_representation
- IS NOT
- json_predicate_type_constraint_opt
- json_key_uniqueness_constraint_opt %prec FORMAT
- {
- $3.location = @2;
- $$ = makeNotExpr(makeJsonIsPredicate($1, $3, $6, $7, @1), @1);
- }
- */
| DEFAULT
{
/*
@@ -15080,25 +14898,6 @@ b_expr: c_expr
}
;
-json_predicate_type_constraint_opt:
- JSON { $$ = JS_TYPE_ANY; }
- | JSON VALUE_P { $$ = JS_TYPE_ANY; }
- | JSON ARRAY { $$ = JS_TYPE_ARRAY; }
- | JSON OBJECT_P { $$ = JS_TYPE_OBJECT; }
- | JSON SCALAR { $$ = JS_TYPE_SCALAR; }
- ;
-
-json_key_uniqueness_constraint_opt:
- WITH_LA_UNIQUE unique_keys { $$ = true; }
- | WITHOUT unique_keys { $$ = false; }
- | /* EMPTY */ %prec empty_json_unique { $$ = false; }
- ;
-
-unique_keys:
- UNIQUE
- | UNIQUE KEYS
- ;
-
/*
* Productions that can be used in both a_expr and b_expr.
*
@@ -15369,16 +15168,6 @@ func_expr: func_application within_group_clause filter_clause over_clause
n->over = $4;
$$ = (Node *) n;
}
- | json_aggregate_func filter_clause over_clause
- {
- JsonAggConstructor *n = IsA($1, JsonObjectAgg) ?
- ((JsonObjectAgg *) $1)->constructor :
- ((JsonArrayAgg *) $1)->constructor;
-
- n->agg_filter = $2;
- n->over = $3;
- $$ = (Node *) $1;
- }
| func_expr_common_subexpr
{ $$ = $1; }
;
@@ -15392,7 +15181,6 @@ func_expr: func_application within_group_clause filter_clause over_clause
func_expr_windowless:
func_application { $$ = $1; }
| func_expr_common_subexpr { $$ = $1; }
- | json_aggregate_func { $$ = $1; }
;
/*
@@ -15685,8 +15473,6 @@ func_expr_common_subexpr:
n->location = @1;
$$ = (Node *) n;
}
- | json_func_expr
- { $$ = $1; }
;
/*
@@ -16406,813 +16192,6 @@ opt_asymmetric: ASYMMETRIC
| /*EMPTY*/
;
-/* SQL/JSON support */
-json_func_expr:
- json_value_constructor
- | json_value_func_expr
- | json_query_expr
- | json_exists_predicate
- | json_parse_expr
- | json_scalar_expr
- | json_serialize_expr
- ;
-
-json_parse_expr:
- JSON '(' json_value_expr json_key_uniqueness_constraint_opt
- json_returning_clause_opt ')'
- {
- JsonParseExpr *n = makeNode(JsonParseExpr);
-
- n->expr = (JsonValueExpr *) $3;
- n->unique_keys = $4;
- n->output = (JsonOutput *) $5;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_scalar_expr:
- JSON_SCALAR '(' a_expr json_returning_clause_opt ')'
- {
- JsonScalarExpr *n = makeNode(JsonScalarExpr);
-
- n->expr = (Expr *) $3;
- n->output = (JsonOutput *) $4;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_serialize_expr:
- JSON_SERIALIZE '(' json_value_expr json_output_clause_opt ')'
- {
- JsonSerializeExpr *n = makeNode(JsonSerializeExpr);
-
- n->expr = (JsonValueExpr *) $3;
- n->output = (JsonOutput *) $4;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_value_func_expr:
- JSON_VALUE '('
- json_api_common_syntax
- json_returning_clause_opt
- json_value_on_behavior_clause_opt
- ')'
- {
- JsonFuncExpr *n = makeNode(JsonFuncExpr);
-
- n->op = JSON_VALUE_OP;
- n->common = (JsonCommon *) $3;
- n->output = (JsonOutput *) $4;
- n->on_empty = $5.on_empty;
- n->on_error = $5.on_error;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_api_common_syntax:
- json_context_item ',' json_path_specification
- json_as_path_name_clause_opt
- json_passing_clause_opt
- {
- JsonCommon *n = makeNode(JsonCommon);
-
- n->expr = (JsonValueExpr *) $1;
- n->pathspec = $3;
- n->pathname = $4;
- n->passing = $5;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_context_item:
- json_value_expr { $$ = $1; }
- ;
-
-json_path_specification:
- a_expr { $$ = $1; }
- ;
-
-json_as_path_name_clause_opt:
- AS json_table_path_name { $$ = $2; }
- | /* EMPTY */ { $$ = NULL; }
- ;
-
-json_table_path_name:
- name { $$ = $1; }
- ;
-
-json_passing_clause_opt:
- PASSING json_arguments { $$ = $2; }
- | /* EMPTY */ { $$ = NIL; }
- ;
-
-json_arguments:
- json_argument { $$ = list_make1($1); }
- | json_arguments ',' json_argument { $$ = lappend($1, $3); }
- ;
-
-json_argument:
- json_value_expr AS ColLabel
- {
- JsonArgument *n = makeNode(JsonArgument);
-
- n->val = (JsonValueExpr *) $1;
- n->name = $3;
- $$ = (Node *) n;
- }
- ;
-
-json_value_expr:
- a_expr json_format_clause_opt
- {
- $$ = (Node *) makeJsonValueExpr((Expr *) $1, castNode(JsonFormat, $2));
- }
- ;
-
-json_format_clause_opt:
- FORMAT json_representation
- {
- $$ = $2;
- castNode(JsonFormat, $$)->location = @1;
- }
- | /* EMPTY */
- {
- $$ = (Node *) makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
- }
- ;
-
-json_representation:
- JSON json_encoding_clause_opt
- {
- $$ = (Node *) makeJsonFormat(JS_FORMAT_JSON, $2, @1);
- }
- /* | other implementation defined JSON representation options (BSON, AVRO etc) */
- ;
-
-json_encoding_clause_opt:
- ENCODING json_encoding { $$ = $2; }
- | /* EMPTY */ { $$ = JS_ENC_DEFAULT; }
- ;
-
-json_encoding:
- name { $$ = makeJsonEncoding($1); }
- ;
-
-json_behavior_error:
- ERROR_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_ERROR, NULL); }
- ;
-
-json_behavior_null:
- NULL_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_NULL, NULL); }
- ;
-
-json_behavior_true:
- TRUE_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_TRUE, NULL); }
- ;
-
-json_behavior_false:
- FALSE_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_FALSE, NULL); }
- ;
-
-json_behavior_unknown:
- UNKNOWN { $$ = makeJsonBehavior(JSON_BEHAVIOR_UNKNOWN, NULL); }
- ;
-
-json_behavior_empty:
- EMPTY_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_EMPTY_OBJECT, NULL); }
- ;
-
-json_behavior_empty_array:
- EMPTY_P ARRAY { $$ = makeJsonBehavior(JSON_BEHAVIOR_EMPTY_ARRAY, NULL); }
- /* non-standard, for Oracle compatibility only */
- | EMPTY_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_EMPTY_ARRAY, NULL); }
- ;
-
-json_behavior_empty_object:
- EMPTY_P OBJECT_P { $$ = makeJsonBehavior(JSON_BEHAVIOR_EMPTY_OBJECT, NULL); }
- ;
-
-json_behavior_default:
- DEFAULT a_expr { $$ = makeJsonBehavior(JSON_BEHAVIOR_DEFAULT, $2); }
- ;
-
-
-json_value_behavior:
- json_behavior_null
- | json_behavior_error
- | json_behavior_default
- ;
-
-json_value_on_behavior_clause_opt:
- json_value_behavior ON EMPTY_P
- { $$.on_empty = $1; $$.on_error = NULL; }
- | json_value_behavior ON EMPTY_P json_value_behavior ON ERROR_P
- { $$.on_empty = $1; $$.on_error = $4; }
- | json_value_behavior ON ERROR_P
- { $$.on_empty = NULL; $$.on_error = $1; }
- | /* EMPTY */
- { $$.on_empty = NULL; $$.on_error = NULL; }
- ;
-
-json_query_expr:
- JSON_QUERY '('
- json_api_common_syntax
- json_output_clause_opt
- json_wrapper_clause_opt
- json_quotes_clause_opt
- json_query_on_behavior_clause_opt
- ')'
- {
- JsonFuncExpr *n = makeNode(JsonFuncExpr);
-
- n->op = JSON_QUERY_OP;
- n->common = (JsonCommon *) $3;
- n->output = (JsonOutput *) $4;
- n->wrapper = $5;
- if (n->wrapper != JSW_NONE && $6 != JS_QUOTES_UNSPEC)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used"),
- parser_errposition(@6)));
- n->omit_quotes = $6 == JS_QUOTES_OMIT;
- n->on_empty = $7.on_empty;
- n->on_error = $7.on_error;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_wrapper_clause_opt:
- json_wrapper_behavior WRAPPER { $$ = $1; }
- | /* EMPTY */ { $$ = 0; }
- ;
-
-json_wrapper_behavior:
- WITHOUT array_opt { $$ = JSW_NONE; }
- | WITH json_conditional_or_unconditional_opt array_opt { $$ = $2; }
- ;
-
-array_opt:
- ARRAY { }
- | /* EMPTY */ { }
- ;
-
-json_conditional_or_unconditional_opt:
- CONDITIONAL { $$ = JSW_CONDITIONAL; }
- | UNCONDITIONAL { $$ = JSW_UNCONDITIONAL; }
- | /* EMPTY */ { $$ = JSW_UNCONDITIONAL; }
- ;
-
-json_quotes_clause_opt:
- json_quotes_behavior QUOTES json_on_scalar_string_opt { $$ = $1; }
- | /* EMPTY */ { $$ = JS_QUOTES_UNSPEC; }
- ;
-
-json_quotes_behavior:
- KEEP { $$ = JS_QUOTES_KEEP; }
- | OMIT { $$ = JS_QUOTES_OMIT; }
- ;
-
-json_on_scalar_string_opt:
- ON SCALAR STRING { }
- | /* EMPTY */ { }
- ;
-
-json_query_behavior:
- json_behavior_error
- | json_behavior_null
- | json_behavior_empty_array
- | json_behavior_empty_object
- | json_behavior_default
- ;
-
-json_query_on_behavior_clause_opt:
- json_query_behavior ON EMPTY_P
- { $$.on_empty = $1; $$.on_error = NULL; }
- | json_query_behavior ON EMPTY_P json_query_behavior ON ERROR_P
- { $$.on_empty = $1; $$.on_error = $4; }
- | json_query_behavior ON ERROR_P
- { $$.on_empty = NULL; $$.on_error = $1; }
- | /* EMPTY */
- { $$.on_empty = NULL; $$.on_error = NULL; }
- ;
-
-json_table:
- JSON_TABLE '('
- json_api_common_syntax
- json_table_columns_clause
- json_table_plan_clause_opt
- json_table_error_clause_opt
- ')'
- {
- JsonTable *n = makeNode(JsonTable);
-
- n->common = (JsonCommon *) $3;
- n->columns = $4;
- n->plan = (JsonTablePlan *) $5;
- n->on_error = $6;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_table_columns_clause:
- COLUMNS '(' json_table_column_definition_list ')' { $$ = $3; }
- ;
-
-json_table_column_definition_list:
- json_table_column_definition
- { $$ = list_make1($1); }
- | json_table_column_definition_list ',' json_table_column_definition
- { $$ = lappend($1, $3); }
- ;
-
-json_table_column_definition:
- json_table_ordinality_column_definition %prec json_table_column
- | json_table_regular_column_definition %prec json_table_column
- | json_table_formatted_column_definition %prec json_table_column
- | json_table_exists_column_definition %prec json_table_column
- | json_table_nested_columns
- ;
-
-json_table_ordinality_column_definition:
- ColId FOR ORDINALITY
- {
- JsonTableColumn *n = makeNode(JsonTableColumn);
-
- n->coltype = JTC_FOR_ORDINALITY;
- n->name = $1;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_table_regular_column_definition:
- ColId Typename
- json_table_column_path_specification_clause_opt
- json_wrapper_clause_opt
- json_quotes_clause_opt
- json_value_on_behavior_clause_opt
- {
- JsonTableColumn *n = makeNode(JsonTableColumn);
-
- n->coltype = JTC_REGULAR;
- n->name = $1;
- n->typeName = $2;
- n->format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
- n->wrapper = $4; /* JSW_NONE */
- n->omit_quotes = $5; /* false */
- n->pathspec = $3;
- n->on_empty = $6.on_empty;
- n->on_error = $6.on_error;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_table_exists_column_definition:
- ColId Typename
- EXISTS json_table_column_path_specification_clause_opt
- json_exists_error_clause_opt
- {
- JsonTableColumn *n = makeNode(JsonTableColumn);
-
- n->coltype = JTC_EXISTS;
- n->name = $1;
- n->typeName = $2;
- n->format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
- n->wrapper = JSW_NONE;
- n->omit_quotes = false;
- n->pathspec = $4;
- n->on_empty = NULL;
- n->on_error = $5;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_table_error_behavior:
- json_behavior_error
- | json_behavior_empty
- ;
-
-json_table_error_clause_opt:
- json_table_error_behavior ON ERROR_P { $$ = $1; }
- | /* EMPTY */ { $$ = NULL; }
- ;
-
-json_table_column_path_specification_clause_opt:
- PATH Sconst { $$ = $2; }
- | /* EMPTY */ %prec json_table_column { $$ = NULL; }
- ;
-
-json_table_formatted_column_definition:
- ColId Typename FORMAT json_representation
- json_table_column_path_specification_clause_opt
- json_wrapper_clause_opt
- json_quotes_clause_opt
- json_query_on_behavior_clause_opt
- {
- JsonTableColumn *n = makeNode(JsonTableColumn);
-
- n->coltype = JTC_FORMATTED;
- n->name = $1;
- n->typeName = $2;
- n->format = castNode(JsonFormat, $4);
- n->pathspec = $5;
- n->wrapper = $6;
- if (n->wrapper != JSW_NONE && $7 != JS_QUOTES_UNSPEC)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("SQL/JSON QUOTES behavior must not be specified when WITH WRAPPER is used"),
- parser_errposition(@7)));
- n->omit_quotes = $7 == JS_QUOTES_OMIT;
- n->on_empty = $8.on_empty;
- n->on_error = $8.on_error;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_table_nested_columns:
- NESTED path_opt Sconst
- json_as_path_name_clause_opt
- json_table_columns_clause
- {
- JsonTableColumn *n = makeNode(JsonTableColumn);
-
- n->coltype = JTC_NESTED;
- n->pathspec = $3;
- n->pathname = $4;
- n->columns = $5;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-path_opt:
- PATH { }
- | /* EMPTY */ { }
- ;
-
-json_table_plan_clause_opt:
- json_table_specific_plan { $$ = $1; }
- | json_table_default_plan { $$ = $1; }
- | /* EMPTY */ { $$ = NULL; }
- ;
-
-json_table_specific_plan:
- PLAN '(' json_table_plan ')' { $$ = $3; }
- ;
-
-json_table_plan:
- json_table_plan_simple
- | json_table_plan_parent_child
- | json_table_plan_sibling
- ;
-
-json_table_plan_simple:
- json_table_path_name
- {
- JsonTablePlan *n = makeNode(JsonTablePlan);
-
- n->plan_type = JSTP_SIMPLE;
- n->pathname = $1;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_table_plan_parent_child:
- json_table_plan_outer
- | json_table_plan_inner
- ;
-
-json_table_plan_outer:
- json_table_plan_simple OUTER_P json_table_plan_primary
- { $$ = makeJsonTableJoinedPlan(JSTPJ_OUTER, $1, $3, @1); }
- ;
-
-json_table_plan_inner:
- json_table_plan_simple INNER_P json_table_plan_primary
- { $$ = makeJsonTableJoinedPlan(JSTPJ_INNER, $1, $3, @1); }
- ;
-
-json_table_plan_sibling:
- json_table_plan_union
- | json_table_plan_cross
- ;
-
-json_table_plan_union:
- json_table_plan_primary UNION json_table_plan_primary
- { $$ = makeJsonTableJoinedPlan(JSTPJ_UNION, $1, $3, @1); }
- | json_table_plan_union UNION json_table_plan_primary
- { $$ = makeJsonTableJoinedPlan(JSTPJ_UNION, $1, $3, @1); }
- ;
-
-json_table_plan_cross:
- json_table_plan_primary CROSS json_table_plan_primary
- { $$ = makeJsonTableJoinedPlan(JSTPJ_CROSS, $1, $3, @1); }
- | json_table_plan_cross CROSS json_table_plan_primary
- { $$ = makeJsonTableJoinedPlan(JSTPJ_CROSS, $1, $3, @1); }
- ;
-
-json_table_plan_primary:
- json_table_plan_simple { $$ = $1; }
- | '(' json_table_plan ')'
- {
- castNode(JsonTablePlan, $2)->location = @1;
- $$ = $2;
- }
- ;
-
-json_table_default_plan:
- PLAN DEFAULT '(' json_table_default_plan_choices ')'
- {
- JsonTablePlan *n = makeNode(JsonTablePlan);
-
- n->plan_type = JSTP_DEFAULT;
- n->join_type = $4;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_table_default_plan_choices:
- json_table_default_plan_inner_outer { $$ = $1 | JSTPJ_UNION; }
- | json_table_default_plan_inner_outer ','
- json_table_default_plan_union_cross { $$ = $1 | $3; }
- | json_table_default_plan_union_cross { $$ = $1 | JSTPJ_OUTER; }
- | json_table_default_plan_union_cross ','
- json_table_default_plan_inner_outer { $$ = $1 | $3; }
- ;
-
-json_table_default_plan_inner_outer:
- INNER_P { $$ = JSTPJ_INNER; }
- | OUTER_P { $$ = JSTPJ_OUTER; }
- ;
-
-json_table_default_plan_union_cross:
- UNION { $$ = JSTPJ_UNION; }
- | CROSS { $$ = JSTPJ_CROSS; }
- ;
-
-json_returning_clause_opt:
- RETURNING Typename
- {
- JsonOutput *n = makeNode(JsonOutput);
-
- n->typeName = $2;
- n->returning = makeNode(JsonReturning);
- n->returning->format =
- makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, @2);
- $$ = (Node *) n;
- }
- | /* EMPTY */ { $$ = NULL; }
- ;
-
-json_output_clause_opt:
- RETURNING Typename json_format_clause_opt
- {
- JsonOutput *n = makeNode(JsonOutput);
-
- n->typeName = $2;
- n->returning = makeNode(JsonReturning);
- n->returning->format = (JsonFormat *) $3;
- $$ = (Node *) n;
- }
- | /* EMPTY */ { $$ = NULL; }
- ;
-
-json_exists_predicate:
- JSON_EXISTS '('
- json_api_common_syntax
- json_returning_clause_opt
- json_exists_error_clause_opt
- ')'
- {
- JsonFuncExpr *p = makeNode(JsonFuncExpr);
-
- p->op = JSON_EXISTS_OP;
- p->common = (JsonCommon *) $3;
- p->output = (JsonOutput *) $4;
- p->on_error = $5;
- p->location = @1;
- $$ = (Node *) p;
- }
- ;
-
-json_exists_error_clause_opt:
- json_exists_error_behavior ON ERROR_P { $$ = $1; }
- | /* EMPTY */ { $$ = NULL; }
- ;
-
-json_exists_error_behavior:
- json_behavior_error
- | json_behavior_true
- | json_behavior_false
- | json_behavior_unknown
- ;
-
-json_value_constructor:
- json_object_constructor
- | json_array_constructor
- ;
-
-json_object_constructor:
- JSON_OBJECT '(' json_object_args ')'
- {
- $$ = $3;
- }
- ;
-
-json_object_args:
- json_object_constructor_args
- | json_object_func_args
- ;
-
-json_object_func_args:
- func_arg_list
- {
- List *func = list_make1(makeString("json_object"));
-
- $$ = (Node *) makeFuncCall(func, $1, COERCE_EXPLICIT_CALL, @1);
- }
- ;
-
-json_object_constructor_args:
- json_object_constructor_args_opt json_output_clause_opt
- {
- JsonObjectConstructor *n = (JsonObjectConstructor *) $1;
-
- n->output = (JsonOutput *) $2;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_object_constructor_args_opt:
- json_name_and_value_list
- json_object_constructor_null_clause_opt
- json_key_uniqueness_constraint_opt
- {
- JsonObjectConstructor *n = makeNode(JsonObjectConstructor);
-
- n->exprs = $1;
- n->absent_on_null = $2;
- n->unique = $3;
- $$ = (Node *) n;
- }
- | /* EMPTY */
- {
- JsonObjectConstructor *n = makeNode(JsonObjectConstructor);
-
- n->exprs = NULL;
- n->absent_on_null = false;
- n->unique = false;
- $$ = (Node *) n;
- }
- ;
-
-json_name_and_value_list:
- json_name_and_value
- { $$ = list_make1($1); }
- | json_name_and_value_list ',' json_name_and_value
- { $$ = lappend($1, $3); }
- ;
-
-json_name_and_value:
-/* TODO This is not supported due to conflicts
- KEY c_expr VALUE_P json_value_expr %prec POSTFIXOP
- { $$ = makeJsonKeyValue($2, $4); }
- |
-*/
- c_expr VALUE_P json_value_expr
- { $$ = makeJsonKeyValue($1, $3); }
- |
- a_expr ':' json_value_expr
- { $$ = makeJsonKeyValue($1, $3); }
- ;
-
-json_object_constructor_null_clause_opt:
- NULL_P ON NULL_P { $$ = false; }
- | ABSENT ON NULL_P { $$ = true; }
- | /* EMPTY */ { $$ = false; }
- ;
-
-json_array_constructor:
- JSON_ARRAY '('
- json_value_expr_list
- json_array_constructor_null_clause_opt
- json_output_clause_opt
- ')'
- {
- JsonArrayConstructor *n = makeNode(JsonArrayConstructor);
-
- n->exprs = $3;
- n->absent_on_null = $4;
- n->output = (JsonOutput *) $5;
- n->location = @1;
- $$ = (Node *) n;
- }
- | JSON_ARRAY '('
- select_no_parens
- /* json_format_clause_opt */
- /* json_array_constructor_null_clause_opt */
- json_output_clause_opt
- ')'
- {
- JsonArrayQueryConstructor *n = makeNode(JsonArrayQueryConstructor);
-
- n->query = $3;
- n->format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
- /* n->format = $4; */
- n->absent_on_null = true /* $5 */;
- n->output = (JsonOutput *) $4;
- n->location = @1;
- $$ = (Node *) n;
- }
- | JSON_ARRAY '('
- json_output_clause_opt
- ')'
- {
- JsonArrayConstructor *n = makeNode(JsonArrayConstructor);
-
- n->exprs = NIL;
- n->absent_on_null = true;
- n->output = (JsonOutput *) $3;
- n->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_value_expr_list:
- json_value_expr { $$ = list_make1($1); }
- | json_value_expr_list ',' json_value_expr { $$ = lappend($1, $3);}
- ;
-
-json_array_constructor_null_clause_opt:
- NULL_P ON NULL_P { $$ = false; }
- | ABSENT ON NULL_P { $$ = true; }
- | /* EMPTY */ { $$ = true; }
- ;
-
-json_aggregate_func:
- json_object_aggregate_constructor
- | json_array_aggregate_constructor
- ;
-
-json_object_aggregate_constructor:
- JSON_OBJECTAGG '('
- json_name_and_value
- json_object_constructor_null_clause_opt
- json_key_uniqueness_constraint_opt
- json_output_clause_opt
- ')'
- {
- JsonObjectAgg *n = makeNode(JsonObjectAgg);
-
- n->arg = (JsonKeyValue *) $3;
- n->absent_on_null = $4;
- n->unique = $5;
- n->constructor = makeNode(JsonAggConstructor);
- n->constructor->output = (JsonOutput *) $6;
- n->constructor->agg_order = NULL;
- n->constructor->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_array_aggregate_constructor:
- JSON_ARRAYAGG '('
- json_value_expr
- json_array_aggregate_order_by_clause_opt
- json_array_constructor_null_clause_opt
- json_output_clause_opt
- ')'
- {
- JsonArrayAgg *n = makeNode(JsonArrayAgg);
-
- n->arg = (JsonValueExpr *) $3;
- n->absent_on_null = $5;
- n->constructor = makeNode(JsonAggConstructor);
- n->constructor->agg_order = $4;
- n->constructor->output = (JsonOutput *) $6;
- n->constructor->location = @1;
- $$ = (Node *) n;
- }
- ;
-
-json_array_aggregate_order_by_clause_opt:
- ORDER BY sortby_list { $$ = $3; }
- | /* EMPTY */ { $$ = NIL; }
- ;
/*****************************************************************************
*
@@ -17664,7 +16643,6 @@ BareColLabel: IDENT { $$ = $1; }
*/
unreserved_keyword:
ABORT_P
- | ABSENT
| ABSOLUTE_P
| ACCESS
| ACTION
@@ -17705,7 +16683,6 @@ unreserved_keyword:
| COMMIT
| COMMITTED
| COMPRESSION
- | CONDITIONAL
| CONFIGURATION
| CONFLICT
| CONNECTION
@@ -17742,12 +16719,10 @@ unreserved_keyword:
| DOUBLE_P
| DROP
| EACH
- | EMPTY_P
| ENABLE_P
| ENCODING
| ENCRYPTED
| ENUM_P
- | ERROR_P
| ESCAPE
| EVENT
| EXCLUDE
@@ -17764,7 +16739,6 @@ unreserved_keyword:
| FIRST_P
| FOLLOWING
| FORCE
- | FORMAT
| FORWARD
| FUNCTION
| FUNCTIONS
@@ -17796,9 +16770,7 @@ unreserved_keyword:
| INSTEAD
| INVOKER
| ISOLATION
- | KEEP
| KEY
- | KEYS
| LABEL
| LANGUAGE
| LARGE_P
@@ -17826,7 +16798,6 @@ unreserved_keyword:
| MOVE
| NAME_P
| NAMES
- | NESTED
| NEW
| NEXT
| NFC
@@ -17844,7 +16815,6 @@ unreserved_keyword:
| OFF
| OIDS
| OLD
- | OMIT
| OPERATOR
| OPTION
| OPTIONS
@@ -17861,8 +16831,6 @@ unreserved_keyword:
| PARTITION
| PASSING
| PASSWORD
- | PATH
- | PLAN
| PLANS
| POLICY
| PRECEDING
@@ -17877,7 +16845,6 @@ unreserved_keyword:
| PROGRAM
| PUBLICATION
| QUOTE
- | QUOTES
| RANGE
| READ
| REASSIGN
@@ -17907,7 +16874,6 @@ unreserved_keyword:
| ROWS
| RULE
| SAVEPOINT
- | SCALAR
| SCHEMA
| SCHEMAS
| SCROLL
@@ -17937,7 +16903,6 @@ unreserved_keyword:
| STORAGE
| STORED
| STRICT_P
- | STRING
| STRIP_P
| SUBSCRIPTION
| SUPPORT
@@ -17960,7 +16925,6 @@ unreserved_keyword:
| UESCAPE
| UNBOUNDED
| UNCOMMITTED
- | UNCONDITIONAL
| UNENCRYPTED
| UNKNOWN
| UNLISTEN
@@ -18018,17 +16982,6 @@ col_name_keyword:
| INT_P
| INTEGER
| INTERVAL
- | JSON
- | JSON_ARRAY
- | JSON_ARRAYAGG
- | JSON_EXISTS
- | JSON_OBJECT
- | JSON_OBJECTAGG
- | JSON_QUERY
- | JSON_SCALAR
- | JSON_SERIALIZE
- | JSON_TABLE
- | JSON_VALUE
| LEAST
| NATIONAL
| NCHAR
@@ -18197,7 +17150,6 @@ reserved_keyword:
*/
bare_label_keyword:
ABORT_P
- | ABSENT
| ABSOLUTE_P
| ACCESS
| ACTION
@@ -18260,7 +17212,6 @@ bare_label_keyword:
| COMMITTED
| COMPRESSION
| CONCURRENTLY
- | CONDITIONAL
| CONFIGURATION
| CONFLICT
| CONNECTION
@@ -18313,13 +17264,11 @@ bare_label_keyword:
| DROP
| EACH
| ELSE
- | EMPTY_P
| ENABLE_P
| ENCODING
| ENCRYPTED
| END_P
| ENUM_P
- | ERROR_P
| ESCAPE
| EVENT
| EXCLUDE
@@ -18340,7 +17289,6 @@ bare_label_keyword:
| FOLLOWING
| FORCE
| FOREIGN
- | FORMAT
| FORWARD
| FREEZE
| FULL
@@ -18385,20 +17333,7 @@ bare_label_keyword:
| IS
| ISOLATION
| JOIN
- | JSON
- | JSON_ARRAY
- | JSON_ARRAYAGG
- | JSON_EXISTS
- | JSON_OBJECT
- | JSON_OBJECTAGG
- | JSON_QUERY
- | JSON_SCALAR
- | JSON_SERIALIZE
- | JSON_TABLE
- | JSON_VALUE
- | KEEP
| KEY
- | KEYS
| LABEL
| LANGUAGE
| LARGE_P
@@ -18434,7 +17369,6 @@ bare_label_keyword:
| NATIONAL
| NATURAL
| NCHAR
- | NESTED
| NEW
| NEXT
| NFC
@@ -18458,7 +17392,6 @@ bare_label_keyword:
| OFF
| OIDS
| OLD
- | OMIT
| ONLY
| OPERATOR
| OPTION
@@ -18479,9 +17412,7 @@ bare_label_keyword:
| PARTITION
| PASSING
| PASSWORD
- | PATH
| PLACING
- | PLAN
| PLANS
| POLICY
| POSITION
@@ -18498,7 +17429,6 @@ bare_label_keyword:
| PROGRAM
| PUBLICATION
| QUOTE
- | QUOTES
| RANGE
| READ
| REAL
@@ -18532,7 +17462,6 @@ bare_label_keyword:
| ROWS
| RULE
| SAVEPOINT
- | SCALAR
| SCHEMA
| SCHEMAS
| SCROLL
@@ -18567,7 +17496,6 @@ bare_label_keyword:
| STORAGE
| STORED
| STRICT_P
- | STRING
| STRIP_P
| SUBSCRIPTION
| SUBSTRING
@@ -18601,7 +17529,6 @@ bare_label_keyword:
| UESCAPE
| UNBOUNDED
| UNCOMMITTED
- | UNCONDITIONAL
| UNENCRYPTED
| UNIQUE
| UNKNOWN
diff --git a/src/backend/parser/parse_clause.c b/src/backend/parser/parse_clause.c
index b85fbebd00..061d0bcc50 100644
--- a/src/backend/parser/parse_clause.c
+++ b/src/backend/parser/parse_clause.c
@@ -690,9 +690,7 @@ transformRangeTableFunc(ParseState *pstate, RangeTableFunc *rtf)
char **names;
int colno;
- /* Currently only XMLTABLE and JSON_TABLE are supported */
-
- tf->functype = TFT_XMLTABLE;
+ /* Currently only XMLTABLE is supported */
constructName = "XMLTABLE";
docType = XMLOID;
@@ -1099,17 +1097,13 @@ transformFromClauseItem(ParseState *pstate, Node *n,
rtr->rtindex = nsitem->p_rtindex;
return (Node *) rtr;
}
- else if (IsA(n, RangeTableFunc) || IsA(n, JsonTable))
+ else if (IsA(n, RangeTableFunc))
{
/* table function is like a plain relation */
RangeTblRef *rtr;
ParseNamespaceItem *nsitem;
- if (IsA(n, RangeTableFunc))
- nsitem = transformRangeTableFunc(pstate, (RangeTableFunc *) n);
- else
- nsitem = transformJsonTable(pstate, (JsonTable *) n);
-
+ nsitem = transformRangeTableFunc(pstate, (RangeTableFunc *) n);
*top_nsitem = nsitem;
*namespace = list_make1(nsitem);
rtr = makeNode(RangeTblRef);
diff --git a/src/backend/parser/parse_collate.c b/src/backend/parser/parse_collate.c
index e90af4c477..7582faabb3 100644
--- a/src/backend/parser/parse_collate.c
+++ b/src/backend/parser/parse_collate.c
@@ -691,13 +691,6 @@ assign_collations_walker(Node *node, assign_collations_context *context)
&loccontext);
}
break;
- case T_JsonExpr:
-
- /*
- * Context item and PASSING arguments are already
- * marked with collations in parse_expr.c.
- */
- break;
default:
/*
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index fabb5f7207..7aaf1c673f 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);
-}
diff --git a/src/backend/parser/parse_jsontable.c b/src/backend/parser/parse_jsontable.c
deleted file mode 100644
index 3e94071248..0000000000
--- a/src/backend/parser/parse_jsontable.c
+++ /dev/null
@@ -1,732 +0,0 @@
-/*-------------------------------------------------------------------------
- *
- * parse_jsontable.c
- * parsing of JSON_TABLE
- *
- * Portions Copyright (c) 1996-2022, PostgreSQL Global Development Group
- * Portions Copyright (c) 1994, Regents of the University of California
- *
- *
- * IDENTIFICATION
- * src/backend/parser/parse_jsontable.c
- *
- *-------------------------------------------------------------------------
- */
-
-#include "postgres.h"
-
-#include "catalog/pg_collation.h"
-#include "catalog/pg_type.h"
-#include "miscadmin.h"
-#include "nodes/makefuncs.h"
-#include "nodes/nodeFuncs.h"
-#include "optimizer/optimizer.h"
-#include "parser/parse_clause.h"
-#include "parser/parse_collate.h"
-#include "parser/parse_expr.h"
-#include "parser/parse_relation.h"
-#include "parser/parse_type.h"
-#include "utils/builtins.h"
-#include "utils/json.h"
-#include "utils/lsyscache.h"
-
-/* Context for JSON_TABLE transformation */
-typedef struct JsonTableContext
-{
- ParseState *pstate; /* parsing state */
- JsonTable *table; /* untransformed node */
- TableFunc *tablefunc; /* transformed node */
- List *pathNames; /* list of all path and columns names */
- int pathNameId; /* path name id counter */
- Oid contextItemTypid; /* type oid of context item (json/jsonb) */
-} JsonTableContext;
-
-static JsonTableParent *transformJsonTableColumns(JsonTableContext *cxt,
- JsonTablePlan *plan,
- List *columns,
- char *pathSpec,
- char **pathName,
- int location);
-
-static Node *
-makeStringConst(char *str, int location)
-{
- A_Const *n = makeNode(A_Const);
-
- n->val.node.type = T_String;
- n->val.sval.sval = str;
- n->location = location;
-
- return (Node *) n;
-}
-
-/*
- * Transform JSON_TABLE column
- * - regular column into JSON_VALUE()
- * - FORMAT JSON column into JSON_QUERY()
- * - EXISTS column into JSON_EXISTS()
- */
-static Node *
-transformJsonTableColumn(JsonTableColumn *jtc, Node *contextItemExpr,
- List *passingArgs, bool errorOnError)
-{
- JsonFuncExpr *jfexpr = makeNode(JsonFuncExpr);
- JsonCommon *common = makeNode(JsonCommon);
- JsonOutput *output = makeNode(JsonOutput);
- char *pathspec;
- JsonFormat *default_format;
-
- jfexpr->op =
- jtc->coltype == JTC_REGULAR ? JSON_VALUE_OP :
- jtc->coltype == JTC_EXISTS ? JSON_EXISTS_OP : JSON_QUERY_OP;
- jfexpr->common = common;
- jfexpr->output = output;
- jfexpr->on_empty = jtc->on_empty;
- jfexpr->on_error = jtc->on_error;
- if (!jfexpr->on_error && errorOnError)
- jfexpr->on_error = makeJsonBehavior(JSON_BEHAVIOR_ERROR, NULL);
- jfexpr->omit_quotes = jtc->omit_quotes;
- jfexpr->wrapper = jtc->wrapper;
- jfexpr->location = jtc->location;
-
- output->typeName = jtc->typeName;
- output->returning = makeNode(JsonReturning);
- output->returning->format = jtc->format;
-
- default_format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
-
- common->pathname = NULL;
- common->expr = makeJsonValueExpr((Expr *) contextItemExpr, default_format);
- common->passing = passingArgs;
-
- if (jtc->pathspec)
- pathspec = jtc->pathspec;
- else
- {
- /* Construct default path as '$."column_name"' */
- StringInfoData path;
-
- initStringInfo(&path);
-
- appendStringInfoString(&path, "$.");
- escape_json(&path, jtc->name);
-
- pathspec = path.data;
- }
-
- common->pathspec = makeStringConst(pathspec, -1);
-
- return (Node *) jfexpr;
-}
-
-static bool
-isJsonTablePathNameDuplicate(JsonTableContext *cxt, const char *pathname)
-{
- ListCell *lc;
-
- foreach(lc, cxt->pathNames)
- {
- if (!strcmp(pathname, (const char *) lfirst(lc)))
- return true;
- }
-
- return false;
-}
-
-/* Register the column name in the path name list. */
-static void
-registerJsonTableColumn(JsonTableContext *cxt, char *colname)
-{
- if (isJsonTablePathNameDuplicate(cxt, colname))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_ALIAS),
- errmsg("duplicate JSON_TABLE column name: %s", colname),
- errhint("JSON_TABLE column names must be distinct from one another.")));
-
- cxt->pathNames = lappend(cxt->pathNames, colname);
-}
-
-/* Recursively register all nested column names in the path name list. */
-static void
-registerAllJsonTableColumns(JsonTableContext *cxt, List *columns)
-{
- ListCell *lc;
-
- foreach(lc, columns)
- {
- JsonTableColumn *jtc = castNode(JsonTableColumn, lfirst(lc));
-
- if (jtc->coltype == JTC_NESTED)
- {
- if (jtc->pathname)
- registerJsonTableColumn(cxt, jtc->pathname);
-
- registerAllJsonTableColumns(cxt, jtc->columns);
- }
- else
- {
- registerJsonTableColumn(cxt, jtc->name);
- }
- }
-}
-
-/* Generate a new unique JSON_TABLE path name. */
-static char *
-generateJsonTablePathName(JsonTableContext *cxt)
-{
- char namebuf[32];
- char *name = namebuf;
-
- do
- {
- snprintf(namebuf, sizeof(namebuf), "json_table_path_%d",
- ++cxt->pathNameId);
- } while (isJsonTablePathNameDuplicate(cxt, name));
-
- name = pstrdup(name);
- cxt->pathNames = lappend(cxt->pathNames, name);
-
- return name;
-}
-
-/* Collect sibling path names from plan to the specified list. */
-static void
-collectSiblingPathsInJsonTablePlan(JsonTablePlan *plan, List **paths)
-{
- if (plan->plan_type == JSTP_SIMPLE)
- *paths = lappend(*paths, plan->pathname);
- else if (plan->plan_type == JSTP_JOINED)
- {
- if (plan->join_type == JSTPJ_INNER ||
- plan->join_type == JSTPJ_OUTER)
- {
- Assert(plan->plan1->plan_type == JSTP_SIMPLE);
- *paths = lappend(*paths, plan->plan1->pathname);
- }
- else if (plan->join_type == JSTPJ_CROSS ||
- plan->join_type == JSTPJ_UNION)
- {
- collectSiblingPathsInJsonTablePlan(plan->plan1, paths);
- collectSiblingPathsInJsonTablePlan(plan->plan2, paths);
- }
- else
- elog(ERROR, "invalid JSON_TABLE join type %d",
- plan->join_type);
- }
-}
-
-/*
- * Validate child JSON_TABLE plan by checking that:
- * - all nested columns have path names specified
- * - all nested columns have corresponding node in the sibling plan
- * - plan does not contain duplicate or extra nodes
- */
-static void
-validateJsonTableChildPlan(ParseState *pstate, JsonTablePlan *plan,
- List *columns)
-{
- ListCell *lc1;
- List *siblings = NIL;
- int nchildren = 0;
-
- if (plan)
- collectSiblingPathsInJsonTablePlan(plan, &siblings);
-
- foreach(lc1, columns)
- {
- JsonTableColumn *jtc = castNode(JsonTableColumn, lfirst(lc1));
-
- if (jtc->coltype == JTC_NESTED)
- {
- ListCell *lc2;
- bool found = false;
-
- if (!jtc->pathname)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("nested JSON_TABLE columns must contain an explicit AS pathname specification if an explicit PLAN clause is used"),
- parser_errposition(pstate, jtc->location)));
-
- /* find nested path name in the list of sibling path names */
- foreach(lc2, siblings)
- {
- if ((found = !strcmp(jtc->pathname, lfirst(lc2))))
- break;
- }
-
- if (!found)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE plan"),
- errdetail("Plan node for nested path %s was not found in plan.", jtc->pathname),
- parser_errposition(pstate, jtc->location)));
-
- nchildren++;
- }
- }
-
- if (list_length(siblings) > nchildren)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE plan"),
- errdetail("Plan node contains some extra or duplicate sibling nodes."),
- parser_errposition(pstate, plan ? plan->location : -1)));
-}
-
-static JsonTableColumn *
-findNestedJsonTableColumn(List *columns, const char *pathname)
-{
- ListCell *lc;
-
- foreach(lc, columns)
- {
- JsonTableColumn *jtc = castNode(JsonTableColumn, lfirst(lc));
-
- if (jtc->coltype == JTC_NESTED &&
- jtc->pathname &&
- !strcmp(jtc->pathname, pathname))
- return jtc;
- }
-
- return NULL;
-}
-
-static Node *
-transformNestedJsonTableColumn(JsonTableContext *cxt, JsonTableColumn *jtc,
- JsonTablePlan *plan)
-{
- JsonTableParent *node;
- char *pathname = jtc->pathname;
-
- node = transformJsonTableColumns(cxt, plan, jtc->columns, jtc->pathspec,
- &pathname, jtc->location);
- node->name = pstrdup(pathname);
-
- return (Node *) node;
-}
-
-static Node *
-makeJsonTableSiblingJoin(bool cross, Node *lnode, Node *rnode)
-{
- JsonTableSibling *join = makeNode(JsonTableSibling);
-
- join->larg = lnode;
- join->rarg = rnode;
- join->cross = cross;
-
- return (Node *) join;
-}
-
-/*
- * Recursively transform child JSON_TABLE plan.
- *
- * Default plan is transformed into a cross/union join of its nested columns.
- * Simple and outer/inner plans are transformed into a JsonTableParent by
- * finding and transforming corresponding nested column.
- * Sibling plans are recursively transformed into a JsonTableSibling.
- */
-static Node *
-transformJsonTableChildPlan(JsonTableContext *cxt, JsonTablePlan *plan,
- List *columns)
-{
- JsonTableColumn *jtc = NULL;
-
- if (!plan || plan->plan_type == JSTP_DEFAULT)
- {
- /* unspecified or default plan */
- Node *res = NULL;
- ListCell *lc;
- bool cross = plan && (plan->join_type & JSTPJ_CROSS);
-
- /* transform all nested columns into cross/union join */
- foreach(lc, columns)
- {
- JsonTableColumn *col = castNode(JsonTableColumn, lfirst(lc));
- Node *node;
-
- if (col->coltype != JTC_NESTED)
- continue;
-
- node = transformNestedJsonTableColumn(cxt, col, plan);
-
- /* join transformed node with previous sibling nodes */
- res = res ? makeJsonTableSiblingJoin(cross, res, node) : node;
- }
-
- return res;
- }
- else if (plan->plan_type == JSTP_SIMPLE)
- {
- jtc = findNestedJsonTableColumn(columns, plan->pathname);
- }
- else if (plan->plan_type == JSTP_JOINED)
- {
- if (plan->join_type == JSTPJ_INNER ||
- plan->join_type == JSTPJ_OUTER)
- {
- Assert(plan->plan1->plan_type == JSTP_SIMPLE);
- jtc = findNestedJsonTableColumn(columns, plan->plan1->pathname);
- }
- else
- {
- Node *node1 = transformJsonTableChildPlan(cxt, plan->plan1,
- columns);
- Node *node2 = transformJsonTableChildPlan(cxt, plan->plan2,
- columns);
-
- return makeJsonTableSiblingJoin(plan->join_type == JSTPJ_CROSS,
- node1, node2);
- }
- }
- else
- elog(ERROR, "invalid JSON_TABLE plan type %d", plan->plan_type);
-
- if (!jtc)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE plan"),
- errdetail("Path name was %s not found in nested columns list.",
- plan->pathname),
- parser_errposition(cxt->pstate, plan->location)));
-
- return transformNestedJsonTableColumn(cxt, jtc, plan);
-}
-
-/* Check whether type is json/jsonb, array, or record. */
-static bool
-typeIsComposite(Oid typid)
-{
- char typtype;
-
- if (typid == JSONOID ||
- typid == JSONBOID ||
- typid == RECORDOID ||
- type_is_array(typid))
- return true;
-
- typtype = get_typtype(typid);
-
- if (typtype == TYPTYPE_COMPOSITE)
- return true;
-
- if (typtype == TYPTYPE_DOMAIN)
- return typeIsComposite(getBaseType(typid));
-
- return false;
-}
-
-/* Append transformed non-nested JSON_TABLE columns to the TableFunc node */
-static void
-appendJsonTableColumns(JsonTableContext *cxt, List *columns)
-{
- ListCell *col;
- ParseState *pstate = cxt->pstate;
- JsonTable *jt = cxt->table;
- TableFunc *tf = cxt->tablefunc;
- bool errorOnError = jt->on_error &&
- jt->on_error->btype == JSON_BEHAVIOR_ERROR;
-
- foreach(col, columns)
- {
- JsonTableColumn *rawc = castNode(JsonTableColumn, lfirst(col));
- Oid typid;
- int32 typmod;
- Node *colexpr;
-
- if (rawc->name)
- {
- /* make sure column names are unique */
- ListCell *colname;
-
- foreach(colname, tf->colnames)
- if (!strcmp((const char *) colname, rawc->name))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("column name \"%s\" is not unique",
- rawc->name),
- parser_errposition(pstate, rawc->location)));
-
- tf->colnames = lappend(tf->colnames,
- makeString(pstrdup(rawc->name)));
- }
-
- /*
- * Determine the type and typmod for the new column. FOR ORDINALITY
- * columns are INTEGER by standard; the others are user-specified.
- */
- switch (rawc->coltype)
- {
- case JTC_FOR_ORDINALITY:
- colexpr = NULL;
- typid = INT4OID;
- typmod = -1;
- break;
-
- case JTC_REGULAR:
- typenameTypeIdAndMod(pstate, rawc->typeName, &typid, &typmod);
-
- /*
- * Use implicit FORMAT JSON for composite types (arrays and
- * records)
- */
- if (typeIsComposite(typid))
- rawc->coltype = JTC_FORMATTED;
- else if (rawc->wrapper != JSW_NONE)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("cannot use WITH WRAPPER clause with scalar columns"),
- parser_errposition(pstate, rawc->location)));
- else if (rawc->omit_quotes)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("cannot use OMIT QUOTES clause with scalar columns"),
- parser_errposition(pstate, rawc->location)));
-
- /* FALLTHROUGH */
- case JTC_EXISTS:
- case JTC_FORMATTED:
- {
- Node *je;
- CaseTestExpr *param = makeNode(CaseTestExpr);
-
- param->collation = InvalidOid;
- param->typeId = cxt->contextItemTypid;
- param->typeMod = -1;
-
- je = transformJsonTableColumn(rawc, (Node *) param,
- NIL, errorOnError);
-
- colexpr = transformExpr(pstate, je, EXPR_KIND_FROM_FUNCTION);
- assign_expr_collations(pstate, colexpr);
-
- typid = exprType(colexpr);
- typmod = exprTypmod(colexpr);
- break;
- }
-
- case JTC_NESTED:
- continue;
-
- default:
- elog(ERROR, "unknown JSON_TABLE column type: %d", rawc->coltype);
- break;
- }
-
- tf->coltypes = lappend_oid(tf->coltypes, typid);
- tf->coltypmods = lappend_int(tf->coltypmods, typmod);
- tf->colcollations = lappend_oid(tf->colcollations, get_typcollation(typid));
- tf->colvalexprs = lappend(tf->colvalexprs, colexpr);
- }
-}
-
-/*
- * Create transformed JSON_TABLE parent plan node by appending all non-nested
- * columns to the TableFunc node and remembering their indices in the
- * colvalexprs list.
- */
-static JsonTableParent *
-makeParentJsonTableNode(JsonTableContext *cxt, char *pathSpec, List *columns)
-{
- JsonTableParent *node = makeNode(JsonTableParent);
-
- node->path = makeConst(JSONPATHOID, -1, InvalidOid, -1,
- DirectFunctionCall1(jsonpath_in,
- CStringGetDatum(pathSpec)),
- false, false);
-
- /* save start of column range */
- node->colMin = list_length(cxt->tablefunc->colvalexprs);
-
- appendJsonTableColumns(cxt, columns);
-
- /* save end of column range */
- node->colMax = list_length(cxt->tablefunc->colvalexprs) - 1;
-
- node->errorOnError =
- cxt->table->on_error &&
- cxt->table->on_error->btype == JSON_BEHAVIOR_ERROR;
-
- return node;
-}
-
-static JsonTableParent *
-transformJsonTableColumns(JsonTableContext *cxt, JsonTablePlan *plan,
- List *columns, char *pathSpec, char **pathName,
- int location)
-{
- JsonTableParent *node;
- JsonTablePlan *childPlan;
- bool defaultPlan = !plan || plan->plan_type == JSTP_DEFAULT;
-
- if (!*pathName)
- {
- if (cxt->table->plan)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE expression"),
- errdetail("JSON_TABLE columns must contain "
- "explicit AS pathname specification if "
- "explicit PLAN clause is used"),
- parser_errposition(cxt->pstate, location)));
-
- *pathName = generateJsonTablePathName(cxt);
- }
-
- if (defaultPlan)
- childPlan = plan;
- else
- {
- /* validate parent and child plans */
- JsonTablePlan *parentPlan;
-
- if (plan->plan_type == JSTP_JOINED)
- {
- if (plan->join_type != JSTPJ_INNER &&
- plan->join_type != JSTPJ_OUTER)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE plan"),
- errdetail("Expected INNER or OUTER JSON_TABLE plan node."),
- parser_errposition(cxt->pstate, plan->location)));
-
- parentPlan = plan->plan1;
- childPlan = plan->plan2;
-
- Assert(parentPlan->plan_type != JSTP_JOINED);
- Assert(parentPlan->pathname);
- }
- else
- {
- parentPlan = plan;
- childPlan = NULL;
- }
-
- if (strcmp(parentPlan->pathname, *pathName))
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("invalid JSON_TABLE plan"),
- errdetail("Path name mismatch: expected %s but %s is given.",
- *pathName, parentPlan->pathname),
- parser_errposition(cxt->pstate, plan->location)));
-
- validateJsonTableChildPlan(cxt->pstate, childPlan, columns);
- }
-
- /* transform only non-nested columns */
- node = makeParentJsonTableNode(cxt, pathSpec, columns);
- node->name = pstrdup(*pathName);
-
- if (childPlan || defaultPlan)
- {
- /* transform recursively nested columns */
- node->child = transformJsonTableChildPlan(cxt, childPlan, columns);
- if (node->child)
- node->outerJoin = !plan || (plan->join_type & JSTPJ_OUTER);
- /* else: default plan case, no children found */
- }
-
- return node;
-}
-
-/*
- * transformJsonTable -
- * Transform a raw JsonTable into TableFunc.
- *
- * Transform the document-generating expression, the row-generating expression,
- * the column-generating expressions, and the default value expressions.
- */
-ParseNamespaceItem *
-transformJsonTable(ParseState *pstate, JsonTable *jt)
-{
- JsonTableContext cxt;
- TableFunc *tf = makeNode(TableFunc);
- JsonFuncExpr *jfe = makeNode(JsonFuncExpr);
- JsonTablePlan *plan = jt->plan;
- JsonCommon *jscommon;
- char *rootPathName = jt->common->pathname;
- char *rootPath;
- bool is_lateral;
-
- cxt.pstate = pstate;
- cxt.table = jt;
- cxt.tablefunc = tf;
- cxt.pathNames = NIL;
- cxt.pathNameId = 0;
-
- if (rootPathName)
- registerJsonTableColumn(&cxt, rootPathName);
-
- registerAllJsonTableColumns(&cxt, jt->columns);
-
-#if 0 /* XXX it' unclear from the standard whether
- * root path name is mandatory or not */
- if (plan && plan->plan_type != JSTP_DEFAULT && !rootPathName)
- {
- /* Assign root path name and create corresponding plan node */
- JsonTablePlan *rootNode = makeNode(JsonTablePlan);
- JsonTablePlan *rootPlan = (JsonTablePlan *)
- makeJsonTableJoinedPlan(JSTPJ_OUTER, (Node *) rootNode,
- (Node *) plan, jt->location);
-
- rootPathName = generateJsonTablePathName(&cxt);
-
- rootNode->plan_type = JSTP_SIMPLE;
- rootNode->pathname = rootPathName;
-
- plan = rootPlan;
- }
-#endif
-
- jscommon = copyObject(jt->common);
- jscommon->pathspec = makeStringConst(pstrdup("$"), -1);
-
- jfe->op = JSON_TABLE_OP;
- jfe->common = jscommon;
- jfe->on_error = jt->on_error;
- jfe->location = jt->common->location;
-
- /*
- * We make lateral_only names of this level visible, whether or not the
- * RangeTableFunc is explicitly marked LATERAL. This is needed for SQL
- * spec compliance and seems useful on convenience grounds for all
- * functions in FROM.
- *
- * (LATERAL can't nest within a single pstate level, so we don't need
- * save/restore logic here.)
- */
- Assert(!pstate->p_lateral_active);
- pstate->p_lateral_active = true;
-
- tf->functype = TFT_JSON_TABLE;
- tf->docexpr = transformExpr(pstate, (Node *) jfe, EXPR_KIND_FROM_FUNCTION);
-
- cxt.contextItemTypid = exprType(tf->docexpr);
-
- if (!IsA(jt->common->pathspec, A_Const) ||
- castNode(A_Const, jt->common->pathspec)->val.node.type != T_String)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("only string constants supported in JSON_TABLE path specification"),
- parser_errposition(pstate,
- exprLocation(jt->common->pathspec))));
-
- rootPath = castNode(A_Const, jt->common->pathspec)->val.sval.sval;
-
- tf->plan = (Node *) transformJsonTableColumns(&cxt, plan, jt->columns,
- rootPath, &rootPathName,
- jt->common->location);
-
- tf->ordinalitycol = -1; /* undefine ordinality column number */
- tf->location = jt->location;
-
- pstate->p_lateral_active = false;
-
- /*
- * Mark the RTE as LATERAL if the user said LATERAL explicitly, or if
- * there are any lateral cross-references in it.
- */
- is_lateral = jt->lateral || contain_vars_of_level((Node *) tf, 0);
-
- return addRangeTableEntryForTableFunc(pstate,
- tf, jt->alias, is_lateral, true);
-}
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index f6b740df0a..f44937a8bb 100644
--- a/src/backend/parser/parse_relation.c
+++ b/src/backend/parser/parse_relation.c
@@ -2017,7 +2017,7 @@ addRangeTableEntryForTableFunc(ParseState *pstate,
bool inFromCl)
{
RangeTblEntry *rte = makeNode(RangeTblEntry);
- char *refname;
+ char *refname = alias ? alias->aliasname : pstrdup("xmltable");
Alias *eref;
int numaliases;
@@ -2035,8 +2035,7 @@ addRangeTableEntryForTableFunc(ParseState *pstate,
Assert(list_length(tf->coltypmods) == list_length(tf->colnames));
Assert(list_length(tf->colcollations) == list_length(tf->colnames));
- refname = alias ? alias->aliasname :
- pstrdup(tf->functype == TFT_XMLTABLE ? "xmltable" : "json_table");
+ refname = alias ? alias->aliasname : pstrdup("xmltable");
rte->rtekind = RTE_TABLEFUNC;
rte->relid = InvalidOid;
@@ -2059,7 +2058,7 @@ addRangeTableEntryForTableFunc(ParseState *pstate,
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),
errmsg("%s function has %d columns available but %d columns specified",
- tf->functype == TFT_XMLTABLE ? "XMLTABLE" : "JSON_TABLE",
+ "XMLTABLE",
list_length(tf->colnames), numaliases)));
rte->eref = eref;
diff --git a/src/backend/parser/parse_target.c b/src/backend/parser/parse_target.c
index 16a0fe59e2..4e1593d900 100644
--- a/src/backend/parser/parse_target.c
+++ b/src/backend/parser/parse_target.c
@@ -1957,46 +1957,6 @@ FigureColnameInternal(Node *node, char **name)
case T_XmlSerialize:
*name = "xmlserialize";
return 2;
- case T_JsonParseExpr:
- *name = "json";
- return 2;
- case T_JsonScalarExpr:
- *name = "json_scalar";
- return 2;
- case T_JsonSerializeExpr:
- *name = "json_serialize";
- return 2;
- case T_JsonObjectConstructor:
- *name = "json_object";
- return 2;
- case T_JsonArrayConstructor:
- case T_JsonArrayQueryConstructor:
- *name = "json_array";
- return 2;
- case T_JsonObjectAgg:
- *name = "json_objectagg";
- return 2;
- case T_JsonArrayAgg:
- *name = "json_arrayagg";
- return 2;
- case T_JsonFuncExpr:
- /* make SQL/JSON functions act like a regular function */
- switch (((JsonFuncExpr *) node)->op)
- {
- case JSON_QUERY_OP:
- *name = "json_query";
- return 2;
- case JSON_VALUE_OP:
- *name = "json_value";
- return 2;
- case JSON_EXISTS_OP:
- *name = "json_exists";
- return 2;
- case JSON_TABLE_OP:
- *name = "json_table";
- return 2;
- }
- break;
default:
break;
}
diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c
index eee0a29c08..50227cc098 100644
--- a/src/backend/parser/parser.c
+++ b/src/backend/parser/parser.c
@@ -150,9 +150,6 @@ base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner)
case USCONST:
cur_token_length = strlen(yyextra->core_yy_extra.scanbuf + *llocp);
break;
- case WITHOUT:
- cur_token_length = 7;
- break;
default:
return cur_token;
}
@@ -224,19 +221,6 @@ base_yylex(YYSTYPE *lvalp, YYLTYPE *llocp, core_yyscan_t yyscanner)
case ORDINALITY:
cur_token = WITH_LA;
break;
- case UNIQUE:
- cur_token = WITH_LA_UNIQUE;
- break;
- }
- break;
-
- case WITHOUT:
- /* Replace WITHOUT by WITHOUT_LA if it's followed by TIME */
- switch (next_token)
- {
- case TIME:
- cur_token = WITHOUT_LA;
- break;
}
break;
diff --git a/src/backend/utils/adt/format_type.c b/src/backend/utils/adt/format_type.c
index 060fd7e183..2918fdbfb6 100644
--- a/src/backend/utils/adt/format_type.c
+++ b/src/backend/utils/adt/format_type.c
@@ -294,10 +294,6 @@ format_type_extended(Oid type_oid, int32 typemod, bits16 flags)
else
buf = pstrdup("character varying");
break;
-
- case JSONOID:
- buf = pstrdup("json");
- break;
}
if (buf == NULL)
diff --git a/src/backend/utils/adt/formatting.c b/src/backend/utils/adt/formatting.c
index 6f8734a947..26f498b5df 100644
--- a/src/backend/utils/adt/formatting.c
+++ b/src/backend/utils/adt/formatting.c
@@ -1045,6 +1045,11 @@ typedef struct NUMProc
*L_currency_symbol;
} NUMProc;
+/* Return flags for DCH_from_char() */
+#define DCH_DATED 0x01
+#define DCH_TIMED 0x02
+#define DCH_ZONED 0x04
+
/* ----------
* Functions
* ----------
@@ -6707,43 +6712,3 @@ float8_to_char(PG_FUNCTION_ARGS)
NUM_TOCHAR_finish;
PG_RETURN_TEXT_P(result);
}
-
-int
-datetime_format_flags(const char *fmt_str, bool *have_error)
-{
- bool incache;
- int fmt_len = strlen(fmt_str);
- int result;
- FormatNode *format;
-
- if (fmt_len > DCH_CACHE_SIZE)
- {
- /*
- * Allocate new memory if format picture is bigger than static cache
- * and do not use cache (call parser always)
- */
- incache = false;
-
- format = (FormatNode *) palloc((fmt_len + 1) * sizeof(FormatNode));
-
- parse_format(format, fmt_str, DCH_keywords,
- DCH_suff, DCH_index, DCH_FLAG, NULL);
- }
- else
- {
- /*
- * Use cache buffers
- */
- DCHCacheEntry *ent = DCH_cache_fetch(fmt_str, false);
-
- incache = true;
- format = ent->format;
- }
-
- result = DCH_datetime_type(format, have_error);
-
- if (!incache)
- pfree(format);
-
- return result;
-}
diff --git a/src/backend/utils/adt/json.c b/src/backend/utils/adt/json.c
index 5fdb7e32ce..fee2ffb55c 100644
--- a/src/backend/utils/adt/json.c
+++ b/src/backend/utils/adt/json.c
@@ -13,10 +13,7 @@
*/
#include "postgres.h"
-#include "access/hash.h"
-#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
-#include "common/hashfn.h"
#include "funcapi.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
@@ -30,41 +27,20 @@
#include "utils/lsyscache.h"
#include "utils/typcache.h"
-/* Common context for key uniqueness check */
-typedef struct HTAB *JsonUniqueCheckState; /* hash table for key names */
-
-/* Hash entry for JsonUniqueCheckState */
-typedef struct JsonUniqueHashEntry
-{
- const char *key;
- int key_len;
- int object_id;
-} JsonUniqueHashEntry;
-
-/* Context for key uniqueness check in builder functions */
-typedef struct JsonUniqueBuilderState
-{
- JsonUniqueCheckState check; /* unique check */
- StringInfoData skipped_keys; /* skipped keys with NULL values */
- MemoryContext mcxt; /* context for saving skipped keys */
-} JsonUniqueBuilderState;
-
-/* Element of object stack for key uniqueness check during json parsing */
-typedef struct JsonUniqueStackEntry
+typedef enum /* type categories for datum_to_json */
{
- struct JsonUniqueStackEntry *parent;
- int object_id;
-} JsonUniqueStackEntry;
-
-/* State for key uniqueness check during json parsing */
-typedef struct JsonUniqueParsingState
-{
- JsonLexContext *lex;
- JsonUniqueCheckState check;
- JsonUniqueStackEntry *stack;
- int id_counter;
- bool unique;
-} JsonUniqueParsingState;
+ 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;
typedef struct JsonAggState
{
@@ -73,7 +49,6 @@ typedef struct JsonAggState
Oid key_output_func;
JsonTypeCategory val_category;
Oid val_output_func;
- JsonUniqueBuilderState unique_check;
} JsonAggState;
static void composite_to_json(Datum composite, StringInfo result,
@@ -84,6 +59,9 @@ static void array_dim_to_json(StringInfo result, int dim, int ndims, int *dims,
bool use_line_feeds);
static void array_to_json_internal(Datum array, StringInfo result,
bool use_line_feeds);
+static void json_categorize_type(Oid typoid,
+ JsonTypeCategory *tcategory,
+ Oid *outfuncoid);
static void datum_to_json(Datum val, bool is_null, StringInfo result,
JsonTypeCategory tcategory, Oid outfuncoid,
bool key_scalar);
@@ -162,7 +140,7 @@ json_recv(PG_FUNCTION_ARGS)
* output function OID. If the returned category is JSONTYPE_CAST, we
* return the OID of the type->JSON cast function instead.
*/
-void
+static void
json_categorize_type(Oid typoid,
JsonTypeCategory *tcategory,
Oid *outfuncoid)
@@ -744,48 +722,6 @@ row_to_json_pretty(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
}
-Datum
-to_json_worker(Datum val, JsonTypeCategory tcategory, Oid outfuncoid)
-{
- StringInfo result = makeStringInfo();
-
- datum_to_json(val, false, result, tcategory, outfuncoid, false);
-
- return PointerGetDatum(cstring_to_text_with_len(result->data, result->len));
-}
-
-bool
-to_json_is_immutable(Oid typoid)
-{
- JsonTypeCategory tcategory;
- Oid outfuncoid;
-
- json_categorize_type(typoid, &tcategory, &outfuncoid);
-
- switch (tcategory)
- {
- case JSONTYPE_BOOL:
- case JSONTYPE_JSON:
- return true;
-
- case JSONTYPE_DATE:
- case JSONTYPE_TIMESTAMP:
- case JSONTYPE_TIMESTAMPTZ:
- return false;
-
- case JSONTYPE_ARRAY:
- return false; /* TODO recurse into elements */
-
- case JSONTYPE_COMPOSITE:
- return false; /* TODO recurse into fields */
-
- case JSONTYPE_NUMERIC:
- case JSONTYPE_CAST:
- default:
- return func_volatile(outfuncoid) == PROVOLATILE_IMMUTABLE;
- }
-}
-
/*
* SQL function to_json(anyvalue)
*/
@@ -794,6 +730,7 @@ to_json(PG_FUNCTION_ARGS)
{
Datum val = PG_GETARG_DATUM(0);
Oid val_type = get_fn_expr_argtype(fcinfo->flinfo, 0);
+ StringInfo result;
JsonTypeCategory tcategory;
Oid outfuncoid;
@@ -805,7 +742,11 @@ to_json(PG_FUNCTION_ARGS)
json_categorize_type(val_type,
&tcategory, &outfuncoid);
- PG_RETURN_DATUM(to_json_worker(val, tcategory, outfuncoid));
+ result = makeStringInfo();
+
+ datum_to_json(val, false, result, tcategory, outfuncoid, false);
+
+ PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
}
/*
@@ -813,8 +754,8 @@ to_json(PG_FUNCTION_ARGS)
*
* aggregate input column as a json array value.
*/
-static Datum
-json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
+Datum
+json_agg_transfn(PG_FUNCTION_ARGS)
{
MemoryContext aggcontext,
oldcontext;
@@ -854,13 +795,8 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
else
{
state = (JsonAggState *) PG_GETARG_POINTER(0);
- }
-
- if (absent_on_null && PG_ARGISNULL(1))
- PG_RETURN_POINTER(state);
-
- if (state->str->len > 1)
appendStringInfoString(state->str, ", ");
+ }
/* fast path for NULLs */
if (PG_ARGISNULL(1))
@@ -873,7 +809,7 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
val = PG_GETARG_DATUM(1);
/* add some whitespace if structured type and not first item */
- if (!PG_ARGISNULL(0) && state->str->len > 1 &&
+ if (!PG_ARGISNULL(0) &&
(state->val_category == JSONTYPE_ARRAY ||
state->val_category == JSONTYPE_COMPOSITE))
{
@@ -891,25 +827,6 @@ json_agg_transfn_worker(FunctionCallInfo fcinfo, bool absent_on_null)
PG_RETURN_POINTER(state);
}
-
-/*
- * json_agg aggregate function
- */
-Datum
-json_agg_transfn(PG_FUNCTION_ARGS)
-{
- return json_agg_transfn_worker(fcinfo, false);
-}
-
-/*
- * json_agg_strict aggregate function
- */
-Datum
-json_agg_strict_transfn(PG_FUNCTION_ARGS)
-{
- return json_agg_transfn_worker(fcinfo, true);
-}
-
/*
* json_agg final function
*/
@@ -933,108 +850,18 @@ json_agg_finalfn(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(catenate_stringinfo_string(state->str, "]"));
}
-/* Functions implementing hash table for key uniqueness check */
-static uint32
-json_unique_hash(const void *key, Size keysize)
-{
- const JsonUniqueHashEntry *entry = (JsonUniqueHashEntry *) key;
- uint32 hash = hash_bytes_uint32(entry->object_id);
-
- hash ^= hash_bytes((const unsigned char *) entry->key, entry->key_len);
-
- return DatumGetUInt32(hash);
-}
-
-static int
-json_unique_hash_match(const void *key1, const void *key2, Size keysize)
-{
- const JsonUniqueHashEntry *entry1 = (const JsonUniqueHashEntry *) key1;
- const JsonUniqueHashEntry *entry2 = (const JsonUniqueHashEntry *) key2;
-
- if (entry1->object_id != entry2->object_id)
- return entry1->object_id > entry2->object_id ? 1 : -1;
-
- if (entry1->key_len != entry2->key_len)
- return entry1->key_len > entry2->key_len ? 1 : -1;
-
- return strncmp(entry1->key, entry2->key, entry1->key_len);
-}
-
-/* Functions implementing object key uniqueness check */
-static void
-json_unique_check_init(JsonUniqueCheckState *cxt)
-{
- HASHCTL ctl;
-
- memset(&ctl, 0, sizeof(ctl));
- ctl.keysize = sizeof(JsonUniqueHashEntry);
- ctl.entrysize = sizeof(JsonUniqueHashEntry);
- ctl.hcxt = CurrentMemoryContext;
- ctl.hash = json_unique_hash;
- ctl.match = json_unique_hash_match;
-
- *cxt = hash_create("json object hashtable",
- 32,
- &ctl,
- HASH_ELEM | HASH_CONTEXT | HASH_FUNCTION | HASH_COMPARE);
-}
-
-static bool
-json_unique_check_key(JsonUniqueCheckState *cxt, const char *key, int object_id)
-{
- JsonUniqueHashEntry entry;
- bool found;
-
- entry.key = key;
- entry.key_len = strlen(key);
- entry.object_id = object_id;
-
- (void) hash_search(*cxt, &entry, HASH_ENTER, &found);
-
- return !found;
-}
-
-static void
-json_unique_builder_init(JsonUniqueBuilderState *cxt)
-{
- json_unique_check_init(&cxt->check);
- cxt->mcxt = CurrentMemoryContext;
- cxt->skipped_keys.data = NULL;
-}
-
-/* On-demand initialization of skipped_keys StringInfo structure */
-static StringInfo
-json_unique_builder_get_skipped_keys(JsonUniqueBuilderState *cxt)
-{
- StringInfo out = &cxt->skipped_keys;
-
- if (!out->data)
- {
- MemoryContext oldcxt = MemoryContextSwitchTo(cxt->mcxt);
-
- initStringInfo(out);
- MemoryContextSwitchTo(oldcxt);
- }
-
- return out;
-}
-
/*
* json_object_agg transition function.
*
* aggregate two input columns as a single json object value.
*/
-static Datum
-json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
- bool absent_on_null, bool unique_keys)
+Datum
+json_object_agg_transfn(PG_FUNCTION_ARGS)
{
MemoryContext aggcontext,
oldcontext;
JsonAggState *state;
- StringInfo out;
Datum arg;
- bool skip;
- int key_offset;
if (!AggCheckCallContext(fcinfo, &aggcontext))
{
@@ -1055,10 +882,6 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
oldcontext = MemoryContextSwitchTo(aggcontext);
state = (JsonAggState *) palloc(sizeof(JsonAggState));
state->str = makeStringInfo();
- if (unique_keys)
- json_unique_builder_init(&state->unique_check);
- else
- memset(&state->unique_check, 0, sizeof(state->unique_check));
MemoryContextSwitchTo(oldcontext);
arg_type = get_fn_expr_argtype(fcinfo->flinfo, 1);
@@ -1086,6 +909,7 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
else
{
state = (JsonAggState *) PG_GETARG_POINTER(0);
+ appendStringInfoString(state->str, ", ");
}
/*
@@ -1101,49 +925,11 @@ json_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 */
- skip = absent_on_null && PG_ARGISNULL(2);
-
- if (skip)
- {
- /* If key uniqueness check is needed we must save skipped keys */
- if (!unique_keys)
- PG_RETURN_POINTER(state);
-
- out = json_unique_builder_get_skipped_keys(&state->unique_check);
- }
- else
- {
- out = state->str;
-
- /*
- * Append comma delimiter only if we have already outputted some
- * fields after the initial string "{ ".
- */
- if (out->len > 2)
- appendStringInfoString(out, ", ");
- }
-
arg = PG_GETARG_DATUM(1);
- key_offset = out->len;
-
- datum_to_json(arg, false, out, state->key_category,
+ datum_to_json(arg, false, state->str, state->key_category,
state->key_output_func, true);
- if (unique_keys)
- {
- const char *key = &out->data[key_offset];
-
- if (!json_unique_check_key(&state->unique_check.check, key, 0))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
- errmsg("duplicate JSON key %s", key)));
-
- if (skip)
- PG_RETURN_POINTER(state);
- }
-
appendStringInfoString(state->str, " : ");
if (PG_ARGISNULL(2))
@@ -1158,42 +944,6 @@ json_object_agg_transfn_worker(FunctionCallInfo fcinfo,
}
/*
- * json_object_agg aggregate function
- */
-Datum
-json_object_agg_transfn(PG_FUNCTION_ARGS)
-{
- return json_object_agg_transfn_worker(fcinfo, false, false);
-}
-
-/*
- * json_object_agg_strict aggregate function
- */
-Datum
-json_object_agg_strict_transfn(PG_FUNCTION_ARGS)
-{
- return json_object_agg_transfn_worker(fcinfo, true, false);
-}
-
-/*
- * json_object_agg_unique aggregate function
- */
-Datum
-json_object_agg_unique_transfn(PG_FUNCTION_ARGS)
-{
- return json_object_agg_transfn_worker(fcinfo, false, true);
-}
-
-/*
- * json_object_agg_unique_strict aggregate function
- */
-Datum
-json_object_agg_unique_strict_transfn(PG_FUNCTION_ARGS)
-{
- return json_object_agg_transfn_worker(fcinfo, true, true);
-}
-
-/*
* json_object_agg final function.
*/
Datum
@@ -1234,14 +984,25 @@ catenate_stringinfo_string(StringInfo buffer, const char *addon)
return result;
}
+/*
+ * SQL function json_build_object(variadic "any")
+ */
Datum
-json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
- bool absent_on_null, bool unique_keys)
+json_build_object(PG_FUNCTION_ARGS)
{
+ int nargs;
int i;
const char *sep = "";
StringInfo result;
- JsonUniqueBuilderState unique_check;
+ Datum *args;
+ bool *nulls;
+ Oid *types;
+
+ /* fetch argument values to build the object */
+ nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
+
+ if (nargs < 0)
+ PG_RETURN_NULL();
if (nargs % 2 != 0)
ereport(ERROR,
@@ -1255,32 +1016,10 @@ json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
appendStringInfoChar(result, '{');
- if (unique_keys)
- json_unique_builder_init(&unique_check);
-
for (i = 0; i < nargs; i += 2)
{
- StringInfo out;
- bool skip;
- int key_offset;
-
- /* Skip null values if absent_on_null */
- skip = absent_on_null && nulls[i + 1];
-
- if (skip)
- {
- /* If key uniqueness check is needed we must save skipped keys */
- if (!unique_keys)
- continue;
-
- out = json_unique_builder_get_skipped_keys(&unique_check);
- }
- else
- {
- appendStringInfoString(result, sep);
- sep = ", ";
- out = result;
- }
+ appendStringInfoString(result, sep);
+ sep = ", ";
/* process key */
if (nulls[i])
@@ -1289,24 +1028,7 @@ json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
errmsg("argument %d cannot be null", i + 1),
errhint("Object keys should be text.")));
- /* save key offset before key appending */
- key_offset = out->len;
-
- add_json(args[i], false, out, types[i], true);
-
- if (unique_keys)
- {
- /* check key uniqueness after key appending */
- const char *key = &out->data[key_offset];
-
- if (!json_unique_check_key(&unique_check.check, key, 0))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
- errmsg("duplicate JSON key %s", key)));
-
- if (skip)
- continue;
- }
+ add_json(args[i], false, result, types[i], true);
appendStringInfoString(result, " : ");
@@ -1316,27 +1038,7 @@ json_build_object_worker(int nargs, Datum *args, bool *nulls, Oid *types,
appendStringInfoChar(result, '}');
- return PointerGetDatum(cstring_to_text_with_len(result->data, result->len));
-}
-
-/*
- * SQL function json_build_object(variadic "any")
- */
-Datum
-json_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(json_build_object_worker(nargs, args, nulls, types, false, false));
+ PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
}
/*
@@ -1348,13 +1050,25 @@ json_build_object_noargs(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(cstring_to_text_with_len("{}", 2));
}
+/*
+ * SQL function json_build_array(variadic "any")
+ */
Datum
-json_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types,
- bool absent_on_null)
+json_build_array(PG_FUNCTION_ARGS)
{
+ int nargs;
int i;
const char *sep = "";
StringInfo result;
+ Datum *args;
+ bool *nulls;
+ Oid *types;
+
+ /* fetch argument values to build the array */
+ nargs = extract_variadic_args(fcinfo, 0, false, &args, &types, &nulls);
+
+ if (nargs < 0)
+ PG_RETURN_NULL();
result = makeStringInfo();
@@ -1362,9 +1076,6 @@ json_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types,
for (i = 0; i < nargs; i++)
{
- if (absent_on_null && nulls[i])
- continue;
-
appendStringInfoString(result, sep);
sep = ", ";
add_json(args[i], nulls[i], result, types[i], false);
@@ -1372,27 +1083,7 @@ json_build_array_worker(int nargs, Datum *args, bool *nulls, Oid *types,
appendStringInfoChar(result, ']');
- return PointerGetDatum(cstring_to_text_with_len(result->data, result->len));
-}
-
-/*
- * SQL function json_build_array(variadic "any")
- */
-Datum
-json_build_array(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(json_build_array_worker(nargs, args, nulls, types, false));
+ PG_RETURN_TEXT_P(cstring_to_text_with_len(result->data, result->len));
}
/*
@@ -1618,106 +1309,6 @@ escape_json(StringInfo buf, const char *str)
appendStringInfoCharMacro(buf, '"');
}
-/* Semantic actions for key uniqueness check */
-static void
-json_unique_object_start(void *_state)
-{
- JsonUniqueParsingState *state = _state;
- JsonUniqueStackEntry *entry;
-
- if (!state->unique)
- return;
-
- /* push object entry to stack */
- entry = palloc(sizeof(*entry));
- entry->object_id = state->id_counter++;
- entry->parent = state->stack;
- state->stack = entry;
-}
-
-static void
-json_unique_object_end(void *_state)
-{
- JsonUniqueParsingState *state = _state;
- JsonUniqueStackEntry *entry;
-
- if (!state->unique)
- return;
-
- entry = state->stack;
- state->stack = entry->parent; /* pop object from stack */
- pfree(entry);
-}
-
-static void
-json_unique_object_field_start(void *_state, char *field, bool isnull)
-{
- JsonUniqueParsingState *state = _state;
- JsonUniqueStackEntry *entry;
-
- if (!state->unique)
- return;
-
- /* find key collision in the current object */
- if (json_unique_check_key(&state->check, field, state->stack->object_id))
- return;
-
- state->unique = false;
-
- /* pop all objects entries */
- while ((entry = state->stack))
- {
- state->stack = entry->parent;
- pfree(entry);
- }
-}
-
-/* Validate JSON text and additionally check key uniqueness */
-bool
-json_validate(text *json, bool check_unique_keys, bool throw_error)
-{
- JsonLexContext *lex = makeJsonLexContext(json, check_unique_keys);
- JsonSemAction uniqueSemAction = {0};
- JsonUniqueParsingState state;
- JsonParseErrorType result;
-
- if (check_unique_keys)
- {
- state.lex = lex;
- state.stack = NULL;
- state.id_counter = 0;
- state.unique = true;
- json_unique_check_init(&state.check);
-
- uniqueSemAction.semstate = &state;
- uniqueSemAction.object_start = json_unique_object_start;
- uniqueSemAction.object_field_start = json_unique_object_field_start;
- uniqueSemAction.object_end = json_unique_object_end;
- }
-
- result = pg_parse_json(lex, check_unique_keys ? &uniqueSemAction : &nullSemAction);
-
- if (result != JSON_SUCCESS)
- {
- if (throw_error)
- json_ereport_error(result, lex);
-
- return false; /* invalid json */
- }
-
- if (check_unique_keys && !state.unique)
- {
- if (throw_error)
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
- errmsg("duplicate JSON object key value")));
-
- return false; /* not unique keys */
- }
-
- return true; /* ok */
-}
-
/*
* SQL function json_typeof(json) -> text
*
@@ -1733,13 +1324,21 @@ json_validate(text *json, bool check_unique_keys, bool throw_error)
Datum
json_typeof(PG_FUNCTION_ARGS)
{
- text *json = PG_GETARG_TEXT_PP(0);
- char *type;
+ text *json;
+
+ JsonLexContext *lex;
JsonTokenType tok;
+ char *type;
+ JsonParseErrorType result;
- /* Lex exactly one token from the input and check its type. */
- tok = json_get_first_token(json, true);
+ json = PG_GETARG_TEXT_PP(0);
+ lex = makeJsonLexContext(json, false);
+ /* Lex exactly one token from the input and check its type. */
+ result = json_lex(lex);
+ if (result != JSON_SUCCESS)
+ json_ereport_error(result, lex);
+ tok = lex->token_type;
switch (tok)
{
case JSON_TOKEN_OBJECT_START:
diff --git a/src/backend/utils/adt/jsonb.c b/src/backend/utils/adt/jsonb.c
index f700c5b4c9..88b0000f9a 100644
--- a/src/backend/utils/adt/jsonb.c
+++ b/src/backend/utils/adt/jsonb.c
@@ -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));
-}
diff --git a/src/backend/utils/adt/jsonb_util.c b/src/backend/utils/adt/jsonb_util.c
index 5318eda9cf..60442758b3 100644
--- a/src/backend/utils/adt/jsonb_util.c
+++ b/src/backend/utils/adt/jsonb_util.c
@@ -64,8 +64,7 @@ static int lengthCompareJsonbStringValue(const void *a, const void *b);
static int lengthCompareJsonbString(const char *val1, int len1,
const char *val2, int len2);
static int lengthCompareJsonbPair(const void *a, const void *b, void *arg);
-static void uniqueifyJsonbObject(JsonbValue *object, bool unique_keys,
- bool skip_nulls);
+static void uniqueifyJsonbObject(JsonbValue *object);
static JsonbValue *pushJsonbValueScalar(JsonbParseState **pstate,
JsonbIteratorToken seq,
JsonbValue *scalarVal);
@@ -690,9 +689,7 @@ pushJsonbValueScalar(JsonbParseState **pstate, JsonbIteratorToken seq,
appendElement(*pstate, scalarVal);
break;
case WJB_END_OBJECT:
- uniqueifyJsonbObject(&(*pstate)->contVal,
- (*pstate)->unique_keys,
- (*pstate)->skip_nulls);
+ uniqueifyJsonbObject(&(*pstate)->contVal);
/* fall through! */
case WJB_END_ARRAY:
/* Steps here common to WJB_END_OBJECT case */
@@ -735,9 +732,6 @@ pushState(JsonbParseState **pstate)
JsonbParseState *ns = palloc(sizeof(JsonbParseState));
ns->next = *pstate;
- ns->unique_keys = false;
- ns->skip_nulls = false;
-
return ns;
}
@@ -1942,7 +1936,7 @@ lengthCompareJsonbPair(const void *a, const void *b, void *binequal)
* Sort and unique-ify pairs in JsonbValue object
*/
static void
-uniqueifyJsonbObject(JsonbValue *object, bool unique_keys, bool skip_nulls)
+uniqueifyJsonbObject(JsonbValue *object)
{
bool hasNonUniq = false;
@@ -1952,32 +1946,15 @@ uniqueifyJsonbObject(JsonbValue *object, bool unique_keys, bool skip_nulls)
qsort_arg(object->val.object.pairs, object->val.object.nPairs, sizeof(JsonbPair),
lengthCompareJsonbPair, &hasNonUniq);
- if (hasNonUniq && unique_keys)
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_JSON_OBJECT_KEY_VALUE),
- errmsg("duplicate JSON object key value")));
-
- if (hasNonUniq || skip_nulls)
+ if (hasNonUniq)
{
- JsonbPair *ptr,
- *res;
-
- while (skip_nulls && object->val.object.nPairs > 0 &&
- object->val.object.pairs->value.type == jbvNull)
- {
- /* If skip_nulls is true, remove leading items with null */
- object->val.object.pairs++;
- object->val.object.nPairs--;
- }
-
- ptr = object->val.object.pairs + 1;
- res = object->val.object.pairs;
+ JsonbPair *ptr = object->val.object.pairs + 1,
+ *res = object->val.object.pairs;
while (ptr - object->val.object.pairs < object->val.object.nPairs)
{
- /* Avoid copying over duplicate or null */
- if (lengthCompareJsonbStringValue(ptr, res) != 0 &&
- (!skip_nulls || ptr->value.type != jbvNull))
+ /* Avoid copying over duplicate */
+ if (lengthCompareJsonbStringValue(ptr, res) != 0)
{
res++;
if (ptr != res)
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c
index 9819e1a45c..82c43617d8 100644
--- a/src/backend/utils/adt/jsonfuncs.c
+++ b/src/backend/utils/adt/jsonfuncs.c
@@ -2656,11 +2656,11 @@ populate_array_dim_jsonb(PopulateArrayContext *ctx, /* context */
check_stack_depth();
- if (jbv->type != jbvBinary ||
- !JsonContainerIsArray(jbc) ||
- JsonContainerIsScalar(jbc))
+ if (jbv->type != jbvBinary || !JsonContainerIsArray(jbc))
populate_array_report_expected_array(ctx, ndim - 1);
+ Assert(!JsonContainerIsScalar(jbc));
+
it = JsonbIteratorInit(jbc);
tok = JsonbIteratorNext(&it, &val, true);
@@ -3132,51 +3132,6 @@ populate_record_field(ColumnIOData *col,
}
}
-/* recursively populate specified type from a json/jsonb value */
-Datum
-json_populate_type(Datum json_val, Oid json_type, Oid typid, int32 typmod,
- void **cache, MemoryContext mcxt, bool *isnull)
-{
- JsValue jsv = {0};
- JsonbValue jbv;
-
- jsv.is_json = json_type == JSONOID;
-
- if (*isnull)
- {
- if (jsv.is_json)
- jsv.val.json.str = NULL;
- else
- jsv.val.jsonb = NULL;
- }
- else if (jsv.is_json)
- {
- text *json = DatumGetTextPP(json_val);
-
- jsv.val.json.str = VARDATA_ANY(json);
- jsv.val.json.len = VARSIZE_ANY_EXHDR(json);
- jsv.val.json.type = JSON_TOKEN_INVALID; /* not used in
- * populate_composite() */
- }
- else
- {
- Jsonb *jsonb = DatumGetJsonbP(json_val);
-
- jsv.val.jsonb = &jbv;
-
- /* fill binary jsonb value pointing to jb */
- jbv.type = jbvBinary;
- jbv.val.binary.data = &jsonb->root;
- jbv.val.binary.len = VARSIZE(jsonb) - VARHDRSZ;
- }
-
- if (!*cache)
- *cache = MemoryContextAllocZero(mcxt, sizeof(ColumnIOData));
-
- return populate_record_field(*cache, typid, typmod, NULL, mcxt,
- PointerGetDatum(NULL), &jsv, isnull);
-}
-
static RecordIOData *
allocate_record_info(MemoryContext mcxt, int ncolumns)
{
@@ -5566,23 +5521,3 @@ transform_string_values_scalar(void *state, char *token, JsonTokenType tokentype
else
appendStringInfoString(_state->strval, token);
}
-
-JsonTokenType
-json_get_first_token(text *json, bool throw_error)
-{
- JsonLexContext *lex;
- JsonParseErrorType result;
-
- lex = makeJsonLexContext(json, false);
-
- /* Lex exactly one token from the input and check its type. */
- result = json_lex(lex);
-
- if (result == JSON_SUCCESS)
- return lex->token_type;
-
- if (throw_error)
- json_ereport_error(result, lex);
-
- return JSON_TOKEN_INVALID; /* invalid json */
-}
diff --git a/src/backend/utils/adt/jsonpath.c b/src/backend/utils/adt/jsonpath.c
index da9df4ae76..91af030095 100644
--- a/src/backend/utils/adt/jsonpath.c
+++ b/src/backend/utils/adt/jsonpath.c
@@ -67,9 +67,7 @@
#include "lib/stringinfo.h"
#include "libpq/pqformat.h"
#include "miscadmin.h"
-#include "nodes/nodeFuncs.h"
#include "utils/builtins.h"
-#include "utils/formatting.h"
#include "utils/json.h"
#include "utils/jsonpath.h"
@@ -1079,258 +1077,3 @@ jspGetArraySubscript(JsonPathItem *v, JsonPathItem *from, JsonPathItem *to,
return true;
}
-
-/* SQL/JSON datatype status: */
-typedef enum JsonPathDatatypeStatus
-{
- jpdsNonDateTime, /* null, bool, numeric, string, array, object */
- jpdsUnknownDateTime, /* unknown datetime type */
- jpdsDateTimeZoned, /* timetz, timestamptz */
- jpdsDateTimeNonZoned /* time, timestamp, date */
-} JsonPathDatatypeStatus;
-
-/* Context for jspIsMutableWalker() */
-typedef struct JsonPathMutableContext
-{
- List *varnames; /* list of variable names */
- List *varexprs; /* list of variable expressions */
- JsonPathDatatypeStatus current; /* status of @ item */
- bool lax; /* jsonpath is lax or strict */
- bool mutable; /* resulting mutability status */
-} JsonPathMutableContext;
-
-/*
- * Recursive walker for jspIsMutable()
- */
-static JsonPathDatatypeStatus
-jspIsMutableWalker(JsonPathItem *jpi, JsonPathMutableContext *cxt)
-{
- JsonPathItem next;
- JsonPathDatatypeStatus status = jpdsNonDateTime;
-
- while (!cxt->mutable)
- {
- JsonPathItem arg;
- JsonPathDatatypeStatus leftStatus;
- JsonPathDatatypeStatus rightStatus;
-
- switch (jpi->type)
- {
- case jpiRoot:
- Assert(status == jpdsNonDateTime);
- break;
-
- case jpiCurrent:
- Assert(status == jpdsNonDateTime);
- status = cxt->current;
- break;
-
- case jpiFilter:
- {
- JsonPathDatatypeStatus prevStatus = cxt->current;
-
- cxt->current = status;
- jspGetArg(jpi, &arg);
- jspIsMutableWalker(&arg, cxt);
-
- cxt->current = prevStatus;
- break;
- }
-
- case jpiVariable:
- {
- int32 len;
- const char *name = jspGetString(jpi, &len);
- ListCell *lc1;
- ListCell *lc2;
-
- Assert(status == jpdsNonDateTime);
-
- forboth(lc1, cxt->varnames, lc2, cxt->varexprs)
- {
- String *varname = lfirst_node(String, lc1);
- Node *varexpr = lfirst(lc2);
-
- if (strncmp(varname->sval, name, len))
- continue;
-
- switch (exprType(varexpr))
- {
- case DATEOID:
- case TIMEOID:
- case TIMESTAMPOID:
- status = jpdsDateTimeNonZoned;
- break;
-
- case TIMETZOID:
- case TIMESTAMPTZOID:
- status = jpdsDateTimeZoned;
- break;
-
- default:
- status = jpdsNonDateTime;
- break;
- }
-
- break;
- }
- break;
- }
-
- case jpiEqual:
- case jpiNotEqual:
- case jpiLess:
- case jpiGreater:
- case jpiLessOrEqual:
- case jpiGreaterOrEqual:
- Assert(status == jpdsNonDateTime);
- jspGetLeftArg(jpi, &arg);
- leftStatus = jspIsMutableWalker(&arg, cxt);
-
- jspGetRightArg(jpi, &arg);
- rightStatus = jspIsMutableWalker(&arg, cxt);
-
- /*
- * Comparison of datetime type with different timezone status
- * is mutable.
- */
- if (leftStatus != jpdsNonDateTime &&
- rightStatus != jpdsNonDateTime &&
- (leftStatus == jpdsUnknownDateTime ||
- rightStatus == jpdsUnknownDateTime ||
- leftStatus != rightStatus))
- cxt->mutable = true;
- break;
-
- case jpiNot:
- case jpiIsUnknown:
- case jpiExists:
- case jpiPlus:
- case jpiMinus:
- Assert(status == jpdsNonDateTime);
- jspGetArg(jpi, &arg);
- jspIsMutableWalker(&arg, cxt);
- break;
-
- case jpiAnd:
- case jpiOr:
- case jpiAdd:
- case jpiSub:
- case jpiMul:
- case jpiDiv:
- case jpiMod:
- case jpiStartsWith:
- Assert(status == jpdsNonDateTime);
- jspGetLeftArg(jpi, &arg);
- jspIsMutableWalker(&arg, cxt);
- jspGetRightArg(jpi, &arg);
- jspIsMutableWalker(&arg, cxt);
- break;
-
- case jpiIndexArray:
- for (int i = 0; i < jpi->content.array.nelems; i++)
- {
- JsonPathItem from;
- JsonPathItem to;
-
- if (jspGetArraySubscript(jpi, &from, &to, i))
- jspIsMutableWalker(&to, cxt);
-
- jspIsMutableWalker(&from, cxt);
- }
- /* FALLTHROUGH */
-
- case jpiAnyArray:
- if (!cxt->lax)
- status = jpdsNonDateTime;
- break;
-
- case jpiAny:
- if (jpi->content.anybounds.first > 0)
- status = jpdsNonDateTime;
- break;
-
- case jpiDatetime:
- if (jpi->content.arg)
- {
- char *template;
- int flags;
-
- jspGetArg(jpi, &arg);
- if (arg.type != jpiString)
- {
- status = jpdsNonDateTime;
- break; /* there will be runtime error */
- }
-
- template = jspGetString(&arg, NULL);
- flags = datetime_format_flags(template, NULL);
- if (flags & DCH_ZONED)
- status = jpdsDateTimeZoned;
- else
- status = jpdsDateTimeNonZoned;
- }
- else
- {
- status = jpdsUnknownDateTime;
- }
- break;
-
- case jpiLikeRegex:
- Assert(status == jpdsNonDateTime);
- jspInitByBuffer(&arg, jpi->base, jpi->content.like_regex.expr);
- jspIsMutableWalker(&arg, cxt);
- break;
-
- /* literals */
- case jpiNull:
- case jpiString:
- case jpiNumeric:
- case jpiBool:
- /* accessors */
- case jpiKey:
- case jpiAnyKey:
- /* special items */
- case jpiSubscript:
- case jpiLast:
- /* item methods */
- case jpiType:
- case jpiSize:
- case jpiAbs:
- case jpiFloor:
- case jpiCeiling:
- case jpiDouble:
- case jpiKeyValue:
- status = jpdsNonDateTime;
- break;
- }
-
- if (!jspGetNext(jpi, &next))
- break;
-
- jpi = &next;
- }
-
- return status;
-}
-
-/*
- * Check whether jsonpath expression is immutable or not.
- */
-bool
-jspIsMutable(JsonPath *path, List *varnames, List *varexprs)
-{
- JsonPathMutableContext cxt;
- JsonPathItem jpi;
-
- cxt.varnames = varnames;
- cxt.varexprs = varexprs;
- cxt.current = jpdsNonDateTime;
- cxt.lax = (path->header & JSONPATH_LAX) != 0;
- cxt.mutable = false;
-
- jspInit(&jpi, path);
- jspIsMutableWalker(&jpi, &cxt);
-
- return cxt.mutable;
-}
diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c
index 9c381ae727..9f4192e079 100644
--- a/src/backend/utils/adt/jsonpath_exec.c
+++ b/src/backend/utils/adt/jsonpath_exec.c
@@ -61,11 +61,9 @@
#include "catalog/pg_collation.h"
#include "catalog/pg_type.h"
-#include "executor/execExpr.h"
#include "funcapi.h"
#include "lib/stringinfo.h"
#include "miscadmin.h"
-#include "nodes/nodeFuncs.h"
#include "regex/regex.h"
#include "utils/builtins.h"
#include "utils/date.h"
@@ -76,8 +74,6 @@
#include "utils/guc.h"
#include "utils/json.h"
#include "utils/jsonpath.h"
-#include "utils/lsyscache.h"
-#include "utils/memutils.h"
#include "utils/timestamp.h"
#include "utils/varlena.h"
@@ -90,16 +86,12 @@ typedef struct JsonBaseObjectInfo
int id;
} JsonBaseObjectInfo;
-typedef int (*JsonPathVarCallback) (void *vars, char *varName, int varNameLen,
- JsonbValue *val, JsonbValue *baseObject);
-
/*
* Context of jsonpath execution.
*/
typedef struct JsonPathExecContext
{
- void *vars; /* variables to substitute into jsonpath */
- JsonPathVarCallback getVar;
+ Jsonb *vars; /* variables to substitute into jsonpath */
JsonbValue *root; /* for $ evaluation */
JsonbValue *current; /* for @ evaluation */
JsonBaseObjectInfo baseObject; /* "base object" for .keyvalue()
@@ -159,59 +151,6 @@ typedef struct JsonValueListIterator
ListCell *next;
} JsonValueListIterator;
-/* Structures for JSON_TABLE execution */
-typedef struct JsonTableScanState JsonTableScanState;
-typedef struct JsonTableJoinState JsonTableJoinState;
-
-struct JsonTableScanState
-{
- JsonTableScanState *parent;
- JsonTableJoinState *nested;
- MemoryContext mcxt;
- JsonPath *path;
- List *args;
- JsonValueList found;
- JsonValueListIterator iter;
- Datum current;
- int ordinal;
- bool currentIsNull;
- bool outerJoin;
- bool errorOnError;
- bool advanceNested;
- bool reset;
-};
-
-struct JsonTableJoinState
-{
- union
- {
- struct
- {
- JsonTableJoinState *left;
- JsonTableJoinState *right;
- bool cross;
- bool advanceRight;
- } join;
- JsonTableScanState scan;
- } u;
- bool is_join;
-};
-
-/* random number to identify JsonTableContext */
-#define JSON_TABLE_CONTEXT_MAGIC 418352867
-
-typedef struct JsonTableContext
-{
- int magic;
- struct
- {
- ExprState *expr;
- JsonTableScanState *scan;
- } *colexprs;
- JsonTableScanState root;
- bool empty;
-} JsonTableContext;
-
/* strict/lax flags is decomposed into four [un]wrap/error flags */
#define jspStrictAbsenseOfErrors(cxt) (!(cxt)->laxMode)
#define jspAutoUnwrap(cxt) ((cxt)->laxMode)
@@ -234,8 +173,7 @@ typedef JsonPathBool (*JsonPathPredicateCallback) (JsonPathItem *jsp,
void *param);
typedef Numeric (*BinaryArithmFunc) (Numeric num1, Numeric num2, bool *error);
-static JsonPathExecResult executeJsonPath(JsonPath *path, void *vars,
- JsonPathVarCallback getVar,
+static JsonPathExecResult executeJsonPath(JsonPath *path, Jsonb *vars,
Jsonb *json, bool throwErrors,
JsonValueList *result, bool useTz);
static JsonPathExecResult executeItem(JsonPathExecContext *cxt,
@@ -287,10 +225,7 @@ static JsonPathExecResult appendBoolResult(JsonPathExecContext *cxt,
static void getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
JsonbValue *value);
static void getJsonPathVariable(JsonPathExecContext *cxt,
- JsonPathItem *variable, JsonbValue *value);
-static int getJsonPathVariableFromJsonb(void *varsJsonb, char *varName,
- int varNameLen, JsonbValue *val,
- JsonbValue *baseObject);
+ JsonPathItem *variable, Jsonb *vars, JsonbValue *value);
static int JsonbArraySize(JsonbValue *jb);
static JsonPathBool executeComparison(JsonPathItem *cmp, JsonbValue *lv,
JsonbValue *rv, void *p);
@@ -302,7 +237,6 @@ static JsonPathExecResult getArrayIndex(JsonPathExecContext *cxt,
JsonPathItem *jsp, JsonbValue *jb, int32 *index);
static JsonBaseObjectInfo setBaseObject(JsonPathExecContext *cxt,
JsonbValue *jbv, int32 id);
-static void JsonValueListClear(JsonValueList *jvl);
static void JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv);
static int JsonValueListLength(const JsonValueList *jvl);
static bool JsonValueListIsEmpty(JsonValueList *jvl);
@@ -320,12 +254,6 @@ static JsonbValue *wrapItemsInArray(const JsonValueList *items);
static int compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
bool useTz, bool *have_error);
-
-static JsonTableJoinState *JsonTableInitPlanState(JsonTableContext *cxt,
- Node *plan, JsonTableScanState *parent);
-static bool JsonTableNextRow(JsonTableScanState *scan);
-
-
/****************** User interface to JsonPath executor ********************/
/*
@@ -355,8 +283,7 @@ jsonb_path_exists_internal(FunctionCallInfo fcinfo, bool tz)
silent = PG_GETARG_BOOL(3);
}
- res = executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
- jb, !silent, NULL, tz);
+ res = executeJsonPath(jp, vars, jb, !silent, NULL, tz);
PG_FREE_IF_COPY(jb, 0);
PG_FREE_IF_COPY(jp, 1);
@@ -411,8 +338,7 @@ jsonb_path_match_internal(FunctionCallInfo fcinfo, bool tz)
silent = PG_GETARG_BOOL(3);
}
- (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
- jb, !silent, &found, tz);
+ (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
PG_FREE_IF_COPY(jb, 0);
PG_FREE_IF_COPY(jp, 1);
@@ -490,8 +416,7 @@ jsonb_path_query_internal(FunctionCallInfo fcinfo, bool tz)
vars = PG_GETARG_JSONB_P_COPY(2);
silent = PG_GETARG_BOOL(3);
- (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
- jb, !silent, &found, tz);
+ (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
funcctx->user_fctx = JsonValueListGetList(&found);
@@ -538,8 +463,7 @@ jsonb_path_query_array_internal(FunctionCallInfo fcinfo, bool tz)
Jsonb *vars = PG_GETARG_JSONB_P(2);
bool silent = PG_GETARG_BOOL(3);
- (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
- jb, !silent, &found, tz);
+ (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
PG_RETURN_JSONB_P(JsonbValueToJsonb(wrapItemsInArray(&found)));
}
@@ -570,8 +494,7 @@ jsonb_path_query_first_internal(FunctionCallInfo fcinfo, bool tz)
Jsonb *vars = PG_GETARG_JSONB_P(2);
bool silent = PG_GETARG_BOOL(3);
- (void) executeJsonPath(jp, vars, getJsonPathVariableFromJsonb,
- jb, !silent, &found, tz);
+ (void) executeJsonPath(jp, vars, jb, !silent, &found, tz);
if (JsonValueListLength(&found) >= 1)
PG_RETURN_JSONB_P(JsonbValueToJsonb(JsonValueListHead(&found)));
@@ -613,9 +536,8 @@ jsonb_path_query_first_tz(PG_FUNCTION_ARGS)
* In other case it tries to find all the satisfied result items.
*/
static JsonPathExecResult
-executeJsonPath(JsonPath *path, void *vars, JsonPathVarCallback getVar,
- Jsonb *json, bool throwErrors, JsonValueList *result,
- bool useTz)
+executeJsonPath(JsonPath *path, Jsonb *vars, Jsonb *json, bool throwErrors,
+ JsonValueList *result, bool useTz)
{
JsonPathExecContext cxt;
JsonPathExecResult res;
@@ -627,16 +549,22 @@ executeJsonPath(JsonPath *path, void *vars, JsonPathVarCallback getVar,
if (!JsonbExtractScalar(&json->root, &jbv))
JsonbInitBinary(&jbv, json);
+ if (vars && !JsonContainerIsObject(&vars->root))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("\"vars\" argument is not an object"),
+ errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.")));
+ }
+
cxt.vars = vars;
- cxt.getVar = getVar;
cxt.laxMode = (path->header & JSONPATH_LAX) != 0;
cxt.ignoreStructuralErrors = cxt.laxMode;
cxt.root = &jbv;
cxt.current = &jbv;
cxt.baseObject.jbc = NULL;
cxt.baseObject.id = 0;
- /* 1 + number of base objects in vars */
- cxt.lastGeneratedObjectId = 1 + getVar(vars, NULL, 0, NULL, NULL);
+ cxt.lastGeneratedObjectId = vars ? 2 : 1;
cxt.innermostArraySize = -1;
cxt.throwErrors = throwErrors;
cxt.useTz = useTz;
@@ -2165,7 +2093,7 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
&value->val.string.len);
break;
case jpiVariable:
- getJsonPathVariable(cxt, item, value);
+ getJsonPathVariable(cxt, item, cxt->vars, value);
return;
default:
elog(ERROR, "unexpected jsonpath item type");
@@ -2177,63 +2105,42 @@ getJsonPathItem(JsonPathExecContext *cxt, JsonPathItem *item,
*/
static void
getJsonPathVariable(JsonPathExecContext *cxt, JsonPathItem *variable,
- JsonbValue *value)
+ Jsonb *vars, JsonbValue *value)
{
char *varName;
int varNameLength;
- JsonbValue baseObject;
- int baseObjectId;
-
- Assert(variable->type == jpiVariable);
- varName = jspGetString(variable, &varNameLength);
-
- if (!cxt->vars ||
- (baseObjectId = cxt->getVar(cxt->vars, varName, varNameLength, value,
- &baseObject)) < 0)
- ereport(ERROR,
- (errcode(ERRCODE_UNDEFINED_OBJECT),
- errmsg("could not find jsonpath variable \"%s\"",
- pnstrdup(varName, varNameLength))));
-
- if (baseObjectId > 0)
- setBaseObject(cxt, &baseObject, baseObjectId);
-}
-
-static int
-getJsonPathVariableFromJsonb(void *varsJsonb, char *varName, int varNameLength,
- JsonbValue *value, JsonbValue *baseObject)
-{
- Jsonb *vars = varsJsonb;
JsonbValue tmp;
JsonbValue *v;
- if (!varName)
+ if (!vars)
{
- if (vars && !JsonContainerIsObject(&vars->root))
- {
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("\"vars\" argument is not an object"),
- errdetail("Jsonpath parameters should be encoded as key-value pairs of \"vars\" object.")));
- }
-
- return vars ? 1 : 0; /* count of base objects */
+ value->type = jbvNull;
+ return;
}
+ Assert(variable->type == jpiVariable);
+ varName = jspGetString(variable, &varNameLength);
tmp.type = jbvString;
tmp.val.string.val = varName;
tmp.val.string.len = varNameLength;
v = findJsonbValueFromContainer(&vars->root, JB_FOBJECT, &tmp);
- if (!v)
- return -1;
-
- *value = *v;
- pfree(v);
+ if (v)
+ {
+ *value = *v;
+ pfree(v);
+ }
+ else
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("could not find jsonpath variable \"%s\"",
+ pnstrdup(varName, varNameLength))));
+ }
- JsonbInitBinary(baseObject, vars);
- return 1;
+ JsonbInitBinary(&tmp, vars);
+ setBaseObject(cxt, &tmp, 1);
}
/**************** Support functions for JsonPath execution *****************/
@@ -2523,13 +2430,6 @@ setBaseObject(JsonPathExecContext *cxt, JsonbValue *jbv, int32 id)
}
static void
-JsonValueListClear(JsonValueList *jvl)
-{
- jvl->singleton = NULL;
- jvl->list = NULL;
-}
-
-static void
JsonValueListAppend(JsonValueList *jvl, JsonbValue *jbv)
{
if (jvl->singleton)
@@ -2897,667 +2797,3 @@ compareDatetime(Datum val1, Oid typid1, Datum val2, Oid typid2,
return DatumGetInt32(DirectFunctionCall2(cmpfunc, val1, val2));
}
-
-/********************Interface to pgsql's executor***************************/
-
-bool
-JsonPathExists(Datum jb, JsonPath *jp, List *vars, bool *error)
-{
- JsonPathExecResult res = executeJsonPath(jp, vars, EvalJsonPathVar,
- DatumGetJsonbP(jb), !error, NULL,
- true);
-
- Assert(error || !jperIsError(res));
-
- if (error && jperIsError(res))
- *error = true;
-
- return res == jperOk;
-}
-
-Datum
-JsonPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper, bool *empty,
- bool *error, List *vars)
-{
- JsonbValue *first;
- bool wrap;
- JsonValueList found = {0};
- JsonPathExecResult res PG_USED_FOR_ASSERTS_ONLY;
- int count;
-
- res = executeJsonPath(jp, vars, EvalJsonPathVar, DatumGetJsonbP(jb), !error,
- &found, true);
-
- Assert(error || !jperIsError(res));
-
- if (error && jperIsError(res))
- {
- *error = true;
- *empty = false;
- return (Datum) 0;
- }
-
- count = JsonValueListLength(&found);
-
- first = count ? JsonValueListHead(&found) : NULL;
-
- if (!first)
- wrap = false;
- else if (wrapper == JSW_NONE)
- wrap = false;
- else if (wrapper == JSW_UNCONDITIONAL)
- wrap = true;
- else if (wrapper == JSW_CONDITIONAL)
- wrap = count > 1 ||
- IsAJsonbScalar(first) ||
- (first->type == jbvBinary &&
- JsonContainerIsScalar(first->val.binary.data));
- else
- {
- elog(ERROR, "unrecognized json wrapper %d", wrapper);
- wrap = false;
- }
-
- if (wrap)
- return JsonbPGetDatum(JsonbValueToJsonb(wrapItemsInArray(&found)));
-
- if (count > 1)
- {
- if (error)
- {
- *error = true;
- return (Datum) 0;
- }
-
- ereport(ERROR,
- (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM),
- errmsg("JSON path expression in JSON_QUERY should return "
- "singleton item without wrapper"),
- errhint("Use WITH WRAPPER clause to wrap SQL/JSON item "
- "sequence into array.")));
- }
-
- if (first)
- return JsonbPGetDatum(JsonbValueToJsonb(first));
-
- *empty = true;
- return PointerGetDatum(NULL);
-}
-
-JsonbValue *
-JsonPathValue(Datum jb, JsonPath *jp, bool *empty, bool *error, List *vars)
-{
- JsonbValue *res;
- JsonValueList found = {0};
- JsonPathExecResult jper PG_USED_FOR_ASSERTS_ONLY;
- int count;
-
- jper = executeJsonPath(jp, vars, EvalJsonPathVar, DatumGetJsonbP(jb), !error,
- &found, true);
-
- Assert(error || !jperIsError(jper));
-
- if (error && jperIsError(jper))
- {
- *error = true;
- *empty = false;
- return NULL;
- }
-
- count = JsonValueListLength(&found);
-
- *empty = !count;
-
- if (*empty)
- return NULL;
-
- if (count > 1)
- {
- if (error)
- {
- *error = true;
- return NULL;
- }
-
- ereport(ERROR,
- (errcode(ERRCODE_MORE_THAN_ONE_SQL_JSON_ITEM),
- errmsg("JSON path expression in JSON_VALUE should return "
- "singleton scalar item")));
- }
-
- res = JsonValueListHead(&found);
-
- if (res->type == jbvBinary &&
- JsonContainerIsScalar(res->val.binary.data))
- JsonbExtractScalar(res->val.binary.data, res);
-
- if (!IsAJsonbScalar(res))
- {
- if (error)
- {
- *error = true;
- return NULL;
- }
-
- ereport(ERROR,
- (errcode(ERRCODE_SQL_JSON_SCALAR_REQUIRED),
- errmsg("JSON path expression in JSON_VALUE should return "
- "singleton scalar item")));
- }
-
- if (res->type == jbvNull)
- return NULL;
-
- return res;
-}
-
-static void
-JsonbValueInitNumericDatum(JsonbValue *jbv, Datum num)
-{
- jbv->type = jbvNumeric;
- jbv->val.numeric = DatumGetNumeric(num);
-}
-
-void
-JsonItemFromDatum(Datum val, Oid typid, int32 typmod, JsonbValue *res)
-{
- switch (typid)
- {
- case BOOLOID:
- res->type = jbvBool;
- res->val.boolean = DatumGetBool(val);
- break;
- case NUMERICOID:
- JsonbValueInitNumericDatum(res, val);
- break;
- case INT2OID:
- JsonbValueInitNumericDatum(res, DirectFunctionCall1(int2_numeric, val));
- break;
- case INT4OID:
- JsonbValueInitNumericDatum(res, DirectFunctionCall1(int4_numeric, val));
- break;
- case INT8OID:
- JsonbValueInitNumericDatum(res, DirectFunctionCall1(int8_numeric, val));
- break;
- case FLOAT4OID:
- JsonbValueInitNumericDatum(res, DirectFunctionCall1(float4_numeric, val));
- break;
- case FLOAT8OID:
- JsonbValueInitNumericDatum(res, DirectFunctionCall1(float8_numeric, val));
- break;
- case TEXTOID:
- case VARCHAROID:
- res->type = jbvString;
- res->val.string.val = VARDATA_ANY(val);
- res->val.string.len = VARSIZE_ANY_EXHDR(val);
- break;
- case DATEOID:
- case TIMEOID:
- case TIMETZOID:
- case TIMESTAMPOID:
- case TIMESTAMPTZOID:
- res->type = jbvDatetime;
- res->val.datetime.value = val;
- res->val.datetime.typid = typid;
- res->val.datetime.typmod = typmod;
- res->val.datetime.tz = 0;
- break;
- case JSONBOID:
- {
- JsonbValue *jbv = res;
- Jsonb *jb = DatumGetJsonbP(val);
-
- if (JsonContainerIsScalar(&jb->root))
- {
- bool result PG_USED_FOR_ASSERTS_ONLY;
-
- result = JsonbExtractScalar(&jb->root, jbv);
- Assert(result);
- }
- else
- JsonbInitBinary(jbv, jb);
- break;
- }
- case JSONOID:
- {
- text *txt = DatumGetTextP(val);
- char *str = text_to_cstring(txt);
- Jsonb *jb =
- DatumGetJsonbP(DirectFunctionCall1(jsonb_in,
- CStringGetDatum(str)));
-
- pfree(str);
-
- JsonItemFromDatum(JsonbPGetDatum(jb), JSONBOID, -1, res);
- break;
- }
- default:
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
- errmsg("only bool, numeric, and text types could be "
- "casted to supported jsonpath types.")));
- }
-}
-
-/************************ JSON_TABLE functions ***************************/
-
-/*
- * Returns private data from executor state. Ensure validity by check with
- * MAGIC number.
- */
-static inline JsonTableContext *
-GetJsonTableContext(TableFuncScanState *state, const char *fname)
-{
- JsonTableContext *result;
-
- if (!IsA(state, TableFuncScanState))
- elog(ERROR, "%s called with invalid TableFuncScanState", fname);
- result = (JsonTableContext *) state->opaque;
- if (result->magic != JSON_TABLE_CONTEXT_MAGIC)
- elog(ERROR, "%s called with invalid TableFuncScanState", fname);
-
- return result;
-}
-
-/* Recursively initialize JSON_TABLE scan state */
-static void
-JsonTableInitScanState(JsonTableContext *cxt, JsonTableScanState *scan,
- JsonTableParent *node, JsonTableScanState *parent,
- List *args, MemoryContext mcxt)
-{
- int i;
-
- scan->parent = parent;
- scan->outerJoin = node->outerJoin;
- scan->errorOnError = node->errorOnError;
- scan->path = DatumGetJsonPathP(node->path->constvalue);
- scan->args = args;
- scan->mcxt = AllocSetContextCreate(mcxt, "JsonTableContext",
- ALLOCSET_DEFAULT_SIZES);
- scan->nested = node->child ?
- JsonTableInitPlanState(cxt, node->child, scan) : NULL;
- scan->current = PointerGetDatum(NULL);
- scan->currentIsNull = true;
-
- for (i = node->colMin; i <= node->colMax; i++)
- cxt->colexprs[i].scan = scan;
-}
-
-/* Recursively initialize JSON_TABLE scan state */
-static JsonTableJoinState *
-JsonTableInitPlanState(JsonTableContext *cxt, Node *plan,
- JsonTableScanState *parent)
-{
- JsonTableJoinState *state = palloc0(sizeof(*state));
-
- if (IsA(plan, JsonTableSibling))
- {
- JsonTableSibling *join = castNode(JsonTableSibling, plan);
-
- state->is_join = true;
- state->u.join.cross = join->cross;
- state->u.join.left = JsonTableInitPlanState(cxt, join->larg, parent);
- state->u.join.right = JsonTableInitPlanState(cxt, join->rarg, parent);
- }
- else
- {
- JsonTableParent *node = castNode(JsonTableParent, plan);
-
- state->is_join = false;
-
- JsonTableInitScanState(cxt, &state->u.scan, node, parent,
- parent->args, parent->mcxt);
- }
-
- return state;
-}
-
-/*
- * JsonTableInitOpaque
- * Fill in TableFuncScanState->opaque for JsonTable processor
- */
-static void
-JsonTableInitOpaque(TableFuncScanState *state, int natts)
-{
- JsonTableContext *cxt;
- PlanState *ps = &state->ss.ps;
- TableFuncScan *tfs = castNode(TableFuncScan, ps->plan);
- TableFunc *tf = tfs->tablefunc;
- JsonExpr *ci = castNode(JsonExpr, tf->docexpr);
- JsonTableParent *root = castNode(JsonTableParent, tf->plan);
- List *args = NIL;
- ListCell *lc;
- int i;
-
- cxt = palloc0(sizeof(JsonTableContext));
- cxt->magic = JSON_TABLE_CONTEXT_MAGIC;
-
- if (ci->passing_values)
- {
- ListCell *exprlc;
- ListCell *namelc;
-
- forboth(exprlc, ci->passing_values,
- namelc, ci->passing_names)
- {
- Expr *expr = (Expr *) lfirst(exprlc);
- String *name = lfirst_node(String, namelc);
- JsonPathVariableEvalContext *var = palloc(sizeof(*var));
-
- var->name = pstrdup(name->sval);
- var->typid = exprType((Node *) expr);
- var->typmod = exprTypmod((Node *) expr);
- var->estate = ExecInitExpr(expr, ps);
- var->econtext = ps->ps_ExprContext;
- var->mcxt = CurrentMemoryContext;
- var->evaluated = false;
- var->value = (Datum) 0;
- var->isnull = true;
-
- args = lappend(args, var);
- }
- }
-
- cxt->colexprs = palloc(sizeof(*cxt->colexprs) *
- list_length(tf->colvalexprs));
-
- JsonTableInitScanState(cxt, &cxt->root, root, NULL, args,
- CurrentMemoryContext);
-
- i = 0;
-
- foreach(lc, tf->colvalexprs)
- {
- Expr *expr = lfirst(lc);
-
- cxt->colexprs[i].expr =
- ExecInitExprWithCaseValue(expr, ps,
- &cxt->colexprs[i].scan->current,
- &cxt->colexprs[i].scan->currentIsNull);
-
- i++;
- }
-
- state->opaque = cxt;
-}
-
-/* Reset scan iterator to the beginning of the item list */
-static void
-JsonTableRescan(JsonTableScanState *scan)
-{
- JsonValueListInitIterator(&scan->found, &scan->iter);
- scan->current = PointerGetDatum(NULL);
- scan->currentIsNull = true;
- scan->advanceNested = false;
- scan->ordinal = 0;
-}
-
-/* Reset context item of a scan, execute JSON path and reset a scan */
-static void
-JsonTableResetContextItem(JsonTableScanState *scan, Datum item)
-{
- MemoryContext oldcxt;
- JsonPathExecResult res;
- Jsonb *js = (Jsonb *) DatumGetJsonbP(item);
-
- JsonValueListClear(&scan->found);
-
- MemoryContextResetOnly(scan->mcxt);
-
- oldcxt = MemoryContextSwitchTo(scan->mcxt);
-
- res = executeJsonPath(scan->path, scan->args, EvalJsonPathVar, js,
- scan->errorOnError, &scan->found, false /* FIXME */ );
-
- MemoryContextSwitchTo(oldcxt);
-
- if (jperIsError(res))
- {
- Assert(!scan->errorOnError);
- JsonValueListClear(&scan->found); /* EMPTY ON ERROR case */
- }
-
- JsonTableRescan(scan);
-}
-
-/*
- * JsonTableSetDocument
- * Install the input document
- */
-static void
-JsonTableSetDocument(TableFuncScanState *state, Datum value)
-{
- JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableSetDocument");
-
- JsonTableResetContextItem(&cxt->root, value);
-}
-
-/* Recursively reset scan and its child nodes */
-static void
-JsonTableRescanRecursive(JsonTableJoinState *state)
-{
- if (state->is_join)
- {
- JsonTableRescanRecursive(state->u.join.left);
- JsonTableRescanRecursive(state->u.join.right);
- state->u.join.advanceRight = false;
- }
- else
- {
- JsonTableRescan(&state->u.scan);
- if (state->u.scan.nested)
- JsonTableRescanRecursive(state->u.scan.nested);
- }
-}
-
-/*
- * Fetch next row from a cross/union joined scan.
- *
- * Returns false at the end of a scan, true otherwise.
- */
-static bool
-JsonTableNextJoinRow(JsonTableJoinState *state)
-{
- if (!state->is_join)
- return JsonTableNextRow(&state->u.scan);
-
- if (state->u.join.advanceRight)
- {
- /* fetch next inner row */
- if (JsonTableNextJoinRow(state->u.join.right))
- return true;
-
- /* inner rows are exhausted */
- if (state->u.join.cross)
- state->u.join.advanceRight = false; /* next outer row */
- else
- return false; /* end of scan */
- }
-
- while (!state->u.join.advanceRight)
- {
- /* fetch next outer row */
- bool left = JsonTableNextJoinRow(state->u.join.left);
-
- if (state->u.join.cross)
- {
- if (!left)
- return false; /* end of scan */
-
- JsonTableRescanRecursive(state->u.join.right);
-
- if (!JsonTableNextJoinRow(state->u.join.right))
- continue; /* next outer row */
-
- state->u.join.advanceRight = true; /* next inner row */
- }
- else if (!left)
- {
- if (!JsonTableNextJoinRow(state->u.join.right))
- return false; /* end of scan */
-
- state->u.join.advanceRight = true; /* next inner row */
- }
-
- break;
- }
-
- return true;
-}
-
-/* Recursively set 'reset' flag of scan and its child nodes */
-static void
-JsonTableJoinReset(JsonTableJoinState *state)
-{
- if (state->is_join)
- {
- JsonTableJoinReset(state->u.join.left);
- JsonTableJoinReset(state->u.join.right);
- state->u.join.advanceRight = false;
- }
- else
- {
- state->u.scan.reset = true;
- state->u.scan.advanceNested = false;
-
- if (state->u.scan.nested)
- JsonTableJoinReset(state->u.scan.nested);
- }
-}
-
-/*
- * Fetch next row from a simple scan with outer/inner joined nested subscans.
- *
- * Returns false at the end of a scan, true otherwise.
- */
-static bool
-JsonTableNextRow(JsonTableScanState *scan)
-{
- /* reset context item if requested */
- if (scan->reset)
- {
- Assert(!scan->parent->currentIsNull);
- JsonTableResetContextItem(scan, scan->parent->current);
- scan->reset = false;
- }
-
- if (scan->advanceNested)
- {
- /* fetch next nested row */
- scan->advanceNested = JsonTableNextJoinRow(scan->nested);
-
- if (scan->advanceNested)
- return true;
- }
-
- for (;;)
- {
- /* fetch next row */
- JsonbValue *jbv = JsonValueListNext(&scan->found, &scan->iter);
- MemoryContext oldcxt;
-
- if (!jbv)
- {
- scan->current = PointerGetDatum(NULL);
- scan->currentIsNull = true;
- return false; /* end of scan */
- }
-
- /* set current row item */
- oldcxt = MemoryContextSwitchTo(scan->mcxt);
- scan->current = JsonbPGetDatum(JsonbValueToJsonb(jbv));
- scan->currentIsNull = false;
- MemoryContextSwitchTo(oldcxt);
-
- scan->ordinal++;
-
- if (!scan->nested)
- break;
-
- JsonTableJoinReset(scan->nested);
-
- scan->advanceNested = JsonTableNextJoinRow(scan->nested);
-
- if (scan->advanceNested || scan->outerJoin)
- break;
- }
-
- return true;
-}
-
-/*
- * JsonTableFetchRow
- * Prepare the next "current" tuple for upcoming GetValue calls.
- * Returns FALSE if the row-filter expression returned no more rows.
- */
-static bool
-JsonTableFetchRow(TableFuncScanState *state)
-{
- JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableFetchRow");
-
- if (cxt->empty)
- return false;
-
- return JsonTableNextRow(&cxt->root);
-}
-
-/*
- * JsonTableGetValue
- * Return the value for column number 'colnum' for the current row.
- *
- * This leaks memory, so be sure to reset often the context in which it's
- * called.
- */
-static Datum
-JsonTableGetValue(TableFuncScanState *state, int colnum,
- Oid typid, int32 typmod, bool *isnull)
-{
- JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableGetValue");
- ExprContext *econtext = state->ss.ps.ps_ExprContext;
- ExprState *estate = cxt->colexprs[colnum].expr;
- JsonTableScanState *scan = cxt->colexprs[colnum].scan;
- Datum result;
-
- if (scan->currentIsNull) /* NULL from outer/union join */
- {
- result = (Datum) 0;
- *isnull = true;
- }
- else if (estate) /* regular column */
- {
- result = ExecEvalExpr(estate, econtext, isnull);
- }
- else
- {
- result = Int32GetDatum(scan->ordinal); /* ordinality column */
- *isnull = false;
- }
-
- return result;
-}
-
-/*
- * JsonTableDestroyOpaque
- */
-static void
-JsonTableDestroyOpaque(TableFuncScanState *state)
-{
- JsonTableContext *cxt = GetJsonTableContext(state, "JsonTableDestroyOpaque");
-
- /* not valid anymore */
- cxt->magic = 0;
-
- state->opaque = NULL;
-}
-
-const TableFuncRoutine JsonbTableRoutine =
-{
- JsonTableInitOpaque,
- JsonTableSetDocument,
- NULL,
- NULL,
- NULL,
- JsonTableFetchRow,
- JsonTableGetValue,
- JsonTableDestroyOpaque
-};
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 9959f6910e..6594a9aac7 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -466,12 +466,6 @@ static void get_coercion_expr(Node *arg, deparse_context *context,
Node *parentNode);
static void get_const_expr(Const *constval, deparse_context *context,
int showtype);
-static void get_json_constructor(JsonConstructorExpr *ctor,
- deparse_context *context, bool showimplicit);
-static void get_json_agg_constructor(JsonConstructorExpr *ctor,
- deparse_context *context,
- const char *funcname,
- bool is_json_objectagg);
static void get_const_collation(Const *constval, deparse_context *context);
static void simple_quote_literal(StringInfo buf, const char *val);
static void get_sublink_expr(SubLink *sublink, deparse_context *context);
@@ -505,10 +499,6 @@ static char *generate_qualified_type_name(Oid typid);
static text *string_to_text(char *str);
static char *flatten_reloptions(Oid relid);
static void get_reloptions(StringInfo buf, Datum reloptions);
-static void get_json_path_spec(Node *path_spec, deparse_context *context,
- bool showimplicit);
-static void get_json_table_columns(TableFunc *tf, JsonTableParent *node,
- deparse_context *context, bool showimplicit);
#define only_marker(rte) ((rte)->inh ? "" : "ONLY ")
@@ -6338,8 +6328,7 @@ get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno,
bool need_paren = (PRETTY_PAREN(context)
|| IsA(expr, FuncExpr)
|| IsA(expr, Aggref)
- || IsA(expr, WindowFunc)
- || IsA(expr, JsonConstructorExpr));
+ || IsA(expr, WindowFunc));
if (need_paren)
appendStringInfoChar(context->buf, '(');
@@ -8198,8 +8187,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_GroupingFunc:
case T_WindowFunc:
case T_FuncExpr:
- case T_JsonConstructorExpr:
- case T_JsonExpr:
/* function-like: name(..) or name[..] */
return true;
@@ -8293,7 +8280,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_NullTest:
case T_BooleanTest:
case T_DistinctExpr:
- case T_JsonIsPredicate:
switch (nodeTag(parentNode))
{
case T_FuncExpr:
@@ -8318,7 +8304,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
case T_GroupingFunc: /* own parentheses */
case T_WindowFunc: /* own parentheses */
case T_CaseExpr: /* other separators */
- case T_JsonExpr: /* own parentheses */
return true;
default:
return false;
@@ -8375,11 +8360,6 @@ isSimpleNode(Node *node, Node *parentNode, int prettyFlags)
return false;
}
- case T_JsonValueExpr:
- /* maybe simple, check args */
- return isSimpleNode((Node *) ((JsonValueExpr *) node)->raw_expr,
- node, prettyFlags);
-
default:
break;
}
@@ -8486,122 +8466,6 @@ get_rule_expr_paren(Node *node, deparse_context *context,
}
-/*
- * get_json_path_spec - Parse back a JSON path specification
- */
-static void
-get_json_path_spec(Node *path_spec, deparse_context *context, bool showimplicit)
-{
- if (IsA(path_spec, Const))
- get_const_expr((Const *) path_spec, context, -1);
- else
- get_rule_expr(path_spec, context, showimplicit);
-}
-
-/*
- * get_json_format - Parse back a JsonFormat node
- */
-static void
-get_json_format(JsonFormat *format, StringInfo buf)
-{
- if (format->format_type == JS_FORMAT_DEFAULT)
- return;
-
- appendStringInfoString(buf,
- format->format_type == JS_FORMAT_JSONB ?
- " FORMAT JSONB" : " FORMAT JSON");
-
- if (format->encoding != JS_ENC_DEFAULT)
- {
- const char *encoding =
- format->encoding == JS_ENC_UTF16 ? "UTF16" :
- format->encoding == JS_ENC_UTF32 ? "UTF32" : "UTF8";
-
- appendStringInfo(buf, " ENCODING %s", encoding);
- }
-}
-
-/*
- * get_json_returning - Parse back a JsonReturning structure
- */
-static void
-get_json_returning(JsonReturning *returning, StringInfo buf,
- bool json_format_by_default)
-{
- if (!OidIsValid(returning->typid))
- return;
-
- appendStringInfo(buf, " RETURNING %s",
- format_type_with_typemod(returning->typid,
- returning->typmod));
-
- if (!json_format_by_default ||
- returning->format->format_type !=
- (returning->typid == JSONBOID ? JS_FORMAT_JSONB : JS_FORMAT_JSON))
- get_json_format(returning->format, buf);
-}
-
-static void
-get_json_behavior(JsonBehavior *behavior, deparse_context *context,
- const char *on)
-{
- /*
- * The order of array elements must correspond to the order of
- * JsonBehaviorType members.
- */
- const char *behavior_names[] =
- {
- " NULL",
- " ERROR",
- " EMPTY",
- " TRUE",
- " FALSE",
- " UNKNOWN",
- " EMPTY ARRAY",
- " EMPTY OBJECT",
- " DEFAULT "
- };
-
- if ((int) behavior->btype < 0 || behavior->btype >= lengthof(behavior_names))
- elog(ERROR, "invalid json behavior type: %d", behavior->btype);
-
- appendStringInfoString(context->buf, behavior_names[behavior->btype]);
-
- if (behavior->btype == JSON_BEHAVIOR_DEFAULT)
- get_rule_expr(behavior->default_expr, context, false);
-
- appendStringInfo(context->buf, " ON %s", on);
-}
-
-/*
- * get_json_expr_options
- *
- * Parse back common options for JSON_QUERY, JSON_VALUE, JSON_EXISTS and
- * JSON_TABLE columns.
- */
-static void
-get_json_expr_options(JsonExpr *jsexpr, deparse_context *context,
- JsonBehaviorType default_behavior)
-{
- if (jsexpr->op == JSON_QUERY_OP)
- {
- if (jsexpr->wrapper == JSW_CONDITIONAL)
- appendStringInfo(context->buf, " WITH CONDITIONAL WRAPPER");
- else if (jsexpr->wrapper == JSW_UNCONDITIONAL)
- appendStringInfo(context->buf, " WITH UNCONDITIONAL WRAPPER");
-
- if (jsexpr->omit_quotes)
- appendStringInfo(context->buf, " OMIT QUOTES");
- }
-
- if (jsexpr->op != JSON_EXISTS_OP &&
- jsexpr->on_empty->btype != default_behavior)
- get_json_behavior(jsexpr->on_empty, context, "EMPTY");
-
- if (jsexpr->on_error->btype != default_behavior)
- get_json_behavior(jsexpr->on_error, context, "ERROR");
-}
-
/* ----------
* get_rule_expr - Parse back an expression
*
@@ -9760,116 +9624,6 @@ get_rule_expr(Node *node, deparse_context *context,
}
break;
-
- case T_JsonValueExpr:
- {
- JsonValueExpr *jve = (JsonValueExpr *) node;
-
- get_rule_expr((Node *) jve->raw_expr, context, false);
- get_json_format(jve->format, context->buf);
- }
- break;
-
- case T_JsonConstructorExpr:
- get_json_constructor((JsonConstructorExpr *) node, context, false);
- break;
-
- case T_JsonIsPredicate:
- {
- JsonIsPredicate *pred = (JsonIsPredicate *) node;
-
- if (!PRETTY_PAREN(context))
- appendStringInfoChar(context->buf, '(');
-
- get_rule_expr_paren(pred->expr, context, true, node);
-
- appendStringInfoString(context->buf, " IS JSON");
-
- /* TODO: handle FORMAT clause */
-
- switch (pred->item_type)
- {
- case JS_TYPE_SCALAR:
- appendStringInfoString(context->buf, " SCALAR");
- break;
- case JS_TYPE_ARRAY:
- appendStringInfoString(context->buf, " ARRAY");
- break;
- case JS_TYPE_OBJECT:
- appendStringInfoString(context->buf, " OBJECT");
- break;
- default:
- break;
- }
-
- if (pred->unique_keys)
- appendStringInfoString(context->buf, " WITH UNIQUE KEYS");
-
- if (!PRETTY_PAREN(context))
- appendStringInfoChar(context->buf, ')');
- }
- break;
-
- case T_JsonExpr:
- {
- JsonExpr *jexpr = (JsonExpr *) node;
-
- switch (jexpr->op)
- {
- case JSON_QUERY_OP:
- appendStringInfoString(buf, "JSON_QUERY(");
- break;
- case JSON_VALUE_OP:
- appendStringInfoString(buf, "JSON_VALUE(");
- break;
- case JSON_EXISTS_OP:
- appendStringInfoString(buf, "JSON_EXISTS(");
- break;
- default:
- elog(ERROR, "unexpected JsonExpr type: %d", jexpr->op);
- break;
- }
-
- get_rule_expr(jexpr->formatted_expr, context, showimplicit);
-
- appendStringInfoString(buf, ", ");
-
- get_json_path_spec(jexpr->path_spec, context, showimplicit);
-
- if (jexpr->passing_values)
- {
- ListCell *lc1,
- *lc2;
- bool needcomma = false;
-
- appendStringInfoString(buf, " PASSING ");
-
- forboth(lc1, jexpr->passing_names,
- lc2, jexpr->passing_values)
- {
- if (needcomma)
- appendStringInfoString(buf, ", ");
- needcomma = true;
-
- get_rule_expr((Node *) lfirst(lc2), context, showimplicit);
- appendStringInfo(buf, " AS %s",
- ((String *) lfirst_node(String, lc1))->sval);
- }
- }
-
- if (jexpr->op != JSON_EXISTS_OP ||
- jexpr->returning->typid != BOOLOID)
- get_json_returning(jexpr->returning, context->buf,
- jexpr->op == JSON_QUERY_OP);
-
- get_json_expr_options(jexpr, context,
- jexpr->op == JSON_EXISTS_OP ?
- JSON_BEHAVIOR_FALSE : JSON_BEHAVIOR_NULL);
-
- appendStringInfoString(buf, ")");
- }
- break;
-
case T_List:
{
char *sep;
@@ -9993,7 +9747,6 @@ looks_like_function(Node *node)
case T_MinMaxExpr:
case T_SQLValueFunction:
case T_XmlExpr:
- case T_JsonExpr:
/* these are all accepted by func_expr_common_subexpr */
return true;
default:
@@ -10139,103 +9892,17 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
appendStringInfoChar(buf, ')');
}
-static void
-get_json_constructor_options(JsonConstructorExpr *ctor, StringInfo buf)
-{
- if (ctor->absent_on_null)
- {
- if (ctor->type == JSCTOR_JSON_OBJECT ||
- ctor->type == JSCTOR_JSON_OBJECTAGG)
- appendStringInfoString(buf, " ABSENT ON NULL");
- }
- else
- {
- if (ctor->type == JSCTOR_JSON_ARRAY ||
- ctor->type == JSCTOR_JSON_ARRAYAGG)
- appendStringInfoString(buf, " NULL ON NULL");
- }
-
- if (ctor->unique)
- appendStringInfoString(buf, " WITH UNIQUE KEYS");
-
- if (!((ctor->type == JSCTOR_JSON_PARSE ||
- ctor->type == JSCTOR_JSON_SCALAR) &&
- ctor->returning->typid == JSONOID))
- get_json_returning(ctor->returning, buf, true);
-}
-
-static void
-get_json_constructor(JsonConstructorExpr *ctor, deparse_context *context,
- bool showimplicit)
-{
- StringInfo buf = context->buf;
- const char *funcname;
- int nargs;
- ListCell *lc;
-
- switch (ctor->type)
- {
- case JSCTOR_JSON_PARSE:
- funcname = "JSON";
- break;
- case JSCTOR_JSON_SCALAR:
- funcname = "JSON_SCALAR";
- break;
- case JSCTOR_JSON_SERIALIZE:
- funcname = "JSON_SERIALIZE";
- break;
- case JSCTOR_JSON_OBJECT:
- funcname = "JSON_OBJECT";
- break;
- case JSCTOR_JSON_ARRAY:
- funcname = "JSON_ARRAY";
- break;
- case JSCTOR_JSON_OBJECTAGG:
- get_json_agg_constructor(ctor, context, "JSON_OBJECTAGG", true);
- return;
- case JSCTOR_JSON_ARRAYAGG:
- get_json_agg_constructor(ctor, context, "JSON_ARRAYAGG", false);
- return;
- default:
- elog(ERROR, "invalid JsonConstructorExprType %d", ctor->type);
- }
-
- appendStringInfo(buf, "%s(", funcname);
-
- nargs = 0;
- foreach(lc, ctor->args)
- {
- if (nargs > 0)
- {
- const char *sep = ctor->type == JSCTOR_JSON_OBJECT &&
- (nargs % 2) != 0 ? " : " : ", ";
-
- appendStringInfoString(buf, sep);
- }
-
- get_rule_expr((Node *) lfirst(lc), context, true);
-
- nargs++;
- }
-
- get_json_constructor_options(ctor, buf);
-
- appendStringInfo(buf, ")");
-}
-
-
/*
- * get_agg_expr_helper - Parse back an Aggref node
+ * get_agg_expr - Parse back an Aggref node
*/
static void
-get_agg_expr_helper(Aggref *aggref, deparse_context *context,
- Aggref *original_aggref, const char *funcname,
- const char *options, bool is_json_objectagg)
+get_agg_expr(Aggref *aggref, deparse_context *context,
+ Aggref *original_aggref)
{
StringInfo buf = context->buf;
Oid argtypes[FUNC_MAX_ARGS];
int nargs;
- bool use_variadic = false;
+ bool use_variadic;
/*
* For a combining aggregate, we look up and deparse the corresponding
@@ -10265,14 +9932,13 @@ get_agg_expr_helper(Aggref *aggref, deparse_context *context,
/* Extract the argument types as seen by the parser */
nargs = get_aggregate_argtypes(aggref, argtypes);
- if (!funcname)
- funcname = generate_function_name(aggref->aggfnoid, nargs, NIL,
- argtypes, aggref->aggvariadic,
- &use_variadic,
- context->special_exprkind);
-
/* Print the aggregate name, schema-qualified if needed */
- appendStringInfo(buf, "%s(%s", funcname,
+ appendStringInfo(buf, "%s(%s",
+ generate_function_name(aggref->aggfnoid, nargs,
+ NIL, argtypes,
+ aggref->aggvariadic,
+ &use_variadic,
+ context->special_exprkind),
(aggref->aggdistinct != NIL) ? "DISTINCT " : "");
if (AGGKIND_IS_ORDERED_SET(aggref->aggkind))
@@ -10308,18 +9974,7 @@ get_agg_expr_helper(Aggref *aggref, deparse_context *context,
if (tle->resjunk)
continue;
if (i++ > 0)
- {
- if (is_json_objectagg)
- {
- if (i > 2)
- break; /* skip ABSENT ON NULL and WITH UNIQUE
- * args */
-
- appendStringInfoString(buf, " : ");
- }
- else
- appendStringInfoString(buf, ", ");
- }
+ appendStringInfoString(buf, ", ");
if (use_variadic && i == nargs)
appendStringInfoString(buf, "VARIADIC ");
get_rule_expr(arg, context, true);
@@ -10333,9 +9988,6 @@ get_agg_expr_helper(Aggref *aggref, deparse_context *context,
}
}
- if (options)
- appendStringInfoString(buf, options);
-
if (aggref->aggfilter != NULL)
{
appendStringInfoString(buf, ") FILTER (WHERE ");
@@ -10346,16 +9998,6 @@ get_agg_expr_helper(Aggref *aggref, deparse_context *context,
}
/*
- * get_agg_expr - Parse back an Aggref node
- */
-static void
-get_agg_expr(Aggref *aggref, deparse_context *context, Aggref *original_aggref)
-{
- get_agg_expr_helper(aggref, context, original_aggref, NULL, NULL,
- false);
-}
-
-/*
* This is a helper function for get_agg_expr(). It's used when we deparse
* a combining Aggref; resolve_special_varno locates the corresponding partial
* Aggref and then calls this.
@@ -10374,12 +10016,10 @@ get_agg_combine_expr(Node *node, deparse_context *context, void *callback_arg)
}
/*
- * get_windowfunc_expr_helper - Parse back a WindowFunc node
+ * get_windowfunc_expr - Parse back a WindowFunc node
*/
static void
-get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
- const char *funcname, const char *options,
- bool is_json_objectagg)
+get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
{
StringInfo buf = context->buf;
Oid argtypes[FUNC_MAX_ARGS];
@@ -10403,30 +10043,16 @@ get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
nargs++;
}
- if (!funcname)
- funcname = generate_function_name(wfunc->winfnoid, nargs, argnames,
- argtypes, false, NULL,
- context->special_exprkind);
-
- appendStringInfo(buf, "%s(", funcname);
-
+ appendStringInfo(buf, "%s(",
+ generate_function_name(wfunc->winfnoid, nargs,
+ argnames, argtypes,
+ false, NULL,
+ context->special_exprkind));
/* winstar can be set only in zero-argument aggregates */
if (wfunc->winstar)
appendStringInfoChar(buf, '*');
else
- {
- if (is_json_objectagg)
- {
- get_rule_expr((Node *) linitial(wfunc->args), context, false);
- appendStringInfoString(buf, " : ");
- get_rule_expr((Node *) lsecond(wfunc->args), context, false);
- }
- else
- get_rule_expr((Node *) wfunc->args, context, true);
- }
-
- if (options)
- appendStringInfoString(buf, options);
+ get_rule_expr((Node *) wfunc->args, context, true);
if (wfunc->aggfilter != NULL)
{
@@ -10464,15 +10090,6 @@ get_windowfunc_expr_helper(WindowFunc *wfunc, deparse_context *context,
}
/*
- * get_windowfunc_expr - Parse back a WindowFunc node
- */
-static void
-get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context)
-{
- get_windowfunc_expr_helper(wfunc, context, NULL, NULL, false);
-}
-
-/*
* get_func_sql_syntax - Parse back a SQL-syntax function call
*
* Returns true if we successfully deparsed, false if we did not
@@ -10712,31 +10329,6 @@ get_func_sql_syntax(FuncExpr *expr, deparse_context *context)
return false;
}
-/*
- * get_json_agg_constructor - Parse back an aggregate JsonConstructorExpr node
- */
-static void
-get_json_agg_constructor(JsonConstructorExpr *ctor, deparse_context *context,
- const char *funcname, bool is_json_objectagg)
-{
- StringInfoData options;
-
- initStringInfo(&options);
- get_json_constructor_options(ctor, &options);
-
- if (IsA(ctor->func, Aggref))
- get_agg_expr_helper((Aggref *) ctor->func, context,
- (Aggref *) ctor->func,
- funcname, options.data, is_json_objectagg);
- else if (IsA(ctor->func, WindowFunc))
- get_windowfunc_expr_helper((WindowFunc *) ctor->func, context,
- funcname, options.data,
- is_json_objectagg);
- else
- elog(ERROR, "invalid JsonConstructorExpr underlying node type: %d",
- nodeTag(ctor->func));
-}
-
/* ----------
* get_coercion_expr
*
@@ -11106,14 +10698,16 @@ get_sublink_expr(SubLink *sublink, deparse_context *context)
/* ----------
- * get_xmltable - Parse back a XMLTABLE function
+ * get_tablefunc - Parse back a table function
* ----------
*/
static void
-get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
+get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
{
StringInfo buf = context->buf;
+ /* XMLTABLE is the only existing implementation. */
+
appendStringInfoString(buf, "XMLTABLE(");
if (tf->ns_uris != NIL)
@@ -11204,271 +10798,6 @@ get_xmltable(TableFunc *tf, deparse_context *context, bool showimplicit)
appendStringInfoChar(buf, ')');
}
-/*
- * get_json_nested_columns - Parse back nested JSON_TABLE columns
- */
-static void
-get_json_table_nested_columns(TableFunc *tf, Node *node,
- deparse_context *context, bool showimplicit,
- bool needcomma)
-{
- if (IsA(node, JsonTableSibling))
- {
- JsonTableSibling *n = (JsonTableSibling *) node;
-
- get_json_table_nested_columns(tf, n->larg, context, showimplicit,
- needcomma);
- get_json_table_nested_columns(tf, n->rarg, context, showimplicit, true);
- }
- else
- {
- JsonTableParent *n = castNode(JsonTableParent, node);
-
- if (needcomma)
- appendStringInfoChar(context->buf, ',');
-
- appendStringInfoChar(context->buf, ' ');
- appendContextKeyword(context, "NESTED PATH ", 0, 0, 0);
- get_const_expr(n->path, context, -1);
- appendStringInfo(context->buf, " AS %s", quote_identifier(n->name));
- get_json_table_columns(tf, n, context, showimplicit);
- }
-}
-
-/*
- * get_json_table_plan - Parse back a JSON_TABLE plan
- */
-static void
-get_json_table_plan(TableFunc *tf, Node *node, deparse_context *context,
- bool parenthesize)
-{
- if (parenthesize)
- appendStringInfoChar(context->buf, '(');
-
- if (IsA(node, JsonTableSibling))
- {
- JsonTableSibling *n = (JsonTableSibling *) node;
-
- get_json_table_plan(tf, n->larg, context,
- IsA(n->larg, JsonTableSibling) ||
- castNode(JsonTableParent, n->larg)->child);
-
- appendStringInfoString(context->buf, n->cross ? " CROSS " : " UNION ");
-
- get_json_table_plan(tf, n->rarg, context,
- IsA(n->rarg, JsonTableSibling) ||
- castNode(JsonTableParent, n->rarg)->child);
- }
- else
- {
- JsonTableParent *n = castNode(JsonTableParent, node);
-
- appendStringInfoString(context->buf, quote_identifier(n->name));
-
- if (n->child)
- {
- appendStringInfoString(context->buf,
- n->outerJoin ? " OUTER " : " INNER ");
- get_json_table_plan(tf, n->child, context,
- IsA(n->child, JsonTableSibling));
- }
- }
-
- if (parenthesize)
- appendStringInfoChar(context->buf, ')');
-}
-
-/*
- * get_json_table_columns - Parse back JSON_TABLE columns
- */
-static void
-get_json_table_columns(TableFunc *tf, JsonTableParent *node,
- deparse_context *context, bool showimplicit)
-{
- StringInfo buf = context->buf;
- JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
- ListCell *lc_colname;
- ListCell *lc_coltype;
- ListCell *lc_coltypmod;
- ListCell *lc_colvarexpr;
- int colnum = 0;
-
- appendStringInfoChar(buf, ' ');
- appendContextKeyword(context, "COLUMNS (", 0, 0, 0);
-
- if (PRETTY_INDENT(context))
- context->indentLevel += PRETTYINDENT_VAR;
-
- forfour(lc_colname, tf->colnames,
- lc_coltype, tf->coltypes,
- lc_coltypmod, tf->coltypmods,
- lc_colvarexpr, tf->colvalexprs)
- {
- char *colname = strVal(lfirst(lc_colname));
- JsonExpr *colexpr;
- Oid typid;
- int32 typmod;
- bool ordinality;
- JsonBehaviorType default_behavior;
-
- typid = lfirst_oid(lc_coltype);
- typmod = lfirst_int(lc_coltypmod);
- colexpr = castNode(JsonExpr, lfirst(lc_colvarexpr));
-
- if (colnum < node->colMin)
- {
- colnum++;
- continue;
- }
-
- if (colnum > node->colMax)
- break;
-
- if (colnum > node->colMin)
- appendStringInfoString(buf, ", ");
-
- colnum++;
-
- ordinality = !colexpr;
-
- appendContextKeyword(context, "", 0, 0, 0);
-
- appendStringInfo(buf, "%s %s", quote_identifier(colname),
- ordinality ? "FOR ORDINALITY" :
- format_type_with_typemod(typid, typmod));
- if (ordinality)
- continue;
-
- if (colexpr->op == JSON_EXISTS_OP)
- {
- appendStringInfoString(buf, " EXISTS");
- default_behavior = JSON_BEHAVIOR_FALSE;
- }
- else
- {
- if (colexpr->op == JSON_QUERY_OP)
- {
- char typcategory;
- bool typispreferred;
-
- get_type_category_preferred(typid, &typcategory, &typispreferred);
-
- if (typcategory == TYPCATEGORY_STRING)
- appendStringInfoString(buf,
- colexpr->format->format_type == JS_FORMAT_JSONB ?
- " FORMAT JSONB" : " FORMAT JSON");
- }
-
- default_behavior = JSON_BEHAVIOR_NULL;
- }
-
- if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR)
- default_behavior = JSON_BEHAVIOR_ERROR;
-
- appendStringInfoString(buf, " PATH ");
-
- get_json_path_spec(colexpr->path_spec, context, showimplicit);
-
- get_json_expr_options(colexpr, context, default_behavior);
- }
-
- if (node->child)
- get_json_table_nested_columns(tf, node->child, context, showimplicit,
- node->colMax >= node->colMin);
-
- if (PRETTY_INDENT(context))
- context->indentLevel -= PRETTYINDENT_VAR;
-
- appendContextKeyword(context, ")", 0, 0, 0);
-}
-
-/* ----------
- * get_json_table - Parse back a JSON_TABLE function
- * ----------
- */
-static void
-get_json_table(TableFunc *tf, deparse_context *context, bool showimplicit)
-{
- StringInfo buf = context->buf;
- JsonExpr *jexpr = castNode(JsonExpr, tf->docexpr);
- JsonTableParent *root = castNode(JsonTableParent, tf->plan);
-
- appendStringInfoString(buf, "JSON_TABLE(");
-
- if (PRETTY_INDENT(context))
- context->indentLevel += PRETTYINDENT_VAR;
-
- appendContextKeyword(context, "", 0, 0, 0);
-
- get_rule_expr(jexpr->formatted_expr, context, showimplicit);
-
- appendStringInfoString(buf, ", ");
-
- get_const_expr(root->path, context, -1);
-
- appendStringInfo(buf, " AS %s", quote_identifier(root->name));
-
- if (jexpr->passing_values)
- {
- ListCell *lc1,
- *lc2;
- bool needcomma = false;
-
- appendStringInfoChar(buf, ' ');
- appendContextKeyword(context, "PASSING ", 0, 0, 0);
-
- if (PRETTY_INDENT(context))
- context->indentLevel += PRETTYINDENT_VAR;
-
- forboth(lc1, jexpr->passing_names,
- lc2, jexpr->passing_values)
- {
- if (needcomma)
- appendStringInfoString(buf, ", ");
- needcomma = true;
-
- appendContextKeyword(context, "", 0, 0, 0);
-
- get_rule_expr((Node *) lfirst(lc2), context, false);
- appendStringInfo(buf, " AS %s",
- quote_identifier((lfirst_node(String, lc1))->sval)
- );
- }
-
- if (PRETTY_INDENT(context))
- context->indentLevel -= PRETTYINDENT_VAR;
- }
-
- get_json_table_columns(tf, root, context, showimplicit);
-
- appendStringInfoChar(buf, ' ');
- appendContextKeyword(context, "PLAN ", 0, 0, 0);
- get_json_table_plan(tf, (Node *) root, context, true);
-
- if (jexpr->on_error->btype != JSON_BEHAVIOR_EMPTY)
- get_json_behavior(jexpr->on_error, context, "ERROR");
-
- if (PRETTY_INDENT(context))
- context->indentLevel -= PRETTYINDENT_VAR;
-
- appendContextKeyword(context, ")", 0, 0, 0);
-}
-
-/* ----------
- * get_tablefunc - Parse back a table function
- * ----------
- */
-static void
-get_tablefunc(TableFunc *tf, deparse_context *context, bool showimplicit)
-{
- /* XMLTABLE and JSON_TABLE are the only existing implementations. */
-
- if (tf->functype == TFT_XMLTABLE)
- get_xmltable(tf, context, showimplicit);
- else if (tf->functype == TFT_JSON_TABLE)
- get_json_table(tf, context, showimplicit);
-}
-
/* ----------
* get_from_clause - Parse back a FROM clause
*
diff --git a/src/backend/utils/misc/queryjumble.c b/src/backend/utils/misc/queryjumble.c
index eeaa0b31fe..a67487e5fe 100644
--- a/src/backend/utils/misc/queryjumble.c
+++ b/src/backend/utils/misc/queryjumble.c
@@ -737,76 +737,6 @@ JumbleExpr(JumbleState *jstate, Node *node)
JumbleExpr(jstate, (Node *) conf->exclRelTlist);
}
break;
- case T_JsonFormat:
- {
- JsonFormat *format = (JsonFormat *) node;
-
- APP_JUMB(format->format_type);
- APP_JUMB(format->encoding);
- }
- break;
- case T_JsonReturning:
- {
- JsonReturning *returning = (JsonReturning *) node;
-
- JumbleExpr(jstate, (Node *) returning->format);
- APP_JUMB(returning->typid);
- APP_JUMB(returning->typmod);
- }
- break;
- case T_JsonValueExpr:
- {
- JsonValueExpr *expr = (JsonValueExpr *) node;
-
- JumbleExpr(jstate, (Node *) expr->raw_expr);
- JumbleExpr(jstate, (Node *) expr->formatted_expr);
- JumbleExpr(jstate, (Node *) expr->format);
- }
- break;
- case T_JsonConstructorExpr:
- {
- JsonConstructorExpr *ctor = (JsonConstructorExpr *) node;
-
- APP_JUMB(ctor->type);
- JumbleExpr(jstate, (Node *) ctor->args);
- JumbleExpr(jstate, (Node *) ctor->func);
- JumbleExpr(jstate, (Node *) ctor->coercion);
- JumbleExpr(jstate, (Node *) ctor->returning);
- APP_JUMB(ctor->absent_on_null);
- APP_JUMB(ctor->unique);
- }
- break;
- case T_JsonIsPredicate:
- {
- JsonIsPredicate *pred = (JsonIsPredicate *) node;
-
- JumbleExpr(jstate, (Node *) pred->expr);
- JumbleExpr(jstate, (Node *) pred->format);
- APP_JUMB(pred->item_type);
- APP_JUMB(pred->unique_keys);
- }
- break;
- case T_JsonExpr:
- {
- JsonExpr *jexpr = (JsonExpr *) node;
-
- APP_JUMB(jexpr->op);
- JumbleExpr(jstate, jexpr->formatted_expr);
- JumbleExpr(jstate, jexpr->path_spec);
- foreach(temp, jexpr->passing_names)
- {
- APP_JUMB_STRING(lfirst_node(String, temp)->sval);
- }
- JumbleExpr(jstate, (Node *) jexpr->passing_values);
- if (jexpr->on_empty)
- {
- APP_JUMB(jexpr->on_empty->btype);
- JumbleExpr(jstate, jexpr->on_empty->default_expr);
- }
- APP_JUMB(jexpr->on_error->btype);
- JumbleExpr(jstate, jexpr->on_error->default_expr);
- }
- break;
case T_List:
foreach(temp, (List *) node)
{
@@ -879,11 +809,9 @@ JumbleExpr(JumbleState *jstate, Node *node)
{
TableFunc *tablefunc = (TableFunc *) node;
- APP_JUMB(tablefunc->functype);
JumbleExpr(jstate, tablefunc->docexpr);
JumbleExpr(jstate, tablefunc->rowexpr);
JumbleExpr(jstate, (Node *) tablefunc->colexprs);
- JumbleExpr(jstate, (Node *) tablefunc->colvalexprs);
}
break;
case T_TableSampleClause: