Commit a833c441 authored by Tom Lane's avatar Tom Lane

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.
parent f66f7a54
<!-- <!--
$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 ...@@ -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> ...@@ -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> ...@@ -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 ...@@ -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>
......
<!-- <!--
$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. ...@@ -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>
......
...@@ -9,7 +9,7 @@ ...@@ -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 @@ ...@@ -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); ...@@ -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, ...@@ -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, ...@@ -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);
......
...@@ -15,7 +15,7 @@ ...@@ -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) ...@@ -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)
......
...@@ -20,7 +20,7 @@ ...@@ -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) ...@@ -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))
......
...@@ -11,7 +11,7 @@ ...@@ -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); ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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 ...@@ -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; }
;
/***************************************************************************** /*****************************************************************************
* *
......
...@@ -10,7 +10,7 @@ ...@@ -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, ...@@ -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;
......
...@@ -7,15 +7,16 @@ ...@@ -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 */
...@@ -7,7 +7,7 @@ ...@@ -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 ...@@ -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) */
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment