diff --git a/contrib/test_decoding/expected/toast.out b/contrib/test_decoding/expected/toast.out index 75c4d22d80..dacefaa010 100644 --- a/contrib/test_decoding/expected/toast.out +++ b/contrib/test_decoding/expected/toast.out @@ -360,6 +360,29 @@ WHERE data NOT LIKE '%INSERT: %'; COMMIT (4 rows) +/* + * Test decoding relation rewrite with toast. + * The insert into tbl2 within the same transaction + * is there to check there is no remaining toast_hash + * not being reset. + */ +CREATE TABLE tbl1 (a INT, b TEXT); +CREATE TABLE tbl2 (a INT); +ALTER TABLE tbl1 ALTER COLUMN b SET STORAGE EXTERNAL; +BEGIN; +INSERT INTO tbl1 VALUES(1, repeat('a', 4000)) ; +ALTER TABLE tbl1 ADD COLUMN id serial primary key; +INSERT INTO tbl2 VALUES(1); +commit; +SELECT substr(data, 1, 200) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + substr +---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + BEGIN + table public.tbl1: INSERT: a[integer]:1 b[text]:'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa + table public.tbl2: INSERT: a[integer]:1 + COMMIT +(4 rows) + SELECT pg_drop_replication_slot('regression_slot'); pg_drop_replication_slot -------------------------- diff --git a/contrib/test_decoding/sql/toast.sql b/contrib/test_decoding/sql/toast.sql index 016c3ab784..c6816e7bc3 100644 --- a/contrib/test_decoding/sql/toast.sql +++ b/contrib/test_decoding/sql/toast.sql @@ -308,4 +308,21 @@ DROP TABLE toasted_several; SELECT regexp_replace(data, '^(.{100}).*(.{100})$', '\1..\2') FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1') WHERE data NOT LIKE '%INSERT: %'; + +/* + * Test decoding relation rewrite with toast. + * The insert into tbl2 within the same transaction + * is there to check there is no remaining toast_hash + * not being reset. + */ +CREATE TABLE tbl1 (a INT, b TEXT); +CREATE TABLE tbl2 (a INT); +ALTER TABLE tbl1 ALTER COLUMN b SET STORAGE EXTERNAL; +BEGIN; +INSERT INTO tbl1 VALUES(1, repeat('a', 4000)) ; +ALTER TABLE tbl1 ADD COLUMN id serial primary key; +INSERT INTO tbl2 VALUES(1); +commit; +SELECT substr(data, 1, 200) FROM pg_logical_slot_get_changes('regression_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1'); + SELECT pg_drop_replication_slot('regression_slot'); diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c index 147b5abc19..0db90c2011 100644 --- a/src/backend/catalog/toasting.c +++ b/src/backend/catalog/toasting.c @@ -36,9 +36,11 @@ #include "utils/syscache.h" static void CheckAndCreateToastTable(Oid relOid, Datum reloptions, - LOCKMODE lockmode, bool check); + LOCKMODE lockmode, bool check, + Oid OIDOldToast); static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, - Datum reloptions, LOCKMODE lockmode, bool check); + Datum reloptions, LOCKMODE lockmode, bool check, + Oid OIDOldToast); static bool needs_toast_table(Relation rel); @@ -57,30 +59,34 @@ static bool needs_toast_table(Relation rel); void AlterTableCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode) { - CheckAndCreateToastTable(relOid, reloptions, lockmode, true); + CheckAndCreateToastTable(relOid, reloptions, lockmode, true, InvalidOid); } void -NewHeapCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode) +NewHeapCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode, + Oid OIDOldToast) { - CheckAndCreateToastTable(relOid, reloptions, lockmode, false); + CheckAndCreateToastTable(relOid, reloptions, lockmode, false, OIDOldToast); } void NewRelationCreateToastTable(Oid relOid, Datum reloptions) { - CheckAndCreateToastTable(relOid, reloptions, AccessExclusiveLock, false); + CheckAndCreateToastTable(relOid, reloptions, AccessExclusiveLock, false, + InvalidOid); } static void -CheckAndCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode, bool check) +CheckAndCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode, + bool check, Oid OIDOldToast) { Relation rel; rel = table_open(relOid, lockmode); /* create_toast_table does all the work */ - (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions, lockmode, check); + (void) create_toast_table(rel, InvalidOid, InvalidOid, reloptions, lockmode, + check, OIDOldToast); table_close(rel, NoLock); } @@ -104,7 +110,7 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid) /* create_toast_table does all the work */ if (!create_toast_table(rel, toastOid, toastIndexOid, (Datum) 0, - AccessExclusiveLock, false)) + AccessExclusiveLock, false, InvalidOid)) elog(ERROR, "\"%s\" does not require a toast table", relName); @@ -121,7 +127,8 @@ BootstrapToastTable(char *relName, Oid toastOid, Oid toastIndexOid) */ static bool create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, - Datum reloptions, LOCKMODE lockmode, bool check) + Datum reloptions, LOCKMODE lockmode, bool check, + Oid OIDOldToast) { Oid relOid = RelationGetRelid(rel); HeapTuple reltup; @@ -258,7 +265,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid, false, true, true, - InvalidOid, + OIDOldToast, NULL); Assert(toast_relid != InvalidOid); diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index b3d8b6deb0..a5817dc5d1 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -735,7 +735,7 @@ make_new_heap(Oid OIDOldHeap, Oid NewTableSpace, Oid NewAccessMethod, if (isNull) reloptions = (Datum) 0; - NewHeapCreateToastTable(OIDNewHeap, reloptions, lockmode); + NewHeapCreateToastTable(OIDNewHeap, reloptions, lockmode, toastid); ReleaseSysCache(tuple); } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index fcd778c62a..ebd2311902 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -3861,6 +3861,10 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bo */ namestrcpy(&(relform->relname), newrelname); + /* reset relrewrite for toast */ + if (relform->relkind == RELKIND_TOASTVALUE) + relform->relrewrite = InvalidOid; + CatalogTupleUpdate(relrelation, &reltup->t_self, reltup); InvokeObjectPostAlterHookArg(RelationRelationId, myrelid, 0, diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h index f3fa85f64e..7067c4c61b 100644 --- a/src/include/catalog/toasting.h +++ b/src/include/catalog/toasting.h @@ -21,7 +21,7 @@ */ extern void NewRelationCreateToastTable(Oid relOid, Datum reloptions); extern void NewHeapCreateToastTable(Oid relOid, Datum reloptions, - LOCKMODE lockmode); + LOCKMODE lockmode, Oid OIDOldToast); extern void AlterTableCreateToastTable(Oid relOid, Datum reloptions, LOCKMODE lockmode); extern void BootstrapToastTable(char *relName,