diff -u src.orig/pl_comp.c src/pl_comp.c
--- src.orig/pl_comp.c	2004-11-19 14:01:15.053237796 +0000
+++ src/pl_comp.c	2004-11-19 14:23:04.192899809 +0000
@@ -783,6 +783,75 @@
 	return T_WORD;
 }
 
+/* ----------
+ * plpgsql_parse_wordexpr		Same lookup for word followed by dot.
+ *                              Should only get here if it wasn't followed by
+ *                              an identifier.
+ * ----------
+ */
+int
+plpgsql_parse_wordexpr(char *word)
+{
+	PLpgSQL_nsitem *ns;
+	char	   *cp[1];
+    int			save_spacescanned = plpgsql_SpaceScanned;
+
+	/* Do case conversion and word separation */
+	/* drop dot to keep converter happy */
+    word[strlen(word) - 1] = '\0';
+    plpgsql_convert_ident(word, cp, 1);
+
+    /* Make sure we've got an open parenthesis */
+	
+    /*
+	 * Do a lookup on the compilers namestack
+	 */
+	ns = plpgsql_ns_lookup(cp[0], NULL);
+	if (ns == NULL)
+	{
+		pfree(cp[0]);
+		return T_ERROR;
+	}
+    switch (ns->itemtype)
+    {
+		case PLPGSQL_NSTYPE_REC:
+			{
+				/*
+				 * First word is a record name, so expression refers to
+				 * field in this record.
+				 */
+				PLpgSQL_recfield *new;
+
+				new = malloc(sizeof(PLpgSQL_recfield));
+                memset(new, 0, sizeof(PLpgSQL_recfield));
+                
+                if (plpgsql_yylex() != '(')
+                    plpgsql_yyerror("expected identifier or \"(\"");
+                new->expr = plpgsql_read_expression(')', ")");
+				new->recparentno = ns->itemno;
+                /* just to be sure - we'll test on this later */
+                new->fieldname = '\0';
+				new->dtype = PLPGSQL_DTYPE_RECFIELD;
+                
+                plpgsql_adddatum((PLpgSQL_datum *) new);
+
+				plpgsql_yylval.scalar = (PLpgSQL_datum *) new;
+                
+                plpgsql_SpaceScanned = save_spacescanned;
+
+				pfree(cp[0]);
+				return T_SCALAR;
+			}
+            
+        /* TODO: deal with rows, too */        
+		
+        default:
+			break;
+
+    }
+	pfree(cp[0]);
+	return T_ERROR;
+}
 
 /* ----------
  * plpgsql_parse_dblword		Same lookup for two words
diff -u src.orig/pl_exec.c src/pl_exec.c
--- src.orig/pl_exec.c	2004-11-19 14:01:15.053237796 +0000
+++ src/pl_exec.c	2004-11-19 15:20:33.160897466 +0000
@@ -2965,7 +2965,8 @@
 				PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
 				PLpgSQL_rec *rec;
 				int			fno;
-				HeapTuple	newtup;
+                char        *fname;
+                HeapTuple	newtup;
 				int			natts;
 				int			i;
 				Datum	   *values;
@@ -2974,7 +2975,7 @@
 				bool		attisnull;
 				Oid			atttype;
 				int32		atttypmod;
-
+                
 				rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
 
 				/*
@@ -2988,20 +2989,71 @@
 					   errmsg("record \"%s\" is not assigned yet",
 							  rec->refname),
 					   errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
-
-				/*
+                
+                
+                /* Have we got an expr to deal with? */
+                fno = 0;
+                fname = '\0';
+                if (recfield->fieldname == '\0') 
+                {
+                    Datum		exprdatum;
+                    Oid			exprtype;
+                    bool        *exprisnull;
+                    
+                    /* Evaluate expression */
+                    exprdatum = exec_eval_expr(estate, recfield->expr, 
+                                    exprisnull, &exprtype);
+                                    
+                    /* If we've got an integer, it's a field number, otherwise
+                     * it's a fieldname
+                     */
+                    if (exprtype == INT4OID) {
+                        exprdatum = exec_simple_cast_value(exprdatum, 
+                                                           exprtype,
+                                                           INT4OID, -1,
+                                                           exprisnull);
+                        fno = DatumGetInt32(exprdatum);
+                    }
+                    else {
+                        fname = convert_value_to_string(
+                                                exprdatum, exprtype);
+                    }
+                    
+                    /* do we need to free datum? */
+                }
+			    else {
+                    fname = recfield->fieldname;
+                }
+                
+                
+                /*
 				 * Get the number of the records field to change and the
-				 * number of attributes in the tuple.
+				 * number of attributes in the tuple, if we didn't get it
+                 * above.
 				 */
