diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index 71e20f2..a0e6d70 100644
*** a/doc/src/sgml/catalogs.sgml
--- b/doc/src/sgml/catalogs.sgml
*************** SCRAM-SHA-256$<replaceable>&lt;iteration
*** 5062,5076 ****
    </indexterm>
  
    <para>
!    The catalog <structname>pg_proc</structname> stores information about functions (or procedures).
!    See <xref linkend="sql-createfunction"/>
!    and <xref linkend="xfunc"/> for more information.
    </para>
  
    <para>
!    The table contains data for aggregate functions as well as plain functions.
!    If <structfield>proisagg</structfield> is true, there should be a matching
!    row in <structfield>pg_aggregate</structfield>.
    </para>
  
    <table>
--- 5062,5078 ----
    </indexterm>
  
    <para>
!    The catalog <structname>pg_proc</structname> stores information about
!    functions, procedures, aggregate functions, and window functions
!    (collectively also known as routines).  See <xref
!    linkend="sql-createfunction"/>, <xref linkend="sql-createprocedure"/>, and
!    <xref linkend="xfunc"/> for more information.
    </para>
  
    <para>
!    If <structfield>prokind</structfield> indicates that the entry is for an
!    aggregate function, there should be a matching row in
!    <structfield>pg_aggregate</structfield>.
    </para>
  
    <table>
*************** SCRAM-SHA-256$<replaceable>&lt;iteration
*** 5157,5173 ****
       </row>
  
       <row>
!       <entry><structfield>proisagg</structfield></entry>
!       <entry><type>bool</type></entry>
!       <entry></entry>
!       <entry>Function is an aggregate function</entry>
!      </row>
! 
!      <row>
!       <entry><structfield>proiswindow</structfield></entry>
!       <entry><type>bool</type></entry>
        <entry></entry>
!       <entry>Function is a window function</entry>
       </row>
  
       <row>
--- 5159,5170 ----
       </row>
  
       <row>
!       <entry><structfield>prokind</structfield></entry>
!       <entry><type>char</type></entry>
        <entry></entry>
!       <entry><literal>f</literal> for a normal function, <literal>p</literal>
!       for a procedure, <literal>a</literal> for an aggregate function, or
!       <literal>w</literal> for a window function</entry>
       </row>
  
       <row>
*************** SCRAM-SHA-256$<replaceable>&lt;iteration
*** 5264,5270 ****
        <entry><structfield>prorettype</structfield></entry>
        <entry><type>oid</type></entry>
        <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
!       <entry>Data type of the return value, or null for a procedure</entry>
       </row>
  
       <row>
--- 5261,5267 ----
        <entry><structfield>prorettype</structfield></entry>
        <entry><type>oid</type></entry>
        <entry><literal><link linkend="catalog-pg-type"><structname>pg_type</structname></link>.oid</literal></entry>
!       <entry>Data type of the return value</entry>
       </row>
  
       <row>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index 1156627..3f2c629 100644
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
*************** objectsInSchemaToOids(ObjectType objtype
*** 830,850 ****
  								BTEqualStrategyNumber, F_OIDEQ,
  								ObjectIdGetDatum(namespaceId));
  
- 					/*
- 					 * When looking for functions, check for return type <>0.
- 					 * When looking for procedures, check for return type ==0.
- 					 * When looking for routines, don't check the return type.
- 					 */
  					if (objtype == OBJECT_FUNCTION)
  						ScanKeyInit(&key[keycount++],
! 									Anum_pg_proc_prorettype,
! 									BTEqualStrategyNumber, F_OIDNE,
! 									InvalidOid);
  					else if (objtype == OBJECT_PROCEDURE)
  						ScanKeyInit(&key[keycount++],
! 									Anum_pg_proc_prorettype,
! 									BTEqualStrategyNumber, F_OIDEQ,
! 									InvalidOid);
  
  					rel = heap_open(ProcedureRelationId, AccessShareLock);
  					scan = heap_beginscan_catalog(rel, keycount, key);
--- 830,846 ----
  								BTEqualStrategyNumber, F_OIDEQ,
  								ObjectIdGetDatum(namespaceId));
  
  					if (objtype == OBJECT_FUNCTION)
+ 						/* includes aggregates and window functions */
  						ScanKeyInit(&key[keycount++],
! 									Anum_pg_proc_prokind,
! 									BTEqualStrategyNumber, F_CHARNE,
! 									CharGetDatum(PROKIND_PROCEDURE));
  					else if (objtype == OBJECT_PROCEDURE)
  						ScanKeyInit(&key[keycount++],
! 									Anum_pg_proc_prokind,
! 									BTEqualStrategyNumber, F_CHAREQ,
! 									CharGetDatum(PROKIND_PROCEDURE));
  
  					rel = heap_open(ProcedureRelationId, AccessShareLock);
  					scan = heap_beginscan_catalog(rel, keycount, key);
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
index 686528c..9a6bf1b 100644
*** a/src/backend/catalog/information_schema.sql
--- b/src/backend/catalog/information_schema.sql
*************** CREATE VIEW routines AS
*** 1413,1419 ****
             CAST(current_database() AS sql_identifier) AS routine_catalog,
             CAST(n.nspname AS sql_identifier) AS routine_schema,
             CAST(p.proname AS sql_identifier) AS routine_name,
!            CAST(CASE WHEN p.prorettype <> 0 THEN 'FUNCTION' ELSE 'PROCEDURE' END
               AS character_data) AS routine_type,
             CAST(null AS sql_identifier) AS module_catalog,
             CAST(null AS sql_identifier) AS module_schema,
--- 1413,1419 ----
             CAST(current_database() AS sql_identifier) AS routine_catalog,
             CAST(n.nspname AS sql_identifier) AS routine_schema,
             CAST(p.proname AS sql_identifier) AS routine_name,
!            CAST(CASE p.prokind WHEN 'f' THEN 'FUNCTION' WHEN 'p' THEN 'PROCEDURE' END
               AS character_data) AS routine_type,
             CAST(null AS sql_identifier) AS module_catalog,
             CAST(null AS sql_identifier) AS module_schema,
*************** CREATE VIEW routines AS
*** 1423,1430 ****
             CAST(null AS sql_identifier) AS udt_name,
  
             CAST(
!              CASE WHEN p.prorettype = 0 THEN NULL
!                   WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY'
                    WHEN nt.nspname = 'pg_catalog' THEN format_type(t.oid, null)
                    ELSE 'USER-DEFINED' END AS character_data)
               AS data_type,
--- 1423,1429 ----
             CAST(null AS sql_identifier) AS udt_name,
  
             CAST(
!              CASE WHEN t.typelem <> 0 AND t.typlen = -1 THEN 'ARRAY'
                    WHEN nt.nspname = 'pg_catalog' THEN format_type(t.oid, null)
                    ELSE 'USER-DEFINED' END AS character_data)
               AS data_type,
*************** CREATE VIEW routines AS
*** 1442,1448 ****
             CAST(null AS cardinal_number) AS datetime_precision,
             CAST(null AS character_data) AS interval_type,
             CAST(null AS cardinal_number) AS interval_precision,
!            CAST(CASE WHEN p.prorettype <> 0 THEN current_database() END AS sql_identifier) AS type_udt_catalog,
             CAST(nt.nspname AS sql_identifier) AS type_udt_schema,
             CAST(t.typname AS sql_identifier) AS type_udt_name,
             CAST(null AS sql_identifier) AS scope_catalog,
--- 1441,1447 ----
             CAST(null AS cardinal_number) AS datetime_precision,
             CAST(null AS character_data) AS interval_type,
             CAST(null AS cardinal_number) AS interval_precision,
!            CAST(current_database() AS sql_identifier) AS type_udt_catalog,
             CAST(nt.nspname AS sql_identifier) AS type_udt_schema,
             CAST(t.typname AS sql_identifier) AS type_udt_name,
             CAST(null AS sql_identifier) AS scope_catalog,
*************** CREATE VIEW routines AS
*** 1464,1470 ****
             CAST('GENERAL' AS character_data) AS parameter_style,
             CAST(CASE WHEN p.provolatile = 'i' THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_deterministic,
             CAST('MODIFIES' AS character_data) AS sql_data_access,
!            CAST(CASE WHEN p.prorettype <> 0 THEN
               CASE WHEN p.proisstrict THEN 'YES' ELSE 'NO' END END AS yes_or_no) AS is_null_call,
             CAST(null AS character_data) AS sql_path,
             CAST('YES' AS yes_or_no) AS schema_level_routine,
--- 1463,1469 ----
             CAST('GENERAL' AS character_data) AS parameter_style,
             CAST(CASE WHEN p.provolatile = 'i' THEN 'YES' ELSE 'NO' END AS yes_or_no) AS is_deterministic,
             CAST('MODIFIES' AS character_data) AS sql_data_access,
!            CAST(CASE WHEN p.prokind <> 'p' THEN
               CASE WHEN p.proisstrict THEN 'YES' ELSE 'NO' END END AS yes_or_no) AS is_null_call,
             CAST(null AS character_data) AS sql_path,
             CAST('YES' AS yes_or_no) AS schema_level_routine,
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 80f561d..119297b 100644
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
*************** getProcedureTypeDescription(StringInfo b
*** 4047,4057 ****
  		elog(ERROR, "cache lookup failed for procedure %u", procid);
  	procForm = (Form_pg_proc) GETSTRUCT(procTup);
  
! 	if (procForm->proisagg)
  		appendStringInfoString(buffer, "aggregate");
! 	else if (procForm->prorettype == InvalidOid)
  		appendStringInfoString(buffer, "procedure");
! 	else
  		appendStringInfoString(buffer, "function");
  
  	ReleaseSysCache(procTup);
--- 4047,4057 ----
  		elog(ERROR, "cache lookup failed for procedure %u", procid);
  	procForm = (Form_pg_proc) GETSTRUCT(procTup);
  
! 	if (procForm->prokind == PROKIND_AGGREGATE)
  		appendStringInfoString(buffer, "aggregate");
! 	else if (procForm->prokind == PROKIND_PROCEDURE)
  		appendStringInfoString(buffer, "procedure");
! 	else						/* function or window function */
  		appendStringInfoString(buffer, "function");
  
  	ReleaseSysCache(procTup);
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index f14ea26..50d8d81 100644
*** a/src/backend/catalog/pg_aggregate.c
--- b/src/backend/catalog/pg_aggregate.c
*************** AggregateCreate(const char *aggName,
*** 616,623 ****
  							 InvalidOid,	/* no validator */
  							 "aggregate_dummy", /* placeholder proc */
  							 NULL,	/* probin */
! 							 true,	/* isAgg */
! 							 false, /* isWindowFunc */
  							 false, /* security invoker (currently not
  									 * definable for agg) */
  							 false, /* isLeakProof */
--- 616,622 ----
  							 InvalidOid,	/* no validator */
  							 "aggregate_dummy", /* placeholder proc */
  							 NULL,	/* probin */
! 							 PROKIND_AGGREGATE,
  							 false, /* security invoker (currently not
  									 * definable for agg) */
  							 false, /* isLeakProof */
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index b59fadb..f7952b9 100644
*** a/src/backend/catalog/pg_proc.c
--- b/src/backend/catalog/pg_proc.c
*************** ProcedureCreate(const char *procedureNam
*** 74,81 ****
  				Oid languageValidator,
  				const char *prosrc,
  				const char *probin,
! 				bool isAgg,
! 				bool isWindowFunc,
  				bool security_definer,
  				bool isLeakProof,
  				bool isStrict,
--- 74,80 ----
  				Oid languageValidator,
  				const char *prosrc,
  				const char *probin,
! 				char prokind,
  				bool security_definer,
  				bool isLeakProof,
  				bool isStrict,
*************** ProcedureCreate(const char *procedureNam
*** 335,342 ****
  	values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
  	values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
  	values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(InvalidOid);
! 	values[Anum_pg_proc_proisagg - 1] = BoolGetDatum(isAgg);
! 	values[Anum_pg_proc_proiswindow - 1] = BoolGetDatum(isWindowFunc);
  	values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
  	values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof);
  	values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
--- 334,340 ----
  	values[Anum_pg_proc_prorows - 1] = Float4GetDatum(prorows);
  	values[Anum_pg_proc_provariadic - 1] = ObjectIdGetDatum(variadicType);
  	values[Anum_pg_proc_protransform - 1] = ObjectIdGetDatum(InvalidOid);
! 	values[Anum_pg_proc_prokind - 1] = CharGetDatum(prokind);
  	values[Anum_pg_proc_prosecdef - 1] = BoolGetDatum(security_definer);
  	values[Anum_pg_proc_proleakproof - 1] = BoolGetDatum(isLeakProof);
  	values[Anum_pg_proc_proisstrict - 1] = BoolGetDatum(isStrict);
*************** ProcedureCreate(const char *procedureNam
*** 403,408 ****
--- 401,421 ----
  			aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_FUNCTION,
  						   procedureName);
  
+ 		/* Not okay to change routine kind */
+ 		if (oldproc->prokind != prokind)
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_WRONG_OBJECT_TYPE),
+ 					 errmsg("cannot change routine type"),
+ 					 (oldproc->prokind == PROKIND_AGGREGATE ?
+ 					  errdetail("\"%s\" is an aggregate function.", procedureName) :
+ 					  oldproc->prokind == PROKIND_FUNCTION ?
+ 					  errdetail("\"%s\" is a function.", procedureName) :
+ 					  oldproc->prokind == PROKIND_PROCEDURE ?
+ 					  errdetail("\"%s\" is a procedure.", procedureName) :
+ 					  oldproc->prokind == PROKIND_WINDOW ?
+ 					  errdetail("\"%s\" is a window function.", procedureName) :
+ 					  0)));
+ 
  		/*
  		 * Not okay to change the return type of the existing proc, since
  		 * existing rules, views, etc may depend on the return type.
*************** ProcedureCreate(const char *procedureNam
*** 535,568 ****
  			}
  		}
  
- 		/* Can't change aggregate or window-function status, either */
- 		if (oldproc->proisagg != isAgg)
- 		{
- 			if (oldproc->proisagg)
- 				ereport(ERROR,
- 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- 						 errmsg("function \"%s\" is an aggregate function",
- 								procedureName)));
- 			else
- 				ereport(ERROR,
- 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- 						 errmsg("function \"%s\" is not an aggregate function",
- 								procedureName)));
- 		}
- 		if (oldproc->proiswindow != isWindowFunc)
- 		{
- 			if (oldproc->proiswindow)
- 				ereport(ERROR,
- 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- 						 errmsg("function \"%s\" is a window function",
- 								procedureName)));
- 			else
- 				ereport(ERROR,
- 						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
- 						 errmsg("function \"%s\" is not a window function",
- 								procedureName)));
- 		}
- 
  		/*
  		 * Do not change existing ownership or permissions, either.  Note
  		 * dependency-update code below has to agree with this decision.
--- 548,553 ----
*************** fmgr_sql_validator(PG_FUNCTION_ARGS)
*** 857,864 ****
  
  	/* Disallow pseudotype result */
  	/* except for RECORD, VOID, or polymorphic */
