commit a3bd6a3c34569cd12be7259947bbef2f52cc99bc
Author: Alexander Korotkov <akorotkov@postgresql.org>
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)';
