summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.global.in2
-rw-r--r--src/Makefile.shlib2
-rw-r--r--src/backend/access/heap/heapam.c23
-rw-r--r--src/backend/access/index/indexam.c15
-rw-r--r--src/backend/access/nbtree/nbtsearch.c33
-rw-r--r--src/backend/catalog/information_schema.sql2
-rw-r--r--src/backend/executor/nodeSeqscan.c3
-rw-r--r--src/backend/parser/parse_utilcmd.c2
-rw-r--r--src/backend/storage/lmgr/predicate.c220
-rw-r--r--src/bin/psql/tab-complete.c6
-rw-r--r--src/include/storage/predicate.h9
-rw-r--r--src/include/storage/predicate_internals.h11
-rw-r--r--src/interfaces/ecpg/test/Makefile2
-rw-r--r--src/test/isolation/Makefile2
14 files changed, 188 insertions, 144 deletions
diff --git a/src/Makefile.global.in b/src/Makefile.global.in
index 56f282712d..e2e7e725a9 100644
--- a/src/Makefile.global.in
+++ b/src/Makefile.global.in
@@ -437,7 +437,7 @@ endif
pg_regress_locale_flags = $(if $(ENCODING),--encoding=$(ENCODING)) $(NOLOCALE)
pg_regress_check = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --temp-install=./tmp_check --top-builddir=$(top_builddir) $(pg_regress_locale_flags)
-pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --psqldir=$(PSQLDIR) $(pg_regress_locale_flags)
+pg_regress_installcheck = $(top_builddir)/src/test/regress/pg_regress --inputdir=$(srcdir) --psqldir="$(PSQLDIR)" $(pg_regress_locale_flags)
pg_regress_clean_files = results/ regression.diffs regression.out tmp_check/ log/
diff --git a/src/Makefile.shlib b/src/Makefile.shlib
index a5cf6c6c16..53b527bcab 100644
--- a/src/Makefile.shlib
+++ b/src/Makefile.shlib
@@ -130,7 +130,7 @@ ifeq ($(PORTNAME), darwin)
ifneq ($(SO_MAJOR_VERSION), 0)
version_link = -compatibility_version $(SO_MAJOR_VERSION) -current_version $(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)
endif
- LINK.shared = $(COMPILER) -dynamiclib -install_name $(libdir)/lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX) $(version_link) $(exported_symbols_list) -multiply_defined suppress
+ LINK.shared = $(COMPILER) -dynamiclib -install_name "$(libdir)/lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX)" $(version_link) $(exported_symbols_list) -multiply_defined suppress
shlib = lib$(NAME).$(SO_MAJOR_VERSION).$(SO_MINOR_VERSION)$(DLSUFFIX)
shlib_major = lib$(NAME).$(SO_MAJOR_VERSION)$(DLSUFFIX)
else
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 01a492e496..b947c11f7d 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -274,7 +274,8 @@ heapgetpage(HeapScanDesc scan, BlockNumber page)
else
valid = HeapTupleSatisfiesVisibility(&loctup, snapshot, buffer);
- CheckForSerializableConflictOut(valid, scan->rs_rd, &loctup, buffer);
+ CheckForSerializableConflictOut(valid, scan->rs_rd, &loctup,
+ buffer, snapshot);
if (valid)
scan->rs_vistuples[ntup++] = lineoff;
@@ -469,7 +470,8 @@ heapgettup(HeapScanDesc scan,
snapshot,
scan->rs_cbuf);
- CheckForSerializableConflictOut(valid, scan->rs_rd, tuple, scan->rs_cbuf);
+ CheckForSerializableConflictOut(valid, scan->rs_rd, tuple,
+ scan->rs_cbuf, snapshot);
if (valid && key != NULL)
HeapKeyTest(tuple, RelationGetDescr(scan->rs_rd),
@@ -478,7 +480,7 @@ heapgettup(HeapScanDesc scan,
if (valid)
{
if (!scan->rs_relpredicatelocked)
- PredicateLockTuple(scan->rs_rd, tuple);
+ PredicateLockTuple(scan->rs_rd, tuple, snapshot);
LockBuffer(scan->rs_cbuf, BUFFER_LOCK_UNLOCK);
return;
}
@@ -747,7 +749,7 @@ heapgettup_pagemode(HeapScanDesc scan,
if (valid)
{
if (!scan->rs_relpredicatelocked)
- PredicateLockTuple(scan->rs_rd, tuple);
+ PredicateLockTuple(scan->rs_rd, tuple, scan->rs_snapshot);
scan->rs_cindex = lineindex;
return;
}
@@ -755,7 +757,7 @@ heapgettup_pagemode(HeapScanDesc scan,
else
{
if (!scan->rs_relpredicatelocked)
- PredicateLockTuple(scan->rs_rd, tuple);
+ PredicateLockTuple(scan->rs_rd, tuple, scan->rs_snapshot);
scan->rs_cindex = lineindex;
return;
}
@@ -1470,9 +1472,9 @@ heap_fetch(Relation relation,
valid = HeapTupleSatisfiesVisibility(tuple, snapshot, buffer);
if (valid)
- PredicateLockTuple(relation, tuple);
+ PredicateLockTuple(relation, tuple, snapshot);
- CheckForSerializableConflictOut(valid, relation, tuple, buffer);
+ CheckForSerializableConflictOut(valid, relation, tuple, buffer, snapshot);
LockBuffer(buffer, BUFFER_LOCK_UNLOCK);
@@ -1588,11 +1590,12 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer,
/* If it's visible per the snapshot, we must return it */
valid = HeapTupleSatisfiesVisibility(&heapTuple, snapshot, buffer);
- CheckForSerializableConflictOut(valid, relation, &heapTuple, buffer);
+ CheckForSerializableConflictOut(valid, relation, &heapTuple, buffer,
+ snapshot);
if (valid)
{
ItemPointerSetOffsetNumber(tid, offnum);
- PredicateLockTuple(relation, &heapTuple);
+ PredicateLockTuple(relation, &heapTuple, snapshot);
if (all_dead)
*all_dead = false;
return true;
@@ -1750,7 +1753,7 @@ heap_get_latest_tid(Relation relation,
* result candidate.
*/
valid = HeapTupleSatisfiesVisibility(&tp, snapshot, buffer);
- CheckForSerializableConflictOut(valid, relation, &tp, buffer);
+ CheckForSerializableConflictOut(valid, relation, &tp, buffer, snapshot);
if (valid)
*tid = ctid;
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 0208765964..31d705c056 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -126,7 +126,7 @@ do { \
} while(0)
static IndexScanDesc index_beginscan_internal(Relation indexRelation,
- int nkeys, int norderbys);
+ int nkeys, int norderbys, Snapshot snapshot);
/* ----------------------------------------------------------------
@@ -234,7 +234,7 @@ index_beginscan(Relation heapRelation,
{
IndexScanDesc scan;
- scan = index_beginscan_internal(indexRelation, nkeys, norderbys);
+ scan = index_beginscan_internal(indexRelation, nkeys, norderbys, snapshot);
/*
* Save additional parameters into the scandesc. Everything else was set
@@ -259,7 +259,7 @@ index_beginscan_bitmap(Relation indexRelation,
{
IndexScanDesc scan;
- scan = index_beginscan_internal(indexRelation, nkeys, 0);
+ scan = index_beginscan_internal(indexRelation, nkeys, 0, snapshot);
/*
* Save additional parameters into the scandesc. Everything else was set
@@ -275,7 +275,7 @@ index_beginscan_bitmap(Relation indexRelation,
*/
static IndexScanDesc
index_beginscan_internal(Relation indexRelation,
- int nkeys, int norderbys)
+ int nkeys, int norderbys, Snapshot snapshot)
{
IndexScanDesc scan;
FmgrInfo *procedure;
@@ -284,7 +284,7 @@ index_beginscan_internal(Relation indexRelation,
GET_REL_PROCEDURE(ambeginscan);
if (!(indexRelation->rd_am->ampredlocks))
- PredicateLockRelation(indexRelation);
+ PredicateLockRelation(indexRelation, snapshot);
/*
* We hold a reference count to the relcache entry throughout the scan.
@@ -602,7 +602,8 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
scan->xs_cbuf);
CheckForSerializableConflictOut(valid, scan->heapRelation,
- heapTuple, scan->xs_cbuf);
+ heapTuple, scan->xs_cbuf,
+ scan->xs_snapshot);
if (valid)
{
@@ -624,7 +625,7 @@ index_getnext(IndexScanDesc scan, ScanDirection direction)
else
scan->xs_next_hot = InvalidOffsetNumber;
- PredicateLockTuple(scan->heapRelation, heapTuple);
+ PredicateLockTuple(scan->heapRelation, heapTuple, scan->xs_snapshot);
LockBuffer(scan->xs_cbuf, BUFFER_LOCK_UNLOCK);
diff --git a/src/backend/access/nbtree/nbtsearch.c b/src/backend/access/nbtree/nbtsearch.c
index 2ce2bc2f00..0771d19463 100644
--- a/src/backend/access/nbtree/nbtsearch.c
+++ b/src/backend/access/nbtree/nbtsearch.c
@@ -64,10 +64,7 @@ _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey,
/* If index is empty and access = BT_READ, no root page is created. */
if (!BufferIsValid(*bufP))
- {
- PredicateLockRelation(rel); /* Nothing finer to lock exists. */
return (BTStack) NULL;
- }
/* Loop iterates once per level descended in the tree */
for (;;)
@@ -92,11 +89,7 @@ _bt_search(Relation rel, int keysz, ScanKey scankey, bool nextkey,
page = BufferGetPage(*bufP);
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
if (P_ISLEAF(opaque))
- {
- if (access == BT_READ)
- PredicateLockPage(rel, BufferGetBlockNumber(*bufP));
break;
- }
/*
* Find the appropriate item on the internal page, and get the child
@@ -855,9 +848,16 @@ _bt_first(IndexScanDesc scan, ScanDirection dir)
if (!BufferIsValid(buf))
{
- /* Only get here if index is completely empty */
+ /*
+ * We only get here if the index is completely empty.
+ * Lock relation because nothing finer to lock exists.
+ */
+ PredicateLockRelation(rel, scan->xs_snapshot);
return false;
}
+ else
+ PredicateLockPage(rel, BufferGetBlockNumber(buf),
+ scan->xs_snapshot);
/* initialize moreLeft/moreRight appropriately for scan direction */
if (ScanDirectionIsForward(dir))
@@ -1153,7 +1153,7 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
if (!P_IGNORE(opaque))
{
- PredicateLockPage(rel, blkno);
+ PredicateLockPage(rel, blkno, scan->xs_snapshot);
/* see if there are any matches on this page */
/* note that this will clear moreRight if we can stop */
if (_bt_readpage(scan, dir, P_FIRSTDATAKEY(opaque)))
@@ -1201,7 +1201,7 @@ _bt_steppage(IndexScanDesc scan, ScanDirection dir)
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
if (!P_IGNORE(opaque))
{
- PredicateLockPage(rel, BufferGetBlockNumber(so->currPos.buf));
+ PredicateLockPage(rel, BufferGetBlockNumber(so->currPos.buf), scan->xs_snapshot);
/* see if there are any matches on this page */
/* note that this will clear moreLeft if we can stop */
if (_bt_readpage(scan, dir, PageGetMaxOffsetNumber(page)))
@@ -1363,11 +1363,7 @@ _bt_get_endpoint(Relation rel, uint32 level, bool rightmost)
buf = _bt_gettrueroot(rel);
if (!BufferIsValid(buf))
- {
- /* empty index... */
- PredicateLockRelation(rel); /* Nothing finer to lock exists. */
return InvalidBuffer;
- }
page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
@@ -1444,13 +1440,16 @@ _bt_endpoint(IndexScanDesc scan, ScanDirection dir)
if (!BufferIsValid(buf))
{
- /* empty index... */
- PredicateLockRelation(rel); /* Nothing finer to lock exists. */
+ /*
+ * Empty index. Lock the whole relation, as nothing finer to lock
+ * exists.
+ */
+ PredicateLockRelation(rel, scan->xs_snapshot);
so->currPos.buf = InvalidBuffer;
return false;
}
- PredicateLockPage(rel, BufferGetBlockNumber(buf));
+ PredicateLockPage(rel, BufferGetBlockNumber(buf), scan->xs_snapshot);
page = BufferGetPage(buf);
opaque = (BTPageOpaque) PageGetSpecialPointer(page);
Assert(P_ISLEAF(opaque));
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index 452a0ead44..81407a3a5e 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -274,7 +274,7 @@ CREATE VIEW attributes AS
CAST(pg_get_expr(ad.adbin, ad.adrelid) AS character_data) AS attribute_default,
CAST(CASE WHEN a.attnotnull OR (t.typtype = 'd' AND t.typnotnull) THEN 'NO' ELSE 'YES' END
AS yes_or_no)
- AS is_nullable,
+ AS is_nullable, -- This column was apparently removed between SQL:2003 and SQL:2008.
CAST(
CASE WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY'
diff --git a/src/backend/executor/nodeSeqscan.c b/src/backend/executor/nodeSeqscan.c
index 1e566b2d50..f356874b44 100644
--- a/src/backend/executor/nodeSeqscan.c
+++ b/src/backend/executor/nodeSeqscan.c
@@ -113,7 +113,8 @@ SeqRecheck(SeqScanState *node, TupleTableSlot *slot)
TupleTableSlot *
ExecSeqScan(SeqScanState *node)
{
- PredicateLockRelation(node->ss_currentRelation);
+ PredicateLockRelation(node->ss_currentRelation,
+ node->ss_currentScanDesc->rs_snapshot);
node->ss_currentScanDesc->rs_relpredicatelocked = true;
return ExecScan((ScanState *) node,
(ExecScanAccessMtd) SeqNext,
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 25ce6a76a5..a6a626f576 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -849,7 +849,6 @@ static void
transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
{
HeapTuple tuple;
- Form_pg_type typ;
TupleDesc tupdesc;
int i;
Oid ofTypeId;
@@ -858,7 +857,6 @@ transformOfType(CreateStmtContext *cxt, TypeName *ofTypename)
tuple = typenameType(NULL, ofTypename, NULL);
check_of_type(tuple);
- typ = (Form_pg_type) GETSTRUCT(tuple);
ofTypeId = HeapTupleGetOid(tuple);
ofTypename->typeOid = ofTypeId; /* cached for later */
diff --git a/src/backend/storage/lmgr/predicate.c b/src/backend/storage/lmgr/predicate.c
index 02f5d033b2..a12f52ecc9 100644
--- a/src/backend/storage/lmgr/predicate.c
+++ b/src/backend/storage/lmgr/predicate.c
@@ -148,9 +148,11 @@
* predicate lock maintenance
* RegisterSerializableTransaction(Snapshot snapshot)
* RegisterPredicateLockingXid(void)
- * PredicateLockRelation(Relation relation)
- * PredicateLockPage(Relation relation, BlockNumber blkno)
- * PredicateLockTuple(Relation relation, HeapTuple tuple)
+ * PredicateLockRelation(Relation relation, Snapshot snapshot)
+ * PredicateLockPage(Relation relation, BlockNumber blkno,
+ * Snapshot snapshot)
+ * PredicateLockTuple(Relation relation, HeapTuple tuple,
+ * Snapshot snapshot)
* PredicateLockPageSplit(Relation relation, BlockNumber oldblkno,
* BlockNumber newblkno);
* PredicateLockPageCombine(Relation relation, BlockNumber oldblkno,
@@ -160,7 +162,8 @@
*
* conflict detection (may also trigger rollback)
* CheckForSerializableConflictOut(bool visible, Relation relation,
- * HeapTupleData *tup, Buffer buffer)
+ * HeapTupleData *tup, Buffer buffer,
+ * Snapshot snapshot)
* CheckForSerializableConflictIn(Relation relation, HeapTupleData *tup,
* Buffer buffer)
* CheckTableForSerializableConflictIn(Relation relation)
@@ -241,9 +244,9 @@
#define SxactIsOnFinishedList(sxact) (!SHMQueueIsDetached(&((sxact)->finishedLink)))
-#define SxactIsPrepared(sxact) (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)
#define SxactIsCommitted(sxact) (((sxact)->flags & SXACT_FLAG_COMMITTED) != 0)
-#define SxactIsRolledBack(sxact) (((sxact)->flags & SXACT_FLAG_ROLLED_BACK) != 0)
+#define SxactIsPrepared(sxact) (((sxact)->flags & SXACT_FLAG_PREPARED) != 0)
+#define SxactIsDoomed(sxact) (((sxact)->flags & SXACT_FLAG_DOOMED) != 0)
#define SxactIsReadOnly(sxact) (((sxact)->flags & SXACT_FLAG_READ_ONLY) != 0)
#define SxactHasSummaryConflictIn(sxact) (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_IN) != 0)
#define SxactHasSummaryConflictOut(sxact) (((sxact)->flags & SXACT_FLAG_SUMMARY_CONFLICT_OUT) != 0)
@@ -256,27 +259,6 @@
#define SxactIsDeferrableWaiting(sxact) (((sxact)->flags & SXACT_FLAG_DEFERRABLE_WAITING) != 0)
#define SxactIsROSafe(sxact) (((sxact)->flags & SXACT_FLAG_RO_SAFE) != 0)
#define SxactIsROUnsafe(sxact) (((sxact)->flags & SXACT_FLAG_RO_UNSAFE) != 0)
-#define SxactIsMarkedForDeath(sxact) (((sxact)->flags & SXACT_FLAG_MARKED_FOR_DEATH) != 0)
-
-/*
- * Is this relation exempt from predicate locking? We don't do predicate
- * locking on system or temporary relations.
- */
-#define SkipPredicateLocksForRelation(relation) \
- (((relation)->rd_id < FirstBootstrapObjectId) \
- || RelationUsesLocalBuffers(relation))
-
-/*
- * When a public interface method is called for serializing a relation within
- * the current transaction, this is the test to see if we should do a quick
- * return.
- */
-#define SkipSerialization(relation) \
- ((!IsolationIsSerializable()) \
- || ((MySerializableXact == InvalidSerializableXact)) \
- || ReleasePredicateLocksIfROSafe() \
- || SkipPredicateLocksForRelation(relation))
-
/*
* Compute the hash code associated with a PREDICATELOCKTARGETTAG.
@@ -444,7 +426,6 @@ static void PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag);
static void DropAllPredicateLocksFromTable(const Relation relation,
bool transfer);
static void SetNewSxactGlobalXmin(void);
-static bool ReleasePredicateLocksIfROSafe(void);
static void ClearOldPredicateLocks(void);
static void ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
bool summarize);
@@ -454,6 +435,91 @@ static void FlagRWConflict(SERIALIZABLEXACT *reader, SERIALIZABLEXACT *writer);
static void OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
SERIALIZABLEXACT *writer);
+
+/*------------------------------------------------------------------------*/
+
+/*
+ * Does this relation participate in predicate locking? Temporary and system
+ * relations are exempt.
+ */
+static inline bool
+PredicateLockingNeededForRelation(Relation relation)
+{
+ return !(relation->rd_id < FirstBootstrapObjectId ||
+ RelationUsesLocalBuffers(relation));
+}
+
+/*
+ * When a public interface method is called for a read, this is the test to
+ * see if we should do a quick return.
+ *
+ * Note: this function has side-effects! If this transaction has been flagged
+ * as RO-safe since the last call, we release all predicate locks and reset
+ * MySerializableXact. That makes subsequent calls to return quickly.
+ *
+ * This is marked as 'inline' to make to eliminate the function call overhead
+ * in the common case that serialization is not needed.
+ */
+static inline bool
+SerializationNeededForRead(Relation relation, Snapshot snapshot)
+{
+ /* Nothing to do if this is not a serializable transaction */
+ if (MySerializableXact == InvalidSerializableXact)
+ return false;
+
+ /*
+ * Don't acquire locks or conflict when scanning with a special snapshot.
+ * This excludes things like CLUSTER and REINDEX. They use the wholesale
+ * functions TransferPredicateLocksToHeapRelation() and
+ * CheckTableForSerializableConflictIn() to participate serialization, but
+ * the scans involved don't need serialization.
+ */
+ if (!IsMVCCSnapshot(snapshot))
+ return false;
+
+ /*
+ * Check if we have just become "RO-safe". If we have, immediately release
+ * all locks as they're not needed anymore. This also resets
+ * MySerializableXact, so that subsequent calls to this function can exit
+ * quickly.
+ *
+ * A transaction is flagged as RO_SAFE if all concurrent R/W
+ * transactions commit without having conflicts out to an earlier
+ * snapshot, thus ensuring that no conflicts are possible for this
+ * transaction.
+ */
+ if (SxactIsROSafe(MySerializableXact))
+ {
+ ReleasePredicateLocks(false);
+ return false;
+ }
+
+ /* Check if the relation doesn't participate in predicate locking */
+ if (!PredicateLockingNeededForRelation(relation))
+ return false;
+
+ return true; /* no excuse to skip predicate locking */
+}
+
+/*
+ * Like SerializationNeededForRead(), but called on writes.
+ * The logic is the same, but there is no snapshot and we can't be RO-safe.
+ */
+static inline bool
+SerializationNeededForWrite(Relation relation)
+{
+ /* Nothing to do if this is not a serializable transaction */
+ if (MySerializableXact == InvalidSerializableXact)
+ return false;
+
+ /* Check if the relation doesn't participate in predicate locking */
+ if (!PredicateLockingNeededForRelation(relation))
+ return false;
+
+ return true; /* no excuse to skip predicate locking */
+}
+
+
/*------------------------------------------------------------------------*/
/*
@@ -542,8 +608,8 @@ RWConflictExists(const SERIALIZABLEXACT *reader, const SERIALIZABLEXACT *writer)
Assert(reader != writer);
/* Check the ends of the purported conflict first. */
- if (SxactIsRolledBack(reader)
- || SxactIsRolledBack(writer)
+ if (SxactIsDoomed(reader)
+ || SxactIsDoomed(writer)
|| SHMQueueEmpty(&reader->outConflicts)
|| SHMQueueEmpty(&writer->inConflicts))
return false;
@@ -2244,11 +2310,11 @@ PredicateLockAcquire(const PREDICATELOCKTARGETTAG *targettag)
* Clear any finer-grained predicate locks this session has on the relation.
*/
void
-PredicateLockRelation(const Relation relation)
+PredicateLockRelation(const Relation relation, const Snapshot snapshot)
{
PREDICATELOCKTARGETTAG tag;
- if (SkipSerialization(relation))
+ if (!SerializationNeededForRead(relation, snapshot))
return;
SET_PREDICATELOCKTARGETTAG_RELATION(tag,
@@ -2267,11 +2333,12 @@ PredicateLockRelation(const Relation relation)
* Clear any finer-grained predicate locks this session has on the relation.
*/
void
-PredicateLockPage(const Relation relation, const BlockNumber blkno)
+PredicateLockPage(const Relation relation, const BlockNumber blkno,
+ const Snapshot snapshot)
{
PREDICATELOCKTARGETTAG tag;
- if (SkipSerialization(relation))
+ if (!SerializationNeededForRead(relation, snapshot))
return;
SET_PREDICATELOCKTARGETTAG_PAGE(tag,
@@ -2289,13 +2356,14 @@ PredicateLockPage(const Relation relation, const BlockNumber blkno)
* Skip if this is a temporary table.
*/
void
-PredicateLockTuple(const Relation relation, const HeapTuple tuple)
+PredicateLockTuple(const Relation relation, const HeapTuple tuple,
+ const Snapshot snapshot)
{
PREDICATELOCKTARGETTAG tag;
ItemPointer tid;
TransactionId targetxmin;
- if (SkipSerialization(relation))
+ if (!SerializationNeededForRead(relation, snapshot))
return;
/*
@@ -2666,7 +2734,7 @@ DropAllPredicateLocksFromTable(const Relation relation, bool transfer)
if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
return;
- if (SkipPredicateLocksForRelation(relation))
+ if (!PredicateLockingNeededForRelation(relation))
return;
dbId = relation->rd_node.dbNode;
@@ -2881,7 +2949,7 @@ PredicateLockPageSplit(const Relation relation, const BlockNumber oldblkno,
if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
return;
- if (SkipPredicateLocksForRelation(relation))
+ if (!PredicateLockingNeededForRelation(relation))
return;
Assert(oldblkno != newblkno);
@@ -2979,7 +3047,7 @@ SetNewSxactGlobalXmin(void)
for (sxact = FirstPredXact(); sxact != NULL; sxact = NextPredXact(sxact))
{
- if (!SxactIsRolledBack(sxact)
+ if (!SxactIsDoomed(sxact)
&& !SxactIsCommitted(sxact)
&& sxact != OldCommittedSxact)
{
@@ -3044,7 +3112,7 @@ ReleasePredicateLocks(const bool isCommit)
}
Assert(!isCommit || SxactIsPrepared(MySerializableXact));
- Assert(!SxactIsRolledBack(MySerializableXact));
+ Assert(!isCommit || !SxactIsDoomed(MySerializableXact));
Assert(!SxactIsCommitted(MySerializableXact));
/* may not be serializable during COMMIT/ROLLBACK PREPARED */
@@ -3084,9 +3152,7 @@ ReleasePredicateLocks(const bool isCommit)
MySerializableXact->flags |= SXACT_FLAG_READ_ONLY;
}
else
- {
- MySerializableXact->flags |= SXACT_FLAG_ROLLED_BACK;
- }
+ MySerializableXact->flags |= SXACT_FLAG_DOOMED;
if (!topLevelIsDeclaredReadOnly)
{
@@ -3311,30 +3377,6 @@ ReleasePredicateLocks(const bool isCommit)
}
/*
- * ReleasePredicateLocksIfROSafe
- * Check if the current transaction is read only and operating on
- * a safe snapshot. If so, release predicate locks and return
- * true.
- *
- * A transaction is flagged as RO_SAFE if all concurrent R/W
- * transactions commit without having conflicts out to an earlier
- * snapshot, thus ensuring that no conflicts are possible for this
- * transaction. Thus, we call this function as part of the
- * SkipSerialization check on all public interface methods.
- */
-static bool
-ReleasePredicateLocksIfROSafe(void)
-{
- if (SxactIsROSafe(MySerializableXact))
- {
- ReleasePredicateLocks(false);
- return true;
- }
- else
- return false;
-}
-
-/*
* Clear old predicate locks, belonging to committed transactions that are no
* longer interesting to any in-progress transaction.
*/
@@ -3486,7 +3528,7 @@ ReleaseOneSerializableXact(SERIALIZABLEXACT *sxact, bool partial,
nextConflict;
Assert(sxact != NULL);
- Assert(SxactIsRolledBack(sxact) || SxactIsCommitted(sxact));
+ Assert(SxactIsDoomed(sxact) || SxactIsCommitted(sxact));
Assert(LWLockHeldByMe(SerializableFinishedListLock));
/*
@@ -3679,7 +3721,8 @@ XidIsConcurrent(TransactionId xid)
*/
void
CheckForSerializableConflictOut(const bool visible, const Relation relation,
- const HeapTuple tuple, const Buffer buffer)
+ const HeapTuple tuple, const Buffer buffer,
+ const Snapshot snapshot)
{
TransactionId xid;
SERIALIZABLEXIDTAG sxidtag;
@@ -3687,10 +3730,11 @@ CheckForSerializableConflictOut(const bool visible, const Relation relation,
SERIALIZABLEXACT *sxact;
HTSV_Result htsvResult;
- if (SkipSerialization(relation))
+ if (!SerializationNeededForRead(relation, snapshot))
return;
- if (SxactIsMarkedForDeath(MySerializableXact))
+ /* Check if someone else has already decided that we need to die */
+ if (SxactIsDoomed(MySerializableXact))
{
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
@@ -3804,11 +3848,9 @@ CheckForSerializableConflictOut(const bool visible, const Relation relation,
}
sxact = sxid->myXact;
Assert(TransactionIdEquals(sxact->topXid, xid));
- if (sxact == MySerializableXact
- || SxactIsRolledBack(sxact)
- || SxactIsMarkedForDeath(sxact))
+ if (sxact == MySerializableXact || SxactIsDoomed(sxact))
{
- /* We can't conflict with our own transaction or one rolled back. */
+ /* Can't conflict with ourself or a transaction that will roll back. */
LWLockRelease(SerializableXactHashLock);
return;
}
@@ -3823,7 +3865,7 @@ CheckForSerializableConflictOut(const bool visible, const Relation relation,
{
if (!SxactIsPrepared(sxact))
{
- sxact->flags |= SXACT_FLAG_MARKED_FOR_DEATH;
+ sxact->flags |= SXACT_FLAG_DOOMED;
LWLockRelease(SerializableXactHashLock);
return;
}
@@ -3950,7 +3992,7 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
mypredlocktag = predlock->tag;
}
}
- else if (!SxactIsRolledBack(sxact)
+ else if (!SxactIsDoomed(sxact)
&& (!SxactIsCommitted(sxact)
|| TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
sxact->finishedBefore))
@@ -3963,7 +4005,7 @@ CheckTargetForConflictsIn(PREDICATELOCKTARGETTAG *targettag)
* Re-check after getting exclusive lock because the other
* transaction may have flagged a conflict.
*/
- if (!SxactIsRolledBack(sxact)
+ if (!SxactIsDoomed(sxact)
&& (!SxactIsCommitted(sxact)
|| TransactionIdPrecedes(GetTransactionSnapshot()->xmin,
sxact->finishedBefore))
@@ -4064,10 +4106,11 @@ CheckForSerializableConflictIn(const Relation relation, const HeapTuple tuple,
{
PREDICATELOCKTARGETTAG targettag;
- if (SkipSerialization(relation))
+ if (!SerializationNeededForWrite(relation))
return;
- if (SxactIsMarkedForDeath(MySerializableXact))
+ /* Check if someone else has already decided that we need to die */
+ if (SxactIsDoomed(MySerializableXact))
ereport(ERROR,
(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),
errmsg("could not serialize access due to read/write dependencies among transactions"),
@@ -4160,7 +4203,7 @@ CheckTableForSerializableConflictIn(const Relation relation)
if (!TransactionIdIsValid(PredXact->SxactGlobalXmin))
return;
- if (SkipSerialization(relation))
+ if (!SerializationNeededForWrite(relation))
return;
/*
@@ -4371,7 +4414,7 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
{
SERIALIZABLEXACT *t0 = conflict->sxactOut;
- if (!SxactIsRolledBack(t0)
+ if (!SxactIsDoomed(t0)
&& (!SxactIsCommitted(t0)
|| t0->commitSeqNo >= writer->commitSeqNo)
&& (!SxactIsReadOnly(t0)
@@ -4418,7 +4461,7 @@ OnConflict_CheckForSerializationFailure(const SERIALIZABLEXACT *reader,
errdetail("Cancelled on conflict out to pivot %u, during read.", writer->topXid),
errhint("The transaction might succeed if retried.")));
}
- writer->flags |= SXACT_FLAG_MARKED_FOR_DEATH;
+ writer->flags |= SXACT_FLAG_DOOMED;
}
}
@@ -4450,7 +4493,8 @@ PreCommit_CheckForSerializationFailure(void)
LWLockAcquire(SerializableXactHashLock, LW_EXCLUSIVE);
- if (SxactIsMarkedForDeath(MySerializableXact))
+ /* Check if someone else has already decided that we need to die */
+ if (SxactIsDoomed(MySerializableXact))
{
LWLockRelease(SerializableXactHashLock);
ereport(ERROR,
@@ -4467,8 +4511,7 @@ PreCommit_CheckForSerializationFailure(void)
while (nearConflict)
{
if (!SxactIsCommitted(nearConflict->sxactOut)
- && !SxactIsRolledBack(nearConflict->sxactOut)
- && !SxactIsMarkedForDeath(nearConflict->sxactOut))
+ && !SxactIsDoomed(nearConflict->sxactOut))
{
RWConflict farConflict;
@@ -4481,10 +4524,9 @@ PreCommit_CheckForSerializationFailure(void)
if (farConflict->sxactOut == MySerializableXact
|| (!SxactIsCommitted(farConflict->sxactOut)
&& !SxactIsReadOnly(farConflict->sxactOut)
- && !SxactIsRolledBack(farConflict->sxactOut)
- && !SxactIsMarkedForDeath(farConflict->sxactOut)))
+ && !SxactIsDoomed(farConflict->sxactOut)))
{
- nearConflict->sxactOut->flags |= SXACT_FLAG_MARKED_FOR_DEATH;
+ nearConflict->sxactOut->flags |= SXACT_FLAG_DOOMED;
break;
}
farConflict = (RWConflict)
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index a43d6e3159..32f418306c 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -369,11 +369,11 @@ static const SchemaQuery Query_for_list_of_updatables = {
NULL
};
-static const SchemaQuery Query_for_list_of_tisvf = {
+static const SchemaQuery Query_for_list_of_relations = {
/* catname */
"pg_catalog.pg_class c",
/* selcondition */
- "c.relkind IN ('r', 'i', 'S', 'v', 'f')",
+ NULL,
/* viscondition */
"pg_catalog.pg_table_is_visible(c.oid)",
/* namespace */
@@ -2826,7 +2826,7 @@ psql_completion(char *text, int start, int end)
/* must be at end of \d list */
else if (strncmp(prev_wd, "\\d", strlen("\\d")) == 0)
- COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tisvf, NULL);
+ COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_relations, NULL);
else if (strcmp(prev_wd, "\\ef") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
diff --git a/src/include/storage/predicate.h b/src/include/storage/predicate.h
index 760c76cff0..aae5326fd8 100644
--- a/src/include/storage/predicate.h
+++ b/src/include/storage/predicate.h
@@ -44,16 +44,17 @@ extern bool PageIsPredicateLocked(const Relation relation, const BlockNumber blk
/* predicate lock maintenance */
extern Snapshot RegisterSerializableTransaction(Snapshot snapshot);
extern void RegisterPredicateLockingXid(const TransactionId xid);
-extern void PredicateLockRelation(const Relation relation);
-extern void PredicateLockPage(const Relation relation, const BlockNumber blkno);
-extern void PredicateLockTuple(const Relation relation, const HeapTuple tuple);
+extern void PredicateLockRelation(const Relation relation, const Snapshot snapshot);
+extern void PredicateLockPage(const Relation relation, const BlockNumber blkno, const Snapshot snapshot);
+extern void PredicateLockTuple(const Relation relation, const HeapTuple tuple, const Snapshot snapshot);
extern void PredicateLockPageSplit(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno);
extern void PredicateLockPageCombine(const Relation relation, const BlockNumber oldblkno, const BlockNumber newblkno);
extern void TransferPredicateLocksToHeapRelation(const Relation relation);
extern void ReleasePredicateLocks(const bool isCommit);
/* conflict detection (may also trigger rollback) */
-extern void CheckForSerializableConflictOut(const bool valid, const Relation relation, const HeapTuple tuple, const Buffer buffer);
+extern void CheckForSerializableConflictOut(const bool valid, const Relation relation, const HeapTuple tuple,
+ const Buffer buffer, const Snapshot snapshot);
extern void CheckForSerializableConflictIn(const Relation relation, const HeapTuple tuple, const Buffer buffer);
extern void CheckTableForSerializableConflictIn(const Relation relation);
diff --git a/src/include/storage/predicate_internals.h b/src/include/storage/predicate_internals.h
index da6e641f4e..b305c6a4c7 100644
--- a/src/include/storage/predicate_internals.h
+++ b/src/include/storage/predicate_internals.h
@@ -90,22 +90,21 @@ typedef struct SERIALIZABLEXACT
int pid; /* pid of associated process */
} SERIALIZABLEXACT;
-#define SXACT_FLAG_ROLLED_BACK 0x00000001
-#define SXACT_FLAG_COMMITTED 0x00000002
+#define SXACT_FLAG_COMMITTED 0x00000001 /* already committed */
+#define SXACT_FLAG_PREPARED 0x00000002 /* about to commit */
+#define SXACT_FLAG_DOOMED 0x00000004 /* will roll back */
/*
* The following flag actually means that the flagged transaction has a
* conflict out *to a transaction which committed ahead of it*. It's hard
* to get that into a name of a reasonable length.
*/
-#define SXACT_FLAG_CONFLICT_OUT 0x00000004
-#define SXACT_FLAG_READ_ONLY 0x00000008
-#define SXACT_FLAG_MARKED_FOR_DEATH 0x00000010
+#define SXACT_FLAG_CONFLICT_OUT 0x00000008
+#define SXACT_FLAG_READ_ONLY 0x00000010
#define SXACT_FLAG_DEFERRABLE_WAITING 0x00000020
#define SXACT_FLAG_RO_SAFE 0x00000040
#define SXACT_FLAG_RO_UNSAFE 0x00000080
#define SXACT_FLAG_SUMMARY_CONFLICT_IN 0x00000100
#define SXACT_FLAG_SUMMARY_CONFLICT_OUT 0x00000200
-#define SXACT_FLAG_PREPARED 0x00000400
/*
* The following types are used to provide an ad hoc list for holding
diff --git a/src/interfaces/ecpg/test/Makefile b/src/interfaces/ecpg/test/Makefile
index 7ee8287cab..2f954c63ce 100644
--- a/src/interfaces/ecpg/test/Makefile
+++ b/src/interfaces/ecpg/test/Makefile
@@ -84,4 +84,4 @@ checktcp: all
./pg_regress --dbname=regress1,connectdb --top-builddir=$(top_builddir) --temp-install=./tmp_check $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule_tcp --create-role=connectuser,connectdb --host=localhost
installcheck: all
- ./pg_regress --psqldir=$(PSQLDIR) --dbname=regress1,connectdb --top-builddir=$(top_builddir) $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule --create-role=connectuser,connectdb
+ ./pg_regress --psqldir="$(PSQLDIR)" --dbname=regress1,connectdb --top-builddir=$(top_builddir) $(pg_regress_locale_flags) $(THREAD) --schedule=$(srcdir)/ecpg_schedule --create-role=connectuser,connectdb
diff --git a/src/test/isolation/Makefile b/src/test/isolation/Makefile
index 7cbcd4b403..0fe8d608cc 100644
--- a/src/test/isolation/Makefile
+++ b/src/test/isolation/Makefile
@@ -73,7 +73,7 @@ maintainer-clean: distclean
rm -f specparse.c specscanner.c
installcheck: all
- ./pg_isolation_regress --psqldir=$(PSQLDIR) --inputdir=$(srcdir) --schedule=$(srcdir)/isolation_schedule
+ ./pg_isolation_regress --psqldir="$(PSQLDIR)" --inputdir=$(srcdir) --schedule=$(srcdir)/isolation_schedule
# We can't support "make check" because isolationtester requires libpq, and
# in fact (on typical platforms using shared libraries) requires libpq to