-				fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
-				if (fno == SPI_ERROR_NOATTRIBUTE)
-					ereport(ERROR,
-							(errcode(ERRCODE_UNDEFINED_COLUMN),
-							 errmsg("record \"%s\" has no field \"%s\"",
-									rec->refname, recfield->fieldname)));
-				fno--;
-				natts = rec->tupdesc->natts;
+                if (fno < 1) 
+                {
+                    fno = SPI_fnumber(rec->tupdesc, fname);
+                    if (fno == SPI_ERROR_NOATTRIBUTE)
+                        ereport(ERROR,
+                                (errcode(ERRCODE_UNDEFINED_COLUMN),
+                                 errmsg("record \"%s\" has no field \"%s\"",
+                                        rec->refname, fname)));
+				}
+                fno--;
+                natts = rec->tupdesc->natts;
+                
+                /*
+                 * Check that fno is within range
+                 */
+                if (fno >= natts) {
+                    ereport(ERROR,
+                            (errcode(ERRCODE_UNDEFINED_COLUMN),
+                             errmsg("record \"%s\" has no field number \"%d\"",
+                                    rec->refname, fno)));
 
+                }
+                
 				/*
 				 * Set up values/datums arrays for heap_formtuple.	For
 				 * all the attributes except the one we want to replace,
@@ -3297,7 +3349,8 @@
 				PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
 				PLpgSQL_rec *rec;
 				int			fno;
-
+                char        *fname;
+                
 				rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
 				if (!HeapTupleIsValid(rec->tup))
 					ereport(ERROR,
@@ -3305,19 +3358,73 @@
 					   errmsg("record \"%s\" is not assigned yet",
 							  rec->refname),
 					   errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
-				fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
-				if (fno == SPI_ERROR_NOATTRIBUTE)
-					ereport(ERROR,
-							(errcode(ERRCODE_UNDEFINED_COLUMN),
-							 errmsg("record \"%s\" has no field \"%s\"",
-									rec->refname, recfield->fieldname)));
-				*typeid = SPI_gettypeid(rec->tupdesc, fno);
+                
+                /* Have we got an expr to deal with? */
+                fno = 0;
+                fname = '\0';
+                if (recfield->fieldname == '\0') 
+                {
+                    Datum		exprdatum;
+                    Oid			exprtype;
+                    bool        *exprisnull;
+                    
+                    /* Evaluate expression */
+                    exprdatum = exec_eval_expr(estate, recfield->expr, 
+                                    exprisnull, &exprtype);
+                                    
+                    
+                    /* If we've got an integer, it's a field number, otherwise
+                     * it's a fieldname
+                     */
+                    if (exprtype == INT4OID) {
+                        exprdatum = exec_simple_cast_value(exprdatum, 
+                                                           exprtype,
+                                                           INT4OID, -1,
+                                                           exprisnull);
+                        fno = DatumGetInt32(exprdatum);
+                    }
+                    else {
+                        fname = convert_value_to_string(
+                                                exprdatum, exprtype);
+                    }
+                }
+                else {
+                    fname = recfield->fieldname;
+                }
+                
+                /*
+				 * Get the number of the records field to change and the
+				 * number of attributes in the tuple.
+				 */
+                if (fno < 1) 
+                {
+                    fno = SPI_fnumber(rec->tupdesc, fname);
+                    if (fno == SPI_ERROR_NOATTRIBUTE)
+                        ereport(ERROR,
+                                (errcode(ERRCODE_UNDEFINED_COLUMN),
+                                 errmsg("record \"%s\" has no field \"%s\"",
+                                        rec->refname, fname)));
+				}
+				
+                *typeid = SPI_gettypeid(rec->tupdesc, fno);
 				*value = SPI_getbinval(rec->tup, rec->tupdesc, fno, isnull);
-				if (expectedtypeid != InvalidOid && expectedtypeid != *typeid)
-					ereport(ERROR,
+                if (*value == SPI_ERROR_NOATTRIBUTE)
+                    ereport(ERROR,
+                            (errcode(ERRCODE_UNDEFINED_COLUMN),
+                             errmsg("record \"%s\" has no field number \"%d\"",
+                                    rec->refname, fno)));
+			    	
+                if (expectedtypeid != InvalidOid && expectedtypeid != *typeid)
+					/* 
+                     * If an expression is used to determine the fieldname and
+                     * the type of that field changes, we'll end up here.
+                     * Should we cast it to the original type, or just throw
+                     * an error?
+                     */
+                    ereport(ERROR,
 							(errcode(ERRCODE_DATATYPE_MISMATCH),
 							 errmsg("type of \"%s.%s\" does not match that when preparing the plan",
-									rec->refname, recfield->fieldname)));
+									rec->refname, fname)));
 				break;
 			}
 
diff -u src.orig/plpgsql.h src/plpgsql.h
--- src.orig/plpgsql.h	2004-11-19 14:01:15.054237644 +0000
+++ src/plpgsql.h	2004-11-19 14:23:17.751845320 +0000
@@ -269,6 +269,7 @@
 	int			dtype;
 	int			rfno;
 	char	   *fieldname;
+	PLpgSQL_expr *expr;
 	int			recparentno;	/* dno of parent record */
 } PLpgSQL_recfield;
 
@@ -675,6 +676,7 @@
 extern PLpgSQL_function *plpgsql_compile(FunctionCallInfo fcinfo,
 				bool forValidator);
 extern int	plpgsql_parse_word(char *word);
+extern int	plpgsql_parse_wordexpr(char *word);
 extern int	plpgsql_parse_dblword(char *word);
 extern int	plpgsql_parse_tripword(char *word);
 extern int	plpgsql_parse_wordtype(char *word);
diff -u src.orig/scan.l src/scan.l
--- src.orig/scan.l	2004-11-19 14:01:15.054237644 +0000
+++ src/scan.l	2004-11-19 14:31:24.079117322 +0000
@@ -195,6 +195,9 @@
 {identifier}					{
 	plpgsql_error_lineno = plpgsql_scanner_lineno();
 	return plpgsql_parse_word(yytext); }
+{identifier}{space}*\.		{
+	plpgsql_error_lineno = plpgsql_scanner_lineno();
+	return plpgsql_parse_wordexpr(yytext); }
 {identifier}{space}*\.{space}*{identifier}	{
 	plpgsql_error_lineno = plpgsql_scanner_lineno();
 	return plpgsql_parse_dblword(yytext); }
