summaryrefslogtreecommitdiff
path: root/src/backend/parser
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser')
-rw-r--r--src/backend/parser/analyze.c104
-rw-r--r--src/backend/parser/gram.y48
-rw-r--r--src/backend/parser/parse_relation.c18
-rw-r--r--src/backend/parser/parse_type.c4
4 files changed, 107 insertions, 67 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 3cb64dc8249..ee6bfe6ae92 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.320 2005/04/14 20:03:24 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.321 2005/04/28 21:47:14 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 transformForUpdate(Query *qry, List *forUpdate);
+static void transformLocking(Query *qry, List *lockedRels, bool forUpdate);
static void transformConstraintAttrs(List *constraintList);
static void transformColumnType(ParseState *pstate, ColumnDef *column);
static void release_pstate_resources(ParseState *pstate);
@@ -1810,8 +1810,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
qry->commandType = CMD_SELECT;
- /* make FOR UPDATE clause available to addRangeTableEntry */
- pstate->p_forUpdate = stmt->forUpdate;
+ /* make FOR UPDATE/FOR SHARE list available to addRangeTableEntry */
+ pstate->p_lockedRels = stmt->lockedRels;
/* process the FROM clause */
transformFromClause(pstate, stmt->fromClause);
@@ -1870,8 +1870,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
parseCheckAggregates(pstate, qry);
- if (stmt->forUpdate != NIL)
- transformForUpdate(qry, stmt->forUpdate);
+ if (stmt->lockedRels != NIL)
+ transformLocking(qry, stmt->lockedRels, stmt->forUpdate);
return qry;
}
@@ -1899,7 +1899,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
List *sortClause;
Node *limitOffset;
Node *limitCount;
- List *forUpdate;
+ List *lockedRels;
+ bool forUpdate;
Node *node;
ListCell *left_tlist,
*dtlist;
@@ -1937,18 +1938,19 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
sortClause = stmt->sortClause;
limitOffset = stmt->limitOffset;
limitCount = stmt->limitCount;
+ lockedRels = stmt->lockedRels;
forUpdate = stmt->forUpdate;
stmt->sortClause = NIL;
stmt->limitOffset = NULL;
stmt->limitCount = NULL;
- stmt->forUpdate = NIL;
+ stmt->lockedRels = NIL;
- /* We don't support forUpdate with set ops at the moment. */
- if (forUpdate)
+ /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
+ if (lockedRels)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT")));
+ errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
/*
* Recursively transform the components of the tree.
@@ -2083,8 +2085,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
parseCheckAggregates(pstate, qry);
- if (forUpdate != NIL)
- transformForUpdate(qry, forUpdate);
+ if (lockedRels != NIL)
+ transformLocking(qry, lockedRels, forUpdate);
return qry;
}
@@ -2107,11 +2109,11 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("INTO is only allowed on first SELECT of UNION/INTERSECT/EXCEPT")));
- /* We don't support forUpdate with set ops at the moment. */
- if (stmt->forUpdate)
+ /* We don't support FOR UPDATE/SHARE with set ops at the moment. */
+ if (stmt->lockedRels)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT")));
+ errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
/*
* If an internal node of a set-op tree has ORDER BY, UPDATE, or LIMIT
@@ -2128,7 +2130,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
{
Assert(stmt->larg != NULL && stmt->rarg != NULL);
if (stmt->sortClause || stmt->limitOffset || stmt->limitCount ||
- stmt->forUpdate)
+ stmt->lockedRels)
isLeaf = true;
else
isLeaf = false;
@@ -2711,47 +2713,67 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
/* exported so planner can check again after rewriting, query pullup, etc */
void
-CheckSelectForUpdate(Query *qry)
+CheckSelectLocking(Query *qry, bool forUpdate)
{
+ const char *operation;
+
+ if (forUpdate)
+ operation = "SELECT FOR UPDATE";
+ else
+ operation = "SELECT FOR SHARE";
+
if (qry->setOperations)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE is not allowed with UNION/INTERSECT/EXCEPT")));
+ /* translator: %s is a SQL command, like SELECT FOR UPDATE */
+ errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT", operation)));
if (qry->distinctClause != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE is not allowed with DISTINCT clause")));
+ /* translator: %s is a SQL command, like SELECT FOR UPDATE */
+ errmsg("%s is not allowed with DISTINCT clause", operation)));
if (qry->groupClause != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE is not allowed with GROUP BY clause")));
+ /* translator: %s is a SQL command, like SELECT FOR UPDATE */
+ errmsg("%s is not allowed with GROUP BY clause", operation)));
if (qry->havingQual != NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE is not allowed with HAVING clause")));
+ /* translator: %s is a SQL command, like SELECT FOR UPDATE */
+ errmsg("%s is not allowed with HAVING clause", operation)));
if (qry->hasAggs)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE is not allowed with aggregate functions")));
+ /* translator: %s is a SQL command, like SELECT FOR UPDATE */
+ errmsg("%s is not allowed with aggregate functions", operation)));
}
/*
- * Convert FOR UPDATE name list into rowMarks list of integer relids
+ * Convert FOR UPDATE/SHARE name list into rowMarks list of integer relids
*
- * NB: if you need to change this, see also markQueryForUpdate()
+ * NB: if you need to change this, see also markQueryForLocking()
* in rewriteHandler.c.
*/
static void
-transformForUpdate(Query *qry, List *forUpdate)
+transformLocking(Query *qry, List *lockedRels, bool forUpdate)
{
- List *rowMarks = qry->rowMarks;
+ List *rowMarks;
ListCell *l;
ListCell *rt;
Index i;
- CheckSelectForUpdate(qry);
+ 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;
+
+ CheckSelectLocking(qry, forUpdate);
+
+ rowMarks = qry->rowMarks;
- if (linitial(forUpdate) == NULL)
+ if (linitial(lockedRels) == NULL)
{
/* all regular tables used in query */
i = 0;
@@ -2770,10 +2792,11 @@ transformForUpdate(Query *qry, List *forUpdate)
case RTE_SUBQUERY:
/*
- * FOR UPDATE of subquery is propagated to subquery's
- * rels
+ * FOR UPDATE/SHARE of subquery is propagated to all
+ * of subquery's rels
*/
- transformForUpdate(rte->subquery, list_make1(NULL));
+ transformLocking(rte->subquery, list_make1(NULL),
+ forUpdate);
break;
default:
/* ignore JOIN, SPECIAL, FUNCTION RTEs */
@@ -2784,7 +2807,7 @@ transformForUpdate(Query *qry, List *forUpdate)
else
{
/* just the named tables */
- foreach(l, forUpdate)
+ foreach(l, lockedRels)
{
char *relname = strVal(lfirst(l));
@@ -2806,25 +2829,26 @@ transformForUpdate(Query *qry, List *forUpdate)
case RTE_SUBQUERY:
/*
- * FOR UPDATE of subquery is propagated to
- * subquery's rels
+ * FOR UPDATE/SHARE of subquery is propagated to
+ * all of subquery's rels
*/
- transformForUpdate(rte->subquery, list_make1(NULL));
+ transformLocking(rte->subquery, list_make1(NULL),
+ forUpdate);
break;
case RTE_JOIN:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE cannot be applied to a join")));
+ errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a join")));
break;
case RTE_SPECIAL:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE cannot be applied to NEW or OLD")));
+ errmsg("SELECT FOR UPDATE/SHARE cannot be applied to NEW or OLD")));
break;
case RTE_FUNCTION:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE cannot be applied to a function")));
+ errmsg("SELECT FOR UPDATE/SHARE cannot be applied to a function")));
break;
default:
elog(ERROR, "unrecognized RTE type: %d",
@@ -2837,7 +2861,7 @@ transformForUpdate(Query *qry, List *forUpdate)
if (rt == NULL)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
- errmsg("relation \"%s\" in FOR UPDATE clause not found in FROM clause",
+ errmsg("relation \"%s\" in FOR UPDATE/SHARE clause not found in FROM clause",
relname)));
}
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 260a2e1b455..c51c10c7a89 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.488 2005/04/23 17:22:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.489 2005/04/28 21:47:14 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 *forUpdate,
+ List *sortClause, List *lockingClause,
Node *limitOffset, Node *limitCount);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static Node *doNegate(Node *n);
@@ -242,7 +242,8 @@ static void doNegateFloat(Value *v);
%type <oncommit> OnCommitOption
%type <withoids> OptWithOids WithOidsAs
-%type <list> for_update_clause opt_for_update_clause update_list
+%type <list> for_locking_clause opt_for_locking_clause
+ update_list
%type <boolean> opt_all
%type <node> join_outer join_qual
@@ -4886,9 +4887,9 @@ select_with_parens:
;
/*
- * FOR UPDATE may be before or after LIMIT/OFFSET.
+ * FOR UPDATE/SHARE 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
+ * We now support both orderings, but prefer LIMIT/OFFSET before FOR UPDATE/SHARE
* 2002-08-28 bjm
*/
select_no_parens:
@@ -4899,13 +4900,13 @@ select_no_parens:
NULL, NULL);
$$ = $1;
}
- | select_clause opt_sort_clause for_update_clause opt_select_limit
+ | select_clause opt_sort_clause for_locking_clause opt_select_limit
{
insertSelectOptions((SelectStmt *) $1, $2, $3,
list_nth($4, 0), list_nth($4, 1));
$$ = $1;
}
- | select_clause opt_sort_clause select_limit opt_for_update_clause
+ | select_clause opt_sort_clause select_limit opt_for_locking_clause
{
insertSelectOptions((SelectStmt *) $1, $2, $4,
list_nth($3, 0), list_nth($3, 1));
@@ -5146,13 +5147,14 @@ having_clause:
| /*EMPTY*/ { $$ = NULL; }
;
-for_update_clause:
- FOR UPDATE update_list { $$ = $3; }
+for_locking_clause:
+ FOR UPDATE update_list { $$ = lcons(makeString("for_update"), $3); }
+ | FOR SHARE update_list { $$ = lcons(makeString("for_share"), $3); }
| FOR READ ONLY { $$ = NULL; }
;
-opt_for_update_clause:
- for_update_clause { $$ = $1; }
+opt_for_locking_clause:
+ for_locking_clause { $$ = $1; }
| /* EMPTY */ { $$ = NULL; }
;
@@ -8379,7 +8381,7 @@ findLeftmostSelect(SelectStmt *node)
*/
static void
insertSelectOptions(SelectStmt *stmt,
- List *sortClause, List *forUpdate,
+ List *sortClause, List *lockingClause,
Node *limitOffset, Node *limitCount)
{
/*
@@ -8394,13 +8396,27 @@ insertSelectOptions(SelectStmt *stmt,
errmsg("multiple ORDER BY clauses not allowed")));
stmt->sortClause = sortClause;
}
- if (forUpdate)
+ if (lockingClause)
{
- if (stmt->forUpdate)
+ Value *type;
+
+ if (stmt->lockedRels)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("multiple FOR UPDATE clauses not allowed")));
- stmt->forUpdate = forUpdate;
+ 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);
}
if (limitOffset)
{
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index b68ae005150..d1e5fca2aae 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.106 2005/04/13 16:50:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.107 2005/04/28 21:47:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -40,7 +40,7 @@ static Node *scanNameSpaceForRelid(ParseState *pstate, Node *nsnode,
Oid relid);
static void scanNameSpaceForConflict(ParseState *pstate, Node *nsnode,
RangeTblEntry *rte1, const char *aliasname1);
-static bool isForUpdate(ParseState *pstate, char *refname);
+static bool isLockedRel(ParseState *pstate, char *refname);
static void expandRelation(Oid relid, Alias *eref,
int rtindex, int sublevels_up,
bool include_dropped,
@@ -759,9 +759,9 @@ addRangeTableEntry(ParseState *pstate,
* Get the rel's OID. This access also ensures that we have an
* up-to-date relcache entry for the rel. Since this is typically the
* first access to a rel in a statement, be careful to get the right
- * access level depending on whether we're doing SELECT FOR UPDATE.
+ * access level depending on whether we're doing SELECT FOR UPDATE/SHARE.
*/
- lockmode = isForUpdate(pstate, refname) ? RowShareLock : AccessShareLock;
+ lockmode = isLockedRel(pstate, refname) ? RowShareLock : AccessShareLock;
rel = heap_openrv(relation, lockmode);
rte->relid = RelationGetRelid(rel);
@@ -1121,17 +1121,17 @@ addRangeTableEntryForJoin(ParseState *pstate,
}
/*
- * Has the specified refname been selected FOR UPDATE?
+ * Has the specified refname been selected FOR UPDATE/FOR SHARE?
*/
static bool
-isForUpdate(ParseState *pstate, char *refname)
+isLockedRel(ParseState *pstate, char *refname)
{
/* Outer loop to check parent query levels as well as this one */
while (pstate != NULL)
{
- if (pstate->p_forUpdate != NIL)
+ if (pstate->p_lockedRels != NIL)
{
- if (linitial(pstate->p_forUpdate) == NULL)
+ if (linitial(pstate->p_lockedRels) == NULL)
{
/* all tables used in query */
return true;
@@ -1141,7 +1141,7 @@ isForUpdate(ParseState *pstate, char *refname)
/* just the named tables */
ListCell *l;
- foreach(l, pstate->p_forUpdate)
+ foreach(l, pstate->p_lockedRels)
{
char *rname = strVal(lfirst(l));
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index aae7908f507..21ce20c5ecf 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.73 2004/12/31 22:00:27 pgsql Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.74 2005/04/28 21:47:14 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -432,7 +432,7 @@ parseTypeString(const char *str, Oid *type_id, int32 *typmod)
stmt->sortClause != NIL ||
stmt->limitOffset != NULL ||
stmt->limitCount != NULL ||
- stmt->forUpdate != NIL ||
+ stmt->lockedRels != NIL ||
stmt->op != SETOP_NONE)
goto fail;
if (list_length(stmt->targetList) != 1)