Skip to content

Commit edcf87d

Browse files
author
Nikita Glukhov
committed
Add JsonValueExpr transformation
1 parent ceb864a commit edcf87d

File tree

9 files changed

+319
-0
lines changed

9 files changed

+319
-0
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3086,6 +3086,15 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
30863086
JumbleExpr(jstate, (Node *) conf->exclRelTlist);
30873087
}
30883088
break;
3089+
case T_JsonValueExpr:
3090+
{
3091+
JsonValueExpr *expr = (JsonValueExpr *) node;
3092+
3093+
JumbleExpr(jstate, (Node *) expr->expr);
3094+
APP_JUMB(expr->format.type);
3095+
APP_JUMB(expr->format.encoding);
3096+
}
3097+
break;
30893098
case T_List:
30903099
foreach(temp, (List *) node)
30913100
{

src/backend/executor/execExpr.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2108,6 +2108,11 @@ ExecInitExprRec(Expr *node, ExprState *state,
21082108
break;
21092109
}
21102110

2111+
case T_JsonValueExpr:
2112+
ExecInitExprRec(((JsonValueExpr *) node)->expr, state, resv,
2113+
resnull);
2114+
break;
2115+
21112116
default:
21122117
elog(ERROR, "unrecognized node type: %d",
21132118
(int) nodeTag(node));

src/backend/nodes/copyfuncs.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2248,6 +2248,20 @@ _copyOnConflictExpr(const OnConflictExpr *from)
22482248
return newnode;
22492249
}
22502250

2251+
/*
2252+
* _copyJsonValueExpr
2253+
*/
2254+
static JsonValueExpr *
2255+
_copyJsonValueExpr(const JsonValueExpr *from)
2256+
{
2257+
JsonValueExpr *newnode = makeNode(JsonValueExpr);
2258+
2259+
COPY_NODE_FIELD(expr);
2260+
COPY_SCALAR_FIELD(format);
2261+
2262+
return newnode;
2263+
}
2264+
22512265
/* ****************************************************************
22522266
* pathnodes.h copy functions
22532267
*
@@ -5145,6 +5159,9 @@ copyObjectImpl(const void *from)
51455159
case T_OnConflictExpr:
51465160
retval = _copyOnConflictExpr(from);
51475161
break;
5162+
case T_JsonValueExpr:
5163+
retval = _copyJsonValueExpr(from);
5164+
break;
51485165

51495166
/*
51505167
* RELATION NODES

src/backend/nodes/equalfuncs.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -818,6 +818,17 @@ _equalOnConflictExpr(const OnConflictExpr *a, const OnConflictExpr *b)
818818
return true;
819819
}
820820

821+
static bool
822+
_equalJsonValueExpr(const JsonValueExpr *a, const JsonValueExpr *b)
823+
{
824+
COMPARE_NODE_FIELD(expr);
825+
COMPARE_SCALAR_FIELD(format.type);
826+
COMPARE_SCALAR_FIELD(format.encoding);
827+
COMPARE_LOCATION_FIELD(format.location);
828+
829+
return true;
830+
}
831+
821832
/*
822833
* Stuff from pathnodes.h
823834
*/
@@ -3210,6 +3221,9 @@ equal(const void *a, const void *b)
32103221
case T_JoinExpr:
32113222
retval = _equalJoinExpr(a, b);
32123223
break;
3224+
case T_JsonValueExpr:
3225+
retval = _equalJsonValueExpr(a, b);
3226+
break;
32133227

