aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-11-05 22:00:46 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-11-05 22:00:46 +0000
commite4044ba2d7487839ae7113074a65f1457fda56d7 (patch)
tree5b4bdc8a14f8502cb11b70880c30d7a09b88e160 /src
parent622736aa4a834caf35867ab75d744dfd7d8f44f8 (diff)
downloadpostgresql-e4044ba2d7487839ae7113074a65f1457fda56d7.tar.gz
postgresql-e4044ba2d7487839ae7113074a65f1457fda56d7.zip
Fix for this problem:
regression=# select 1 from tenk1 ta cross join tenk1 tb for update; ERROR: no relation entry for relid 3 7.3 said "SELECT FOR UPDATE cannot be applied to a join", which was better but still wrong, considering that 7.2 took the query just fine. Fix by making transformForUpdate() ignore JOIN and other special RTE types, rather than trying to mark them FOR UPDATE. The actual error message now only appears if you explicitly name the join in FOR UPDATE.
Diffstat (limited to 'src')
-rw-r--r--src/backend/optimizer/plan/initsplan.c10
-rw-r--r--src/backend/parser/analyze.c78
2 files changed, 58 insertions, 30 deletions
diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index eec153b70d3..58a9e16eb65 100644
--- a/src/backend/optimizer/plan/initsplan.c
+++ b/src/backend/optimizer/plan/initsplan.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.91 2003/09/25 06:58:00 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/plan/initsplan.c,v 1.92 2003/11/05 22:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -91,14 +91,6 @@ add_base_rels_to_query(Query *root, Node *jtnode)
add_base_rels_to_query(root, j->larg);
add_base_rels_to_query(root, j->rarg);
-
- /*
- * Safety check: join RTEs should not be SELECT FOR UPDATE targets
- */
- if (intMember(j->rtindex, root->rowMarks))
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("SELECT FOR UPDATE cannot be applied to a join")));
}
else
elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index d6fbc6b3d76..f30fcdd2793 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.290 2003/10/02 06:32:45 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.291 2003/11/05 22:00:46 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2821,6 +2821,12 @@ CheckSelectForUpdate(Query *qry)
errmsg("SELECT FOR UPDATE is not allowed with aggregate functions")));
}
+/*
+ * Convert FOR UPDATE name list into rowMarks list of integer relids
+ *
+ * NB: if you need to change this, see also markQueryForUpdate()
+ * in rewriteHandler.c.
+ */
static void
transformForUpdate(Query *qry, List *forUpdate)
{
@@ -2833,23 +2839,30 @@ transformForUpdate(Query *qry, List *forUpdate)
if (lfirst(forUpdate) == NULL)
{
- /* all tables used in query */
+ /* all regular tables used in query */
i = 0;
foreach(rt, qry->rtable)
{
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
++i;
- if (rte->rtekind == RTE_SUBQUERY)
- {
- /* FOR UPDATE of subquery is propagated to subquery's rels */
- transformForUpdate(rte->subquery, makeList1(NULL));
- }
- else
+ switch (rte->rtekind)
{
- if (!intMember(i, rowMarks)) /* avoid duplicates */
- rowMarks = lappendi(rowMarks, i);
- rte->checkForWrite = true;
+ case RTE_RELATION:
+ if (!intMember(i, rowMarks)) /* avoid duplicates */
+ rowMarks = lappendi(rowMarks, i);
+ rte->checkForWrite = true;
+ break;
+ case RTE_SUBQUERY:
+ /*
+ * FOR UPDATE of subquery is propagated to subquery's
+ * rels
+ */
+ transformForUpdate(rte->subquery, makeList1(NULL));
+ break;
+ default:
+ /* ignore JOIN, SPECIAL, FUNCTION RTEs */
+ break;
}
}
}
@@ -2868,18 +2881,41 @@ transformForUpdate(Query *qry, List *forUpdate)
++i;
if (strcmp(rte->eref->aliasname, relname) == 0)
{
- if (rte->rtekind == RTE_SUBQUERY)
+ switch (rte->rtekind)
{
- /* propagate to subquery */
- transformForUpdate(rte->subquery, makeList1(NULL));
- }
- else
- {
- if (!intMember(i, rowMarks)) /* avoid duplicates */
- rowMarks = lappendi(rowMarks, i);
- rte->checkForWrite = true;
+ case RTE_RELATION:
+ if (!intMember(i, rowMarks)) /* avoid duplicates */
+ rowMarks = lappendi(rowMarks, i);
+ rte->checkForWrite = true;
+ break;
+ case RTE_SUBQUERY:
+ /*
+ * FOR UPDATE of subquery is propagated to
+ * subquery's rels
+ */
+ transformForUpdate(rte->subquery, makeList1(NULL));
+ break;
+ case RTE_JOIN:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("SELECT FOR UPDATE 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")));
+ break;
+ case RTE_FUNCTION:
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("SELECT FOR UPDATE cannot be applied to a function")));
+ break;
+ default:
+ elog(ERROR, "unrecognized RTE type: %d",
+ (int) rte->rtekind);
+ break;
}
- break;
+ break; /* out of foreach loop */
}
}
if (rt == NIL)