summaryrefslogtreecommitdiff
path: root/src/test
diff options
context:
space:
mode:
Diffstat (limited to 'src/test')
-rw-r--r--src/test/isolation/specs/cluster-toast-value-reuse.spec2
-rw-r--r--src/test/modules/test_ddl_deparse/Makefile2
-rw-r--r--src/test/modules/test_ddl_deparse/expected/create_sequence.out (renamed from src/test/modules/test_ddl_deparse/expected/create_sequence_1.out)0
-rw-r--r--src/test/modules/test_ddl_deparse/meson.build2
-rw-r--r--src/test/modules/test_ddl_deparse/sql/create_sequence.sql (renamed from src/test/modules/test_ddl_deparse/sql/create_sequence_1.sql)0
-rw-r--r--src/test/perl/PostgreSQL/Test/Kerberos.pm1
-rw-r--r--src/test/regress/expected/join.out15
-rw-r--r--src/test/regress/expected/partition_join.out94
-rw-r--r--src/test/regress/expected/subselect.out233
-rw-r--r--src/test/regress/sql/subselect.sql67
10 files changed, 344 insertions, 72 deletions
diff --git a/src/test/isolation/specs/cluster-toast-value-reuse.spec b/src/test/isolation/specs/cluster-toast-value-reuse.spec
index 1930eedb850..9a2d10600b3 100644
--- a/src/test/isolation/specs/cluster-toast-value-reuse.spec
+++ b/src/test/isolation/specs/cluster-toast-value-reuse.spec
@@ -27,7 +27,7 @@ setup
-- Seed data: one row with big string to force TOAST tuple and trigger the todo=0 code path.
INSERT INTO cluster_toast_value(flag, value)
- VALUES (0, repeat(md5('1'), 120) || repeat('x', 8000));
+ VALUES (0, repeat(encode(sha256('1'), 'hex'), 120) || repeat('x', 8000));
CLUSTER cluster_toast_value;
}
diff --git a/src/test/modules/test_ddl_deparse/Makefile b/src/test/modules/test_ddl_deparse/Makefile
index 3a57a95c849..6a9c133ebe9 100644
--- a/src/test/modules/test_ddl_deparse/Makefile
+++ b/src/test/modules/test_ddl_deparse/Makefile
@@ -13,7 +13,7 @@ REGRESS = test_ddl_deparse \
create_type \
create_conversion \
create_domain \
- create_sequence_1 \
+ create_sequence \
create_table \
create_transform \
alter_table \
diff --git a/src/test/modules/test_ddl_deparse/expected/create_sequence_1.out b/src/test/modules/test_ddl_deparse/expected/create_sequence.out
index 5837ea484e4..5837ea484e4 100644
--- a/src/test/modules/test_ddl_deparse/expected/create_sequence_1.out
+++ b/src/test/modules/test_ddl_deparse/expected/create_sequence.out
diff --git a/src/test/modules/test_ddl_deparse/meson.build b/src/test/modules/test_ddl_deparse/meson.build
index bff65ba6333..e60aee3b1d3 100644
--- a/src/test/modules/test_ddl_deparse/meson.build
+++ b/src/test/modules/test_ddl_deparse/meson.build
@@ -33,7 +33,7 @@ tests += {
'create_type',
'create_conversion',
'create_domain',
- 'create_sequence_1',
+ 'create_sequence',
'create_table',
'create_transform',
'alter_table',
diff --git a/src/test/modules/test_ddl_deparse/sql/create_sequence_1.sql b/src/test/modules/test_ddl_deparse/sql/create_sequence.sql
index 9e6743f9830..9e6743f9830 100644
--- a/src/test/modules/test_ddl_deparse/sql/create_sequence_1.sql
+++ b/src/test/modules/test_ddl_deparse/sql/create_sequence.sql
diff --git a/src/test/perl/PostgreSQL/Test/Kerberos.pm b/src/test/perl/PostgreSQL/Test/Kerberos.pm
index b72dd2fbaf4..07a1ea899d0 100644
--- a/src/test/perl/PostgreSQL/Test/Kerberos.pm
+++ b/src/test/perl/PostgreSQL/Test/Kerberos.pm
@@ -9,6 +9,7 @@ package PostgreSQL::Test::Kerberos;
use strict;
use warnings FATAL => 'all';
use PostgreSQL::Test::Utils;
+use Test::More;
our (
$krb5_bin_dir, $krb5_sbin_dir, $krb5_config, $kinit,
diff --git a/src/test/regress/expected/join.out b/src/test/regress/expected/join.out
index 4d5d35d0727..98b05c94a11 100644
--- a/src/test/regress/expected/join.out
+++ b/src/test/regress/expected/join.out
@@ -9468,23 +9468,20 @@ where exists (select 1 from tenk1 t3
---------------------------------------------------------------------------------
Nested Loop
Output: t1.unique1, t2.hundred
- -> Hash Join
+ -> Merge Join
Output: t1.unique1, t3.tenthous
- Hash Cond: (t3.thousand = t1.unique1)
- -> HashAggregate
+ Merge Cond: (t3.thousand = t1.unique1)
+ -> Unique
Output: t3.thousand, t3.tenthous
- Group Key: t3.thousand, t3.tenthous
-> Index Only Scan using tenk1_thous_tenthous on public.tenk1 t3
Output: t3.thousand, t3.tenthous
- -> Hash
+ -> Index Only Scan using onek_unique1 on public.onek t1
Output: t1.unique1
- -> Index Only Scan using onek_unique1 on public.onek t1
- Output: t1.unique1
- Index Cond: (t1.unique1 < 1)
+ Index Cond: (t1.unique1 < 1)
-> Index Only Scan using tenk1_hundred on public.tenk1 t2
Output: t2.hundred
Index Cond: (t2.hundred = t3.tenthous)
-(18 rows)
+(15 rows)
-- ... unless it actually is unique
create table j3 as select unique1, tenthous from onek;
diff --git a/src/test/regress/expected/partition_join.out b/src/test/regress/expected/partition_join.out
index d5368186caa..24e06845f92 100644
--- a/src/test/regress/expected/partition_join.out
+++ b/src/test/regress/expected/partition_join.out
@@ -1134,48 +1134,50 @@ EXPLAIN (COSTS OFF)
SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHERE t1.a = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.b = 0 ORDER BY t1.a;
QUERY PLAN
---------------------------------------------------------------------------------
- Sort
+ Merge Append
Sort Key: t1.a
- -> Append
- -> Nested Loop
- Join Filter: (t1_2.a = t1_5.b)
- -> HashAggregate
- Group Key: t1_5.b
+ -> Nested Loop
+ Join Filter: (t1_2.a = t1_5.b)
+ -> Unique
+ -> Sort
+ Sort Key: t1_5.b
-> Hash Join
Hash Cond: (((t2_1.a + t2_1.b) / 2) = t1_5.b)
-> Seq Scan on prt1_e_p1 t2_1
-> Hash
-> Seq Scan on prt2_p1 t1_5
Filter: (a = 0)
- -> Index Scan using iprt1_p1_a on prt1_p1 t1_2
- Index Cond: (a = ((t2_1.a + t2_1.b) / 2))
- Filter: (b = 0)
- -> Nested Loop
- Join Filter: (t1_3.a = t1_6.b)
- -> HashAggregate
- Group Key: t1_6.b
+ -> Index Scan using iprt1_p1_a on prt1_p1 t1_2
+ Index Cond: (a = ((t2_1.a + t2_1.b) / 2))
+ Filter: (b = 0)
+ -> Nested Loop
+ Join Filter: (t1_3.a = t1_6.b)
+ -> Unique
+ -> Sort
+ Sort Key: t1_6.b
-> Hash Join
Hash Cond: (((t2_2.a + t2_2.b) / 2) = t1_6.b)
-> Seq Scan on prt1_e_p2 t2_2
-> Hash
-> Seq Scan on prt2_p2 t1_6
Filter: (a = 0)
- -> Index Scan using iprt1_p2_a on prt1_p2 t1_3
- Index Cond: (a = ((t2_2.a + t2_2.b) / 2))
- Filter: (b = 0)
- -> Nested Loop
- Join Filter: (t1_4.a = t1_7.b)
- -> HashAggregate
- Group Key: t1_7.b
+ -> Index Scan using iprt1_p2_a on prt1_p2 t1_3
+ Index Cond: (a = ((t2_2.a + t2_2.b) / 2))
+ Filter: (b = 0)
+ -> Nested Loop
+ Join Filter: (t1_4.a = t1_7.b)
+ -> Unique
+ -> Sort
+ Sort Key: t1_7.b
-> Nested Loop
-> Seq Scan on prt2_p3 t1_7
Filter: (a = 0)
-> Index Scan using iprt1_e_p3_ab2 on prt1_e_p3 t2_3
Index Cond: (((a + b) / 2) = t1_7.b)
- -> Index Scan using iprt1_p3_a on prt1_p3 t1_4
- Index Cond: (a = ((t2_3.a + t2_3.b) / 2))
- Filter: (b = 0)
-(41 rows)
+ -> Index Scan using iprt1_p3_a on prt1_p3 t1_4
+ Index Cond: (a = ((t2_3.a + t2_3.b) / 2))
+ Filter: (b = 0)
+(43 rows)
SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1, prt1_e t2 WHERE t1.a = 0 AND t1.b = (t2.a + t2.b)/2) AND t1.b = 0 ORDER BY t1.a;
a | b | c
@@ -1190,46 +1192,48 @@ EXPLAIN (COSTS OFF)
SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.c = 0)) AND t1.b = 0 ORDER BY t1.a;
QUERY PLAN
---------------------------------------------------------------------------
- Sort
+ Merge Append
Sort Key: t1.a
- -> Append
- -> Nested Loop
- -> HashAggregate
- Group Key: t1_6.b
+ -> Nested Loop
+ -> Unique
+ -> Sort
+ Sort Key: t1_6.b
-> Hash Semi Join
Hash Cond: (t1_6.b = ((t1_9.a + t1_9.b) / 2))
-> Seq Scan on prt2_p1 t1_6
-> Hash
-> Seq Scan on prt1_e_p1 t1_9
Filter: (c = 0)
- -> Index Scan using iprt1_p1_a on prt1_p1 t1_3
- Index Cond: (a = t1_6.b)
- Filter: (b = 0)
- -> Nested Loop
- -> HashAggregate
- Group Key: t1_7.b
+ -> Index Scan using iprt1_p1_a on prt1_p1 t1_3
+ Index Cond: (a = t1_6.b)
+ Filter: (b = 0)
+ -> Nested Loop
+ -> Unique
+ -> Sort
+ Sort Key: t1_7.b
-> Hash Semi Join
Hash Cond: (t1_7.b = ((t1_10.a + t1_10.b) / 2))
-> Seq Scan on prt2_p2 t1_7
-> Hash
-> Seq Scan on prt1_e_p2 t1_10
Filter: (c = 0)
- -> Index Scan using iprt1_p2_a on prt1_p2 t1_4
- Index Cond: (a = t1_7.b)
- Filter: (b = 0)
- -> Nested Loop
- -> HashAggregate
- Group Key: t1_8.b
+ -> Index Scan using iprt1_p2_a on prt1_p2 t1_4
+ Index Cond: (a = t1_7.b)
+ Filter: (b = 0)
+ -> Nested Loop
+ -> Unique
+ -> Sort
+ Sort Key: t1_8.b
-> Hash Semi Join
Hash Cond: (t1_8.b = ((t1_11.a + t1_11.b) / 2))
-> Seq Scan on prt2_p3 t1_8
-> Hash
-> Seq Scan on prt1_e_p3 t1_11
Filter: (c = 0)
- -> Index Scan using iprt1_p3_a on prt1_p3 t1_5
- Index Cond: (a = t1_8.b)
- Filter: (b = 0)
-(39 rows)
+ -> Index Scan using iprt1_p3_a on prt1_p3 t1_5
+ Index Cond: (a = t1_8.b)
+ Filter: (b = 0)
+(41 rows)
SELECT t1.* FROM prt1 t1 WHERE t1.a IN (SELECT t1.b FROM prt2 t1 WHERE t1.b IN (SELECT (t1.a + t1.b)/2 FROM prt1_e t1 WHERE t1.c = 0)) AND t1.b = 0 ORDER BY t1.a;
a | b | c
diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out
index 18fed63e738..0563d0cd5a1 100644
--- a/src/test/regress/expected/subselect.out
+++ b/src/test/regress/expected/subselect.out
@@ -708,6 +708,212 @@ select * from numeric_table
(4 rows)
--
+-- Test that a semijoin implemented by unique-ifying the RHS can explore
+-- different paths of the RHS rel.
+--
+create table semijoin_unique_tbl (a int, b int);
+insert into semijoin_unique_tbl select i%10, i%10 from generate_series(1,1000)i;
+create index on semijoin_unique_tbl(a, b);
+analyze semijoin_unique_tbl;
+-- Ensure that we get a plan with Unique + IndexScan
+explain (verbose, costs off)
+select * from semijoin_unique_tbl t1, semijoin_unique_tbl t2
+where (t1.a, t2.a) in (select a, b from semijoin_unique_tbl t3)
+order by t1.a, t2.a;
+ QUERY PLAN
+------------------------------------------------------------------------------------------------------
+ Nested Loop
+ Output: t1.a, t1.b, t2.a, t2.b
+ -> Merge Join
+ Output: t1.a, t1.b, t3.b
+ Merge Cond: (t3.a = t1.a)
+ -> Unique
+ Output: t3.a, t3.b
+ -> Index Only Scan using semijoin_unique_tbl_a_b_idx on public.semijoin_unique_tbl t3
+ Output: t3.a, t3.b
+ -> Index Only Scan using semijoin_unique_tbl_a_b_idx on public.semijoin_unique_tbl t1
+ Output: t1.a, t1.b
+ -> Memoize
+ Output: t2.a, t2.b
+ Cache Key: t3.b
+ Cache Mode: logical
+ -> Index Only Scan using semijoin_unique_tbl_a_b_idx on public.semijoin_unique_tbl t2
+ Output: t2.a, t2.b
+ Index Cond: (t2.a = t3.b)
+(18 rows)
+
+-- Ensure that we can unique-ify expressions more complex than plain Vars
+explain (verbose, costs off)
+select * from semijoin_unique_tbl t1, semijoin_unique_tbl t2
+where (t1.a, t2.a) in (select a+1, b+1 from semijoin_unique_tbl t3)
+order by t1.a, t2.a;
+ QUERY PLAN
+------------------------------------------------------------------------------------------------
+ Incremental Sort
+ Output: t1.a, t1.b, t2.a, t2.b
+ Sort Key: t1.a, t2.a
+ Presorted Key: t1.a
+ -> Merge Join
+ Output: t1.a, t1.b, t2.a, t2.b
+ Merge Cond: (t1.a = ((t3.a + 1)))
+ -> Index Only Scan using semijoin_unique_tbl_a_b_idx on public.semijoin_unique_tbl t1
+ Output: t1.a, t1.b
+ -> Sort
+ Output: t2.a, t2.b, t3.a, ((t3.a + 1))
+ Sort Key: ((t3.a + 1))
+ -> Hash Join
+ Output: t2.a, t2.b, t3.a, (t3.a + 1)
+ Hash Cond: (t2.a = (t3.b + 1))
+ -> Seq Scan on public.semijoin_unique_tbl t2
+ Output: t2.a, t2.b
+ -> Hash
+ Output: t3.a, t3.b
+ -> HashAggregate
+ Output: t3.a, t3.b
+ Group Key: (t3.a + 1), (t3.b + 1)
+ -> Seq Scan on public.semijoin_unique_tbl t3
+ Output: t3.a, t3.b, (t3.a + 1), (t3.b + 1)
+(24 rows)
+
+-- encourage use of parallel plans
+set parallel_setup_cost=0;
+set parallel_tuple_cost=0;
+set min_parallel_table_scan_size=0;
+set max_parallel_workers_per_gather=4;
+set enable_indexscan to off;
+-- Ensure that we get a parallel plan for the unique-ification
+explain (verbose, costs off)
+select * from semijoin_unique_tbl t1, semijoin_unique_tbl t2
+where (t1.a, t2.a) in (select a, b from semijoin_unique_tbl t3)
+order by t1.a, t2.a;
+ QUERY PLAN
+----------------------------------------------------------------------------------------
+ Nested Loop
+ Output: t1.a, t1.b, t2.a, t2.b
+ -> Merge Join
+ Output: t1.a, t1.b, t3.b
+ Merge Cond: (t3.a = t1.a)
+ -> Unique
+ Output: t3.a, t3.b
+ -> Gather Merge
+ Output: t3.a, t3.b
+ Workers Planned: 2
+ -> Sort
+ Output: t3.a, t3.b
+ Sort Key: t3.a, t3.b
+ -> HashAggregate
+ Output: t3.a, t3.b
+ Group Key: t3.a, t3.b
+ -> Parallel Seq Scan on public.semijoin_unique_tbl t3
+ Output: t3.a, t3.b
+ -> Materialize
+ Output: t1.a, t1.b
+ -> Gather Merge
+ Output: t1.a, t1.b
+ Workers Planned: 2
+ -> Sort
+ Output: t1.a, t1.b
+ Sort Key: t1.a
+ -> Parallel Seq Scan on public.semijoin_unique_tbl t1
+ Output: t1.a, t1.b
+ -> Memoize
+ Output: t2.a, t2.b
+ Cache Key: t3.b
+ Cache Mode: logical
+ -> Bitmap Heap Scan on public.semijoin_unique_tbl t2
+ Output: t2.a, t2.b
+ Recheck Cond: (t2.a = t3.b)
+ -> Bitmap Index Scan on semijoin_unique_tbl_a_b_idx
+ Index Cond: (t2.a = t3.b)
+(37 rows)
+
+reset enable_indexscan;
+reset max_parallel_workers_per_gather;
+reset min_parallel_table_scan_size;
+reset parallel_tuple_cost;
+reset parallel_setup_cost;
+drop table semijoin_unique_tbl;
+create table unique_tbl_p (a int, b int) partition by range(a);
+create table unique_tbl_p1 partition of unique_tbl_p for values from (0) to (5);
+create table unique_tbl_p2 partition of unique_tbl_p for values from (5) to (10);
+create table unique_tbl_p3 partition of unique_tbl_p for values from (10) to (20);
+insert into unique_tbl_p select i%12, i from generate_series(0, 1000)i;
+create index on unique_tbl_p1(a);
+create index on unique_tbl_p2(a);
+create index on unique_tbl_p3(a);
+analyze unique_tbl_p;
+set enable_partitionwise_join to on;
+-- Ensure that the unique-ification works for partition-wise join
+explain (verbose, costs off)
+select * from unique_tbl_p t1, unique_tbl_p t2
+where (t1.a, t2.a) in (select a, a from unique_tbl_p t3)
+order by t1.a, t2.a;
+ QUERY PLAN
+------------------------------------------------------------------------------------------------
+ Merge Append
+ Sort Key: t1.a
+ -> Nested Loop
+ Output: t1_1.a, t1_1.b, t2_1.a, t2_1.b
+ -> Nested Loop
+ Output: t1_1.a, t1_1.b, t3_1.a
+ -> Unique
+ Output: t3_1.a
+ -> Index Only Scan using unique_tbl_p1_a_idx on public.unique_tbl_p1 t3_1
+ Output: t3_1.a
+ -> Index Scan using unique_tbl_p1_a_idx on public.unique_tbl_p1 t1_1
+ Output: t1_1.a, t1_1.b
+ Index Cond: (t1_1.a = t3_1.a)
+ -> Memoize
+ Output: t2_1.a, t2_1.b
+ Cache Key: t1_1.a
+ Cache Mode: logical
+ -> Index Scan using unique_tbl_p1_a_idx on public.unique_tbl_p1 t2_1
+ Output: t2_1.a, t2_1.b
+ Index Cond: (t2_1.a = t1_1.a)
+ -> Nested Loop
+ Output: t1_2.a, t1_2.b, t2_2.a, t2_2.b
+ -> Nested Loop
+ Output: t1_2.a, t1_2.b, t3_2.a
+ -> Unique
+ Output: t3_2.a
+ -> Index Only Scan using unique_tbl_p2_a_idx on public.unique_tbl_p2 t3_2
+ Output: t3_2.a
+ -> Index Scan using unique_tbl_p2_a_idx on public.unique_tbl_p2 t1_2
+ Output: t1_2.a, t1_2.b
+ Index Cond: (t1_2.a = t3_2.a)
+ -> Memoize
+ Output: t2_2.a, t2_2.b
+ Cache Key: t1_2.a
+ Cache Mode: logical
+ -> Index Scan using unique_tbl_p2_a_idx on public.unique_tbl_p2 t2_2
+ Output: t2_2.a, t2_2.b
+ Index Cond: (t2_2.a = t1_2.a)
+ -> Nested Loop
+ Output: t1_3.a, t1_3.b, t2_3.a, t2_3.b
+ -> Nested Loop
+ Output: t1_3.a, t1_3.b, t3_3.a
+ -> Unique
+ Output: t3_3.a
+ -> Sort
+ Output: t3_3.a
+ Sort Key: t3_3.a
+ -> Seq Scan on public.unique_tbl_p3 t3_3
+ Output: t3_3.a
+ -> Index Scan using unique_tbl_p3_a_idx on public.unique_tbl_p3 t1_3
+ Output: t1_3.a, t1_3.b
+ Index Cond: (t1_3.a = t3_3.a)
+ -> Memoize
+ Output: t2_3.a, t2_3.b
+ Cache Key: t1_3.a
+ Cache Mode: logical
+ -> Index Scan using unique_tbl_p3_a_idx on public.unique_tbl_p3 t2_3
+ Output: t2_3.a, t2_3.b
+ Index Cond: (t2_3.a = t1_3.a)
+(59 rows)
+
+reset enable_partitionwise_join;
+drop table unique_tbl_p;
+--
-- Test case for bug #4290: bogus calculation of subplan param sets
--
create temp table ta (id int primary key, val int);
@@ -2672,18 +2878,17 @@ EXPLAIN (COSTS OFF)
SELECT * FROM onek
WHERE (unique1,ten) IN (VALUES (1,1), (20,0), (99,9), (17,99))
ORDER BY unique1;
- QUERY PLAN
------------------------------------------------------------------
- Sort
- Sort Key: onek.unique1
- -> Nested Loop
- -> HashAggregate
- Group Key: "*VALUES*".column1, "*VALUES*".column2
+ QUERY PLAN
+----------------------------------------------------------------
+ Nested Loop
+ -> Unique
+ -> Sort
+ Sort Key: "*VALUES*".column1, "*VALUES*".column2
-> Values Scan on "*VALUES*"
- -> Index Scan using onek_unique1 on onek
- Index Cond: (unique1 = "*VALUES*".column1)
- Filter: ("*VALUES*".column2 = ten)
-(9 rows)
+ -> Index Scan using onek_unique1 on onek
+ Index Cond: (unique1 = "*VALUES*".column1)
+ Filter: ("*VALUES*".column2 = ten)
+(8 rows)
EXPLAIN (COSTS OFF)
SELECT * FROM onek
@@ -2858,12 +3063,10 @@ SELECT ten FROM onek WHERE unique1 IN (VALUES (1), (2) ORDER BY 1);
-> Unique
-> Sort
Sort Key: "*VALUES*".column1
- -> Sort
- Sort Key: "*VALUES*".column1
- -> Values Scan on "*VALUES*"
+ -> Values Scan on "*VALUES*"
-> Index Scan using onek_unique1 on onek
Index Cond: (unique1 = "*VALUES*".column1)
-(9 rows)
+(7 rows)
EXPLAIN (COSTS OFF)
SELECT ten FROM onek WHERE unique1 IN (VALUES (1), (2) LIMIT 1);
diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql
index d9a841fbc9f..a6d276a115b 100644
--- a/src/test/regress/sql/subselect.sql
+++ b/src/test/regress/sql/subselect.sql
@@ -362,6 +362,73 @@ select * from numeric_table
where num_col in (select float_col from float_table);
--
+-- Test that a semijoin implemented by unique-ifying the RHS can explore
+-- different paths of the RHS rel.
+--
+
+create table semijoin_unique_tbl (a int, b int);
+insert into semijoin_unique_tbl select i%10, i%10 from generate_series(1,1000)i;
+create index on semijoin_unique_tbl(a, b);
+analyze semijoin_unique_tbl;
+
+-- Ensure that we get a plan with Unique + IndexScan
+explain (verbose, costs off)
+select * from semijoin_unique_tbl t1, semijoin_unique_tbl t2
+where (t1.a, t2.a) in (select a, b from semijoin_unique_tbl t3)
+order by t1.a, t2.a;
+
+-- Ensure that we can unique-ify expressions more complex than plain Vars
+explain (verbose, costs off)
+select * from semijoin_unique_tbl t1, semijoin_unique_tbl t2
+where (t1.a, t2.a) in (select a+1, b+1 from semijoin_unique_tbl t3)
+order by t1.a, t2.a;
+
+-- encourage use of parallel plans
+set parallel_setup_cost=0;
+set parallel_tuple_cost=0;
+set min_parallel_table_scan_size=0;
+set max_parallel_workers_per_gather=4;
+
+set enable_indexscan to off;
+
+-- Ensure that we get a parallel plan for the unique-ification
+explain (verbose, costs off)
+select * from semijoin_unique_tbl t1, semijoin_unique_tbl t2
+where (t1.a, t2.a) in (select a, b from semijoin_unique_tbl t3)
+order by t1.a, t2.a;
+
+reset enable_indexscan;
+
+reset max_parallel_workers_per_gather;
+reset min_parallel_table_scan_size;
+reset parallel_tuple_cost;
+reset parallel_setup_cost;
+
+drop table semijoin_unique_tbl;
+
+create table unique_tbl_p (a int, b int) partition by range(a);
+create table unique_tbl_p1 partition of unique_tbl_p for values from (0) to (5);
+create table unique_tbl_p2 partition of unique_tbl_p for values from (5) to (10);
+create table unique_tbl_p3 partition of unique_tbl_p for values from (10) to (20);
+insert into unique_tbl_p select i%12, i from generate_series(0, 1000)i;
+create index on unique_tbl_p1(a);
+create index on unique_tbl_p2(a);
+create index on unique_tbl_p3(a);
+analyze unique_tbl_p;
+
+set enable_partitionwise_join to on;
+
+-- Ensure that the unique-ification works for partition-wise join
+explain (verbose, costs off)
+select * from unique_tbl_p t1, unique_tbl_p t2
+where (t1.a, t2.a) in (select a, a from unique_tbl_p t3)
+order by t1.a, t2.a;
+
+reset enable_partitionwise_join;
+
+drop table unique_tbl_p;
+
+--
-- Test case for bug #4290: bogus calculation of subplan param sets
--