! 	if (proc->prorettype &&
! 		get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
  		proc->prorettype != RECORDOID &&
  		proc->prorettype != VOIDOID &&
  		!IsPolymorphicType(proc->prorettype))
--- 842,848 ----
  
  	/* Disallow pseudotype result */
  	/* except for RECORD, VOID, or polymorphic */
! 	if (get_typtype(proc->prorettype) == TYPTYPE_PSEUDO &&
  		proc->prorettype != RECORDOID &&
  		proc->prorettype != VOIDOID &&
  		!IsPolymorphicType(proc->prorettype))
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 5652e9e..5e6e8a6 100644
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
*************** WHERE
*** 332,340 ****
  UNION ALL
  SELECT
  	l.objoid, l.classoid, l.objsubid,
! 	CASE WHEN pro.proisagg = true THEN 'aggregate'::text
! 	     WHEN pro.proisagg = false THEN 'function'::text
! 	END AS objtype,
  	pro.pronamespace AS objnamespace,
  	CASE WHEN pg_function_is_visible(pro.oid)
  	     THEN quote_ident(pro.proname)
--- 332,342 ----
  UNION ALL
  SELECT
  	l.objoid, l.classoid, l.objsubid,
! 	CASE pro.prokind
!             WHEN 'a' THEN 'aggregate'::text
!             WHEN 'f' THEN 'function'::text
!             WHEN 'p' THEN 'procedure'::text
!             WHEN 'w' THEN 'window'::text END AS objtype,
  	pro.pronamespace AS objnamespace,
  	CASE WHEN pg_function_is_visible(pro.oid)
  	     THEN quote_ident(pro.proname)
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
index fc4ce8d..4b38ef6 100644
*** a/src/backend/commands/dropcmds.c
--- b/src/backend/commands/dropcmds.c
*************** RemoveObjects(DropStmt *stmt)
*** 92,98 ****
  		 */
  		if (stmt->removeType == OBJECT_FUNCTION)
  		{
! 			if (get_func_isagg(address.objectId))
  				ereport(ERROR,
  						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  						 errmsg("\"%s\" is an aggregate function",
--- 92,98 ----
  		 */
  		if (stmt->removeType == OBJECT_FUNCTION)
  		{
! 			if (get_func_prokind(address.objectId) == PROKIND_AGGREGATE)
  				ereport(ERROR,
  						(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  						 errmsg("\"%s\" is an aggregate function",
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index abdfa24..b1f87d0 100644
*** a/src/backend/commands/functioncmds.c
--- b/src/backend/commands/functioncmds.c
*************** CreateFunction(ParseState *pstate, Creat
*** 1003,1011 ****
  
  	if (stmt->is_procedure)
  	{
  		Assert(!stmt->returnType);
! 
! 		prorettype = InvalidOid;
  		returnsSet = false;
  	}
  	else if (stmt->returnType)
--- 1003,1014 ----
  
  	if (stmt->is_procedure)
  	{
+ 		/*
+ 		 * Sometime in the future, procedures might be allowed to return
+ 		 * results; for now, they all return VOID.
+ 		 */
  		Assert(!stmt->returnType);
! 		prorettype = VOIDOID;
  		returnsSet = false;
  	}
  	else if (stmt->returnType)
*************** CreateFunction(ParseState *pstate, Creat
*** 1097,1104 ****
  						   languageValidator,
  						   prosrc_str,	/* converted to text later */
  						   probin_str,	/* converted to text later */
! 						   false,	/* not an aggregate */
! 						   isWindowFunc,
  						   security,
  						   isLeakProof,
  						   isStrict,
--- 1100,1106 ----
  						   languageValidator,
  						   prosrc_str,	/* converted to text later */
  						   probin_str,	/* converted to text later */
! 						   stmt->is_procedure ? PROKIND_PROCEDURE : (isWindowFunc ? PROKIND_WINDOW : PROKIND_FUNCTION),
  						   security,
  						   isLeakProof,
  						   isStrict,
*************** RemoveFunctionById(Oid funcOid)
*** 1126,1132 ****
  {
  	Relation	relation;
  	HeapTuple	tup;
! 	bool		isagg;
  
  	/*
  	 * Delete the pg_proc tuple.
--- 1128,1134 ----
  {
  	Relation	relation;
  	HeapTuple	tup;
! 	char		prokind;
  
  	/*
  	 * Delete the pg_proc tuple.
*************** RemoveFunctionById(Oid funcOid)
*** 1137,1143 ****
  	if (!HeapTupleIsValid(tup)) /* should not happen */
  		elog(ERROR, "cache lookup failed for function %u", funcOid);
  
! 	isagg = ((Form_pg_proc) GETSTRUCT(tup))->proisagg;
  
  	CatalogTupleDelete(relation, &tup->t_self);
  
--- 1139,1145 ----
  	if (!HeapTupleIsValid(tup)) /* should not happen */
  		elog(ERROR, "cache lookup failed for function %u", funcOid);
  
! 	prokind = ((Form_pg_proc) GETSTRUCT(tup))->prokind;
  
  	CatalogTupleDelete(relation, &tup->t_self);
  
*************** RemoveFunctionById(Oid funcOid)
*** 1148,1154 ****
  	/*
  	 * If there's a pg_aggregate tuple, delete that too.
  	 */
! 	if (isagg)
  	{
  		relation = heap_open(AggregateRelationId, RowExclusiveLock);
  
--- 1150,1156 ----
  	/*
  	 * If there's a pg_aggregate tuple, delete that too.
  	 */
! 	if (prokind == PROKIND_AGGREGATE)
  	{
  		relation = heap_open(AggregateRelationId, RowExclusiveLock);
  
*************** AlterFunction(ParseState *pstate, AlterF
*** 1203,1215 ****
  		aclcheck_error(ACLCHECK_NOT_OWNER, stmt->objtype,
  					   NameListToString(stmt->func->objname));
  
! 	if (procForm->proisagg)
  		ereport(ERROR,
  				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  				 errmsg("\"%s\" is an aggregate function",
  						NameListToString(stmt->func->objname))));
  
! 	is_procedure = (procForm->prorettype == InvalidOid);
  
  	/* Examine requested actions. */
  	foreach(l, stmt->actions)
--- 1205,1217 ----
  		aclcheck_error(ACLCHECK_NOT_OWNER, stmt->objtype,
  					   NameListToString(stmt->func->objname));
  
! 	if (procForm->prokind == PROKIND_AGGREGATE)
  		ereport(ERROR,
  				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  				 errmsg("\"%s\" is an aggregate function",
  						NameListToString(stmt->func->objname))));
  
! 	is_procedure = (procForm->prokind == PROKIND_PROCEDURE);
  
  	/* Examine requested actions. */
  	foreach(l, stmt->actions)
*************** CreateCast(CreateCastStmt *stmt)
*** 1525,1538 ****
  					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
  					 errmsg("cast function must not be volatile")));
  #endif
! 		if (procstruct->proisagg)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! 					 errmsg("cast function must not be an aggregate function")));
! 		if (procstruct->proiswindow)
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! 					 errmsg("cast function must not be a window function")));
  		if (procstruct->proretset)
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
--- 1527,1536 ----
  					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
  					 errmsg("cast function must not be volatile")));
  #endif
! 		if (procstruct->prokind != PROKIND_FUNCTION)
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! 					 errmsg("cast function must be a normal function")));
  		if (procstruct->proretset)
  			ereport(ERROR,
  					(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
*************** check_transform_function(Form_pg_proc pr
*** 1777,1790 ****
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
  				 errmsg("transform function must not be volatile")));
! 	if (procstruct->proisagg)
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! 				 errmsg("transform function must not be an aggregate function")));
! 	if (procstruct->proiswindow)
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! 				 errmsg("transform function must not be a window function")));
  	if (procstruct->proretset)
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
--- 1775,1784 ----
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
  				 errmsg("transform function must not be volatile")));
