On 05/16/2014 04:46 PM, Craig Ringer wrote: > > I'll follow up with the patch and a git tree when it's ready, hopefully > tonight.
Here's a rebased version of Simon's original patch that runs on current master. I still need to merge the isolation tests for it merged and sorted out, and after re-reading it I'd like to change "waitMode" into an enum, not just some #defines . Hope it's useful for comparison and ideas. -- Craig Ringer http://www.2ndQuadrant.com/ PostgreSQL Development, 24x7 Support, Training & Services
>From c9532344cdabcde4d1992659ec8be8ad4b0041ce Mon Sep 17 00:00:00 2001 From: Craig Ringer <cr...@2ndquadrant.com> Date: Wed, 31 Jul 2013 18:37:46 +0800 Subject: [PATCH] implement FOR UPDATE SKIP LOCKED --- src/backend/access/heap/heapam.c | 54 ++++++++++++++++++++----------- src/backend/executor/execMain.c | 2 +- src/backend/executor/nodeLockRows.c | 20 +++++++++++- src/backend/nodes/copyfuncs.c | 6 ++-- src/backend/nodes/equalfuncs.c | 4 +-- src/backend/nodes/outfuncs.c | 6 ++-- src/backend/nodes/readfuncs.c | 2 +- src/backend/optimizer/plan/planner.c | 4 +-- src/backend/optimizer/prep/prepsecurity.c | 8 ++--- src/backend/optimizer/prep/prepunion.c | 2 +- src/backend/parser/analyze.c | 17 +++++----- src/backend/parser/gram.y | 23 ++++++++----- src/backend/rewrite/rewriteHandler.c | 18 +++++------ src/backend/utils/adt/ruleutils.c | 4 ++- src/include/access/heapam.h | 2 +- src/include/nodes/execnodes.h | 5 ++- src/include/nodes/parsenodes.h | 4 +-- src/include/nodes/plannodes.h | 2 +- src/include/parser/analyze.h | 2 +- src/include/parser/kwlist.h | 2 ++ 20 files changed, 118 insertions(+), 69 deletions(-) diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index b77c32c..8e7f2bf 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -56,6 +56,7 @@ #include "catalog/namespace.h" #include "miscadmin.h" #include "pgstat.h" +#include "nodes/execnodes.h" #include "storage/bufmgr.h" #include "storage/freespace.h" #include "storage/lmgr.h" @@ -4081,7 +4082,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 - * nowait: if true, ereport rather than blocking if lock not available + * waitMode: mode describes handling of lock waits * follow_updates: if true, follow the update chain to also lock descendant * tuples. * @@ -4105,7 +4106,7 @@ get_mxact_status_for_lock(LockTupleMode mode, bool is_update) */ HTSU_Result heap_lock_tuple(Relation relation, HeapTuple tuple, - CommandId cid, LockTupleMode mode, bool nowait, + CommandId cid, LockTupleMode mode, int waitMode, bool follow_updates, Buffer *buffer, HeapUpdateFailureData *hufd) { @@ -4208,16 +4209,21 @@ l3: */ if (!have_tuple_lock) { - if (nowait) + if (waitMode == WAITMODE_NORMAL) + LockTupleTuplock(relation, tid, mode); + else { if (!ConditionalLockTupleTuplock(relation, tid, mode)) - ereport(ERROR, + { + if (waitMode == WAITMODE_SKIP_LOCKED) + return result; + else if (waitMode == WAITMODE_NOWAIT) + ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), - errmsg("could not obtain lock on row in relation \"%s\"", - RelationGetRelationName(relation)))); + errmsg("could not obtain lock on row in relation \"%s\"", + RelationGetRelationName(relation)))); + } } - else - LockTupleTuplock(relation, tid, mode); have_tuple_lock = true; } @@ -4419,21 +4425,26 @@ l3: elog(ERROR, "invalid lock mode in heap_lock_tuple"); /* wait for multixact to end */ - if (nowait) + if (waitMode == WAITMODE_NORMAL) + MultiXactIdWait((MultiXactId) xwait, status, infomask, + relation, &tuple->t_data->t_ctid, + XLTW_Lock, NULL); + else { if (!ConditionalMultiXactIdWait((MultiXactId) xwait, status, infomask, relation, &tuple->t_data->t_ctid, XLTW_Lock, NULL)) - ereport(ERROR, + { + if (waitMode == WAITMODE_SKIP_LOCKED) + return result; + else if (waitMode == WAITMODE_NOWAIT) + ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("could not obtain lock on row in relation \"%s\"", RelationGetRelationName(relation)))); + } } - else - MultiXactIdWait((MultiXactId) xwait, status, infomask, - relation, &tuple->t_data->t_ctid, - XLTW_Lock, NULL); /* if there are updates, follow the update chain */ if (follow_updates && @@ -4479,17 +4490,22 @@ l3: else { /* wait for regular transaction to end */ - if (nowait) + if (waitMode == WAITMODE_NORMAL) + XactLockTableWait(xwait, relation, &tuple->t_data->t_ctid, + XLTW_Lock); + else { if (!ConditionalXactLockTableWait(xwait)) - ereport(ERROR, + { + if (waitMode == WAITMODE_SKIP_LOCKED) + return result; + else if (waitMode == WAITMODE_NOWAIT) + ereport(ERROR, (errcode(ERRCODE_LOCK_NOT_AVAILABLE), errmsg("could not obtain lock on row in relation \"%s\"", RelationGetRelationName(relation)))); + } } - else - XactLockTableWait(xwait, relation, &tuple->t_data->t_ctid, - XLTW_Lock); /* if there are updates, follow the update chain */ if (follow_updates && diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 072c7df..896fba6 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -830,7 +830,7 @@ InitPlan(QueryDesc *queryDesc, int eflags) erm->prti = rc->prti; erm->rowmarkId = rc->rowmarkId; erm->markType = rc->markType; - erm->noWait = rc->noWait; + erm->waitMode = rc->waitMode; ItemPointerSetInvalid(&(erm->curCtid)); estate->es_rowMarks = lappend(estate->es_rowMarks, erm); } diff --git a/src/backend/executor/nodeLockRows.c b/src/backend/executor/nodeLockRows.c index 298d4b4..3384981 100644 --- a/src/backend/executor/nodeLockRows.c +++ b/src/backend/executor/nodeLockRows.c @@ -133,7 +133,7 @@ lnext: test = heap_lock_tuple(erm->relation, &tuple, estate->es_output_cid, - lockmode, erm->noWait, true, + lockmode, erm->waitMode, true, &buffer, &hufd); ReleaseBuffer(buffer); switch (test) @@ -197,6 +197,24 @@ lnext: /* Continue loop until we have all target tuples */ break; + case HeapTupleBeingUpdated: + if (IsolationUsesXactSnapshot()) + ereport(ERROR, + (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE), + errmsg("could not serialize access due to concurrent update"))); + /* + * If we were skipping locks this result + * was expected, so we simply skip the + * whole row completely. Note that this + * behaviour means we get different + * results from this depending upon + * concurrent activity. + * + * Otherwise fall thru to an ERROR. + */ + if (erm->waitMode == WAITMODE_SKIP_LOCKED) + goto lnext; + default: elog(ERROR, "unrecognized heap_lock_tuple status: %u", test); diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 43530aa..fb2b4f5 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -959,7 +959,7 @@ _copyPlanRowMark(const PlanRowMark *from) COPY_SCALAR_FIELD(prti); COPY_SCALAR_FIELD(rowmarkId); COPY_SCALAR_FIELD(markType); - COPY_SCALAR_FIELD(noWait); + COPY_SCALAR_FIELD(waitMode); COPY_SCALAR_FIELD(isParent); return newnode; @@ -2070,7 +2070,7 @@ _copyRowMarkClause(const RowMarkClause *from) COPY_SCALAR_FIELD(rti); COPY_SCALAR_FIELD(strength); - COPY_SCALAR_FIELD(noWait); + COPY_SCALAR_FIELD(waitMode); COPY_SCALAR_FIELD(pushedDown); return newnode; @@ -2439,7 +2439,7 @@ _copyLockingClause(const LockingClause *from) COPY_NODE_FIELD(lockedRels); COPY_SCALAR_FIELD(strength); - COPY_SCALAR_FIELD(noWait); + COPY_SCALAR_FIELD(waitMode); return newnode; } diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 2407cb7..bee38c0 100644 --- a/src/backend/nodes/equalfuncs.c +++ b/src/backend/nodes/equalfuncs.c @@ -2262,7 +2262,7 @@ _equalLockingClause(const LockingClause *a, const LockingClause *b) { COMPARE_NODE_FIELD(lockedRels); COMPARE_SCALAR_FIELD(strength); - COMPARE_SCALAR_FIELD(noWait); + COMPARE_SCALAR_FIELD(waitMode); return true; } @@ -2358,7 +2358,7 @@ _equalRowMarkClause(const RowMarkClause *a, const RowMarkClause *b) { COMPARE_SCALAR_FIELD(rti); COMPARE_SCALAR_FIELD(strength); - COMPARE_SCALAR_FIELD(noWait); + COMPARE_SCALAR_FIELD(waitMode); COMPARE_SCALAR_FIELD(pushedDown); return true; diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 11c7486..c5c1d22 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -836,7 +836,7 @@ _outPlanRowMark(StringInfo str, const PlanRowMark *node) WRITE_UINT_FIELD(prti); WRITE_UINT_FIELD(rowmarkId); WRITE_ENUM_FIELD(markType, RowMarkType); - WRITE_BOOL_FIELD(noWait); + WRITE_INT_FIELD(waitMode); WRITE_BOOL_FIELD(isParent); } @@ -2121,7 +2121,7 @@ _outLockingClause(StringInfo str, const LockingClause *node) WRITE_NODE_FIELD(lockedRels); WRITE_ENUM_FIELD(strength, LockClauseStrength); - WRITE_BOOL_FIELD(noWait); + WRITE_INT_FIELD(waitMode); } static void @@ -2311,7 +2311,7 @@ _outRowMarkClause(StringInfo str, const RowMarkClause *node) WRITE_UINT_FIELD(rti); WRITE_ENUM_FIELD(strength, LockClauseStrength); - WRITE_BOOL_FIELD(noWait); + WRITE_INT_FIELD(waitMode); WRITE_BOOL_FIELD(pushedDown); } diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 1ec4f3c..6be54d5 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -320,7 +320,7 @@ _readRowMarkClause(void) READ_UINT_FIELD(rti); READ_ENUM_FIELD(strength, LockClauseStrength); - READ_BOOL_FIELD(noWait); + READ_INT_FIELD(waitMode); READ_BOOL_FIELD(pushedDown); READ_DONE(); diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 0f1e2e4..fc12292 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -2228,7 +2228,7 @@ preprocess_rowmarks(PlannerInfo *root) newrc->markType = ROW_MARK_KEYSHARE; break; } - newrc->noWait = rc->noWait; + newrc->waitMode = rc->waitMode; newrc->isParent = false; prowmarks = lappend(prowmarks, newrc); @@ -2256,7 +2256,7 @@ preprocess_rowmarks(PlannerInfo *root) newrc->markType = ROW_MARK_REFERENCE; else newrc->markType = ROW_MARK_COPY; - newrc->noWait = false; /* doesn't matter */ + newrc->waitMode = 0; /* doesn't matter (but 0 is NORMAL) */ newrc->isParent = false; prowmarks = lappend(prowmarks, newrc); diff --git a/src/backend/optimizer/prep/prepsecurity.c b/src/backend/optimizer/prep/prepsecurity.c index dd7f900..0b4add8 100644 --- a/src/backend/optimizer/prep/prepsecurity.c +++ b/src/backend/optimizer/prep/prepsecurity.c @@ -233,19 +233,19 @@ expand_security_qual(PlannerInfo *root, List *tlist, int rt_index, { case ROW_MARK_EXCLUSIVE: applyLockingClause(subquery, 1, LCS_FORUPDATE, - rc->noWait, false); + rc->waitMode, false); break; case ROW_MARK_NOKEYEXCLUSIVE: applyLockingClause(subquery, 1, LCS_FORNOKEYUPDATE, - rc->noWait, false); + rc->waitMode, false); break; case ROW_MARK_SHARE: applyLockingClause(subquery, 1, LCS_FORSHARE, - rc->noWait, false); + rc->waitMode, false); break; case ROW_MARK_KEYSHARE: applyLockingClause(subquery, 1, LCS_FORKEYSHARE, - rc->noWait, false); + rc->waitMode, false); break; case ROW_MARK_REFERENCE: case ROW_MARK_COPY: diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index 0410fdd..fa7c806 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -1389,7 +1389,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti) newrc->prti = rti; newrc->rowmarkId = oldrc->rowmarkId; newrc->markType = oldrc->markType; - newrc->noWait = oldrc->noWait; + newrc->waitMode = oldrc->waitMode; newrc->isParent = false; root->rowMarks = lappend(root->rowMarks, newrc); diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index fb6c44c..5062a62 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -2358,13 +2358,14 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, allrels = makeNode(LockingClause); allrels->lockedRels = NIL; /* indicates all rels */ allrels->strength = lc->strength; - allrels->noWait = lc->noWait; + allrels->waitMode = lc->waitMode; if (lockedRels == NIL) { /* all regular tables used in query */ i = 0; foreach(rt, qry->rtable) + { RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt); @@ -2373,12 +2374,12 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, { case RTE_RELATION: applyLockingClause(qry, i, - lc->strength, lc->noWait, pushedDown); + lc->strength, lc->waitMode, pushedDown); rte->requiredPerms |= ACL_SELECT_FOR_UPDATE; break; case RTE_SUBQUERY: applyLockingClause(qry, i, - lc->strength, lc->noWait, pushedDown); + lc->strength, lc->waitMode, pushedDown); /* * FOR UPDATE/SHARE of subquery is propagated to all of @@ -2425,13 +2426,13 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, { case RTE_RELATION: applyLockingClause(qry, i, - lc->strength, lc->noWait, + lc->strength, lc->waitMode, pushedDown); rte->requiredPerms |= ACL_SELECT_FOR_UPDATE; break; case RTE_SUBQUERY: applyLockingClause(qry, i, - lc->strength, lc->noWait, + lc->strength, lc->waitMode, pushedDown); /* see comment above */ transformLockingClause(pstate, rte->subquery, @@ -2499,7 +2500,7 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc, */ void applyLockingClause(Query *qry, Index rtindex, - LockClauseStrength strength, bool noWait, bool pushedDown) + LockClauseStrength strength, int waitMode, bool pushedDown) { RowMarkClause *rc; @@ -2524,7 +2525,7 @@ applyLockingClause(Query *qry, Index rtindex, * And of course pushedDown becomes false if any clause is explicit. */ rc->strength = Max(rc->strength, strength); - rc->noWait |= noWait; + rc->waitMode |= waitMode; rc->pushedDown &= pushedDown; return; } @@ -2533,7 +2534,7 @@ applyLockingClause(Query *qry, Index rtindex, rc = makeNode(RowMarkClause); rc->rti = rtindex; rc->strength = strength; - rc->noWait = noWait; + rc->waitMode = waitMode; rc->pushedDown = pushedDown; qry->rowMarks = lappend(qry->rowMarks, rc); } diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 7b9895d..30596cd 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -268,11 +268,11 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); transaction_mode_item create_extension_opt_item alter_extension_opt_item -%type <ival> opt_lock lock_type cast_context +%type <ival> opt_lock lock_type opt_nowait opt_waitmode cast_context %type <ival> vacuum_option_list vacuum_option_elem %type <boolean> opt_force opt_or_replace opt_grant_grant_option opt_grant_admin_option - opt_nowait opt_if_exists opt_with_data + opt_if_exists opt_with_data %type <list> OptRoleList AlterOptRoleList %type <defelt> CreateOptRoleElem AlterOptRoleElem @@ -563,7 +563,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); LABEL LANGUAGE LARGE_P LAST_P LATERAL_P LC_COLLATE_P LC_CTYPE_P LEADING LEAKPROOF LEAST LEFT LEVEL LIKE LIMIT LISTEN LOAD LOCAL - LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P + LOCALTIME LOCALTIMESTAMP LOCATION LOCK_P LOCKED MAPPING MATCH MATERIALIZED MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE @@ -587,7 +587,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query); SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE SEQUENCES SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF SHARE - SHOW SIMILAR SIMPLE SMALLINT SNAPSHOT SOME STABLE STANDALONE_P START + SHOW SIMILAR SIMPLE SKIP SMALLINT SNAPSHOT SOME STABLE STANDALONE_P START STATEMENT STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SYMMETRIC SYSID SYSTEM_P @@ -9184,10 +9184,15 @@ lock_type: ACCESS SHARE { $$ = AccessShareLock; } | ACCESS EXCLUSIVE { $$ = AccessExclusiveLock; } ; -opt_nowait: NOWAIT { $$ = TRUE; } - | /*EMPTY*/ { $$ = FALSE; } +opt_nowait: NOWAIT { $$ = WAITMODE_NOWAIT; } + | /*EMPTY*/ { $$ = WAITMODE_NORMAL; } ; +opt_waitmode: + NOWAIT { $$ = WAITMODE_NOWAIT; } + | SKIP LOCKED { $$ = WAITMODE_SKIP_LOCKED; } + | /*EMPTY*/ { $$ = WAITMODE_NORMAL; } + ; /***************************************************************************** * @@ -9790,12 +9795,12 @@ for_locking_items: ; for_locking_item: - for_locking_strength locked_rels_list opt_nowait + for_locking_strength locked_rels_list opt_waitmode { LockingClause *n = makeNode(LockingClause); n->lockedRels = $2; n->strength = $1; - n->noWait = $3; + n->waitMode = $3; $$ = (Node *) n; } ; @@ -12921,6 +12926,7 @@ unreserved_keyword: | LOCAL | LOCATION | LOCK_P + | LOCKED | MAPPING | MATCH | MATERIALIZED @@ -13003,6 +13009,7 @@ unreserved_keyword: | SHARE | SHOW | SIMPLE + | SKIP | SNAPSHOT | STABLE | STANDALONE_P diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index e6c5530..f7ad6b1 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -62,7 +62,7 @@ static void rewriteValuesRTE(RangeTblEntry *rte, Relation target_relation, static void rewriteTargetListUD(Query *parsetree, RangeTblEntry *target_rte, Relation target_relation); static void markQueryForLocking(Query *qry, Node *jtnode, - LockClauseStrength strength, bool noWait, bool pushedDown); + LockClauseStrength strength, int waitMode, bool pushedDown); static List *matchLocks(CmdType event, RuleLock *rulelocks, int varno, Query *parsetree); static Query *fireRIRrules(Query *parsetree, List *activeRIRs, @@ -1481,7 +1481,7 @@ ApplyRetrieveRule(Query *parsetree, */ if (rc != NULL) markQueryForLocking(rule_action, (Node *) rule_action->jointree, - rc->strength, rc->noWait, true); + rc->strength, rc->waitMode, true); return parsetree; } @@ -1499,7 +1499,7 @@ ApplyRetrieveRule(Query *parsetree, */ static void markQueryForLocking(Query *qry, Node *jtnode, - LockClauseStrength strength, bool noWait, bool pushedDown) + LockClauseStrength strength, int waitMode, bool pushedDown) { if (jtnode == NULL) return; @@ -1510,15 +1510,15 @@ markQueryForLocking(Query *qry, Node *jtnode, if (rte->rtekind == RTE_RELATION) { - applyLockingClause(qry, rti, strength, noWait, pushedDown); + applyLockingClause(qry, rti, strength, waitMode, pushedDown); rte->requiredPerms |= ACL_SELECT_FOR_UPDATE; } else if (rte->rtekind == RTE_SUBQUERY) { - applyLockingClause(qry, rti, strength, noWait, pushedDown); + applyLockingClause(qry, rti, strength, waitMode, pushedDown); /* FOR UPDATE/SHARE of subquery is propagated to subquery's rels */ markQueryForLocking(rte->subquery, (Node *) rte->subquery->jointree, - strength, noWait, true); + strength, waitMode, true); } /* other RTE types are unaffected by FOR UPDATE */ } @@ -1528,14 +1528,14 @@ markQueryForLocking(Query *qry, Node *jtnode, ListCell *l; foreach(l, f->fromlist) - markQueryForLocking(qry, lfirst(l), strength, noWait, pushedDown); + markQueryForLocking(qry, lfirst(l), strength, waitMode, pushedDown); } else if (IsA(jtnode, JoinExpr)) { JoinExpr *j = (JoinExpr *) jtnode; - markQueryForLocking(qry, j->larg, strength, noWait, pushedDown); - markQueryForLocking(qry, j->rarg, strength, noWait, pushedDown); + markQueryForLocking(qry, j->larg, strength, waitMode, pushedDown); + markQueryForLocking(qry, j->rarg, strength, waitMode, pushedDown); } else elog(ERROR, "unrecognized node type: %d", diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index a30d8fe..50ec077 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -4437,8 +4437,10 @@ get_select_query_def(Query *query, deparse_context *context, appendStringInfo(buf, " OF %s", quote_identifier(get_rtable_name(rc->rti, context))); - if (rc->noWait) + if (rc->waitMode == WAITMODE_NOWAIT) appendStringInfoString(buf, " NOWAIT"); + else if (rc->waitMode == WAITMODE_SKIP_LOCKED) + appendStringInfoString(buf, " SKIP LOCKED"); } } diff --git a/src/include/access/heapam.h b/src/include/access/heapam.h index 493839f..c09b75f 100644 --- a/src/include/access/heapam.h +++ b/src/include/access/heapam.h @@ -144,7 +144,7 @@ extern HTSU_Result heap_update(Relation relation, ItemPointer otid, CommandId cid, Snapshot crosscheck, bool wait, HeapUpdateFailureData *hufd, LockTupleMode *lockmode); extern HTSU_Result heap_lock_tuple(Relation relation, HeapTuple tuple, - CommandId cid, LockTupleMode mode, bool nowait, + CommandId cid, LockTupleMode mode, int waitMode, bool follow_update, Buffer *buffer, HeapUpdateFailureData *hufd); extern void heap_inplace_update(Relation relation, HeapTuple tuple); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 0ab2a13..e05bf38 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -429,9 +429,12 @@ typedef struct ExecRowMark Index prti; /* parent range table index, if child */ Index rowmarkId; /* unique identifier for resjunk columns */ RowMarkType markType; /* see enum in nodes/plannodes.h */ - bool noWait; /* NOWAIT option */ + int waitMode; /* NOWAIT and SKIP LOCKED options */ ItemPointerData curCtid; /* ctid of currently locked tuple, if any */ } ExecRowMark; +#define WAITMODE_NORMAL 0 +#define WAITMODE_NOWAIT 1 +#define WAITMODE_SKIP_LOCKED 2 /* * ExecAuxRowMark - diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 7e560a1..ea358e9 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -616,7 +616,7 @@ typedef struct LockingClause NodeTag type; List *lockedRels; /* FOR [KEY] UPDATE/SHARE relations */ LockClauseStrength strength; - bool noWait; /* NOWAIT option */ + int waitMode; /* e.g. NOWAIT */ } LockingClause; /* @@ -961,7 +961,7 @@ typedef struct RowMarkClause NodeTag type; Index rti; /* range table index of target relation */ LockClauseStrength strength; - bool noWait; /* NOWAIT option */ + int waitMode; /* e.g. NOWAIT */ bool pushedDown; /* pushed down from higher query level? */ } RowMarkClause; diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 3b9c683..b9c1fa7 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -831,7 +831,7 @@ typedef struct PlanRowMark Index prti; /* range table index of parent relation */ Index rowmarkId; /* unique identifier for resjunk columns */ RowMarkType markType; /* see enum above */ - bool noWait; /* NOWAIT option */ + int waitMode; /* NOWAIT option */ bool isParent; /* true if this is a "dummy" parent entry */ } PlanRowMark; diff --git a/src/include/parser/analyze.h b/src/include/parser/analyze.h index 370a445..74e3825 100644 --- a/src/include/parser/analyze.h +++ b/src/include/parser/analyze.h @@ -39,6 +39,6 @@ extern bool analyze_requires_snapshot(Node *parseTree); extern char *LCS_asString(LockClauseStrength strength); extern void CheckSelectLocking(Query *qry, LockClauseStrength strength); extern void applyLockingClause(Query *qry, Index rtindex, - LockClauseStrength strength, bool noWait, bool pushedDown); + LockClauseStrength strength, int waitMode, bool pushedDown); #endif /* ANALYZE_H */ diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h index 61fae22..969c27c 100644 --- a/src/include/parser/kwlist.h +++ b/src/include/parser/kwlist.h @@ -231,6 +231,7 @@ PG_KEYWORD("localtime", LOCALTIME, RESERVED_KEYWORD) PG_KEYWORD("localtimestamp", LOCALTIMESTAMP, RESERVED_KEYWORD) PG_KEYWORD("location", LOCATION, UNRESERVED_KEYWORD) PG_KEYWORD("lock", LOCK_P, UNRESERVED_KEYWORD) +PG_KEYWORD("locked", LOCKED, UNRESERVED_KEYWORD) PG_KEYWORD("mapping", MAPPING, UNRESERVED_KEYWORD) PG_KEYWORD("match", MATCH, UNRESERVED_KEYWORD) PG_KEYWORD("materialized", MATERIALIZED, UNRESERVED_KEYWORD) @@ -344,6 +345,7 @@ PG_KEYWORD("share", SHARE, UNRESERVED_KEYWORD) PG_KEYWORD("show", SHOW, UNRESERVED_KEYWORD) PG_KEYWORD("similar", SIMILAR, TYPE_FUNC_NAME_KEYWORD) PG_KEYWORD("simple", SIMPLE, UNRESERVED_KEYWORD) +PG_KEYWORD("skip", SKIP, UNRESERVED_KEYWORD) PG_KEYWORD("smallint", SMALLINT, COL_NAME_KEYWORD) PG_KEYWORD("snapshot", SNAPSHOT, UNRESERVED_KEYWORD) PG_KEYWORD("some", SOME, RESERVED_KEYWORD) -- 1.9.0
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers