Add OWNER option to CREATE DATABASE, so superusers can create databases
authorTom Lane
Sun, 24 Feb 2002 20:20:21 +0000 (20:20 +0000)
committerTom Lane
Sun, 24 Feb 2002 20:20:21 +0000 (20:20 +0000)
on behalf of unprivileged users.  Also, make '=' optional in CREATE
DATABASE syntax.  From Gavin Sherry, with kibitzing and docs by Tom Lane.

doc/src/sgml/ref/create_database.sgml
doc/src/sgml/release.sgml
src/backend/commands/dbcommands.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/parser/gram.y
src/backend/tcop/utility.c
src/include/commands/dbcommands.h
src/include/nodes/parsenodes.h

index b208f100eace36917ffdaa8582c020e23be506fc..2c87d215914b1497833918ebb7e33f0f9098a189 100644 (file)
@@ -1,5 +1,5 @@
 
 
@@ -24,9 +24,10 @@ PostgreSQL documentation
   
   
 CREATE DATABASE name
-    [ WITH [ LOCATION = 'dbpath' ]
-           [ TEMPLATE = template ]
-           [ ENCODING = encoding ] ]
+    [ WITH [ OWNER [ = ] dbowner ]
+           [ LOCATION [ = ] 'dbpath' ]
+           [ TEMPLATE [ = ] template ]
+           [ ENCODING [ = ] encoding ] ]
   
 
   
@@ -47,6 +48,16 @@ CREATE DATABASE name
        
       
      
+     
+      dbowner
+      
+       
+        Name of the database user who will own the new database,
+   or DEFAULT to use the default (namely, the
+   user executing the command).
+       
+      
+     
      
       dbpath
       
@@ -171,7 +182,15 @@ CREATE DATABASE name
   
    CREATE DATABASE creates a new
    PostgreSQL database.
-   The creator becomes the owner of the new database.
+  
+
+  
+   Normally, the creator becomes the owner of the new database.
+   A different owner may be specified by using the 
+   clause (but only superusers may create databases on behalf of other users).
+   To create a database owned by oneself, either superuser privilege
+   or CREATEDB privilege is required.  A superuser may create a database
+   for another user, even if that user has no special privileges himself.
   
 
   
@@ -327,7 +346,8 @@ Type:  \copyright for distribution terms
    
    
     There is no CREATE DATABASE statement in SQL92.
-    Databases are equivalent to catalogs whose creation is implementation-defined.
+    Databases are equivalent to catalogs, whose creation is
+    implementation-defined.
    
   
  
index fae659919de4cb44caf780163ceb0a11522de99d..edcdc9405aa42fa5733b3044bb5538b36b7fa9a0 100644 (file)
@@ -1,5 +1,5 @@
 
 
 
@@ -26,6 +26,7 @@ worries about funny characters.
 
 Access privileges on functions
 Access privileges on procedural languages
+CREATE DATABASE has OWNER option so superuser can create DB for someone else
 Kerberos 5 support now works with Heimdal
 ]]>
 
index 142fefb60fb868636f272cc35776a1874ba39e7e..712df38ec51470e281feddbc60938f835452dad8 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.82 2002/02/23 20:55:46 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.83 2002/02/24 20:20:19 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,6 +34,7 @@
 #include "storage/sinval.h"
 #include "utils/builtins.h"
 #include "utils/fmgroids.h"
+#include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
 #ifdef MULTIBYTE
@@ -55,8 +56,9 @@ static bool remove_dbdirs(const char *real_loc, const char *altloc);
  */
 
 void
