{
JsonIsPredicate *pred = op->d.is_json.pred;
Datum js = *op->resvalue;
- Oid exprtype;
+ Oid exprtype = pred->exprBaseType;
bool res;
if (*op->resnull)
return;
}
- exprtype = exprType(pred->expr);
-
if (exprtype == TEXTOID || exprtype == JSONOID)
{
text *json = DatumGetTextP(js);
*/
Node *
makeJsonIsPredicate(Node *expr, JsonFormat *format, JsonValueType item_type,
- bool unique_keys, int location)
+ bool unique_keys, Oid exprBaseType, int location)
{
JsonIsPredicate *n = makeNode(JsonIsPredicate);
n->format = format;
n->item_type = item_type;
n->unique_keys = unique_keys;
+ n->exprBaseType = exprBaseType;
n->location = location;
return (Node *) n;
{
JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
- $$ = makeJsonIsPredicate($1, format, $3, $4, @1);
+ $$ = makeJsonIsPredicate($1, format, $3, $4, InvalidOid, @1);
}
/*
* Required by SQL/JSON, but there are conflicts
IS json_predicate_type_constraint
json_key_uniqueness_constraint_opt %prec IS
{
- $$ = makeJsonIsPredicate($1, $2, $4, $5, @1);
+ $$ = makeJsonIsPredicate($1, $2, $4, $5, InvalidOid, @1);
}
*/
| a_expr IS NOT
{
JsonFormat *format = makeJsonFormat(JS_FORMAT_DEFAULT, JS_ENC_DEFAULT, -1);
- $$ = makeNotExpr(makeJsonIsPredicate($1, format, $4, $5, @1), @1);
+ $$ = makeNotExpr(makeJsonIsPredicate($1, format, $4, $5, InvalidOid, @1), @1);
}
/*
* Required by SQL/JSON, but there are conflicts
json_predicate_type_constraint
json_key_uniqueness_constraint_opt %prec IS
{
- $$ = makeNotExpr(makeJsonIsPredicate($1, $2, $5, $6, @1), @1);
+ $$ = makeNotExpr(makeJsonIsPredicate($1, $2, $5, $6, InvalidOid, @1), @1);
}
*/
| DEFAULT
Node *raw_expr = transformExprRecurse(pstate, jsexpr);
Node *expr = raw_expr;
- *exprtype = exprType(expr);
+ *exprtype = getBaseType(exprType(expr));
/* prepare input document */
if (*exprtype == BYTEAOID)
/* make resulting expression */
if (exprtype != TEXTOID && exprtype != JSONOID && exprtype != JSONBOID)
ereport(ERROR,
- (errcode(ERRCODE_DATATYPE_MISMATCH),
- errmsg("cannot use type %s in IS JSON predicate",
- format_type_be(exprtype))));
+ errcode(ERRCODE_DATATYPE_MISMATCH),
+ errmsg("cannot use type %s in IS JSON predicate",
+ format_type_be(exprType(expr))),
+ parser_errposition(pstate, exprLocation(expr)));
/* This intentionally(?) drops the format clause. */
return makeJsonIsPredicate(expr, NULL, pred->item_type,
- pred->unique_keys, pred->location);
+ pred->unique_keys, exprtype, pred->location);
}
/*
extern Node *makeJsonKeyValue(Node *key, Node *value);
extern Node *makeJsonIsPredicate(Node *expr, JsonFormat *format,
JsonValueType item_type, bool unique_keys,
- int location);
+ Oid exprBaseType, int location);
extern JsonBehavior *makeJsonBehavior(JsonBehaviorType btype, Node *expr,
int location);
extern JsonTablePath *makeJsonTablePath(Const *pathvalue, char *pathname);
JsonFormat *format; /* FORMAT clause, if specified */
JsonValueType item_type; /* JSON item type */
bool unique_keys; /* check key uniqueness? */
+ Oid exprBaseType; /* base type of the subject expression */
ParseLoc location; /* token location, or -1 if unknown */
} JsonIsPredicate;
SELECT NULL::int IS JSON;
ERROR: cannot use type integer in IS JSON predicate
+LINE 1: SELECT NULL::int IS JSON;
+ ^
+-- IS JSON with domain types
+CREATE DOMAIN jd1 AS json CHECK ((VALUE ->'a')::text <> '3');
+CREATE DOMAIN jd2 AS jsonb CHECK ((VALUE ->'a') = '1'::jsonb);
+CREATE DOMAIN jd3 AS text CHECK (VALUE <> 'a');
+CREATE DOMAIN jd4 AS bytea CHECK (VALUE <> '\x61');
+CREATE DOMAIN jd5 AS date CHECK (VALUE <> NULL);
+-- NULLs through domains should return NULL (not error)
+SELECT NULL::jd1 IS JSON, NULL::jd2 IS JSON, NULL::jd3 IS JSON, NULL::jd4 IS JSON;
+ ?column? | ?column? | ?column? | ?column?
+----------+----------+----------+----------
+ | | |
+(1 row)
+
+SELECT NULL::jd1 IS NOT JSON;
+ ?column?
+----------
+
+(1 row)
+
+-- domain over unsupported base type should error
+SELECT NULL::jd5 IS JSON; -- error
+ERROR: cannot use type jd5 in IS JSON predicate
+LINE 1: SELECT NULL::jd5 IS JSON;
+ ^
+SELECT NULL::jd5 IS JSON WITH UNIQUE KEYS; -- error
+ERROR: cannot use type jd5 in IS JSON predicate
+LINE 1: SELECT NULL::jd5 IS JSON WITH UNIQUE KEYS;
+ ^
+-- domain constraint violation during cast
+SELECT a::jd2 IS JSON WITH UNIQUE KEYS as col1 FROM (VALUES('{"a": 1, "a": 2}')) s(a); -- error
+ERROR: value for domain jd2 violates check constraint "jd2_check"
+-- view creation and deparsing with domain IS JSON
+CREATE VIEW domain_isjson AS
+WITH cte(a) AS (VALUES('{"a": 1, "a": 2}'))
+SELECT a::jd1 IS JSON WITH UNIQUE KEYS as jd1,
+ a::jd3 IS JSON WITH UNIQUE KEYS as jd3,
+ a::jd4 IS JSON WITH UNIQUE KEYS as jd4
+FROM cte;
+\sv domain_isjson
+CREATE OR REPLACE VIEW public.domain_isjson AS
+ WITH cte(a) AS (
+ VALUES ('{"a": 1, "a": 2}'::text)
+ )
+ SELECT a::jd1 IS JSON WITH UNIQUE KEYS AS jd1,
+ a::jd3 IS JSON WITH UNIQUE KEYS AS jd3,
+ a::jd4 IS JSON WITH UNIQUE KEYS AS jd4
+ FROM cte
+SELECT * FROM domain_isjson;
+ jd1 | jd3 | jd4
+-----+-----+-----
+ f | f | f
+(1 row)
+
+DROP VIEW domain_isjson;
+DROP DOMAIN jd5, jd4, jd3, jd2, jd1;
SELECT '' IS JSON;
?column?
----------
SELECT NULL::bytea IS JSON;
SELECT NULL::int IS JSON;
+-- IS JSON with domain types
+CREATE DOMAIN jd1 AS json CHECK ((VALUE ->'a')::text <> '3');
+CREATE DOMAIN jd2 AS jsonb CHECK ((VALUE ->'a') = '1'::jsonb);
+CREATE DOMAIN jd3 AS text CHECK (VALUE <> 'a');
+CREATE DOMAIN jd4 AS bytea CHECK (VALUE <> '\x61');
+CREATE DOMAIN jd5 AS date CHECK (VALUE <> NULL);
+
+-- NULLs through domains should return NULL (not error)
+SELECT NULL::jd1 IS JSON, NULL::jd2 IS JSON, NULL::jd3 IS JSON, NULL::jd4 IS JSON;
+SELECT NULL::jd1 IS NOT JSON;
+
+-- domain over unsupported base type should error
+SELECT NULL::jd5 IS JSON; -- error
+SELECT NULL::jd5 IS JSON WITH UNIQUE KEYS; -- error
+
+-- domain constraint violation during cast
+SELECT a::jd2 IS JSON WITH UNIQUE KEYS as col1 FROM (VALUES('{"a": 1, "a": 2}')) s(a); -- error
+
+-- view creation and deparsing with domain IS JSON
+CREATE VIEW domain_isjson AS
+WITH cte(a) AS (VALUES('{"a": 1, "a": 2}'))
+SELECT a::jd1 IS JSON WITH UNIQUE KEYS as jd1,
+ a::jd3 IS JSON WITH UNIQUE KEYS as jd3,
+ a::jd4 IS JSON WITH UNIQUE KEYS as jd4
+FROM cte;
+\sv domain_isjson
+SELECT * FROM domain_isjson;
+
+DROP VIEW domain_isjson;
+DROP DOMAIN jd5, jd4, jd3, jd2, jd1;
+
SELECT '' IS JSON;
SELECT bytea '\x00' IS JSON;