diff --git a/src/backend/optimizer/plan/initsplan.c b/src/backend/optimizer/plan/initsplan.c
index eec153b70d3338552b124f52682da8b7813b59c6..58a9e16eb65f9369657e9ab119099b3e8c58ee81 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 d6fbc6b3d76768377ffd40a04cde408bfd589c6c..f30fcdd2793fea41e81715f901a4a67762afae50 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)