v1-0001-handle-key-words-empty-array-and-empty-object.nocfbot
application/octet-stream
Filename: v1-0001-handle-key-words-empty-array-and-empty-object.nocfbot
Type: application/octet-stream
Part: 0
Message:
Re: remaining sql/json patches
From d32400963e34b8ab334f72903de74e00bc7f8c64 Mon Sep 17 00:00:00 2001
From: pgaddict <jian.universality@gmail.com>
Date: Tue, 28 Nov 2023 09:32:28 +0800
Subject: [PATCH v1 1/1] handle key words "empty array" and "empty object".
transform empty array to jsonb '[]', empty object to jsonb '{}'.
current implementation for "error on empty" will tranformed to
"error on empty null on empty".
Add a bool element to JsonBehavior, so we can disambiguate "error on empty"
and "error on empty null on error".
---
src/backend/executor/execExpr.c | 12 ++++---
src/backend/executor/execExprInterp.c | 2 +-
src/backend/parser/parse_expr.c | 38 +++++++++++++++++++--
src/include/nodes/primnodes.h | 1 +
src/test/regress/expected/jsonb_sqljson.out | 22 +++---------
5 files changed, 50 insertions(+), 25 deletions(-)
diff --git a/src/backend/executor/execExpr.c b/src/backend/executor/execExpr.c
index cfbd9272..5138c66c 100644
--- a/src/backend/executor/execExpr.c
+++ b/src/backend/executor/execExpr.c
@@ -4223,7 +4223,9 @@ ExecInitJsonExpr(JsonExpr *jexpr, ExprState *state,
List *jumps_to_end = NIL;
ListCell *lc;
ExprEvalStep *as;
-
+ bool throw_errors;
+ throw_errors = (jexpr->on_error &&
+ jexpr->on_error->btype == JSON_BEHAVIOR_ERROR);
jsestate->jsexpr = jexpr;
/*
@@ -4312,7 +4314,7 @@ ExecInitJsonExpr(JsonExpr *jexpr, ExprState *state,
jsestate->jump_eval_result_coercion =
ExecInitJsonCoercion(scratch, state, jsestate,
jexpr->result_coercion,
- jexpr->on_error->btype == JSON_BEHAVIOR_ERROR,
+ throw_errors,
resv, resnull);
/*
@@ -4358,7 +4360,7 @@ ExecInitJsonExpr(JsonExpr *jexpr, ExprState *state,
jsestate->eval_item_coercion_jumps[item_coercion->item_type] =
ExecInitJsonCoercion(scratch, state, jsestate,
coercion,
- jexpr->on_error->btype == JSON_BEHAVIOR_ERROR,
+ throw_errors,
resv, resnull);
/* Emit JUMP step to skip past other coercions' steps. */
@@ -4550,8 +4552,8 @@ ExecInitJsonExpr(JsonExpr *jexpr, ExprState *state,
* Adjust remaining jump target addresses now that we have the necessary
* steps in place.
*/
- Assert(on_error_step_off >= 0 || jexpr == NULL ||
- jexpr->on_error->btype == JSON_BEHAVIOR_ERROR);
+ Assert(on_error_step_off >= 0 || jexpr == NULL || throw_errors);
+
jsestate->jump_error = on_error_step_off;
/* Adjust EEOP_JUMP steps */
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 74217fb5..d00207a1 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -4385,7 +4385,7 @@ ExecEvalJsonExprPath(ExprState *state, ExprEvalStep *op,
if (jexpr->on_empty &&
jexpr->on_empty->btype == JSON_BEHAVIOR_ERROR)
{
- if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR)
+ if (jexpr->on_error->btype == JSON_BEHAVIOR_ERROR || jexpr->on_error->absent)
ereport(ERROR,
(errcode(ERRCODE_NO_SQL_JSON_ITEM),
errmsg("no SQL/JSON item")));
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 6c8918c6..0d5d32e3 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -4644,9 +4644,43 @@ transformJsonBehavior(ParseState *pstate, JsonBehavior *behavior,
location = behavior->location;
if (behavior_type == JSON_BEHAVIOR_DEFAULT)
default_expr = transformExprRecurse(pstate, behavior->default_expr);
- }
- behavior = makeJsonBehavior(behavior_type, default_expr, location);
+ if (behavior_type == JSON_BEHAVIOR_EMPTY_OBJECT)
+ {
+ Datum d = DirectFunctionCall1(jsonb_in, CStringGetDatum("{}"));
+
+ /* make a jsonb {} const for coercing it to returning typeid */
+ default_expr = (Node *) makeConst(JSONBOID,
+ -1,
+ InvalidOid,
+ -1,
+ d,
+ false, /* isnull */
+ false /* byval */ );
+ }
+
+ if (behavior_type == JSON_BEHAVIOR_EMPTY_ARRAY)
+ {
+ Datum d = DirectFunctionCall1(jsonb_in, CStringGetDatum("[]"));
+
+ /* make a jsonb [] const for coercing it to returning typeid */
+ default_expr = (Node *) makeConst(JSONBOID,
+ -1,
+ InvalidOid,
+ -1,
+ d,
+ false, /* isnull */
+ false /* byval */ );
+ }
+
+ behavior = makeJsonBehavior(behavior_type, default_expr, location);
+ behavior->absent = false;
+ }
+ else
+ {
+ behavior = makeJsonBehavior(behavior_type, default_expr, location);
+ behavior->absent = true;
+ }
/*
* Also coerce the DEFAULT expression, if any, to match the returning
diff --git a/src/include/nodes/primnodes.h b/src/include/nodes/primnodes.h
index e48249f8..0a658936 100644
--- a/src/include/nodes/primnodes.h
+++ b/src/include/nodes/primnodes.h
@@ -1723,6 +1723,7 @@ typedef struct JsonBehavior
Node *default_expr; /* default expression when btype is
* JSON_BEHAVIOR_DEFAULT */
int location; /* token location, or -1 if unknown */
+ bool absent; /* if not explicitly specified then true else false.*/
} JsonBehavior;
/*
diff --git a/src/test/regress/expected/jsonb_sqljson.out b/src/test/regress/expected/jsonb_sqljson.out
index 8b835817..61c538f5 100644
--- a/src/test/regress/expected/jsonb_sqljson.out
+++ b/src/test/regress/expected/jsonb_sqljson.out
@@ -657,11 +657,7 @@ SELECT JSON_QUERY(jsonb '[]', '$[*]' EMPTY OBJECT ON EMPTY);
(1 row)
SELECT JSON_QUERY(jsonb '[]', '$[*]' ERROR ON EMPTY);
- json_query
-------------
-
-(1 row)
-
+ERROR: no SQL/JSON item
SELECT JSON_QUERY(jsonb '[]', '$[*]' DEFAULT '"empty"' ON EMPTY);
json_query
------------
@@ -764,17 +760,9 @@ SELECT JSON_QUERY(jsonb '[1,2]', '$' RETURNING bytea FORMAT JSON);
(1 row)
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea EMPTY OBJECT ON ERROR);
- json_query
-------------
- \x7b7d
-(1 row)
-
+ERROR: cannot cast DEFAULT expression of type jsonb to bytea
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING bytea FORMAT JSON EMPTY OBJECT ON ERROR);
- json_query
-------------
- \x7b7d
-(1 row)
-
+ERROR: cannot cast DEFAULT expression of type jsonb to bytea
SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING json EMPTY OBJECT ON ERROR);
json_query
------------
@@ -788,9 +776,9 @@ SELECT JSON_QUERY(jsonb '[1,2]', '$[*]' RETURNING jsonb EMPTY OBJECT ON ERROR);
(1 row)
SELECT JSON_QUERY(jsonb '[3,4]', '$[*]' RETURNING bigint[] EMPTY OBJECT ON ERROR);
-ERROR: expected JSON array
+ERROR: cannot cast DEFAULT expression of type jsonb to bigint[]
SELECT JSON_QUERY(jsonb '"[3,4]"', '$[*]' RETURNING bigint[] EMPTY OBJECT ON ERROR);
-ERROR: expected JSON array
+ERROR: cannot cast DEFAULT expression of type jsonb to bigint[]
-- RETUGNING pseudo-types not allowed
SELECT JSON_QUERY(jsonb '[3,4]', '$[*]' RETURNING anyarray EMPTY OBJECT ON ERROR);
ERROR: returning pseudo-types is not supported in SQL/JSON functions
--
2.34.1