mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Add NOWAIT option to SELECT FOR UPDATE/SHARE.
Original patch by Hans-Juergen Schoenig, revisions by Karel Zak and Tom Lane.
This commit is contained in:
@@ -6,7 +6,7 @@
|
||||
* Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.323 2005/07/28 22:27:00 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.324 2005/08/01 20:31:09 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -134,7 +134,7 @@ static void transformFKConstraints(ParseState *pstate,
|
||||
bool isAddConstraint);
|
||||
static void applyColumnNames(List *dst, List *src);
|
||||
static List *getSetColTypes(ParseState *pstate, Node *node);
|
||||
static void transformLocking(Query *qry, List *lockedRels, bool forUpdate);
|
||||
static void transformLockingClause(Query *qry, LockingClause *lc);
|
||||
static void transformConstraintAttrs(List *constraintList);
|
||||
static void transformColumnType(ParseState *pstate, ColumnDef *column);
|
||||
static void release_pstate_resources(ParseState *pstate);
|
||||
@@ -1812,8 +1812,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
|
||||
qry->commandType = CMD_SELECT;
|
||||
|
||||
/* make FOR UPDATE/FOR SHARE list available to addRangeTableEntry */
|
||||
pstate->p_lockedRels = stmt->lockedRels;
|
||||
/* make FOR UPDATE/FOR SHARE info available to addRangeTableEntry */
|
||||
pstate->p_locking_clause = stmt->lockingClause;
|
||||
|
||||
/* process the FROM clause */
|
||||
transformFromClause(pstate, stmt->fromClause);
|
||||
@@ -1872,8 +1872,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
|
||||
parseCheckAggregates(pstate, qry);
|
||||
|
||||
if (stmt->lockedRels != NIL)
|
||||
transformLocking(qry, stmt->lockedRels, stmt->forUpdate);
|
||||
if (stmt->lockingClause)
|
||||
transformLockingClause(qry, stmt->lockingClause);
|
||||
|
||||
return qry;
|
||||
}
|
||||
@@ -1901,8 +1901,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
List *sortClause;
|
||||
Node *limitOffset;
|
||||
Node *limitCount;
|
||||
List *lockedRels;
|
||||
bool forUpdate;
|
||||
LockingClause *lockingClause;
|
||||
Node *node;
|
||||
ListCell *left_tlist,
|
||||
*dtlist;
|
||||
@@ -1940,16 +1939,15 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
sortClause = stmt->sortClause;
|
||||
limitOffset = stmt->limitOffset;
|
||||
limitCount = stmt->limitCount;
|
||||
lockedRels = stmt->lockedRels;
|
||||
forUpdate = stmt->forUpdate;
|
||||
lockingClause = stmt->lockingClause;
|
||||
|
||||
stmt->sortClause = NIL;
|
||||
stmt->limitOffset = NULL;
|
||||
stmt->limitCount = NULL;
|
||||
stmt->lockedRels = NIL;
|
||||
stmt->lockingClause = NULL;
|
||||
|
||||
/* We don't support FOR UPDATE/SHARE with set ops at the moment. */
|
||||
if (lockedRels)
|
||||
if (lockingClause)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
|
||||
@@ -2089,8 +2087,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
|
||||
parseCheckAggregates(pstate, qry);
|
||||
|
||||
if (lockedRels != NIL)
|
||||
transformLocking(qry, lockedRels, forUpdate);
|
||||
if (lockingClause)
|
||||
transformLockingClause(qry, lockingClause);
|
||||
|
||||
return qry;
|
||||
}
|
||||
@@ -2114,7 +2112,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));
|
||||
/* We don't support FOR UPDATE/SHARE with set ops at the moment. */
|
||||
if (stmt->lockedRels)
|
||||
if (stmt->lockingClause)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
|
||||
@@ -2134,7 +2132,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
|
||||
{
|
||||
Assert(stmt->larg != NULL && stmt->rarg != NULL);
|
||||
if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
|
||||
stmt->lockedRels)
|
||||
stmt->lockingClause)
|
||||
isLeaf = true;
|
||||
else
|
||||
isLeaf = false;
|
||||
@@ -2760,24 +2758,40 @@ CheckSelectLocking(Query *qry, bool forUpdate)
|
||||
* in rewriteHandler.c.
|
||||
*/
|
||||
static void
|
||||
transformLocking(Query *qry, List *lockedRels, bool forUpdate)
|
||||
transformLockingClause(Query *qry, LockingClause *lc)
|
||||
{
|
||||
List *lockedRels = lc->lockedRels;
|
||||
List *rowMarks;
|
||||
ListCell *l;
|
||||
ListCell *rt;
|
||||
Index i;
|
||||
LockingClause *allrels;
|
||||
|
||||
if (qry->rowMarks && forUpdate != qry->forUpdate)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
|
||||
qry->forUpdate = forUpdate;
|
||||
if (qry->rowMarks)
|
||||
{
|
||||
if (lc->forUpdate != qry->forUpdate)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
|
||||
if (lc->nowait != qry->rowNoWait)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||
errmsg("cannot use both wait and NOWAIT in one query")));
|
||||
}
|
||||
qry->forUpdate = lc->forUpdate;
|
||||
qry->rowNoWait = lc->nowait;
|
||||
|
||||
CheckSelectLocking(qry, lc->forUpdate);
|
||||
|
||||
/* 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->nowait = lc->nowait;
|
||||
|
||||
CheckSelectLocking(qry, forUpdate);
|
||||
|
||||
rowMarks = qry->rowMarks;
|
||||
|
||||
if (linitial(lockedRels) == NULL)
|
||||
if (lockedRels == NIL)
|
||||
{
|
||||
/* all regular tables used in query */
|
||||
i = 0;
|
||||
@@ -2799,8 +2813,7 @@ transformLocking(Query *qry, List *lockedRels, bool forUpdate)
|
||||
* FOR UPDATE/SHARE of subquery is propagated to all
|
||||
* of subquery's rels
|
||||
*/
|
||||
transformLocking(rte->subquery, list_make1(NULL),
|
||||
forUpdate);
|
||||
transformLockingClause(rte->subquery, allrels);
|
||||
break;
|
||||
default:
|
||||
/* ignore JOIN, SPECIAL, FUNCTION RTEs */
|
||||
@@ -2836,8 +2849,7 @@ transformLocking(Query *qry, List *lockedRels, bool forUpdate)
|
||||
* FOR UPDATE/SHARE of subquery is propagated to
|
||||
* all of subquery's rels
|
||||
*/
|
||||
transformLocking(rte->subquery, list_make1(NULL),
|
||||
forUpdate);
|
||||
transformLockingClause(rte->subquery, allrels);
|
||||
break;
|
||||
case RTE_JOIN:
|
||||
ereport(ERROR,
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.506 2005/08/01 04:03:56 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.507 2005/08/01 20:31:09 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -87,7 +87,7 @@ static List *check_func_name(List *names);
|
||||
static List *extractArgTypes(List *parameters);
|
||||
static SelectStmt *findLeftmostSelect(SelectStmt *node);
|
||||
static void insertSelectOptions(SelectStmt *stmt,
|
||||
List *sortClause, List *lockingClause,
|
||||
List *sortClause, Node *lockingClause,
|
||||
Node *limitOffset, Node *limitCount);
|
||||
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
|
||||
static Node *doNegate(Node *n);
|
||||
@@ -132,7 +132,7 @@ static void doNegateFloat(Value *v);
|
||||
|
||||
%type <node> stmt schema_stmt
|
||||
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt
|
||||
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
|
||||
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
|
||||
AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
|
||||
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
|
||||
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
|
||||
@@ -165,7 +165,7 @@ static void doNegateFloat(Value *v);
|
||||
|
||||
%type <dbehavior> opt_drop_behavior
|
||||
|
||||
%type <list> createdb_opt_list alterdb_opt_list copy_opt_list
|
||||
%type <list> createdb_opt_list alterdb_opt_list copy_opt_list
|
||||
transaction_mode_list
|
||||
%type <defelt> createdb_opt_item alterdb_opt_item copy_opt_item
|
||||
transaction_mode_item
|
||||
@@ -240,8 +240,8 @@ static void doNegateFloat(Value *v);
|
||||
%type <oncommit> OnCommitOption
|
||||
%type <withoids> OptWithOids WithOidsAs
|
||||
|
||||
%type <list> for_locking_clause opt_for_locking_clause
|
||||
update_list
|
||||
%type <node> for_locking_clause opt_for_locking_clause
|
||||
%type <list> locked_rels_list
|
||||
%type <boolean> opt_all
|
||||
|
||||
%type <node> join_outer join_qual
|
||||
@@ -4555,7 +4555,7 @@ opt_equal: '=' {}
|
||||
*****************************************************************************/
|
||||
|
||||
AlterDatabaseStmt:
|
||||
ALTER DATABASE database_name opt_with alterdb_opt_list
|
||||
ALTER DATABASE database_name opt_with alterdb_opt_list
|
||||
{
|
||||
AlterDatabaseStmt *n = makeNode(AlterDatabaseStmt);
|
||||
n->dbname = $3;
|
||||
@@ -5070,7 +5070,7 @@ lock_type: ACCESS SHARE { $$ = AccessShareLock; }
|
||||
| ACCESS EXCLUSIVE { $$ = AccessExclusiveLock; }
|
||||
;
|
||||
|
||||
opt_nowait: NOWAIT { $$ = TRUE; }
|
||||
opt_nowait: NOWAIT { $$ = TRUE; }
|
||||
| /*EMPTY*/ { $$ = FALSE; }
|
||||
;
|
||||
|
||||
@@ -5191,7 +5191,7 @@ select_no_parens:
|
||||
simple_select { $$ = $1; }
|
||||
| select_clause sort_clause
|
||||
{
|
||||
insertSelectOptions((SelectStmt *) $1, $2, NIL,
|
||||
insertSelectOptions((SelectStmt *) $1, $2, NULL,
|
||||
NULL, NULL);
|
||||
$$ = $1;
|
||||
}
|
||||
@@ -5424,14 +5424,6 @@ select_offset_value:
|
||||
a_expr { $$ = $1; }
|
||||
;
|
||||
|
||||
/*
|
||||
* jimmy bell-style recursive queries aren't supported in the
|
||||
* current system.
|
||||
*
|
||||
* ...however, recursive addattr and rename supported. make special
|
||||
* cases for these.
|
||||
*/
|
||||
|
||||
group_clause:
|
||||
GROUP_P BY expr_list { $$ = $3; }
|
||||
| /*EMPTY*/ { $$ = NIL; }
|
||||
@@ -5443,8 +5435,22 @@ having_clause:
|
||||
;
|
||||
|
||||
for_locking_clause:
|
||||
FOR UPDATE update_list { $$ = lcons(makeString("for_update"), $3); }
|
||||
| FOR SHARE update_list { $$ = lcons(makeString("for_share"), $3); }
|
||||
FOR UPDATE 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;
|
||||
$$ = (Node *) n;
|
||||
}
|
||||
| FOR READ ONLY { $$ = NULL; }
|
||||
;
|
||||
|
||||
@@ -5453,9 +5459,9 @@ opt_for_locking_clause:
|
||||
| /* EMPTY */ { $$ = NULL; }
|
||||
;
|
||||
|
||||
update_list:
|
||||
locked_rels_list:
|
||||
OF name_list { $$ = $2; }
|
||||
| /* EMPTY */ { $$ = list_make1(NULL); }
|
||||
| /* EMPTY */ { $$ = NIL; }
|
||||
;
|
||||
|
||||
/*****************************************************************************
|
||||
@@ -8691,7 +8697,7 @@ findLeftmostSelect(SelectStmt *node)
|
||||
*/
|
||||
static void
|
||||
insertSelectOptions(SelectStmt *stmt,
|
||||
List *sortClause, List *lockingClause,
|
||||
List *sortClause, Node *lockingClause,
|
||||
Node *limitOffset, Node *limitCount)
|
||||
{
|
||||
/*
|
||||
@@ -8708,25 +8714,11 @@ insertSelectOptions(SelectStmt *stmt,
|
||||
}
|
||||
if (lockingClause)
|
||||
{
|
||||
Value *type;
|
||||
|
||||
if (stmt->lockedRels)
|
||||
if (stmt->lockingClause)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("multiple FOR UPDATE/FOR SHARE clauses not allowed")));
|
||||
|
||||
Assert(list_length(lockingClause) > 1);
|
||||
/* 1st is Value node containing "for_update" or "for_share" */
|
||||
type = (Value *) linitial(lockingClause);
|
||||
Assert(IsA(type, String));
|
||||
if (strcmp(strVal(type), "for_update") == 0)
|
||||
stmt->forUpdate = true;
|
||||
else if (strcmp(strVal(type), "for_share") == 0)
|
||||
stmt->forUpdate = false;
|
||||
else
|
||||
elog(ERROR, "invalid first node in locking clause");
|
||||
|
||||
stmt->lockedRels = list_delete_first(lockingClause);
|
||||
stmt->lockingClause = (LockingClause *) lockingClause;
|
||||
}
|
||||
if (limitOffset)
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.112 2005/06/28 05:08:58 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.113 2005/08/01 20:31:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -903,9 +903,9 @@ isLockedRel(ParseState *pstate, char *refname)
|
||||
/* Outer loop to check parent query levels as well as this one */
|
||||
while (pstate != NULL)
|
||||
{
|
||||
if (pstate->p_lockedRels != NIL)
|
||||
if (pstate->p_locking_clause)
|
||||
{
|
||||
if (linitial(pstate->p_lockedRels) == NULL)
|
||||
if (pstate->p_locking_clause->lockedRels == NIL)
|
||||
{
|
||||
/* all tables used in query */
|
||||
return true;
|
||||
@@ -915,7 +915,7 @@ isLockedRel(ParseState *pstate, char *refname)
|
||||
/* just the named tables */
|
||||
ListCell *l;
|
||||
|
||||
foreach(l, pstate->p_lockedRels)
|
||||
foreach(l, pstate->p_locking_clause->lockedRels)
|
||||
{
|
||||
char *rname = strVal(lfirst(l));
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.75 2005/05/29 18:24:13 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.76 2005/08/01 20:31:10 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -423,7 +423,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
|
||||
stmt->sortClause != NIL ||
|
||||
stmt->limitOffset != NULL ||
|
||||
stmt->limitCount != NULL ||
|
||||
stmt->lockedRels != NIL ||
|
||||
stmt->lockingClause != NULL ||
|
||||
stmt->op != SETOP_NONE)
|
||||
goto fail;
|
||||
if (list_length(stmt->targetList) != 1)
|
||||
|
||||
Reference in New Issue
Block a user