Robert Haas wrote:
> On Wed, Sep 10, 2014 at 9:47 AM, Alvaro Herrera
> <[email protected]> wrote:
> > I attach some additional minor suggestions to your patch.
>
> I don't see any attachment.
Uh. Here it is.
--
Álvaro Herrera http://www.2ndQuadrant.com/
PostgreSQL Development, 24x7 Support, Training & Services
diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c
index 51d1889..2b336b0 100644
--- a/src/backend/access/heap/heapam.c
+++ b/src/backend/access/heap/heapam.c
@@ -4090,7 +4090,7 @@ get_mxact_status_for_lock(LockTupleMode mode, bool is_update)
* cid: current command ID (used for visibility test, and stored into
* tuple's cmax if lock is successful)
* mode: indicates if shared or exclusive tuple lock is desired
- * wait_policy: whether to block, ereport or skip if lock not available
+ * wait_policy: what to do if tuple lock is not available
* follow_updates: if true, follow the update chain to also lock descendant
* tuples.
*
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index e4065c2..a718c0b 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1928,6 +1928,9 @@ EvalPlanQual(EState *estate, EPQState *epqstate,
*
* Returns a palloc'd copy of the newest tuple version, or NULL if we find
* that there is no newest version (ie, the row was deleted not updated).
+ * We also return NULL if the tuple is locked and the wait policy is to skip
+ * such tuples.
+ *
* If successful, we have locked the newest tuple version, so caller does not
* need to worry about it changing anymore.
*
@@ -1994,7 +1997,7 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
break;
case LockWaitSkip:
if (!ConditionalXactLockTableWait(SnapshotDirty.xmax))
- return NULL; /* skipping instead of waiting */
+ return NULL; /* skip instead of waiting */
break;
case LockWaitError:
if (!ConditionalXactLockTableWait(SnapshotDirty.xmax))
@@ -2076,6 +2079,10 @@ EvalPlanQualFetch(EState *estate, Relation relation, int lockmode,
/* tuple was deleted, so give up */
return NULL;
+ case HeapTupleWouldBlock:
+ elog(WARNING, "this is an odd case");
+ return NULL;
+
default:
ReleaseBuffer(buffer);
elog(ERROR, "unrecognized heap_lock_tuple status: %u",
diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c
index f9feff4..990240b 100644
--- a/src/backend/executor/nodeLockRows.c
+++ b/src/backend/executor/nodeLockRows.c
@@ -179,7 +179,10 @@ lnext:
if (copyTuple == NULL)
{
- /* Tuple was deleted or skipped (in SKIP LOCKED), so don't return it */
+ /*
+ * Tuple was deleted; or it's locked and we're under SKIP
+ * LOCKED policy, so don't return it
+ */
goto lnext;
}
/* remember the actually locked tuple's TID */
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 0f6e9b0..1f66928 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -2515,11 +2515,12 @@ applyLockingClause(Query *qry, Index rtindex,
* a shared and exclusive lock at the same time; it'll end up being
* exclusive anyway.)
*
- * We also consider that NOWAIT wins if it is specified multiple ways,
- * otherwise SKIP LOCKED wins. This is a bit more debatable but
- * raising an error doesn't seem helpful. (Consider for instance
- * SELECT FOR UPDATE NOWAIT from a view that internally contains a
- * plain FOR UPDATE spec.)
+ * Similarly, if the same RTE is specified with more than one lock wait
+ * policy, consider that NOWAIT wins over SKIP LOCKED, which in turn
+ * wins over waiting for the lock (the default). This is a bit more
+ * debatable but raising an error doesn't seem helpful. (Consider for
+ * instance SELECT FOR UPDATE NOWAIT from a view that internally
+ * contains a plain FOR UPDATE spec.)
*
* And of course pushedDown becomes false if any clause is explicit.
*/
diff --git a/src/include/utils/lockwaitpolicy.h b/src/include/utils/lockwaitpolicy.h
index f8ad07e..7f9a693 100644
--- a/src/include/utils/lockwaitpolicy.h
+++ b/src/include/utils/lockwaitpolicy.h
@@ -1,34 +1,31 @@
/*-------------------------------------------------------------------------
- *
* lockwaitpolicy.h
- * Header file for the enum LockWaitPolicy enum, which is needed in
- * several modules (parser, planner, executor, heap manager).
+ * Header file for LockWaitPolicy enum.
*
* Copyright (c) 2014, PostgreSQL Global Development Group
*
* src/include/utils/lockwaitpolicy.h
- *
*-------------------------------------------------------------------------
*/
#ifndef LOCKWAITPOLICY_H
#define LOCKWAITPOLICY_H
/*
- * Policy for what to do when a row lock cannot be obtained immediately.
- *
- * The enum values defined here control how the parser treats multiple FOR
- * UPDATE/SHARE clauses that affect the same table. If multiple locking
- * clauses are defined then the one with the highest numerical value takes
- * precedence -- see applyLockingClause.
+ * This enum controls how to deal with rows being locked by FOR UPDATE/SHARE
+ * clauses (i.e., NOWAIT and SKIP LOCKED clauses). The ordering here is
+ * important, because the highest numerical value will takes precedence when a
+ * RTE is specified multiple ways. See applyLockingClause.
*/
typedef enum
{
- /* Wait for the lock to become available */
- LockWaitBlock = 1,
- /* SELECT FOR UPDATE SKIP LOCKED, skipping rows that can't be locked */
- LockWaitSkip = 2,
- /* SELECT FOR UPDATE NOWAIT, abandoning the transaction */
- LockWaitError = 3
+ /* Wait for the lock to become available (default behavior) */
+ LockWaitBlock,
+
+ /* Skip rows that can't be locked (SKIP LOCKED) */
+ LockWaitSkip,
+
+ /* Raise an error if a row cannot be locked (NOWAIT) */
+ LockWaitError
} LockWaitPolicy;
#endif /* LOCKWAITPOLICY_H */
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers