aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/test_decoding/expected/toast.out22
-rw-r--r--contrib/test_decoding/sql/toast.sql16
-rw-r--r--src/backend/catalog/toasting.c29
-rw-r--r--src/backend/commands/cluster.c10
-rw-r--r--src/backend/commands/tablecmds.c31
-rw-r--r--src/include/catalog/toasting.h2
-rw-r--r--src/include/commands/tablecmds.h2
7 files changed, 99 insertions, 13 deletions
diff --git a/contrib/test_decoding/expected/toast.out b/contrib/test_decoding/expected/toast.out
index 75c4d22d801..cd03e9d50a1 100644
--- a/contrib/test_decoding/expected/toast.out
+++ b/contrib/test_decoding/expected/toast.out
@@ -360,6 +360,28 @@ 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 that 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 016c3ab7842..d1c560a174d 100644
--- a/contrib/test_decoding/sql/toast.sql
+++ b/contrib/test_decoding/sql/toast.sql
@@ -308,4 +308,20 @@ 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 that 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 147b5abc190..0db90c2011a 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 39185cc5b9f..9d22f648a84 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);
}
@@ -1526,6 +1526,14 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
RenameRelationInternal(toastidx,
NewToastName, true, true);
+
+ /*
+ * Reset the relrewrite for the toast. The command-counter
+ * increment is required here as we are about to update
+ * the tuple that is updated as part of RenameRelationInternal.
+ */
+ CommandCounterIncrement();
+ ResetRelRewrite(newrel->rd_rel->reltoastrelid);
}
relation_close(newrel, NoLock);
}
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index a03077139d5..dbee6ae199f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3850,6 +3850,37 @@ RenameRelationInternal(Oid myrelid, const char *newrelname, bool is_internal, bo
}
/*
+ * ResetRelRewrite - reset relrewrite
+ */
+void
+ResetRelRewrite(Oid myrelid)
+{
+ Relation relrelation; /* for RELATION relation */
+ HeapTuple reltup;
+ Form_pg_class relform;
+
+ /*
+ * Find relation's pg_class tuple.
+ */
+ relrelation = table_open(RelationRelationId, RowExclusiveLock);
+
+ reltup = SearchSysCacheCopy1(RELOID, ObjectIdGetDatum(myrelid));
+ if (!HeapTupleIsValid(reltup)) /* shouldn't happen */
+ elog(ERROR, "cache lookup failed for relation %u", myrelid);
+ relform = (Form_pg_class) GETSTRUCT(reltup);
+
+ /*
+ * Update pg_class tuple.
+ */
+ relform->relrewrite = InvalidOid;
+
+ CatalogTupleUpdate(relrelation, &reltup->t_self, reltup);
+
+ heap_freetuple(reltup);
+ table_close(relrelation, RowExclusiveLock);
+}
+
+/*
* Disallow ALTER TABLE (and similar commands) when the current backend has
* any open reference to the target table besides the one just acquired by
* the calling command; this implies there's an open cursor or active plan.
diff --git a/src/include/catalog/toasting.h b/src/include/catalog/toasting.h
index f3fa85f64e5..7067c4c61bc 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,
diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h
index 14f4b4882ff..336549cc5f0 100644
--- a/src/include/commands/tablecmds.h
+++ b/src/include/commands/tablecmds.h
@@ -78,6 +78,8 @@ extern void RenameRelationInternal(Oid myrelid,
const char *newrelname, bool is_internal,
bool is_index);
+extern void ResetRelRewrite(Oid myrelid);
+
extern void find_composite_type_dependencies(Oid typeOid,
Relation origRelation,
const char *origTypeName);