Re: [HACKERS] Inconsistent syntax in GRANT - Mailing list pgsql-patches

From Bruce Momjian
Subject Re: [HACKERS] Inconsistent syntax in GRANT
Date
Msg-id 200601062038.k06Kc0Q09011@candle.pha.pa.us
Whole thread Raw
In response to Re: [HACKERS] Inconsistent syntax in GRANT  (Bruce Momjian <pgman@candle.pha.pa.us>)
List pgsql-patches
Bruce Momjian wrote:
> > I'm not sure offhand what keywords we'd want to use, but now is the time
> > to look at it, *before* it becomes set in stone that GRANT ON SEQUENCE
> > is just another spelling of GRANT ON TABLE.
>
> Sequences do not support INSERT, UPDATE, or DELETE, but we overload
> UPDATE to control nextval()/setval(), so I just allowed SELECT and
> UPDATE.  I am not sure it makes any sense to allow rules, references,
> and triggers on sequences.  However, using ALL or TABLE keywords you can
> define those permissions to a sequence.

Here is an updated patch.  The standard doesn't have GRANT VIEW so I
didn't implement that.

One tricky issue I realized is that we should dump out GRANT SEQUENCE,
if possible.  I have added code to check in pg_dump and use GRANT
SEQUENCE if only SELECT, UPDATE, or ALL are used.

--
  Bruce Momjian                        |  http://candle.pha.pa.us
  pgman@candle.pha.pa.us               |  (610) 359-1001
  +  If your life is a hard drive,     |  13 Roberts Road
  +  Christ can be your backup.        |  Newtown Square, Pennsylvania 19073
Index: doc/src/sgml/ref/grant.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/grant.sgml,v
retrieving revision 1.50
diff -c -c -r1.50 grant.sgml
*** doc/src/sgml/ref/grant.sgml    20 Oct 2005 19:18:01 -0000    1.50
--- doc/src/sgml/ref/grant.sgml    6 Jan 2006 20:33:45 -0000
***************
*** 25,30 ****
--- 25,35 ----
      ON [ TABLE ] <replaceable class="PARAMETER">tablename</replaceable> [, ...]
      TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] [ WITH GRANT OPTION ] 

+ GRANT { { SELECT | UPDATE }
+     [,...] | ALL [ PRIVILEGES ] }
+     ON SEQUENCE <replaceable class="PARAMETER">tablename</replaceable> [, ...]
+     TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] [ WITH GRANT OPTION ] 
+
  GRANT { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
      ON DATABASE <replaceable>dbname</replaceable> [, ...]
      TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] [ WITH GRANT OPTION ] 
***************
*** 511,517 ****

     <para>
      The <literal>RULE</literal> privilege, and privileges on
!     databases, tablespaces, schemas, languages, and sequences are
      <productname>PostgreSQL</productname> extensions.
     </para>
   </refsect1>
--- 516,522 ----

     <para>
      The <literal>RULE</literal> privilege, and privileges on
!     databases, tablespaces, schemas, and languages are
      <productname>PostgreSQL</productname> extensions.
     </para>
   </refsect1>
Index: doc/src/sgml/ref/revoke.sgml
===================================================================
RCS file: /cvsroot/pgsql/doc/src/sgml/ref/revoke.sgml,v
retrieving revision 1.35
diff -c -c -r1.35 revoke.sgml
*** doc/src/sgml/ref/revoke.sgml    20 Oct 2005 19:18:01 -0000    1.35
--- doc/src/sgml/ref/revoke.sgml    6 Jan 2006 20:33:46 -0000
***************
*** 28,33 ****
--- 28,40 ----
      [ CASCADE | RESTRICT ]

  REVOKE [ GRANT OPTION FOR ]
