diff --git a/src/backend/distributed/executor/multi_utility.c b/src/backend/distributed/executor/multi_utility.c index 4a4993e4b..ab0e1c2c2 100644 --- a/src/backend/distributed/executor/multi_utility.c +++ b/src/backend/distributed/executor/multi_utility.c @@ -40,6 +40,8 @@ #include "utils/syscache.h" +bool EnableDDLPropagation = true; /* ddl propagation is enabled */ + /* * This struct defines the state for the callback for drop statements. * It is copied as it is from commands/tablecmds.c in Postgres source. @@ -145,39 +147,43 @@ multi_ProcessUtility(Node *parsetree, } } - if (IsA(parsetree, IndexStmt)) + /* ddl commands are propagated to workers only if EnableDDLPropagation is set */ + if (EnableDDLPropagation) { - parsetree = ProcessIndexStmt((IndexStmt *) parsetree, queryString); - } - - if (IsA(parsetree, DropStmt)) - { - DropStmt *dropStatement = (DropStmt *) parsetree; - if (dropStatement->removeType == OBJECT_INDEX) + if (IsA(parsetree, IndexStmt)) { - parsetree = ProcessDropIndexStmt(dropStatement, queryString); + parsetree = ProcessIndexStmt((IndexStmt *) parsetree, queryString); } - } - if (IsA(parsetree, AlterTableStmt)) - { - AlterTableStmt *alterTableStmt = (AlterTableStmt *) parsetree; - if (alterTableStmt->relkind == OBJECT_TABLE) + if (IsA(parsetree, DropStmt)) { - parsetree = ProcessAlterTableStmt(alterTableStmt, queryString); + DropStmt *dropStatement = (DropStmt *) parsetree; + if (dropStatement->removeType == OBJECT_INDEX) + { + parsetree = ProcessDropIndexStmt(dropStatement, queryString); + } } - } - /* - * ALTER TABLE ... RENAME statements have their node type as RenameStmt and - * not AlterTableStmt. So, we intercept RenameStmt to tackle these commands. - */ - if (IsA(parsetree, RenameStmt)) - { - RenameStmt *renameStmt = (RenameStmt *) parsetree; - if (IsAlterTableRenameStmt(renameStmt)) + if (IsA(parsetree, AlterTableStmt)) { - ErrorIfDistributedRenameStmt(renameStmt); + AlterTableStmt *alterTableStmt = (AlterTableStmt *) parsetree; + if (alterTableStmt->relkind == OBJECT_TABLE) + { + parsetree = ProcessAlterTableStmt(alterTableStmt, queryString); + } + } + + /* + * ALTER TABLE ... RENAME statements have their node type as RenameStmt and + * not AlterTableStmt. So, we intercept RenameStmt to tackle these commands. + */ + if (IsA(parsetree, RenameStmt)) + { + RenameStmt *renameStmt = (RenameStmt *) parsetree; + if (IsAlterTableRenameStmt(renameStmt)) + { + ErrorIfDistributedRenameStmt(renameStmt); + } } } diff --git a/src/backend/distributed/shared_library_init.c b/src/backend/distributed/shared_library_init.c index 31b8a39e7..388508432 100644 --- a/src/backend/distributed/shared_library_init.c +++ b/src/backend/distributed/shared_library_init.c @@ -308,6 +308,16 @@ RegisterCitusConfigVariables(void) 0, NULL, NULL, NULL); + DefineCustomBoolVariable( + "citus.enable_ddl_propagation", + gettext_noop("Enables propagating DDL statements to worker shards"), + NULL, + &EnableDDLPropagation, + true, + PGC_USERSET, + 0, + NULL, NULL, NULL); + DefineCustomIntVariable( "citus.shard_replication_factor", gettext_noop("Sets the replication factor for shards."), diff --git a/src/include/distributed/multi_utility.h b/src/include/distributed/multi_utility.h index 63b5a2e52..2b3a7cdf1 100644 --- a/src/include/distributed/multi_utility.h +++ b/src/include/distributed/multi_utility.h @@ -12,6 +12,7 @@ #include "tcop/utility.h" +extern bool EnableDDLPropagation; extern void multi_ProcessUtility(Node *parsetree, const char *queryString, ProcessUtilityContext context, ParamListInfo params, diff --git a/src/test/regress/input/multi_alter_table_statements.source b/src/test/regress/input/multi_alter_table_statements.source index 2b46cbc39..f7be6dc69 100644 --- a/src/test/regress/input/multi_alter_table_statements.source +++ b/src/test/regress/input/multi_alter_table_statements.source @@ -162,7 +162,56 @@ FROM ORDER BY attnum; \c - - - :master_port +-- verify that we don't intercept DDL commands if propagation is turned off +SET citus.enable_ddl_propagation to false; + +-- table rename statement can be performed now +ALTER TABLE lineitem_alter RENAME TO lineitem_renamed; +-- verify rename is performed +SELECT relname FROM pg_class WHERE relname = 'lineitem_alter' or relname = 'lineitem_renamed'; + +-- revert it to original name +ALTER TABLE lineitem_renamed RENAME TO lineitem_alter; + +-- this column is added to master table and not workers +ALTER TABLE lineitem_alter ADD COLUMN column_only_added_to_master int; + +-- verify newly added column is not present in a worker shard +\c - - - :worker_1_port +SELECT column_only_added_to_master FROM lineitem_alter_103000 LIMIT 0; +\c - - - :master_port + +-- ddl propagation flag is reset to default, disable it again +SET citus.enable_ddl_propagation to false; + +-- following query succeeds since it accesses an previously existing column +SELECT l_orderkey FROM lineitem_alter LIMIT 0; + +-- make master and workers have the same schema again +ALTER TABLE lineitem_alter DROP COLUMN column_only_added_to_master; +-- now this should succeed +SELECT * FROM lineitem_alter LIMIT 0; + +-- previously unsupported statements are accepted by postgresql now +ALTER TABLE lineitem_alter ALTER COLUMN l_orderkey SET STATISTICS 100; +ALTER TABLE lineitem_alter DROP CONSTRAINT IF EXISTS non_existent_contraint; +ALTER TABLE lineitem_alter SET WITHOUT OIDS; + +-- even distribution column can be dropped however postgresql prevents this. +ALTER TABLE lineitem_alter DROP COLUMN l_orderkey; + +-- Even unique indexes on l_partkey (non-partition column) are allowed. +-- Citus would have prevented that. +CREATE UNIQUE INDEX unique_lineitem_partkey on lineitem_alter(l_partkey); +SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter'; + +-- verify index is not created on worker +\c - - - :worker_1_port +SELECT indexname, tablename FROM pg_indexes WHERE tablename like 'lineitem_alter_%'; +\c - - - :master_port + -- Cleanup the table and its shards +SET citus.enable_ddl_propagation to true; SELECT master_apply_delete_command('DELETE FROM lineitem_alter'); DROP TABLE lineitem_alter; -- check that nothing's left over on workers diff --git a/src/test/regress/output/multi_alter_table_statements.source b/src/test/regress/output/multi_alter_table_statements.source index 78f0b380c..378248546 100644 --- a/src/test/regress/output/multi_alter_table_statements.source +++ b/src/test/regress/output/multi_alter_table_statements.source @@ -451,8 +451,74 @@ ORDER BY attnum; ........pg.dropped.23........ | - (29 rows) +\c - - - :master_port +-- verify that we don't intercept DDL commands if propagation is turned off +SET citus.enable_ddl_propagation to false; +-- table rename statement can be performed now +ALTER TABLE lineitem_alter RENAME TO lineitem_renamed; +-- verify rename is performed +SELECT relname FROM pg_class WHERE relname = 'lineitem_alter' or relname = 'lineitem_renamed'; + relname +------------------ + lineitem_renamed +(1 row) + +-- revert it to original name +ALTER TABLE lineitem_renamed RENAME TO lineitem_alter; +-- this column is added to master table and not workers +ALTER TABLE lineitem_alter ADD COLUMN column_only_added_to_master int; +-- verify newly added column is not present in a worker shard +\c - - - :worker_1_port +SELECT column_only_added_to_master FROM lineitem_alter_103000 LIMIT 0; +ERROR: column "column_only_added_to_master" does not exist +LINE 1: SELECT column_only_added_to_master FROM lineitem_alter_10300... + ^ +\c - - - :master_port +-- ddl propagation flag is reset to default, disable it again +SET citus.enable_ddl_propagation to false; +-- following query succeeds since it accesses an previously existing column +SELECT l_orderkey FROM lineitem_alter LIMIT 0; + l_orderkey +------------ +(0 rows) + +-- make master and workers have the same schema again +ALTER TABLE lineitem_alter DROP COLUMN column_only_added_to_master; +-- now this should succeed +SELECT * FROM lineitem_alter LIMIT 0; + l_orderkey | l_partkey | l_suppkey | l_linenumber | l_quantity | l_extendedprice | l_discount | l_tax | l_returnflag | l_linestatus | l_shipdate | l_commitdate | l_receiptdate | l_shipinstruct | l_shipmode | l_comment | null_column +------------+-----------+-----------+--------------+------------+-----------------+------------+-------+--------------+--------------+------------+--------------+---------------+----------------+------------+-----------+------------- +(0 rows) + +-- previously unsupported statements are accepted by postgresql now +ALTER TABLE lineitem_alter ALTER COLUMN l_orderkey SET STATISTICS 100; +ALTER TABLE lineitem_alter DROP CONSTRAINT IF EXISTS non_existent_contraint; +NOTICE: constraint "non_existent_contraint" of relation "lineitem_alter" does not exist, skipping +ALTER TABLE lineitem_alter SET WITHOUT OIDS; +-- even distribution column can be dropped however postgresql prevents this. +ALTER TABLE lineitem_alter DROP COLUMN l_orderkey; +ERROR: cannot drop table lineitem_alter column l_orderkey because other objects depend on it +DETAIL: table lineitem_alter depends on table lineitem_alter column l_orderkey +HINT: Use DROP ... CASCADE to drop the dependent objects too. +-- Even unique indexes on l_partkey (non-partition column) are allowed. +-- Citus would have prevented that. +CREATE UNIQUE INDEX unique_lineitem_partkey on lineitem_alter(l_partkey); +SELECT indexname, tablename FROM pg_indexes WHERE tablename = 'lineitem_alter'; + indexname | tablename +-------------------------+---------------- + unique_lineitem_partkey | lineitem_alter +(1 row) + +-- verify index is not created on worker +\c - - - :worker_1_port +SELECT indexname, tablename FROM pg_indexes WHERE tablename like 'lineitem_alter_%'; + indexname | tablename +-----------+----------- +(0 rows) + \c - - - :master_port -- Cleanup the table and its shards +SET citus.enable_ddl_propagation to true; SELECT master_apply_delete_command('DELETE FROM lineitem_alter'); master_apply_delete_command -----------------------------