Skip to content

Commit e4e2afa

Browse files
committed
[yugabyte#25052] XCluster: DDL Replication for supported pg extensions
Summary: This diff adds ddl replication support for the most common pg extensions supported by YB along with tests. Complete list of extensions obtained from tested: - file_fdw - fuzzystrmatch - pgcrypto - postgres_fdw - sslinfo - uuid-ossp - hypopg - pg_stat_monitor - pgaudit - hll - hstore - pg_trgm - pgtap - tablefunc - vector A few additional notes: # Some of the extensions do create types and this change has started allowing CREATE/ALTER/DROP TYPE. No work has been done to preserve the OIDs of the types on source/target. This will come in later once we add support for User-defined types to be used in tables. Most extensions that create types are using the type within functions and not persisting data with it. # Extensions that create tables under the covers have not been enabled e.g. pg_cron, pg_partman. These fail as they execute CREATE TABLE as part of extension creation which is a not a simple pass through DDL. This is intentional for now with a workaround of installing these extensions on non-replicated databases. Jira: DB-14183 Test Plan: ybt xcluster_ddl_replication_pgregress-test XClusterPgRegressDDLReplicationTest.PgRegressCreateDropPgOnlyDdls ybt xcluster_ddl_replication_pgregress-test XClusterPgRegressDDLReplicationTest.PgRegressAlterPgOnlyDdls ybt xcluster_ddl_replication_pgregress-test XClusterPgRegressDDLReplicationTest.PgRegressCreateDropTablePartitions2 ybt xcluster_ddl_replication_pgregress-test XClusterPgRegressDDLReplicationTest.PgRegressCreateDropExtensions Reviewers: jhe, xCluster, hsunder Reviewed By: jhe Subscribers: yql Differential Revision: https://phorge.dev.yugabyte.com/D40452
1 parent c240554 commit e4e2afa

File tree

8 files changed

+318
-35
lines changed

8 files changed

+318
-35
lines changed

python/yugabyte/yb_dist_tests.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ def set_global_conf_from_dict(global_conf_dict: Dict[str, str]) -> GlobalTestCon
194194
'thirdparty_url.txt',
195195
'upgrade_test_builds',
196196
'gflag_allowlist.txt',
197+
'test_xcluster_ddl_replication_sql',
197198
f'{POSTGRES_BUILD_SUBDIR}/contrib',
198199
f'{POSTGRES_BUILD_SUBDIR}/src/test/modules',
199200
f'{POSTGRES_BUILD_SUBDIR}/src/test/regress',

src/postgres/yb-extensions/yb_xcluster_ddl_replication/source_ddl_end_handler.c

Lines changed: 70 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@
1414

1515
#include "source_ddl_end_handler.h"
1616

17+
#include "catalog/pg_am_d.h"
18+
#include "catalog/pg_amop_d.h"
19+
#include "catalog/pg_amproc_d.h"
1720
#include "catalog/pg_attrdef_d.h"
1821
#include "catalog/pg_cast_d.h"
1922
#include "catalog/pg_collation_d.h"
@@ -22,6 +25,7 @@
2225
#include "catalog/pg_extension_d.h"
2326
#include "catalog/pg_foreign_data_wrapper_d.h"
2427
#include "catalog/pg_foreign_server_d.h"
28+
#include "catalog/pg_foreign_table_d.h"
2529
#include "catalog/pg_namespace_d.h"
2630
#include "catalog/pg_operator_d.h"
2731
#include "catalog/pg_opclass_d.h"
@@ -31,6 +35,11 @@
3135
#include "catalog/pg_rewrite_d.h"
3236
#include "catalog/pg_statistic_ext.h"
3337
#include "catalog/pg_trigger_d.h"
38+
#include "catalog/pg_ts_config_d.h"
39+
#include "catalog/pg_ts_config_map_d.h"
40+
#include "catalog/pg_ts_dict_d.h"
41+
#include "catalog/pg_ts_parser_d.h"
42+
#include "catalog/pg_ts_template_d.h"
3443
#include "catalog/pg_type_d.h"
3544
#include "catalog/pg_user_mapping_d.h"
3645
#include "executor/spi.h"
@@ -55,8 +64,8 @@
5564

5665
#define ALLOWED_DDL_LIST \
5766
X(CMDTAG_COMMENT) \
58-
X(CMDTAG_CREATE_AGGREGATE) \
5967
X(CMDTAG_CREATE_ACCESS_METHOD) \
68+
X(CMDTAG_CREATE_AGGREGATE) \
6069
X(CMDTAG_CREATE_CAST) \
6170
X(CMDTAG_CREATE_COLLATION) \
6271
X(CMDTAG_CREATE_DOMAIN) \
@@ -79,13 +88,14 @@
7988
X(CMDTAG_CREATE_TEXT_SEARCH_PARSER) \
8089
X(CMDTAG_CREATE_TEXT_SEARCH_TEMPLATE) \
8190
X(CMDTAG_CREATE_TRIGGER) \
91+
X(CMDTAG_CREATE_TYPE) \
8292
X(CMDTAG_CREATE_USER_MAPPING) \
8393
X(CMDTAG_CREATE_VIEW) \
84-
X(CMDTAG_IMPORT_FOREIGN_SCHEMA) \
8594
X(CMDTAG_ALTER_AGGREGATE) \
8695
X(CMDTAG_ALTER_CAST) \
8796
X(CMDTAG_ALTER_COLLATION) \
8897
X(CMDTAG_ALTER_DOMAIN) \
98+
X(CMDTAG_ALTER_EXTENSION) \
8999
X(CMDTAG_ALTER_FUNCTION) \
90100
X(CMDTAG_ALTER_OPERATOR) \
91101
X(CMDTAG_ALTER_OPERATOR_CLASS) \
@@ -101,7 +111,38 @@
101111
X(CMDTAG_ALTER_TEXT_SEARCH_PARSER) \
102112
X(CMDTAG_ALTER_TEXT_SEARCH_TEMPLATE) \
103113
X(CMDTAG_ALTER_TRIGGER) \
114+
X(CMDTAG_ALTER_TYPE) \
104115
X(CMDTAG_ALTER_VIEW) \
116+
X(CMDTAG_DROP_ACCESS_METHOD) \
117+
X(CMDTAG_DROP_AGGREGATE) \
118+
X(CMDTAG_DROP_CAST) \
119+
X(CMDTAG_DROP_COLLATION) \
120+
X(CMDTAG_DROP_DOMAIN) \
121+
X(CMDTAG_DROP_EXTENSION) \
122+
X(CMDTAG_DROP_FOREIGN_DATA_WRAPPER) \
123+
X(CMDTAG_DROP_FOREIGN_TABLE) \
124+
X(CMDTAG_DROP_FUNCTION) \
125+
X(CMDTAG_DROP_OPERATOR) \
126+
X(CMDTAG_DROP_OPERATOR_CLASS) \
127+
X(CMDTAG_DROP_OPERATOR_FAMILY) \
128+
X(CMDTAG_DROP_POLICY) \
129+
X(CMDTAG_DROP_PROCEDURE) \
130+
X(CMDTAG_DROP_ROUTINE) \
131+
X(CMDTAG_DROP_RULE) \
132+
X(CMDTAG_DROP_SCHEMA) \
133+
X(CMDTAG_DROP_SERVER) \
134+
X(CMDTAG_DROP_STATISTICS) \
135+
X(CMDTAG_DROP_TEXT_SEARCH_CONFIGURATION) \
136+
X(CMDTAG_DROP_TEXT_SEARCH_DICTIONARY) \
137+
X(CMDTAG_DROP_TEXT_SEARCH_PARSER) \
138+
X(CMDTAG_DROP_TEXT_SEARCH_TEMPLATE) \
139+
X(CMDTAG_DROP_TRIGGER) \
140+
X(CMDTAG_DROP_TYPE) \
141+
X(CMDTAG_DROP_USER_MAPPING) \
142+
X(CMDTAG_DROP_VIEW) \
143+
X(CMDTAG_GRANT) \
144+
X(CMDTAG_IMPORT_FOREIGN_SCHEMA) \
145+
X(CMDTAG_REVOKE) \
105146
X(CMDTAG_SECURITY_LABEL)
106147

107148
typedef struct NewRelMapEntry
@@ -147,19 +188,27 @@ IsPrimaryIndex(Relation rel)
147188
}
148189

