summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/access/heap/heapam.c9
-rw-r--r--src/backend/access/index/indexam.c8
-rw-r--r--src/backend/utils/time/snapmgr.c19
-rw-r--r--src/include/utils/snapmgr.h3
4 files changed, 35 insertions, 4 deletions
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 0dcd6ee817e..ee692c03c3c 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -1143,6 +1143,15 @@ heap_beginscan(Relation relation, Snapshot snapshot,
if (!(snapshot && IsMVCCSnapshot(snapshot)))
scan->rs_base.rs_flags &= ~SO_ALLOW_PAGEMODE;
+ /* Check that a historic snapshot is not used for non-catalog tables */
+ if (snapshot &&
+ IsHistoricMVCCSnapshot(snapshot) &&
+ !RelationIsAccessibleInLogicalDecoding(relation))
+ {
+ elog(ERROR, "cannot query non-catalog table \"%s\" during logical decoding",
+ RelationGetRelationName(relation));
+ }
+
/*
* For seqscan and sample scans in a serializable transaction, acquire a
* predicate lock on the entire relation. This is required not only to
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 1a4f36fe0a9..31b22d9f397 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -263,6 +263,14 @@ index_beginscan(Relation heapRelation,
Assert(snapshot != InvalidSnapshot);
+ /* Check that a historic snapshot is not used for non-catalog tables */
+ if (IsHistoricMVCCSnapshot(snapshot) &&
+ !RelationIsAccessibleInLogicalDecoding(heapRelation))
+ {
+ elog(ERROR, "cannot query non-catalog table \"%s\" during logical decoding",
+ RelationGetRelationName(heapRelation));
+ }
+
scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot, NULL, false);
/*
diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c
index ea35f30f494..65561cc6bc3 100644
--- a/src/backend/utils/time/snapmgr.c
+++ b/src/backend/utils/time/snapmgr.c
@@ -271,12 +271,23 @@ Snapshot
GetTransactionSnapshot(void)
{
/*
- * This should not be called while doing logical decoding. Historic
- * snapshots are only usable for catalog access, not for general-purpose
- * queries.
+ * Return historic snapshot if doing logical decoding.
+ *
+ * Historic snapshots are only usable for catalog access, not for
+ * general-purpose queries. The caller is responsible for ensuring that
+ * the snapshot is used correctly! (PostgreSQL code never calls this
+ * during logical decoding, but extensions can do it.)
*/
if (HistoricSnapshotActive())
- elog(ERROR, "cannot take query snapshot during logical decoding");
+ {
+ /*
+ * We'll never need a non-historic transaction snapshot in this
+ * (sub-)transaction, so there's no need to be careful to set one up
+ * for later calls to GetTransactionSnapshot().
+ */
+ Assert(!FirstSnapshotSet);
+ return HistoricSnapshot;
+ }
/* First call in transaction? */
if (!FirstSnapshotSet)
diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h
index d346be71642..604c1f90216 100644
--- a/src/include/utils/snapmgr.h
+++ b/src/include/utils/snapmgr.h
@@ -56,6 +56,9 @@ extern PGDLLIMPORT SnapshotData SnapshotToastData;
((snapshot)->snapshot_type == SNAPSHOT_MVCC || \
(snapshot)->snapshot_type == SNAPSHOT_HISTORIC_MVCC)
+#define IsHistoricMVCCSnapshot(snapshot) \
+ ((snapshot)->snapshot_type == SNAPSHOT_HISTORIC_MVCC)
+
extern Snapshot GetTransactionSnapshot(void);
extern Snapshot GetLatestSnapshot(void);
extern void SnapshotSetCommandId(CommandId curcid);