Skip to content

Commit 9133dce

Browse files
committed
[yugabyte#24077] xCluster: add new (currently disabled) test for replicating enum DDLs
Summary: Here I add a test, XClusterPgRegressDDLReplicationTest.PgRegressCreateDropExtensions, to ensure we can automatically replicate enum DDLs. This test tries all the various forms of DDLs that create/alter/drop enums and makes sure they can be replicated automatically. Success here is no errors and we end up with the same schemas (determined by YSQL dump ignoring OIDs) on both sides as well as the same enum label OID's. Currently I have implemented "pass-through" where these DDLs are automatically executed on the target universe but I have not put in the code needed to keep the label OIDs the same. I have thus disabled the test for now. Note that the testing for the same enum label OIDs on both sides is done for all of these regression tests in case we end up adding a enum statement to one of those. The BEGIN/ROLLBACK statements are commented out currently because there is a bug where we do not properly handle ordering DDLs inside of transactions; this should be fixed by yugabyte#23957, as per the inserted TODO. Jira: DB-12970 Test Plan: I temporary added a enum statement to one of the other tests and the test successfully failed because the enum labels were different. If I undisable the new test and comment out the OID perturbation, all the DDLs are successfully passed across and work. If I leave in the perturbation, the test fails with backfill index crashing due to the OIDs being inconsistent between the pg_enum table and the actual table's row contents. This is expected -- we don't expect things to work unless the OIDs are the same. Reviewers: jhe, xCluster, hsunder Reviewed By: jhe Subscribers: ybase Differential Revision: https://phorge.dev.yugabyte.com/D41267
1 parent 4a67d9d commit 9133dce

File tree

4 files changed

+210
-1
lines changed

4 files changed

+210
-1
lines changed
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
--
2+
-- Creating enums
3+
--
4+
5+
-- Taken from postgres/src/test/regress/sql/enum.sql
6+
7+
CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple');
8+
9+
10+
--
11+
-- adding new values
12+
--
13+
14+
CREATE TYPE planets AS ENUM ( 'venus', 'earth', 'mars' );
15+
16+
ALTER TYPE planets ADD VALUE 'uranus';
17+
18+
ALTER TYPE planets ADD VALUE 'mercury' BEFORE 'venus';
19+
ALTER TYPE planets ADD VALUE 'saturn' BEFORE 'uranus';
20+
ALTER TYPE planets ADD VALUE 'jupiter' AFTER 'mars';
21+
ALTER TYPE planets ADD VALUE 'neptune' AFTER 'uranus';
22+
23+
ALTER TYPE planets ADD VALUE IF NOT EXISTS 'pluto';
24+
25+
26+
--
27+
-- Test inserting so many values that we have to renumber
28+
-- Renumbering is not supported by YugabyteDB so skipping this test.
29+
--
30+
-- create type insenum as enum ('L1', 'L2');
31+
--
32+
-- alter type insenum add value 'i1' before 'L2';
33+
-- alter type insenum add value 'i2' before 'L2';
34+
-- alter type insenum add value 'i3' before 'L2';
35+
-- alter type insenum add value 'i4' before 'L2';
36+
-- alter type insenum add value 'i5' before 'L2';
37+
-- alter type insenum add value 'i6' before 'L2';
38+
-- alter type insenum add value 'i7' before 'L2';
39+
-- alter type insenum add value 'i8' before 'L2';
40+
-- alter type insenum add value 'i9' before 'L2';
41+
-- alter type insenum add value 'i10' before 'L2';
42+
-- alter type insenum add value 'i11' before 'L2';
43+
-- alter type insenum add value 'i12' before 'L2';
44+
-- alter type insenum add value 'i13' before 'L2';
45+
-- alter type insenum add value 'i14' before 'L2';
46+
-- alter type insenum add value 'i15' before 'L2';
47+
-- alter type insenum add value 'i16' before 'L2';
48+
-- alter type insenum add value 'i17' before 'L2';
49+
-- alter type insenum add value 'i18' before 'L2';
50+
-- alter type insenum add value 'i19' before 'L2';
51+
-- alter type insenum add value 'i20' before 'L2';
52+
-- alter type insenum add value 'i21' before 'L2';
53+
-- alter type insenum add value 'i22' before 'L2';
54+
-- alter type insenum add value 'i23' before 'L2';
55+
-- alter type insenum add value 'i24' before 'L2';
56+
-- alter type insenum add value 'i25' before 'L2';
57+
-- alter type insenum add value 'i26' before 'L2';
58+
-- alter type insenum add value 'i27' before 'L2';
59+
-- alter type insenum add value 'i28' before 'L2';
60+
-- alter type insenum add value 'i29' before 'L2';
61+
-- alter type insenum add value 'i30' before 'L2';
62+
63+
--
64+
-- Basic table creation
65+
--
66+
CREATE TABLE enumtest (col rainbow);
67+
INSERT INTO enumtest values ('red'), ('orange'), ('yellow'), ('green');
68+
COPY enumtest FROM stdin;
69+
blue
70+
purple
71+
\.
72+
73+
--
74+
-- Index tests, force use of index
75+
--
76+
SET enable_seqscan = off;
77+
SET enable_bitmapscan = off;
78+
79+
--
80+
-- Btree index / opclass with the various operators
81+
--
82+
CREATE UNIQUE INDEX enumtest_btree ON enumtest USING btree (col);
83+
84+
--
85+
-- Hash index / opclass with the = operator
86+
--
87+
CREATE INDEX enumtest_hash ON enumtest USING hash (col);
88+
89+
--
90+
-- End index tests
91+
--
92+
RESET enable_seqscan;
93+
RESET enable_bitmapscan;
94+
95+
--
96+
-- Domains over enums
97+
--
98+
CREATE DOMAIN rgb AS rainbow CHECK (VALUE IN ('red', 'green', 'blue'));
99+
100+
--
101+
-- User functions, can't test perl/python etc here since may not be compiled.
102+
--
103+
CREATE FUNCTION echo_me(anyenum) RETURNS text AS $$
104+
BEGIN
105+
RETURN $1::text || 'omg';
106+
END
107+
$$ LANGUAGE plpgsql;
108+
--
109+
-- Concrete function should override generic one
110+
--
111+
CREATE FUNCTION echo_me(rainbow) RETURNS text AS $$
112+
BEGIN
113+
RETURN $1::text || 'wtf';
114+
END
115+
$$ LANGUAGE plpgsql;
116+
117+
--
118+
-- RI triggers on enum types
119+
--
120+
CREATE TABLE enumtest_parent (id rainbow PRIMARY KEY);
121+
CREATE TABLE enumtest_child (parent rainbow REFERENCES enumtest_parent);
122+
INSERT INTO enumtest_parent VALUES ('red');
123+
INSERT INTO enumtest_child VALUES ('red');
124+
125+
-- check renaming a value
126+
ALTER TYPE rainbow RENAME VALUE 'red' TO 'crimson';
127+
128+
--
129+
-- check transactional behaviour of ALTER TYPE ... ADD VALUE
130+
--
131+
-- NOTE: at least as of 1/2025, in YugabyteDB, ROLLBACK only rolls
132+
-- back DMLs; DDLs are not rolled back.
133+
--
134+
-- TODO(Julien): once #23957 is done, uncomment the BEGIN & ROLLBACK statements below.
135+
CREATE TYPE bogus AS ENUM('good');
136+
137+
BEGIN;
138+
ALTER TYPE bogus ADD VALUE 'new';
139+
SAVEPOINT x;
140+
SELECT enum_first(null::bogus); -- safe
141+
ROLLBACK TO x;
142+
COMMIT;
143+
144+
-- BEGIN;
145+
ALTER TYPE bogus RENAME TO bogon;
146+
ALTER TYPE bogon ADD VALUE 'bad';
147+
-- ROLLBACK;
148+
149+
-- BEGIN;
150+
CREATE TYPE bogus2 AS ENUM('good','bad','ugly');
151+
ALTER TYPE bogus2 RENAME TO bogon2;
152+
-- ROLLBACK;
153+
154+
-- BEGIN;
155+
CREATE TYPE bogus3 AS ENUM('good');
156+
ALTER TYPE bogus3 RENAME TO bogon3;
157+
ALTER TYPE bogon3 ADD VALUE 'bad';
158+
ALTER TYPE bogon3 ADD VALUE 'ugly';
159+
-- ROLLBACK;
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
--
2+
-- Drops enums from yb/integration-tests/xcluster/sql/create_enum.sql
3+
--
4+
5+
--
6+
-- If we drop the original generic one, we don't have to qualify the type
7+
-- anymore, since there's only one match
8+
--
9+
DROP FUNCTION echo_me(anyenum);
10+
DROP FUNCTION echo_me(rainbow);
11+
12+
DROP TABLE enumtest_child;
13+
DROP TABLE enumtest_parent;
14+
15+
DROP TYPE bogon;
16+
DROP TYPE bogon2;
17+
DROP TYPE bogon3;
18+
19+
-- this also drops DOMAIN rgb and TABLE enumtest.
20+
DROP TYPE rainbow CASCADE;

src/yb/integration-tests/xcluster/xcluster_ddl_replication_pgregress-test.cc

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,15 @@ class XClusterPgRegressDDLReplicationTest : public XClusterDDLReplicationTestBas
5858
return std::regex_replace(output, pattern, "\n<binary_upgrade_set_next>");
5959
}
6060

