diff --git a/src/backend/distributed/commands/index.c b/src/backend/distributed/commands/index.c index 008f4fa90..5f1598510 100644 --- a/src/backend/distributed/commands/index.c +++ b/src/backend/distributed/commands/index.c @@ -1202,6 +1202,15 @@ ErrorIfUnsupportedIndexStmt(IndexStmt *createIndexStatement) "is currently unsupported"))); } + if (AllowUnsafeConstraints) + { + /* + * The user explicitly wants to allow the constraint without + * distribution column. + */ + return; + } + Var *partitionKey = DistPartitionKeyOrError(relationId); List *indexParameterList = createIndexStatement->indexParams; IndexElem *indexElement = NULL; diff --git a/src/backend/distributed/commands/table.c b/src/backend/distributed/commands/table.c index bc897eec6..689176890 100644 --- a/src/backend/distributed/commands/table.c +++ b/src/backend/distributed/commands/table.c @@ -54,6 +54,12 @@ /* controlled via GUC, should be accessed via GetEnableLocalReferenceForeignKeys() */ bool EnableLocalReferenceForeignKeys = true; +/* + * GUC that controls whether to allow unique/exclude constraints without + * distribution column. + */ +bool AllowUnsafeConstraints = false; + /* Local functions forward declarations for unsupported command checks */ static void PostprocessCreateTableStmtForeignKeys(CreateStmt *createStatement); static void PostprocessCreateTableStmtPartitionOf(CreateStmt *createStatement, @@ -2573,6 +2579,16 @@ ErrorIfUnsupportedConstraint(Relation relation, char distributionMethod, errhint("Consider using hash partitioning."))); } + if (AllowUnsafeConstraints) + { + /* + * The user explicitly wants to allow the constraint without + * distribution column. + */ + index_close(indexDesc, NoLock); + continue; + } + int attributeCount = indexInfo->ii_NumIndexAttrs; AttrNumber *attributeNumberArray = indexInfo->ii_IndexAttrNumbers; diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index 4846f64a0..125194f87 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -821,6 +821,26 @@ RegisterCitusConfigVariables(void) GUC_NO_SHOW_ALL, NULL, NULL, NULL); + DefineCustomBoolVariable( + "citus.allow_unsafe_constraints", + gettext_noop("Enables unique constraints and exclusion constraints " + "that do not include a distribution column."), + gettext_noop("To enforce global uniqueness, Citus normally requires " + "that unique constraints and exclusion constraints contain " + "the distribution column. If the tuple does not include the " + "distribution column, Citus cannot ensure that the same value " + "is not present in another shard. However, in some cases the " + "index creator knows that uniqueness within the shard implies " + "global uniqueness (e.g. when indexing an expression derived " + "from the distribution column) and adding the distribution column " + "separately may not be desirable. This setting can then be used " + "to disable the check."), + &AllowUnsafeConstraints, + false, + PGC_USERSET, + GUC_NO_SHOW_ALL, + NULL, NULL, NULL); + DefineCustomBoolVariable( "citus.allow_unsafe_locks_from_workers", gettext_noop("Enables acquiring a distributed lock from a worker " diff --git a/src/include/distributed/commands.h b/src/include/distributed/commands.h index d5dedadaa..b3ddba31d 100644 --- a/src/include/distributed/commands.h +++ b/src/include/distributed/commands.h @@ -27,6 +27,12 @@ extern bool AddAllLocalTablesToMetadata; /* controlled via GUC, should be accessed via EnableLocalReferenceForeignKeys() */ extern bool EnableLocalReferenceForeignKeys; +/* + * GUC that controls whether to allow unique/exclude constraints without + * distribution column. + */ +extern bool AllowUnsafeConstraints; + extern bool EnableUnsafeTriggers; extern int MaxMatViewSizeToAutoRecreate; diff --git a/src/test/regress/expected/multi_alter_table_add_constraints.out b/src/test/regress/expected/multi_alter_table_add_constraints.out index e96326c18..2833facce 100644 --- a/src/test/regress/expected/multi_alter_table_add_constraints.out +++ b/src/test/regress/expected/multi_alter_table_add_constraints.out @@ -279,6 +279,19 @@ SELECT create_distributed_table('products', 'product_no'); ALTER TABLE products ADD CONSTRAINT exc_name EXCLUDE USING btree (name with =); ERROR: cannot create constraint on "products" DETAIL: Distributed relations cannot have UNIQUE, EXCLUDE, or PRIMARY KEY constraints that do not include the partition column (with an equality operator if EXCLUDE). +-- check that we can disable the constraint check for EXCLUDE +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +ALTER TABLE products ADD CONSTRAINT exc_name EXCLUDE USING btree (name with =); +-- not enforced across shards +INSERT INTO products VALUES (1,'boat',10.0); +INSERT INTO products VALUES (2,'boat',11.0); +-- enforced within the shard +INSERT INTO products VALUES (1,'boat',12.0); +ERROR: conflicting key value violates exclusion constraint "exc_name_1450103" +DETAIL: Key (name)=(boat) conflicts with existing key (name)=(boat). +CONTEXT: while executing command on localhost:xxxxx +ROLLBACK; -- We can add composite exclusion ALTER TABLE products ADD CONSTRAINT exc_pno_name EXCLUDE USING btree (product_no with =, name with =); -- 4th command will error out since it conflicts with exc_pno_name constraint @@ -453,6 +466,46 @@ INSERT INTO products VALUES(1,'product_1', 5); -- DDL should pick the right connections after a single INSERT ALTER TABLE products ADD CONSTRAINT unn_pno UNIQUE(product_no); ROLLBACK; +-- check that we can disable the constraint check for CREATE UNIQUE INDEX +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +CREATE UNIQUE INDEX ON products (name, price); +-- not enforced across shards +INSERT INTO products VALUES (1,'boat',10.0); +INSERT INTO products VALUES (2,'boat',11.0); +-- enforced within the shard +INSERT INTO products VALUES (1,'boat',10.0); +ERROR: duplicate key value violates unique constraint "products_name_price_idx_1450203" +DETAIL: Key (name, price)=(boat, 10.0) already exists. +CONTEXT: while executing command on localhost:xxxxx +ROLLBACK; +-- check that we can disable the constraint check for CREATE UNIQUE INDEX CONCURRENTLY +SET citus.allow_unsafe_constraints TO on; +CREATE UNIQUE INDEX CONCURRENTLY product_idx ON products (name, price); +-- not enforced across shards +INSERT INTO products VALUES (1,'boat',10.0); +INSERT INTO products VALUES (2,'boat',11.0); +-- enforced within the shard +INSERT INTO products VALUES (1,'boat',10.0); +ERROR: duplicate key value violates unique constraint "product_idx_1450203" +DETAIL: Key (name, price)=(boat, 10.0) already exists. +CONTEXT: while executing command on localhost:xxxxx +DROP INDEX product_idx; +TRUNCATE products; +RESET citus.allow_unsafe_constraints; +-- check that we can disable the constraint check for ADD CONSTRAINT .. PRIMARY KEY +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +ALTER TABLE products ADD CONSTRAINT products_pk PRIMARY KEY (name, price); +-- not enforced across shards +INSERT INTO products VALUES (1,'boat',10.0); +INSERT INTO products VALUES (2,'boat',11.0); +-- enforced within the shard +INSERT INTO products VALUES (1,'boat',10.0); +ERROR: duplicate key value violates unique constraint "products_pk_1450203" +DETAIL: Key (name, price)=(boat, 10.0) already exists. +CONTEXT: while executing command on localhost:xxxxx +ROLLBACK; BEGIN; -- Add constraints ALTER TABLE products ADD CONSTRAINT unn_pno UNIQUE(product_no); diff --git a/src/test/regress/expected/multi_create_table_constraints.out b/src/test/regress/expected/multi_create_table_constraints.out index f68983d6f..f4b9fa889 100644 --- a/src/test/regress/expected/multi_create_table_constraints.out +++ b/src/test/regress/expected/multi_create_table_constraints.out @@ -42,6 +42,24 @@ CREATE TABLE pk_on_non_part_col SELECT create_distributed_table('pk_on_non_part_col', 'partition_col', 'hash'); ERROR: cannot create constraint on "pk_on_non_part_col" DETAIL: Distributed relations cannot have UNIQUE, EXCLUDE, or PRIMARY KEY constraints that do not include the partition column (with an equality operator if EXCLUDE). +-- check that we can disable the constraint check +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +SELECT create_distributed_table('pk_on_non_part_col', 'partition_col', 'hash'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +-- not enforced across shards +INSERT INTO pk_on_non_part_col VALUES (1,1); +INSERT INTO pk_on_non_part_col VALUES (2,1); +-- enforced within shard +INSERT INTO pk_on_non_part_col VALUES (1,1); +ERROR: duplicate key value violates unique constraint "pk_on_non_part_col_pkey_365000" +DETAIL: Key (other_col)=(1) already exists. +CONTEXT: while executing command on localhost:xxxxx +END; CREATE TABLE uq_on_non_part_col ( partition_col integer, @@ -59,6 +77,24 @@ CREATE TABLE ex_on_non_part_col SELECT create_distributed_table('ex_on_non_part_col', 'partition_col', 'hash'); ERROR: cannot create constraint on "ex_on_non_part_col" DETAIL: Distributed relations cannot have UNIQUE, EXCLUDE, or PRIMARY KEY constraints that do not include the partition column (with an equality operator if EXCLUDE). +-- check that we can disable the constraint check +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +SELECT create_distributed_table('ex_on_non_part_col', 'partition_col', 'hash'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +-- not enforced across shards +INSERT INTO ex_on_non_part_col VALUES (1,1); +INSERT INTO ex_on_non_part_col VALUES (2,1); +-- enforced within shard +INSERT INTO ex_on_non_part_col VALUES (1,1); +ERROR: conflicting key value violates exclusion constraint "ex_on_non_part_col_other_col_excl_365004" +DETAIL: Key (other_col)=(1) conflicts with existing key (other_col)=(1). +CONTEXT: while executing command on localhost:xxxxx +END; -- now show that Citus can distribute unique and EXCLUDE constraints that -- include the partition column for hash-partitioned tables. -- However, EXCLUDE constraints must include the partition column with @@ -100,9 +136,37 @@ SELECT create_distributed_table('uq_two_columns', 'partition_col', 'hash'); INSERT INTO uq_two_columns (partition_col, other_col) VALUES (1,1); INSERT INTO uq_two_columns (partition_col, other_col) VALUES (1,1); -ERROR: duplicate key value violates unique constraint "uq_two_columns_partition_col_other_col_key_365008" +ERROR: duplicate key value violates unique constraint "uq_two_columns_partition_col_other_col_key_365016" DETAIL: Key (partition_col, other_col)=(1, 1) already exists. CONTEXT: while executing command on localhost:xxxxx +CREATE TABLE pk_on_two_non_part_cols +( + partition_col integer, + other_col integer, + other_col_2 text, + PRIMARY KEY (other_col, other_col_2) +); +SELECT create_distributed_table('pk_on_two_non_part_cols', 'partition_col', 'hash'); +ERROR: cannot create constraint on "pk_on_two_non_part_cols" +DETAIL: Distributed relations cannot have UNIQUE, EXCLUDE, or PRIMARY KEY constraints that do not include the partition column (with an equality operator if EXCLUDE). +-- check that we can disable the constraint check +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +SELECT create_distributed_table('pk_on_two_non_part_cols', 'partition_col', 'hash'); + create_distributed_table +--------------------------------------------------------------------- + +(1 row) + +-- not enforced across shards +INSERT INTO pk_on_two_non_part_cols VALUES (1,1,1); +INSERT INTO pk_on_two_non_part_cols VALUES (2,1,1); +-- enforced within shard +INSERT INTO pk_on_two_non_part_cols VALUES (1,1,1); +ERROR: duplicate key value violates unique constraint "pk_on_two_non_part_cols_pkey_365020" +DETAIL: Key (other_col, other_col_2)=(1, 1) already exists. +CONTEXT: while executing command on localhost:xxxxx +END; CREATE TABLE ex_on_part_col ( partition_col integer, @@ -117,7 +181,7 @@ SELECT create_distributed_table('ex_on_part_col', 'partition_col', 'hash'); INSERT INTO ex_on_part_col (partition_col, other_col) VALUES (1,1); INSERT INTO ex_on_part_col (partition_col, other_col) VALUES (1,2); -ERROR: conflicting key value violates exclusion constraint "ex_on_part_col_partition_col_excl_365012" +ERROR: conflicting key value violates exclusion constraint "ex_on_part_col_partition_col_excl_365024" DETAIL: Key (partition_col)=(1) conflicts with existing key (partition_col)=(1). CONTEXT: while executing command on localhost:xxxxx CREATE TABLE ex_on_two_columns @@ -134,7 +198,7 @@ SELECT create_distributed_table('ex_on_two_columns', 'partition_col', 'hash'); INSERT INTO ex_on_two_columns (partition_col, other_col) VALUES (1,1); INSERT INTO ex_on_two_columns (partition_col, other_col) VALUES (1,1); -ERROR: conflicting key value violates exclusion constraint "ex_on_two_columns_partition_col_other_col_excl_365016" +ERROR: conflicting key value violates exclusion constraint "ex_on_two_columns_partition_col_other_col_excl_365028" DETAIL: Key (partition_col, other_col)=(1, 1) conflicts with existing key (partition_col, other_col)=(1, 1). CONTEXT: while executing command on localhost:xxxxx CREATE TABLE ex_on_two_columns_prt @@ -153,7 +217,7 @@ INSERT INTO ex_on_two_columns_prt (partition_col, other_col) VALUES (1,1); INSERT INTO ex_on_two_columns_prt (partition_col, other_col) VALUES (1,1); INSERT INTO ex_on_two_columns_prt (partition_col, other_col) VALUES (1,101); INSERT INTO ex_on_two_columns_prt (partition_col, other_col) VALUES (1,101); -ERROR: conflicting key value violates exclusion constraint "ex_on_two_columns_prt_partition_col_other_col_excl_365020" +ERROR: conflicting key value violates exclusion constraint "ex_on_two_columns_prt_partition_col_other_col_excl_365032" DETAIL: Key (partition_col, other_col)=(1, 101) conflicts with existing key (partition_col, other_col)=(1, 101). CONTEXT: while executing command on localhost:xxxxx CREATE TABLE ex_wrong_operator @@ -179,7 +243,7 @@ SELECT create_distributed_table('ex_overlaps', 'partition_col', 'hash'); INSERT INTO ex_overlaps (partition_col, other_col) VALUES ('[2016-01-01 00:00:00, 2016-02-01 00:00:00]', '[2016-01-01 00:00:00, 2016-02-01 00:00:00]'); INSERT INTO ex_overlaps (partition_col, other_col) VALUES ('[2016-01-01 00:00:00, 2016-02-01 00:00:00]', '[2016-01-15 00:00:00, 2016-02-01 00:00:00]'); -ERROR: conflicting key value violates exclusion constraint "ex_overlaps_other_col_partition_col_excl_365027" +ERROR: conflicting key value violates exclusion constraint "ex_overlaps_other_col_partition_col_excl_365039" DETAIL: Key (other_col, partition_col)=(["2016-01-15 00:00:00","2016-02-01 00:00:00"], ["2016-01-01 00:00:00","2016-02-01 00:00:00"]) conflicts with existing key (other_col, partition_col)=(["2016-01-01 00:00:00","2016-02-01 00:00:00"], ["2016-01-01 00:00:00","2016-02-01 00:00:00"]). CONTEXT: while executing command on localhost:xxxxx -- now show that Citus can distribute unique and EXCLUDE constraints that @@ -223,7 +287,7 @@ SELECT create_distributed_table('uq_two_columns_named', 'partition_col', 'hash') INSERT INTO uq_two_columns_named (partition_col, other_col) VALUES (1,1); INSERT INTO uq_two_columns_named (partition_col, other_col) VALUES (1,1); -ERROR: duplicate key value violates unique constraint "uq_two_columns_named_uniq_365036" +ERROR: duplicate key value violates unique constraint "uq_two_columns_named_uniq_365048" DETAIL: Key (partition_col, other_col)=(1, 1) already exists. CONTEXT: while executing command on localhost:xxxxx CREATE TABLE ex_on_part_col_named @@ -240,7 +304,7 @@ SELECT create_distributed_table('ex_on_part_col_named', 'partition_col', 'hash') INSERT INTO ex_on_part_col_named (partition_col, other_col) VALUES (1,1); INSERT INTO ex_on_part_col_named (partition_col, other_col) VALUES (1,2); -ERROR: conflicting key value violates exclusion constraint "ex_on_part_col_named_exclude_365040" +ERROR: conflicting key value violates exclusion constraint "ex_on_part_col_named_exclude_365052" DETAIL: Key (partition_col)=(1) conflicts with existing key (partition_col)=(1). CONTEXT: while executing command on localhost:xxxxx CREATE TABLE ex_on_two_columns_named @@ -257,7 +321,7 @@ SELECT create_distributed_table('ex_on_two_columns_named', 'partition_col', 'has INSERT INTO ex_on_two_columns_named (partition_col, other_col) VALUES (1,1); INSERT INTO ex_on_two_columns_named (partition_col, other_col) VALUES (1,1); -ERROR: conflicting key value violates exclusion constraint "ex_on_two_columns_named_exclude_365044" +ERROR: conflicting key value violates exclusion constraint "ex_on_two_columns_named_exclude_365056" DETAIL: Key (partition_col, other_col)=(1, 1) conflicts with existing key (partition_col, other_col)=(1, 1). CONTEXT: while executing command on localhost:xxxxx CREATE TABLE ex_multiple_excludes @@ -276,11 +340,11 @@ SELECT create_distributed_table('ex_multiple_excludes', 'partition_col', 'hash') INSERT INTO ex_multiple_excludes (partition_col, other_col, other_other_col) VALUES (1,1,1); INSERT INTO ex_multiple_excludes (partition_col, other_col, other_other_col) VALUES (1,1,2); -ERROR: conflicting key value violates exclusion constraint "ex_multiple_excludes_excl1_365048" +ERROR: conflicting key value violates exclusion constraint "ex_multiple_excludes_excl1_365060" DETAIL: Key (partition_col, other_col)=(1, 1) conflicts with existing key (partition_col, other_col)=(1, 1). CONTEXT: while executing command on localhost:xxxxx INSERT INTO ex_multiple_excludes (partition_col, other_col, other_other_col) VALUES (1,2,1); -ERROR: conflicting key value violates exclusion constraint "ex_multiple_excludes_excl2_365048" +ERROR: conflicting key value violates exclusion constraint "ex_multiple_excludes_excl2_365060" DETAIL: Key (partition_col, other_other_col)=(1, 1) conflicts with existing key (partition_col, other_other_col)=(1, 1). CONTEXT: while executing command on localhost:xxxxx CREATE TABLE ex_wrong_operator_named @@ -306,7 +370,7 @@ SELECT create_distributed_table('ex_overlaps_named', 'partition_col', 'hash'); INSERT INTO ex_overlaps_named (partition_col, other_col) VALUES ('[2016-01-01 00:00:00, 2016-02-01 00:00:00]', '[2016-01-01 00:00:00, 2016-02-01 00:00:00]'); INSERT INTO ex_overlaps_named (partition_col, other_col) VALUES ('[2016-01-01 00:00:00, 2016-02-01 00:00:00]', '[2016-01-15 00:00:00, 2016-02-01 00:00:00]'); -ERROR: conflicting key value violates exclusion constraint "ex_overlaps_operator_named_exclude_365055" +ERROR: conflicting key value violates exclusion constraint "ex_overlaps_operator_named_exclude_365067" DETAIL: Key (other_col, partition_col)=(["2016-01-15 00:00:00","2016-02-01 00:00:00"], ["2016-01-01 00:00:00","2016-02-01 00:00:00"]) conflicts with existing key (other_col, partition_col)=(["2016-01-01 00:00:00","2016-02-01 00:00:00"], ["2016-01-01 00:00:00","2016-02-01 00:00:00"]). CONTEXT: while executing command on localhost:xxxxx -- now show that Citus allows unique constraints on range-partitioned tables. @@ -336,13 +400,13 @@ SELECT create_distributed_table('check_example', 'partition_col', 'hash'); \c - - :public_worker_1_host :worker_1_port SELECT "Column", "Type", "Definition" FROM index_attrs WHERE - relid = 'check_example_partition_col_key_365056'::regclass; + relid = 'check_example_partition_col_key_365068'::regclass; Column | Type | Definition --------------------------------------------------------------------- partition_col | integer | partition_col (1 row) -SELECT "Constraint", "Definition" FROM table_checks WHERE relid='public.check_example_365056'::regclass; +SELECT "Constraint", "Definition" FROM table_checks WHERE relid='public.check_example_365068'::regclass; Constraint | Definition --------------------------------------------------------------------- check_example_other_col_check | CHECK (other_col >= 100) diff --git a/src/test/regress/expected/multi_fix_partition_shard_index_names.out b/src/test/regress/expected/multi_fix_partition_shard_index_names.out index 6e0afeb7b..99f603541 100644 --- a/src/test/regress/expected/multi_fix_partition_shard_index_names.out +++ b/src/test/regress/expected/multi_fix_partition_shard_index_names.out @@ -521,9 +521,9 @@ SELECT tablename, indexname FROM pg_indexes WHERE schemaname = 'fix_idx_names' O tablename | indexname --------------------------------------------------------------------- date_partitioned_citus_local_table | date_partitioned_citus_local_table_measureid_idx - date_partitioned_citus_local_table_361377 | date_partitioned_citus_local_table_measureid_idx_361377 + date_partitioned_citus_local_table_361369 | date_partitioned_citus_local_table_measureid_idx_361369 partition_local_table | partition_local_table_measureid_idx - partition_local_table_361378 | partition_local_table_measureid_idx_361378 + partition_local_table_361370 | partition_local_table_measureid_idx_361370 (4 rows) -- creating a single object should only need to trigger fixing the single object @@ -699,9 +699,9 @@ NOTICE: issuing SET citus.enable_ddl_propagation TO 'off' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing SET citus.enable_ddl_propagation TO 'off' DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx -NOTICE: issuing SELECT citus_internal_add_partition_metadata ('fix_idx_names.p2'::regclass, 'h', 'dist_col', 1370000, 's') +NOTICE: issuing SELECT citus_internal_add_partition_metadata ('fix_idx_names.p2'::regclass, 'h', 'dist_col', 1370001, 's') DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx -NOTICE: issuing SELECT citus_internal_add_partition_metadata ('fix_idx_names.p2'::regclass, 'h', 'dist_col', 1370000, 's') +NOTICE: issuing SELECT citus_internal_add_partition_metadata ('fix_idx_names.p2'::regclass, 'h', 'dist_col', 1370001, 's') DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx NOTICE: issuing WITH shard_data(relationname, shardid, storagetype, shardminvalue, shardmaxvalue) AS (VALUES ('fix_idx_names.p2'::regclass, 915002, 't'::"char", '-2147483648', '2147483647')) SELECT citus_internal_add_shard_metadata(relationname, shardid, storagetype, shardminvalue, shardmaxvalue) FROM shard_data; DETAIL: on server postgres@localhost:xxxxx connectionId: xxxxxxx @@ -753,7 +753,7 @@ DETAIL: drop cascades to table not_partitioned drop cascades to table not_distributed drop cascades to table fk_table drop cascades to table p -drop cascades to table date_partitioned_citus_local_table_361377 +drop cascades to table date_partitioned_citus_local_table_361369 drop cascades to table date_partitioned_citus_local_table drop cascades to table parent_table SELECT citus_remove_node('localhost', :master_port); diff --git a/src/test/regress/multi_1_schedule b/src/test/regress/multi_1_schedule index 433254dec..bef14d45a 100644 --- a/src/test/regress/multi_1_schedule +++ b/src/test/regress/multi_1_schedule @@ -62,7 +62,7 @@ test: multi_remove_node_reference_table # ---------- test: multi_create_table test: multi_create_table_superuser -test: multi_create_table_constraints multi_master_protocol multi_load_data multi_load_data_superuser multi_behavioral_analytics_create_table +test: multi_master_protocol multi_load_data multi_load_data_superuser multi_behavioral_analytics_create_table 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 diff --git a/src/test/regress/sql/multi_alter_table_add_constraints.sql b/src/test/regress/sql/multi_alter_table_add_constraints.sql index 612e4d22b..2ff12ef66 100644 --- a/src/test/regress/sql/multi_alter_table_add_constraints.sql +++ b/src/test/regress/sql/multi_alter_table_add_constraints.sql @@ -239,6 +239,17 @@ SELECT create_distributed_table('products', 'product_no'); -- Command below should error out since 'name' is not a distribution column ALTER TABLE products ADD CONSTRAINT exc_name EXCLUDE USING btree (name with =); +-- check that we can disable the constraint check for EXCLUDE +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +ALTER TABLE products ADD CONSTRAINT exc_name EXCLUDE USING btree (name with =); +-- not enforced across shards +INSERT INTO products VALUES (1,'boat',10.0); +INSERT INTO products VALUES (2,'boat',11.0); +-- enforced within the shard +INSERT INTO products VALUES (1,'boat',12.0); +ROLLBACK; + -- We can add composite exclusion ALTER TABLE products ADD CONSTRAINT exc_pno_name EXCLUDE USING btree (product_no with =, name with =); @@ -399,6 +410,40 @@ INSERT INTO products VALUES(1,'product_1', 5); ALTER TABLE products ADD CONSTRAINT unn_pno UNIQUE(product_no); ROLLBACK; +-- check that we can disable the constraint check for CREATE UNIQUE INDEX +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +CREATE UNIQUE INDEX ON products (name, price); +-- not enforced across shards +INSERT INTO products VALUES (1,'boat',10.0); +INSERT INTO products VALUES (2,'boat',11.0); +-- enforced within the shard +INSERT INTO products VALUES (1,'boat',10.0); +ROLLBACK; + +-- check that we can disable the constraint check for CREATE UNIQUE INDEX CONCURRENTLY +SET citus.allow_unsafe_constraints TO on; +CREATE UNIQUE INDEX CONCURRENTLY product_idx ON products (name, price); +-- not enforced across shards +INSERT INTO products VALUES (1,'boat',10.0); +INSERT INTO products VALUES (2,'boat',11.0); +-- enforced within the shard +INSERT INTO products VALUES (1,'boat',10.0); +DROP INDEX product_idx; +TRUNCATE products; +RESET citus.allow_unsafe_constraints; + +-- check that we can disable the constraint check for ADD CONSTRAINT .. PRIMARY KEY +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +ALTER TABLE products ADD CONSTRAINT products_pk PRIMARY KEY (name, price); +-- not enforced across shards +INSERT INTO products VALUES (1,'boat',10.0); +INSERT INTO products VALUES (2,'boat',11.0); +-- enforced within the shard +INSERT INTO products VALUES (1,'boat',10.0); +ROLLBACK; + BEGIN; -- Add constraints ALTER TABLE products ADD CONSTRAINT unn_pno UNIQUE(product_no); diff --git a/src/test/regress/sql/multi_create_table_constraints.sql b/src/test/regress/sql/multi_create_table_constraints.sql index 281f8aaea..c0f8c7c50 100644 --- a/src/test/regress/sql/multi_create_table_constraints.sql +++ b/src/test/regress/sql/multi_create_table_constraints.sql @@ -31,6 +31,17 @@ CREATE TABLE pk_on_non_part_col ); SELECT create_distributed_table('pk_on_non_part_col', 'partition_col', 'hash'); +-- check that we can disable the constraint check +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +SELECT create_distributed_table('pk_on_non_part_col', 'partition_col', 'hash'); +-- not enforced across shards +INSERT INTO pk_on_non_part_col VALUES (1,1); +INSERT INTO pk_on_non_part_col VALUES (2,1); +-- enforced within shard +INSERT INTO pk_on_non_part_col VALUES (1,1); +END; + CREATE TABLE uq_on_non_part_col ( partition_col integer, @@ -46,6 +57,17 @@ CREATE TABLE ex_on_non_part_col ); SELECT create_distributed_table('ex_on_non_part_col', 'partition_col', 'hash'); +-- check that we can disable the constraint check +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +SELECT create_distributed_table('ex_on_non_part_col', 'partition_col', 'hash'); +-- not enforced across shards +INSERT INTO ex_on_non_part_col VALUES (1,1); +INSERT INTO ex_on_non_part_col VALUES (2,1); +-- enforced within shard +INSERT INTO ex_on_non_part_col VALUES (1,1); +END; + -- now show that Citus can distribute unique and EXCLUDE constraints that -- include the partition column for hash-partitioned tables. -- However, EXCLUDE constraints must include the partition column with @@ -76,6 +98,26 @@ SELECT create_distributed_table('uq_two_columns', 'partition_col', 'hash'); INSERT INTO uq_two_columns (partition_col, other_col) VALUES (1,1); INSERT INTO uq_two_columns (partition_col, other_col) VALUES (1,1); +CREATE TABLE pk_on_two_non_part_cols +( + partition_col integer, + other_col integer, + other_col_2 text, + PRIMARY KEY (other_col, other_col_2) +); +SELECT create_distributed_table('pk_on_two_non_part_cols', 'partition_col', 'hash'); + +-- check that we can disable the constraint check +BEGIN; +SET LOCAL citus.allow_unsafe_constraints TO on; +SELECT create_distributed_table('pk_on_two_non_part_cols', 'partition_col', 'hash'); +-- not enforced across shards +INSERT INTO pk_on_two_non_part_cols VALUES (1,1,1); +INSERT INTO pk_on_two_non_part_cols VALUES (2,1,1); +-- enforced within shard +INSERT INTO pk_on_two_non_part_cols VALUES (1,1,1); +END; + CREATE TABLE ex_on_part_col ( partition_col integer, @@ -226,8 +268,8 @@ CREATE TABLE check_example SELECT create_distributed_table('check_example', 'partition_col', 'hash'); \c - - :public_worker_1_host :worker_1_port SELECT "Column", "Type", "Definition" FROM index_attrs WHERE - relid = 'check_example_partition_col_key_365056'::regclass; -SELECT "Constraint", "Definition" FROM table_checks WHERE relid='public.check_example_365056'::regclass; + relid = 'check_example_partition_col_key_365068'::regclass; +SELECT "Constraint", "Definition" FROM table_checks WHERE relid='public.check_example_365068'::regclass; \c - - :master_host :master_port -- Index-based constraints are created with shard-extended names, but others