diff --git a/contrib/sepgsql/expected/create.out b/contrib/sepgsql/expected/create.out
index d450dc5..68d7e61 100644
--- a/contrib/sepgsql/expected/create.out
+++ b/contrib/sepgsql/expected/create.out
@@ -39,13 +39,25 @@ LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfine
 LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_seq_t:s0 tclass=db_sequence name="sequence regtest_seq"
 CREATE TYPE regtest_type AS (a int, b text);
 LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+CREATE FUNCTION regtest_func (text) RETURNS bool LANGUAGE plpgsql
+    AS 'BEGIN RAISE NOTICE ''hello => %'', $1; RETURN true; END';
+LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function regtest_func(text)"
+CREATE AGGREGATE regtest_agg (
+    sfunc1 = int4pl, basetype = int4, stype1 = int4,
+    initcond1 = '0'
+);
+LOG:  SELinux: allowed { add_name } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_schema_t:s0 tclass=db_schema name="schema regtest_schema"
+LOG:  SELinux: allowed { create } scontext=unconfined_u:unconfined_r:unconfined_t:s0 tcontext=unconfined_u:object_r:sepgsql_proc_exec_t:s0 tclass=db_procedure name="function regtest_agg(integer)"
 --
 -- clean-up 
 --
 DROP DATABASE IF EXISTS regtest_sepgsql_test_database;
 DROP SCHEMA IF EXISTS regtest_schema CASCADE;
-NOTICE:  drop cascades to 4 other objects
+NOTICE:  drop cascades to 6 other objects
 DETAIL:  drop cascades to table regtest_table
 drop cascades to view regtest_view
 drop cascades to sequence regtest_seq
 drop cascades to type regtest_type
+drop cascades to function regtest_func(text)
+drop cascades to function regtest_agg(integer)
diff --git a/contrib/sepgsql/hooks.c b/contrib/sepgsql/hooks.c
index aa56d9c..1eeec1e 100644
--- a/contrib/sepgsql/hooks.c
+++ b/contrib/sepgsql/hooks.c
@@ -155,6 +155,15 @@ sepgsql_object_prep_create(Oid classId, Oid objectId, int subId,
 										 args->pg_class.tupdesc);
 			break;
 
+		case ProcedureRelationId:
+			cinfo->ncontext =
+				sepgsql_proc_prep_create(args->pg_proc.proname,
+										 args->pg_proc.proargs,
+										 args->pg_proc.namespaceId,
+										 args->pg_proc.languageId,
+										 args->pg_proc.leakproof);
+			break;
+
 		default:
 			/* Ignore unsupported object classes */
 			break;