61+
Result<std::string> ReadEnumLabelInfo(
62+
Cluster& cluster, const std::string& database_name = "yugabyte") {
63+
auto conn = VERIFY_RESULT(cluster.ConnectToDB(database_name));
64+
return VERIFY_RESULT(conn.FetchAllAsString(
65+
"SELECT typname, enumlabel, pg_enum.oid, enumsortorder FROM pg_enum "
66+
"JOIN pg_type ON pg_enum.enumtypid = pg_type.oid;",
67+
", ", "\n"));
68+
}
69+
6170
void ExecutePgFile(const std::string& file_path) {
6271
std::vector<std::string> args;
6372
args.push_back(GetPgToolPath("ysqlsh"));
@@ -81,8 +90,16 @@ class XClusterPgRegressDDLReplicationTest : public XClusterDDLReplicationTestBas
8190
const auto sub_dir = "test_xcluster_ddl_replication_sql";
8291
const auto test_sql_dir = JoinPathSegments(env_util::GetRootDir(sub_dir), sub_dir, "sql");
8392

84-
// Setup xCluster.
8593
RETURN_NOT_OK(SetUpClusters());
94+
95+
// Perturb OIDs on consumer side to make sure we don't accidentally preserve OIDs.
96+
auto conn = VERIFY_RESULT(consumer_cluster_.ConnectToDB("yugabyte"));
97+
RETURN_NOT_OK(
98+
conn.Execute("CREATE TYPE gratuitous_enum AS ENUM ('red', 'orange', 'yellow', 'green', "
99+
"'blue', 'purple');"));
100+
RETURN_NOT_OK(conn.Execute("DROP TYPE gratuitous_enum;"));
101+
102+
// Setup xCluster.
86103
RETURN_NOT_OK(CheckpointReplicationGroup());
87104
RETURN_NOT_OK(CreateReplicationFromCheckpoint());
88105

@@ -104,6 +121,12 @@ class XClusterPgRegressDDLReplicationTest : public XClusterDDLReplicationTestBas
104121
auto producer_dump = VERIFY_RESULT(RunYSQLDump(producer_cluster_));
105122
auto consumer_dump = VERIFY_RESULT(RunYSQLDump(consumer_cluster_));
106123
SCHECK_EQ(producer_dump, consumer_dump, IllegalState, "Ysqldumps do not match");
124+
125+
auto producer_enum_label_info = VERIFY_RESULT(ReadEnumLabelInfo(producer_cluster_));
126+
auto consumer_enum_label_info = VERIFY_RESULT(ReadEnumLabelInfo(consumer_cluster_));
127+
SCHECK_EQ(
128+
producer_enum_label_info, consumer_enum_label_info, IllegalState,
129+
"enum label information does not match");
107130
}
108131

