Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.143
diff -c -r2.143 catalogs.sgml
*** doc/src/sgml/catalogs.sgml	22 Jan 2007 01:35:19 -0000	2.143
--- doc/src/sgml/catalogs.sgml	27 Jan 2007 23:05:33 -0000
***************
*** 2635,2640 ****
--- 2635,2647 ----
       </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, usually either the owner of the database, or the superuser who created it</entry>
+      </row>
+ 
+      <row>
        <entry><structfield>lanispl</structfield></entry>
        <entry><type>bool</type></entry>
        <entry></entry>
***************
*** 3267,3272 ****
--- 3274,3285 ----
       </row>
  
       <row>
+       <entry><structfield>tmpldbaallowed</structfield></entry>
+       <entry><type>boolean</type></entry>
+       <entry>True if language can be created by a database owner if it is trusted</entry>
+      </row>
+ 
+      <row>
        <entry><structfield>tmplhandler</structfield></entry>
        <entry><type>text</type></entry>
        <entry>Name of call handler function</entry>
Index: doc/src/sgml/ref/alter_language.sgml
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/doc/src/sgml/ref/alter_language.sgml,v
retrieving revision 1.6
diff -c -r1.6 alter_language.sgml
*** doc/src/sgml/ref/alter_language.sgml	16 Sep 2006 00:30:16 -0000	1.6
--- doc/src/sgml/ref/alter_language.sgml	26 Jan 2007 01:01:40 -0000
***************
*** 21,26 ****
--- 21,28 ----
   <refsynopsisdiv>
  <synopsis>
  ALTER LANGUAGE <replaceable>name</replaceable> RENAME TO <replaceable>newname</replaceable>
+ 
+ ALTER LANGUAGE <replaceable>name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
  </synopsis>
   </refsynopsisdiv>
  
***************
*** 48,53 ****
--- 50,64 ----
     </varlistentry>
  
     <varlistentry>
+     <term><replaceable>new_owner</replaceable></term>
+     <listitem>
+      <para>
+       The new owner of the language.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
      <term><replaceable>newname</replaceable></term>
      <listitem>
       <para>
Index: doc/src/sgml/ref/create_language.sgml
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/doc/src/sgml/ref/create_language.sgml,v
retrieving revision 1.42
diff -c -r1.42 create_language.sgml
*** doc/src/sgml/ref/create_language.sgml	16 Sep 2006 00:30:17 -0000	1.42
--- doc/src/sgml/ref/create_language.sgml	28 Jan 2007 00:04:10 -0000
***************
*** 36,42 ****
     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.
    </para>
  
    <para>
--- 36,47 ----
     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, unless the language is present in the
!    <link linkend="catalog-pg-pltemplate"><structname>pg_pltemplate</structname></link>
!    system catalog, the language template is marked as trusted, and the
!    <structfield>tmpldbaallowed</structfield> column for the template is
!    true, in which case the database owner is also allowed to register
!    the language.
    </para>
  
    <para>
Index: src/backend/catalog/aclchk.c
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/src/backend/catalog/aclchk.c,v
retrieving revision 1.135
diff -c -r1.135 aclchk.c
*** src/backend/catalog/aclchk.c	23 Jan 2007 05:07:17 -0000	1.135
--- src/backend/catalog/aclchk.c	26 Jan 2007 23:53:03 -0000
***************
*** 1003,1013 ****
  		/*
  		 * 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;
  		aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
  								   &isNull);
  		if (isNull)
--- 1003,1010 ----
  		/*
  		 * Get owner ID and working copy of existing ACL. If there's no ACL,
  		 * substitute the proper default.
  		 */
! 		ownerId = pg_language_tuple->lanowner;
  		aclDatum = SysCacheGetAttr(LANGNAME, tuple, Anum_pg_language_lanacl,
  								   &isNull);
  		if (isNull)
***************
*** 1770,1777 ****
  				(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;
  
  	aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
  							   &isNull);
