/*
* If the joinrel is parallel-safe, we may be able to consider a
- * partial hash join. However, we can't handle JOIN_UNIQUE_OUTER,
- * because the outer path will be partial, and therefore we won't be
- * able to properly guarantee uniqueness. Also, the resulting path
- * must not be parameterized.
+ * partial hash join.
+ *
+ * However, we can't handle JOIN_UNIQUE_OUTER, because the outer path
+ * will be partial, and therefore we won't be able to properly
+ * guarantee uniqueness.
+ *
+ * Similarly, we can't handle JOIN_RIGHT_SEMI, because the hash table
+ * is either a shared hash table or a private hash table per backend.
+ * In the shared case, there is no concurrency protection for the
+ * match flags, so multiple workers could inspect and set the flags
+ * concurrently, potentially producing incorrect results. In the
+ * private case, each worker has its own copy of the hash table, so no
+ * single process has all the match flags.
+ *
+ * Also, the resulting path must not be parameterized.
*/
if (joinrel->consider_parallel &&
save_jointype != JOIN_UNIQUE_OUTER &&
+ save_jointype != JOIN_RIGHT_SEMI &&
outerrel->partial_pathlist != NIL &&
bms_is_empty(joinrel->lateral_relids))
{
* total inner path will also be parallel-safe, but if not, we'll
* have to search for the cheapest safe, unparameterized inner
* path. If doing JOIN_UNIQUE_INNER, we can't use any alternative
- * inner path. If full, right, right-semi or right-anti join, we
- * can't use parallelism (building the hash table in each backend)
- * because no one process has all the match bits.
+ * inner path. If full, right, or right-anti join, we can't use
+ * parallelism (building the hash table in each backend) because
+ * no one process has all the match bits.
*/
if (save_jointype == JOIN_FULL ||
save_jointype == JOIN_RIGHT ||
- save_jointype == JOIN_RIGHT_SEMI ||
save_jointype == JOIN_RIGHT_ANTI)
cheapest_safe_inner = NULL;
else if (cheapest_total_inner->parallel_safe)
3 | 3 | 4 | 4
(6 rows)
+--
+-- regression test for bug with parallel-hash-right-semi join
+--
+begin;
+-- encourage use of parallel plans
+set local parallel_setup_cost=0;
+set local parallel_tuple_cost=0;
+set local min_parallel_table_scan_size=0;
+set local max_parallel_workers_per_gather=4;
+-- ensure we don't get parallel hash right semi join
+explain (costs off)
+select * from tenk1 t1
+where exists (select 1 from tenk1 t2 where fivethous = t1.fivethous)
+and t1.fivethous < 5;
+ QUERY PLAN
+--------------------------------------------------
+ Gather
+ Workers Planned: 4
+ -> Parallel Hash Semi Join
+ Hash Cond: (t1.fivethous = t2.fivethous)
+ -> Parallel Seq Scan on tenk1 t1
+ Filter: (fivethous < 5)
+ -> Parallel Hash
+ -> Parallel Seq Scan on tenk1 t2
+(8 rows)
+
+rollback;
--
-- regression test for bug #13908 (hash join with skew tuples & nbatch increase)
--
(select t1.a+t3.a from tbl_rs t3) and t2.a < 5)
on true;
+--
+-- regression test for bug with parallel-hash-right-semi join
+--
+
+begin;
+
+-- encourage use of parallel plans
+set local parallel_setup_cost=0;
+set local parallel_tuple_cost=0;
+set local min_parallel_table_scan_size=0;
+set local max_parallel_workers_per_gather=4;
+
+-- ensure we don't get parallel hash right semi join
+explain (costs off)
+select * from tenk1 t1
+where exists (select 1 from tenk1 t2 where fivethous = t1.fivethous)
+and t1.fivethous < 5;
+
+rollback;
+
--
-- regression test for bug #13908 (hash join with skew tuples & nbatch increase)
--