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

Commit 98a30c9

Browse files
author
Nikita Glukhov
committed
Add nodes for IS JSON execution
1 parent 6c13c76 commit 98a30c9

File tree

17 files changed

+207
-220
lines changed

17 files changed

+207
-220
lines changed

src/backend/executor/execExpr.c

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2194,9 +2194,17 @@ ExecInitExprRec(Expr *node, ExprState *state,
21942194
break;
21952195

21962196
case T_JsonIsPredicate:
2197-
ExecInitExprRec((Expr *) ((JsonIsPredicate *) node)->expr, state, resv,
2198-
resnull);
2199-
break;
2197+
{
2198+
JsonIsPredicate *pred = (JsonIsPredicate *) node;
2199+
2200+
ExecInitExprRec((Expr *) pred->expr, state, resv, resnull);
2201+
2202+
scratch.opcode = EEOP_IS_JSON;
2203+
scratch.d.is_json.pred = pred;
2204+
2205+
ExprEvalPushStep(state, &scratch);
2206+
break;
2207+
}
22002208

22012209
default:
22022210
elog(ERROR, "unrecognized node type: %d",

src/backend/executor/execExprInterp.c

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@
7373
#include "utils/expandedrecord.h"
7474
#include "utils/json.h"
7575
#include "utils/jsonb.h"
76+
#include "utils/jsonfuncs.h"
7677
#include "utils/lsyscache.h"
7778
#include "utils/memutils.h"
7879
#include "utils/timestamp.h"
@@ -435,6 +436,7 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
435436
&&CASE_EEOP_SUBPLAN,
436437
&&CASE_EEOP_ALTERNATIVE_SUBPLAN,
437438
&&CASE_EEOP_JSON_CONSTRUCTOR,
439+
&&CASE_EEOP_IS_JSON,
438440
&&CASE_EEOP_AGG_STRICT_DESERIALIZE,
439441
&&CASE_EEOP_AGG_DESERIALIZE,
440442
&&CASE_EEOP_AGG_STRICT_INPUT_CHECK_ARGS,
@@ -1807,6 +1809,14 @@ ExecInterpExpr(ExprState *state, ExprContext *econtext, bool *isnull)
18071809
EEO_NEXT();
18081810
}
18091811

1812+
EEO_CASE(EEOP_IS_JSON)
1813+
{
1814+
/* too complex for an inline implementation */
1815+
ExecEvalJsonIsPredicate(state, op);
1816+
1817+
EEO_NEXT();
1818+
}
1819+
18101820
EEO_CASE(EEOP_LAST)
18111821
{
18121822
/* unreachable */
@@ -3862,6 +3872,91 @@ ExecEvalXmlExpr(ExprState *state, ExprEvalStep *op)
38623872
}
38633873
}
38643874

