diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index d89cd8a498458d1301bb7a4ee835f6bba8e947cd..7d325d1dde58f736ebaefab76bb3c6ac386e8f75 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.147 2007/03/22 15:46:56 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.148 2007/03/26 16:58:37 tgl Exp $ -->
 <!--
  Documentation of the system catalogs, directed toward PostgreSQL developers
  -->
@@ -2655,6 +2655,13 @@
       <entry>Name of the language</entry>
      </row>
 
+     <row>
+      <entry><structfield>lanowner</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+      <entry>Owner of the language</entry>
+     </row>
+
      <row>
       <entry><structfield>lanispl</structfield></entry>
       <entry><type>bool</type></entry>
@@ -3265,7 +3272,7 @@
   <table>
    <title><structname>pg_pltemplate</> Columns</title>
 
-   <tgroup cols=4>
+   <tgroup cols=3>
     <thead>
      <row>
       <entry>Name</entry>
@@ -3287,6 +3294,12 @@
       <entry>True if language is considered trusted</entry>
      </row>
 
+     <row>
+      <entry><structfield>tmpldbacreate</structfield></entry>
+      <entry><type>boolean</type></entry>
+      <entry>True if language may be created by a database owner</entry>
+     </row>
+
      <row>
       <entry><structfield>tmplhandler</structfield></entry>
       <entry><type>text</type></entry>
diff --git a/doc/src/sgml/ref/alter_language.sgml b/doc/src/sgml/ref/alter_language.sgml
index 9c336f163bf97b31544fa79869f331bea465bf1a..e0cdb9d5a562ccb4733406738fe096e8cf2aa58b 100644
--- a/doc/src/sgml/ref/alter_language.sgml
+++ b/doc/src/sgml/ref/alter_language.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/alter_language.sgml,v 1.6 2006/09/16 00:30:16 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_language.sgml,v 1.7 2007/03/26 16:58:38 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -20,7 +20,8 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-ALTER LANGUAGE <replaceable>name</replaceable> RENAME TO <replaceable>newname</replaceable>
+ALTER [ PROCEDURAL ] LANGUAGE <replaceable>name</replaceable> RENAME TO <replaceable>newname</replaceable>
+ALTER [ PROCEDURAL ] LANGUAGE <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
 </synopsis>
  </refsynopsisdiv>
 
@@ -29,8 +30,9 @@ ALTER LANGUAGE <replaceable>name</replaceable> RENAME TO <replaceable>newname</r
 
   <para>
    <command>ALTER LANGUAGE</command> changes the definition of a
-   language.  The only functionality is to rename the language.  Only
-   a superuser can rename languages.
+   procedural language.  The only functionality is to rename the language or
+   assign a new owner.  You must be superuser or owner of the language to
+   use <command>ALTER LANGUAGE</command>.
   </para>
  </refsect1>
 
@@ -55,6 +57,15 @@ ALTER LANGUAGE <replaceable>name</replaceable> RENAME TO <replaceable>newname</r
      </para>
     </listitem>
    </varlistentry>
+
+   <varlistentry>
+    <term><replaceable>new_owner</replaceable></term>
+    <listitem>
+     <para>
+      The new owner of the language
+     </para>
+    </listitem>
+   </varlistentry>
   </variablelist>
  </refsect1>
 
diff --git a/doc/src/sgml/ref/create_language.sgml b/doc/src/sgml/ref/create_language.sgml
index b09b38bee99c4ab6c92fe61c692bf2a840eb4bc5..bb853feb19ce3ff47b82795a414c9f82e1cf37f5 100644
--- a/doc/src/sgml/ref/create_language.sgml
+++ b/doc/src/sgml/ref/create_language.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/create_language.sgml,v 1.43 2007/01/31 23:26:03 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_language.sgml,v 1.44 2007/03/26 16:58:38 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -34,9 +34,7 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</
    <productname>PostgreSQL</productname> user can register a new
    procedural language with a <productname>PostgreSQL</productname>
    database.  Subsequently, functions and trigger procedures can be
-   defined in this new language.  The user must have the
-   <productname>PostgreSQL</productname> superuser privilege to
-   register a new language.
+   defined in this new language.
   </para>
 
   <para>
