diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml
index 639647eab3ca2cf4853e0ff7dbc6d048d93d9cf3..ca9eca5138d98b06972fa6a27d3b2ea88138263c 100644
--- a/doc/src/sgml/ref/create_function.sgml
+++ b/doc/src/sgml/ref/create_function.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.83 2008/12/18 18:20:33 tgl Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.84 2008/12/31 02:25:03 tgl Exp $
 -->
 
 <refentry id="SQL-CREATEFUNCTION">
@@ -25,6 +25,7 @@ CREATE [ OR REPLACE ] FUNCTION
     [ RETURNS <replaceable class="parameter">rettype</replaceable>
       | RETURNS TABLE ( <replaceable class="parameter">colname</replaceable> <replaceable class="parameter">coltype</replaceable> [, ...] ) ]
   { LANGUAGE <replaceable class="parameter">langname</replaceable>
+    | WINDOW
     | IMMUTABLE | STABLE | VOLATILE
     | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT
     | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
@@ -241,6 +242,20 @@ CREATE [ OR REPLACE ] FUNCTION
      </listitem>
     </varlistentry>
 
+    <varlistentry>
+     <term><literal>WINDOW</literal></term>
+
+     <listitem>
+      <para>
+       <literal>WINDOW</literal> indicates that the function is a
+       <firstterm>window function</> rather than a plain function.
+       This is currently only useful for functions written in C.
+       The <literal>WINDOW</> attribute cannot be changed when
+       replacing an existing function definition.
+      </para>
+     </listitem>
+    </varlistentry>
+
     <varlistentry>
      <term><literal>IMMUTABLE</literal></term>
      <term><literal>STABLE</literal></term>
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 414366bc54ec021d32c5c16f0bd46eaea63af22a..8aad4a0ea44c5772c7269ae75a783fef3469d593 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.99 2008/12/18 18:20:33 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.100 2008/12/31 02:25:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -217,6 +217,7 @@ AggregateCreate(const char *aggName,
 							  "aggregate_dummy",		/* placeholder proc */
 							  NULL,		/* probin */
 							  true,		/* isAgg */
+							  false,	/* isWindowFunc */
 							  false,	/* security invoker (currently not
 										 * definable for agg) */
 							  false,	/* isStrict (not needed for agg) */
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 8ff22c23c9ec2593c99bbf156e7c85409a231f84..d11a067a5d92fd9c846c2cf163ae53e7f1aa0c41 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.158 2008/12/28 18:53:54 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.159 2008/12/31 02:25:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,7 +53,7 @@ static bool match_prosrc_to_literal(const char *prosrc, const char *literal,
  *
  * Note: allParameterTypes, parameterModes, parameterNames, and proconfig
  * are either arrays of the proper types or NULL.  We declare them Datum,
- * not "ArrayType *", to avoid importing array.h into pg_proc.h.
+ * not "ArrayType *", to avoid importing array.h into pg_proc_fn.h.
  * ----------------------------------------------------------------
  */
 Oid
@@ -67,6 +67,7 @@ ProcedureCreate(const char *procedureName,
 				const char *prosrc,
 				const char *probin,
 				bool isAgg,
+				bool isWindowFunc,
 				bool security_definer,
 				bool isStrict,
 				char volatility,
@@ -80,8 +81,6 @@ ProcedureCreate(const char *procedureName,
 				float4 prorows)
 {
 	Oid			retval;
-	/* XXX we don't currently have a way to make new window functions */
-	bool		isWindowFunc = false;
 	int			parameterCount;
 	int			allParamCount;
 	Oid		   *allParams;
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 8963f98117813a73b9d38c1cf518bf3bec358d7b..13f1debf6692b28eea7051ea86d3b429f36563f7 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.104 2008/12/28 18:53:55 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.105 2008/12/31 02:25:03 tgl Exp $
  *
  * DESCRIPTION
  *	  These routines take the parse tree and pick out the
@@ -503,6 +503,7 @@ static void
 compute_attributes_sql_style(List *options,
 							 List **as,
 							 char **language,
+							 bool *windowfunc_p,
 							 char *volatility_p,
 							 bool *strict_p,
 							 bool *security_definer,
@@ -513,6 +514,7 @@ compute_attributes_sql_style(List *options,
 	ListCell   *option;
 	DefElem    *as_item = NULL;
 	DefElem    *language_item = NULL;
+	DefElem    *windowfunc_item = NULL;
 	DefElem    *volatility_item = NULL;
 	DefElem    *strict_item = NULL;
 	DefElem    *security_item = NULL;
@@ -540,6 +542,14 @@ compute_attributes_sql_style(List *options,
 						 errmsg("conflicting or redundant options")));
 			language_item = defel;
 		}
+		else if (strcmp(defel->defname, "window") == 0)
+		{
+			if (windowfunc_item)
+				ereport(ERROR,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("conflicting or redundant options")));
+			windowfunc_item = defel;
+		}
 		else if (compute_common_attribute(defel,
 										  &volatility_item,
 										  &strict_item,
@@ -578,6 +588,8 @@ compute_attributes_sql_style(List *options,
 	}
 
 	/* process optional items */
+	if (windowfunc_item)
+		*windowfunc_p = intVal(windowfunc_item->arg);
 	if (volatility_item)
 		*volatility_p = interpret_func_volatility(volatility_item);
 	if (strict_item)
@@ -735,7 +747,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 	ArrayType  *parameterNames;
 	List	   *parameterDefaults;
 	Oid			requiredResultType;
-	bool		isStrict,
+	bool		isWindowFunc,
+				isStrict,
 				security;
 	char		volatility;
 	ArrayType  *proconfig;
@@ -756,6 +769,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 					   get_namespace_name(namespaceId));
 
 	/* default attributes */
+	isWindowFunc = false;
 	isStrict = false;
 	security = false;
 	volatility = PROVOLATILE_VOLATILE;
@@ -766,7 +780,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 	/* override attributes from explicit list */
 	compute_attributes_sql_style(stmt->options,
 								 &as_clause, &language,
-								 &volatility, &isStrict, &security,
+								 &isWindowFunc, &volatility,
+								 &isStrict, &security,
 								 &proconfig, &procost, &prorows);
 
 	/* Convert language name to canonical case */
@@ -892,6 +907,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 					prosrc_str, /* converted to text later */
 					probin_str, /* converted to text later */
 					false,		/* not an aggregate */
+					isWindowFunc,
 					security,
 					isStrict,
 					volatility,
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 3188156c4d143a6224edf855138c6d545b62b516..ea37352b4192452d2dbdb19313816e67c025e92b 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.82 2008/12/18 18:20:33 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.83 2008/12/31 02:25:03 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -140,6 +140,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 pltemplate->tmplhandler,
 										 pltemplate->tmpllibrary,
 										 false, /* isAgg */
+										 false,	/* isWindowFunc */
 										 false, /* security_definer */
 										 false, /* isStrict */
 										 PROVOLATILE_VOLATILE,
@@ -174,6 +175,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 pltemplate->tmplvalidator,
 										 pltemplate->tmpllibrary,
 										 false, /* isAgg */
+										 false,	/* isWindowFunc */
 										 false, /* security_definer */
 										 false, /* isStrict */
 										 PROVOLATILE_VOLATILE,
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 34dc40a1056dacc198741b912ba84be414cb7789..011041f303770bc1fb4d5c75def0ae52d0fde665 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.649 2008/12/31 00:08:36 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.650 2008/12/31 02:25:04 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -4801,6 +4801,10 @@ createfunc_opt_item:
 				{
 					$$ = makeDefElem("language", (Node *)makeString($2));
 				}
+			| WINDOW
+				{
+					$$ = makeDefElem("window", (Node *)makeInteger(TRUE));
+				}
 			| common_func_opt_item
 				{
 					$$ = $1;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 4a44b733cf35d288c8fb7b401c2ef11d38e3b775..f48ee4ae96d5a0ab3be8f01bef92816547a36a72 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.292 2008/12/31 00:08:37 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.293 2008/12/31 02:25:04 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1466,6 +1466,8 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
 	/* Emit some miscellaneous options on one line */
 	oldlen = buf.len;
 
+	if (proc->proiswindow)
+		appendStringInfoString(&buf, " WINDOW");
 	switch (proc->provolatile)
 	{
 		case PROVOLATILE_IMMUTABLE:
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index ae7233dbf83316f179964715bc2f99a31688c219..b8f6932ded0fb5775ff82711f788436f67e2cfc0 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12,7 +12,7 @@
  *	by PostgreSQL
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.509 2008/12/19 16:25:18 petere Exp $
+ *	  $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.510 2008/12/31 02:25:05 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -6916,6 +6916,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 	char	   *proallargtypes;
 	char	   *proargmodes;
 	char	   *proargnames;
+	char	   *proiswindow;
 	char	   *provolatile;
 	char	   *proisstrict;
 	char	   *prosecdef;
@@ -6956,7 +6957,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 						  "pg_catalog.pg_get_function_arguments(oid) as funcargs, "
 						  "pg_catalog.pg_get_function_identity_arguments(oid) as funciargs, "
 						  "pg_catalog.pg_get_function_result(oid) as funcresult, "
-						  "provolatile, proisstrict, prosecdef, "
+						  "proiswindow, provolatile, proisstrict, prosecdef, "
 						  "proconfig, procost, prorows, "
 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
 						  "FROM pg_catalog.pg_proc "
@@ -6968,6 +6969,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		appendPQExpBuffer(query,
 						  "SELECT proretset, prosrc, probin, "
 						  "proallargtypes, proargmodes, proargnames, "
+						  "false as proiswindow, "
 						  "provolatile, proisstrict, prosecdef, "
 						  "proconfig, procost, prorows, "
 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
@@ -6980,6 +6982,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		appendPQExpBuffer(query,
 						  "SELECT proretset, prosrc, probin, "
 						  "proallargtypes, proargmodes, proargnames, "
+						  "false as proiswindow, "
 						  "provolatile, proisstrict, prosecdef, "
 						  "null as proconfig, 0 as procost, 0 as prorows, "
 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
@@ -6994,6 +6997,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 						  "null as proallargtypes, "
 						  "null as proargmodes, "
 						  "proargnames, "
+						  "false as proiswindow, "
 						  "provolatile, proisstrict, prosecdef, "
 						  "null as proconfig, 0 as procost, 0 as prorows, "
 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
@@ -7008,6 +7012,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 						  "null as proallargtypes, "
 						  "null as proargmodes, "
 						  "null as proargnames, "
+						  "false as proiswindow, "
 						  "provolatile, proisstrict, prosecdef, "
 						  "null as proconfig, 0 as procost, 0 as prorows, "
 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) as lanname "
@@ -7022,9 +7027,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 						  "null as proallargtypes, "
 						  "null as proargmodes, "
 						  "null as proargnames, "
+						  "false as proiswindow, "
 			 "case when proiscachable then 'i' else 'v' end as provolatile, "
 						  "proisstrict, "
-						  "'f'::boolean as prosecdef, "
+						  "false as prosecdef, "
 						  "null as proconfig, 0 as procost, 0 as prorows, "
 		  "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
 						  "FROM pg_proc "
@@ -7038,9 +7044,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 						  "null as proallargtypes, "
 						  "null as proargmodes, "
 						  "null as proargnames, "
+						  "false as proiswindow, "
 			 "case when proiscachable then 'i' else 'v' end as provolatile, "
-						  "'f'::boolean as proisstrict, "
-						  "'f'::boolean as prosecdef, "
+						  "false as proisstrict, "
+						  "false as prosecdef, "
 						  "null as proconfig, 0 as procost, 0 as prorows, "
 		  "(SELECT lanname FROM pg_language WHERE oid = prolang) as lanname "
 						  "FROM pg_proc "
@@ -7077,6 +7084,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 		proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
 		funcargs = funciargs = funcresult = NULL;
 	}
+	proiswindow = PQgetvalue(res, 0, PQfnumber(res, "proiswindow"));
 	provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
 	proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
 	prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
@@ -7217,6 +7225,10 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
 	}
 
 	appendPQExpBuffer(q, "\n    LANGUAGE %s", fmtId(lanname));
+
+	if (proiswindow[0] == 't')
+		appendPQExpBuffer(q, " WINDOW");
+
 	if (provolatile[0] != PROVOLATILE_VOLATILE)
 	{
 		if (provolatile[0] == PROVOLATILE_IMMUTABLE)
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index cab31d45e151bead9f5c14fdade1c18f551da1ec..5941b546fcf6f393a496d3a0372ef02929316d0d 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc_fn.h,v 1.4 2008/12/18 18:20:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc_fn.h,v 1.5 2008/12/31 02:25:06 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,6 +26,7 @@ extern Oid ProcedureCreate(const char *procedureName,
 				const char *prosrc,
 				const char *probin,
 				bool isAgg,
+				bool isWindowFunc,
 				bool security_definer,
 				bool isStrict,
 				char volatility,