--- 1767,1773 ----
  				(errcode(ERRCODE_UNDEFINED_OBJECT),
  				 errmsg("language with OID %u does not exist", lang_oid)));
  
! 	ownerId = ((Form_pg_language) GETSTRUCT(tuple))->lanowner;
  
  	aclDatum = SysCacheGetAttr(LANGOID, tuple, Anum_pg_language_lanacl,
  							   &isNull);
***************
*** 2148,2153 ****
--- 2144,2177 ----
  }
  
  /*
+  * 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).
   */
  bool
Index: src/backend/commands/alter.c
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/src/backend/commands/alter.c,v
retrieving revision 1.22
diff -c -r1.22 alter.c
*** src/backend/commands/alter.c	23 Jan 2007 05:07:17 -0000	1.22
--- src/backend/commands/alter.c	25 Jan 2007 23:55:41 -0000
***************
*** 203,208 ****
--- 203,212 ----
  			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,
Index: src/backend/commands/proclang.c
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/src/backend/commands/proclang.c,v
retrieving revision 1.71
diff -c -r1.71 proclang.c
*** src/backend/commands/proclang.c	22 Jan 2007 01:35:20 -0000	1.71
--- src/backend/commands/proclang.c	27 Jan 2007 06:45:05 -0000
***************
*** 17,32 ****
--- 17,36 ----
  #include "access/heapam.h"
  #include "catalog/dependency.h"
  #include "catalog/indexing.h"
+ #include "catalog/pg_authid.h"
+ #include "catalog/pg_database.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,49 ****
  typedef struct
  {
  	bool		tmpltrusted;	/* trusted? */
  	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);
  static PLTemplate *find_language_template(const char *languageName);
  
  
  /* ---------------------------------------------------------------------
--- 40,58 ----
  typedef struct
  {
  	bool		tmpltrusted;	/* trusted? */
+ 	bool		tmpldbaallowed;	/* 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 languageOwner, Oid handlerOid, Oid valOid, bool trusted);
  static PLTemplate *find_language_template(const char *languageName);
+ static void AlterLanguageOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId);
+ 
+ static Oid get_current_datdba();
+ static Oid find_desired_language_owner (PLTemplate *pltemplate);
  
  
  /* ---------------------------------------------------------------------
***************
*** 61,74 ****
  	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
  	 */
--- 70,75 ----
***************
*** 97,102 ****
--- 98,125 ----
  					(errmsg("using pg_pltemplate information instead of CREATE LANGUAGE parameters")));
  
  		/*
+ 		 * Check permission
+ 		 */
+ 		if (pltemplate->tmpltrusted && pltemplate->tmpldbaallowed)
+ 		{
+ 				if (!pg_database_ownercheck(MyDatabaseId, GetUserId()))
+ 					aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+ 							get_database_name(MyDatabaseId));
+ 		}
+ 		else if (!superuser())
+ 		{
+ 			if (!pltemplate->tmpltrusted)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 						 errmsg("must be superuser to create untrusted procedural language")));
+ 			else
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 						 errmsg("must be superuser to create procedural language \"%s\"", languageName),
+ 						 errhint("Column pg_pltemplate.tmpldbaallowed has been set to false for this language.")));
+ 		}
+ 
+ 		/*
  		 * Find or create the handler function, which we force to be in the
  		 * pg_catalog schema.  If already present, it must have the correct
  		 * return type.
***************
*** 171,177 ****
  			valOid = InvalidOid;
  
  		/* ok, create it */
! 		create_proc_lang(languageName, handlerOid, valOid,
  						 pltemplate->tmpltrusted);
  	}
  	else
--- 194,200 ----
  			valOid = InvalidOid;
  
  		/* ok, create it */
! 		create_proc_lang(languageName, find_desired_language_owner(pltemplate), handlerOid, valOid,
  						 pltemplate->tmpltrusted);
  	}
  	else
