aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/Makefile10
-rw-r--r--doc/src/sgml/ref/allfiles.sgml5
-rw-r--r--doc/src/sgml/ref/alter_group.sgml162
-rw-r--r--doc/src/sgml/ref/alter_user.sgml111
-rw-r--r--doc/src/sgml/ref/commands.sgml5
-rw-r--r--doc/src/sgml/ref/create_group.sgml176
-rw-r--r--doc/src/sgml/ref/create_user.sgml137
-rw-r--r--doc/src/sgml/ref/drop_group.sgml138
-rw-r--r--doc/src/sgml/ref/drop_user.sgml65
-rw-r--r--src/backend/commands/copy.c21
-rw-r--r--src/backend/commands/user.c935
-rw-r--r--src/backend/parser/gram.y94
-rw-r--r--src/backend/tcop/utility.c20
-rw-r--r--src/backend/utils/misc/superuser.c7
-rw-r--r--src/bin/scripts/createuser4
-rw-r--r--src/include/commands/copy.h4
-rw-r--r--src/include/commands/user.h14
-rw-r--r--src/include/nodes/parsenodes.h20
18 files changed, 1150 insertions, 778 deletions
diff --git a/doc/src/sgml/Makefile b/doc/src/sgml/Makefile
index 59e8431a666..864d4621c24 100644
--- a/doc/src/sgml/Makefile
+++ b/doc/src/sgml/Makefile
@@ -8,7 +8,7 @@
#
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/doc/src/sgml/Makefile,v 1.12 1999/12/05 20:21:59 momjian Exp $
+# $Header: /cvsroot/pgsql/doc/src/sgml/Makefile,v 1.13 2000/01/14 22:11:31 petere Exp $
#
#----------------------------------------------------------------------------
@@ -85,15 +85,17 @@ APPLICATIONS= createdb.sgml createuser.sgml \
psql-ref.sgml \
vacuumdb.sgml
-COMMANDS= abort.sgml alter_table.sgml alter_user.sgml \
+COMMANDS= abort.sgml alter_group.sgml alter_table.sgml alter_user.sgml \
begin.sgml \
close.sgml cluster.sgml commit.sgml copy.sgml \
- create_aggregate.sgml create_database.sgml create_function.sgml create_index.sgml \
+ create_aggregate.sgml create_database.sgml create_function.sgml create_group.sgml \
+ create_index.sgml \
create_language.sgml create_operator.sgml create_rule.sgml create_sequence.sgml \
create_table.sgml create_table_as.sgml create_trigger.sgml create_type.sgml \
create_user.sgml create_view.sgml \
declare.sgml delete.sgml \
- drop_aggregate.sgml drop_database.sgml drop_function.sgml drop_index.sgml \
+ drop_aggregate.sgml drop_database.sgml drop_function.sgml drop_group.sgml \
+ drop_index.sgml \
drop_language.sgml drop_operator.sgml drop_rule.sgml drop_sequence.sgml \
drop_table.sgml drop_trigger.sgml drop_type.sgml drop_user.sgml drop_view.sgml \
explain.sgml fetch.sgml grant.sgml \
diff --git a/doc/src/sgml/ref/allfiles.sgml b/doc/src/sgml/ref/allfiles.sgml
index dc04300f2a2..09516b166b0 100644
--- a/doc/src/sgml/ref/allfiles.sgml
+++ b/doc/src/sgml/ref/allfiles.sgml
@@ -1,5 +1,5 @@
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.14 1999/12/05 20:02:42 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.15 2000/01/14 22:11:32 petere Exp $
Postgres documentation
Complete list of usable sgml source files in this directory.
-->
@@ -40,6 +40,7 @@ Complete list of usable sgml source files in this directory.
<!-- these are in the "commands" reference chapter -->
<!entity abort system "abort.sgml">
+<!entity alterGroup system "alter_group.sgml">
<!entity alterTable system "alter_table.sgml">
<!entity alterUser system "alter_user.sgml">
<!entity begin system "begin.sgml">
@@ -50,6 +51,7 @@ Complete list of usable sgml source files in this directory.
<!entity createAggregate system "create_aggregate.sgml">
<!entity createDatabase system "create_database.sgml">
<!entity createFunction system "create_function.sgml">
+<!entity createGroup system "create_group.sgml">
<!entity createIndex system "create_index.sgml">
<!entity createLanguage system "create_language.sgml">
<!entity createOperator system "create_operator.sgml">
@@ -66,6 +68,7 @@ Complete list of usable sgml source files in this directory.
<!entity dropAggregate system "drop_aggregate.sgml">
<!entity dropDatabase system "drop_database.sgml">
<!entity dropFunction system "drop_function.sgml">
+<!entity dropGroup system "drop_group.sgml">
<!entity dropIndex system "drop_index.sgml">
<!entity dropLanguage system "drop_language.sgml">
<!entity dropOperator system "drop_operator.sgml">
diff --git a/doc/src/sgml/ref/alter_group.sgml b/doc/src/sgml/ref/alter_group.sgml
new file mode 100644
index 00000000000..debbe979e1a
--- /dev/null
+++ b/doc/src/sgml/ref/alter_group.sgml
@@ -0,0 +1,162 @@
+<!--
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_group.sgml,v 1.1 2000/01/14 22:11:32 petere Exp $
+Postgres documentation
+-->
+
+<refentry id="SQL-ALTERGROUP">
+ <refmeta>
+ <refentrytitle id="SQL-ALTERGROUP-title">
+ ALTER GROUP
+ </refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>
+ ALTER GROUP
+ </refname>
+ <refpurpose>
+ Add users to a group, remove users from a group
+ </refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <refsynopsisdivinfo>
+ <date>2000-01-14</date>
+ </refsynopsisdivinfo>
+ <synopsis>
+ALTER GROUP <replaceable class="PARAMETER">name</replaceable> ADD USER <replaceable class="PARAMETER">username</replaceable> [, ... ]
+ALTER GROUP <replaceable class="PARAMETER">name</replaceable> DROP USER <replaceable class="PARAMETER">username</replaceable> [, ... ]
+ </synopsis>
+
+ <refsect2 id="R2-SQL-ALTERGROUP-1">
+ <refsect2info>
+ <date>2000-01-14</date>
+ </refsect2info>
+ <title>
+ Inputs
+ </title>
+
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="PARAMETER">name</replaceable></term>
+ <listitem>
+ <para>
+ The name of the group to modify.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="PARAMETER">username</replaceable></term>
+ <listitem>
+ <para>
+ Users which are to be added or removed from the group. The user
+ names must exist.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </para>
+ </refsect2>
+
+ <refsect2 id="R2-SQL-ALTERGROUP-2">
+ <refsect2info>
+ <date>2000-01-14</date>
+ </refsect2info>
+ <title>
+ Outputs
+ </title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><computeroutput>ALTER GROUP</computeroutput></term>
+ <listitem>
+ <para>
+ Message returned if the alteration was successful.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </para>
+ </refsect2>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-SQL-ALTERGROUP-1">
+ <refsect1info>
+ <date>2000-01-14</date>
+ </refsect1info>
+ <title>
+ Description
+ </title>
+ <para>
+ <command>ALTER GROUP</command> is used to change add users to a group or
+ remove them from a group. Only database superusers can use this command.
+ Adding a user to a group does not create the user. Similarly, removing
+ a user from a group does not drop the user itself.
+ </para>
+ <para>
+ Use <xref linkend="SQL-CREATEGROUP" endterm="SQL-CREATEGROUP-title">
+ to create a new group and <xref linkend="SQL-DROPGROUP"
+ endterm="SQL-DROPGROUP-title"> to remove a group.
+ </para>
+ </refsect1>
+
+ <refsect1 id="R1-SQL-ALTERGROUP-2">
+ <title>
+ Usage
+ </title>
+ <para>
+ Add users to a group:
+
+<programlisting>
+ALTER GROUP staff ADD USER karl, john
+</programlisting>
+
+ Remove a user from a group
+
+<programlisting>
+ALTER GROUP workers DROP USER beth
+</programlisting>
+
+ </para>
+ </refsect1>
+
+ <refsect1 id="R1-SQL-ALTERGROUP-3">
+ <title>
+ Compatibility
+ </title>
+
+ <refsect2 id="R2-SQL-ALTERGROUP-4">
+ <refsect2info>
+ <date>2000-01-14</date>
+ </refsect2info>
+ <title>
+ SQL92
+ </title>
+ <para>
+ There is no <command>ALTER GROUP</command> statement in
+ <acronym>SQL92</acronym>. The concept of roles is
+ similar.
+ </para>
+ </refsect2>
+ </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:nil
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:"../reference.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:"/usr/lib/sgml/catalog"
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/src/sgml/ref/alter_user.sgml b/doc/src/sgml/ref/alter_user.sgml
index 75bcca86546..f3ce32bb16f 100644
--- a/doc/src/sgml/ref/alter_user.sgml
+++ b/doc/src/sgml/ref/alter_user.sgml
@@ -1,5 +1,5 @@
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.9 1999/11/30 03:57:22 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/alter_user.sgml,v 1.10 2000/01/14 22:11:32 petere Exp $
Postgres documentation
-->
@@ -24,11 +24,8 @@ Postgres documentation
</refsynopsisdivinfo>
<synopsis>
ALTER USER <replaceable class="PARAMETER">username</replaceable>
- [ WITH
- [ SYSID <replaceable class="PARAMETER">uid</replaceable> ]
- [ PASSWORD <replaceable class="PARAMETER">password</replaceable> ] ]
+ [ WITH PASSWORD '<replaceable class="PARAMETER">password</replaceable>' ]
[ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ]
- [ IN GROUP <replaceable class="PARAMETER">groupname</replaceable> [, ...] ]
[ VALID UNTIL '<replaceable class="PARAMETER">abstime</replaceable>' ]
</synopsis>
@@ -41,23 +38,18 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable>
</title>
<para>
- Refer to <command>CREATE USER</command> for a detailed description of each
- clause.
- </para>
-
- <para>
<variablelist>
<varlistentry>
- <term><replaceable class="PARAMETER"> username </replaceable></term>
+ <term><replaceable class="PARAMETER">username</replaceable></term>
<listitem>
<para>
- The Postgres account name of the user whose details are to be altered.
+ The name of the user whose details are to be altered.
</para>
</listitem>
</varlistentry>
<varlistentry>
- <term><replaceable class="PARAMETER"> password </replaceable></term>
+ <term><replaceable class="PARAMETER">password</replaceable></term>
<listitem>
<para>
The new password to be used for this account.
@@ -66,36 +58,36 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable>
</varlistentry>
<varlistentry>
- <term><replaceable class="parameter">uid</replaceable></term>
+ <term>CREATEDB</term>
+ <term>NOCREATEDB</term>
<listitem>
- <para>
- The new <productname>PostgreSQL</productname> user id of the user.
- Since this number is used as a key into the
- <literal>pg_shadow</literal>/<literal>pg_user</literal> table
- throughout the system catalogs, it is not recommended that you change
- it unless the user in question does not own anything at all and/or
- you really know what you are doing. Note that it is not necessary that
- database and <acronym>UNIX</acronym> user ids match, but some people
- choose to keep the numbers the same.
+ <para>
+ These clauses define a user's ability to create databases.
+ If CREATEDB is specified, the user being defined will
+ be allowed to create his own databases. Using NOCREATEDB
+ will deny a user the ability to create databases.
</para>
</listitem>
</varlistentry>
<varlistentry>
- <term><replaceable class="PARAMETER"> groupname </replaceable></term>
+ <term>CREATEUSER</term>
+ <term>NOCREATEUSER</term>
<listitem>
<para>
- The name of an access group into which this account is to be put.
+ These clauses determine whether a user will be permitted to
+ create new users himself. This option will also make the user
+ a superuser who can override all access restrictions.
</para>
</listitem>
</varlistentry>
<varlistentry>
- <term><replaceable class="PARAMETER"> abstime </replaceable></term>
+ <term><replaceable class="PARAMETER">abstime</replaceable></term>
<listitem>
<para>
The date (and, optionally, the time)
- at which this user's access is to be terminated.
+ at which this user's password is to expire.
</para>
</listitem>
</varlistentry>
@@ -113,9 +105,7 @@ ALTER USER <replaceable class="PARAMETER">username</replaceable>
<para>
<variablelist>
<varlistentry>
- <term><computeroutput>
-ALTER USER
- </computeroutput></term>
+ <term><computeroutput>ALTER USER</computeroutput></term>
<listitem>
<para>
Message returned if the alteration was successful.
@@ -125,7 +115,7 @@ ALTER USER
<varlistentry>
<term><computeroutput>
-ERROR: alterUser: user "username" does not exist
+ERROR: ALTER USER: user "username" does not exist
</computeroutput></term>
<listitem>
<para>
@@ -148,39 +138,15 @@ ERROR: alterUser: user "username" does not exist
</title>
<para>
<command>ALTER USER</command> is used to change the attributes of a user's
- <productname>Postgres</productname> account.
- Also, it is only possible for the
- <productname>Postgres</productname>
- user or any user with read and modify permissions on
- <literal>pg_shadow</literal> to alter user passwords.
+ <productname>PostgreSQL</productname> account. Only a database superuser
+ can change privileges and password expiration with this command. Ordinary
+ users can only change their own password.
</para>
-
<para>
- If any of the clauses of the alter user statement are
- omitted, the corresponding value in the <literal>pg_shadow</literal> table
- is left unchanged.
+ Use <xref linkend="SQL-CREATEUSER" endterm="SQL-CREATEUSER-title">
+ to create a new user and <xref linkend="SQL-DROPUSER"
+ endterm="SQL-DROPUSER-title"> to remove a user.
</para>
-
- <refsect2 id="R2-SQL-ALTERUSER-3">
- <refsect2info>
- <date>1998-09-08</date>
- </refsect2info>
- <title>
- Notes
- </title>
- <para>
- <command>ALTER USER</command>
- is a <productname>Postgres</productname>
- language extension.
- </para>
- <para>
- Refer to <command>CREATE/DROP USER</command>
- to create or remove a user account.
- </para>
- <para>
- The IN GROUP clause is not yet implemented.
- </para>
- </refsect2>
</refsect1>
<refsect1 id="R1-SQL-ALTERUSER-2">
@@ -190,34 +156,29 @@ ERROR: alterUser: user "username" does not exist
<para>
Change a user password:
- <programlisting>
-ALTER USER davide WITH PASSWORD hu8jmn3;
- </programlisting>
+<programlisting>
+ALTER USER davide WITH PASSWORD 'hu8jmn3';
+</programlisting>
Change a user's valid until date
- <programlisting>
+<programlisting>
ALTER USER manuel VALID UNTIL 'Jan 31 2030';
- </programlisting>
+</programlisting>
Change a user's valid until date, specifying that his
authorisation should expire at midday on 4th May 1998 using
the time zone which is one hour ahead of UTC
- <programlisting>
+<programlisting>
ALTER USER chris VALID UNTIL 'May 4 12:00:00 1998 +1';
- </programlisting>
+</programlisting>
Give a user the ability to create other users and new databases.
- <programlisting>
+<programlisting>
ALTER USER miriam CREATEUSER CREATEDB;
- </programlisting>
-
- Place a user in two groups
+</programlisting>
- <programlisting>
-ALTER USER miriam IN GROUP sales, payroll;
- </programlisting>
</para>
</refsect1>
diff --git a/doc/src/sgml/ref/commands.sgml b/doc/src/sgml/ref/commands.sgml
index a8f32017393..8516904dbf1 100644
--- a/doc/src/sgml/ref/commands.sgml
+++ b/doc/src/sgml/ref/commands.sgml
@@ -1,5 +1,5 @@
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/Attic/commands.sgml,v 1.21 1999/12/05 20:02:42 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/Attic/commands.sgml,v 1.22 2000/01/14 22:11:32 petere Exp $
Postgres documentation
-->
@@ -14,6 +14,7 @@ Postgres documentation
</abstract>
&abort;
+ &alterGroup;
&alterTable;
&alterUser;
&begin;
@@ -24,6 +25,7 @@ Postgres documentation
&createAggregate;
&createDatabase;
&createFunction;
+ &createGroup;
&createIndex;
&createLanguage;
&createOperator;
@@ -40,6 +42,7 @@ Postgres documentation
&dropAggregate;
&dropDatabase;
&dropFunction;
+ &dropGroup;
&dropIndex;
&dropLanguage;
&dropOperator;
diff --git a/doc/src/sgml/ref/create_group.sgml b/doc/src/sgml/ref/create_group.sgml
new file mode 100644
index 00000000000..52023723016
--- /dev/null
+++ b/doc/src/sgml/ref/create_group.sgml
@@ -0,0 +1,176 @@
+<!--
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_group.sgml,v 1.1 2000/01/14 22:11:32 petere Exp $
+Postgres documentation
+-->
+
+<refentry id="SQL-CREATEGROUP">
+ <refmeta>
+ <refentrytitle id="sql-creategroup-title">
+ CREATE GROUP
+ </refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>
+ CREATE GROUP
+ </refname>
+ <refpurpose>
+ Creates a new group
+ </refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <refsynopsisdivinfo>
+ <date>2000-01-14</date>
+ </refsynopsisdivinfo>
+ <synopsis>
+CREATE GROUP <replaceable class="PARAMETER">name</replaceable>
+ [ WITH
+ [ SYSID <replaceable class="PARAMETER">gid</replaceable> ]
+ [ USER <replaceable class="PARAMETER">username</replaceable> [, ...] ] ]
+ </synopsis>
+
+ <refsect2 id="R2-SQL-CREATEGROUP-1">
+ <refsect2info>
+ <date>2000-01-14</date>
+ </refsect2info>
+ <title>
+ Inputs
+ </title>
+ <para>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="parameter">name</replaceable></term>
+ <listitem>
+ <para>
+ The name of the group.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">gid</replaceable></term>
+ <listitem>
+ <para>
+ The <literal>SYSID</literal> clause can be used to choose
+ the <productname>PostgreSQL</productname> group id of the new
+ group. It is not necessary to do so, however.
+ </para>
+ <para>
+ If this is not specified, the highest assigned group id plus one,
+ starting at 1, will be used as default.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">username</replaceable></term>
+ <listitem>
+ <para>
+ A list of users to include in the group. The users must already exist.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </para>
+ </refsect2>
+
+ <refsect2 id="R2-SQL-CREATEGROUP-2">
+ <refsect2info>
+ <date>2000-01-14</date>
+ </refsect2info>
+ <title>
+ Outputs
+ </title>
+
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><computeroutput>CREATE GROUP</computeroutput></term>
+ <listitem>
+ <para>
+ Message returned if the command completes successfully.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </refsect2>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-SQL-CREATEGROUP-1">
+ <refsect1info>
+ <date>2000-01-14</date>
+ </refsect1info>
+ <title>
+ Description
+ </title>
+ <para>
+ CREATE GROUP will create a new group in the database installation.
+ Refer to the adminstrator's guide for information about using groups
+ for authentication.
+ You must be a database superuser to use this command.
+ </para>
+ <para>
+ Use <xref linkend="SQL-ALTERGROUP" endterm="SQL-ALTERGROUP-title">
+ to change a group's membership, and <xref linkend="SQL-DROPGROUP"
+ endterm="SQL-DROPGROUP-title"> to remove a group.
+ </para>
+ </refsect1>
+ <refsect1 id="R1-SQL-CREATEGROUP-2">
+ <title>
+ Usage
+ </title>
+ <para>
+ Create an empty group:
+<programlisting>
+CREATE GROUP staff
+</programlisting>
+ </para>
+
+ <para>
+ Create a group with members:
+<programlisting>
+CREATE GROUP marketing WITH USER jonathan, david
+</programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1 id="R1-SQL-CREATEGROUP-3">
+ <title>
+ Compatibility
+ </title>
+
+ <refsect2 id="R2-SQL-CREATEGROUP-4">
+ <refsect2info>
+ <date>2000-01-14</date>
+ </refsect2info>
+ <title>
+ SQL92
+ </title>
+
+ <para>
+ There is no <command>CREATE GROUP</command> statement in SQL92.
+ Roles are similar in concept to groups.
+ </para>
+ </refsect2>
+ </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:nil
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:"../reference.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:"/usr/lib/sgml/catalog"
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/src/sgml/ref/create_user.sgml b/doc/src/sgml/ref/create_user.sgml
index 2f5d1d7feea..6994837751d 100644
--- a/doc/src/sgml/ref/create_user.sgml
+++ b/doc/src/sgml/ref/create_user.sgml
@@ -1,5 +1,5 @@
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_user.sgml,v 1.12 1999/12/04 05:03:49 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/create_user.sgml,v 1.13 2000/01/14 22:11:32 petere Exp $
Postgres documentation
-->
@@ -15,7 +15,7 @@ Postgres documentation
CREATE USER
</refname>
<refpurpose>
- Creates account information for a new user
+ Creates a new database user
</refpurpose>
</refnamediv>
<refsynopsisdiv>
@@ -26,7 +26,7 @@ Postgres documentation
CREATE USER <replaceable class="PARAMETER">username</replaceable>
[ WITH
[ SYSID <replaceable class="PARAMETER">uid</replaceable> ]
- [ PASSWORD <replaceable class="PARAMETER">password</replaceable> ] ]
+ [ PASSWORD '<replaceable class="PARAMETER">password</replaceable>' ] ]
[ CREATEDB | NOCREATEDB ] [ CREATEUSER | NOCREATEUSER ]
[ IN GROUP <replaceable class="PARAMETER">groupname</replaceable> [, ...] ]
[ VALID UNTIL '<replaceable class="PARAMETER">abstime</replaceable>' ]
@@ -62,13 +62,6 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable>
choose to keep the numbers the same.
</para>
<para>
- If you still want the
- OS user id and the <filename>usesysid</filename> to match
- for any given user,
- use the <application>createuser</application> script provided with
- the <productname>Postgres</productname> distribution.
- </para>
- <para>
If this is not specified, the highest assigned user id plus one
will be used as default.
</para>
@@ -79,30 +72,11 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable>
<term><replaceable class="parameter">password</replaceable></term>
<listitem>
<para>
- The PASSWORD clause sets the user's password within
- the "<filename>pg_shadow</filename>" table. For this reason,
- <filename>"pg_shadow</filename>" is no
- longer accessible to the instance of
- <productname>Postgres</productname> that the
- <productname>Postgres</productname>
- user's password is initially set to NULL.
- </para>
- <para>
- When a
- user's password in the "<filename>pg_shadow</filename>"
- table is NULL, user
- authentication proceeds as it historically has (HBA,
- PG_PASSWORD, etc). However, if a password is set for a
- user, a new authentication system supplants any other
- configured for the <productname>Postgres</productname>
- instance, and the password
- stored in the "<filename>pg_shadow</filename>" table is used
- for authentication.
- For more details on how this authentication system
- functions see pg_crypt(3). If the WITH PASSWORD clause is
- omitted, the user's password is set to the empty
- string which equates to a NULL value in the authentication
- system mentioned above.
+ Sets the user's password. If you do not plan to use password
+ authentication you can omit this option, otherwise the user
+ won't be able to connect to a password-authenticated server.
+ See pg_hba.conf(5) or the administrator's guide for details on
+ how to set up authentication mechanisms.
</para>
</listitem>
</varlistentry>
@@ -127,8 +101,8 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable>
<listitem>
<para>
These clauses determine whether a user will be permitted to
- create new
- users in an instance of <productname>Postgres</productname>.
+ create new users himself. This option will also make the user
+ a superuser who can override all access restrictions.
Omitting this clause will set the user's value of this
attribute to be NOCREATEUSER.
</para>
@@ -149,15 +123,8 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable>
<listitem>
<para>
The VALID UNTIL clause sets an absolute time after which the
- user's <productname>Postgres</productname>
- login is no longer valid. Please note that
- if a user does not have a password defined in the
- "<filename>pg_shadow</filename>"
- table, the valid until date will not be checked
- during user authentication. If this clause is omitted,
- a NULL value is stored in "<filename>pg_shadow</filename>"
- for this attribute,
- and the login will be valid for all time.
+ user's password is no longer valid.
+ If this clause is omitted the login will be valid for all time.
</para>
</listitem>
</varlistentry>
@@ -176,9 +143,7 @@ CREATE USER <replaceable class="PARAMETER">username</replaceable>
<para>
<variablelist>
<varlistentry>
- <term><computeroutput>
-CREATE USER
- </computeroutput></term>
+ <term><computeroutput>CREATE USER</computeroutput></term>
<listitem>
<para>
Message returned if the command completes successfully.
@@ -199,61 +164,38 @@ CREATE USER
</title>
<para>
CREATE USER will add a new user to an instance of
- <productname>PostgreSQL</productname>.
+ <productname>PostgreSQL</productname>. Refer to the adminstrator's
+ guide for information about managing users and authentication.
+ You must be a database superuser to use this command.
</para>
-
- <refsect2 id="R2-SQL-CREATEUSER-3">
- <refsect2info>
- <date>1998-09-21</date>
- </refsect2info>
- <title>
- Notes
- </title>
- <para>
- <command>CREATE USER</command> statement is a
- <productname>Postgres</productname> language extension.
- </para>
- <para>
- Use <command>DROP USER</command> or <command>ALTER USER</command>
- statements to remove or modify a user account.
- </para>
- <para>
- Refer to the <filename>pg_shadow</filename> table for further information.
- </para>
- <programlisting>
- Table "pg_shadow"
- Attribute | Type | Extra
--------------+---------+-------
- usename | name |
- usesysid | int4 |
- usecreatedb | bool |
- usetrace | bool |
- usesuper | bool |
- usecatupd | bool |
- passwd | text |
- valuntil | abstime |
- </programlisting>
- </refsect2>
- </refsect1>
-
+ <para>
+ Use <xref linkend="SQL-ALTERUSER" endterm="SQL-ALTERUSER-title">
+ to change a user's password and privileges, and <xref linkend="SQL-DROPUSER"
+ endterm="SQL-DROPUSER-title"> to remove a user.
+ Use <command>ALTER GROUP</command> to add or remove the user from other groups.
+ <productname>PostgreSQL</productname>
+ comes with a script <xref linkend="APP-CREATEUSER"
+ endterm="APP-CREATEUSER-title">
+ which has the same functionality as this command (in fact, it calls this command)
+ but can be run from the command shell.
+ </para>
+ </refsect1>
<refsect1 id="R1-SQL-CREATEUSER-2">
<title>
Usage
</title>
<para>
Create a user with no password:
-
- <programlisting>
+<programlisting>
CREATE USER jonathan
- </programlisting>
+</programlisting>
</para>
<para>
Create a user with a password:
-
- <programlisting>
-CREATE USER davide WITH PASSWORD "jw8s0F4"
- </programlisting>
+<programlisting>
+CREATE USER davide WITH PASSWORD 'jw8s0F4'
+</programlisting>
</para>
<para>
@@ -261,17 +203,16 @@ CREATE USER davide WITH PASSWORD "jw8s0F4"
Note that after one second has ticked in 2002, the account is not
valid:
- <programlisting>
-CREATE USER miriam WITH PASSWORD "jw8s0F4" VALID UNTIL 'Jan 1 2002'
- </programlisting>
+<programlisting>
+CREATE USER miriam WITH PASSWORD 'jw8s0F4' VALID UNTIL 'Jan 1 2002'
+</programlisting>
</para>
<para>
Create an account where the user can create databases:
-
- <programlisting>
-CREATE USER manuel WITH PASSWORD "jw8s0F4" CREATEDB
- </programlisting>
+<programlisting>
+CREATE USER manuel WITH PASSWORD 'jw8s0F4' CREATEDB
+</programlisting>
</para>
</refsect1>
diff --git a/doc/src/sgml/ref/drop_group.sgml b/doc/src/sgml/ref/drop_group.sgml
new file mode 100644
index 00000000000..0d7db1ef098
--- /dev/null
+++ b/doc/src/sgml/ref/drop_group.sgml
@@ -0,0 +1,138 @@
+<!--
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_group.sgml,v 1.1 2000/01/14 22:11:32 petere Exp $
+Postgres documentation
+-->
+
+<refentry id="SQL-DROPGROUP">
+ <refmeta>
+ <refentrytitle id="SQL-DROPGROUP-TITLE">
+ DROP GROUP
+ </refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+ <refnamediv>
+ <refname>
+ DROP GROUP
+ </refname>
+ <refpurpose>
+ Removes a group
+ </refpurpose>
+ </refnamediv>
+ <refsynopsisdiv>
+ <refsynopsisdivinfo>
+ <date>2000-01-14</date>
+ </refsynopsisdivinfo>
+ <synopsis>
+DROP GROUP <replaceable class="PARAMETER">name</replaceable>
+ </synopsis>
+
+ <refsect2 id="R2-SQL-DROPGROUP-1">
+ <refsect2info>
+ <date>2000-01-14</date>
+ </refsect2info>
+ <title>
+ Inputs
+ </title>
+ <para>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="PARAMETER">name</replaceable></term>
+ <listitem>
+ <para>
+ The name of an existing group.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </para>
+ </refsect2>
+
+ <refsect2 id="R2-SQL-DROPGROUP-2">
+ <refsect2info>
+ <date>2000-01-14</date>
+ </refsect2info>
+ <title>
+ Outputs
+ </title>
+ <para>
+ <variablelist>
+ <varlistentry>
+ <term><computeroutput>DROP GROUP</computeroutput></term>
+ <listitem>
+ <para>
+ The message returned if the group is successfully deleted.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ </variablelist>
+ </para>
+ </refsect2>
+ </refsynopsisdiv>
+
+ <refsect1 id="R1-SQL-DROPGROUP-1">
+ <refsect1info>
+ <date>2000-01-14</date>
+ </refsect1info>
+ <title>
+ Description
+ </title>
+ <para>
+ <command>DROP GROUP</command> removes the specified group from the database.
+ The users in the group are not deleted.
+ </para>
+ <para>
+ Use <xref linkend="SQL-CREATEGROUP" endterm="SQL-CREATEGROUP-title">
+ to add new groups, and <xref linkend="SQL-ALTERGROUP"
+ endterm="SQL-ALTERGROUP-title"> to change a group's membership.
+ </para>
+ </refsect1>
+
+ <refsect1 id="R1-SQL-DROPGROUP-2">
+ <title>
+ Usage
+ </title>
+ <para>
+ To drop a group:
+<programlisting>
+DROP GROUP staff;
+</programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1 id="R1-SQL-DROPGROUP-3">
+ <title>
+ Compatibility
+ </title>
+
+ <refsect2 id="R2-SQL-DROPGROUP-4">
+ <refsect2info>
+ <date>2000-01-14</date>
+ </refsect2info>
+ <title>
+ SQL92
+ </title>
+ <para>
+ There is no <command>DROP GROUP</command> in <acronym>SQL92</acronym>.
+ </para>
+ </refsect2>
+ </refsect1>
+</refentry>
+
+<!-- Keep this comment at the end of the file
+Local variables:
+mode: sgml
+sgml-omittag:nil
+sgml-shorttag:t
+sgml-minimize-attributes:nil
+sgml-always-quote-attributes:t
+sgml-indent-step:1
+sgml-indent-data:t
+sgml-parent-document:nil
+sgml-default-dtd-file:"../reference.ced"
+sgml-exposed-tags:nil
+sgml-local-catalogs:"/usr/lib/sgml/catalog"
+sgml-local-ecat-files:nil
+End:
+-->
diff --git a/doc/src/sgml/ref/drop_user.sgml b/doc/src/sgml/ref/drop_user.sgml
index 27f339f82dc..b2a96e0090f 100644
--- a/doc/src/sgml/ref/drop_user.sgml
+++ b/doc/src/sgml/ref/drop_user.sgml
@@ -1,5 +1,5 @@
<!--
-$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_user.sgml,v 1.9 1999/12/07 22:41:41 momjian Exp $
+$Header: /cvsroot/pgsql/doc/src/sgml/ref/drop_user.sgml,v 1.10 2000/01/14 22:11:32 petere Exp $
Postgres documentation
-->
@@ -15,7 +15,7 @@ Postgres documentation
DROP USER
</refname>
<refpurpose>
- Removes an user account information
+ Removes a user
</refpurpose>
</refnamediv>
<refsynopsisdiv>
@@ -58,18 +58,17 @@ DROP USER <replaceable class="PARAMETER">name</replaceable>
<para>
<variablelist>
<varlistentry>
- <term><computeroutput>
-DROP
- </computeroutput></term>
+ <term><computeroutput>DROP USER</computeroutput></term>
<listitem>
<para>
The message returned if the user is successfully deleted.
</para>
</listitem>
</varlistentry>
+
<varlistentry>
<term><computeroutput>
-ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does not exist.
+ERROR: DROP USER: user "<replaceable class="parameter">name</replaceable>" does not exist
</computeroutput></term>
<listitem>
<para>
@@ -77,6 +76,18 @@ ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does
</para>
</listitem>
</varlistentry>
+
+ <varlistentry>
+ <term><computeroutput>
+DROP USER: user "<replaceable class="parameter">name</replaceable>" owns database "<replaceable class="parameter">name</replaceable>", cannot be removed
+ </computeroutput></term>
+ <listitem>
+ <para>
+ You must drop the database first or change its ownership.
+ </para>
+ </listitem>
+ </varlistentry>
+
</variablelist>
</para>
</refsect2>
@@ -90,30 +101,20 @@ ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does
Description
</title>
<para>
- <command>DROP USER</command> removes the specified
- user from the database,
- along with any databases owned by the user. It
- does not remove tables, views, or triggers owned by the
- named user in databases not owned by the user.
+ <command>DROP USER</command> removes the specified user from the database.
+ It does not remove tables, views, or other objects owned by the user. If the
+ user owns any database you get an error.
</para>
-
- <refsect2 id="R2-SQL-DROPUSER-3">
- <refsect2info>
- <date>1998-09-22</date>
- </refsect2info>
- <title>
- Notes
- </title>
- <para>
- <command>DROP USER</command> is a <productname>Postgres</productname>
- language extension.
- </para>
- <para>
- Refer to <command>CREATE USER</command> and
- <command>ALTER USER</command> for information on
- how to create or modify user accounts.
- </para>
- </refsect2>
+ <para>
+ Use <xref linkend="SQL-CREATEUSER" endterm="SQL-CREATEUSER-title">
+ to add new users, and <xref linkend="SQL-ALTERUSER"
+ endterm="SQL-ALTERUSER-title"> to change a user's properties.
+ <productname>PostgreSQL</productname>
+ comes with a script <xref linkend="APP-DROPUSER"
+ endterm="APP-DROPUSER-title">
+ which has the same functionality as this command (in fact, it calls this command)
+ but can be run from the command shell.
+ </para>
</refsect1>
<refsect1 id="R1-SQL-DROPUSER-2">
@@ -122,9 +123,9 @@ ERROR: removeUser: user "<replaceable class="parameter">name</replaceable>" does
</title>
<para>
To drop a user account:
- <programlisting>
-DROP USER Jonathan;
- </programlisting>
+<programlisting>
+DROP USER jonathan;
+</programlisting>
</para>
</refsect1>
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
index f42665a9564..7a8dd880079 100644
--- a/src/backend/commands/copy.c
+++ b/src/backend/commands/copy.c
@@ -6,7 +6,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.94 1999/12/16 22:19:41 wieck Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.95 2000/01/14 22:11:33 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -97,7 +97,11 @@ CopySendData(void *databuf, int datasize, FILE *fp)
fe_eof = true;
}
else
+ {
fwrite(databuf, datasize, 1, fp);
+ if (ferror(fp))
+ elog(ERROR, "CopySendData: %s", strerror(errno));
+ }
}
static void
@@ -219,7 +223,7 @@ CopyDonePeek(FILE *fp, int c, int pickup)
void
DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
- char *filename, char *delim, char *null_print, int fileumask)
+ char *filename, char *delim, char *null_print)
{
/*----------------------------------------------------------------------------
Either unload or reload contents of class <relname>, depending on <from>.
@@ -235,11 +239,6 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
If in the text format, delimit columns with delimiter <delim> and print
NULL values as <null_print>.
- <fileumask> is the umask(2) setting to use while creating an output file.
- This should usually be more liberal than the backend's normal 077 umask,
- but not always (in particular, "pg_pwd" should be written with 077!).
- Up through version 6.5, <fileumask> was always 000, which was foolhardy.
-
When loading in the text format from an input stream (as opposed to
a file), recognize a "." on a line by itself as EOF. Also recognize
a stream EOF. When unloading in the text format to an output stream,
@@ -272,12 +271,11 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
result = pg_aclcheck(relname, UserName, required_access);
if (result != ACLCHECK_OK)
elog(ERROR, "%s: %s", relname, aclcheck_error_strings[result]);
- else if (!pipe && !superuser())
+ if (!pipe && !superuser())
elog(ERROR, "You must have Postgres superuser privilege to do a COPY "
"directly to or from a file. Anyone can COPY to stdout or "
"from stdin. Psql's \\copy command also works for anyone.");
- else
- {
+
if (from)
{ /* copy from file to database */
if (rel->rd_rel->relkind == RELKIND_SEQUENCE)
@@ -324,7 +322,7 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
{
mode_t oumask; /* Pre-existing umask value */
- oumask = umask((mode_t) fileumask);
+ oumask = umask((mode_t) 022);
#ifndef __CYGWIN32__
fp = AllocateFile(filename, "w");
#else
@@ -350,7 +348,6 @@ DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
if (IsUnderPostmaster)
pq_endcopyout(false);
}
- }
/*
* Close the relation. If reading, we can release the AccessShareLock
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index bb18cad4aff..f53d34cb0f3 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -5,7 +5,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: user.c,v 1.47 1999/12/21 22:39:01 wieck Exp $
+ * $Id: user.c,v 1.48 2000/01/14 22:11:33 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -31,6 +31,7 @@
#include "tcop/tcopprot.h"
#include "utils/acl.h"
#include "utils/array.h"
+#include "utils/builtins.h"
#include "utils/syscache.h"
static void CheckPgUserAclNotNull(void);
@@ -38,30 +39,26 @@ static void CheckPgUserAclNotNull(void);
#define SQL_LENGTH 512
/*---------------------------------------------------------------------
- * update_pg_pwd
+ * write_password_file / update_pg_pwd
*
* copy the modified contents of pg_shadow to a file used by the postmaster
* for user authentication. The file is stored as $PGDATA/pg_pwd.
*
- * NB: caller is responsible for ensuring that only one backend can
- * execute this routine at a time. Acquiring AccessExclusiveLock on
- * pg_shadow is the standard way to do that.
+ * This function set is both a trigger function for direct updates to pg_shadow
+ * as well as being called directly from create/alter/drop user.
*---------------------------------------------------------------------
*/
-
-HeapTuple
-update_pg_pwd(void)
+static void
+write_password_file(Relation rel)
{
char *filename,
*tempname;
int bufsize;
-
-
- /*
- * This is a trigger, so clean out the information provided by
- * the trigger manager.
- */
- CurrentTriggerData = NULL;
+ FILE *fp;
+ mode_t oumask;
+ HeapScanDesc scan;
+ HeapTuple tuple;
+ TupleDesc dsc = RelationGetDescr(rel);
/*
* Create a temporary filename to be renamed later. This prevents the
@@ -71,86 +68,134 @@ update_pg_pwd(void)
filename = crypt_getpwdfilename();
bufsize = strlen(filename) + 12;
tempname = (char *) palloc(bufsize);
+
snprintf(tempname, bufsize, "%s.%d", filename, MyProcPid);
+ oumask = umask((mode_t) 077);
+ fp = AllocateFile(tempname, "w");
+ umask(oumask);
+ if (fp == NULL)
+ elog(ERROR, "%s: %s", tempname, strerror(errno));
+
+ /* read table */
+ scan = heap_beginscan(rel, false, SnapshotSelf, 0, NULL);
+ while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
+ {
+ Datum datum_n, datum_p, datum_v;
+ bool null_n, null_p, null_v;
+
+ datum_n = heap_getattr(tuple, Anum_pg_shadow_usename, dsc, &null_n);
+ if (null_n)
+ continue; /* don't allow empty users */
+ datum_p = heap_getattr(tuple, Anum_pg_shadow_passwd, dsc, &null_p);
+ /* It could be argued that people having a null password
+ shouldn't be allowed to connect, because they need
+ to have a password set up first. If you think assuming
+ an empty password in that case is better, erase the following line. */
+ if (null_p)
+ continue;
+ datum_v = heap_getattr(tuple, Anum_pg_shadow_valuntil, dsc, &null_v);
+
+ /* These fake entries are not really necessary. To remove them, the parser
+ in backend/libpq/crypt.c would need to be adjusted. Initdb might also
+ need adjustments. */
+ fprintf(fp,
+ "%s"
+ CRYPT_PWD_FILE_SEPSTR
+ "0"
+ CRYPT_PWD_FILE_SEPSTR
+ "x"
+ CRYPT_PWD_FILE_SEPSTR
+ "x"
+ CRYPT_PWD_FILE_SEPSTR
+ "x"
+ CRYPT_PWD_FILE_SEPSTR
+ "x"
+ CRYPT_PWD_FILE_SEPSTR
+ "%s"
+ CRYPT_PWD_FILE_SEPSTR
+ "%s\n",
+ nameout(DatumGetName(datum_n)),
+ null_p ? "" : textout((text*)datum_p),
+ null_v ? "\\N" : nabstimeout((AbsoluteTime)datum_v) /* this is how the parser wants it */
+ );
+ if (ferror(fp))
+ elog(ERROR, "%s: %s", tempname, strerror(errno));
+ fflush(fp);
+ }
+ heap_endscan(scan);
+ FreeFile(fp);
- /*
- * Copy the contents of pg_shadow to the pg_pwd ASCII file using the
- * SEPCHAR character as the delimiter between fields. Make sure the
- * file is created with mode 600 (umask 077).
- */
- DoCopy(ShadowRelationName, /* relname */
- false, /* binary */
- false, /* oids */
- false, /* from */
- false, /* pipe */
- tempname, /* filename */
- CRYPT_PWD_FILE_SEPSTR, /* delim */
- "", /* nulls */
- 0077); /* fileumask */
- /*
- * And rename the temp file to its final name, deleting the old pg_pwd.
- */
- rename(tempname, filename);
+ /*
+ * And rename the temp file to its final name, deleting the old pg_pwd.
+ */
+ rename(tempname, filename);
- /*
+ /*
* Create a flag file the postmaster will detect the next time it
* tries to authenticate a user. The postmaster will know to reload
* the pg_pwd file contents.
*/
filename = crypt_getpwdreloadfilename();
- creat(filename, S_IRUSR | S_IWUSR);
+ if (creat(filename, S_IRUSR | S_IWUSR) == -1)
+ elog(ERROR, "%s: %s", filename, strerror(errno));
pfree((void *) tempname);
+}
+
+
+
+/* This is the wrapper for triggers. */
+HeapTuple
+update_pg_pwd(void)
+{
+ Relation rel = heap_openr(ShadowRelationName, AccessExclusiveLock);
+ write_password_file(rel);
+ heap_close(rel, AccessExclusiveLock);
- return NULL;
+ /*
+ * This is a trigger, so clean out the information provided by
+ * the trigger manager.
+ */
+ CurrentTriggerData = NULL;
+ return NULL;
}
-/*---------------------------------------------------------------------
- * DefineUser
- *
- * Add the user to the pg_shadow relation, and if specified make sure the
- * user is specified in the desired groups of defined in pg_group.
- *---------------------------------------------------------------------
+
+
+/*
+ * CREATE USER
*/
void
-DefineUser(CreateUserStmt *stmt, CommandDest dest)
+CreateUser(CreateUserStmt *stmt)
{
- char *pg_shadow,
- sql[SQL_LENGTH];
Relation pg_shadow_rel;
TupleDesc pg_shadow_dsc;
HeapScanDesc scan;
HeapTuple tuple;
+ Datum new_record[Natts_pg_shadow];
+ char new_record_nulls[Natts_pg_shadow];
bool user_exists = false,
sysid_exists = false,
- inblock,
- havesysid,
- havepassword,
- havevaluntil;
+ havesysid;
int max_id = -1;
List *item;
- havesysid = stmt->sysid >= 0;
- havepassword = stmt->password && stmt->password[0];
- havevaluntil = stmt->validUntil && stmt->validUntil[0];
+ havesysid = stmt->sysid > 0;
- if (havepassword)
+ /* Check some permissions first */
+ if (stmt->password)
CheckPgUserAclNotNull();
- if (!(inblock = IsTransactionBlock()))
- BeginTransactionBlock();
- /*
- * Make sure the user attempting to create a user can insert into the
- * pg_shadow relation.
- */
- pg_shadow = GetPgUserName();
- if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR | ACL_AP) != ACLCHECK_OK)
- {
- UserAbortTransactionBlock();
- elog(ERROR, "DefineUser: user \"%s\" does not have SELECT and INSERT privilege for \"%s\"",
- pg_shadow, ShadowRelationName);
- return;
- }
+ if (!superuser())
+ elog(ERROR, "CREATE USER: permission denied");
+
+ /* The reason for the following is this:
+ * If you start a transaction block, create a user, then roll back the
+ * transaction, the pg_pwd won't get rolled back due to a bug in the
+ * Unix file system ( :}). Hence this is in the interest of security.
+ */
+ if (IsTransactionBlock())
+ elog(ERROR, "CREATE USER: may not be called in a transaction block");
/*
* Scan the pg_shadow relation to be certain the user or id doesn't already
@@ -184,49 +229,64 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest)
if (user_exists || sysid_exists)
{
heap_close(pg_shadow_rel, AccessExclusiveLock);
- UserAbortTransactionBlock();
if (user_exists)
- elog(ERROR, "DefineUser: user name \"%s\" already exists", stmt->user);
+ elog(ERROR, "CREATE USER: user name \"%s\" already exists", stmt->user);
else
- elog(ERROR, "DefineUser: sysid %d is already assigned", stmt->sysid);
+ elog(ERROR, "CREATE USER: sysid %d is already assigned", stmt->sysid);
return;
}
- /*
- * Build the insert statement to be executed.
- *
- * XXX Ugly as this code is, it still fails to cope with ' or \ in any of
- * the provided strings.
- *
- * XXX This routine would be *lots* better if it inserted the new
- * tuple with formtuple/heap_insert. For one thing, all of the
- * transaction-block gamesmanship could be eliminated, because
- * it's only there to make the world safe for a recursive call
- * to pg_exec_query_dest().
- */
- snprintf(sql, SQL_LENGTH,
- "insert into %s (usename,usesysid,usecreatedb,usetrace,"
- "usesuper,usecatupd,passwd,valuntil) "
- "values('%s',%d,'%c','f','%c','%c',%s%s%s,%s%s%s)",
- ShadowRelationName,
- stmt->user,
- havesysid ? stmt->sysid : max_id + 1,
- (stmt->createdb && *stmt->createdb) ? 't' : 'f',
- (stmt->createuser && *stmt->createuser) ? 't' : 'f',
- ((stmt->createdb && *stmt->createdb) ||
- (stmt->createuser && *stmt->createuser)) ? 't' : 'f',
- havepassword ? "'" : "",
- havepassword ? stmt->password : "NULL",
- havepassword ? "'" : "",
- havevaluntil ? "'" : "",
- havevaluntil ? stmt->validUntil : "NULL",
- havevaluntil ? "'" : "");
+ /*
+ * Build a tuple to insert
+ */
+ new_record[Anum_pg_shadow_usename-1] = PointerGetDatum(namein(stmt->user)); /* this truncated properly */
+ new_record[Anum_pg_shadow_usesysid-1] = Int32GetDatum(havesysid ? stmt->sysid : max_id + 1);
- /*
- * XXX If insert fails, say because a bogus valuntil date is given,
- * need to catch the resulting error and undo our transaction.
- */
- pg_exec_query_dest(sql, dest, false);
+ AssertState(BoolIsValid(stmt->createdb));
+ new_record[Anum_pg_shadow_usecreatedb-1] = (Datum)(stmt->createdb);
+ new_record[Anum_pg_shadow_usetrace-1] = (Datum)(false);
+ AssertState(BoolIsValid(stmt->createuser));
+ new_record[Anum_pg_shadow_usesuper-1] = (Datum)(stmt->createuser);
+ /* superuser gets catupd right by default */
+ new_record[Anum_pg_shadow_usecatupd-1] = (Datum)(stmt->createuser);
+
+ if (stmt->password)
+ new_record[Anum_pg_shadow_passwd-1] = PointerGetDatum(textin(stmt->password));
+ if (stmt->validUntil)
+ new_record[Anum_pg_shadow_valuntil-1] = PointerGetDatum(nabstimein(stmt->validUntil));
+
+ new_record_nulls[Anum_pg_shadow_usename-1] = ' ';
+ new_record_nulls[Anum_pg_shadow_usesysid-1] = ' ';
+
+ new_record_nulls[Anum_pg_shadow_usecreatedb-1] = ' ';
+ new_record_nulls[Anum_pg_shadow_usetrace-1] = ' ';
+ new_record_nulls[Anum_pg_shadow_usesuper-1] = ' ';
+ new_record_nulls[Anum_pg_shadow_usecatupd-1] = ' ';
+
+ new_record_nulls[Anum_pg_shadow_passwd-1] = stmt->password ? ' ' : 'n';
+ new_record_nulls[Anum_pg_shadow_valuntil-1] = stmt->validUntil ? ' ' : 'n';
+
+ tuple = heap_formtuple(pg_shadow_dsc, new_record, new_record_nulls);
+ Assert(tuple);
+
+ /*
+ * Insert a new record in the pg_shadow table
+ */
+ if (heap_insert(pg_shadow_rel, tuple) == InvalidOid)
+ elog(ERROR, "CREATE USER: heap_insert failed");
+
+ /*
+ * Update indexes
+ */
+ if (RelationGetForm(pg_shadow_rel)->relhasindex) {
+ Relation idescs[Num_pg_shadow_indices];
+
+ CatalogOpenIndices(Num_pg_shadow_indices,
+ Name_pg_shadow_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_shadow_indices, pg_shadow_rel,
+ tuple);
+ CatalogCloseIndices(Num_pg_shadow_indices, idescs);
+ }
/*
* Add the user to the groups specified. We'll just call the below
@@ -236,59 +296,49 @@ DefineUser(CreateUserStmt *stmt, CommandDest dest)
{
AlterGroupStmt ags;
- ags.name = strVal(lfirst(item));
+ ags.name = strVal(lfirst(item)); /* the group name to add this in */
ags.action = +1;
- ags.listUsers = lcons((void*)makeString(stmt->user), NIL);
- AlterGroup(&ags, dest);
+ ags.listUsers = lcons((void*)makeInteger(havesysid ? stmt->sysid : max_id + 1), NIL);
+ AlterGroup(&ags, "CREATE USER");
}
/*
* Write the updated pg_shadow data to the flat password file.
- * Because we are still holding AccessExclusiveLock on pg_shadow,
- * we can be sure no other backend will try to write the flat
- * file at the same time.
*/
- update_pg_pwd();
-
+ write_password_file(pg_shadow_rel);
/*
* Now we can clean up.
*/
heap_close(pg_shadow_rel, AccessExclusiveLock);
-
- if (IsTransactionBlock() && !inblock)
- EndTransactionBlock();
}
+
+/*
+ * ALTER USER
+ */
extern void
-AlterUser(AlterUserStmt *stmt, CommandDest dest)
+AlterUser(AlterUserStmt *stmt)
{
-
- char *pg_shadow,
- sql[SQL_LENGTH];
+ Datum new_record[Natts_pg_shadow];
+ char new_record_nulls[Natts_pg_shadow];
Relation pg_shadow_rel;
TupleDesc pg_shadow_dsc;
- HeapTuple tuple;
- bool inblock;
- bool comma = false;
+ HeapTuple tuple, new_tuple;
+ bool null;
if (stmt->password)
CheckPgUserAclNotNull();
- if (!(inblock = IsTransactionBlock()))
- BeginTransactionBlock();
- /*
- * Make sure the user attempting to create a user can insert into the
- * pg_shadow relation.
- */
- pg_shadow = GetPgUserName();
- if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR) != ACLCHECK_OK)
- {
- UserAbortTransactionBlock();
- elog(ERROR, "AlterUser: user \"%s\" does not have SELECT and UPDATE privilege for \"%s\"",
- pg_shadow, ShadowRelationName);
- return;
- }
+ /* must be superuser or just want to change your own password */
+ if (!superuser() &&
+ !(stmt->createdb==0 && stmt->createuser==0 && !stmt->validUntil
+ && stmt->password && strcmp(GetPgUserName(), stmt->user)==0))
+ elog(ERROR, "ALTER USER: permission denied");
+
+ /* see comments in create user */
+ if (IsTransactionBlock())
+ elog(ERROR, "ALTER USER: may not be called in a transaction block");
/*
* Scan the pg_shadow relation to be certain the user exists.
@@ -304,142 +354,135 @@ AlterUser(AlterUserStmt *stmt, CommandDest dest)
if (!HeapTupleIsValid(tuple))
{
heap_close(pg_shadow_rel, AccessExclusiveLock);
- UserAbortTransactionBlock();
- elog(ERROR, "AlterUser: user \"%s\" does not exist", stmt->user);
+ elog(ERROR, "ALTER USER: user \"%s\" does not exist", stmt->user);
}
- /* look for duplicate sysid */
- tuple = SearchSysCacheTuple(SHADOWSYSID,
- Int32GetDatum(stmt->sysid),
- 0, 0, 0);
- if (HeapTupleIsValid(tuple))
- {
- Datum datum;
- bool null;
+ /*
+ * Build a tuple to update, perusing the information just obtained
+ */
+ new_record[Anum_pg_shadow_usename-1] = PointerGetDatum(namein(stmt->user));
+ new_record_nulls[Anum_pg_shadow_usename-1] = ' ';
- datum = heap_getattr(tuple, Anum_pg_shadow_usename, pg_shadow_dsc, &null);
- if (datum && !null && strcmp((char *) datum, stmt->user) != 0)
- {
- heap_close(pg_shadow_rel, AccessExclusiveLock);
- UserAbortTransactionBlock();
- elog(ERROR, "AlterUser: sysid %d is already assigned", stmt->sysid);
- }
- }
+ /* sysid - leave as is */
+ new_record[Anum_pg_shadow_usesysid-1] = heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null);
+ new_record_nulls[Anum_pg_shadow_usesysid-1] = null ? 'n' : ' ';
+ /* createdb */
+ if (stmt->createdb == 0)
+ {
+ /* don't change */
+ new_record[Anum_pg_shadow_usecreatedb-1] = heap_getattr(tuple, Anum_pg_shadow_usecreatedb, pg_shadow_dsc, &null);
+ new_record_nulls[Anum_pg_shadow_usecreatedb-1] = null ? 'n' : ' ';
+ }
+ else
+ {
+ new_record[Anum_pg_shadow_usecreatedb-1] = (Datum)(stmt->createdb > 0 ? true : false);
+ new_record_nulls[Anum_pg_shadow_usecreatedb-1] = ' ';
+ }
- /*
- * Create the update statement to modify the user.
- *
- * XXX see diatribe in preceding routine. This code is just as bogus.
- */
- snprintf(sql, SQL_LENGTH, "update %s set ", ShadowRelationName);
+ /* trace - leave as is */
+ new_record[Anum_pg_shadow_usetrace-1] = heap_getattr(tuple, Anum_pg_shadow_usetrace, pg_shadow_dsc, &null);
+ new_record_nulls[Anum_pg_shadow_usetrace-1] = null ? 'n' : ' ';
- if (stmt->password)
+ /* createuser (superuser) */
+ if (stmt->createuser == 0)
{
- snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
- "passwd = '%s'", stmt->password);
- comma = true;
+ /* don't change */
+ new_record[Anum_pg_shadow_usesuper-1] = heap_getattr(tuple, Anum_pg_shadow_usesuper, pg_shadow_dsc, &null);
+ new_record_nulls[Anum_pg_shadow_usesuper-1] = null ? 'n' : ' ';
}
-
- if (stmt->sysid>=0)
+ else
{
- if (comma)
- strcat(sql, ", ");
- snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
- "usesysid = %d", stmt->sysid);
- comma = true;
+ new_record[Anum_pg_shadow_usesuper-1] = (Datum)(stmt->createuser > 0 ? true : false);
+ new_record_nulls[Anum_pg_shadow_usesuper-1] = ' ';
}
- if (stmt->createdb)
+ /* catupd - set to false if someone's superuser priv is being yanked */
+ if (stmt->createuser < 0)
{
- if (comma)
- strcat(sql, ", ");
- snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
- "usecreatedb='%c'",
- *stmt->createdb ? 't' : 'f');
- comma = true;
+ new_record[Anum_pg_shadow_usecatupd-1] = (Datum)(false);
+ new_record_nulls[Anum_pg_shadow_usecatupd-1] = ' ';
+ }
+ else
+ {
+ /* leave alone */
+ new_record[Anum_pg_shadow_usecatupd-1] = heap_getattr(tuple, Anum_pg_shadow_usecatupd, pg_shadow_dsc, &null);
+ new_record_nulls[Anum_pg_shadow_usecatupd-1] = null ? 'n' : ' ';
}
- if (stmt->createuser)
+ /* password */
+ if (stmt->password)
{
- if (comma)
- strcat(sql, ", ");
- snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
- "usesuper='%c'",
- *stmt->createuser ? 't' : 'f');
- comma = true;
+ new_record[Anum_pg_shadow_passwd-1] = PointerGetDatum(textin(stmt->password));
+ new_record_nulls[Anum_pg_shadow_passwd-1] = ' ';
+ }
+ else
+ {
+ /* leave as is */
+ new_record[Anum_pg_shadow_passwd-1] = heap_getattr(tuple, Anum_pg_shadow_passwd, pg_shadow_dsc, &null);
+ new_record_nulls[Anum_pg_shadow_passwd-1] = null ? 'n' : ' ';
}
- if (stmt->validUntil)
+ /* valid until */
+ if (stmt->validUntil)
+ {
+ new_record[Anum_pg_shadow_valuntil-1] = PointerGetDatum(nabstimein(stmt->validUntil));
+ new_record_nulls[Anum_pg_shadow_valuntil-1] = ' ';
+ }
+ else
{
- if (comma)
- strcat(sql, ", ");
- snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
- "valuntil='%s'",
- stmt->validUntil);
+ /* leave as is */
+ new_record[Anum_pg_shadow_valuntil-1] = heap_getattr(tuple, Anum_pg_shadow_valuntil, pg_shadow_dsc, &null);
+ new_record_nulls[Anum_pg_shadow_valuntil-1] = null ? 'n' : ' ';
}
- snprintf(sql + strlen(sql), SQL_LENGTH - strlen(sql),
- " where usename = '%s'",
- stmt->user);
+ new_tuple = heap_formtuple(pg_shadow_dsc, new_record, new_record_nulls);
+ Assert(new_tuple);
+ /* XXX check return value of this? */
+ heap_update(pg_shadow_rel, &tuple->t_self, new_tuple, NULL);
- pg_exec_query_dest(sql, dest, false);
- /*
- * Add stuff here for groups?
- */
- if (stmt->groupElts)
- elog(NOTICE, "IN GROUP is not implemented for ALTER USER.");
+ /* Update indexes */
+ if (RelationGetForm(pg_shadow_rel)->relhasindex)
+ {
+ Relation idescs[Num_pg_shadow_indices];
+
+ CatalogOpenIndices(Num_pg_shadow_indices,
+ Name_pg_shadow_indices, idescs);
+ CatalogIndexInsert(idescs, Num_pg_shadow_indices, pg_shadow_rel,
+ tuple);
+ CatalogCloseIndices(Num_pg_shadow_indices, idescs);
+ }
/*
* Write the updated pg_shadow data to the flat password file.
- * Because we are still holding AccessExclusiveLock on pg_shadow,
- * we can be sure no other backend will try to write the flat
- * file at the same time.
*/
- update_pg_pwd();
+ write_password_file(pg_shadow_rel);
/*
* Now we can clean up.
*/
heap_close(pg_shadow_rel, AccessExclusiveLock);
- if (IsTransactionBlock() && !inblock)
- EndTransactionBlock();
}
-extern void
-RemoveUser(char *user, CommandDest dest)
+
+/*
+ * DROP USER
+ */
+void
+DropUser(DropUserStmt *stmt)
{
- char *pg_shadow;
- Relation pg_shadow_rel,
- pg_rel;
- TupleDesc pg_dsc;
- HeapScanDesc scan;
- HeapTuple tuple;
- Datum datum;
- char sql[SQL_LENGTH];
- bool n,
- inblock;
- int32 usesysid;
- int ndbase = 0;
- char **dbase = NULL;
+ Relation pg_shadow_rel;
+ TupleDesc pg_shadow_dsc;
+ List *item;
- if (!(inblock = IsTransactionBlock()))
- BeginTransactionBlock();
+ if (!superuser())
+ elog(ERROR, "DROP USER: permission denied");
- /*
- * Make sure the user attempting to create a user can delete from the
- * pg_shadow relation.
- */
- pg_shadow = GetPgUserName();
- if (pg_aclcheck(ShadowRelationName, pg_shadow, ACL_RD | ACL_WR) != ACLCHECK_OK)
- {
- UserAbortTransactionBlock();
- elog(ERROR, "RemoveUser: user \"%s\" does not have SELECT and DELETE privilege for \"%s\"",
- pg_shadow, ShadowRelationName);
- }
+ if (IsTransactionBlock())
+ elog(ERROR, "DROP USER: may not be called in a transaction block");
/*
* Scan the pg_shadow relation to find the usesysid of the user to be
@@ -447,100 +490,109 @@ RemoveUser(char *user, CommandDest dest)
* our update of the flat password file.
*/
pg_shadow_rel = heap_openr(ShadowRelationName, AccessExclusiveLock);
- pg_dsc = RelationGetDescr(pg_shadow_rel);
+ pg_shadow_dsc = RelationGetDescr(pg_shadow_rel);
- tuple = SearchSysCacheTuple(SHADOWNAME,
- PointerGetDatum(user),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
- {
- heap_close(pg_shadow_rel, AccessExclusiveLock);
- UserAbortTransactionBlock();
- elog(ERROR, "RemoveUser: user \"%s\" does not exist", user);
- }
+ foreach(item, stmt->users)
+ {
+ HeapTuple tuple,
+ tmp_tuple;
+ Relation pg_rel;
+ TupleDesc pg_dsc;
+ ScanKeyData scankey;
+ HeapScanDesc scan;
+ Datum datum;
+ bool null;
+ int32 usesysid;
+ const char *user = strVal(lfirst(item));
+
+ tuple = SearchSysCacheTuple(SHADOWNAME,
+ PointerGetDatum(user),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ heap_close(pg_shadow_rel, AccessExclusiveLock);
+ elog(ERROR, "DROP USER: user \"%s\" does not exist%s", user,
+ (length(stmt->users) > 1) ? " (no users removed)" : "");
+ }
- usesysid = (int32) heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_dsc, &n);
+ usesysid = DatumGetInt32(heap_getattr(tuple, Anum_pg_shadow_usesysid, pg_shadow_dsc, &null));
- /*
- * Perform a scan of the pg_database relation to find the databases
- * owned by usesysid. Then drop them.
- */
- pg_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
- pg_dsc = RelationGetDescr(pg_rel);
+ /*-------------------
+ * Check if user still owns a database. If so, error out.
+ *
+ * (It used to be that this function would drop the database automatically.
+ * This is not only very dangerous for people that don't read the manual,
+ * it doesn't seem to be the behaviour one would expect either.)
+ * -- petere 2000/01/14)
+ *-------------------*/
+ pg_rel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
+ pg_dsc = RelationGetDescr(pg_rel);
- scan = heap_beginscan(pg_rel, false, SnapshotNow, 0, NULL);
- while (HeapTupleIsValid(tuple = heap_getnext(scan, 0)))
- {
- datum = heap_getattr(tuple, Anum_pg_database_datdba, pg_dsc, &n);
-
- if ((int) datum == usesysid)
- {
- datum = heap_getattr(tuple, Anum_pg_database_datname, pg_dsc, &n);
- if (memcmp((void *) datum, "template1", 9) != 0)
- {
- dbase =
- (char **) repalloc((void *) dbase, sizeof(char *) * (ndbase + 1));
- dbase[ndbase] = (char *) palloc(NAMEDATALEN + 1);
- memcpy((void *) dbase[ndbase], (void *) datum, NAMEDATALEN);
- dbase[ndbase++][NAMEDATALEN] = '\0';
- }
- }
- }
- heap_endscan(scan);
- heap_close(pg_rel, AccessExclusiveLock);
+ ScanKeyEntryInitialize(&scankey, 0x0, Anum_pg_database_datdba, F_INT4EQ,
+ Int32GetDatum(usesysid));
- while (ndbase--)
- {
- elog(NOTICE, "Dropping database %s", dbase[ndbase]);
- snprintf(sql, SQL_LENGTH, "DROP DATABASE %s", dbase[ndbase]);
- pfree((void *) dbase[ndbase]);
- pg_exec_query_dest(sql, dest, false);
- }
- if (dbase)
- pfree((void *) dbase);
+ scan = heap_beginscan(pg_rel, false, SnapshotNow, 1, &scankey);
- /*
- * Since pg_shadow is global over all databases, one of two things
- * must be done to insure complete consistency. First, pg_shadow
- * could be made non-global. This would elminate the code above for
- * deleting database and would require the addition of code to delete
- * tables, views, etc owned by the user.
- *
- * The second option would be to create a means of deleting tables, view,
- * etc. owned by the user from other databases. pg_shadow is global
- * and so this must be done at some point.
- *
- * Let us not forget that the user should be removed from the pg_groups
- * also.
- *
- * Todd A. Brandys 11/18/1997
- *
- */
+ if (HeapTupleIsValid(tmp_tuple = heap_getnext(scan, 0)))
+ {
+ datum = heap_getattr(tmp_tuple, Anum_pg_database_datname, pg_dsc, &null);
+ heap_close(pg_shadow_rel, AccessExclusiveLock);
+ elog(ERROR, "DROP USER: user \"%s\" owns database \"%s\", cannot be removed%s",
+ user, nameout(DatumGetName(datum)),
+ (length(stmt->users) > 1) ? " (no users removed)" : ""
+ );
+ }
+
+ heap_endscan(scan);
+ heap_close(pg_rel, AccessExclusiveLock);
- /*
- * Remove the user from the pg_shadow table
- */
- snprintf(sql, SQL_LENGTH,
- "delete from %s where usename = '%s'", ShadowRelationName, user);
- pg_exec_query_dest(sql, dest, false);
+ /*
+ * Somehow we'd have to check for tables, views, etc. owned by the user
+ * as well, but those could be spread out over all sorts of databases
+ * which we don't have access to (easily).
+ */
- /*
- * Write the updated pg_shadow data to the flat password file.
- * Because we are still holding AccessExclusiveLock on pg_shadow,
- * we can be sure no other backend will try to write the flat
- * file at the same time.
- */
- update_pg_pwd();
+ /*
+ * Remove the user from the pg_shadow table
+ */
+ heap_delete(pg_shadow_rel, &tuple->t_self, NULL);
+
+ /*
+ * Remove user from groups
+ *
+ * try calling alter group drop user for every group
+ */
+ pg_rel = heap_openr(GroupRelationName, AccessExclusiveLock);
+ pg_dsc = RelationGetDescr(pg_rel);
+ scan = heap_beginscan(pg_rel, false, SnapshotNow, 0, NULL);
+ while (HeapTupleIsValid(tmp_tuple = heap_getnext(scan, 0)))
+ {
+ AlterGroupStmt ags;
+
+ datum = heap_getattr(tmp_tuple, Anum_pg_group_groname, pg_dsc, &null);
+
+ ags.name = nameout(DatumGetName(datum)); /* the group name from which to try to drop the user */
+ ags.action = -1;
+ ags.listUsers = lcons((void*)makeInteger(usesysid), NIL);
+ AlterGroup(&ags, "DROP USER");
+ }
+ heap_endscan(scan);
+ heap_close(pg_rel, AccessExclusiveLock);
+ }
/*
- * Now we can clean up.
+ * Write the updated pg_shadow data to the flat password file.
*/
- heap_close(pg_shadow_rel, AccessExclusiveLock);
+ write_password_file(pg_shadow_rel);
- if (IsTransactionBlock() && !inblock)
- EndTransactionBlock();
+ /*
+ * Now we can clean up.
+ */
+ heap_close(pg_shadow_rel, AccessExclusiveLock);
}
+
+
/*
* CheckPgUserAclNotNull
*
@@ -556,51 +608,56 @@ CheckPgUserAclNotNull()
0, 0, 0);
if (!HeapTupleIsValid(htup))
{
- elog(ERROR, "IsPgUserAclNull: class \"%s\" not found",
+ /* BIG problem */
+ elog(ERROR, "IsPgUserAclNull: \"%s\" not found",
ShadowRelationName);
}
if (heap_attisnull(htup, Anum_pg_class_relacl))
{
- elog(NOTICE, "To use passwords, you have to revoke permissions on pg_shadow");
- elog(NOTICE, "so normal users can not read the passwords.");
- elog(ERROR, "Try 'REVOKE ALL ON pg_shadow FROM PUBLIC'");
+ elog(ERROR,
+ "To use passwords, you have to revoke permissions on %s "
+ "so normal users cannot read the passwords. "
+ "Try 'REVOKE ALL ON \"%s\" FROM PUBLIC'.",
+ ShadowRelationName, ShadowRelationName);
}
return;
}
-/*** GROUP THINGS ***/
+/*
+ * CREATE GROUP
+ */
void
-CreateGroup(CreateGroupStmt *stmt, CommandDest dest)
+CreateGroup(CreateGroupStmt *stmt)
{
Relation pg_group_rel;
HeapScanDesc scan;
HeapTuple tuple;
TupleDesc pg_group_dsc;
- bool inblock;
bool group_exists = false,
sysid_exists = false;
- int max_id = -1;
+ int max_id = 0;
Datum new_record[Natts_pg_group];
char new_record_nulls[Natts_pg_group];
List *item, *newlist=NULL;
ArrayType *userarray;
-
- if (!(inblock = IsTransactionBlock()))
- BeginTransactionBlock();
-
/*
* Make sure the user can do this.
*/
- if (pg_aclcheck(GroupRelationName, GetPgUserName(), ACL_RD | ACL_AP) != ACLCHECK_OK)
- {
- UserAbortTransactionBlock();
- elog(ERROR, "CreateGroup: Permission denied.");
- }
+ if (!superuser())
+ elog(ERROR, "CREATE GROUP: permission denied");
+
+ /*
+ * There is not real reason for this, but it makes it consistent
+ * with create user, and it seems like a good idea anyway.
+ */
+ if (IsTransactionBlock())
+ elog(ERROR, "CREATE GROUP: may not be called in a transaction block");
+
pg_group_rel = heap_openr(GroupRelationName, AccessExclusiveLock);
pg_group_dsc = RelationGetDescr(pg_group_rel);
@@ -628,11 +685,10 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest)
if (group_exists || sysid_exists)
{
heap_close(pg_group_rel, AccessExclusiveLock);
- UserAbortTransactionBlock();
if (group_exists)
- elog(ERROR, "CreateGroup: Group name \"%s\" already exists.", stmt->name);
+ elog(ERROR, "CREATE GROUP: group name \"%s\" already exists", stmt->name);
else
- elog(ERROR, "CreateGroup: Group sysid %d is already assigned.", stmt->sysid);
+ elog(ERROR, "CREATE GROUP: group sysid %d is already assigned", stmt->sysid);
}
/*
@@ -650,8 +706,7 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest)
if (!HeapTupleIsValid(tuple))
{
heap_close(pg_group_rel, AccessExclusiveLock);
- UserAbortTransactionBlock();
- elog(ERROR, "CreateGroup: User \"%s\" does not exist.", groupuser);
+ elog(ERROR, "CREATE GROUP: user \"%s\" does not exist", groupuser);
}
v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid);
@@ -716,33 +771,34 @@ CreateGroup(CreateGroupStmt *stmt, CommandDest dest)
CatalogCloseIndices(Num_pg_group_indices, idescs);
}
- heap_close(pg_group_rel, NoLock);
-
- if (IsTransactionBlock() && !inblock)
- EndTransactionBlock();
+ heap_close(pg_group_rel, AccessExclusiveLock);
}
+/*
+ * ALTER GROUP
+ */
void
-AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
+AlterGroup(AlterGroupStmt *stmt, const char * tag)
{
Relation pg_group_rel;
TupleDesc pg_group_dsc;
- bool inblock;
HeapTuple group_tuple;
- if (!(inblock = IsTransactionBlock()))
- BeginTransactionBlock();
-
- /*
+ /*
* Make sure the user can do this.
*/
- if (pg_aclcheck(GroupRelationName, GetPgUserName(), ACL_RD | ACL_WR) != ACLCHECK_OK)
- {
- UserAbortTransactionBlock();
- elog(ERROR, "AlterGroup: Permission denied.");
- }
+ if (!superuser())
+ elog(ERROR, "%s: permission denied", tag);
+
+ /*
+ * There is not real reason for this, but it makes it consistent
+ * with alter user, and it seems like a good idea anyway.
+ */
+ if (IsTransactionBlock())
+ elog(ERROR, "%s: may not be called in a transaction block", tag);
+
pg_group_rel = heap_openr(GroupRelationName, AccessExclusiveLock);
pg_group_dsc = RelationGetDescr(pg_group_rel);
@@ -755,69 +811,14 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
if (!HeapTupleIsValid(group_tuple = SearchSysCacheTupleCopy(GRONAME, PointerGetDatum(stmt->name), 0, 0, 0)))
{
heap_close(pg_group_rel, AccessExclusiveLock);
- UserAbortTransactionBlock();
- elog(ERROR, "AlterGroup: Group \"%s\" does not exist.", stmt->name);
+ elog(ERROR, "%s: group \"%s\" does not exist", tag, stmt->name);
}
+ AssertState(stmt->action == +1 || stmt->action == -1);
/*
* Now decide what to do.
*/
- if (stmt->action == 0) /* change sysid */
- {
- ScanKeyData keys[2];
- HeapTuple tuple;
- HeapScanDesc scan;
- Datum new_record[Natts_pg_group];
- char new_record_nulls[Natts_pg_group];
- bool null;
-
- /*
- * First check if the id is already assigned.
- */
- ScanKeyEntryInitialize(&keys[0], 0x0, Anum_pg_group_grosysid, F_INT4EQ,
- Int32GetDatum(stmt->sysid));
- ScanKeyEntryInitialize(&keys[1], 0x0, Anum_pg_group_groname, F_NAMENE,
- PointerGetDatum(stmt->name));
- scan = heap_beginscan(pg_group_rel, false, SnapshotNow, 2, keys);
-
- if (HeapTupleIsValid(heap_getnext(scan, false)))
- {
- heap_endscan(scan);
- heap_close(pg_group_rel, AccessExclusiveLock);
- UserAbortTransactionBlock();
- elog(ERROR, "AlterGroup: Group sysid %d is already assigned.", stmt->sysid);
- }
- heap_endscan(scan);
-
- /*
- * Insert the new tuple with the updated sysid
- */
- new_record[Anum_pg_group_groname-1] = (Datum)(stmt->name);
- new_record[Anum_pg_group_grosysid-1] = (Datum)(stmt->sysid);
- new_record[Anum_pg_group_grolist-1] = heap_getattr(group_tuple, Anum_pg_group_grolist, pg_group_dsc, &null);
- new_record_nulls[Anum_pg_group_groname-1] = ' ';
- new_record_nulls[Anum_pg_group_grosysid-1] = ' ';
- new_record_nulls[Anum_pg_group_grolist-1] = null ? 'n' : ' ';
-
- tuple = heap_formtuple(pg_group_dsc, new_record, new_record_nulls);
- heap_update(pg_group_rel, &group_tuple->t_self, tuple, NULL);
-
- /* Update indexes */
- if (RelationGetForm(pg_group_rel)->relhasindex) {
- Relation idescs[Num_pg_group_indices];
-
- CatalogOpenIndices(Num_pg_group_indices,
- Name_pg_group_indices, idescs);
- CatalogIndexInsert(idescs, Num_pg_group_indices, pg_group_rel,
- tuple);
- CatalogCloseIndices(Num_pg_group_indices, idescs);
- }
- }
-
- /*
- * add users to group
- */
- else if (stmt->action > 0)
+ if (stmt->action == +1) /* add users, might also be invoked by create user */
{
Datum new_record[Natts_pg_group];
char new_record_nulls[Natts_pg_group] = { ' ', ' ', ' '};
@@ -853,22 +854,34 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
foreach(item, stmt->listUsers)
{
Value *v;
- /* Get the uid of the proposed user to add. */
- tuple = SearchSysCacheTuple(SHADOWNAME,
- PointerGetDatum(strVal(lfirst(item))),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
+ if (strcmp(tag, "ALTER GROUP")==0)
{
- heap_close(pg_group_rel, AccessExclusiveLock);
- UserAbortTransactionBlock();
- elog(ERROR, "AlterGroup: User \"%s\" does not exist.", strVal(lfirst(item)));
+ /* Get the uid of the proposed user to add. */
+ tuple = SearchSysCacheTuple(SHADOWNAME,
+ PointerGetDatum(strVal(lfirst(item))),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ heap_close(pg_group_rel, AccessExclusiveLock);
+ elog(ERROR, "%s: user \"%s\" does not exist", tag, strVal(lfirst(item)));
+ }
+ v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid);
}
-
- v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid);
+ else if (strcmp(tag, "CREATE USER")==0)
+ {
+ /* in this case we already know the uid and it wouldn't
+ be in the cache anyway yet */
+ v = lfirst(item);
+ }
+ else
+ elog(ERROR, "AlterGroup: unknown tag %s", tag);
+
if (!member(v, newlist))
newlist = lcons(v, newlist);
else
- elog(NOTICE, "AlterGroup: User \"%s\" is already in group \"%s\".", strVal(lfirst(item)), stmt->name);
+ /* we silently assume here that this error will only come up
+ in a ALTER GROUP statement */
+ elog(NOTICE, "%s: user \"%s\" is already in group \"%s\"", tag, strVal(lfirst(item)), stmt->name);
}
newarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32));
@@ -906,17 +919,18 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
}
} /* endif alter group add user */
- /*
- * drop users from group
- */
- else if (stmt->action < 0)
+ else if (stmt->action == -1) /*drop users from group */
{
Datum datum;
bool null;
+ bool is_dropuser = strcmp(tag, "DROP USER")==0;
datum = heap_getattr(group_tuple, Anum_pg_group_grolist, pg_group_dsc, &null);
if (null)
- elog(NOTICE, "AlterGroup: Group \"%s\"'s membership is NULL.", stmt->name);
+ {
+ if (!is_dropuser)
+ elog(NOTICE, "ALTER GROUP: group \"%s\" does not have any members", stmt->name);
+ }
else
{
HeapTuple tuple;
@@ -950,22 +964,28 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
foreach(item, stmt->listUsers)
{
Value *v;
- /* Get the uid of the proposed user to drop. */
- tuple = SearchSysCacheTuple(SHADOWNAME,
- PointerGetDatum(strVal(lfirst(item))),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
+ if (!is_dropuser)
{
- heap_close(pg_group_rel, AccessExclusiveLock);
- UserAbortTransactionBlock();
- elog(ERROR, "AlterGroup: User \"%s\" does not exist.", strVal(lfirst(item)));
+ /* Get the uid of the proposed user to drop. */
+ tuple = SearchSysCacheTuple(SHADOWNAME,
+ PointerGetDatum(strVal(lfirst(item))),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ heap_close(pg_group_rel, AccessExclusiveLock);
+ elog(ERROR, "ALTER GROUP: user \"%s\" does not exist", strVal(lfirst(item)));
+ }
+ v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid);
+ }
+ else
+ {
+ /* for dropuser we already know the uid */
+ v = lfirst(item);
}
-
- v = makeInteger(((Form_pg_shadow) GETSTRUCT(tuple))->usesysid);
if (member(v, newlist))
newlist = LispRemove(v, newlist);
- else
- elog(NOTICE, "AlterGroup: User \"%s\" is not in group \"%s\".", strVal(lfirst(item)), stmt->name);
+ else if (!is_dropuser)
+ elog(NOTICE, "ALTER GROUP: user \"%s\" is not in group \"%s\"", strVal(lfirst(item)), stmt->name);
}
newarray = palloc(ARR_OVERHEAD(1) + length(newlist) * sizeof(int32));
@@ -1005,40 +1025,40 @@ AlterGroup(AlterGroupStmt *stmt, CommandDest dest)
} /* endif group not null */
} /* endif alter group drop user */
- heap_close(pg_group_rel, NoLock);
+ heap_close(pg_group_rel, AccessExclusiveLock);
pfree(group_tuple);
-
- if (IsTransactionBlock() && !inblock)
- EndTransactionBlock();
}
+/*
+ * DROP GROUP
+ */
void
-DropGroup(DropGroupStmt *stmt, CommandDest dest)
+DropGroup(DropGroupStmt *stmt)
{
Relation pg_group_rel;
HeapScanDesc scan;
HeapTuple tuple;
TupleDesc pg_group_dsc;
- bool inblock;
bool gro_exists = false;
- if (!(inblock = IsTransactionBlock()))
- BeginTransactionBlock();
-
- /*
+ /*
* Make sure the user can do this.
*/
- if (pg_aclcheck(GroupRelationName, GetPgUserName(), ACL_RD | ACL_WR) != ACLCHECK_OK)
- {
- UserAbortTransactionBlock();
- elog(ERROR, "DropGroup: Permission denied.");
- }
+ if (!superuser())
+ elog(ERROR, "DROP GROUP: permission denied");
/*
- * Scan the pg_group table and delete all matching users.
+ * There is not real reason for this, but it makes it consistent
+ * with drop user, and it seems like a good idea anyway.
+ */
+ if (IsTransactionBlock())
+ elog(ERROR, "DROP GROUP: may not be called in a transaction block");
+
+ /*
+ * Scan the pg_group table and delete all matching groups.
*/
pg_group_rel = heap_openr(GroupRelationName, AccessExclusiveLock);
pg_group_dsc = RelationGetDescr(pg_group_rel);
@@ -1055,7 +1075,6 @@ DropGroup(DropGroupStmt *stmt, CommandDest dest)
gro_exists = true;
heap_delete(pg_group_rel, &tuple->t_self, NULL);
}
-
}
heap_endscan(scan);
@@ -1067,12 +1086,8 @@ DropGroup(DropGroupStmt *stmt, CommandDest dest)
{
heap_close(pg_group_rel, AccessExclusiveLock);
UserAbortTransactionBlock();
- elog(ERROR, "DropGroup: Group \"%s\" does not exist.", stmt->name);
+ elog(ERROR, "DROP GROUP: group \"%s\" does not exist", stmt->name);
}
- heap_close(pg_group_rel, NoLock);
-
- if (IsTransactionBlock() && !inblock)
- EndTransactionBlock();
+ heap_close(pg_group_rel, AccessExclusiveLock);
}
-
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index e21a26dcd6f..069af39f05f 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.124 2000/01/13 18:26:07 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.125 2000/01/14 22:11:34 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -90,7 +90,6 @@ static Node *doNegate(Node *n);
char chr;
char *str;
bool boolean;
- bool* pboolean; /* for pg_shadow privileges */
List *list;
Node *node;
Value *value;
@@ -137,11 +136,11 @@ static Node *doNegate(Node *n);
%type <ival> opt_lock, lock_type
%type <boolean> opt_lmode
-%type <pboolean> user_createdb_clause, user_createuser_clause
+%type <ival> user_createdb_clause, user_createuser_clause
%type <str> user_passwd_clause
%type <ival> sysid_clause
%type <str> user_valid_clause
-%type <list> user_group_list, user_group_clause, users_in_new_group_clause
+%type <list> user_list, user_group_clause, users_in_new_group_clause
%type <boolean> TriggerActionTime, TriggerForSpec, PLangTrusted
@@ -459,8 +458,8 @@ CreateUserStmt: CREATE USER UserId
n->user = $3;
n->sysid = -1;
n->password = NULL;
- n->createdb = $4;
- n->createuser = $5;
+ n->createdb = $4 == +1 ? true : false;
+ n->createuser = $5 == +1 ? true : false;
n->groupElts = $6;
n->validUntil = $7;
$$ = (Node *)n;
@@ -473,8 +472,8 @@ CreateUserStmt: CREATE USER UserId
n->user = $3;
n->sysid = $5;
n->password = $6;
- n->createdb = $7;
- n->createuser = $8;
+ n->createdb = $7 == +1 ? true : false;
+ n->createuser = $8 == +1 ? true : false;
n->groupElts = $9;
n->validUntil = $10;
$$ = (Node *)n;
@@ -489,30 +488,26 @@ CreateUserStmt: CREATE USER UserId
*****************************************************************************/
AlterUserStmt: ALTER USER UserId user_createdb_clause
- user_createuser_clause user_group_clause user_valid_clause
+ user_createuser_clause user_valid_clause
{
AlterUserStmt *n = makeNode(AlterUserStmt);
n->user = $3;
- n->sysid = -1;
n->password = NULL;
n->createdb = $4;
n->createuser = $5;
- n->groupElts = $6;
- n->validUntil = $7;
+ n->validUntil = $6;
$$ = (Node *)n;
}
- | ALTER USER UserId WITH sysid_clause user_passwd_clause
+ | ALTER USER UserId WITH PASSWORD Sconst
user_createdb_clause
- user_createuser_clause user_group_clause user_valid_clause
+ user_createuser_clause user_valid_clause
{
AlterUserStmt *n = makeNode(AlterUserStmt);
n->user = $3;
- n->sysid = $5;
n->password = $6;
n->createdb = $7;
n->createuser = $8;
- n->groupElts = $9;
- n->validUntil = $10;
+ n->validUntil = $9;
$$ = (Node *)n;
}
;
@@ -524,53 +519,38 @@ AlterUserStmt: ALTER USER UserId user_createdb_clause
*
*****************************************************************************/
-DropUserStmt: DROP USER UserId
+DropUserStmt: DROP USER user_list
{
DropUserStmt *n = makeNode(DropUserStmt);
- n->user = $3;
+ n->users = $3;
$$ = (Node *)n;
}
;
-user_passwd_clause: PASSWORD UserId { $$ = $2; }
+user_passwd_clause: PASSWORD Sconst { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
-sysid_clause: SYSID Iconst { $$ = $2; }
+sysid_clause: SYSID Iconst
+ {
+ if ($2 <= 0)
+ elog(ERROR, "sysid must be positive");
+ $$ = $2;
+ }
| /*EMPTY*/ { $$ = -1; }
;
-user_createdb_clause: CREATEDB
- {
- bool* b;
- $$ = (b = (bool*)palloc(sizeof(bool)));
- *b = true;
- }
- | NOCREATEDB
- {
- bool* b;
- $$ = (b = (bool*)palloc(sizeof(bool)));
- *b = false;
- }
- | /*EMPTY*/ { $$ = NULL; }
+user_createdb_clause: CREATEDB { $$ = +1; }
+ | NOCREATEDB { $$ = -1; }
+ | /*EMPTY*/ { $$ = 0; }
;
-user_createuser_clause: CREATEUSER
- {
- bool* b;
- $$ = (b = (bool*)palloc(sizeof(bool)));
- *b = true;
- }
- | NOCREATEUSER
- {
- bool* b;
- $$ = (b = (bool*)palloc(sizeof(bool)));
- *b = false;
- }
- | /*EMPTY*/ { $$ = NULL; }
+user_createuser_clause: CREATEUSER { $$ = +1; }
+ | NOCREATEUSER { $$ = -1; }
+ | /*EMPTY*/ { $$ = 0; }
;
-user_group_list: user_group_list ',' UserId
+user_list: user_list ',' UserId
{
$$ = lcons((void*)makeString($3), $1);
}
@@ -580,7 +560,7 @@ user_group_list: user_group_list ',' UserId
}
;
-user_group_clause: IN GROUP user_group_list { $$ = $3; }
+user_group_clause: IN GROUP user_list { $$ = $3; }
| /*EMPTY*/ { $$ = NULL; }
;
@@ -615,7 +595,7 @@ CreateGroupStmt: CREATE GROUP UserId
}
;
-users_in_new_group_clause: USER user_group_list { $$ = $2; }
+users_in_new_group_clause: USER user_list { $$ = $2; }
| /* EMPTY */ { $$ = NULL; }
;
@@ -626,17 +606,7 @@ users_in_new_group_clause: USER user_group_list { $$ = $2; }
*
*****************************************************************************/
-AlterGroupStmt: ALTER GROUP UserId WITH SYSID Iconst
- {
- AlterGroupStmt *n = makeNode(AlterGroupStmt);
- n->name = $3;
- n->sysid = $6;
- n->action = 0;
- n->listUsers = NULL;
- $$ = (Node *)n;
- }
- |
- ALTER GROUP UserId ADD USER user_group_list
+AlterGroupStmt: ALTER GROUP UserId ADD USER user_list
{
AlterGroupStmt *n = makeNode(AlterGroupStmt);
n->name = $3;
@@ -646,7 +616,7 @@ AlterGroupStmt: ALTER GROUP UserId WITH SYSID Iconst
$$ = (Node *)n;
}
|
- ALTER GROUP UserId DROP USER user_group_list
+ ALTER GROUP UserId DROP USER user_list
{
AlterGroupStmt *n = makeNode(AlterGroupStmt);
n->name = $3;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 0a97e3acacf..ed1cf862e7f 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.77 2000/01/13 18:26:10 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.78 2000/01/14 22:11:35 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -266,11 +266,7 @@ ProcessUtility(Node *parsetree,
*/
stmt->filename,
stmt->delimiter,
- stmt->null_print,
- /*
- * specify 022 umask while writing files with COPY.
- */
- 0022);
+ stmt->null_print);
}
break;
@@ -775,21 +771,21 @@ ProcessUtility(Node *parsetree,
PS_SET_STATUS(commandTag = "CREATE USER");
CHECK_IF_ABORTED();
- DefineUser((CreateUserStmt *) parsetree, dest);
+ CreateUser((CreateUserStmt *) parsetree);
break;
case T_AlterUserStmt:
PS_SET_STATUS(commandTag = "ALTER USER");
CHECK_IF_ABORTED();
- AlterUser((AlterUserStmt *) parsetree, dest);
+ AlterUser((AlterUserStmt *) parsetree);
break;
case T_DropUserStmt:
PS_SET_STATUS(commandTag = "DROP USER");
CHECK_IF_ABORTED();
- RemoveUser(((DropUserStmt *) parsetree)->user, dest);
+ DropUser((DropUserStmt *) parsetree);
break;
case T_LockStmt:
@@ -810,21 +806,21 @@ ProcessUtility(Node *parsetree,
PS_SET_STATUS(commandTag = "CREATE GROUP");
CHECK_IF_ABORTED();
- CreateGroup((CreateGroupStmt *) parsetree, dest);
+ CreateGroup((CreateGroupStmt *) parsetree);
break;
case T_AlterGroupStmt:
PS_SET_STATUS(commandTag = "ALTER GROUP");
CHECK_IF_ABORTED();
- AlterGroup((AlterGroupStmt *) parsetree, dest);
+ AlterGroup((AlterGroupStmt *) parsetree, "ALTER GROUP");
break;
case T_DropGroupStmt:
PS_SET_STATUS(commandTag = "DROP GROUP");
CHECK_IF_ABORTED();
- DropGroup((DropGroupStmt *) parsetree, dest);
+ DropGroup((DropGroupStmt *) parsetree);
break;
/*
diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c
index c1f0a3231db..51d0d29c7b6 100644
--- a/src/backend/utils/misc/superuser.c
+++ b/src/backend/utils/misc/superuser.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.12 1999/11/24 16:52:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/superuser.c,v 1.13 2000/01/14 22:11:36 petere Exp $
*
* DESCRIPTION
* See superuser().
@@ -18,6 +18,7 @@
#include "postgres.h"
#include "catalog/pg_shadow.h"
#include "utils/syscache.h"
+#include "miscadmin.h"
bool
superuser(void)
@@ -26,12 +27,10 @@ superuser(void)
The Postgres user running this command has Postgres superuser
privileges.
--------------------------------------------------------------------------*/
- extern char *UserName; /* defined in global.c */
-
HeapTuple utup;
utup = SearchSysCacheTuple(SHADOWNAME,
- PointerGetDatum(UserName),
+ PointerGetDatum(GetPgUserName()),
0, 0, 0);
Assert(utup != NULL);
return ((Form_pg_shadow) GETSTRUCT(utup))->usesuper;
diff --git a/src/bin/scripts/createuser b/src/bin/scripts/createuser
index dd184c9a4e8..8849994b6e9 100644
--- a/src/bin/scripts/createuser
+++ b/src/bin/scripts/createuser
@@ -8,7 +8,7 @@
#
#
# IDENTIFICATION
-# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createuser,v 1.5 2000/01/12 19:36:36 petere Exp $
+# $Header: /cvsroot/pgsql/src/bin/scripts/Attic/createuser,v 1.6 2000/01/14 22:11:36 petere Exp $
#
# Note - this should NOT be setuid.
#
@@ -193,7 +193,7 @@ QUERY="CREATE USER \"$NewUser\""
SUBQUERY=
[ "$SysID" ] && SUBQUERY="$SUBQUERY SYSID $SysID"
-[ "$Password" ] && SUBQUERY="$SUBQUERY PASSWORD \"$Password\""
+[ "$Password" ] && SUBQUERY="$SUBQUERY PASSWORD '$Password'"
[ "$SUBQUERY" ] && QUERY="$QUERY WITH $SUBQUERY"
[ "$CanCreateDb" = t ] && QUERY="$QUERY CREATEDB"
diff --git a/src/include/commands/copy.h b/src/include/commands/copy.h
index 1f2af72122b..4560cd3672c 100644
--- a/src/include/commands/copy.h
+++ b/src/include/commands/copy.h
@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: copy.h,v 1.7 1999/12/14 00:08:19 momjian Exp $
+ * $Id: copy.h,v 1.8 2000/01/14 22:11:37 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -15,6 +15,6 @@
void DoCopy(char *relname, bool binary, bool oids, bool from, bool pipe,
- char *filename, char *delim, char *null_print, int fileumask);
+ char *filename, char *delim, char *null_print);
#endif /* COPY_H */
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index 036f1576820..6a52fe613d9 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -11,15 +11,15 @@
#define USER_H
#include "nodes/parsenodes.h"
-#include "tcop/dest.h"
+#include "access/htup.h"
-extern void DefineUser(CreateUserStmt *stmt, CommandDest);
-extern void AlterUser(AlterUserStmt *stmt, CommandDest);
-extern void RemoveUser(char *user, CommandDest);
+extern void CreateUser(CreateUserStmt *stmt);
+extern void AlterUser(AlterUserStmt *stmt);
+extern void DropUser(DropUserStmt *stmt);
-extern void CreateGroup(CreateGroupStmt *stmt, CommandDest dest);
-extern void AlterGroup(AlterGroupStmt *stmt, CommandDest dest);
-extern void DropGroup(DropGroupStmt *stmt, CommandDest dest);
+extern void CreateGroup(CreateGroupStmt *stmt);
+extern void AlterGroup(AlterGroupStmt *stmt, const char * tag);
+extern void DropGroup(DropGroupStmt *stmt);
extern HeapTuple update_pg_pwd(void);
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 714f06d5db0..0b2a2a0e93a 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -6,7 +6,7 @@
*
* Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.92 1999/12/16 17:24:19 momjian Exp $
+ * $Id: parsenodes.h,v 1.93 2000/01/14 22:11:38 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -270,18 +270,26 @@ typedef struct CreateUserStmt
char *user; /* PostgreSQL user login */
char *password; /* PostgreSQL user password */
int sysid; /* PgSQL system id (-1 if don't care) */
- bool *createdb; /* Can the user create databases? */
- bool *createuser; /* Can this user create users? */
+ bool createdb; /* Can the user create databases? */
+ bool createuser; /* Can this user create users? */
List *groupElts; /* The groups the user is a member of */
char *validUntil; /* The time the login is valid until */
} CreateUserStmt;
-typedef CreateUserStmt AlterUserStmt;
+typedef struct AlterUserStmt
+{
+ NodeTag type;
+ char *user; /* PostgreSQL user login */
+ char *password; /* PostgreSQL user password */
+ int createdb; /* Can the user create databases? */
+ int createuser; /* Can this user create users? */
+ char *validUntil; /* The time the login is valid until */
+} AlterUserStmt;
typedef struct DropUserStmt
{
NodeTag type;
- char *user; /* PostgreSQL user login */
+ List *users; /* List of users to remove */
} DropUserStmt;
@@ -301,7 +309,7 @@ typedef struct AlterGroupStmt
{
NodeTag type;
char *name; /* name of group to alter */
- int action; /* +1 = add, -1 = drop, 0 = other (HACK!) */
+ int action; /* +1 = add, -1 = drop user */
int sysid; /* sysid change */
List *listUsers; /* list of users to add/drop */
} AlterGroupStmt;