3875+
void
3876+
ExecEvalJsonIsPredicate(ExprState *state, ExprEvalStep *op)
3877+
{
3878+
JsonIsPredicate *pred = op->d.is_json.pred;
3879+
Datum js = *op->resvalue;
3880+
Oid exprtype;
3881+
bool res;
3882+
3883+
if (*op->resnull)
3884+
{
3885+
*op->resvalue = BoolGetDatum(false);
3886+
return;
3887+
}
3888+
3889+
exprtype = exprType(pred->expr);
3890+
3891+
if (exprtype == TEXTOID || exprtype == JSONOID)
3892+
{
3893+
text *json = DatumGetTextP(js);
3894+
3895+
if (pred->value_type == JS_TYPE_ANY)
3896+
res = true;
3897+
else
3898+
{
3899+
switch (json_get_first_token(json, false))
3900+
{
3901+
case JSON_TOKEN_OBJECT_START:
3902+
res = pred->value_type == JS_TYPE_OBJECT;
3903+
break;
3904+
case JSON_TOKEN_ARRAY_START:
3905+
res = pred->value_type == JS_TYPE_ARRAY;
3906+
break;
3907+
case JSON_TOKEN_STRING:
3908+
case JSON_TOKEN_NUMBER:
3909+
case JSON_TOKEN_TRUE:
3910+
case JSON_TOKEN_FALSE:
3911+
case JSON_TOKEN_NULL:
3912+
res = pred->value_type == JS_TYPE_SCALAR;
3913+
break;
3914+
default:
3915+
res = false;
3916+
break;
3917+
}
3918+
}
3919+
3920+
/*
3921+
* Do full parsing pass only for uniqueness check or for
3922+
* JSON text validation.
3923+
*/
3924+
if (res && (pred->unique_keys || exprtype == TEXTOID))
3925+
res = json_validate(json, pred->unique_keys);
3926+
}
3927+
else if (exprtype == JSONBOID)
3928+
{
3929+
if (pred->value_type == JS_TYPE_ANY)
3930+
res = true;
3931+
else
3932+
{
3933+
Jsonb *jb = DatumGetJsonbP(js);
3934+
3935+
switch (pred->value_type)
3936+
{
3937+
case JS_TYPE_OBJECT:
3938+
res = JB_ROOT_IS_OBJECT(jb);
3939+
break;
3940+
case JS_TYPE_ARRAY:
3941+
res = JB_ROOT_IS_ARRAY(jb) && !JB_ROOT_IS_SCALAR(jb);
3942+
break;
3943+
case JS_TYPE_SCALAR:
3944+
res = JB_ROOT_IS_ARRAY(jb) && JB_ROOT_IS_SCALAR(jb);
3945+
break;
3946+
default:
3947+
res = false;
3948+
break;
3949+
}
3950+
}
3951+
3952+
/* Key uniqueness check is redundant for jsonb */
3953+
}
3954+
else
3955+
res = false;
3956+
3957+
*op->resvalue = BoolGetDatum(res);
3958+
}
3959+
38653960
/*
38663961
* ExecEvalGroupingFunc
38673962
*

src/backend/nodes/makefuncs.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -890,14 +890,15 @@ makeJsonKeyValue(Node *key, Node *value)
890890
*/
891891
Node *
892892
makeJsonIsPredicate(Node *expr, JsonFormat *format, JsonValueType value_type,
893-
bool unique_keys)
893+
bool unique_keys, int location)
894894
{
895895
JsonIsPredicate *n = makeNode(JsonIsPredicate);
896896

897897
n->expr = expr;
898898
n->format = format;
899899
n->value_type = value_type;
900900
n->unique_keys = unique_keys;
901+
n->location = location;
901902

902903
return (Node *) n;
903904
}

src/backend/parser/gram.y

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13382,7 +13382,7 @@ a_expr: c_expr { $$ = $1; }
1338213382
json_key_uniqueness_constraint_opt %prec IS
1338313383
{
1338413384
JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
13385-
$$ = makeJsonIsPredicate($1, format, $4, $5);
13385+
$$ = makeJsonIsPredicate($1, format, $4, $5, @1);
1338613386
}
1338713387
/*
1338813388
* Required by standard, but it would conflict with expressions
@@ -13394,7 +13394,7 @@ a_expr: c_expr { $$ = $1; }
1339413394
json_key_uniqueness_constraint_opt %prec FORMAT
1339513395
{
1339613396
$3.location = @2;
13397-
$$ = makeJsonIsPredicate($1, $3, $6, $7);
13397+
$$ = makeJsonIsPredicate($1, $3, $6, $7, @1);
1339813398
}
1339913399
*/
1340013400
| a_expr
@@ -13403,7 +13403,7 @@ a_expr: c_expr { $$ = $1; }
1340313403
json_key_uniqueness_constraint_opt %prec IS
1340413404
{
1340513405
JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
13406-
$$ = makeNotExpr(makeJsonIsPredicate($1, format, $5, $6), @1);
13406+
$$ = makeNotExpr(makeJsonIsPredicate($1, format, $5, $6, @1), @1);
1340713407
}
1340813408
/*
1340913409
* Required by standard, but it would conflict with expressions
@@ -13415,7 +13415,7 @@ a_expr: c_expr { $$ = $1; }
1341513415
json_key_uniqueness_constraint_opt %prec FORMAT
1341613416
{
1341713417
$3.location = @2;
13418-
$$ = makeNotExpr(makeJsonIsPredicate($1, $3, $7, $8), @1);
13418+
$$ = makeNotExpr(makeJsonIsPredicate($1, $3, $7, $8, @1), @1);
1341913419
}
1342013420
*/
1342113421
| DEFAULT

