Add OWNER option to CREATE DATABASE, so superusers can create databases

on behalf of unprivileged users.  Also, make '=' optional in CREATE
DATABASE syntax.  From Gavin Sherry, with kibitzing and docs by Tom Lane.
This commit is contained in:
Tom Lane 2002-02-24 20:20:21 +00:00
parent f66f7a542f
commit a833c441fd
9 changed files with 97 additions and 30 deletions

View File

@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_database.sgml,v 1.23 2002/01/20 22:19:56 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_database.sgml,v 1.24 2002/02/24 20:20:18 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -24,9 +24,10 @@ PostgreSQL documentation
</refsynopsisdivinfo> </refsynopsisdivinfo>
<synopsis> <synopsis>
CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
[ WITH [ LOCATION = '<replaceable class="parameter">dbpath</replaceable>' ] [ WITH [ OWNER [ = ] <replaceable class="parameter">dbowner</replaceable> ]
[ TEMPLATE = <replaceable class="parameter">template</replaceable> ] [ LOCATION [ = ] '<replaceable class="parameter">dbpath</replaceable>' ]
[ ENCODING = <replaceable class="parameter">encoding</replaceable> ] ] [ TEMPLATE [ = ] <replaceable class="parameter">template</replaceable> ]
[ ENCODING [ = ] <replaceable class="parameter">encoding</replaceable> ] ]
</synopsis> </synopsis>
<refsect2 id="R2-SQL-CREATEDATABASE-1"> <refsect2 id="R2-SQL-CREATEDATABASE-1">
@ -47,6 +48,16 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><replaceable class="parameter">dbowner</replaceable></term>
<listitem>
<para>
Name of the database user who will own the new database,
or <literal>DEFAULT</literal> to use the default (namely, the
user executing the command).
</para>
</listitem>
</varlistentry>
<varlistentry> <varlistentry>
<term><replaceable class="parameter">dbpath</replaceable></term> <term><replaceable class="parameter">dbpath</replaceable></term>
<listitem> <listitem>
@ -171,7 +182,15 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
<para> <para>
<command>CREATE DATABASE</command> creates a new <command>CREATE DATABASE</command> creates a new
<productname>PostgreSQL</productname> database. <productname>PostgreSQL</productname> database.
The creator becomes the owner of the new database. </para>
<para>
Normally, the creator becomes the owner of the new database.
A different owner may be specified by using the <option>OWNER</>
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.
</para> </para>
<para> <para>
@ -327,7 +346,8 @@ Type: \copyright for distribution terms
</title> </title>
<para> <para>
There is no <command>CREATE DATABASE</command> statement in SQL92. There is no <command>CREATE DATABASE</command> statement in SQL92.
Databases are equivalent to catalogs whose creation is implementation-defined. Databases are equivalent to catalogs, whose creation is
implementation-defined.
</para> </para>
</refsect2> </refsect2>
</refsect1> </refsect1>

View File

