aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2006-04-30 18:30:40 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2006-04-30 18:30:40 +0000
commit986085a7f08c72219abf47f8b968213e81ab943c (patch)
treea80d30e59cffd042ed9adb024afc5f5d6bf00e16 /src/backend
parent931bfc96644b8f51a49161f780d43506e55d2b13 (diff)
downloadpostgresql-986085a7f08c72219abf47f8b968213e81ab943c.tar.gz
postgresql-986085a7f08c72219abf47f8b968213e81ab943c.zip
Improve the representation of FOR UPDATE/FOR SHARE so that we can
support both FOR UPDATE and FOR SHARE in one command, as well as both NOWAIT and normal WAIT behavior. The more general code is actually simpler and cleaner.
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/executor/execMain.c43
-rw-r--r--src/backend/executor/execUtils.c4
-rw-r--r--src/backend/nodes/copyfuncs.c23
-rw-r--r--src/backend/nodes/equalfuncs.c21
-rw-r--r--src/backend/nodes/outfuncs.c21
-rw-r--r--src/backend/nodes/readfuncs.c23
-rw-r--r--src/backend/optimizer/path/allpaths.c4
-rw-r--r--src/backend/optimizer/plan/createplan.c6
-rw-r--r--src/backend/optimizer/prep/prepjointree.c24
-rw-r--r--src/backend/optimizer/prep/preptlist.c10
-rw-r--r--src/backend/optimizer/prep/prepunion.c4
-rw-r--r--src/backend/parser/analyze.c113
-rw-r--r--src/backend/parser/gram.y46
-rw-r--r--src/backend/parser/parse_relation.c38
-rw-r--r--src/backend/parser/parse_type.c4
-rw-r--r--src/backend/rewrite/rewriteHandler.c31
-rw-r--r--src/backend/rewrite/rewriteManip.c14
-rw-r--r--src/backend/tcop/utility.c4
-rw-r--r--src/backend/utils/adt/ruleutils.c30
19 files changed, 256 insertions, 207 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 31951db4c26..e8e0c8bd56d 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -26,7 +26,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.269 2006/03/05 15:58:25 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.270 2006/04/30 18:30:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -452,6 +452,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
Relation intoRelationDesc;
bool do_select_into;
TupleDesc tupType;
+ ListCell *l;
/*
* Do permissions checks. It's sufficient to examine the query's top
@@ -486,7 +487,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* parseTree->resultRelations identifies them all
*/
ResultRelInfo *resultRelInfo;
- ListCell *l;
numResultRelations = list_length(resultRelations);
resultRelInfos = (ResultRelInfo *)
@@ -549,26 +549,21 @@ InitPlan(QueryDesc *queryDesc, int eflags)
* Have to lock relations selected FOR UPDATE/FOR SHARE
*/
estate->es_rowMarks = NIL;
- estate->es_forUpdate = parseTree->forUpdate;
- estate->es_rowNoWait = parseTree->rowNoWait;
- if (parseTree->rowMarks != NIL)
+ foreach(l, parseTree->rowMarks)
{
- ListCell *l;
-
- foreach(l, parseTree->rowMarks)
- {
- Index rti = lfirst_int(l);
- Oid relid = getrelid(rti, rangeTable);
- Relation relation;
- ExecRowMark *erm;
-
- relation = heap_open(relid, RowShareLock);
- erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
- erm->relation = relation;
- erm->rti = rti;
- snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rti);
- estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
- }
+ RowMarkClause *rc = (RowMarkClause *) lfirst(l);
+ Oid relid = getrelid(rc->rti, rangeTable);
+ Relation relation;
+ ExecRowMark *erm;
+
+ relation = heap_open(relid, RowShareLock);
+ erm = (ExecRowMark *) palloc(sizeof(ExecRowMark));
+ erm->relation = relation;
+ erm->rti = rc->rti;
+ erm->forUpdate = rc->forUpdate;
+ erm->noWait = rc->noWait;
+ snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rc->rti);
+ estate->es_rowMarks = lappend(estate->es_rowMarks, erm);
}
/*
@@ -1222,7 +1217,7 @@ lnext: ;
tuple.t_self = *((ItemPointer) DatumGetPointer(datum));
- if (estate->es_forUpdate)
+ if (erm->forUpdate)
lockmode = LockTupleExclusive;
else
lockmode = LockTupleShared;
@@ -1230,7 +1225,7 @@ lnext: ;
test = heap_lock_tuple(erm->relation, &tuple, &buffer,
&update_ctid, &update_xmax,
estate->es_snapshot->curcid,
- lockmode, estate->es_rowNoWait);
+ lockmode, erm->noWait);
ReleaseBuffer(buffer);
switch (test)
{
@@ -2258,8 +2253,6 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
epqstate->es_param_exec_vals = (ParamExecData *)
palloc0(estate->es_topPlan->nParamExec * sizeof(ParamExecData));
epqstate->es_rowMarks = estate->es_rowMarks;
- epqstate->es_forUpdate = estate->es_forUpdate;
- epqstate->es_rowNoWait = estate->es_rowNoWait;
epqstate->es_instrument = estate->es_instrument;
epqstate->es_select_into = estate->es_select_into;
epqstate->es_into_oids = estate->es_into_oids;
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 3696b5a208c..d1a294f9bb8 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.133 2006/03/05 15:58:26 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.134 2006/04/30 18:30:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -204,8 +204,6 @@ CreateExecutorState(void)
estate->es_processed = 0;
estate->es_lastoid = InvalidOid;
estate->es_rowMarks = NIL;
- estate->es_forUpdate = false;
- estate->es_rowNoWait = false;
estate->es_instrument = false;
estate->es_select_into = false;
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index b060d38b5ed..6bf342ab92c 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.334 2006/04/22 01:25:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.335 2006/04/30 18:30:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1409,6 +1409,18 @@ _copyGroupClause(GroupClause *from)
return newnode;
}
+static RowMarkClause *
+_copyRowMarkClause(RowMarkClause *from)
+{
+ RowMarkClause *newnode = makeNode(RowMarkClause);
+
+ COPY_SCALAR_FIELD(rti);
+ COPY_SCALAR_FIELD(forUpdate);
+ COPY_SCALAR_FIELD(noWait);
+
+ return newnode;
+}
+
static A_Expr *
_copyAExpr(A_Expr *from)
{
@@ -1650,7 +1662,7 @@ _copyLockingClause(LockingClause *from)
COPY_NODE_FIELD(lockedRels);
COPY_SCALAR_FIELD(forUpdate);
- COPY_SCALAR_FIELD(nowait);
+ COPY_SCALAR_FIELD(noWait);
return newnode;
}
@@ -1673,9 +1685,6 @@ _copyQuery(Query *from)
COPY_SCALAR_FIELD(hasSubLinks);
COPY_NODE_FIELD(rtable);
COPY_NODE_FIELD(jointree);
- COPY_NODE_FIELD(rowMarks);
- COPY_SCALAR_FIELD(forUpdate);
- COPY_SCALAR_FIELD(rowNoWait);
COPY_NODE_FIELD(targetList);
COPY_NODE_FIELD(groupClause);
COPY_NODE_FIELD(havingQual);
@@ -1683,6 +1692,7 @@ _copyQuery(Query *from)
COPY_NODE_FIELD(sortClause);
COPY_NODE_FIELD(limitOffset);
COPY_NODE_FIELD(limitCount);
+ COPY_NODE_FIELD(rowMarks);
COPY_NODE_FIELD(setOperations);
COPY_NODE_FIELD(resultRelations);
@@ -3284,6 +3294,9 @@ copyObject(void *from)
case T_GroupClause:
retval = _copyGroupClause(from);
break;
+ case T_RowMarkClause:
+ retval = _copyRowMarkClause(from);
+ break;
case T_FkConstraint:
retval = _copyFkConstraint(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 94799d0c85f..7f7eb06fbcd 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.270 2006/04/22 01:25:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.271 2006/04/30 18:30:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -665,9 +665,6 @@ _equalQuery(Query *a, Query *b)
COMPARE_SCALAR_FIELD(hasSubLinks);
COMPARE_NODE_FIELD(rtable);
COMPARE_NODE_FIELD(jointree);
- COMPARE_NODE_FIELD(rowMarks);
- COMPARE_SCALAR_FIELD(forUpdate);
- COMPARE_SCALAR_FIELD(rowNoWait);
COMPARE_NODE_FIELD(targetList);
COMPARE_NODE_FIELD(groupClause);
COMPARE_NODE_FIELD(havingQual);
@@ -675,6 +672,7 @@ _equalQuery(Query *a, Query *b)
COMPARE_NODE_FIELD(sortClause);
COMPARE_NODE_FIELD(limitOffset);
COMPARE_NODE_FIELD(limitCount);
+ COMPARE_NODE_FIELD(rowMarks);
COMPARE_NODE_FIELD(setOperations);
COMPARE_NODE_FIELD(resultRelations);
@@ -1688,7 +1686,7 @@ _equalLockingClause(LockingClause *a, LockingClause *b)
{
COMPARE_NODE_FIELD(lockedRels);
COMPARE_SCALAR_FIELD(forUpdate);
- COMPARE_SCALAR_FIELD(nowait);
+ COMPARE_SCALAR_FIELD(noWait);
return true;
}
@@ -1724,6 +1722,16 @@ _equalSortClause(SortClause *a, SortClause *b)
}
static bool
+_equalRowMarkClause(RowMarkClause *a, RowMarkClause *b)
+{
+ COMPARE_SCALAR_FIELD(rti);
+ COMPARE_SCALAR_FIELD(forUpdate);
+ COMPARE_SCALAR_FIELD(noWait);
+
+ return true;
+}
+
+static bool
_equalFkConstraint(FkConstraint *a, FkConstraint *b)
{
COMPARE_STRING_FIELD(constr_name);
@@ -2297,6 +2305,9 @@ equal(void *a, void *b)
/* GroupClause is equivalent to SortClause */
retval = _equalSortClause(a, b);
break;
+ case T_RowMarkClause:
+ retval = _equalRowMarkClause(a, b);
+ break;
case T_FkConstraint:
retval = _equalFkConstraint(a, b);
break;
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 314d68d2ef9..25d3a112799 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.273 2006/04/22 01:25:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.274 2006/04/30 18:30:39 tgl Exp $
*
* NOTES
* Every node type that can appear in stored rules' parsetrees *must*
@@ -1418,7 +1418,7 @@ _outLockingClause(StringInfo str, LockingClause *node)
WRITE_NODE_FIELD(lockedRels);
WRITE_BOOL_FIELD(forUpdate);
- WRITE_BOOL_FIELD(nowait);
+ WRITE_BOOL_FIELD(noWait);
}
static void
@@ -1514,9 +1514,6 @@ _outQuery(StringInfo str, Query *node)
WRITE_BOOL_FIELD(hasSubLinks);
WRITE_NODE_FIELD(rtable);
WRITE_NODE_FIELD(jointree);
- WRITE_NODE_FIELD(rowMarks);
- WRITE_BOOL_FIELD(forUpdate);
- WRITE_BOOL_FIELD(rowNoWait);
WRITE_NODE_FIELD(targetList);
WRITE_NODE_FIELD(groupClause);
WRITE_NODE_FIELD(havingQual);
@@ -1524,6 +1521,7 @@ _outQuery(StringInfo str, Query *node)
WRITE_NODE_FIELD(sortClause);
WRITE_NODE_FIELD(limitOffset);
WRITE_NODE_FIELD(limitCount);
+ WRITE_NODE_FIELD(rowMarks);
WRITE_NODE_FIELD(setOperations);
WRITE_NODE_FIELD(resultRelations);
}
@@ -1547,6 +1545,16 @@ _outGroupClause(StringInfo str, GroupClause *node)
}
static void
+_outRowMarkClause(StringInfo str, RowMarkClause *node)
+{
+ WRITE_NODE_TYPE("ROWMARKCLAUSE");
+
+ WRITE_UINT_FIELD(rti);
+ WRITE_BOOL_FIELD(forUpdate);
+ WRITE_BOOL_FIELD(noWait);
+}
+
+static void
_outSetOperationStmt(StringInfo str, SetOperationStmt *node)
{
WRITE_NODE_TYPE("SETOPERATIONSTMT");
@@ -2113,6 +2121,9 @@ _outNode(StringInfo str, void *obj)
case T_GroupClause:
_outGroupClause(str, obj);
break;
+ case T_RowMarkClause:
+ _outRowMarkClause(str, obj);
+ break;
case T_SetOperationStmt:
_outSetOperationStmt(str, obj);
break;
diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c
index 9fdf02fd568..dd6995a1722 100644
--- a/src/backend/nodes/readfuncs.c
+++ b/src/backend/nodes/readfuncs.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.188 2006/04/22 01:25:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.189 2006/04/30 18:30:39 tgl Exp $
*
* NOTES
* Path and Plan nodes do not have any readfuncs support, because we
@@ -147,9 +147,6 @@ _readQuery(void)
READ_BOOL_FIELD(hasSubLinks);
READ_NODE_FIELD(rtable);
READ_NODE_FIELD(jointree);
- READ_NODE_FIELD(rowMarks);
- READ_BOOL_FIELD(forUpdate);
- READ_BOOL_FIELD(rowNoWait);
READ_NODE_FIELD(targetList);
READ_NODE_FIELD(groupClause);
READ_NODE_FIELD(havingQual);
@@ -157,6 +154,7 @@ _readQuery(void)
READ_NODE_FIELD(sortClause);
READ_NODE_FIELD(limitOffset);
READ_NODE_FIELD(limitCount);
+ READ_NODE_FIELD(rowMarks);
READ_NODE_FIELD(setOperations);
READ_NODE_FIELD(resultRelations);
@@ -220,6 +218,21 @@ _readGroupClause(void)
}
/*
+ * _readRowMarkClause
+ */
+static RowMarkClause *
+_readRowMarkClause(void)
+{
+ READ_LOCALS(RowMarkClause);
+
+ READ_UINT_FIELD(rti);
+ READ_BOOL_FIELD(forUpdate);
+ READ_BOOL_FIELD(noWait);
+
+ READ_DONE();
+}
+
+/*
* _readSetOperationStmt
*/
static SetOperationStmt *
@@ -934,6 +947,8 @@ parseNodeString(void)
return_value = _readSortClause();
else if (MATCH("GROUPCLAUSE", 11))
return_value = _readGroupClause();
+ else if (MATCH("ROWMARKCLAUSE", 13))
+ return_value = _readRowMarkClause();
else if (MATCH("SETOPERATIONSTMT", 16))
return_value = _readSetOperationStmt();
else if (MATCH("ALIAS", 5))
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 9ce72837b9c..f35e87962da 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.144 2006/03/05 15:58:28 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.145 2006/04/30 18:30:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -268,7 +268,7 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
* currently supposes that every rowMark relation is involved in every
* row returned by the query.)
*/
- if (list_member_int(root->parse->rowMarks, parentRTindex))
+ if (get_rowmark(root->parse, parentRTindex))
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("SELECT FOR UPDATE/SHARE is not supported for inheritance queries")));
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index 9750789f0c2..174b20f622a 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.209 2006/04/25 16:54:09 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.210 2006/04/30 18:30:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -843,7 +843,7 @@ create_indexscan_plan(PlannerInfo *root,
if (best_path->indexinfo->indpred)
{
if (baserelid != root->parse->resultRelation &&
- !list_member_int(root->parse->rowMarks, baserelid))
+ get_rowmark(root->parse, baserelid) == NULL)
if (predicate_implied_by(clausel,
best_path->indexinfo->indpred))
continue;
@@ -962,7 +962,7 @@ create_bitmap_scan_plan(PlannerInfo *root,
if (ipath->indexinfo->indpred)
{
if (baserelid != root->parse->resultRelation &&
- !list_member_int(root->parse->rowMarks, baserelid))
+ get_rowmark(root->parse, baserelid) == NULL)
if (predicate_implied_by(clausel,
ipath->indexinfo->indpred))
continue;
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c
index ae538c9cc00..f3b6df46f21 100644
--- a/src/backend/optimizer/prep/prepjointree.c
+++ b/src/backend/optimizer/prep/prepjointree.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.37 2006/03/07 01:00:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.38 2006/04/30 18:30:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -409,29 +409,9 @@ pull_up_simple_subquery(PlannerInfo *root, Node *jtnode, RangeTblEntry *rte,
/*
* Pull up any FOR UPDATE/SHARE markers, too. (OffsetVarNodes
- * already adjusted the marker values, so just list_concat the
- * list.)
- *
- * Executor can't handle multiple FOR UPDATE/SHARE/NOWAIT flags,
- * so complain if they are valid but different
+ * already adjusted the marker rtindexes, so just concat the lists.)
*/
- if (parse->rowMarks && subquery->rowMarks)
- {
- if (parse->forUpdate != subquery->forUpdate)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
- if (parse->rowNoWait != subquery->rowNoWait)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot use both wait and NOWAIT in one query")));
- }
parse->rowMarks = list_concat(parse->rowMarks, subquery->rowMarks);
- if (subquery->rowMarks)
- {
- parse->forUpdate = subquery->forUpdate;
- parse->rowNoWait = subquery->rowNoWait;
- }
/*
* We also have to fix the relid sets of any parent InClauseInfo
diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c
index 5a37b86eb5b..0e06d0e8881 100644
--- a/src/backend/optimizer/prep/preptlist.c
+++ b/src/backend/optimizer/prep/preptlist.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.81 2006/04/05 22:11:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/preptlist.c,v 1.82 2006/04/30 18:30:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -116,7 +116,7 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
* invalid. This is also checked at parse time, but that's
* insufficient because of rule substitution, query pullup, etc.
*/
- CheckSelectLocking(parse, parse->forUpdate);
+ CheckSelectLocking(parse);
/*
* Currently the executor only supports FOR UPDATE/SHARE at top level
@@ -128,19 +128,19 @@ preprocess_targetlist(PlannerInfo *root, List *tlist)
foreach(l, parse->rowMarks)
{
- Index rti = lfirst_int(l);
+ RowMarkClause *rc = (RowMarkClause *) lfirst(l);
Var *var;
char *resname;
TargetEntry *tle;
- var = makeVar(rti,
+ var = makeVar(rc->rti,
SelfItemPointerAttributeNumber,
TIDOID,
-1,
0);
resname = (char *) palloc(32);
- snprintf(resname, 32, "ctid%u", rti);
+ snprintf(resname, 32, "ctid%u", rc->rti);
tle = makeTargetEntry((Expr *) var,
list_length(tlist) + 1,
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 8c0457295c6..3b9e740cadf 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.131 2006/03/05 15:58:31 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.132 2006/04/30 18:30:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -816,7 +816,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
*/
if (rti == parse->resultRelation)
lockmode = RowExclusiveLock;
- else if (list_member_int(parse->rowMarks, rti))
+ else if (get_rowmark(parse, rti))
lockmode = RowShareLock;
else
lockmode = AccessShareLock;
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index d69c0f17864..566c9a0488d 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.333 2006/04/22 01:25:59 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.334 2006/04/30 18:30:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1805,6 +1805,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
{
Query *qry = makeNode(Query);
Node *qual;
+ ListCell *l;
qry->commandType = CMD_SELECT;
@@ -1870,8 +1871,10 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
parseCheckAggregates(pstate, qry);
- if (stmt->lockingClause)
- transformLockingClause(qry, stmt->lockingClause);
+ foreach(l, stmt->lockingClause)
+ {
+ transformLockingClause(qry, (LockingClause *) lfirst(l));
+ }
return qry;
}
@@ -1899,10 +1902,11 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
List *sortClause;
Node *limitOffset;
Node *limitCount;
- LockingClause *lockingClause;
+ List *lockingClause;
Node *node;
ListCell *left_tlist,
- *dtlist;
+ *dtlist,
+ *l;
List *targetvars,
*targetnames,
*sv_relnamespace,
@@ -1942,7 +1946,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
stmt->sortClause = NIL;
stmt->limitOffset = NULL;
stmt->limitCount = NULL;
- stmt->lockingClause = NULL;
+ stmt->lockingClause = NIL;
/* We don't support FOR UPDATE/SHARE with set ops at the moment. */
if (lockingClause)
@@ -2084,8 +2088,10 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
if (pstate->p_hasAggs || qry->groupClause || qry->havingQual)
parseCheckAggregates(pstate, qry);
- if (lockingClause)
- transformLockingClause(qry, lockingClause);
+ foreach(l, lockingClause)
+ {
+ transformLockingClause(qry, (LockingClause *) lfirst(l));
+ }
return qry;
}
@@ -2743,44 +2749,34 @@ transformExecuteStmt(ParseState *pstate, ExecuteStmt *stmt)
/* exported so planner can check again after rewriting, query pullup, etc */
void
-CheckSelectLocking(Query *qry, bool forUpdate)
+CheckSelectLocking(Query *qry)
{
- const char *operation;
-
- if (forUpdate)
- operation = "SELECT FOR UPDATE";
- else
- operation = "SELECT FOR SHARE";
-
if (qry->setOperations)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- /* translator: %s is a SQL command, like SELECT FOR UPDATE */
- errmsg("%s is not allowed with UNION/INTERSECT/EXCEPT", operation)));
+ errmsg("SELECT FOR UPDATE/SHARE is not allowed with UNION/INTERSECT/EXCEPT")));
if (qry->distinctClause != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- /* translator: %s is a SQL command, like SELECT FOR UPDATE */
- errmsg("%s is not allowed with DISTINCT clause", operation)));
+ errmsg("SELECT FOR UPDATE/SHARE is not allowed with DISTINCT clause")));
if (qry->groupClause != NIL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- /* translator: %s is a SQL command, like SELECT FOR UPDATE */
- errmsg("%s is not allowed with GROUP BY clause", operation)));
+ errmsg("SELECT FOR UPDATE/SHARE is not allowed with GROUP BY clause")));
if (qry->havingQual != NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- /* translator: %s is a SQL command, like SELECT FOR UPDATE */
- errmsg("%s is not allowed with HAVING clause", operation)));
+ errmsg("SELECT FOR UPDATE/SHARE is not allowed with HAVING clause")));
if (qry->hasAggs)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- /* translator: %s is a SQL command, like SELECT FOR UPDATE */
- errmsg("%s is not allowed with aggregate functions", operation)));
+ errmsg("SELECT FOR UPDATE/SHARE is not allowed with aggregate functions")));
}
/*
- * Convert FOR UPDATE/SHARE name list into rowMarks list of integer relids
+ * Transform a FOR UPDATE/SHARE clause
+ *
+ * This basically involves replacing names by integer relids.
*
* NB: if you need to change this, see also markQueryForLocking()
* in rewriteHandler.c.
@@ -2789,35 +2785,18 @@ static void
transformLockingClause(Query *qry, LockingClause *lc)
{
List *lockedRels = lc->lockedRels;
- List *rowMarks;
ListCell *l;
ListCell *rt;
Index i;
LockingClause *allrels;
- 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);
+ CheckSelectLocking(qry);
/* 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;
-
- rowMarks = qry->rowMarks;
+ allrels->noWait = lc->noWait;
if (lockedRels == NIL)
{
@@ -2831,8 +2810,7 @@ transformLockingClause(Query *qry, LockingClause *lc)
switch (rte->rtekind)
{
case RTE_RELATION:
- /* use list_append_unique to avoid duplicates */
- rowMarks = list_append_unique_int(rowMarks, i);
+ applyLockingClause(qry, i, lc->forUpdate, lc->noWait);
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
break;
case RTE_SUBQUERY:
@@ -2867,8 +2845,8 @@ transformLockingClause(Query *qry, LockingClause *lc)
switch (rte->rtekind)
{
case RTE_RELATION:
- /* use list_append_unique to avoid duplicates */
- rowMarks = list_append_unique_int(rowMarks, i);
+ applyLockingClause(qry, i,
+ lc->forUpdate, lc->noWait);
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
break;
case RTE_SUBQUERY:
@@ -2909,8 +2887,41 @@ transformLockingClause(Query *qry, LockingClause *lc)
relname)));
}
}
+}
+
+/*
+ * Record locking info for a single rangetable item
+ */
+void
+applyLockingClause(Query *qry, Index rtindex, bool forUpdate, bool noWait)
+{
+ RowMarkClause *rc;
+
+ /* Check for pre-existing entry for same rtindex */
+ if ((rc = get_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.)
+ *
+ * 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. (Consider for instance SELECT FOR UPDATE NOWAIT
+ * from a view that internally contains a plain FOR UPDATE spec.)
+ */
+ rc->forUpdate |= forUpdate;
+ rc->noWait |= noWait;
+ return;
+ }
- qry->rowMarks = rowMarks;
+ /* Make a new RowMarkClause */
+ rc = makeNode(RowMarkClause);
+ rc->rti = rtindex;
+ rc->forUpdate = forUpdate;
+ rc->noWait = noWait;
+ qry->rowMarks = lappend(qry->rowMarks, rc);
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 8870261e441..69e7a201425 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.543 2006/04/27 00:33:45 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.544 2006/04/30 18:30:39 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -96,7 +96,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, Node *lockingClause,
+ List *sortClause, List *lockingClause,
Node *limitOffset, Node *limitCount);
static Node *makeSetOp(SetOperation op, bool all, Node *larg, Node *rarg);
static Node *doNegate(Node *n, int location);
@@ -253,7 +253,8 @@ static void doNegateFloat(Value *v);
%type <oncommit> OnCommitOption
%type <withoids> OptWithOids
-%type <node> for_locking_clause opt_for_locking_clause
+%type <node> for_locking_item
+%type <list> for_locking_clause opt_for_locking_clause for_locking_items
%type <list> locked_rels_list
%type <boolean> opt_all
@@ -5400,7 +5401,7 @@ select_no_parens:
simple_select { $$ = $1; }
| select_clause sort_clause
{
- insertSelectOptions((SelectStmt *) $1, $2, NULL,
+ insertSelectOptions((SelectStmt *) $1, $2, NIL,
NULL, NULL);
$$ = $1;
}
@@ -5644,12 +5645,27 @@ having_clause:
;
for_locking_clause:
+ for_locking_items { $$ = $1; }
+ | FOR READ ONLY { $$ = NIL; }
+ ;
+
+opt_for_locking_clause:
+ for_locking_clause { $$ = $1; }
+ | /* EMPTY */ { $$ = NIL; }
+ ;
+
+for_locking_items:
+ for_locking_item { $$ = list_make1($1); }
+ | for_locking_items for_locking_item { $$ = lappend($1, $2); }
+ ;
+
+for_locking_item:
FOR UPDATE locked_rels_list opt_nowait
{
LockingClause *n = makeNode(LockingClause);
n->lockedRels = $3;
n->forUpdate = TRUE;
- n->nowait = $4;
+ n->noWait = $4;
$$ = (Node *) n;
}
| FOR SHARE locked_rels_list opt_nowait
@@ -5657,15 +5673,9 @@ for_locking_clause:
LockingClause *n = makeNode(LockingClause);
n->lockedRels = $3;
n->forUpdate = FALSE;
- n->nowait = $4;
+ n->noWait = $4;
$$ = (Node *) n;
}
- | FOR READ ONLY { $$ = NULL; }
- ;
-
-opt_for_locking_clause:
- for_locking_clause { $$ = $1; }
- | /* EMPTY */ { $$ = NULL; }
;
locked_rels_list:
@@ -8976,7 +8986,7 @@ findLeftmostSelect(SelectStmt *node)
*/
static void
insertSelectOptions(SelectStmt *stmt,
- List *sortClause, Node *lockingClause,
+ List *sortClause, List *lockingClause,
Node *limitOffset, Node *limitCount)
{
/*
@@ -8991,14 +9001,8 @@ insertSelectOptions(SelectStmt *stmt,
errmsg("multiple ORDER BY clauses not allowed")));
stmt->sortClause = sortClause;
}
- if (lockingClause)
- {
- if (stmt->lockingClause)
- ereport(ERROR,
- (errcode(ERRCODE_SYNTAX_ERROR),
- errmsg("multiple FOR UPDATE/FOR SHARE clauses not allowed")));
- stmt->lockingClause = (LockingClause *) lockingClause;
- }
+ /* We can handle multiple locking clauses, though */
+ stmt->lockingClause = list_concat(stmt->lockingClause, lockingClause);
if (limitOffset)
{
if (stmt->limitOffset)
diff --git a/src/backend/parser/parse_relation.c b/src/backend/parser/parse_relation.c
index d3e138e8ecb..10f71712ff6 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.122 2006/03/23 00:19:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.123 2006/04/30 18:30:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1001,6 +1001,8 @@ addRangeTableEntryForJoin(ParseState *pstate,
/*
* Has the specified refname been selected FOR UPDATE/FOR SHARE?
+ *
+ * Note: we pay no attention to whether it's FOR UPDATE vs FOR SHARE.
*/
static bool
isLockedRel(ParseState *pstate, char *refname)
@@ -1008,9 +1010,13 @@ isLockedRel(ParseState *pstate, char *refname)
/* Outer loop to check parent query levels as well as this one */
while (pstate != NULL)
{
- if (pstate->p_locking_clause)
+ ListCell *l;
+
+ foreach(l, pstate->p_locking_clause)
{
- if (pstate->p_locking_clause->lockedRels == NIL)
+ LockingClause *lc = (LockingClause *) lfirst(l);
+
+ if (lc->lockedRels == NIL)
{
/* all tables used in query */
return true;
@@ -1018,11 +1024,11 @@ isLockedRel(ParseState *pstate, char *refname)
else
{
/* just the named tables */
- ListCell *l;
+ ListCell *l2;
- foreach(l, pstate->p_locking_clause->lockedRels)
+ foreach(l2, lc->lockedRels)
{
- char *rname = strVal(lfirst(l));
+ char *rname = strVal(lfirst(l2));
if (strcmp(refname, rname) == 0)
return true;
@@ -1703,6 +1709,26 @@ get_tle_by_resno(List *tlist, AttrNumber resno)
}
/*
+ * Given a Query and rangetable index, return relation's RowMarkClause if any
+ *
+ * Returns NULL if relation is not selected FOR UPDATE/SHARE
+ */
+RowMarkClause *
+get_rowmark(Query *qry, Index rtindex)
+{
+ ListCell *l;
+
+ foreach(l, qry->rowMarks)
+ {
+ RowMarkClause *rc = (RowMarkClause *) lfirst(l);
+
+ if (rc->rti == rtindex)
+ return rc;
+ }
+ return NULL;
+}
+
+/*
* given relation and att name, return attnum of variable
*
* Returns InvalidAttrNumber if the attr doesn't exist (or is dropped).
diff --git a/src/backend/parser/parse_type.c b/src/backend/parser/parse_type.c
index fec4552c9c4..5965bf5ae41 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.80 2006/04/04 19:35:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/parse_type.c,v 1.81 2006/04/30 18:30:39 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->lockingClause != NULL ||
+ stmt->lockingClause != NIL ||
stmt->op != SETOP_NONE)
goto fail;
if (list_length(stmt->targetList) != 1)
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 6d1ace66f1a..d3052f8da2a 100644
--- a/src/backend/rewrite/rewriteHandler.c
+++ b/src/backend/rewrite/rewriteHandler.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.162 2006/04/05 22:11:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteHandler.c,v 1.163 2006/04/30 18:30:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -130,7 +130,7 @@ AcquireRewriteLocks(Query *parsetree)
*/
if (rt_index == parsetree->resultRelation)
lockmode = RowExclusiveLock;
- else if (list_member_int(parsetree->rowMarks, rt_index))
+ else if (get_rowmark(parsetree, rt_index))
lockmode = RowShareLock;
else
lockmode = AccessShareLock;
@@ -907,6 +907,7 @@ ApplyRetrieveRule(Query *parsetree,
Query *rule_action;
RangeTblEntry *rte,
*subrte;
+ RowMarkClause *rc;
if (list_length(rule->actions) != 1)
elog(ERROR, "expected just one rule action");
@@ -954,20 +955,20 @@ ApplyRetrieveRule(Query *parsetree,
/*
* FOR UPDATE/SHARE of view?
*/
- if (list_member_int(parsetree->rowMarks, rt_index))
+ if ((rc = get_rowmark(parsetree, rt_index)) != NULL)
{
/*
* Remove the view from the list of rels that will actually be marked
- * FOR UPDATE/SHARE by the executor. It will still be access- checked
+ * FOR UPDATE/SHARE by the executor. It will still be access-checked
* for write access, though.
*/
- parsetree->rowMarks = list_delete_int(parsetree->rowMarks, rt_index);
+ parsetree->rowMarks = list_delete_ptr(parsetree->rowMarks, rc);
/*
* Set up the view's referenced tables as if FOR UPDATE/SHARE.
*/
- markQueryForLocking(rule_action, parsetree->forUpdate,
- parsetree->rowNoWait, true);
+ markQueryForLocking(rule_action, rc->forUpdate,
+ rc->noWait, true);
}
return parsetree;
@@ -987,20 +988,6 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
Index rti = 0;
ListCell *l;
- if (qry->rowMarks)
- {
- if (forUpdate != qry->forUpdate)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot use both FOR UPDATE and FOR SHARE in one query")));
- if (noWait != qry->rowNoWait)
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("cannot use both wait and NOWAIT in one query")));
- }
- qry->forUpdate = forUpdate;
- qry->rowNoWait = noWait;
-
foreach(l, qry->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(l);
@@ -1014,7 +1001,7 @@ markQueryForLocking(Query *qry, bool forUpdate, bool noWait, bool skipOldNew)
if (rte->rtekind == RTE_RELATION)
{
- qry->rowMarks = list_append_unique_int(qry->rowMarks, rti);
+ applyLockingClause(qry, rti, forUpdate, noWait);
rte->requiredPerms |= ACL_SELECT_FOR_UPDATE;
}
else if (rte->rtekind == RTE_SUBQUERY)
diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c
index 175df7a695a..906e7c4a04b 100644
--- a/src/backend/rewrite/rewriteManip.c
+++ b/src/backend/rewrite/rewriteManip.c
@@ -7,7 +7,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.98 2006/04/05 22:11:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/rewrite/rewriteManip.c,v 1.99 2006/04/30 18:30:39 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -240,7 +240,11 @@ OffsetVarNodes(Node *node, int offset, int sublevels_up)
if (qry->resultRelation)
qry->resultRelation += offset;
foreach(l, qry->rowMarks)
- lfirst_int(l) += offset;
+ {
+ RowMarkClause *rc = (RowMarkClause *) lfirst(l);
+
+ rc->rti += offset;
+ }
}
query_tree_walker(qry, OffsetVarNodes_walker,
(void *) &context, 0);
@@ -395,8 +399,10 @@ ChangeVarNodes(Node *node, int rt_index, int new_index, int sublevels_up)
qry->resultRelation = new_index;
foreach(l, qry->rowMarks)
{
- if (lfirst_int(l) == rt_index)
- lfirst_int(l) = new_index;
+ RowMarkClause *rc = (RowMarkClause *) lfirst(l);
+
+ if (rc->rti == rt_index)
+ rc->rti = new_index;
}
}
query_tree_walker(qry, ChangeVarNodes_walker,
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index b54d50702b0..5729b58450a 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.256 2006/04/15 17:45:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.257 2006/04/30 18:30:40 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1796,7 +1796,7 @@ CreateQueryTag(Query *parsetree)
tag = "SELECT INTO";
else if (parsetree->rowMarks != NIL)
{
- if (parsetree->forUpdate)
+ if (((RowMarkClause *) linitial(parsetree->rowMarks))->forUpdate)
tag = "SELECT FOR UPDATE";
else
tag = "SELECT FOR SHARE";
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index c0db64bf896..67897a2938a 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -2,7 +2,7 @@
* ruleutils.c - Functions to convert stored expressions/querytrees
* back to source text
*
- * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.220 2006/04/22 01:26:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.221 2006/04/30 18:30:40 tgl Exp $
**********************************************************************/
#include "postgres.h"
@@ -1858,27 +1858,21 @@ get_select_query_def(Query *query, deparse_context *context,
get_rule_expr(query->limitCount, context, false);
}
- /* Add the FOR UPDATE/SHARE clause if present */
- if (query->rowMarks != NIL)
+ /* Add FOR UPDATE/SHARE clauses if present */
+ foreach(l, query->rowMarks)
{
- if (query->forUpdate)
- appendContextKeyword(context, " FOR UPDATE OF ",
+ RowMarkClause *rc = (RowMarkClause *) lfirst(l);
+ RangeTblEntry *rte = rt_fetch(rc->rti, query->rtable);
+
+ if (rc->forUpdate)
+ appendContextKeyword(context, " FOR UPDATE",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
else
- appendContextKeyword(context, " FOR SHARE OF ",
+ appendContextKeyword(context, " FOR SHARE",
-PRETTYINDENT_STD, PRETTYINDENT_STD, 0);
- sep = "";
- foreach(l, query->rowMarks)
- {
- int rtindex = lfirst_int(l);
- RangeTblEntry *rte = rt_fetch(rtindex, query->rtable);
-
- appendStringInfo(buf, "%s%s",
- sep,
- quote_identifier(rte->eref->aliasname));
- sep = ", ";
- }
- if (query->rowNoWait)
+ appendStringInfo(buf, " OF %s",
+ quote_identifier(rte->eref->aliasname));
+ if (rc->noWait)
appendStringInfo(buf, " NOWAIT");
}
}