diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 8e7097c9619160931d9beeac19dbcf8635a077e9..72735873c4e5336f076b7e450308a453b93a8ab7 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -4,7 +4,7 @@
  *						  procedural language
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.82 2005/10/13 15:34:19 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.83 2006/02/12 04:59:32 tgl Exp $
  *
  *	  This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -881,9 +881,15 @@ for_control		:
 							new->cmd_type = PLPGSQL_STMT_DYNFORS;
 							new->lineno   = $1;
 							if ($2.rec)
+							{
 								new->rec = $2.rec;
+								check_assignable((PLpgSQL_datum *) new->rec);
+							}
 							else if ($2.row)
+							{
 								new->row = $2.row;
+								check_assignable((PLpgSQL_datum *) new->row);
+							}
 							else
 							{
 								plpgsql_error_lineno = $1;
@@ -942,6 +948,7 @@ for_control		:
 
 								expr2 = plpgsql_read_expression(K_LOOP, "LOOP");
 
+								/* create loop's private variable */
 								fvar = (PLpgSQL_var *)
 									plpgsql_build_variable($2.name,
 														   $2.lineno,
@@ -986,9 +993,15 @@ for_control		:
 								new->cmd_type = PLPGSQL_STMT_FORS;
 								new->lineno   = $1;
 								if ($2.rec)
+								{
 									new->rec = $2.rec;
+									check_assignable((PLpgSQL_datum *) new->rec);
+								}
 								else if ($2.row)
+								{
 									new->row = $2.row;
+									check_assignable((PLpgSQL_datum *) new->row);
+								}
 								else
 								{
 									plpgsql_error_lineno = $1;
@@ -1002,6 +1015,17 @@ for_control		:
 					}
 				;
 
+/*
+ * Processing the for_variable is tricky because we don't yet know if the
+ * FOR is an integer FOR loop or a loop over query results.  In the former
+ * case, the variable is just a name that we must instantiate as a loop
+ * local variable, regardless of any other definition it might have.
+ * Therefore, we always save the actual identifier into $$.name where it
+ * can be used for that case.  We also save the outer-variable definition,
+ * if any, because that's what we need for the loop-over-query case.  Note
+ * that we must NOT apply check_assignable() or any other semantic check
+ * until we know what's what.
+ */
 for_variable	: T_SCALAR
 					{
 						char		*name;
@@ -1304,13 +1328,13 @@ stmt_dynexecute : K_EXECUTE lno
 							switch (yylex())
 							{
 								case T_ROW:
-									check_assignable((PLpgSQL_datum *) yylval.row);
 									new->row = yylval.row;
+									check_assignable((PLpgSQL_datum *) new->row);
 									break;
 
 								case T_RECORD:
-									check_assignable((PLpgSQL_datum *) yylval.row);
 									new->rec = yylval.rec;
+									check_assignable((PLpgSQL_datum *) new->rec);
 									break;
 
 								case T_SCALAR:
@@ -1917,11 +1941,13 @@ make_select_stmt(void)
 			{
 				case T_ROW:
 					row = yylval.row;
+					check_assignable((PLpgSQL_datum *) row);
 					have_into = true;
 					break;
 
 				case T_RECORD:
 					rec = yylval.rec;
+					check_assignable((PLpgSQL_datum *) rec);
 					have_into = true;
 					break;
 
@@ -2028,10 +2054,12 @@ make_fetch_stmt(void)
 	{
 		case T_ROW:
 			row = yylval.row;
+			check_assignable((PLpgSQL_datum *) row);
 			break;
 
 		case T_RECORD:
 			rec = yylval.rec;
+			check_assignable((PLpgSQL_datum *) rec);
 			break;
 
 		case T_SCALAR:
@@ -2039,7 +2067,12 @@ make_fetch_stmt(void)
 			break;
 
 		default:
-			yyerror("syntax error");
+			plpgsql_error_lineno = plpgsql_scanner_lineno();
+			ereport(ERROR,
+					(errcode(ERRCODE_SYNTAX_ERROR),
+					 errmsg("syntax error at \"%s\"", yytext),
+					 errdetail("Expected record variable, row variable, "
+							   "or list of scalar variables.")));
 	}
 
 	tok = yylex();
@@ -2136,13 +2169,13 @@ read_into_scalar_list(const char *initial_name,
 				plpgsql_error_lineno = plpgsql_scanner_lineno();
 				ereport(ERROR,
 						(errcode(ERRCODE_SYNTAX_ERROR),
-						 errmsg("\"%s\" is not a variable",
+						 errmsg("\"%s\" is not a scalar variable",
 								yytext)));
 		}
 	}
 
 	/*
-	 * We read an extra, non-comma character from yylex(), so push it
+	 * We read an extra, non-comma token from yylex(), so push it
 	 * back onto the input stream
 	 */
 	plpgsql_push_back_token(tok);