src/backend/parser/parse_expr.c

Lines changed: 3 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -4346,24 +4346,6 @@ transformJsonArrayConstructor(ParseState *pstate, JsonArrayConstructor *ctor)
43464346
ctor->location);
43474347
}
43484348

4349-
static const char *
4350-
JsonValueTypeStrings[] =
4351-
{
4352-
"any",
4353-
"object",
4354-
"array",
4355-
"scalar",
4356-
};
4357-
4358-
static Const *
4359-
makeJsonValueTypeConst(JsonValueType type)
4360-
{
4361-
return makeConst(TEXTOID, -1, InvalidOid, -1,
4362-
PointerGetDatum(cstring_to_text(
4363-
JsonValueTypeStrings[(int) type])),
4364-
false, false);
4365-
}
4366-
43674349
/*
43684350
* Transform IS JSON predicate into
43694351
* json[b]_is_valid(json, value_type [, check_key_uniqueness]) call.
@@ -4373,7 +4355,6 @@ transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *pred)
43734355
{
43744356
Node *expr = transformExprRecurse(pstate, pred->expr);
43754357
Oid exprtype = exprType(expr);
4376-
FuncExpr *fexpr;
43774358

43784359
/* prepare input document */
43794360
if (exprtype == BYTEAOID)
@@ -4408,38 +4389,12 @@ transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *pred)
44084389
expr = (Node *) makeJsonValueExpr((Expr *) expr, pred->format);
44094390

44104391
/* make resulting expression */
4411-
if (exprtype == TEXTOID || exprtype == JSONOID)
4412-
{
4413-
fexpr = makeFuncExpr(F_JSON_IS_VALID, BOOLOID,
4414-
list_make3(expr,
4415-
makeJsonValueTypeConst(pred->value_type),
4416-
makeBoolConst(pred->unique_keys, false)),
4417-
InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
4418-
4419-
fexpr->location = pred->location;
4420-
}
4421-
else if (exprtype == JSONBOID)
4422-
{
4423-
/* XXX the following expressions also can be used here:
4424-
* jsonb_type(jsonb) = 'type' (for object and array checks)
4425-
* CASE jsonb_type(jsonb) WHEN ... END (for scalars checks)
4426-
*/
4427-
fexpr = makeFuncExpr(F_JSONB_IS_VALID, BOOLOID,
4428-
list_make2(expr,
4429-
makeJsonValueTypeConst(pred->value_type)),
4430-
InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
4431-
4432-
fexpr->location = pred->location;
4433-
}
4434-
else
4435-
{
4392+
if (exprtype != TEXTOID && exprtype != JSONOID && exprtype != JSONBOID)
44364393
ereport(ERROR,
44374394
(errcode(ERRCODE_DATATYPE_MISMATCH),
44384395
errmsg("cannot use type %s in IS JSON predicate",
44394396
format_type_be(exprtype))));
4440-
return NULL;
4441-
}
44424397

4443-
return makeJsonIsPredicate((Node *) fexpr, NULL, pred->value_type,
4444-
pred->unique_keys);
4398+
return makeJsonIsPredicate((Node *) expr, NULL, pred->value_type,
4399+
pred->unique_keys, pred->location);
44454400
}

0 commit comments

Comments
 (0)