149190
bool
150-
IsPassThroughDdlSupported(const char *command_tag_name)
191+
IsPassThroughDdlCommandSupported(CommandTag command_tag)
151192
{
152-
if (command_tag_name == NULL || *command_tag_name == '\0')
153-
return false;
154-
155-
CommandTag command_tag = GetCommandTagEnum(command_tag_name);
156193
switch (command_tag)
157194
{
158195
#define X(CMD_TAG_VALUE) case CMD_TAG_VALUE: return true;
159196
ALLOWED_DDL_LIST
160197
#undef X
161198
default: return false;
162199
}
200+
201+
return false;
202+
}
203+
204+
bool
205+
IsPassThroughDdlSupported(const char *command_tag_name)
206+
{
207+
if (command_tag_name == NULL || *command_tag_name == '\0')
208+
return false;
209+
210+
CommandTag command_tag = GetCommandTagEnum(command_tag_name);
211+
return IsPassThroughDdlCommandSupported(command_tag);
163212
}
164213

165214
bool
@@ -239,7 +288,7 @@ ProcessSourceEventTriggerDDLCommands(JsonbParseState *state)
239288
initStringInfo(&query_buf);
240289
appendStringInfo(&query_buf, "SELECT objid, command_tag FROM "
241290
"pg_catalog.pg_event_trigger_ddl_commands()");
242-
int exec_res = SPI_execute(query_buf.data, /*readonly*/ true, /*tcount*/ 0);
291+
int exec_res = SPI_execute(query_buf.data, /* readonly */ true, /* tcount */ 0);
243292
if (exec_res != SPI_OK_SELECT)
244293
elog(ERROR, "SPI_exec failed (error %d): %s", exec_res, query_buf.data);
245294

