commit a3bd6a3c34569cd12be7259947bbef2f52cc99bc Author: Alexander Korotkov Date: Wed Jan 20 20:03:05 2021 +0300 Initial. Reported-by: Bug: Discussion: Author: Reviewed-by: Tested-by: Backpatch-through: diff --git a/src/backend/utils/adt/jsonpath_exec.c b/src/backend/utils/adt/jsonpath_exec.c index 4d185c27b47..5d7b0752bc0 100644 --- a/src/backend/utils/adt/jsonpath_exec.c +++ b/src/backend/utils/adt/jsonpath_exec.c @@ -198,7 +198,8 @@ static JsonPathBool executeNestedBoolItem(JsonPathExecContext *cxt, static JsonPathExecResult executeAnyItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbContainer *jbc, JsonValueList *found, uint32 level, uint32 first, uint32 last, - bool ignoreStructuralErrors, bool unwrapNext); + bool ignoreStructuralErrors, bool unwrapNext, + bool strictMode); static JsonPathBool executePredicate(JsonPathExecContext *cxt, JsonPathItem *pred, JsonPathItem *larg, JsonPathItem *rarg, JsonbValue *jb, bool unwrapRightArg, @@ -860,7 +861,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, return executeAnyItem (cxt, hasNext ? &elem : NULL, jb->val.binary.data, found, 1, 1, 1, - false, jspAutoUnwrap(cxt)); + false, jspAutoUnwrap(cxt), false); } else if (unwrap && JsonbType(jb) == jbvArray) return executeItemUnwrapTargetArray(cxt, jsp, jb, found, false); @@ -926,12 +927,16 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, if (jsp->content.anybounds.first == 0) { bool savedIgnoreStructuralErrors; + bool savedLaxMode; savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors; + savedLaxMode = cxt->laxMode; cxt->ignoreStructuralErrors = true; + cxt->laxMode = false; res = executeNextItem(cxt, jsp, &elem, jb, found, true); cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors; + cxt->laxMode = savedLaxMode; if (res == jperOk && !found) break; @@ -944,7 +949,7 @@ executeItemOptUnwrapTarget(JsonPathExecContext *cxt, JsonPathItem *jsp, 1, jsp->content.anybounds.first, jsp->content.anybounds.last, - true, jspAutoUnwrap(cxt)); + true, false, true); break; } @@ -1128,7 +1133,7 @@ executeItemUnwrapTargetArray(JsonPathExecContext *cxt, JsonPathItem *jsp, return executeAnyItem (cxt, jsp, jb->val.binary.data, found, 1, 1, 1, - false, unwrapElements); + false, unwrapElements, false); } /* @@ -1375,7 +1380,7 @@ executeNestedBoolItem(JsonPathExecContext *cxt, JsonPathItem *jsp, static JsonPathExecResult executeAnyItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbContainer *jbc, JsonValueList *found, uint32 level, uint32 first, uint32 last, - bool ignoreStructuralErrors, bool unwrapNext) + bool ignoreStructuralErrors, bool unwrapNext, bool strictMode) { JsonPathExecResult res = jperNotFound; JsonbIterator *it; @@ -1410,17 +1415,18 @@ executeAnyItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbContainer *jbc, /* check expression */ if (jsp) { - if (ignoreStructuralErrors) - { - bool savedIgnoreStructuralErrors; + bool savedIgnoreStructuralErrors; + bool savedLaxMode; - savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors; + savedIgnoreStructuralErrors = cxt->ignoreStructuralErrors; + savedLaxMode = cxt->laxMode; + if (ignoreStructuralErrors) cxt->ignoreStructuralErrors = true; - res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext); - cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors; - } - else - res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext); + if (strictMode) + cxt->laxMode = false; + res = executeItemOptUnwrapTarget(cxt, jsp, &v, found, unwrapNext); + cxt->ignoreStructuralErrors = savedIgnoreStructuralErrors; + cxt->laxMode = savedLaxMode; if (jperIsError(res)) break; @@ -1439,7 +1445,7 @@ executeAnyItem(JsonPathExecContext *cxt, JsonPathItem *jsp, JsonbContainer *jbc, res = executeAnyItem (cxt, jsp, v.val.binary.data, found, level + 1, first, last, - ignoreStructuralErrors, unwrapNext); + ignoreStructuralErrors, unwrapNext, strictMode); if (jperIsError(res)) break; diff --git a/src/test/regress/expected/jsonb_jsonpath.out b/src/test/regress/expected/jsonb_jsonpath.out index 508ddd797ed..d0dfa4f076b 100644 --- a/src/test/regress/expected/jsonb_jsonpath.out +++ b/src/test/regress/expected/jsonb_jsonpath.out @@ -707,6 +707,20 @@ select jsonb_path_query('{"a": {"c": {"b": 1}}}', 'lax $.**{2 to 3}.b ? (@ > 0)' 1 (1 row) +select jsonb_path_query('[{"a": 1, "b": [{"a": 2}]}]', 'lax $.**.a'); + jsonb_path_query +------------------ + 1 + 2 +(2 rows) + +select jsonb_path_query('[{"a": 1, "b": [{"a": 2}]}]', 'strict $.**.a'); + jsonb_path_query +------------------ + 1 + 2 +(2 rows) + select jsonb '{"a": {"b": 1}}' @? '$.**.b ? ( @ > 0)'; ?column? ---------- diff --git a/src/test/regress/sql/jsonb_jsonpath.sql b/src/test/regress/sql/jsonb_jsonpath.sql index 60f73cb0590..d8d89d73739 100644 --- a/src/test/regress/sql/jsonb_jsonpath.sql +++ b/src/test/regress/sql/jsonb_jsonpath.sql @@ -136,6 +136,8 @@ select jsonb_path_query('{"a": {"c": {"b": 1}}}', 'lax $.**{0 to last}.b ? (@ > select jsonb_path_query('{"a": {"c": {"b": 1}}}', 'lax $.**{1 to last}.b ? (@ > 0)'); select jsonb_path_query('{"a": {"c": {"b": 1}}}', 'lax $.**{1 to 2}.b ? (@ > 0)'); select jsonb_path_query('{"a": {"c": {"b": 1}}}', 'lax $.**{2 to 3}.b ? (@ > 0)'); +select jsonb_path_query('[{"a": 1, "b": [{"a": 2}]}]', 'lax $.**.a'); +select jsonb_path_query('[{"a": 1, "b": [{"a": 2}]}]', 'strict $.**.a'); select jsonb '{"a": {"b": 1}}' @? '$.**.b ? ( @ > 0)'; select jsonb '{"a": {"b": 1}}' @? '$.**{0}.b ? ( @ > 0)';