! 	if (procstruct->prokind != PROKIND_FUNCTION)
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
! 				 errmsg("transform function must be a normal function")));
  	if (procstruct->proretset)
  		ereport(ERROR,
  				(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 2ec9624..447bd49 100644
*** a/src/backend/commands/proclang.c
--- b/src/backend/commands/proclang.c
*************** CreateProceduralLanguage(CreatePLangStmt
*** 129,136 ****
  									  F_FMGR_C_VALIDATOR,
  									  pltemplate->tmplhandler,
  									  pltemplate->tmpllibrary,
! 									  false,	/* isAgg */
! 									  false,	/* isWindowFunc */
  									  false,	/* security_definer */
  									  false,	/* isLeakProof */
  									  false,	/* isStrict */
--- 129,135 ----
  									  F_FMGR_C_VALIDATOR,
  									  pltemplate->tmplhandler,
  									  pltemplate->tmpllibrary,
! 									  PROKIND_FUNCTION,
  									  false,	/* security_definer */
  									  false,	/* isLeakProof */
  									  false,	/* isStrict */
*************** CreateProceduralLanguage(CreatePLangStmt
*** 169,176 ****
  										  F_FMGR_C_VALIDATOR,
  										  pltemplate->tmplinline,
  										  pltemplate->tmpllibrary,
! 										  false,	/* isAgg */
! 										  false,	/* isWindowFunc */
  										  false,	/* security_definer */
  										  false,	/* isLeakProof */
  										  true, /* isStrict */
--- 168,174 ----
  										  F_FMGR_C_VALIDATOR,
  										  pltemplate->tmplinline,
  										  pltemplate->tmpllibrary,
! 										  PROKIND_FUNCTION,
  										  false,	/* security_definer */
  										  false,	/* isLeakProof */
  										  true, /* isStrict */
*************** CreateProceduralLanguage(CreatePLangStmt
*** 212,219 ****
  										  F_FMGR_C_VALIDATOR,
  										  pltemplate->tmplvalidator,
  										  pltemplate->tmpllibrary,
! 										  false,	/* isAgg */
! 										  false,	/* isWindowFunc */
  										  false,	/* security_definer */
  										  false,	/* isLeakProof */
  										  true, /* isStrict */
--- 210,216 ----
  										  F_FMGR_C_VALIDATOR,
  										  pltemplate->tmplvalidator,
  										  pltemplate->tmpllibrary,
! 										  PROKIND_FUNCTION,
  										  false,	/* security_definer */
  										  false,	/* isLeakProof */
  										  true, /* isStrict */
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 899a5c4..bf3cd3a 100644
*** a/src/backend/commands/typecmds.c
--- b/src/backend/commands/typecmds.c
*************** makeRangeConstructors(const char *name, 
*** 1672,1679 ****
  								 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
  								 prosrc[i], /* prosrc */
  								 NULL,	/* probin */
! 								 false, /* isAgg */
! 								 false, /* isWindowFunc */
  								 false, /* security_definer */
  								 false, /* leakproof */
  								 false, /* isStrict */
--- 1672,1678 ----
  								 F_FMGR_INTERNAL_VALIDATOR, /* language validator */
  								 prosrc[i], /* prosrc */
  								 NULL,	/* probin */
! 								 PROKIND_FUNCTION,
  								 false, /* security_definer */
  								 false, /* leakproof */
  								 false, /* isStrict */
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 7e249f5..78bc4ab 100644
*** a/src/backend/executor/functions.c
--- b/src/backend/executor/functions.c
*************** init_execution_state(List *queryTree_lis
*** 573,580 ****
  	 *
  	 * Note: don't set setsResult if the function returns VOID, as evidenced
  	 * by not having made a junkfilter.  This ensures we'll throw away any
! 	 * output from a utility statement that check_sql_fn_retval deemed to not
! 	 * have output.
  	 */
  	if (lasttages && fcache->junkFilter)
  	{
--- 573,579 ----
  	 *
  	 * Note: don't set setsResult if the function returns VOID, as evidenced
  	 * by not having made a junkfilter.  This ensures we'll throw away any
! 	 * output from the last statement in such a function.
  	 */
  	if (lasttages && fcache->junkFilter)
  	{
*************** init_sql_fcache(FmgrInfo *finfo, Oid col
*** 659,666 ****
  	fcache->rettype = rettype;
  
  	/* Fetch the typlen and byval info for the result type */
! 	if (rettype)
! 		get_typlenbyval(rettype, &fcache->typlen, &fcache->typbyval);
  
  	/* Remember whether we're returning setof something */
  	fcache->returnsSet = procedureStruct->proretset;
--- 658,664 ----
  	fcache->rettype = rettype;
  
  	/* Fetch the typlen and byval info for the result type */
! 	get_typlenbyval(rettype, &fcache->typlen, &fcache->typbyval);
  
  	/* Remember whether we're returning setof something */
  	fcache->returnsSet = procedureStruct->proretset;
*************** fmgr_sql(PG_FUNCTION_ARGS)
*** 1324,1331 ****
  		}
  		else
  		{
! 			/* Should only get here for procedures and VOID functions */
! 			Assert(fcache->rettype == InvalidOid || fcache->rettype == VOIDOID);
  			fcinfo->isnull = true;
  			result = (Datum) 0;
  		}
--- 1322,1329 ----
  		}
  		else
  		{
! 			/* Should only get here for VOID functions and procedures */
! 			Assert(fcache->rettype == VOIDOID);
  			fcinfo->isnull = true;
  			result = (Datum) 0;
  		}
*************** check_sql_fn_retval(Oid func_id, Oid ret
*** 1549,1557 ****
  	if (modifyTargetList)
  		*modifyTargetList = false;	/* initialize for no change */
  	if (junkFilter)
! 		*junkFilter = NULL;		/* initialize in case of procedure/VOID result */
  
! 	if (!rettype)
  		return false;
  
  	/*
--- 1547,1559 ----
  	if (modifyTargetList)
  		*modifyTargetList = false;	/* initialize for no change */
  	if (junkFilter)
! 		*junkFilter = NULL;		/* initialize in case of VOID result */
  
! 	/*
! 	 * If it's declared to return VOID, we don't care what's in the function.
! 	 * (This takes care of the procedure case, as well.)
! 	 */
! 	if (rettype == VOIDOID)
  		return false;
  
  	/*
*************** check_sql_fn_retval(Oid func_id, Oid ret
*** 1597,1617 ****
  	else
  	{
  		/* Empty function body, or last statement is a utility command */
! 		if (rettype && rettype != VOIDOID)
! 			ereport(ERROR,
! 					(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
! 					 errmsg("return type mismatch in function declared to return %s",
! 							format_type_be(rettype)),
! 					 errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE RETURNING.")));
! 		return false;
  	}
  
  	/*
  	 * OK, check that the targetlist returns something matching the declared
! 	 * type.  (We used to insist that the declared type not be VOID in this
! 	 * case, but that makes it hard to write a void function that exits after
! 	 * calling another void function.  Instead, we insist that the tlist
! 	 * return void ... so void is treated as if it were a scalar type below.)
  	 */
  
  	/*
--- 1599,1615 ----
  	else
  	{
  		/* Empty function body, or last statement is a utility command */
! 		ereport(ERROR,
! 				(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
! 				 errmsg("return type mismatch in function declared to return %s",
! 						format_type_be(rettype)),
! 				 errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE RETURNING.")));
! 		return false;			/* keep compiler quiet */
  	}
  
  	/*
  	 * OK, check that the targetlist returns something matching the declared
! 	 * type.
  	 */
  
  	/*
*************** check_sql_fn_retval(Oid func_id, Oid ret
*** 1624,1631 ****
  	if (fn_typtype == TYPTYPE_BASE ||
  		fn_typtype == TYPTYPE_DOMAIN ||
  		fn_typtype == TYPTYPE_ENUM ||
! 		fn_typtype == TYPTYPE_RANGE ||
! 		rettype == VOIDOID)
  	{
  		/*
  		 * For scalar-type returns, the target list must have exactly one
--- 1622,1628 ----
  	if (fn_typtype == TYPTYPE_BASE ||
  		fn_typtype == TYPTYPE_DOMAIN ||
  		fn_typtype == TYPTYPE_ENUM ||
! 		fn_typtype == TYPTYPE_RANGE)
  	{
  		/*
  		 * For scalar-type returns, the target list must have exactly one
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 89f27ce..a9a09af 100644
*** a/src/backend/optimizer/util/clauses.c
--- b/src/backend/optimizer/util/clauses.c
*************** inline_function(Oid funcid, Oid result_t
*** 4484,4495 ****
  
  	/*
  	 * Forget it if the function is not SQL-language or has other showstopper
! 	 * properties.  (The nargs check is just paranoia.)
  	 */
  	if (funcform->prolang != SQLlanguageId ||
  		funcform->prosecdef ||
  		funcform->proretset ||
- 		funcform->prorettype == InvalidOid ||
  		funcform->prorettype == RECORDOID ||
  		!heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
  		funcform->pronargs != list_length(args))
--- 4484,4495 ----
  
  	/*
  	 * Forget it if the function is not SQL-language or has other showstopper
! 	 * properties.  (The prokind and nargs checks are just paranoia.)
  	 */
  	if (funcform->prolang != SQLlanguageId ||
  		funcform->prosecdef ||
+ 		funcform->prokind != PROKIND_FUNCTION ||
  		funcform->proretset ||
  		funcform->prorettype == RECORDOID ||
  		!heap_attisnull(func_tuple, Anum_pg_proc_proconfig) ||
  		funcform->pronargs != list_length(args))
diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c
index 085aa87..665d332 100644
*** a/src/backend/parser/parse_coerce.c
--- b/src/backend/parser/parse_coerce.c
*************** build_coercion_expression(Node *node,
*** 834,841 ****
  		 */
  		/* Assert(targetTypeId == procstruct->prorettype); */
  		Assert(!procstruct->proretset);
! 		Assert(!procstruct->proisagg);
! 		Assert(!procstruct->proiswindow);
  		nargs = procstruct->pronargs;
  		Assert(nargs >= 1 && nargs <= 3);
  		/* Assert(procstruct->proargtypes.values[0] == exprType(node)); */
--- 834,840 ----
  		 */
  		/* Assert(targetTypeId == procstruct->prorettype); */
  		Assert(!procstruct->proretset);
! 		Assert(procstruct->prokind == PROKIND_FUNCTION);
  		nargs = procstruct->pronargs;
  		Assert(nargs >= 1 && nargs <= 3);
  		/* Assert(procstruct->proargtypes.values[0] == exprType(node)); */
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index 2a4ac09..ea5d521 100644
*** a/src/backend/parser/parse_func.c
--- b/src/backend/parser/parse_func.c
*************** func_get_detail(List *funcname,
*** 1614,1627 ****
  				*argdefaults = defaults;
  			}
  		}
! 		if (pform->proisagg)
! 			result = FUNCDETAIL_AGGREGATE;
! 		else if (pform->proiswindow)
! 			result = FUNCDETAIL_WINDOWFUNC;
! 		else if (pform->prorettype == InvalidOid)
! 			result = FUNCDETAIL_PROCEDURE;
! 		else
! 			result = FUNCDETAIL_NORMAL;
  		ReleaseSysCache(ftup);
  		return result;
  	}
--- 1614,1640 ----
  				*argdefaults = defaults;
  			}
  		}
! 
! 		switch (pform->prokind)
! 		{
! 			case PROKIND_AGGREGATE:
! 				result = FUNCDETAIL_AGGREGATE;
! 				break;
! 			case PROKIND_FUNCTION:
! 				result = FUNCDETAIL_NORMAL;
! 				break;
! 			case PROKIND_PROCEDURE:
! 				result = FUNCDETAIL_PROCEDURE;
! 				break;
! 			case PROKIND_WINDOW:
! 				result = FUNCDETAIL_WINDOWFUNC;
! 				break;
! 			default:
! 				elog(ERROR, "unrecognized prokind: %c", pform->prokind);
! 				result = FUNCDETAIL_NORMAL; /* keep compiler quiet */
! 				break;
! 		}
! 
  		ReleaseSysCache(ftup);
  		return result;
  	}
*************** LookupFuncWithArgs(ObjectType objtype, O
*** 2067,2073 ****
  	if (objtype == OBJECT_FUNCTION)
  	{
  		/* Make sure it's a function, not a procedure */
! 		if (oid && get_func_rettype(oid) == InvalidOid)
  		{
  			if (noError)
  				return InvalidOid;
--- 2080,2086 ----
  	if (objtype == OBJECT_FUNCTION)
  	{
  		/* Make sure it's a function, not a procedure */
! 		if (oid && get_func_prokind(oid) == PROKIND_PROCEDURE)
  		{
  			if (noError)
  				return InvalidOid;
*************** LookupFuncWithArgs(ObjectType objtype, O
*** 2098,2104 ****
  		}
  
  		/* Make sure it's a procedure */
! 		if (get_func_rettype(oid) != InvalidOid)
  		{
  			if (noError)
  				return InvalidOid;
--- 2111,2117 ----
  		}
  
  		/* Make sure it's a procedure */
! 		if (get_func_prokind(oid) != PROKIND_PROCEDURE)
  		{
  			if (noError)
  				return InvalidOid;
*************** LookupFuncWithArgs(ObjectType objtype, O
*** 2134,2140 ****
  		}
  
  		/* Make sure it's an aggregate */
! 		if (!get_func_isagg(oid))
  		{
  			if (noError)
  				return InvalidOid;
--- 2147,2153 ----
  		}
  
  		/* Make sure it's an aggregate */
! 		if (get_func_prokind(oid) != PROKIND_AGGREGATE)
  		{
  			if (noError)
  				return InvalidOid;
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 3697466..b58ee3c 100644
*** a/src/backend/utils/adt/ruleutils.c
--- b/src/backend/utils/adt/ruleutils.c
*************** pg_get_functiondef(PG_FUNCTION_ARGS)
*** 2481,2492 ****
  	proc = (Form_pg_proc) GETSTRUCT(proctup);
  	name = NameStr(proc->proname);
  
! 	if (proc->proisagg)
  		ereport(ERROR,
  				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  				 errmsg("\"%s\" is an aggregate function", name)));
  
! 	isfunction = (proc->prorettype != InvalidOid);
  
  	/*
  	 * We always qualify the function name, to ensure the right function gets
--- 2481,2492 ----
  	proc = (Form_pg_proc) GETSTRUCT(proctup);
  	name = NameStr(proc->proname);
  
! 	if (proc->prokind == PROKIND_AGGREGATE)
  		ereport(ERROR,
  				(errcode(ERRCODE_WRONG_OBJECT_TYPE),
  				 errmsg("\"%s\" is an aggregate function", name)));
  
! 	isfunction = (proc->prokind != PROKIND_PROCEDURE);
  
  	/*
  	 * We always qualify the function name, to ensure the right function gets
*************** pg_get_functiondef(PG_FUNCTION_ARGS)
*** 2513,2519 ****
  	/* Emit some miscellaneous options on one line */
  	oldlen = buf.len;
  
! 	if (proc->proiswindow)
  		appendStringInfoString(&buf, " WINDOW");
  	switch (proc->provolatile)
  	{
--- 2513,2519 ----
  	/* Emit some miscellaneous options on one line */
  	oldlen = buf.len;
  
! 	if (proc->prokind == PROKIND_WINDOW)
  		appendStringInfoString(&buf, " WINDOW");
  	switch (proc->provolatile)
  	{
*************** pg_get_function_result(PG_FUNCTION_ARGS)
*** 2717,2723 ****
  	if (!HeapTupleIsValid(proctup))
  		PG_RETURN_NULL();
  
! 	if (((Form_pg_proc) GETSTRUCT(proctup))->prorettype == InvalidOid)
  	{
  		ReleaseSysCache(proctup);
  		PG_RETURN_NULL();
--- 2717,2723 ----
  	if (!HeapTupleIsValid(proctup))
  		PG_RETURN_NULL();
  
! 	if (((Form_pg_proc) GETSTRUCT(proctup))->prokind == PROKIND_PROCEDURE)
  	{
  		ReleaseSysCache(proctup);
  		PG_RETURN_NULL();
*************** print_function_arguments(StringInfo buf,
*** 2817,2823 ****
  	}
  
  	/* Check for special treatment of ordered-set aggregates */
! 	if (proc->proisagg)
  	{
  		HeapTuple	aggtup;
  		Form_pg_aggregate agg;
--- 2817,2823 ----
  	}
  
  	/* Check for special treatment of ordered-set aggregates */
! 	if (proc->prokind == PROKIND_AGGREGATE)
  	{
  		HeapTuple	aggtup;
  		Form_pg_aggregate agg;
diff --git a/src/backend/utils/cache/lsyscache.c b/src/backend/utils/cache/lsyscache.c
index 51b6b4f..bba595a 100644
*** a/src/backend/utils/cache/lsyscache.c
--- b/src/backend/utils/cache/lsyscache.c
*************** func_parallel(Oid funcid)
*** 1600,1619 ****
  }
  
  /*
!  * get_func_isagg
!  *	   Given procedure id, return the function's proisagg field.
   */
! bool
! get_func_isagg(Oid funcid)
  {
  	HeapTuple	tp;
! 	bool		result;
  
  	tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
  	if (!HeapTupleIsValid(tp))
  		elog(ERROR, "cache lookup failed for function %u", funcid);
  
! 	result = ((Form_pg_proc) GETSTRUCT(tp))->proisagg;
  	ReleaseSysCache(tp);
  	return result;
  }
--- 1600,1619 ----
  }
  
  /*
!  * get_func_prokind
!  *	   Given procedure id, return the routine kind.
   */
! char
! get_func_prokind(Oid funcid)
  {
  	HeapTuple	tp;
! 	char		result;
  
  	tp = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
  	if (!HeapTupleIsValid(tp))
  		elog(ERROR, "cache lookup failed for function %u", funcid);
  
! 	result = ((Form_pg_proc) GETSTRUCT(tp))->prokind;
  	ReleaseSysCache(tp);
  	return result;
  }
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 2c934e6..566cbf2 100644
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
*************** getAggregates(Archive *fout, int *numAgg
*** 5407,5417 ****
--- 5407,5421 ----
  		PQExpBuffer racl_subquery = createPQExpBuffer();
  		PQExpBuffer initacl_subquery = createPQExpBuffer();
  		PQExpBuffer initracl_subquery = createPQExpBuffer();
+ 		const char *agg_check;
  
  		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
  						initracl_subquery, "p.proacl", "p.proowner", "'f'",
  						dopt->binary_upgrade);
  
+ 		agg_check = (fout->remoteVersion >= 110000 ? "p.prokind = 'a'"
+ 					 : "p.proisagg");
+ 
  		appendPQExpBuffer(query, "SELECT p.tableoid, p.oid, "
  						  "p.proname AS aggname, "
  						  "p.pronamespace AS aggnamespace, "
*************** getAggregates(Archive *fout, int *numAgg
*** 5426,5432 ****
  						  "(p.oid = pip.objoid "
  						  "AND pip.classoid = 'pg_proc'::regclass "
  						  "AND pip.objsubid = 0) "
! 						  "WHERE p.proisagg AND ("
  						  "p.pronamespace != "
  						  "(SELECT oid FROM pg_namespace "
  						  "WHERE nspname = 'pg_catalog') OR "
--- 5430,5436 ----
  						  "(p.oid = pip.objoid "
  						  "AND pip.classoid = 'pg_proc'::regclass "
  						  "AND pip.objsubid = 0) "
! 						  "WHERE %s AND ("
  						  "p.pronamespace != "
  						  "(SELECT oid FROM pg_namespace "
  						  "WHERE nspname = 'pg_catalog') OR "
*************** getAggregates(Archive *fout, int *numAgg
*** 5435,5441 ****
  						  acl_subquery->data,
  						  racl_subquery->data,
  						  initacl_subquery->data,
! 						  initracl_subquery->data);
  		if (dopt->binary_upgrade)
  			appendPQExpBufferStr(query,
  								 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
--- 5439,5446 ----
  						  acl_subquery->data,
  						  racl_subquery->data,
  						  initacl_subquery->data,
! 						  initracl_subquery->data,
! 						  agg_check);
  		if (dopt->binary_upgrade)
  			appendPQExpBufferStr(query,
  								 " OR EXISTS(SELECT 1 FROM pg_depend WHERE "
*************** getFuncs(Archive *fout, int *numFuncs)
*** 5616,5626 ****
--- 5621,5635 ----
  		PQExpBuffer racl_subquery = createPQExpBuffer();
  		PQExpBuffer initacl_subquery = createPQExpBuffer();
  		PQExpBuffer initracl_subquery = createPQExpBuffer();
+ 		const char *not_agg_check;
  
  		buildACLQueries(acl_subquery, racl_subquery, initacl_subquery,
  						initracl_subquery, "p.proacl", "p.proowner", "'f'",
  						dopt->binary_upgrade);
  
+ 		not_agg_check = (fout->remoteVersion >= 110000 ? "p.prokind <> 'a'"
+ 						 : "NOT p.proisagg");
+ 
  		appendPQExpBuffer(query,
  						  "SELECT p.tableoid, p.oid, p.proname, p.prolang, "
  						  "p.pronargs, p.proargtypes, p.prorettype, "
*************** getFuncs(Archive *fout, int *numFuncs)
*** 5635,5641 ****
  						  "(p.oid = pip.objoid "
  						  "AND pip.classoid = 'pg_proc'::regclass "
  						  "AND pip.objsubid = 0) "
! 						  "WHERE NOT proisagg"
  						  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
  						  "WHERE classid = 'pg_proc'::regclass AND "
  						  "objid = p.oid AND deptype = 'i')"
--- 5644,5650 ----
  						  "(p.oid = pip.objoid "
  						  "AND pip.classoid = 'pg_proc'::regclass "
  						  "AND pip.objsubid = 0) "
! 						  "WHERE %s"
  						  "\n  AND NOT EXISTS (SELECT 1 FROM pg_depend "
  						  "WHERE classid = 'pg_proc'::regclass AND "
  						  "objid = p.oid AND deptype = 'i')"
*************** getFuncs(Archive *fout, int *numFuncs)
*** 5655,5660 ****
--- 5664,5670 ----
  						  initacl_subquery->data,
  						  initracl_subquery->data,
  						  username_subquery,
+ 						  not_agg_check,
  						  g_last_builtin_oid,
  						  g_last_builtin_oid);
  		if (dopt->binary_upgrade)
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11424,11435 ****
  	char	   *funcargs;
  	char	   *funciargs;
  	char	   *funcresult;
- 	bool		is_procedure;
  	char	   *proallargtypes;
  	char	   *proargmodes;
  	char	   *proargnames;
  	char	   *protrftypes;
! 	char	   *proiswindow;
  	char	   *provolatile;
  	char	   *proisstrict;
  	char	   *prosecdef;
--- 11434,11444 ----
  	char	   *funcargs;
  	char	   *funciargs;
  	char	   *funcresult;
  	char	   *proallargtypes;
  	char	   *proargmodes;
  	char	   *proargnames;
  	char	   *protrftypes;
! 	char	   *prokind;
  	char	   *provolatile;
  	char	   *proisstrict;
  	char	   *prosecdef;
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11459,11465 ****
  	asPart = createPQExpBuffer();
  
  	/* Fetch function-specific details */
! 	if (fout->remoteVersion >= 90600)
  	{
  		/*
  		 * proparallel was added in 9.6
--- 11468,11493 ----
  	asPart = createPQExpBuffer();
  
  	/* Fetch function-specific details */
! 	if (fout->remoteVersion >= 110000)
! 	{
! 		/*
! 		 * prokind was added in 11
! 		 */
! 		appendPQExpBuffer(query,
! 						  "SELECT proretset, prosrc, probin, "
! 						  "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, "
! 						  "array_to_string(protrftypes, ' ') AS protrftypes, "
! 						  "prokind, provolatile, proisstrict, prosecdef, "
! 						  "proleakproof, proconfig, procost, prorows, "
! 						  "proparallel, "
! 						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
! 						  "FROM pg_catalog.pg_proc "
! 						  "WHERE oid = '%u'::pg_catalog.oid",
! 						  finfo->dobj.catId.oid);
! 	}
! 	else if (fout->remoteVersion >= 90600)
  	{
  		/*
  		 * proparallel was added in 9.6
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11470,11476 ****
  						  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
  						  "pg_catalog.pg_get_function_result(oid) AS funcresult, "
  						  "array_to_string(protrftypes, ' ') AS protrftypes, "
! 						  "proiswindow, provolatile, proisstrict, prosecdef, "
  						  "proleakproof, proconfig, procost, prorows, "
  						  "proparallel, "
  						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
--- 11498,11505 ----
  						  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
  						  "pg_catalog.pg_get_function_result(oid) AS funcresult, "
  						  "array_to_string(protrftypes, ' ') AS protrftypes, "
! 						  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
! 						  "provolatile, proisstrict, prosecdef, "
  						  "proleakproof, proconfig, procost, prorows, "
  						  "proparallel, "
  						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11489,11495 ****
  						  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
  						  "pg_catalog.pg_get_function_result(oid) AS funcresult, "
  						  "array_to_string(protrftypes, ' ') AS protrftypes, "
! 						  "proiswindow, provolatile, proisstrict, prosecdef, "
  						  "proleakproof, proconfig, procost, prorows, "
  						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
  						  "FROM pg_catalog.pg_proc "
--- 11518,11525 ----
  						  "pg_catalog.pg_get_function_identity_arguments(oid) AS funciargs, "
  						  "pg_catalog.pg_get_function_result(oid) AS funcresult, "
  						  "array_to_string(protrftypes, ' ') AS protrftypes, "
! 						  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
! 						  "provolatile, proisstrict, prosecdef, "
  						  "proleakproof, proconfig, procost, prorows, "
  						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
  						  "FROM pg_catalog.pg_proc "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11506,11512 ****
  						  "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, "
! 						  "proiswindow, provolatile, proisstrict, prosecdef, "
  						  "proleakproof, proconfig, procost, prorows, "
  						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
  						  "FROM pg_catalog.pg_proc "
--- 11536,11543 ----
  						  "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, "
! 						  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
! 						  "provolatile, proisstrict, prosecdef, "
  						  "proleakproof, proconfig, procost, prorows, "
  						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
  						  "FROM pg_catalog.pg_proc "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11524,11530 ****
  						  "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, "
! 						  "proiswindow, provolatile, proisstrict, prosecdef, "
  						  "false AS proleakproof, "
  						  " proconfig, procost, prorows, "
  						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
--- 11555,11562 ----
  						  "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, "
! 						  "CASE WHEN proiswindow THEN 'w' ELSE 'f' END AS prokind, "
! 						  "provolatile, proisstrict, prosecdef, "
  						  "false AS proleakproof, "
  						  " proconfig, procost, prorows, "
  						  "(SELECT lanname FROM pg_catalog.pg_language WHERE oid = prolang) AS lanname "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11537,11543 ****
  		appendPQExpBuffer(query,
  						  "SELECT proretset, prosrc, probin, "
  						  "proallargtypes, proargmodes, proargnames, "
! 						  "false AS proiswindow, "
  						  "provolatile, proisstrict, prosecdef, "
  						  "false AS proleakproof, "
  						  "proconfig, procost, prorows, "
--- 11569,11575 ----
  		appendPQExpBuffer(query,
  						  "SELECT proretset, prosrc, probin, "
  						  "proallargtypes, proargmodes, proargnames, "
! 						  "'f' AS prokind, "
  						  "provolatile, proisstrict, prosecdef, "
  						  "false AS proleakproof, "
  						  "proconfig, procost, prorows, "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11551,11557 ****
  		appendPQExpBuffer(query,
  						  "SELECT proretset, prosrc, probin, "
  						  "proallargtypes, proargmodes, proargnames, "
! 						  "false AS proiswindow, "
  						  "provolatile, proisstrict, prosecdef, "
  						  "false AS proleakproof, "
  						  "null AS proconfig, 0 AS procost, 0 AS prorows, "
--- 11583,11589 ----
  		appendPQExpBuffer(query,
  						  "SELECT proretset, prosrc, probin, "
  						  "proallargtypes, proargmodes, proargnames, "
! 						  "'f' AS prokind, "
  						  "provolatile, proisstrict, prosecdef, "
  						  "false AS proleakproof, "
  						  "null AS proconfig, 0 AS procost, 0 AS prorows, "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11567,11573 ****
  						  "null AS proallargtypes, "
  						  "null AS proargmodes, "
  						  "proargnames, "
! 						  "false AS proiswindow, "
  						  "provolatile, proisstrict, prosecdef, "
  						  "false AS proleakproof, "
  						  "null AS proconfig, 0 AS procost, 0 AS prorows, "
--- 11599,11605 ----
  						  "null AS proallargtypes, "
  						  "null AS proargmodes, "
  						  "proargnames, "
! 						  "'f' AS prokind, "
  						  "provolatile, proisstrict, prosecdef, "
  						  "false AS proleakproof, "
  						  "null AS proconfig, 0 AS procost, 0 AS prorows, "
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11586,11596 ****
  	{
  		funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
  		funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
! 		is_procedure = PQgetisnull(res, 0, PQfnumber(res, "funcresult"));
! 		if (is_procedure)
! 			funcresult = NULL;
! 		else
! 			funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
  		proallargtypes = proargmodes = proargnames = NULL;
  	}
  	else
--- 11618,11624 ----
  	{
  		funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
  		funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
! 		funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
  		proallargtypes = proargmodes = proargnames = NULL;
  	}
  	else
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11599,11611 ****
  		proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
  		proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
  		funcargs = funciargs = funcresult = NULL;
- 		is_procedure = false;
  	}
  	if (PQfnumber(res, "protrftypes") != -1)
  		protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
  	else
  		protrftypes = 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"));
--- 11627,11638 ----
  		proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
  		proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
  		funcargs = funciargs = funcresult = NULL;
  	}
  	if (PQfnumber(res, "protrftypes") != -1)
  		protrftypes = PQgetvalue(res, 0, PQfnumber(res, "protrftypes"));
  	else
  		protrftypes = NULL;
! 	prokind = PQgetvalue(res, 0, PQfnumber(res, "prokind"));
  	provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
  	proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
  	prosecdef = PQgetvalue(res, 0, PQfnumber(res, "prosecdef"));
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11731,11737 ****
  
  	funcsig_tag = format_function_signature(fout, finfo, false);
  
! 	keyword = is_procedure ? "PROCEDURE" : "FUNCTION";
  
  	appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
  					  keyword,
--- 11758,11767 ----
  
  	funcsig_tag = format_function_signature(fout, finfo, false);
  
! 	if (prokind[0] == PROKIND_PROCEDURE)
! 		keyword = "PROCEDURE";
! 	else
! 		keyword = "FUNCTION";	/* works for window functions too */
  
  	appendPQExpBuffer(delqry, "DROP %s %s.%s;\n",
  					  keyword,
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11744,11751 ****
  					  funcfullsig ? funcfullsig :
  					  funcsig);
  
! 	if (is_procedure)
! 		;
  	else if (funcresult)
  		appendPQExpBuffer(q, " RETURNS %s", funcresult);
  	else
--- 11774,11781 ----
  					  funcfullsig ? funcfullsig :
  					  funcsig);
  
! 	if (prokind[0] == PROKIND_PROCEDURE)
! 		 /* no result type to output */ ;
  	else if (funcresult)
  		appendPQExpBuffer(q, " RETURNS %s", funcresult);
  	else
*************** dumpFunc(Archive *fout, FuncInfo *finfo)
*** 11776,11782 ****
  		}
  	}
  
! 	if (proiswindow[0] == 't')
  		appendPQExpBufferStr(q, " WINDOW");
  
  	if (provolatile[0] != PROVOLATILE_VOLATILE)
--- 11806,11812 ----
  		}
  	}
  
! 	if (prokind[0] == PROKIND_WINDOW)
  		appendPQExpBufferStr(q, " WINDOW");
  
  	if (provolatile[0] != PROVOLATILE_VOLATILE)
diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl
index 6f74e15..1bea6ae 100644
*** a/src/bin/pg_dump/t/002_pg_dump.pl
--- b/src/bin/pg_dump/t/002_pg_dump.pl
*************** qr/^GRANT SELECT ON TABLE dump_test_seco
*** 6257,6264 ****
  						   prorows,
  						   provariadic,
  						   protransform,
! 						   proisagg,
! 						   proiswindow,
  						   prosecdef,
  						   proleakproof,
  						   proisstrict,
--- 6257,6263 ----
  						   prorows,
  						   provariadic,
  						   protransform,
! 						   prokind,
  						   prosecdef,
  						   proleakproof,
  						   proisstrict,
*************** qr/^GRANT SELECT ON TABLE dump_test_seco
*** 6290,6297 ****
  		\QGRANT SELECT(prorows) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
  		\QGRANT SELECT(provariadic) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
  		\QGRANT SELECT(protransform) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
! 		\QGRANT SELECT(proisagg) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
! 		\QGRANT SELECT(proiswindow) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
  		\QGRANT SELECT(prosecdef) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
  		\QGRANT SELECT(proleakproof) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
  		\QGRANT SELECT(proisstrict) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
--- 6289,6295 ----
  		\QGRANT SELECT(prorows) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
  		\QGRANT SELECT(provariadic) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
  		\QGRANT SELECT(protransform) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
! 		\QGRANT SELECT(prokind) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
  		\QGRANT SELECT(prosecdef) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
  		\QGRANT SELECT(proleakproof) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
  		\QGRANT SELECT(proisstrict) ON TABLE pg_catalog.pg_proc TO PUBLIC;\E\n.*
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 466a780..0c3be1f 100644
*** a/src/bin/psql/describe.c
--- b/src/bin/psql/describe.c
*************** describeAggregates(const char *pattern, 
*** 100,111 ****
  						  "  pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n",
  						  gettext_noop("Argument data types"));
  
! 	appendPQExpBuffer(&buf,
! 					  "  pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
! 					  "FROM pg_catalog.pg_proc p\n"
! 					  "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
! 					  "WHERE p.proisagg\n",
! 					  gettext_noop("Description"));
  
  	if (!showSystem && !pattern)
  		appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
--- 100,119 ----
  						  "  pg_catalog.format_type(p.proargtypes[0], NULL) AS \"%s\",\n",
  						  gettext_noop("Argument data types"));
  
! 	if (pset.sversion >= 110000)
! 		appendPQExpBuffer(&buf,
! 						  "  pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
! 						  "FROM pg_catalog.pg_proc p\n"
! 						  "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
! 						  "WHERE p.prokind = 'a'\n",
! 						  gettext_noop("Description"));
! 	else
! 		appendPQExpBuffer(&buf,
! 						  "  pg_catalog.obj_description(p.oid, 'pg_proc') as \"%s\"\n"
! 						  "FROM pg_catalog.pg_proc p\n"
! 						  "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = p.pronamespace\n"
! 						  "WHERE p.proisagg\n",
! 						  gettext_noop("Description"));
  
  	if (!showSystem && !pattern)
  		appendPQExpBufferStr(&buf, "      AND n.nspname <> 'pg_catalog'\n"
*************** describeFunctions(const char *functypes,
*** 346,359 ****
  					  gettext_noop("Schema"),
  					  gettext_noop("Name"));
  
! 	if (pset.sversion >= 80400)
  		appendPQExpBuffer(&buf,
  						  "  pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
  						  "  pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
  						  " CASE\n"
  						  "  WHEN p.proisagg THEN '%s'\n"
  						  "  WHEN p.proiswindow THEN '%s'\n"
- 						  "  WHEN p.prorettype = 0 THEN '%s'\n"
  						  "  WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
  						  "  ELSE '%s'\n"
  						  " END as \"%s\"",
--- 354,384 ----
  					  gettext_noop("Schema"),
  					  gettext_noop("Name"));
  
! 	if (pset.sversion >= 110000)
! 		appendPQExpBuffer(&buf,
! 						  "  pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
! 						  "  pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
! 						  " CASE p.prokind\n"
! 						  "  WHEN 'a' THEN '%s'\n"
! 						  "  WHEN 'w' THEN '%s'\n"
! 						  "  WHEN 'p' THEN '%s'\n"
! 						  "  ELSE '%s'\n"
! 						  " END as \"%s\"",
! 						  gettext_noop("Result data type"),
! 						  gettext_noop("Argument data types"),
! 		/* translator: "agg" is short for "aggregate" */
! 						  gettext_noop("agg"),
! 						  gettext_noop("window"),
! 						  gettext_noop("proc"),
! 						  gettext_noop("func"),
! 						  gettext_noop("Type"));
! 	else if (pset.sversion >= 80400)
  		appendPQExpBuffer(&buf,
  						  "  pg_catalog.pg_get_function_result(p.oid) as \"%s\",\n"
  						  "  pg_catalog.pg_get_function_arguments(p.oid) as \"%s\",\n"
  						  " CASE\n"
  						  "  WHEN p.proisagg THEN '%s'\n"
  						  "  WHEN p.proiswindow THEN '%s'\n"
  						  "  WHEN p.prorettype = 'pg_catalog.trigger'::pg_catalog.regtype THEN '%s'\n"
  						  "  ELSE '%s'\n"
  						  " END as \"%s\"",
*************** describeFunctions(const char *functypes,
*** 362,368 ****
  		/* translator: "agg" is short for "aggregate" */
  						  gettext_noop("agg"),
  						  gettext_noop("window"),
- 						  gettext_noop("proc"),
  						  gettext_noop("trigger"),
  						  gettext_noop("func"),
  						  gettext_noop("Type"));
--- 387,392 ----
*************** describeFunctions(const char *functypes,
*** 494,500 ****
  				appendPQExpBufferStr(&buf, "WHERE ");
  				have_where = true;
  			}
! 			appendPQExpBufferStr(&buf, "NOT p.proisagg\n");
  		}
  		if (!showTrigger)
  		{
--- 518,527 ----
  				appendPQExpBufferStr(&buf, "WHERE ");
  				have_where = true;
  			}
! 			if (pset.sversion >= 110000)
! 				appendPQExpBufferStr(&buf, "p.prokind <> 'a'\n");
! 			else
! 				appendPQExpBufferStr(&buf, "NOT p.proisagg\n");
  		}
  		if (!showTrigger)
  		{
*************** describeFunctions(const char *functypes,
*** 516,522 ****
  				appendPQExpBufferStr(&buf, "WHERE ");
  				have_where = true;
  			}
! 			appendPQExpBufferStr(&buf, "NOT p.proiswindow\n");
  		}
  	}
  	else
--- 543,552 ----
  				appendPQExpBufferStr(&buf, "WHERE ");
  				have_where = true;
  			}
! 			if (pset.sversion >= 110000)
! 				appendPQExpBufferStr(&buf, "p.prokind <> 'w'\n");
! 			else
! 				appendPQExpBufferStr(&buf, "NOT p.proiswindow\n");
  		}
  	}
  	else
*************** describeFunctions(const char *functypes,
*** 528,534 ****
  		/* Note: at least one of these must be true ... */
  		if (showAggregate)
  		{
! 			appendPQExpBufferStr(&buf, "p.proisagg\n");
  			needs_or = true;
  		}
  		if (showTrigger)
--- 558,567 ----
  		/* Note: at least one of these must be true ... */
  		if (showAggregate)
  		{
! 			if (pset.sversion >= 110000)
! 				appendPQExpBufferStr(&buf, "p.prokind = 'a'\n");
! 			else
! 				appendPQExpBufferStr(&buf, "p.proisagg\n");
  			needs_or = true;
  		}
  		if (showTrigger)
*************** describeFunctions(const char *functypes,
*** 543,549 ****
  		{
  			if (needs_or)
  				appendPQExpBufferStr(&buf, "       OR ");
! 			appendPQExpBufferStr(&buf, "p.proiswindow\n");
  			needs_or = true;
  		}
  		appendPQExpBufferStr(&buf, "      )\n");
--- 576,585 ----
  		{
  			if (needs_or)
  				appendPQExpBufferStr(&buf, "       OR ");
! 			if (pset.sversion >= 110000)
! 				appendPQExpBufferStr(&buf, "p.prokind = 'w'\n");
! 			else
! 				appendPQExpBufferStr(&buf, "p.proiswindow\n");
  			needs_or = true;
  		}
  		appendPQExpBufferStr(&buf, "      )\n");
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 8bc4a19..cf23d13 100644
*** a/src/bin/psql/tab-complete.c
--- b/src/bin/psql/tab-complete.c
*************** static const SchemaQuery Query_for_list_
*** 349,355 ****
  	/* catname */
  	"pg_catalog.pg_proc p",
  	/* selcondition */
! 	"p.proisagg",
  	/* viscondition */
  	"pg_catalog.pg_function_is_visible(p.oid)",
  	/* namespace */
--- 349,355 ----
  	/* catname */
  	"pg_catalog.pg_proc p",
  	/* selcondition */
! 	"p.prokind = 'a'",
  	/* viscondition */
  	"pg_catalog.pg_function_is_visible(p.oid)",
  	/* namespace */
*************** static const SchemaQuery Query_for_list_
*** 397,403 ****
  	/* catname */
  	"pg_catalog.pg_proc p",
  	/* selcondition */
! 	"p.prorettype <> 0",
  	/* viscondition */
  	"pg_catalog.pg_function_is_visible(p.oid)",
  	/* namespace */
--- 397,403 ----
  	/* catname */
  	"pg_catalog.pg_proc p",
  	/* selcondition */
! 	"p.prokind IN ('f', 'w')",
  	/* viscondition */
  	"pg_catalog.pg_function_is_visible(p.oid)",
  	/* namespace */
*************** static const SchemaQuery Query_for_list_
*** 428,434 ****
  	/* catname */
  	"pg_catalog.pg_proc p",
  	/* selcondition */
! 	"p.prorettype = 0",
  	/* viscondition */
  	"pg_catalog.pg_function_is_visible(p.oid)",
  	/* namespace */
--- 428,434 ----
  	/* catname */
  	"pg_catalog.pg_proc p",
  	/* selcondition */
! 	"p.prokind = 'p'",
  	/* viscondition */
  	"pg_catalog.pg_function_is_visible(p.oid)",
  	/* namespace */
diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h
index 26b1866..01cf59e 100644
*** a/src/include/catalog/pg_class.h
--- b/src/include/catalog/pg_class.h
*************** DATA(insert OID = 1247 (  pg_type		PGNSP
*** 151,157 ****
  DESCR("");
  DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 22 0 f f f f f f f t n f 3 1 _null_ _null_ _null_));
  DESCR("");
! DATA(insert OID = 1255 (  pg_proc		PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 29 0 t f f f f f f t n f 3 1 _null_ _null_ _null_));
  DESCR("");
  DATA(insert OID = 1259 (  pg_class		PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 33 0 t f f f f f f t n f 3 1 _null_ _null_ _null_));
  DESCR("");
--- 151,157 ----
  DESCR("");
  DATA(insert OID = 1249 (  pg_attribute	PGNSP 75 0 PGUID 0 0 0 0 0 0 0 f f p r 22 0 f f f f f f f t n f 3 1 _null_ _null_ _null_));
  DESCR("");
! DATA(insert OID = 1255 (  pg_proc		PGNSP 81 0 PGUID 0 0 0 0 0 0 0 f f p r 28 0 t f f f f f f t n f 3 1 _null_ _null_ _null_));
  DESCR("");
  DATA(insert OID = 1259 (  pg_class		PGNSP 83 0 PGUID 0 0 0 0 0 0 0 f f p r 33 0 t f f f f f f t n f 3 1 _null_ _null_ _null_));
  DESCR("");
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c00d055..b25c918 100644
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** CATALOG(pg_proc,1255) BKI_BOOTSTRAP BKI_
*** 43,50 ****
  	float4		prorows;		/* estimated # of rows out (if proretset) */
  	Oid			provariadic;	/* element type of variadic array, or 0 */
  	regproc		protransform;	/* transforms calls to it during planning */
! 	bool		proisagg;		/* is it an aggregate? */
! 	bool		proiswindow;	/* is it a window function? */
  	bool		prosecdef;		/* security definer */
  	bool		proleakproof;	/* is it a leak-proof function? */
  	bool		proisstrict;	/* strict with respect to NULLs? */
--- 43,49 ----
  	float4		prorows;		/* estimated # of rows out (if proretset) */
  	Oid			provariadic;	/* element type of variadic array, or 0 */
  	regproc		protransform;	/* transforms calls to it during planning */
! 	char		prokind;		/* see PROKIND_ categories below */
  	bool		prosecdef;		/* security definer */
  	bool		proleakproof;	/* is it a leak-proof function? */
  	bool		proisstrict;	/* strict with respect to NULLs? */
*************** typedef FormData_pg_proc *Form_pg_proc;
*** 86,92 ****
   *		compiler constants for pg_proc
   * ----------------
   */
! #define Natts_pg_proc					29
  #define Anum_pg_proc_proname			1
  #define Anum_pg_proc_pronamespace		2
  #define Anum_pg_proc_proowner			3
--- 85,91 ----
   *		compiler constants for pg_proc
   * ----------------
   */
! #define Natts_pg_proc					28
  #define Anum_pg_proc_proname			1
  #define Anum_pg_proc_pronamespace		2
  #define Anum_pg_proc_proowner			3
*************** typedef FormData_pg_proc *Form_pg_proc;
*** 95,121 ****
  #define Anum_pg_proc_prorows			6
  #define Anum_pg_proc_provariadic		7
  #define Anum_pg_proc_protransform		8
! #define Anum_pg_proc_proisagg			9
! #define Anum_pg_proc_proiswindow		10
! #define Anum_pg_proc_prosecdef			11
! #define Anum_pg_proc_proleakproof		12
! #define Anum_pg_proc_proisstrict		13
! #define Anum_pg_proc_proretset			14
! #define Anum_pg_proc_provolatile		15
! #define Anum_pg_proc_proparallel		16
! #define Anum_pg_proc_pronargs			17
! #define Anum_pg_proc_pronargdefaults	18
! #define Anum_pg_proc_prorettype			19
! #define Anum_pg_proc_proargtypes		20
! #define Anum_pg_proc_proallargtypes		21
! #define Anum_pg_proc_proargmodes		22
! #define Anum_pg_proc_proargnames		23
! #define Anum_pg_proc_proargdefaults		24
! #define Anum_pg_proc_protrftypes		25
! #define Anum_pg_proc_prosrc				26
! #define Anum_pg_proc_probin				27
! #define Anum_pg_proc_proconfig			28
! #define Anum_pg_proc_proacl				29
  
  /* ----------------
   *		initial contents of pg_proc
--- 94,119 ----
  #define Anum_pg_proc_prorows			6
  #define Anum_pg_proc_provariadic		7
  #define Anum_pg_proc_protransform		8
! #define Anum_pg_proc_prokind			9
! #define Anum_pg_proc_prosecdef			10
! #define Anum_pg_proc_proleakproof		11
! #define Anum_pg_proc_proisstrict		12
! #define Anum_pg_proc_proretset			13
! #define Anum_pg_proc_provolatile		14
! #define Anum_pg_proc_proparallel		15
! #define Anum_pg_proc_pronargs			16
! #define Anum_pg_proc_pronargdefaults	17
! #define Anum_pg_proc_prorettype			18
! #define Anum_pg_proc_proargtypes		19
! #define Anum_pg_proc_proallargtypes		20
! #define Anum_pg_proc_proargmodes		21
! #define Anum_pg_proc_proargnames		22
! #define Anum_pg_proc_proargdefaults		23
! #define Anum_pg_proc_protrftypes		24
! #define Anum_pg_proc_prosrc				25
! #define Anum_pg_proc_probin				26
! #define Anum_pg_proc_proconfig			27
! #define Anum_pg_proc_proacl				28
  
  /* ----------------
   *		initial contents of pg_proc
*************** DATA(insert OID = 5028 ( satisfies_hash_
*** 5576,5581 ****
--- 5574,5587 ----
  DESCR("hash partition CHECK constraint");
  
  /*
+  * Symbolic values for prokind column
+  */
+ #define PROKIND_FUNCTION 'f'
+ #define PROKIND_AGGREGATE 'a'
+ #define PROKIND_WINDOW 'w'
+ #define PROKIND_PROCEDURE 'p'
+ 
+ /*
   * Symbolic values for provolatile column: these indicate whether the result
   * of a function is dependent *only* on the values of its explicit arguments,
   * or can change due to outside factors (such as parameter variables or
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 098e2e6..b66871b 100644
*** a/src/include/catalog/pg_proc_fn.h
--- b/src/include/catalog/pg_proc_fn.h
*************** extern ObjectAddress ProcedureCreate(con
*** 27,34 ****
  				Oid languageValidator,
  				const char *prosrc,
  				const char *probin,
! 				bool isAgg,
! 				bool isWindowFunc,
  				bool security_definer,
  				bool isLeakProof,
  				bool isStrict,
--- 27,33 ----
  				Oid languageValidator,
  				const char *prosrc,
  				const char *probin,
! 				char prokind,
  				bool security_definer,
  				bool isLeakProof,
  				bool isStrict,
diff --git a/src/include/utils/lsyscache.h b/src/include/utils/lsyscache.h
index 1f6c04a..e55ea40 100644
*** a/src/include/utils/lsyscache.h
--- b/src/include/utils/lsyscache.h
*************** extern bool get_func_retset(Oid funcid);
*** 117,123 ****
  extern bool func_strict(Oid funcid);
  extern char func_volatile(Oid funcid);
  extern char func_parallel(Oid funcid);
! extern bool get_func_isagg(Oid funcid);
  extern bool get_func_leakproof(Oid funcid);
  extern float4 get_func_cost(Oid funcid);
  extern float4 get_func_rows(Oid funcid);
--- 117,123 ----
  extern bool func_strict(Oid funcid);
  extern char func_volatile(Oid funcid);
  extern char func_parallel(Oid funcid);
! extern char get_func_prokind(Oid funcid);
  extern bool get_func_leakproof(Oid funcid);
  extern float4 get_func_cost(Oid funcid);
  extern float4 get_func_rows(Oid funcid);
diff --git a/src/pl/plperl/plperl.c b/src/pl/plperl/plperl.c
index 77c41b2..fa8e2fd 100644
*** a/src/pl/plperl/plperl.c
--- b/src/pl/plperl/plperl.c
*************** compile_plperl_function(Oid fn_oid, bool
*** 2832,2838 ****
  		 * Get the required information for input conversion of the
  		 * return value.
  		 ************************************************************/
! 		if (!is_trigger && !is_event_trigger && procStruct->prorettype)
  		{
  			Oid			rettype = procStruct->prorettype;
  
--- 2832,2839 ----
  		 * Get the required information for input conversion of the
  		 * return value.
  		 ************************************************************/
! 		if (!is_trigger && !is_event_trigger &&
! 			procStruct->prokind != PROKIND_PROCEDURE)
  		{
  			Oid			rettype = procStruct->prorettype;
  
diff --git a/src/pl/plpgsql/src/pl_comp.c b/src/pl/plpgsql/src/pl_comp.c
index d07a16a..6fbbc4a 100644
*** a/src/pl/plpgsql/src/pl_comp.c
--- b/src/pl/plpgsql/src/pl_comp.c
*************** do_compile(FunctionCallInfo fcinfo,
*** 275,280 ****
--- 275,281 ----
  	bool		isnull;
  	char	   *proc_source;
  	HeapTuple	typeTup;
+ 	Form_pg_type typeStruct;
  	PLpgSQL_variable *var;
  	PLpgSQL_rec *rec;
  	int			i;
*************** do_compile(FunctionCallInfo fcinfo,
*** 365,370 ****
--- 366,373 ----
  	else
  		function->fn_is_trigger = PLPGSQL_NOT_TRIGGER;
  
+ 	function->fn_prokind = procStruct->prokind;
+ 
  	/*
  	 * Initialize the compiler, particularly the namespace stack.  The
  	 * outermost namespace contains function parameters and other special
*************** do_compile(FunctionCallInfo fcinfo,
*** 529,538 ****
  			/*
  			 * Lookup the function's return type
  			 */
- 			if (rettypeid)
- 			{
- 				Form_pg_type typeStruct;
- 
  				typeTup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(rettypeid));
  				if (!HeapTupleIsValid(typeTup))
  					elog(ERROR, "cache lookup failed for type %u", rettypeid);
--- 532,537 ----
*************** do_compile(FunctionCallInfo fcinfo,
*** 577,583 ****
  				}
  
  				ReleaseSysCache(typeTup);
- 			}
  			break;
  
  		case PLPGSQL_DML_TRIGGER:
--- 576,581 ----
*************** plpgsql_compile_inline(char *proc_source
*** 890,895 ****
--- 888,894 ----
  	function->fn_retset = false;
  	function->fn_retistuple = false;
  	function->fn_retisdomain = false;
+ 	function->fn_prokind = PROKIND_FUNCTION;
  	/* a bit of hardwired knowledge about type VOID here */
  	function->fn_retbyval = true;
  	function->fn_rettyplen = sizeof(int32);
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index 4ff87e0..297aa3e 100644
*** a/src/pl/plpgsql/src/pl_exec.c
--- b/src/pl/plpgsql/src/pl_exec.c
*************** plpgsql_exec_function(PLpgSQL_function *
*** 573,579 ****
  	estate.err_text = NULL;
  	estate.err_stmt = (PLpgSQL_stmt *) (func->action);
  	rc = exec_stmt_block(&estate, func->action);
! 	if (rc != PLPGSQL_RC_RETURN && func->fn_rettype)
  	{
  		estate.err_stmt = NULL;
  		estate.err_text = NULL;
--- 573,579 ----
  	estate.err_text = NULL;
  	estate.err_stmt = (PLpgSQL_stmt *) (func->action);
  	rc = exec_stmt_block(&estate, func->action);
! 	if (rc != PLPGSQL_RC_RETURN)
  	{
  		estate.err_stmt = NULL;
  		estate.err_text = NULL;
*************** plpgsql_exec_function(PLpgSQL_function *
*** 617,625 ****
  	}
  	else if (!estate.retisnull)
  	{
! 		if (!func->fn_rettype)
  			ereport(ERROR,
! 					(errmsg("cannot return a value from a procedure")));
  
  		/*
  		 * Cast result value to function's declared result type, and copy it
--- 617,626 ----
  	}
  	else if (!estate.retisnull)
  	{
! 		if (func->fn_prokind == PROKIND_PROCEDURE)
  			ereport(ERROR,
! 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 					 errmsg("cannot return a value from a procedure")));
  
  		/*
  		 * Cast result value to function's declared result type, and copy it
*************** exec_stmt_return(PLpgSQL_execstate *esta
*** 2956,2964 ****
  	/*
  	 * Special hack for function returning VOID: instead of NULL, return a
  	 * non-null VOID value.  This is of dubious importance but is kept for
! 	 * backwards compatibility.
  	 */
! 	if (estate->fn_rettype == VOIDOID)
  	{
  		estate->retval = (Datum) 0;
  		estate->retisnull = false;
--- 2957,2966 ----
  	/*
  	 * Special hack for function returning VOID: instead of NULL, return a
  	 * non-null VOID value.  This is of dubious importance but is kept for
! 	 * backwards compatibility.  We don't do it for procedures, though.
  	 */
! 	if (estate->fn_rettype == VOIDOID &&
! 		estate->func->fn_prokind != PROKIND_PROCEDURE)
  	{
  		estate->retval = (Datum) 0;
  		estate->retisnull = false;
diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y
index 688fbd6..697ead0 100644
*** a/src/pl/plpgsql/src/pl_gram.y
--- b/src/pl/plpgsql/src/pl_gram.y
***************
*** 16,21 ****
--- 16,22 ----
  #include "postgres.h"
  
  #include "catalog/namespace.h"
+ #include "catalog/pg_proc.h"
  #include "catalog/pg_type.h"
  #include "parser/parser.h"
  #include "parser/parse_type.h"
*************** make_return_stmt(int location)
*** 3137,3143 ****
  					 parser_errposition(yylloc)));
  		new->retvarno = plpgsql_curr_compile->out_param_varno;
  	}
! 	else if (plpgsql_curr_compile->fn_rettype == VOIDOID)
  	{
  		if (yylex() != ';')
  			ereport(ERROR,
--- 3138,3145 ----
  					 parser_errposition(yylloc)));
  		new->retvarno = plpgsql_curr_compile->out_param_varno;
  	}
! 	else if (plpgsql_curr_compile->fn_rettype == VOIDOID &&
! 			 plpgsql_curr_compile->fn_prokind != PROKIND_PROCEDURE)
  	{
  		if (yylex() != ';')
  			ereport(ERROR,
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 26a7344..dd59036 100644
*** a/src/pl/plpgsql/src/plpgsql.h
--- b/src/pl/plpgsql/src/plpgsql.h
*************** typedef struct PLpgSQL_function
*** 918,923 ****
--- 918,924 ----
  	bool		fn_retisdomain;
  	bool		fn_retset;
  	bool		fn_readonly;
+ 	char		fn_prokind;
  
  	int			fn_nargs;
  	int			fn_argvarnos[FUNC_MAX_ARGS];
diff --git a/src/pl/plpython/plpy_procedure.c b/src/pl/plpython/plpy_procedure.c
index 4e06413..82cc3f2 100644
*** a/src/pl/plpython/plpy_procedure.c
--- b/src/pl/plpython/plpy_procedure.c
*************** PLy_procedure_create(HeapTuple procTup, 
*** 188,194 ****
  		proc->fn_tid = procTup->t_self;
  		proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
  		proc->is_setof = procStruct->proretset;
! 		proc->is_procedure = (procStruct->prorettype == InvalidOid);
  		proc->src = NULL;
  		proc->argnames = NULL;
  		proc->args = NULL;
--- 188,194 ----
  		proc->fn_tid = procTup->t_self;
  		proc->fn_readonly = (procStruct->provolatile != PROVOLATILE_VOLATILE);
  		proc->is_setof = procStruct->proretset;
! 		proc->is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
  		proc->src = NULL;
  		proc->argnames = NULL;
  		proc->args = NULL;
*************** PLy_procedure_create(HeapTuple procTup, 
*** 208,214 ****
  		 * get information required for output conversion of the return value,
  		 * but only if this isn't a trigger or procedure.
  		 */
! 		if (!is_trigger && procStruct->prorettype)
  		{
  			Oid			rettype = procStruct->prorettype;
  			HeapTuple	rvTypeTup;
--- 208,214 ----
  		 * get information required for output conversion of the return value,
  		 * but only if this isn't a trigger or procedure.
  		 */
! 		if (!is_trigger && procStruct->prokind != PROKIND_PROCEDURE)
  		{
  			Oid			rettype = procStruct->prorettype;
  			HeapTuple	rvTypeTup;
diff --git a/src/pl/tcl/pltcl.c b/src/pl/tcl/pltcl.c
index 5df4dfd..2eb6c33 100644
*** a/src/pl/tcl/pltcl.c
--- b/src/pl/tcl/pltcl.c
*************** compile_pltcl_function(Oid fn_oid, Oid t
*** 1523,1531 ****
  		 * Get the required information for input conversion of the
  		 * return value.
  		 ************************************************************/
! 		prodesc->fn_is_procedure = (procStruct->prorettype == InvalidOid);
  
! 		if (!is_trigger && !is_event_trigger && procStruct->prorettype)
  		{
  			Oid			rettype = procStruct->prorettype;
  
--- 1523,1531 ----
  		 * Get the required information for input conversion of the
  		 * return value.
  		 ************************************************************/
! 		prodesc->fn_is_procedure = (procStruct->prokind == PROKIND_PROCEDURE);
  
! 		if (!is_trigger && !is_event_trigger && !prodesc->fn_is_procedure)
  		{
  			Oid			rettype = procStruct->prorettype;
  
diff --git a/src/test/regress/expected/alter_generic.out b/src/test/regress/expected/alter_generic.out
index 44356de..3e40df1 100644
*** a/src/test/regress/expected/alter_generic.out
--- b/src/test/regress/expected/alter_generic.out
*************** ERROR:  must be owner of function alt_ag
*** 83,103 ****
  ALTER AGGREGATE alt_agg2(int) SET SCHEMA alt_nsp2;  -- failed (name conflict)
  ERROR:  function alt_agg2(integer) already exists in schema "alt_nsp2"
  RESET SESSION AUTHORIZATION;
! SELECT n.nspname, proname, prorettype::regtype, proisagg, a.rolname
    FROM pg_proc p, pg_namespace n, pg_authid a
    WHERE p.pronamespace = n.oid AND p.proowner = a.oid
      AND n.nspname IN ('alt_nsp1', 'alt_nsp2')
    ORDER BY nspname, proname;
!  nspname  |  proname  | prorettype | proisagg |       rolname       
! ----------+-----------+------------+----------+---------------------
!  alt_nsp1 | alt_agg2  | integer    | t        | regress_alter_user2
!  alt_nsp1 | alt_agg3  | integer    | t        | regress_alter_user1
!  alt_nsp1 | alt_agg4  | integer    | t        | regress_alter_user2
!  alt_nsp1 | alt_func2 | integer    | f        | regress_alter_user2
!  alt_nsp1 | alt_func3 | integer    | f        | regress_alter_user1
!  alt_nsp1 | alt_func4 | integer    | f        | regress_alter_user2
!  alt_nsp2 | alt_agg2  | integer    | t        | regress_alter_user3
!  alt_nsp2 | alt_func2 | integer    | f        | regress_alter_user3
  (8 rows)
  
  --
--- 83,103 ----
  ALTER AGGREGATE alt_agg2(int) SET SCHEMA alt_nsp2;  -- failed (name conflict)
  ERROR:  function alt_agg2(integer) already exists in schema "alt_nsp2"
  RESET SESSION AUTHORIZATION;
! SELECT n.nspname, proname, prorettype::regtype, prokind, a.rolname
    FROM pg_proc p, pg_namespace n, pg_authid a
    WHERE p.pronamespace = n.oid AND p.proowner = a.oid
      AND n.nspname IN ('alt_nsp1', 'alt_nsp2')
    ORDER BY nspname, proname;
!  nspname  |  proname  | prorettype | prokind |       rolname       
! ----------+-----------+------------+---------+---------------------
!  alt_nsp1 | alt_agg2  | integer    | a       | regress_alter_user2
!  alt_nsp1 | alt_agg3  | integer    | a       | regress_alter_user1
!  alt_nsp1 | alt_agg4  | integer    | a       | regress_alter_user2
!  alt_nsp1 | alt_func2 | integer    | f       | regress_alter_user2
!  alt_nsp1 | alt_func3 | integer    | f       | regress_alter_user1
!  alt_nsp1 | alt_func4 | integer    | f       | regress_alter_user2
!  alt_nsp2 | alt_agg2  | integer    | a       | regress_alter_user3
!  alt_nsp2 | alt_func2 | integer    | f       | regress_alter_user3
  (8 rows)
  
  --
diff --git a/src/test/regress/expected/create_function_3.out b/src/test/regress/expected/create_function_3.out
index 5ff1e0d..3cdd92c 100644
*** a/src/test/regress/expected/create_function_3.out
--- b/src/test/regress/expected/create_function_3.out
*************** ERROR:  could not find a function named 
*** 271,276 ****
--- 271,285 ----
  DROP FUNCTION functest_b_2;  -- error, ambiguous
  ERROR:  function name "functest_b_2" is not unique
  HINT:  Specify the argument list to select the function unambiguously.
+ -- CREATE OR REPLACE tests
+ CREATE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL AS 'SELECT $1';
+ CREATE OR REPLACE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL WINDOW AS 'SELECT $1';
+ ERROR:  cannot change routine type
+ DETAIL:  "functest1" is a function.
+ CREATE OR REPLACE PROCEDURE functest1(a int) LANGUAGE SQL AS 'SELECT $1';
+ ERROR:  cannot change routine type
+ DETAIL:  "functest1" is a function.
+ DROP FUNCTION functest1(a int);
  -- Cleanups
  DROP SCHEMA temp_func_test CASCADE;
  NOTICE:  drop cascades to 16 other objects
diff --git a/src/test/regress/expected/opr_sanity.out b/src/test/regress/expected/opr_sanity.out
index 6616cc1..01608d2 100644
*** a/src/test/regress/expected/opr_sanity.out
--- b/src/test/regress/expected/opr_sanity.out
*************** WHERE p1.prolang = 0 OR p1.prorettype = 
*** 74,79 ****
--- 74,80 ----
         0::oid = ANY (p1.proargtypes) OR
         procost <= 0 OR
         CASE WHEN proretset THEN prorows <= 0 ELSE prorows != 0 END OR
+        prokind NOT IN ('f', 'a', 'w', 'p') OR
         provolatile NOT IN ('i', 's', 'v') OR
         proparallel NOT IN ('s', 'r', 'u');
   oid | proname 
*************** WHERE prosrc IS NULL OR prosrc = '' OR p
*** 88,97 ****
  -----+---------
  (0 rows)
  
! -- proiswindow shouldn't be set together with proisagg or proretset
  SELECT p1.oid, p1.proname
  FROM pg_proc AS p1
! WHERE proiswindow AND (proisagg OR proretset);
   oid | proname 
  -----+---------
  (0 rows)
--- 89,98 ----
  -----+---------
  (0 rows)
  
! -- proretset should only be set for normal functions
  SELECT p1.oid, p1.proname
  FROM pg_proc AS p1
! WHERE proretset AND prokind != 'f';
   oid | proname 
  -----+---------
  (0 rows)
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 154,162 ****
  WHERE p1.oid < p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     (p1.proisagg = false OR p2.proisagg = false) AND
      (p1.prolang != p2.prolang OR
!      p1.proisagg != p2.proisagg OR
       p1.prosecdef != p2.prosecdef OR
       p1.proleakproof != p2.proleakproof OR
       p1.proisstrict != p2.proisstrict OR
--- 155,163 ----
  WHERE p1.oid < p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     (p1.prokind != 'a' OR p2.prokind != 'a') AND
      (p1.prolang != p2.prolang OR
!      p1.prokind != p2.prokind OR
       p1.prosecdef != p2.prosecdef OR
       p1.proleakproof != p2.proleakproof OR
       p1.proisstrict != p2.proisstrict OR
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 182,188 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.prorettype < p2.prorettype)
--- 183,189 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.prorettype < p2.prorettype)
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 198,204 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.proargtypes[0] < p2.proargtypes[0])
--- 199,205 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.proargtypes[0] < p2.proargtypes[0])
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 216,222 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.proargtypes[1] < p2.proargtypes[1])
--- 217,223 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.proargtypes[1] < p2.proargtypes[1])
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 233,239 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[2] < p2.proargtypes[2])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
--- 234,240 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[2] < p2.proargtypes[2])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 246,252 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[3] < p2.proargtypes[3])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
--- 247,253 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[3] < p2.proargtypes[3])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 259,265 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[4] < p2.proargtypes[4])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
--- 260,266 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[4] < p2.proargtypes[4])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 271,277 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[5] < p2.proargtypes[5])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
--- 272,278 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[5] < p2.proargtypes[5])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 283,289 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[6] < p2.proargtypes[6])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
--- 284,290 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[6] < p2.proargtypes[6])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 295,301 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[7] < p2.proargtypes[7])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
--- 296,302 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[7] < p2.proargtypes[7])
  ORDER BY 1, 2;
   proargtypes | proargtypes 
*************** WHERE aggfnoid = 0 OR aggtransfn = 0 OR
*** 1292,1306 ****
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (NOT p.proisagg OR p.proretset OR p.pronargs < a.aggnumdirectargs);
   aggfnoid | proname 
  ----------+---------
  (0 rows)
  
! -- Make sure there are no proisagg pg_proc entries without matches.
  SELECT oid, proname
  FROM pg_proc as p
! WHERE p.proisagg AND
      NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid);
   oid | proname 
  -----+---------
--- 1293,1307 ----
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (p.prokind != 'a' OR p.proretset OR p.pronargs < a.aggnumdirectargs);
   aggfnoid | proname 
  ----------+---------
  (0 rows)
  
! -- Make sure there are no prokind = PROKIND_AGGREGATE pg_proc entries without matches.
  SELECT oid, proname
  FROM pg_proc as p
! WHERE p.prokind = 'a' AND
      NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid);
   oid | proname 
  -----+---------
*************** ORDER BY 1, 2;
*** 1639,1645 ****
  SELECT p1.oid::regprocedure, p2.oid::regprocedure
  FROM pg_proc AS p1, pg_proc AS p2
  WHERE p1.oid < p2.oid AND p1.proname = p2.proname AND
!     p1.proisagg AND p2.proisagg AND
      array_dims(p1.proargtypes) != array_dims(p2.proargtypes)
  ORDER BY 1;
       oid      |   oid   
--- 1640,1646 ----
  SELECT p1.oid::regprocedure, p2.oid::regprocedure
  FROM pg_proc AS p1, pg_proc AS p2
  WHERE p1.oid < p2.oid AND p1.proname = p2.proname AND
!     p1.prokind = 'a' AND p2.prokind = 'a' AND
      array_dims(p1.proargtypes) != array_dims(p2.proargtypes)
  ORDER BY 1;
       oid      |   oid   
*************** ORDER BY 1;
*** 1650,1656 ****
  -- For the same reason, built-in aggregates with default arguments are no good.
  SELECT oid, proname
  FROM pg_proc AS p
! WHERE proisagg AND proargdefaults IS NOT NULL;
   oid | proname 
  -----+---------
  (0 rows)
--- 1651,1657 ----
  -- For the same reason, built-in aggregates with default arguments are no good.
  SELECT oid, proname
  FROM pg_proc AS p
! WHERE prokind = 'a' AND proargdefaults IS NOT NULL;
   oid | proname 
  -----+---------
  (0 rows)
*************** WHERE proisagg AND proargdefaults IS NOT
*** 1660,1666 ****
  -- that is not subject to the misplaced ORDER BY issue).
  SELECT p.oid, proname
  FROM pg_proc AS p JOIN pg_aggregate AS a ON a.aggfnoid = p.oid
! WHERE proisagg AND provariadic != 0 AND a.aggkind = 'n';
   oid | proname 
  -----+---------
  (0 rows)
--- 1661,1667 ----
  -- that is not subject to the misplaced ORDER BY issue).
  SELECT p.oid, proname
  FROM pg_proc AS p JOIN pg_aggregate AS a ON a.aggfnoid = p.oid
! WHERE prokind = 'a' AND provariadic != 0 AND a.aggkind = 'n';
   oid | proname 
  -----+---------
  (0 rows)
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 5acb92f..d7eff6c 100644
*** a/src/test/regress/expected/rules.out
--- b/src/test/regress/expected/rules.out
*************** UNION ALL
*** 1521,1529 ****
   SELECT l.objoid,
      l.classoid,
      l.objsubid,
!         CASE
!             WHEN (pro.proisagg = true) THEN 'aggregate'::text
!             WHEN (pro.proisagg = false) THEN 'function'::text
              ELSE NULL::text
          END AS objtype,
      pro.pronamespace AS objnamespace,
--- 1521,1531 ----
   SELECT l.objoid,
      l.classoid,
      l.objsubid,
!         CASE pro.prokind
!             WHEN 'a'::"char" THEN 'aggregate'::text
!             WHEN 'f'::"char" THEN 'function'::text
!             WHEN 'p'::"char" THEN 'procedure'::text
!             WHEN 'w'::"char" THEN 'window'::text
              ELSE NULL::text
          END AS objtype,
      pro.pronamespace AS objnamespace,
diff --git a/src/test/regress/sql/alter_generic.sql b/src/test/regress/sql/alter_generic.sql
index 96be6e7..fd43f23 100644
*** a/src/test/regress/sql/alter_generic.sql
--- b/src/test/regress/sql/alter_generic.sql
*************** ALTER AGGREGATE alt_agg2(int) SET SCHEMA
*** 81,87 ****
  
  RESET SESSION AUTHORIZATION;
  
! SELECT n.nspname, proname, prorettype::regtype, proisagg, a.rolname
    FROM pg_proc p, pg_namespace n, pg_authid a
    WHERE p.pronamespace = n.oid AND p.proowner = a.oid
      AND n.nspname IN ('alt_nsp1', 'alt_nsp2')
--- 81,87 ----
  
  RESET SESSION AUTHORIZATION;
  
! SELECT n.nspname, proname, prorettype::regtype, prokind, a.rolname
    FROM pg_proc p, pg_namespace n, pg_authid a
    WHERE p.pronamespace = n.oid AND p.proowner = a.oid
      AND n.nspname IN ('alt_nsp1', 'alt_nsp2')
diff --git a/src/test/regress/sql/create_function_3.sql b/src/test/regress/sql/create_function_3.sql
index fbdf831..8f209d5 100644
*** a/src/test/regress/sql/create_function_3.sql
--- b/src/test/regress/sql/create_function_3.sql
*************** DROP FUNCTION functest_b_1;  -- error, n
*** 175,180 ****
--- 175,188 ----
  DROP FUNCTION functest_b_2;  -- error, ambiguous
  
  
+ -- CREATE OR REPLACE tests
+ 
+ CREATE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL AS 'SELECT $1';
+ CREATE OR REPLACE FUNCTION functest1(a int) RETURNS int LANGUAGE SQL WINDOW AS 'SELECT $1';
+ CREATE OR REPLACE PROCEDURE functest1(a int) LANGUAGE SQL AS 'SELECT $1';
+ DROP FUNCTION functest1(a int);
+ 
+ 
  -- Cleanups
  DROP SCHEMA temp_func_test CASCADE;
  DROP USER regress_unpriv_user;
diff --git a/src/test/regress/sql/opr_sanity.sql b/src/test/regress/sql/opr_sanity.sql
index e8fdf84..a593d37 100644
*** a/src/test/regress/sql/opr_sanity.sql
--- b/src/test/regress/sql/opr_sanity.sql
*************** WHERE p1.prolang = 0 OR p1.prorettype = 
*** 82,87 ****
--- 82,88 ----
         0::oid = ANY (p1.proargtypes) OR
         procost <= 0 OR
         CASE WHEN proretset THEN prorows <= 0 ELSE prorows != 0 END OR
+        prokind NOT IN ('f', 'a', 'w', 'p') OR
         provolatile NOT IN ('i', 's', 'v') OR
         proparallel NOT IN ('s', 'r', 'u');
  
*************** SELECT p1.oid, p1.proname
*** 90,99 ****
  FROM pg_proc as p1
  WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-';
  
! -- proiswindow shouldn't be set together with proisagg or proretset
  SELECT p1.oid, p1.proname
  FROM pg_proc AS p1
! WHERE proiswindow AND (proisagg OR proretset);
  
  -- currently, no built-in functions should be SECURITY DEFINER;
  -- this might change in future, but there will probably never be many.
--- 91,100 ----
  FROM pg_proc as p1
  WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-';
  
! -- proretset should only be set for normal functions
  SELECT p1.oid, p1.proname
  FROM pg_proc AS p1
! WHERE proretset AND prokind != 'f';
  
  -- currently, no built-in functions should be SECURITY DEFINER;
  -- this might change in future, but there will probably never be many.
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 140,148 ****
  WHERE p1.oid < p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     (p1.proisagg = false OR p2.proisagg = false) AND
      (p1.prolang != p2.prolang OR
!      p1.proisagg != p2.proisagg OR
       p1.prosecdef != p2.prosecdef OR
       p1.proleakproof != p2.proleakproof OR
       p1.proisstrict != p2.proisstrict OR
--- 141,149 ----
  WHERE p1.oid < p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     (p1.prokind != 'a' OR p2.prokind != 'a') AND
      (p1.prolang != p2.prolang OR
!      p1.prokind != p2.prokind OR
       p1.prosecdef != p2.prosecdef OR
       p1.proleakproof != p2.proleakproof OR
       p1.proisstrict != p2.proisstrict OR
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 166,172 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.prorettype < p2.prorettype)
--- 167,173 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.prorettype < p2.prorettype)
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 177,183 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.proargtypes[0] < p2.proargtypes[0])
--- 178,184 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.proargtypes[0] < p2.proargtypes[0])
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 188,194 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.proargtypes[1] < p2.proargtypes[1])
--- 189,195 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      p1.prosrc NOT LIKE E'range\\_constructor_' AND
      p2.prosrc NOT LIKE E'range\\_constructor_' AND
      (p1.proargtypes[1] < p2.proargtypes[1])
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 199,205 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[2] < p2.proargtypes[2])
  ORDER BY 1, 2;
  
--- 200,206 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[2] < p2.proargtypes[2])
  ORDER BY 1, 2;
  
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 208,214 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[3] < p2.proargtypes[3])
  ORDER BY 1, 2;
  
--- 209,215 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[3] < p2.proargtypes[3])
  ORDER BY 1, 2;
  
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 217,223 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[4] < p2.proargtypes[4])
  ORDER BY 1, 2;
  
