prohibit_parallel_limit_subselect_v1.patch

application/octet-stream

Filename: prohibit_parallel_limit_subselect_v1.patch
Type: application/octet-stream
Part: 0
Message: Re: BUG #15324: Non-deterministic behaviour from parallelised sub-query

Patch

Same data as JSON: GET /api/v1/attachments/:id/patch the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes. API reference →
Format: unified
Series: patch v1
File+
src/backend/optimizer/util/clauses.c 36 1
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index a04ad6e99e6..aecb6dfa72b 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -1208,12 +1208,25 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
 
 	/*
 	 * Really we should not see SubLink during a max_interesting == restricted
-	 * scan, but if we do, return true.
+	 * scan, but if we do, return true.  Also, we can't push sub-select
+	 * containing LIMIT/OFFSET to workers as that can change the results
+	 * depending on what is beneath LIMIT node.  So, consider that case as
+	 * parallel-unsafe.
 	 */
 	else if (IsA(node, SubLink))
 	{
+		Query	   *subquery;
+		SubLink *sublink = (SubLink *) node;
+
 		if (max_parallel_hazard_test(PROPARALLEL_RESTRICTED, context))
 			return true;
+
+		subquery = castNode(Query, sublink->subselect);
+		if (subquery->limitOffset || subquery->limitCount)
+		{
+			context->max_hazard = PROPARALLEL_UNSAFE;
+			return true;
+		}
 	}
 
 	/*
@@ -1274,6 +1287,7 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
 	else if (IsA(node, Query))
 	{
 		Query	   *query = (Query *) node;
+		ListCell   *rt;
 
 		/* SELECT FOR UPDATE/SHARE must be treated as unsafe */
 		if (query->rowMarks != NULL)
@@ -1282,6 +1296,27 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
 			return true;
 		}
 
+		/*
+		 * We can't push sub-select containing LIMIT/OFFSET to workers as that
+		 * can change the results depending on what is beneath LIMIT node.
+		 * So, consider that case as parallel-unsafe.
+		 */
+		foreach(rt, query->rtable)
+		{
+			RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
+
+			if (rte->rtekind == RTE_SUBQUERY)
+			{
+				Query	*subquery = castNode(Query, rte->subquery);
+
+				if (subquery->limitOffset || subquery->limitCount)
+				{
+					context->max_hazard = PROPARALLEL_UNSAFE;
+					return true;
+				}
+			}
+		}
+
 		/* Recurse into subselects */
 		return query_tree_walker(query,
 								 max_parallel_hazard_walker,