From 07aa36fb45d34ac170df2048c1ad224813b7f659 Mon Sep 17 00:00:00 2001
From: Bharath Rupireddy <bharath.rupireddy@enterprisedb.com>
Date: Wed, 16 Dec 2020 09:27:59 +0530
Subject: [PATCH v12 3/3] Tests For Parallel Inserts in CTAS

---
 src/test/regress/expected/write_parallel.out | 1226 ++++++++++++++++++
 src/test/regress/sql/write_parallel.sql      |  402 ++++++
 2 files changed, 1628 insertions(+)

diff --git a/src/test/regress/expected/write_parallel.out b/src/test/regress/expected/write_parallel.out
index 0c4da2591a..f8f1890228 100644
--- a/src/test/regress/expected/write_parallel.out
+++ b/src/test/regress/expected/write_parallel.out
@@ -76,4 +76,1230 @@ explain (costs off) create table parallel_write as execute prep_stmt;
 
 create table parallel_write as execute prep_stmt;
 drop table parallel_write;
+--
+-- Test parallel inserts in create table as/select into/create materialized
+-- view.
+--
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select length(stringu1) from tenk1;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 4
+   Workers Launched: 4
+ ->  Create parallel_write
+   ->  Parallel Seq Scan on tenk1 (actual rows=2000 loops=5)
+(5 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+ 10000
+(1 row)
+
+drop table parallel_write;
+-- parallel inserts must not occur as the table is temporary
+explain (costs off, analyze on, timing off, summary off)
+create temporary table parallel_write as select length(stringu1) from tenk1;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Gather (actual rows=10000 loops=1)
+   Workers Planned: 4
+   Workers Launched: 4
+   ->  Parallel Seq Scan on tenk1 (actual rows=2000 loops=5)
+(4 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+ 10000
+(1 row)
+
+drop table parallel_write;
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+create unlogged table parallel_write as select length(stringu1) from tenk1;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 4
+   Workers Launched: 4
+ ->  Create parallel_write
+   ->  Parallel Seq Scan on tenk1 (actual rows=2000 loops=5)
+(5 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+ 10000
+(1 row)
+
+drop table parallel_write;
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+select length(stringu1) into parallel_write from tenk1;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 4
+   Workers Launched: 4
+ ->  Create parallel_write
+   ->  Parallel Seq Scan on tenk1 (actual rows=2000 loops=5)
+(5 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+ 10000
+(1 row)
+
+drop table parallel_write;
+-- parallel inserts must not occur as the table is temporary
+explain (costs off, analyze on, timing off, summary off)
+select length(stringu1) into temporary parallel_write from tenk1;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Gather (actual rows=10000 loops=1)
+   Workers Planned: 4
+   Workers Launched: 4
+   ->  Parallel Seq Scan on tenk1 (actual rows=2000 loops=5)
+(4 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+ 10000
+(1 row)
+
+drop table parallel_write;
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+select length(stringu1) into unlogged parallel_write from tenk1;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 4
+   Workers Launched: 4
+ ->  Create parallel_write
+   ->  Parallel Seq Scan on tenk1 (actual rows=2000 loops=5)
+(5 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+ 10000
+(1 row)
+
+drop table parallel_write;
+-- parallel inserts must not occur as the parallelism will not be picked
+-- for select part because of for update clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select length(stringu1) from tenk1 for update;
+                     QUERY PLAN                      
+-----------------------------------------------------
+ LockRows (actual rows=10000 loops=1)
+   ->  Seq Scan on tenk1 (actual rows=10000 loops=1)
+(2 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+ 10000
+(1 row)
+
+drop table parallel_write;
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+create materialized view parallel_mat_view as
+    select length(stringu1) from tenk1;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 4
+   Workers Launched: 4
+ ->  Create parallel_mat_view
+   ->  Parallel Seq Scan on tenk1 (actual rows=2000 loops=5)
+(5 rows)
+
+select count(*) from parallel_mat_view;
+ count 
+-------
+ 10000
+(1 row)
+
+drop materialized view parallel_mat_view;
+-- parallel inserts must occur
+prepare parallel_write_prep as select length(stringu1) from tenk1;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as execute parallel_write_prep;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 4
+   Workers Launched: 4
+ ->  Create parallel_write
+   ->  Parallel Seq Scan on tenk1 (actual rows=2000 loops=5)
+(5 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+ 10000
+(1 row)
+
+deallocate parallel_write_prep;
+drop table parallel_write;
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select now(), four from tenk1;
+                         QUERY PLAN                          
+-------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 4
+   Workers Launched: 4
+ ->  Create parallel_write
+   ->  Parallel Seq Scan on tenk1 (actual rows=2000 loops=5)
+(5 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+ 10000
+(1 row)
+
+drop table parallel_write;
+-- parallel inserts must not occur as the parallelism will not be picked
+-- for select part because of the parallel unsafe function
+create sequence parallel_write_sequence;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select nextval('parallel_write_sequence'), four from tenk1;
+                  QUERY PLAN                   
+-----------------------------------------------
+ Seq Scan on tenk1 (actual rows=10000 loops=1)
+(1 row)
+
+select count(*) from parallel_write;
+ count 
+-------
+ 10000
+(1 row)
+
+drop table parallel_write;
+drop sequence parallel_write_sequence;
+-- parallel inserts must occur, as there is init plan that gets executed by
+-- each parallel worker
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select two col1,
+    (select two from (select * from tenk2) as tt limit 1) col2
+    from tenk1  where tenk1.four = 3;
+                               QUERY PLAN                               
+------------------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 4
+   Params Evaluated: $1
+   Workers Launched: 3
+ ->  Create parallel_write
+   InitPlan 1 (returns $1)
+     ->  Limit (actual rows=1 loops=1)
+           ->  Gather (actual rows=1 loops=1)
+                 Workers Planned: 4
+                 Workers Launched: 4
+                 ->  Parallel Seq Scan on tenk2 (actual rows=1 loops=5)
+   ->  Parallel Seq Scan on tenk1 (actual rows=625 loops=4)
+         Filter: (four = 3)
+         Rows Removed by Filter: 1875
+(14 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+  2500
+(1 row)
+
+drop table parallel_write;
+-- parallel inserts must not occur, as there is sub plan that gets executed by
+-- the Gather node in leader
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select two col1,
+    (select tenk1.two from generate_series(1,1)) col2
+    from tenk1  where tenk1.four = 3;
+                             QUERY PLAN                              
+---------------------------------------------------------------------
+ Gather (actual rows=2500 loops=1)
+   Workers Planned: 4
+   Workers Launched: 4
+   ->  Parallel Seq Scan on tenk1 (actual rows=500 loops=5)
+         Filter: (four = 3)
+         Rows Removed by Filter: 1500
+   SubPlan 1
+     ->  Function Scan on generate_series (actual rows=1 loops=2500)
+(8 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+  2500
+(1 row)
+
+drop table parallel_write;
+create table temp1(col1) as select * from generate_series(1,5);
+create table temp2(col2) as select * from temp1;
+create table temp3(col3) as select * from temp1;
+-- parallel inserts must not occur, as there is a limit clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select * from temp1 limit 4;
+                           QUERY PLAN                           
+----------------------------------------------------------------
+ Limit (actual rows=4 loops=1)
+   ->  Gather (actual rows=4 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+         ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+(5 rows)
+
+drop table parallel_write;
+-- parallel inserts must not occur, as there is an order by clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select * from temp1 order by 1;
+                           QUERY PLAN                           
+----------------------------------------------------------------
+ Gather Merge (actual rows=5 loops=1)
+   Workers Planned: 3
+   Workers Launched: 3
+   ->  Sort (actual rows=1 loops=4)
+         Sort Key: col1
+         Sort Method: quicksort  Memory: 25kB
+         Worker 0:  Sort Method: quicksort  Memory: 25kB
+         Worker 1:  Sort Method: quicksort  Memory: 25kB
+         Worker 2:  Sort Method: quicksort  Memory: 25kB
+         ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+(10 rows)
+
+drop table parallel_write;
+-- parallel inserts must not occur, as there is an order by clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select * from temp1 order by 1;
+                           QUERY PLAN                           
+----------------------------------------------------------------
+ Gather Merge (actual rows=5 loops=1)
+   Workers Planned: 3
+   Workers Launched: 3
+   ->  Sort (actual rows=1 loops=4)
+         Sort Key: col1
+         Sort Method: quicksort  Memory: 25kB
+         Worker 0:  Sort Method: quicksort  Memory: 25kB
+         Worker 1:  Sort Method: quicksort  Memory: 25kB
+         Worker 2:  Sort Method: quicksort  Memory: 25kB
+         ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+(10 rows)
+
+drop table parallel_write;
+-- parallel inserts must not occur, as there is a distinct clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select distinct * from temp1;
+                           QUERY PLAN                           
+----------------------------------------------------------------
+ HashAggregate (actual rows=5 loops=1)
+   Group Key: col1
+   Batches: 1  Memory Usage: 40kB
+   ->  Gather (actual rows=5 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+         ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+(7 rows)
+
+drop table parallel_write;
+-- parallel inserts must not occur, as there is an aggregate and group clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select count(*) from temp1 group by col1;
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ Finalize HashAggregate (actual rows=5 loops=1)
+   Group Key: col1
+   Batches: 1  Memory Usage: 40kB
+   ->  Gather (actual rows=5 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+         ->  Partial HashAggregate (actual rows=1 loops=4)
+               Group Key: col1
+               Batches: 1  Memory Usage: 40kB
+               Worker 0:  Batches: 1  Memory Usage: 40kB
+               Worker 1:  Batches: 1  Memory Usage: 40kB
+               Worker 2:  Batches: 1  Memory Usage: 40kB
+               ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+(13 rows)
+
+drop table parallel_write;
+-- parallel inserts must not occur, as there is an aggregate, group and having
+-- clauses
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select count(col1), (select col3 from
+        (select * from temp3) as tt limit 1) col4 from temp1, temp2
+    where temp1.col1 = temp2.col2 group by col4 having count(col1) > 0;
+                                    QUERY PLAN                                    
+----------------------------------------------------------------------------------
+ Finalize GroupAggregate (actual rows=1 loops=1)
+   Group Key: ($1)
+   Filter: (count(temp1.col1) > 0)
+   InitPlan 1 (returns $1)
+     ->  Limit (actual rows=1 loops=1)
+           ->  Gather (actual rows=1 loops=1)
+                 Workers Planned: 3
+                 Workers Launched: 3
+                 ->  Parallel Seq Scan on temp3 (actual rows=0 loops=4)
+   ->  Gather (actual rows=1 loops=1)
+         Workers Planned: 3
+         Params Evaluated: $1
+         Workers Launched: 3
+         ->  Partial GroupAggregate (actual rows=0 loops=4)
+               Group Key: $1
+               ->  Parallel Hash Join (actual rows=1 loops=4)
+                     Hash Cond: (temp1.col1 = temp2.col2)
+                     ->  Parallel Seq Scan on temp1 (actual rows=5 loops=1)
+                     ->  Parallel Hash (actual rows=1 loops=4)
+                           Buckets: 4096  Batches: 1  Memory Usage: 64kB
+                           ->  Parallel Seq Scan on temp2 (actual rows=5 loops=1)
+(21 rows)
+
+drop table parallel_write;
+-- parallel inserts must not occur, as there is a window function
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select avg(col1) OVER (PARTITION BY col1) from temp1;
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ WindowAgg (actual rows=5 loops=1)
+   ->  Sort (actual rows=5 loops=1)
+         Sort Key: col1
+         Sort Method: quicksort  Memory: 25kB
+         ->  Gather (actual rows=5 loops=1)
+               Workers Planned: 3
+               Workers Launched: 3
+               ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+(8 rows)
+
+drop table parallel_write;
+-- nested loop join is the top node under which Gather node exists, so parallel
+-- inserts must not occur
+set enable_nestloop to on;
+set enable_mergejoin to off;
+set enable_hashjoin to off;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1, temp2  where temp1.col1 = temp2.col2;
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ Nested Loop (actual rows=5 loops=1)
+   Join Filter: (temp1.col1 = temp2.col2)
+   Rows Removed by Join Filter: 20
+   ->  Gather (actual rows=5 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+         ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+   ->  Materialize (actual rows=5 loops=5)
+         ->  Gather (actual rows=5 loops=1)
+               Workers Planned: 3
+               Workers Launched: 3
+               ->  Parallel Seq Scan on temp2 (actual rows=1 loops=4)
+(12 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     5
+(1 row)
+
+drop table parallel_write;
+-- the top node is Gather under which merge join happens, so parallel inserts
+-- must occur
+set enable_nestloop to off;
+set enable_mergejoin to on;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1, temp2  where temp1.col1 = temp2.col2;
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 3
+   Workers Launched: 3
+ ->  Create parallel_write
+   ->  Merge Join (actual rows=1 loops=4)
+         Merge Cond: (temp1.col1 = temp2.col2)
+         ->  Sort (actual rows=1 loops=4)
+               Sort Key: temp1.col1
+               Sort Method: quicksort  Memory: 25kB
+               Worker 0:  Sort Method: quicksort  Memory: 25kB
+               Worker 1:  Sort Method: quicksort  Memory: 25kB
+               Worker 2:  Sort Method: quicksort  Memory: 25kB
+               ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+         ->  Sort (actual rows=5 loops=1)
+               Sort Key: temp2.col2
+               Sort Method: quicksort  Memory: 25kB
+               ->  Seq Scan on temp2 (actual rows=5 loops=1)
+(17 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     5
+(1 row)
+
+drop table parallel_write;
+-- parallel hash join happens under Gather node, so parallel inserts must occur
+set enable_mergejoin to off;
+set enable_hashjoin to on;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1, temp2  where temp1.col1 = temp2.col2;
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 3
+   Workers Launched: 3
+ ->  Create parallel_write
+   ->  Parallel Hash Join (actual rows=1 loops=4)
+         Hash Cond: (temp1.col1 = temp2.col2)
+         ->  Parallel Seq Scan on temp1 (actual rows=5 loops=1)
+         ->  Parallel Hash (actual rows=1 loops=4)
+               Buckets: 4096  Batches: 1  Memory Usage: 64kB
+               ->  Parallel Seq Scan on temp2 (actual rows=5 loops=1)
+(10 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     5
+(1 row)
+
+drop table parallel_write;
+reset enable_nestloop;
+reset enable_mergejoin;
+reset enable_hashjoin;
+-- test cases for performing parallel inserts when Append node is at the top
+-- and Gather node is in one of its direct sub plans.
+-- case 1: parallel inserts must occur at each Gather node as we can push the
+-- CTAS dest receiver.
+-- Append
+-- 	->Gather
+-- 		->Parallel Seq Scan
+-- 	->Gather
+-- 		->Parallel Seq Scan
+-- 	->Gather
+-- 		->Parallel Seq Scan
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 where col1 = 5 union all
+    select * from temp2 where col2 = 5 union all
+    select * from temp2 where col2 = 5;
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ Append (actual rows=0 loops=1)
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+       ->  Create parallel_write
+       ->  Parallel Seq Scan on temp1 (actual rows=0 loops=4)
+               Filter: (col1 = 5)
+               Rows Removed by Filter: 1
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+       ->  Create parallel_write
+       ->  Parallel Seq Scan on temp2 (actual rows=0 loops=4)
+               Filter: (col2 = 5)
+               Rows Removed by Filter: 1
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+       ->  Create parallel_write
+       ->  Parallel Seq Scan on temp2 temp2_1 (actual rows=0 loops=4)
+               Filter: (col2 = 5)
+               Rows Removed by Filter: 1
+(22 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     3
+(1 row)
+
+drop table parallel_write;
+-- case 2: parallel inserts must occur at the top Gather node as we can push
+-- the CTAS dest receiver to it.
+-- Gather
+-- 	->Parallel Append
+-- 		->Parallel Seq Scan
+-- 		->Parallel Seq Scan
+-- 		->Parallel Seq Scan
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 union all
+    select * from temp2 union all
+    select * from temp2;
+                               QUERY PLAN                               
+------------------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 3
+   Workers Launched: 3
+ ->  Create parallel_write
+   ->  Parallel Append (actual rows=4 loops=4)
+         ->  Parallel Seq Scan on temp1 (actual rows=5 loops=1)
+         ->  Parallel Seq Scan on temp2 (actual rows=5 loops=1)
+         ->  Parallel Seq Scan on temp2 temp2_1 (actual rows=5 loops=1)
+(8 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+    15
+(1 row)
+
+drop table parallel_write;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select (select col2 from temp2 limit 1) col2 from temp1 union all
+    select (select col2 from temp2 limit 1) col2 from temp1 union all
+    select * from temp2;
+                                   QUERY PLAN                                   
+--------------------------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 3
+   Params Evaluated: $1, $3
+   Workers Launched: 1
+ ->  Create parallel_write
+   InitPlan 1 (returns $1)
+     ->  Limit (actual rows=1 loops=1)
+           ->  Gather (actual rows=1 loops=1)
+                 Workers Planned: 3
+                 Workers Launched: 3
+                 ->  Parallel Seq Scan on temp2 temp2_1 (actual rows=0 loops=4)
+   InitPlan 2 (returns $3)
+     ->  Limit (actual rows=1 loops=1)
+           ->  Gather (actual rows=1 loops=1)
+                 Workers Planned: 3
+                 Workers Launched: 3
+                 ->  Parallel Seq Scan on temp2 temp2_2 (actual rows=0 loops=4)
+   ->  Parallel Append (actual rows=8 loops=2)
+         ->  Parallel Seq Scan on temp1 (actual rows=5 loops=1)
+         ->  Parallel Seq Scan on temp1 temp1_1 (actual rows=5 loops=1)
+         ->  Parallel Seq Scan on temp2 (actual rows=5 loops=1)
+(21 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+    15
+(1 row)
+
+drop table parallel_write;
+-- case 3: parallel inserts must occur at each Gather node as we can push the
+-- CTAS dest receiver. Non-Gather nodes will do inserts by sending tuples to
+-- Append and from there to CTAS dest receiver.
+-- Append
+-- 	->Gather
+-- 		->Parallel Seq Scan
+-- 	->Seq Scan / Join / any other non-Gather node
+-- 	->Gather
+-- 		->Parallel Seq Scan
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 where col1 = 5 union all
+    select (select temp1.col1 from temp2 limit 1) col2 from temp1 union all
+    select * from temp1 where col1 = 5;
+                                  QUERY PLAN                                   
+-------------------------------------------------------------------------------
+ Append (actual rows=5 loops=1)
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+       ->  Create parallel_write
+       ->  Parallel Seq Scan on temp1 temp1_1 (actual rows=0 loops=4)
+               Filter: (col1 = 5)
+               Rows Removed by Filter: 1
+   ->  Seq Scan on temp1 (actual rows=5 loops=1)
+         SubPlan 1
+           ->  Limit (actual rows=1 loops=5)
+                 ->  Gather (actual rows=1 loops=5)
+                       Workers Planned: 3
+                       Workers Launched: 3
+                       ->  Parallel Seq Scan on temp2 (actual rows=0 loops=20)
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+       ->  Create parallel_write
+       ->  Parallel Seq Scan on temp1 temp1_2 (actual rows=0 loops=4)
+               Filter: (col1 = 5)
+               Rows Removed by Filter: 1
+(22 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     7
+(1 row)
+
+drop table parallel_write;
+alter table temp2 set (parallel_workers = 0);
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select * from temp1 where col1 = (select 1) union all  select * from temp1 where col1 = (select 1) union all
+ select * from temp2 where col2 = (select 2);
+                               QUERY PLAN                               
+------------------------------------------------------------------------
+ Append (actual rows=1 loops=1)
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Params Evaluated: $0
+         Workers Launched: 3
+       ->  Create parallel_write
+       InitPlan 1 (returns $0)
+           ->  Result (actual rows=1 loops=1)
+         ->  Parallel Seq Scan on temp1 (actual rows=0 loops=4)
+               Filter: (col1 = $0)
+               Rows Removed by Filter: 1
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Params Evaluated: $1
+         Workers Launched: 3
+       ->  Create parallel_write
+       InitPlan 2 (returns $1)
+           ->  Result (actual rows=1 loops=1)
+         ->  Parallel Seq Scan on temp1 temp1_1 (actual rows=0 loops=4)
+               Filter: (col1 = $1)
+               Rows Removed by Filter: 1
+   ->  Seq Scan on temp2 (actual rows=1 loops=1)
+         Filter: (col2 = $2)
+         Rows Removed by Filter: 4
+         InitPlan 3 (returns $2)
+           ->  Result (actual rows=1 loops=1)
+(26 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     3
+(1 row)
+
+alter table temp2 reset (parallel_workers);
+drop table parallel_write;
+-- case 4: parallel inserts must not occur as there will be no direct Gather
+-- node under Append node. Non-Gather nodes will do inserts by sending tuples
+-- to Append and from there to CTAS dest receiver.
+-- Append
+-- 	->Seq Scan / Join / any other non-Gather node
+-- 	->Seq Scan / Join / any other non-Gather node
+-- 	->Seq Scan / Join / any other non-Gather node
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 union all
+    select * from temp2 union all
+    select (select temp1.col1 from temp2 limit 1) col2 from temp1;
+                                      QUERY PLAN                                       
+---------------------------------------------------------------------------------------
+ Append (actual rows=15 loops=1)
+   ->  Seq Scan on temp1 (actual rows=5 loops=1)
+   ->  Seq Scan on temp2 (actual rows=5 loops=1)
+   ->  Seq Scan on temp1 temp1_1 (actual rows=5 loops=1)
+         SubPlan 1
+           ->  Limit (actual rows=1 loops=5)
+                 ->  Gather (actual rows=1 loops=5)
+                       Workers Planned: 3
+                       Workers Launched: 3
+                       ->  Parallel Seq Scan on temp2 temp2_1 (actual rows=0 loops=20)
+(10 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+    15
+(1 row)
+
+drop table parallel_write;
+-- case 5: parallel inserts must occur at the top Gather node as we can push
+-- the CTAS dest receiver to it.
+-- Gather
+-- 	->Parallel Append
+-- 		->Seq Scan / Join / any other non-Gather node
+-- 		->Parallel Seq Scan
+-- 		->Parallel Seq Scan
+alter table temp2 set (parallel_workers = 0);
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 union all
+    select * from temp2 union all
+    select * from temp1;
+                               QUERY PLAN                               
+------------------------------------------------------------------------
+ Gather (actual rows=0 loops=1)
+   Workers Planned: 3
+   Workers Launched: 3
+ ->  Create parallel_write
+   ->  Parallel Append (actual rows=4 loops=4)
+         ->  Seq Scan on temp2 (actual rows=5 loops=1)
+         ->  Parallel Seq Scan on temp1 (actual rows=5 loops=1)
+         ->  Parallel Seq Scan on temp1 temp1_1 (actual rows=5 loops=1)
+(8 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+    15
+(1 row)
+
+drop table parallel_write;
+alter table temp2 reset (parallel_workers);
+-- case 6: parallel inserts must occur at each Gather node as we can push the
+-- CTAS dest receiver.
+-- Append
+--  ->Append
+--     ->Gather
+-- 		->Parallel Seq Scan
+--  ->Append
+--     ->Gather
+-- 		->Parallel Seq Scan
+--  ->Gather
+--  ->Gather
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from temp2 where col2 = (select 2) union all
+    select * from temp2 where col2 = (select 2);
+                                 QUERY PLAN                                 
+----------------------------------------------------------------------------
+ Append (actual rows=0 loops=1)
+   ->  Append (actual rows=0 loops=1)
+         InitPlan 1 (returns $0)
+           ->  Result (actual rows=1 loops=1)
+         ->  Gather (actual rows=0 loops=1)
+               Workers Planned: 3
+               Params Evaluated: $0, $1
+               Workers Launched: 3
+             ->  Create parallel_write
+             InitPlan 2 (returns $1)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Result (actual rows=0 loops=4)
+                     One-Time Filter: ($1 = $0)
+                     ->  Parallel Seq Scan on temp1 (actual rows=0 loops=4)
+                           Filter: (col1 = $0)
+                           Rows Removed by Filter: 1
+         ->  Gather (actual rows=0 loops=1)
+               Workers Planned: 3
+               Params Evaluated: $0, $2
+               Workers Launched: 3
+             ->  Create parallel_write
+             InitPlan 3 (returns $2)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Result (actual rows=0 loops=4)
+                     One-Time Filter: ($2 = $0)
+                     ->  Parallel Seq Scan on temp2 (never executed)
+                           Filter: (col2 = $0)
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Params Evaluated: $3
+         Workers Launched: 3
+       ->  Create parallel_write
+       InitPlan 4 (returns $3)
+           ->  Result (actual rows=1 loops=1)
+         ->  Parallel Seq Scan on temp2 temp2_1 (actual rows=0 loops=4)
+               Filter: (col2 = $3)
+               Rows Removed by Filter: 1
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Params Evaluated: $4
+         Workers Launched: 3
+       ->  Create parallel_write
+       InitPlan 5 (returns $4)
+           ->  Result (actual rows=1 loops=1)
+         ->  Parallel Seq Scan on temp2 temp2_2 (actual rows=0 loops=4)
+               Filter: (col2 = $4)
+               Rows Removed by Filter: 1
+(47 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     3
+(1 row)
+
+drop table parallel_write;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from temp1 where col1 = 5 union all
+    select * from temp2 where col2 = 5;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Append (actual rows=0 loops=1)
+   ->  Append (actual rows=0 loops=1)
+         InitPlan 1 (returns $0)
+           ->  Result (actual rows=1 loops=1)
+         ->  Gather (actual rows=0 loops=1)
+               Workers Planned: 3
+               Params Evaluated: $0, $1
+               Workers Launched: 3
+             ->  Create parallel_write
+             InitPlan 2 (returns $1)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Result (actual rows=0 loops=4)
+                     One-Time Filter: ($1 = $0)
+                     ->  Parallel Seq Scan on temp1 (actual rows=0 loops=4)
+                           Filter: (col1 = $0)
+                           Rows Removed by Filter: 1
+         ->  Gather (actual rows=0 loops=1)
+               Workers Planned: 3
+               Params Evaluated: $0, $2
+               Workers Launched: 3
+             ->  Create parallel_write
+             InitPlan 3 (returns $2)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Result (actual rows=0 loops=4)
+                     One-Time Filter: ($2 = $0)
+                     ->  Parallel Seq Scan on temp2 (never executed)
+                           Filter: (col2 = $0)
+   ->  Append (actual rows=0 loops=1)
+         InitPlan 4 (returns $3)
+           ->  Result (actual rows=1 loops=1)
+         ->  Gather (actual rows=0 loops=1)
+               Workers Planned: 3
+               Params Evaluated: $3, $4
+               Workers Launched: 3
+             ->  Create parallel_write
+             InitPlan 5 (returns $4)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Result (actual rows=0 loops=4)
+                     One-Time Filter: ($4 = $3)
+                     ->  Parallel Seq Scan on temp1 temp1_1 (actual rows=0 loops=4)
+                           Filter: (col1 = $3)
+                           Rows Removed by Filter: 1
+         ->  Gather (actual rows=0 loops=1)
+               Workers Planned: 3
+               Params Evaluated: $3, $5
+               Workers Launched: 3
+             ->  Create parallel_write
+             InitPlan 6 (returns $5)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Result (actual rows=0 loops=4)
+                     One-Time Filter: ($5 = $3)
+                     ->  Parallel Seq Scan on temp2 temp2_1 (never executed)
+                           Filter: (col2 = $3)
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+       ->  Create parallel_write
+       ->  Parallel Seq Scan on temp1 temp1_2 (actual rows=0 loops=4)
+               Filter: (col1 = 5)
+               Rows Removed by Filter: 1
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+       ->  Create parallel_write
+       ->  Parallel Seq Scan on temp2 temp2_2 (actual rows=0 loops=4)
+               Filter: (col2 = 5)
+               Rows Removed by Filter: 1
+(67 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     4
+(1 row)
+
+drop table parallel_write;
+-- case 7: parallel inserts must occur at each Gather node as we can push the
+-- CTAS dest receiver. Non-Gather nodes will do inserts by sending tuples
+-- to Append and from there to CTAS dest receiver.
+-- Append
+--  ->Append
+--     ->Gather
+-- 		->Parallel Seq Scan
+--  ->Append
+--     ->Gather
+-- 		->Parallel Seq Scan
+--  ->Seq Scan / Join / any other non-Gather node
+--  ->Gather
+alter table temp2 set (parallel_workers = 0);
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from temp2 where col2 = (select 2) union all
+    select * from temp1 where col1 = (select 2);
+                                 QUERY PLAN                                 
+----------------------------------------------------------------------------
+ Append (actual rows=1 loops=1)
+   ->  Append (actual rows=0 loops=1)
+         InitPlan 1 (returns $0)
+           ->  Result (actual rows=1 loops=1)
+         ->  Gather (actual rows=0 loops=1)
+               Workers Planned: 3
+               Params Evaluated: $0, $1
+               Workers Launched: 3
+             ->  Create parallel_write
+             InitPlan 2 (returns $1)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Result (actual rows=0 loops=4)
+                     One-Time Filter: ($1 = $0)
+                     ->  Parallel Seq Scan on temp1 (actual rows=0 loops=4)
+                           Filter: (col1 = $0)
+                           Rows Removed by Filter: 1
+         ->  Result (actual rows=0 loops=1)
+               One-Time Filter: ($2 = $0)
+               InitPlan 3 (returns $2)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Seq Scan on temp2 (never executed)
+                     Filter: (col2 = $0)
+   ->  Seq Scan on temp2 temp2_1 (actual rows=1 loops=1)
+         Filter: (col2 = $3)
+         Rows Removed by Filter: 4
+         InitPlan 4 (returns $3)
+           ->  Result (actual rows=1 loops=1)
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Params Evaluated: $4
+         Workers Launched: 3
+       ->  Create parallel_write
+       InitPlan 5 (returns $4)
+           ->  Result (actual rows=1 loops=1)
+         ->  Parallel Seq Scan on temp1 temp1_1 (actual rows=0 loops=4)
+               Filter: (col1 = $4)
+               Rows Removed by Filter: 1
+(37 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     3
+(1 row)
+
+drop table parallel_write;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from temp1 where col1 = 5 union all
+    select * from temp2 where col2 = 5;
+                                     QUERY PLAN                                     
+------------------------------------------------------------------------------------
+ Append (actual rows=1 loops=1)
+   ->  Append (actual rows=0 loops=1)
+         InitPlan 1 (returns $0)
+           ->  Result (actual rows=1 loops=1)
+         ->  Gather (actual rows=0 loops=1)
+               Workers Planned: 3
+               Params Evaluated: $0, $1
+               Workers Launched: 3
+             ->  Create parallel_write
+             InitPlan 2 (returns $1)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Result (actual rows=0 loops=4)
+                     One-Time Filter: ($1 = $0)
+                     ->  Parallel Seq Scan on temp1 (actual rows=0 loops=4)
+                           Filter: (col1 = $0)
+                           Rows Removed by Filter: 1
+         ->  Result (actual rows=0 loops=1)
+               One-Time Filter: ($2 = $0)
+               InitPlan 3 (returns $2)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Seq Scan on temp2 (never executed)
+                     Filter: (col2 = $0)
+   ->  Append (actual rows=0 loops=1)
+         InitPlan 4 (returns $3)
+           ->  Result (actual rows=1 loops=1)
+         ->  Gather (actual rows=0 loops=1)
+               Workers Planned: 3
+               Params Evaluated: $3, $4
+               Workers Launched: 3
+             ->  Create parallel_write
+             InitPlan 5 (returns $4)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Result (actual rows=0 loops=4)
+                     One-Time Filter: ($4 = $3)
+                     ->  Parallel Seq Scan on temp1 temp1_1 (actual rows=0 loops=4)
+                           Filter: (col1 = $3)
+                           Rows Removed by Filter: 1
+         ->  Result (actual rows=0 loops=1)
+               One-Time Filter: ($5 = $3)
+               InitPlan 6 (returns $5)
+                 ->  Result (actual rows=1 loops=1)
+               ->  Seq Scan on temp2 temp2_1 (never executed)
+                     Filter: (col2 = $3)
+   ->  Gather (actual rows=0 loops=1)
+         Workers Planned: 3
+         Workers Launched: 3
+       ->  Create parallel_write
+       ->  Parallel Seq Scan on temp1 temp1_2 (actual rows=0 loops=4)
+               Filter: (col1 = 5)
+               Rows Removed by Filter: 1
+   ->  Seq Scan on temp2 temp2_2 (actual rows=1 loops=1)
+         Filter: (col2 = 5)
+         Rows Removed by Filter: 4
+(53 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     4
+(1 row)
+
+drop table parallel_write;
+alter table temp2 reset (parallel_workers);
+-- case 8: parallel inserts must not occur because there is no Gather or Append
+-- node at the top for union, except/except all, intersect/intersect all
+-- cases.
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 union
+    select * from temp2;
+                              QUERY PLAN                              
+----------------------------------------------------------------------
+ HashAggregate (actual rows=5 loops=1)
+   Group Key: temp1.col1
+   Batches: 1  Memory Usage: 217kB
+   ->  Append (actual rows=10 loops=1)
+         ->  Gather (actual rows=5 loops=1)
+               Workers Planned: 3
+               Workers Launched: 3
+               ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+         ->  Gather (actual rows=5 loops=1)
+               Workers Planned: 3
+               Workers Launched: 3
+               ->  Parallel Seq Scan on temp2 (actual rows=1 loops=4)
+(12 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     5
+(1 row)
+
+drop table parallel_write;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 except
+    select * from temp2 where col2 < 3;
+                                 QUERY PLAN                                 
+----------------------------------------------------------------------------
+ HashSetOp Except (actual rows=3 loops=1)
+   ->  Append (actual rows=7 loops=1)
+         ->  Subquery Scan on "*SELECT* 1" (actual rows=5 loops=1)
+               ->  Gather (actual rows=5 loops=1)
+                     Workers Planned: 3
+                     Workers Launched: 3
+                     ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+         ->  Subquery Scan on "*SELECT* 2" (actual rows=2 loops=1)
+               ->  Gather (actual rows=2 loops=1)
+                     Workers Planned: 3
+                     Workers Launched: 3
+                     ->  Parallel Seq Scan on temp2 (actual rows=0 loops=4)
+                           Filter: (col2 < 3)
+                           Rows Removed by Filter: 1
+(14 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     3
+(1 row)
+
+drop table parallel_write;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 except all
+    select * from temp2 where col2 < 3;
+                                 QUERY PLAN                                 
+----------------------------------------------------------------------------
+ HashSetOp Except All (actual rows=3 loops=1)
+   ->  Append (actual rows=7 loops=1)
+         ->  Subquery Scan on "*SELECT* 1" (actual rows=5 loops=1)
+               ->  Gather (actual rows=5 loops=1)
+                     Workers Planned: 3
+                     Workers Launched: 3
+                     ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+         ->  Subquery Scan on "*SELECT* 2" (actual rows=2 loops=1)
+               ->  Gather (actual rows=2 loops=1)
+                     Workers Planned: 3
+                     Workers Launched: 3
+                     ->  Parallel Seq Scan on temp2 (actual rows=0 loops=4)
+                           Filter: (col2 < 3)
+                           Rows Removed by Filter: 1
+(14 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     3
+(1 row)
+
+drop table parallel_write;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 intersect
+    select * from temp2;
+                                 QUERY PLAN                                 
+----------------------------------------------------------------------------
+ HashSetOp Intersect (actual rows=5 loops=1)
+   ->  Append (actual rows=10 loops=1)
+         ->  Subquery Scan on "*SELECT* 1" (actual rows=5 loops=1)
+               ->  Gather (actual rows=5 loops=1)
+                     Workers Planned: 3
+                     Workers Launched: 3
+                     ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+         ->  Subquery Scan on "*SELECT* 2" (actual rows=5 loops=1)
+               ->  Gather (actual rows=5 loops=1)
+                     Workers Planned: 3
+                     Workers Launched: 3
+                     ->  Parallel Seq Scan on temp2 (actual rows=1 loops=4)
+(12 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     5
+(1 row)
+
+drop table parallel_write;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 intersect all
+    select * from temp2;
+                                 QUERY PLAN                                 
+----------------------------------------------------------------------------
+ HashSetOp Intersect All (actual rows=5 loops=1)
+   ->  Append (actual rows=10 loops=1)
+         ->  Subquery Scan on "*SELECT* 1" (actual rows=5 loops=1)
+               ->  Gather (actual rows=5 loops=1)
+                     Workers Planned: 3
+                     Workers Launched: 3
+                     ->  Parallel Seq Scan on temp1 (actual rows=1 loops=4)
+         ->  Subquery Scan on "*SELECT* 2" (actual rows=5 loops=1)
+               ->  Gather (actual rows=5 loops=1)
+                     Workers Planned: 3
+                     Workers Launched: 3
+                     ->  Parallel Seq Scan on temp2 (actual rows=1 loops=4)
+(12 rows)
+
+select count(*) from parallel_write;
+ count 
+-------
+     5
+(1 row)
+
+drop table parallel_write;
+drop table temp1;
+drop table temp2;
+drop table temp3;
 rollback;
diff --git a/src/test/regress/sql/write_parallel.sql b/src/test/regress/sql/write_parallel.sql
index 78b479cedf..67de31fb91 100644
--- a/src/test/regress/sql/write_parallel.sql
+++ b/src/test/regress/sql/write_parallel.sql
@@ -39,4 +39,406 @@ explain (costs off) create table parallel_write as execute prep_stmt;
 create table parallel_write as execute prep_stmt;
 drop table parallel_write;
 
+--
+-- Test parallel inserts in create table as/select into/create materialized
+-- view.
+--
+
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select length(stringu1) from tenk1;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- parallel inserts must not occur as the table is temporary
+explain (costs off, analyze on, timing off, summary off)
+create temporary table parallel_write as select length(stringu1) from tenk1;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+create unlogged table parallel_write as select length(stringu1) from tenk1;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+select length(stringu1) into parallel_write from tenk1;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- parallel inserts must not occur as the table is temporary
+explain (costs off, analyze on, timing off, summary off)
+select length(stringu1) into temporary parallel_write from tenk1;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+select length(stringu1) into unlogged parallel_write from tenk1;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- parallel inserts must not occur as the parallelism will not be picked
+-- for select part because of for update clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select length(stringu1) from tenk1 for update;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+create materialized view parallel_mat_view as
+    select length(stringu1) from tenk1;
+select count(*) from parallel_mat_view;
+drop materialized view parallel_mat_view;
+
+-- parallel inserts must occur
+prepare parallel_write_prep as select length(stringu1) from tenk1;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as execute parallel_write_prep;
+select count(*) from parallel_write;
+deallocate parallel_write_prep;
+drop table parallel_write;
+
+-- parallel inserts must occur
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select now(), four from tenk1;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- parallel inserts must not occur as the parallelism will not be picked
+-- for select part because of the parallel unsafe function
+create sequence parallel_write_sequence;
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select nextval('parallel_write_sequence'), four from tenk1;
+select count(*) from parallel_write;
+drop table parallel_write;
+drop sequence parallel_write_sequence;
+
+-- parallel inserts must occur, as there is init plan that gets executed by
+-- each parallel worker
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select two col1,
+    (select two from (select * from tenk2) as tt limit 1) col2
+    from tenk1  where tenk1.four = 3;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- parallel inserts must not occur, as there is sub plan that gets executed by
+-- the Gather node in leader
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select two col1,
+    (select tenk1.two from generate_series(1,1)) col2
+    from tenk1  where tenk1.four = 3;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+create table temp1(col1) as select * from generate_series(1,5);
+create table temp2(col2) as select * from temp1;
+create table temp3(col3) as select * from temp1;
+
+-- parallel inserts must not occur, as there is a limit clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select * from temp1 limit 4;
+drop table parallel_write;
+
+-- parallel inserts must not occur, as there is an order by clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select * from temp1 order by 1;
+drop table parallel_write;
+
+-- parallel inserts must not occur, as there is an order by clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select * from temp1 order by 1;
+drop table parallel_write;
+
+-- parallel inserts must not occur, as there is a distinct clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select distinct * from temp1;
+drop table parallel_write;
+
+-- parallel inserts must not occur, as there is an aggregate and group clause
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select count(*) from temp1 group by col1;
+drop table parallel_write;
+
+-- parallel inserts must not occur, as there is an aggregate, group and having
+-- clauses
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select count(col1), (select col3 from
+        (select * from temp3) as tt limit 1) col4 from temp1, temp2
+    where temp1.col1 = temp2.col2 group by col4 having count(col1) > 0;
+drop table parallel_write;
+
+-- parallel inserts must not occur, as there is a window function
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select avg(col1) OVER (PARTITION BY col1) from temp1;
+drop table parallel_write;
+
+-- nested loop join is the top node under which Gather node exists, so parallel
+-- inserts must not occur
+set enable_nestloop to on;
+set enable_mergejoin to off;
+set enable_hashjoin to off;
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1, temp2  where temp1.col1 = temp2.col2;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- the top node is Gather under which merge join happens, so parallel inserts
+-- must occur
+set enable_nestloop to off;
+set enable_mergejoin to on;
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1, temp2  where temp1.col1 = temp2.col2;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- parallel hash join happens under Gather node, so parallel inserts must occur
+set enable_mergejoin to off;
+set enable_hashjoin to on;
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1, temp2  where temp1.col1 = temp2.col2;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+reset enable_nestloop;
+reset enable_mergejoin;
+reset enable_hashjoin;
+
+-- test cases for performing parallel inserts when Append node is at the top
+-- and Gather node is in one of its direct sub plans.
+
+-- case 1: parallel inserts must occur at each Gather node as we can push the
+-- CTAS dest receiver.
+-- Append
+-- 	->Gather
+-- 		->Parallel Seq Scan
+-- 	->Gather
+-- 		->Parallel Seq Scan
+-- 	->Gather
+-- 		->Parallel Seq Scan
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 where col1 = 5 union all
+    select * from temp2 where col2 = 5 union all
+    select * from temp2 where col2 = 5;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- case 2: parallel inserts must occur at the top Gather node as we can push
+-- the CTAS dest receiver to it.
+-- Gather
+-- 	->Parallel Append
+-- 		->Parallel Seq Scan
+-- 		->Parallel Seq Scan
+-- 		->Parallel Seq Scan
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 union all
+    select * from temp2 union all
+    select * from temp2;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select (select col2 from temp2 limit 1) col2 from temp1 union all
+    select (select col2 from temp2 limit 1) col2 from temp1 union all
+    select * from temp2;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- case 3: parallel inserts must occur at each Gather node as we can push the
+-- CTAS dest receiver. Non-Gather nodes will do inserts by sending tuples to
+-- Append and from there to CTAS dest receiver.
+-- Append
+-- 	->Gather
+-- 		->Parallel Seq Scan
+-- 	->Seq Scan / Join / any other non-Gather node
+-- 	->Gather
+-- 		->Parallel Seq Scan
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 where col1 = 5 union all
+    select (select temp1.col1 from temp2 limit 1) col2 from temp1 union all
+    select * from temp1 where col1 = 5;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+alter table temp2 set (parallel_workers = 0);
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as select * from temp1 where col1 = (select 1) union all  select * from temp1 where col1 = (select 1) union all
+ select * from temp2 where col2 = (select 2);
+select count(*) from parallel_write;
+alter table temp2 reset (parallel_workers);
+drop table parallel_write;
+
+-- case 4: parallel inserts must not occur as there will be no direct Gather
+-- node under Append node. Non-Gather nodes will do inserts by sending tuples
+-- to Append and from there to CTAS dest receiver.
+-- Append
+-- 	->Seq Scan / Join / any other non-Gather node
+-- 	->Seq Scan / Join / any other non-Gather node
+-- 	->Seq Scan / Join / any other non-Gather node
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 union all
+    select * from temp2 union all
+    select (select temp1.col1 from temp2 limit 1) col2 from temp1;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- case 5: parallel inserts must occur at the top Gather node as we can push
+-- the CTAS dest receiver to it.
+-- Gather
+-- 	->Parallel Append
+-- 		->Seq Scan / Join / any other non-Gather node
+-- 		->Parallel Seq Scan
+-- 		->Parallel Seq Scan
+
+alter table temp2 set (parallel_workers = 0);
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 union all
+    select * from temp2 union all
+    select * from temp1;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+alter table temp2 reset (parallel_workers);
+
+-- case 6: parallel inserts must occur at each Gather node as we can push the
+-- CTAS dest receiver.
+-- Append
+--  ->Append
+--     ->Gather
+-- 		->Parallel Seq Scan
+--  ->Append
+--     ->Gather
+-- 		->Parallel Seq Scan
+--  ->Gather
+--  ->Gather
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from temp2 where col2 = (select 2) union all
+    select * from temp2 where col2 = (select 2);
+select count(*) from parallel_write;
+drop table parallel_write;
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from temp1 where col1 = 5 union all
+    select * from temp2 where col2 = 5;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+-- case 7: parallel inserts must occur at each Gather node as we can push the
+-- CTAS dest receiver. Non-Gather nodes will do inserts by sending tuples
+-- to Append and from there to CTAS dest receiver.
+-- Append
+--  ->Append
+--     ->Gather
+-- 		->Parallel Seq Scan
+--  ->Append
+--     ->Gather
+-- 		->Parallel Seq Scan
+--  ->Seq Scan / Join / any other non-Gather node
+--  ->Gather
+
+alter table temp2 set (parallel_workers = 0);
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from temp2 where col2 = (select 2) union all
+    select * from temp1 where col1 = (select 2);
+select count(*) from parallel_write;
+drop table parallel_write;
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from (select * from temp1 where col1 = (select 1) union all
+            select * from temp2 where col2 = (select 2)) as tt
+        where col1 = (select 1) union all
+    select * from temp1 where col1 = 5 union all
+    select * from temp2 where col2 = 5;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+alter table temp2 reset (parallel_workers);
+
+-- case 8: parallel inserts must not occur because there is no Gather or Append
+-- node at the top for union, except/except all, intersect/intersect all
+-- cases.
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 union
+    select * from temp2;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 except
+    select * from temp2 where col2 < 3;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 except all
+    select * from temp2 where col2 < 3;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 intersect
+    select * from temp2;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+explain (costs off, analyze on, timing off, summary off)
+create table parallel_write as
+    select * from temp1 intersect all
+    select * from temp2;
+select count(*) from parallel_write;
+drop table parallel_write;
+
+drop table temp1;
+drop table temp2;
+drop table temp3;
 rollback;
-- 
2.25.1