@@ -196,7 +205,8 @@ sepgsql_object_post_create(Oid classId, Oid objectId, int subId,
 			break;
 
 		case ProcedureRelationId:
-			sepgsql_proc_post_create(objectId);
+			sepgsql_proc_post_create(objectId,
+									 !cinfo ? NULL : cinfo->ncontext);
 			break;
 
 		default:
diff --git a/contrib/sepgsql/proc.c b/contrib/sepgsql/proc.c
index 9630d45..c0e2c0e 100644
--- a/contrib/sepgsql/proc.c
+++ b/contrib/sepgsql/proc.c
@@ -18,6 +18,7 @@
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_proc.h"
 #include "commands/seclabel.h"
+#include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
 #include "utils/tqual.h"
@@ -25,55 +26,131 @@
 #include "sepgsql.h"
 
 /*
- * sepgsql_proc_post_create
+ * sepgsql_proc_prep_create
+ *
+ *
  *
- * This routine assigns a default security label on a newly defined
- * procedure.
  */
-void
-sepgsql_proc_post_create(Oid functionId)
+const char *
+sepgsql_proc_prep_create(const char *proname,
+						 oidvector *proargs,
+						 Oid namespaceId,
+						 Oid languageId,
+						 bool leakproof)
 {
-	Relation	rel;
-	ScanKeyData skey;
-	SysScanDesc sscan;
-	HeapTuple	tuple;
-	Oid			namespaceId;
-	ObjectAddress object;
 	char	   *scontext;
 	char	   *tcontext;
 	char	   *ncontext;
+	uint32		required;
+	StringInfoData	audit_name;
+	ObjectAddress	object;
+	int			i;
 
 	/*
-	 * Fetch namespace of the new procedure. Because pg_proc entry is not
-	 * visible right now, we need to scan the catalog using SnapshotSelf.
+	 * check db_schema:{add_name} permission
 	 */
-	rel = heap_open(ProcedureRelationId, AccessShareLock);
+	object.classId = NamespaceRelationId;
+	object.objectId = namespaceId;
+	object.objectSubId = 0;
+	sepgsql_avc_check_perms(&object,
+							SEPG_CLASS_DB_SCHEMA,
+							SEPG_DB_SCHEMA__ADD_NAME,
+							getObjectDescription(&object),
+							true);
 
-	ScanKeyInit(&skey,
-				ObjectIdAttributeNumber,
-				BTEqualStrategyNumber, F_OIDEQ,
-				ObjectIdGetDatum(functionId));
+	/*
+	 * compute default security label of new function
+	 */
+	scontext = sepgsql_get_client_label();
+	tcontext = sepgsql_get_label(NamespaceRelationId, namespaceId, 0);
+	ncontext = sepgsql_compute_create(scontext, tcontext,
+									  SEPG_CLASS_DB_PROCEDURE);
 
-	sscan = systable_beginscan(rel, ProcedureOidIndexId, true,
-							   SnapshotSelf, 1, &skey);
+	/*
+	 * check db_procedure:{create (install)} permission
+	 */
+	required = SEPG_DB_PROCEDURE__CREATE;
+	if (leakproof)
+		required |= SEPG_DB_PROCEDURE__INSTALL;
 
-	tuple = systable_getnext(sscan);
-	if (!HeapTupleIsValid(tuple))
-		elog(ERROR, "catalog lookup failed for proc %u", functionId);
+	/*
+	 * XXX - format_procedure() is not available at this point,
+	 * so we need to construct human readable function names by hand.
+	 */
+	initStringInfo(&audit_name);
+	appendStringInfo(&audit_name, _("function %s("),
+					 quote_identifier(proname));
+	for (i = 0; i < proargs->dim1; i++)
+	{
+		if (i > 0)
+			appendStringInfoChar(&audit_name, ',');
+		appendStringInfoString(&audit_name,
+							   format_type_be(proargs->values[i]));
+	}
+	appendStringInfoChar(&audit_name, ')');
+
+	sepgsql_avc_check_perms_label(ncontext,
+								  SEPG_CLASS_DB_PROCEDURE,
+								  required,
+								  audit_name.data,
+								  true);
 
-	namespaceId = ((Form_pg_proc) GETSTRUCT(tuple))->pronamespace;
+	/*
+	 * XXX - db_language:{implement} also shoule be checked here.
+	 */
+	return ncontext;
+}
 
-	systable_endscan(sscan);
-	heap_close(rel, AccessShareLock);
+/*
+ * sepgsql_proc_post_create
+ *
+ * This routine assigns a default security label on a newly defined
+ * procedure.
+ */
+void
+sepgsql_proc_post_create(Oid functionId, const char *ncontext)
+{
+	ObjectAddress	object;
 
 	/*
-	 * Compute a default security label when we create a new procedure object
-	 * under the specified namespace.
+	 * In the case when system internal functions are constructed,
+	 * prep-creation hook is not invoked, security label to be
+	 * assigned on is not also computed yet. Thus, we try to obtain 
+	 * the default security label based on the properties of system
+	 * catalogs.
 	 */
-	scontext = sepgsql_get_client_label();
-	tcontext = sepgsql_get_label(NamespaceRelationId, namespaceId, 0);
-	ncontext = sepgsql_compute_create(scontext, tcontext,
-									  SEPG_CLASS_DB_PROCEDURE);
+	if (!ncontext)
+	{
+		Relation	rel;
+		ScanKeyData skey;
+		SysScanDesc sscan;
+		HeapTuple	tuple;
+		Form_pg_proc	procForm;
+
+		rel = heap_open(ProcedureRelationId, AccessShareLock);
+
+		ScanKeyInit(&skey,
+					ObjectIdAttributeNumber,
+					BTEqualStrategyNumber, F_OIDEQ,
+					ObjectIdGetDatum(functionId));
+
+		sscan = systable_beginscan(rel, ProcedureOidIndexId, true,
+								   SnapshotSelf, 1, &skey);
+
+		tuple = systable_getnext(sscan);
+		if (!HeapTupleIsValid(tuple))
+			elog(ERROR, "catalog lookup failed for proc %u", functionId);
+
+		procForm = (Form_pg_proc) GETSTRUCT(tuple);
+
+		ncontext = sepgsql_proc_prep_create(NameStr(procForm->proname),
+											&procForm->proargtypes,
+											procForm->pronamespace,
+											procForm->prolang,
+											false);
+		systable_endscan(sscan);
+		heap_close(rel, AccessShareLock);
+	}
 
 	/*
 	 * Assign the default security label on a new procedure
@@ -82,9 +159,6 @@ sepgsql_proc_post_create(Oid functionId)
 	object.objectId = functionId;
 	object.objectSubId = 0;
 	SetSecurityLabel(&object, SEPGSQL_LABEL_TAG, ncontext);
-
-	pfree(tcontext);
-	pfree(ncontext);
 }
 
 /*
diff --git a/contrib/sepgsql/sepgsql.h b/contrib/sepgsql/sepgsql.h
index cd9c4c6..56d2056 100644
--- a/contrib/sepgsql/sepgsql.h
+++ b/contrib/sepgsql/sepgsql.h
@@ -338,7 +338,12 @@ extern void sepgsql_relation_relabel(Oid relOid, const char *seclabel);
 /*
  * proc.c
  */
-extern void sepgsql_proc_post_create(Oid functionId);
+extern const char *sepgsql_proc_prep_create(const char *proname,
+											oidvector *proargs,
+											Oid namespaceId,
+											Oid languageId,
+											bool leakproof);
+extern void sepgsql_proc_post_create(Oid functionId, const char *ncontext);
 extern void sepgsql_proc_relabel(Oid functionId, const char *seclabel);
 
 #endif   /* SEPGSQL_H */
diff --git a/contrib/sepgsql/sql/create.sql b/contrib/sepgsql/sql/create.sql
index 4e12411..bc4a664 100644
--- a/contrib/sepgsql/sql/create.sql
+++ b/contrib/sepgsql/sql/create.sql
@@ -21,6 +21,14 @@ CREATE SEQUENCE regtest_seq;
 
 CREATE TYPE regtest_type AS (a int, b text);
 
+CREATE FUNCTION regtest_func (text) RETURNS bool LANGUAGE plpgsql
+    AS 'BEGIN RAISE NOTICE ''hello => %'', $1; RETURN true; END';
+
+CREATE AGGREGATE regtest_agg (
+    sfunc1 = int4pl, basetype = int4, stype1 = int4,
+    initcond1 = '0'
+);
+
 --
 -- clean-up 
 --
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 86e8c6b..0cd0ca3 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -50,7 +50,8 @@ AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval)
+				const char *agginitval,
+				Datum hook_private)
 {
 	Relation	aggdesc;
 	HeapTuple	tup;
@@ -229,7 +230,8 @@ AggregateCreate(const char *aggName,
 							  NIL,		/* parameterDefaults */
 							  PointerGetDatum(NULL),	/* proconfig */
 							  1,	/* procost */
-							  0);		/* prorows */
+							  0,	/* prorows */
+							  hook_private);	/* hook_private */
 
 	/*
 	 * Okay to create the pg_aggregate entry.
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 8378c36..7fb5ef2 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -85,7 +85,8 @@ ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows)
+				float4 prorows,
+				Datum hook_private)
 {
 	Oid			retval;
 	int			parameterCount;
@@ -646,7 +647,9 @@ ProcedureCreate(const char *procedureName,
 	heap_freetuple(tup);
 
 	/* Post creation hook for new function */
-	InvokeObjectAccessHook(OAT_POST_CREATE, ProcedureRelationId, retval, 0);
+	InvokeObjectAccessHookArg(OAT_POST_CREATE,
+							  ProcedureRelationId, retval, 0,
+							  hook_private);
 
 	heap_close(rel, RowExclusiveLock);
 
diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index a2122c1..f02a467 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -25,7 +25,9 @@
 #include "access/heapam.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
+#include "catalog/objectaccess.h"
 #include "catalog/pg_aggregate.h"
+#include "catalog/pg_language.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
 #include "commands/defrem.h"
@@ -60,6 +62,7 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 	Oid		   *aggArgTypes;
 	int			numArgs;
 	Oid			transTypeId;
+	Datum		hook_private = 0;
 	ListCell   *pl;
 
 	/* Convert list of names to a name and namespace */
@@ -192,6 +195,11 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 							format_type_be(transTypeId))));
 	}
 
+	/* Prep-creation hook for new aggregate functions */
+	InvokePrepCreateProcedureHook(&hook_private, aggName,
+								  buildoidvector(aggArgTypes, numArgs),
+								  aggNamespace, INTERNALlanguageId, false);
+
 	/*
 	 * Most of the argument-checking is done inside of AggregateCreate
 	 */
@@ -203,7 +211,8 @@ DefineAggregate(List *name, List *args, bool oldstyle, List *parameters)
 					finalfuncName,		/* final function name */
 					sortoperatorName,	/* sort operator name */
 					transTypeId,	/* transition data type */
-					initval);	/* initial condition */
+					initval,	/* initial condition */
+					hook_private);
 }
 
 
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 92abd44..33c65be 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -801,6 +801,7 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 	HeapTuple	languageTuple;
 	Form_pg_language languageStruct;
 	List	   *as_clause;
