From 1365e36ba86871094437b2907b1505b78055ec47 Mon Sep 17 00:00:00 2001 From: Richard Guo Date: Tue, 18 Apr 2023 16:25:36 +0800 Subject: [PATCH v3] Support "Right Semi Join" plan shapes --- src/backend/commands/explain.c | 3 + src/backend/executor/nodeHashjoin.c | 14 +- src/backend/optimizer/path/joinpath.c | 45 ++-- src/backend/optimizer/path/joinrels.c | 3 + src/backend/optimizer/path/pathkeys.c | 3 + src/include/nodes/nodes.h | 1 + src/test/regress/expected/join.out | 20 +- src/test/regress/expected/partition_join.out | 216 +++++++++--------- src/test/regress/expected/select_parallel.out | 32 +-- src/test/regress/expected/updatable_views.out | 6 +- 10 files changed, 194 insertions(+), 149 deletions(-) diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c index f1d71bc54e..40b4765a04 100644 --- a/src/backend/commands/explain.c +++ b/src/backend/commands/explain.c @@ -1569,6 +1569,9 @@ ExplainNode(PlanState *planstate, List *ancestors, case JOIN_ANTI: jointype = "Anti"; break; + case JOIN_RIGHT_SEMI: + jointype = "Right Semi"; + break; case JOIN_RIGHT_ANTI: jointype = "Right Anti"; break; diff --git a/src/backend/executor/nodeHashjoin.c b/src/backend/executor/nodeHashjoin.c index 25a2d78f15..8a95f51a33 100644 --- a/src/backend/executor/nodeHashjoin.c +++ b/src/backend/executor/nodeHashjoin.c @@ -534,6 +534,14 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel) } } + /* + * In a right-semijoin, we only need the first match for each + * inner tuple. + */ + if (node->js.jointype == JOIN_RIGHT_SEMI && + HeapTupleHeaderHasMatch(HJTUPLE_MINTUPLE(node->hj_CurTuple))) + continue; + /* * We've got a match, but still need to test non-hashed quals. * ExecScanHashBucket already set up all the state needed to @@ -552,8 +560,9 @@ ExecHashJoinImpl(PlanState *pstate, bool parallel) /* - * This is really only needed if HJ_FILL_INNER(node), but - * we'll avoid the branch and just set it always. + * This is really only needed if HJ_FILL_INNER(node) or + * it's a right-semijoin, but we'll avoid the branch and + * just set it always. */ if (!HeapTupleHeaderHasMatch(HJTUPLE_MINTUPLE(node->hj_CurTuple))) HeapTupleHeaderSetMatch(HJTUPLE_MINTUPLE(node->hj_CurTuple)); @@ -780,6 +789,7 @@ ExecInitHashJoin(HashJoin *node, EState *estate, int eflags) { case JOIN_INNER: case JOIN_SEMI: + case JOIN_RIGHT_SEMI: break; case JOIN_LEFT: case JOIN_ANTI: diff --git a/src/backend/optimizer/path/joinpath.c b/src/backend/optimizer/path/joinpath.c index b2916ad690..31cb9b814b 100644 --- a/src/backend/optimizer/path/joinpath.c +++ b/src/backend/optimizer/path/joinpath.c @@ -287,8 +287,8 @@ add_paths_to_joinrel(PlannerInfo *root, * sorted. This includes both nestloops and mergejoins where the outer * path is already ordered. Again, skip this if we can't mergejoin. * (That's okay because we know that nestloop can't handle - * right/right-anti/full joins at all, so it wouldn't work in the - * prohibited cases either.) + * right/right-anti/right-semi/full joins at all, so it wouldn't work in + * the prohibited cases either.) */ if (mergejoin_allowed) match_unsorted_outer(root, joinrel, outerrel, innerrel, @@ -1720,6 +1720,13 @@ match_unsorted_outer(PlannerInfo *root, Path *matpath = NULL; ListCell *lc1; + /* + * For now we do not support RIGHT_SEMI join in mergejoin or nestloop + * join. + */ + if (jointype == JOIN_RIGHT_SEMI) + return; + /* * Nestloop only supports inner, left, semi, and anti joins. Also, if we * are doing a right, right-anti or full mergejoin, we must use *all* the @@ -2289,13 +2296,14 @@ hash_inner_and_outer(PlannerInfo *root, * 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, 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, right-anti or right-semi 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_ANTI) + save_jointype == JOIN_RIGHT_ANTI || + save_jointype == JOIN_RIGHT_SEMI) cheapest_safe_inner = NULL; else if (cheapest_total_inner->parallel_safe) cheapest_safe_inner = cheapest_total_inner; @@ -2318,14 +2326,14 @@ hash_inner_and_outer(PlannerInfo *root, * Select mergejoin clauses that are usable for a particular join. * Returns a list of RestrictInfo nodes for those clauses. * - * *mergejoin_allowed is normally set to true, but it is set to false if - * this is a right/right-anti/full join and there are nonmergejoinable join - * clauses. The executor's mergejoin machinery cannot handle such cases, so - * we have to avoid generating a mergejoin plan. (Note that this flag does - * NOT consider whether there are actually any mergejoinable clauses. This is - * correct because in some cases we need to build a clauseless mergejoin. - * Simply returning NIL is therefore not enough to distinguish safe from - * unsafe cases.) + * *mergejoin_allowed is normally set to true, but it is set to false if this + * is a right-semi join, or this is a right/right-anti/full join and there are + * nonmergejoinable join clauses. The executor's mergejoin machinery cannot + * handle such cases, so we have to avoid generating a mergejoin plan. (Note + * that this flag does NOT consider whether there are actually any + * mergejoinable clauses. This is correct because in some cases we need to + * build a clauseless mergejoin. Simply returning NIL is therefore not enough + * to distinguish safe from unsafe cases.) * * We also mark each selected RestrictInfo to show which side is currently * being considered as outer. These are transient markings that are only @@ -2349,6 +2357,15 @@ select_mergejoin_clauses(PlannerInfo *root, bool have_nonmergeable_joinclause = false; ListCell *l; + /* + * For now we do not support RIGHT_SEMI join in mergejoin. + */ + if (jointype == JOIN_RIGHT_SEMI) + { + *mergejoin_allowed = false; + return NIL; + } + foreach(l, restrictlist) { RestrictInfo *restrictinfo = (RestrictInfo *) lfirst(l); diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c index d03ace50a1..0f165bb224 100644 --- a/src/backend/optimizer/path/joinrels.c +++ b/src/backend/optimizer/path/joinrels.c @@ -973,6 +973,9 @@ populate_joinrel_with_paths(PlannerInfo *root, RelOptInfo *rel1, add_paths_to_joinrel(root, joinrel, rel1, rel2, JOIN_SEMI, sjinfo, restrictlist); + add_paths_to_joinrel(root, joinrel, rel2, rel1, + JOIN_RIGHT_SEMI, sjinfo, + restrictlist); } /* diff --git a/src/backend/optimizer/path/pathkeys.c b/src/backend/optimizer/path/pathkeys.c index fdb60aaa8d..476f286065 100644 --- a/src/backend/optimizer/path/pathkeys.c +++ b/src/backend/optimizer/path/pathkeys.c @@ -1097,6 +1097,9 @@ build_join_pathkeys(PlannerInfo *root, JoinType jointype, List *outer_pathkeys) { + /* RIGHT_SEMI should not come here */ + Assert(jointype != JOIN_RIGHT_SEMI); + if (jointype == JOIN_FULL || jointype == JOIN_RIGHT || jointype == JOIN_RIGHT_ANTI) diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 4c32682e4c..ccef7b0d0c 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.h @@ -317,6 +317,7 @@ typedef enum JoinType */ JOIN_SEMI, /* 1 copy of each LHS row that has match(es) */ JOIN_ANTI, /* 1 copy of each LHS row that has no match */ + JOIN_RIGHT_SEMI, /* 1 copy of each RHS row that has match(es) */ JOIN_RIGHT_ANTI, /* 1 copy of each RHS row that has no match */ /* diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out index 446959e3c5..0cac52138e 100644 --- a/src/test/regress/expected/join.out +++ b/src/test/regress/expected/join.out @@ -1909,18 +1909,18 @@ select * from int4_tbl i4, tenk1 a where exists(select * from tenk1 b where a.twothousand = b.twothousand and a.fivethous <> b.fivethous) and i4.f1 = a.tenthous; - QUERY PLAN ----------------------------------------------- - Hash Semi Join - Hash Cond: (a.twothousand = b.twothousand) + QUERY PLAN +------------------------------------------------- + Hash Right Semi Join + Hash Cond: (b.twothousand = a.twothousand) Join Filter: (a.fivethous <> b.fivethous) - -> Hash Join - Hash Cond: (a.tenthous = i4.f1) - -> Seq Scan on tenk1 a - -> Hash - -> Seq Scan on int4_tbl i4 + -> Seq Scan on tenk1 b -> Hash - -> Seq Scan on tenk1 b + -> Hash Join + Hash Cond: (a.tenthous = i4.f1) + -> Seq Scan on tenk1 a + -> Hash + -> Seq Scan on int4_tbl i4 (10 rows) -- diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out index 6560fe2416..26da5692cd 100644 --- a/src/test/regress/expected/partition_join.out +++ b/src/test/regress/expected/partition_join.out @@ -2375,24 +2375,24 @@ SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a Sort Sort Key: t1.a -> Append - -> Hash Semi Join - Hash Cond: (t1_1.a = t2_1.b) - -> Seq Scan on prt1_adv_p1 t1_1 - Filter: (b = 0) + -> Hash Right Semi Join + Hash Cond: (t2_1.b = t1_1.a) + -> Seq Scan on prt2_adv_p1 t2_1 -> Hash - -> Seq Scan on prt2_adv_p1 t2_1 - -> Hash Semi Join - Hash Cond: (t1_2.a = t2_2.b) - -> Seq Scan on prt1_adv_p2 t1_2 - Filter: (b = 0) + -> Seq Scan on prt1_adv_p1 t1_1 + Filter: (b = 0) + -> Hash Right Semi Join + Hash Cond: (t2_2.b = t1_2.a) + -> Seq Scan on prt2_adv_p2 t2_2 -> Hash - -> Seq Scan on prt2_adv_p2 t2_2 - -> Hash Semi Join - Hash Cond: (t1_3.a = t2_3.b) - -> Seq Scan on prt1_adv_p3 t1_3 - Filter: (b = 0) + -> Seq Scan on prt1_adv_p2 t1_2 + Filter: (b = 0) + -> Hash Right Semi Join + Hash Cond: (t2_3.b = t1_3.a) + -> Seq Scan on prt2_adv_p3 t2_3 -> Hash - -> Seq Scan on prt2_adv_p3 t2_3 + -> Seq Scan on prt1_adv_p3 t1_3 + Filter: (b = 0) (21 rows) SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a; @@ -2584,24 +2584,24 @@ SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a Sort Sort Key: t1.a -> Append - -> Hash Semi Join - Hash Cond: (t1_1.a = t2_1.b) - -> Seq Scan on prt1_adv_p1 t1_1 - Filter: (b = 0) + -> Hash Right Semi Join + Hash Cond: (t2_1.b = t1_1.a) + -> Seq Scan on prt2_adv_p1 t2_1 -> Hash - -> Seq Scan on prt2_adv_p1 t2_1 - -> Hash Semi Join - Hash Cond: (t1_2.a = t2_2.b) - -> Seq Scan on prt1_adv_p2 t1_2 - Filter: (b = 0) + -> Seq Scan on prt1_adv_p1 t1_1 + Filter: (b = 0) + -> Hash Right Semi Join + Hash Cond: (t2_2.b = t1_2.a) + -> Seq Scan on prt2_adv_p2 t2_2 -> Hash - -> Seq Scan on prt2_adv_p2 t2_2 - -> Hash Semi Join - Hash Cond: (t1_3.a = t2_3.b) - -> Seq Scan on prt1_adv_p3 t1_3 - Filter: (b = 0) + -> Seq Scan on prt1_adv_p2 t1_2 + Filter: (b = 0) + -> Hash Right Semi Join + Hash Cond: (t2_3.b = t1_3.a) + -> Seq Scan on prt2_adv_p3 t2_3 -> Hash - -> Seq Scan on prt2_adv_p3 t2_3 + -> Seq Scan on prt1_adv_p3 t1_3 + Filter: (b = 0) (21 rows) SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a; @@ -2868,25 +2868,25 @@ SELECT t1.a, t1.c, t2.b, t2.c FROM prt1_adv t1 INNER JOIN prt2_adv t2 ON (t1.a = -- semi join EXPLAIN (COSTS OFF) SELECT t1.* FROM prt1_adv t1 WHERE EXISTS (SELECT 1 FROM prt2_adv t2 WHERE t1.a = t2.b) AND t1.b = 0 ORDER BY t1.a; - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +------------------------------------------------------ Sort Sort Key: t1.a - -> Hash Semi Join - Hash Cond: (t1.a = t2.b) + -> Hash Right Semi Join + Hash Cond: (t2.b = t1.a) -> Append - -> Seq Scan on prt1_adv_p1 t1_1 - Filter: (b = 0) - -> Seq Scan on prt1_adv_p2 t1_2 - Filter: (b = 0) - -> Seq Scan on prt1_adv_p3 t1_3 - Filter: (b = 0) + -> Seq Scan on prt2_adv_p1 t2_1 + -> Seq Scan on prt2_adv_p2 t2_2 + -> Seq Scan on prt2_adv_p3_1 t2_3 + -> Seq Scan on prt2_adv_p3_2 t2_4 -> Hash -> Append - -> Seq Scan on prt2_adv_p1 t2_1 - -> Seq Scan on prt2_adv_p2 t2_2 - -> Seq Scan on prt2_adv_p3_1 t2_3 - -> Seq Scan on prt2_adv_p3_2 t2_4 + -> Seq Scan on prt1_adv_p1 t1_1 + Filter: (b = 0) + -> Seq Scan on prt1_adv_p2 t1_2 + Filter: (b = 0) + -> Seq Scan on prt1_adv_p3 t1_3 + Filter: (b = 0) (17 rows) -- left join @@ -3265,27 +3265,30 @@ SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = -- semi join EXPLAIN (COSTS OFF) SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a; - QUERY PLAN ----------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------- Sort Sort Key: t1.a -> Append - -> Nested Loop Semi Join - Join Filter: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c)) - -> Seq Scan on plt1_adv_p1 t1_1 - Filter: (b < 10) + -> Hash Right Semi Join + Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c)) -> Seq Scan on plt2_adv_p1 t2_1 - -> Nested Loop Semi Join - Join Filter: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c)) - -> Seq Scan on plt1_adv_p2 t1_2 - Filter: (b < 10) + -> Hash + -> Seq Scan on plt1_adv_p1 t1_1 + Filter: (b < 10) + -> Hash Right Semi Join + Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c)) -> Seq Scan on plt2_adv_p2 t2_2 - -> Nested Loop Semi Join - Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c)) - -> Seq Scan on plt1_adv_p3 t1_3 - Filter: (b < 10) + -> Hash + -> Seq Scan on plt1_adv_p2 t1_2 + Filter: (b < 10) + -> Hash Right Semi Join + Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c)) -> Seq Scan on plt2_adv_p3 t2_3 -(18 rows) + -> Hash + -> Seq Scan on plt1_adv_p3 t1_3 + Filter: (b < 10) +(21 rows) SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a; a | b | c @@ -3455,27 +3458,30 @@ SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = -- semi join EXPLAIN (COSTS OFF) SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a; - QUERY PLAN ----------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------- Sort Sort Key: t1.a -> Append - -> Nested Loop Semi Join - Join Filter: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c)) - -> Seq Scan on plt1_adv_p1 t1_1 - Filter: (b < 10) + -> Hash Right Semi Join + Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c)) -> Seq Scan on plt2_adv_p1 t2_1 - -> Nested Loop Semi Join - Join Filter: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c)) - -> Seq Scan on plt1_adv_p2 t1_2 - Filter: (b < 10) + -> Hash + -> Seq Scan on plt1_adv_p1 t1_1 + Filter: (b < 10) + -> Hash Right Semi Join + Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c)) -> Seq Scan on plt2_adv_p2 t2_2 - -> Nested Loop Semi Join - Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c)) - -> Seq Scan on plt1_adv_p3 t1_3 - Filter: (b < 10) + -> Hash + -> Seq Scan on plt1_adv_p2 t1_2 + Filter: (b < 10) + -> Hash Right Semi Join + Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c)) -> Seq Scan on plt2_adv_p3 t2_3 -(18 rows) + -> Hash + -> Seq Scan on plt1_adv_p3 t1_3 + Filter: (b < 10) +(21 rows) SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a; a | b | c @@ -3671,25 +3677,25 @@ SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = -- semi join EXPLAIN (COSTS OFF) SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a; - QUERY PLAN --------------------------------------------------------- + QUERY PLAN +------------------------------------------------------ Sort Sort Key: t1.a - -> Hash Semi Join - Hash Cond: ((t1.a = t2.a) AND (t1.c = t2.c)) + -> Hash Right Semi Join + Hash Cond: ((t2.a = t1.a) AND (t2.c = t1.c)) -> Append - -> Seq Scan on plt1_adv_p1 t1_1 - Filter: (b < 10) - -> Seq Scan on plt1_adv_p2 t1_2 - Filter: (b < 10) - -> Seq Scan on plt1_adv_p3 t1_3 - Filter: (b < 10) + -> Seq Scan on plt2_adv_p1 t2_1 + -> Seq Scan on plt2_adv_p2_1 t2_2 + -> Seq Scan on plt2_adv_p2_2 t2_3 + -> Seq Scan on plt2_adv_p3 t2_4 -> Hash -> Append - -> Seq Scan on plt2_adv_p1 t2_1 - -> Seq Scan on plt2_adv_p2_1 t2_2 - -> Seq Scan on plt2_adv_p2_2 t2_3 - -> Seq Scan on plt2_adv_p3 t2_4 + -> Seq Scan on plt1_adv_p1 t1_1 + Filter: (b < 10) + -> Seq Scan on plt1_adv_p2 t1_2 + Filter: (b < 10) + -> Seq Scan on plt1_adv_p3 t1_3 + Filter: (b < 10) (17 rows) -- left join @@ -3819,28 +3825,30 @@ SELECT t1.a, t1.c, t2.a, t2.c FROM plt1_adv t1 INNER JOIN plt2_adv t2 ON (t1.a = -- semi join EXPLAIN (COSTS OFF) SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a; - QUERY PLAN ----------------------------------------------------------------------- + QUERY PLAN +-------------------------------------------------------------------- Sort Sort Key: t1.a -> Append - -> Hash Semi Join - Hash Cond: ((t1_1.a = t2_1.a) AND (t1_1.c = t2_1.c)) - -> Seq Scan on plt1_adv_p1_null t1_1 - Filter: (b < 10) + -> Hash Right Semi Join + Hash Cond: ((t2_1.a = t1_1.a) AND (t2_1.c = t1_1.c)) + -> Seq Scan on plt2_adv_p1 t2_1 -> Hash - -> Seq Scan on plt2_adv_p1 t2_1 - -> Nested Loop Semi Join - Join Filter: ((t1_2.a = t2_2.a) AND (t1_2.c = t2_2.c)) - -> Seq Scan on plt1_adv_p2 t1_2 - Filter: (b < 10) + -> Seq Scan on plt1_adv_p1_null t1_1 + Filter: (b < 10) + -> Hash Right Semi Join + Hash Cond: ((t2_2.a = t1_2.a) AND (t2_2.c = t1_2.c)) -> Seq Scan on plt2_adv_p2 t2_2 - -> Nested Loop Semi Join - Join Filter: ((t1_3.a = t2_3.a) AND (t1_3.c = t2_3.c)) - -> Seq Scan on plt1_adv_p3 t1_3 - Filter: (b < 10) + -> Hash + -> Seq Scan on plt1_adv_p2 t1_2 + Filter: (b < 10) + -> Hash Right Semi Join + Hash Cond: ((t2_3.a = t1_3.a) AND (t2_3.c = t1_3.c)) -> Seq Scan on plt2_adv_p3_null t2_3 -(19 rows) + -> Hash + -> Seq Scan on plt1_adv_p3 t1_3 + Filter: (b < 10) +(21 rows) SELECT t1.* FROM plt1_adv t1 WHERE EXISTS (SELECT 1 FROM plt2_adv t2 WHERE t1.a = t2.a AND t1.c = t2.c) AND t1.b < 10 ORDER BY t1.a; a | b | c diff --git a/src/test/regress/expected/select_parallel.out b/src/test/regress/expected/select_parallel.out index d88353d496..d524989f25 100644 --- a/src/test/regress/expected/select_parallel.out +++ b/src/test/regress/expected/select_parallel.out @@ -999,26 +999,26 @@ reset role; explain (costs off, verbose) select count(*) from tenk1 a where (unique1, two) in (select unique1, row_number() over() from tenk1 b); - QUERY PLAN ----------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------- Aggregate Output: count(*) - -> Hash Semi Join - Hash Cond: ((a.unique1 = b.unique1) AND (a.two = (row_number() OVER (?)))) - -> Gather + -> Hash Right Semi Join + Hash Cond: ((b.unique1 = a.unique1) AND ((row_number() OVER (?)) = a.two)) + -> WindowAgg + Output: b.unique1, row_number() OVER (?) + -> Gather + Output: b.unique1 + Workers Planned: 4 + -> Parallel Index Only Scan using tenk1_unique1 on public.tenk1 b + Output: b.unique1 + -> Hash Output: a.unique1, a.two - Workers Planned: 4 - -> Parallel Seq Scan on public.tenk1 a + -> Gather Output: a.unique1, a.two - -> Hash - Output: b.unique1, (row_number() OVER (?)) - -> WindowAgg - Output: b.unique1, row_number() OVER (?) - -> Gather - Output: b.unique1 - Workers Planned: 4 - -> Parallel Index Only Scan using tenk1_unique1 on public.tenk1 b - Output: b.unique1 + Workers Planned: 4 + -> Parallel Seq Scan on public.tenk1 a + Output: a.unique1, a.two (18 rows) -- LIMIT/OFFSET within sub-selects can't be pushed to workers. diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out index a73c1f90c4..c9951687c2 100644 --- a/src/test/regress/expected/updatable_views.out +++ b/src/test/regress/expected/updatable_views.out @@ -2672,10 +2672,10 @@ NOTICE: snooped value: 8 SELECT * FROM v1 WHERE b=8; a | b | c | d ---+---+------+------ - 9 | 8 | t1 | t11d - 9 | 8 | t11 | t11d - 9 | 8 | t12 | t11d 9 | 8 | t111 | t11d + 9 | 8 | t12 | t11d + 9 | 8 | t11 | t11d + 9 | 8 | t1 | t11d (4 rows) DELETE FROM v1 WHERE snoop(a) AND leakproof(a); -- should not delete everything, just where a>5 -- 2.31.0