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

Commit 743c812

Browse files
author
Nikita Glukhov
committed
SQL/JSON functions for json type
1 parent d8e9ebb commit 743c812

File tree

8 files changed

+1445
-54
lines changed

8 files changed

+1445
-54
lines changed

src/backend/executor/execExprInterp.c

Lines changed: 63 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4150,17 +4150,21 @@ ExecEvalAggOrderedTransTuple(ExprState *state, ExprEvalStep *op,
41504150
*/
41514151
static Datum
41524152
ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
4153-
ExprState *default_estate, bool *is_null)
4153+
ExprState *default_estate, bool is_jsonb, bool *is_null)
41544154
{
41554155
*is_null = false;
41564156

41574157
switch (behavior->btype)
41584158
{
41594159
case JSON_BEHAVIOR_EMPTY_ARRAY:
4160-
return JsonbPGetDatum(JsonbMakeEmptyArray());
4160+
return is_jsonb
4161+
? JsonbPGetDatum(JsonbMakeEmptyArray())
4162+
: PointerGetDatum(cstring_to_text("[]"));
41614163

41624164
case JSON_BEHAVIOR_EMPTY_OBJECT:
4163-
return JsonbPGetDatum(JsonbMakeEmptyObject());
4165+
return is_jsonb
4166+
? JsonbPGetDatum(JsonbMakeEmptyObject())
4167+
: PointerGetDatum(cstring_to_text("{}"));
41644168

41654169
case JSON_BEHAVIOR_TRUE:
41664170
return BoolGetDatum(true);
@@ -4187,17 +4191,20 @@ ExecEvalJsonBehavior(ExprContext *econtext, JsonBehavior *behavior,
41874191
*/
41884192
static Datum
41894193
ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
4190-
Datum res, bool *isNull)
4194+
Datum res, bool *isNull, bool isJsonb)
41914195
{
41924196
JsonExpr *jexpr = op->d.jsonexpr.jsexpr;
41934197
JsonCoercion *coercion = jexpr->result_coercion;
4194-
Jsonb *jb = *isNull ? NULL : DatumGetJsonbP(res);
4198+
Jsonb *jb = *isNull || !isJsonb ? NULL : DatumGetJsonbP(res);
4199+
Json *js = *isNull || isJsonb ? NULL : DatumGetJsonP(res);
41954200

41964201
if ((coercion && coercion->via_io) ||
4197-
(jexpr->omit_quotes && !*isNull && JB_ROOT_IS_SCALAR(jb)))
4202+
(jexpr->omit_quotes && !*isNull &&
4203+
(isJsonb ? JB_ROOT_IS_SCALAR(jb) : JsonContainerIsScalar(&js->root))))
41984204
{
41994205
/* strip quotes and call typinput function */
4200-
char *str = *isNull ? NULL : JsonbUnquote(jb);
4206+
char *str = *isNull ? NULL :
4207+
(isJsonb ? JsonbUnquote(jb) : JsonUnquote(js));
42014208

42024209
res = InputFunctionCall(&op->d.jsonexpr.input.func, str,
42034210
op->d.jsonexpr.input.typioparam,
@@ -4211,7 +4218,7 @@ ExecEvalJsonExprCoercion(ExprEvalStep *op, ExprContext *econtext,
42114218
res = ExecEvalExpr(op->d.jsonexpr.result_expr, econtext, isNull);
42124219
}
42134220
else if (coercion && coercion->via_populate)
4214-
res = json_populate_type(res, JSONBOID,
4221+
res = json_populate_type(res, isJsonb ? JSONBOID : JSONOID,
42154222
jexpr->returning.typid,
42164223
jexpr->returning.typmod,
42174224
&op->d.jsonexpr.cache,
@@ -4245,7 +4252,7 @@ EvalJsonPathVar(void *cxt, bool *isnull)
42454252
* corresponding SQL type and a pointer to the coercion state.
42464253
*/
42474254
Datum
4248-
ExecPrepareJsonItemCoercion(JsonbValue *item,
4255+
ExecPrepareJsonItemCoercion(JsonbValue *item, bool is_jsonb,
42494256
JsonReturning *returning,
42504257
struct JsonCoercionsState *coercions,
42514258
struct JsonCoercionState **pcoercion)
@@ -4254,8 +4261,14 @@ ExecPrepareJsonItemCoercion(JsonbValue *item,
42544261
Datum res;
42554262
JsonbValue jbvbuf;
42564263

4257-
if (item->type == jbvBinary && JsonContainerIsScalar(item->val.binary.data))
4258-
item = JsonbExtractScalar(item->val.binary.data, &jbvbuf);
4264+
if (item->type == jbvBinary)
4265+
{
4266+
if (JsonContainerIsScalar(item->val.binary.data))
4267+
item = is_jsonb
4268+
? JsonbExtractScalar(item->val.binary.data, &jbvbuf)
4269+
: JsonExtractScalar((JsonContainer *) item->val.binary.data,
4270+
&jbvbuf);
4271+
}
42594272

42604273
/* get coercion state reference and datum of the corresponding SQL type */
42614274
switch (item->type)
@@ -4312,7 +4325,18 @@ ExecPrepareJsonItemCoercion(JsonbValue *item,
43124325
case jbvObject:
43134326
case jbvBinary:
43144327
coercion = &coercions->composite;
4315-
res = JsonbPGetDatum(JsonbValueToJsonb(item));
4328+
if (is_jsonb)
4329+
{
4330+
Jsonb *jb = JsonbValueToJsonb(item);
4331+
4332+
res = JsonbPGetDatum(jb);
4333+
}
4334+
else
4335+
{
4336+
Json *js = JsonbValueToJson(item);
4337+
4338+
res = JsonPGetDatum(js);
4339+
}
43164340
break;
43174341

43184342
default:
@@ -4327,7 +4351,8 @@ ExecPrepareJsonItemCoercion(JsonbValue *item,
43274351

43284352
static Datum
43294353
ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
4330-
JsonExpr *jexpr, JsonPath *path, Datum item, bool *resnull)
4354+
JsonExpr *jexpr, JsonPath *path, Datum item, bool isjsonb,
4355+
bool *resnull)
43314356
{
43324357
bool empty = false;
43334358
Datum res = (Datum) 0;
@@ -4343,7 +4368,8 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
43434368
if (isnull)
43444369
{
43454370
/* execute domain checks for NULLs */
4346-
(void) ExecEvalJsonExprCoercion(op, econtext, res, resnull);
4371+
(void) ExecEvalJsonExprCoercion(op, econtext, res, resnull,
4372+
isjsonb);
43474373
*resnull = true;
43484374
return (Datum) 0;
43494375
}
@@ -4352,15 +4378,15 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
43524378
switch (jexpr->op)
43534379
{
43544380
case IS_JSON_QUERY:
4355-
res = JsonbPathQuery(item, path, jexpr->wrapper, &empty,
4356-
op->d.jsonexpr.args);
4381+
res = (isjsonb ? JsonbPathQuery : JsonPathQuery)
4382+
(item, path, jexpr->wrapper, &empty, op->d.jsonexpr.args);
43574383
*resnull = !DatumGetPointer(res);
43584384
break;
43594385

43604386
case IS_JSON_VALUE:
43614387
{
4362-
JsonbValue *jbv = JsonbPathValue(item, path, &empty,
4363-
op->d.jsonexpr.args);
4388+
JsonbValue *jbv = (isjsonb ? JsonbPathValue : JsonPathValue)
4389+
(item, path, &empty, op->d.jsonexpr.args);
43644390
struct JsonCoercionState *jcstate;
43654391

43664392
if (!jbv) /* NULL or empty */
@@ -4375,12 +4401,14 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
43754401
jexpr->returning.typid == JSONBOID)
43764402
{
43774403
/* Use result coercion from json[b] to the output type */
4378-
res = JsonbPGetDatum(JsonbValueToJsonb(jbv));
4404+
res = isjsonb
4405+
? JsonbPGetDatum(JsonbValueToJsonb(jbv))
4406+
: JsonPGetDatum(JsonbValueToJson(jbv));
43794407
break;
43804408
}
43814409

43824410
/* Use coercion from SQL/JSON item type to the output type */
4383-
res = ExecPrepareJsonItemCoercion(jbv,
4411+
res = ExecPrepareJsonItemCoercion(jbv, isjsonb,
43844412
&op->d.jsonexpr.jsexpr->returning,
43854413
&op->d.jsonexpr.coercions,
43864414
&jcstate);
@@ -4416,7 +4444,8 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
44164444

44174445
case IS_JSON_EXISTS:
44184446
*resnull = false;
4419-
return BoolGetDatum(JsonbPathExists(item, path, op->d.jsonexpr.args));
4447+
return BoolGetDatum((isjsonb ? JsonbPathExists : JsonPathExists)
4448+
(item, path, op->d.jsonexpr.args));
44204449

44214450
default:
44224451
elog(ERROR, "unrecognized SQL/JSON expression op %d", jexpr->op);
@@ -4432,14 +4461,15 @@ ExecEvalJsonExpr(ExprState *state, ExprEvalStep *op, ExprContext *econtext,
44324461

44334462
/* execute ON EMPTY behavior */
44344463
res = ExecEvalJsonBehavior(econtext, &jexpr->on_empty,
4435-
op->d.jsonexpr.default_on_empty, resnull);
4464+
op->d.jsonexpr.default_on_empty,
4465+
isjsonb, resnull);
44364466

44374467
/* result is already coerced in DEFAULT behavior case */
44384468
if (jexpr->on_empty.btype == JSON_BEHAVIOR_DEFAULT)
44394469
return res;
44404470
}
44414471

4442-
return ExecEvalJsonExprCoercion(op, econtext, res, resnull);
4472+
return ExecEvalJsonExprCoercion(op, econtext, res, resnull, isjsonb);
44434473
}
44444474

44454475
bool
@@ -4460,14 +4490,18 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
44604490
Datum res = (Datum) 0;
44614491
JsonPath *path;
44624492
ListCell *lc;
4493+
Oid formattedType = exprType(jexpr->formatted_expr ?
4494+
jexpr->formatted_expr :
4495+
jexpr->raw_expr);
4496+
bool isjsonb = formattedType == JSONBOID;
44634497

44644498
*op->resnull = true; /* until we get a result */
44654499
*op->resvalue = (Datum) 0;
44664500

44674501
if (op->d.jsonexpr.raw_expr->isnull || op->d.jsonexpr.pathspec->isnull)
44684502
{
44694503
/* execute domain checks for NULLs */
4470-
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
4504+
(void) ExecEvalJsonExprCoercion(op, econtext, res, op->resnull, isjsonb);
44714505

44724506
Assert(*op->resnull);
44734507
*op->resnull = true;
@@ -4490,7 +4524,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
44904524
if (!ExecEvalJsonNeedsSubTransaction(jexpr))
44914525
{
44924526
/* No need to use PG_TRY/PG_CATCH with subtransactions. */
4493-
res = ExecEvalJsonExpr(state, op, econtext, jexpr, path, item,
4527+
res = ExecEvalJsonExpr(state, op, econtext, jexpr, path, item, isjsonb,
44944528
op->resnull);
44954529
}
44964530
else
@@ -4509,7 +4543,7 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
45094543
PG_TRY();
45104544
{
45114545
res = ExecEvalJsonExpr(state, op, econtext, jexpr, path, item,
4512-
op->resnull);
4546+
isjsonb, op->resnull);
45134547

45144548
/* Commit the inner transaction, return to outer xact context */
45154549
ReleaseCurrentSubTransaction();
@@ -4536,12 +4570,13 @@ ExecEvalJson(ExprState *state, ExprEvalStep *op, ExprContext *econtext)
45364570
/* Execute ON ERROR behavior. */
45374571
res = ExecEvalJsonBehavior(econtext, &jexpr->on_error,
45384572
op->d.jsonexpr.default_on_error,
4539-
op->resnull);
4573+
isjsonb, op->resnull);
45404574

45414575
if (jexpr->op != IS_JSON_EXISTS &&
45424576
/* result is already coerced in DEFAULT behavior case */
45434577
jexpr->on_error.btype != JSON_BEHAVIOR_DEFAULT)
4544-
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull);
4578+
res = ExecEvalJsonExprCoercion(op, econtext, res, op->resnull,
4579+
isjsonb);
45454580
}
45464581
PG_END_TRY();
45474582
}

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
@@ -794,7 +794,7 @@ extern void ExecEvalSysVar(ExprState *state, ExprEvalStep *op,
794794
ExprContext *econtext, TupleTableSlot *slot);
795795
extern void ExecEvalJson(ExprState *state, ExprEvalStep *op,
796796
ExprContext *econtext);
797-
extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item,
797+
extern Datum ExecPrepareJsonItemCoercion(struct JsonbValue *item, bool is_jsonb,
798798
JsonReturning *returning,
799799
struct JsonCoercionsState *coercions,
800800
struct JsonCoercionState **pjcstate);

src/include/utils/jsonpath.h

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

335+
extern bool JsonPathExists(Datum json, JsonPath *path, List *vars);
336+
extern JsonbValue *JsonPathValue(Datum json, JsonPath *jp, bool *empty,
337+
List *vars);
338+
extern Datum JsonPathQuery(Datum json, JsonPath *jp, JsonWrapper wrapper,
339+
bool *empty, List *vars);
340+
335341
extern Datum EvalJsonPathVar(void *cxt, bool *isnull);
336342

337343
#endif

src/include/utils/jsonpath_json.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@
9292

9393
/* redefine global jsonpath functions */
9494
#define executeJsonPath executeJsonPathJson
95+
#define JsonbPathExists JsonPathExists
96+
#define JsonbPathQuery JsonPathQuery
97+
#define JsonbPathValue JsonPathValue
9598

9699
static inline JsonbValue *
97100
JsonbInitBinary(JsonbValue *jbv, Json *jb)

0 commit comments

Comments
 (0)