-createdb(const char *dbname, const char *dbpath,
-        const char *dbtemplate, int encoding)
+createdb(const char *dbname, const char *dbowner,
+        const char *dbpath, const char *dbtemplate,
+        int encoding)
 {
    char       *nominal_loc;
    char       *alt_loc;
@@ -79,12 +81,31 @@ createdb(const char *dbname, const char *dbpath,
    Datum       new_record[Natts_pg_database];
    char        new_record_nulls[Natts_pg_database];
    Oid         dboid;
+   int32       datdba;
 
+   /* obtain sysid of proposed owner */
+   if (dbowner)
+       datdba = get_usesysid(dbowner); /* will elog if no such user */
+   else
+       datdba = GetUserId();
+
+   /* check permission to create database */
    if (!get_user_info(GetUserId(), &use_super, &use_createdb))
        elog(ERROR, "current user name is invalid");
 
-   if (!use_createdb && !use_super)
-       elog(ERROR, "CREATE DATABASE: permission denied");
+   if (datdba == (int32) GetUserId())
+   {
+       /* creating database for self: can be superuser or createdb */
+       if (!use_createdb && !use_super)
+           elog(ERROR, "CREATE DATABASE: permission denied");
+   }
+   else
+   {
+       /* creating database for someone else: must be superuser */
+       /* note that the someone else need not have any permissions */
+       if (!use_super)
+           elog(ERROR, "CREATE DATABASE: permission denied");
+   }
 
    /* don't call this in a transaction block */
    if (IsTransactionBlock())
@@ -254,7 +275,7 @@ createdb(const char *dbname, const char *dbpath,
    /* Form tuple */
    new_record[Anum_pg_database_datname - 1] =
        DirectFunctionCall1(namein, CStringGetDatum(dbname));
-   new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(GetUserId());
+   new_record[Anum_pg_database_datdba - 1] = Int32GetDatum(datdba);
    new_record[Anum_pg_database_encoding - 1] = Int32GetDatum(encoding);
    new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
    new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);
index 153d257d26c7e76950421523a0bf5d32f0f030eb..03ceb08eba2c6aded68543c4f4f3fd10b7c9cbe1 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.161 2002/02/18 23:11:14 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.162 2002/02/24 20:20:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2231,6 +2231,8 @@ _copyCreatedbStmt(CreatedbStmt *from)
 
    if (from->dbname)
        newnode->dbname = pstrdup(from->dbname);
+   if (from->dbowner)
+       newnode->dbowner = pstrdup(from->dbowner);
    if (from->dbpath)
        newnode->dbpath = pstrdup(from->dbpath);
    if (from->dbtemplate)
index 886963f8808a666910f81fc5c5f37b2480e39866..2ea41d6e522600cf7cf7690fa05a1d3a72f3ef90 100644 (file)
@@ -20,7 +20,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.109 2002/02/18 23:11:14 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.110 2002/02/24 20:20:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1099,6 +1099,8 @@ _equalCreatedbStmt(CreatedbStmt *a, CreatedbStmt *b)
 {
    if (!equalstr(a->dbname, b->dbname))
        return false;
+   if (!equalstr(a->dbowner, b->dbowner))
+       return false;
    if (!equalstr(a->dbpath, b->dbpath))
        return false;
    if (!equalstr(a->dbtemplate, b->dbtemplate))
index a23273c1a7d8440d26c8ae16d3f67b88428cdc01..37d9364eae8154dfa663bf576d07d7e828a71794 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.278 2002/02/18 23:11:17 petere Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.279 2002/02/24 20:20:20 tgl Exp $
  *
  * HISTORY
  *   AUTHOR            DATE            MAJOR EVENT
@@ -153,6 +153,7 @@ static void doNegateFloat(Value *v);
 %type     drop_behavior
 
 %type    createdb_opt_list, createdb_opt_item
+%type     opt_equal
 
 %type    opt_lock, lock_type
 %type     opt_force, opt_or_replace
@@ -733,6 +734,7 @@ CreateSchemaStmt:  CREATE SCHEMA UserId
                    /* for now, just make this the same as CREATE DATABASE */
                    CreatedbStmt *n = makeNode(CreatedbStmt);
                    n->dbname = $3;
+                   n->dbowner = NULL;
                    n->dbpath = NULL;
                    n->dbtemplate = NULL;
                    n->encoding = -1;
@@ -3049,6 +3051,7 @@ CreatedbStmt:  CREATE DATABASE database_name WITH createdb_opt_list
 
                    n->dbname = $3;
                    /* set default options */
+                   n->dbowner = NULL;
                    n->dbpath = NULL;
                    n->dbtemplate = NULL;
                    n->encoding = -1;
@@ -3068,6 +3071,9 @@ CreatedbStmt:  CREATE DATABASE database_name WITH createdb_opt_list
                            case 3:
                                n->encoding = lfirsti(lnext(optitem));
                                break;
+                           case 4:
+                               n->dbowner = (char *) lsecond(optitem);
+                               break;
                        }
                    }
                    $$ = (Node *)n;
@@ -3076,6 +3082,7 @@ CreatedbStmt:  CREATE DATABASE database_name WITH createdb_opt_list
                {
                    CreatedbStmt *n = makeNode(CreatedbStmt);
                    n->dbname = $3;
+                   n->dbowner = NULL;
                    n->dbpath = NULL;
                    n->dbtemplate = NULL;
                    n->encoding = -1;
@@ -3093,23 +3100,23 @@ createdb_opt_list:  createdb_opt_item
  * createdb_opt_item returns 2-element lists, with the first element
  * being an integer code to indicate which item was specified.
  */
-createdb_opt_item:  LOCATION '=' Sconst
+createdb_opt_item:  LOCATION opt_equal Sconst
                {
                    $$ = lconsi(1, makeList1($3));
                }
-       | LOCATION '=' DEFAULT
+       | LOCATION opt_equal DEFAULT
                {
                    $$ = lconsi(1, makeList1(NULL));
                }
-       | TEMPLATE '=' name
+       | TEMPLATE opt_equal name
                {
                    $$ = lconsi(2, makeList1($3));
                }
-       | TEMPLATE '=' DEFAULT
+       | TEMPLATE opt_equal DEFAULT
                {
                    $$ = lconsi(2, makeList1(NULL));
                }
-       | ENCODING '=' Sconst
+       | ENCODING opt_equal Sconst
                {
                    int     encoding;
 #ifdef MULTIBYTE
@@ -3123,7 +3130,7 @@ createdb_opt_item:  LOCATION '=' Sconst
 #endif
                    $$ = lconsi(3, makeListi1(encoding));
                }
-       | ENCODING '=' Iconst
+       | ENCODING opt_equal Iconst
                {
 #ifdef MULTIBYTE
                    if (!pg_get_enconv_by_encoding($3))
@@ -3134,12 +3141,23 @@ createdb_opt_item:  LOCATION '=' Sconst
 #endif
                    $$ = lconsi(3, makeListi1($3));
                }
-       | ENCODING '=' DEFAULT
+       | ENCODING opt_equal DEFAULT
                {
                    $$ = lconsi(3, makeListi1(-1));
                }
+       | OWNER opt_equal name 
+               {
+                   $$ = lconsi(4, makeList1($3));
+               }
+       | OWNER opt_equal DEFAULT
+               {
+                   $$ = lconsi(4, makeList1(NULL));
+               }
        ;
 
+opt_equal: '='                             { $$ = TRUE; }
+       | /*EMPTY*/                         { $$ = FALSE; }
+       ;
 
 /*****************************************************************************
  *
index 766512ae59c96882a78c6dff62df6587fc7aa194..f80a6bdca44f75357e94f5be72a8ffb13c7efaa0 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.125 2002/02/07 00:27:30 inoue Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.126 2002/02/24 20:20:20 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -624,8 +624,9 @@ ProcessUtility(Node *parsetree,
 
                set_ps_display(commandTag = "CREATE DATABASE");
 
-               createdb(stmt->dbname, stmt->dbpath,
-                        stmt->dbtemplate, stmt->encoding);
+               createdb(stmt->dbname, stmt->dbowner,
+                        stmt->dbpath, stmt->dbtemplate,
+                        stmt->encoding);
            }
            break;
 
index 23c68d3c35054f29e56be90d1ae0a54dc3a8ca95..0636130c2e1c7fed6a4acf712910120a9c1ef4ba 100644 (file)
@@ -7,15 +7,16 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: dbcommands.h,v 1.19 2001/11/05 17:46:33 momjian Exp $
+ * $Id: dbcommands.h,v 1.20 2002/02/24 20:20:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef DBCOMMANDS_H
 #define DBCOMMANDS_H
 
-extern void createdb(const char *dbname, const char *dbpath,
-        const char *dbtemplate, int encoding);
+extern void createdb(const char *dbname, const char *dbowner,
+                    const char *dbpath, const char *dbtemplate,
+                    int encoding);
 extern void dropdb(const char *dbname);
 
 #endif   /* DBCOMMANDS_H */
index 252c509cc4620fc4e2efd8b2c2b355389ad36bdc..0b40fe99480f66f1a2ca1b8a8a53783855d01988 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.152 2002/02/18 23:11:41 petere Exp $
+ * $Id: parsenodes.h,v 1.153 2002/02/24 20:20:21 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -679,6 +679,7 @@ typedef struct CreatedbStmt
 {
    NodeTag     type;
    char       *dbname;         /* name of database to create */
+   char       *dbowner;        /* name of owner (NULL = default) */
    char       *dbpath;         /* location of database (NULL = default) */
    char       *dbtemplate;     /* template to use (NULL = default) */
    int         encoding;       /* MULTIBYTE encoding (-1 = use default) */