From ac6778fa3348db8522c3177839659a2c38484497 Mon Sep 17 00:00:00 2001 From: PonyboyYbr <94borelyang@gmail.com> Date: Wed, 11 May 2022 15:46:40 -0700 Subject: [PATCH 09/12] Support replication of DDL type T_RenameStmt: table rename is allowed in both database level and table level DDL replication. Rename of other objects are only allowed in database level DDL replication. Co-authored-by: Borui Yang --- src/backend/commands/alter.c | 5 ++-- src/backend/commands/tablecmds.c | 15 ++++++++++- src/backend/tcop/utility.c | 20 ++++++++++++--- src/include/commands/alter.h | 3 ++- src/include/commands/tablecmds.h | 2 +- src/test/subscription/t/030_rep_ddls.pl | 33 +++++++++++++++++++++++-- 6 files changed, 67 insertions(+), 11 deletions(-) diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c index 5456b8222b..1ca8f99e0c 100644 --- a/src/backend/commands/alter.c +++ b/src/backend/commands/alter.c @@ -328,7 +328,8 @@ AlterObjectRename_internal(Relation rel, Oid objectId, const char *new_name) * Return value is the address of the renamed object. */ ObjectAddress -ExecRenameStmt(RenameStmt *stmt) +ExecRenameStmt(ParseState *pstate, RenameStmt *stmt, + bool isCompleteQuery) { switch (stmt->renameType) { @@ -354,7 +355,7 @@ ExecRenameStmt(RenameStmt *stmt) case OBJECT_MATVIEW: case OBJECT_INDEX: case OBJECT_FOREIGN_TABLE: - return RenameRelation(stmt); + return RenameRelation(pstate, stmt, isCompleteQuery); case OBJECT_COLUMN: case OBJECT_ATTRIBUTE: diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 3c9b6409ca..65386f2641 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3820,11 +3820,12 @@ RenameConstraint(RenameStmt *stmt) * RENAME */ ObjectAddress -RenameRelation(RenameStmt *stmt) +RenameRelation(ParseState *pstate, RenameStmt *stmt, bool isCompleteQuery) { bool is_index_stmt = stmt->renameType == OBJECT_INDEX; Oid relid; ObjectAddress address; + bool ddlxlog = XLogLogicalInfoActive() && isCompleteQuery; /* * Grab an exclusive lock on the target table, index, sequence, view, @@ -3872,6 +3873,18 @@ RenameRelation(RenameStmt *stmt) is_index_stmt = obj_is_index; } + if (ddlxlog && + ddl_need_xlog(relid, false)) + { + bool transactional = true; + const char* prefix = ""; + LogLogicalDDLMessage(prefix, + GetUserId(), + pstate->p_sourcetext, + strlen(pstate->p_sourcetext), + transactional); + } + /* Do the work */ RenameRelationInternal(relid, stmt->newname, false, is_index_stmt); diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index e9e7567209..1abd77a60e 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -1002,7 +1002,7 @@ standard_ProcessUtility(PlannedStmt *pstmt, context, params, queryEnv, dest, qc); else - ExecRenameStmt(stmt); + ExecRenameStmt(pstate, stmt, context != PROCESS_UTILITY_SUBCOMMAND); } break; @@ -1195,8 +1195,20 @@ LogLogicalDDLCommand(Node *parsetree, const char *queryString) */ case T_AlterTableStmt: case T_IndexStmt: - case T_RenameStmt: /* TODO */ - case T_AlterOwnerStmt: /* TODO */ + case T_RenameStmt: + { + RenameStmt *stmt = (RenameStmt *) parsetree; + if(!stmt->relation && ddl_need_xlog(InvalidOid, true)){ + bool transactional = true; + const char* prefix = ""; + LogLogicalDDLMessage(prefix, + GetUserId(), + queryString, + strlen(queryString), + transactional); + } + } + case T_AlterOwnerStmt: /* TODO, it is data control case, save for later update */ break; /* DropStmt depends on the removeType */ @@ -2008,7 +2020,7 @@ ProcessUtilitySlow(ParseState *pstate, break; case T_RenameStmt: - address = ExecRenameStmt((RenameStmt *) parsetree); + address = ExecRenameStmt(pstate, (RenameStmt *) parsetree, isCompleteQuery); break; case T_AlterObjectDependsStmt: diff --git a/src/include/commands/alter.h b/src/include/commands/alter.h index 52f5e6f6d2..df9333eb93 100644 --- a/src/include/commands/alter.h +++ b/src/include/commands/alter.h @@ -17,9 +17,10 @@ #include "catalog/dependency.h" #include "catalog/objectaddress.h" #include "nodes/parsenodes.h" +#include "parser/parse_node.h" #include "utils/relcache.h" -extern ObjectAddress ExecRenameStmt(RenameStmt *stmt); +extern ObjectAddress ExecRenameStmt(ParseState *pstate, RenameStmt *stmt, bool isCompleteQuery); extern ObjectAddress ExecAlterObjectDependsStmt(AlterObjectDependsStmt *stmt, ObjectAddress *refAddress); diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index 24106de2e5..f96bb57d56 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -74,7 +74,7 @@ extern ObjectAddress renameatt(RenameStmt *stmt); extern ObjectAddress RenameConstraint(RenameStmt *stmt); -extern ObjectAddress RenameRelation(RenameStmt *stmt); +extern ObjectAddress RenameRelation(ParseState *pstate, RenameStmt *stmt, bool isCompleteQuery); extern void RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, diff --git a/src/test/subscription/t/030_rep_ddls.pl b/src/test/subscription/t/030_rep_ddls.pl index b4df1bfefd..51126b489b 100644 --- a/src/test/subscription/t/030_rep_ddls.pl +++ b/src/test/subscription/t/030_rep_ddls.pl @@ -30,7 +30,6 @@ $node_subscriber->safe_psql('postgres', $ddl); $node_subscriber2->safe_psql('postgres', $ddl); my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres'; - # mypub has pubddl_database on $node_publisher->safe_psql('postgres', "CREATE PUBLICATION mypub FOR ALL TABLES;"); @@ -269,7 +268,7 @@ $result = $node_subscriber->safe_psql('postgres', "SELECT count(*) from s1.t6;") is($result, qq(1), 'SELECT INTO s1.t6 is replicated with data'); # TEST Create DomainStmt -$node_publisher->safe_psql('postgres', "CREATE DOMAIN s1.space_check AS VARCHAR NOT NULL CHECK (value !~ '\s');"); +$node_publisher->safe_psql('postgres', "CREATE DOMAIN s1.space_check AS VARCHAR NOT NULL CHECK (value !~ '\\s');"); $node_publisher->wait_for_catchup('mysub'); @@ -348,6 +347,36 @@ $node_publisher->wait_for_catchup('mysub'); $result = $node_subscriber->safe_psql('postgres', "SELECT count(*) FROM pg_catalog.pg_cast c, pg_catalog.pg_proc p WHERE p.proname='add' AND c.castfunc=p.oid;"); is($result, qq(1), 'CreateCast Stmt is replicated'); +#TEST RenameStmt for FUNCTION +$node_publisher->safe_psql('postgres', "ALTER FUNCTION add RENAME TO plus;"); + +$node_publisher->wait_for_catchup('mysub'); + +$result = $node_subscriber->safe_psql('postgres', "SELECT count(*) from pg_catalog.pg_proc p where p.proname='plus';"); +is($result, qq(1), 'RENAME FUNCTION Stmt is replicated'); + +#TEST RenameStmt for table +$node_publisher->safe_psql('postgres', "CREATE DATABASE db1;"); +$node_publisher->safe_psql('db1', "CREATE TABLE t7 (id int primary key, name varchar);"); +$node_publisher->safe_psql('db1', "CREATE TABLE t8 (id int primary key, name varchar);"); +$node_publisher->safe_psql('db1', + "CREATE PUBLICATION mypub3 FOR TABLE t7 with (ddl = 'table');"); +my $publisher_connstr_db1 = $node_publisher->connstr . ' dbname=db1'; +$node_subscriber->safe_psql('postgres', "CREATE DATABASE db1;"); +$node_subscriber->safe_psql('db1', "CREATE TABLE t7 (id int primary key, name varchar);"); +$node_subscriber->safe_psql('db1', "CREATE TABLE t8 (id int primary key, name varchar);"); +$node_subscriber->safe_psql('db1', + "CREATE SUBSCRIPTION mysub3 CONNECTION '$publisher_connstr_db1' PUBLICATION mypub3;" +); +$node_publisher->wait_for_catchup('mysub3'); +$node_publisher->safe_psql('db1', "ALTER TABLE t7 RENAME TO newt7;"); +$node_publisher->safe_psql('db1', "ALTER TABLE t8 RENAME TO newt8;"); +$node_publisher->wait_for_catchup('mysub3'); +$result = $node_subscriber->safe_psql('db1', "SELECT count(*) from pg_tables where tablename = 'newt7';"); +is($result, qq(1), 'Rename t7 to newt7 is replicated'); +$result = $node_subscriber->safe_psql('db1', "SELECT count(*) from pg_tables where tablename = 'newt8';"); +is($result, qq(0), 'Rename t8 to newt8 is not replicated'); + #TEST DDL in function $node_publisher->safe_psql('postgres', qq{ CREATE OR REPLACE FUNCTION func_ddl (tname varchar(20)) -- 2.32.0