***************
*** 189,194 ****
--- 212,225 ----
  					 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,233 ****
  			valOid = InvalidOid;
  
  		/* ok, create it */
! 		create_proc_lang(languageName, handlerOid, valOid, stmt->pltrusted);
  	}
  }
  
--- 258,264 ----
  			valOid = InvalidOid;
  
  		/* ok, create it */
! 		create_proc_lang(languageName, GetUserId(), handlerOid, valOid, stmt->pltrusted);
  	}
  }
  
***************
*** 236,242 ****
   */
  static void
  create_proc_lang(const char *languageName,
! 				 Oid handlerOid, Oid valOid, bool trusted)
  {
  	Relation	rel;
  	TupleDesc	tupDesc;
--- 267,273 ----
   */
  static void
  create_proc_lang(const char *languageName,
! 				 Oid languageOwner, Oid handlerOid, Oid valOid, bool trusted)
  {
  	Relation	rel;
  	TupleDesc	tupDesc;
***************
*** 258,263 ****
--- 289,295 ----
  
  	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,282 ****
--- 309,320 ----
  	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;
***************
*** 295,300 ****
--- 333,371 ----
  	heap_close(rel, RowExclusiveLock);
  }
  
+ static Oid get_current_datdba()
+ {
+ 	/* find datdba for current db */
+ 	HeapTuple	tuple;
+ 	Oid			dba;
+ 
+ 	tuple = SearchSysCache(DATABASEOID,
+ 			ObjectIdGetDatum(MyDatabaseId),
+ 			0, 0, 0);
+ 	if (!HeapTupleIsValid(tuple))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_DATABASE),
+ 				 errmsg("database with OID %u does not exist", MyDatabaseId)));
+ 
+ 	dba = ((Form_pg_database) GETSTRUCT(tuple))->datdba;
+ 
+ 	ReleaseSysCache(tuple);
+ 	return dba;
+ }
+ 
+ 
+ static Oid find_desired_language_owner (PLTemplate *pltemplate)
+ {
+ 	if (pltemplate->tmpltrusted && pltemplate->tmpldbaallowed)
+ 	{
+ 		return get_current_datdba();
+ 	}
+ 	else
+ 	{
+ 		return GetUserId();
+ 	}
+ }
+ 
  /*
   * Look to see if we have template information for the given language name.
   */
***************
*** 325,330 ****
--- 396,402 ----
  
  		result = (PLTemplate *) palloc0(sizeof(PLTemplate));
  		result->tmpltrusted = tmpl->tmpltrusted;
+ 		result->tmpldbaallowed = tmpl->tmpldbaallowed;
  
  		/* Remaining fields are variable-width so we need heap_getattr */
  		datum = heap_getattr(tup, Anum_pg_pltemplate_tmplhandler,
***************
*** 382,395 ****
  	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
  	 */
  	languageName = case_translate_language_name(stmt->plname);
--- 454,459 ----
***************
*** 411,416 ****
--- 475,487 ----
  		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,488 ****
  				(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")));
  
  	/* rename */
  	namestrcpy(&(((Form_pg_language) GETSTRUCT(tup))->lanname), newname);
--- 549,558 ----
  				(errcode(ERRCODE_DUPLICATE_OBJECT),
  				 errmsg("language \"%s\" already exists", newname)));
  
! 	/* 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,494 ****
--- 562,670 ----
  	heap_close(rel, NoLock);
  	heap_freetuple(tup);
  }
+ 
+ /*
+  * Change language owner
+  */
+ void
+ AlterLanguageOwner(const char *name, Oid newOwnerId)
+ {
+ 	HeapTuple	tup;
+ 	Relation	rel;
+ 
+ 	/* 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)));
+ 
+ 	AlterLanguageOwner_internal(tup, rel, newOwnerId);
+ 
+ 	ReleaseSysCache(tup);
+ 	heap_close(rel, RowExclusiveLock);
+ }
+ 
+ static void
+ AlterLanguageOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerId)
+ {
+ 	Form_pg_language lanForm;
+ 
+ 	Assert(tup->t_tableOid == LanguageRelationId);
+ 	Assert(RelationGetRelid(rel) == LanguageRelationId);
+ 
+ 	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;
+ 		AclResult	aclresult;
+ 
+ 		/* 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);
+ 
+ 		/*
+ 		 * must have rights to create this language
+ 		 */
+ 		if (!has_privs_of_role(newOwnerId, find_desired_language_owner (find_language_template (NameStr(lanForm->lanname)))))
+ 		{
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ 					 errmsg("new user must be allowed to create this language")));
+ 		}
+ 
+ 		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);
+ 	}
+ }
Index: src/backend/parser/gram.y
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.577
diff -c -r2.577 gram.y
*** src/backend/parser/gram.y	25 Jan 2007 11:53:51 -0000	2.577
--- src/backend/parser/gram.y	25 Jan 2007 23:55:10 -0000
***************
*** 4596,4601 ****
--- 4596,4609 ----
  					n->newowner = $7;
  					$$ = (Node *)n;
  				}
