aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/tablecmds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r--src/backend/commands/tablecmds.c104
1 files changed, 95 insertions, 9 deletions
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index ec2f9616edd..801db12bee7 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -16,6 +16,7 @@
#include "access/genam.h"
#include "access/heapam.h"
+#include "access/heapam_xlog.h"
#include "access/multixact.h"
#include "access/reloptions.h"
#include "access/relscan.h"
@@ -1322,11 +1323,7 @@ ExecuteTruncate(TruncateStmt *stmt)
{
List *rels = NIL;
List *relids = NIL;
- List *seq_relids = NIL;
- EState *estate;
- ResultRelInfo *resultRelInfos;
- ResultRelInfo *resultRelInfo;
- SubTransactionId mySubid;
+ List *relids_logged = NIL;
ListCell *cell;
/*
@@ -1350,6 +1347,9 @@ ExecuteTruncate(TruncateStmt *stmt)
truncate_check_rel(rel);
rels = lappend(rels, rel);
relids = lappend_oid(relids, myrelid);
+ /* Log this relation only if needed for logical decoding */
+ if (RelationIsLogicallyLogged(rel))
+ relids_logged = lappend_oid(relids_logged, myrelid);
if (recurse)
{
@@ -1370,6 +1370,9 @@ ExecuteTruncate(TruncateStmt *stmt)
truncate_check_rel(rel);
rels = lappend(rels, rel);
relids = lappend_oid(relids, childrelid);
+ /* Log this relation only if needed for logical decoding */
+ if (RelationIsLogicallyLogged(rel))
+ relids_logged = lappend_oid(relids_logged, childrelid);
}
}
else if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
@@ -1379,7 +1382,47 @@ ExecuteTruncate(TruncateStmt *stmt)
errhint("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly.")));
}
+ ExecuteTruncateGuts(rels, relids, relids_logged,
+ stmt->behavior, stmt->restart_seqs);
+
+ /* And close the rels */
+ foreach(cell, rels)
+ {
+ Relation rel = (Relation) lfirst(cell);
+
+ heap_close(rel, NoLock);
+ }
+}
+
+/*
+ * ExecuteTruncateGuts
+ *
+ * Internal implementation of TRUNCATE. This is called by the actual TRUNCATE
+ * command (see above) as well as replication subscribers that execute a
+ * replicated TRUNCATE action.
+ *
+ * explicit_rels is the list of Relations to truncate that the command
+ * specified. relids is the list of Oids corresponding to explicit_rels.
+ * relids_logged is the list of Oids (a subset of relids) that require
+ * WAL-logging. This is all a bit redundant, but the existing callers have
+ * this information handy in this form.
+ */
+void
+ExecuteTruncateGuts(List *explicit_rels, List *relids, List *relids_logged,
+ DropBehavior behavior, bool restart_seqs)
+{
+ List *rels;
+ List *seq_relids = NIL;
+ EState *estate;
+ ResultRelInfo *resultRelInfos;
+ ResultRelInfo *resultRelInfo;
+ SubTransactionId mySubid;
+ ListCell *cell;
+ Oid *logrelids;
+
/*
+ * Open, exclusive-lock, and check all the explicitly-specified relations
+ *
* In CASCADE mode, suck in all referencing relations as well. This
* requires multiple iterations to find indirectly-dependent relations. At
* each phase, we need to exclusive-lock new rels before looking for their
@@ -1387,7 +1430,8 @@ ExecuteTruncate(TruncateStmt *stmt)
* soon as we open it, to avoid a faux pas such as holding lock for a long
* time on a rel we have no permissions for.
*/
- if (stmt->behavior == DROP_CASCADE)
+ rels = list_copy(explicit_rels);
+ if (behavior == DROP_CASCADE)
{
for (;;)
{
@@ -1409,6 +1453,9 @@ ExecuteTruncate(TruncateStmt *stmt)
truncate_check_rel(rel);
rels = lappend(rels, rel);
relids = lappend_oid(relids, relid);
+ /* Log this relation only if needed for logical decoding */
+ if (RelationIsLogicallyLogged(rel))
+ relids_logged = lappend_oid(relids_logged, relid);
}
}
}
@@ -1421,7 +1468,7 @@ ExecuteTruncate(TruncateStmt *stmt)
#ifdef USE_ASSERT_CHECKING
heap_truncate_check_FKs(rels, false);
#else
- if (stmt->behavior == DROP_RESTRICT)
+ if (behavior == DROP_RESTRICT)
heap_truncate_check_FKs(rels, false);
#endif
@@ -1431,7 +1478,7 @@ ExecuteTruncate(TruncateStmt *stmt)
* We want to do this early since it's pointless to do all the truncation
* work only to fail on sequence permissions.
*/
- if (stmt->restart_seqs)
+ if (restart_seqs)
{
foreach(cell, rels)
{
@@ -1587,6 +1634,41 @@ ExecuteTruncate(TruncateStmt *stmt)
}
/*
+ * Write a WAL record to allow this set of actions to be logically decoded.
+ *
+ * Assemble an array of relids so we can write a single WAL record for the
+ * whole action.
+ */
+ if (list_length(relids_logged) > 0)
+ {
+ xl_heap_truncate xlrec;
+ int i = 0;
+
+ /* should only get here if wal_level >= logical */
+ Assert(XLogLogicalInfoActive());
+
+ logrelids = palloc(list_length(relids_logged) * sizeof(Oid));
+ foreach (cell, relids_logged)
+ logrelids[i++] = lfirst_oid(cell);
+
+ xlrec.dbId = MyDatabaseId;
+ xlrec.nrelids = list_length(relids_logged);
+ xlrec.flags = 0;
+ if (behavior == DROP_CASCADE)
+ xlrec.flags |= XLH_TRUNCATE_CASCADE;
+ if (restart_seqs)
+ xlrec.flags |= XLH_TRUNCATE_RESTART_SEQS;
+
+ XLogBeginInsert();
+ XLogRegisterData((char *) &xlrec, SizeOfHeapTruncate);
+ XLogRegisterData((char *) logrelids, list_length(relids_logged) * sizeof(Oid));
+
+ XLogSetRecordFlags(XLOG_INCLUDE_ORIGIN);
+
+ (void) XLogInsert(RM_HEAP_ID, XLOG_HEAP_TRUNCATE);
+ }
+
+ /*
* Process all AFTER STATEMENT TRUNCATE triggers.
*/
resultRelInfo = resultRelInfos;
@@ -1603,7 +1685,11 @@ ExecuteTruncate(TruncateStmt *stmt)
/* We can clean up the EState now */
FreeExecutorState(estate);
- /* And close the rels (can't do this while EState still holds refs) */
+ /*
+ * Close any rels opened by CASCADE (can't do this while EState still
+ * holds refs)
+ */
+ rels = list_difference_ptr(rels, explicit_rels);
foreach(cell, rels)
{
Relation rel = (Relation) lfirst(cell);