--- 218,224 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[4] < p2.proargtypes[4])
  ORDER BY 1, 2;
  
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 226,232 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[5] < p2.proargtypes[5])
  ORDER BY 1, 2;
  
--- 227,233 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[5] < p2.proargtypes[5])
  ORDER BY 1, 2;
  
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 235,241 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[6] < p2.proargtypes[6])
  ORDER BY 1, 2;
  
--- 236,242 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[6] < p2.proargtypes[6])
  ORDER BY 1, 2;
  
*************** FROM pg_proc AS p1, pg_proc AS p2
*** 244,250 ****
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     NOT p1.proisagg AND NOT p2.proisagg AND
      (p1.proargtypes[7] < p2.proargtypes[7])
  ORDER BY 1, 2;
  
--- 245,251 ----
  WHERE p1.oid != p2.oid AND
      p1.prosrc = p2.prosrc AND
      p1.prolang = 12 AND p2.prolang = 12 AND
!     p1.prokind != 'a' AND p2.prokind != 'a' AND
      (p1.proargtypes[7] < p2.proargtypes[7])
  ORDER BY 1, 2;
  
*************** WHERE aggfnoid = 0 OR aggtransfn = 0 OR
*** 804,816 ****
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (NOT p.proisagg OR p.proretset OR p.pronargs < a.aggnumdirectargs);
  
