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

Commit c227874

Browse files
author
Nikita Glukhov
committed
Add json support for JSON_EXISTS, JSON_VALUE, JSON_QUERY
1 parent 0e9f94c commit c227874

File tree

6 files changed

+1373
-51
lines changed

6 files changed

+1373
-51
lines changed

src/backend/executor/execExprInterp.c

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -3673,17 +3673,20 @@ 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;
36793679
JsonCoercion *coercion = jexpr->result_coercion;
3680-
Jsonb *jb = *isNull ? NULL : DatumGetJsonbP(res);
3680+
Jsonb *jb = *isNull || !isJsonb ? NULL : DatumGetJsonbP(res);
3681+
Json *js = *isNull || isJsonb ? NULL : DatumGetJsonP(res);
36813682

36823683
if ((coercion && coercion->via_io) ||
3683-
(jexpr->omit_quotes && !*isNull && JB_ROOT_IS_SCALAR(jb)))
3684+
(jexpr->omit_quotes && !*isNull &&
3685+
(isJsonb ? JB_ROOT_IS_SCALAR(jb) : JsonContainerIsScalar(&js->root))))
36843686
{
36853687
/* strip quotes and call typinput function */
3686-
char *str = *isNull ? NULL : JsonbUnquote(jb);
3688+
char *str = *isNull ? NULL :
3689+
(isJsonb ? JsonbUnquote(jb) : JsonUnquote(js));
36873690

36883691
res = InputFunctionCall(&op->d.jsonexpr.input.func, str,
36893692
op->d.jsonexpr.input.typioparam,
@@ -3693,7 +3696,7 @@ ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
36933696
res = ExecEvalExprPassingCaseValue(op->d.jsonexpr.result_expr, econtext,
36943697
isNull, res, *isNull);
36953698
else if (coercion && coercion->via_populate)
3696-
res = json_populate_type(res, JSONBOID,
3699+
res = json_populate_type(res, isJsonb ? JSONBOID : JSONOID,
36973700
jexpr->returning.typid,
36983701
jexpr->returning.typmod,
36993702
&op->d.jsonexpr.cache,
@@ -3727,7 +3730,7 @@ EvalJsonPathVar(void *cxt, bool *isnull)
37273730
* corresponding SQL type and a pointer to the coercion state.
37283731
*/
37293732
Datum
3730-
ExecPrepareJsonItemCoercion(JsonbValue *item,
3733+
ExecPrepareJsonItemCoercion(JsonbValue *item, bool is_jsonb,
37313734
JsonReturning *returning,
37323735
struct JsonCoercionsState *coercions,
37333736
struct JsonCoercionState **pcoercion)
@@ -3736,8 +3739,14 @@ ExecPrepareJsonItemCoercion(JsonbValue *item,
37363739
Datum res;
37373740
JsonbValue jbvbuf;
37383741

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

37423751
/* get coercion state reference and datum of the corresponding SQL type */
37433752
switch (item->type)
@@ -3794,7 +3803,18 @@ ExecPrepareJsonItemCoercion(JsonbValue *item,
37943803
case jbvObject:
37953804
case jbvBinary:
37963805
coercion = &coercions->composite;
3797-
res = JsonbPGetDatum(JsonbValueToJsonb(item));
3806+
if (is_jsonb)
3807+
{
3808+
Jsonb *jb = JsonbValueToJsonb(item);
3809+
3810+
res = JsonbPGetDatum(jb);
3811+
}
3812+
else
3813+
{
3814+
Json *js = JsonbValueToJson(item);
3815+
3816+
res = JsonPGetDatum(js);
3817+
}
37983818
break;
37993819

38003820
default:
@@ -3809,7 +3829,8 @@ ExecPrepareJsonItemCoercion(JsonbValue *item,
38093829

38103830
static Datum
38113831
ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
3812-
JsonExpr *jexpr, JsonPath *path, Datum item, bool *resnull)
3832+
JsonExpr *jexpr, JsonPath *path, Datum item, bool isjsonb,
3833+
bool *resnull)
38133834
{
38143835
bool empty = false;
38153836
Datum res = (Datum) 0;
@@ -3823,7 +3844,8 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
38233844
if (isnull)
38243845
{
38253846
/* execute domain checks for NULLs */
3826-
(void) ExecEvalJsonExprCoercion(op, econtext, res, resnull);
3847+
(void) ExecEvalJsonExprCoercion(op, econtext, res, resnull,
3848+
isjsonb);
38273849
*resnull = true;
38283850
return (Datum) 0;
38293851
}
@@ -3832,23 +3854,23 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
38323854
switch (jexpr->op)
38333855
{
38343856
case IS_JSON_QUERY:
3835-
res = JsonbPathQuery(item, path, jexpr->wrapper, &empty,
3836-
op->d.jsonexpr.args);
3857+
res = (isjsonb ? JsonbPathQuery : JsonPathQuery)
3858+
(item, path, jexpr->wrapper, &empty, op->d.jsonexpr.args);
38373859
*resnull = !DatumGetPointer(res);
38383860
break;
38393861

38403862
case IS_JSON_VALUE:
38413863
{
3842-
JsonbValue *jbv = JsonbPathValue(item, path, &empty,
3843-
op->d.jsonexpr.args);
3864+
JsonbValue *jbv = (isjsonb ? JsonbPathValue : JsonPathValue)
3865+
(item, path, &empty, op->d.jsonexpr.args);
38443866
struct JsonCoercionState *jcstate;
38453867

38463868
if (!jbv)
38473869
break;
38483870

38493871
*resnull = false;
38503872

3851-
res = ExecPrepareJsonItemCoercion(jbv,
3873+
res = ExecPrepareJsonItemCoercion(jbv, isjsonb,
38523874
&op->d.jsonexpr.jsexpr->returning,
38533875
&op->d.jsonexpr.coercions,
38543876
&jcstate);
@@ -3861,8 +3883,11 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
38613883
jexpr->returning.typid == JSONBOID)
38623884
{
38633885
/* use coercion via I/O from json[b] to the output type */
3864-
res = JsonbPGetDatum(JsonbValueToJsonb(jbv));
3865-
res = ExecEvalJsonExprCoercion(op, econtext, res, resnull);
3886+
res = isjsonb
3887+
? JsonbPGetDatum(JsonbValueToJsonb(jbv))
3888+
: JsonPGetDatum(JsonbValueToJson(jbv));
3889+
res = ExecEvalJsonExprCoercion(op, econtext, res,
3890+
resnull, isjsonb);
38663891
}
38673892
else if (jcstate->estate)
38683893
{
@@ -3876,7 +3901,8 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
38763901
break;
38773902

38783903
case IS_JSON_EXISTS:
3879-
res = BoolGetDatum(JsonbPathExists(item, path, op->d.jsonexpr.args));
3904+
res = BoolGetDatum((isjsonb ? JsonbPathExists : JsonPathExists)
3905+
(item, path, op->d.jsonexpr.args));
38803906
*resnull = false;
38813907
break;
38823908

@@ -3895,15 +3921,15 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
38953921

38963922
/* execute ON EMPTY behavior */
38973923
res = ExecEvalJsonBehavior(econtext, &jexpr->on_empty,
3898-
op->d.jsonexpr.default_on_empty, true,
3899-
resnull);
3924+
op->d.jsonexpr.default_on_empty,
3925+
isjsonb, resnull);
39003926
}
39013927

39023928
if (jexpr->op != IS_JSON_EXISTS &&
39033929
(!empty ? jexpr->op != IS_JSON_VALUE :
39043930
/* result is already coerced in DEFAULT behavior case */
39053931
jexpr->on_empty.btype != JSON_BEHAVIOR_DEFAULT))
3906-
res = ExecEvalJsonExprCoercion(op, econtext, res, resnull);
3932+
res = ExecEvalJsonExprCoercion(op, econtext, res, resnull, isjsonb);
39073933

39083934
return res;
39093935
}
@@ -3931,7 +3957,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39313957
if (op->d.jsonexpr.raw_expr->isnull || op->d.jsonexpr.pathspec->isnull)
39323958
{
39333959
/* execute domain checks for NULLs */
3934-
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
3960+
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull, isjsonb);
39353961

39363962
Assert(*op->resnull);
39373963
*op->resnull = true;
@@ -3954,7 +3980,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39543980
if (jexpr->on_error.btype == JSON_BEHAVIOR_ERROR)
39553981
{
39563982
/* No need to use PG_TRY/PG_CATCH. */
3957-
res = ExecEvalJsonExpr(state, op, econtext, jexpr, path, item,
3983+
res = ExecEvalJsonExpr(state, op, econtext, jexpr, path, item, isjsonb,
39583984
op->resnull);
39593985
}
39603986
else
@@ -3964,7 +3990,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39643990
PG_TRY();
39653991
{
39663992
res = ExecEvalJsonExpr(state, op, econtext, jexpr, path, item,
3967-
op->resnull);
3993+
isjsonb, op->resnull);
39683994
}
39693995
PG_CATCH();
39703996
{
@@ -3986,7 +4012,8 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39864012
if (jexpr->op != IS_JSON_EXISTS &&
39874013
/* Result is already coerced in DEFAULT behavior case. */
39884014
jexpr->on_error.btype != JSON_BEHAVIOR_DEFAULT)
3989-
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
4015+
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
4016+
isjsonb);
39904017
}
39914018
PG_END_TRY();
39924019
}

src/backend/parser/parse_expr.c

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4666,13 +4666,10 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
46664666
JsonExpr *jsexpr = transformJsonExprCommon(pstate, func);
46674667
Node *contextItemExpr =
46684668
jsexpr->formatted_expr ? jsexpr->formatted_expr : jsexpr->raw_expr;
4669-
const char *func_name = NULL;
46704669

46714670
switch (func->op)
46724671
{
46734672
case IS_JSON_VALUE:
4674-
func_name = "JSON_VALUE";
4675-
46764673
transformJsonFuncExprOutput(pstate, func, jsexpr);
46774674

46784675
jsexpr->returning.format.type = JS_FORMAT_DEFAULT;
@@ -4693,8 +4690,6 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
46934690
break;
46944691

46954692
case IS_JSON_QUERY:
4696-
func_name = "JSON_QUERY";
4697-
46984693
transformJsonFuncExprOutput(pstate, func, jsexpr);
46994694

47004695
jsexpr->wrapper = func->wrapper;
@@ -4703,8 +4698,6 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
47034698
break;
47044699

47054700
case IS_JSON_EXISTS:
4706-
func_name = "JSON_EXISTS";
4707-
47084701
jsexpr->returning.format.type = JS_FORMAT_DEFAULT;
47094702
jsexpr->returning.format.encoding = JS_ENC_DEFAULT;
47104703
jsexpr->returning.format.location = -1;
@@ -4714,11 +4707,5 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
47144707
break;
47154708
}
47164709

4717-
if (exprType(contextItemExpr) != JSONBOID)
4718-
ereport(ERROR,
4719-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4720-
errmsg("%s() is not yet implemented for json type", func_name),
4721-
parser_errposition(pstate, func->location)));
4722-
47234710
return (Node *) jsexpr;
47244711
}

src/include/executor/execExpr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -697,7 +697,7 @@ extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op,
697697
ExprContext *econtext);
698698
extern void ExecEvalJson(ExprState *state, ExprEvalStep *op,
699699
ExprContext *econtext);
700-
extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item,
700+
extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item, bool is_jsonb,
701701
JsonReturning *returning,
702702
struct JsonCoercionsState *coercions,
703703
struct JsonCoercionState **pjcstate);

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)