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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy