On Thu, 25 Jan 2007, Jeremy Drake wrote:

> On Thu, 25 Jan 2007, Jeremy Drake wrote:
>
> > I think that an ALTER LANGUAGE OWNER TO is the proper response to these
> > things, and unless I hear otherwise I will attempt to add this to my
> > patch.
>
> Here is the patch which adds this.  It also allows ALTER LANGUAGE RENAME
> TO for the owner, which I missed before.  I would appreciate someone with
> more knowledge of the permissions infrastructure to take a look at it
> since I am fairly new to it and may not fully understand its intricacies.
>

I have refactored the owner checking of languages in the same manner as it
is for other owned objects.  I have changed to using standard permissions
error messages (aclcheck_error) for the language permissions errors.

I consider this patch ready for review, assuming the permissions rules
outlined by Tom Lane on -hackers are valid.  For reference, here are the
rules that this patch is intended to implement:

On Wed, 24 Jan 2007, Tom Lane wrote:

> In detail, it'd look something like:
>
> * For an untrusted language: must be superuser to either create or use
> the language (no change from current rules).  Ownership of the
> pg_language entry is really irrelevant, as is its ACL.
>
> * For a trusted language:
>
> * if pg_pltemplate.something is ON: either a superuser or the current
> DB's owner can CREATE the language.  In either case the pg_language
> entry will be marked as owned by the DB owner (pg_database.datdba),
> which means that subsequently he (or a superuser) can grant or deny
> USAGE within his DB.
>
> * if pg_pltemplate.something is OFF: must be superuser to CREATE the
> language; subsequently it will be owned by you, so only you or another
> superuser can grant or deny USAGE (same behavior as currently).

The only difference from this is, that when superuser is required, the
owner of the language is not the superuser who created it, but
BOOTSTRAP_SUPERUSERID.  This is because my interpretation was that the
"same behavior as currently" took precedence.  The current behavior in cvs
is that languages have no owner, and for purposes where one would be
needed it is assumed to be BOOTSTRAP_SUPERUSERID.

Is this valid, or should I instead set the owner to GetUserId() in those
cases?


-- 
Academic politics is the most vicious and bitter form of politics,
because the stakes are so low.
                -- Wallace Sayre
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: 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 00:20:19 -0000
***************
*** 17,22 ****
--- 17,24 ----
  #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"
***************
*** 27,32 ****
--- 29,35 ----
  #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);
  
  
  /* ---------------------------------------------------------------------
--- 39,57 ----
  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
         */
--- 69,74 ----
***************
*** 97,102 ****
--- 97,124 ----
                                        (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
--- 193,199 ----
                        valOid = InvalidOid;
  
                /* ok, create it */
!               create_proc_lang(languageName, 
find_desired_language_owner(pltemplate), handlerOid, valOid,
                                                 pltemplate->tmpltrusted);
        }
        else
***************
*** 189,194 ****
--- 211,224 ----
                                         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);
        }
  }
  
--- 257,263 ----
                        valOid = InvalidOid;
  
                /* ok, create it */
!               create_proc_lang(languageName, BOOTSTRAP_SUPERUSERID, 
handlerOid, valOid, stmt->pltrusted);
        }
  }
  
***************
*** 236,242 ****
   */
  static void
  create_proc_lang(const char *languageName,
!                                Oid handlerOid, Oid valOid, bool trusted)
  {
        Relation        rel;
        TupleDesc       tupDesc;
--- 266,272 ----
   */
  static void
  create_proc_lang(const char *languageName,
!                                Oid languageOwner, Oid handlerOid, Oid valOid, 
bool trusted)
  {
        Relation        rel;
        TupleDesc       tupDesc;
***************
*** 258,263 ****
--- 288,294 ----
  
        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 ****
--- 308,319 ----
        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 ****
--- 332,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
+       {
+               /* current behaviour */
+               return BOOTSTRAP_SUPERUSERID;
+       }
+ }
+ 
  /*
   * 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);
---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

Reply via email to