]> granicus.if.org Git - postgresql/commitdiff
Throw error in jsonb_path_match() when result is not single boolean
authorAlexander Korotkov <akorotkov@postgresql.org>
Mon, 1 Apr 2019 15:09:20 +0000 (18:09 +0300)
committerAlexander Korotkov <akorotkov@postgresql.org>
Mon, 1 Apr 2019 15:09:20 +0000 (18:09 +0300)
jsonb_path_match() checks if jsonb document matches jsonpath query.  Therefore,
jsonpath query should return single boolean.  Currently, if result of jsonpath
is not a single boolean, NULL is returned independently whether silent mode
is on or off.  But that appears to be wrong when silent mode is off.  This
commit makes jsonb_path_match() throw an error in this case.

Author: Nikita Glukhov

src/backend/utils/adt/jsonpath_exec.c
src/test/regress/expected/jsonb_jsonpath.out
src/test/regress/sql/jsonb_jsonpath.sql

index c07225749e5620841f6345069d413cce641c320a..074cea24ae31c2aeb2b6f120d11ccf52f7724427 100644 (file)
@@ -320,7 +320,6 @@ jsonb_path_match(PG_FUNCTION_ARGS)
 {
        Jsonb      *jb = PG_GETARG_JSONB_P(0);
        JsonPath   *jp = PG_GETARG_JSONPATH_P(1);
-       JsonbValue *jbv;
        JsonValueList found = {0};
        Jsonb      *vars = NULL;
        bool            silent = true;
@@ -333,18 +332,27 @@ jsonb_path_match(PG_FUNCTION_ARGS)
 
        (void) executeJsonPath(jp, vars, jb, !silent, &found);
 
-       if (JsonValueListLength(&found) < 1)
-               PG_RETURN_NULL();
-
-       jbv = JsonValueListHead(&found);
-
        PG_FREE_IF_COPY(jb, 0);
        PG_FREE_IF_COPY(jp, 1);
 
-       if (jbv->type != jbvBool)
-               PG_RETURN_NULL();
+       if (JsonValueListLength(&found) == 1)
+       {
+               JsonbValue *jbv = JsonValueListHead(&found);
+
+               if (jbv->type == jbvBool)
+                       PG_RETURN_BOOL(jbv->val.boolean);
+
+               if (jbv->type == jbvNull)
+                       PG_RETURN_NULL();
+       }
+
+       if (!silent)
+               ereport(ERROR,
+                               (errcode(ERRCODE_SINGLETON_JSON_ITEM_REQUIRED),
+                                errmsg(ERRMSG_SINGLETON_JSON_ITEM_REQUIRED),
+                                errdetail("expression should return a singleton boolean")));
 
-       PG_RETURN_BOOL(jbv->val.boolean);
+       PG_RETURN_NULL();
 }
 
 /*
index 4a84d9157fa3a58bf55880747fdf511cd7658a53..49a857bca626110ef57209145f6c2c589ee405c9 100644 (file)
@@ -1769,6 +1769,57 @@ SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.
  f
 (1 row)
 
+SELECT jsonb_path_match('true', '$', silent => false);
+ jsonb_path_match 
+------------------
+ t
+(1 row)
+
+SELECT jsonb_path_match('false', '$', silent => false);
+ jsonb_path_match 
+------------------
+ f
+(1 row)
+
+SELECT jsonb_path_match('null', '$', silent => false);
+ jsonb_path_match 
+------------------
+(1 row)
+
+SELECT jsonb_path_match('1', '$', silent => true);
+ jsonb_path_match 
+------------------
+(1 row)
+
+SELECT jsonb_path_match('1', '$', silent => false);
+ERROR:  singleton SQL/JSON item required
+DETAIL:  expression should return a singleton boolean
+SELECT jsonb_path_match('"a"', '$', silent => false);
+ERROR:  singleton SQL/JSON item required
+DETAIL:  expression should return a singleton boolean
+SELECT jsonb_path_match('{}', '$', silent => false);
+ERROR:  singleton SQL/JSON item required
+DETAIL:  expression should return a singleton boolean
+SELECT jsonb_path_match('[true]', '$', silent => false);
+ERROR:  singleton SQL/JSON item required
+DETAIL:  expression should return a singleton boolean
+SELECT jsonb_path_match('{}', 'lax $.a', silent => false);
+ERROR:  singleton SQL/JSON item required
+DETAIL:  expression should return a singleton boolean
+SELECT jsonb_path_match('{}', 'strict $.a', silent => false);
+ERROR:  SQL/JSON member not found
+DETAIL:  JSON object does not contain key "a"
+SELECT jsonb_path_match('{}', 'strict $.a', silent => true);
+ jsonb_path_match 
+------------------
+(1 row)
+
+SELECT jsonb_path_match('[true, true]', '$[*]', silent => false);
+ERROR:  singleton SQL/JSON item required
+DETAIL:  expression should return a singleton boolean
 SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 1';
  ?column? 
 ----------
index 28c861bb179d4823b8f0c6e213b46dad3d5874d5..464ff94be3774f4f5e5daab37613f112e5e94651 100644 (file)
@@ -366,6 +366,18 @@ SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}]', '$[*].a ? (@ > 1)');
 SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.a > $min && @.a < $max)', vars => '{"min": 1, "max": 4}');
 SELECT jsonb_path_exists('[{"a": 1}, {"a": 2}, {"a": 3}, {"a": 5}]', '$[*] ? (@.a > $min && @.a < $max)', vars => '{"min": 3, "max": 4}');
 
+SELECT jsonb_path_match('true', '$', silent => false);
+SELECT jsonb_path_match('false', '$', silent => false);
+SELECT jsonb_path_match('null', '$', silent => false);
+SELECT jsonb_path_match('1', '$', silent => true);
+SELECT jsonb_path_match('1', '$', silent => false);
+SELECT jsonb_path_match('"a"', '$', silent => false);
+SELECT jsonb_path_match('{}', '$', silent => false);
+SELECT jsonb_path_match('[true]', '$', silent => false);
+SELECT jsonb_path_match('{}', 'lax $.a', silent => false);
+SELECT jsonb_path_match('{}', 'strict $.a', silent => false);
+SELECT jsonb_path_match('{}', 'strict $.a', silent => true);
+SELECT jsonb_path_match('[true, true]', '$[*]', silent => false);
 SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 1';
 SELECT jsonb '[{"a": 1}, {"a": 2}]' @@ '$[*].a > 2';
 SELECT jsonb_path_match('[{"a": 1}, {"a": 2}]', '$[*].a > 1');