diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-08-01 20:31:16 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-08-01 20:31:16 +0000 |
commit | 2a4fad1a0e43d6375ffa8eddb2d8dfa1ed36593f (patch) | |
tree | bb2bc2208507b0ab2403850e8dd01003a4ed73e9 /src/backend/parser | |
parent | ca7abcd89dbeecb82cde50fccf4f6c483244fdf7 (diff) | |
download | postgresql-2a4fad1a0e43d6375ffa8eddb2d8dfa1ed36593f.tar.gz postgresql-2a4fad1a0e43d6375ffa8eddb2d8dfa1ed36593f.zip |
Add NOWAIT option to SELECT FOR UPDATE/SHARE.
Original patch by Hans-Juergen Schoenig, revisions by Karel Zak
and Tom Lane.
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/analyze.c | 70 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 68 | ||||
-rw-r--r-- | src/backend/parser/parse_relation.c | 8 | ||||
-rw-r--r-- | src/backend/parser/parse_type.c | 4 |
4 files changed, 77 insertions, 73 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index a9211cfe931..099bb714831 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -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, diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 8e79355cdd5..768fb4ada75 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -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) { diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c index 51d200736b0..85984cb1d9e 100644 --- a/src/backend/parser/parse_relation.c +++ b/src/backend/parser/parse_relation.c @@ -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)); diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c index d8fba16b555..008c1fe6a54 100644 --- a/src/backend/parser/parse_type.c +++ b/src/backend/parser/parse_type.c @@ -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) |