! -- Make sure there are no proisagg pg_proc entries without matches.
  
  SELECT oid, proname
  FROM pg_proc as p
! WHERE p.proisagg AND
      NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid);
  
  -- If there is no finalfn then the output type must be the transtype.
--- 805,817 ----
  SELECT a.aggfnoid::oid, p.proname
  FROM pg_aggregate as a, pg_proc as p
  WHERE a.aggfnoid = p.oid AND
!     (p.prokind != 'a' OR p.proretset OR p.pronargs < a.aggnumdirectargs);
  
! -- Make sure there are no prokind = PROKIND_AGGREGATE pg_proc entries without matches.
  
  SELECT oid, proname
  FROM pg_proc as p
! WHERE p.prokind = 'a' AND
      NOT EXISTS (SELECT 1 FROM pg_aggregate a WHERE a.aggfnoid = p.oid);
  
  -- If there is no finalfn then the output type must be the transtype.
*************** ORDER BY 1, 2;
*** 1089,1095 ****
  SELECT p1.oid::regprocedure, p2.oid::regprocedure
  FROM pg_proc AS p1, pg_proc AS p2
  WHERE p1.oid < p2.oid AND p1.proname = p2.proname AND
!     p1.proisagg AND p2.proisagg AND
      array_dims(p1.proargtypes) != array_dims(p2.proargtypes)
  ORDER BY 1;
  
