diff options
Diffstat (limited to 'src/backend/commands/tablecmds.c')
-rw-r--r-- | src/backend/commands/tablecmds.c | 104 |
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); |