From 30d0a65f40c2c017d602ed4b819bed3ee2ac50bc Mon Sep 17 00:00:00 2001 From: Onder Kalaci Date: Thu, 14 Jan 2021 19:41:21 +0300 Subject: [PATCH] Adds citus.enable_local_reference_table_foreign_keys When enabled any foreign keys between local tables and reference tables supported by converting the local table to a citus local table. When the coordinator is not in the metadata, the logic is disabled as foreign keys are not allowed in this configuration. --- src/backend/distributed/commands/table.c | 37 ++++++++++++++++++- src/backend/distributed/shared_library_init.c | 12 ++++++ src/include/distributed/commands.h | 5 +++ .../expected/fkeys_between_local_ref.out | 22 +++++++++++ .../regress/sql/fkeys_between_local_ref.sql | 20 ++++++++++ 5 files changed, 94 insertions(+), 2 deletions(-) diff --git a/src/backend/distributed/commands/table.c b/src/backend/distributed/commands/table.c index 09b205851..4187ddff0 100644 --- a/src/backend/distributed/commands/table.c +++ b/src/backend/distributed/commands/table.c @@ -42,8 +42,13 @@ #include "utils/syscache.h" +/* controlled via GUC, should be accessed via GetEnableLocalReferenceForeignKeys() */ +bool EnableLocalReferenceForeignKeys = true; + + /* Local functions forward declarations for unsupported command checks */ static void PostprocessCreateTableStmtForeignKeys(CreateStmt *createStatement); +static bool ShouldEnableLocalReferenceForeignKeys(void); static void PostprocessCreateTableStmtPartitionOf(CreateStmt *createStatement, const char *queryString); static bool AlterTableDefinesFKeyBetweenPostgresAndNonDistTable( @@ -84,6 +89,7 @@ static void SetInterShardDDLTaskRelationShardList(Task *task, ShardInterval *leftShardInterval, ShardInterval *rightShardInterval); + /* * We need to run some of the commands sequentially if there is a foreign constraint * from/to reference table. @@ -194,6 +200,14 @@ PostprocessCreateTableStmt(CreateStmt *createStatement, const char *queryString) static void PostprocessCreateTableStmtForeignKeys(CreateStmt *createStatement) { + if (!ShouldEnableLocalReferenceForeignKeys()) + { + /* + * Either the user disabled foreign keys from/to local/reference tables + * or the coordinator is not in the metadata */ + return; + } + /* * Relation must exist and it is already locked as standard process utility * is already executed. @@ -227,6 +241,25 @@ PostprocessCreateTableStmtForeignKeys(CreateStmt *createStatement) } +/* + * ShouldEnableLocalReferenceForeignKeys is a wrapper around getting the GUC + * EnableLocalReferenceForeignKeys. If the coordinator is not added + * to the metadata, the function returns false. Else, the function returns + * the value set by the user + * + */ +static bool +ShouldEnableLocalReferenceForeignKeys(void) +{ + if (!EnableLocalReferenceForeignKeys) + { + return false; + } + + return CoordinatorAddedAsWorkerNode(); +} + + /* * PostprocessCreateTableStmtPartitionOf processes CREATE TABLE ... PARTITION OF * statements and it checks if user creates the table as a partition of a distributed @@ -412,8 +445,8 @@ PreprocessAlterTableStmt(Node *node, const char *alterTableCommand, leftRelationId = IndexGetRelation(leftRelationId, missingOk); } - if (processUtilityContext != PROCESS_UTILITY_SUBCOMMAND && - CoordinatorAddedAsWorkerNode() && + if (ShouldEnableLocalReferenceForeignKeys() && + processUtilityContext != PROCESS_UTILITY_SUBCOMMAND && AlterTableDefinesFKeyBetweenPostgresAndNonDistTable(alterTableStatement)) { /* diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index 6182e4e8a..af2996bc0 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -585,6 +585,18 @@ RegisterCitusConfigVariables(void) GUC_STANDARD, NULL, NULL, NULL); + DefineCustomBoolVariable( + "citus.enable_local_reference_table_foreign_keys", + gettext_noop("Enables foreign keys from/to local tables"), + gettext_noop("When enabled, foreign keys between local tables and reference " + "tables supported."), + &EnableLocalReferenceForeignKeys, + true, + PGC_USERSET, + GUC_STANDARD, + NULL, NULL, NULL); + + DefineCustomBoolVariable( "citus.enable_single_hash_repartition_joins", gettext_noop("Enables single hash repartitioning between hash " diff --git a/src/include/distributed/commands.h b/src/include/distributed/commands.h index 66b26b0aa..04f4eef97 100644 --- a/src/include/distributed/commands.h +++ b/src/include/distributed/commands.h @@ -20,6 +20,11 @@ #include "tcop/dest.h" #include "tcop/utility.h" + +/* controlled via GUC, should be accessed via EnableLocalReferenceForeignKeys() */ +extern bool EnableLocalReferenceForeignKeys; + + /* * DistributeObjectOps specifies handlers for node/object type pairs. * Instances of this type should all be declared in deparse.c. diff --git a/src/test/regress/expected/fkeys_between_local_ref.out b/src/test/regress/expected/fkeys_between_local_ref.out index 775f9677b..df6f8323f 100644 --- a/src/test/regress/expected/fkeys_between_local_ref.out +++ b/src/test/regress/expected/fkeys_between_local_ref.out @@ -391,6 +391,28 @@ BEGIN; reference_table_1 | n | t (8 rows) +ROLLBACK; +BEGIN; + -- disable foreign keys to reference tables + SET LOCAL citus.enable_local_reference_table_foreign_keys TO false; + CREATE TABLE local_table_6 (col_1 INT PRIMARY KEY); + ALTER TABLE local_table_2 ADD CONSTRAINT fkey_11 FOREIGN KEY (col_1) REFERENCES reference_table_1(col_1) ON DELETE CASCADE; + CREATE TABLE local_table_5 ( + col_1 INT UNIQUE REFERENCES local_table_6(col_1), + col_2 INT REFERENCES local_table_3(col_1), + FOREIGN KEY (col_1) REFERENCES local_table_5(col_1), + FOREIGN KEY (col_1) REFERENCES reference_table_1(col_1)); + -- Now show none of local_table_5 & 6 to should be converted to citus local tables + -- as it is disabled + SELECT logicalrelid::text AS tablename, partmethod, repmodel FROM pg_dist_partition + WHERE logicalrelid::text IN (SELECT tablename FROM pg_tables WHERE schemaname='fkeys_between_local_ref') + ORDER BY tablename; + tablename | partmethod | repmodel +--------------------------------------------------------------------- + distributed_table | h | c + reference_table_1 | n | t +(2 rows) + ROLLBACK; -- this errors out as we don't support creating citus local -- tables from partitioned tables diff --git a/src/test/regress/sql/fkeys_between_local_ref.sql b/src/test/regress/sql/fkeys_between_local_ref.sql index e767a072f..ac1a8eba1 100644 --- a/src/test/regress/sql/fkeys_between_local_ref.sql +++ b/src/test/regress/sql/fkeys_between_local_ref.sql @@ -285,6 +285,26 @@ BEGIN; ORDER BY tablename; ROLLBACK; +BEGIN; + -- disable foreign keys to reference tables + SET LOCAL citus.enable_local_reference_table_foreign_keys TO false; + CREATE TABLE local_table_6 (col_1 INT PRIMARY KEY); + + ALTER TABLE local_table_2 ADD CONSTRAINT fkey_11 FOREIGN KEY (col_1) REFERENCES reference_table_1(col_1) ON DELETE CASCADE; + + CREATE TABLE local_table_5 ( + col_1 INT UNIQUE REFERENCES local_table_6(col_1), + col_2 INT REFERENCES local_table_3(col_1), + FOREIGN KEY (col_1) REFERENCES local_table_5(col_1), + FOREIGN KEY (col_1) REFERENCES reference_table_1(col_1)); + + -- Now show none of local_table_5 & 6 to should be converted to citus local tables + -- as it is disabled + SELECT logicalrelid::text AS tablename, partmethod, repmodel FROM pg_dist_partition + WHERE logicalrelid::text IN (SELECT tablename FROM pg_tables WHERE schemaname='fkeys_between_local_ref') + ORDER BY tablename; +ROLLBACK; + -- this errors out as we don't support creating citus local -- tables from partitioned tables CREATE TABLE part_local_table (col_1 INT REFERENCES reference_table_1(col_1)) PARTITION BY RANGE (col_1);