--- 1090,1096 ----
  SELECT p1.oid::regprocedure, p2.oid::regprocedure
  FROM pg_proc AS p1, pg_proc AS p2
  WHERE p1.oid < p2.oid AND p1.proname = p2.proname AND
!     p1.prokind = 'a' AND p2.prokind = 'a' AND
      array_dims(p1.proargtypes) != array_dims(p2.proargtypes)
  ORDER BY 1;
  
*************** ORDER BY 1;
*** 1097,1103 ****
  
  SELECT oid, proname
  FROM pg_proc AS p
! WHERE proisagg AND proargdefaults IS NOT NULL;
  
  -- For the same reason, we avoid creating built-in variadic aggregates, except
  -- that variadic ordered-set aggregates are OK (since they have special syntax
--- 1098,1104 ----
  
  SELECT oid, proname
  FROM pg_proc AS p
! WHERE prokind = 'a' AND proargdefaults IS NOT NULL;
  
  -- For the same reason, we avoid creating built-in variadic aggregates, except
  -- that variadic ordered-set aggregates are OK (since they have special syntax
*************** WHERE proisagg AND proargdefaults IS NOT
*** 1105,1111 ****
  
  SELECT p.oid, proname
  FROM pg_proc AS p JOIN pg_aggregate AS a ON a.aggfnoid = p.oid
! WHERE proisagg AND provariadic != 0 AND a.aggkind = 'n';
  
  
  -- **************** pg_opfamily ****************
--- 1106,1112 ----
  
  SELECT p.oid, proname
  FROM pg_proc AS p JOIN pg_aggregate AS a ON a.aggfnoid = p.oid
! WHERE prokind = 'a' AND provariadic != 0 AND a.aggkind = 'n';
  
  
  -- **************** pg_opfamily ****************
