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

Commit b6288f6

Browse files
author
Nikita Glukhov
committed
Add IS JSON predicate transformation
1 parent 9fc9511 commit b6288f6

File tree

17 files changed

+780
-4
lines changed

17 files changed

+780
-4
lines changed

contrib/pg_stat_statements/pg_stat_statements.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2832,6 +2832,14 @@ JumbleExpr(pgssJumbleState *jstate, Node *node)
28322832
APP_JUMB(opts->absent_on_null);
28332833
}
28342834
break;
2835+
case T_JsonIsPredicateOpts:
2836+
{
2837+
JsonIsPredicateOpts *opts = (JsonIsPredicateOpts *) node;
2838+
2839+
APP_JUMB(opts->unique_keys);
2840+
APP_JUMB(opts->value_type);
2841+
}
2842+
break;
28352843
case T_List:
28362844
foreach(temp, (List *) node)
28372845
{

src/backend/nodes/copyfuncs.c

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2264,6 +2264,36 @@ _copyJsonArrayQueryCtor(const JsonArrayQueryCtor *from)
22642264
return newnode;
22652265
}
22662266

2267+
/*
2268+
* _copyJsonIsPredicate
2269+
*/
2270+
static JsonIsPredicate *
2271+
_copyJsonIsPredicate(const JsonIsPredicate *from)
2272+
{
2273+
JsonIsPredicate *newnode = makeNode(JsonIsPredicate);
2274+
2275+
COPY_NODE_FIELD(expr);
2276+
COPY_SCALAR_FIELD(format);
2277+
COPY_SCALAR_FIELD(vtype);
2278+
COPY_SCALAR_FIELD(unique_keys);
2279+
2280+
return newnode;
2281+
}
2282+
2283+
/*
2284+
* _copyJsonIsPredicateOpts
2285+
*/
2286+
static JsonIsPredicateOpts *
2287+
_copyJsonIsPredicateOpts(const JsonIsPredicateOpts *from)
2288+
{
2289+
JsonIsPredicateOpts *newnode = makeNode(JsonIsPredicateOpts);
2290+
2291+
COPY_SCALAR_FIELD(value_type);
2292+
COPY_SCALAR_FIELD(unique_keys);
2293+
2294+
return newnode;
2295+
}
2296+
22672297
/* ****************************************************************
22682298
* relation.h copy functions
22692299
*
@@ -5157,6 +5187,12 @@ copyObjectImpl(const void *from)
51575187
case T_JsonArrayAgg:
51585188
retval = _copyJsonArrayAgg(from);
51595189
break;
5190+
case T_JsonIsPredicate:
5191+
retval = _copyJsonIsPredicate(from);
5192+
break;
5193+
case T_JsonIsPredicateOpts:
5194+
retval = _copyJsonIsPredicateOpts(from);
5195+
break;
51605196

51615197
/*
51625198
* RELATION NODES

src/backend/nodes/equalfuncs.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -843,6 +843,16 @@ _equalJsonCtorOpts(const JsonCtorOpts *a, const JsonCtorOpts *b)
843843
return true;
844844
}
845845

846+
static bool
847+
_equalJsonIsPredicateOpts(const JsonIsPredicateOpts *a,
848+
const JsonIsPredicateOpts *b)
849+
{
850+
COMPARE_SCALAR_FIELD(value_type);
851+
COMPARE_SCALAR_FIELD(unique_keys);
852+
853+
return true;
854+
}
855+
846856
/*
847857
* Stuff from relation.h
848858
*/
@@ -3185,6 +3195,9 @@ equal(const void *a, const void *b)
31853195
case T_JsonCtorOpts:
31863196
retval = _equalJsonCtorOpts(a, b);
31873197
break;
3198+
case T_JsonIsPredicateOpts:
3199+
retval = _equalJsonIsPredicateOpts(a, b);
3200+
break;
31883201