+ 			| ALTER LANGUAGE name OWNER TO RoleId
+ 				{
+ 					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ 					n->objectType = OBJECT_LANGUAGE;
+ 					n->object = list_make1($3);
+ 					n->newowner = $6;
+ 					$$ = (Node *)n;
+ 				}
  			| ALTER OPERATOR any_operator '(' oper_argtypes ')' OWNER TO RoleId
  				{
  					AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
Index: src/backend/tcop/utility.c
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/src/backend/tcop/utility.c,v
retrieving revision 1.271
diff -c -r1.271 utility.c
*** src/backend/tcop/utility.c	23 Jan 2007 05:07:18 -0000	1.271
--- src/backend/tcop/utility.c	26 Jan 2007 00:53:24 -0000
***************
*** 1530,1535 ****
--- 1530,1538 ----
  				case OBJECT_FUNCTION:
  					tag = "ALTER FUNCTION";
  					break;
+ 				case OBJECT_LANGUAGE:
+ 					tag = "ALTER LANGUAGE";
+ 					break;
  				case OBJECT_OPERATOR:
  					tag = "ALTER OPERATOR";
  					break;
Index: src/bin/psql/tab-complete.c
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/src/bin/psql/tab-complete.c,v
retrieving revision 1.157
diff -c -r1.157 tab-complete.c
*** src/bin/psql/tab-complete.c	5 Jan 2007 22:19:49 -0000	1.157
--- src/bin/psql/tab-complete.c	27 Jan 2007 00:40:45 -0000
***************
*** 651,657 ****
  	/* ALTER LANGUAGE <name> */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
! 		COMPLETE_WITH_CONST("RENAME TO");
  
  	/* ALTER USER,ROLE <name> */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
--- 651,662 ----
  	/* ALTER LANGUAGE <name> */
  	else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
  			 pg_strcasecmp(prev2_wd, "LANGUAGE") == 0)