32143228
/*
32153229
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,9 @@ exprType(const Node *expr)
258258
case T_PlaceHolderVar:
259259
type = exprType((Node *) ((const PlaceHolderVar *) expr)->phexpr);
260260
break;
261+
case T_JsonValueExpr:
262+
type = exprType((Node *) ((const JsonValueExpr *) expr)->expr);
263+
break;
261264
default:
262265
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
263266
type = InvalidOid; /* keep compiler quiet */
@@ -491,6 +494,8 @@ exprTypmod(const Node *expr)
491494
return ((const SetToDefault *) expr)->typeMod;
492495
case T_PlaceHolderVar:
493496
return exprTypmod((Node *) ((const PlaceHolderVar *) expr)->phexpr);
497+
case T_JsonValueExpr:
498+
return exprTypmod((Node *) ((const JsonValueExpr *) expr)->expr);
494499
default:
495500
break;
496501
}
@@ -906,6 +911,9 @@ exprCollation(const Node *expr)
906911
case T_PlaceHolderVar:
907912
coll = exprCollation((Node *) ((const PlaceHolderVar *) expr)->phexpr);
908913
break;
914+
case T_JsonValueExpr:
915+
coll = exprCollation((Node *) ((const JsonValueExpr *) expr)->expr);
916+
break;
909917
default:
910918
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
911919
coll = InvalidOid; /* keep compiler quiet */
@@ -1109,6 +1117,10 @@ exprSetCollation(Node *expr, Oid collation)
11091117
Assert(!OidIsValid(collation)); /* result is always an integer
11101118
* type */
11111119
break;
1120+
case T_JsonValueExpr:
1121+
exprSetCollation((Node *) ((const JsonValueExpr *) expr)->expr,
1122+
collation);
1123+
break;
11121124
default:
11131125
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
11141126
break;
@@ -1549,6 +1561,9 @@ exprLocation(const Node *expr)
15491561
case T_PartitionRangeDatum:
15501562
loc = ((const PartitionRangeDatum *) expr)->location;
15511563
break;
1564+
case T_JsonValueExpr:
1565+
loc = exprLocation((Node *) ((const JsonValueExpr *) expr)->expr);
1566+
break;
15521567
default:
15531568
/* for any other node type it's just unknown... */
15541569
loc = -1;
@@ -2246,6 +2261,8 @@ expression_tree_walker(Node *node,
22462261
return true;
22472262
}
22482263
break;
2264+
case T_JsonValueExpr:
2265+
return walker(((JsonValueExpr *) node)->expr, context);
22492266
default:
22502267
elog(ERROR, "unrecognized node type: %d",
22512268
(int) nodeTag(node));
@@ -3169,6 +3186,16 @@ expression_tree_mutator(Node *node,
31693186
return (Node *) newnode;
31703187
}
31713188
break;
3189+
case T_JsonValueExpr:
3190+
{
3191+
JsonValueExpr *jve = (JsonValueExpr *) node;
3192+
JsonValueExpr *newnode;
3193+
3194+
FLATCOPY(newnode, jve, JsonValueExpr);
3195+
MUTATE(newnode->expr, jve->expr, Expr *);
3196+
3197+
return (Node *) newnode;
3198+
}
31723199
default:
31733200
elog(ERROR, "unrecognized node type: %d",
31743201
(int) nodeTag(node));
@@ -3864,6 +3891,8 @@ raw_expression_tree_walker(Node *node,
38643891
break;
38653892
case T_CommonTableExpr:
38663893
return walker(((CommonTableExpr *) node)->ctequery, context);
3894+
case T_JsonValueExpr:
3895+
return walker(((JsonValueExpr *) node)->expr, context);
38673896
default:
38683897
elog(ERROR, "unrecognized node type: %d",
38693898
(int) nodeTag(node));

src/backend/nodes/outfuncs.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1709,6 +1709,17 @@ _outOnConflictExpr(StringInfo str, const OnConflictExpr *node)
17091709
WRITE_NODE_FIELD(exclRelTlist);
17101710
}
17111711

