16
16
17
17
#include "access/genam.h"
18
18
#include "access/heapam.h"
19
+ #include "access/heapam_xlog.h"
19
20
#include "access/multixact.h"
20
21
#include "access/reloptions.h"
21
22
#include "access/relscan.h"
@@ -1322,11 +1323,7 @@ ExecuteTruncate(TruncateStmt *stmt)
1322
1323
{
1323
1324
List * rels = NIL ;
1324
1325
List * relids = NIL ;
1325
- List * seq_relids = NIL ;
1326
- EState * estate ;
1327
- ResultRelInfo * resultRelInfos ;
1328
- ResultRelInfo * resultRelInfo ;
1329
- SubTransactionId mySubid ;
1326
+ List * relids_logged = NIL ;
1330
1327
ListCell * cell ;
1331
1328
1332
1329
/*
@@ -1350,6 +1347,9 @@ ExecuteTruncate(TruncateStmt *stmt)
1350
1347
truncate_check_rel (rel );
1351
1348
rels = lappend (rels , rel );
1352
1349
relids = lappend_oid (relids , myrelid );
1350
+ /* Log this relation only if needed for logical decoding */
1351
+ if (RelationIsLogicallyLogged (rel ))
1352
+ relids_logged = lappend_oid (relids_logged , myrelid );
1353
1353
1354
1354
if (recurse )
1355
1355
{
@@ -1370,6 +1370,9 @@ ExecuteTruncate(TruncateStmt *stmt)
1370
1370
truncate_check_rel (rel );
1371
1371
rels = lappend (rels , rel );
1372
1372
relids = lappend_oid (relids , childrelid );
1373
+ /* Log this relation only if needed for logical decoding */
1374
+ if (RelationIsLogicallyLogged (rel ))
1375
+ relids_logged = lappend_oid (relids_logged , childrelid );
1373
1376
}
1374
1377
}
1375
1378
else if (rel -> rd_rel -> relkind == RELKIND_PARTITIONED_TABLE )
@@ -1379,15 +1382,56 @@ ExecuteTruncate(TruncateStmt *stmt)
1379
1382
errhint ("Do not specify the ONLY keyword, or use TRUNCATE ONLY on the partitions directly." )));
1380
1383
}
1381
1384
1385
+ ExecuteTruncateGuts (rels , relids , relids_logged ,
1386
+ stmt -> behavior , stmt -> restart_seqs );
1387
+
1388
+ /* And close the rels */
1389
+ foreach (cell , rels )
1390
+ {
1391
+ Relation rel = (Relation ) lfirst (cell );
1392
+
1393
+ heap_close (rel , NoLock );
1394
+ }
1395
+ }
1396
+
1397
+ /*
1398
+ * ExecuteTruncateGuts
1399
+ *
1400
+ * Internal implementation of TRUNCATE. This is called by the actual TRUNCATE
1401
+ * command (see above) as well as replication subscribers that execute a
1402
+ * replicated TRUNCATE action.
1403
+ *
1404
+ * explicit_rels is the list of Relations to truncate that the command
1405
+ * specified. relids is the list of Oids corresponding to explicit_rels.
1406
+ * relids_logged is the list of Oids (a subset of relids) that require
1407
+ * WAL-logging. This is all a bit redundant, but the existing callers have
1408
+ * this information handy in this form.
1409
+ */
1410
+ void
1411
+ ExecuteTruncateGuts (List * explicit_rels , List * relids , List * relids_logged ,
1412
+ DropBehavior behavior , bool restart_seqs )
1413
+ {
1414
+ List * rels ;
1415
+ List * seq_relids = NIL ;
1416
+ EState * estate ;
1417
+ ResultRelInfo * resultRelInfos ;
1418
+ ResultRelInfo * resultRelInfo ;
1419
+ SubTransactionId mySubid ;
1420
+ ListCell * cell ;
1421
+ Oid * logrelids ;
1422
+
1382
1423
/*
1424
+ * Open, exclusive-lock, and check all the explicitly-specified relations
1425
+ *
1383
1426
* In CASCADE mode, suck in all referencing relations as well. This
1384
1427
* requires multiple iterations to find indirectly-dependent relations. At
1385
1428
* each phase, we need to exclusive-lock new rels before looking for their
1386
1429
* dependencies, else we might miss something. Also, we check each rel as
1387
1430
* soon as we open it, to avoid a faux pas such as holding lock for a long
1388
1431
* time on a rel we have no permissions for.
1389
1432
*/
1390
- if (stmt -> behavior == DROP_CASCADE )
1433
+ rels = list_copy (explicit_rels );
1434
+ if (behavior == DROP_CASCADE )
1391
1435
{
1392
1436
for (;;)
1393
1437
{
@@ -1409,6 +1453,9 @@ ExecuteTruncate(TruncateStmt *stmt)
1409
1453
truncate_check_rel (rel );
1410
1454
rels = lappend (rels , rel );
1411
1455
relids = lappend_oid (relids , relid );
1456
+ /* Log this relation only if needed for logical decoding */
1457
+ if (RelationIsLogicallyLogged (rel ))
1458
+ relids_logged = lappend_oid (relids_logged , relid );
1412
1459
}
1413
1460
}
1414
1461
}
@@ -1421,7 +1468,7 @@ ExecuteTruncate(TruncateStmt *stmt)
1421
1468
#ifdef USE_ASSERT_CHECKING
1422
1469
heap_truncate_check_FKs (rels , false);
1423
1470
#else
1424
- if (stmt -> behavior == DROP_RESTRICT )
1471
+ if (behavior == DROP_RESTRICT )
1425
1472
heap_truncate_check_FKs (rels , false);
1426
1473
#endif
1427
1474
@@ -1431,7 +1478,7 @@ ExecuteTruncate(TruncateStmt *stmt)
1431
1478
* We want to do this early since it's pointless to do all the truncation
1432
1479
* work only to fail on sequence permissions.
1433
1480
*/
1434
- if (stmt -> restart_seqs )
1481
+ if (restart_seqs )
1435
1482
{
1436
1483
foreach (cell , rels )
1437
1484
{
@@ -1586,6 +1633,41 @@ ExecuteTruncate(TruncateStmt *stmt)
1586
1633
ResetSequence (seq_relid );
1587
1634
}
1588
1635
1636
+ /*
1637
+ * Write a WAL record to allow this set of actions to be logically decoded.
1638
+ *
1639
+ * Assemble an array of relids so we can write a single WAL record for the
1640
+ * whole action.
1641
+ */
1642
+ if (list_length (relids_logged ) > 0 )
1643
+ {
1644
+ xl_heap_truncate xlrec ;
1645
+ int i = 0 ;
1646
+
1647
+ /* should only get here if wal_level >= logical */
1648
+ Assert (XLogLogicalInfoActive ());
1649
+
1650
+ logrelids = palloc (list_length (relids_logged ) * sizeof (Oid ));
1651
+ foreach (cell , relids_logged )
1652
+ logrelids [i ++ ] = lfirst_oid (cell );
1653
+
1654
+ xlrec .dbId = MyDatabaseId ;
1655
+ xlrec .nrelids = list_length (relids_logged );
1656
+ xlrec .flags = 0 ;
1657
+ if (behavior == DROP_CASCADE )
1658
+ xlrec .flags |= XLH_TRUNCATE_CASCADE ;
1659
+ if (restart_seqs )
1660
+ xlrec .flags |= XLH_TRUNCATE_RESTART_SEQS ;
1661
+
1662
+ XLogBeginInsert ();
1663
+ XLogRegisterData ((char * ) & xlrec , SizeOfHeapTruncate );
1664
+ XLogRegisterData ((char * ) logrelids , list_length (relids_logged ) * sizeof (Oid ));
1665
+
1666
+ XLogSetRecordFlags (XLOG_INCLUDE_ORIGIN );
1667
+
1668
+ (void ) XLogInsert (RM_HEAP_ID , XLOG_HEAP_TRUNCATE );
1669
+ }
1670
+
1589
1671
/*
1590
1672
* Process all AFTER STATEMENT TRUNCATE triggers.
1591
1673
*/
@@ -1603,7 +1685,11 @@ ExecuteTruncate(TruncateStmt *stmt)
1603
1685
/* We can clean up the EState now */
1604
1686
FreeExecutorState (estate );
1605
1687
1606
- /* And close the rels (can't do this while EState still holds refs) */
1688
+ /*
1689
+ * Close any rels opened by CASCADE (can't do this while EState still
1690
+ * holds refs)
1691
+ */
1692
+ rels = list_difference_ptr (rels , explicit_rels );
1607
1693
foreach (cell , rels )
1608
1694
{
1609
1695
Relation rel = (Relation ) lfirst (cell );
0 commit comments