@@ -64,6 +62,20 @@ CREATE [ TRUSTED ] [ PROCEDURAL ] LANGUAGE <replaceable class="parameter">name</
    old dump files, which are likely to contain out-of-date information
    about language support functions.
   </para>
+
+  <para>
+   Ordinarily, the user must have the
+   <productname>PostgreSQL</productname> superuser privilege to
+   register a new language.  However, the owner of a database can register
+   a new language within that database if the language is listed in
+   the <structname>pg_pltemplate</structname> catalog and is marked
+   as allowed to be created by database owners (<structfield>tmpldbacreate</>
+   is true).  The default is that trusted languages can be created
+   by database owners, but this can be adjusted by superusers by modifying
+   the contents of <structname>pg_pltemplate</structname>.
+   The creator of a language becomes its owner and can later
+   drop it, rename it, or assign it to a new owner.
+  </para>
  </refsect1>
 
  <refsect1 id="sql-createlanguage-parameters">
diff --git a/doc/src/sgml/ref/drop_language.sgml b/doc/src/sgml/ref/drop_language.sgml
index ad37287da67ee3d2d3c4252a8337e0f10f2655cf..1e3c960a72035abf2843e94a25ab3a96ba8e604b 100644
--- a/doc/src/sgml/ref/drop_language.sgml
+++ b/doc/src/sgml/ref/drop_language.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/drop_language.sgml,v 1.24 2007/01/31 23:26:03 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/drop_language.sgml,v 1.25 2007/03/26 16:58:38 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -31,6 +31,8 @@ DROP [ PROCEDURAL ] LANGUAGE [ IF EXISTS ] <replaceable class="PARAMETER">name</
    <command>DROP LANGUAGE</command> will remove the definition
    of the previously registered procedural language called
    <replaceable class="parameter">name</replaceable>.
+   You must be superuser or owner of the language to
+   use <command>DROP LANGUAGE</command>.
   </para>
  </refsect1>
   
@@ -43,7 +45,7 @@ DROP [ PROCEDURAL ] LANGUAGE [ IF EXISTS ] <replaceable class="PARAMETER">name</
     <term><literal>IF EXISTS</literal></term>
     <listitem>
      <para>
-      Do not throw an error if the function does not exist. A notice is issued 
+      Do not throw an error if the language does not exist. A notice is issued 
       in this case.
      </para>
     </listitem>
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index a2b64c78b3fed51fb5fb5464cb7fcd9e847173ce..b837ba4e91c32ba66f2baba6187407a3f3606e0f 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.137 2007/02/14 01:58:56 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.138 2007/03/26 16:58:38 tgl Exp $
  *
  * NOTES
  *	  See acl.h.
@@ -1003,11 +1003,8 @@ ExecGrant_Language(InternalGrant *istmt)
 		/*
 		 * Get owner ID and working copy of existing ACL. If there's no ACL,
 		 * substitute the proper default.
-		 *
-		 * Note: for now, languages are treated as owned by the bootstrap
-		 * user. We should add an owner column to pg_language instead.
 		 */
-		ownerId = BOOTSTRAP_SUPERUSERID;
+		ownerId = pg_language_tuple->lanowner;
 		aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
 								   &isNull);
 		if (isNull)
@@ -1770,8 +1767,7 @@ pg_language_aclmask(Oid lang_oid, Oid roleid,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
 				 errmsg("language with OID %u does not exist", lang_oid)));
 
-	/* XXX pg_language should have an owner column, but doesn't */
-	ownerId = BOOTSTRAP_SUPERUSERID;
+	ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
 
 	aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
 							   &isNull);
@@ -2147,6 +2143,34 @@ pg_proc_ownercheck(Oid proc_oid, Oid roleid)
 	return has_privs_of_role(roleid, ownerId);
 }
 
