aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c58
-rw-r--r--src/backend/parser/gram.y29
2 files changed, 44 insertions, 43 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 5aa6ecce7b3..ede41af6dbc 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -2139,7 +2139,7 @@ transformCreateTableAsStmt(ParseState *pstate, CreateTableAsStmt *stmt)
/*
- * Check for features that are not supported together with FOR UPDATE/SHARE.
+ * Check for features that are not supported together with FOR [KEY] UPDATE/SHARE.
*
* exported so planner can check again after rewriting, query pullup, etc
*/
@@ -2149,35 +2149,35 @@ CheckSelectLocking(Query *qry)
if (qry->setOperations)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
+ errmsg("SELECT FOR UPDATE/SHARE/FOR KEY UPDATE/FOR KEY SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
if (qry->distinctClause != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE is not allowed with DISTINCT clause")));
+ errmsg("SELECT FOR UPDATE/SHARE/FOR KEY UPDATE/FOR KEY SHARE is not allowed with DISTINCT clause")));
if (qry->groupClause != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE is not allowed with GROUP BY clause")));
+ errmsg("SELECT FOR UPDATE/SHARE/FOR KEY UPDATE/FOR KEY SHARE is not allowed with GROUP BY clause")));
if (qry->havingQual != NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE is not allowed with HAVING clause")));
+ errmsg("SELECT FOR UPDATE/SHARE/FOR KEY UPDATE/FOR KEY SHARE is not allowed with HAVING clause")));
if (qry->hasAggs)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE is not allowed with aggregate functions")));
+ errmsg("SELECT FOR UPDATE/SHARE/FOR KEY UPDATE/FOR KEY SHARE is not allowed with aggregate functions")));
if (qry->hasWindowFuncs)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE is not allowed with window functions")));
+ errmsg("SELECT FOR UPDATE/SHARE/FOR KEY UPDATE/FOR KEY SHARE is not allowed with window functions")));
if (expression_returns_set((Node *) qry->targetList))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE is not allowed with set-returning functions in the target list")));
+ errmsg("SELECT FOR UPDATE/SHARE/FOR KEY UPDATE/FOR KEY SHARE is not allowed with set-returning functions in the target list")));
}
/*
- * Transform a FOR UPDATE/SHARE clause
+ * Transform a FOR [KEY] UPDATE/SHARE clause
*
* This basically involves replacing names by integer relids.
*
@@ -2199,7 +2199,7 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
/* make a clause we can pass down to subqueries to select all rels */
allrels = makeNode(LockingClause);
allrels->lockedRels = NIL; /* indicates all rels */
- allrels->forUpdate = lc->forUpdate;
+ allrels->strength = lc->strength;
allrels->noWait = lc->noWait;
if (lockedRels == NIL)
@@ -2218,15 +2218,15 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
if (rte->relkind == RELKIND_FOREIGN_TABLE)
break;
applyLockingClause(qry, i,
- lc->forUpdate, lc->noWait, pushedDown);
+ lc->strength, lc->noWait, pushedDown);
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
break;
case RTE_SUBQUERY:
applyLockingClause(qry, i,
- lc->forUpdate, lc->noWait, pushedDown);
+ lc->strength, lc->noWait, pushedDown);
/*
- * FOR UPDATE/SHARE of subquery is propagated to all of
+ * FOR [KEY] UPDATE/SHARE of subquery is propagated to all of
* subquery's rels, too. We could do this later (based on
* the marking of the subquery RTE) but it is convenient
* to have local knowledge in each query level about which
@@ -2252,7 +2252,7 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
if (thisrel->catalogname || thisrel->schemaname)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("SELECT FOR UPDATE/SHARE must specify unqualified relation names"),
+ errmsg("SELECT FOR UPDATE/SHARE/KEY UPDATE/KEY SHARE must specify unqualified relation names"),
parser_errposition(pstate, thisrel->location)));
i = 0;
@@ -2269,17 +2269,17 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
if (rte->relkind == RELKIND_FOREIGN_TABLE)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE cannot be used with foreign table \"%s\"",
+ errmsg("SELECT FOR UPDATE/SHARE/KEY UPDATE/KEY SHARE cannot be used with foreign table \"%s\"",
rte->eref->aliasname),
parser_errposition(pstate, thisrel->location)));
applyLockingClause(qry, i,
- lc->forUpdate, lc->noWait,
+ lc->strength, lc->noWait,
pushedDown);
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
break;
case RTE_SUBQUERY:
applyLockingClause(qry, i,
- lc->forUpdate, lc->noWait,
+ lc->strength, lc->noWait,
pushedDown);
/* see comment above */
transformLockingClause(pstate, rte->subquery,
@@ -2288,25 +2288,25 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
case RTE_JOIN:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a join"),
+ errmsg("SELECT FOR UPDATE/SHARE/KEY UPDATE/KEY SHARE cannot be applied to a join"),
parser_errposition(pstate, thisrel->location)));
break;
case RTE_FUNCTION:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a function"),
+ errmsg("SELECT FOR UPDATE/SHARE/KEY UPDATE/KEY SHARE cannot be applied to a function"),
parser_errposition(pstate, thisrel->location)));
break;
case RTE_VALUES:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE cannot be applied to VALUES"),
+ errmsg("SELECT FOR UPDATE/SHARE/KEY UPDATE/KEY SHARE cannot be applied to VALUES"),
parser_errposition(pstate, thisrel->location)));
break;
case RTE_CTE:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a WITH query"),
+ errmsg("SELECT FOR UPDATE/SHARE/KEY UPDATE/KEY SHARE cannot be applied to a WITH query"),
parser_errposition(pstate, thisrel->location)));
break;
default:
@@ -2320,7 +2320,7 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
if (rt == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
- errmsg("relation \"%s\" in FOR UPDATE/SHARE clause not found in FROM clause",
+ errmsg("relation \"%s\" in FOR UPDATE/SHARE/KEY UPDATE/KEY SHARE clause not found in FROM clause",
thisrel->relname),
parser_errposition(pstate, thisrel->location)));
}
@@ -2332,7 +2332,7 @@ transformLockingClause(ParseState *pstate, Query *qry, LockingClause *lc,
*/
void
applyLockingClause(Query *qry, Index rtindex,
- bool forUpdate, bool noWait, bool pushedDown)
+ LockClauseStrength strength, bool noWait, bool pushedDown)
{
RowMarkClause *rc;
@@ -2344,10 +2344,10 @@ applyLockingClause(Query *qry, Index rtindex,
if ((rc = get_parse_rowmark(qry, rtindex)) != NULL)
{
/*
- * If the same RTE is specified both FOR UPDATE and FOR SHARE, treat
- * it as FOR UPDATE. (Reasonable, since you can't take both a shared
- * and exclusive lock at the same time; it'll end up being exclusive
- * anyway.)
+ * If the same RTE is specified for more than one locking strength,
+ * treat is as the strongest. (Reasonable, since you can't take both a
+ * shared and exclusive lock at the same time; it'll end up being
+ * exclusive anyway.)
*
* We also consider that NOWAIT wins if it's specified both ways. This
* is a bit more debatable but raising an error doesn't seem helpful.
@@ -2356,7 +2356,7 @@ applyLockingClause(Query *qry, Index rtindex,
*
* And of course pushedDown becomes false if any clause is explicit.
*/
- rc->forUpdate |= forUpdate;
+ rc->strength = Max(rc->strength, strength);
rc->noWait |= noWait;
rc->pushedDown &= pushedDown;
return;
@@ -2365,7 +2365,7 @@ applyLockingClause(Query *qry, Index rtindex,
/* Make a new RowMarkClause */
rc = makeNode(RowMarkClause);
rc->rti = rtindex;
- rc->forUpdate = forUpdate;
+ rc->strength = strength;
rc->noWait = noWait;
rc->pushedDown = pushedDown;
qry->rowMarks = lappend(qry->rowMarks, rc);
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index b19afa88e73..828e11058e9 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -361,6 +361,7 @@ static void processCASbits(int cas_bits, int location, const char *constrType,
%type <ival> OptTemp
%type <oncommit> OnCommitOption
+%type <ival> for_locking_strength
%type <node> for_locking_item
%type <list> for_locking_clause opt_for_locking_clause for_locking_items
%type <list> locked_rels_list
@@ -8900,9 +8901,10 @@ select_with_parens:
* The duplicative productions are annoying, but hard to get rid of without
* creating shift/reduce conflicts.
*
- * FOR UPDATE/SHARE may be before or after LIMIT/OFFSET.
+ * The locking clause (FOR UPDATE etc) may be before or after LIMIT/OFFSET.
* In <=7.2.X, LIMIT/OFFSET had to be after FOR UPDATE
- * We now support both orderings, but prefer LIMIT/OFFSET before FOR UPDATE/SHARE
+ * We now support both orderings, but prefer LIMIT/OFFSET before the locking
+ * clause.
* 2002-08-28 bjm
*/
select_no_parens:
@@ -9321,24 +9323,23 @@ for_locking_items:
;
for_locking_item:
- FOR UPDATE locked_rels_list opt_nowait
+ for_locking_strength locked_rels_list opt_nowait
{
LockingClause *n = makeNode(LockingClause);
- n->lockedRels = $3;
- n->forUpdate = TRUE;
- n->noWait = $4;
- $$ = (Node *) n;
- }
- | FOR SHARE locked_rels_list opt_nowait
- {
- LockingClause *n = makeNode(LockingClause);
- n->lockedRels = $3;
- n->forUpdate = FALSE;
- n->noWait = $4;
+ n->lockedRels = $2;
+ n->strength = $1;
+ n->noWait = $3;
$$ = (Node *) n;
}
;
+for_locking_strength:
+ FOR UPDATE { $$ = LCS_FORUPDATE; }
+ | FOR NO KEY UPDATE { $$ = LCS_FORNOKEYUPDATE; }
+ | FOR SHARE { $$ = LCS_FORSHARE; }
+ | FOR KEY SHARE { $$ = LCS_FORKEYSHARE; }
+ ;
+
locked_rels_list:
OF qualified_name_list { $$ = $2; }
| /* EMPTY */ { $$ = NIL; }