v1-0003-refactor-the-QUOTE-behavior-for-json_value.no-cfbot
application/octet-stream
Filename: v1-0003-refactor-the-QUOTE-behavior-for-json_value.no-cfbot
Type: application/octet-stream
Part: 3
Message:
Re: remaining sql/json patches
From b48457e7aa984ba44c9daab3ef29599445528d13 Mon Sep 17 00:00:00 2001
From: jian he <jian.universality@gmail.com>
Date: Wed, 3 Jan 2024 16:11:39 +0800
Subject: [PATCH v1 3/4] refactor the QUOTE behavior for json_value.
By default, json_value, the QUOTES behavior is not allowed.
However, in many cases, json_table will transform to json_value.
json_table can specify quotes behavior freely.
To coordinate with json_table quotes behavior,
for json_value, we set the default to omit_quotes, if specified keep QUOTE
via json_table , we can set keep_quotes to true.
---
src/backend/executor/execExprInterp.c | 16 ++++++++++---
src/backend/parser/parse_expr.c | 26 ++++++++++++++++++---
src/test/regress/expected/jsonb_sqljson.out | 12 ++++++++--
3 files changed, 46 insertions(+), 8 deletions(-)
diff --git a/src/backend/executor/execExprInterp.c b/src/backend/executor/execExprInterp.c
index 5d075043..a667057a 100644
--- a/src/backend/executor/execExprInterp.c
+++ b/src/backend/executor/execExprInterp.c
@@ -4408,6 +4408,7 @@ ExecPrepareJsonItemCoercion(JsonbValue *item, JsonExprState *jsestate,
bool via_expr;
int jump_to;
JsonbValue buf;
+ char *str;
if (item->type == jbvBinary && JsonContainerIsScalar(item->val.binary.data))
{
@@ -4433,9 +4434,18 @@ ExecPrepareJsonItemCoercion(JsonbValue *item, JsonExprState *jsestate,
case jbvString:
via_expr = item_coercion_via_expr[JsonItemTypeString];
jump_to = eval_item_coercion_jumps[JsonItemTypeString];
- *resvalue =
- PointerGetDatum(cstring_to_text_with_len(item->val.string.val,
- item->val.string.len));
+ /* if we keep_quotes, then we need double-quote it. */
+ if (!jsestate->jsexpr->omit_quotes)
+ {
+ str = psprintf("\"%s\"", item->val.string.val);
+ *resvalue =
+ PointerGetDatum(cstring_to_text_with_len(str,
+ item->val.string.len+2));
+ }
+ else
+ *resvalue =
+ PointerGetDatum(cstring_to_text_with_len(item->val.string.val,
+ item->val.string.len));
break;
case jbvNumeric:
diff --git a/src/backend/parser/parse_expr.c b/src/backend/parser/parse_expr.c
index 6027b34e..e7abc457 100644
--- a/src/backend/parser/parse_expr.c
+++ b/src/backend/parser/parse_expr.c
@@ -103,7 +103,7 @@ static Node *coerceJsonExpr(ParseState *pstate, Node *expr,
const JsonReturning *returning);
static JsonCoercion *makeJsonCoercion(const JsonReturning *returning);
static List *InitJsonItemCoercions(ParseState *pstate, const JsonReturning *returning,
- Oid contextItemTypeId);
+ Oid contextItemTypeId, bool keep_quotes);
static JsonBehavior *transformJsonBehavior(ParseState *pstate, JsonBehavior *behavior,
JsonBehaviorType default_behavior,
JsonReturning *returning);
@@ -4351,6 +4351,7 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
break;
case JSON_VALUE_OP:
+ jsexpr->omit_quotes = (func->quotes != JS_QUOTES_KEEP);
if (!OidIsValid(jsexpr->returning->typid))
{
/* Make JSON_VALUE return text by default */
@@ -4359,6 +4360,19 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
}
jsexpr->result_coercion = coerceJsonFuncExprOutput(pstate, jsexpr);
+ /*
+ * JSON_VALUE_OP not allowed to specify quotes behavior.
+ * By default it omit quotes.
+ * However JSON_TABLE_OP will be transformed to JSON_VALUE_OP in some cases,
+ * JSON_TABLE_OP can specify keep/omit quotes.
+ * So here we need adjust it.
+ */
+ if (jsexpr->result_coercion)
+ {
+ JsonCoercion *coercion = (JsonCoercion *) jsexpr->result_coercion;
+ if (!jsexpr->omit_quotes)
+ coercion->keep_quotes = true;
+ }
/*
* Initialize expressions to coerce the scalar value returned
* by JsonPathValue() to the "returning" type.
@@ -4366,7 +4380,7 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
if (jsexpr->result_coercion)
jsexpr->item_coercions =
InitJsonItemCoercions(pstate, jsexpr->returning,
- exprType(jsexpr->formatted_expr));
+ exprType(jsexpr->formatted_expr), !jsexpr->omit_quotes);
if (func->on_empty)
jsexpr->on_empty = transformJsonBehavior(pstate,
@@ -4627,7 +4641,7 @@ coerceJsonExpr(ParseState *pstate, Node *expr, const JsonReturning *returning)
*/
static List *
InitJsonItemCoercions(ParseState *pstate, const JsonReturning *returning,
- Oid contextItemTypeId)
+ Oid contextItemTypeId, bool keep_quotes)
{
List *item_coercions = NIL;
int i;
@@ -4677,6 +4691,12 @@ InitJsonItemCoercions(ParseState *pstate, const JsonReturning *returning,
item_coercion->item_type = item_types[i].item_type;
item_coercion->coercion = coerceJsonExpr(pstate, expr, returning);
+ if (item_coercion->coercion)
+ {
+ JsonCoercion *coercion = (JsonCoercion *) item_coercion->coercion;
+ if (keep_quotes)
+ coercion->keep_quotes = true;
+ }
item_coercions = lappend(item_coercions, item_coercion);
}
diff --git a/src/test/regress/expected/jsonb_sqljson.out b/src/test/regress/expected/jsonb_sqljson.out
index e0613cc2..f6a2c1fc 100644
--- a/src/test/regress/expected/jsonb_sqljson.out
+++ b/src/test/regress/expected/jsonb_sqljson.out
@@ -301,7 +301,11 @@ SELECT JSON_VALUE(jsonb '"2017-02-20"', '$' RETURNING date) + 9;
-- Test NULL checks execution in domain types
CREATE DOMAIN sqljsonb_int_not_null AS int NOT NULL;
SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null);
-ERROR: domain sqljsonb_int_not_null does not allow null values
+ json_value
+------------
+
+(1 row)
+
SELECT JSON_VALUE(jsonb 'null', '$' RETURNING sqljsonb_int_not_null ERROR ON ERROR);
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 ON ERROR);
@@ -313,7 +317,11 @@ SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT 2 ON
(1 row)
SELECT JSON_VALUE(jsonb '1', '$.a' RETURNING sqljsonb_int_not_null DEFAULT NULL ON EMPTY ERROR ON ERROR);
-ERROR: domain sqljsonb_int_not_null does not allow null values
+ json_value
+------------
+
+(1 row)
+
CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
CREATE DOMAIN rgb AS rainbow CHECK (VALUE IN ('red', 'green', 'blue'));
SELECT JSON_VALUE('"purple"'::jsonb, 'lax $[*]' RETURNING rgb);
--
2.34.1