diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index d9c484b0243e08dff4a41367d5360a338f23d9a7..1a699acd1b8e79bf2412f15902ee5a202fe27095 100644
--- a/src/backend/catalog/information_schema.sql
+++ b/src/backend/catalog/information_schema.sql
@@ -4,7 +4,7 @@
  *
  * Copyright 2003, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.22 2004/01/24 23:45:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.23 2004/02/03 08:29:56 joe Exp $
  */
 
 /*
@@ -399,17 +399,9 @@ GRANT SELECT ON columns TO PUBLIC;
 CREATE FUNCTION _pg_keypositions() RETURNS SETOF integer
     LANGUAGE sql
     IMMUTABLE
-    AS 'select 1 union all select 2 union all select 3 union all
-        select 4 union all select 5 union all select 6 union all
-        select 7 union all select 8 union all select 9 union all
-        select 10 union all select 11 union all select 12 union all
-        select 13 union all select 14 union all select 15 union all
-        select 16 union all select 17 union all select 18 union all
-        select 19 union all select 20 union all select 21 union all
-        select 22 union all select 23 union all select 24 union all
-        select 25 union all select 26 union all select 27 union all
-        select 28 union all select 29 union all select 30 union all
-        select 31 union all select 32';
+    AS 'select g.s
+        from generate_series(1,current_setting(''max_index_keys'')::int,1)
+        as g(s)';
 
 CREATE VIEW constraint_column_usage AS
     SELECT CAST(current_database() AS sql_identifier) AS table_catalog,
diff --git a/src/backend/utils/adt/int.c b/src/backend/utils/adt/int.c
index e23706582e268a31ed79be5cfff1f9ec55e7120a..82dab407ff40c52afbb16abbb5e3c0b08367c98a 100644
--- a/src/backend/utils/adt/int.c
+++ b/src/backend/utils/adt/int.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.59 2003/12/01 21:52:37 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/int.c,v 1.60 2004/02/03 08:29:56 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,6 +34,7 @@
 #include <ctype.h>
 #include <limits.h>
 
+#include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "utils/builtins.h"
 
@@ -44,6 +45,13 @@
 #define SHRT_MIN (-0x8000)
 #endif
 
+typedef struct
+{
+	int32		current;
+	int32		finish;
+	int32		step;
+}	generate_series_fctx;
+
 /*****************************************************************************
  *	 USER I/O ROUTINES														 *
  *****************************************************************************/
@@ -1021,3 +1029,84 @@ int2shr(PG_FUNCTION_ARGS)
 
 	PG_RETURN_INT16(arg1 >> arg2);
 }