+/*
+ * Ownership check for a procedural language (specified by OID)
+ */
+bool
+pg_language_ownercheck(Oid lan_oid, Oid roleid)
+{
+	HeapTuple	tuple;
+	Oid			ownerId;
+
+	/* Superusers bypass all permission checking. */
+	if (superuser_arg(roleid))
+		return true;
+
+	tuple = SearchSysCache(LANGOID,
+						   ObjectIdGetDatum(lan_oid),
+						   0, 0, 0);
+	if (!HeapTupleIsValid(tuple))
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_FUNCTION),
+				 errmsg("language with OID %u does not exist", lan_oid)));
+
+	ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
+
+	ReleaseSysCache(tuple);
+
+	return has_privs_of_role(roleid, ownerId);
+}
+
 /*
  * Ownership check for a namespace (specified by OID).
  */
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index 30b7ebde00213eec88531f243adcb70753abbdd5..118e4adb16650ea86088c46468ce97bdae03c1c1 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.22 2007/01/23 05:07:17 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.23 2007/03/26 16:58:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -203,6 +203,10 @@ ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
 			AlterFunctionOwner(stmt->object, stmt->objarg, newowner);
 			break;
 
+		case OBJECT_LANGUAGE:
+			AlterLanguageOwner((char *) linitial(stmt->object), newowner);
+			break;
+
 		case OBJECT_OPERATOR:
 			Assert(list_length(stmt->objarg) == 2);
 			AlterOperatorOwner(stmt->object,
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 028ab5e5217b5fcc7effb50315c31e858c63783c..e396e0018d0a902017177393365e72f51026c135 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.71 2007/01/22 01:35:20 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.72 2007/03/26 16:58:38 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,16 +17,19 @@
 #include "access/heapam.h"
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
+#include "catalog/pg_authid.h"
 #include "catalog/pg_language.h"
 #include "catalog/pg_namespace.h"
 #include "catalog/pg_pltemplate.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_type.h"
+#include "commands/dbcommands.h"
 #include "commands/defrem.h"
 #include "commands/proclang.h"
 #include "miscadmin.h"
 #include "parser/gramparse.h"
 #include "parser/parse_func.h"
+#include "utils/acl.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
 #include "utils/lsyscache.h"
@@ -36,13 +39,14 @@
 typedef struct
 {
 	bool		tmpltrusted;	/* trusted? */
+	bool		tmpldbacreate;	/* db owner allowed to create? */
 	char	   *tmplhandler;	/* name of handler function */
 	char	   *tmplvalidator;	/* name of validator function, or NULL */
 	char	   *tmpllibrary;	/* path of shared library */
 } PLTemplate;
 
 static void create_proc_lang(const char *languageName,
-				 Oid handlerOid, Oid valOid, bool trusted);
+				 Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted);
 static PLTemplate *find_language_template(const char *languageName);
 
 
@@ -60,14 +64,6 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 	Oid			funcrettype;
 	Oid			funcargtypes[1];
 
-	/*
-	 * Check permission
-	 */
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to create procedural language")));
-
 	/*
 	 * Translate the language name and check that this language doesn't
 	 * already exist
@@ -96,6 +92,21 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 			ereport(NOTICE,
 					(errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));
 
+		/*
+		 * Check permission
+		 */
+		if (!superuser())
+		{
+			if (!pltemplate->tmpldbacreate)
+				ereport(ERROR,
+						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+						 errmsg("must be superuser to create procedural language \"%s\"",
+								languageName)));
+			if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
+				aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+							   get_database_name(MyDatabaseId));
+		}
+
 		/*
 		 * Find or create the handler function, which we force to be in the
 		 * pg_catalog schema.  If already present, it must have the correct
@@ -171,7 +182,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 			valOid = InvalidOid;
 
 		/* ok, create it */
-		create_proc_lang(languageName, handlerOid, valOid,
+		create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
 						 pltemplate->tmpltrusted);
 	}
 	else
@@ -188,6 +199,14 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 							languageName),
 					 errhint("The supported languages are listed in the pg_pltemplate system catalog.")));
 
+		/*
+		 * Check permission
+		 */
+		if (!superuser())
+			ereport(ERROR,
+					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+					 errmsg("must be superuser to create custom procedural language")));
+
 		/*
 		 * Lookup the PL handler function and check that it is of the expected
 		 * return type
@@ -227,7 +246,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
 			valOid = InvalidOid;
 
 		/* ok, create it */
-		create_proc_lang(languageName, handlerOid, valOid, stmt->pltrusted);
+		create_proc_lang(languageName, GetUserId(), handlerOid, valOid,
+						 stmt->pltrusted);
 	}
 }
 
