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)
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