1712+
static void
1713+
_outJsonValueExpr(StringInfo str, const JsonValueExpr *node)
1714+
{
1715+
WRITE_NODE_TYPE("JSONVALUEEXPR");
1716+
1717+
WRITE_NODE_FIELD(expr);
1718+
WRITE_ENUM_FIELD(format.type, JsonFormatType);
1719+
WRITE_ENUM_FIELD(format.encoding, JsonEncoding);
1720+
WRITE_LOCATION_FIELD(format.location);
1721+
}
1722+
17121723
/*****************************************************************************
17131724
*
17141725
* Stuff from pathnodes.h.
@@ -4337,6 +4348,9 @@ outNode(StringInfo str, const void *obj)
43374348
case T_PartitionRangeDatum:
43384349
_outPartitionRangeDatum(str, obj);
43394350
break;
4351+
case T_JsonValueExpr:
4352+
_outJsonValueExpr(str, obj);
4353+
break;
43404354

43414355
default:
43424356

src/backend/nodes/readfuncs.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,22 @@ _readOnConflictExpr(void)
13431343
READ_DONE();
13441344
}
13451345

1346+
/*
1347+
* _readJsonValueExpr
1348+
*/
1349+
static JsonValueExpr *
1350+
_readJsonValueExpr(void)
1351+
{
1352+
READ_LOCALS(JsonValueExpr);
1353+
1354+
READ_NODE_FIELD(expr);
1355+
READ_ENUM_FIELD(format.type, JsonFormatType);
1356+
READ_ENUM_FIELD(format.encoding, JsonEncoding);
1357+
READ_LOCATION_FIELD(format.location);
1358+
1359+
READ_DONE();
1360+
}
1361+
13461362
/*
13471363
* Stuff from pathnodes.h.
13481364
*
@@ -2880,6 +2896,8 @@ parseNodeString(void)
28802896
return_value = _readPartitionBoundSpec();
28812897
else if (MATCH("PARTITIONRANGEDATUM", 19))
28822898
return_value = _readPartitionRangeDatum();
2899+
else if (MATCH("JSONVALUEEXPR", 13))
2900+
return_value = _readJsonValueExpr();
28832901
else
28842902
{
28852903
elog(ERROR, "badly formatted node string \"%.32s\"...", token);

src/backend/parser/parse_expr.c

Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "parser/parse_type.h"
3535
#include "utils/builtins.h"
3636
#include "utils/date.h"
37+
#include "utils/fmgroids.h"
3738
#include "utils/lsyscache.h"
3839
#include "utils/timestamp.h"
3940
#include "utils/xml.h"
@@ -3569,3 +3570,159 @@ ParseExprKindName(ParseExprKind exprKind)
35693570
}
35703571
return "unrecognized expression kind";
35713572
}
3573+
3574+
/*
3575+
* Make string Const node from JSON encoding name.
3576+
*
3577+
* UTF8 is default encoding.
3578+
*/
3579+
static Const *
3580+
getJsonEncodingConst(JsonFormat *format)
3581+
{
3582+
JsonEncoding encoding;
3583+
const char *enc;
3584+
Name encname = palloc(sizeof(NameData));
3585+
3586+
if (!format ||
3587+
format->type == JS_FORMAT_DEFAULT ||
3588+
format->encoding == JS_ENC_DEFAULT)
3589+
encoding = JS_ENC_UTF8;
3590+
else
3591+
encoding = format->encoding;
3592+
3593+
switch (encoding)
3594+
{
3595+
case JS_ENC_UTF16:
3596+
enc = "UTF16";
3597+
break;
3598+
case JS_ENC_UTF32:
3599+
enc = "UTF32";
3600+
break;
3601+
case JS_ENC_UTF8:
3602+
default:
3603+
enc = "UTF8";
3604+
break;
3605+
}
3606+
3607+
namestrcpy(encname, enc);
3608+
3609+
return makeConst(NAMEOID, -1, InvalidOid, NAMEDATALEN,
3610+
NameGetDatum(encname), false, false);
3611+
}
3612+
3613+
/*
3614+
* Make bytea => text conversion using specified JSON format encoding.
3615+
*/
3616+
static Node *
3617+
makeJsonByteaToTextConversion(Node *expr, JsonFormat *format, int location)
3618+
{
3619+
Const *encoding = getJsonEncodingConst(format);
3620+
FuncExpr *fexpr = makeFuncExpr(F_PG_CONVERT_FROM, TEXTOID,
3621+
list_make2(expr, encoding),
3622+
InvalidOid, InvalidOid,
3623+
COERCE_INTERNAL_CAST);
3624+
3625+
fexpr->location = location;
3626+
3627+
return (Node *) fexpr;
3628+
}
3629+
3630+
/*
3631+
* Transform JSON value expression using specified input JSON format or
3632+
* default format otherwise.
3633+
*/
3634+
static Node *
3635+
transformJsonValueExpr(ParseState *pstate, JsonValueExpr *ve,
3636+
JsonFormatType default_format)
3637+
{
3638+
Node *expr = transformExprRecurse(pstate, (Node *) ve->expr);
3639+
JsonFormatType format;
3640+
Oid exprtype;
3641+
int location;
3642+
char typcategory;
3643+
bool typispreferred;
3644+
3645+
if (exprType(expr) == UNKNOWNOID)
3646+
expr = coerce_to_specific_type(pstate, expr, TEXTOID, "JSON_VALUE_EXPR");
3647+
3648+
exprtype = exprType(expr);
3649+
location = exprLocation(expr);
3650+
3651+
get_type_category_preferred(exprtype, &typcategory, &typispreferred);
3652+
3653+
if (ve->format.type != JS_FORMAT_DEFAULT)
3654+
{
3655+
if (ve->format.encoding != JS_ENC_DEFAULT && exprtype != BYTEAOID)
3656+
ereport(ERROR,
3657+
(errcode(ERRCODE_DATATYPE_MISMATCH),
3658+
errmsg("JSON ENCODING clause is only allowed for bytea input type"),
3659+
parser_errposition(pstate, ve->format.location)));
3660+
3661+
if (exprtype == JSONOID || exprtype == JSONBOID)
3662+
{
3663+
format = JS_FORMAT_DEFAULT; /* do not format json[b] types */
3664+
ereport(WARNING,
3665+
(errmsg("FORMAT JSON has no effect for json and jsonb types"),
3666+
parser_errposition(pstate, ve->format->location)));
3667+
}
3668+
else
3669+
format = ve->format.type;
3670+
}
3671+
else if (exprtype == JSONOID || exprtype == JSONBOID)
3672+
format = JS_FORMAT_DEFAULT; /* do not format json[b] types */
3673+
else
3674+
format = default_format;
3675+
3676+
if (format != JS_FORMAT_DEFAULT)
3677+
{
3678+
Oid targettype = format == JS_FORMAT_JSONB ? JSONBOID : JSONOID;
3679+
Node *coerced;
3680+
FuncExpr *fexpr;
3681+
3682+
if (exprtype != BYTEAOID && typcategory != TYPCATEGORY_STRING)
3683+
ereport(ERROR,
3684+
(errcode(ERRCODE_DATATYPE_MISMATCH),
3685+
errmsg(ve->format.type == JS_FORMAT_DEFAULT ?
3686+
"cannot use non-string types with implicit FORMAT JSON clause" :
3687+
"cannot use non-string types with explicit FORMAT JSON clause"),
3688+
parser_errposition(pstate, ve->format.location >= 0 ?
3689+
ve->format.location : location)));
3690+
3691+
/* Convert encoded JSON text from bytea. */
3692+
if (format == JS_FORMAT_JSON && exprtype == BYTEAOID)
3693+
{
3694+
expr = makeJsonByteaToTextConversion(expr, &ve->format, location);
3695+
exprtype = TEXTOID;
3696+
}
3697+
3698+
/* Try to coerce to the target type. */
3699+
coerced = coerce_to_target_type(pstate, expr, exprtype,
3700+
targettype, -1,
3701+
COERCION_EXPLICIT,
3702+
COERCE_INTERNAL_CAST,
3703+
location);
3704+
3705+
if (coerced)
3706+
expr = coerced;
3707+
else
3708+
{
3709+
/* If coercion failed, use to_json()/to_jsonb() functions. */
3710+
Oid fnoid = targettype == JSONOID ? F_TO_JSON : F_TO_JSONB;
3711+
3712+
fexpr = makeFuncExpr(fnoid, targettype, list_make1(expr),
3713+
InvalidOid, InvalidOid,
3714+
COERCE_INTERNAL_CAST);
3715+
fexpr->location = location;
3716+
3717+
expr = (Node *) fexpr;
3718+
}
3719+
3720+
ve = copyObject(ve);
3721+
ve->expr = (Expr *) expr;
3722+
3723+
expr = (Node *) ve;
3724+
}
3725+
3726+
return expr;
3727+
}
3728+

0 commit comments

Comments
 (0)