Add DDL support null-shard-key tables(#6778/#6784/#6787/#6859)

Add tests for ddl coverage:
* indexes
* partitioned tables + indexes with long names
* triggers
* foreign keys
* statistics
* grant & revoke statements
* truncate & vacuum
* create/test/drop view that depends on a dist table with no shard key
* policy & rls test

* alter table add/drop/alter_type column (using sequences/different data
  types/identity columns)
* alter table add constraint (not null, check, exclusion constraint)
* alter table add column with a default value / set default / drop
  default
* alter table set option (autovacuum)

* indexes / constraints without names
* multiple subcommands

Adds support for
* Creating new partitions after distributing (with null key) the parent
table
* Attaching partitions to a distributed table with null distribution key
(and automatically distribute the new partition with null key as well)
* Detaching partitions from it
pull/6867/head
Ahmet Gedemenli 2023-03-21 12:24:16 +03:00 committed by Onur Tirtir
parent fa467e05e7
commit cdf54ff4b1
9 changed files with 956 additions and 29 deletions

View File

@ -134,7 +134,6 @@ static List * HashSplitPointsForShardList(List *shardList);
static List * HashSplitPointsForShardCount(int shardCount);
static List * WorkerNodesForShardList(List *shardList);
static List * RoundRobinWorkerNodeList(List *workerNodeList, int listLength);
static void CreateNullShardKeyDistTable(Oid relationId, char *colocateWithTableName);
static CitusTableParams DecideCitusTableParams(CitusTableType tableType,
DistributedTableParams *
distributedTableParams);
@ -1031,7 +1030,7 @@ CreateReferenceTable(Oid relationId)
* CreateNullShardKeyDistTable is a wrapper around CreateCitusTable that creates a
* single shard distributed table that doesn't have a shard key.
*/
static void
void
CreateNullShardKeyDistTable(Oid relationId, char *colocateWithTableName)
{
DistributedTableParams distributedTableParams = {

View File

@ -384,6 +384,11 @@ PostprocessCreateTableStmtPartitionOf(CreateStmt *createStatement, const
*/
if (IsCitusTable(parentRelationId))
{
/*
* We can create Citus local tables and distributed tables with null shard keys
* right away, without switching to sequential mode, because they are going to
* have only one shard.
*/
if (IsCitusTableType(parentRelationId, CITUS_LOCAL_TABLE))
{
CreateCitusLocalTablePartitionOf(createStatement, relationId,
@ -391,11 +396,18 @@ PostprocessCreateTableStmtPartitionOf(CreateStmt *createStatement, const
return;
}
char *parentRelationName = generate_qualified_relation_name(parentRelationId);
if (IsCitusTableType(parentRelationId, NULL_KEY_DISTRIBUTED_TABLE))
{
CreateNullShardKeyDistTable(relationId, parentRelationName);
return;
}
Var *parentDistributionColumn = DistPartitionKeyOrError(parentRelationId);
char *distributionColumnName =
ColumnToColumnName(parentRelationId, (Node *) parentDistributionColumn);
char parentDistributionMethod = DISTRIBUTE_BY_HASH;
char *parentRelationName = generate_qualified_relation_name(parentRelationId);
SwitchToSequentialAndLocalExecutionIfPartitionNameTooLong(parentRelationId,
relationId);
@ -589,19 +601,32 @@ PreprocessAttachCitusPartitionToCitusTable(Oid parentCitusRelationId, Oid
/*
* DistributePartitionUsingParent takes a parent and a partition relation and
* distributes the partition, using the same distribution column as the parent.
* It creates a *hash* distributed table by default, as partitioned tables can only be
* distributed by hash.
* distributes the partition, using the same distribution column as the parent, if the
* parent has a distribution column. It creates a *hash* distributed table by default, as
* partitioned tables can only be distributed by hash, unless it's null key distributed.
*
* If the parent has no distribution key, we distribute the partition with null key too.
*/
static void
DistributePartitionUsingParent(Oid parentCitusRelationId, Oid partitionRelationId)
{
char *parentRelationName = generate_qualified_relation_name(parentCitusRelationId);
if (!HasDistributionKey(parentCitusRelationId))
{
/*
* If the parent is null key distributed, we should distribute the partition
* with null distribution key as well.
*/
CreateNullShardKeyDistTable(partitionRelationId, parentRelationName);
return;
}
Var *distributionColumn = DistPartitionKeyOrError(parentCitusRelationId);
char *distributionColumnName = ColumnToColumnName(parentCitusRelationId,
(Node *) distributionColumn);
char distributionMethod = DISTRIBUTE_BY_HASH;
char *parentRelationName = generate_qualified_relation_name(parentCitusRelationId);
SwitchToSequentialAndLocalExecutionIfPartitionNameTooLong(
parentCitusRelationId, partitionRelationId);

View File

@ -1404,7 +1404,7 @@ DistPartitionKeyOrError(Oid relationId)
if (partitionKey == NULL)
{
ereport(ERROR, (errmsg(
"no distribution column found for relation %d, because it is a reference table",
"no distribution column found for relation %d",
relationId)));
}

View File

@ -326,6 +326,7 @@ extern void DeletePartitionRow(Oid distributedRelationId);
extern void DeleteShardRow(uint64 shardId);
extern void UpdatePlacementGroupId(uint64 placementId, int groupId);
extern void DeleteShardPlacementRow(uint64 placementId);
extern void CreateNullShardKeyDistTable(Oid relationId, char *colocateWithTableName);
extern void CreateDistributedTable(Oid relationId, char *distributionColumnName,
char distributionMethod, int shardCount,
bool shardCountIsStrict, char *colocateWithTableName);

View File

@ -0,0 +1,154 @@
CREATE SCHEMA alter_null_dist_key;
SET search_path TO alter_null_dist_key;
SET citus.next_shard_id TO 1720000;
SET citus.shard_count TO 32;
SET citus.shard_replication_factor TO 1;
CREATE SEQUENCE dist_seq;
CREATE TABLE null_dist_table(a bigint DEFAULT nextval('dist_seq') UNIQUE, "b" text, c bigint GENERATED BY DEFAULT AS IDENTITY);
INSERT INTO null_dist_table("b") VALUES ('test');
SELECT create_distributed_table('null_dist_table', null, colocate_with=>'none', distribution_type=>null);
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$alter_null_dist_key.null_dist_table$$)
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- add column
ALTER TABLE null_dist_table ADD COLUMN d bigint DEFAULT 2;
SELECT * FROM null_dist_table ORDER BY c;
a | b | c | d
---------------------------------------------------------------------
1 | test | 1 | 2
(1 row)
-- alter default, set to 3
ALTER TABLE null_dist_table ALTER COLUMN d SET DEFAULT 3;
INSERT INTO null_dist_table("b") VALUES ('test');
SELECT * FROM null_dist_table ORDER BY c;
a | b | c | d
---------------------------------------------------------------------
1 | test | 1 | 2
2 | test | 2 | 3
(2 rows)
-- drop default, see null
ALTER TABLE null_dist_table ALTER COLUMN d DROP DEFAULT;
INSERT INTO null_dist_table("b") VALUES ('test');
SELECT * FROM null_dist_table ORDER BY c;
a | b | c | d
---------------------------------------------------------------------
1 | test | 1 | 2
2 | test | 2 | 3
3 | test | 3 |
(3 rows)
-- cleanup the rows that were added to test the default behavior
DELETE FROM null_dist_table WHERE "b" = 'test' AND a > 1;
-- alter column type
ALTER TABLE null_dist_table ALTER COLUMN d TYPE text;
UPDATE null_dist_table SET d = 'this is a text' WHERE d = '2';
SELECT * FROM null_dist_table ORDER BY c;
a | b | c | d
---------------------------------------------------------------------
1 | test | 1 | this is a text
(1 row)
-- drop seq column
ALTER TABLE null_dist_table DROP COLUMN a;
SELECT * FROM null_dist_table ORDER BY c;
b | c | d
---------------------------------------------------------------------
test | 1 | this is a text
(1 row)
-- add not null constraint
ALTER TABLE null_dist_table ALTER COLUMN b SET NOT NULL;
-- not null constraint violation, error out
INSERT INTO null_dist_table VALUES (NULL, 2, 'test');
ERROR: null value in column "b" violates not-null constraint
DETAIL: Failing row contains (null, 2, test).
CONTEXT: while executing command on localhost:xxxxx
-- drop not null constraint and try again
ALTER TABLE null_dist_table ALTER COLUMN b DROP NOT NULL;
INSERT INTO null_dist_table VALUES (NULL, 3, 'test');
SELECT * FROM null_dist_table ORDER BY c;
b | c | d
---------------------------------------------------------------------
test | 1 | this is a text
| 3 | test
(2 rows)
-- add exclusion constraint
ALTER TABLE null_dist_table ADD CONSTRAINT exc_b EXCLUDE USING btree (b with =);
-- rename the exclusion constraint, errors out
ALTER TABLE null_dist_table RENAME CONSTRAINT exc_b TO exc_b_1;
ERROR: renaming constraints belonging to distributed tables is currently unsupported
-- create exclusion constraint without a name
ALTER TABLE null_dist_table ADD EXCLUDE USING btree (b with =);
-- test setting autovacuum option
ALTER TABLE null_dist_table SET (autovacuum_enabled = false);
-- test multiple subcommands
ALTER TABLE null_dist_table ADD COLUMN int_column1 INTEGER,
DROP COLUMN d;
SELECT * FROM null_dist_table ORDER BY c;
b | c | int_column1
---------------------------------------------------------------------
test | 1 |
| 3 |
(2 rows)
-- test policy and row level security
CREATE TABLE null_dist_key_with_policy (table_user text);
INSERT INTO null_dist_key_with_policy VALUES ('user_1');
SELECT create_distributed_table('null_dist_key_with_policy', null);
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$alter_null_dist_key.null_dist_key_with_policy$$)
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- enable rls
ALTER TABLE null_dist_key_with_policy ENABLE ROW LEVEL SECURITY;
-- user_1 will be allowed to see the inserted row
CREATE ROLE user_1 WITH LOGIN;
GRANT ALL ON SCHEMA alter_null_dist_key TO user_1;
GRANT ALL ON TABLE alter_null_dist_key.null_dist_key_with_policy TO user_1;
CREATE POLICY table_policy ON null_dist_key_with_policy TO user_1
USING (table_user = current_user);
-- user_2 will not be allowed to see the inserted row
CREATE ROLE user_2 WITH LOGIN;
GRANT ALL ON SCHEMA alter_null_dist_key TO user_2;
GRANT ALL ON TABLE alter_null_dist_key.null_dist_key_with_policy TO user_2;
CREATE POLICY table_policy_1 ON null_dist_key_with_policy TO user_2
USING (table_user = current_user);
\c - user_1 -
SELECT * FROM alter_null_dist_key.null_dist_key_with_policy;
table_user
---------------------------------------------------------------------
user_1
(1 row)
\c - user_2 -
SELECT * FROM alter_null_dist_key.null_dist_key_with_policy;
table_user
---------------------------------------------------------------------
(0 rows)
-- postgres will always be allowed to see the row as a superuser
\c - postgres -
SELECT * FROM alter_null_dist_key.null_dist_key_with_policy;
table_user
---------------------------------------------------------------------
user_1
(1 row)
-- cleanup
SET client_min_messages TO ERROR;
DROP SCHEMA alter_null_dist_key CASCADE;
DROP ROLE user_1, user_2;

View File

@ -497,7 +497,8 @@ SELECT * FROM null_dist_key_table_2 ORDER BY a;
DROP TABLE null_dist_key_table_1, null_dist_key_table_2;
-- create indexes before creating the null dist key tables
-- .. for an initially empty table
CREATE TABLE null_dist_key_table_1(a int);
CREATE TABLE null_dist_key_table_1(a int, b int);
CREATE STATISTICS s1 (dependencies) ON a, b FROM null_dist_key_table_1;
CREATE INDEX null_dist_key_table_1_idx ON null_dist_key_table_1(a);
SELECT create_distributed_table('null_dist_key_table_1', null, colocate_with=>'none');
create_distributed_table
@ -505,6 +506,7 @@ SELECT create_distributed_table('null_dist_key_table_1', null, colocate_with=>'n
(1 row)
CREATE STATISTICS s2 (dependencies) ON a, b FROM null_dist_key_table_1;
-- .. and for another table having data in it before creating null dist key table
CREATE TABLE null_dist_key_table_2(a int);
INSERT INTO null_dist_key_table_2 VALUES(1);
@ -515,6 +517,11 @@ SELECT create_distributed_table('null_dist_key_table_2', null, colocate_with=>'n
(1 row)
-- test create index concurrently, then reindex
CREATE INDEX CONCURRENTLY ind_conc ON null_dist_key_table_2(a);
REINDEX INDEX ind_conc;
REINDEX INDEX CONCURRENTLY ind_conc;
DROP INDEX ind_conc;
SELECT * FROM null_dist_key_table_2 ORDER BY a;
a
---------------------------------------------------------------------
@ -536,15 +543,23 @@ BEGIN;
CREATE ROLE table_users;
CREATE POLICY table_policy ON null_dist_key_table_3 TO table_users
USING (table_user = current_user);
GRANT ALL ON TABLE null_dist_key_table_3 TO table_users;
ALTER TABLE null_dist_key_table_3 OWNER TO table_users;
SELECT create_distributed_table('null_dist_key_table_3', null, colocate_with=>'none');
create_distributed_table
---------------------------------------------------------------------
(1 row)
REVOKE ALL ON TABLE null_dist_key_table_3 FROM table_users;
ALTER TABLE null_dist_key_table_3 OWNER TO postgres;
GRANT ALL ON TABLE null_dist_key_table_3 TO table_users;
ROLLBACK;
ALTER STATISTICS s2 SET STATISTICS 46;
ALTER TABLE null_dist_key_table_1 SET SCHEMA public;
DROP STATISTICS s1, s2;
-- drop them for next tests
DROP TABLE null_dist_key_table_1, null_dist_key_table_2, distributed_table;
DROP TABLE public.null_dist_key_table_1, null_dist_key_table_2, distributed_table;
-- tests for object names that should be escaped properly
CREATE SCHEMA "NULL_!_dist_key";
CREATE TABLE "NULL_!_dist_key"."my_TABLE.1!?!"(id int, "Second_Id" int);
@ -643,6 +658,348 @@ SELECT create_distributed_table('sensors', NULL, distribution_type=>null);
(1 row)
-- verify we can create new partitions after distributing the parent table
CREATE TABLE sensors_2001 PARTITION OF sensors FOR VALUES FROM ('2001-01-01') TO ('2002-01-01');
-- verify we can attach to a null dist key table
CREATE TABLE sensors_2002 (measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data));
ALTER TABLE sensors ATTACH PARTITION sensors_2002 FOR VALUES FROM ('2002-01-01') TO ('2003-01-01');
-- verify we can detach from a null dist key table
ALTER TABLE sensors DETACH PARTITION sensors_2001;
-- error out when attaching a noncolocated partition
CREATE TABLE sensors_2003 (measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data));
SELECT create_distributed_table('sensors_2003', NULL, distribution_type=>null, colocate_with=>'none');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE sensors ATTACH PARTITION sensors_2003 FOR VALUES FROM ('2003-01-01') TO ('2004-01-01');
ERROR: distributed tables cannot have non-colocated distributed tables as a partition
DROP TABLE sensors_2003;
-- verify we can attach after distributing, if the parent and partition are colocated
CREATE TABLE sensors_2004 (measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data));
SELECT create_distributed_table('sensors_2004', NULL, distribution_type=>null, colocate_with=>'sensors');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE sensors ATTACH PARTITION sensors_2004 FOR VALUES FROM ('2004-01-01') TO ('2005-01-01');
-- verify we can attach a citus local table
CREATE TABLE sensors_2005 (measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data));
SELECT citus_add_local_table_to_metadata('sensors_2005');
citus_add_local_table_to_metadata
---------------------------------------------------------------------
(1 row)
ALTER TABLE sensors ATTACH PARTITION sensors_2005 FOR VALUES FROM ('2005-01-01') TO ('2006-01-01');
-- check metadata
-- check all partitions and the parent on pg_dist_partition
SELECT logicalrelid::text FROM pg_dist_partition WHERE logicalrelid::text IN ('sensors', 'sensors_2000', 'sensors_2001', 'sensors_2002', 'sensors_2004', 'sensors_2005') ORDER BY logicalrelid::text;
logicalrelid
---------------------------------------------------------------------
sensors
sensors_2000
sensors_2001
sensors_2002
sensors_2004
sensors_2005
(6 rows)
-- verify they are all colocated
SELECT COUNT(DISTINCT(colocationid)) FROM pg_dist_partition WHERE logicalrelid::text IN ('sensors', 'sensors_2000', 'sensors_2001', 'sensors_2002', 'sensors_2004', 'sensors_2005');
count
---------------------------------------------------------------------
1
(1 row)
-- verify all partitions are placed on the same node
SELECT COUNT(DISTINCT(groupid)) FROM pg_dist_placement WHERE shardid IN
(SELECT shardid FROM pg_dist_shard WHERE logicalrelid::text IN ('sensors', 'sensors_2000', 'sensors_2001', 'sensors_2002', 'sensors_2004', 'sensors_2005'));
count
---------------------------------------------------------------------
1
(1 row)
-- verify the shard of sensors_2000 is attached to the parent shard, on the worker node
SELECT COUNT(*) FROM run_command_on_workers($$
SELECT relpartbound FROM pg_class WHERE relname LIKE 'sensors_2000_1______';$$)
WHERE length(result) > 0;
count
---------------------------------------------------------------------
1
(1 row)
-- verify the shard of sensors_2001 is detached from the parent shard, on the worker node
SELECT COUNT(*) FROM run_command_on_workers($$
SELECT relpartbound FROM pg_class WHERE relname LIKE 'sensors_2001_1______';$$)
WHERE length(result) > 0;
count
---------------------------------------------------------------------
0
(1 row)
-- verify the shard of sensors_2002 is attached to the parent shard, on the worker node
SELECT COUNT(*) FROM run_command_on_workers($$
SELECT relpartbound FROM pg_class WHERE relname LIKE 'sensors_2002_1______';$$)
WHERE length(result) > 0;
count
---------------------------------------------------------------------
1
(1 row)
-- create a partitioned citus local table and verify we error out when attaching a partition with null dist key
CREATE TABLE partitioned_citus_local_tbl(
measureid integer,
eventdatetime date,
measure_data jsonb,
PRIMARY KEY (measureid, eventdatetime, measure_data))
PARTITION BY RANGE(eventdatetime);
SELECT citus_add_local_table_to_metadata('partitioned_citus_local_tbl');
citus_add_local_table_to_metadata
---------------------------------------------------------------------
(1 row)
CREATE TABLE partition_with_null_key (measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data));
SELECT create_distributed_table('partition_with_null_key', NULL, distribution_type=>null);
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE partitioned_citus_local_tbl ATTACH PARTITION partition_with_null_key FOR VALUES FROM ('2004-01-01') TO ('2005-01-01');
ERROR: non-distributed partitioned tables cannot have distributed partitions
-- test partitioned tables + indexes with long names
CREATE TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(
id int PRIMARY KEY,
"TeNANt_Id" int,
"jsondata" jsonb NOT NULL,
name text,
price numeric CHECK (price > 0),
serial_data bigserial, UNIQUE (id, price))
PARTITION BY LIST(id);
CREATE TABLE "NULL_!_dist_key"."partition1_nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
PARTITION OF "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
FOR VALUES IN (1);
CREATE TABLE "NULL_!_dist_key"."partition2_nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
PARTITION OF "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
FOR VALUES IN (2);
CREATE TABLE "NULL_!_dist_key"."partition100_nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
PARTITION OF "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
FOR VALUES IN (100);
-- create some objects before create_distributed_table
CREATE INDEX "my!Index1New" ON "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id) WITH ( fillfactor = 80 ) WHERE id > 10;
CREATE UNIQUE INDEX uniqueIndexNew ON "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" (id);
-- ingest some data before create_distributed_table
set client_min_messages to ERROR;
INSERT INTO "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" VALUES (1, 1, row_to_json(row(1,1), true)),
(2, 1, row_to_json(row(2,2), 'false'));
reset client_min_messages;
-- create a replica identity before create_distributed_table
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" REPLICA IDENTITY USING INDEX uniqueIndexNew;
NOTICE: identifier "nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" will be truncated to "nullKeyTable.1!?!9012345678901234567890123456789012345678901234"
-- test triggers
SET client_min_messages TO ERROR;
CREATE FUNCTION insert_id_100() RETURNS trigger AS $insert_100$
BEGIN
INSERT INTO "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" VALUES (100, 1, row_to_json(row(1,1), true));
RETURN NEW;
END;
$insert_100$ LANGUAGE plpgsql;
CREATE TABLE null_key_table_with_trigger(a INT);
SELECT create_distributed_table('null_key_table_with_trigger', null);
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- try to add a trigger after distributing the table, fails
CREATE TRIGGER insert_100_trigger
AFTER UPDATE ON null_key_table_with_trigger
FOR EACH STATEMENT EXECUTE FUNCTION insert_id_100();
ERROR: triggers are not supported on distributed tables
-- now try to distribute a table that already has a trigger on it
CREATE TRIGGER insert_100_trigger
AFTER UPDATE ON "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
FOR EACH STATEMENT EXECUTE FUNCTION insert_id_100();
-- error out because of the trigger
SELECT create_distributed_table('"NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"', null);
ERROR: cannot distribute relation "nullKeyTable.1!?!9012345678901234567890123456789012345678901234" because it has triggers
HINT: Consider dropping all the triggers on "nullKeyTable.1!?!9012345678901234567890123456789012345678901234" and retry.
SET citus.enable_unsafe_triggers TO ON;
RESET client_min_messages;
-- this shouldn't give any syntax errors
SELECT create_distributed_table('"NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"', null);
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$"NULL_!_dist_key"."partition1_nullKeyTable.1!?!90123456789012345678901234567890123"$$)
NOTICE: Copying data from local table...
NOTICE: copying the data has completed
DETAIL: The local data in the table is no longer visible, but is still on disk.
HINT: To remove the local data, run: SELECT truncate_local_data_after_distributing_table($$"NULL_!_dist_key"."partition2_nullKeyTable.1!?!90123456789012345678901234567890123"$$)
create_distributed_table
---------------------------------------------------------------------
(1 row)
-- now we can add triggers on distributed tables, because we set the GUC to on
CREATE TRIGGER insert_100_trigger_2
AFTER UPDATE ON null_key_table_with_trigger
FOR EACH STATEMENT EXECUTE FUNCTION insert_id_100();
SET client_min_messages TO ERROR;
UPDATE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" SET "TeNANt_Id"="TeNANt_Id"+1;
-- we should see one row with id = 100
SELECT COUNT(*) FROM "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" WHERE id = 100;
count
---------------------------------------------------------------------
1
(1 row)
-- create some objects after create_distributed_table
CREATE INDEX "my!Index2New" ON "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id) WITH ( fillfactor = 90 ) WHERE id < 20;
CREATE UNIQUE INDEX uniqueIndex2New ON "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id);
-- error out for already existing, because of the unique index
INSERT INTO "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" VALUES (1, 1, row_to_json(row(1,1), true));
ERROR: duplicate key value violates unique constraint "partition1_nullKeyTable.1!?!901234567890123456_bf4a8ac1_1730056"
DETAIL: Key (id)=(X) already exists.
CONTEXT: while executing command on localhost:xxxxx
-- verify all 4 shard indexes are created on the same node
SELECT result FROM run_command_on_workers($$
SELECT COUNT(*) FROM pg_indexes WHERE indexname LIKE '%my!Index_New_1%' OR indexname LIKE '%uniqueindex%new_1%';$$)
ORDER BY nodeport;
result
---------------------------------------------------------------------
4
0
(2 rows)
-- foreign key to a ref table
CREATE TABLE dummy_reference_table (a INT PRIMARY KEY);
SELECT create_reference_table('dummy_reference_table');
create_reference_table
---------------------------------------------------------------------
(1 row)
TRUNCATE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789";
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_ref FOREIGN KEY (id) REFERENCES dummy_reference_table(a);
BEGIN; -- try to add the same fkey, reversed
ALTER TABLE dummy_reference_table
ADD CONSTRAINT fkey_to_dummy_ref FOREIGN KEY (a) REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id);
ERROR: cannot create foreign key constraint since foreign keys from reference tables and local tables to distributed tables are not supported
DETAIL: Reference tables and local tables can only have foreign keys to reference tables and local tables
ROLLBACK;
-- errors out because of foreign key violation
INSERT INTO "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" VALUES (100, 1, row_to_json(row(1,1), true));
ERROR: insert or update on table "partition100_nullKeyTable.1!?!9012345678901234_0aba0bf3_1730058" violates foreign key constraint "fkey_to_dummy_ref_1730055"
DETAIL: Key (id)=(X) is not present in table "dummy_reference_table_1730059".
CONTEXT: while executing command on localhost:xxxxx
-- now inserts successfully
INSERT INTO dummy_reference_table VALUES (100);
INSERT INTO "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" VALUES (100, 1, row_to_json(row(1,1), true));
DELETE FROM "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" WHERE id = 100;
-- foreign key to a local table, errors out
CREATE TABLE local_table_for_fkey (a INT PRIMARY KEY);
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_local FOREIGN KEY (id) REFERENCES local_table_for_fkey(a);
ERROR: referenced table "local_table_for_fkey" must be a distributed table or a reference table
DETAIL: To enforce foreign keys, the referencing and referenced rows need to be stored on the same node.
HINT: You could use SELECT create_reference_table('local_table_for_fkey') to replicate the referenced table to all nodes or consider dropping the foreign key
-- Normally, we support foreign keys from Postgres tables to distributed
-- tables assuming that the user will soon distribute the local table too
-- anyway. However, this is not the case for null-shard-key tables before
-- we improve SQL support.
ALTER TABLE local_table_for_fkey
ADD CONSTRAINT fkey_from_dummy_local FOREIGN KEY (a) REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id);
ERROR: queries that reference a distributed table without a shard key can only reference colocated distributed tables or reference tables
DETAIL: Local tables cannot be used in distributed queries.
CONTEXT: SQL statement "SELECT fk."a" FROM ONLY "create_null_dist_key"."local_table_for_fkey" fk LEFT OUTER JOIN "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234" pk ON ( pk."id" OPERATOR(pg_catalog.=) fk."a") WHERE pk."id" IS NULL AND (fk."a" IS NOT NULL)"
-- foreign key to a citus local table, errors out
CREATE TABLE citus_local_table_for_fkey (a INT PRIMARY KEY);
SELECT citus_add_local_table_to_metadata('citus_local_table_for_fkey');
citus_add_local_table_to_metadata
---------------------------------------------------------------------
(1 row)
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_citus_local FOREIGN KEY (id) REFERENCES citus_local_table_for_fkey(a);
ERROR: cannot create foreign key constraint since relations are not colocated or not referencing a reference table
DETAIL: A distributed table can only have foreign keys if it is referencing another colocated hash distributed table or a reference table
-- reversed, still fails
ALTER TABLE citus_local_table_for_fkey
ADD CONSTRAINT fkey_from_dummy_citus_local FOREIGN KEY (a) REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id);
ERROR: cannot create foreign key constraint since foreign keys from reference tables and local tables to distributed tables are not supported
DETAIL: Reference tables and local tables can only have foreign keys to reference tables and local tables
-- foreign key to a distributed table, errors out because not colocated
CREATE TABLE dist_table_for_fkey (a INT PRIMARY KEY);
SELECT create_distributed_table('dist_table_for_fkey', 'a');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_dist FOREIGN KEY (id) REFERENCES dist_table_for_fkey(a);
ERROR: cannot create foreign key constraint since relations are not colocated or not referencing a reference table
DETAIL: A distributed table can only have foreign keys if it is referencing another colocated hash distributed table or a reference table
-- reversed, still fails
ALTER TABLE dist_table_for_fkey
ADD CONSTRAINT fkey_to_dummy_dist FOREIGN KEY (a) REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id);
ERROR: cannot create foreign key constraint since relations are not colocated or not referencing a reference table
DETAIL: A distributed table can only have foreign keys if it is referencing another colocated hash distributed table or a reference table
-- create a null key distributed table, not colocated with the partitioned table, and then try to create a fkey
CREATE TABLE null_key_dist_not_colocated (a INT PRIMARY KEY);
SELECT create_distributed_table('null_key_dist_not_colocated', null, colocate_with=>'none');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_dist FOREIGN KEY (id) REFERENCES null_key_dist_not_colocated(a);
ERROR: cannot create foreign key constraint since relations are not colocated or not referencing a reference table
DETAIL: A distributed table can only have foreign keys if it is referencing another colocated hash distributed table or a reference table
-- create a null key distributed table, colocated with the partitioned table, and then create a fkey
CREATE TABLE null_key_dist (a INT PRIMARY KEY);
SELECT create_distributed_table('null_key_dist', null, colocate_with=>'"NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_dist FOREIGN KEY (id) REFERENCES null_key_dist(a);
-- check supported ON DELETE and ON UPDATE commands
ALTER TABLE null_key_dist ADD CONSTRAINT fkey_add_test_1 FOREIGN KEY(a)
REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id) ON DELETE SET DEFAULT;
ALTER TABLE null_key_dist ADD CONSTRAINT fkey_add_test_2 FOREIGN KEY(a)
REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id) ON UPDATE CASCADE;
ALTER TABLE null_key_dist ADD CONSTRAINT fkey_add_test_3 FOREIGN KEY(a)
REFERENCES dummy_reference_table(a) ON DELETE SET DEFAULT;
ALTER TABLE null_key_dist ADD CONSTRAINT fkey_add_test_4 FOREIGN KEY(a)
REFERENCES dummy_reference_table(a) ON UPDATE CASCADE;
ALTER TABLE null_key_dist DROP CONSTRAINT fkey_add_test_1;
ALTER TABLE null_key_dist DROP CONSTRAINT fkey_add_test_2;
ALTER TABLE null_key_dist DROP CONSTRAINT fkey_add_test_3;
ALTER TABLE null_key_dist DROP CONSTRAINT fkey_add_test_4;
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" DROP CONSTRAINT fkey_to_dummy_dist;
-- create a view that depends on the null shard key table
CREATE VIEW public.v1 AS SELECT * FROM null_key_dist;
SELECT * FROM public.v1;
a
---------------------------------------------------------------------
(0 rows)
DELETE FROM null_key_dist;
VACUUM null_key_dist;
TRUNCATE null_key_dist;
DROP TABLE null_key_dist CASCADE;
RESET client_min_messages;
CREATE TABLE multi_level_partitioning_parent(
measureid integer,
eventdatetime date,
@ -771,7 +1128,7 @@ BEGIN;
INSERT INTO referencing_table VALUES (1, 2);
-- fails
INSERT INTO referencing_table VALUES (2, 2);
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730049"
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730098"
DETAIL: Key (a)=(2) is not present in table "referenced_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
ROLLBACK;
@ -817,7 +1174,7 @@ BEGIN;
INSERT INTO referencing_table VALUES (1, 2);
-- fails
INSERT INTO referencing_table VALUES (2, 2);
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730085"
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730134"
DETAIL: Key (a)=(2) is not present in table "referenced_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
ROLLBACK;
@ -935,8 +1292,8 @@ SELECT result, success FROM run_command_on_workers($$
$$);
result | success
---------------------------------------------------------------------
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730102" | f
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730102" | f
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730151" | f
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730151" | f
(2 rows)
DROP TABLE referencing_table, referenced_table;
@ -951,8 +1308,8 @@ SELECT create_distributed_table('self_fkey_test', NULL, distribution_type=>null)
INSERT INTO self_fkey_test VALUES (1, 1); -- ok
INSERT INTO self_fkey_test VALUES (2, 3); -- fails
ERROR: insert or update on table "self_fkey_test_1730103" violates foreign key constraint "self_fkey_test_b_fkey_1730103"
DETAIL: Key (b)=(3) is not present in table "self_fkey_test_1730103".
ERROR: insert or update on table "self_fkey_test_1730152" violates foreign key constraint "self_fkey_test_b_fkey_1730152"
DETAIL: Key (b)=(3) is not present in table "self_fkey_test_1730152".
CONTEXT: while executing command on localhost:xxxxx
-- similar foreign key tests but this time create the referencing table later on
-- referencing table is a null shard key table
@ -976,7 +1333,7 @@ BEGIN;
INSERT INTO referencing_table VALUES (1, 2);
-- fails
INSERT INTO referencing_table VALUES (2, 2);
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730105"
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730154"
DETAIL: Key (a)=(2) is not present in table "referenced_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
ROLLBACK;
@ -999,7 +1356,7 @@ BEGIN;
INSERT INTO referencing_table VALUES (2, 1);
-- fails
INSERT INTO referencing_table VALUES (1, 2);
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_b_fkey_1730107"
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_b_fkey_1730156"
DETAIL: Key (a, b)=(1, 2) is not present in table "referenced_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
ROLLBACK;
@ -1040,6 +1397,24 @@ BEGIN;
SELECT create_distributed_table('referencing_table', NULL, distribution_type=>null, colocate_with=>'referenced_table');
ERROR: cannot create foreign key constraint since Citus does not support ON DELETE / UPDATE SET DEFAULT actions on the columns that default to sequences
ROLLBACK;
BEGIN;
CREATE TABLE referenced_table(a int UNIQUE, b int);
SELECT create_distributed_table('referenced_table', NULL, distribution_type=>null);
create_distributed_table
---------------------------------------------------------------------
(1 row)
CREATE TABLE referencing_table(a serial, b int);
SELECT create_distributed_table('referencing_table', NULL, distribution_type=>null, colocate_with=>'referenced_table');
create_distributed_table
---------------------------------------------------------------------
(1 row)
ALTER TABLE referencing_table ADD CONSTRAINT fkey_to_dummy_ref_on_update FOREIGN KEY (a) REFERENCES referenced_table(a) ON UPDATE SET DEFAULT;
ERROR: cannot create foreign key constraint since Citus does not support ON DELETE / UPDATE SET DEFAULT actions on the columns that default to sequences
ROLLBACK;
-- to a non-colocated null dist key table
BEGIN;
CREATE TABLE referenced_table(a int UNIQUE, b int);
@ -1088,7 +1463,7 @@ BEGIN;
INSERT INTO referencing_table VALUES (1, 2);
-- fails
INSERT INTO referencing_table VALUES (2, 2);
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730146"
ERROR: insert or update on table "referencing_table_xxxxxxx" violates foreign key constraint "referencing_table_a_fkey_1730197"
DETAIL: Key (a)=(2) is not present in table "referenced_table_xxxxxxx".
CONTEXT: while executing command on localhost:xxxxx
ROLLBACK;
@ -1339,10 +1714,6 @@ CREATE TABLE trigger_table_1 (value int);
CREATE TRIGGER trigger_1
BEFORE INSERT ON trigger_table_1
FOR EACH ROW EXECUTE FUNCTION increment_value();
SELECT create_distributed_table('trigger_table_1', NULL, distribution_type=>null);
ERROR: cannot distribute relation "trigger_table_1" because it has triggers
HINT: Consider dropping all the triggers on "trigger_table_1" and retry.
SET citus.enable_unsafe_triggers TO ON;
SELECT create_distributed_table('trigger_table_1', NULL, distribution_type=>null);
create_distributed_table
---------------------------------------------------------------------
@ -1423,10 +1794,19 @@ TRUNCATE trigger_table_3;
NOTICE: notice_truncate()
CONTEXT: PL/pgSQL function notice_truncate() line XX at RAISE
SET client_min_messages TO WARNING;
-- test rename, disable and drop trigger
ALTER TRIGGER trigger_4 ON trigger_table_3 RENAME TO trigger_new_name;
ALTER TABLE trigger_table_3 DISABLE TRIGGER ALL;
DROP TRIGGER trigger_new_name ON trigger_table_3;
-- enable the remaining triggers
ALTER TABLE trigger_table_3 ENABLE TRIGGER ALL;
-- try a few simple queries at least to make sure that we don't crash
BEGIN;
INSERT INTO nullkey_c1_t1 SELECT * FROM nullkey_c2_t1;
ROLLBACK;
DROP TRIGGER IF EXISTS trigger_1 ON trigger_table_1;
DROP TRIGGER trigger_2 ON trigger_table_2 CASCADE;
DROP TRIGGER trigger_3 ON trigger_table_3 RESTRICT;
-- cleanup at exit
SET client_min_messages TO ERROR;
DROP SCHEMA create_null_dist_key, "NULL_!_dist_key" CASCADE;

View File

@ -68,7 +68,7 @@ test: multi_master_protocol multi_load_data multi_load_data_superuser multi_beha
test: multi_behavioral_analytics_basics multi_behavioral_analytics_single_shard_queries multi_insert_select_non_pushable_queries multi_insert_select multi_behavioral_analytics_create_table_superuser
test: multi_shard_update_delete recursive_dml_with_different_planners_executors
test: insert_select_repartition window_functions dml_recursive multi_insert_select_window
test: multi_insert_select_conflict citus_table_triggers
test: multi_insert_select_conflict citus_table_triggers alter_table_null_dist_key
test: multi_row_insert insert_select_into_local_table alter_index
# following should not run in parallel because it relies on connection counts to workers

View File

@ -0,0 +1,98 @@
CREATE SCHEMA alter_null_dist_key;
SET search_path TO alter_null_dist_key;
SET citus.next_shard_id TO 1720000;
SET citus.shard_count TO 32;
SET citus.shard_replication_factor TO 1;
CREATE SEQUENCE dist_seq;
CREATE TABLE null_dist_table(a bigint DEFAULT nextval('dist_seq') UNIQUE, "b" text, c bigint GENERATED BY DEFAULT AS IDENTITY);
INSERT INTO null_dist_table("b") VALUES ('test');
SELECT create_distributed_table('null_dist_table', null, colocate_with=>'none', distribution_type=>null);
-- add column
ALTER TABLE null_dist_table ADD COLUMN d bigint DEFAULT 2;
SELECT * FROM null_dist_table ORDER BY c;
-- alter default, set to 3
ALTER TABLE null_dist_table ALTER COLUMN d SET DEFAULT 3;
INSERT INTO null_dist_table("b") VALUES ('test');
SELECT * FROM null_dist_table ORDER BY c;
-- drop default, see null
ALTER TABLE null_dist_table ALTER COLUMN d DROP DEFAULT;
INSERT INTO null_dist_table("b") VALUES ('test');
SELECT * FROM null_dist_table ORDER BY c;
-- cleanup the rows that were added to test the default behavior
DELETE FROM null_dist_table WHERE "b" = 'test' AND a > 1;
-- alter column type
ALTER TABLE null_dist_table ALTER COLUMN d TYPE text;
UPDATE null_dist_table SET d = 'this is a text' WHERE d = '2';
SELECT * FROM null_dist_table ORDER BY c;
-- drop seq column
ALTER TABLE null_dist_table DROP COLUMN a;
SELECT * FROM null_dist_table ORDER BY c;
-- add not null constraint
ALTER TABLE null_dist_table ALTER COLUMN b SET NOT NULL;
-- not null constraint violation, error out
INSERT INTO null_dist_table VALUES (NULL, 2, 'test');
-- drop not null constraint and try again
ALTER TABLE null_dist_table ALTER COLUMN b DROP NOT NULL;
INSERT INTO null_dist_table VALUES (NULL, 3, 'test');
SELECT * FROM null_dist_table ORDER BY c;
-- add exclusion constraint
ALTER TABLE null_dist_table ADD CONSTRAINT exc_b EXCLUDE USING btree (b with =);
-- rename the exclusion constraint, errors out
ALTER TABLE null_dist_table RENAME CONSTRAINT exc_b TO exc_b_1;
-- create exclusion constraint without a name
ALTER TABLE null_dist_table ADD EXCLUDE USING btree (b with =);
-- test setting autovacuum option
ALTER TABLE null_dist_table SET (autovacuum_enabled = false);
-- test multiple subcommands
ALTER TABLE null_dist_table ADD COLUMN int_column1 INTEGER,
DROP COLUMN d;
SELECT * FROM null_dist_table ORDER BY c;
-- test policy and row level security
CREATE TABLE null_dist_key_with_policy (table_user text);
INSERT INTO null_dist_key_with_policy VALUES ('user_1');
SELECT create_distributed_table('null_dist_key_with_policy', null);
-- enable rls
ALTER TABLE null_dist_key_with_policy ENABLE ROW LEVEL SECURITY;
-- user_1 will be allowed to see the inserted row
CREATE ROLE user_1 WITH LOGIN;
GRANT ALL ON SCHEMA alter_null_dist_key TO user_1;
GRANT ALL ON TABLE alter_null_dist_key.null_dist_key_with_policy TO user_1;
CREATE POLICY table_policy ON null_dist_key_with_policy TO user_1
USING (table_user = current_user);
-- user_2 will not be allowed to see the inserted row
CREATE ROLE user_2 WITH LOGIN;
GRANT ALL ON SCHEMA alter_null_dist_key TO user_2;
GRANT ALL ON TABLE alter_null_dist_key.null_dist_key_with_policy TO user_2;
CREATE POLICY table_policy_1 ON null_dist_key_with_policy TO user_2
USING (table_user = current_user);
\c - user_1 -
SELECT * FROM alter_null_dist_key.null_dist_key_with_policy;
\c - user_2 -
SELECT * FROM alter_null_dist_key.null_dist_key_with_policy;
-- postgres will always be allowed to see the row as a superuser
\c - postgres -
SELECT * FROM alter_null_dist_key.null_dist_key_with_policy;
-- cleanup
SET client_min_messages TO ERROR;
DROP SCHEMA alter_null_dist_key CASCADE;
DROP ROLE user_1, user_2;

View File

@ -317,9 +317,11 @@ DROP TABLE null_dist_key_table_1, null_dist_key_table_2;
-- create indexes before creating the null dist key tables
-- .. for an initially empty table
CREATE TABLE null_dist_key_table_1(a int);
CREATE TABLE null_dist_key_table_1(a int, b int);
CREATE STATISTICS s1 (dependencies) ON a, b FROM null_dist_key_table_1;
CREATE INDEX null_dist_key_table_1_idx ON null_dist_key_table_1(a);
SELECT create_distributed_table('null_dist_key_table_1', null, colocate_with=>'none');
CREATE STATISTICS s2 (dependencies) ON a, b FROM null_dist_key_table_1;
-- .. and for another table having data in it before creating null dist key table
CREATE TABLE null_dist_key_table_2(a int);
@ -327,6 +329,12 @@ INSERT INTO null_dist_key_table_2 VALUES(1);
CREATE INDEX null_dist_key_table_2_idx ON null_dist_key_table_2(a);
SELECT create_distributed_table('null_dist_key_table_2', null, colocate_with=>'none');
-- test create index concurrently, then reindex
CREATE INDEX CONCURRENTLY ind_conc ON null_dist_key_table_2(a);
REINDEX INDEX ind_conc;
REINDEX INDEX CONCURRENTLY ind_conc;
DROP INDEX ind_conc;
SELECT * FROM null_dist_key_table_2 ORDER BY a;
-- show that we do not support inheritance relationships
@ -347,11 +355,22 @@ BEGIN;
CREATE POLICY table_policy ON null_dist_key_table_3 TO table_users
USING (table_user = current_user);
GRANT ALL ON TABLE null_dist_key_table_3 TO table_users;
ALTER TABLE null_dist_key_table_3 OWNER TO table_users;
SELECT create_distributed_table('null_dist_key_table_3', null, colocate_with=>'none');
REVOKE ALL ON TABLE null_dist_key_table_3 FROM table_users;
ALTER TABLE null_dist_key_table_3 OWNER TO postgres;
GRANT ALL ON TABLE null_dist_key_table_3 TO table_users;
ROLLBACK;
ALTER STATISTICS s2 SET STATISTICS 46;
ALTER TABLE null_dist_key_table_1 SET SCHEMA public;
DROP STATISTICS s1, s2;
-- drop them for next tests
DROP TABLE null_dist_key_table_1, null_dist_key_table_2, distributed_table;
DROP TABLE public.null_dist_key_table_1, null_dist_key_table_2, distributed_table;
-- tests for object names that should be escaped properly
@ -438,6 +457,240 @@ SELECT create_distributed_table('sensors_2000', NULL, distribution_type=>null);
SELECT create_distributed_table('sensors', NULL, distribution_type=>null);
-- verify we can create new partitions after distributing the parent table
CREATE TABLE sensors_2001 PARTITION OF sensors FOR VALUES FROM ('2001-01-01') TO ('2002-01-01');
-- verify we can attach to a null dist key table
CREATE TABLE sensors_2002 (measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data));
ALTER TABLE sensors ATTACH PARTITION sensors_2002 FOR VALUES FROM ('2002-01-01') TO ('2003-01-01');
-- verify we can detach from a null dist key table
ALTER TABLE sensors DETACH PARTITION sensors_2001;
-- error out when attaching a noncolocated partition
CREATE TABLE sensors_2003 (measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data));
SELECT create_distributed_table('sensors_2003', NULL, distribution_type=>null, colocate_with=>'none');
ALTER TABLE sensors ATTACH PARTITION sensors_2003 FOR VALUES FROM ('2003-01-01') TO ('2004-01-01');
DROP TABLE sensors_2003;
-- verify we can attach after distributing, if the parent and partition are colocated
CREATE TABLE sensors_2004 (measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data));
SELECT create_distributed_table('sensors_2004', NULL, distribution_type=>null, colocate_with=>'sensors');
ALTER TABLE sensors ATTACH PARTITION sensors_2004 FOR VALUES FROM ('2004-01-01') TO ('2005-01-01');
-- verify we can attach a citus local table
CREATE TABLE sensors_2005 (measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data));
SELECT citus_add_local_table_to_metadata('sensors_2005');
ALTER TABLE sensors ATTACH PARTITION sensors_2005 FOR VALUES FROM ('2005-01-01') TO ('2006-01-01');
-- check metadata
-- check all partitions and the parent on pg_dist_partition
SELECT logicalrelid::text FROM pg_dist_partition WHERE logicalrelid::text IN ('sensors', 'sensors_2000', 'sensors_2001', 'sensors_2002', 'sensors_2004', 'sensors_2005') ORDER BY logicalrelid::text;
-- verify they are all colocated
SELECT COUNT(DISTINCT(colocationid)) FROM pg_dist_partition WHERE logicalrelid::text IN ('sensors', 'sensors_2000', 'sensors_2001', 'sensors_2002', 'sensors_2004', 'sensors_2005');
-- verify all partitions are placed on the same node
SELECT COUNT(DISTINCT(groupid)) FROM pg_dist_placement WHERE shardid IN
(SELECT shardid FROM pg_dist_shard WHERE logicalrelid::text IN ('sensors', 'sensors_2000', 'sensors_2001', 'sensors_2002', 'sensors_2004', 'sensors_2005'));
-- verify the shard of sensors_2000 is attached to the parent shard, on the worker node
SELECT COUNT(*) FROM run_command_on_workers($$
SELECT relpartbound FROM pg_class WHERE relname LIKE 'sensors_2000_1______';$$)
WHERE length(result) > 0;
-- verify the shard of sensors_2001 is detached from the parent shard, on the worker node
SELECT COUNT(*) FROM run_command_on_workers($$
SELECT relpartbound FROM pg_class WHERE relname LIKE 'sensors_2001_1______';$$)
WHERE length(result) > 0;
-- verify the shard of sensors_2002 is attached to the parent shard, on the worker node
SELECT COUNT(*) FROM run_command_on_workers($$
SELECT relpartbound FROM pg_class WHERE relname LIKE 'sensors_2002_1______';$$)
WHERE length(result) > 0;
-- create a partitioned citus local table and verify we error out when attaching a partition with null dist key
CREATE TABLE partitioned_citus_local_tbl(
measureid integer,
eventdatetime date,
measure_data jsonb,
PRIMARY KEY (measureid, eventdatetime, measure_data))
PARTITION BY RANGE(eventdatetime);
SELECT citus_add_local_table_to_metadata('partitioned_citus_local_tbl');
CREATE TABLE partition_with_null_key (measureid integer, eventdatetime date, measure_data jsonb, PRIMARY KEY (measureid, eventdatetime, measure_data));
SELECT create_distributed_table('partition_with_null_key', NULL, distribution_type=>null);
ALTER TABLE partitioned_citus_local_tbl ATTACH PARTITION partition_with_null_key FOR VALUES FROM ('2004-01-01') TO ('2005-01-01');
-- test partitioned tables + indexes with long names
CREATE TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(
id int PRIMARY KEY,
"TeNANt_Id" int,
"jsondata" jsonb NOT NULL,
name text,
price numeric CHECK (price > 0),
serial_data bigserial, UNIQUE (id, price))
PARTITION BY LIST(id);
CREATE TABLE "NULL_!_dist_key"."partition1_nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
PARTITION OF "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
FOR VALUES IN (1);
CREATE TABLE "NULL_!_dist_key"."partition2_nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
PARTITION OF "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
FOR VALUES IN (2);
CREATE TABLE "NULL_!_dist_key"."partition100_nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
PARTITION OF "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
FOR VALUES IN (100);
-- create some objects before create_distributed_table
CREATE INDEX "my!Index1New" ON "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id) WITH ( fillfactor = 80 ) WHERE id > 10;
CREATE UNIQUE INDEX uniqueIndexNew ON "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" (id);
-- ingest some data before create_distributed_table
set client_min_messages to ERROR;
INSERT INTO "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" VALUES (1, 1, row_to_json(row(1,1), true)),
(2, 1, row_to_json(row(2,2), 'false'));
reset client_min_messages;
-- create a replica identity before create_distributed_table
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" REPLICA IDENTITY USING INDEX uniqueIndexNew;
-- test triggers
SET client_min_messages TO ERROR;
CREATE FUNCTION insert_id_100() RETURNS trigger AS $insert_100$
BEGIN
INSERT INTO "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" VALUES (100, 1, row_to_json(row(1,1), true));
RETURN NEW;
END;
$insert_100$ LANGUAGE plpgsql;
CREATE TABLE null_key_table_with_trigger(a INT);
SELECT create_distributed_table('null_key_table_with_trigger', null);
-- try to add a trigger after distributing the table, fails
CREATE TRIGGER insert_100_trigger
AFTER UPDATE ON null_key_table_with_trigger
FOR EACH STATEMENT EXECUTE FUNCTION insert_id_100();
-- now try to distribute a table that already has a trigger on it
CREATE TRIGGER insert_100_trigger
AFTER UPDATE ON "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
FOR EACH STATEMENT EXECUTE FUNCTION insert_id_100();
-- error out because of the trigger
SELECT create_distributed_table('"NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"', null);
SET citus.enable_unsafe_triggers TO ON;
RESET client_min_messages;
-- this shouldn't give any syntax errors
SELECT create_distributed_table('"NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"', null);
-- now we can add triggers on distributed tables, because we set the GUC to on
CREATE TRIGGER insert_100_trigger_2
AFTER UPDATE ON null_key_table_with_trigger
FOR EACH STATEMENT EXECUTE FUNCTION insert_id_100();
SET client_min_messages TO ERROR;
UPDATE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" SET "TeNANt_Id"="TeNANt_Id"+1;
-- we should see one row with id = 100
SELECT COUNT(*) FROM "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" WHERE id = 100;
-- create some objects after create_distributed_table
CREATE INDEX "my!Index2New" ON "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id) WITH ( fillfactor = 90 ) WHERE id < 20;
CREATE UNIQUE INDEX uniqueIndex2New ON "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id);
-- error out for already existing, because of the unique index
INSERT INTO "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" VALUES (1, 1, row_to_json(row(1,1), true));
-- verify all 4 shard indexes are created on the same node
SELECT result FROM run_command_on_workers($$
SELECT COUNT(*) FROM pg_indexes WHERE indexname LIKE '%my!Index_New_1%' OR indexname LIKE '%uniqueindex%new_1%';$$)
ORDER BY nodeport;
-- foreign key to a ref table
CREATE TABLE dummy_reference_table (a INT PRIMARY KEY);
SELECT create_reference_table('dummy_reference_table');
TRUNCATE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789";
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_ref FOREIGN KEY (id) REFERENCES dummy_reference_table(a);
BEGIN; -- try to add the same fkey, reversed
ALTER TABLE dummy_reference_table
ADD CONSTRAINT fkey_to_dummy_ref FOREIGN KEY (a) REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id);
ROLLBACK;
-- errors out because of foreign key violation
INSERT INTO "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" VALUES (100, 1, row_to_json(row(1,1), true));
-- now inserts successfully
INSERT INTO dummy_reference_table VALUES (100);
INSERT INTO "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" VALUES (100, 1, row_to_json(row(1,1), true));
DELETE FROM "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" WHERE id = 100;
-- foreign key to a local table, errors out
CREATE TABLE local_table_for_fkey (a INT PRIMARY KEY);
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_local FOREIGN KEY (id) REFERENCES local_table_for_fkey(a);
-- Normally, we support foreign keys from Postgres tables to distributed
-- tables assuming that the user will soon distribute the local table too
-- anyway. However, this is not the case for null-shard-key tables before
-- we improve SQL support.
ALTER TABLE local_table_for_fkey
ADD CONSTRAINT fkey_from_dummy_local FOREIGN KEY (a) REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id);
-- foreign key to a citus local table, errors out
CREATE TABLE citus_local_table_for_fkey (a INT PRIMARY KEY);
SELECT citus_add_local_table_to_metadata('citus_local_table_for_fkey');
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_citus_local FOREIGN KEY (id) REFERENCES citus_local_table_for_fkey(a);
-- reversed, still fails
ALTER TABLE citus_local_table_for_fkey
ADD CONSTRAINT fkey_from_dummy_citus_local FOREIGN KEY (a) REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id);
-- foreign key to a distributed table, errors out because not colocated
CREATE TABLE dist_table_for_fkey (a INT PRIMARY KEY);
SELECT create_distributed_table('dist_table_for_fkey', 'a');
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_dist FOREIGN KEY (id) REFERENCES dist_table_for_fkey(a);
-- reversed, still fails
ALTER TABLE dist_table_for_fkey
ADD CONSTRAINT fkey_to_dummy_dist FOREIGN KEY (a) REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id);
-- create a null key distributed table, not colocated with the partitioned table, and then try to create a fkey
CREATE TABLE null_key_dist_not_colocated (a INT PRIMARY KEY);
SELECT create_distributed_table('null_key_dist_not_colocated', null, colocate_with=>'none');
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_dist FOREIGN KEY (id) REFERENCES null_key_dist_not_colocated(a);
-- create a null key distributed table, colocated with the partitioned table, and then create a fkey
CREATE TABLE null_key_dist (a INT PRIMARY KEY);
SELECT create_distributed_table('null_key_dist', null, colocate_with=>'"NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"');
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"
ADD CONSTRAINT fkey_to_dummy_dist FOREIGN KEY (id) REFERENCES null_key_dist(a);
-- check supported ON DELETE and ON UPDATE commands
ALTER TABLE null_key_dist ADD CONSTRAINT fkey_add_test_1 FOREIGN KEY(a)
REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id) ON DELETE SET DEFAULT;
ALTER TABLE null_key_dist ADD CONSTRAINT fkey_add_test_2 FOREIGN KEY(a)
REFERENCES "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789"(id) ON UPDATE CASCADE;
ALTER TABLE null_key_dist ADD CONSTRAINT fkey_add_test_3 FOREIGN KEY(a)
REFERENCES dummy_reference_table(a) ON DELETE SET DEFAULT;
ALTER TABLE null_key_dist ADD CONSTRAINT fkey_add_test_4 FOREIGN KEY(a)
REFERENCES dummy_reference_table(a) ON UPDATE CASCADE;
ALTER TABLE null_key_dist DROP CONSTRAINT fkey_add_test_1;
ALTER TABLE null_key_dist DROP CONSTRAINT fkey_add_test_2;
ALTER TABLE null_key_dist DROP CONSTRAINT fkey_add_test_3;
ALTER TABLE null_key_dist DROP CONSTRAINT fkey_add_test_4;
ALTER TABLE "NULL_!_dist_key"."nullKeyTable.1!?!9012345678901234567890123456789012345678901234567890123456789" DROP CONSTRAINT fkey_to_dummy_dist;
-- create a view that depends on the null shard key table
CREATE VIEW public.v1 AS SELECT * FROM null_key_dist;
SELECT * FROM public.v1;
DELETE FROM null_key_dist;
VACUUM null_key_dist;
TRUNCATE null_key_dist;
DROP TABLE null_key_dist CASCADE;
RESET client_min_messages;
CREATE TABLE multi_level_partitioning_parent(
measureid integer,
eventdatetime date,
@ -685,6 +938,15 @@ BEGIN;
SELECT create_distributed_table('referencing_table', NULL, distribution_type=>null, colocate_with=>'referenced_table');
ROLLBACK;
BEGIN;
CREATE TABLE referenced_table(a int UNIQUE, b int);
SELECT create_distributed_table('referenced_table', NULL, distribution_type=>null);
CREATE TABLE referencing_table(a serial, b int);
SELECT create_distributed_table('referencing_table', NULL, distribution_type=>null, colocate_with=>'referenced_table');
ALTER TABLE referencing_table ADD CONSTRAINT fkey_to_dummy_ref_on_update FOREIGN KEY (a) REFERENCES referenced_table(a) ON UPDATE SET DEFAULT;
ROLLBACK;
-- to a non-colocated null dist key table
BEGIN;
CREATE TABLE referenced_table(a int UNIQUE, b int);
@ -888,9 +1150,6 @@ FOR EACH ROW EXECUTE FUNCTION increment_value();
SELECT create_distributed_table('trigger_table_1', NULL, distribution_type=>null);
SET citus.enable_unsafe_triggers TO ON;
SELECT create_distributed_table('trigger_table_1', NULL, distribution_type=>null);
INSERT INTO trigger_table_1 VALUES(1), (2);
SELECT * FROM trigger_table_1 ORDER BY value;
@ -952,11 +1211,22 @@ SET client_min_messages TO NOTICE;
TRUNCATE trigger_table_3;
SET client_min_messages TO WARNING;
-- test rename, disable and drop trigger
ALTER TRIGGER trigger_4 ON trigger_table_3 RENAME TO trigger_new_name;
ALTER TABLE trigger_table_3 DISABLE TRIGGER ALL;
DROP TRIGGER trigger_new_name ON trigger_table_3;
-- enable the remaining triggers
ALTER TABLE trigger_table_3 ENABLE TRIGGER ALL;
-- try a few simple queries at least to make sure that we don't crash
BEGIN;
INSERT INTO nullkey_c1_t1 SELECT * FROM nullkey_c2_t1;
ROLLBACK;
DROP TRIGGER IF EXISTS trigger_1 ON trigger_table_1;
DROP TRIGGER trigger_2 ON trigger_table_2 CASCADE;
DROP TRIGGER trigger_3 ON trigger_table_3 RESTRICT;
-- cleanup at exit
SET client_min_messages TO ERROR;
DROP SCHEMA create_null_dist_key, "NULL_!_dist_key" CASCADE;