109132
return Status::OK();
@@ -175,4 +198,8 @@ TEST_F(XClusterPgRegressDDLReplicationTest, PgRegressCreateDropExtensions) {
175198
ASSERT_OK(TestPgRegress("pgonly_extensions_create.sql", "pgonly_extensions_drop.sql"));
176199
}
177200

201+
TEST_F(XClusterPgRegressDDLReplicationTest, YB_DISABLE_TEST(PgRegressCreateDropEnum)) {
202+
ASSERT_OK(TestPgRegress("create_enum.sql", "drop_enum.sql"));
203+
}
204+
178205
} // namespace yb

src/yb/tserver/xcluster_ddl_queue_handler.cc

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,7 @@ const std::unordered_set<std::string> kSupportedCommandTags {
8888
"ALTER TABLE",
8989
"ALTER INDEX",
9090
// Pass thru DDLs
91+
"ALTER TYPE", // Pass-through for now
9192
"CREATE ACCESS METHOD",
9293
"CREATE AGGREGATE",
9394
"CREATE CAST",
@@ -112,6 +113,7 @@ const std::unordered_set<std::string> kSupportedCommandTags {
112113
"CREATE TEXT SEARCH PARSER",
113114
"CREATE TEXT SEARCH TEMPLATE",
114115
"CREATE TRIGGER",
116+
"CREATE TYPE", // Pass-through for now
115117
"CREATE USER MAPPING",
116118
"CREATE VIEW",
117119
"COMMENT",
@@ -159,6 +161,7 @@ const std::unordered_set<std::string> kSupportedCommandTags {
159161
"DROP TEXT SEARCH PARSER",
160162
"DROP TEXT SEARCH TEMPLATE",
161163
"DROP TRIGGER",
164+
"DROP TYPE", // Pass-through for now
162165
"DROP USER MAPPING",
163166
"DROP VIEW",
164167
"IMPORT FOREIGN SCHEMA",

0 commit comments

Comments
 (0)