blob: 6f5396cefcd3dbeed69ec3a6af7a0daf4c1b8af0 [file] [log] [blame]
-- Test DELETE and UPDATE on an inherited table.
-- The special aspect of this table is that the inherited table has
-- a different distribution key. 'p' table's distribution key matches
-- that of 'r', but 'p2's doesn't. Test that the planner adds a Motion
-- node correctly for p2.
create table todelete (a int) distributed by (a);
create table parent (a int, b int, c int) distributed by (a);
create table child (a int, b int, c int) inherits (parent) distributed by (b);
insert into parent select g, g, g from generate_series(1,5) g;
insert into child select g, g, g from generate_series(6,10) g;
insert into todelete select generate_series(3,4);
delete from parent using todelete where parent.a = todelete.a;
insert into todelete select generate_series(5,7);
update parent set c=c+100 from todelete where parent.a = todelete.a;
select * from parent;
drop table todelete;
drop table child;
drop table parent;
-- This is similar to the above, but with a partitioned table (which is
-- implemented by inheritance) rather than an explicitly inherited table.
-- The scans on some of the partitions degenerate into Result nodes with
-- False one-time filter, which don't need a Motion node.
create table todelete (a int, b int) distributed by (a);
create table target (a int, b int, c int)
distributed by (a)
partition by range (c) (start(1) end(5) every(1), default partition extra);
insert into todelete select g, g % 4 from generate_series(1, 10) g;
insert into target select g, 0, 3 from generate_series(1, 5) g;
insert into target select g, 0, 1 from generate_series(1, 5) g;
delete from target where c = 3 and a in (select b from todelete);
insert into todelete values (1, 5);
update target set b=target.b+100 where c = 3 and a in (select b from todelete);
select * from target;
-- Also test an update with a qual that doesn't match any partition. The
-- Append degenerates into a dummy Result with false One-Time Filter.
alter table target drop default partition;
update target set b = 10 where c = 10;
drop table todelete;
drop table target;
--
-- Test updated on inheritance parent table, where some child tables need a
-- Split Update, but not all.
--
create table base_tbl (a int4, b int4) distributed by (a);
create table child_a (a int4, b int4) inherits (base_tbl) distributed by (a);
create table child_b (a int4, b int4) inherits (base_tbl) distributed by (b);
insert into base_tbl select g, g from generate_series(1, 5) g;
explain (costs off) update base_tbl set a=a+1;
update base_tbl set a = 5;
--
-- Explicit Distribution motion must be added if any of the child nodes
-- contains any motion excluding the motions in initplans.
-- These test cases and expectation are applicable for GPDB planner not for ORCA.
--
SET gp_autostats_mode = NONE;
CREATE TABLE keo1 ( user_vie_project_code_pk character varying(24), user_vie_fiscal_year_period_sk character varying(24), user_vie_act_cntr_marg_cum character varying(24)) DISTRIBUTED RANDOMLY;
INSERT INTO keo1 VALUES ('1', '1', '1');
CREATE TABLE keo2 ( projects_pk character varying(24)) DISTRIBUTED RANDOMLY;
INSERT INTO keo2 VALUES ('1');
CREATE TABLE keo3 ( sky_per character varying(24), bky_per character varying(24)) DISTRIBUTED BY (sky_per);
INSERT INTO keo3 VALUES ('1', '1');
CREATE TABLE keo4 ( keo_para_required_period character varying(6), keo_para_budget_date character varying(24)) DISTRIBUTED RANDOMLY;
INSERT INTO keo4 VALUES ('1', '1');
ANALYZE keo1, keo2, keo3, keo4;
-- Explicit Redistribution motion should be added in case of GPDB Planner (test case not applicable for ORCA)
EXPLAIN (COSTS OFF) UPDATE keo1 SET user_vie_act_cntr_marg_cum = 234.682 FROM
( SELECT a.user_vie_project_code_pk FROM keo1 a INNER JOIN keo2 b
ON b.projects_pk=a.user_vie_project_code_pk
WHERE a.user_vie_fiscal_year_period_sk =
(SELECT MAX (sky_per) FROM keo3 WHERE bky_per =
(SELECT keo4.keo_para_required_period FROM keo4 WHERE keo_para_budget_date =
(SELECT min (keo4.keo_para_budget_date) FROM keo4)))
) t1
WHERE t1.user_vie_project_code_pk = keo1.user_vie_project_code_pk;
UPDATE keo1 SET user_vie_act_cntr_marg_cum = 234.682 FROM
( SELECT a.user_vie_project_code_pk FROM keo1 a INNER JOIN keo2 b
ON b.projects_pk=a.user_vie_project_code_pk
WHERE a.user_vie_fiscal_year_period_sk =
(SELECT MAX (sky_per) FROM keo3 WHERE bky_per =
(SELECT keo4.keo_para_required_period FROM keo4 WHERE keo_para_budget_date =
(SELECT min (keo4.keo_para_budget_date) FROM keo4)))
) t1
WHERE t1.user_vie_project_code_pk = keo1.user_vie_project_code_pk;
SELECT user_vie_act_cntr_marg_cum FROM keo1;
-- Explicit Redistribution motion should not be added in case of GPDB Planner (test case not applicable to ORCA)
CREATE TABLE keo5 (x int, y int) DISTRIBUTED BY (x);
INSERT INTO keo5 VALUES (1,1);
EXPLAIN (COSTS OFF) DELETE FROM keo5 WHERE x IN (SELECT x FROM keo5 WHERE EXISTS (SELECT x FROM keo5 WHERE x < 2));
DELETE FROM keo5 WHERE x IN (SELECT x FROM keo5 WHERE EXISTS (SELECT x FROM keo5 WHERE x < 2));
SELECT x FROM keo5;
RESET gp_autostats_mode;
DROP TABLE keo1;
DROP TABLE keo2;
DROP TABLE keo3;
DROP TABLE keo4;
DROP TABLE keo5;
--
-- text types. We should support the following updates.
--
CREATE TEMP TABLE ttab1 (a varchar(15), b integer) DISTRIBUTED BY (a);
CREATE TEMP TABLE ttab2 (a varchar(15), b integer) DISTRIBUTED BY (a);
UPDATE ttab1 SET b = ttab2.b FROM ttab2 WHERE ttab1.a = ttab2.a;
DROP TABLE ttab1;
DROP TABLE ttab2;
CREATE TEMP TABLE ttab1 (a text, b integer) DISTRIBUTED BY (a);
CREATE TEMP TABLE ttab2 (a text, b integer) DISTRIBUTED BY (a);
UPDATE ttab1 SET b = ttab2.b FROM ttab2 WHERE ttab1.a = ttab2.a;
DROP TABLE ttab1;
DROP TABLE ttab2;
CREATE TEMP TABLE ttab1 (a varchar, b integer) DISTRIBUTED BY (a);
CREATE TEMP TABLE ttab2 (a varchar, b integer) DISTRIBUTED BY (a);
UPDATE ttab1 SET b = ttab2.b FROM ttab2 WHERE ttab1.a = ttab2.a;
DROP TABLE ttab1;
DROP TABLE ttab2;
CREATE TEMP TABLE ttab1 (a char(15), b integer) DISTRIBUTED BY (a);
CREATE TEMP TABLE ttab2 (a char(15), b integer) DISTRIBUTED BY (a);
UPDATE ttab1 SET b = ttab2.b FROM ttab2 WHERE ttab1.a = ttab2.a;
DROP TABLE IF EXISTS update_distr_key;
CREATE TEMP TABLE update_distr_key (a int, b int) DISTRIBUTED BY (a);
INSERT INTO update_distr_key select i, i* 10 from generate_series(0, 9) i;
UPDATE update_distr_key SET a = 5 WHERE b = 10;
SELECT * from update_distr_key;
DROP TABLE update_distr_key;
-- below cases is to test multi-hash-cols
CREATE TABLE tab3(c1 int, c2 int, c3 int, c4 int, c5 int) DISTRIBUTED BY (c1, c2, c3);
CREATE TABLE tab5(c1 int, c2 int, c3 int, c4 int, c5 int) DISTRIBUTED BY (c1, c2, c3, c4, c5);
INSERT INTO tab3 SELECT i, i, i, i, i FROM generate_series(1, 10)i;
INSERT INTO tab5 SELECT i, i, i, i, i FROM generate_series(1, 10)i;
-- test tab3
SELECT gp_segment_id, * FROM tab3;
UPDATE tab3 set c1 = 9 where c4 = 1;
SELECT gp_segment_id, * FROM tab3;
UPDATE tab3 set (c1,c2) = (5,6) where c4 = 1;
SELECT gp_segment_id, * FROM tab3;
UPDATE tab3 set (c1,c2,c3) = (3,2,1) where c4 = 1;
SELECT gp_segment_id, * FROM tab3;
UPDATE tab3 set c1 = 11 where c2 = 10 and c2 < 1;
SELECT gp_segment_id, * FROM tab3;
-- test tab5
SELECT gp_segment_id, * FROM tab5;
UPDATE tab5 set c1 = 1000 where c4 = 1;
SELECT gp_segment_id, * FROM tab5;
UPDATE tab5 set (c1,c2) = (9,10) where c4 = 1;
SELECT gp_segment_id, * FROM tab5;
UPDATE tab5 set (c1,c2,c4) = (5,8,6) where c4 = 1;
SELECT gp_segment_id, * FROM tab5;
UPDATE tab5 set (c1,c2,c3,c4,c5) = (1,2,3,0,6) where c5 = 1;
SELECT gp_segment_id, * FROM tab5;
UPDATE tab5 set c1 = 11 where c3 = 10 and c3 < 1;
SELECT gp_segment_id, * FROM tab5;
EXPLAIN (COSTS OFF ) UPDATE tab3 SET C1 = C1 + 1, C5 = C5+1;
-- clean up
drop table tab3;
drop table tab5;
-- Update distribution key
-- start_ignore
drop table if exists r;
drop table if exists s;
drop table if exists update_dist;
drop table if exists update_ao_table;
drop table if exists update_aoco_table;
-- end_ignore
-- Update normal table distribution key
create table update_dist(a int) distributed by (a);
insert into update_dist values(1);
update update_dist set a=0 where a=1;
select * from update_dist;
-- Update distribution key with join
create table r (a int, b int) distributed by (a);
create table s (a int, b int) distributed by (a);
insert into r select generate_series(1, 5), generate_series(1, 5) * 2;
insert into s select generate_series(1, 5), generate_series(1, 5) * 2;
select * from r;
select * from s;
update r set a = r.a + 1 from s where r.a = s.a;
select * from r;
update r set a = r.a + 1 where a in (select a from s);
select * from r;
-- Update redistribution
delete from r;
delete from s;
insert into r select generate_series(1, 5), generate_series(1, 5);
insert into s select generate_series(1, 5), generate_series(1, 5) * 2;
select * from r;
select * from s;
update r set a = r.a + 1 from s where r.b = s.b;
select * from r;
update r set a = r.a + 1 where b in (select b from s);
select * from r;
-- Update hash aggreate group by
delete from r;
delete from s;
insert into r select generate_series(1, 5), generate_series(1, 5) * 2;
insert into s select generate_series(1, 5), generate_series(1, 5);
select * from r;
select * from s;
update s set a = s.a + 1 where exists (select 1 from r where s.a = r.b);
select * from s;
-- Update ao table distribution key
create table update_ao_table (a int, b int) WITH (appendonly=true) distributed by (a);
insert into update_ao_table select g, g from generate_series(1, 5) g;
select * from update_ao_table;
update update_ao_table set a = a + 1 where b = 3;
select * from update_ao_table;
-- Update aoco table distribution key
create table update_aoco_table (a int, b int) WITH (appendonly=true, orientation=column) distributed by (a);
insert into update_aoco_table select g,g from generate_series(1, 5) g;
select * from update_aoco_table;
update update_aoco_table set a = a + 1 where b = 3;
select * from update_aoco_table;
-- Update prepare
delete from s;
insert into s select generate_series(1, 5), generate_series(1, 5);
select * from r;
select * from s;
prepare update_s(int) as update s set a = s.a + $1 where exists (select 1 from r where s.a = r.b);
execute update_s(10);
select * from s;
-- Confirm that a split update is not created for a table excluded by
-- constraints in the planner.
create table nosplitupdate (a int) distributed by (a);
explain update nosplitupdate set a=0 where a=1 and a<1;
-- test split-update when split-node's flow is entry
create table tsplit_entry (c int);
insert into tsplit_entry values (1), (2);
analyze tsplit_entry;
-- start_ignore
-- gp_segment_configuration scan is different when using different FTS
explain update tsplit_entry set c = s.a from (select count(*) as a from gp_segment_configuration) s;
-- end_ignore
update tsplit_entry set c = s.a from (select count(*) as a from gp_segment_configuration) s;
CREATE TABLE update_gp_foo (
a_dist int,
b int,
c_part int,
d int
)
WITH (appendonly=false) DISTRIBUTED BY (a_dist) PARTITION BY RANGE(c_part)
(
PARTITION p20190305 START (1) END (2) WITH (tablename='update_gp_foo_1_prt_p20190305', appendonly=false)
);
CREATE TABLE update_gp_foo1 (
a_dist int,
b int,
c_part int,
d int
)
WITH (appendonly=false) DISTRIBUTED BY (a_dist) PARTITION BY RANGE(c_part)
(
PARTITION p20190305 START (1) END (2) WITH (tablename='update_gp_foo1_1_prt_p20190305', appendonly=false)
);
INSERT INTO update_gp_foo VALUES (12, 40, 1, 50);
INSERT INTO update_gp_foo1 VALUES (12, 3, 1, 50);
UPDATE update_gp_foo
SET b = update_gp_foo.c_part,
d = update_gp_foo1.a_dist
FROM update_gp_foo1;
SELECT * from update_gp_foo;
-- Test insert on conflict do update
-- Insert on conflict do update is an insert statement but might
-- invoke ExecUpdate on segments, but updating distkeys of a table
-- may lead to wrong data distribution. We will check this before
-- planning, if a `insert on conflict do update` statement set the
-- dist keys of the table, it will raise an error.
-- See github issue: https://github.com/greenplum-db/gpdb/issues/9444
create table t_insert_on_conflict_update_distkey(a int, b int) distributed by (a);
create unique index uidx_t_insert_on_conflict_update_distkey on t_insert_on_conflict_update_distkey(a, b);
-- the following statement should error out because the on conflict update want to
-- modify the tuple's distkey which might lead to wrong data distribution
insert into t_insert_on_conflict_update_distkey values (1, 1) on conflict(a, b) do update set a = 1;
drop index uidx_t_insert_on_conflict_update_distkey;
drop table t_insert_on_conflict_update_distkey;
-- randomly distributed table cannot add unique constrain, so next we test replicated table
create table t_insert_on_conflict_update_distkey(a int, b int) distributed replicated;
create unique index uidx_t_insert_on_conflict_update_distkey on t_insert_on_conflict_update_distkey(a, b);
-- the following statement should succeed because replicated table does not contain distkey
insert into t_insert_on_conflict_update_distkey values (1, 1) on conflict(a, b) do update set a = 1;
-- Some tests on a partitioned table.
CREATE TABLE update_gp_rangep (a int, b int, orig_a int) DISTRIBUTED BY (b) PARTITION BY RANGE (a);
CREATE TABLE update_gp_rangep_1_to_10 PARTITION OF update_gp_rangep FOR VALUES FROM (1) TO (10);
CREATE TABLE update_gp_rangep_10_to_20 PARTITION OF update_gp_rangep FOR VALUES FROM (10) TO (20);
INSERT INTO update_gp_rangep SELECT g, g, g FROM generate_series(1, 4) g;
-- Simple case: Same partition, same node.
UPDATE update_gp_rangep SET a = 9 WHERE a = 1;
-- Distribution key update, same partition.
UPDATE update_gp_rangep SET b = 1 WHERE a = 2;
-- Move row to different partition, but no change in distribution key
UPDATE update_gp_rangep SET a = 10 WHERE a = 3;
-- Move row to different partition and also change distribution key
UPDATE update_gp_rangep SET a = 11, b = 1 WHERE a = 4;
SELECT tableoid::regclass, * FROM update_gp_rangep ORDER BY orig_a;
-- Also do a lookup with specific distribution key. If the rows were not
-- correctly moved across segments, this would fail to find them, assuming
-- that direct dispatch is effective.
SELECT tableoid::regclass, * FROM update_gp_rangep WHERE b = 1;
-- Test for update with LASJ_NOTIN
-- See Issue: https://github.com/greenplum-db/gpdb/issues/13265
-- Actually master branch does not have the above issue even master
-- does have the same problematic code (other parts of code are
-- refactored). Also cherry-pick the case to master and keep it
-- since more test cases do no harm.
create table t1_13265(a int, b int, c int, d int) distributed by (a);
create table t2_13265(a int, b int, c int, d int) distributed by (a);
insert into t1_13265 values (1, null, 1, 1);
insert into t2_13265 values (2, null, 2, 2);
explain (verbose, costs off)
update t1_13265 set b = 2 where
(c, d) not in (select c, d from t2_13265 where a = 2);
update t1_13265 set b = 2 where
(c, d) not in (select c, d from t2_13265 where a = 2);
select * from t1_13265;
-- test for update on partition table
CREATE TABLE into_table (
a numeric(10,0) NOT NULL,
b numeric(10,0) NOT NULL,
c numeric(10,0) NOT NULL,
d character varying(4),
e character varying(10),
f int
) DISTRIBUTED BY (a, b, c) PARTITION BY RANGE(f) (start (1) end(5) every(1));
CREATE TABLE from_table (
a numeric(10,0) NOT NULL,
b numeric(10,0) NOT NULL,
c numeric(10,0) NOT NULL,
d character varying(4),
e character varying(10),
f int
) DISTRIBUTED BY (a);
insert into into_table select i*1.5,i*2,i*3,'dd'||i,'ee'||i, i from generate_series(1,4) i;
insert into from_table select i*1.5,i*2,i*3,'xx'||i,'yy'||i, i+1 from generate_series(1,3) i;
explain (costs off)
update into_table set d=from_table.d, e=from_table.e, f=from_table.f from from_table
where into_table.a=from_table.a and into_table.b=from_table.b and into_table.c=from_table.c;
update into_table set d=from_table.d, e=from_table.e, f=from_table.f from from_table
where into_table.a=from_table.a and into_table.b=from_table.b and into_table.c=from_table.c;
select * from into_table order by a;
-- start_ignore
drop table r;
drop table s;
drop table update_dist;
drop table update_ao_table;
drop table update_aoco_table;
drop table nosplitupdate;
drop table tsplit_entry;
drop table t1_13265;
drop table t2_13265;
drop table into_table;
drop table from_table;
-- end_ignore