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

Commit 6c13c76

Browse files
author
Nikita Glukhov
committed
Add IS JSON predicate transformation
1 parent 3578661 commit 6c13c76

File tree

17 files changed

+730
-4
lines changed

17 files changed

+730
-4
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3124,6 +3124,16 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
31243124
APP_JUMB(ctor->absent_on_null);
31253125
}
31263126
break;
3127+
case T_JsonIsPredicate:
3128+
{
3129+
JsonIsPredicate *pred = (JsonIsPredicate *) node;
3130+
3131+
JumbleExpr(jstate, (Node *) pred->expr);
3132+
JumbleExpr(jstate, (Node *) pred->format);
3133+
APP_JUMB(pred->unique_keys);
3134+
APP_JUMB(pred->value_type);
3135+
}
3136+
break;
31273137
case T_List:
31283138
foreach(temp, (List *) node)
31293139
{

src/backend/executor/execExpr.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2193,6 +2193,11 @@ ExecInitExprRec(Expr *node, ExprState *state,
21932193
}
21942194
break;
21952195

2196+
case T_JsonIsPredicate:
2197+
ExecInitExprRec((Expr *) ((JsonIsPredicate *) node)->expr, state, resv,
2198+
resnull);
2199+
break;
2200+
21962201
default:
21972202
elog(ERROR, "unrecognized node type: %d",
21982203
(int) nodeTag(node));

src/backend/nodes/copyfuncs.c

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2440,6 +2440,23 @@ _copyJsonArrayQueryConstructor(const JsonArrayQueryConstructor *from)
24402440
return newnode;
24412441
}
24422442

2443+
/*
2444+
* _copyJsonIsPredicate
2445+
*/
2446+
static JsonIsPredicate *
2447+
_copyJsonIsPredicate(const JsonIsPredicate *from)
2448+
{
2449+
JsonIsPredicate *newnode = makeNode(JsonIsPredicate);
2450+
2451+
COPY_NODE_FIELD(expr);
2452+
COPY_SCALAR_FIELD(format);
2453+
COPY_SCALAR_FIELD(value_type);
2454+
COPY_SCALAR_FIELD(unique_keys);
2455+
COPY_LOCATION_FIELD(location);
2456+
2457+
return newnode;
2458+
}
2459+
24432460
/* ****************************************************************
24442461
* pathnodes.h copy functions
24452462
*
@@ -5373,6 +5390,9 @@ copyObjectImpl(const void *from)
53735390
case T_JsonArrayAgg:
53745391
retval = _copyJsonArrayAgg(from);
53755392
break;
5393+
case T_JsonIsPredicate:
5394+
retval = _copyJsonIsPredicate(from);
5395+
break;
53765396

53775397
/*
53785398
* RELATION NODES

src/backend/nodes/equalfuncs.c

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -953,6 +953,18 @@ _equalJsonArrayQueryConstructor(const JsonArrayQueryConstructor *a,
953953
return true;
954954
}
955955

956+
static bool
957+
_equalJsonIsPredicate(const JsonIsPredicate *a,
958+
const JsonIsPredicate *b)
959+
{
960+
COMPARE_NODE_FIELD(expr);
961+
COMPARE_SCALAR_FIELD(value_type);
962+
COMPARE_SCALAR_FIELD(unique_keys);
963+
COMPARE_LOCATION_FIELD(location);
964+
965+
return true;
966+
}
967+
956968
/*
957969
* Stuff from pathnodes.h
958970
*/
@@ -3357,6 +3369,9 @@ equal(const void *a, const void *b)
33573369
case T_JsonConstructorExpr:
33583370
retval = _equalJsonConstructorExpr(a, b);
33593371
break;
3372+
case T_JsonIsPredicate:
3373+
retval = _equalJsonIsPredicate(a, b);
3374+
break;
33603375