@ -1,5 +1,5 @@
<!-- <!--
$Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.117 2002/02/23 04:17:45 petere Exp $ $Header: /cvsroot/pgsql/doc/src/sgml/release.sgml,v 1.118 2002/02/24 20:20:19 tgl Exp $
--> -->
<appendix id="release"> <appendix id="release">
@ -26,6 +26,7 @@ worries about funny characters.
<literallayout><![CDATA[ <literallayout><![CDATA[
Access privileges on functions Access privileges on functions
Access privileges on procedural languages 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 Kerberos 5 support now works with Heimdal
]]></literallayout> ]]></literallayout>

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 "storage/sinval.h"
#include "utils/builtins.h" #include "utils/builtins.h"
#include "utils/fmgroids.h" #include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#ifdef MULTIBYTE #ifdef MULTIBYTE
@ -55,8 +56,9 @@ static bool remove_dbdirs(const char *real_loc, const char *altloc);
*/ */
void void
createdb(const char *dbname, const char *dbpath, createdb(const char *dbname, const char *dbowner,
const char *dbtemplate, int encoding) const char *dbpath, const char *dbtemplate,
int encoding)
{ {
char *nominal_loc; char *nominal_loc;
char *alt_loc; char *alt_loc;
@ -79,12 +81,31 @@ createdb(const char *dbname, const char *dbpath,
Datum new_record[Natts_pg_database]; Datum new_record[Natts_pg_database];
char new_record_nulls[Natts_pg_database]; char new_record_nulls[Natts_pg_database];
Oid dboid; 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)) if (!get_user_info(GetUserId(), &use_super, &use_createdb))
elog(ERROR, "current user name is invalid"); elog(ERROR, "current user name is invalid");
if (!use_createdb && !use_super) if (datdba == (int32) GetUserId())
elog(ERROR, "CREATE DATABASE: permission denied"); {
/* 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 */ /* don't call this in a transaction block */
if (IsTransactionBlock()) if (IsTransactionBlock())
@ -254,7 +275,7 @@ createdb(const char *dbname, const char *dbpath,
/* Form tuple */ /* Form tuple */
new_record[Anum_pg_database_datname - 1] = new_record[Anum_pg_database_datname - 1] =
DirectFunctionCall1(namein, CStringGetDatum(dbname)); 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_encoding - 1] = Int32GetDatum(encoding);
new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false); new_record[Anum_pg_database_datistemplate - 1] = BoolGetDatum(false);
new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true); new_record[Anum_pg_database_datallowconn - 1] = BoolGetDatum(true);

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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) if (from->dbname)
newnode->dbname = pstrdup(from->dbname); newnode->dbname = pstrdup(from->dbname);
if (from->dbowner)
newnode->dbowner = pstrdup(from->dbowner);
if (from->dbpath) if (from->dbpath)
newnode->dbpath = pstrdup(from->dbpath); newnode->dbpath = pstrdup(from->dbpath);
if (from->dbtemplate) if (from->dbtemplate)

View File