@@ -236,7 +256,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
  */
 static void
 create_proc_lang(const char *languageName,
-				 Oid handlerOid, Oid valOid, bool trusted)
+				 Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted)
 {
 	Relation	rel;
 	TupleDesc	tupDesc;
@@ -258,6 +278,7 @@ create_proc_lang(const char *languageName,
 
 	namestrcpy(&langname, languageName);
 	values[Anum_pg_language_lanname - 1] = NameGetDatum(&langname);
+	values[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(languageOwner);
 	values[Anum_pg_language_lanispl - 1] = BoolGetDatum(true);
 	values[Anum_pg_language_lanpltrusted - 1] = BoolGetDatum(trusted);
 	values[Anum_pg_language_lanplcallfoid - 1] = ObjectIdGetDatum(handlerOid);
@@ -277,6 +298,12 @@ create_proc_lang(const char *languageName,
 	myself.objectId = HeapTupleGetOid(tup);
 	myself.objectSubId = 0;
 
+	/* dependency on owner of language */
+	referenced.classId = AuthIdRelationId;
+	referenced.objectId = languageOwner;
+	referenced.objectSubId = 0;
+	recordSharedDependencyOn(&myself, &referenced, SHARED_DEPENDENCY_OWNER);
+
 	/* dependency on the PL handler function */
 	referenced.classId = ProcedureRelationId;
 	referenced.objectId = handlerOid;
@@ -325,6 +352,7 @@ find_language_template(const char *languageName)
 
 		result = (PLTemplate *) palloc0(sizeof(PLTemplate));
 		result->tmpltrusted = tmpl->tmpltrusted;
+		result->tmpldbacreate = tmpl->tmpldbacreate;
 
 		/* Remaining fields are variable-width so we need heap_getattr */
 		datum = heap_getattr(tup, Anum_pg_pltemplate_tmplhandler,
@@ -381,14 +409,6 @@ DropProceduralLanguage(DropPLangStmt *stmt)
 	HeapTuple	langTup;
 	ObjectAddress object;
 
-	/*
-	 * Check permission
-	 */
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to drop procedural language")));
-
 	/*
 	 * Translate the language name, check that the language exists
 	 */
@@ -411,6 +431,13 @@ DropProceduralLanguage(DropPLangStmt *stmt)
 		return;
 	}
 
+	/*
+	 * Check permission
+	 */
+	if (!pg_language_ownercheck(HeapTupleGetOid(langTup), GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
+					   languageName);
+
 	object.classId = LanguageRelationId;
 	object.objectId = HeapTupleGetOid(langTup);
 	object.objectSubId = 0;
@@ -478,11 +505,10 @@ RenameLanguage(const char *oldname, const char *newname)
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
 				 errmsg("language \"%s\" already exists", newname)));
 
-	/* must be superuser, since we do not have owners for PLs */
-	if (!superuser())
-		ereport(ERROR,
-				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-				 errmsg("must be superuser to rename procedural language")));
+	/* must be owner of PL */
+	if (!pg_language_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
+					   oldname);
 
 	/* rename */
 	namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname);
@@ -492,3 +518,87 @@ RenameLanguage(const char *oldname, const char *newname)
 	heap_close(rel, NoLock);
 	heap_freetuple(tup);
 }
