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

Commit f5208cd

Browse files
author
Nikita Glukhov
committed
Add json support for JSON_EXISTS, JSON_VALUE, JSON_QUERY
1 parent 48d02a4 commit f5208cd

File tree

7 files changed

+1328
-52
lines changed

7 files changed

+1328
-52
lines changed

src/backend/executor/execExprInterp.c

Lines changed: 51 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -3722,16 +3722,19 @@ ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
37223722
*/
37233723
static Datum
37243724
ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
3725-
Datum res, bool *isNull)
3725+
Datum res, bool *isNull, bool isJsonb)
37263726
{
37273727
JsonExpr *jexpr = op->d.jsonexpr.jsexpr;
3728-
Jsonb *jb = *isNull ? NULL : DatumGetJsonbP(res);
3728+
Jsonb *jb = *isNull || !isJsonb ? NULL : DatumGetJsonbP(res);
3729+
Json *js = *isNull || isJsonb ? NULL : DatumGetJsonP(res);
37293730

37303731
if (jexpr->coerce_via_io ||
3731-
(jexpr->omit_quotes && !*isNull && JB_ROOT_IS_SCALAR(jb)))
3732+
(jexpr->omit_quotes && !*isNull &&
3733+
(isJsonb ? JB_ROOT_IS_SCALAR(jb) : JsonContainerIsScalar(&js->root))))
37323734
{
37333735
/* strip quotes and call typinput function */
3734-
char *str = *isNull ? NULL : JsonbUnquote(jb);
3736+
char *str = *isNull ? NULL :
3737+
(isJsonb ? JsonbUnquote(jb) : JsonUnquote(js));
37353738

37363739
res = InputFunctionCall(&op->d.jsonexpr.input.func, str,
37373740
op->d.jsonexpr.input.typioparam,
@@ -3741,7 +3744,7 @@ ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
37413744
res = ExecEvalExprPassingCaseValue(op->d.jsonexpr.result_expr, econtext,
37423745
isNull, res, *isNull);
37433746
else if (jexpr->coerce_via_populate)
3744-
res = json_populate_type(res, JSONBOID,
3747+
res = json_populate_type(res, isJsonb ? JSONBOID : JSONOID,
37453748
jexpr->returning.typid,
37463749
jexpr->returning.typmod,
37473750
&op->d.jsonexpr.cache,
@@ -3775,7 +3778,8 @@ EvalJsonPathVar(void *cxt, bool *isnull)
37753778
* corresponding SQL type and a pointer to the coercion state.
37763779
*/
37773780
Datum
3778-
ExecPrepareJsonItemCoercion(JsonbValue *item, JsonReturning *returning,
3781+
ExecPrepareJsonItemCoercion(JsonbValue *item, bool is_jsonb,
3782+
JsonReturning *returning,
37793783
struct JsonScalarCoercions *coercions,
37803784
MemoryContext mcxt,
37813785
struct JsonScalarCoercionExprState **pcestate)
@@ -3785,8 +3789,14 @@ ExecPrepareJsonItemCoercion(JsonbValue *item, JsonReturning *returning,
37853789
Oid typid;
37863790
JsonbValue jbvbuf;
37873791

3788-
if (item->type == jbvBinary && JsonContainerIsScalar(item->val.binary.data))
3789-
item = JsonbExtractScalar(item->val.binary.data, &jbvbuf);
3792+
if (item->type == jbvBinary)
3793+
{
3794+
if (JsonContainerIsScalar(item->val.binary.data))
3795+
item = is_jsonb
3796+
? JsonbExtractScalar(item->val.binary.data, &jbvbuf)
3797+
: JsonExtractScalar((JsonContainer *) item->val.binary.data,
3798+
&jbvbuf);
3799+
}
37903800

37913801
/* get coercion state reference and datum of the corresponding SQL type */
37923802
switch (item->type)
@@ -3848,8 +3858,20 @@ ExecPrepareJsonItemCoercion(JsonbValue *item, JsonReturning *returning,
38483858
case jbvObject:
38493859
case jbvBinary:
38503860
cestate = &coercions->composite;
3851-
res = JsonbPGetDatum(JsonbValueToJsonb(item));
3852-
typid = JSONBOID;
3861+
if (is_jsonb)
3862+
{
3863+
Jsonb *jb = JsonbValueToJsonb(item);
3864+
3865+
res = JsonbPGetDatum(jb);
3866+
typid = JSONBOID;
3867+
}
3868+
else
3869+
{
3870+
Json *js = JsonbValueToJson(item);
3871+
3872+
res = JsonPGetDatum(js);
3873+
typid = JSONOID;
3874+
}
38533875
break;
38543876

38553877
default:
@@ -3920,7 +3942,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39203942
if (op->d.jsonexpr.raw_expr->isnull)
39213943
{
39223944
/* execute domain checks for NULLs */
3923-
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
3945+
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull, isjsonb);
39243946
return;
39253947
}
39263948

@@ -3950,31 +3972,32 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39503972
if (isnull)
39513973
{
39523974
/* execute domain checks for NULLs */
3953-
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
3975+
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
3976+
isjsonb);
39543977
return;
39553978
}
39563979
}
39573980

39583981
switch (jexpr->op)
39593982
{
39603983
case IS_JSON_QUERY:
3961-
res = JsonbPathQuery(item, path, jexpr->wrapper, &empty,
3962-
op->d.jsonexpr.args);
3984+
res = (isjsonb ? JsonbPathQuery : JsonPathQuery)
3985+
(item, path, jexpr->wrapper, &empty, op->d.jsonexpr.args);
39633986
*op->resnull = !DatumGetPointer(res);
39643987
break;
39653988

39663989
case IS_JSON_VALUE:
39673990
{
3968-
JsonbValue *jbv = JsonbPathValue(item, path, &empty,
3969-
op->d.jsonexpr.args);
3991+
JsonbValue *jbv = (isjsonb ? JsonbPathValue : JsonPathValue)
3992+
(item, path, &empty, op->d.jsonexpr.args);
39703993
struct JsonScalarCoercionExprState *cestate;
39713994

39723995
if (!jbv)
39733996
break;
39743997

39753998
*op->resnull = false;
39763999

3977-
res = ExecPrepareJsonItemCoercion(jbv,
4000+
res = ExecPrepareJsonItemCoercion(jbv, isjsonb,
39784001
&op->d.jsonexpr.jsexpr->returning,
39794002
&op->d.jsonexpr.scalar,
39804003
econtext->ecxt_per_query_memory,
@@ -3987,9 +4010,11 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
39874010
jexpr->returning.typid == JSONBOID)
39884011
{
39894012
/* use coercion from json[b] to the output type */
3990-
res = JsonbPGetDatum(JsonbValueToJsonb(jbv));
3991-
res = ExecEvalJsonExprCoercion(op, econtext,
3992-
res, op->resnull);
4013+
res = isjsonb
4014+
? JsonbPGetDatum(JsonbValueToJsonb(jbv))
4015+
: JsonPGetDatum(JsonbValueToJson(jbv));
4016+
res = ExecEvalJsonExprCoercion(op, econtext, res,
4017+
op->resnull, isjsonb);
39934018
}
39944019
else if (cestate->result_expr_state)
39954020
{
@@ -4003,8 +4028,8 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
40034028
break;
40044029

40054030
case IS_JSON_EXISTS:
4006-
res = BoolGetDatum(JsonbPathExists(item, path,
4007-
op->d.jsonexpr.args));
4031+
res = BoolGetDatum((isjsonb ? JsonbPathExists : JsonPathExists)
4032+
(item, path, op->d.jsonexpr.args));
40084033
*op->resnull = false;
40094034
break;
40104035

@@ -4031,7 +4056,8 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
40314056
(!empty ? jexpr->op != IS_JSON_VALUE :
40324057
/* result is already coerced in DEFAULT behavior case */
40334058
jexpr->on_empty.btype != JSON_BEHAVIOR_DEFAULT))
4034-
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
4059+
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
4060+
isjsonb);
40354061
}
40364062
PG_CATCH();
40374063
{
@@ -4050,7 +4076,8 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
40504076
if (jexpr->op != IS_JSON_EXISTS &&
40514077
/* result is already coerced in DEFAULT behavior case */
40524078
jexpr->on_error.btype != JSON_BEHAVIOR_DEFAULT)
4053-
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
4079+
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
4080+
isjsonb);
40544081
}
40554082
PG_END_TRY();
40564083

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
@@ -698,7 +698,7 @@ extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op,
698698
ExprContext *econtext);
699699
extern void ExecEvalJson(ExprState *state, ExprEvalStep *op,
700700
ExprContext *econtext);
701-
extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item,
701+
extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item, bool is_jsonb,
702702
JsonReturning *returning,
703703
struct JsonScalarCoercions *coercions,
704704
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)