mirror of https://github.com/citusdata/citus.git
397 lines
11 KiB
PL/PgSQL
397 lines
11 KiB
PL/PgSQL
SET citus.shard_replication_factor to 1;
|
|
SET citus.next_shard_id TO 60000;
|
|
SET citus.next_placement_id TO 60000;
|
|
|
|
create schema test_pg12;
|
|
set search_path to test_pg12;
|
|
|
|
-- Test generated columns
|
|
-- val1 after val2 to test https://github.com/citusdata/citus/issues/3538
|
|
create table gen1 (
|
|
id int,
|
|
val2 int GENERATED ALWAYS AS (val1 + 2) STORED,
|
|
val1 int
|
|
);
|
|
create table gen2 (
|
|
id int,
|
|
val1 int,
|
|
val2 int GENERATED ALWAYS AS (val1 + 2) STORED
|
|
);
|
|
|
|
insert into gen1 (id, val1) values (1,4),(3,6),(5,2),(7,2);
|
|
insert into gen2 (id, val1) values (1,4),(3,6),(5,2),(7,2);
|
|
|
|
select create_distributed_table('gen1', 'id');
|
|
select create_distributed_table('gen2', 'val2');
|
|
|
|
copy gen1 to :'temp_dir''pg12_copy_test_generated';
|
|
|
|
insert into gen1 (id, val1) values (2,4),(4,6),(6,2),(8,2);
|
|
insert into gen2 (id, val1) values (2,4),(4,6),(6,2),(8,2);
|
|
|
|
select * from gen1 order by 1,2,3;
|
|
select * from gen2 order by 1,2,3;
|
|
|
|
truncate gen1;
|
|
copy gen1 from :'temp_dir''pg12_copy_test_generated';
|
|
select * from gen1 order by 1,2,3;
|
|
|
|
-- Test new VACUUM/ANALYZE options
|
|
analyze (skip_locked) gen1;
|
|
vacuum (skip_locked) gen1;
|
|
vacuum (truncate 0) gen1;
|
|
vacuum (index_cleanup 1) gen1;
|
|
|
|
-- COPY FROM
|
|
create table cptest (id int, val int);
|
|
select create_distributed_table('cptest', 'id');
|
|
copy cptest from STDIN with csv where val < 4;
|
|
1,6
|
|
2,3
|
|
3,2
|
|
4,9
|
|
5,4
|
|
\.
|
|
select sum(id), sum(val) from cptest;
|
|
|
|
-- CTE materialized/not materialized
|
|
CREATE TABLE single_hash_repartition_first (id int, sum int, avg float);
|
|
CREATE TABLE single_hash_repartition_second (id int primary key, sum int, avg float);
|
|
|
|
SELECT create_distributed_table('single_hash_repartition_first', 'id');
|
|
SELECT create_distributed_table('single_hash_repartition_second', 'id');
|
|
|
|
INSERT INTO single_hash_repartition_first
|
|
SELECT i, i * 3, i * 0.3
|
|
FROM generate_series(0, 100) i;
|
|
|
|
INSERT INTO single_hash_repartition_second
|
|
SELECT i * 2, i * 5, i * 0.6
|
|
FROM generate_series(0, 100) i;
|
|
|
|
-- a sample router query with NOT MATERIALIZED
|
|
-- which pushes down the filters to the CTE
|
|
SELECT public.coordinator_plan($Q$
|
|
EXPLAIN (COSTS OFF)
|
|
WITH cte1 AS NOT MATERIALIZED
|
|
(
|
|
SELECT id
|
|
FROM single_hash_repartition_first t1
|
|
)
|
|
SELECT count(*)
|
|
FROM cte1, single_hash_repartition_second
|
|
WHERE cte1.id = single_hash_repartition_second.id AND single_hash_repartition_second.id = 45;
|
|
$Q$);
|
|
|
|
-- same query, without NOT MATERIALIZED, which is already default
|
|
-- which pushes down the filters to the CTE
|
|
SELECT public.coordinator_plan($Q$
|
|
EXPLAIN (COSTS OFF)
|
|
WITH cte1 AS
|
|
(
|
|
SELECT id
|
|
FROM single_hash_repartition_first t1
|
|
)
|
|
SELECT count(*)
|
|
FROM cte1, single_hash_repartition_second
|
|
WHERE cte1.id = single_hash_repartition_second.id AND single_hash_repartition_second.id = 45;
|
|
$Q$);
|
|
|
|
-- same query with MATERIALIZED
|
|
-- which prevents pushing down filters to the CTE,
|
|
-- thus becoming a real-time query
|
|
SELECT public.coordinator_plan($Q$
|
|
EXPLAIN (COSTS OFF)
|
|
WITH cte1 AS MATERIALIZED
|
|
(
|
|
SELECT id
|
|
FROM single_hash_repartition_first t1
|
|
)
|
|
SELECT count(*)
|
|
FROM cte1, single_hash_repartition_second
|
|
WHERE cte1.id = single_hash_repartition_second.id AND single_hash_repartition_second.id = 45;
|
|
$Q$);
|
|
|
|
-- similar query with MATERIALIZED
|
|
-- now manually have the same filter in the CTE
|
|
-- thus becoming a router query again
|
|
SELECT public.coordinator_plan($Q$
|
|
EXPLAIN (COSTS OFF)
|
|
WITH cte1 AS MATERIALIZED
|
|
(
|
|
SELECT id
|
|
FROM single_hash_repartition_first t1
|
|
WHERE id = 45
|
|
)
|
|
SELECT count(*)
|
|
FROM cte1, single_hash_repartition_second
|
|
WHERE cte1.id = single_hash_repartition_second.id AND single_hash_repartition_second.id = 45;
|
|
$Q$);
|
|
|
|
-- now, have a real-time query without MATERIALIZED
|
|
-- these are sanitiy checks, because all of the CTEs are recursively
|
|
-- planned and there is no benefit that Citus can have
|
|
SELECT public.coordinator_plan($Q$
|
|
EXPLAIN (COSTS OFF)
|
|
WITH cte1 AS MATERIALIZED
|
|
(
|
|
SELECT id
|
|
FROM single_hash_repartition_first t1
|
|
WHERE sum = 45
|
|
)
|
|
SELECT count(*)
|
|
FROM cte1, single_hash_repartition_second
|
|
WHERE cte1.id = single_hash_repartition_second.id AND single_hash_repartition_second.sum = 45;
|
|
$Q$);
|
|
|
|
SELECT public.coordinator_plan($Q$
|
|
EXPLAIN (COSTS OFF)
|
|
WITH cte1 AS NOT MATERIALIZED
|
|
(
|
|
SELECT id
|
|
FROM single_hash_repartition_first t1
|
|
WHERE sum = 45
|
|
)
|
|
SELECT count(*)
|
|
FROM cte1, single_hash_repartition_second
|
|
WHERE cte1.id = single_hash_repartition_second.id AND single_hash_repartition_second.sum = 45;
|
|
$Q$);
|
|
|
|
-- Foreign keys to partition tables
|
|
CREATE TABLE collections_list (
|
|
key bigint,
|
|
collection_id integer,
|
|
value numeric,
|
|
PRIMARY KEY(key, collection_id)
|
|
) PARTITION BY LIST (collection_id);
|
|
|
|
CREATE TABLE collections_list_0
|
|
PARTITION OF collections_list (key, collection_id, value)
|
|
FOR VALUES IN ( 0 );
|
|
CREATE TABLE collections_list_1
|
|
PARTITION OF collections_list (key, collection_id, value)
|
|
FOR VALUES IN ( 1 );
|
|
|
|
CREATE TABLE collection_users
|
|
(used_id integer, collection_id integer, key bigint);
|
|
|
|
ALTER TABLE collection_users
|
|
ADD CONSTRAINT collection_users_fkey FOREIGN KEY (key, collection_id) REFERENCES collections_list (key, collection_id);
|
|
|
|
-- sanity check for postgres
|
|
INSERT INTO collections_list VALUES (1, 0, '1.1');
|
|
INSERT INTO collection_users VALUES (1, 0, 1);
|
|
|
|
-- should fail because of fkey
|
|
INSERT INTO collection_users VALUES (1, 1000, 1);
|
|
|
|
SELECT create_distributed_table('collections_list', 'key');
|
|
SELECT create_distributed_table('collection_users', 'key');
|
|
|
|
-- should still fail because of fkey
|
|
INSERT INTO collection_users VALUES (1, 1000, 1);
|
|
|
|
-- whereas new record with partition should go through
|
|
INSERT INTO collections_list VALUES (2, 1, '1.2');
|
|
INSERT INTO collection_users VALUES (5, 1, 2);
|
|
|
|
-- AND CHAIN
|
|
CREATE TABLE test (x int, y int);
|
|
INSERT INTO test (x,y) SELECT i,i*3 from generate_series(1, 100) i;
|
|
|
|
SELECT create_distributed_table('test', 'x');
|
|
|
|
-- single shard queries with CHAIN
|
|
BEGIN;
|
|
UPDATE test SET y = 15 WHERE x = 1;
|
|
COMMIT AND CHAIN;
|
|
SELECT * FROM test WHERE x = 1;
|
|
COMMIT;
|
|
|
|
BEGIN;
|
|
UPDATE test SET y = 20 WHERE x = 1;
|
|
ROLLBACK AND CHAIN;
|
|
SELECT * FROM test WHERE x = 1;
|
|
COMMIT;
|
|
|
|
-- multi shard queries with CHAIN
|
|
BEGIN;
|
|
UPDATE test SET y = 25;
|
|
COMMIT AND CHAIN;
|
|
SELECT DISTINCT y FROM test;
|
|
COMMIT;
|
|
|
|
BEGIN;
|
|
UPDATE test SET y = 30;
|
|
ROLLBACK AND CHAIN;
|
|
SELECT DISTINCT y FROM test;
|
|
COMMIT;
|
|
|
|
-- does read only carry over?
|
|
|
|
BEGIN READ ONLY;
|
|
COMMIT AND CHAIN;
|
|
UPDATE test SET y = 35;
|
|
COMMIT;
|
|
SELECT DISTINCT y FROM test;
|
|
|
|
BEGIN READ ONLY;
|
|
ROLLBACK AND CHAIN;
|
|
UPDATE test SET y = 40;
|
|
COMMIT;
|
|
SELECT DISTINCT y FROM test;
|
|
|
|
-- non deterministic collations
|
|
SET client_min_messages TO WARNING;
|
|
CREATE COLLATION test_pg12.case_insensitive (
|
|
provider = icu,
|
|
locale = '@colStrength=secondary',
|
|
deterministic = false
|
|
);
|
|
RESET client_min_messages;
|
|
|
|
CREATE TABLE col_test (
|
|
id int,
|
|
val text collate case_insensitive
|
|
);
|
|
|
|
insert into col_test values
|
|
(1, 'asdF'), (2, 'vAlue'), (3, 'asDF');
|
|
|
|
-- Hash distribution of non deterministic collations are unsupported
|
|
select create_distributed_table('col_test', 'val');
|
|
select create_distributed_table('col_test', 'id');
|
|
|
|
insert into col_test values
|
|
(4, 'vALue'), (5, 'AsDf'), (6, 'value');
|
|
|
|
select count(*)
|
|
from col_test
|
|
where val = 'asdf';
|
|
|
|
BEGIN;
|
|
CREATE TABLE generated_stored_col_test (x int, y int generated always as (x+1) stored);
|
|
SELECT citus_add_local_table_to_metadata('generated_stored_col_test');
|
|
|
|
-- simply check if GENERATED ALWAYS AS (...) STORED expression works fine
|
|
INSERT INTO generated_stored_col_test VALUES(1), (2);
|
|
SELECT * FROM generated_stored_col_test ORDER BY 1,2;
|
|
|
|
-- show that we keep such expressions on shell relation and shard relation
|
|
SELECT s.relname, a.attname, a.attgenerated
|
|
FROM pg_class s
|
|
JOIN pg_attribute a ON a.attrelid=s.oid
|
|
WHERE s.relname LIKE 'generated_stored_col_test%' AND
|
|
attname = 'y'
|
|
ORDER BY 1,2;
|
|
ROLLBACK;
|
|
|
|
CREATE TABLE generated_stored_dist (
|
|
col_1 int,
|
|
"col\'_2" text,
|
|
col_3 text generated always as (UPPER("col\'_2")) stored
|
|
);
|
|
|
|
SELECT create_distributed_table ('generated_stored_dist', 'col_1');
|
|
|
|
INSERT INTO generated_stored_dist VALUES (1, 'text_1'), (2, 'text_2');
|
|
SELECT * FROM generated_stored_dist ORDER BY 1,2,3;
|
|
|
|
INSERT INTO generated_stored_dist VALUES (1, 'text_1'), (2, 'text_2');
|
|
SELECT alter_distributed_table('generated_stored_dist', shard_count := 5, cascade_to_colocated := false);
|
|
SELECT * FROM generated_stored_dist ORDER BY 1,2,3;
|
|
|
|
CREATE TABLE generated_stored_local (
|
|
col_1 int,
|
|
"col\'_2" text,
|
|
col_3 text generated always as (UPPER("col\'_2")) stored
|
|
);
|
|
|
|
SELECT citus_add_local_table_to_metadata('generated_stored_local');
|
|
|
|
INSERT INTO generated_stored_local VALUES (1, 'text_1'), (2, 'text_2');
|
|
SELECT * FROM generated_stored_local ORDER BY 1,2,3;
|
|
|
|
SELECT create_distributed_table ('generated_stored_local', 'col_1');
|
|
|
|
INSERT INTO generated_stored_local VALUES (1, 'text_1'), (2, 'text_2');
|
|
SELECT * FROM generated_stored_local ORDER BY 1,2,3;
|
|
|
|
create table generated_stored_columnar(i int) partition by range(i);
|
|
create table generated_stored_columnar_p0 partition of generated_stored_columnar for values from (0) to (10);
|
|
create table generated_stored_columnar_p1 partition of generated_stored_columnar for values from (10) to (20);
|
|
SELECT alter_table_set_access_method('generated_stored_columnar_p0', 'columnar');
|
|
|
|
CREATE TABLE generated_stored_ref (
|
|
col_1 int,
|
|
col_2 int,
|
|
col_3 int generated always as (col_1+col_2) stored,
|
|
col_4 int,
|
|
col_5 int generated always as (col_4*2-col_1) stored
|
|
);
|
|
|
|
SELECT create_reference_table ('generated_stored_ref');
|
|
|
|
INSERT INTO generated_stored_ref (col_1, col_4) VALUES (1,2), (11,12);
|
|
INSERT INTO generated_stored_ref (col_1, col_2, col_4) VALUES (100,101,102), (200,201,202);
|
|
|
|
SELECT * FROM generated_stored_ref ORDER BY 1,2,3,4,5;
|
|
|
|
BEGIN;
|
|
SELECT undistribute_table('generated_stored_ref');
|
|
INSERT INTO generated_stored_ref (col_1, col_4) VALUES (11,12), (21,22);
|
|
INSERT INTO generated_stored_ref (col_1, col_2, col_4) VALUES (200,201,202), (300,301,302);
|
|
SELECT * FROM generated_stored_ref ORDER BY 1,2,3,4,5;
|
|
ROLLBACK;
|
|
|
|
BEGIN;
|
|
-- drop some of the columns not having "generated always as stored" expressions
|
|
-- PRE PG15, this would drop generated columns too
|
|
-- In PG15, CASCADE option must be specified
|
|
-- Relevant PG Commit: cb02fcb4c95bae08adaca1202c2081cfc81a28b5
|
|
SET client_min_messages TO WARNING;
|
|
ALTER TABLE generated_stored_ref DROP COLUMN col_1 CASCADE;
|
|
RESET client_min_messages;
|
|
ALTER TABLE generated_stored_ref DROP COLUMN col_4;
|
|
|
|
-- show that undistribute_table works fine
|
|
SELECT undistribute_table('generated_stored_ref');
|
|
INSERT INTO generated_stored_ref VALUES (5);
|
|
SELECT * FROM generated_stored_REF ORDER BY 1;
|
|
ROLLBACK;
|
|
|
|
BEGIN;
|
|
-- now drop all columns
|
|
ALTER TABLE generated_stored_ref DROP COLUMN col_3;
|
|
ALTER TABLE generated_stored_ref DROP COLUMN col_5;
|
|
ALTER TABLE generated_stored_ref DROP COLUMN col_1;
|
|
ALTER TABLE generated_stored_ref DROP COLUMN col_2;
|
|
ALTER TABLE generated_stored_ref DROP COLUMN col_4;
|
|
|
|
-- show that undistribute_table works fine
|
|
SELECT undistribute_table('generated_stored_ref');
|
|
|
|
SELECT * FROM generated_stored_ref;
|
|
ROLLBACK;
|
|
|
|
CREATE TABLE superuser_columnar_table (a int) USING columnar;
|
|
|
|
CREATE USER read_access;
|
|
SET ROLE read_access;
|
|
|
|
-- user shouldn't be able to execute ALTER TABLE ... SET
|
|
-- or ALTER TABLE ... RESET for a columnar table that it
|
|
-- doesn't own
|
|
ALTER TABLE test_pg12.superuser_columnar_table SET(columnar.chunk_group_row_limit = 100);
|
|
ALTER TABLE test_pg12.superuser_columnar_table RESET (columnar.chunk_group_row_limit);
|
|
|
|
RESET ROLE;
|
|
DROP USER read_access;
|
|
|
|
\set VERBOSITY terse
|
|
drop schema test_pg12 cascade;
|
|
\set VERBOSITY default
|
|
|
|
SET citus.shard_replication_factor to 2;
|
|
|