! 	{
! 		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 &&
Index: src/include/catalog/pg_language.h
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/src/include/catalog/pg_language.h,v
retrieving revision 1.29
diff -c -r1.29 pg_language.h
*** src/include/catalog/pg_language.h	5 Jan 2007 22:19:52 -0000	1.29
--- src/include/catalog/pg_language.h	25 Jan 2007 03:51:13 -0000
***************
*** 36,41 ****
--- 36,42 ----
  CATALOG(pg_language,2612)
  {
  	NameData	lanname;
+ 	Oid			lanowner;		/* language owner */
  	bool		lanispl;		/* Is a procedural language */
  	bool		lanpltrusted;	/* PL is trusted */
  	Oid			lanplcallfoid;	/* Call handler for PL */
***************
*** 54,79 ****
   *		compiler constants for pg_language
   * ----------------
   */
! #define Natts_pg_language				6
  #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
  
  /* ----------------
   *		initial contents of pg_language
   * ----------------
   */
  
! DATA(insert OID = 12 ( "internal" f f 0 2246 _null_ ));
  DESCR("Built-in functions");
  #define INTERNALlanguageId 12
! DATA(insert OID = 13 ( "c" f f 0 2247 _null_ ));
  DESCR("Dynamically-loaded C functions");
  #define ClanguageId 13
! DATA(insert OID = 14 ( "sql" f t 0 2248 _null_ ));
  DESCR("SQL-language functions");
  #define SQLlanguageId 14
  
--- 55,81 ----
   *		compiler constants for pg_language
   * ----------------
   */
! #define Natts_pg_language				7
  #define Anum_pg_language_lanname		1
! #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" PGUID f f 0 2246 _null_ ));
  DESCR("Built-in functions");
  #define INTERNALlanguageId 12
! DATA(insert OID = 13 ( "c" PGUID f f 0 2247 _null_ ));
  DESCR("Dynamically-loaded C functions");
  #define ClanguageId 13
! DATA(insert OID = 14 ( "sql" PGUID f t 0 2248 _null_ ));
  DESCR("SQL-language functions");
  #define SQLlanguageId 14
  
Index: src/include/catalog/pg_pltemplate.h
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/src/include/catalog/pg_pltemplate.h,v
retrieving revision 1.3
diff -c -r1.3 pg_pltemplate.h
*** src/include/catalog/pg_pltemplate.h	5 Jan 2007 22:19:53 -0000	1.3
--- src/include/catalog/pg_pltemplate.h	25 Jan 2007 01:36:57 -0000
***************
*** 37,42 ****
--- 37,43 ----
  {
  	NameData	tmplname;		/* name of PL */
  	bool		tmpltrusted;	/* PL is trusted? */
+ 	bool		tmpldbaallowed;	/* 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,66 ****
   *		compiler constants for pg_pltemplate
   * ----------------
   */
! #define Natts_pg_pltemplate					6
  #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
  
  
  /* ----------------
--- 55,68 ----
   *		compiler constants for pg_pltemplate
   * ----------------
   */
! #define Natts_pg_pltemplate					7
  #define Anum_pg_pltemplate_tmplname			1
  #define Anum_pg_pltemplate_tmpltrusted		2
! #define Anum_pg_pltemplate_tmpldbaallowed	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,78 ****
   * ----------------
   */
  
! 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_ ));
  
  #endif   /* PG_PLTEMPLATE_H */
--- 70,80 ----
   * ----------------
   */
  
! 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 t "pltclu_call_handler" _null_ "$libdir/pltcl" _null_ ));
! DATA(insert ( "plperl"		t t "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ ));
! DATA(insert ( "plperlu"		f t "plperl_call_handler" "plperl_validator" "$libdir/plperl" _null_ ));
! DATA(insert ( "plpythonu"	f t "plpython_call_handler" _null_ "$libdir/plpython" _null_ ));
  
  #endif   /* PG_PLTEMPLATE_H */
Index: src/include/commands/proclang.h
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/src/include/commands/proclang.h,v
retrieving revision 1.11
diff -c -r1.11 proclang.h
*** src/include/commands/proclang.h	8 Sep 2005 20:07:42 -0000	1.11
--- src/include/commands/proclang.h	26 Jan 2007 00:37:51 -0000
***************
*** 15,20 ****
--- 15,21 ----
  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 */
Index: src/include/utils/acl.h
===================================================================
RCS file: /data/local/jeremyd/postgres/cvsuproot/pgsql/src/include/utils/acl.h,v
retrieving revision 1.100
diff -c -r1.100 acl.h
*** src/include/utils/acl.h	23 Jan 2007 05:07:18 -0000	1.100
--- src/include/utils/acl.h	27 Jan 2007 00:05:16 -0000
***************
*** 274,279 ****
--- 274,280 ----
  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);
