| -- |
| -- PARALLEL |
| -- We have CBDB style parallel now, open this file in parallel mode. |
| -- |
| set enable_parallel = on; |
| set optimizer = off; |
| create function sp_parallel_restricted(int) returns int as |
| $$begin return $1; end$$ language plpgsql parallel restricted; |
| begin; |
| -- 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; |
| -- Parallel Append with partial-subplans |
| explain (costs off) |
| select round(avg(aa)), sum(aa) from a_star; |
| QUERY PLAN |
| ----------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 9:1 (slice1; segments: 9) |
| -> Partial Aggregate |
| -> Parallel Append |
| -> Seq Scan on d_star a_star_4 |
| -> Seq Scan on f_star a_star_6 |
| -> Seq Scan on e_star a_star_5 |
| -> Seq Scan on b_star a_star_2 |
| -> Seq Scan on c_star a_star_3 |
| -> Seq Scan on a_star a_star_1 |
| Optimizer: Postgres query optimizer |
| (11 rows) |
| |
| select round(avg(aa)), sum(aa) from a_star a1; |
| round | sum |
| -------+----- |
| 14 | 355 |
| (1 row) |
| |
| -- Parallel Append with both partial and non-partial subplans |
| alter table c_star set (parallel_workers = 0); |
| alter table d_star set (parallel_workers = 0); |
| explain (costs off) |
| select round(avg(aa)), sum(aa) from a_star; |
| QUERY PLAN |
| ----------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 9:1 (slice1; segments: 9) |
| -> Partial Aggregate |
| -> Parallel Append |
| -> Seq Scan on d_star a_star_4 |
| -> Seq Scan on f_star a_star_6 |
| -> Seq Scan on e_star a_star_5 |
| -> Seq Scan on b_star a_star_2 |
| -> Seq Scan on c_star a_star_3 |
| -> Seq Scan on a_star a_star_1 |
| Optimizer: Postgres query optimizer |
| (11 rows) |
| |
| select round(avg(aa)), sum(aa) from a_star a2; |
| round | sum |
| -------+----- |
| 14 | 355 |
| (1 row) |
| |
| -- Parallel Append with only non-partial subplans |
| alter table a_star set (parallel_workers = 0); |
| alter table b_star set (parallel_workers = 0); |
| alter table e_star set (parallel_workers = 0); |
| alter table f_star set (parallel_workers = 0); |
| explain (costs off) |
| select round(avg(aa)), sum(aa) from a_star; |
| QUERY PLAN |
| ----------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 9:1 (slice1; segments: 9) |
| -> Partial Aggregate |
| -> Parallel Append |
| -> Seq Scan on d_star a_star_4 |
| -> Seq Scan on f_star a_star_6 |
| -> Seq Scan on e_star a_star_5 |
| -> Seq Scan on b_star a_star_2 |
| -> Seq Scan on c_star a_star_3 |
| -> Seq Scan on a_star a_star_1 |
| Optimizer: Postgres query optimizer |
| (11 rows) |
| |
| select round(avg(aa)), sum(aa) from a_star a3; |
| round | sum |
| -------+----- |
| 14 | 355 |
| (1 row) |
| |
| -- Disable Parallel Append |
| alter table a_star reset (parallel_workers); |
| alter table b_star reset (parallel_workers); |
| alter table c_star reset (parallel_workers); |
| alter table d_star reset (parallel_workers); |
| alter table e_star reset (parallel_workers); |
| alter table f_star reset (parallel_workers); |
| set enable_parallel_append to off; |
| explain (costs off) |
| select round(avg(aa)), sum(aa) from a_star; |
| QUERY PLAN |
| ----------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 3:1 (slice1; segments: 3) |
| -> Partial Aggregate |
| -> Append |
| -> Seq Scan on a_star a_star_1 |
| -> Seq Scan on b_star a_star_2 |
| -> Seq Scan on c_star a_star_3 |
| -> Seq Scan on d_star a_star_4 |
| -> Seq Scan on e_star a_star_5 |
| -> Seq Scan on f_star a_star_6 |
| Optimizer: Postgres query optimizer |
| (11 rows) |
| |
| select round(avg(aa)), sum(aa) from a_star a4; |
| round | sum |
| -------+----- |
| 14 | 355 |
| (1 row) |
| |
| reset enable_parallel_append; |
| -- Parallel Append that runs serially |
| create function sp_test_func() returns setof text as |
| $$ select 'foo'::varchar union all select 'bar'::varchar $$ |
| language sql stable; |
| select sp_test_func() order by 1; |
| sp_test_func |
| -------------- |
| bar |
| foo |
| (2 rows) |
| |
| -- Parallel Append is not to be used when the subpath depends on the outer param |
| create table part_pa_test(a int, b int) partition by range(a); |
| NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Greenplum Database data distribution key for this table. |
| HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. |
| create table part_pa_test_p1 partition of part_pa_test for values from (minvalue) to (0); |
| NOTICE: table has parent, setting distribution columns to match parent table |
| create table part_pa_test_p2 partition of part_pa_test for values from (0) to (maxvalue); |
| NOTICE: table has parent, setting distribution columns to match parent table |
| explain (costs off) |
| select (select max((select pa1.b from part_pa_test pa1 where pa1.a = pa2.a))) |
| from part_pa_test pa2; |
| QUERY PLAN |
| ------------------------------------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 3:1 (slice1; segments: 3) |
| -> Partial Aggregate |
| -> Append |
| -> Seq Scan on part_pa_test_p1 pa2_1 |
| -> Seq Scan on part_pa_test_p2 pa2_2 |
| SubPlan 1 |
| -> Result |
| Filter: (pa1.a = pa2.a) |
| -> Materialize |
| -> Broadcast Motion 3:3 (slice2; segments: 3) |
| -> Append |
| -> Seq Scan on part_pa_test_p1 pa1_1 |
| -> Seq Scan on part_pa_test_p2 pa1_2 |
| SubPlan 2 |
| -> Result |
| Optimizer: Postgres query optimizer |
| (17 rows) |
| |
| drop table part_pa_test; |
| -- test with leader participation disabled |
| set parallel_leader_participation = off; |
| explain (costs off) |
| select count(*) from tenk1 where stringu1 = 'GRAAAA'; |
| QUERY PLAN |
| --------------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 12:1 (slice1; segments: 12) |
| -> Partial Aggregate |
| -> Parallel Seq Scan on tenk1 |
| Filter: (stringu1 = 'GRAAAA'::name) |
| Optimizer: Postgres query optimizer |
| (6 rows) |
| |
| select count(*) from tenk1 where stringu1 = 'GRAAAA'; |
| count |
| ------- |
| 15 |
| (1 row) |
| |
| -- test with leader participation disabled, but no workers available (so |
| -- the leader will have to run the plan despite the setting) |
| set max_parallel_workers = 0; |
| explain (costs off) |
| select count(*) from tenk1 where stringu1 = 'GRAAAA'; |
| QUERY PLAN |
| --------------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 12:1 (slice1; segments: 12) |
| -> Partial Aggregate |
| -> Parallel Seq Scan on tenk1 |
| Filter: (stringu1 = 'GRAAAA'::name) |
| Optimizer: Postgres query optimizer |
| (6 rows) |
| |
| select count(*) from tenk1 where stringu1 = 'GRAAAA'; |
| count |
| ------- |
| 15 |
| (1 row) |
| |
| reset max_parallel_workers; |
| reset parallel_leader_participation; |
| -- test that parallel_restricted function doesn't run in worker |
| alter table tenk1 set (parallel_workers = 4); |
| explain (verbose, costs off) |
| select sp_parallel_restricted(unique1) from tenk1 |
| where stringu1 = 'GRAAAA' order by 1; |
| QUERY PLAN |
| ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Gather Motion 3:1 (slice1; segments: 3) |
| Output: (sp_parallel_restricted(unique1)) |
| Merge Key: (sp_parallel_restricted(unique1)) |
| -> Sort |
| Output: (sp_parallel_restricted(unique1)) |
| Sort Key: (sp_parallel_restricted(tenk1.unique1)) |
| -> Seq Scan on public.tenk1 |
| Output: sp_parallel_restricted(unique1) |
| Filter: (tenk1.stringu1 = 'GRAAAA'::name) |
| Settings: enable_parallel = 'on', min_parallel_table_scan_size = '0', optimizer = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0' |
| Optimizer: Postgres query optimizer |
| (11 rows) |
| |
| -- test parallel plan when group by expression is in target list. |
| explain (costs off) |
| select length(stringu1) from tenk1 group by length(stringu1); |
| QUERY PLAN |
| --------------------------------------------------------------- |
| Gather Motion 12:1 (slice1; segments: 12) |
| -> HashAggregate |
| Group Key: (length((stringu1)::text)) |
| -> Redistribute Motion 12:12 (slice2; segments: 12) |
| Hash Key: (length((stringu1)::text)) |
| Hash Module: 3 |
| -> Parallel Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (8 rows) |
| |
| select length(stringu1) from tenk1 group by length(stringu1); |
| length |
| -------- |
| 6 |
| (1 row) |
| |
| explain (costs off) |
| select stringu1, count(*) from tenk1 group by stringu1 order by stringu1; |
| QUERY PLAN |
| --------------------------------------------------------------------- |
| Gather Motion 12:1 (slice1; segments: 12) |
| Merge Key: stringu1 |
| -> Sort |
| Sort Key: stringu1 |
| -> HashAggregate |
| Group Key: stringu1 |
| -> Redistribute Motion 12:12 (slice2; segments: 12) |
| Hash Key: stringu1 |
| Hash Module: 3 |
| -> Parallel Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (11 rows) |
| |
| -- test that parallel plan for aggregates is not selected when |
| -- target list contains parallel restricted clause. |
| explain (costs off) |
| select sum(sp_parallel_restricted(unique1)) from tenk1 |
| group by(sp_parallel_restricted(unique1)); |
| QUERY PLAN |
| ------------------------------------------------------------ |
| Gather Motion 3:1 (slice1; segments: 3) |
| -> HashAggregate |
| Group Key: (sp_parallel_restricted(unique1)) |
| -> Redistribute Motion 3:3 (slice2; segments: 3) |
| Hash Key: (sp_parallel_restricted(unique1)) |
| -> Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (7 rows) |
| |
| -- test prepared statement |
| prepare tenk1_count(integer) As select count((unique1)) from tenk1 where hundred > $1; |
| explain (costs off) execute tenk1_count(1); |
| QUERY PLAN |
| -------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 12:1 (slice1; segments: 12) |
| -> Partial Aggregate |
| -> Parallel Seq Scan on tenk1 |
| Filter: (hundred > 1) |
| Optimizer: Postgres query optimizer |
| (6 rows) |
| |
| execute tenk1_count(1); |
| count |
| ------- |
| 9800 |
| (1 row) |
| |
| deallocate tenk1_count; |
| -- test parallel plans for queries containing un-correlated subplans. |
| alter table tenk2 set (parallel_workers = 0); |
| explain (costs off) |
| select count(*) from tenk1 where (two, four) not in |
| (select hundred, thousand from tenk2 where thousand > 100); |
| QUERY PLAN |
| -------------------------------------------------------------------------------------------- |
| Aggregate |
| -> Gather Motion 12:1 (slice1; segments: 12) |
| -> Nested Loop Left Anti Semi (Not-In) Join |
| Join Filter: ((tenk1.two = tenk2.hundred) AND (tenk1.four = tenk2.thousand)) |
| -> Parallel Seq Scan on tenk1 |
| -> Materialize |
| -> Broadcast Motion 3:12 (slice2; segments: 3) |
| -> Seq Scan on tenk2 |
| Filter: (thousand > 100) |
| Optimizer: Postgres query optimizer |
| (10 rows) |
| |
| select count(*) from tenk1 where (two, four) not in |
| (select hundred, thousand from tenk2 where thousand > 100); |
| count |
| ------- |
| 10000 |
| (1 row) |
| |
| -- this is not parallel-safe due to use of random() within SubLink's testexpr: |
| explain (costs off) |
| select * from tenk1 where (unique1 + random())::integer not in |
| (select ten from tenk2); |
| QUERY PLAN |
| ----------------------------------------------------------------- |
| Gather Motion 3:1 (slice1; segments: 3) |
| -> Seq Scan on tenk1 |
| Filter: (SubPlan 1) |
| SubPlan 1 |
| -> Materialize |
| -> Broadcast Motion 3:3 (slice2; segments: 3) |
| -> Seq Scan on tenk2 |
| Optimizer: Postgres query optimizer |
| (8 rows) |
| |
| alter table tenk2 reset (parallel_workers); |
| -- test parallel plan for a query containing initplan. |
| set enable_indexscan = off; |
| set enable_indexonlyscan = off; |
| set enable_bitmapscan = off; |
| alter table tenk2 set (parallel_workers = 2); |
| explain (costs off) |
| select count(*) from tenk1 |
| where tenk1.unique1 = (Select max(tenk2.unique1) from tenk2); |
| QUERY PLAN |
| -------------------------------------------------------- |
| Aggregate |
| InitPlan 1 (returns $1) (slice2) |
| -> Finalize Aggregate |
| -> Gather Motion 6:1 (slice3; segments: 6) |
| -> Partial Aggregate |
| -> Parallel Seq Scan on tenk2 |
| -> Gather Motion 12:1 (slice1; segments: 12) |
| -> Parallel Seq Scan on tenk1 |
| Filter: (unique1 = $1) |
| Optimizer: Postgres query optimizer |
| (10 rows) |
| |
| select count(*) from tenk1 |
| where tenk1.unique1 = (Select max(tenk2.unique1) from tenk2); |
| count |
| ------- |
| 1 |
| (1 row) |
| |
| reset enable_indexscan; |
| reset enable_indexonlyscan; |
| reset enable_bitmapscan; |
| alter table tenk2 reset (parallel_workers); |
| -- test parallel index scans. |
| set enable_seqscan to off; |
| set enable_bitmapscan to off; |
| explain (costs off) |
| select count((unique1)) from tenk1 where hundred > 1; |
| QUERY PLAN |
| -------------------------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 12:1 (slice1; segments: 12) |
| -> Partial Aggregate |
| -> Parallel Index Scan using tenk1_hundred on tenk1 |
| Index Cond: (hundred > 1) |
| Optimizer: Postgres query optimizer |
| (6 rows) |
| |
| select count((unique1)) from tenk1 where hundred > 1; |
| count |
| ------- |
| 9800 |
| (1 row) |
| |
| -- test parallel index-only scans. |
| explain (costs off) |
| select count(*) from tenk1 where thousand > 95; |
| QUERY PLAN |
| -------------------------------------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 12:1 (slice1; segments: 12) |
| -> Partial Aggregate |
| -> Parallel Index Only Scan using tenk1_thous_tenthous on tenk1 |
| Index Cond: (thousand > 95) |
| Optimizer: Postgres query optimizer |
| (6 rows) |
| |
| select count(*) from tenk1 where thousand > 95; |
| count |
| ------- |
| 9040 |
| (1 row) |
| |
| -- test rescan cases too |
| set enable_material = false; |
| explain (costs off) |
| select * from |
| (select count(unique1) from tenk1 where hundred > 10) ss |
| right join (values (1),(2),(3)) v(x) on true; |
| QUERY PLAN |
| ----------------------------------------------------------------------- |
| Nested Loop Left Join |
| -> Values Scan on "*VALUES*" |
| -> Materialize |
| -> Finalize Aggregate |
| -> Gather Motion 3:1 (slice1; segments: 3) |
| -> Partial Aggregate |
| -> Index Scan using tenk1_hundred on tenk1 |
| Index Cond: (hundred > 10) |
| Optimizer: Postgres query optimizer |
| (9 rows) |
| |
| select * from |
| (select count(unique1) from tenk1 where hundred > 10) ss |
| right join (values (1),(2),(3)) v(x) on true; |
| count | x |
| -------+--- |
| 8900 | 1 |
| 8900 | 2 |
| 8900 | 3 |
| (3 rows) |
| |
| explain (costs off) |
| select * from |
| (select count(*) from tenk1 where thousand > 99) ss |
| right join (values (1),(2),(3)) v(x) on true; |
| QUERY PLAN |
| ----------------------------------------------------------------------------------- |
| Nested Loop Left Join |
| -> Values Scan on "*VALUES*" |
| -> Materialize |
| -> Finalize Aggregate |
| -> Gather Motion 3:1 (slice1; segments: 3) |
| -> Partial Aggregate |
| -> Index Only Scan using tenk1_thous_tenthous on tenk1 |
| Index Cond: (thousand > 99) |
| Optimizer: Postgres query optimizer |
| (9 rows) |
| |
| select * from |
| (select count(*) from tenk1 where thousand > 99) ss |
| right join (values (1),(2),(3)) v(x) on true; |
| count | x |
| -------+--- |
| 9000 | 1 |
| 9000 | 2 |
| 9000 | 3 |
| (3 rows) |
| |
| -- test rescans for a Limit node with a parallel node beneath it. |
| reset enable_seqscan; |
| set enable_indexonlyscan to off; |
| set enable_indexscan to off; |
| alter table tenk1 set (parallel_workers = 0); |
| alter table tenk2 set (parallel_workers = 1); |
| explain (costs off) |
| select count(*) from tenk1 |
| left join (select tenk2.unique1 from tenk2 order by 1 limit 1000) ss |
| on tenk1.unique1 < ss.unique1 + 1 |
| where tenk1.unique1 < 2; |
| QUERY PLAN |
| ------------------------------------------------------------------ |
| Aggregate |
| -> Nested Loop Left Join |
| Join Filter: (tenk1.unique1 < (tenk2.unique1 + 1)) |
| -> Gather Motion 3:1 (slice1; segments: 3) |
| -> Seq Scan on tenk1 |
| Filter: (unique1 < 2) |
| -> Materialize |
| -> Limit |
| -> Gather Motion 3:1 (slice2; segments: 3) |
| Merge Key: tenk2.unique1 |
| -> Limit |
| -> Sort |
| Sort Key: tenk2.unique1 |
| -> Seq Scan on tenk2 |
| Optimizer: Postgres query optimizer |
| (15 rows) |
| |
| select count(*) from tenk1 |
| left join (select tenk2.unique1 from tenk2 order by 1 limit 1000) ss |
| on tenk1.unique1 < ss.unique1 + 1 |
| where tenk1.unique1 < 2; |
| count |
| ------- |
| 1999 |
| (1 row) |
| |
| --reset the value of workers for each table as it was before this test. |
| alter table tenk1 set (parallel_workers = 4); |
| alter table tenk2 reset (parallel_workers); |
| reset enable_material; |
| reset enable_bitmapscan; |
| reset enable_indexonlyscan; |
| reset enable_indexscan; |
| -- test parallel bitmap heap scan. |
| set enable_seqscan to off; |
| set enable_indexscan to off; |
| set enable_hashjoin to off; |
| set enable_mergejoin to off; |
| set enable_material to off; |
| -- test prefetching, if the platform allows it |
| DO $$ |
| BEGIN |
| SET effective_io_concurrency = 50; |
| EXCEPTION WHEN invalid_parameter_value THEN |
| END $$; |
| set work_mem='64kB'; --set small work mem to force lossy pages |
| explain (costs off) |
| select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0; |
| QUERY PLAN |
| ------------------------------------------------------------------------------ |
| Finalize Aggregate |
| -> Gather Motion 12:1 (slice1; segments: 12) |
| -> Partial Aggregate |
| -> Nested Loop |
| -> Parallel Seq Scan on tenk2 |
| Filter: (thousand = 0) |
| -> Materialize |
| -> Broadcast Motion 3:12 (slice2; segments: 3) |
| -> Bitmap Heap Scan on tenk1 |
| Recheck Cond: (hundred > 1) |
| -> Bitmap Index Scan on tenk1_hundred |
| Index Cond: (hundred > 1) |
| Optimizer: Postgres query optimizer |
| (13 rows) |
| |
| select count(*) from tenk1, tenk2 where tenk1.hundred > 1 and tenk2.thousand=0; |
| count |
| ------- |
| 98000 |
| (1 row) |
| |
| create table bmscantest (a int, t text); |
| NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'a' as the Greenplum Database data distribution key for this table. |
| HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. |
| insert into bmscantest select r, 'fooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo' FROM generate_series(1,100000) r; |
| create index i_bmtest ON bmscantest(a); |
| select count(*) from bmscantest where a>1; |
| count |
| ------- |
| 99999 |
| (1 row) |
| |
| -- test accumulation of stats for parallel nodes |
| reset enable_seqscan; |
| alter table tenk2 set (parallel_workers = 0); |
| explain (analyze, timing off, summary off, costs off) |
| select count(*) from tenk1, tenk2 where tenk1.hundred > 1 |
| and tenk2.thousand=0; |
| QUERY PLAN |
| ------------------------------------------------------------------------------------------------------ |
| Finalize Aggregate (actual rows=1 loops=1) |
| -> Gather Motion 3:1 (slice1; segments: 3) (actual rows=3 loops=1) |
| -> Partial Aggregate (actual rows=1 loops=1) |
| -> Nested Loop (actual rows=49000 loops=1) |
| -> Seq Scan on tenk2 (actual rows=5 loops=1) |
| Filter: (thousand = 0) |
| Rows Removed by Filter: 3363 |
| -> Materialize (actual rows=9800 loops=5) |
| -> Broadcast Motion 3:3 (slice2; segments: 3) (actual rows=9800 loops=1) |
| -> Seq Scan on tenk1 (actual rows=3320 loops=1) |
| Filter: (hundred > 1) |
| Rows Removed by Filter: 66 |
| Optimizer: Postgres query optimizer |
| (13 rows) |
| |
| alter table tenk2 reset (parallel_workers); |
| reset work_mem; |
| create function explain_parallel_sort_stats() returns setof text |
| language plpgsql as |
| $$ |
| declare ln text; |
| begin |
| for ln in |
| explain (analyze, timing off, summary off, costs off) |
| select * from |
| (select ten from tenk1 where ten < 100 order by ten) ss |
| right join (values (1),(2),(3)) v(x) on true |
| loop |
| ln := regexp_replace(ln, 'Memory: \S*', 'Memory: xxx'); |
| return next ln; |
| end loop; |
| end; |
| $$; |
| -- test sort stats plan, disable parallel |
| set max_parallel_workers_per_gather = 0; |
| select * from explain_parallel_sort_stats(); |
| explain_parallel_sort_stats |
| ---------------------------------------------------------------------------------- |
| Nested Loop Left Join (actual rows=30000 loops=1) |
| -> Values Scan on "*VALUES*" (actual rows=3 loops=1) |
| -> Materialize (actual rows=10000 loops=3) |
| -> Gather Motion 3:1 (slice1; segments: 3) (actual rows=10000 loops=1) |
| Merge Key: tenk1.ten |
| -> Sort (actual rows=3386 loops=1) |
| Sort Key: tenk1.ten |
| Sort Method: quicksort Memory: xxx |
| -> Seq Scan on tenk1 (actual rows=3386 loops=1) |
| Filter: (ten < 100) |
| Optimizer: Postgres query optimizer |
| (11 rows) |
| |
| reset max_parallel_workers_per_gather; |
| reset enable_indexscan; |
| reset enable_hashjoin; |
| reset enable_mergejoin; |
| reset enable_material; |
| reset effective_io_concurrency; |
| drop table bmscantest; |
| drop function explain_parallel_sort_stats(); |
| -- test parallel merge join path. |
| analyze tenk2; |
| set enable_hashjoin to off; |
| set enable_nestloop to off; |
| explain (costs off) |
| select count(*) from tenk1, tenk2 where tenk1.unique1 = tenk2.unique1; |
| QUERY PLAN |
| ---------------------------------------------------------------------- |
| Finalize Aggregate |
| -> Gather Motion 3:1 (slice1; segments: 3) |
| -> Partial Aggregate |
| -> Merge Join |
| Merge Cond: (tenk1.unique1 = tenk2.unique1) |
| -> Index Only Scan using tenk1_unique1 on tenk1 |
| -> Index Only Scan using tenk2_unique1 on tenk2 |
| Optimizer: Postgres query optimizer |
| (10 rows) |
| |
| select count(*) from tenk1, tenk2 where tenk1.unique1 = tenk2.unique1; |
| count |
| ------- |
| 10000 |
| (1 row) |
| |
| reset enable_hashjoin; |
| reset enable_nestloop; |
| -- test gather merge |
| set enable_hashagg = false; |
| explain (costs off) |
| select count(*) from tenk1 group by twenty; |
| QUERY PLAN |
| ------------------------------------------------------------------ |
| Gather Motion 6:1 (slice1; segments: 6) |
| -> Finalize GroupAggregate |
| Group Key: twenty |
| -> Sort |
| Sort Key: twenty |
| -> Redistribute Motion 6:6 (slice2; segments: 6) |
| Hash Key: twenty |
| Hash Module: 3 |
| -> Partial GroupAggregate |
| Group Key: twenty |
| -> Sort |
| Sort Key: twenty |
| -> Parallel Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (14 rows) |
| |
| select count(*) from tenk1 group by twenty; |
| count |
| ------- |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| (20 rows) |
| |
| --test expressions in targetlist are pushed down for gather merge |
| create function sp_simple_func(var1 integer) returns integer |
| as $$ |
| begin |
| return var1 + 10; |
| end; |
| $$ language plpgsql PARALLEL SAFE; |
| explain (costs off, verbose) |
| select ten, sp_simple_func(ten) from tenk1 where ten < 100 order by ten; |
| QUERY PLAN |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Gather Motion 6:1 (slice1; segments: 6) |
| Output: ten, (sp_simple_func(ten)) |
| Merge Key: ten |
| -> Result |
| Output: ten, sp_simple_func(ten) |
| -> Sort |
| Output: ten |
| Sort Key: tenk1.ten |
| -> Parallel Seq Scan on public.tenk1 |
| Output: ten |
| Filter: (tenk1.ten < 100) |
| Settings: enable_hashagg = 'off', enable_parallel = 'on', min_parallel_table_scan_size = '0', optimizer = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0' |
| Optimizer: Postgres query optimizer |
| (13 rows) |
| |
| drop function sp_simple_func(integer); |
| -- test handling of SRFs in targetlist (bug in 10.0) |
| explain (costs off) |
| select count(*), generate_series(1,2) from tenk1 group by twenty; |
| QUERY PLAN |
| ------------------------------------------------------------------------ |
| Gather Motion 6:1 (slice1; segments: 6) |
| -> ProjectSet |
| -> Finalize GroupAggregate |
| Group Key: twenty |
| -> Sort |
| Sort Key: twenty |
| -> Redistribute Motion 6:6 (slice2; segments: 6) |
| Hash Key: twenty |
| Hash Module: 3 |
| -> Partial GroupAggregate |
| Group Key: twenty |
| -> Sort |
| Sort Key: twenty |
| -> Parallel Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (15 rows) |
| |
| select count(*), generate_series(1,2) from tenk1 group by twenty; |
| count | generate_series |
| -------+----------------- |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| 500 | 1 |
| 500 | 2 |
| (40 rows) |
| |
| -- test gather merge with parallel leader participation disabled |
| set parallel_leader_participation = off; |
| explain (costs off) |
| select count(*) from tenk1 group by twenty; |
| QUERY PLAN |
| ------------------------------------------------------------------ |
| Gather Motion 6:1 (slice1; segments: 6) |
| -> Finalize GroupAggregate |
| Group Key: twenty |
| -> Sort |
| Sort Key: twenty |
| -> Redistribute Motion 6:6 (slice2; segments: 6) |
| Hash Key: twenty |
| Hash Module: 3 |
| -> Partial GroupAggregate |
| Group Key: twenty |
| -> Sort |
| Sort Key: twenty |
| -> Parallel Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (14 rows) |
| |
| select count(*) from tenk1 group by twenty; |
| count |
| ------- |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| 500 |
| (20 rows) |
| |
| reset parallel_leader_participation; |
| --test rescan behavior of gather merge |
| set enable_material = false; |
| explain (costs off) |
| select * from |
| (select string4, count(unique2) |
| from tenk1 group by string4 order by string4) ss |
| right join (values (1),(2),(3)) v(x) on true; |
| QUERY PLAN |
| ------------------------------------------------------------------------------ |
| Nested Loop Left Join |
| -> Values Scan on "*VALUES*" |
| -> Materialize |
| -> Gather Motion 3:1 (slice1; segments: 3) |
| -> Finalize GroupAggregate |
| Group Key: tenk1.string4 |
| -> Sort |
| Sort Key: tenk1.string4 |
| -> Redistribute Motion 3:3 (slice2; segments: 3) |
| Hash Key: tenk1.string4 |
| -> Partial GroupAggregate |
| Group Key: tenk1.string4 |
| -> Sort |
| Sort Key: tenk1.string4 |
| -> Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (16 rows) |
| |
| select * from |
| (select string4, count(unique2) |
| from tenk1 group by string4 order by string4) ss |
| right join (values (1),(2),(3)) v(x) on true; |
| string4 | count | x |
| ---------+-------+--- |
| AAAAxx | 2500 | 1 |
| HHHHxx | 2500 | 1 |
| VVVVxx | 2500 | 1 |
| OOOOxx | 2500 | 1 |
| AAAAxx | 2500 | 2 |
| HHHHxx | 2500 | 2 |
| VVVVxx | 2500 | 2 |
| OOOOxx | 2500 | 2 |
| AAAAxx | 2500 | 3 |
| HHHHxx | 2500 | 3 |
| VVVVxx | 2500 | 3 |
| OOOOxx | 2500 | 3 |
| (12 rows) |
| |
| reset enable_material; |
| reset enable_hashagg; |
| -- check parallelized int8 aggregate (bug #14897) |
| explain (costs off) |
| select avg(unique1::int8) from tenk1; |
| QUERY PLAN |
| ------------------------------------------------ |
| Finalize Aggregate |
| -> Gather Motion 6:1 (slice1; segments: 6) |
| -> Partial Aggregate |
| -> Parallel Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (5 rows) |
| |
| select avg(unique1::int8) from tenk1; |
| avg |
| ----------------------- |
| 4999.5000000000000000 |
| (1 row) |
| |
| -- gather merge test with a LIMIT |
| explain (costs off) |
| select fivethous from tenk1 order by fivethous limit 4; |
| QUERY PLAN |
| ---------------------------------------------------- |
| Limit |
| -> Gather Motion 6:1 (slice1; segments: 6) |
| Merge Key: fivethous |
| -> Limit |
| -> Sort |
| Sort Key: fivethous |
| -> Parallel Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (8 rows) |
| |
| select fivethous from tenk1 order by fivethous limit 4; |
| fivethous |
| ----------- |
| 0 |
| 0 |
| 1 |
| 1 |
| (4 rows) |
| |
| -- gather merge test with 0 worker |
| set max_parallel_workers = 0; |
| explain (costs off) |
| select string4 from tenk1 order by string4 limit 5; |
| QUERY PLAN |
| ---------------------------------------------------- |
| Limit |
| -> Gather Motion 6:1 (slice1; segments: 6) |
| Merge Key: string4 |
| -> Limit |
| -> Sort |
| Sort Key: string4 |
| -> Parallel Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (8 rows) |
| |
| select string4 from tenk1 order by string4 limit 5; |
| string4 |
| --------- |
| AAAAxx |
| AAAAxx |
| AAAAxx |
| AAAAxx |
| AAAAxx |
| (5 rows) |
| |
| -- gather merge test with 0 workers, with parallel leader |
| -- participation disabled (the leader will have to run the plan |
| -- despite the setting) |
| set parallel_leader_participation = off; |
| explain (costs off) |
| select string4 from tenk1 order by string4 limit 5; |
| QUERY PLAN |
| ---------------------------------------------------- |
| Limit |
| -> Gather Motion 6:1 (slice1; segments: 6) |
| Merge Key: string4 |
| -> Limit |
| -> Sort |
| Sort Key: string4 |
| -> Parallel Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (8 rows) |
| |
| select string4 from tenk1 order by string4 limit 5; |
| string4 |
| --------- |
| AAAAxx |
| AAAAxx |
| AAAAxx |
| AAAAxx |
| AAAAxx |
| (5 rows) |
| |
| reset parallel_leader_participation; |
| reset max_parallel_workers; |
| SAVEPOINT settings; |
| SET LOCAL force_parallel_mode = 1; |
| explain (costs off) |
| select stringu1::int2 from tenk1 where unique1 = 1; |
| QUERY PLAN |
| -------------------------------------------------------- |
| Gather Motion 2:1 (slice1; segments: 2) |
| -> Parallel Index Scan using tenk1_unique1 on tenk1 |
| Index Cond: (unique1 = 1) |
| Optimizer: Postgres query optimizer |
| (4 rows) |
| |
| ROLLBACK TO SAVEPOINT settings; |
| -- exercise record typmod remapping between backends |
| CREATE FUNCTION make_record(n int) |
| RETURNS RECORD LANGUAGE plpgsql PARALLEL SAFE AS |
| $$ |
| BEGIN |
| RETURN CASE n |
| WHEN 1 THEN ROW(1) |
| WHEN 2 THEN ROW(1, 2) |
| WHEN 3 THEN ROW(1, 2, 3) |
| WHEN 4 THEN ROW(1, 2, 3, 4) |
| ELSE ROW(1, 2, 3, 4, 5) |
| END; |
| END; |
| $$; |
| SAVEPOINT settings; |
| SET LOCAL force_parallel_mode = 1; |
| SELECT make_record(x) FROM (SELECT generate_series(1, 5) x) ss ORDER BY x; |
| make_record |
| ------------- |
| (1) |
| (1,2) |
| (1,2,3) |
| (1,2,3,4) |
| (1,2,3,4,5) |
| (5 rows) |
| |
| ROLLBACK TO SAVEPOINT settings; |
| DROP function make_record(n int); |
| -- test the sanity of parallel query after the active role is dropped. |
| drop role if exists regress_parallel_worker; |
| create role regress_parallel_worker; |
| set role regress_parallel_worker; |
| reset session authorization; |
| drop role regress_parallel_worker; |
| set force_parallel_mode = 1; |
| select count(*) from tenk1; |
| count |
| ------- |
| 10000 |
| (1 row) |
| |
| reset force_parallel_mode; |
| reset role; |
| -- Window function calculation can't be pushed to workers. |
| -- CBDB_PARALLEL: window function's subpath could be parallel. |
| explain (costs off, verbose) |
| select count(*) from tenk1 a where (unique1, two) in |
| (select unique1, row_number() over() from tenk1 b); |
| QUERY PLAN |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Finalize Aggregate |
| Output: count(*) |
| -> Gather Motion 6:1 (slice1; segments: 6) |
| Output: (PARTIAL count(*)) |
| -> Partial Aggregate |
| Output: PARTIAL count(*) |
| -> Parallel Hash Semi Join |
| Hash Cond: ((a.unique1 = b.unique1) AND (a.two = (row_number() OVER (?)))) |
| -> Parallel Seq Scan on public.tenk1 a |
| Output: a.unique1, a.unique2, a.two, a.four, a.ten, a.twenty, a.hundred, a.thousand, a.twothousand, a.fivethous, a.tenthous, a.odd, a.even, a.stringu1, a.stringu2, a.string4 |
| -> Parallel Hash |
| Output: b.unique1, (row_number() OVER (?)) |
| -> Redistribute Motion 1:6 (slice2; segments: 1) |
| Output: b.unique1, (row_number() OVER (?)) |
| Hash Key: b.unique1 |
| Hash Module: 3 |
| -> WindowAgg |
| Output: b.unique1, row_number() OVER (?) |
| -> Gather Motion 6:1 (slice3; segments: 6) |
| Output: b.unique1 |
| -> Parallel Seq Scan on public.tenk1 b |
| Output: b.unique1 |
| Settings: enable_parallel = 'on', min_parallel_table_scan_size = '0', optimizer = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0' |
| Optimizer: Postgres query optimizer |
| (24 rows) |
| |
| -- LIMIT/OFFSET within sub-selects can't be pushed to workers. |
| explain (costs off) |
| select * from tenk1 a where two in |
| (select two from tenk1 b where stringu1 like '%AAAA' limit 3); |
| QUERY PLAN |
| --------------------------------------------------------------------------------------- |
| Gather Motion 3:1 (slice1; segments: 3) |
| -> Hash Join |
| Hash Cond: (a.two = b.two) |
| -> Seq Scan on tenk1 a |
| -> Hash |
| -> Broadcast Motion 1:3 (slice2; segments: 1) |
| -> HashAggregate |
| Group Key: b.two |
| -> Limit |
| -> Gather Motion 3:1 (slice3; segments: 3) |
| -> Limit |
| -> Seq Scan on tenk1 b |
| Filter: (stringu1 ~~ '%AAAA'::text) |
| Optimizer: Postgres query optimizer |
| (14 rows) |
| |
| -- to increase the parallel query test coverage |
| SAVEPOINT settings; |
| SET LOCAL force_parallel_mode = 1; |
| -- CBDB_PARALLEL_FIXME: analyze actual rows may be different by running multiple times. |
| EXPLAIN (timing off, summary off, costs off) SELECT * FROM tenk1; |
| QUERY PLAN |
| ------------------------------------------ |
| Gather Motion 6:1 (slice1; segments: 6) |
| -> Parallel Seq Scan on tenk1 |
| Optimizer: Postgres query optimizer |
| (3 rows) |
| |
| ROLLBACK TO SAVEPOINT settings; |
| -- provoke error in worker |
| -- (make the error message long enough to require multiple bufferloads) |
| SAVEPOINT settings; |
| SET LOCAL force_parallel_mode = 1; |
| select (stringu1 || repeat('abcd', 5000))::int2 from tenk1 where unique1 = 1; |
| ERROR: invalid input syntax for type smallint: "BAAAAAabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd" (seg1 slice1 127.0.1.1:9003 pid=1200934) |
| ROLLBACK TO SAVEPOINT settings; |
| -- test interaction with set-returning functions |
| SAVEPOINT settings; |
| -- multiple subqueries under a single Gather node |
| -- must set parallel_setup_cost > 0 to discourage multiple Gather nodes |
| SET LOCAL parallel_setup_cost = 10; |
| EXPLAIN (COSTS OFF) |
| SELECT unique1 FROM tenk1 WHERE fivethous = tenthous + 1 |
| UNION ALL |
| SELECT unique1 FROM tenk1 WHERE fivethous = tenthous + 1; |
| QUERY PLAN |
| ---------------------------------------------------- |
| Gather Motion 6:1 (slice1; segments: 6) |
| -> Parallel Append |
| -> Parallel Seq Scan on tenk1 |
| Filter: (fivethous = (tenthous + 1)) |
| -> Parallel Seq Scan on tenk1 tenk1_1 |
| Filter: (fivethous = (tenthous + 1)) |
| Optimizer: Postgres query optimizer |
| (7 rows) |
| |
| ROLLBACK TO SAVEPOINT settings; |
| -- can't use multiple subqueries under a single Gather node due to initPlans |
| EXPLAIN (COSTS OFF) |
| SELECT unique1 FROM tenk1 WHERE fivethous = |
| (SELECT unique1 FROM tenk1 WHERE fivethous = 1 LIMIT 1) |
| UNION ALL |
| SELECT unique1 FROM tenk1 WHERE fivethous = |
| (SELECT unique2 FROM tenk1 WHERE fivethous = 1 LIMIT 1) |
| ORDER BY 1; |
| QUERY PLAN |
| -------------------------------------------------------------------------- |
| Gather Motion 6:1 (slice1; segments: 6) |
| Merge Key: tenk1.unique1 |
| -> Sort |
| Sort Key: tenk1.unique1 |
| -> Parallel Append |
| -> Parallel Seq Scan on tenk1 |
| Filter: (fivethous = $1) |
| InitPlan 2 (returns $1) (slice2) |
| -> Limit |
| -> Gather Motion 6:1 (slice3; segments: 6) |
| -> Limit |
| -> Parallel Seq Scan on tenk1 tenk1_3 |
| Filter: (fivethous = 1) |
| -> Parallel Seq Scan on tenk1 tenk1_1 |
| Filter: (fivethous = $0) |
| InitPlan 1 (returns $0) (slice4) |
| -> Limit |
| -> Gather Motion 6:1 (slice5; segments: 6) |
| -> Limit |
| -> Parallel Seq Scan on tenk1 tenk1_2 |
| Filter: (fivethous = 1) |
| Optimizer: Postgres query optimizer |
| (22 rows) |
| |
| -- test interaction with SRFs |
| SELECT * FROM information_schema.foreign_data_wrapper_options |
| ORDER BY 1, 2, 3; |
| foreign_data_wrapper_catalog | foreign_data_wrapper_name | option_name | option_value |
| ------------------------------+---------------------------+-------------+-------------- |
| (0 rows) |
| |
| EXPLAIN (VERBOSE, COSTS OFF) |
| SELECT generate_series(1, two), array(select generate_series(1, two)) |
| FROM tenk1 ORDER BY tenthous; |
| QUERY PLAN |
| ----------------------------------------------------------------------------------------------------------------------------------------------- |
| Gather Motion 3:1 (slice1; segments: 3) |
| Output: (generate_series(1, tenk1.two)), ((SubPlan 1)), tenk1.tenthous |
| Merge Key: tenk1.tenthous |
| -> ProjectSet |
| Output: generate_series(1, tenk1.two), (SubPlan 1), tenk1.tenthous |
| -> Result |
| Output: tenk1.two, tenk1.tenthous |
| -> Sort |
| Output: tenk1.tenthous, tenk1.two |
| Sort Key: tenk1.tenthous |
| -> Seq Scan on public.tenk1 |
| Output: tenk1.tenthous, tenk1.two |
| SubPlan 1 |
| -> ProjectSet |
| Output: generate_series(1, tenk1.two) |
| -> Result |
| Settings: enable_parallel = 'on', min_parallel_table_scan_size = '0', optimizer = 'off', parallel_setup_cost = '0', parallel_tuple_cost = '0' |
| Optimizer: Postgres query optimizer |
| (18 rows) |
| |
| -- test passing expanded-value representations to workers |
| CREATE FUNCTION make_some_array(int,int) returns int[] as |
| $$declare x int[]; |
| begin |
| x[1] := $1; |
| x[2] := $2; |
| return x; |
| end$$ language plpgsql parallel safe; |
| CREATE TABLE fooarr(f1 text, f2 int[], f3 text); |
| NOTICE: Table doesn't have 'DISTRIBUTED BY' clause -- Using column named 'f1' as the Greenplum Database data distribution key for this table. |
| HINT: The 'DISTRIBUTED BY' clause determines the distribution of data. Make sure column(s) chosen are the optimal data distribution key to minimize skew. |
| INSERT INTO fooarr VALUES('1', ARRAY[1,2], 'one'); |
| PREPARE pstmt(text, int[]) AS SELECT * FROM fooarr WHERE f1 = $1 AND f2 = $2; |
| EXPLAIN (COSTS OFF) EXECUTE pstmt('1', make_some_array(1,2)); |
| QUERY PLAN |
| ------------------------------------------------------------------ |
| Gather Motion 2:1 (slice1; segments: 2) |
| -> Parallel Seq Scan on fooarr |
| Filter: ((f1 = '1'::text) AND (f2 = '{1,2}'::integer[])) |
| Optimizer: Postgres query optimizer |
| (4 rows) |
| |
| EXECUTE pstmt('1', make_some_array(1,2)); |
| f1 | f2 | f3 |
| ----+-------+----- |
| 1 | {1,2} | one |
| (1 row) |
| |
| DEALLOCATE pstmt; |
| -- test interaction between subquery and partial_paths |
| CREATE VIEW tenk1_vw_sec WITH (security_barrier) AS SELECT * FROM tenk1; |
| EXPLAIN (COSTS OFF) |
| SELECT 1 FROM tenk1_vw_sec |
| WHERE (SELECT sum(f1) FROM int4_tbl WHERE f1 < unique1) < 100; |
| QUERY PLAN |
| ----------------------------------------------------------------------------- |
| Gather Motion 3:1 (slice1; segments: 3) |
| -> Subquery Scan on tenk1_vw_sec |
| Filter: ((SubPlan 1) < 100) |
| -> Seq Scan on tenk1 |
| SubPlan 1 |
| -> Aggregate |
| -> Result |
| Filter: (int4_tbl.f1 < tenk1_vw_sec.unique1) |
| -> Materialize |
| -> Broadcast Motion 3:3 (slice2; segments: 3) |
| -> Seq Scan on int4_tbl |
| Optimizer: Postgres query optimizer |
| (12 rows) |
| |
| rollback; |
| reset enable_parallel; |
| reset optimizer; |