diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 8636a0a6b85628f6f3c6d99b99e8ed9c0db7d89c..7364e89b949ed109c6e6fcec13a63efcaea8ac14 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.87 2006/03/09 21:29:36 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.88 2006/03/23 04:22:36 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1714,6 +1714,44 @@ lno				:
 %%
 
 
+#define MAX_EXPR_PARAMS  1024
+
+/*
+ * determine the expression parameter position to use for a plpgsql datum
+ *
+ * It is important that any given plpgsql datum map to just one parameter.
+ * We used to be sloppy and assign a separate parameter for each occurrence
+ * of a datum reference, but that fails for situations such as "select DATUM
+ * from ... group by DATUM".
+ *
+ * The params[] array must be of size MAX_EXPR_PARAMS.
+ */
+static int
+assign_expr_param(int dno, int *params, int *nparams)
+{
+	int		i;
+
+	/* already have an instance of this dno? */
+	for (i = 0; i < *nparams; i++)
+	{
+		if (params[i] == dno)
+			return i+1;
+	}
+	/* check for array overflow */
+	if (*nparams >= MAX_EXPR_PARAMS)
+	{
+		plpgsql_error_lineno = plpgsql_scanner_lineno();
+		ereport(ERROR,
+				(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
+				 errmsg("too many variables specified in SQL statement")));
+	}
+	/* add new parameter dno to array */
+	params[*nparams] = dno;
+	(*nparams)++;
+	return *nparams;
+}
+
+
 PLpgSQL_expr *
 plpgsql_read_expression(int until, const char *expected)
 {
@@ -1752,7 +1790,7 @@ read_sql_construct(int until,
 	PLpgSQL_dstring		ds;
 	int					parenlevel = 0;
 	int					nparams = 0;
-	int					params[1024];
+	int					params[MAX_EXPR_PARAMS];
 	char				buf[32];
 	PLpgSQL_expr		*expr;
 
@@ -1804,32 +1842,26 @@ read_sql_construct(int until,
 		if (plpgsql_SpaceScanned)
 			plpgsql_dstring_append(&ds, " ");
 
-		/* Check for array overflow */
-		if (nparams >= 1024)
-		{
-			plpgsql_error_lineno = lno;
-			ereport(ERROR,
-					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-					 errmsg("too many variables specified in SQL statement")));
-		}
-
 		switch (tok)
 		{
 			case T_SCALAR:
-				params[nparams] = yylval.scalar->dno;
-				snprintf(buf, sizeof(buf), " $%d ", ++nparams);
+				snprintf(buf, sizeof(buf), " $%d ",
+						 assign_expr_param(yylval.scalar->dno,
+										   params, &nparams));
 				plpgsql_dstring_append(&ds, buf);
 				break;
 
 			case T_ROW:
-				params[nparams] = yylval.row->rowno;
-				snprintf(buf, sizeof(buf), " $%d ", ++nparams);
+				snprintf(buf, sizeof(buf), " $%d ",
+						 assign_expr_param(yylval.row->rowno,
+										   params, &nparams));
 				plpgsql_dstring_append(&ds, buf);
 				break;
 
 			case T_RECORD:
-				params[nparams] = yylval.rec->recno;
-				snprintf(buf, sizeof(buf), " $%d ", ++nparams);
+				snprintf(buf, sizeof(buf), " $%d ",
+						 assign_expr_param(yylval.rec->recno,
+										   params, &nparams));
 				plpgsql_dstring_append(&ds, buf);
 				break;
 
@@ -1927,7 +1959,7 @@ make_select_stmt(void)
 {
 	PLpgSQL_dstring		ds;
 	int					nparams = 0;
-	int					params[1024];
+	int					params[MAX_EXPR_PARAMS];
 	char				buf[32];
 	PLpgSQL_expr		*expr;
 	PLpgSQL_row			*row = NULL;
@@ -1992,32 +2024,26 @@ make_select_stmt(void)
 		if (plpgsql_SpaceScanned)
 			plpgsql_dstring_append(&ds, " ");
 
-		/* Check for array overflow */
-		if (nparams >= 1024)
-		{
-			plpgsql_error_lineno = plpgsql_scanner_lineno();
-			ereport(ERROR,
-					(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
-					 errmsg("too many parameters specified in SQL statement")));
-		}
-
 		switch (tok)
 		{
 			case T_SCALAR:
-				params[nparams] = yylval.scalar->dno;
-				snprintf(buf, sizeof(buf), " $%d ", ++nparams);
+				snprintf(buf, sizeof(buf), " $%d ",
+						 assign_expr_param(yylval.scalar->dno,
+										   params, &nparams));
 				plpgsql_dstring_append(&ds, buf);
 				break;
 
 			case T_ROW:
-				params[nparams] = yylval.row->rowno;
-				snprintf(buf, sizeof(buf), " $%d ", ++nparams);
+				snprintf(buf, sizeof(buf), " $%d ",
+						 assign_expr_param(yylval.row->rowno,
+										   params, &nparams));
 				plpgsql_dstring_append(&ds, buf);
 				break;
 
 			case T_RECORD:
-				params[nparams] = yylval.rec->recno;
-				snprintf(buf, sizeof(buf), " $%d ", ++nparams);
+				snprintf(buf, sizeof(buf), " $%d ",
+						 assign_expr_param(yylval.rec->recno,
+										   params, &nparams));
 				plpgsql_dstring_append(&ds, buf);
 				break;
 
diff --git a/src/test/regress/expected/plpgsql.out b/src/test/regress/expected/plpgsql.out
index e72383bbb72c27b9e5a471cb44ce23ffd718613b..6e6597dadb2f452a7880e74c9295101efb570810 100644
--- a/src/test/regress/expected/plpgsql.out
+++ b/src/test/regress/expected/plpgsql.out
@@ -2776,3 +2776,21 @@ NOTICE:  4 bb cc
  
 (1 row)
 
+-- regression test: verify that multiple uses of same plpgsql datum within
+-- a SQL command all get mapped to the same $n parameter.  The return value
+-- of the SELECT is not important, we only care that it doesn't fail with
+-- a complaint about an ungrouped column reference.
+create function multi_datum_use(p1 int) returns bool as $$
+declare
+  x int;
+  y int;
+begin
+  select into x,y unique1/p1, unique1/$1 from tenk1 group by unique1/p1;
+  return x = y;
+end$$ language plpgsql;
+select multi_datum_use(42);
+ multi_datum_use 
+-----------------
+ t
+(1 row)
+
diff --git a/src/test/regress/sql/plpgsql.sql b/src/test/regress/sql/plpgsql.sql
index a2d65817b1fc4066eb52a88f622ad6a071b57f2b..19e145be65f359bc3c3d22318cab92656e31c0f0 100644
--- a/src/test/regress/sql/plpgsql.sql
+++ b/src/test/regress/sql/plpgsql.sql
@@ -2309,3 +2309,18 @@ end;
 $proc$ language plpgsql;
 
 select for_vect();
+
+-- regression test: verify that multiple uses of same plpgsql datum within
+-- a SQL command all get mapped to the same $n parameter.  The return value
+-- of the SELECT is not important, we only care that it doesn't fail with
+-- a complaint about an ungrouped column reference.
+create function multi_datum_use(p1 int) returns bool as $$
+declare
+  x int;
+  y int;
+begin
+  select into x,y unique1/p1, unique1/$1 from tenk1 group by unique1/p1;
+  return x = y;
+end$$ language plpgsql;
+
+select multi_datum_use(42);