33613376
/*
33623377
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,9 @@ exprType(const Node *expr)
268268
case T_JsonConstructorExpr:
269269
type = ((const JsonConstructorExpr *) expr)->returning->typid;
270270
break;
271+
case T_JsonIsPredicate:
272+
type = BOOLOID;
273+
break;
271274
default:
272275
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
273276
type = InvalidOid; /* keep compiler quiet */
@@ -933,6 +936,9 @@ exprCollation(const Node *expr)
933936
coll = InvalidOid;
934937
}
935938
break;
939+
case T_JsonIsPredicate:
940+
coll = InvalidOid; /* result is always an boolean type */
941+
break;
936942
default:
937943
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
938944
coll = InvalidOid; /* keep compiler quiet */
@@ -1150,6 +1156,9 @@ exprSetCollation(Node *expr, Oid collation)
11501156
Assert(!OidIsValid(collation)); /* result is always an json[b] type */
11511157
}
11521158
break;
1159+
case T_JsonIsPredicate:
1160+
Assert(!OidIsValid(collation)); /* result is always boolean */
1161+
break;
11531162
default:
11541163
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
11551164
break;
@@ -1596,6 +1605,9 @@ exprLocation(const Node *expr)
15961605
case T_JsonConstructorExpr:
15971606
loc = ((const JsonConstructorExpr *) expr)->location;
15981607
break;
1608+
case T_JsonIsPredicate:
1609+
loc = ((const JsonIsPredicate *) expr)->location;
1610+
break;
15991611
default:
16001612
/* for any other node type it's just unknown... */
16011613
loc = -1;
@@ -2315,6 +2327,8 @@ expression_tree_walker(Node *node,
23152327
return true;
23162328
}
23172329
break;
2330+
case T_JsonIsPredicate:
2331+
return walker(((JsonIsPredicate *) node)->expr, context);
23182332
default:
23192333
elog(ERROR, "unrecognized node type: %d",
23202334
(int) nodeTag(node));
@@ -3272,6 +3286,16 @@ expression_tree_mutator(Node *node,
32723286
MUTATE(newnode->coercion, jve->coercion, Expr *);
32733287
MUTATE(newnode->returning, jve->returning, JsonReturning *);
32743288

3289+
return (Node *) newnode;
3290+
}
3291+
case T_JsonIsPredicate:
3292+
{
3293+
JsonIsPredicate *pred = (JsonIsPredicate *) node;
3294+
JsonIsPredicate *newnode;
3295+
3296+
FLATCOPY(newnode, pred, JsonIsPredicate);
3297+
MUTATE(newnode->expr, pred->expr, Node *);
3298+
32753299
return (Node *) newnode;
32763300
}
32773301
default:
@@ -4081,6 +4105,8 @@ raw_expression_tree_walker(Node *node,
40814105
return true;
40824106
}
40834107
break;
4108+
case T_JsonIsPredicate:
4109+
return walker(((JsonIsPredicate *) node)->expr, context);
40844110
default:
40854111
elog(ERROR, "unrecognized node type: %d",
40864112
(int) nodeTag(node));

src/backend/nodes/outfuncs.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1754,6 +1754,17 @@ _outJsonConstructorExpr(StringInfo str, const JsonConstructorExpr *node)
17541754
WRITE_LOCATION_FIELD(location);
17551755
}
17561756