31893202
/*
31903203
* RELATION NODES

src/backend/nodes/nodeFuncs.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3782,6 +3782,8 @@ raw_expression_tree_walker(Node *node,
37823782
return true;
37833783
}
37843784
break;
3785+
case T_JsonIsPredicate:
3786+
return walker(((JsonIsPredicate *) node)->expr, context);
37853787
default:
37863788
elog(ERROR, "unrecognized node type: %d",
37873789
(int) nodeTag(node));

src/backend/nodes/outfuncs.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1727,6 +1727,15 @@ _outJsonCtorOpts(StringInfo str, const JsonCtorOpts *node)
17271727
WRITE_BOOL_FIELD(absent_on_null);
17281728
}
17291729

1730+
static void
1731+
_outJsonIsPredicateOpts(StringInfo str, const JsonIsPredicateOpts *node)
1732+
{
1733+
WRITE_NODE_TYPE("JSONISOPTS");
1734+
1735+
WRITE_ENUM_FIELD(value_type, JsonValueType);
1736+
WRITE_BOOL_FIELD(unique_keys);
1737+
}
1738+
17301739
/*****************************************************************************
17311740
*
17321741
* Stuff from relation.h.
@@ -4275,6 +4284,9 @@ outNode(StringInfo str, const void *obj)
42754284
case T_JsonCtorOpts:
42764285
_outJsonCtorOpts(str, obj);
42774286
break;
4287+
case T_JsonIsPredicateOpts:
4288+
_outJsonIsPredicateOpts(str, obj);
4289+
break;
42784290

42794291
default:
42804292

src/backend/nodes/readfuncs.c

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1364,6 +1364,20 @@ _readJsonCtorOpts(void)
13641364
READ_DONE();
13651365
}
13661366

1367+
/*
1368+
* _readJsonIsPredicateOpts
1369+
*/
1370+
static JsonIsPredicateOpts *
1371+
_readJsonIsPredicateOpts()
1372+
{
1373+
READ_LOCALS(JsonIsPredicateOpts);
1374+
1375+
READ_ENUM_FIELD(value_type, JsonValueType);
1376+
READ_BOOL_FIELD(unique_keys);
1377+
1378+
READ_DONE();
1379+
}
1380+
13671381
/*
13681382
* Stuff from parsenodes.h.
13691383
*/
@@ -2713,6 +2727,8 @@ parseNodeString(void)
27132727
return_value = _readJsonValueExpr();
27142728
else if (MATCH("JSONCTOROPTS", 12))
27152729
return_value = _readJsonCtorOpts();
2730+
else if (MATCH("JSONISOPTS", 10))
2731+
return_value = _readJsonIsPredicateOpts();
27162732
else
27172733
{
27182734
elog(ERROR, "badly formatted node string \"%.32s\"...", token);

src/backend/parser/parse_expr.c

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ static Node *transformJsonArrayQueryCtor(ParseState *pstate,
130130
JsonArrayQueryCtor *ctor);
131131
static Node *transformJsonObjectAgg(ParseState *pstate, JsonObjectAgg *agg);
132132
static Node *transformJsonArrayAgg(ParseState *pstate, JsonArrayAgg *agg);
133+
static Node *transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *p);
133134
static Node *make_row_comparison_op(ParseState *pstate, List *opname,
134135
List *largs, List *rargs, int location);
135136
static Node *make_row_distinct_op(ParseState *pstate, List *opname,
@@ -398,6 +399,10 @@ transformExprRecurse(ParseState *pstate, Node *expr)
398399
result = transformJsonArrayAgg(pstate, (JsonArrayAgg *) expr);
399400
break;
400401

402+
case T_JsonIsPredicate:
403+
result = transformJsonIsPredicate(pstate, (JsonIsPredicate *) expr);
404+
break;
405+
401406
default:
402407
/* should not reach here */
403408
elog(ERROR, "unrecognized node type: %d", (int) nodeTag(expr));
@@ -4155,3 +4160,108 @@ transformJsonArrayCtor(ParseState *pstate, JsonArrayCtor *ctor)
41554160

41564161
return coerceJsonFuncExpr(pstate, (Node *) fexpr, &returning, true);
41574162
}
4163+
4164+
static const char *
4165+
JsonValueTypeStrings[] =
4166+
{
4167+
"any",
4168+
"object",
4169+
"array",
4170+
"scalar",
4171+
};
4172+
4173+
static Const *
4174+
makeJsonValueTypeConst(JsonValueType type)
4175+
{
4176+
return makeConst(TEXTOID, -1, InvalidOid, -1,
4177+
PointerGetDatum(cstring_to_text(
4178+
JsonValueTypeStrings[(int) type])),
4179+
false, false);
4180+
}
4181+
4182+
/*
4183+
* Transform IS JSON predicate into
4184+
* json[b]_is_valid(json, value_type [, check_key_uniqueness]) call.
4185+
*/
4186+
static Node *
4187+
transformJsonIsPredicate(ParseState *pstate, JsonIsPredicate *pred)
4188+
{
4189+
Node *expr = transformExprRecurse(pstate, pred->expr);
4190+
Oid exprtype = exprType(expr);
4191+
FuncExpr *fexpr;
4192+
JsonIsPredicateOpts *opts;
4193+
4194+
/* prepare input document */
4195+
if (exprtype == BYTEAOID)
4196+
{
4197+
expr = makeJsonByteaToTextConversion(expr, &pred->format,
4198+
exprLocation(expr));
4199+
exprtype = TEXTOID;
4200+
}
4201+
else
4202+
{
4203+
char typcategory;
4204+
bool typispreferred;
4205+
4206+
get_type_category_preferred(exprtype, &typcategory, &typispreferred);
4207+
4208+
if (exprtype == UNKNOWNOID || typcategory == TYPCATEGORY_STRING)
4209+
{
4210+
expr = coerce_to_target_type(pstate, (Node *) expr, exprtype,
4211+
TEXTOID, -1,
4212+
COERCION_IMPLICIT,
4213+
COERCE_IMPLICIT_CAST, -1);
4214+
exprtype = TEXTOID;
4215+
}
4216+
4217+
if (pred->format.encoding != JS_ENC_DEFAULT)
4218+
ereport(ERROR,
4219+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
4220+
parser_errposition(pstate, pred->format.location),
4221+
errmsg("cannot use JSON FORMAT ENCODING clause for non-bytea input types")));
4222+
}
4223+
4224+
expr = (Node *) makeJsonValueExpr((Expr *) expr, pred->format);
4225+
4226+
/* make resulting expression */
4227+
if (exprtype == TEXTOID || exprtype == JSONOID)
4228+
{
4229+
fexpr = makeFuncExpr(F_JSON_IS_VALID, BOOLOID,
4230+
list_make3(expr,
4231+
makeJsonValueTypeConst(pred->vtype),
4232+
makeBoolConst(pred->unique_keys, false)),
4233+
InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
4234+
4235+
fexpr->location = pred->location;
4236+
}
4237+
else if (exprtype == JSONBOID)
4238+
{
4239+
/* XXX the following expressions also can be used here:
4240+
* jsonb_type(jsonb) = 'type' (for object and array checks)
4241+
* CASE jsonb_type(jsonb) WHEN ... END (for scalars checks)
4242+
*/
4243+
fexpr = makeFuncExpr(F_JSONB_IS_VALID, BOOLOID,
4244+
list_make2(expr,
4245+
makeJsonValueTypeConst(pred->vtype)),
4246+
InvalidOid, InvalidOid, COERCE_EXPLICIT_CALL);
4247+
4248+
fexpr->location = pred->location;
4249+
}
4250+
else
4251+
{
4252+
ereport(ERROR,
4253+
(errcode(ERRCODE_DATATYPE_MISMATCH),
4254+
errmsg("cannot use type %s in IS JSON predicate",
4255+
format_type_be(exprtype))));
4256+
return NULL;
4257+
}
4258+
4259+
opts = makeNode(JsonIsPredicateOpts);
4260+
opts->unique_keys = pred->unique_keys;
4261+
opts->value_type = pred->vtype;
4262+
4263+
fexpr->funcformat2 = FUNCFMT_IS_JSON;
4264+
fexpr->funcformatopts = (Node *) opts;
4265+
4266+
return (Node *) fexpr;
4267+
}

0 commit comments

Comments
 (0)