Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6081f03

Browse files
author
Nikita Glukhov
committed
Add json support for JSON_EXISTS, JSON_VALUE, JSON_QUERY
1 parent 4406615 commit 6081f03

File tree

6 files changed

+1327
-51
lines changed

6 files changed

+1327
-51
lines changed

src/backend/executor/execExprInterp.c

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3673,16 +3673,19 @@ ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
36733673
*/
36743674
static Datum
36753675
ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
3676-
Datum res, bool *isNull)
3676+
Datum res, bool *isNull, bool isJsonb)
36773677
{
36783678
JsonExpr *jexpr = op->d.jsonexpr.jsexpr;
3679-
Jsonb *jb = *isNull ? NULL : DatumGetJsonbP(res);
3679+
Jsonb *jb = *isNull || !isJsonb ? NULL : DatumGetJsonbP(res);
3680+
Json *js = *isNull || isJsonb ? NULL : DatumGetJsonP(res);
36803681

36813682
if (jexpr->coerce_via_io ||
3682-
(jexpr->omit_quotes && !*isNull && JB_ROOT_IS_SCALAR(jb)))
3683+
(jexpr->omit_quotes && !*isNull &&
3684+
(isJsonb ? JB_ROOT_IS_SCALAR(jb) : JsonContainerIsScalar(&js->root))))
36833685
{
36843686
/* strip quotes and call typinput function */
3685-
char *str = *isNull ? NULL : JsonbUnquote(jb);
3687+
char *str = *isNull ? NULL :
3688+
(isJsonb ? JsonbUnquote(jb) : JsonUnquote(js));
36863689

36873690
res = InputFunctionCall(&op->d.jsonexpr.input.func, str,
36883691
op->d.jsonexpr.input.typioparam,
@@ -3692,7 +3695,7 @@ ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
36923695
res = ExecEvalExprPassingCaseValue(op->d.jsonexpr.result_expr, econtext,
36933696
isNull, res, *isNull);
36943697
else if (jexpr->coerce_via_populate)
3695-
res = json_populate_type(res, JSONBOID,
3698+
res = json_populate_type(res, isJsonb ? JSONBOID : JSONOID,
36963699
jexpr->returning.typid,
36973700
jexpr->returning.typmod,
36983701
&op->d.jsonexpr.cache,
@@ -3726,7 +3729,8 @@ EvalJsonPathVar(void *cxt, bool *isnull)
37263729
* corresponding SQL type and a pointer to the coercion state.
37273730
*/
37283731
Datum
3729-
ExecPrepareJsonItemCoercion(JsonbValue *item, JsonReturning *returning,
3732+
ExecPrepareJsonItemCoercion(JsonbValue *item, bool is_jsonb,
3733+
JsonReturning *returning,
37303734
struct JsonScalarCoercions *coercions,
37313735
MemoryContext mcxt,
37323736
struct JsonScalarCoercionExprState **pcestate)
@@ -3736,8 +3740,14 @@ ExecPrepareJsonItemCoercion(JsonbValue *item, JsonReturning *returning,
37363740
Oid typid;
37373741
JsonbValue jbvbuf;
37383742

3739-
if (item->type == jbvBinary && JsonContainerIsScalar(item->val.binary.data))
3740-
item = JsonbExtractScalar(item->val.binary.data, &jbvbuf);
3743+
if (item->type == jbvBinary)
3744+
{
3745+
if (JsonContainerIsScalar(item->val.binary.data))
3746+
item = is_jsonb
3747+
? JsonbExtractScalar(item->val.binary.data, &jbvbuf)
3748+
: JsonExtractScalar((JsonContainer *) item->val.binary.data,
3749+
&jbvbuf);
3750+
}
37413751

37423752
/* get coercion state reference and datum of the corresponding SQL type */
37433753
switch (item->type)
@@ -3799,8 +3809,20 @@ ExecPrepareJsonItemCoercion(JsonbValue *item, JsonReturning *returning,
37993809
case jbvObject:
38003810
case jbvBinary:
38013811
cestate = &coercions->composite;
3802-
res = JsonbPGetDatum(JsonbValueToJsonb(item));
3803-
typid = JSONBOID;
3812+
if (is_jsonb)
3813+
{
3814+
Jsonb *jb = JsonbValueToJsonb(item);
3815+
3816+
res = JsonbPGetDatum(jb);
3817+
typid = JSONBOID;
3818+
}
3819+
else
3820+
{
3821+
Json *js = JsonbValueToJson(item);
3822+
3823+
res = JsonPGetDatum(js);
3824+
typid = JSONOID;
3825+
}
38043826
break;
38053827

38063828
default:
@@ -3871,7 +3893,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
38713893
if (op->d.jsonexpr.raw_expr->isnull)
38723894
{
38733895
/* execute domain checks for NULLs */
3874-
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
3896+
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull, isjsonb);
38753897
return;
38763898
}
38773899

@@ -3901,31 +3923,32 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39013923
if (isnull)
39023924
{
39033925
/* execute domain checks for NULLs */
3904-
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
3926+
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
3927+
isjsonb);
39053928
return;
39063929
}
39073930
}
39083931

39093932
switch (jexpr->op)
39103933
{
39113934
case IS_JSON_QUERY:
3912-
res = JsonbPathQuery(item, path, jexpr->wrapper, &empty,
3913-
op->d.jsonexpr.args);
3935+
res = (isjsonb ? JsonbPathQuery : JsonPathQuery)
3936+
(item, path, jexpr->wrapper, &empty, op->d.jsonexpr.args);
39143937
*op->resnull = !DatumGetPointer(res);
39153938
break;
39163939

39173940
case IS_JSON_VALUE:
39183941
{
3919-
JsonbValue *jbv = JsonbPathValue(item, path, &empty,
3920-
op->d.jsonexpr.args);
3942+
JsonbValue *jbv = (isjsonb ? JsonbPathValue : JsonPathValue)
3943+
(item, path, &empty, op->d.jsonexpr.args);
39213944
struct JsonScalarCoercionExprState *cestate;
39223945

39233946
if (!jbv)
39243947
break;
39253948

39263949
*op->resnull = false;
39273950

3928-
res = ExecPrepareJsonItemCoercion(jbv,
3951+
res = ExecPrepareJsonItemCoercion(jbv, isjsonb,
39293952
&op->d.jsonexpr.jsexpr->returning,
39303953
&op->d.jsonexpr.scalar,
39313954
econtext->ecxt_per_query_memory,
@@ -3938,9 +3961,11 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39383961
jexpr->returning.typid == JSONBOID)
39393962
{
39403963
/* use coercion from json[b] to the output type */
3941-
res = JsonbPGetDatum(JsonbValueToJsonb(jbv));
3942-
res = ExecEvalJsonExprCoercion(op, econtext,
3943-
res, op->resnull);
3964+
res = isjsonb
3965+
? JsonbPGetDatum(JsonbValueToJsonb(jbv))
3966+
: JsonPGetDatum(JsonbValueToJson(jbv));
3967+
res = ExecEvalJsonExprCoercion(op, econtext, res,
3968+
op->resnull, isjsonb);
39443969
}
39453970
else if (cestate->result_expr_state)
39463971
{
@@ -3954,8 +3979,8 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39543979
break;
39553980

39563981
case IS_JSON_EXISTS:
3957-
res = BoolGetDatum(JsonbPathExists(item, path,
3958-
op->d.jsonexpr.args));
3982+
res = BoolGetDatum((isjsonb ? JsonbPathExists : JsonPathExists)
3983+
(item, path, op->d.jsonexpr.args));
39593984
*op->resnull = false;
39603985
break;
39613986

@@ -3982,7 +4007,8 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39824007
(!empty ? jexpr->op != IS_JSON_VALUE :
39834008
/* result is already coerced in DEFAULT behavior case */
39844009
jexpr->on_empty.btype != JSON_BEHAVIOR_DEFAULT))
3985-
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
4010+
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
4011+
isjsonb);
39864012
}
39874013
PG_CATCH();
39884014
{
@@ -4001,7 +4027,8 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
40014027
if (jexpr->op != IS_JSON_EXISTS &&
40024028
/* result is already coerced in DEFAULT behavior case */
40034029
jexpr->on_error.btype != JSON_BEHAVIOR_DEFAULT)
4004-
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
4030+
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
4031+
isjsonb);
40054032
}
40064033
PG_END_TRY();
40074034

src/backend/parser/parse_expr.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4594,15 +4594,10 @@ static Node *
45944594
transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
45954595
{
45964596
JsonExpr *jsexpr = transformJsonExprCommon(pstate, func);
4597-
Node *expr = jsexpr->formatted_expr ?
4598-
jsexpr->formatted_expr : jsexpr->raw_expr;
4599-
const char *func_name = NULL;
46004597

46014598
switch (func->op)
46024599
{
46034600
case IS_JSON_VALUE:
4604-
func_name = "JSON_VALUE";
4605-
46064601
transformJsonFuncExprOutput(pstate, func, jsexpr);
46074602

46084603
jsexpr->returning.format.type = JS_FORMAT_DEFAULT;
@@ -4618,8 +4613,6 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
46184613
break;
46194614

46204615
case IS_JSON_QUERY:
4621-
func_name = "JSON_QUERY";
4622-
46234616
transformJsonFuncExprOutput(pstate, func, jsexpr);
46244617

46254618
jsexpr->wrapper = func->wrapper;
@@ -4628,8 +4621,6 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
46284621
break;
46294622

46304623
case IS_JSON_EXISTS:
4631-
func_name = "JSON_EXISTS";
4632-
46334624
jsexpr->returning.format.type = JS_FORMAT_DEFAULT;
46344625
jsexpr->returning.format.encoding = JS_ENC_DEFAULT;
46354626
jsexpr->returning.format.location = -1;
@@ -4639,11 +4630,5 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
46394630
break;
46404631
}
46414632

4642-
if (exprType(expr) != JSONBOID)
4643-
ereport(ERROR,
4644-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4645-
errmsg("%s() is not yet implemented for json type", func_name),
4646-
parser_errposition(pstate, func->location)));
4647-
46484633
return (Node *) jsexpr;
46494634
}

src/include/executor/execExpr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op,
699699
ExprContext *econtext);
700700
extern void ExecEvalJson(ExprState *state, ExprEvalStep *op,
701701
ExprContext *econtext);
702-
extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item,
702+
extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item, bool is_jsonb,
703703
JsonReturning *returning,
704704
struct JsonScalarCoercions *coercions,
705705
MemoryContext mcxt,

src/include/utils/jsonpath.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -319,6 +319,12 @@ extern Datum JsonbPathQuery(Datum jb, JsonPath *jp, JsonWrapper wrapper,
319319
extern JsonbValue *JsonbPathValue(Datum jb, JsonPath *jp, bool *empty,
320320
List *vars);
321321

322+
extern bool JsonPathExists(Datum json, JsonPath *path, List *vars);
323+
extern JsonbValue *JsonPathValue(Datum json, JsonPath *jp, bool *empty,
324+
List *vars);
325+
extern Datum JsonPathQuery(Datum json, JsonPath *jp, JsonWrapper wrapper,
326+
bool *empty, List *vars);
327+
322328
extern Datum EvalJsonPathVar(void *cxt, bool *isnull);
323329

324330
#endif

0 commit comments

Comments
 (0)