@@ -312,7 +361,7 @@ ProcessSourceEventTriggerDroppedObjects()
312361
appendStringInfo(&query_buf, "SELECT classid, is_temporary, "
313362
"object_type, schema_name, object_name FROM "
314363
"pg_catalog.pg_event_trigger_dropped_objects()");
315-
int exec_res = SPI_execute(query_buf.data, /*readonly*/ true, /*tcount*/ 0);
364+
int exec_res = SPI_execute(query_buf.data, /* readonly */ true, /* tcount */ 0);
316365
if (exec_res != SPI_OK_SELECT)
317366
elog(ERROR, "SPI_exec failed (error %d): %s", exec_res, query_buf.data);
318367

@@ -353,20 +402,32 @@ ProcessSourceEventTriggerDroppedObjects()
353402
"supported by yb_xcluster_ddl_replication\n%s",
354403
kManualReplicationErrorMsg)));
355404
switch_fallthrough();
405+
case AccessMethodRelationId:
406+
case AccessMethodOperatorRelationId:
407+
case AccessMethodProcedureRelationId:
356408
case AttrDefaultRelationId:
357409
case CastRelationId:
358410
case CollationRelationId:
359411
case ConstraintRelationId:
360412
case ConversionRelationId:
361413
case ExtensionRelationId:
362414
case ForeignDataWrapperRelationId:
415+
case ForeignServerRelationId:
416+
case ForeignTableRelationId:
417+
case NamespaceRelationId:
363418
case OperatorClassRelationId:
364419
case OperatorFamilyRelationId:
365420
case OperatorRelationId:
366421
case PolicyRelationId:
367422
case ProcedureRelationId:
423+
case RewriteRelationId:
368424
case StatisticExtRelationId:
369425
case TriggerRelationId:
426+
case TSConfigRelationId:
427+
case TSConfigMapRelationId:
428+
case TSDictionaryRelationId:
429+
case TSParserRelationId:
430+
case TSTemplateRelationId:
370431
case TypeRelationId:
371432
case UserMappingRelationId:
372433
should_replicate_ddl = true;

src/postgres/yb-extensions/yb_xcluster_ddl_replication/source_ddl_end_handler.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,12 @@
1616
#define YB_XCLUSTER_DDL_REPLICATION_SOURCE_DDL_END
1717

1818
#include "postgres.h"
19+
#include "tcop/cmdtag.h"
1920
#include "utils/jsonb.h"
2021

22+
bool
23+
IsPassThroughDdlCommandSupported(CommandTag command_tag);
24+
2125
/*
2226
* Iterate over pg_catalog.pg_event_trigger_ddl_commands() and process each base
2327
* command (a single query may be composed of multiple base commands).

0 commit comments

Comments
 (0)