@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * 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)) if (!equalstr(a->dbname, b->dbname))
return false; return false;
if (!equalstr(a->dbowner, b->dbowner))
return false;
if (!equalstr(a->dbpath, b->dbpath)) if (!equalstr(a->dbpath, b->dbpath))
return false; return false;
if (!equalstr(a->dbtemplate, b->dbtemplate)) if (!equalstr(a->dbtemplate, b->dbtemplate))

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -153,6 +153,7 @@ static void doNegateFloat(Value *v);
%type <ival> drop_behavior %type <ival> drop_behavior
%type <list> createdb_opt_list, createdb_opt_item %type <list> createdb_opt_list, createdb_opt_item
%type <boolean> opt_equal
%type <ival> opt_lock, lock_type %type <ival> opt_lock, lock_type
%type <boolean> opt_force, opt_or_replace %type <boolean> opt_force, opt_or_replace
@ -733,6 +734,7 @@ CreateSchemaStmt: CREATE SCHEMA UserId
/* for now, just make this the same as CREATE DATABASE */ /* for now, just make this the same as CREATE DATABASE */
CreatedbStmt *n = makeNode(CreatedbStmt); CreatedbStmt *n = makeNode(CreatedbStmt);
n->dbname = $3; n->dbname = $3;
n->dbowner = NULL;
n->dbpath = NULL; n->dbpath = NULL;
n->dbtemplate = NULL; n->dbtemplate = NULL;
n->encoding = -1; n->encoding = -1;
@ -3049,6 +3051,7 @@ CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_list
n->dbname = $3; n->dbname = $3;
/* set default options */ /* set default options */
n->dbowner = NULL;
n->dbpath = NULL; n->dbpath = NULL;
n->dbtemplate = NULL; n->dbtemplate = NULL;
n->encoding = -1; n->encoding = -1;
@ -3068,6 +3071,9 @@ CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_list
case 3: case 3:
n->encoding = lfirsti(lnext(optitem)); n->encoding = lfirsti(lnext(optitem));
break; break;
case 4:
n->dbowner = (char *) lsecond(optitem);
break;
} }
} }
$$ = (Node *)n; $$ = (Node *)n;
@ -3076,6 +3082,7 @@ CreatedbStmt: CREATE DATABASE database_name WITH createdb_opt_list
{ {
CreatedbStmt *n = makeNode(CreatedbStmt); CreatedbStmt *n = makeNode(CreatedbStmt);
n->dbname = $3; n->dbname = $3;
n->dbowner = NULL;
n->dbpath = NULL; n->dbpath = NULL;
n->dbtemplate = NULL; n->dbtemplate = NULL;
n->encoding = -1; n->encoding = -1;
@ -3093,23 +3100,23 @@ createdb_opt_list: createdb_opt_item
* createdb_opt_item returns 2-element lists, with the first element * createdb_opt_item returns 2-element lists, with the first element
* being an integer code to indicate which item was specified. * 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)); $$ = lconsi(1, makeList1($3));
} }
| LOCATION '=' DEFAULT | LOCATION opt_equal DEFAULT
{ {
$$ = lconsi(1, makeList1(NULL)); $$ = lconsi(1, makeList1(NULL));
} }
| TEMPLATE '=' name | TEMPLATE opt_equal name
{ {
$$ = lconsi(2, makeList1($3)); $$ = lconsi(2, makeList1($3));
} }
| TEMPLATE '=' DEFAULT | TEMPLATE opt_equal DEFAULT
{ {
$$ = lconsi(2, makeList1(NULL)); $$ = lconsi(2, makeList1(NULL));
} }
| ENCODING '=' Sconst | ENCODING opt_equal Sconst
{ {
int encoding; int encoding;
#ifdef MULTIBYTE #ifdef MULTIBYTE
@ -3123,7 +3130,7 @@ createdb_opt_item: LOCATION '=' Sconst
#endif #endif
$$ = lconsi(3, makeListi1(encoding)); $$ = lconsi(3, makeListi1(encoding));
} }
| ENCODING '=' Iconst | ENCODING opt_equal Iconst
{ {
#ifdef MULTIBYTE #ifdef MULTIBYTE
if (!pg_get_enconv_by_encoding($3)) if (!pg_get_enconv_by_encoding($3))
@ -3134,12 +3141,23 @@ createdb_opt_item: LOCATION '=' Sconst
#endif #endif
$$ = lconsi(3, makeListi1($3)); $$ = lconsi(3, makeListi1($3));
} }
| ENCODING '=' DEFAULT | ENCODING opt_equal DEFAULT
{ {
$$ = lconsi(3, makeListi1(-1)); $$ = 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; }
;
/***************************************************************************** /*****************************************************************************
* *

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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"); set_ps_display(commandTag = "CREATE DATABASE");
createdb(stmt->dbname, stmt->dbpath, createdb(stmt->dbname, stmt->dbowner,
stmt->dbtemplate, stmt->encoding); stmt->dbpath, stmt->dbtemplate,
stmt->encoding);
} }
break; break;

View File

@ -7,15 +7,16 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 #ifndef DBCOMMANDS_H
#define DBCOMMANDS_H #define DBCOMMANDS_H
extern void createdb(const char *dbname, const char *dbpath, extern void createdb(const char *dbname, const char *dbowner,
const char *dbtemplate, int encoding); const char *dbpath, const char *dbtemplate,
int encoding);
extern void dropdb(const char *dbname); extern void dropdb(const char *dbname);
#endif /* DBCOMMANDS_H */ #endif /* DBCOMMANDS_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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; NodeTag type;
char *dbname; /* name of database to create */ char *dbname; /* name of database to create */
char *dbowner; /* name of owner (NULL = default) */
char *dbpath; /* location of database (NULL = default) */ char *dbpath; /* location of database (NULL = default) */
char *dbtemplate; /* template to use (NULL = default) */ char *dbtemplate; /* template to use (NULL = default) */
int encoding; /* MULTIBYTE encoding (-1 = use default) */ int encoding; /* MULTIBYTE encoding (-1 = use default) */