mirror of https://github.com/postgres/postgres
Create an ALTER DEFAULT PRIVILEGES command, which allows users to adjust
the privileges that will be applied to subsequently-created objects. Such adjustments are always per owning role, and can be restricted to objects created in particular schemas too. A notable benefit is that users can override the traditional default privilege settings, eg, the PUBLIC EXECUTE privilege traditionally granted by default for functions. Petr Jelinek
This commit is contained in:
parent
41f89e3bbc
commit
249724cb01
|
@ -1,4 +1,4 @@
|
|||
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.207 2009/09/22 23:43:37 tgl Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.208 2009/10/05 19:24:32 tgl Exp $ -->
|
||||
<!--
|
||||
Documentation of the system catalogs, directed toward PostgreSQL developers
|
||||
-->
|
||||
|
@ -113,6 +113,11 @@
|
|||
<entry>databases within this database cluster</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-default-acl"><structname>pg_default_acl</structname></link></entry>
|
||||
<entry>default privileges for object types</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><link linkend="catalog-pg-depend"><structname>pg_depend</structname></link></entry>
|
||||
<entry>dependencies between database objects</entry>
|
||||
|
@ -2155,6 +2160,93 @@
|
|||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="catalog-pg-default-acl">
|
||||
<title><structname>pg_default_acl</structname></title>
|
||||
|
||||
<indexterm zone="catalog-pg-default-acl">
|
||||
<primary>pg_default_acl</primary>
|
||||
</indexterm>
|
||||
|
||||
<para>
|
||||
The catalog <structname>pg_default_acl</> stores initial
|
||||
privileges to be assigned to newly created objects.
|
||||
</para>
|
||||
|
||||
<table>
|
||||
<title><structname>pg_default_acl</> Columns</title>
|
||||
|
||||
<tgroup cols="4">
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Name</entry>
|
||||
<entry>Type</entry>
|
||||
<entry>References</entry>
|
||||
<entry>Description</entry>
|
||||
</row>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<row>
|
||||
<entry><structfield>defaclrole</structfield></entry>
|
||||
<entry><type>oid</type></entry>
|
||||
<entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
|
||||
<entry>The OID of the role associated with this entry</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>defaclnamespace</structfield></entry>
|
||||
<entry><type>oid</type></entry>
|
||||
<entry><literal><link linkend="catalog-pg-namespace"><structname>pg_namespace</structname></link>.oid</literal></entry>
|
||||
<entry>The OID of the namespace associated with this entry,
|
||||
or 0 if none</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>defaclobjtype</structfield></entry>
|
||||
<entry><type>char</type></entry>
|
||||
<entry></entry>
|
||||
<entry>
|
||||
Type of object this entry is for:
|
||||
<literal>r</> = relation (table, view),
|
||||
<literal>S</> = sequence,
|
||||
<literal>f</> = function
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row>
|
||||
<entry><structfield>defaclacl</structfield></entry>
|
||||
<entry><type>aclitem[]</type></entry>
|
||||
<entry></entry>
|
||||
<entry>
|
||||
Access privileges that this type of object should have on creation
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<para>
|
||||
A <structname>pg_default_acl</> entry shows the initial privileges to
|
||||
be assigned to an object belonging to the indicated user. There are
|
||||
currently two types of entry: <quote>global</> entries with
|
||||
<structfield>defaclnamespace</> = 0, and <quote>per-schema</> entries
|
||||
that reference a particular schema. If a global entry is present then
|
||||
it <emphasis>overrides</> the normal hard-wired default privileges
|
||||
for the object type. A per-schema entry, if present, represents privileges
|
||||
to be <emphasis>added to</> the global or hard-wired default privileges.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Note that when an ACL entry in another catalog is NULL, it is taken
|
||||
to represent the hard-wired default privileges for its object,
|
||||
<emphasis>not</> whatever might be in <structname>pg_default_acl</>
|
||||
at the moment. <structname>pg_default_acl</> is only consulted during
|
||||
object creation.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
|
||||
<sect1 id="catalog-pg-depend">
|
||||
<title><structname>pg_depend</structname></title>
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.75 2009/09/22 23:43:37 tgl Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.76 2009/10/05 19:24:33 tgl Exp $
|
||||
PostgreSQL documentation
|
||||
Complete list of usable sgml source files in this directory.
|
||||
-->
|
||||
|
@ -9,6 +9,7 @@ Complete list of usable sgml source files in this directory.
|
|||
<!entity alterAggregate system "alter_aggregate.sgml">
|
||||
<!entity alterConversion system "alter_conversion.sgml">
|
||||
<!entity alterDatabase system "alter_database.sgml">
|
||||
<!entity alterDefaultPrivileges system "alter_default_privileges.sgml">
|
||||
<!entity alterDomain system "alter_domain.sgml">
|
||||
<!entity alterForeignDataWrapper system "alter_foreign_data_wrapper.sgml">
|
||||
<!entity alterFunction system "alter_function.sgml">
|
||||
|
|
|
@ -0,0 +1,211 @@
|
|||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/alter_default_privileges.sgml,v 1.1 2009/10/05 19:24:33 tgl Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
<refentry id="SQL-ALTERDEFAULTPRIVILEGES">
|
||||
<refmeta>
|
||||
<refentrytitle id="SQL-ALTERDEFAULTPRIVILEGES-TITLE">ALTER DEFAULT PRIVILEGES</refentrytitle>
|
||||
<manvolnum>7</manvolnum>
|
||||
<refmiscinfo>SQL - Language Statements</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>ALTER DEFAULT PRIVILEGES</refname>
|
||||
<refpurpose>define default access privileges</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<indexterm zone="sql-alterdefaultprivileges">
|
||||
<primary>ALTER DEFAULT PRIVILEGES</primary>
|
||||
</indexterm>
|
||||
|
||||
<refsynopsisdiv>
|
||||
<synopsis>
|
||||
ALTER DEFAULT PRIVILEGES
|
||||
[ FOR { ROLE | USER } <replaceable>target_role</replaceable> [, ...] ]
|
||||
[ IN SCHEMA <replaceable>schema_name</replaceable> [, ...] ]
|
||||
<replaceable class="parameter">abbreviated_grant_or_revoke</replaceable>
|
||||
|
||||
<phrase>where <replaceable class="parameter">abbreviated_grant_or_revoke</replaceable> is one of:</phrase>
|
||||
|
||||
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
|
||||
[,...] | ALL [ PRIVILEGES ] }
|
||||
ON TABLE
|
||||
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
|
||||
|
||||
GRANT { { USAGE | SELECT | UPDATE }
|
||||
[,...] | ALL [ PRIVILEGES ] }
|
||||
ON SEQUENCE
|
||||
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
|
||||
|
||||
GRANT { EXECUTE | ALL [ PRIVILEGES ] }
|
||||
ON FUNCTION
|
||||
TO { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
|
||||
|
||||
REVOKE [ GRANT OPTION FOR ]
|
||||
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
|
||||
[,...] | ALL [ PRIVILEGES ] }
|
||||
ON TABLE
|
||||
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
|
||||
[ CASCADE | RESTRICT ]
|
||||
|
||||
REVOKE [ GRANT OPTION FOR ]
|
||||
{ { USAGE | SELECT | UPDATE }
|
||||
[,...] | ALL [ PRIVILEGES ] }
|
||||
ON SEQUENCE
|
||||
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
|
||||
[ CASCADE | RESTRICT ]
|
||||
|
||||
REVOKE [ GRANT OPTION FOR ]
|
||||
{ EXECUTE | ALL [ PRIVILEGES ] }
|
||||
ON FUNCTION
|
||||
FROM { [ GROUP ] <replaceable class="PARAMETER">role_name</replaceable> | PUBLIC } [, ...]
|
||||
[ CASCADE | RESTRICT ]
|
||||
</synopsis>
|
||||
</refsynopsisdiv>
|
||||
|
||||
<refsect1 id="sql-alterdefaultprivileges-description">
|
||||
<title>Description</title>
|
||||
|
||||
<para>
|
||||
<command>ALTER DEFAULT PRIVILEGES</> allows you to set the privileges
|
||||
that will be applied to objects created in the future. (It does not
|
||||
affect privileges assigned to already-existing objects.) Currently,
|
||||
only the privileges for tables (including views), sequences, and
|
||||
functions can be altered.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
You can change default privileges only for objects that will be created by
|
||||
yourself or by roles that you are a member of. The privileges can be set
|
||||
globally (i.e., for all objects created in the current database),
|
||||
or just for objects created in specified schemas. Default privileges
|
||||
that are specified per-schema are added to whatever the global default
|
||||
privileges are for the particular object type.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As explained under <xref linkend="sql-grant" endterm="sql-grant-title">,
|
||||
the default privileges for any object type normally grant all grantable
|
||||
permissions to the object owner, and may grant some privileges to
|
||||
<literal>PUBLIC</> as well. However, this behavior can be changed by
|
||||
altering the global default privileges with
|
||||
<command>ALTER DEFAULT PRIVILEGES</>.
|
||||
</para>
|
||||
|
||||
<refsect2>
|
||||
<title>Parameters</title>
|
||||
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term><replaceable>target_role</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of an existing role of which the current role is a member.
|
||||
If <literal>FOR ROLE</> is omitted, the current role is assumed.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable>schema_name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of an existing schema. Each <replaceable>target_role</>
|
||||
must have <literal>CREATE</> privileges for each specified schema.
|
||||
If <literal>IN SCHEMA</> is omitted, the global default privileges
|
||||
are altered.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><replaceable>role_name</replaceable></term>
|
||||
<listitem>
|
||||
<para>
|
||||
The name of an existing role to grant or revoke privileges for.
|
||||
This parameter, and all the other parameters in
|
||||
<replaceable class="parameter">abbreviated_grant_or_revoke</>,
|
||||
act as described under
|
||||
<xref linkend="sql-grant" endterm="sql-grant-title"> or
|
||||
<xref linkend="sql-revoke" endterm="sql-revoke-title">,
|
||||
except that one is setting permissions for a whole class of objects
|
||||
rather than specific named objects.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="sql-alterdefaultprivileges-notes">
|
||||
<title>Notes</title>
|
||||
|
||||
<para>
|
||||
Use <xref linkend="app-psql">'s <command>\ddp</command> command
|
||||
to obtain information about existing assignments of default privileges.
|
||||
The meaning of the privilege values is the same as explained for
|
||||
<command>\dp</command> under
|
||||
<xref linkend="sql-grant" endterm="sql-grant-title">.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you wish to drop a role that has had its global default privileges
|
||||
altered, it is necessary to use <command>DROP OWNED BY</> first,
|
||||
to get rid of the default privileges entry for the role.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1 id="sql-alterdefaultprivileges-examples">
|
||||
<title>Examples</title>
|
||||
|
||||
<para>
|
||||
Grant SELECT privilege to everyone for all tables (and views) you
|
||||
subsequently create in schema <literal>myschema</literal>, and allow
|
||||
role <literal>webuser</> to INSERT into them too:
|
||||
|
||||
<programlisting>
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA myschema GRANT SELECT ON TABLE TO PUBLIC;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA myschema GRANT INSERT ON TABLE TO webuser;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Undo the above, so that subsequently-created tables won't have any
|
||||
more permissions than normal:
|
||||
|
||||
<programlisting>
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA myschema REVOKE SELECT ON TABLE FROM PUBLIC;
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA myschema REVOKE INSERT ON TABLE FROM webuser;
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Remove the public EXECUTE permission that is normally granted on functions,
|
||||
for all functions subsequently created by role <literal>admin</>:
|
||||
|
||||
<programlisting>
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE admin REVOKE EXECUTE ON FUNCTION FROM PUBLIC;
|
||||
</programlisting>
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Compatibility</title>
|
||||
|
||||
<para>
|
||||
There is no <command>ALTER DEFAULT PRIVILEGES</command> statement in the SQL
|
||||
standard.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>See Also</title>
|
||||
|
||||
<simplelist type="inline">
|
||||
<member><xref linkend="sql-grant" endterm="sql-grant-title"></member>
|
||||
<member><xref linkend="sql-revoke" endterm="sql-revoke-title"></member>
|
||||
</simplelist>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.77 2009/09/19 10:23:27 petere Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.78 2009/10/05 19:24:34 tgl Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
|
@ -80,14 +80,6 @@ GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replace
|
|||
they are different enough to be described separately.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As of <productname>PostgreSQL</productname> 8.1, the concepts of users and
|
||||
groups have been unified into a single kind of entity called a role.
|
||||
It is therefore no longer necessary to use the keyword <literal>GROUP</>
|
||||
to identify whether a grantee is a user or a group. <literal>GROUP</>
|
||||
is still allowed in the command, but it is a noise word.
|
||||
</para>
|
||||
|
||||
<refsect2 id="sql-grant-description-objects">
|
||||
<title>GRANT on Database Objects</title>
|
||||
|
||||
|
@ -145,6 +137,9 @@ GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replace
|
|||
security, issue the <command>REVOKE</> in the same transaction that
|
||||
creates the object; then there is no window in which another user
|
||||
can use the object.)
|
||||
Also, these initial default privilege settings can be changed using the
|
||||
<xref linkend="sql-alterdefaultprivileges" endterm="sql-alterdefaultprivileges-title">
|
||||
command.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -388,6 +383,14 @@ GRANT <replaceable class="PARAMETER">role_name</replaceable> [, ...] TO <replace
|
|||
to revoke access privileges.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Since <productname>PostgreSQL</productname> 8.1, the concepts of users and
|
||||
groups have been unified into a single kind of entity called a role.
|
||||
It is therefore no longer necessary to use the keyword <literal>GROUP</>
|
||||
to identify whether a grantee is a user or a group. <literal>GROUP</>
|
||||
is still allowed in the command, but it is a noise word.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A user may perform <command>SELECT</>, <command>INSERT</>, etc. on a
|
||||
column if he holds that privilege for either the specific column or
|
||||
|
@ -518,8 +521,13 @@ GRANT SELECT (col1), UPDATE (col1) ON mytable TO miriam_rw;
|
|||
<command>REVOKE</> on an object
|
||||
will instantiate the default privileges (producing, for example,
|
||||
<literal>{miriam=arwdDxt/miriam}</>) and then modify them per the
|
||||
specified request. Entries are shown in <quote>Column access
|
||||
specified request. Similarly, entries are shown in <quote>Column access
|
||||
privileges</> only for columns with nondefault privileges.
|
||||
(Note: for this purpose, <quote>default privileges</> always means the
|
||||
built-in default privileges for the object's type. An object whose
|
||||
privileges have been affected by an <command>ALTER DEFAULT PRIVILEGES</>
|
||||
command will always be shown with an explicit privilege entry that
|
||||
includes the effects of the <command>ALTER</>.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
|
@ -602,9 +610,10 @@ GRANT admins TO joe;
|
|||
<refsect1>
|
||||
<title>See Also</title>
|
||||
|
||||
<simpara>
|
||||
<xref linkend="sql-revoke" endterm="sql-revoke-title">
|
||||
</simpara>
|
||||
<simplelist type="inline">
|
||||
<member><xref linkend="sql-revoke" endterm="sql-revoke-title"></member>
|
||||
<member><xref linkend="sql-alterdefaultprivileges" endterm="sql-alterdefaultprivileges-title"></member>
|
||||
</simplelist>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<!--
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.229 2009/08/11 12:02:58 momjian Exp $
|
||||
$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.230 2009/10/05 19:24:34 tgl Exp $
|
||||
PostgreSQL documentation
|
||||
-->
|
||||
|
||||
|
@ -978,6 +978,29 @@ testdb=>
|
|||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>\ddp [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
|
||||
<listitem>
|
||||
<para>
|
||||
Lists default access privilege settings. An entry is shown for
|
||||
each role (and schema, if applicable) for which the default
|
||||
privilege settings have been changed from the built-in defaults.
|
||||
If <replaceable class="parameter">pattern</replaceable> is
|
||||
specified, only entries whose role name or schema name matches
|
||||
the pattern are listed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <xref linkend="sql-alterdefaultprivileges"
|
||||
endterm="sql-alterdefaultprivileges-title"> command is used to set
|
||||
default access privileges. The meaning of the
|
||||
privilege display is explained under
|
||||
<xref linkend="sql-grant" endterm="sql-grant-title">.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
|
||||
<varlistentry>
|
||||
<term><literal>\dD[S] [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
|
||||
<listitem>
|
||||
|
@ -1142,8 +1165,8 @@ testdb=>
|
|||
class="parameter">pattern</replaceable> is specified, only
|
||||
those roles whose names match the pattern are listed.
|
||||
(This command is now effectively the same as <literal>\du</literal>).
|
||||
If the form <literal>\dg+</literal> is used, additional information
|
||||
is shown about each role, including the comment for each role.
|
||||
If the form <literal>\dg+</literal> is used, additional information
|
||||
is shown about each role, including the comment for each role.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -1235,7 +1258,9 @@ testdb=>
|
|||
<para>
|
||||
The <xref linkend="sql-grant" endterm="sql-grant-title"> and
|
||||
<xref linkend="sql-revoke" endterm="sql-revoke-title">
|
||||
commands are used to set access privileges.
|
||||
commands are used to set access privileges. The meaning of the
|
||||
privilege display is explained under
|
||||
<xref linkend="sql-grant" endterm="sql-grant-title">.
|
||||
</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
@ -2045,12 +2070,6 @@ lo_import 152801
|
|||
specified, only tables,views and sequences whose names match the pattern are listed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <xref linkend="sql-grant" endterm="sql-grant-title"> and
|
||||
<xref linkend="sql-revoke" endterm="sql-revoke-title">
|
||||
commands are used to set access privileges.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This is an alias for <command>\dp</command> (<quote>display
|
||||
privileges</quote>).
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<!-- $PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.68 2009/09/22 23:43:37 tgl Exp $ -->
|
||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.69 2009/10/05 19:24:33 tgl Exp $ -->
|
||||
|
||||
<part id="reference">
|
||||
<title>Reference</title>
|
||||
|
@ -37,6 +37,7 @@
|
|||
&alterAggregate;
|
||||
&alterConversion;
|
||||
&alterDatabase;
|
||||
&alterDefaultPrivileges;
|
||||
&alterDomain;
|
||||
&alterForeignDataWrapper;
|
||||
&alterFunction;
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.99 2009/09/27 01:32:11 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.100 2009/10/05 19:24:34 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -226,6 +226,7 @@ Boot_CreateStmt:
|
|||
0,
|
||||
ONCOMMIT_NOOP,
|
||||
(Datum) 0,
|
||||
false,
|
||||
true);
|
||||
elog(DEBUG4, "relation created with oid %u", id);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
#
|
||||
# Makefile for backend/catalog
|
||||
#
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.71 2009/08/26 22:24:43 petere Exp $
|
||||
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.72 2009/10/05 19:24:34 tgl Exp $
|
||||
#
|
||||
#-------------------------------------------------------------------------
|
||||
|
||||
|
@ -37,6 +37,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
|
|||
pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \
|
||||
pg_ts_parser.h pg_ts_template.h \
|
||||
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
|
||||
pg_default_acl.h \
|
||||
toasting.h indexing.h \
|
||||
)
|
||||
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.154 2009/06/11 14:48:54 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.155 2009/10/05 19:24:35 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* See acl.h.
|
||||
|
@ -27,6 +27,7 @@
|
|||
#include "catalog/pg_authid.h"
|
||||
#include "catalog/pg_conversion.h"
|
||||
#include "catalog/pg_database.h"
|
||||
#include "catalog/pg_default_acl.h"
|
||||
#include "catalog/pg_foreign_data_wrapper.h"
|
||||
#include "catalog/pg_foreign_server.h"
|
||||
#include "catalog/pg_language.h"
|
||||
|
@ -51,6 +52,51 @@
|
|||
#include "utils/tqual.h"
|
||||
|
||||
|
||||
/*
|
||||
* The information about one Grant/Revoke statement, in internal format: object
|
||||
* and grantees names have been turned into Oids, the privilege list is an
|
||||
* AclMode bitmask. If 'privileges' is ACL_NO_RIGHTS (the 0 value) and
|
||||
* all_privs is true, 'privileges' will be internally set to the right kind of
|
||||
* ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the
|
||||
* InternalGrant struct!)
|
||||
*
|
||||
* Note: 'all_privs' and 'privileges' represent object-level privileges only.
|
||||
* There might also be column-level privilege specifications, which are
|
||||
* represented in col_privs (this is a list of untransformed AccessPriv nodes).
|
||||
* Column privileges are only valid for objtype ACL_OBJECT_RELATION.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool is_grant;
|
||||
GrantObjectType objtype;
|
||||
List *objects;
|
||||
bool all_privs;
|
||||
AclMode privileges;
|
||||
List *col_privs;
|
||||
List *grantees;
|
||||
bool grant_option;
|
||||
DropBehavior behavior;
|
||||
} InternalGrant;
|
||||
|
||||
/*
|
||||
* Internal format used by ALTER DEFAULT PRIVILEGES.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
Oid roleid; /* owning role */
|
||||
Oid nspid; /* namespace, or InvalidOid if none */
|
||||
/* remaining fields are same as in InternalGrant: */
|
||||
bool is_grant;
|
||||
GrantObjectType objtype;
|
||||
bool all_privs;
|
||||
AclMode privileges;
|
||||
List *grantees;
|
||||
bool grant_option;
|
||||
DropBehavior behavior;
|
||||
} InternalDefaultACL;
|
||||
|
||||
|
||||
static void ExecGrantStmt_oids(InternalGrant *istmt);
|
||||
static void ExecGrant_Relation(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Database(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Fdw(InternalGrant *grantStmt);
|
||||
|
@ -60,6 +106,9 @@ static void ExecGrant_Language(InternalGrant *grantStmt);
|
|||
static void ExecGrant_Namespace(InternalGrant *grantStmt);
|
||||
static void ExecGrant_Tablespace(InternalGrant *grantStmt);
|
||||
|
||||
static void SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames);
|
||||
static void SetDefaultACL(InternalDefaultACL *iacls);
|
||||
|
||||
static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
|
||||
static void expand_col_privileges(List *colnames, Oid table_oid,
|
||||
AclMode this_privileges,
|
||||
|
@ -361,11 +410,11 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
|||
errormsg = gettext_noop("invalid privilege type %s for foreign server");
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
|
||||
(int) stmt->objtype);
|
||||
/* keep compiler quiet */
|
||||
all_privileges = ACL_NO_RIGHTS;
|
||||
errormsg = NULL;
|
||||
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
|
||||
(int) stmt->objtype);
|
||||
}
|
||||
|
||||
if (stmt->privileges == NIL)
|
||||
|
@ -421,11 +470,9 @@ ExecuteGrantStmt(GrantStmt *stmt)
|
|||
/*
|
||||
* ExecGrantStmt_oids
|
||||
*
|
||||
* "Internal" entrypoint for granting and revoking privileges. This is
|
||||
* exported for pg_shdepend.c to use in revoking privileges when dropping
|
||||
* a role.
|
||||
* Internal entry point for granting and revoking privileges.
|
||||
*/
|
||||
void
|
||||
static void
|
||||
ExecGrantStmt_oids(InternalGrant *istmt)
|
||||
{
|
||||
switch (istmt->objtype)
|
||||
|
@ -609,6 +656,563 @@ objectNamesToOids(GrantObjectType objtype, List *objnames)
|
|||
return objects;
|
||||
}
|
||||
|
||||
/*
|
||||
* ALTER DEFAULT PRIVILEGES statement
|
||||
*/
|
||||
void
|
||||
ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
|
||||
{
|
||||
GrantStmt *action = stmt->action;
|
||||
InternalDefaultACL iacls;
|
||||
ListCell *cell;
|
||||
List *rolenames = NIL;
|
||||
List *nspnames = NIL;
|
||||
DefElem *drolenames = NULL;
|
||||
DefElem *dnspnames = NULL;
|
||||
AclMode all_privileges;
|
||||
const char *errormsg;
|
||||
|
||||
/* Deconstruct the "options" part of the statement */
|
||||
foreach(cell, stmt->options)
|
||||
{
|
||||
DefElem *defel = (DefElem *) lfirst(cell);
|
||||
|
||||
if (strcmp(defel->defname, "schemas") == 0)
|
||||
{
|
||||
if (dnspnames)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
dnspnames = defel;
|
||||
}
|
||||
else if (strcmp(defel->defname, "roles") == 0)
|
||||
{
|
||||
if (drolenames)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_SYNTAX_ERROR),
|
||||
errmsg("conflicting or redundant options")));
|
||||
drolenames = defel;
|
||||
}
|
||||
else
|
||||
elog(ERROR, "option \"%s\" not recognized", defel->defname);
|
||||
}
|
||||
|
||||
if (dnspnames)
|
||||
nspnames = (List *) dnspnames->arg;
|
||||
if (drolenames)
|
||||
rolenames = (List *) drolenames->arg;
|
||||
|
||||
/* Prepare the InternalDefaultACL representation of the statement */
|
||||
/* roleid to be filled below */
|
||||
/* nspid to be filled in SetDefaultACLsInSchemas */
|
||||
iacls.is_grant = action->is_grant;
|
||||
iacls.objtype = action->objtype;
|
||||
/* all_privs to be filled below */
|
||||
/* privileges to be filled below */
|
||||
iacls.grantees = NIL; /* filled below */
|
||||
iacls.grant_option = action->grant_option;
|
||||
iacls.behavior = action->behavior;
|
||||
|
||||
/*
|
||||
* Convert the PrivGrantee list into an Oid list. Note that at this point
|
||||
* we insert an ACL_ID_PUBLIC into the list if an empty role name is
|
||||
* detected (which is what the grammar uses if PUBLIC is found), so
|
||||
* downstream there shouldn't be any additional work needed to support
|
||||
* this case.
|
||||
*/
|
||||
foreach(cell, action->grantees)
|
||||
{
|
||||
PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
|
||||
|
||||
if (grantee->rolname == NULL)
|
||||
iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
|
||||
else
|
||||
iacls.grantees =
|
||||
lappend_oid(iacls.grantees,
|
||||
get_roleid_checked(grantee->rolname));
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert action->privileges, a list of privilege strings,
|
||||
* into an AclMode bitmask.
|
||||
*/
|
||||
switch (action->objtype)
|
||||
{
|
||||
case ACL_OBJECT_RELATION:
|
||||
all_privileges = ACL_ALL_RIGHTS_RELATION;
|
||||
errormsg = gettext_noop("invalid privilege type %s for relation");
|
||||
break;
|
||||
case ACL_OBJECT_SEQUENCE:
|
||||
all_privileges = ACL_ALL_RIGHTS_SEQUENCE;
|
||||
errormsg = gettext_noop("invalid privilege type %s for sequence");
|
||||
break;
|
||||
case ACL_OBJECT_FUNCTION:
|
||||
all_privileges = ACL_ALL_RIGHTS_FUNCTION;
|
||||
errormsg = gettext_noop("invalid privilege type %s for function");
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
|
||||
(int) action->objtype);
|
||||
/* keep compiler quiet */
|
||||
all_privileges = ACL_NO_RIGHTS;
|
||||
errormsg = NULL;
|
||||
}
|
||||
|
||||
if (action->privileges == NIL)
|
||||
{
|
||||
iacls.all_privs = true;
|
||||
|
||||
/*
|
||||
* will be turned into ACL_ALL_RIGHTS_* by the internal routines
|
||||
* depending on the object type
|
||||
*/
|
||||
iacls.privileges = ACL_NO_RIGHTS;
|
||||
}
|
||||
else
|
||||
{
|
||||
iacls.all_privs = false;
|
||||
iacls.privileges = ACL_NO_RIGHTS;
|
||||
|
||||
foreach(cell, action->privileges)
|
||||
{
|
||||
AccessPriv *privnode = (AccessPriv *) lfirst(cell);
|
||||
AclMode priv;
|
||||
|
||||
if (privnode->cols)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
||||
errmsg("default privileges cannot be set for columns")));
|
||||
|
||||
if (privnode->priv_name == NULL) /* parser mistake? */
|
||||
elog(ERROR, "AccessPriv node must specify privilege");
|
||||
priv = string_to_privilege(privnode->priv_name);
|
||||
|
||||
if (priv & ~((AclMode) all_privileges))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
|
||||
errmsg(errormsg, privilege_to_string(priv))));
|
||||
|
||||
iacls.privileges |= priv;
|
||||
}
|
||||
}
|
||||
|
||||
if (rolenames == NIL)
|
||||
{
|
||||
/* Set permissions for myself */
|
||||
iacls.roleid = GetUserId();
|
||||
|
||||
SetDefaultACLsInSchemas(&iacls, nspnames);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Look up the role OIDs and do permissions checks */
|
||||
ListCell *rolecell;
|
||||
|
||||
foreach(rolecell, rolenames)
|
||||
{
|
||||
char *rolename = strVal(lfirst(rolecell));
|
||||
|
||||
iacls.roleid = get_roleid_checked(rolename);
|
||||
|
||||
/*
|
||||
* We insist that calling user be a member of each target role.
|
||||
* If he has that, he could become that role anyway via SET ROLE,
|
||||
* so FOR ROLE is just a syntactic convenience and doesn't give
|
||||
* any special privileges.
|
||||
*/
|
||||
check_is_member_of_role(GetUserId(), iacls.roleid);
|
||||
|
||||
SetDefaultACLsInSchemas(&iacls, nspnames);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Process ALTER DEFAULT PRIVILEGES for a list of target schemas
|
||||
*
|
||||
* All fields of *iacls except nspid were filled already
|
||||
*/
|
||||
static void
|
||||
SetDefaultACLsInSchemas(InternalDefaultACL *iacls, List *nspnames)
|
||||
{
|
||||
if (nspnames == NIL)
|
||||
{
|
||||
/* Set database-wide permissions if no schema was specified */
|
||||
iacls->nspid = InvalidOid;
|
||||
|
||||
SetDefaultACL(iacls);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Look up the schema OIDs and do permissions checks */
|
||||
ListCell *nspcell;
|
||||
|
||||
foreach(nspcell, nspnames)
|
||||
{
|
||||
char *nspname = strVal(lfirst(nspcell));
|
||||
AclResult aclresult;
|
||||
|
||||
/*
|
||||
* Normally we'd use LookupCreationNamespace here, but it's
|
||||
* important to do the permissions check against the target role
|
||||
* not the calling user, so write it out in full. We require
|
||||
* CREATE privileges, since without CREATE you won't be able to do
|
||||
* anything using the default privs anyway.
|
||||
*/
|
||||
iacls->nspid = GetSysCacheOid(NAMESPACENAME,
|
||||
CStringGetDatum(nspname),
|
||||
0, 0, 0);
|
||||
if (!OidIsValid(iacls->nspid))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_SCHEMA),
|
||||
errmsg("schema \"%s\" does not exist", nspname)));
|
||||
|
||||
aclresult = pg_namespace_aclcheck(iacls->nspid, iacls->roleid,
|
||||
ACL_CREATE);
|
||||
if (aclresult != ACLCHECK_OK)
|
||||
aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
|
||||
nspname);
|
||||
|
||||
SetDefaultACL(iacls);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Create or update a pg_default_acl entry
|
||||
*/
|
||||
static void
|
||||
SetDefaultACL(InternalDefaultACL *iacls)
|
||||
{
|
||||
AclMode this_privileges = iacls->privileges;
|
||||
char objtype;
|
||||
Relation rel;
|
||||
HeapTuple tuple;
|
||||
bool isNew;
|
||||
Acl *old_acl;
|
||||
Acl *new_acl;
|
||||
HeapTuple newtuple;
|
||||
Datum values[Natts_pg_default_acl];
|
||||
bool nulls[Natts_pg_default_acl];
|
||||
bool replaces[Natts_pg_default_acl];
|
||||
int noldmembers;
|
||||
int nnewmembers;
|
||||
Oid *oldmembers;
|
||||
Oid *newmembers;
|
||||
|
||||
rel = heap_open(DefaultAclRelationId, RowExclusiveLock);
|
||||
|
||||
/*
|
||||
* Convert ACL object type to pg_default_acl object type
|
||||
* and handle all_privs option
|
||||
*/
|
||||
switch (iacls->objtype)
|
||||
{
|
||||
case ACL_OBJECT_RELATION:
|
||||
objtype = DEFACLOBJ_RELATION;
|
||||
if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
|
||||
this_privileges = ACL_ALL_RIGHTS_RELATION;
|
||||
break;
|
||||
|
||||
case ACL_OBJECT_SEQUENCE:
|
||||
objtype = DEFACLOBJ_SEQUENCE;
|
||||
if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
|
||||
this_privileges = ACL_ALL_RIGHTS_SEQUENCE;
|
||||
break;
|
||||
|
||||
case ACL_OBJECT_FUNCTION:
|
||||
objtype = DEFACLOBJ_FUNCTION;
|
||||
if (iacls->all_privs && this_privileges == ACL_NO_RIGHTS)
|
||||
this_privileges = ACL_ALL_RIGHTS_FUNCTION;
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized objtype: %d",
|
||||
(int) iacls->objtype);
|
||||
objtype = 0; /* keep compiler quiet */
|
||||
break;
|
||||
}
|
||||
|
||||
/* Search for existing row for this object type in catalog */
|
||||
tuple = SearchSysCache(DEFACLROLENSPOBJ,
|
||||
ObjectIdGetDatum(iacls->roleid),
|
||||
ObjectIdGetDatum(iacls->nspid),
|
||||
CharGetDatum(objtype),
|
||||
0);
|
||||
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
|
||||
aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
|
||||
Anum_pg_default_acl_defaclacl,
|
||||
&isNull);
|
||||
if (!isNull)
|
||||
old_acl = DatumGetAclPCopy(aclDatum);
|
||||
else
|
||||
old_acl = NULL;
|
||||
isNew = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
old_acl = NULL;
|
||||
isNew = true;
|
||||
}
|
||||
|
||||
if (old_acl == NULL)
|
||||
{
|
||||
/*
|
||||
* If we are creating a global entry, start with the hard-wired
|
||||
* defaults and modify as per command. Otherwise, start with an empty
|
||||
* ACL and modify that. This is needed because global entries
|
||||
* replace the hard-wired defaults, while others do not.
|
||||
*/
|
||||
if (!OidIsValid(iacls->nspid))
|
||||
old_acl = acldefault(iacls->objtype, iacls->roleid);
|
||||
else
|
||||
old_acl = make_empty_acl();
|
||||
}
|
||||
|
||||
/*
|
||||
* We need the members of both old and new ACLs so we can correct the
|
||||
* shared dependency information. Collect data before
|
||||
* merge_acl_with_grant throws away old_acl.
|
||||
*/
|
||||
noldmembers = aclmembers(old_acl, &oldmembers);
|
||||
|
||||
/*
|
||||
* Generate new ACL. Grantor of rights is always the same as the
|
||||
* target role.
|
||||
*/
|
||||
new_acl = merge_acl_with_grant(old_acl,
|
||||
iacls->is_grant,
|
||||
iacls->grant_option,
|
||||
iacls->behavior,
|
||||
iacls->grantees,
|
||||
this_privileges,
|
||||
iacls->roleid,
|
||||
iacls->roleid);
|
||||
|
||||
/* finished building new ACL value, now insert it */
|
||||
MemSet(values, 0, sizeof(values));
|
||||
MemSet(nulls, false, sizeof(nulls));
|
||||
MemSet(replaces, false, sizeof(replaces));
|
||||
|
||||
if (isNew)
|
||||
{
|
||||
values[Anum_pg_default_acl_defaclrole - 1] = ObjectIdGetDatum(iacls->roleid);
|
||||
values[Anum_pg_default_acl_defaclnamespace - 1] = ObjectIdGetDatum(iacls->nspid);
|
||||
values[Anum_pg_default_acl_defaclobjtype - 1] = CharGetDatum(objtype);
|
||||
values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
|
||||
|
||||
newtuple = heap_form_tuple(RelationGetDescr(rel), values, nulls);
|
||||
simple_heap_insert(rel, newtuple);
|
||||
}
|
||||
else
|
||||
{
|
||||
values[Anum_pg_default_acl_defaclacl - 1] = PointerGetDatum(new_acl);
|
||||
replaces[Anum_pg_default_acl_defaclacl - 1] = true;
|
||||
|
||||
newtuple = heap_modify_tuple(tuple, RelationGetDescr(rel),
|
||||
values, nulls, replaces);
|
||||
simple_heap_update(rel, &newtuple->t_self, newtuple);
|
||||
}
|
||||
|
||||
/* keep the catalog indexes up to date */
|
||||
CatalogUpdateIndexes(rel, newtuple);
|
||||
|
||||
/* these dependencies don't change in an update */
|
||||
if (isNew)
|
||||
{
|
||||
/* dependency on role */
|
||||
recordDependencyOnOwner(DefaultAclRelationId,
|
||||
HeapTupleGetOid(newtuple),
|
||||
iacls->roleid);
|
||||
|
||||
/* dependency on namespace */
|
||||
if (OidIsValid(iacls->nspid))
|
||||
{
|
||||
ObjectAddress myself,
|
||||
referenced;
|
||||
|
||||
myself.classId = DefaultAclRelationId;
|
||||
myself.objectId = HeapTupleGetOid(newtuple);
|
||||
myself.objectSubId = 0;
|
||||
|
||||
referenced.classId = NamespaceRelationId;
|
||||
referenced.objectId = iacls->nspid;
|
||||
referenced.objectSubId = 0;
|
||||
|
||||
recordDependencyOn(&myself, &referenced, DEPENDENCY_AUTO);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Update the shared dependency ACL info
|
||||
*/
|
||||
nnewmembers = aclmembers(new_acl, &newmembers);
|
||||
|
||||
updateAclDependencies(DefaultAclRelationId, HeapTupleGetOid(newtuple), 0,
|
||||
iacls->roleid, iacls->is_grant,
|
||||
noldmembers, oldmembers,
|
||||
nnewmembers, newmembers);
|
||||
|
||||
pfree(new_acl);
|
||||
|
||||
if (HeapTupleIsValid(tuple))
|
||||
ReleaseSysCache(tuple);
|
||||
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* RemoveRoleFromObjectACL
|
||||
*
|
||||
* Used by shdepDropOwned to remove mentions of a role in ACLs
|
||||
*/
|
||||
void
|
||||
RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid)
|
||||
{
|
||||
if (classid == DefaultAclRelationId)
|
||||
{
|
||||
InternalDefaultACL iacls;
|
||||
Form_pg_default_acl pg_default_acl_tuple;
|
||||
Relation rel;
|
||||
ScanKeyData skey[1];
|
||||
SysScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
|
||||
/* first fetch info needed by SetDefaultACL */
|
||||
rel = heap_open(DefaultAclRelationId, AccessShareLock);
|
||||
|
||||
ScanKeyInit(&skey[0],
|
||||
ObjectIdAttributeNumber,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(objid));
|
||||
|
||||
scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
|
||||
SnapshotNow, 1, skey);
|
||||
|
||||
tuple = systable_getnext(scan);
|
||||
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "could not find tuple for default ACL %u", objid);
|
||||
|
||||
pg_default_acl_tuple = (Form_pg_default_acl) GETSTRUCT(tuple);
|
||||
|
||||
iacls.roleid = pg_default_acl_tuple->defaclrole;
|
||||
iacls.nspid = pg_default_acl_tuple->defaclnamespace;
|
||||
|
||||
switch (pg_default_acl_tuple->defaclobjtype)
|
||||
{
|
||||
case DEFACLOBJ_RELATION:
|
||||
iacls.objtype = ACL_OBJECT_RELATION;
|
||||
break;
|
||||
case ACL_OBJECT_SEQUENCE:
|
||||
iacls.objtype = ACL_OBJECT_SEQUENCE;
|
||||
break;
|
||||
case DEFACLOBJ_FUNCTION:
|
||||
iacls.objtype = ACL_OBJECT_FUNCTION;
|
||||
break;
|
||||
default:
|
||||
/* Shouldn't get here */
|
||||
elog(ERROR, "unexpected default ACL type %d",
|
||||
pg_default_acl_tuple->defaclobjtype);
|
||||
break;
|
||||
}
|
||||
|
||||
systable_endscan(scan);
|
||||
heap_close(rel, AccessShareLock);
|
||||
|
||||
iacls.is_grant = false;
|
||||
iacls.all_privs = true;
|
||||
iacls.privileges = ACL_NO_RIGHTS;
|
||||
iacls.grantees = list_make1_oid(roleid);
|
||||
iacls.grant_option = false;
|
||||
iacls.behavior = DROP_CASCADE;
|
||||
|
||||
/* Do it */
|
||||
SetDefaultACL(&iacls);
|
||||
}
|
||||
else
|
||||
{
|
||||
InternalGrant istmt;
|
||||
|
||||
switch (classid)
|
||||
{
|
||||
case RelationRelationId:
|
||||
/* it's OK to use RELATION for a sequence */
|
||||
istmt.objtype = ACL_OBJECT_RELATION;
|
||||
break;
|
||||
case DatabaseRelationId:
|
||||
istmt.objtype = ACL_OBJECT_DATABASE;
|
||||
break;
|
||||
case ProcedureRelationId:
|
||||
istmt.objtype = ACL_OBJECT_FUNCTION;
|
||||
break;
|
||||
case LanguageRelationId:
|
||||
istmt.objtype = ACL_OBJECT_LANGUAGE;
|
||||
break;
|
||||
case NamespaceRelationId:
|
||||
istmt.objtype = ACL_OBJECT_NAMESPACE;
|
||||
break;
|
||||
case TableSpaceRelationId:
|
||||
istmt.objtype = ACL_OBJECT_TABLESPACE;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unexpected object class %u", classid);
|
||||
break;
|
||||
}
|
||||
istmt.is_grant = false;
|
||||
istmt.objects = list_make1_oid(objid);
|
||||
istmt.all_privs = true;
|
||||
istmt.privileges = ACL_NO_RIGHTS;
|
||||
istmt.col_privs = NIL;
|
||||
istmt.grantees = list_make1_oid(roleid);
|
||||
istmt.grant_option = false;
|
||||
istmt.behavior = DROP_CASCADE;
|
||||
|
||||
ExecGrantStmt_oids(&istmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove a pg_default_acl entry
|
||||
*/
|
||||
void
|
||||
RemoveDefaultACLById(Oid defaclOid)
|
||||
{
|
||||
Relation rel;
|
||||
ScanKeyData skey[1];
|
||||
SysScanDesc scan;
|
||||
HeapTuple tuple;
|
||||
|
||||
rel = heap_open(DefaultAclRelationId, RowExclusiveLock);
|
||||
|
||||
ScanKeyInit(&skey[0],
|
||||
ObjectIdAttributeNumber,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(defaclOid));
|
||||
|
||||
scan = systable_beginscan(rel, DefaultAclOidIndexId, true,
|
||||
SnapshotNow, 1, skey);
|
||||
|
||||
tuple = systable_getnext(scan);
|
||||
|
||||
if (!HeapTupleIsValid(tuple))
|
||||
elog(ERROR, "could not find tuple for default ACL %u", defaclOid);
|
||||
|
||||
simple_heap_delete(rel, &tuple->t_self);
|
||||
|
||||
systable_endscan(scan);
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* expand_col_privileges
|
||||
*
|
||||
|
@ -3532,3 +4136,106 @@ pg_conversion_ownercheck(Oid conv_oid, Oid roleid)
|
|||
|
||||
return has_privs_of_role(roleid, ownerId);
|
||||
}
|
||||
|
||||
/*
|
||||
* Fetch pg_default_acl entry for given role, namespace and object type
|
||||
* (object type must be given in pg_default_acl's encoding).
|
||||
* Returns NULL if no such entry.
|
||||
*/
|
||||
static Acl *
|
||||
get_default_acl_internal(Oid roleId, Oid nsp_oid, char objtype)
|
||||
{
|
||||
Acl *result = NULL;
|
||||
HeapTuple tuple;
|
||||
|
||||
tuple = SearchSysCache(DEFACLROLENSPOBJ,
|
||||
ObjectIdGetDatum(roleId),
|
||||
ObjectIdGetDatum(nsp_oid),
|
||||
CharGetDatum(objtype),
|
||||
0);
|
||||
|
||||
if (HeapTupleIsValid(tuple))
|
||||
{
|
||||
Datum aclDatum;
|
||||
bool isNull;
|
||||
|
||||
aclDatum = SysCacheGetAttr(DEFACLROLENSPOBJ, tuple,
|
||||
Anum_pg_default_acl_defaclacl,
|
||||
&isNull);
|
||||
if (!isNull)
|
||||
result = DatumGetAclPCopy(aclDatum);
|
||||
ReleaseSysCache(tuple);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* Get default permissions for newly created object within given schema
|
||||
*
|
||||
* Returns NULL if built-in system defaults should be used
|
||||
*/
|
||||
Acl *
|
||||
get_user_default_acl(GrantObjectType objtype, Oid ownerId, Oid nsp_oid)
|
||||
{
|
||||
Acl *result;
|
||||
Acl *glob_acl;
|
||||
Acl *schema_acl;
|
||||
Acl *def_acl;
|
||||
char defaclobjtype;
|
||||
|
||||
/*
|
||||
* Use NULL during bootstrap, since pg_default_acl probably isn't there
|
||||
* yet.
|
||||
*/
|
||||
if (IsBootstrapProcessingMode())
|
||||
return NULL;
|
||||
|
||||
/* Check if object type is supported in pg_default_acl */
|
||||
switch (objtype)
|
||||
{
|
||||
case ACL_OBJECT_RELATION:
|
||||
defaclobjtype = DEFACLOBJ_RELATION;
|
||||
break;
|
||||
|
||||
case ACL_OBJECT_SEQUENCE:
|
||||
defaclobjtype = DEFACLOBJ_SEQUENCE;
|
||||
break;
|
||||
|
||||
case ACL_OBJECT_FUNCTION:
|
||||
defaclobjtype = DEFACLOBJ_FUNCTION;
|
||||
break;
|
||||
|
||||
default:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Look up the relevant pg_default_acl entries */
|
||||
glob_acl = get_default_acl_internal(ownerId, InvalidOid, defaclobjtype);
|
||||
schema_acl = get_default_acl_internal(ownerId, nsp_oid, defaclobjtype);
|
||||
|
||||
/* Quick out if neither entry exists */
|
||||
if (glob_acl == NULL && schema_acl == NULL)
|
||||
return NULL;
|
||||
|
||||
/* We need to know the hard-wired default value, too */
|
||||
def_acl = acldefault(objtype, ownerId);
|
||||
|
||||
/* If there's no global entry, substitute the hard-wired default */
|
||||
if (glob_acl == NULL)
|
||||
glob_acl = def_acl;
|
||||
|
||||
/* Merge in any per-schema privileges */
|
||||
result = aclmerge(glob_acl, schema_acl, ownerId);
|
||||
|
||||
/*
|
||||
* For efficiency, we want to return NULL if the result equals default.
|
||||
* This requires sorting both arrays to get an accurate comparison.
|
||||
*/
|
||||
aclitemsort(result);
|
||||
aclitemsort(def_acl);
|
||||
if (aclequal(result, def_acl))
|
||||
result = NULL;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.91 2009/09/22 15:46:34 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.92 2009/10/05 19:24:35 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -32,6 +32,7 @@
|
|||
#include "catalog/pg_conversion.h"
|
||||
#include "catalog/pg_conversion_fn.h"
|
||||
#include "catalog/pg_database.h"
|
||||
#include "catalog/pg_default_acl.h"
|
||||
#include "catalog/pg_depend.h"
|
||||
#include "catalog/pg_foreign_data_wrapper.h"
|
||||
#include "catalog/pg_foreign_server.h"
|
||||
|
@ -64,6 +65,7 @@
|
|||
#include "parser/parsetree.h"
|
||||
#include "rewrite/rewriteRemove.h"
|
||||
#include "storage/lmgr.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/guc.h"
|
||||
|
@ -146,7 +148,8 @@ static const Oid object_classes[MAX_OCLASS] = {
|
|||
TableSpaceRelationId, /* OCLASS_TBLSPACE */
|
||||
ForeignDataWrapperRelationId, /* OCLASS_FDW */
|
||||
ForeignServerRelationId, /* OCLASS_FOREIGN_SERVER */
|
||||
UserMappingRelationId /* OCLASS_USER_MAPPING */
|
||||
UserMappingRelationId, /* OCLASS_USER_MAPPING */
|
||||
DefaultAclRelationId /* OCLASS_DEFACL */
|
||||
};
|
||||
|
||||
|
||||
|
@ -1136,6 +1139,10 @@ doDeletion(const ObjectAddress *object)
|
|||
RemoveUserMappingById(object->objectId);
|
||||
break;
|
||||
|
||||
case OCLASS_DEFACL:
|
||||
RemoveDefaultACLById(object->objectId);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unrecognized object class: %u",
|
||||
object->classId);
|
||||
|
@ -2055,6 +2062,10 @@ getObjectClass(const ObjectAddress *object)
|
|||
case UserMappingRelationId:
|
||||
Assert(object->objectSubId == 0);
|
||||
return OCLASS_USER_MAPPING;
|
||||
|
||||
case DefaultAclRelationId:
|
||||
Assert(object->objectSubId == 0);
|
||||
return OCLASS_DEFACL;
|
||||
}
|
||||
|
||||
/* shouldn't get here */
|
||||
|
@ -2597,6 +2608,69 @@ getObjectDescription(const ObjectAddress *object)
|
|||
break;
|
||||
}
|
||||
|
||||
case OCLASS_DEFACL:
|
||||
{
|
||||
Relation defaclrel;
|
||||
ScanKeyData skey[1];
|
||||
SysScanDesc rcscan;
|
||||
HeapTuple tup;
|
||||
Form_pg_default_acl defacl;
|
||||
|
||||
defaclrel = heap_open(DefaultAclRelationId, AccessShareLock);
|
||||
|
||||
ScanKeyInit(&skey[0],
|
||||
ObjectIdAttributeNumber,
|
||||
BTEqualStrategyNumber, F_OIDEQ,
|
||||
ObjectIdGetDatum(object->objectId));
|
||||
|
||||
rcscan = systable_beginscan(defaclrel, DefaultAclOidIndexId,
|
||||
true, SnapshotNow, 1, skey);
|
||||
|
||||
tup = systable_getnext(rcscan);
|
||||
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "could not find tuple for default ACL %u",
|
||||
object->objectId);
|
||||
|
||||
defacl = (Form_pg_default_acl) GETSTRUCT(tup);
|
||||
|
||||
switch (defacl->defaclobjtype)
|
||||
{
|
||||
case DEFACLOBJ_RELATION:
|
||||
appendStringInfo(&buffer,
|
||||
_("default privileges on new relations belonging to role %s"),
|
||||
GetUserNameFromId(defacl->defaclrole));
|
||||
break;
|
||||
case DEFACLOBJ_SEQUENCE:
|
||||
appendStringInfo(&buffer,
|
||||
_("default privileges on new sequences belonging to role %s"),
|
||||
GetUserNameFromId(defacl->defaclrole));
|
||||
break;
|
||||
case DEFACLOBJ_FUNCTION:
|
||||
appendStringInfo(&buffer,
|
||||
_("default privileges on new functions belonging to role %s"),
|
||||
GetUserNameFromId(defacl->defaclrole));
|
||||
break;
|
||||
default:
|
||||
/* shouldn't get here */
|
||||
appendStringInfo(&buffer,
|
||||
_("default privileges belonging to role %s"),
|
||||
GetUserNameFromId(defacl->defaclrole));
|
||||
break;
|
||||
}
|
||||
|
||||
if (OidIsValid(defacl->defaclnamespace))
|
||||
{
|
||||
appendStringInfo(&buffer,
|
||||
_(" in schema %s"),
|
||||
get_namespace_name(defacl->defaclnamespace));
|
||||
}
|
||||
|
||||
systable_endscan(rcscan);
|
||||
heap_close(defaclrel, AccessShareLock);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
appendStringInfo(&buffer, "unrecognized object %u %u %d",
|
||||
object->classId,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.359 2009/09/26 22:42:01 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.360 2009/10/05 19:24:35 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
|
@ -59,6 +59,7 @@
|
|||
#include "storage/bufmgr.h"
|
||||
#include "storage/freespace.h"
|
||||
#include "storage/smgr.h"
|
||||
#include "utils/acl.h"
|
||||
#include "utils/builtins.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/inval.h"
|
||||
|
@ -74,6 +75,7 @@ static void AddNewRelationTuple(Relation pg_class_desc,
|
|||
Oid new_rel_oid, Oid new_type_oid,
|
||||
Oid relowner,
|
||||
char relkind,
|
||||
Datum relacl,
|
||||
Datum reloptions);
|
||||
static Oid AddNewRelationType(const char *typeName,
|
||||
Oid typeNamespace,
|
||||
|
@ -636,14 +638,16 @@ AddNewAttributeTuples(Oid new_rel_oid,
|
|||
* Caller has already opened and locked pg_class.
|
||||
* Tuple data is taken from new_rel_desc->rd_rel, except for the
|
||||
* variable-width fields which are not present in a cached reldesc.
|
||||
* We always initialize relacl to NULL (i.e., default permissions),
|
||||
* and reloptions is set to the passed-in text array (if any).
|
||||
* relacl and reloptions are passed in Datum form (to avoid having
|
||||
* to reference the data types in heap.h). Pass (Datum) 0 to set them
|
||||
* to NULL.
|
||||
* --------------------------------
|
||||
*/
|
||||
void
|
||||
InsertPgClassTuple(Relation pg_class_desc,
|
||||
Relation new_rel_desc,
|
||||
Oid new_rel_oid,
|
||||
Datum relacl,
|
||||
Datum reloptions)
|
||||
{
|
||||
Form_pg_class rd_rel = new_rel_desc->rd_rel;
|
||||
|
@ -678,8 +682,10 @@ InsertPgClassTuple(Relation pg_class_desc,
|
|||
values[Anum_pg_class_relhastriggers - 1] = BoolGetDatum(rd_rel->relhastriggers);
|
||||
values[Anum_pg_class_relhassubclass - 1] = BoolGetDatum(rd_rel->relhassubclass);
|
||||
values[Anum_pg_class_relfrozenxid - 1] = TransactionIdGetDatum(rd_rel->relfrozenxid);
|
||||
/* start out with empty permissions */
|
||||
nulls[Anum_pg_class_relacl - 1] = true;
|
||||
if (relacl != (Datum) 0)
|
||||
values[Anum_pg_class_relacl - 1] = relacl;
|
||||
else
|
||||
nulls[Anum_pg_class_relacl - 1] = true;
|
||||
if (reloptions != (Datum) 0)
|
||||
values[Anum_pg_class_reloptions - 1] = reloptions;
|
||||
else
|
||||
|
@ -715,6 +721,7 @@ AddNewRelationTuple(Relation pg_class_desc,
|
|||
Oid new_type_oid,
|
||||
Oid relowner,
|
||||
char relkind,
|
||||
Datum relacl,
|
||||
Datum reloptions)
|
||||
{
|
||||
Form_pg_class new_rel_reltup;
|
||||
|
@ -775,7 +782,8 @@ AddNewRelationTuple(Relation pg_class_desc,
|
|||
new_rel_desc->rd_att->tdtypeid = new_type_oid;
|
||||
|
||||
/* Now build and insert the tuple */
|
||||
InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid, reloptions);
|
||||
InsertPgClassTuple(pg_class_desc, new_rel_desc, new_rel_oid,
|
||||
relacl, reloptions);
|
||||
}
|
||||
|
||||
|
||||
|
@ -831,6 +839,27 @@ AddNewRelationType(const char *typeName,
|
|||
* heap_create_with_catalog
|
||||
*
|
||||
* creates a new cataloged relation. see comments above.
|
||||
*
|
||||
* Arguments:
|
||||
* relname: name to give to new rel
|
||||
* relnamespace: OID of namespace it goes in
|
||||
* reltablespace: OID of tablespace it goes in
|
||||
* relid: OID to assign to new rel, or InvalidOid to select a new OID
|
||||
* reltypeid: OID to assign to rel's rowtype, or InvalidOid to select one
|
||||
* ownerid: OID of new rel's owner
|
||||
* tupdesc: tuple descriptor (source of column definitions)
|
||||
* cooked_constraints: list of precooked check constraints and defaults
|
||||
* relkind: relkind for new rel
|
||||
* shared_relation: TRUE if it's to be a shared relation
|
||||
* oidislocal: TRUE if oid column (if any) should be marked attislocal
|
||||
* oidinhcount: attinhcount to assign to oid column (if any)
|
||||
* oncommit: ON COMMIT marking (only relevant if it's a temp table)
|
||||
* reloptions: reloptions in Datum form, or (Datum) 0 if none
|
||||
* use_user_acl: TRUE if should look for user-defined default permissions;
|
||||
* if FALSE, relacl is always set NULL
|
||||
* allow_system_table_mods: TRUE to allow creation in system namespaces
|
||||
*
|
||||
* Returns the OID of the new relation
|
||||
* --------------------------------
|
||||
*/
|
||||
Oid
|
||||
|
@ -848,10 +877,12 @@ heap_create_with_catalog(const char *relname,
|
|||
int oidinhcount,
|
||||
OnCommitAction oncommit,
|
||||
Datum reloptions,
|
||||
bool use_user_acl,
|
||||
bool allow_system_table_mods)
|
||||
{
|
||||
Relation pg_class_desc;
|
||||
Relation new_rel_desc;
|
||||
Acl *relacl;
|
||||
Oid old_type_oid;
|
||||
Oid new_type_oid;
|
||||
Oid new_array_oid = InvalidOid;
|
||||
|
@ -920,6 +951,30 @@ heap_create_with_catalog(const char *relname,
|
|||
relid = GetNewRelFileNode(reltablespace, shared_relation,
|
||||
pg_class_desc);
|
||||
|
||||
/*
|
||||
* Determine the relation's initial permissions.
|
||||
*/
|
||||
if (use_user_acl)
|
||||
{
|
||||
switch (relkind)
|
||||
{
|
||||
case RELKIND_RELATION:
|
||||
case RELKIND_VIEW:
|
||||
relacl = get_user_default_acl(ACL_OBJECT_RELATION, ownerid,
|
||||
relnamespace);
|
||||
break;
|
||||
case RELKIND_SEQUENCE:
|
||||
relacl = get_user_default_acl(ACL_OBJECT_SEQUENCE, ownerid,
|
||||
relnamespace);
|
||||
break;
|
||||
default:
|
||||
relacl = NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
relacl = NULL;
|
||||
|
||||
/*
|
||||
* Create the relcache entry (mostly dummy at this point) and the physical
|
||||
* disk file. (If we fail further down, it's the smgr's responsibility to
|
||||
|
@ -1027,6 +1082,7 @@ heap_create_with_catalog(const char *relname,
|
|||
new_type_oid,
|
||||
ownerid,
|
||||
relkind,
|
||||
PointerGetDatum(relacl),
|
||||
reloptions);
|
||||
|
||||
/*
|
||||
|
@ -1037,12 +1093,15 @@ heap_create_with_catalog(const char *relname,
|
|||
|
||||
/*
|
||||
* Make a dependency link to force the relation to be deleted if its
|
||||
* namespace is. Also make a dependency link to its owner.
|
||||
* namespace is. Also make a dependency link to its owner, as well
|
||||
* as dependencies for any roles mentioned in the default ACL.
|
||||
*
|
||||
* For composite types, these dependencies are tracked for the pg_type
|
||||
* entry, so we needn't record them here. Likewise, TOAST tables don't
|
||||
* need a namespace dependency (they live in a pinned namespace) nor an
|
||||
* owner dependency (they depend indirectly through the parent table).
|
||||
* owner dependency (they depend indirectly through the parent table),
|
||||
* nor should they have any ACL entries.
|
||||
*
|
||||
* Also, skip this in bootstrap mode, since we don't make dependencies
|
||||
* while bootstrapping.
|
||||
*/
|
||||
|
@ -1062,6 +1121,18 @@ heap_create_with_catalog(const char *relname,
|
|||
recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
|
||||
|
||||
recordDependencyOnOwner(RelationRelationId, relid, ownerid);
|
||||
|
||||
if (relacl != NULL)
|
||||
{
|
||||
int nnewmembers;
|
||||
Oid *newmembers;
|
||||
|
||||
nnewmembers = aclmembers(relacl, &newmembers);
|
||||
updateAclDependencies(RelationRelationId, relid, 0,
|
||||
ownerid, true,
|
||||
0, NULL,
|
||||
nnewmembers, newmembers);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.321 2009/08/02 22:14:52 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.322 2009/10/05 19:24:35 tgl Exp $
|
||||
*
|
||||
*
|
||||
* INTERFACE ROUTINES
|
||||
|
@ -664,6 +664,7 @@ index_create(Oid heapRelationId,
|
|||
*/
|
||||
InsertPgClassTuple(pg_class, indexRelation,
|
||||
RelationGetRelid(indexRelation),
|
||||
(Datum) 0,
|
||||
reloptions);
|
||||
|
||||
/* done with pg_class */
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.166 2009/10/02 18:13:04 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.167 2009/10/05 19:24:36 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -90,6 +90,7 @@ ProcedureCreate(const char *procedureName,
|
|||
bool internalOutParam = false;
|
||||
Oid variadicType = InvalidOid;
|
||||
Oid proowner = GetUserId();
|
||||
Acl *proacl = NULL;
|
||||
Relation rel;
|
||||
HeapTuple tup;
|
||||
HeapTuple oldtup;
|
||||
|
@ -331,8 +332,7 @@ ProcedureCreate(const char *procedureName,
|
|||
values[Anum_pg_proc_proconfig - 1] = proconfig;
|
||||
else
|
||||
nulls[Anum_pg_proc_proconfig - 1] = true;
|
||||
/* start out with empty permissions */
|
||||
nulls[Anum_pg_proc_proacl - 1] = true;
|
||||
/* proacl will be determined later */
|
||||
|
||||
rel = heap_open(ProcedureRelationId, RowExclusiveLock);
|
||||
tupDesc = RelationGetDescr(rel);
|
||||
|
@ -489,6 +489,15 @@ ProcedureCreate(const char *procedureName,
|
|||
else
|
||||
{
|
||||
/* Creating a new procedure */
|
||||
|
||||
/* First, get default permissions and set up proacl */
|
||||
proacl = get_user_default_acl(ACL_OBJECT_FUNCTION, proowner,
|
||||
procNamespace);
|
||||
if (proacl != NULL)
|
||||
values[Anum_pg_proc_proacl - 1] = PointerGetDatum(proacl);
|
||||
else
|
||||
nulls[Anum_pg_proc_proacl - 1] = true;
|
||||
|
||||
tup = heap_form_tuple(tupDesc, values, nulls);
|
||||
simple_heap_insert(rel, tup);
|
||||
is_update = false;
|
||||
|
@ -543,6 +552,19 @@ ProcedureCreate(const char *procedureName,
|
|||
if (!is_update)
|
||||
recordDependencyOnOwner(ProcedureRelationId, retval, proowner);
|
||||
|
||||
/* dependency on any roles mentioned in ACL */
|
||||
if (!is_update && proacl != NULL)
|
||||
{
|
||||
int nnewmembers;
|
||||
Oid *newmembers;
|
||||
|
||||
nnewmembers = aclmembers(proacl, &newmembers);
|
||||
updateAclDependencies(ProcedureRelationId, retval, 0,
|
||||
proowner, true,
|
||||
0, NULL,
|
||||
nnewmembers, newmembers);
|
||||
}
|
||||
|
||||
heap_freetuple(tup);
|
||||
|
||||
heap_close(rel, RowExclusiveLock);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.34 2009/06/11 14:48:55 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.35 2009/10/05 19:24:36 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -23,6 +23,7 @@
|
|||
#include "catalog/pg_authid.h"
|
||||
#include "catalog/pg_conversion.h"
|
||||
#include "catalog/pg_database.h"
|
||||
#include "catalog/pg_default_acl.h"
|
||||
#include "catalog/pg_language.h"
|
||||
#include "catalog/pg_namespace.h"
|
||||
#include "catalog/pg_operator.h"
|
||||
|
@ -1180,7 +1181,6 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
|
|||
while ((tuple = systable_getnext(scan)) != NULL)
|
||||
{
|
||||
Form_pg_shdepend sdepForm = (Form_pg_shdepend) GETSTRUCT(tuple);
|
||||
InternalGrant istmt;
|
||||
ObjectAddress obj;
|
||||
|
||||
/* We only operate on objects in the current database */
|
||||
|
@ -1195,42 +1195,9 @@ shdepDropOwned(List *roleids, DropBehavior behavior)
|
|||
elog(ERROR, "unexpected dependency type");
|
||||
break;
|
||||
case SHARED_DEPENDENCY_ACL:
|
||||
switch (sdepForm->classid)
|
||||
{
|
||||
case RelationRelationId:
|
||||
/* it's OK to use RELATION for a sequence */
|
||||
istmt.objtype = ACL_OBJECT_RELATION;
|
||||
break;
|
||||
case DatabaseRelationId:
|
||||
istmt.objtype = ACL_OBJECT_DATABASE;
|
||||
break;
|
||||
case ProcedureRelationId:
|
||||
istmt.objtype = ACL_OBJECT_FUNCTION;
|
||||
break;
|
||||
case LanguageRelationId:
|
||||
istmt.objtype = ACL_OBJECT_LANGUAGE;
|
||||
break;
|
||||
case NamespaceRelationId:
|
||||
istmt.objtype = ACL_OBJECT_NAMESPACE;
|
||||
break;
|
||||
case TableSpaceRelationId:
|
||||
istmt.objtype = ACL_OBJECT_TABLESPACE;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unexpected object type %d",
|
||||
sdepForm->classid);
|
||||
break;
|
||||
}
|
||||
istmt.is_grant = false;
|
||||
istmt.objects = list_make1_oid(sdepForm->objid);
|
||||
istmt.all_privs = true;
|
||||
istmt.privileges = ACL_NO_RIGHTS;
|
||||
istmt.col_privs = NIL;
|
||||
istmt.grantees = list_make1_oid(roleid);
|
||||
istmt.grant_option = false;
|
||||
istmt.behavior = DROP_CASCADE;
|
||||
|
||||
ExecGrantStmt_oids(&istmt);
|
||||
RemoveRoleFromObjectACL(roleid,
|
||||
sdepForm->classid,
|
||||
sdepForm->objid);
|
||||
break;
|
||||
case SHARED_DEPENDENCY_OWNER:
|
||||
/* Save it for deletion below */
|
||||
|
@ -1365,8 +1332,15 @@ shdepReassignOwned(List *roleids, Oid newrole)
|
|||
AlterLanguageOwner_oid(sdepForm->objid, newrole);
|
||||
break;
|
||||
|
||||
case DefaultAclRelationId:
|
||||
/*
|
||||
* Ignore default ACLs; they should be handled by
|
||||
* DROP OWNED, not REASSIGN OWNED.
|
||||
*/
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "unexpected classid %d", sdepForm->classid);
|
||||
elog(ERROR, "unexpected classid %u", sdepForm->classid);
|
||||
break;
|
||||
}
|
||||
/* Make sure the next iteration will see my changes */
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.19 2009/09/26 22:42:01 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/catalog/toasting.c,v 1.20 2009/10/05 19:24:36 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -213,6 +213,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
|
|||
0,
|
||||
ONCOMMIT_NOOP,
|
||||
reloptions,
|
||||
false,
|
||||
true);
|
||||
|
||||
/* make the toast relation visible, else index creation will fail */
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.187 2009/09/26 22:42:01 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.188 2009/10/05 19:24:36 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -713,6 +713,7 @@ make_new_heap(Oid OIDOldHeap, const char *NewName, Oid NewTableSpace)
|
|||
0,
|
||||
ONCOMMIT_NOOP,
|
||||
reloptions,
|
||||
false,
|
||||
allowSystemTableMods);
|
||||
|
||||
ReleaseSysCache(tuple);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.299 2009/09/26 22:42:01 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.300 2009/10/05 19:24:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -521,6 +521,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
|
|||
parentOidCount,
|
||||
stmt->oncommit,
|
||||
reloptions,
|
||||
true,
|
||||
allowSystemTableMods);
|
||||
|
||||
StoreCatalogInheritance(relationId, inheritOids);
|
||||
|
@ -6098,6 +6099,7 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
|
|||
case OCLASS_FDW:
|
||||
case OCLASS_FOREIGN_SERVER:
|
||||
case OCLASS_USER_MAPPING:
|
||||
case OCLASS_DEFACL:
|
||||
|
||||
/*
|
||||
* We don't expect any of these sorts of objects to depend on
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.329 2009/09/27 20:09:57 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.330 2009/10/05 19:24:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -2909,6 +2909,7 @@ OpenIntoRel(QueryDesc *queryDesc)
|
|||
0,
|
||||
into->onCommit,
|
||||
reloptions,
|
||||
true,
|
||||
allowSystemTableMods);
|
||||
|
||||
FreeTupleDesc(tupdesc);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.438 2009/09/22 23:43:37 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.439 2009/10/05 19:24:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -2345,6 +2345,17 @@ _copyGrantRoleStmt(GrantRoleStmt *from)
|
|||
return newnode;
|
||||
}
|
||||
|
||||
static AlterDefaultPrivilegesStmt *
|
||||
_copyAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *from)
|
||||
{
|
||||
AlterDefaultPrivilegesStmt *newnode = makeNode(AlterDefaultPrivilegesStmt);
|
||||
|
||||
COPY_NODE_FIELD(options);
|
||||
COPY_NODE_FIELD(action);
|
||||
|
||||
return newnode;
|
||||
}
|
||||
|
||||
static DeclareCursorStmt *
|
||||
_copyDeclareCursorStmt(DeclareCursorStmt *from)
|
||||
{
|
||||
|
@ -3760,6 +3771,9 @@ copyObject(void *from)
|
|||
case T_GrantRoleStmt:
|
||||
retval = _copyGrantRoleStmt(from);
|
||||
break;
|
||||
case T_AlterDefaultPrivilegesStmt:
|
||||
retval = _copyAlterDefaultPrivilegesStmt(from);
|
||||
break;
|
||||
case T_DeclareCursorStmt:
|
||||
retval = _copyDeclareCursorStmt(from);
|
||||
break;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.361 2009/09/22 23:43:38 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.362 2009/10/05 19:24:38 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1028,6 +1028,15 @@ _equalGrantRoleStmt(GrantRoleStmt *a, GrantRoleStmt *b)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *a, AlterDefaultPrivilegesStmt *b)
|
||||
{
|
||||
COMPARE_NODE_FIELD(options);
|
||||
COMPARE_NODE_FIELD(action);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
_equalDeclareCursorStmt(DeclareCursorStmt *a, DeclareCursorStmt *b)
|
||||
{
|
||||
|
@ -2537,6 +2546,9 @@ equal(void *a, void *b)
|
|||
case T_GrantRoleStmt:
|
||||
retval = _equalGrantRoleStmt(a, b);
|
||||
break;
|
||||
case T_AlterDefaultPrivilegesStmt:
|
||||
retval = _equalAlterDefaultPrivilegesStmt(a, b);
|
||||
break;
|
||||
case T_DeclareCursorStmt:
|
||||
retval = _equalDeclareCursorStmt(a, b);
|
||||
break;
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.679 2009/09/22 23:43:38 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.680 2009/10/05 19:24:38 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
|
@ -188,7 +188,9 @@ static TypeName *TableFuncTypeName(List *columns);
|
|||
AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterFdwStmt
|
||||
AlterForeignServerStmt AlterGroupStmt
|
||||
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
|
||||
AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
|
||||
AlterUserStmt AlterUserMappingStmt AlterUserSetStmt
|
||||
AlterRoleStmt AlterRoleSetStmt
|
||||
AlterDefaultPrivilegesStmt DefACLAction
|
||||
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
|
||||
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
|
||||
CreateDomainStmt CreateGroupStmt CreateOpClassStmt
|
||||
|
@ -269,6 +271,9 @@ static TypeName *TableFuncTypeName(List *columns);
|
|||
%type <privtarget> privilege_target
|
||||
%type <funwithargs> function_with_argtypes
|
||||
%type <list> function_with_argtypes_list
|
||||
%type <ival> defacl_privilege_target
|
||||
%type <defelt> DefACLOption
|
||||
%type <list> DefACLOptionList
|
||||
|
||||
%type <list> stmtblock stmtmulti
|
||||
OptTableElementList TableElementList OptInherit definition
|
||||
|
@ -625,6 +630,7 @@ stmtmulti: stmtmulti ';' stmt
|
|||
stmt :
|
||||
AlterDatabaseStmt
|
||||
| AlterDatabaseSetStmt
|
||||
| AlterDefaultPrivilegesStmt
|
||||
| AlterDomainStmt
|
||||
| AlterFdwStmt
|
||||
| AlterForeignServerStmt
|
||||
|
@ -1891,7 +1897,7 @@ reloption_list:
|
|||
;
|
||||
|
||||
/* This should match def_elem and also allow qualified names */
|
||||
reloption_elem:
|
||||
reloption_elem:
|
||||
ColLabel '=' def_arg
|
||||
{
|
||||
$$ = makeDefElem($1, (Node *) $3);
|
||||
|
@ -4576,6 +4582,93 @@ opt_granted_by: GRANTED BY RoleId { $$ = $3; }
|
|||
| /*EMPTY*/ { $$ = NULL; }
|
||||
;
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
* ALTER DEFAULT PRIVILEGES statement
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
AlterDefaultPrivilegesStmt:
|
||||
ALTER DEFAULT PRIVILEGES DefACLOptionList DefACLAction
|
||||
{
|
||||
AlterDefaultPrivilegesStmt *n = makeNode(AlterDefaultPrivilegesStmt);
|
||||
n->options = $4;
|
||||
n->action = (GrantStmt *) $5;
|
||||
$$ = (Node*)n;
|
||||
}
|
||||
;
|
||||
|
||||
DefACLOptionList:
|
||||
DefACLOptionList DefACLOption { $$ = lappend($1, $2); }
|
||||
| /* EMPTY */ { $$ = NIL; }
|
||||
;
|
||||
|
||||
DefACLOption:
|
||||
IN_P SCHEMA name_list
|
||||
{
|
||||
$$ = makeDefElem("schemas", (Node *)$3);
|
||||
}
|
||||
| FOR ROLE name_list
|
||||
{
|
||||
$$ = makeDefElem("roles", (Node *)$3);
|
||||
}
|
||||
| FOR USER name_list
|
||||
{
|
||||
$$ = makeDefElem("roles", (Node *)$3);
|
||||
}
|
||||
;
|
||||
|
||||
/*
|
||||
* This should match GRANT/REVOKE, except that target objects are missing
|
||||
* and we only allow a subset of object types.
|
||||
*/
|
||||
DefACLAction:
|
||||
GRANT privileges ON defacl_privilege_target TO grantee_list
|
||||
opt_grant_grant_option
|
||||
{
|
||||
GrantStmt *n = makeNode(GrantStmt);
|
||||
n->is_grant = true;
|
||||
n->privileges = $2;
|
||||
n->objtype = $4;
|
||||
n->objects = NIL;
|
||||
n->grantees = $6;
|
||||
n->grant_option = $7;
|
||||
$$ = (Node*)n;
|
||||
}
|
||||
| REVOKE privileges ON defacl_privilege_target
|
||||
FROM grantee_list opt_drop_behavior
|
||||
{
|
||||
GrantStmt *n = makeNode(GrantStmt);
|
||||
n->is_grant = false;
|
||||
n->grant_option = false;
|
||||
n->privileges = $2;
|
||||
n->objtype = $4;
|
||||
n->objects = NIL;
|
||||
n->grantees = $6;
|
||||
n->behavior = $7;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
| REVOKE GRANT OPTION FOR privileges ON defacl_privilege_target
|
||||
FROM grantee_list opt_drop_behavior
|
||||
{
|
||||
GrantStmt *n = makeNode(GrantStmt);
|
||||
n->is_grant = false;
|
||||
n->grant_option = true;
|
||||
n->privileges = $5;
|
||||
n->objtype = $7;
|
||||
n->objects = NIL;
|
||||
n->grantees = $9;
|
||||
n->behavior = $10;
|
||||
$$ = (Node *)n;
|
||||
}
|
||||
;
|
||||
|
||||
defacl_privilege_target:
|
||||
TABLE { $$ = ACL_OBJECT_RELATION; }
|
||||
| FUNCTION { $$ = ACL_OBJECT_FUNCTION; }
|
||||
| SEQUENCE { $$ = ACL_OBJECT_SEQUENCE; }
|
||||
;
|
||||
|
||||
|
||||
/*****************************************************************************
|
||||
*
|
||||
|
@ -8632,10 +8725,11 @@ a_expr: c_expr { $$ = $1; }
|
|||
$$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2);
|
||||
}
|
||||
/*
|
||||
* Ideally we would not use hard-wired operators below but instead use
|
||||
* opclasses. However, mixed data types and other issues make this
|
||||
* difficult: http://archives.postgresql.org/pgsql-hackers/2008-08/msg01142.php
|
||||
*/
|
||||
* Ideally we would not use hard-wired operators below but
|
||||
* instead use opclasses. However, mixed data types and other
|
||||
* issues make this difficult:
|
||||
* http://archives.postgresql.org/pgsql-hackers/2008-08/msg01142.php
|
||||
*/
|
||||
| a_expr BETWEEN opt_asymmetric b_expr AND b_expr %prec BETWEEN
|
||||
{
|
||||
$$ = (Node *) makeA_Expr(AEXPR_AND, NIL,
|
||||
|
|
|
@ -10,7 +10,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.314 2009/09/22 23:43:38 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.315 2009/10/05 19:24:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -199,6 +199,7 @@ check_xact_readonly(Node *parsetree)
|
|||
case T_DropPropertyStmt:
|
||||
case T_GrantStmt:
|
||||
case T_GrantRoleStmt:
|
||||
case T_AlterDefaultPrivilegesStmt:
|
||||
case T_TruncateStmt:
|
||||
case T_DropOwnedStmt:
|
||||
case T_ReassignOwnedStmt:
|
||||
|
@ -701,6 +702,10 @@ ProcessUtility(Node *parsetree,
|
|||
GrantRole((GrantRoleStmt *) parsetree);
|
||||
break;
|
||||
|
||||
case T_AlterDefaultPrivilegesStmt:
|
||||
ExecAlterDefaultPrivilegesStmt((AlterDefaultPrivilegesStmt *) parsetree);
|
||||
break;
|
||||
|
||||
/*
|
||||
* **************** object creation / destruction *****************
|
||||
*/
|
||||
|
@ -1687,6 +1692,10 @@ CreateCommandTag(Node *parsetree)
|
|||
}
|
||||
break;
|
||||
|
||||
case T_AlterDefaultPrivilegesStmt:
|
||||
tag = "ALTER DEFAULT PRIVILEGES";
|
||||
break;
|
||||
|
||||
case T_DefineStmt:
|
||||
switch (((DefineStmt *) parsetree)->kind)
|
||||
{
|
||||
|
@ -2240,6 +2249,10 @@ GetCommandLogLevel(Node *parsetree)
|
|||
lev = LOGSTMT_DDL;
|
||||
break;
|
||||
|
||||
case T_AlterDefaultPrivilegesStmt:
|
||||
lev = LOGSTMT_DDL;
|
||||
break;
|
||||
|
||||
case T_DefineStmt:
|
||||
lev = LOGSTMT_DDL;
|
||||
break;
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.149 2009/08/03 21:11:39 joe Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.150 2009/10/05 19:24:41 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -77,6 +77,7 @@ static Acl *allocacl(int n);
|
|||
static void check_acl(const Acl *acl);
|
||||
static const char *aclparse(const char *s, AclItem *aip);
|
||||
static bool aclitem_match(const AclItem *a1, const AclItem *a2);
|
||||
static int aclitemComparator(const void *arg1, const void *arg2);
|
||||
static void check_circularity(const Acl *old_acl, const AclItem *mod_aip,
|
||||
Oid ownerId);
|
||||
static Acl *recursive_revoke(Acl *acl, Oid grantee, AclMode revoke_privs,
|
||||
|
@ -382,6 +383,15 @@ allocacl(int n)
|
|||
return new_acl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a zero-entry ACL
|
||||
*/
|
||||
Acl *
|
||||
make_empty_acl(void)
|
||||
{
|
||||
return allocacl(0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy an ACL
|
||||
*/
|
||||
|
@ -423,6 +433,98 @@ aclconcat(const Acl *left_acl, const Acl *right_acl)
|
|||
return result_acl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Merge two ACLs
|
||||
*
|
||||
* This produces a properly merged ACL with no redundant entries.
|
||||
* Returns NULL on NULL input.
|
||||
*/
|
||||
Acl *
|
||||
aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId)
|
||||
{
|
||||
Acl *result_acl;
|
||||
AclItem *aip;
|
||||
int i,
|
||||
num;
|
||||
|
||||
/* Check for cases where one or both are empty/null */
|
||||
if (left_acl == NULL || ACL_NUM(left_acl) == 0)
|
||||
{
|
||||
if (right_acl == NULL || ACL_NUM(right_acl) == 0)
|
||||
return NULL;
|
||||
else
|
||||
return aclcopy(right_acl);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (right_acl == NULL || ACL_NUM(right_acl) == 0)
|
||||
return aclcopy(left_acl);
|
||||
}
|
||||
|
||||
/* Merge them the hard way, one item at a time */
|
||||
result_acl = aclcopy(left_acl);
|
||||
|
||||
aip = ACL_DAT(right_acl);
|
||||
num = ACL_NUM(right_acl);
|
||||
|
||||
for (i = 0; i < num; i++, aip++)
|
||||
{
|
||||
Acl *tmp_acl;
|
||||
|
||||
tmp_acl = aclupdate(result_acl, aip, ACL_MODECHG_ADD,
|
||||
ownerId, DROP_RESTRICT);
|
||||
pfree(result_acl);
|
||||
result_acl = tmp_acl;
|
||||
}
|
||||
|
||||
return result_acl;
|
||||
}
|
||||
|
||||
/*
|
||||
* Sort the items in an ACL (into an arbitrary but consistent order)
|
||||
*/
|
||||
void
|
||||
aclitemsort(Acl *acl)
|
||||
{
|
||||
if (acl != NULL && ACL_NUM(acl) > 1)
|
||||
qsort(ACL_DAT(acl), ACL_NUM(acl), sizeof(AclItem), aclitemComparator);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check if two ACLs are exactly equal
|
||||
*
|
||||
* This will not detect equality if the two arrays contain the same items
|
||||
* in different orders. To handle that case, sort both inputs first,
|
||||
* using aclitemsort().
|
||||
*/
|
||||
bool
|
||||
aclequal(const Acl *left_acl, const Acl *right_acl)
|
||||
{
|
||||
/* Check for cases where one or both are empty/null */
|
||||
if (left_acl == NULL || ACL_NUM(left_acl) == 0)
|
||||
{
|
||||
if (right_acl == NULL || ACL_NUM(right_acl) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (right_acl == NULL || ACL_NUM(right_acl) == 0)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ACL_NUM(left_acl) != ACL_NUM(right_acl))
|
||||
return false;
|
||||
|
||||
if (memcmp(ACL_DAT(left_acl),
|
||||
ACL_DAT(right_acl),
|
||||
ACL_NUM(left_acl) * sizeof(AclItem)) == 0)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Verify that an ACL array is acceptable (one-dimensional and has no nulls)
|
||||
*/
|
||||
|
@ -555,6 +657,31 @@ aclitem_match(const AclItem *a1, const AclItem *a2)
|
|||
a1->ai_grantor == a2->ai_grantor;
|
||||
}
|
||||
|
||||
/*
|
||||
* aclitemComparator
|
||||
* qsort comparison function for AclItems
|
||||
*/
|
||||
static int
|
||||
aclitemComparator(const void *arg1, const void *arg2)
|
||||
{
|
||||
const AclItem *a1 = (const AclItem *) arg1;
|
||||
const AclItem *a2 = (const AclItem *) arg2;
|
||||
|
||||
if (a1->ai_grantee > a2->ai_grantee)
|
||||
return 1;
|
||||
if (a1->ai_grantee < a2->ai_grantee)
|
||||
return -1;
|
||||
if (a1->ai_grantor > a2->ai_grantor)
|
||||
return 1;
|
||||
if (a1->ai_grantor < a2->ai_grantor)
|
||||
return -1;
|
||||
if (a1->ai_privs > a2->ai_privs)
|
||||
return 1;
|
||||
if (a1->ai_privs < a2->ai_privs)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* aclitem equality operator
|
||||
*/
|
||||
|
@ -593,6 +720,9 @@ hash_aclitem(PG_FUNCTION_ARGS)
|
|||
*
|
||||
* Change this routine if you want to alter the default access policy for
|
||||
* newly-created objects (or any object with a NULL acl entry).
|
||||
*
|
||||
* Note that these are the hard-wired "defaults" that are used in the
|
||||
* absence of any pg_default_acl entry.
|
||||
*/
|
||||
Acl *
|
||||
acldefault(GrantObjectType objtype, Oid ownerId)
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.120 2009/06/11 14:49:05 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.121 2009/10/05 19:24:45 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* These routines allow the parser/planner/executor to perform
|
||||
|
@ -31,6 +31,7 @@
|
|||
#include "catalog/pg_constraint.h"
|
||||
#include "catalog/pg_conversion.h"
|
||||
#include "catalog/pg_database.h"
|
||||
#include "catalog/pg_default_acl.h"
|
||||
#include "catalog/pg_enum.h"
|
||||
#include "catalog/pg_foreign_data_wrapper.h"
|
||||
#include "catalog/pg_foreign_server.h"
|
||||
|
@ -344,6 +345,18 @@ static const struct cachedesc cacheinfo[] = {
|
|||
},
|
||||
4
|
||||
},
|
||||
{DefaultAclRelationId, /* DEFACLROLENSPOBJ */
|
||||
DefaultAclRoleNspObjIndexId,
|
||||
0,
|
||||
3,
|
||||
{
|
||||
Anum_pg_default_acl_defaclrole,
|
||||
Anum_pg_default_acl_defaclnamespace,
|
||||
Anum_pg_default_acl_defaclobjtype,
|
||||
0
|
||||
},
|
||||
256
|
||||
},
|
||||
{EnumRelationId, /* ENUMOID */
|
||||
EnumOidIndexId,
|
||||
0,
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.107 2009/06/11 14:49:07 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.108 2009/10/05 19:24:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -93,6 +93,7 @@ getSchemaData(int *numTablesPtr)
|
|||
TSConfigInfo *cfginfo;
|
||||
FdwInfo *fdwinfo;
|
||||
ForeignServerInfo *srvinfo;
|
||||
DefaultACLInfo *daclinfo;
|
||||
int numNamespaces;
|
||||
int numAggregates;
|
||||
int numInherits;
|
||||
|
@ -108,6 +109,7 @@ getSchemaData(int *numTablesPtr)
|
|||
int numTSConfigs;
|
||||
int numForeignDataWrappers;
|
||||
int numForeignServers;
|
||||
int numDefaultACLs;
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "reading schemas\n");
|
||||
|
@ -166,6 +168,10 @@ getSchemaData(int *numTablesPtr)
|
|||
write_msg(NULL, "reading user-defined foreign servers\n");
|
||||
srvinfo = getForeignServers(&numForeignServers);
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "reading default privileges\n");
|
||||
daclinfo = getDefaultACLs(&numDefaultACLs);
|
||||
|
||||
if (g_verbose)
|
||||
write_msg(NULL, "reading user-defined operator families\n");
|
||||
opfinfo = getOpfamilies(&numOpfamilies);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.48 2009/08/04 21:56:08 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.49 2009/10/05 19:24:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -490,18 +490,22 @@ parsePGArray(const char *atext, char ***itemarray, int *nitems)
|
|||
* acls: the ACL string fetched from the database
|
||||
* owner: username of object owner (will be passed through fmtId); can be
|
||||
* NULL or empty string to indicate "no owner known"
|
||||
* prefix: string to prefix to each generated command; typically empty
|
||||
* remoteVersion: version of database
|
||||
*
|
||||
* Returns TRUE if okay, FALSE if could not parse the acl string.
|
||||
* The resulting commands (if any) are appended to the contents of 'sql'.
|
||||
*
|
||||
* Note: when processing a default ACL, prefix is "ALTER DEFAULT PRIVILEGES "
|
||||
* or something similar, and name is an empty string.
|
||||
*
|
||||
* Note: beware of passing a fmtId() result directly as 'name' or 'subname',
|
||||
* since this routine uses fmtId() internally.
|
||||
*/
|
||||
bool
|
||||
buildACLCommands(const char *name, const char *subname,
|
||||
const char *type, const char *acls, const char *owner,
|
||||
int remoteVersion,
|
||||
const char *prefix, int remoteVersion,
|
||||
PQExpBuffer sql)
|
||||
{
|
||||
char **aclitems;
|
||||
|
@ -549,7 +553,7 @@ buildACLCommands(const char *name, const char *subname,
|
|||
* wire-in knowledge about the default public privileges for different
|
||||
* kinds of objects.
|
||||
*/
|
||||
appendPQExpBuffer(firstsql, "REVOKE ALL");
|
||||
appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
|
||||
if (subname)
|
||||
appendPQExpBuffer(firstsql, "(%s)", subname);
|
||||
appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
|
||||
|
@ -564,8 +568,8 @@ buildACLCommands(const char *name, const char *subname,
|
|||
if (remoteVersion < 80200 && strcmp(type, "DATABASE") == 0)
|
||||
{
|
||||
/* database CONNECT priv didn't exist before 8.2 */
|
||||
appendPQExpBuffer(firstsql, "GRANT CONNECT ON %s %s TO PUBLIC;\n",
|
||||
type, name);
|
||||
appendPQExpBuffer(firstsql, "%sGRANT CONNECT ON %s %s TO PUBLIC;\n",
|
||||
prefix, type, name);
|
||||
}
|
||||
|
||||
/* Scan individual ACL items */
|
||||
|
@ -594,20 +598,20 @@ buildACLCommands(const char *name, const char *subname,
|
|||
? strcmp(privswgo->data, "ALL") != 0
|
||||
: strcmp(privs->data, "ALL") != 0)
|
||||
{
|
||||
appendPQExpBuffer(firstsql, "REVOKE ALL");
|
||||
appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
|
||||
if (subname)
|
||||
appendPQExpBuffer(firstsql, "(%s)", subname);
|
||||
appendPQExpBuffer(firstsql, " ON %s %s FROM %s;\n",
|
||||
type, name, fmtId(grantee->data));
|
||||
if (privs->len > 0)
|
||||
appendPQExpBuffer(firstsql,
|
||||
"GRANT %s ON %s %s TO %s;\n",
|
||||
privs->data, type, name,
|
||||
"%sGRANT %s ON %s %s TO %s;\n",
|
||||
prefix, privs->data, type, name,
|
||||
fmtId(grantee->data));
|
||||
if (privswgo->len > 0)
|
||||
appendPQExpBuffer(firstsql,
|
||||
"GRANT %s ON %s %s TO %s WITH GRANT OPTION;\n",
|
||||
privswgo->data, type, name,
|
||||
"%sGRANT %s ON %s %s TO %s WITH GRANT OPTION;\n",
|
||||
prefix, privswgo->data, type, name,
|
||||
fmtId(grantee->data));
|
||||
}
|
||||
}
|
||||
|
@ -623,8 +627,8 @@ buildACLCommands(const char *name, const char *subname,
|
|||
|
||||
if (privs->len > 0)
|
||||
{
|
||||
appendPQExpBuffer(secondsql, "GRANT %s ON %s %s TO ",
|
||||
privs->data, type, name);
|
||||
appendPQExpBuffer(secondsql, "%sGRANT %s ON %s %s TO ",
|
||||
prefix, privs->data, type, name);
|
||||
if (grantee->len == 0)
|
||||
appendPQExpBuffer(secondsql, "PUBLIC;\n");
|
||||
else if (strncmp(grantee->data, "group ",
|
||||
|
@ -636,8 +640,8 @@ buildACLCommands(const char *name, const char *subname,
|
|||
}
|
||||
if (privswgo->len > 0)
|
||||
{
|
||||
appendPQExpBuffer(secondsql, "GRANT %s ON %s %s TO ",
|
||||
privswgo->data, type, name);
|
||||
appendPQExpBuffer(secondsql, "%sGRANT %s ON %s %s TO ",
|
||||
prefix, privswgo->data, type, name);
|
||||
if (grantee->len == 0)
|
||||
appendPQExpBuffer(secondsql, "PUBLIC");
|
||||
else if (strncmp(grantee->data, "group ",
|
||||
|
@ -661,7 +665,7 @@ buildACLCommands(const char *name, const char *subname,
|
|||
*/
|
||||
if (!found_owner_privs && owner)
|
||||
{
|
||||
appendPQExpBuffer(firstsql, "REVOKE ALL");
|
||||
appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
|
||||
if (subname)
|
||||
appendPQExpBuffer(firstsql, "(%s)", subname);
|
||||
appendPQExpBuffer(firstsql, " ON %s %s FROM %s;\n",
|
||||
|
@ -682,6 +686,50 @@ buildACLCommands(const char *name, const char *subname,
|
|||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
* Build ALTER DEFAULT PRIVILEGES command(s) for single pg_default_acl entry.
|
||||
*
|
||||
* type: the object type (as seen in GRANT command)
|
||||
* nspname: schema name, or NULL for global default privileges
|
||||
* acls: the ACL string fetched from the database
|
||||
* owner: username of privileges owner (will be passed through fmtId)
|
||||
* remoteVersion: version of database
|
||||
*
|
||||
* Returns TRUE if okay, FALSE if could not parse the acl string.
|
||||
* The resulting commands (if any) are appended to the contents of 'sql'.
|
||||
*/
|
||||
bool
|
||||
buildDefaultACLCommands(const char *type, const char *nspname,
|
||||
const char *acls, const char *owner,
|
||||
int remoteVersion,
|
||||
PQExpBuffer sql)
|
||||
{
|
||||
bool result;
|
||||
PQExpBuffer prefix;
|
||||
|
||||
prefix = createPQExpBuffer();
|
||||
|
||||
/*
|
||||
* We incorporate the target role directly into the command, rather than
|
||||
* playing around with SET ROLE or anything like that. This is so that
|
||||
* a permissions error leads to nothing happening, rather than
|
||||
* changing default privileges for the wrong user.
|
||||
*/
|
||||
appendPQExpBuffer(prefix, "ALTER DEFAULT PRIVILEGES FOR ROLE %s ",
|
||||
fmtId(owner));
|
||||
if (nspname)
|
||||
appendPQExpBuffer(prefix, "IN SCHEMA %s ", fmtId(nspname));
|
||||
|
||||
result = buildACLCommands("", NULL,
|
||||
type, acls, owner,
|
||||
prefix->data, remoteVersion,
|
||||
sql);
|
||||
|
||||
destroyPQExpBuffer(prefix);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* This will parse an aclitem string, having the general form
|
||||
* username=privilegecodes/grantor
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.25 2009/08/04 21:56:08 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.h,v 1.26 2009/10/05 19:24:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -34,8 +34,12 @@ extern int parse_version(const char *versionString);
|
|||
extern bool parsePGArray(const char *atext, char ***itemarray, int *nitems);
|
||||
extern bool buildACLCommands(const char *name, const char *subname,
|
||||
const char *type, const char *acls, const char *owner,
|
||||
int remoteVersion,
|
||||
const char *prefix, int remoteVersion,
|
||||
PQExpBuffer sql);
|
||||
extern bool buildDefaultACLCommands(const char *type, const char *nspname,
|
||||
const char *acls, const char *owner,
|
||||
int remoteVersion,
|
||||
PQExpBuffer sql);
|
||||
extern void processSQLNamePattern(PGconn *conn, PQExpBuffer buf,
|
||||
const char *pattern,
|
||||
bool have_where, bool force_escape,
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.175 2009/08/07 22:48:34 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.176 2009/10/05 19:24:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -2072,7 +2072,8 @@ ReadToc(ArchiveHandle *AH)
|
|||
* the entries into sections
|
||||
*/
|
||||
if (strcmp(te->desc, "COMMENT") == 0 ||
|
||||
strcmp(te->desc, "ACL") == 0)
|
||||
strcmp(te->desc, "ACL") == 0 ||
|
||||
strcmp(te->desc, "DEFAULT ACL") == 0)
|
||||
te->section = SECTION_NONE;
|
||||
else if (strcmp(te->desc, "TABLE DATA") == 0 ||
|
||||
strcmp(te->desc, "BLOBS") == 0 ||
|
||||
|
@ -2227,7 +2228,8 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls)
|
|||
return 0;
|
||||
|
||||
/* If it's an ACL, maybe ignore it */
|
||||
if ((!include_acls || ropt->aclsSkip) && strcmp(te->desc, "ACL") == 0)
|
||||
if ((!include_acls || ropt->aclsSkip) &&
|
||||
(strcmp(te->desc, "ACL") == 0 || strcmp(te->desc, "DEFAULT ACL") == 0))
|
||||
return 0;
|
||||
|
||||
if (!ropt->create && strcmp(te->desc, "DATABASE") == 0)
|
||||
|
@ -2721,12 +2723,14 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat
|
|||
/* ACLs are dumped only during acl pass */
|
||||
if (acl_pass)
|
||||
{
|
||||
if (strcmp(te->desc, "ACL") != 0)
|
||||
if (!(strcmp(te->desc, "ACL") == 0 ||
|
||||
strcmp(te->desc, "DEFAULT ACL") == 0))
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (strcmp(te->desc, "ACL") == 0)
|
||||
if (strcmp(te->desc, "ACL") == 0 ||
|
||||
strcmp(te->desc, "DEFAULT ACL") == 0)
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
* by PostgreSQL
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.548 2009/09/22 23:43:38 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.549 2009/10/05 19:24:45 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -34,6 +34,7 @@
|
|||
#include "access/sysattr.h"
|
||||
#include "catalog/pg_cast.h"
|
||||
#include "catalog/pg_class.h"
|
||||
#include "catalog/pg_default_acl.h"
|
||||
#include "catalog/pg_largeobject.h"
|
||||
#include "catalog/pg_proc.h"
|
||||
#include "catalog/pg_trigger.h"
|
||||
|
@ -162,6 +163,7 @@ static void dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo);
|
|||
static void dumpUserMappings(Archive *fout, const char *target,
|
||||
const char *servername, const char *namespace,
|
||||
const char *owner, CatalogId catalogId, DumpId dumpId);
|
||||
static void dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo);
|
||||
|
||||
static void dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
|
||||
const char *type, const char *name, const char *subname,
|
||||
|
@ -1049,6 +1051,23 @@ selectDumpableType(TypeInfo *tinfo)
|
|||
tinfo->dobj.dump = true;
|
||||
}
|
||||
|
||||
/*
|
||||
* selectDumpableDefaultACL: policy-setting subroutine
|
||||
* Mark a default ACL as to be dumped or not
|
||||
*
|
||||
* For per-schema default ACLs, dump if the schema is to be dumped.
|
||||
* Otherwise dump if we are dumping "everything". Note that dataOnly
|
||||
* and aclsSkip are checked separately.
|
||||
*/
|
||||
static void
|
||||
selectDumpableDefaultACL(DefaultACLInfo *dinfo)
|
||||
{
|
||||
if (dinfo->dobj.namespace)
|
||||
dinfo->dobj.dump = dinfo->dobj.namespace->dobj.dump;
|
||||
else
|
||||
dinfo->dobj.dump = include_everything;
|
||||
}
|
||||
|
||||
/*
|
||||
* selectDumpableObject: policy-setting subroutine
|
||||
* Mark a generic dumpable object as to be dumped or not
|
||||
|
@ -1779,7 +1798,7 @@ dumpDatabase(Archive *AH)
|
|||
PQExpBuffer loFrozenQry = createPQExpBuffer();
|
||||
PQExpBuffer loOutQry = createPQExpBuffer();
|
||||
int i_relfrozenxid;
|
||||
|
||||
|
||||
appendPQExpBuffer(loFrozenQry, "SELECT relfrozenxid\n"
|
||||
"FROM pg_catalog.pg_class\n"
|
||||
"WHERE oid = %d;\n",
|
||||
|
@ -1808,7 +1827,7 @@ dumpDatabase(Archive *AH)
|
|||
loOutQry->data, "", NULL,
|
||||
NULL, 0,
|
||||
NULL, NULL);
|
||||
|
||||
|
||||
PQclear(lo_res);
|
||||
destroyPQExpBuffer(loFrozenQry);
|
||||
destroyPQExpBuffer(loOutQry);
|
||||
|
@ -5645,6 +5664,94 @@ getForeignServers(int *numForeignServers)
|
|||
return srvinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* getDefaultACLs:
|
||||
* read all default ACL information in the system catalogs and return
|
||||
* them in the DefaultACLInfo structure
|
||||
*
|
||||
* numDefaultACLs is set to the number of ACLs read in
|
||||
*/
|
||||
DefaultACLInfo *
|
||||
getDefaultACLs(int *numDefaultACLs)
|
||||
{
|
||||
DefaultACLInfo *daclinfo;
|
||||
PQExpBuffer query;
|
||||
PGresult *res;
|
||||
int i_oid;
|
||||
int i_tableoid;
|
||||
int i_defaclrole;
|
||||
int i_defaclnamespace;
|
||||
int i_defaclobjtype;
|
||||
int i_defaclacl;
|
||||
int i,
|
||||
ntups;
|
||||
|
||||
if (g_fout->remoteVersion < 80500)
|
||||
{
|
||||
*numDefaultACLs = 0;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
query = createPQExpBuffer();
|
||||
|
||||
/* Make sure we are in proper schema */
|
||||
selectSourceSchema("pg_catalog");
|
||||
|
||||
appendPQExpBuffer(query, "SELECT oid, tableoid, "
|
||||
"(%s defaclrole) AS defaclrole, "
|
||||
"defaclnamespace, "
|
||||
"defaclobjtype, "
|
||||
"defaclacl "
|
||||
"FROM pg_default_acl",
|
||||
username_subquery);
|
||||
|
||||
res = PQexec(g_conn, query->data);
|
||||
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
|
||||
|
||||
ntups = PQntuples(res);
|
||||
*numDefaultACLs = ntups;
|
||||
|
||||
daclinfo = (DefaultACLInfo *) malloc(ntups * sizeof(DefaultACLInfo));
|
||||
|
||||
i_oid = PQfnumber(res, "oid");
|
||||
i_tableoid = PQfnumber(res, "tableoid");
|
||||
i_defaclrole = PQfnumber(res, "defaclrole");
|
||||
i_defaclnamespace = PQfnumber(res, "defaclnamespace");
|
||||
i_defaclobjtype = PQfnumber(res, "defaclobjtype");
|
||||
i_defaclacl = PQfnumber(res, "defaclacl");
|
||||
|
||||
for (i = 0; i < ntups; i++)
|
||||
{
|
||||
Oid nspid = atooid(PQgetvalue(res, i, i_defaclnamespace));
|
||||
|
||||
daclinfo[i].dobj.objType = DO_DEFAULT_ACL;
|
||||
daclinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
|
||||
daclinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
|
||||
AssignDumpId(&daclinfo[i].dobj);
|
||||
/* cheesy ... is it worth coming up with a better object name? */
|
||||
daclinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_defaclobjtype));
|
||||
|
||||
if (nspid != InvalidOid)
|
||||
daclinfo[i].dobj.namespace = findNamespace(nspid,
|
||||
daclinfo[i].dobj.catId.oid);
|
||||
else
|
||||
daclinfo[i].dobj.namespace = NULL;
|
||||
|
||||
daclinfo[i].defaclrole = strdup(PQgetvalue(res, i, i_defaclrole));
|
||||
daclinfo[i].defaclobjtype = *(PQgetvalue(res, i, i_defaclobjtype));
|
||||
daclinfo[i].defaclacl = strdup(PQgetvalue(res, i, i_defaclacl));
|
||||
|
||||
/* Decide whether we want to dump it */
|
||||
selectDumpableDefaultACL(&(daclinfo[i]));
|
||||
}
|
||||
|
||||
PQclear(res);
|
||||
|
||||
destroyPQExpBuffer(query);
|
||||
|
||||
return daclinfo;
|
||||
}
|
||||
|
||||
/*
|
||||
* dumpComment --
|
||||
*
|
||||
|
@ -6058,6 +6165,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
|
|||
case DO_FOREIGN_SERVER:
|
||||
dumpForeignServer(fout, (ForeignServerInfo *) dobj);
|
||||
break;
|
||||
case DO_DEFAULT_ACL:
|
||||
dumpDefaultACL(fout, (DefaultACLInfo *) dobj);
|
||||
break;
|
||||
case DO_BLOBS:
|
||||
ArchiveEntry(fout, dobj->catId, dobj->dumpId,
|
||||
dobj->name, NULL, NULL, "",
|
||||
|
@ -9791,6 +9901,72 @@ dumpUserMappings(Archive *fout, const char *target,
|
|||
destroyPQExpBuffer(q);
|
||||
}
|
||||
|
||||
/*
|
||||
* Write out default privileges information
|
||||
*/
|
||||
static void
|
||||
dumpDefaultACL(Archive *fout, DefaultACLInfo *daclinfo)
|
||||
{
|
||||
PQExpBuffer q;
|
||||
PQExpBuffer tag;
|
||||
const char *type;
|
||||
|
||||
/* Skip if not to be dumped */
|
||||
if (!daclinfo->dobj.dump || dataOnly || aclsSkip)
|
||||
return;
|
||||
|
||||
q = createPQExpBuffer();
|
||||
tag = createPQExpBuffer();
|
||||
|
||||
switch (daclinfo->defaclobjtype)
|
||||
{
|
||||
case DEFACLOBJ_RELATION:
|
||||
type = "TABLE";
|
||||
break;
|
||||
case DEFACLOBJ_SEQUENCE:
|
||||
type = "SEQUENCE";
|
||||
break;
|
||||
case DEFACLOBJ_FUNCTION:
|
||||
type = "FUNCTION";
|
||||
break;
|
||||
default:
|
||||
/* shouldn't get here */
|
||||
write_msg(NULL, "unknown object type (%d) in default privileges\n",
|
||||
(int) daclinfo->defaclobjtype);
|
||||
exit_nicely();
|
||||
type = ""; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
appendPQExpBuffer(tag, "DEFAULT %s PRIVILEGES", type);
|
||||
|
||||
/* build the actual command(s) for this tuple */
|
||||
if (!buildDefaultACLCommands(type,
|
||||
daclinfo->dobj.namespace != NULL ?
|
||||
daclinfo->dobj.namespace->dobj.name : NULL,
|
||||
daclinfo->defaclacl,
|
||||
daclinfo->defaclrole,
|
||||
fout->remoteVersion,
|
||||
q))
|
||||
{
|
||||
write_msg(NULL, "could not parse default ACL list (%s)\n",
|
||||
daclinfo->defaclacl);
|
||||
exit_nicely();
|
||||
}
|
||||
|
||||
ArchiveEntry(fout, daclinfo->dobj.catId, daclinfo->dobj.dumpId,
|
||||
tag->data,
|
||||
daclinfo->dobj.namespace ? daclinfo->dobj.namespace->dobj.name : NULL,
|
||||
NULL,
|
||||
daclinfo->defaclrole,
|
||||
false, "DEFAULT ACL", SECTION_NONE,
|
||||
q->data, "", NULL,
|
||||
daclinfo->dobj.dependencies, daclinfo->dobj.nDeps,
|
||||
NULL, NULL);
|
||||
|
||||
destroyPQExpBuffer(tag);
|
||||
destroyPQExpBuffer(q);
|
||||
}
|
||||
|
||||
/*----------
|
||||
* Write out grant/revoke information
|
||||
*
|
||||
|
@ -9820,7 +9996,8 @@ dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
|
|||
|
||||
sql = createPQExpBuffer();
|
||||
|
||||
if (!buildACLCommands(name, subname, type, acls, owner, fout->remoteVersion, sql))
|
||||
if (!buildACLCommands(name, subname, type, acls, owner,
|
||||
"", fout->remoteVersion, sql))
|
||||
{
|
||||
write_msg(NULL, "could not parse ACL list (%s) for object \"%s\" (%s)\n",
|
||||
acls, name, type);
|
||||
|
@ -10263,7 +10440,7 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
|
|||
fmtId(tbinfo->dobj.name));
|
||||
appendPQExpBuffer(q, "ALTER COLUMN %s ",
|
||||
fmtId(tbinfo->attnames[j]));
|
||||
appendPQExpBuffer(q, "SET STATISTICS DISTINCT %g;\n",
|
||||
appendPQExpBuffer(q, "SET STATISTICS DISTINCT %g;\n",
|
||||
tbinfo->attdistinct[j]);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.157 2009/09/22 23:43:40 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.158 2009/10/05 19:24:46 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -114,6 +114,7 @@ typedef enum
|
|||
DO_TSCONFIG,
|
||||
DO_FDW,
|
||||
DO_FOREIGN_SERVER,
|
||||
DO_DEFAULT_ACL,
|
||||
DO_BLOBS,
|
||||
DO_BLOB_COMMENTS
|
||||
} DumpableObjectType;
|
||||
|
@ -432,6 +433,14 @@ typedef struct _foreignServerInfo
|
|||
char *srvoptions;
|
||||
} ForeignServerInfo;
|
||||
|
||||
typedef struct _defaultACLInfo
|
||||
{
|
||||
DumpableObject dobj;
|
||||
char *defaclrole;
|
||||
char defaclobjtype;
|
||||
char *defaclacl;
|
||||
} DefaultACLInfo;
|
||||
|
||||
/* global decls */
|
||||
extern bool force_quotes; /* double-quotes for identifiers flag */
|
||||
extern bool g_verbose; /* verbose flag */
|
||||
|
@ -516,5 +525,6 @@ extern TSTemplateInfo *getTSTemplates(int *numTSTemplates);
|
|||
extern TSConfigInfo *getTSConfigurations(int *numTSConfigs);
|
||||
extern FdwInfo *getForeignDataWrappers(int *numForeignDataWrappers);
|
||||
extern ForeignServerInfo *getForeignServers(int *numForeignServers);
|
||||
extern DefaultACLInfo *getDefaultACLs(int *numDefaultACLs);
|
||||
|
||||
#endif /* PG_DUMP_H */
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.25 2009/06/11 14:49:07 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.26 2009/10/05 19:24:46 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -23,8 +23,8 @@ static const char *modulename = gettext_noop("sorter");
|
|||
* Objects are sorted by priority levels, and within an equal priority level
|
||||
* by OID. (This is a relatively crude hack to provide semi-reasonable
|
||||
* behavior for old databases without full dependency info.) Note: text
|
||||
* search and foreign-data objects can't really happen here, so the rather
|
||||
* bogus priorities for them don't matter.
|
||||
* search, foreign-data, and default ACL objects can't really happen here,
|
||||
* so the rather bogus priorities for them don't matter.
|
||||
*/
|
||||
static const int oldObjectTypePriority[] =
|
||||
{
|
||||
|
@ -54,6 +54,7 @@ static const int oldObjectTypePriority[] =
|
|||
5, /* DO_TSCONFIG */
|
||||
3, /* DO_FDW */
|
||||
4, /* DO_FOREIGN_SERVER */
|
||||
17, /* DO_DEFAULT_ACL */
|
||||
10, /* DO_BLOBS */
|
||||
11 /* DO_BLOB_COMMENTS */
|
||||
};
|
||||
|
@ -90,6 +91,7 @@ static const int newObjectTypePriority[] =
|
|||
13, /* DO_TSCONFIG */
|
||||
14, /* DO_FDW */
|
||||
15, /* DO_FOREIGN_SERVER */
|
||||
27, /* DO_DEFAULT_ACL */
|
||||
20, /* DO_BLOBS */
|
||||
21 /* DO_BLOB_COMMENTS */
|
||||
};
|
||||
|
@ -1139,6 +1141,11 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize)
|
|||
"FOREIGN SERVER %s (ID %d OID %u)",
|
||||
obj->name, obj->dumpId, obj->catId.oid);
|
||||
return;
|
||||
case DO_DEFAULT_ACL:
|
||||
snprintf(buf, bufsize,
|
||||
"DEFAULT ACL %s (ID %d OID %u)",
|
||||
obj->name, obj->dumpId, obj->catId.oid);
|
||||
return;
|
||||
case DO_BLOBS:
|
||||
snprintf(buf, bufsize,
|
||||
"BLOBS (ID %d)",
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.126 2009/06/11 14:49:07 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.127 2009/10/05 19:24:46 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -989,7 +989,7 @@ dumpTablespaces(PGconn *conn)
|
|||
|
||||
if (!skip_acls &&
|
||||
!buildACLCommands(fspcname, NULL, "TABLESPACE", spcacl, spcowner,
|
||||
server_version, buf))
|
||||
"", server_version, buf))
|
||||
{
|
||||
fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
|
||||
progname, spcacl, fspcname);
|
||||
|
@ -1289,7 +1289,7 @@ dumpCreateDB(PGconn *conn)
|
|||
|
||||
if (!skip_acls &&
|
||||
!buildACLCommands(fdbname, NULL, "DATABASE", dbacl, dbowner,
|
||||
server_version, buf))
|
||||
"", server_version, buf))
|
||||
{
|
||||
fprintf(stderr, _("%s: could not parse ACL list (%s) for database \"%s\"\n"),
|
||||
progname, dbacl, fdbname);
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.207 2009/09/13 22:18:22 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.208 2009/10/05 19:24:46 tgl Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
#include "command.h"
|
||||
|
@ -361,7 +361,10 @@ exec_command(const char *cmd,
|
|||
success = listCasts(pattern);
|
||||
break;
|
||||
case 'd':
|
||||
success = objectDescription(pattern, show_system);
|
||||
if (strcmp(cmd, "ddp") == 0)
|
||||
success = listDefaultACLs(pattern);
|
||||
else
|
||||
success = objectDescription(pattern, show_system);
|
||||
break;
|
||||
case 'D':
|
||||
success = listDomains(pattern, show_system);
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
*
|
||||
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.226 2009/07/29 20:56:19 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.227 2009/10/05 19:24:46 tgl Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
|
||||
|
@ -732,6 +732,73 @@ permissionsList(const char *pattern)
|
|||
}
|
||||
|
||||
|
||||
/*
|
||||
* \ddp
|
||||
*
|
||||
* List DefaultACLs. The pattern can match either schema or role name.
|
||||
*/
|
||||
bool
|
||||
listDefaultACLs(const char *pattern)
|
||||
{
|
||||
PQExpBufferData buf;
|
||||
PGresult *res;
|
||||
printQueryOpt myopt = pset.popt;
|
||||
static const bool translate_columns[] = {false, false, true, false};
|
||||
|
||||
if (pset.sversion < 80500)
|
||||
{
|
||||
fprintf(stderr, _("The server (version %d.%d) does not support altering default privileges.\n"),
|
||||
pset.sversion / 10000, (pset.sversion / 100) % 100);
|
||||
return true;
|
||||
}
|
||||
|
||||
initPQExpBuffer(&buf);
|
||||
|
||||
printfPQExpBuffer(&buf,
|
||||
"SELECT pg_catalog.pg_get_userbyid(d.defaclrole) AS \"%s\",\n"
|
||||
" n.nspname AS \"%s\",\n"
|
||||
" CASE d.defaclobjtype WHEN 'r' THEN '%s' WHEN 'S' THEN '%s' WHEN 'f' THEN '%s' END AS \"%s\",\n"
|
||||
" ",
|
||||
gettext_noop("Owner"),
|
||||
gettext_noop("Schema"),
|
||||
gettext_noop("table"),
|
||||
gettext_noop("sequence"),
|
||||
gettext_noop("function"),
|
||||
gettext_noop("Type"));
|
||||
|
||||
printACLColumn(&buf, "d.defaclacl");
|
||||
|
||||
appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_default_acl d\n"
|
||||
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = d.defaclnamespace\n");
|
||||
|
||||
processSQLNamePattern(pset.db, &buf, pattern, false, false,
|
||||
NULL,
|
||||
"n.nspname",
|
||||
"pg_catalog.pg_get_userbyid(d.defaclrole)",
|
||||
NULL);
|
||||
|
||||
appendPQExpBuffer(&buf, "ORDER BY 1, 2, 3;");
|
||||
|
||||
res = PSQLexec(buf.data, false);
|
||||
if (!res)
|
||||
{
|
||||
termPQExpBuffer(&buf);
|
||||
return false;
|
||||
}
|
||||
|
||||
myopt.nullPrint = NULL;
|
||||
printfPQExpBuffer(&buf, _("Default access privileges"));
|
||||
myopt.title = buf.data;
|
||||
myopt.translate_header = true;
|
||||
myopt.translate_columns = translate_columns;
|
||||
|
||||
printQuery(res, &myopt, pset.queryFout, pset.logfile);
|
||||
|
||||
termPQExpBuffer(&buf);
|
||||
PQclear(res);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Get object comments
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.40 2009/04/21 15:49:06 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.41 2009/10/05 19:24:46 tgl Exp $
|
||||
*/
|
||||
#ifndef DESCRIBE_H
|
||||
#define DESCRIBE_H
|
||||
|
@ -30,6 +30,9 @@ extern bool describeRoles(const char *pattern, bool verbose);
|
|||
/* \z (or \dp) */
|
||||
extern bool permissionsList(const char *pattern);
|
||||
|
||||
/* \ddp */
|
||||
extern bool listDefaultACLs(const char *pattern);
|
||||
|
||||
/* \dd */
|
||||
extern bool objectDescription(const char *pattern, bool showSystem);
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
*
|
||||
* Copyright (c) 2000-2009, PostgreSQL Global Development Group
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.152 2009/09/18 05:00:42 petere Exp $
|
||||
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.153 2009/10/05 19:24:46 tgl Exp $
|
||||
*/
|
||||
#include "postgres_fe.h"
|
||||
|
||||
|
@ -201,6 +201,7 @@ slashUsage(unsigned short int pager)
|
|||
fprintf(output, _(" \\dc[S] [PATTERN] list conversions\n"));
|
||||
fprintf(output, _(" \\dC [PATTERN] list casts\n"));
|
||||
fprintf(output, _(" \\dd[S] [PATTERN] show comments on objects\n"));
|
||||
fprintf(output, _(" \\ddp [PATTERN] list default privileges\n"));
|
||||
fprintf(output, _(" \\dD[S] [PATTERN] list domains\n"));
|
||||
fprintf(output, _(" \\des[+] [PATTERN] list foreign servers\n"));
|
||||
fprintf(output, _(" \\deu[+] [PATTERN] list user mappings\n"));
|
||||
|
|
|
@ -37,7 +37,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.540 2009/09/26 22:42:01 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.541 2009/10/05 19:24:46 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -53,6 +53,6 @@
|
|||
*/
|
||||
|
||||
/* yyyymmddN */
|
||||
#define CATALOG_VERSION_NO 200909261
|
||||
#define CATALOG_VERSION_NO 200910051
|
||||
|
||||
#endif
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.40 2009/06/11 14:49:09 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.41 2009/10/05 19:24:48 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -146,6 +146,7 @@ typedef enum ObjectClass
|
|||
OCLASS_FDW, /* pg_foreign_data_wrapper */
|
||||
OCLASS_FOREIGN_SERVER, /* pg_foreign_server */
|
||||
OCLASS_USER_MAPPING, /* pg_user_mapping */
|
||||
OCLASS_DEFACL, /* pg_default_acl */
|
||||
MAX_OCLASS /* MUST BE LAST */
|
||||
} ObjectClass;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.93 2009/09/26 22:42:02 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.94 2009/10/05 19:24:48 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -57,6 +57,7 @@ extern Oid heap_create_with_catalog(const char *relname,
|
|||
int oidinhcount,
|
||||
OnCommitAction oncommit,
|
||||
Datum reloptions,
|
||||
bool use_user_acl,
|
||||
bool allow_system_table_mods);
|
||||
|
||||
extern void heap_drop_with_catalog(Oid relid);
|
||||
|
@ -76,6 +77,7 @@ extern void InsertPgAttributeTuple(Relation pg_attribute_rel,
|
|||
extern void InsertPgClassTuple(Relation pg_class_desc,
|
||||
Relation new_rel_desc,
|
||||
Oid new_rel_oid,
|
||||
Datum relacl,
|
||||
Datum reloptions);
|
||||
|
||||
extern List *AddRelationNewConstraints(Relation rel,
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.108 2009/06/11 14:49:09 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.109 2009/10/05 19:24:48 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -267,6 +267,11 @@ DECLARE_UNIQUE_INDEX(pg_user_mapping_oid_index, 174, on pg_user_mapping using bt
|
|||
DECLARE_UNIQUE_INDEX(pg_user_mapping_user_server_index, 175, on pg_user_mapping using btree(umuser oid_ops, umserver oid_ops));
|
||||
#define UserMappingUserServerIndexId 175
|
||||
|
||||
DECLARE_UNIQUE_INDEX(pg_default_acl_role_nsp_obj_index, 827, on pg_default_acl using btree(defaclrole oid_ops, defaclnamespace oid_ops, defaclobjtype char_ops));
|
||||
#define DefaultAclRoleNspObjIndexId 827
|
||||
DECLARE_UNIQUE_INDEX(pg_default_acl_oid_index, 828, on pg_default_acl using btree(oid oid_ops));
|
||||
#define DefaultAclOidIndexId 828
|
||||
|
||||
/* last step of initialization script: build the indexes declared above */
|
||||
BUILD_INDICES
|
||||
|
||||
|
|
|
@ -0,0 +1,75 @@
|
|||
/*-------------------------------------------------------------------------
|
||||
*
|
||||
* pg_default_acl.h
|
||||
* definition of default ACLs for new objects.
|
||||
*
|
||||
*
|
||||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/catalog/pg_default_acl.h,v 1.1 2009/10/05 19:24:48 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* the genbki.sh script reads this file and generates .bki
|
||||
* information from the DATA() statements.
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
#ifndef PG_DEFAULT_ACL_H
|
||||
#define PG_DEFAULT_ACL_H
|
||||
|
||||
#include "catalog/genbki.h"
|
||||
|
||||
/* ----------------
|
||||
* pg_default_acl definition. cpp turns this into
|
||||
* typedef struct FormData_pg_default_acl
|
||||
* ----------------
|
||||
*/
|
||||
#define DefaultAclRelationId 826
|
||||
|
||||
CATALOG(pg_default_acl,826)
|
||||
{
|
||||
Oid defaclrole; /* OID of role owning this ACL */
|
||||
Oid defaclnamespace; /* OID of namespace, or 0 for all */
|
||||
char defaclobjtype; /* see DEFACLOBJ_xxx constants below */
|
||||
|
||||
/*
|
||||
* VARIABLE LENGTH FIELDS start here.
|
||||
*/
|
||||
|
||||
aclitem defaclacl[1]; /* permissions to add at CREATE time */
|
||||
} FormData_pg_default_acl;
|
||||
|
||||
/* ----------------
|
||||
* Form_pg_default_acl corresponds to a pointer to a tuple with
|
||||
* the format of pg_default_acl relation.
|
||||
* ----------------
|
||||
*/
|
||||
typedef FormData_pg_default_acl *Form_pg_default_acl;
|
||||
|
||||
/* ----------------
|
||||
* compiler constants for pg_default_acl
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
#define Natts_pg_default_acl 4
|
||||
#define Anum_pg_default_acl_defaclrole 1
|
||||
#define Anum_pg_default_acl_defaclnamespace 2
|
||||
#define Anum_pg_default_acl_defaclobjtype 3
|
||||
#define Anum_pg_default_acl_defaclacl 4
|
||||
|
||||
/* ----------------
|
||||
* pg_default_acl has no initial contents
|
||||
* ----------------
|
||||
*/
|
||||
|
||||
/*
|
||||
* Types of objects for which the user is allowed to specify default
|
||||
* permissions through pg_default_acl. These codes are used in the
|
||||
* defaclobjtype column.
|
||||
*/
|
||||
#define DEFACLOBJ_RELATION 'r' /* table, view */
|
||||
#define DEFACLOBJ_SEQUENCE 'S' /* sequence */
|
||||
#define DEFACLOBJ_FUNCTION 'f' /* function */
|
||||
|
||||
#endif /* PG_DEFAULT_ACL_H */
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.226 2009/09/22 23:43:41 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.227 2009/10/05 19:24:48 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -261,6 +261,7 @@ typedef enum NodeTag
|
|||
T_SetOperationStmt,
|
||||
T_GrantStmt,
|
||||
T_GrantRoleStmt,
|
||||
T_AlterDefaultPrivilegesStmt,
|
||||
T_ClosePortalStmt,
|
||||
T_ClusterStmt,
|
||||
T_CopyStmt,
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.402 2009/09/22 23:43:41 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.403 2009/10/05 19:24:48 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -1259,6 +1259,17 @@ typedef struct GrantRoleStmt
|
|||
DropBehavior behavior; /* drop behavior (for REVOKE) */
|
||||
} GrantRoleStmt;
|
||||
|
||||
/* ----------------------
|
||||
* Alter Default Privileges Statement
|
||||
* ----------------------
|
||||
*/
|
||||
typedef struct AlterDefaultPrivilegesStmt
|
||||
{
|
||||
NodeTag type;
|
||||
List *options; /* list of DefElem */
|
||||
GrantStmt *action; /* GRANT/REVOKE action (with objects=NIL) */
|
||||
} AlterDefaultPrivilegesStmt;
|
||||
|
||||
/* ----------------------
|
||||
* Copy Statement
|
||||
*
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.108 2009/06/11 14:49:13 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.109 2009/10/05 19:24:49 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* An ACL array is simply an array of AclItems, representing the union
|
||||
|
@ -193,41 +193,23 @@ typedef enum AclObjectKind
|
|||
MAX_ACL_KIND /* MUST BE LAST */
|
||||
} AclObjectKind;
|
||||
|
||||
/*
|
||||
* The information about one Grant/Revoke statement, in internal format: object
|
||||
* and grantees names have been turned into Oids, the privilege list is an
|
||||
* AclMode bitmask. If 'privileges' is ACL_NO_RIGHTS (the 0 value) and
|
||||
* all_privs is true, 'privileges' will be internally set to the right kind of
|
||||
* ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the
|
||||
* InternalGrant struct!)
|
||||
*
|
||||
* Note: 'all_privs' and 'privileges' represent object-level privileges only.
|
||||
* There might also be column-level privilege specifications, which are
|
||||
* represented in col_privs (this is a list of untransformed AccessPriv nodes).
|
||||
* Column privileges are only valid for objtype ACL_OBJECT_RELATION.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
bool is_grant;
|
||||
GrantObjectType objtype;
|
||||
List *objects;
|
||||
bool all_privs;
|
||||
AclMode privileges;
|
||||
List *col_privs;
|
||||
List *grantees;
|
||||
bool grant_option;
|
||||
DropBehavior behavior;
|
||||
} InternalGrant;
|
||||
|
||||
/*
|
||||
* routines used internally
|
||||
*/
|
||||
extern Acl *acldefault(GrantObjectType objtype, Oid ownerId);
|
||||
extern Acl *get_user_default_acl(GrantObjectType objtype, Oid ownerId,
|
||||
Oid nsp_oid);
|
||||
|
||||
extern Acl *aclupdate(const Acl *old_acl, const AclItem *mod_aip,
|
||||
int modechg, Oid ownerId, DropBehavior behavior);
|
||||
extern Acl *aclnewowner(const Acl *old_acl, Oid oldOwnerId, Oid newOwnerId);
|
||||
extern Acl *make_empty_acl(void);
|
||||
extern Acl *aclcopy(const Acl *orig_acl);
|
||||
extern Acl *aclconcat(const Acl *left_acl, const Acl *right_acl);
|
||||
extern Acl *aclmerge(const Acl *left_acl, const Acl *right_acl, Oid ownerId);
|
||||
extern void aclitemsort(Acl *acl);
|
||||
extern bool aclequal(const Acl *left_acl, const Acl *right_acl);
|
||||
|
||||
extern AclMode aclmask(const Acl *acl, Oid roleid, Oid ownerId,
|
||||
AclMode mask, AclMaskHow how);
|
||||
|
@ -261,7 +243,10 @@ extern Datum hash_aclitem(PG_FUNCTION_ARGS);
|
|||
* prototypes for functions in aclchk.c
|
||||
*/
|
||||
extern void ExecuteGrantStmt(GrantStmt *stmt);
|
||||
extern void ExecGrantStmt_oids(InternalGrant *istmt);
|
||||
extern void ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt);
|
||||
|
||||
extern void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid);
|
||||
extern void RemoveDefaultACLById(Oid defaclOid);
|
||||
|
||||
extern AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum,
|
||||
Oid roleid, AclMode mask, AclMaskHow how);
|
||||
|
|
|
@ -9,7 +9,7 @@
|
|||
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.74 2009/01/01 17:24:02 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.75 2009/10/05 19:24:49 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
|
@ -49,6 +49,7 @@ enum SysCacheIdentifier
|
|||
CONSTROID,
|
||||
CONVOID,
|
||||
DATABASEOID,
|
||||
DEFACLROLENSPOBJ,
|
||||
ENUMOID,
|
||||
ENUMTYPOIDNAME,
|
||||
FOREIGNDATAWRAPPERNAME,
|
||||
|
|
|
@ -836,6 +836,117 @@ SELECT has_sequence_privilege('x_seq', 'USAGE');
|
|||
t
|
||||
(1 row)
|
||||
|
||||
-- test default ACLs
|
||||
\c -
|
||||
CREATE SCHEMA testns;
|
||||
GRANT ALL ON SCHEMA testns TO regressuser1;
|
||||
CREATE TABLE testns.acltest1 (x int);
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'SELECT'); -- no
|
||||
has_table_privilege
|
||||
---------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'INSERT'); -- no
|
||||
has_table_privilege
|
||||
---------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT SELECT ON TABLE TO public;
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'SELECT'); -- no
|
||||
has_table_privilege
|
||||
---------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'INSERT'); -- no
|
||||
has_table_privilege
|
||||
---------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
DROP TABLE testns.acltest1;
|
||||
CREATE TABLE testns.acltest1 (x int);
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'SELECT'); -- yes
|
||||
has_table_privilege
|
||||
---------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'INSERT'); -- no
|
||||
has_table_privilege
|
||||
---------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT INSERT ON TABLE TO regressuser1;
|
||||
DROP TABLE testns.acltest1;
|
||||
CREATE TABLE testns.acltest1 (x int);
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'SELECT'); -- yes
|
||||
has_table_privilege
|
||||
---------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'INSERT'); -- yes
|
||||
has_table_privilege
|
||||
---------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA testns REVOKE INSERT ON TABLE FROM regressuser1;
|
||||
DROP TABLE testns.acltest1;
|
||||
CREATE TABLE testns.acltest1 (x int);
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'SELECT'); -- yes
|
||||
has_table_privilege
|
||||
---------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'INSERT'); -- no
|
||||
has_table_privilege
|
||||
---------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE regressuser1 REVOKE EXECUTE ON FUNCTION FROM public;
|
||||
SET ROLE regressuser1;
|
||||
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
|
||||
SELECT has_function_privilege('regressuser2', 'testns.foo()', 'EXECUTE'); -- no
|
||||
has_function_privilege
|
||||
------------------------
|
||||
f
|
||||
(1 row)
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT EXECUTE ON FUNCTION to public;
|
||||
DROP FUNCTION testns.foo();
|
||||
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
|
||||
SELECT has_function_privilege('regressuser2', 'testns.foo()', 'EXECUTE'); -- yes
|
||||
has_function_privilege
|
||||
------------------------
|
||||
t
|
||||
(1 row)
|
||||
|
||||
DROP FUNCTION testns.foo();
|
||||
RESET ROLE;
|
||||
SELECT count(*)
|
||||
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
|
||||
WHERE nspname = 'testns';
|
||||
count
|
||||
-------
|
||||
2
|
||||
(1 row)
|
||||
|
||||
DROP SCHEMA testns CASCADE;
|
||||
NOTICE: drop cascades to table testns.acltest1
|
||||
SELECT d.* -- check that entries went away
|
||||
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
|
||||
WHERE nspname IS NULL AND defaclnamespace != 0;
|
||||
defaclrole | defaclnamespace | defaclobjtype | defaclacl
|
||||
------------+-----------------+---------------+-----------
|
||||
(0 rows)
|
||||
|
||||
-- clean up
|
||||
\c
|
||||
drop sequence x_seq;
|
||||
|
@ -860,7 +971,9 @@ DROP TABLE atestp1;
|
|||
DROP TABLE atestp2;
|
||||
DROP GROUP regressgroup1;
|
||||
DROP GROUP regressgroup2;
|
||||
-- these are needed to clean up permissions
|
||||
REVOKE USAGE ON LANGUAGE sql FROM regressuser1;
|
||||
DROP OWNED BY regressuser1;
|
||||
DROP USER regressuser1;
|
||||
DROP USER regressuser2;
|
||||
DROP USER regressuser3;
|
||||
|
|
|
@ -95,6 +95,7 @@ SELECT relname, relhasindex
|
|||
pg_constraint | t
|
||||
pg_conversion | t
|
||||
pg_database | t
|
||||
pg_default_acl | t
|
||||
pg_depend | t
|
||||
pg_description | t
|
||||
pg_enum | t
|
||||
|
@ -151,7 +152,7 @@ SELECT relname, relhasindex
|
|||
timetz_tbl | f
|
||||
tinterval_tbl | f
|
||||
varchar_tbl | f
|
||||
(140 rows)
|
||||
(141 rows)
|
||||
|
||||
--
|
||||
-- another sanity check: every system catalog that has OIDs should have
|
||||
|
|
|
@ -484,6 +484,73 @@ SET SESSION AUTHORIZATION regressuser2;
|
|||
|
||||
SELECT has_sequence_privilege('x_seq', 'USAGE');
|
||||
|
||||
|
||||
-- test default ACLs
|
||||
\c -
|
||||
|
||||
CREATE SCHEMA testns;
|
||||
GRANT ALL ON SCHEMA testns TO regressuser1;
|
||||
|
||||
CREATE TABLE testns.acltest1 (x int);
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'SELECT'); -- no
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'INSERT'); -- no
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT SELECT ON TABLE TO public;
|
||||
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'SELECT'); -- no
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'INSERT'); -- no
|
||||
|
||||
DROP TABLE testns.acltest1;
|
||||
CREATE TABLE testns.acltest1 (x int);
|
||||
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'SELECT'); -- yes
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'INSERT'); -- no
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT INSERT ON TABLE TO regressuser1;
|
||||
|
||||
DROP TABLE testns.acltest1;
|
||||
CREATE TABLE testns.acltest1 (x int);
|
||||
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'SELECT'); -- yes
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'INSERT'); -- yes
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA testns REVOKE INSERT ON TABLE FROM regressuser1;
|
||||
|
||||
DROP TABLE testns.acltest1;
|
||||
CREATE TABLE testns.acltest1 (x int);
|
||||
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'SELECT'); -- yes
|
||||
SELECT has_table_privilege('regressuser1', 'testns.acltest1', 'INSERT'); -- no
|
||||
|
||||
ALTER DEFAULT PRIVILEGES FOR ROLE regressuser1 REVOKE EXECUTE ON FUNCTION FROM public;
|
||||
|
||||
SET ROLE regressuser1;
|
||||
|
||||
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
|
||||
|
||||
SELECT has_function_privilege('regressuser2', 'testns.foo()', 'EXECUTE'); -- no
|
||||
|
||||
ALTER DEFAULT PRIVILEGES IN SCHEMA testns GRANT EXECUTE ON FUNCTION to public;
|
||||
|
||||
DROP FUNCTION testns.foo();
|
||||
CREATE FUNCTION testns.foo() RETURNS int AS 'select 1' LANGUAGE sql;
|
||||
|
||||
SELECT has_function_privilege('regressuser2', 'testns.foo()', 'EXECUTE'); -- yes
|
||||
|
||||
DROP FUNCTION testns.foo();
|
||||
|
||||
RESET ROLE;
|
||||
|
||||
SELECT count(*)
|
||||
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
|
||||
WHERE nspname = 'testns';
|
||||
|
||||
DROP SCHEMA testns CASCADE;
|
||||
|
||||
SELECT d.* -- check that entries went away
|
||||
FROM pg_default_acl d LEFT JOIN pg_namespace n ON defaclnamespace = n.oid
|
||||
WHERE nspname IS NULL AND defaclnamespace != 0;
|
||||
|
||||
-- clean up
|
||||
|
||||
\c
|
||||
|
@ -513,7 +580,10 @@ DROP TABLE atestp2;
|
|||
DROP GROUP regressgroup1;
|
||||
DROP GROUP regressgroup2;
|
||||
|
||||
-- these are needed to clean up permissions
|
||||
REVOKE USAGE ON LANGUAGE sql FROM regressuser1;
|
||||
DROP OWNED BY regressuser1;
|
||||
|
||||
DROP USER regressuser1;
|
||||
DROP USER regressuser2;
|
||||
DROP USER regressuser3;
|
||||
|
|
Loading…
Reference in New Issue