+
+/*
+ * non-persistent numeric series generator
+ */
+Datum
+generate_series_int4(PG_FUNCTION_ARGS)
+{
+	return generate_series_step_int4(fcinfo);
+}
+
+Datum
+generate_series_step_int4(PG_FUNCTION_ARGS)
+{
+	FuncCallContext		   *funcctx;
+	generate_series_fctx   *fctx;
+	int32					result;
+	MemoryContext			oldcontext;
+
+	/* stuff done only on the first call of the function */
+	if (SRF_IS_FIRSTCALL())
+	{
+		int32			start = PG_GETARG_INT32(0);
+		int32			finish = PG_GETARG_INT32(1);
+		int32			step = 1;
+
+		/* see if we were given an explicit step size */
+		if (PG_NARGS() == 3)
+			step = PG_GETARG_INT32(2);
+		if (step == 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("step size may not equal zero")));
+
+		/* create a function context for cross-call persistence */
+		funcctx = SRF_FIRSTCALL_INIT();
+
+		/*
+		 * switch to memory context appropriate for multiple function
+		 * calls
+		 */
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+		/* allocate memory for user context */
+		fctx = (generate_series_fctx *) palloc(sizeof(generate_series_fctx));
+
+		/*
+		 * Use fctx to keep state from call to call.
+		 * Seed current with the original start value
+		 */
+		fctx->current = start;
+		fctx->finish = finish;
+		fctx->step = step;
+
+		funcctx->user_fctx = fctx;
+		MemoryContextSwitchTo(oldcontext);
+	}
+
+	/* stuff done on every call of the function */
+	funcctx = SRF_PERCALL_SETUP();
+
+	/*
+	 * get the saved state and use current as the result for
+	 * this iteration
+	 */
+	fctx = funcctx->user_fctx;
+	result = fctx->current;
+
+	if ((fctx->step > 0 && fctx->current <= fctx->finish) ||
+		(fctx->step < 0 && fctx->current >= fctx->finish))
+	{
+		/* increment current in preparation for next iteration */
+		fctx->current += fctx->step;
+
+		/* do when there is more left to send */
+		SRF_RETURN_NEXT(funcctx, Int32GetDatum(result));
+	}
+	else
+		/* do when there is no more left */
+		SRF_RETURN_DONE(funcctx);
+}
+
diff --git a/src/backend/utils/adt/int8.c b/src/backend/utils/adt/int8.c
index 016330a053395a716d74914b00508437e0362cfb..200876e7989573a866de2a150bbc25d193f356a8 100644
--- a/src/backend/utils/adt/int8.c
+++ b/src/backend/utils/adt/int8.c
@@ -7,21 +7,29 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.50 2003/12/01 21:52:37 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/int8.c,v 1.51 2004/02/03 08:29:56 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "postgres.h"
 
 #include <ctype.h>
+#include <limits.h>
 #include <math.h>
 
+#include "funcapi.h"
 #include "libpq/pqformat.h"
 #include "utils/int8.h"
 
 
 #define MAXINT8LEN		25
 
+typedef struct
+{
+	int64		current;
+	int64		finish;
+	int64		step;
+}	generate_series_fctx;
 
 /***********************************************************************
  **
@@ -936,3 +944,84 @@ int8_text(PG_FUNCTION_ARGS)
 
 	PG_RETURN_TEXT_P(result);
 }
+
+/*
+ * non-persistent numeric series generator
+ */
+Datum
+generate_series_int8(PG_FUNCTION_ARGS)
+{
+	return generate_series_step_int8(fcinfo);
+}
+
+Datum
+generate_series_step_int8(PG_FUNCTION_ARGS)
+{
+	FuncCallContext		   *funcctx;
+	generate_series_fctx   *fctx;
+	int64					result;
+	MemoryContext			oldcontext;
+
+	/* stuff done only on the first call of the function */
+	if (SRF_IS_FIRSTCALL())
+	{
+		int64			start = PG_GETARG_INT64(0);
+		int64			finish = PG_GETARG_INT64(1);
+		int64			step = 1;
+
+		/* see if we were given an explicit step size */
+		if (PG_NARGS() == 3)
+			step = PG_GETARG_INT64(2);
+		if (step == 0)
+			ereport(ERROR,
+					(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+					 errmsg("step size may not equal zero")));
+
+		/* create a function context for cross-call persistence */
+		funcctx = SRF_FIRSTCALL_INIT();
+
+		/*
+		 * switch to memory context appropriate for multiple function
+		 * calls
+		 */
+		oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
+
+		/* allocate memory for user context */
+		fctx = (generate_series_fctx *) palloc(sizeof(generate_series_fctx));
+
+		/*
+		 * Use fctx to keep state from call to call.
+		 * Seed current with the original start value
+		 */
+		fctx->current = start;
+		fctx->finish = finish;
+		fctx->step = step;
+
+		funcctx->user_fctx = fctx;
+		MemoryContextSwitchTo(oldcontext);
+	}
+
+	/* stuff done on every call of the function */
+	funcctx = SRF_PERCALL_SETUP();
+
+	/*
+	 * get the saved state and use current as the result for
+	 * this iteration
+	 */
+	fctx = funcctx->user_fctx;
+	result = fctx->current;
+
+	if ((fctx->step > 0 && fctx->current <= fctx->finish) ||
+		(fctx->step < 0 && fctx->current >= fctx->finish))
+	{
+		/* increment current in preparation for next iteration */
+		fctx->current += fctx->step;
+
+		/* do when there is more left to send */
+		SRF_RETURN_NEXT(funcctx, Int64GetDatum(result));
+	}
+	else
+		/* do when there is no more left */
+		SRF_RETURN_DONE(funcctx);
+}
+
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 7dd262c1e464f424a41acbfb4faf420a7dc3fd2b..fa6a7f1e605240796f63be6de3553ece0530a626 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.216 2004/01/14 23:01:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.217 2004/02/03 08:29:56 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200401141
+#define CATALOG_VERSION_NO	200402021
 
 #endif
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 4f197e99753abfefccf362f549950341e43325a2..fb6eb885d8530735c34734f2846d223285306a0b 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.318 2004/01/06 23:55:19 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.319 2004/02/03 08:29:56 joe Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -3424,6 +3424,17 @@ DESCR("constraint description with pretty-print option");
 DATA(insert OID = 2509 (  pg_get_expr		   PGNSP PGUID 12 f f t f s 3 25 "25 26 16" _null_ pg_get_expr_ext - _null_ ));
 DESCR("deparse an encoded expression with pretty-print option");
 