+     { { SELECT | UPDATE }
+     [,...] | ALL [ PRIVILEGES ] }
+     ON SEQUENCE <replaceable class="PARAMETER">tablename</replaceable> [, ...]
+     FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] 
+     [ CASCADE | RESTRICT ]
+
+ REVOKE [ GRANT OPTION FOR ]
      { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
      ON DATABASE <replaceable>dbname</replaceable> [, ...]
      FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable
class="PARAMETER">groupname</replaceable>| PUBLIC } [, ...] 
Index: src/backend/catalog/aclchk.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v
retrieving revision 1.123
diff -c -c -r1.123 aclchk.c
*** src/backend/catalog/aclchk.c    1 Dec 2005 02:03:00 -0000    1.123
--- src/backend/catalog/aclchk.c    6 Jan 2006 20:33:46 -0000
***************
*** 283,288 ****
--- 283,289 ----
      switch (stmt->objtype)
      {
          case ACL_OBJECT_RELATION:
+         case ACL_OBJECT_SEQUENCE:
              all_privileges = ACL_ALL_RIGHTS_RELATION;
              errormsg = _("invalid privilege type %s for table");
              break;
***************
*** 356,361 ****
--- 357,363 ----
      switch (istmt->objtype)
      {
          case ACL_OBJECT_RELATION:
+         case ACL_OBJECT_SEQUENCE:
              ExecGrant_Relation(istmt);
              break;
          case ACL_OBJECT_DATABASE:
***************
*** 395,400 ****
--- 397,403 ----
      switch (objtype)
      {
          case ACL_OBJECT_RELATION:
+         case ACL_OBJECT_SEQUENCE:
              foreach(cell, objnames)
              {
                  Oid            relOid;
***************
*** 577,582 ****
--- 580,599 ----
                       errmsg("\"%s\" is a composite type",
                              NameStr(pg_class_tuple->relname))));

+         if (istmt->objtype == ACL_OBJECT_SEQUENCE)
+         {
+             if (pg_class_tuple->relkind != RELKIND_SEQUENCE)
+                 ereport(ERROR,
+                         (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                          errmsg("\"%s\" is not a sequence",
+                                 NameStr(pg_class_tuple->relname))));
+             if (istmt->privileges != ACL_ALL_RIGHTS_RELATION &&
+                 istmt->privileges & ~(ACL_SELECT | ACL_UPDATE))
+                 ereport(ERROR,
+                         (errcode(ERRCODE_INVALID_GRANT_OPERATION),
+                          errmsg("sequences only support SELECT and UPDATE privileges")));
+         }
+
          /*
           * Get owner ID and working copy of existing ACL. If there's no ACL,
           * substitute the proper default.
Index: src/backend/catalog/pg_shdepend.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/catalog/pg_shdepend.c,v
retrieving revision 1.6
diff -c -c -r1.6 pg_shdepend.c
*** src/backend/catalog/pg_shdepend.c    1 Dec 2005 02:03:00 -0000    1.6
--- src/backend/catalog/pg_shdepend.c    6 Jan 2006 20:33:47 -0000
***************
*** 1133,1138 ****
--- 1133,1139 ----
                      switch (sdepForm->classid)
                      {
                          case RelationRelationId:
+                             /* could be a sequence */
                              istmt.objtype = ACL_OBJECT_RELATION;
                              break;
                          case DatabaseRelationId:
Index: src/backend/parser/gram.y
===================================================================
RCS file: /cvsroot/pgsql/src/backend/parser/gram.y,v
retrieving revision 2.521
diff -c -c -r2.521 gram.y
*** src/backend/parser/gram.y    29 Dec 2005 04:53:18 -0000    2.521
--- src/backend/parser/gram.y    6 Jan 2006 20:33:49 -0000
***************
*** 3322,3327 ****
--- 3322,3334 ----
                      n->objs = $2;
                      $$ = n;
                  }
+             | SEQUENCE qualified_name_list
+                 {
+                     PrivTarget *n = makeNode(PrivTarget);
+                     n->objtype = ACL_OBJECT_SEQUENCE;
+                     n->objs = $2;
+                     $$ = n;
+                 }
              | FUNCTION function_with_argtypes_list
                  {
                      PrivTarget *n = makeNode(PrivTarget);
Index: src/backend/utils/adt/acl.c
===================================================================
RCS file: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v
retrieving revision 1.129
diff -c -c -r1.129 acl.c
*** src/backend/utils/adt/acl.c    18 Nov 2005 02:38:23 -0000    1.129
--- src/backend/utils/adt/acl.c    6 Jan 2006 20:33:50 -0000
***************
*** 542,547 ****
--- 542,548 ----
      switch (objtype)
      {
          case ACL_OBJECT_RELATION:
+         case ACL_OBJECT_SEQUENCE:
              world_default = ACL_NO_RIGHTS;
              owner_default = ACL_ALL_RIGHTS_RELATION;
              break;
Index: src/bin/pg_dump/dumputils.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_dump/dumputils.c,v
retrieving revision 1.23
diff -c -c -r1.23 dumputils.c
*** src/bin/pg_dump/dumputils.c    3 Dec 2005 21:06:18 -0000    1.23
--- src/bin/pg_dump/dumputils.c    6 Jan 2006 20:33:51 -0000
***************
*** 395,404 ****
--- 395,420 ----
      /* Scan individual ACL items */
      for (i = 0; i < naclitems; i++)
      {
+         const char *outType = type;
+
          if (!parseAclItem(aclitems[i], type, name, remoteVersion,
                            grantee, grantor, privs, privswgo))
              return false;

+         /*
+          *    For backward compatibility, non-SEQUENCE GRANT statements can
+          *    assign non-SELECT, non-UPDATE permissions.  We allow those
+          *    to be dumped by changing SEQUENCE to TABLE.
+          */
+         if (strcmp(outType, "SEQUENCE") == 0)
+         {
+             if (strcmp(privs->data, "SELECT") != 0 &&
+                 strcmp(privs->data, "UPDATE") != 0 &&
+                 strcmp(privs->data, "SELECT,UPDATE") != 0 &&
+                 strcmp(privs->data, "ALL") != 0)
+             outType = "TABLE";
+         }
+
          if (grantor->len == 0 && owner)
              printfPQExpBuffer(grantor, "%s", owner);

***************
*** 419,433 ****
                      : strcmp(privs->data, "ALL") != 0)
                  {
                      appendPQExpBuffer(firstsql, "REVOKE ALL ON %s %s FROM %s;\n",
!                                       type, name,
                                        fmtId(grantee->data));
                      if (privs->len > 0)
                          appendPQExpBuffer(firstsql, "GRANT %s ON %s %s TO %s;\n",
!                                           privs->data, type, name,
                                            fmtId(grantee->data));
                      if (privswgo->len > 0)
                          appendPQExpBuffer(firstsql, "GRANT %s ON %s %s TO %s WITH GRANT OPTION;\n",
!                                           privswgo->data, type, name,
                                            fmtId(grantee->data));
                  }
              }
--- 435,449 ----
                      : strcmp(privs->data, "ALL") != 0)
                  {
                      appendPQExpBuffer(firstsql, "REVOKE ALL ON %s %s FROM %s;\n",
!                                       outType, name,
                                        fmtId(grantee->data));
                      if (privs->len > 0)
                          appendPQExpBuffer(firstsql, "GRANT %s ON %s %s TO %s;\n",
!                                           privs->data, outType, name,
                                            fmtId(grantee->data));
                      if (privswgo->len > 0)
                          appendPQExpBuffer(firstsql, "GRANT %s ON %s %s TO %s WITH GRANT OPTION;\n",
!                                           privswgo->data, outType, name,
                                            fmtId(grantee->data));
                  }
              }