+
+/*
+ * Change language owner
+ */
+void
+AlterLanguageOwner(const char *name, Oid newOwnerId)
+{
+	HeapTuple	tup;
+	Relation	rel;
+	Form_pg_language lanForm;
+
+	/* Translate name for consistency with CREATE */
+	name = case_translate_language_name(name);
+
+	rel = heap_open(LanguageRelationId, RowExclusiveLock);
+
+	tup = SearchSysCache(LANGNAME,
+						 CStringGetDatum(name),
+						 0, 0, 0);
+	if (!HeapTupleIsValid(tup))
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("language \"%s\" does not exist", name)));
+	lanForm = (Form_pg_language) GETSTRUCT(tup);
+
+	/*
+	 * If the new owner is the same as the existing owner, consider the
+	 * command to have succeeded.  This is for dump restoration purposes.
+	 */
+	if (lanForm->lanowner != newOwnerId)
+	{
+		Datum		repl_val[Natts_pg_language];
+		char		repl_null[Natts_pg_language];
+		char		repl_repl[Natts_pg_language];
+		Acl		   *newAcl;
+		Datum		aclDatum;
+		bool		isNull;
+		HeapTuple	newtuple;
+
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_language_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_LANGUAGE,
+						   NameStr(lanForm->lanname));
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(), newOwnerId);
+
+		memset(repl_null, ' ', sizeof(repl_null));
+		memset(repl_repl, ' ', sizeof(repl_repl));
+
+		repl_repl[Anum_pg_language_lanowner - 1] = 'r';
+		repl_val[Anum_pg_language_lanowner - 1] = ObjectIdGetDatum(newOwnerId);
+
+		/*
+		 * Determine the modified ACL for the new owner.  This is only
+		 * necessary when the ACL is non-null.
+		 */
+		aclDatum = SysCacheGetAttr(LANGNAME, tup,
+								   Anum_pg_language_lanacl,
+								   &isNull);
+		if (!isNull)
+		{
+			newAcl = aclnewowner(DatumGetAclP(aclDatum),
+								 lanForm->lanowner, newOwnerId);
+			repl_repl[Anum_pg_language_lanacl - 1] = 'r';
+			repl_val[Anum_pg_language_lanacl - 1] = PointerGetDatum(newAcl);
+		}
+
+		newtuple = heap_modifytuple(tup, RelationGetDescr(rel),
+									repl_val, repl_null, repl_repl);
+
+		simple_heap_update(rel, &newtuple->t_self, newtuple);
+		CatalogUpdateIndexes(rel, newtuple);
+
+		heap_freetuple(newtuple);
+
+		/* Update owner dependency reference */
+		changeDependencyOnOwner(LanguageRelationId, HeapTupleGetOid(tup),
+								newOwnerId);
+	}
+
+	ReleaseSysCache(tup);
+	heap_close(rel, RowExclusiveLock);
+}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 75404716d5a1f82a6a70d46188484e22fbe88ab4..8cad738a357e7c1c28b436ff33084f77a39ed27c 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.583 2007/03/19 23:38:29 wieck Exp $
+ *	  $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.584 2007/03/26 16:58:39 tgl Exp $
  *
  * HISTORY
  *	  AUTHOR			DATE			MAJOR EVENT
@@ -4447,12 +4447,12 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
 					n->newname = $6;
 					$$ = (Node *)n;
 				}
-			| ALTER LANGUAGE name RENAME TO name
+			| ALTER opt_procedural LANGUAGE name RENAME TO name
 				{
 					RenameStmt *n = makeNode(RenameStmt);
 					n->renameType = OBJECT_LANGUAGE;
-					n->subname = $3;
-					n->newname = $6;
+					n->subname = $4;
+					n->newname = $7;
 					$$ = (Node *)n;
 				}
 			| ALTER OPERATOR CLASS any_name USING access_method RENAME TO name
@@ -4654,6 +4654,14 @@ AlterOwnerStmt: ALTER AGGREGATE func_name aggr_args OWNER TO RoleId
 					n->newowner = $7;
 					$$ = (Node *)n;
 				}