+/* non-persistent series generator */
+DATA(insert OID = 1066 (  generate_series PGNSP PGUID 12 f f t t v 3 23 "23 23 23" _null_ generate_series_step_int4 - _null_ ));
+DESCR("non-persistent series generator");
+DATA(insert OID = 1067 (  generate_series PGNSP PGUID 12 f f t t v 2 23 "23 23" _null_ generate_series_int4 - _null_ ));
+DESCR("non-persistent series generator");
+
+DATA(insert OID = 1068 (  generate_series PGNSP PGUID 12 f f t t v 3 20 "20 20 20" _null_ generate_series_step_int8 - _null_ ));
+DESCR("non-persistent series generator");
+DATA(insert OID = 1069 (  generate_series PGNSP PGUID 12 f f t t v 2 20 "20 20" _null_ generate_series_int8 - _null_ ));
+DESCR("non-persistent series generator");
+
 
 /*
  * Symbolic values for provolatile column: these indicate whether the result
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index dc5e2f267cc7dfd94d0c6f57317d90ed2a7b0222..593f002c68f17f5305464875c2234924f2bd5d33 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.233 2004/01/19 19:04:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.234 2004/02/03 08:29:57 joe Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -175,6 +175,8 @@ extern Datum int2xor(PG_FUNCTION_ARGS);
 extern Datum int2not(PG_FUNCTION_ARGS);
 extern Datum int2shl(PG_FUNCTION_ARGS);
 extern Datum int2shr(PG_FUNCTION_ARGS);
+extern Datum generate_series_int4(PG_FUNCTION_ARGS);
+extern Datum generate_series_step_int4(PG_FUNCTION_ARGS);
 
 /* name.c */
 extern Datum namein(PG_FUNCTION_ARGS);
diff --git a/src/include/utils/int8.h b/src/include/utils/int8.h
index 7fe9800b2359010ee7f166bcd99a1cb27bffea75..eaaf9448a927b4ad68e7e1b47de04d16469e1155 100644
--- a/src/include/utils/int8.h
+++ b/src/include/utils/int8.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/int8.h,v 1.40 2003/12/01 21:52:38 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/int8.h,v 1.41 2004/02/03 08:29:57 joe Exp $
  *
  * NOTES
  * These data types are supported on all 64-bit architectures, and may
@@ -112,4 +112,7 @@ extern Datum oidtoi8(PG_FUNCTION_ARGS);
 extern Datum int8_text(PG_FUNCTION_ARGS);
 extern Datum text_int8(PG_FUNCTION_ARGS);
 
+extern Datum generate_series_int8(PG_FUNCTION_ARGS);
+extern Datum generate_series_step_int8(PG_FUNCTION_ARGS);
+
 #endif   /* INT8_H */