***************
*** 444,450 ****
                  if (privs->len > 0)
                  {
                      appendPQExpBuffer(secondsql, "GRANT %s ON %s %s TO ",
!                                       privs->data, type, name);
                      if (grantee->len == 0)
                          appendPQExpBuffer(secondsql, "PUBLIC;\n");
                      else if (strncmp(grantee->data, "group ",
--- 460,466 ----
                  if (privs->len > 0)
                  {
                      appendPQExpBuffer(secondsql, "GRANT %s ON %s %s TO ",
!                                       privs->data, outType, name);
                      if (grantee->len == 0)
                          appendPQExpBuffer(secondsql, "PUBLIC;\n");
                      else if (strncmp(grantee->data, "group ",
***************
*** 457,463 ****
                  if (privswgo->len > 0)
                  {
                      appendPQExpBuffer(secondsql, "GRANT %s ON %s %s TO ",
!                                       privswgo->data, type, name);
                      if (grantee->len == 0)
                          appendPQExpBuffer(secondsql, "PUBLIC");
                      else if (strncmp(grantee->data, "group ",
--- 473,479 ----
                  if (privswgo->len > 0)
                  {
                      appendPQExpBuffer(secondsql, "GRANT %s ON %s %s TO ",
!                                       privswgo->data, outType, name);
                      if (grantee->len == 0)
                          appendPQExpBuffer(secondsql, "PUBLIC");
                      else if (strncmp(grantee->data, "group ",
***************
*** 480,489 ****
       * If we didn't find any owner privs, the owner must have revoked 'em all
       */
      if (!found_owner_privs && owner)
-     {
          appendPQExpBuffer(firstsql, "REVOKE ALL ON %s %s FROM %s;\n",
                            type, name, fmtId(owner));
-     }

      destroyPQExpBuffer(grantee);
      destroyPQExpBuffer(grantor);
--- 496,503 ----
***************
*** 568,574 ****
      resetPQExpBuffer(privs);
      resetPQExpBuffer(privswgo);

!     if (strcmp(type, "TABLE") == 0)
      {
          CONVERT_PRIV('a', "INSERT");
          CONVERT_PRIV('r', "SELECT");
--- 582,588 ----
      resetPQExpBuffer(privs);
      resetPQExpBuffer(privswgo);

!     if (strcmp(type, "TABLE") == 0 || strcmp(type, "SEQUENCE") == 0)
      {
          CONVERT_PRIV('a', "INSERT");
          CONVERT_PRIV('r', "SELECT");
Index: src/bin/pg_dump/pg_dump.c
===================================================================
RCS file: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v
retrieving revision 1.425
diff -c -c -r1.425 pg_dump.c
*** src/bin/pg_dump/pg_dump.c    6 Jan 2006 19:08:33 -0000    1.425
--- src/bin/pg_dump/pg_dump.c    6 Jan 2006 20:33:56 -0000
***************
*** 6776,6782 ****

          /* Handle the ACL here */
          namecopy = strdup(fmtId(tbinfo->dobj.name));
!         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE",
                  namecopy, tbinfo->dobj.name,
                  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
                  tbinfo->relacl);
--- 6776,6784 ----

          /* Handle the ACL here */
          namecopy = strdup(fmtId(tbinfo->dobj.name));
!         dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
!                 /* Issue GRANT SEQUENCE, if applicable */
!                 tbinfo->relkind != RELKIND_SEQUENCE ? "TABLE" : "SEQUENCE",
                  namecopy, tbinfo->dobj.name,
                  tbinfo->dobj.namespace->dobj.name, tbinfo->rolname,
                  tbinfo->relacl);
Index: src/include/nodes/parsenodes.h
===================================================================
RCS file: /cvsroot/pgsql/src/include/nodes/parsenodes.h,v
retrieving revision 1.298
diff -c -c -r1.298 parsenodes.h
*** src/include/nodes/parsenodes.h    7 Dec 2005 15:20:55 -0000    1.298
--- src/include/nodes/parsenodes.h    6 Jan 2006 20:33:56 -0000
***************
*** 884,890 ****
   */
  typedef enum GrantObjectType
  {
!     ACL_OBJECT_RELATION,        /* table, view, sequence */
      ACL_OBJECT_DATABASE,        /* database */
      ACL_OBJECT_FUNCTION,        /* function */
      ACL_OBJECT_LANGUAGE,        /* procedural language */
--- 884,891 ----
   */
  typedef enum GrantObjectType
  {
!     ACL_OBJECT_RELATION,        /* table, view */
!     ACL_OBJECT_SEQUENCE,        /* sequence */
      ACL_OBJECT_DATABASE,        /* database */
      ACL_OBJECT_FUNCTION,        /* function */
      ACL_OBJECT_LANGUAGE,        /* procedural language */

pgsql-patches by date:

Previous
From: Tom Lane
Date:
Subject: Re: [HACKERS] Inconsistent syntax in GRANT
Next
From: Bruce Momjian
Date:
Subject: Re: [HACKERS] Inconsistent syntax in GRANT