+			| ALTER opt_procedural LANGUAGE name OWNER TO RoleId
+				{
+					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+					n->objectType = OBJECT_LANGUAGE;
+					n->object = list_make1($4);
+					n->newowner = $7;
+					$$ = (Node *)n;
+				}
 			| ALTER OPERATOR any_operator '(' oper_argtypes ')' OWNER TO RoleId
 				{
 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index be274a72f10e3bc82fa15bc524d0628fec16840f..daf23fd0fe5586917067aa77a2e3d5f0dec38e88 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.274 2007/03/13 00:33:42 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.275 2007/03/26 16:58:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1551,6 +1551,9 @@ CreateCommandTag(Node *parsetree)
 				case OBJECT_FUNCTION:
 					tag = "ALTER FUNCTION";
 					break;
+				case OBJECT_LANGUAGE:
+					tag = "ALTER LANGUAGE";
+					break;
 				case OBJECT_OPERATOR:
 					tag = "ALTER OPERATOR";
 					break;
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index cd979cfaddfab63617549d01370398722cedfe10..981168bfa7cf0c316b114615ca6d9f20dde36e5b 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *		$PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.143 2007/03/18 16:50:44 neilc Exp $
+ *		$PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.144 2007/03/26 16:58:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2440,6 +2440,7 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH)
 
 	/* objects named by just a name */
 	if (strcmp(type, "DATABASE") == 0 ||
+		strcmp(type, "PROCEDURAL LANGUAGE") == 0 ||
 		strcmp(type, "SCHEMA") == 0)
 	{
 		appendPQExpBuffer(buf, "%s %s", type, fmtId(te->tag));
@@ -2583,6 +2584,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
 			strcmp(te->desc, "OPERATOR") == 0 ||
 			strcmp(te->desc, "OPERATOR CLASS") == 0 ||
 			strcmp(te->desc, "OPERATOR FAMILY") == 0 ||
+			strcmp(te->desc, "PROCEDURAL LANGUAGE") == 0 ||
 			strcmp(te->desc, "SCHEMA") == 0 ||
 			strcmp(te->desc, "TABLE") == 0 ||
 			strcmp(te->desc, "TYPE") == 0 ||
@@ -2603,7 +2605,6 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
 				 strcmp(te->desc, "DEFAULT") == 0 ||
 				 strcmp(te->desc, "FK CONSTRAINT") == 0 ||
 				 strcmp(te->desc, "INDEX") == 0 ||
-				 strcmp(te->desc, "PROCEDURAL LANGUAGE") == 0 ||
 				 strcmp(te->desc, "RULE") == 0 ||
 				 strcmp(te->desc, "TRIGGER") == 0)
 		{
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 61bf13eb4fdb6b9434f8ff7b33c5f2453957c61b..b0c9e70a46f2423084c1e509b74a797a90899fb8 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -12,7 +12,7 @@
  *	by PostgreSQL
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.464 2007/03/22 20:47:12 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.465 2007/03/26 16:58:39 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -4030,7 +4030,19 @@ getProcLangs(int *numProcLangs)
 	/* Make sure we are in proper schema */
 	selectSourceSchema("pg_catalog");
 
-	if (g_fout->remoteVersion >= 80100)
+	if (g_fout->remoteVersion >= 80300)
+	{
+		/* pg_language has a lanowner column */
+		appendPQExpBuffer(query, "SELECT tableoid, oid, "
+						  "lanname, lanpltrusted, lanplcallfoid, "
+						  "lanvalidator,  lanacl, "
+						  "(%s lanowner) as lanowner "
+						  "FROM pg_language "
+						  "WHERE lanispl "
+						  "ORDER BY oid",
+						  username_subquery);
+	}
+	else if (g_fout->remoteVersion >= 80100)
 	{
 		/* Languages are owned by the bootstrap superuser, OID 10 */
 		appendPQExpBuffer(query, "SELECT tableoid, oid, *, "
diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c
index 63db48546bf3c7e59a82b152d23e490af812467d..970bbecadf8d53982d529d9a9a734bd1a6df72d3 100644
--- a/src/bin/psql/tab-complete.c
+++ b/src/bin/psql/tab-complete.c
@@ -3,7 +3,7 @@
  *
  * Copyright (c) 2000-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.159 2007/02/23 18:20:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.160 2007/03/26 16:58:40 tgl Exp $
  */
 
 /*----------------------------------------------------------------------
@@ -651,7 +651,12 @@ psql_completion(char *text, int start, int end)
 	/* ALTER LANGUAGE <name> */
 	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
 			 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
-		COMPLETE_WITH_CONST("RENAME TO");
+	{
+		static const char *const list_ALTERLANGUAGE[] =
+		{"OWNER TO", "RENAME TO", NULL};
+
+		COMPLETE_WITH_LIST(list_ALTERLANGUAGE);
+	}
 
 	/* ALTER USER,ROLE <name> */
 	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index e7ab0e78f028b691f2faaa5de5ca5d007ced58bf..79dd0cdb10e1c59da4f2432fe7ad62f6296242e1 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.394 2007/03/25 11:56:04 ishii Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.395 2007/03/26 16:58:41 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200703251
+#define CATALOG_VERSION_NO	200703261
 
 #endif
diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h
index a7e449e5139d8ad00d614226f0b66a9165009e58..bf4fdd2774f446b2c75e524c5dc5d9e4c7e58a81 100644
--- a/src/include/catalog/pg_language.h
+++ b/src/include/catalog/pg_language.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_language.h,v 1.29 2007/01/05 22:19:52 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_language.h,v 1.30 2007/03/26 16:58:41 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -35,11 +35,12 @@
 
 CATALOG(pg_language,2612)
 {
-	NameData	lanname;
+	NameData	lanname;		/* Language name */
+	Oid			lanowner;		/* Language's owner */
 	bool		lanispl;		/* Is a procedural language */
 	bool		lanpltrusted;	/* PL is trusted */
 	Oid			lanplcallfoid;	/* Call handler for PL */
-	Oid			lanvalidator;	/* optional validation function */
+	Oid			lanvalidator;	/* Optional validation function */
 	aclitem		lanacl[1];		/* Access privileges */
 } FormData_pg_language;
 
@@ -54,26 +55,27 @@ typedef FormData_pg_language *Form_pg_language;
  *		compiler constants for pg_language
  * ----------------
  */
-#define Natts_pg_language				6
+#define Natts_pg_language				7
 #define Anum_pg_language_lanname		1
-#define Anum_pg_language_lanispl		2
-#define Anum_pg_language_lanpltrusted		3
-#define Anum_pg_language_lanplcallfoid		4
-#define Anum_pg_language_lanvalidator		5
-#define Anum_pg_language_lanacl			6
+#define Anum_pg_language_lanowner		2
+#define Anum_pg_language_lanispl		3
+#define Anum_pg_language_lanpltrusted	4
+#define Anum_pg_language_lanplcallfoid	5
+#define Anum_pg_language_lanvalidator	6
+#define Anum_pg_language_lanacl			7
 
 /* ----------------
  *		initial contents of pg_language
  * ----------------
  */
 
-DATA(insert OID = 12 ( "internal" f f 0 2246 _null_ ));
+DATA(insert OID = 12 ( "internal" PGUID f f 0 2246 _null_ ));
 DESCR("Built-in functions");
 #define INTERNALlanguageId 12
-DATA(insert OID = 13 ( "c" f f 0 2247 _null_ ));
+DATA(insert OID = 13 ( "c" PGUID f f 0 2247 _null_ ));
 DESCR("Dynamically-loaded C functions");
 #define ClanguageId 13
-DATA(insert OID = 14 ( "sql" f t 0 2248 _null_ ));
+DATA(insert OID = 14 ( "sql" PGUID f t 0 2248 _null_ ));
 DESCR("SQL-language functions");
 #define SQLlanguageId 14
 
diff --git a/src/include/catalog/pg_pltemplate.h b/src/include/catalog/pg_pltemplate.h
index a5c05f4d069030429b1bf6725e442b0259926fd1..7f33eed49e33fa99e584f2741ef0a17427694ff7 100644
--- a/src/include/catalog/pg_pltemplate.h
+++ b/src/include/catalog/pg_pltemplate.h
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.3 2007/01/05 22:19:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_pltemplate.h,v 1.4 2007/03/26 16:58:41 tgl Exp $
  *
  * NOTES
  *	  the genbki.sh script reads this file and generates .bki
@@ -37,6 +37,7 @@ CATALOG(pg_pltemplate,1136) BKI_SHARED_RELATION BKI_WITHOUT_OIDS
 {
 	NameData	tmplname;		/* name of PL */
 	bool		tmpltrusted;	/* PL is trusted? */
+	bool		tmpldbacreate;	/* PL is installable by db owner? */
 	text		tmplhandler;	/* name of call handler function */
 	text		tmplvalidator;	/* name of validator function, or NULL */
 	text		tmpllibrary;	/* path of shared library */
@@ -54,13 +55,14 @@ typedef FormData_pg_pltemplate *Form_pg_pltemplate;
  *		compiler constants for pg_pltemplate
  * ----------------
  */
-#define Natts_pg_pltemplate					6
+#define Natts_pg_pltemplate					7
 #define Anum_pg_pltemplate_tmplname			1
 #define Anum_pg_pltemplate_tmpltrusted		2
-#define Anum_pg_pltemplate_tmplhandler		3
-#define Anum_pg_pltemplate_tmplvalidator	4
-#define Anum_pg_pltemplate_tmpllibrary		5
-#define Anum_pg_pltemplate_tmplacl			6
+#define Anum_pg_pltemplate_tmpldbacreate	3
+#define Anum_pg_pltemplate_tmplhandler		4
+#define Anum_pg_pltemplate_tmplvalidator	5
+#define Anum_pg_pltemplate_tmpllibrary		6
+#define Anum_pg_pltemplate_tmplacl			7
 
 
 /* ----------------
@@ -68,11 +70,11 @@ typedef FormData_pg_pltemplate *Form_pg_pltemplate;
  * ----------------
  */
 
-DATA(insert ( "plpgsql"		t "plpgsql_call_handler" "plpgsql_validator" "$libdir/plpgsql" _null_ ));
-DATA(insert ( "pltcl"		t "pltcl_call_handler" _null_ "$libdir/pltcl" _null_ ));
-DATA(insert ( "pltclu"		f "pltclu_call_handler" _null_ "$libdir/pltcl" _null_ ));
-DATA(insert ( "plperl"		t "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ ));
-DATA(insert ( "plperlu"		f "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ ));
-DATA(insert ( "plpythonu"	f "plpython_call_handler" _null_ "$libdir/plpython" _null_ ));
+DATA(insert ( "plpgsql"		t t "plpgsql_call_handler" "plpgsql_validator" "$libdir/plpgsql" _null_ ));
+DATA(insert ( "pltcl"		t t "pltcl_call_handler" _null_ "$libdir/pltcl" _null_ ));
+DATA(insert ( "pltclu"		f f "pltclu_call_handler" _null_ "$libdir/pltcl" _null_ ));
+DATA(insert ( "plperl"		t t "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ ));
+DATA(insert ( "plperlu"		f f "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ ));
+DATA(insert ( "plpythonu"	f f "plpython_call_handler" _null_ "$libdir/plpython" _null_ ));
 
 #endif   /* PG_PLTEMPLATE_H */
diff --git a/src/include/commands/proclang.h b/src/include/commands/proclang.h
index 7f38a8542ac2782cdece5905859b8e6687ca1476..0ae128285d19d8fc729eecfa8d514d3ed131fc02 100644
--- a/src/include/commands/proclang.h
+++ b/src/include/commands/proclang.h
@@ -15,6 +15,7 @@ extern void CreateProceduralLanguage(CreatePLangStmt *stmt);
 extern void DropProceduralLanguage(DropPLangStmt *stmt);
 extern void DropProceduralLanguageById(Oid langOid);
 extern void RenameLanguage(const char *oldname, const char *newname);
+extern void AlterLanguageOwner(const char *name, Oid newOwnerId);
 extern bool PLTemplateExists(const char *languageName);
 
 #endif   /* PROCLANG_H */
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 14522bc6fb19ac60dcc30f6dcdcb1ef4522af8b9..5eb054e14661981ac6d9be7c19e17188d8b0c4d9 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.100 2007/01/23 05:07:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.101 2007/03/26 16:58:41 tgl Exp $
  *
  * NOTES
  *	  An ACL array is simply an array of AclItems, representing the union
@@ -274,6 +274,7 @@ extern bool pg_class_ownercheck(Oid class_oid, Oid roleid);
 extern bool pg_type_ownercheck(Oid type_oid, Oid roleid);
 extern bool pg_oper_ownercheck(Oid oper_oid, Oid roleid);
 extern bool pg_proc_ownercheck(Oid proc_oid, Oid roleid);
+extern bool pg_language_ownercheck(Oid lan_oid, Oid roleid);
 extern bool pg_namespace_ownercheck(Oid nsp_oid, Oid roleid);
 extern bool pg_tablespace_ownercheck(Oid spc_oid, Oid roleid);
 extern bool pg_opclass_ownercheck(Oid opc_oid, Oid roleid);