v6-0001-Fix-returning-of-json-b-domains-in-JSON_VALUE.patch
text/x-patch
Filename: v6-0001-Fix-returning-of-json-b-domains-in-JSON_VALUE.patch
Type: text/x-patch
Part: 0
Message:
Re: SQL/JSON features for v15
Patch
Format: format-patch
Series: patch v6-0001
Subject: Fix returning of json[b] domains in JSON_VALUE()
| File | + | − |
|---|---|---|
| src/backend/executor/execExpr.c | 3 | 1 |
| src/backend/executor/execExprInterp.c | 10 | 7 |
| src/backend/optimizer/util/clauses.c | 1 | 1 |
| src/backend/parser/parse_expr.c | 51 | 14 |
| src/include/executor/execExpr.h | 11 | 3 |
| src/test/regress/expected/jsonb_sqljson.out | 180 | 1 |
| src/test/regress/sql/jsonb_sqljson.sql | 62 | 1 |
From e843bb377d0ff7132a1ccc43c07ba892d16628a9 Mon Sep 17 00:00:00 2001
From: Nikita Glukhov <n.gluhov@postgrespro.ru>
Date: Mon, 15 Aug 2022 20:18:11 +0300
Subject: [PATCH v6 1/3] Fix returning of json[b] domains in JSON_VALUE()
---
src/backend/executor/execExpr.c | 4 +-
src/backend/executor/execExprInterp.c | 17 +-
src/backend/optimizer/util/clauses.c | 2 +-
src/backend/parser/parse_expr.c | 65 +++++--
src/include/executor/execExpr.h | 14 +-
src/test/regress/expected/jsonb_sqljson.out | 181 +++++++++++++++++++-
src/test/regress/sql/jsonb_sqljson.sql | 63 ++++++-
7 files changed, 318 insertions(+), 28 deletions(-)
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index d0a57c7aaee..96196d50876 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -2645,13 +2645,15 @@ ExecInitExprRec(Expr *node, ExprState *state,
Datum *caseval;
bool *casenull;
+ jsestate->coercions =
+ palloc(sizeof(*jsestate->coercions));
jsestate->coercion_expr =
palloc(sizeof(*jsestate->coercion_expr));
caseval = &jsestate->coercion_expr->value;
casenull = &jsestate->coercion_expr->isnull;
- for (cstate = &jsestate->coercions.null,
+ for (cstate = &jsestate->coercions->null,
coercion = &jexpr->coercions->null;
coercion <= &jexpr->coercions->composite;
coercion++, cstate++)
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 636794ca6f1..353346d5528 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -5053,10 +5053,13 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
*resnull = false;
/* coerce scalar item to the output type */
- if (jexpr->returning->typid == JSONOID ||
- jexpr->returning->typid == JSONBOID)
+ if (!jsestate->coercions)
{
- /* Use result coercion from json[b] to the output type */
+ /*
+ * Use result coercion from json[b] to the output
+ * type when casting to json[b] types or their
+ * domains.
+ */
res = JsonbPGetDatum(JsonbValueToJsonb(jbv));
break;
}
@@ -5064,7 +5067,7 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
/* Use coercion from SQL/JSON item type to the output type */
res = ExecPrepareJsonItemCoercion(jbv,
jsestate->jsexpr->returning,
- &jsestate->coercions,
+ jsestate->coercions,
&jcstate);
if (jcstate->coercion &&
@@ -5161,7 +5164,7 @@ ExecEvalJsonExpr(ExprEvalStep *op, ExprContext *econtext,
bool
ExecEvalJsonNeedsSubTransaction(JsonExpr *jsexpr,
- struct JsonCoercionsState *coercions)
+ bool consider_conditional_coercions)
{
if (jsexpr->on_error->btype == JSON_BEHAVIOR_ERROR)
return false;
@@ -5169,7 +5172,7 @@ ExecEvalJsonNeedsSubTransaction(JsonExpr *jsexpr,
if (jsexpr->op == JSON_EXISTS_OP && !jsexpr->result_coercion)
return false;
- if (!coercions)
+ if (consider_conditional_coercions)
return true;
return false;
@@ -5218,7 +5221,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
var->evaluated = false;
}
- needSubtrans = ExecEvalJsonNeedsSubTransaction(jexpr, &jsestate->coercions);
+ needSubtrans = ExecEvalJsonNeedsSubTransaction(jexpr, false);
cxt.path = path;
cxt.error = throwErrors ? NULL : &error;
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 533df86ff77..a1d868bb87b 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -901,7 +901,7 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
{
JsonExpr *jsexpr = (JsonExpr *) node;
- if (ExecEvalJsonNeedsSubTransaction(jsexpr, NULL))
+ if (ExecEvalJsonNeedsSubTransaction(jsexpr, true))
{
context->max_hazard = PROPARALLEL_UNSAFE;
return true;
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index fabb5f72076..31fb5555659 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -4203,12 +4203,29 @@ coerceJsonExpr(ParseState *pstate, Node *expr, const JsonReturning *returning)
return coercion;
}
+/* Is it a json/jsonb type or its domain? */
+static bool
+isJsonType(Oid typid)
+{
+ Oid basetypid;
+
+ if (typid == JSONOID || typid == JSONBOID)
+ return true;
+
+ basetypid = getBaseType(typid);
+
+ if (basetypid == JSONOID || basetypid == JSONBOID)
+ return true;
+
+ return false;
+}
+
/*
* Transform a JSON output clause of JSON_VALUE and JSON_QUERY.
*/
static void
transformJsonFuncExprOutput(ParseState *pstate, JsonFuncExpr *func,
- JsonExpr *jsexpr)
+ JsonExpr *jsexpr, bool *returning_json)
{
Node *expr = jsexpr->formatted_expr;
@@ -4225,13 +4242,20 @@ transformJsonFuncExprOutput(ParseState *pstate, JsonFuncExpr *func,
{
JsonReturning ret;
- if (func->op == JSON_VALUE_OP &&
- jsexpr->returning->typid != JSONOID &&
- jsexpr->returning->typid != JSONBOID)
+ *returning_json = isJsonType(jsexpr->returning->typid);
+
+ if (func->op == JSON_VALUE_OP && !*returning_json)
{
- /* Forced coercion via I/O for JSON_VALUE for non-JSON types */
+ /*
+ * In JSON_VALUE result_coercion can only be used when
+ * returning JSON types and for NULL values (resulting
+ * item is JSON null or NULL behavior is used).
+ * So there is no need to find a cast from json[b] to
+ * output type when it is a non-JSON type, we only need to
+ * check domains for NOT NULL, what can be done using I/O
+ * coercion.
+ */
jsexpr->result_coercion = makeNode(JsonCoercion);
- jsexpr->result_coercion->expr = NULL;
jsexpr->result_coercion->via_io = true;
return;
}
@@ -4251,8 +4275,11 @@ transformJsonFuncExprOutput(ParseState *pstate, JsonFuncExpr *func,
}
}
else
+ {
assignDefaultJsonReturningType(jsexpr->formatted_expr, jsexpr->format,
jsexpr->returning);
+ *returning_json = true;
+ }
}
/*
@@ -4321,10 +4348,11 @@ initJsonItemCoercion(ParseState *pstate, Oid typid,
return coerceJsonExpr(pstate, expr, returning);
}
-static void
-initJsonItemCoercions(ParseState *pstate, JsonItemCoercions *coercions,
- const JsonReturning *returning, Oid contextItemTypeId)
+static JsonItemCoercions *
+initJsonItemCoercions(ParseState *pstate, const JsonReturning *returning,
+ Oid contextItemTypeId)
{
+ JsonItemCoercions *coercions = makeNode(JsonItemCoercions);
struct
{
JsonCoercion **coercion;
@@ -4347,6 +4375,8 @@ initJsonItemCoercions(ParseState *pstate, JsonItemCoercions *coercions,
for (p = coercionTypids; p->coercion; p++)
*p->coercion = initJsonItemCoercion(pstate, p->typid, returning);
+
+ return coercions;
}
/*
@@ -4358,13 +4388,14 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
JsonExpr *jsexpr = transformJsonExprCommon(pstate, func);
const char *func_name = NULL;
Node *contextItemExpr = jsexpr->formatted_expr;
+ bool returning_json;
switch (func->op)
{
case JSON_VALUE_OP:
func_name = "JSON_VALUE";
- transformJsonFuncExprOutput(pstate, func, jsexpr);
+ transformJsonFuncExprOutput(pstate, func, jsexpr, &returning_json);
jsexpr->returning->format->format_type = JS_FORMAT_DEFAULT;
jsexpr->returning->format->encoding = JS_ENC_DEFAULT;
@@ -4377,16 +4408,22 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
coerceDefaultJsonExpr(pstate, jsexpr,
jsexpr->on_error->default_expr);
- jsexpr->coercions = makeNode(JsonItemCoercions);
- initJsonItemCoercions(pstate, jsexpr->coercions, jsexpr->returning,
- exprType(contextItemExpr));
+ /*
+ * Don't initialize item coercions if returning one of JSON
+ * types or their domains. Coercion will be done using
+ * "result_coercion".
+ */
+ if (!returning_json)
+ jsexpr->coercions =
+ initJsonItemCoercions(pstate, jsexpr->returning,
+ exprType(contextItemExpr));
break;
case JSON_QUERY_OP:
func_name = "JSON_QUERY";
- transformJsonFuncExprOutput(pstate, func, jsexpr);
+ transformJsonFuncExprOutput(pstate, func, jsexpr, &returning_json);
jsexpr->on_empty->default_expr =
coerceDefaultJsonExpr(pstate, jsexpr,
diff --git a/src/include/executor/execExpr.h b/src/include/executor/execExpr.h
index c8ef917ffe0..de9bbd2abcd 100644
--- a/src/include/executor/execExpr.h
+++ b/src/include/executor/execExpr.h
@@ -781,6 +781,15 @@ typedef struct JsonExprState
void *cache; /* cache for json_populate_type() */
+ /*
+ * This is used only in JSON_VALUE.
+ *
+ * States for coercion from SQL/JSON item types directly to the
+ * output type.
+ *
+ * "coercions == NULL" means output type is json[b] or its domain
+ * and we use "result_expr" for coercion.
+ */
struct JsonCoercionsState
{
struct JsonCoercionState
@@ -797,8 +806,7 @@ typedef struct JsonExprState
timestamp,
timestamptz,
composite;
- } coercions; /* states for coercion from SQL/JSON item
- * types directly to the output type */
+ } *coercions;
} JsonExprState;
/* functions in execExpr.c */
@@ -867,7 +875,7 @@ extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item,
struct JsonCoercionsState *coercions,
struct JsonCoercionState **pjcstate);
extern bool ExecEvalJsonNeedsSubTransaction(JsonExpr *jsexpr,
- struct JsonCoercionsState *);
+ bool consider_conditional_coercions);
extern Datum ExecEvalExprPassingCaseValue(ExprState *estate,
ExprContext *econtext, bool *isnull,
Datum caseval_datum,
diff --git a/src/test/regress/expected/jsonb_sqljson.out b/src/test/regress/expected/jsonb_sqljson.out
index ef496110af3..ee5e597909c 100644
--- a/src/test/regress/expected/jsonb_sqljson.out
+++ b/src/test/regress/expected/jsonb_sqljson.out
@@ -349,14 +349,193 @@ SELECT JSON_VALUE(jsonb '"2017-02-20"', '$' RETURNING date) + 9;
03-01-2017
(1 row)
--- Test NULL checks execution in domain types
+-- Test for domain types
CREATE DOMAIN sqljsonb_int_not_null AS int NOT NULL;
+CREATE DOMAIN sqljsonb_json_not_null AS json NOT NULL CHECK (VALUE::text <> '0');
+CREATE DOMAIN sqljsonb_jsonb_not_null AS jsonb NOT NULL CHECK (VALUE <> '0');
+-- Test casting to json[b] domains (items casted as is, strings are not unquoted)
+SELECT JSON_VALUE(jsonb '"1"', '$' RETURNING sqljsonb_json_not_null);
+ json_value
+------------
+ "1"
+(1 row)
+
+SELECT JSON_VALUE(jsonb '"1"', '$' RETURNING sqljsonb_jsonb_not_null);
+ json_value
+------------
+ "1"
+(1 row)
+
+SELECT JSON_VALUE(jsonb '1', '$' RETURNING sqljsonb_json_not_null);
+ json_value
+------------
+ 1
+(1 row)
+
+SELECT JSON_VALUE(jsonb '1', '$' RETURNING sqljsonb_jsonb_not_null);
+ json_value
+------------
+ 1
+(1 row)
+
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null);
+ERROR: domain sqljsonb_json_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null);
+ERROR: domain sqljsonb_jsonb_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'true', '$' RETURNING sqljsonb_json_not_null);
+ json_value
+------------
+ true
+(1 row)
+
+SELECT JSON_VALUE(jsonb 'true', '$' RETURNING sqljsonb_jsonb_not_null);
+ json_value
+------------
+ true
+(1 row)
+
+-- Test NULL checks execution in domain types
SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null);
ERROR: domain sqljsonb_int_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT 2 ON EMPTY);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON EMPTY);
+ERROR: domain sqljsonb_int_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT 2 ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON EMPTY DEFAULT 2 ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null NULL ON ERROR);
ERROR: domain sqljsonb_int_not_null does not allow null values
SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON ERROR);
ERROR: domain sqljsonb_int_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null);
+ERROR: domain sqljsonb_json_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null DEFAULT '2' ON EMPTY);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null DEFAULT NULL ON EMPTY);
+ERROR: domain sqljsonb_json_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null DEFAULT '2' ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null DEFAULT NULL ON EMPTY DEFAULT '2' ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null NULL ON ERROR);
+ERROR: domain sqljsonb_json_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null DEFAULT NULL ON ERROR);
+ERROR: domain sqljsonb_json_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null);
+ERROR: domain sqljsonb_jsonb_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null DEFAULT '2' ON EMPTY);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null DEFAULT NULL ON EMPTY);
+ERROR: domain sqljsonb_jsonb_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null DEFAULT '2' ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null DEFAULT NULL ON EMPTY DEFAULT '2' ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null NULL ON ERROR);
+ERROR: domain sqljsonb_jsonb_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null DEFAULT NULL ON ERROR);
+ERROR: domain sqljsonb_jsonb_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null);
+ERROR: domain sqljsonb_int_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null DEFAULT 2 ON EMPTY);
+ERROR: domain sqljsonb_int_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null DEFAULT 2 ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null NULL ON ERROR);
+ERROR: domain sqljsonb_int_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null DEFAULT NULL ON ERROR);
+ERROR: domain sqljsonb_int_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null);
+ERROR: domain sqljsonb_json_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null DEFAULT '2' ON EMPTY);
+ERROR: domain sqljsonb_json_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null DEFAULT '2' ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null NULL ON ERROR);
+ERROR: domain sqljsonb_json_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null DEFAULT NULL ON ERROR);
+ERROR: domain sqljsonb_json_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null);
+ERROR: domain sqljsonb_jsonb_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null DEFAULT '2' ON EMPTY);
+ERROR: domain sqljsonb_jsonb_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null DEFAULT '2' ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null NULL ON ERROR);
+ERROR: domain sqljsonb_jsonb_not_null does not allow null values
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null DEFAULT NULL ON ERROR);
+ERROR: domain sqljsonb_jsonb_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_json_not_null);
+ERROR: domain sqljsonb_json_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_json_not_null ERROR ON ERROR);
+ERROR: value for domain sqljsonb_json_not_null violates check constraint "sqljsonb_json_not_null_check"
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_json_not_null DEFAULT '2' ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_jsonb_not_null);
+ERROR: domain sqljsonb_jsonb_not_null does not allow null values
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_jsonb_not_null ERROR ON ERROR);
+ERROR: value for domain sqljsonb_jsonb_not_null violates check constraint "sqljsonb_jsonb_not_null_check"
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_jsonb_not_null DEFAULT '2' ON ERROR);
+ json_value
+------------
+ 2
+(1 row)
+
+-- Test returning of non-scalar items
SELECT JSON_VALUE(jsonb '[]', '$');
json_value
------------
diff --git a/src/test/regress/sql/jsonb_sqljson.sql b/src/test/regress/sql/jsonb_sqljson.sql
index fff25374808..d70104b70ef 100644
--- a/src/test/regress/sql/jsonb_sqljson.sql
+++ b/src/test/regress/sql/jsonb_sqljson.sql
@@ -82,12 +82,73 @@ SELECT JSON_VALUE(jsonb '"123"', '$' RETURNING int) + 234;
SELECT JSON_VALUE(jsonb '"2017-02-20"', '$' RETURNING date) + 9;
--- Test NULL checks execution in domain types
+-- Test for domain types
CREATE DOMAIN sqljsonb_int_not_null AS int NOT NULL;
+CREATE DOMAIN sqljsonb_json_not_null AS json NOT NULL CHECK (VALUE::text <> '0');
+CREATE DOMAIN sqljsonb_jsonb_not_null AS jsonb NOT NULL CHECK (VALUE <> '0');
+
+-- Test casting to json[b] domains (items casted as is, strings are not unquoted)
+SELECT JSON_VALUE(jsonb '"1"', '$' RETURNING sqljsonb_json_not_null);
+SELECT JSON_VALUE(jsonb '"1"', '$' RETURNING sqljsonb_jsonb_not_null);
+SELECT JSON_VALUE(jsonb '1', '$' RETURNING sqljsonb_json_not_null);
+SELECT JSON_VALUE(jsonb '1', '$' RETURNING sqljsonb_jsonb_not_null);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null);
+SELECT JSON_VALUE(jsonb 'true', '$' RETURNING sqljsonb_json_not_null);
+SELECT JSON_VALUE(jsonb 'true', '$' RETURNING sqljsonb_jsonb_not_null);
+
+-- Test NULL checks execution in domain types
SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT 2 ON EMPTY);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON EMPTY);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT 2 ON ERROR);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON EMPTY DEFAULT 2 ON ERROR);
SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null NULL ON ERROR);
SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON ERROR);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null DEFAULT '2' ON EMPTY);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null DEFAULT NULL ON EMPTY);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null DEFAULT '2' ON ERROR);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null DEFAULT NULL ON EMPTY DEFAULT '2' ON ERROR);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null NULL ON ERROR);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_json_not_null DEFAULT NULL ON ERROR);
+
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null DEFAULT '2' ON EMPTY);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null DEFAULT NULL ON EMPTY);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null DEFAULT '2' ON ERROR);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null DEFAULT NULL ON EMPTY DEFAULT '2' ON ERROR);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null NULL ON ERROR);
+SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_jsonb_not_null DEFAULT NULL ON ERROR);
+
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null DEFAULT 2 ON EMPTY);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null DEFAULT 2 ON ERROR);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null NULL ON ERROR);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null DEFAULT NULL ON ERROR);
+
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null DEFAULT '2' ON EMPTY);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null DEFAULT '2' ON ERROR);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null NULL ON ERROR);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_json_not_null DEFAULT NULL ON ERROR);
+
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null DEFAULT '2' ON EMPTY);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null DEFAULT '2' ON ERROR);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null NULL ON ERROR);
+SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_jsonb_not_null DEFAULT NULL ON ERROR);
+
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_json_not_null);
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_json_not_null ERROR ON ERROR);
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_json_not_null DEFAULT '2' ON ERROR);
+
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_jsonb_not_null);
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_jsonb_not_null ERROR ON ERROR);
+SELECT JSON_VALUE(jsonb '0', '$' RETURNING sqljsonb_jsonb_not_null DEFAULT '2' ON ERROR);
+
+-- Test returning of non-scalar items
SELECT JSON_VALUE(jsonb '[]', '$');
SELECT JSON_VALUE(jsonb '[]', '$' ERROR ON ERROR);
SELECT JSON_VALUE(jsonb '{}', '$');
--
2.25.1