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

Commit f941428

Browse files
author
Nikita Glukhov
committed
Add json support for JSON_EXISTS, JSON_VALUE, JSON_QUERY
1 parent ffd61e2 commit f941428

File tree

7 files changed

+1386
-55
lines changed

7 files changed

+1386
-55
lines changed

src/backend/executor/execExprInterp.c

Lines changed: 65 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4146,17 +4146,21 @@ ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op,
41464146
*/
41474147
static Datum
41484148
ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
4149-
ExprState *default_estate, bool *is_null)
4149+
ExprState *default_estate, bool is_jsonb, bool *is_null)
41504150
{
41514151
*is_null = false;
41524152

41534153
switch (behavior->btype)
41544154
{
41554155
case JSON_BEHAVIOR_EMPTY_ARRAY:
4156-
return JsonbPGetDatum(JsonbMakeEmptyArray());
4156+
return is_jsonb
4157+
? JsonbPGetDatum(JsonbMakeEmptyArray())
4158+
: PointerGetDatum(cstring_to_text("[]"));
41574159

41584160
case JSON_BEHAVIOR_EMPTY_OBJECT:
4159-
return JsonbPGetDatum(JsonbMakeEmptyObject());
4161+
return is_jsonb
4162+
? JsonbPGetDatum(JsonbMakeEmptyObject())
4163+
: PointerGetDatum(cstring_to_text("{}"));
41604164

41614165
case JSON_BEHAVIOR_TRUE:
41624166
return BoolGetDatum(true);
@@ -4183,17 +4187,20 @@ ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
41834187
*/
41844188
static Datum
41854189
ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
4186-
Datum res, bool *isNull)
4190+
Datum res, bool *isNull, bool isJsonb)
41874191
{
41884192
JsonExpr *jexpr = op->d.jsonexpr.jsexpr;
41894193
JsonCoercion *coercion = jexpr->result_coercion;
4190-
Jsonb *jb = *isNull ? NULL : DatumGetJsonbP(res);
4194+
Jsonb *jb = *isNull || !isJsonb ? NULL : DatumGetJsonbP(res);
4195+
Json *js = *isNull || isJsonb ? NULL : DatumGetJsonP(res);
41914196

41924197
if ((coercion && coercion->via_io) ||
4193-
(jexpr->omit_quotes && !*isNull && JB_ROOT_IS_SCALAR(jb)))
4198+
(jexpr->omit_quotes && !*isNull &&
4199+
(isJsonb ? JB_ROOT_IS_SCALAR(jb) : JsonContainerIsScalar(&js->root))))
41944200
{
41954201
/* strip quotes and call typinput function */
4196-
char *str = *isNull ? NULL : JsonbUnquote(jb);
4202+
char *str = *isNull ? NULL :
4203+
(isJsonb ? JsonbUnquote(jb) : JsonUnquote(js));
41974204

41984205
res = InputFunctionCall(&op->d.jsonexpr.input.func, str,
41994206
op->d.jsonexpr.input.typioparam,
@@ -4207,7 +4214,7 @@ ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
42074214
res = ExecEvalExpr(op->d.jsonexpr.result_expr, econtext, isNull);
42084215
}
42094216
else if (coercion && coercion->via_populate)
4210-
res = json_populate_type(res, JSONBOID,
4217+
res = json_populate_type(res, isJsonb ? JSONBOID : JSONOID,
42114218
jexpr->returning.typid,
42124219
jexpr->returning.typmod,
42134220
&op->d.jsonexpr.cache,
@@ -4241,7 +4248,7 @@ EvalJsonPathVar(void *cxt, bool *isnull)
42414248
* corresponding SQL type and a pointer to the coercion state.
42424249
*/
42434250
Datum
4244-
ExecPrepareJsonItemCoercion(JsonbValue *item,
4251+
ExecPrepareJsonItemCoercion(JsonbValue *item, bool is_jsonb,
42454252
JsonReturning *returning,
42464253
struct JsonCoercionsState *coercions,
42474254
struct JsonCoercionState **pcoercion)
@@ -4250,8 +4257,14 @@ ExecPrepareJsonItemCoercion(JsonbValue *item,
42504257
Datum res;
42514258
JsonbValue jbvbuf;
42524259

4253-
if (item->type == jbvBinary && JsonContainerIsScalar(item->val.binary.data))
4254-
item = JsonbExtractScalar(item->val.binary.data, &jbvbuf);
4260+
if (item->type == jbvBinary)
4261+
{
4262+
if (JsonContainerIsScalar(item->val.binary.data))
4263+
item = is_jsonb
4264+
? JsonbExtractScalar(item->val.binary.data, &jbvbuf)
4265+
: JsonExtractScalar((JsonContainer *) item->val.binary.data,
4266+
&jbvbuf);
4267+
}
42554268

42564269
/* get coercion state reference and datum of the corresponding SQL type */
42574270
switch (item->type)
@@ -4308,7 +4321,18 @@ ExecPrepareJsonItemCoercion(JsonbValue *item,
43084321
case jbvObject:
43094322
case jbvBinary:
43104323
coercion = &coercions->composite;
4311-
res = JsonbPGetDatum(JsonbValueToJsonb(item));
4324+
if (is_jsonb)
4325+
{
4326+
Jsonb *jb = JsonbValueToJsonb(item);
4327+
4328+
res = JsonbPGetDatum(jb);
4329+
}
4330+
else
4331+
{
4332+
Json *js = JsonbValueToJson(item);
4333+
4334+
res = JsonPGetDatum(js);
4335+
}
43124336
break;
43134337

43144338
default:
@@ -4323,7 +4347,8 @@ ExecPrepareJsonItemCoercion(JsonbValue *item,
43234347

43244348
static Datum
43254349
ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
4326-
JsonExpr *jexpr, JsonPath *path, Datum item, bool *resnull)
4350+
JsonExpr *jexpr, JsonPath *path, Datum item, bool isjsonb,
4351+
bool *resnull)
43274352
{
43284353
bool empty = false;
43294354
Datum res = (Datum) 0;
@@ -4339,7 +4364,8 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
43394364
if (isnull)
43404365
{
43414366
/* execute domain checks for NULLs */
4342-
(void) ExecEvalJsonExprCoercion(op, econtext, res, resnull);
4367+
(void) ExecEvalJsonExprCoercion(op, econtext, res, resnull,
4368+
isjsonb);
43434369
*resnull = true;
43444370
return (Datum) 0;
43454371
}
@@ -4348,23 +4374,23 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
43484374
switch (jexpr->op)
43494375
{
43504376
case IS_JSON_QUERY:
4351-
res = JsonbPathQuery(item, path, jexpr->wrapper, &empty,
4352-
op->d.jsonexpr.args);
4377+
res = (isjsonb ? JsonbPathQuery : JsonPathQuery)
4378+
(item, path, jexpr->wrapper, &empty, op->d.jsonexpr.args);
43534379
*resnull = !DatumGetPointer(res);
43544380
break;
43554381

43564382
case IS_JSON_VALUE:
43574383
{
4358-
JsonbValue *jbv = JsonbPathValue(item, path, &empty,
4359-
op->d.jsonexpr.args);
4384+
JsonbValue *jbv = (isjsonb ? JsonbPathValue : JsonPathValue)
4385+
(item, path, &empty, op->d.jsonexpr.args);
43604386
struct JsonCoercionState *jcstate;
43614387

43624388
if (!jbv)
43634389
break;
43644390

43654391
*resnull = false;
43664392

4367-
res = ExecPrepareJsonItemCoercion(jbv,
4393+
res = ExecPrepareJsonItemCoercion(jbv, isjsonb,
43684394
&op->d.jsonexpr.jsexpr->returning,
43694395
&op->d.jsonexpr.coercions,
43704396
&jcstate);
@@ -4377,8 +4403,11 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
43774403
jexpr->returning.typid == JSONBOID)
43784404
{
43794405
/* use coercion via I/O from json[b] to the output type */
4380-
res = JsonbPGetDatum(JsonbValueToJsonb(jbv));
4381-
res = ExecEvalJsonExprCoercion(op, econtext, res, resnull);
4406+
res = isjsonb
4407+
? JsonbPGetDatum(JsonbValueToJsonb(jbv))
4408+
: JsonPGetDatum(JsonbValueToJson(jbv));
4409+
res = ExecEvalJsonExprCoercion(op, econtext, res,
4410+
resnull, isjsonb);
43824411
}
43834412
else if (jcstate->estate)
43844413
{
@@ -4392,7 +4421,8 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
43924421
break;
43934422

43944423
case IS_JSON_EXISTS:
4395-
res = BoolGetDatum(JsonbPathExists(item, path, op->d.jsonexpr.args));
4424+
res = BoolGetDatum((isjsonb ? JsonbPathExists : JsonPathExists)
4425+
(item, path, op->d.jsonexpr.args));
43964426
*resnull = false;
43974427
break;
43984428

@@ -4411,14 +4441,15 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
44114441

44124442
/* execute ON EMPTY behavior */
44134443
res = ExecEvalJsonBehavior(econtext, &jexpr->on_empty,
4414-
op->d.jsonexpr.default_on_empty, resnull);
4444+
op->d.jsonexpr.default_on_empty,
4445+
isjsonb, resnull);
44154446
}
44164447

44174448
if (jexpr->op != IS_JSON_EXISTS &&
44184449
(!empty ? jexpr->op != IS_JSON_VALUE :
44194450
/* result is already coerced in DEFAULT behavior case */
44204451
jexpr->on_empty.btype != JSON_BEHAVIOR_DEFAULT))
4421-
res = ExecEvalJsonExprCoercion(op, econtext, res, resnull);
4452+
res = ExecEvalJsonExprCoercion(op, econtext, res, resnull, isjsonb);
44224453

44234454
return res;
44244455
}
@@ -4441,14 +4472,18 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
44414472
Datum res = (Datum) 0;
44424473
JsonPath *path;
44434474
ListCell *lc;
4475+
Oid formattedType = exprType(jexpr->formatted_expr ?
4476+
jexpr->formatted_expr :
4477+
jexpr->raw_expr);
4478+
bool isjsonb = formattedType == JSONBOID;
44444479

44454480
*op->resnull = true; /* until we get a result */
44464481
*op->resvalue = (Datum) 0;
44474482

44484483
if (op->d.jsonexpr.raw_expr->isnull || op->d.jsonexpr.pathspec->isnull)
44494484
{
44504485
/* execute domain checks for NULLs */
4451-
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
4486+
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull, isjsonb);
44524487

44534488
Assert(*op->resnull);
44544489
*op->resnull = true;
@@ -4471,7 +4506,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
44714506
if (!ExecEvalJsonNeedsSubTransaction(jexpr))
44724507
{
44734508
/* No need to use PG_TRY/PG_CATCH with subtransactions. */
4474-
res = ExecEvalJsonExpr(state, op, econtext, jexpr, path, item,
4509+
res = ExecEvalJsonExpr(state, op, econtext, jexpr, path, item, isjsonb,
44754510
op->resnull);
44764511
}
44774512
else
@@ -4498,7 +4533,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
44984533
PG_TRY();
44994534
{
45004535
res = ExecEvalJsonExpr(state, op, newecontext, jexpr, path, item,
4501-
op->resnull);
4536+
isjsonb, op->resnull);
45024537

45034538
/* Commit the inner transaction, return to outer xact context */
45044539
ReleaseCurrentSubTransaction();
@@ -4527,12 +4562,13 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
45274562
/* Execute ON ERROR behavior. */
45284563
res = ExecEvalJsonBehavior(econtext, &jexpr->on_error,
45294564
op->d.jsonexpr.default_on_error,
4530-
op->resnull);
4565+
isjsonb, op->resnull);
45314566

45324567
if (jexpr->op != IS_JSON_EXISTS &&
45334568
/* result is already coerced in DEFAULT behavior case */
45344569
jexpr->on_error.btype != JSON_BEHAVIOR_DEFAULT)
4535-
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
4570+
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
4571+
isjsonb);
45364572
}
45374573
PG_END_TRY();
45384574
}

src/backend/parser/parse_expr.c

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -4685,13 +4685,10 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
46854685
JsonExpr *jsexpr = transformJsonExprCommon(pstate, func);
46864686
Node *contextItemExpr =
46874687
jsexpr->formatted_expr ? jsexpr->formatted_expr : jsexpr->raw_expr;
4688-
const char *func_name = NULL;
46894688

46904689
switch (func->op)
46914690
{
46924691
case IS_JSON_VALUE:
4693-
func_name = "JSON_VALUE";
4694-
46954692
transformJsonFuncExprOutput(pstate, func, jsexpr);
46964693

46974694
jsexpr->returning.format.type = JS_FORMAT_DEFAULT;
@@ -4712,8 +4709,6 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
47124709
break;
47134710

47144711
case IS_JSON_QUERY:
4715-
func_name = "JSON_QUERY";
4716-
47174712
transformJsonFuncExprOutput(pstate, func, jsexpr);
47184713

47194714
jsexpr->wrapper = func->wrapper;
@@ -4722,8 +4717,6 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
47224717
break;
47234718

47244719
case IS_JSON_EXISTS:
4725-
func_name = "JSON_EXISTS";
4726-
47274720
jsexpr->returning.format.type = JS_FORMAT_DEFAULT;
47284721
jsexpr->returning.format.encoding = JS_ENC_DEFAULT;
47294722
jsexpr->returning.format.location = -1;
@@ -4733,11 +4726,5 @@ transformJsonFuncExpr(ParseState *pstate, JsonFuncExpr *func)
47334726
break;
47344727
}
47354728

4736-
if (exprType(contextItemExpr) != JSONBOID)
4737-
ereport(ERROR,
4738-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4739-
errmsg("%s() is not yet implemented for json type", func_name),
4740-
parser_errposition(pstate, func->location)));
4741-
47424729
return (Node *) jsexpr;
47434730
}

src/include/executor/execExpr.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ extern void ExecEvalWholeRowVar(ExprState *state, ExprEvalStep *op,
788788
ExprContext *econtext);
789789
extern void ExecEvalJson(ExprState *state, ExprEvalStep *op,
790790
ExprContext *econtext);
791-
extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item,
791+
extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item, bool is_jsonb,
792792
JsonReturning *returning,
793793
struct JsonCoercionsState *coercions,
794794
struct JsonCoercionState **pjcstate);

src/include/utils/jsonpath.h

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

307+
extern bool JsonPathExists(Datum json, JsonPath *path, List *vars);
308+
extern JsonbValue *JsonPathValue(Datum json, JsonPath *jp, bool *empty,
309+
List *vars);
310+
extern Datum JsonPathQuery(Datum json, JsonPath *jp, JsonWrapper wrapper,
311+
bool *empty, List *vars);
312+
307313
extern Datum EvalJsonPathVar(void *cxt, bool *isnull);
308314

309315
#endif

0 commit comments

Comments
 (0)