aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
authorAndrew Dunstan <andrew@dunslane.net>2022-03-03 13:15:13 -0500
committerAndrew Dunstan <andrew@dunslane.net>2022-03-30 16:30:37 -0400
commit606948b058dc16bce494270eea577011a602810e (patch)
treedad8b48083701f5560b6696b6ad770a3c6af84d3 /src/backend/executor
parent8e053dc6dfbee4ae412e98ad73cfd4662d7453ac (diff)
downloadpostgresql-606948b058dc16bce494270eea577011a602810e.tar.gz
postgresql-606948b058dc16bce494270eea577011a602810e.zip
SQL JSON functions
This Patch introduces three SQL standard JSON functions: JSON() (incorrectly mentioned in my commit message for f4fb45d15c) JSON_SCALAR() JSON_SERIALIZE() JSON() produces json values from text, bytea, json or jsonb values, and has facilitites for handling duplicate keys. JSON_SCALAR() produces a json value from any scalar sql value, including json and jsonb. JSON_SERIALIZE() produces text or bytea from input which containis or represents json or jsonb; For the most part these functions don't add any significant new capabilities, but they will be of use to users wanting standard compliant JSON handling. Nikita Glukhov Reviewers have included (in no particular order) Andres Freund, Alexander Korotkov, Pavel Stehule, Andrew Alsup, Erik Rijkers, Zihong Yu, Himanshu Upadhyaya, Daniel Gustafsson, Justin Pryzby. Discussion: https://postgr.es/m/cd0bb935-0158-78a7-08b5-904886deac4b@postgrespro.ru
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execExpr.c45
-rw-r--r--src/backend/executor/execExprInterp.c42
2 files changed, 86 insertions, 1 deletions
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index 1c364a7f4c5..d4d3850ec7c 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -47,6 +47,8 @@
#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"
@@ -2460,6 +2462,12 @@ ExecInitExprRec(Expr *node, ExprState *state,
{
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
{
scratch.opcode = EEOP_JSON_CONSTRUCTOR;
@@ -2492,6 +2500,43 @@ ExecInitExprRec(Expr *node, ExprState *state,
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;
+
+ scratch.d.json_constructor.arg_type_cache =
+ palloc(sizeof(*scratch.d.json_constructor.arg_type_cache) * nargs);
+
+ for (int i = 0; i < nargs; i++)
+ {
+ int category;
+ Oid outfuncid;
+ Oid typid = scratch.d.json_constructor.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;
+ }
+
+ scratch.d.json_constructor.arg_type_cache[i].outfuncid = outfuncid;
+ scratch.d.json_constructor.arg_type_cache[i].category = category;
+ }
+ }
+
ExprEvalPushStep(state, &scratch);
}
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 1215f707e28..7d4253d970d 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -3982,7 +3982,7 @@ ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op)
* JSON text validation.
*/
if (res && (pred->unique_keys || exprtype == TEXTOID))
- res = json_validate(json, pred->unique_keys);
+ res = json_validate(json, pred->unique_keys, false);
}
else if (exprtype == JSONBOID)
{
@@ -4527,6 +4527,46 @@ ExecEvalJsonConstructor(ExprState *state, ExprEvalStep *op,
op->d.json_constructor.arg_types,
op->d.json_constructor.constructor->absent_on_null,
op->d.json_constructor.constructor->unique);
+ else if (ctor->type == JSCTOR_JSON_SCALAR)
+ {
+ if (op->d.json_constructor.arg_nulls[0])
+ {
+ res = (Datum) 0;
+ isnull = true;
+ }
+ else
+ {
+ Datum value = op->d.json_constructor.arg_values[0];
+ int category = op->d.json_constructor.arg_type_cache[0].category;
+ Oid outfuncid = op->d.json_constructor.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 (op->d.json_constructor.arg_nulls[0])
+ {
+ res = (Datum) 0;
+ isnull = true;
+ }
+ else
+ {
+ Datum value = op->d.json_constructor.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;