1757+
static void
1758+
_outJsonIsPredicate(StringInfo str, const JsonIsPredicate *node)
1759+
{
1760+
WRITE_NODE_TYPE("JSONISPREDICATE");
1761+
1762+
WRITE_NODE_FIELD(expr);
1763+
WRITE_ENUM_FIELD(value_type, JsonValueType);
1764+
WRITE_BOOL_FIELD(unique_keys);
1765+
WRITE_LOCATION_FIELD(location);
1766+
}
1767+
17571768
/*****************************************************************************
17581769
*
17591770
* Stuff from pathnodes.h.
@@ -4394,6 +4405,9 @@ outNode(StringInfo str, const void *obj)
43944405
case T_JsonConstructorExpr:
43954406
_outJsonConstructorExpr(str, obj);
43964407
break;
4408+
case T_JsonIsPredicate:
4409+
_outJsonIsPredicate(str, obj);
4410+
break;
43974411

43984412
default:
43994413

src/backend/nodes/readfuncs.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1408,6 +1408,22 @@ _readJsonConstructorExpr(void)
14081408
READ_DONE();
14091409
}
14101410

1411+
/*
1412+
* _readJsonIsPredicate
1413+
*/
1414+
static JsonIsPredicate *
1415+
_readJsonIsPredicate()
1416+
{
1417+
READ_LOCALS(JsonIsPredicate);
1418+
1419+
READ_NODE_FIELD(expr);
1420+
READ_ENUM_FIELD(value_type, JsonValueType);
1421+
READ_BOOL_FIELD(unique_keys);
1422+
READ_LOCATION_FIELD(location);
1423+
1424+
READ_DONE();
1425+
}
1426+
14111427
/*
14121428
* Stuff from pathnodes.h.
14131429
*
@@ -2953,6 +2969,8 @@ parseNodeString(void)
29532969
return_value = _readJsonValueExpr();
29542970
else if (MATCH("JSONCTOREXPR", 12))
29552971
return_value = _readJsonConstructorExpr();
2972+
else if (MATCH("JSONISPREDICATE", 15))
2973+
return_value = _readJsonIsPredicate();
29562974
else
29572975
{
29582976
elog(ERROR, "badly formatted node string \"%.32s\"...", token);

src/backend/parser/parse_expr.c

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ static Node *transformJsonArrayQueryConstructor(ParseState *pstate,
131131
JsonArrayQueryConstructor *ctor);
132132
static Node *transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg);
133133
static Node *transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg);
134+
static Node *transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *p);
134135
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
135136
List *largs, List *rargs, int location);
136137
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
@@ -399,6 +400,10 @@ transformExprRecurse(ParseState *pstate, Node *expr)
399400
result = transformJsonArrayAgg(pstate, (JsonArrayAgg *) expr);
400401
break;
401402

403+
case T_JsonIsPredicate:
404+
result = transformJsonIsPredicate(pstate, (JsonIsPredicate *) expr);
405+
break;
406+
402407
default:
403408
/* should not reach here */
404409
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -4340,3 +4345,101 @@ transformJsonArrayConstructor(ParseState *pstate, JsonArrayConstructor *ctor)
43404345
returning, false, ctor->absent_on_null,
43414346
ctor->location);
43424347
}
4348+
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+
4367+
/*
4368+
* Transform IS JSON predicate into
4369+
* json[b]_is_valid(json, value_type [, check_key_uniqueness]) call.
4370+
*/
4371+
static Node *
4372+
transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *pred)
4373+
{
4374+
Node *expr = transformExprRecurse(pstate, pred->expr);
4375+
Oid exprtype = exprType(expr);
4376+
FuncExpr *fexpr;
4377+
4378+
/* prepare input document */
4379+
if (exprtype == BYTEAOID)
4380+
{
4381+
expr = makeJsonByteaToTextConversion(expr, pred->format,
4382+
exprLocation(expr));
4383+
exprtype = TEXTOID;
4384+
}
4385+
else
4386+
{
4387+
char typcategory;
4388+
bool typispreferred;
4389+
4390+
get_type_category_preferred(exprtype, &typcategory, &typispreferred);
4391+
4392+
if (exprtype == UNKNOWNOID || typcategory == TYPCATEGORY_STRING)
4393+
{
4394+
expr = coerce_to_target_type(pstate, (Node *) expr, exprtype,
4395+
TEXTOID, -1,
4396+
COERCION_IMPLICIT,
4397+
COERCE_IMPLICIT_CAST, -1);
4398+
exprtype = TEXTOID;
4399+
}
4400+
4401+
if (pred->format->encoding != JS_ENC_DEFAULT)
4402+
ereport(ERROR,
4403+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4404+
parser_errposition(pstate, pred->format->location),
4405+
errmsg("cannot use JSON FORMAT ENCODING clause for non-bytea input types")));
4406+
}
4407+
4408+
expr = (Node *) makeJsonValueExpr((Expr *) expr, pred->format);
4409+
4410+
/* 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+
{
4436+
ereport(ERROR,
4437+
(errcode(ERRCODE_DATATYPE_MISMATCH),
4438+
errmsg("cannot use type %s in IS JSON predicate",
4439+
format_type_be(exprtype))));
4440+
return NULL;
4441+
}
4442+
4443+
return makeJsonIsPredicate((Node *) fexpr, NULL, pred->value_type,
4444+
pred->unique_keys);
4445+
}

0 commit comments

Comments
 (0)