+	Datum		hook_private = 0;
 
 	/* Convert list of names to a name and namespace */
 	namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
@@ -935,6 +936,10 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 				 errmsg("ROWS is not applicable when function does not return a set")));
 
+	/* Prep-creation hook for new function */
+	InvokePrepCreateProcedureHook(&hook_private, funcname, parameterTypes,
+								  namespaceId, languageOid, false);
+
 	/*
 	 * And now that we have all the parameters, and know we're permitted to do
 	 * so, go ahead and create the function.
@@ -960,7 +965,8 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
 					parameterDefaults,
 					PointerGetDatum(proconfig),
 					procost,
-					prorows);
+					prorows,
+					hook_private);
 }
 
 
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 98770c5..1392dca 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -146,7 +146,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 (Datum) 0);
 		}
 
 		/*
@@ -181,7 +182,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 											NIL,
 											PointerGetDatum(NULL),
 											1,
-											0);
+											0,
+											(Datum) 0);
 			}
 		}
 		else
@@ -219,7 +221,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 										 NIL,
 										 PointerGetDatum(NULL),
 										 1,
-										 0);
+										 0,
+										 (Datum) 0);
 			}
 		}
 		else
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index a1628bc..1354215 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -1472,7 +1472,8 @@ makeRangeConstructor(char *name, Oid namespace, Oid rangeOid, Oid subtype)
 								  NIL,	/* parameterDefaults */
 								  PointerGetDatum(NULL),		/* proconfig */
 								  1.0,	/* procost */
-								  0.0); /* prorows */
+								  0.0, /* prorows */
+								  (Datum) 0);	/* hook_private */
 
 		/*
 		 * Make the constructor internally-dependent on the range type so that
diff --git a/src/include/catalog/objectaccess.h b/src/include/catalog/objectaccess.h
index d151ee5..db57e03 100644
--- a/src/include/catalog/objectaccess.h
+++ b/src/include/catalog/objectaccess.h
@@ -65,6 +65,14 @@ typedef union
 		Oid			tablespaceId;
 		TupleDesc	tupdesc;
 	} pg_class;
+	struct {
+		Datum	   *private;
+		const char *proname;
+		oidvector  *proargs;
+		Oid			namespaceId;
+		Oid			languageId;
+		bool		leakproof;
+	} pg_proc;
 } ObjectAccessCreateObjectArgs;
 
 /*
@@ -151,4 +159,24 @@ extern PGDLLIMPORT object_access_hook_type object_access_hook;
 		}																\
 	} while(0)
 
+#define InvokePrepCreateProcedureHook(_private,_proname,_proargs,		\
+									  _namespace,_language,_leakproof)	\
+	do {																\
+		if (object_access_hook)											\
+		{																\
+			ObjectAccessCreateObjectArgs	__args;						\
+																		\
+			__args.pg_proc.private = (_private);						\
+			__args.pg_proc.proname = (_proname);						\
+			__args.pg_proc.proargs = (_proargs);						\
+			__args.pg_proc.namespaceId = (_namespace);					\
+			__args.pg_proc.languageId = (_language);					\
+			__args.pg_proc.leakproof = (_leakproof);					\
+																		\
+			(*object_access_hook)(OAT_PREP_CREATE,						\
+								  ProcedureRelationId, InvalidOid, 0,	\
+								  PointerGetDatum(&__args));			\
+		}																\
+	} while(0)
+
 #endif   /* OBJECTACCESS_H */
diff --git a/src/include/catalog/pg_aggregate.h b/src/include/catalog/pg_aggregate.h
index 26966d2..7b2d172 100644
--- a/src/include/catalog/pg_aggregate.h
+++ b/src/include/catalog/pg_aggregate.h
@@ -237,6 +237,7 @@ extern void AggregateCreate(const char *aggName,
 				List *aggfinalfnName,
 				List *aggsortopName,
 				Oid aggTransType,
-				const char *agginitval);
+				const char *agginitval,
+				Datum hook_private);
 
 #endif   /* PG_AGGREGATE_H */
diff --git a/src/include/catalog/pg_proc_fn.h b/src/include/catalog/pg_proc_fn.h
index 09d779f..a28786f 100644
--- a/src/include/catalog/pg_proc_fn.h
+++ b/src/include/catalog/pg_proc_fn.h
@@ -37,7 +37,8 @@ extern Oid ProcedureCreate(const char *procedureName,
 				List *parameterDefaults,
 				Datum proconfig,
 				float4 procost,
-				float4 prorows);
+				float4 prorows,
+				Datum hook_private);
 
 extern bool function_parse_error_transpose(const char *prosrc);
 
