-<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.184 2008/12/18 18:20:33 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.185 2008/12/19 16:25:16 petere Exp $ -->
<!--
Documentation of the system catalogs, directed toward PostgreSQL developers
-->
<entry>enum label and value definitions</entry>
</row>
+ <row>
+ <entry><link linkend="catalog-pg-foreign-data-wrapper"><structname>pg_foreign_data_wrapper</structname></link></entry>
+ <entry>foreign-data wrapper definitions</entry>
+ </row>
+
+ <row>
+ <entry><link linkend="catalog-pg-foreign-server"><structname>pg_foreign_server</structname></link></entry>
+ <entry>foreign server definitions</entry>
+ </row>
+
<row>
<entry><link linkend="catalog-pg-index"><structname>pg_index</structname></link></entry>
<entry>additional index information</entry>
<entry><link linkend="catalog-pg-type"><structname>pg_type</structname></link></entry>
<entry>data types</entry>
</row>
+
+ <row>
+ <entry><link linkend="catalog-pg-user-mapping"><structname>pg_user_mapping</structname></link></entry>
+ <entry>mappings of users to foreign servers</entry>
+ </row>
</tbody>
</tgroup>
</table>
</sect1>
+ <sect1 id="catalog-pg-foreign-data-wrapper">
+ <title><structname>pg_foreign_data_wrapper</structname></title>
+
+ <indexterm zone="catalog-pg-foreign-data-wrapper">
+ <primary>pg_foreign_data_wrapper</primary>
+ </indexterm>
+
+ <para>
+ The catalog <structname>pg_foreign_data_wrapper</structname> stores
+ foreign-data wrapper definitions. A foreign-data wrapper is the
+ mechanism by which external data, residing on foreign servers, is
+ accessed.
+ </para>
+
+ <table>
+ <title><structname>pg_foreign_data_wrapper</> 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>fdwname</structfield></entry>
+ <entry><type>name</type></entry>
+ <entry></entry>
+ <entry>Name of the foreign-data wrapper</entry>
+ </row>
+
+ <row>
+ <entry><structfield>fdwowner</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+ <entry>Owner of the foreign-data wrapper</entry>
+ </row>
+
+ <row>
+ <entry><structfield>fdwlibrary</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry></entry>
+ <entry>File name of the library implementing this foreign-data wrapper</entry>
+ </row>
+
+ <row>
+ <entry><structfield>fdwacl</structfield></entry>
+ <entry><type>aclitem[]</type></entry>
+ <entry></entry>
+ <entry>
+ Access privileges; see
+ <xref linkend="sql-grant" endterm="sql-grant-title"> and
+ <xref linkend="sql-revoke" endterm="sql-revoke-title">
+ for details
+ </entry>
+ </row>
+
+ <row>
+ <entry><structfield>fdwoptions</structfield></entry>
+ <entry><type>text[]</type></entry>
+ <entry></entry>
+ <entry>
+ Foreign-data wrapper specific options, as <quote>keyword=value</> strings
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+
+ <sect1 id="catalog-pg-foreign-server">
+ <title><structname>pg_foreign_server</structname></title>
+
+ <indexterm zone="catalog-pg-foreign-server">
+ <primary>pg_foreign_server</primary>
+ </indexterm>
+
+ <para>
+ The catalog <structname>pg_foreign_server</structname> stores
+ foreign server definitions. A foreign server describes the
+ connection to a remote server, managing external data. Foreign
+ servers are accessed via foreign-data wrappers.
+ </para>
+
+ <table>
+ <title><structname>pg_foreign_server</> 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>srvname</structfield></entry>
+ <entry><type>name</type></entry>
+ <entry></entry>
+ <entry>Name of the foreign server</entry>
+ </row>
+
+ <row>
+ <entry><structfield>srvowner</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+ <entry>Owner of the foreign server</entry>
+ </row>
+
+ <row>
+ <entry><structfield>srvfdw</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-foreign-data-wrapper"><structname>pg_foreign_data_wrapper</structname></link>.oid</literal></entry>
+ <entry>The OID of the foreign-data wrapper of this foreign server</entry>
+ </row>
+
+ <row>
+ <entry><structfield>srvtype</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry></entry>
+ <entry>Type of the server (optional)</entry>
+ </row>
+
+ <row>
+ <entry><structfield>srvversion</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry></entry>
+ <entry>Version of the server (optional)</entry>
+ </row>
+
+ <row>
+ <entry><structfield>srvacl</structfield></entry>
+ <entry><type>aclitem[]</type></entry>
+ <entry></entry>
+ <entry>
+ Access privileges; see
+ <xref linkend="sql-grant" endterm="sql-grant-title"> and
+ <xref linkend="sql-revoke" endterm="sql-revoke-title">
+ for details
+ </entry>
+ </row>
+
+ <row>
+ <entry><structfield>srvoptions</structfield></entry>
+ <entry><type>text[]</type></entry>
+ <entry></entry>
+ <entry>
+ Foreign server specific options, as <quote>keyword=value</> strings.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+
+ <sect1 id="catalog-pg-user-mapping">
+ <title><structname>pg_user_mapping</structname></title>
+
+ <indexterm zone="catalog-pg-user-mapping">
+ <primary>pg_user_mapping</primary>
+ </indexterm>
+
+ <para>
+ The catalog <structname>pg_user_mapping</structname> stores
+ the mappings from local user to remote. Access to this catalog is
+ restricted from normal users, use the view
+ <link linkend="view-pg-user-mappings"><structname>pg_user_mappings</structname></link>
+ instead.
+ </para>
+
+ <table>
+ <title><structname>pg_user_mapping</> 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>umuser</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+ <entry>OID of the local role being mapped, 0 if the user mapping is public</entry>
+ </row>
+
+ <row>
+ <entry><structfield>umserver</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-foreign-server"><structname>pg_foreign_server</structname></link>.oid</literal></entry>
+ <entry>
+ The OID of the foreign server that contains this mapping
+ </entry>
+ </row>
+
+ <row>
+ <entry><structfield>umoptions</structfield></entry>
+ <entry><type>text[]</type></entry>
+ <entry></entry>
+ <entry>
+ User mapping specific options, as <quote>keyword=value</> strings.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+
<sect1 id="catalog-pg-index">
<title><structname>pg_index</structname></title>
</sect1>
+ <sect1 id="view-pg-user-mappings">
+ <title><structname>pg_user_mappings</structname></title>
+
+ <indexterm zone="view-pg-user-mappings">
+ <primary>pg_user_mappings</primary>
+ </indexterm>
+
+ <para>
+ The view <structname>pg_user_mappings</structname> provides access
+ to information about user mappings. This is essentially a publicly
+ readable view of
+ <link linkend="catalog-pg-user-mapping"><structname>pg_user_mapping</structname></link>
+ that leaves out the options field if the user has no rights to use
+ it.
+ </para>
+
+ <table>
+ <title><structname>pg_user_mappings</> Columns</title>
+
+ <tgroup cols=3>
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Type</entry>
+ <entry>References</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><structfield>umid</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-user-mapping"><structname>pg_user_mapping</structname></link>.oid</literal></entry>
+ <entry>OID of the user mapping</entry>
+ </row>
+
+ <row>
+ <entry><structfield>srvid</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-foreign-server"><structname>pg_foreign_server</structname></link>.oid</literal></entry>
+ <entry>
+ The OID of the foreign server that contains this mapping
+ </entry>
+ </row>
+
+ <row>
+ <entry><structfield>srvname</structfield></entry>
+ <entry><type>text</type></entry>
+ <entry></entry>
+ <entry>
+ Name of the foreign server
+ </entry>
+ </row>
+
+ <row>
+ <entry><structfield>umuser</structfield></entry>
+ <entry><type>oid</type></entry>
+ <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+ <entry>OID of the local role being mapped, 0 if the user mapping is public</entry>
+ </row>
+
+ <row>
+ <entry><structfield>usename</structfield></entry>
+ <entry><type>name</type></entry>
+ <entry></entry>
+ <entry>Name of the local user to be mapped</entry>
+ </row>
+
+ <row>
+ <entry><structfield>umoptions</structfield></entry>
+ <entry><type>text[]</type></entry>
+ <entry></entry>
+ <entry>
+ User mapping specific options, as <quote>keyword=value</>
+ strings, if the current user is the owner of the foreign
+ server, else null.
+ </entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+
<sect1 id="view-pg-views">
<title><structname>pg_views</structname></title>
-<!-- $PostgreSQL: pgsql/doc/src/sgml/features.sgml,v 2.29 2008/11/27 12:12:02 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/features.sgml,v 2.30 2008/12/19 16:25:16 petere Exp $ -->
<appendix id="features">
<title>SQL Conformance</title>
</para>
<para>
- The <productname>PostgreSQL</productname> core covers parts 1, 2,
+ The <productname>PostgreSQL</productname> core covers parts 1, 2, 9,
11, and 14. Part 3 is covered by the ODBC driver, and part 13 is
covered by the PL/Java plug-in, but exact conformance is currently
not being verified for these components. There are currently no
- implementations of parts 4, 9, and 10
+ implementations of parts 4 and 10
for <productname>PostgreSQL</productname>.
</para>
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.462 2008/12/18 18:20:33 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.463 2008/12/19 16:25:16 petere Exp $ -->
<chapter id="functions">
<title>Functions and Operators</title>
<entry><type>boolean</type></entry>
<entry>does current user have privilege for database</entry>
</row>
+ <row>
+ <entry><literal><function>has_foreign_data_wrapper_privilege</function>(<parameter>user</parameter>,
+ <parameter>fdw</parameter>,
+ <parameter>privilege</parameter>)</literal>
+ </entry>
+ <entry><type>boolean</type></entry>
+ <entry>does user have privilege for foreign-data wrapper</entry>
+ </row>
+ <row>
+ <entry><literal><function>has_foreign_data_wrapper_privilege</function>(<parameter>fdw</parameter>,
+ <parameter>privilege</parameter>)</literal>
+ </entry>
+ <entry><type>boolean</type></entry>
+ <entry>does current user have privilege for foreign-data wrapper</entry>
+ </row>
<row>
<entry><literal><function>has_function_privilege</function>(<parameter>user</parameter>,
<parameter>function</parameter>,
<entry><type>boolean</type></entry>
<entry>does current user have privilege for schema</entry>
</row>
+ <row>
+ <entry><literal><function>has_server_privilege</function>(<parameter>user</parameter>,
+ <parameter>server</parameter>,
+ <parameter>privilege</parameter>)</literal>
+ </entry>
+ <entry><type>boolean</type></entry>
+ <entry>does user have privilege for foreign server</entry>
+ </row>
+ <row>
+ <entry><literal><function>has_server_privilege</function>(<parameter>server</parameter>,
+ <parameter>privilege</parameter>)</literal>
+ </entry>
+ <entry><type>boolean</type></entry>
+ <entry>does current user have privilege for foreign server</entry>
+ </row>
<row>
<entry><literal><function>has_table_privilege</function>(<parameter>user</parameter>,
<parameter>table</parameter>,
<indexterm>
<primary>has_function_privilege</primary>
</indexterm>
+ <indexterm>
+ <primary>has_foreign_data_wrapper_privilege</primary>
+ </indexterm>
<indexterm>
<primary>has_language_privilege</primary>
</indexterm>
<indexterm>
<primary>has_schema_privilege</primary>
</indexterm>
+ <indexterm>
+ <primary>has_server_privilege</primary>
+ </indexterm>
<indexterm>
<primary>has_table_privilege</primary>
</indexterm>
</programlisting>
</para>
+ <para>
+ <function>has_foreign_data_wrapper_privilege</function> checks whether a user
+ can access a foreign-data wrapper in a particular way. The possibilities for its
+ arguments are analogous to <function>has_table_privilege</function>.
+ The desired access privilege type must evaluate to
+ <literal>USAGE</literal>.
+ </para>
+
<para>
<function>has_language_privilege</function> checks whether a user
can access a procedural language in a particular way. The possibilities
<literal>USAGE</literal>.
</para>
+ <para>
+ <function>has_server_privilege</function> checks whether a user
+ can access a foreign server in a particular way. The possibilities for its
+ arguments are analogous to <function>has_table_privilege</function>.
+ The desired access privilege type must evaluate to
+ <literal>USAGE</literal>.
+ </para>
+
<para>
<function>has_table_privilege</function> checks whether a user
can access a table in a particular way. The user can be
-<!-- $PostgreSQL: pgsql/doc/src/sgml/information_schema.sgml,v 1.35 2008/11/25 20:47:42 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/information_schema.sgml,v 1.36 2008/12/19 16:25:16 petere Exp $ -->
<chapter id="information-schema">
<title>The Information Schema</title>
</table>
</sect1>
+ <sect1 id="infoschema-foreign-data-wrapper-options">
+ <title><literal>foreign_data_wrapper_options</literal></title>
+
+ <para>
+ The view <literal>foreign_data_wrapper_options</literal> contains
+ all the options defined for foreign-data wrappers in the current
+ database. Only those foreign-data wrappers are shown that the
+ current user has access to (by way of being the owner or having
+ some privilege).
+ </para>
+
+ <table>
+ <title><literal>foreign_data_wrapper_options</literal> Columns</title>
+
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Data Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><literal>foreign_data_wrapper_catalog</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the database that the foreign-data wrapper is defined in (always the current database)</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_data_wrapper_name</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the foreign-data wrapper</entry>
+ </row>
+
+ <row>
+ <entry><literal>option_name</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of an option</entry>
+ </row>
+
+ <row>
+ <entry><literal>option_value</literal></entry>
+ <entry><type>character_data</type></entry>
+ <entry>Value of the option</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+ <sect1 id="infoschema-foreign-data-wrappers">
+ <title><literal>foreign_data_wrappers</literal></title>
+
+ <para>
+ The view <literal>foreign_data_wrappers</literal> contains all
+ foreign-data wrappers defined in the current database. Only those
+ foreign-data wrappers are shown that the current user has access to
+ (by way of being the owner or having some privilege).
+ </para>
+
+ <table>
+ <title><literal>foreign_data_wrappers</literal> Columns</title>
+
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Data Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><literal>foreign_data_wrapper_catalog</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the database that contains the foreign-data
+ wrapper (always the current database)</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_data_wrapper_name</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the foreign-data wrapper</entry>
+ </row>
+
+ <row>
+ <entry><literal>authorization_identifier</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the owner of the foreign server</entry>
+ </row>
+
+ <row>
+ <entry><literal>library_name</literal></entry>
+ <entry><type>character_data</type></entry>
+ <entry>File name of the library that implementing this foreign-data wrapper</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_data_wrapper_language</literal></entry>
+ <entry><type>character_data</type></entry>
+ <entry>Language used to implement this foreign-data wrapper</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+ <sect1 id="infoschema-foreign-server-options">
+ <title><literal>foreign_server_options</literal></title>
+
+ <para>
+ The view <literal>foreign_server_options</literal> contains all the
+ options defined for foreign servers in the current database. Only
+ those foreign servers are shown that the current user has access to
+ (by way of being the owner or having some privilege).
+ </para>
+
+ <table>
+ <title><literal>foreign_server_options</literal> Columns</title>
+
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Data Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><literal>foreign_server_catalog</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the database that the foreign server is defined in (always the current database)</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_server_name</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the foreign server</entry>
+ </row>
+
+ <row>
+ <entry><literal>option_name</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of an option</entry>
+ </row>
+
+ <row>
+ <entry><literal>option_value</literal></entry>
+ <entry><type>character_data</type></entry>
+ <entry>Value of the option</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+ <sect1 id="infoschema-foreign-servers">
+ <title><literal>foreign_servers</literal></title>
+
+ <para>
+ The view <literal>foreign_servers</literal> contains all foreign
+ servers defined in the current database. Only those foreign
+ servers are shown that the current user has access to (by way of
+ being the owner or having some privilege).
+ </para>
+
+ <table>
+ <title><literal>foreign_servers</literal> Columns</title>
+
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Data Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><literal>foreign_server_catalog</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the database that the foreign server is defined in (always the current database)</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_server_name</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the foreign server</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_data_wrapper_catalog</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the database that contains the foreign-data
+ wrapper used by the foreign server (always the current database)</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_data_wrapper_name</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the foreign-data wrapper used by the foreign server</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_server_type</literal></entry>
+ <entry><type>character_data</type></entry>
+ <entry>Foreign server type information, if specified upon creation</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_server_version</literal></entry>
+ <entry><type>character_data</type></entry>
+ <entry>Foreign server version information, if specified upon creation</entry>
+ </row>
+
+ <row>
+ <entry><literal>authorization_identifier</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the owner of the foreign server</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
<sect1 id="infoschema-key-column-usage">
<title><literal>key_column_usage</literal></title>
<title><literal>role_usage_grants</literal></title>
<para>
- The view <literal>role_usage_grants</literal> is meant to identify
+ The view <literal>role_usage_grants</literal> identifies
<literal>USAGE</literal> privileges granted on various kinds of
- objects to a currently enabled role or by a currently enabled role.
- In <productname>PostgreSQL</productname>, this currently only
- applies to domains, and since domains do not have real privileges
- in <productname>PostgreSQL</productname>, this view is empty.
+ objects where the grantor or grantee is a currently enabled role.
Further information can be found under
- <literal>usage_privileges</literal>. In the future, this view might
- contain more useful information.
+ <literal>usage_privileges</literal>.
</para>
<table>
<row>
<entry><literal>grantor</literal></entry>
<entry><type>sql_identifier</type></entry>
- <entry>In the future, the name of the role that granted the privilege</entry>
+ <entry>The name of the role that granted the privilege</entry>
</row>
<row>
<entry><literal>grantee</literal></entry>
<entry><type>sql_identifier</type></entry>
- <entry>In the future, the name of the role that the privilege was granted to</entry>
+ <entry>The name of the role that the privilege was granted to</entry>
</row>
<row>
<row>
<entry><literal>object_schema</literal></entry>
<entry><type>sql_identifier</type></entry>
- <entry>Name of the schema containing the object</entry>
+ <entry>Name of the schema containing the object, if applicable,
+ else an empty string</entry>
</row>
<row>
<row>
<entry><literal>object_type</literal></entry>
<entry><type>character_data</type></entry>
- <entry>In the future, the type of the object</entry>
+ <entry><literal>DOMAIN</literal> or <literal>FOREIGN DATA WRAPPER</literal> or <literal>FOREIGN SERVER</literal></entry>
</row>
<row>
<title><literal>usage_privileges</literal></title>
<para>
- The view <literal>usage_privileges</literal> is meant to identify
+ The view <literal>usage_privileges</literal> identifies
<literal>USAGE</literal> privileges granted on various kinds of
objects to a currently enabled role or by a currently enabled role.
- In <productname>PostgreSQL</productname>, this currently only
- applies to domains, and since domains do not have real privileges
+ In <productname>PostgreSQL</productname>, this currently applies to
+ domains, foreign-data wrappers, and foreign servers. There is one
+ row for each combination of object, grantor, and grantee.
+ </para>
+
+ <para>
+ Since domains do not have real privileges
in <productname>PostgreSQL</productname>, this view shows implicit
- <literal>USAGE</literal> privileges granted to
- <literal>PUBLIC</literal> for all domains. In the future, this
- view might contain more useful information.
+ non-grantable <literal>USAGE</literal> privileges granted by the
+ owner to <literal>PUBLIC</literal> for all domains. The other
+ object types, however, show real privileges.
</para>
<table>
<row>
<entry><literal>grantor</literal></entry>
<entry><type>sql_identifier</type></entry>
- <entry>Currently set to the name of the owner of the object</entry>
+ <entry>Name of the role that granted the privilege</entry>
</row>
<row>
<entry><literal>grantee</literal></entry>
<entry><type>sql_identifier</type></entry>
- <entry>Currently always <literal>PUBLIC</literal></entry>
+ <entry>Name of the role that the privilege was granted to</entry>
</row>
<row>
<row>
<entry><literal>object_schema</literal></entry>
<entry><type>sql_identifier</type></entry>
- <entry>Name of the schema containing the object</entry>
+ <entry>Name of the schema containing the object, if applicable,
+ else an empty string</entry>
</row>
<row>
<row>
<entry><literal>object_type</literal></entry>
<entry><type>character_data</type></entry>
- <entry>Currently always <literal>DOMAIN</literal></entry>
+ <entry><literal>DOMAIN</literal> or <literal>FOREIGN DATA WRAPPER</literal> or <literal>FOREIGN SERVER</literal></entry>
</row>
<row>
<row>
<entry><literal>is_grantable</literal></entry>
<entry><type>character_data</type></entry>
- <entry>Currently always <literal>NO</literal></entry>
+ <entry><literal>YES</literal> if the privilege is grantable, <literal>NO</literal> if not</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+ <sect1 id="infoschema-user-mapping-options">
+ <title><literal>user_mapping_options</literal></title>
+
+ <para>
+ The view <literal>user_mapping_options</literal> contains all the
+ options defined for user mappings in the current database. Only
+ those user mappings are shown where the current user has access to
+ the corresponding foreign server (by way of being the owner or
+ having some privilege).
+ </para>
+
+ <table>
+ <title><literal>user_mapping_options</literal> Columns</title>
+
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Data Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><literal>authorization_identifier</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the user being mapped,
+ or <literal>PUBLIC</literal> if the mapping is public</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_server_catalog</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the database that the foreign server used by this
+ mapping is defined in (always the current database)</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_server_name</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the foreign server used by this mapping</entry>
+ </row>
+
+ <row>
+ <entry><literal>option_name</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of an option</entry>
+ </row>
+
+ <row>
+ <entry><literal>option_value</literal></entry>
+ <entry><type>character_data</type></entry>
+ <entry>Value of the option</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </sect1>
+
+ <sect1 id="infoschema-user-mappings">
+ <title><literal>user_mappings</literal></title>
+
+ <para>
+ The view <literal>user_mappings</literal> contains all user
+ mappings defined in the current database. Only those user mappings
+ are shown where the current user has access to the corresponding
+ foreign server (by way of being the owner or having some
+ privilege).
+ </para>
+
+ <table>
+ <title><literal>user_mappings</literal> Columns</title>
+
+ <tgroup cols="3">
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Data Type</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><literal>authorization_identifier</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the user being mapped,
+ or <literal>PUBLIC</literal> if the mapping is public</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_server_catalog</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the database that the foreign server used by this
+ mapping is defined in (always the current database)</entry>
+ </row>
+
+ <row>
+ <entry><literal>foreign_server_name</literal></entry>
+ <entry><type>sql_identifier</type></entry>
+ <entry>Name of the foreign server used by this mapping</entry>
</row>
</tbody>
</tgroup>
-<!-- $PostgreSQL: pgsql/doc/src/sgml/keywords.sgml,v 2.21 2008/12/03 12:39:57 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/keywords.sgml,v 2.22 2008/12/19 16:25:16 petere Exp $ -->
<appendix id="sql-keywords-appendix">
<title><acronym>SQL</acronym> Key Words</title>
<entry>reserved</entry>
<entry>reserved</entry>
</row>
+ <row>
+ <entry><token>LIBRARY</token></entry>
+ <entry>non-reserved</entry>
+ <entry>non-reserved</entry>
+ <entry>non-reserved</entry>
+ <entry></entry>
+ <entry></entry>
+ </row>
<row>
<entry><token>LIKE</token></entry>
<entry>reserved (can be function or type)</entry>
<row>
<entry><token>MAPPING</token></entry>
<entry>non-reserved</entry>
- <entry></entry>
- <entry></entry>
+ <entry>non-reserved</entry>
+ <entry>non-reserved</entry>
<entry></entry>
<entry></entry>
</row>
</row>
<row>
<entry><token>OPTIONS</token></entry>
- <entry></entry>
+ <entry>non-reserved</entry>
<entry>non-reserved</entry>
<entry>non-reserved</entry>
<entry>non-reserved</entry>
<entry>non-reserved</entry>
<entry>non-reserved</entry>
</row>
+ <row>
+ <entry><token>SERVER</token></entry>
+ <entry>non-reserved</entry>
+ <entry>non-reserved</entry>
+ <entry>non-reserved</entry>
+ <entry></entry>
+ <entry></entry>
+ </row>
<row>
<entry><token>SERVER_NAME</token></entry>
<entry></entry>
<entry>reserved</entry>
<entry>reserved</entry>
</row>
+ <row>
+ <entry><token>WRAPPER</token></entry>
+ <entry>non-reserved</entry>
+ <entry>non-reserved</entry>
+ <entry>non-reserved</entry>
+ <entry></entry>
+ <entry></entry>
+ </row>
<row>
<entry><token>WRITE</token></entry>
<entry>non-reserved</entry>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.73 2008/03/27 17:24:16 momjian Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.74 2008/12/19 16:25:16 petere Exp $
PostgreSQL documentation
Complete list of usable sgml source files in this directory.
-->
<!entity alterConversion system "alter_conversion.sgml">
<!entity alterDatabase system "alter_database.sgml">
<!entity alterDomain system "alter_domain.sgml">
+<!entity alterForeignDataWrapper system "alter_foreign_data_wrapper.sgml">
<!entity alterFunction system "alter_function.sgml">
<!entity alterGroup system "alter_group.sgml">
<!entity alterIndex system "alter_index.sgml">
<!entity alterOperatorFamily system "alter_opfamily.sgml">
<!entity alterRole system "alter_role.sgml">
<!entity alterSchema system "alter_schema.sgml">
+<!entity alterServer system "alter_server.sgml">
<!entity alterSequence system "alter_sequence.sgml">
<!entity alterTable system "alter_table.sgml">
<!entity alterTableSpace system "alter_tablespace.sgml">
<!entity alterTrigger system "alter_trigger.sgml">
<!entity alterType system "alter_type.sgml">
<!entity alterUser system "alter_user.sgml">
+<!entity alterUserMapping system "alter_user_mapping.sgml">
<!entity alterView system "alter_view.sgml">
<!entity analyze system "analyze.sgml">
<!entity begin system "begin.sgml">
<!entity createConversion system "create_conversion.sgml">
<!entity createDatabase system "create_database.sgml">
<!entity createDomain system "create_domain.sgml">
+<!entity createForeignDataWrapper system "create_foreign_data_wrapper.sgml">
<!entity createFunction system "create_function.sgml">
<!entity createGroup system "create_group.sgml">
<!entity createIndex system "create_index.sgml">
<!entity createRule system "create_rule.sgml">
<!entity createSchema system "create_schema.sgml">
<!entity createSequence system "create_sequence.sgml">
+<!entity createServer system "create_server.sgml">
<!entity createTable system "create_table.sgml">
<!entity createTableAs system "create_table_as.sgml">
<!entity createTableSpace system "create_tablespace.sgml">
<!entity createTSTemplate system "create_tstemplate.sgml">
<!entity createType system "create_type.sgml">
<!entity createUser system "create_user.sgml">
+<!entity createUserMapping system "create_user_mapping.sgml">
<!entity createView system "create_view.sgml">
<!entity deallocate system "deallocate.sgml">
<!entity declare system "declare.sgml">
<!entity dropConversion system "drop_conversion.sgml">
<!entity dropDatabase system "drop_database.sgml">
<!entity dropDomain system "drop_domain.sgml">
+<!entity dropForeignDataWrapper system "drop_foreign_data_wrapper.sgml">
<!entity dropFunction system "drop_function.sgml">
<!entity dropGroup system "drop_group.sgml">
<!entity dropIndex system "drop_index.sgml">
<!entity dropRule system "drop_rule.sgml">
<!entity dropSchema system "drop_schema.sgml">
<!entity dropSequence system "drop_sequence.sgml">
+<!entity dropServer system "drop_server.sgml">
<!entity dropTable system "drop_table.sgml">
<!entity dropTableSpace system "drop_tablespace.sgml">
<!entity dropTrigger system "drop_trigger.sgml">
<!entity dropTSTemplate system "drop_tstemplate.sgml">
<!entity dropType system "drop_type.sgml">
<!entity dropUser system "drop_user.sgml">
+<!entity dropUserMapping system "drop_user_mapping.sgml">
<!entity dropView system "drop_view.sgml">
<!entity end system "end.sgml">
<!entity execute system "execute.sgml">
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_foreign_data_wrapper.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-ALTERFOREIGNDATAWRAPPER">
+ <refmeta>
+ <refentrytitle id="sql-alterforeigndatawrapper-title">ALTER FOREIGN DATA WRAPPER</refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>ALTER FOREIGN DATA WRAPPER</refname>
+ <refpurpose>change the definition of a foreign-data wrapper</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-alterforeigndatawrapper">
+ <primary>ALTER FOREIGN DATA WRAPPER</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable>
+ [ LIBRARY '<replaceable class="parameter">libraryname</replaceable>' ]
+ [ OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ]) ]
+ALTER FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>ALTER FOREIGN DATA WRAPPER</command> changes the
+ definition of a foreign-data wrapper. The first form of the
+ command changes the library or the generic options of the
+ foreign-data wrapper (at least one clause is required). The second
+ form changes the owner of the foreign-data wrapper.
+ </para>
+
+ <para>
+ Only superusers can alter foreign-data wrappers. Additionally,
+ only superusers can own foreign-data wrappers.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="parameter">name</replaceable></term>
+ <listitem>
+ <para>
+ The name of an existing foreign-data wrapper.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">libraryname</replaceable></term>
+ <listitem>
+ <para>
+ New name of the foreign-data wrapper library.
+ </para>
+
+ <para>
+ Note that it is possible that after changing the library, the
+ options to the foreign-data wrapper, servers, and user mappings
+ have become invalid. It is up to the user to make sure that
+ these options are correct before using the foreign-data
+ wrapper.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] )</literal></term>
+ <listitem>
+ <para>
+ Change options for the foreign-data
+ wrapper. <literal>ADD</>, <literal>SET</>, and <literal>DROP</>
+ specify the action to be performed. <literal>ADD</> is assumed
+ if no operation is explicitly specified. Option names must be
+ unique; names and values are also validated using the foreign
+ data wrapper library.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ Change a foreign-data wrapper <literal>dbi</>, add
+ option <literal>foo</>, drop <literal>bar</>:
+<programlisting>
+ALTER FOREIGN DATA WRAPPER dbi OPTIONS (ADD foo '1', DROP 'bar');
+</programlisting>
+ </para>
+
+ <para>
+ Change the foreign-data wrapper <literal>dbi</> library
+ to <literal>/home/bob/mylibrary.so</>:
+<programlisting>
+ALTER FOREIGN DATA WRAPPER dbi LIBRARY '/home/bob/mylibrary.so';
+</programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ <command>ALTER FOREIGN DATA WRAPPER</command> conforms to ISO/IEC
+ 9075-9 (SQL/MED). The standard does not specify the <literal>OWNER
+ TO</> variant of the command.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-createforeigndatawrapper" endterm="sql-createforeigndatawrapper-title"></member>
+ <member><xref linkend="sql-dropforeigndatawrapper" endterm="sql-dropforeigndatawrapper-title"></member>
+ </simplelist>
+ </refsect1>
+
+</refentry>
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_server.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-ALTERSERVER">
+ <refmeta>
+ <refentrytitle id="sql-alterserver-title">ALTER SERVER</refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>ALTER SERVER</refname>
+ <refpurpose>change the definition of a foreign server</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-alterserver">
+ <primary>ALTER SERVER</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+ALTER SERVER <replaceable class="parameter">servername</replaceable> [ VERSION 'newversion' ]
+ [ OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] ) ]
+ALTER SERVER <replaceable class="PARAMETER">servername</replaceable> OWNER TO <replaceable>new_owner</replaceable>
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>ALTER SERVER</command> changes the definition of a foreign
+ server. The first form changes the server version string or the
+ generic options of the server (at least one clause is required).
+ The second form changes the owner of the server.
+ </para>
+
+ <para>
+ To alter the server you must be the owner of the server.
+ Additionally to alter the owner, you must own the server and also
+ be a direct or indirect member of the new owning role, and you must
+ have <literal>USAGE</> privilege on the server's foreign-data
+ wrapper. (Note that superusers satisfy all these criteria
+ automatically.)
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="parameter">servername</replaceable></term>
+ <listitem>
+ <para>
+ The name of an existing server.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">serverversion</replaceable></term>
+ <listitem>
+ <para>
+ New server version.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] )</literal></term>
+ <listitem>
+ <para>
+ Change options for the
+ server. <literal>ADD</>, <literal>SET</>, and <literal>DROP</>
+ specify the action to be performed. <literal>ADD</> is assumed
+ if no operation is explicitly specified. Option names must be
+ unique; names and values are also validated using the server's
+ foreign-data wrapper library.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ Alter server <literal>foo</>, add connection options:
+<programlisting>
+ALTER SERVER foo OPTIONS (host 'foo', dbname 'foodb');
+</programlisting>
+ </para>
+
+ <para>
+ Alter server <literal>foo</>, change version,
+ change <literal>host</> option:
+<programlisting>
+ALTER SERVER foo VERSION '8.4' OPTIONS (SET host 'baz');
+</programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ <command>ALTER SERVER</command> conforms to ISO/IEC 9075-9 (SQL/MED).
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-createserver" endterm="sql-createserver-title"></member>
+ <member><xref linkend="sql-dropserver" endterm="sql-dropserver-title"></member>
+ </simplelist>
+ </refsect1>
+
+</refentry>
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/alter_user_mapping.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-ALTERUSERMAPPING">
+ <refmeta>
+ <refentrytitle id="sql-alterusermapping-title">ALTER USER MAPPING</refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>ALTER USER MAPPING</refname>
+ <refpurpose>change the definition of a user mapping</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-alterusermapping">
+ <primary>ALTER USER MAPPING</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+ALTER USER MAPPING FOR { <replaceable class="parameter">username</replaceable> | USER | CURRENT_USER | PUBLIC }
+ SERVER <replaceable class="parameter">servername</replaceable>
+ OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] )
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>ALTER USER MAPPING</command> changes the definition of a
+ user mapping. Only the owner of the server can change the user
+ mappings of that server.
+ </para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="parameter">username</replaceable></term>
+ <listitem>
+ <para>
+ User name of the mapping. <literal>CURRENT_USER</>
+ and <literal>USER</> match the name of the current
+ user. <literal>PUBLIC</> is used to match all present and future
+ user names in the system.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">servername</replaceable></term>
+ <listitem>
+ <para>
+ Server name of the user mapping.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>OPTIONS ( [ ADD | SET | DROP ] <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] )</literal></term>
+ <listitem>
+ <para>
+ Change options for the user mapping. The new options override
+ any previously specified
+ options. <literal>ADD</>, <literal>SET</>, and <literal>DROP</>
+ specify the action to be performed. <literal>ADD</> is assumed
+ if no operation is explicitly specified. Option names must be
+ unique; options are also validated by the server's foreign-data
+ wrapper.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ Change the password for user mapping <literal>bob</>, server<literal> foo</>:
+<programlisting>
+ALTER USER MAPPING FOR bob SERVER foo OPTIONS (user 'bob', password 'public');
+</programlisting>
+ </para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ <command>ALTER USER MAPPING</command> conforms to ISO/IEC 9075-9
+ (SQL/MED). There is a subtle syntax issue: The standard omits
+ the <literal>FOR</literal> key word. Since both <literal>CREATE
+ USER MAPPING</literal> and <literal>DROP USER MAPPING</literal> use
+ <literal>FOR</literal> in analogous positions, and IBM DB2 (being
+ the other major SQL/MED implementation) also requires it
+ for <literal>ALTER USER MAPPING</literal>, PostgreSQL diverges from
+ the standard here in the interest of consistency and
+ interoperability.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-createusermapping" endterm="sql-createusermapping-title"></member>
+ <member><xref linkend="sql-dropusermapping" endterm="sql-dropusermapping-title"></member>
+ </simplelist>
+ </refsect1>
+
+</refentry>
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_foreign_data_wrapper.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-CREATEFOREIGNDATAWRAPPER">
+ <refmeta>
+ <refentrytitle id="sql-createforeigndatawrapper-title">CREATE FOREIGN DATA WRAPPER</refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>CREATE FOREIGN DATA WRAPPER</refname>
+ <refpurpose>define a new foreign-data wrapper</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-createforeigndatawrapper">
+ <primary>CREATE FOREIGN DATA WRAPPER</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+CREATE FOREIGN DATA WRAPPER <replaceable class="parameter">name</replaceable>
+ LIBRARY '<replaceable class="parameter">libraryname</replaceable>'
+ LANGUAGE C
+ [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] ) ]
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>CREATE FOREIGN DATA WRAPPER</command> creates a new
+ foreign-data wrapper. The user who defines a foreign-data wrapper
+ becomes its owner.
+ </para>
+
+ <para>
+ The foreign-data wrapper name must be unique within the database.
+ </para>
+
+ <para>
+ Only superusers can create foreign-data wrappers.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="parameter">name</replaceable></term>
+ <listitem>
+ <para>
+ The name of the foreign-data wrapper to be created.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">libraryname</replaceable></term>
+ <listitem>
+ <para>
+ The name of the shared library implementing the foreign-data
+ wrapper. The file name is specified in the same way as for
+ shared library names in <xref linkend="sql-createfunction"
+ endterm="sql-createfunction-title">; in particular, one can rely
+ on a search path and automatic addition of the system's standard
+ shared library file name extension.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>LANGUAGE C</literal></term>
+ <listitem>
+ <para>
+ Currently, only the C programming language is supported for
+ implementing foreign-data wrappers.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>OPTIONS ( <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] )</literal></term>
+ <listitem>
+ <para>
+ This clause specifies options for the new foreign-data wrapper.
+ The allowed option names and values are specific to each foreign
+ data wrapper and are validated using the foreign-data wrapper
+ library. Option names must be unique.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Notes</title>
+
+ <para>
+ At the moment, the foreign-data wrapper functionality is very
+ rudimentary. The purpose of foreign-data wrappers, foreign
+ servers, and user mappings is to store this information in a
+ standard way so that it can be queried by interested applications.
+ The functionality to actually query external data does not exist
+ yet.
+ </para>
+
+ <para>
+ The C language API for foreign-data wrappers is currently not
+ documented, stable, or complete. Would-be authors of functionality
+ interfacing with the SQL/MED functionality are advised to contact
+ the PostgreSQL developers.
+ </para>
+
+ <para>
+ There are currently two foreign-data wrapper libraries
+ provided: <filename>dummy_fdw</filename>, which does nothing and
+ could be useful for testing,
+ and <filename>postgresql_fdw</filename>, which accepts options
+ corresponding to <application>libpq</> connection parameters.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ Create a foreign-data wrapper <literal>dummy</> with
+ library <literal>dummy_fdw</>:
+<programlisting>
+CREATE FOREIGN DATA WRAPPER dummy LIBRARY 'dummy_fdw' LANGUAGE C;
+</programlisting>
+ </para>
+
+ <para>
+ Create a foreign-data wrapper <literal>postgresql</> with
+ library <literal>postgresql_fdw</>:
+<programlisting>
+CREATE FOREIGN DATA WRAPPER postgresql LIBRARY 'postgresql_fdw' LANGUAGE C;
+</programlisting>
+ </para>
+
+ <para>
+ Create a foreign-data wrapper <literal>mywrapper</> with library
+ <literal>/home/bob/mywrapper.so</> and some options:
+<programlisting>
+CREATE FOREIGN DATA WRAPPER mywrapper
+ LIBRARY '/home/bob/mywrapper.so'
+ LANGUAGE C
+ OPTIONS (debug 'true');
+</programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ <command>CREATE FOREIGN DATA WRAPPER</command> conforms to ISO/IEC
+ 9075-9 (SQL/MED), with the exception that
+ the <literal>LIBRARY</literal> clause is not optional in
+ PostgreSQL.
+ </para>
+
+ <para>
+ Note, however, that the SQL/MED functionality as a whole is not yet
+ conforming.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-alterforeigndatawrapper" endterm="sql-alterforeigndatawrapper-title"></member>
+ <member><xref linkend="sql-dropforeigndatawrapper" endterm="sql-dropforeigndatawrapper-title"></member>
+ <member><xref linkend="sql-createserver" endterm="sql-createserver-title"></member>
+ <member><xref linkend="sql-createusermapping" endterm="sql-createusermapping-title"></member>
+ </simplelist>
+ </refsect1>
+
+</refentry>
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_server.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-CREATESERVER">
+ <refmeta>
+ <refentrytitle id="sql-createserver-title">CREATE SERVER</refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>CREATE SERVER</refname>
+ <refpurpose>define a new foreign server</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-createserver">
+ <primary>CREATE SERVER</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+CREATE SERVER <replaceable class="parameter">servername</replaceable> [ TYPE 'servertype' ] [ VERSION 'serverversion' ]
+ FOREIGN DATA WRAPPER <replaceable class="parameter">fdwname</replaceable>
+ [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [, ... ] ) ]
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>CREATE SERVER</command> defines a new foreign server. The
+ user who defines the server becomes its owner.
+ </para>
+
+ <para>
+ The server name must be unique within database.
+ </para>
+
+ <para>
+ Creating a server requires <literal>USAGE</> privilege on the
+ foreign-data wrapper being used.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="parameter">servername</replaceable></term>
+ <listitem>
+ <para>
+ The name of the foreign server to be created.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">servertype</replaceable></term>
+ <listitem>
+ <para>
+ Optional server type.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">serverversion</replaceable></term>
+ <listitem>
+ <para>
+ Optional server version.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">fdwname</replaceable></term>
+ <listitem>
+ <para>
+ The name of the foreign-data wrapper that manages the server.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>OPTIONS ( <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] )</literal></term>
+ <listitem>
+ <para>
+ This clause specifies the options for the server. The options
+ typically define the connection details of the server, but the
+ actual names and values are dependent on the server's
+ foreign-data wrapper.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ Create a server <literal>foo</> that uses the built-in foreign-data
+ wrapper <literal>default</>:
+<programlisting>
+CREATE SERVER foo FOREIGN DATA WRAPPER "default";
+</programlisting>
+ </para>
+
+ <para>
+ Create a server <literal>myserver</> that uses the
+ foreign-data wrapper <literal>pgsql</>:
+<programlisting>
+CREATE SERVER myserver FOREIGN DATA WRAPPER pgsql OPTIONS (host 'foo', dbname 'foodb', port '5432');
+</programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ <command>CREATE SERVER</command> conforms to ISO/IEC 9075-9 (SQL/MED).
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-alterserver" endterm="sql-alterserver-title"></member>
+ <member><xref linkend="sql-dropserver" endterm="sql-dropserver-title"></member>
+ <member><xref linkend="sql-createforeigndatawrapper" endterm="sql-createforeigndatawrapper-title"></member>
+ <member><xref linkend="sql-createusermapping" endterm="sql-createusermapping-title"></member>
+ </simplelist>
+ </refsect1>
+
+</refentry>
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/create_user_mapping.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-CREATEUSERMAPPING">
+ <refmeta>
+ <refentrytitle id="sql-createusermapping-title">CREATE USER MAPPING</refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>CREATE USER MAPPING</refname>
+ <refpurpose>define a new mapping of a user to a foreign server</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-createusermapping">
+ <primary>CREATE USER MAPPING</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+CREATE USER MAPPING FOR { <replaceable class="parameter">username</replaceable> | USER | CURRENT_USER | PUBLIC }
+ SERVER <replaceable class="parameter">servername</replaceable>
+ [ OPTIONS ( <replaceable class="PARAMETER">option</replaceable> '<replaceable class="PARAMETER">value</replaceable>' [ , ... ] ) ]
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>CREATE USER MAPPING</command> defines a mapping of a user
+ to a foreign server. You must be the owner of the server to define
+ user mappings for it.
+ </para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><replaceable class="parameter">username</replaceable></term>
+ <listitem>
+ <para>
+ The name of an existing user that is mapped to foreign server.
+ <literal>CURRENT_USER</> and <literal>USER</> match the name of
+ the current user. <literal>PUBLIC</> is used to match all
+ present and future user names in the system.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">servername</replaceable></term>
+ <listitem>
+ <para>
+ The name of an existing server for which the user mapping is
+ to be created.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>OPTIONS ( <replaceable class="PARAMETER">option</replaceable> ['<replaceable class="PARAMETER">value</replaceable>'] [, ... ] )</literal></term>
+ <listitem>
+ <para>
+ This clause specifies the options of the user mapping. The
+ options typically define the actual user name and password of
+ the mapping. Option names must be unque. The allowed option
+ names and values are specific to the server's foreign-data wrapper.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ Create a user mapping for user <literal>bob</>, server <literal>foo</>:
+<programlisting>
+CREATE USER MAPPING FOR bob SERVER foo OPTIONS (user 'bob', password 'secret');
+</programlisting>
+ </para>
+
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ <command>CREATE USER MAPPING</command> conforms to ISO/IEC 9075-9 (SQL/MED).
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-alterusermapping" endterm="sql-alterusermapping-title"></member>
+ <member><xref linkend="sql-dropusermapping" endterm="sql-dropusermapping-title"></member>
+ <member><xref linkend="sql-createforeigndatawrapper" endterm="sql-createforeigndatawrapper-title"></member>
+ <member><xref linkend="sql-createserver" endterm="sql-createserver-title"></member>
+ </simplelist>
+ </refsect1>
+
+</refentry>
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/drop_foreign_data_wrapper.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-DROPFOREIGNDATAWRAPPER">
+ <refmeta>
+ <refentrytitle id="sql-dropforeigndatawrapper-title">DROP FOREIGN DATA WRAPPER</refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>DROP FOREIGN DATA WRAPPER</refname>
+ <refpurpose>remove a foreign-data wrapper</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-dropforeigndatawrapper">
+ <primary>DROP FOREIGN DATA WRAPPER</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+DROP FOREIGN DATA WRAPPER [ IF EXISTS ] <replaceable class="parameter">name</replaceable> [ CASCADE | RESTRICT ]
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>DROP FOREIGN DATA WRAPPER</command> removes an existing
+ foreign-data wrapper. To execute this command, the current user
+ must be the owner of the foreign-data wrapper.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>IF EXISTS</literal></term>
+ <listitem>
+ <para>
+ Do not throw an error if the foreign-data wrapper does not
+ exist. A notice is issued in this case.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">name</replaceable></term>
+ <listitem>
+ <para>
+ The name of an existing foreign-data wrapper.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>CASCADE</literal></term>
+ <listitem>
+ <para>
+ Automatically drop objects that depend on the foreign-data
+ wrapper (such as servers).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>RESTRICT</literal></term>
+ <listitem>
+ <para>
+ Refuse to drop the foreign-data wrappers if any objects depend
+ on it. This is the default.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ Drop the foreign-data wrapper <literal>dbi</>:
+<programlisting>
+DROP FOREIGN DATA WRAPPER dbi;
+</programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ <command>DROP FOREIGN DATA WRAPPER</command> conforms to ISO/IEC
+ 9075-9 (SQL/MED). The <literal>IF EXISTS</> clause is
+ a <productname>PostgreSQL</> extension.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-createforeigndatawrapper" endterm="sql-createforeigndatawrapper-title"></member>
+ <member><xref linkend="sql-alterforeigndatawrapper" endterm="sql-alterforeigndatawrapper-title"></member>
+ </simplelist>
+ </refsect1>
+
+</refentry>
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/drop_server.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-DROPSERVER">
+ <refmeta>
+ <refentrytitle id="sql-dropserver-title">DROP SERVER</refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>DROP SERVER</refname>
+ <refpurpose>remove a foreign server descriptor</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-dropserver">
+ <primary>DROP SERVER</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+DROP SERVER [ IF EXISTS ] <replaceable class="parameter">servername</replaceable> [ CASCADE | RESTRICT ]
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>DROP SERVER</command> removes an existing foreign server
+ descriptor. To execute this command, the current user must be the
+ owner of the server.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>IF EXISTS</literal></term>
+ <listitem>
+ <para>
+ Do not throw an error if the server does not exist. A notice is
+ issued in this case.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">servername</replaceable></term>
+ <listitem>
+ <para>
+ The name of an existing server.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>CASCADE</literal></term>
+ <listitem>
+ <para>
+ Automatically drop objects that depend on the server (such as
+ user mappings).
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><literal>RESTRICT</literal></term>
+ <listitem>
+ <para>
+ Refuse to drop the server if any objects depend on it. This is
+ the default.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ Drop a server <literal>foo</> if it exists:
+<programlisting>
+DROP SERVER IF EXISTS foo;
+</programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ <command>DROP SERVER</command> conforms to ISO/IEC 9075-9
+ (SQL/MED). The <literal>IF EXISTS</> clause is
+ a <productname>PostgreSQL</> extension.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-createserver" endterm="sql-createserver-title"></member>
+ <member><xref linkend="sql-alterserver" endterm="sql-alterserver-title"></member>
+ </simplelist>
+ </refsect1>
+
+</refentry>
--- /dev/null
+<!--
+$PostgreSQL: pgsql/doc/src/sgml/ref/drop_user_mapping.sgml,v 1.1 2008/12/19 16:25:16 petere Exp $
+PostgreSQL documentation
+-->
+
+<refentry id="SQL-DROPUSERMAPPING">
+ <refmeta>
+ <refentrytitle id="sql-dropusermapping-title">DROP USER MAPPING</refentrytitle>
+ <refmiscinfo>SQL - Language Statements</refmiscinfo>
+ </refmeta>
+
+ <refnamediv>
+ <refname>DROP USER MAPPING</refname>
+ <refpurpose>remove a user mapping for a foreign server</refpurpose>
+ </refnamediv>
+
+ <indexterm zone="sql-dropusermapping">
+ <primary>DROP USER MAPPING</primary>
+ </indexterm>
+
+ <refsynopsisdiv>
+<synopsis>
+DROP USER MAPPING [ IF EXISTS ] FOR { <replaceable class="parameter">username</replaceable> | USER | CURRENT_USER | PUBLIC } SERVER <replaceable class="parameter">servername</replaceable>
+</synopsis>
+ </refsynopsisdiv>
+
+ <refsect1>
+ <title>Description</title>
+
+ <para>
+ <command>DROP USER MAPPING</command> removes an existing user
+ mapping from foreign server. To execute this command, the current
+ user must be the owner of the server containing the mapping.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Parameters</title>
+
+ <variablelist>
+ <varlistentry>
+ <term><literal>IF EXISTS</literal></term>
+ <listitem>
+ <para>
+ Do not throw an error if the user mapping does not exist. A
+ notice is issued in this case.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">username</replaceable></term>
+ <listitem>
+ <para>
+ User name of the mapping. <literal>CURRENT_USER</>
+ and <literal>USER</> match the name of the current
+ user. <literal>PUBLIC</> is used to match all present and
+ future user names in the system.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><replaceable class="parameter">servername</replaceable></term>
+ <listitem>
+ <para>
+ Server name of the user mapping.
+ </para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ </refsect1>
+
+ <refsect1>
+ <title>Examples</title>
+
+ <para>
+ Drop a user mapping <literal>bob</>, server <literal>foo</> if it exists:
+<programlisting>
+DROP USER MAPPING IF EXISTS FOR bob SERVER foo;
+</programlisting>
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>Compatibility</title>
+
+ <para>
+ <command>DROP USER MAPPING</command> conforms to ISO/IEC 9075-9
+ (SQL/MED). The <literal>IF EXISTS</> clause is
+ a <productname>PostgreSQL</> extension.
+ </para>
+ </refsect1>
+
+ <refsect1>
+ <title>See Also</title>
+
+ <simplelist type="inline">
+ <member><xref linkend="sql-createusermapping" endterm="sql-createusermapping-title"></member>
+ <member><xref linkend="sql-alterusermapping" endterm="sql-alterusermapping-title"></member>
+ </simplelist>
+ </refsect1>
+
+</refentry>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.72 2008/11/14 10:22:47 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.73 2008/12/19 16:25:16 petere Exp $
PostgreSQL documentation
-->
ON DATABASE <replaceable>dbname</replaceable> [, ...]
TO { [ GROUP ] <replaceable class="PARAMETER">rolename</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+GRANT { USAGE | ALL [ PRIVILEGES ] }
+ ON FOREIGN DATA WRAPPER <replaceable>fdwname</> [, ...]
+ TO { [ GROUP ] <replaceable class="PARAMETER">rolename</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
+GRANT { USAGE | ALL [ PRIVILEGES ] }
+ ON FOREIGN SERVER <replaceable>servername</> [, ...]
+ TO { [ GROUP ] <replaceable class="PARAMETER">rolename</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
+
GRANT { EXECUTE | ALL [ PRIVILEGES ] }
ON FUNCTION <replaceable>funcname</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) [, ...]
TO { [ GROUP ] <replaceable class="PARAMETER">rolename</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
<para>
The <command>GRANT</command> command has two basic variants: one
that grants privileges on a database object (table, view, sequence,
- database, function, procedural language, schema, or tablespace),
- and one that grants membership in a role. These variants are
- similar in many ways, but they are different enough to be described
- separately.
+ database, foreign-data wrapper, foreign server, function,
+ procedural language, schema, or tablespace), and one that grants
+ membership in a role. These variants are similar in many ways, but
+ they are different enough to be described separately.
</para>
<para>
For sequences, this privilege allows the use of the
<function>currval</function> and <function>nextval</function> functions.
</para>
+ <para>
+ For foreign-data wrappers, this privilege enables the grantee
+ to create new servers using that foreign-data wrapper.
+ </para>
+ <para>
+ For servers, this privilege enables the grantee to query the
+ options of the server and associated user mappings.
+ </para>
</listitem>
</varlistentry>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.213 2008/12/01 09:20:37 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.214 2008/12/19 16:25:16 petere Exp $
PostgreSQL documentation
-->
</varlistentry>
+ <varlistentry>
+ <term><literal>\des [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
+ <term><literal>\des+ [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
+ <listitem>
+ <para>
+ Lists all foreign servers (mnemonic: <quote>external
+ servers</quote>).
+ If <replaceable class="parameter">pattern</replaceable> is
+ specified, only those servers whose name matches the pattern
+ are listed. If the form <literal>\des+</literal> is used, a
+ full desription of each server is shown, including the
+ server's ACL, type, version, and options.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><literal>\deu [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
+ <term><literal>\deu+ [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
+ <listitem>
+ <para>
+ Lists all user mappings (mnemonic: <quote>external
+ users</quote>).
+ If <replaceable class="parameter">pattern</replaceable> is
+ specified, only those mappings whose user names match the
+ pattern are listed. If the form <literal>\deu+</literal> is
+ used, additional information about each mapping is shown.
+ </para>
+
+ <caution>
+ <para>
+ <literal>\deu+</literal> might also display the user name and
+ password of the remote user, so care should be taken not to
+ disclose them.
+ </para>
+ </caution>
+ </listitem>
+ </varlistentry>
+
+
+ <varlistentry>
+ <term><literal>\dew [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
+ <term><literal>\dew+ [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
+ <listitem>
+ <para>
+ Lists all foreign-data wrappers (mnemonic: <quote>external
+ wrappers</quote>).
+ If <replaceable class="parameter">pattern</replaceable> is
+ specified, only those foreign-data wrappers whose name matches
+ the pattern are listed. If the form <literal>\dew+</literal>
+ is used, the ACL and options of the foreign-data wrapper are
+ also shown.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry>
<term><literal>\df [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
<term><literal>\df+ [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
<!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/revoke.sgml,v 1.49 2008/11/14 10:22:47 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/revoke.sgml,v 1.50 2008/12/19 16:25:16 petere Exp $
PostgreSQL documentation
-->
FROM { [ GROUP ] <replaceable class="PARAMETER">rolename</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
+REVOKE [ GRANT OPTION FOR ]
+ { USAGE | ALL [ PRIVILEGES ] }
+ ON FOREIGN DATA WRAPPER <replaceable>fdwname</replaceable> [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">rolename</replaceable> | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
+
+REVOKE [ GRANT OPTION FOR ]
+ { USAGE | ALL [ PRIVILEGES ] }
+ ON FOREIGN SERVER <replaceable>servername</replaceable> [, ...]
+ FROM { [ GROUP ] <replaceable class="PARAMETER">rolename</replaceable> | PUBLIC } [, ...]
+ [ CASCADE | RESTRICT ]
+
REVOKE [ GRANT OPTION FOR ]
{ EXECUTE | ALL [ PRIVILEGES ] }
ON FUNCTION <replaceable>funcname</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] ) [, ...]
-<!-- $PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.66 2008/03/27 17:24:16 momjian Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.67 2008/12/19 16:25:16 petere Exp $ -->
<part id="reference">
<title>Reference</title>
&alterConversion;
&alterDatabase;
&alterDomain;
+ &alterForeignDataWrapper;
&alterFunction;
&alterGroup;
&alterIndex;
&alterRole;
&alterSchema;
&alterSequence;
+ &alterServer;
&alterTable;
&alterTableSpace;
&alterTSConfig;
&alterTrigger;
&alterType;
&alterUser;
+ &alterUserMapping;
&alterView;
&analyze;
&begin;
&createConversion;
&createDatabase;
&createDomain;
+ &createForeignDataWrapper;
&createFunction;
&createGroup;
&createIndex;
&createRule;
&createSchema;
&createSequence;
+ &createServer;
&createTable;
&createTableAs;
&createTableSpace;
&createTrigger;
&createType;
&createUser;
+ &createUserMapping;
&createView;
&deallocate;
&declare;
&dropConversion;
&dropDatabase;
&dropDomain;
+ &dropForeignDataWrapper;
&dropFunction;
&dropGroup;
&dropIndex;
&dropRule;
&dropSchema;
&dropSequence;
+ &dropServer;
&dropTable;
&dropTableSpace;
&dropTSConfig;
&dropTrigger;
&dropType;
&dropUser;
+ &dropUserMapping;
&dropView;
&end;
&execute;
#
# Copyright (c) 1994, Regents of the University of California
#
-# $PostgreSQL: pgsql/src/Makefile,v 1.43 2008/03/18 16:24:50 petere Exp $
+# $PostgreSQL: pgsql/src/Makefile,v 1.44 2008/12/19 16:25:16 petere Exp $
#
#-------------------------------------------------------------------------
$(MAKE) -C backend $@
$(MAKE) -C backend/utils/mb/conversion_procs $@
$(MAKE) -C backend/snowball $@
+ $(MAKE) -C backend/foreign $@-fdw
$(MAKE) -C include $@
$(MAKE) -C interfaces $@
$(MAKE) -C bin $@
# Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
# Portions Copyright (c) 1994, Regents of the University of California
#
-# $PostgreSQL: pgsql/src/backend/Makefile,v 1.130 2008/08/29 13:02:32 petere Exp $
+# $PostgreSQL: pgsql/src/backend/Makefile,v 1.131 2008/12/19 16:25:16 petere Exp $
#
#-------------------------------------------------------------------------
top_builddir = ../..
include $(top_builddir)/src/Makefile.global
-SUBDIRS = access bootstrap catalog parser commands executor lib libpq \
+SUBDIRS = access bootstrap catalog parser commands executor foreign lib libpq \
main nodes optimizer port postmaster regex rewrite \
storage tcop tsearch utils $(top_builddir)/src/timezone
#
# Makefile for backend/catalog
#
-# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.67 2008/11/19 10:34:51 heikki Exp $
+# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.68 2008/12/19 16:25:16 petere Exp $
#
#-------------------------------------------------------------------------
pg_authid.h pg_auth_members.h pg_shdepend.h pg_shdescription.h \
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 \
toasting.h indexing.h \
)
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.149 2008/11/02 01:45:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.150 2008/12/19 16:25:16 petere Exp $
*
* NOTES
* See acl.h.
#include "catalog/pg_authid.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
+#include "catalog/pg_foreign_data_wrapper.h"
+#include "catalog/pg_foreign_server.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_dict.h"
#include "commands/dbcommands.h"
+#include "foreign/foreign.h"
#include "miscadmin.h"
#include "parser/parse_func.h"
#include "utils/acl.h"
static void ExecGrant_Relation(InternalGrant *grantStmt);
static void ExecGrant_Database(InternalGrant *grantStmt);
+static void ExecGrant_Fdw(InternalGrant *grantStmt);
+static void ExecGrant_ForeignServer(InternalGrant *grantStmt);
static void ExecGrant_Function(InternalGrant *grantStmt);
static void ExecGrant_Language(InternalGrant *grantStmt);
static void ExecGrant_Namespace(InternalGrant *grantStmt);
case ACL_KIND_TABLESPACE:
whole_mask = ACL_ALL_RIGHTS_TABLESPACE;
break;
+ case ACL_KIND_FDW:
+ whole_mask = ACL_ALL_RIGHTS_FDW;
+ break;
+ case ACL_KIND_FOREIGN_SERVER:
+ whole_mask = ACL_ALL_RIGHTS_FOREIGN_SERVER;
+ break;
default:
elog(ERROR, "unrecognized object kind: %d", objkind);
/* not reached, but keep compiler quiet */
all_privileges = ACL_ALL_RIGHTS_TABLESPACE;
errormsg = gettext_noop("invalid privilege type %s for tablespace");
break;
+ case ACL_OBJECT_FDW:
+ all_privileges = ACL_ALL_RIGHTS_FDW;
+ errormsg = gettext_noop("invalid privilege type %s for foreign-data wrapper");
+ break;
+ case ACL_OBJECT_FOREIGN_SERVER:
+ all_privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
+ errormsg = gettext_noop("invalid privilege type %s for foreign server");
+ break;
default:
/* keep compiler quiet */
all_privileges = ACL_NO_RIGHTS;
case ACL_OBJECT_DATABASE:
ExecGrant_Database(istmt);
break;
+ case ACL_OBJECT_FDW:
+ ExecGrant_Fdw(istmt);
+ break;
+ case ACL_OBJECT_FOREIGN_SERVER:
+ ExecGrant_ForeignServer(istmt);
+ break;
case ACL_OBJECT_FUNCTION:
ExecGrant_Function(istmt);
break;
heap_close(relation, AccessShareLock);
}
break;
+ case ACL_OBJECT_FDW:
+ foreach(cell, objnames)
+ {
+ char *fdwname = strVal(lfirst(cell));
+ Oid fdwid = GetForeignDataWrapperOidByName(fdwname, false);
+
+ objects = lappend_oid(objects, fdwid);
+ }
+ break;
+ case ACL_OBJECT_FOREIGN_SERVER:
+ foreach(cell, objnames)
+ {
+ char *srvname = strVal(lfirst(cell));
+ Oid srvid = GetForeignServerOidByName(srvname, false);
+
+ objects = lappend_oid(objects, srvid);
+ }
+ break;
default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) objtype);
heap_close(relation, RowExclusiveLock);
}
+static void
+ExecGrant_Fdw(InternalGrant *istmt)
+{
+ Relation relation;
+ ListCell *cell;
+
+ if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
+ istmt->privileges = ACL_ALL_RIGHTS_FDW;
+
+ relation = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
+
+ foreach(cell, istmt->objects)
+ {
+ Oid fdwid = lfirst_oid(cell);
+ Form_pg_foreign_data_wrapper pg_fdw_tuple;
+ Datum aclDatum;
+ bool isNull;
+ AclMode avail_goptions;
+ AclMode this_privileges;
+ Acl *old_acl;
+ Acl *new_acl;
+ Oid grantorId;
+ Oid ownerId;
+ HeapTuple tuple;
+ HeapTuple newtuple;
+ Datum values[Natts_pg_foreign_data_wrapper];
+ bool nulls[Natts_pg_foreign_data_wrapper];
+ bool replaces[Natts_pg_foreign_data_wrapper];
+ int noldmembers;
+ int nnewmembers;
+ Oid *oldmembers;
+ Oid *newmembers;
+
+ tuple = SearchSysCache(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(fdwid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
+
+ pg_fdw_tuple = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
+
+ /*
+ * Get owner ID and working copy of existing ACL. If there's no ACL,
+ * substitute the proper default.
+ */
+ ownerId = pg_fdw_tuple->fdwowner;
+ aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
+ Anum_pg_foreign_data_wrapper_fdwacl,
+ &isNull);
+ if (isNull)
+ old_acl = acldefault(ACL_OBJECT_FDW, ownerId);
+ else
+ old_acl = DatumGetAclPCopy(aclDatum);
+
+ /* Determine ID to do the grant as, and available grant options */
+ select_best_grantor(GetUserId(), istmt->privileges,
+ old_acl, ownerId,
+ &grantorId, &avail_goptions);
+
+ /*
+ * Restrict the privileges to what we can actually grant, and emit the
+ * standards-mandated warning and error messages.
+ */
+ this_privileges =
+ restrict_and_check_grant(istmt->is_grant, avail_goptions,
+ istmt->all_privs, istmt->privileges,
+ fdwid, grantorId, ACL_KIND_FDW,
+ NameStr(pg_fdw_tuple->fdwname));
+
+ /*
+ * Generate new ACL.
+ *
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+
+ new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
+ istmt->grant_option, istmt->behavior,
+ istmt->grantees, this_privileges,
+ grantorId, ownerId);
+
+ nnewmembers = aclmembers(new_acl, &newmembers);
+
+ /* finished building new ACL value, now insert it */
+ MemSet(values, 0, sizeof(values));
+ MemSet(nulls, false, sizeof(nulls));
+ MemSet(replaces, false, sizeof(replaces));
+
+ replaces[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
+ values[Anum_pg_foreign_data_wrapper_fdwacl - 1] = PointerGetDatum(new_acl);
+
+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
+ nulls, replaces);
+
+ simple_heap_update(relation, &newtuple->t_self, newtuple);
+
+ /* keep the catalog indexes up to date */
+ CatalogUpdateIndexes(relation, newtuple);
+
+ /* Update the shared dependency ACL info */
+ updateAclDependencies(ForeignDataWrapperRelationId, HeapTupleGetOid(tuple),
+ ownerId, istmt->is_grant,
+ noldmembers, oldmembers,
+ nnewmembers, newmembers);
+
+ ReleaseSysCache(tuple);
+
+ pfree(new_acl);
+
+ /* prevent error when processing duplicate objects */
+ CommandCounterIncrement();
+ }
+
+ heap_close(relation, RowExclusiveLock);
+}
+
+static void ExecGrant_ForeignServer(InternalGrant *istmt)
+{
+ Relation relation;
+ ListCell *cell;
+
+ if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
+ istmt->privileges = ACL_ALL_RIGHTS_FOREIGN_SERVER;
+
+ relation = heap_open(ForeignServerRelationId, RowExclusiveLock);
+
+ foreach(cell, istmt->objects)
+ {
+ Oid srvid = lfirst_oid(cell);
+ Form_pg_foreign_server pg_server_tuple;
+ Datum aclDatum;
+ bool isNull;
+ AclMode avail_goptions;
+ AclMode this_privileges;
+ Acl *old_acl;
+ Acl *new_acl;
+ Oid grantorId;
+ Oid ownerId;
+ HeapTuple tuple;
+ HeapTuple newtuple;
+ Datum values[Natts_pg_foreign_server];
+ bool nulls[Natts_pg_foreign_server];
+ bool replaces[Natts_pg_foreign_server];
+ int noldmembers;
+ int nnewmembers;
+ Oid *oldmembers;
+ Oid *newmembers;
+
+ tuple = SearchSysCache(FOREIGNSERVEROID,
+ ObjectIdGetDatum(srvid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup failed for foreign server %u", srvid);
+
+ pg_server_tuple = (Form_pg_foreign_server) GETSTRUCT(tuple);
+
+ /*
+ * Get owner ID and working copy of existing ACL. If there's no ACL,
+ * substitute the proper default.
+ */
+ ownerId = pg_server_tuple->srvowner;
+ aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
+ Anum_pg_foreign_server_srvacl,
+ &isNull);
+ if (isNull)
+ old_acl = acldefault(ACL_OBJECT_FOREIGN_SERVER, ownerId);
+ else
+ old_acl = DatumGetAclPCopy(aclDatum);
+
+ /* Determine ID to do the grant as, and available grant options */
+ select_best_grantor(GetUserId(), istmt->privileges,
+ old_acl, ownerId,
+ &grantorId, &avail_goptions);
+
+ /*
+ * Restrict the privileges to what we can actually grant, and emit the
+ * standards-mandated warning and error messages.
+ */
+ this_privileges =
+ restrict_and_check_grant(istmt->is_grant, avail_goptions,
+ istmt->all_privs, istmt->privileges,
+ srvid, grantorId, ACL_KIND_FOREIGN_SERVER,
+ NameStr(pg_server_tuple->srvname));
+
+ /*
+ * Generate new ACL.
+ *
+ * We need the members of both old and new ACLs so we can correct the
+ * shared dependency information.
+ */
+ noldmembers = aclmembers(old_acl, &oldmembers);
+
+ new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
+ istmt->grant_option, istmt->behavior,
+ istmt->grantees, this_privileges,
+ grantorId, ownerId);
+
+ nnewmembers = aclmembers(new_acl, &newmembers);
+
+ /* finished building new ACL value, now insert it */
+ MemSet(values, 0, sizeof(values));
+ MemSet(nulls, false, sizeof(nulls));
+ MemSet(replaces, false, sizeof(replaces));
+
+ replaces[Anum_pg_foreign_server_srvacl - 1] = true;
+ values[Anum_pg_foreign_server_srvacl - 1] = PointerGetDatum(new_acl);
+
+ newtuple = heap_modify_tuple(tuple, RelationGetDescr(relation), values,
+ nulls, replaces);
+
+ simple_heap_update(relation, &newtuple->t_self, newtuple);
+
+ /* keep the catalog indexes up to date */
+ CatalogUpdateIndexes(relation, newtuple);
+
+ /* Update the shared dependency ACL info */
+ updateAclDependencies(ForeignServerRelationId, HeapTupleGetOid(tuple),
+ ownerId, istmt->is_grant,
+ noldmembers, oldmembers,
+ nnewmembers, newmembers);
+
+ ReleaseSysCache(tuple);
+
+ pfree(new_acl);
+
+ /* prevent error when processing duplicate objects */
+ CommandCounterIncrement();
+ }
+
+ heap_close(relation, RowExclusiveLock);
+}
+
static void
ExecGrant_Function(InternalGrant *istmt)
{
/* ACL_KIND_TSDICTIONARY */
gettext_noop("permission denied for text search dictionary %s"),
/* ACL_KIND_TSCONFIGURATION */
- gettext_noop("permission denied for text search configuration %s")
+ gettext_noop("permission denied for text search configuration %s"),
+ /* ACL_KIND_FDW */
+ gettext_noop("permission denied for foreign-data wrapper %s"),
+ /* ACL_KIND_FOREIGN_SERVER */
+ gettext_noop("permission denied for foreign server %s")
};
static const char *const not_owner_msg[MAX_ACL_KIND] =
/* ACL_KIND_TSDICTIONARY */
gettext_noop("must be owner of text search dictionary %s"),
/* ACL_KIND_TSCONFIGURATION */
- gettext_noop("must be owner of text search configuration %s")
+ gettext_noop("must be owner of text search configuration %s"),
+ /* ACL_KIND_FDW */
+ gettext_noop("must be owner of foreign-data wrapper %s"),
+ /* ACL_KIND_FOREIGN_SERVER */
+ gettext_noop("must be owner of foreign server %s")
};
return pg_namespace_aclmask(table_oid, roleid, mask, how);
case ACL_KIND_TABLESPACE:
return pg_tablespace_aclmask(table_oid, roleid, mask, how);
+ case ACL_KIND_FDW:
+ return pg_foreign_data_wrapper_aclmask(table_oid, roleid, mask, how);
+ case ACL_KIND_FOREIGN_SERVER:
+ return pg_foreign_server_aclmask(table_oid, roleid, mask, how);
default:
elog(ERROR, "unrecognized objkind: %d",
(int) objkind);
return result;
}
+/*
+ * Exported routine for examining a user's privileges for a foreign
+ * data wrapper
+ */
+AclMode
+pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid,
+ AclMode mask, AclMaskHow how)
+{
+ AclMode result;
+ HeapTuple tuple;
+ Datum aclDatum;
+ bool isNull;
+ Acl *acl;
+ Oid ownerId;
+
+ Form_pg_foreign_data_wrapper fdwForm;
+
+ /* Bypass permission checks for superusers */
+ if (superuser_arg(roleid))
+ return mask;
+
+ /*
+ * Must get the FDW's tuple from pg_foreign_data_wrapper
+ */
+ tuple = SearchSysCache(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(fdw_oid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errmsg("foreign-data wrapper with OID %u does not exist",
+ fdw_oid)));
+ fdwForm = (Form_pg_foreign_data_wrapper) GETSTRUCT(tuple);
+
+ /*
+ * Normal case: get the FDW's ACL from pg_foreign_data_wrapper
+ */
+ ownerId = fdwForm->fdwowner;
+
+ aclDatum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID, tuple,
+ Anum_pg_foreign_data_wrapper_fdwacl, &isNull);
+ if (isNull)
+ {
+ /* No ACL, so build default ACL */
+ acl = acldefault(ACL_OBJECT_FDW, ownerId);
+ aclDatum = (Datum) 0;
+ }
+ else
+ {
+ /* detoast rel's ACL if necessary */
+ acl = DatumGetAclP(aclDatum);
+ }
+
+ result = aclmask(acl, roleid, ownerId, mask, how);
+
+ /* if we have a detoasted copy, free it */
+ if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
+ pfree(acl);
+
+ ReleaseSysCache(tuple);
+
+ return result;
+}
+
+/*
+ * Exported routine for examining a user's privileges for a foreign
+ * server.
+ */
+AclMode
+pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
+ AclMode mask, AclMaskHow how)
+{
+ AclMode result;
+ HeapTuple tuple;
+ Datum aclDatum;
+ bool isNull;
+ Acl *acl;
+ Oid ownerId;
+
+ Form_pg_foreign_server srvForm;
+
+ /* Bypass permission checks for superusers */
+ if (superuser_arg(roleid))
+ return mask;
+
+ /*
+ * Must get the FDW's tuple from pg_foreign_data_wrapper
+ */
+ tuple = SearchSysCache(FOREIGNSERVEROID,
+ ObjectIdGetDatum(srv_oid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errmsg("foreign server with OID %u does not exist",
+ srv_oid)));
+ srvForm = (Form_pg_foreign_server) GETSTRUCT(tuple);
+
+ /*
+ * Normal case: get the foreign server's ACL from pg_foreign_server
+ */
+ ownerId = srvForm->srvowner;
+
+ aclDatum = SysCacheGetAttr(FOREIGNSERVEROID, tuple,
+ Anum_pg_foreign_server_srvacl, &isNull);
+ if (isNull)
+ {
+ /* No ACL, so build default ACL */
+ acl = acldefault(ACL_OBJECT_FOREIGN_SERVER, ownerId);
+ aclDatum = (Datum) 0;
+ }
+ else
+ {
+ /* detoast rel's ACL if necessary */
+ acl = DatumGetAclP(aclDatum);
+ }
+
+ result = aclmask(acl, roleid, ownerId, mask, how);
+
+ /* if we have a detoasted copy, free it */
+ if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
+ pfree(acl);
+
+ ReleaseSysCache(tuple);
+
+ return result;
+}
/*
* Exported routine for checking a user's access privileges to a table
return ACLCHECK_NO_PRIV;
}
+/*
+ * Exported routine for checking a user's access privileges to a foreign
+ * data wrapper
+ */
+AclResult
+pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode)
+{
+ if (pg_foreign_data_wrapper_aclmask(fdw_oid, roleid, mode, ACLMASK_ANY) != 0)
+ return ACLCHECK_OK;
+ else
+ return ACLCHECK_NO_PRIV;
+}
+
+/*
+ * Exported routine for checking a user's access privileges to a foreign
+ * server
+ */
+AclResult
+pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode)
+{
+ if (pg_foreign_server_aclmask(srv_oid, roleid, mode, ACLMASK_ANY) != 0)
+ return ACLCHECK_OK;
+ else
+ return ACLCHECK_NO_PRIV;
+}
/*
* Ownership check for a relation (specified by OID).
return has_privs_of_role(roleid, ownerId);
}
+/*
+ * Ownership check for a foreign server (specified by OID).
+ */
+bool
+pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid)
+{
+ HeapTuple tuple;
+ Oid ownerId;
+
+ /* Superusers bypass all permission checking. */
+ if (superuser_arg(roleid))
+ return true;
+
+ tuple = SearchSysCache(FOREIGNSERVEROID,
+ ObjectIdGetDatum(srv_oid),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("foreign server with OID %u does not exist",
+ srv_oid)));
+
+ ownerId = ((Form_pg_foreign_server) GETSTRUCT(tuple))->srvowner;
+
+ ReleaseSysCache(tuple);
+
+ return has_privs_of_role(roleid, ownerId);
+}
/*
* Ownership check for a database (specified by OID).
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.82 2008/11/10 21:49:16 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/dependency.c,v 1.83 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/pg_conversion_fn.h"
#include "catalog/pg_database.h"
#include "catalog/pg_depend.h"
+#include "catalog/pg_foreign_data_wrapper.h"
+#include "catalog/pg_foreign_server.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_ts_parser.h"
#include "catalog/pg_ts_template.h"
#include "catalog/pg_type.h"
+#include "catalog/pg_user_mapping.h"
#include "commands/comment.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
#include "commands/tablespace.h"
#include "commands/trigger.h"
#include "commands/typecmds.h"
+#include "foreign/foreign.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
RemoveTSConfigurationById(object->objectId);
break;
+ case OCLASS_USER_MAPPING:
+ RemoveUserMappingById(object->objectId);
+ break;
+
+ case OCLASS_FOREIGN_SERVER:
+ RemoveForeignServerById(object->objectId);
+ break;
+
+ case OCLASS_FDW:
+ RemoveForeignDataWrapperById(object->objectId);
+ break;
+
/* OCLASS_ROLE, OCLASS_DATABASE, OCLASS_TBLSPACE not handled */
default:
case TableSpaceRelationId:
Assert(object->objectSubId == 0);
return OCLASS_TBLSPACE;
+
+ case ForeignDataWrapperRelationId:
+ Assert(object->objectSubId == 0);
+ return OCLASS_FDW;
+
+ case ForeignServerRelationId:
+ Assert(object->objectSubId == 0);
+ return OCLASS_FOREIGN_SERVER;
+
+ case UserMappingRelationId:
+ Assert(object->objectSubId == 0);
+ return OCLASS_USER_MAPPING;
}
/* shouldn't get here */
break;
}
+ case OCLASS_FDW:
+ {
+ ForeignDataWrapper *fdw;
+
+ fdw = GetForeignDataWrapper(object->objectId);
+ appendStringInfo(&buffer, _("foreign-data wrapper %s"), fdw->fdwname);
+ break;
+ }
+
+ case OCLASS_FOREIGN_SERVER:
+ {
+ ForeignServer *srv;
+
+ srv = GetForeignServer(object->objectId);
+ appendStringInfo(&buffer, _("server %s"), srv->servername);
+ break;
+ }
+
+ case OCLASS_USER_MAPPING:
+ {
+ HeapTuple tup;
+ Oid useid;
+ char *usename;
+
+ tup = SearchSysCache(USERMAPPINGOID,
+ ObjectIdGetDatum(object->objectId),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tup))
+ elog(ERROR, "cache lookup failed for user mapping %u",
+ object->objectId);
+
+ useid = ((Form_pg_user_mapping) GETSTRUCT(tup))->umuser;
+
+ ReleaseSysCache(tup);
+
+ if (OidIsValid(useid))
+ usename = GetUserNameFromId(useid);
+ else
+ usename = "public";
+
+ appendStringInfo(&buffer, _("user mapping for %s"), usename);
+ break;
+ }
+
default:
appendStringInfo(&buffer, "unrecognized object %u %u %d",
object->classId,
*
* Copyright (c) 2003-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.46 2008/09/08 00:47:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/information_schema.sql,v 1.47 2008/12/19 16:25:17 petere Exp $
*/
/*
* ROLE_USAGE_GRANTS view
*/
--- See USAGE_PRIVILEGES.
-
CREATE VIEW role_usage_grants AS
- SELECT CAST(null AS sql_identifier) AS grantor,
- CAST(null AS sql_identifier) AS grantee,
+
+ /* foreign-data wrappers */
+ SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
+ CAST(g_grantee.rolname AS sql_identifier) AS grantee,
CAST(current_database() AS sql_identifier) AS object_catalog,
- CAST(null AS sql_identifier) AS object_schema,
- CAST(null AS sql_identifier) AS object_name,
- CAST(null AS character_data) AS object_type,
+ CAST('' AS sql_identifier) AS object_schema,
+ CAST(fdw.fdwname AS sql_identifier) AS object_name,
+ CAST('FOREIGN DATA WRAPPER' AS character_data) AS object_type,
CAST('USAGE' AS character_data) AS privilege_type,
- CAST(null AS character_data) AS is_grantable
+ CAST(
+ CASE WHEN aclcontains(fdw.fdwacl,
+ makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', true))
+ THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
- WHERE false;
+ FROM pg_foreign_data_wrapper fdw,
+ pg_authid u_grantor,
+ pg_authid g_grantee
+
+ WHERE aclcontains(fdw.fdwacl,
+ makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', false))
+ AND (u_grantor.rolname IN (SELECT role_name FROM enabled_roles)
+ OR g_grantee.rolname IN (SELECT role_name FROM enabled_roles))
+
+ UNION ALL
+
+ /* foreign server */
+ SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
+ CAST(g_grantee.rolname AS sql_identifier) AS grantee,
+ CAST(current_database() AS sql_identifier) AS object_catalog,
+ CAST('' AS sql_identifier) AS object_schema,
+ CAST(srv.srvname AS sql_identifier) AS object_name,
+ CAST('FOREIGN SERVER' AS character_data) AS object_type,
+ CAST('USAGE' AS character_data) AS privilege_type,
+ CAST(
+ CASE WHEN aclcontains(srv.srvacl,
+ makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', true))
+ THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
+
+ FROM pg_foreign_server srv,
+ pg_authid u_grantor,
+ pg_authid g_grantee
+
+ WHERE aclcontains(srv.srvacl,
+ makeaclitem(g_grantee.oid, u_grantor.oid, 'USAGE', false))
+ AND (u_grantor.rolname IN (SELECT role_name FROM enabled_roles)
+ OR g_grantee.rolname IN (SELECT role_name FROM enabled_roles));
GRANT SELECT ON role_usage_grants TO PUBLIC;
* USAGE_PRIVILEGES view
*/
--- Of the things currently implemented in PostgreSQL, usage privileges
--- apply only to domains. Since domains have no real privileges, we
--- represent all domains with implicit usage privilege here.
-
CREATE VIEW usage_privileges AS
+
+ /* domains */
+ -- Domains have no real privileges, so we represent all domains with implicit usage privilege here.
SELECT CAST(u.rolname AS sql_identifier) AS grantor,
CAST('PUBLIC' AS sql_identifier) AS grantee,
CAST(current_database() AS sql_identifier) AS object_catalog,
WHERE u.oid = t.typowner
AND t.typnamespace = n.oid
- AND t.typtype = 'd';
+ AND t.typtype = 'd'
+
+ UNION ALL
+
+ /* foreign-data wrappers */
+ SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
+ CAST(grantee.rolname AS sql_identifier) AS grantee,
+ CAST(current_database() AS sql_identifier) AS object_catalog,
+ CAST('' AS sql_identifier) AS object_schema,
+ CAST(fdw.fdwname AS sql_identifier) AS object_name,
+ CAST('FOREIGN DATA WRAPPER' AS character_data) AS object_type,
+ CAST('USAGE' AS character_data) AS privilege_type,
+ CAST(
+ CASE WHEN aclcontains(fdw.fdwacl,
+ makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', true))
+ THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
+
+ FROM pg_foreign_data_wrapper fdw,
+ pg_authid u_grantor,
+ (
+ SELECT oid, rolname FROM pg_authid
+ UNION ALL
+ SELECT 0::oid, 'PUBLIC'
+ ) AS grantee (oid, rolname)
+
+ WHERE aclcontains(fdw.fdwacl,
+ makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', false))
+ AND (pg_has_role(u_grantor.oid, 'USAGE')
+ OR pg_has_role(grantee.oid, 'USAGE')
+ OR grantee.rolname = 'PUBLIC')
+
+ UNION ALL
+
+ /* foreign servers */
+ SELECT CAST(u_grantor.rolname AS sql_identifier) AS grantor,
+ CAST(grantee.rolname AS sql_identifier) AS grantee,
+ CAST(current_database() AS sql_identifier) AS object_catalog,
+ CAST('' AS sql_identifier) AS object_schema,
+ CAST(srv.srvname AS sql_identifier) AS object_name,
+ CAST('FOREIGN SERVER' AS character_data) AS object_type,
+ CAST('USAGE' AS character_data) AS privilege_type,
+ CAST(
+ CASE WHEN aclcontains(srv.srvacl,
+ makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', true))
+ THEN 'YES' ELSE 'NO' END AS character_data) AS is_grantable
+
+ FROM pg_foreign_server srv,
+ pg_authid u_grantor,
+ (
+ SELECT oid, rolname FROM pg_authid
+ UNION ALL
+ SELECT 0::oid, 'PUBLIC'
+ ) AS grantee (oid, rolname)
+
+ WHERE aclcontains(srv.srvacl,
+ makeaclitem(grantee.oid, u_grantor.oid, 'USAGE', false))
+ AND (pg_has_role(u_grantor.oid, 'USAGE')
+ OR pg_has_role(grantee.oid, 'USAGE')
+ OR grantee.rolname = 'PUBLIC');
GRANT SELECT ON usage_privileges TO PUBLIC;
FROM data_type_privileges );
GRANT SELECT ON element_types TO PUBLIC;
+
+
+-- SQL/MED views; these use section numbers from part 9 of the standard.
+
+/* Base view for foreign-data wrappers */
+CREATE VIEW _pg_foreign_data_wrappers AS
+ SELECT w.oid,
+ w.fdwowner,
+ w.fdwoptions,
+ CAST(current_database() AS sql_identifier) AS foreign_data_wrapper_catalog,
+ CAST(fdwname AS sql_identifier) AS foreign_data_wrapper_name,
+ CAST(u.rolname AS sql_identifier) AS authorization_identifier,
+ CAST(fdwlibrary AS character_data) AS library_name,
+ CAST('c' AS character_data) AS foreign_data_wrapper_language
+ FROM pg_foreign_data_wrapper w, pg_authid u
+ WHERE u.oid = w.fdwowner
+ AND (pg_has_role(fdwowner, 'USAGE')
+ OR has_foreign_data_wrapper_privilege(w.oid, 'USAGE'));
+
+
+/*
+ * 24.4
+ * FOREIGN_DATA_WRAPPER_OPTIONS view
+ */
+CREATE VIEW foreign_data_wrapper_options AS
+ SELECT foreign_data_wrapper_catalog,
+ foreign_data_wrapper_name,
+ CAST((pg_options_to_table(w.fdwoptions)).option_name AS sql_identifier) AS option_name,
+ CAST((pg_options_to_table(w.fdwoptions)).option_value AS character_data) AS option_value
+ FROM _pg_foreign_data_wrappers w;
+
+GRANT SELECT ON foreign_data_wrapper_options TO PUBLIC;
+
+
+/*
+ * 24.5
+ * FOREIGN_DATA_WRAPPERS view
+ */
+CREATE VIEW foreign_data_wrappers AS
+ SELECT foreign_data_wrapper_catalog,
+ foreign_data_wrapper_name,
+ authorization_identifier,
+ library_name,
+ foreign_data_wrapper_language
+ FROM _pg_foreign_data_wrappers w;
+
+GRANT SELECT ON foreign_data_wrappers TO PUBLIC;
+
+
+/* Base view for foreign servers */
+CREATE VIEW _pg_foreign_servers AS
+ SELECT s.oid,
+ s.srvoptions,
+ CAST(current_database() AS sql_identifier) AS foreign_server_catalog,
+ CAST(srvname AS sql_identifier) AS foreign_server_name,
+ w.foreign_data_wrapper_catalog,
+ w.foreign_data_wrapper_name,
+ CAST(srvtype AS character_data) AS foreign_server_type,
+ CAST(srvversion AS character_data) AS foreign_server_version,
+ CAST(u.rolname AS sql_identifier) AS authorization_identifier
+ FROM pg_foreign_server s, _pg_foreign_data_wrappers w, pg_authid u
+ WHERE w.oid = s.srvfdw
+ AND u.oid = s.srvowner
+ AND (pg_has_role(s.srvowner, 'USAGE')
+ OR has_server_privilege(s.oid, 'USAGE'));
+
+
+/*
+ * 24.6
+ * FOREIGN_SERVER_OPTIONS view
+ */
+CREATE VIEW foreign_server_options AS
+ SELECT foreign_server_catalog,
+ foreign_server_name,
+ CAST((pg_options_to_table(s.srvoptions)).option_name AS sql_identifier) AS option_name,
+ CAST((pg_options_to_table(s.srvoptions)).option_value AS character_data) AS option_value
+ FROM _pg_foreign_servers s;
+
+GRANT SELECT ON TABLE foreign_server_options TO PUBLIC;
+
+
+/*
+ * 24.7
+ * FOREIGN_SERVERS view
+ */
+CREATE VIEW foreign_servers AS
+ SELECT foreign_server_catalog,
+ foreign_server_name,
+ foreign_data_wrapper_catalog,
+ foreign_data_wrapper_name,
+ foreign_server_type,
+ foreign_server_version,
+ authorization_identifier
+ FROM _pg_foreign_servers;
+
+GRANT SELECT ON foreign_servers TO PUBLIC;
+
+
+/* Base view for user mappings */
+CREATE VIEW _pg_user_mappings AS
+ SELECT um.oid,
+ um.umoptions,
+ CAST(COALESCE(u.rolname,'PUBLIC') AS sql_identifier ) AS authorization_identifier,
+ s.foreign_server_catalog,
+ s.foreign_server_name
+ FROM pg_user_mapping um LEFT JOIN pg_authid u ON (u.oid = um.umuser),
+ _pg_foreign_servers s
+ WHERE s.oid = um.umserver;
+
+
+/*
+ * 24.12
+ * USER_MAPPING_OPTIONS view
+ */
+CREATE VIEW user_mapping_options AS
+ SELECT authorization_identifier,
+ foreign_server_catalog,
+ foreign_server_name,
+ CAST((pg_options_to_table(um.umoptions)).option_name AS sql_identifier) AS option_name,
+ CAST((pg_options_to_table(um.umoptions)).option_value AS character_data) AS option_value
+ FROM _pg_user_mappings um;
+
+GRANT SELECT ON user_mapping_options TO PUBLIC;
+
+
+/*
+ * 24.13
+ * USER_MAPPINGS view
+ */
+CREATE VIEW user_mappings AS
+ SELECT authorization_identifier,
+ foreign_server_catalog,
+ foreign_server_name
+ FROM _pg_user_mappings;
+
+GRANT SELECT ON user_mappings TO PUBLIC;
T653 SQL-schema statements in external routines NO
T654 SQL-dynamic statements in external routines NO
T655 Cyclically dependent routines NO
+M001 Datalinks NO
+M002 Datalinks via SQL/CLI NO
+M003 Datalinks via Embedded SQL NO
+M004 Foreign data support NO
+M005 Foreign schema support NO
+M006 GetSQLString routine NO
+M007 TransmitRequest NO
+M009 GetOpts and GetStatistics routines NO
+M010 Foreign data wrapper support NO
+M011 Datalinks via Ada NO
+M012 Datalinks via C NO
+M013 Datalinks via COBOL NO
+M014 Datalinks via Fortran NO
+M015 Datalinks via M NO
+M016 Datalinks via Pascal NO
+M017 Datalinks via PL/I NO
+M018 Foreign data wrapper interface routines in Ada NO
+M019 Foreign data wrapper interface routines in C NO
+M020 Foreign data wrapper interface routines in COBOL NO
+M021 Foreign data wrapper interface routines in Fortran NO
+M022 Foreign data wrapper interface routines in MUMPS NO
+M023 Foreign data wrapper interface routines in Pascal NO
+M024 Foreign data wrapper interface routines in PL/I NO
+M030 SQL-server foreign data support NO
+M031 Foreign data wrapper general routines NO
X010 XML type YES
X011 Arrays of XML type YES
X012 Multisets of XML type NO
*
* Copyright (c) 1996-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.56 2008/11/09 21:24:32 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.57 2008/12/19 16:25:17 petere Exp $
*/
CREATE VIEW pg_roles AS
pg_stat_get_buf_written_backend() AS buffers_backend,
pg_stat_get_buf_alloc() AS buffers_alloc;
+CREATE VIEW pg_user_mappings AS
+ SELECT
+ U.oid AS umid,
+ S.oid AS srvid,
+ S.srvname AS srvname,
+ U.umuser AS umuser,
+ CASE WHEN U.umuser = 0 THEN
+ 'public'
+ ELSE
+ A.rolname
+ END AS usename,
+ CASE WHEN pg_has_role(S.srvowner, 'USAGE') OR has_server_privilege(S.oid, 'USAGE') THEN
+ U.umoptions
+ ELSE
+ NULL
+ END AS umoptions
+ FROM pg_user_mapping U
+ LEFT JOIN pg_authid A ON (A.oid = U.umuser) JOIN
+ pg_foreign_server S ON (U.umserver = S.oid);
+
+REVOKE ALL on pg_user_mapping FROM public;
+
-- Tsearch debug function. Defined here because it'd be pretty unwieldy
-- to put it into pg_proc.h
# Makefile for backend/commands
#
# IDENTIFICATION
-# $PostgreSQL: pgsql/src/backend/commands/Makefile,v 1.38 2008/02/19 10:30:07 petere Exp $
+# $PostgreSQL: pgsql/src/backend/commands/Makefile,v 1.39 2008/12/19 16:25:17 petere Exp $
#
#-------------------------------------------------------------------------
OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
conversioncmds.o copy.o \
- dbcommands.o define.o discard.o explain.o functioncmds.o \
+ dbcommands.o define.o discard.o explain.o foreigncmds.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \
schemacmds.o sequence.o tablecmds.o tablespace.o trigger.o \
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.29 2008/06/15 01:25:53 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/alter.c,v 1.30 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
AlterTSConfigurationOwner(stmt->object, newowner);
break;
+ case OBJECT_FDW:
+ AlterForeignDataWrapperOwner(strVal(linitial(stmt->object)),
+ newowner);
+ break;
+
+ case OBJECT_FOREIGN_SERVER:
+ AlterForeignServerOwner(strVal(linitial(stmt->object)), newowner);
+ break;
+
default:
elog(ERROR, "unrecognized AlterOwnerStmt type: %d",
(int) stmt->objectType);
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * foreigncmds.c
+ * foreign-data wrapper/server creation/manipulation commands
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ *
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/commands/foreigncmds.c,v 1.1 2008/12/19 16:25:17 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/heapam.h"
+#include "access/reloptions.h"
+#include "catalog/catalog.h"
+#include "catalog/dependency.h"
+#include "catalog/indexing.h"
+#include "catalog/pg_foreign_data_wrapper.h"
+#include "catalog/pg_foreign_server.h"
+#include "catalog/pg_type.h"
+#include "catalog/pg_user_mapping.h"
+#include "commands/defrem.h"
+#include "foreign/foreign.h"
+#include "miscadmin.h"
+#include "utils/acl.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/rel.h"
+#include "utils/syscache.h"
+
+
+/*
+ * Convert a DefElem list to the text array format that is used in
+ * pg_foreign_data_wrapper, pg_foreign_server, and pg_user_mapping.
+ *
+ * Note: The array is usually stored to database without further
+ * processing, hence any validation should be done before this
+ * conversion.
+ */
+static Datum
+optionListToArray(List *options)
+{
+ ArrayBuildState *astate = NULL;
+ ListCell *cell;
+ text *t;
+
+ foreach (cell, options)
+ {
+ DefElem *def = lfirst(cell);
+ const char *value = "";
+ Size len;
+
+ value = defGetString(def);
+ len = VARHDRSZ + strlen(def->defname) + 1 + strlen(value);
+ t = palloc(len + 1);
+ SET_VARSIZE(t, len);
+ sprintf(VARDATA(t), "%s=%s", def->defname, value);
+
+ astate = accumArrayResult(astate, PointerGetDatum(t),
+ false, TEXTOID,
+ CurrentMemoryContext);
+ }
+
+ if (astate)
+ return makeArrayResult(astate, CurrentMemoryContext);
+
+ return PointerGetDatum(NULL);
+}
+
+
+/*
+ * Transform the list of OptionDefElem into list of generic options.
+ * The result is converted to array of text suitable for storing in
+ * options.
+ *
+ * This is used by CREATE/ALTER of FOREIGN DATA WRAPPER/SERVER/USER
+ * MAPPING. In the ALTER cases, oldOptions is the current text array
+ * of options.
+ */
+static Datum
+transformGenericOptions(Datum oldOptions,
+ List *optionDefList,
+ GenericOptionFlags flags,
+ ForeignDataWrapper *fdw,
+ OptionListValidatorFunc validateOptionList)
+{
+ List *resultOptions = untransformRelOptions(oldOptions);
+ ListCell *optcell;
+
+ foreach (optcell, optionDefList)
+ {
+ ListCell *cell;
+ ListCell *prev = NULL;
+ OptionDefElem *od = lfirst(optcell);
+
+ /*
+ * Find the element in resultOptions. We need this for
+ * validation in all cases.
+ */
+ foreach (cell, resultOptions)
+ {
+ DefElem *def = lfirst(cell);
+
+ if (strcmp(def->defname, od->def->defname) == 0)
+ break;
+ else
+ prev = cell;
+ }
+
+ /*
+ * It is possible to perform multiple SET/DROP actions on the
+ * same option. The standard permits this, as long as the
+ * options to be added are unique.
+ */
+
+ switch (od->alter_op)
+ {
+ case ALTER_OPT_DROP:
+ if (!cell)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("option \"%s\" not found",
+ od->def->defname)));
+ resultOptions = list_delete_cell(resultOptions, cell, prev);
+ break;
+
+ case ALTER_OPT_SET:
+ if (!cell)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("option \"%s\" not found",
+ od->def->defname)));
+ lfirst(cell) = od->def;
+ break;
+
+ case ALTER_OPT_ADD:
+ if (cell)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("option \"%s\" provided more than once",
+ od->def->defname)));
+ resultOptions = lappend(resultOptions, od->def);
+ break;
+
+ default:
+ elog(ERROR, "unrecognized action %d on option \"%s\"",
+ od->alter_op, od->def->defname);
+ break;
+ }
+ }
+
+ if (validateOptionList)
+ validateOptionList(fdw, flags, resultOptions);
+
+ return optionListToArray(resultOptions);
+}
+
+
+/*
+ * Convert the user mapping user name to OID
+ */
+static Oid
+GetUserOidFromMapping(const char *username, bool missing_ok)
+{
+ if (!username)
+ /* PUBLIC user mapping */
+ return InvalidOid;
+
+ if (strcmp(username, "current_user") == 0)
+ /* map to the owner */
+ return GetUserId();
+
+ /* map to provided user */
+ return missing_ok ? get_roleid(username) : get_roleid_checked(username);
+}
+
+
+/*
+ * Change foreign-data wrapper owner.
+ *
+ * Allow this only for superusers; also the new owner must be a
+ * superuser.
+ */
+void
+AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId)
+{
+ HeapTuple tup;
+ Relation rel;
+ Oid fdwId;
+
+ Form_pg_foreign_data_wrapper form;
+
+ /* Must be a superuser to change a FDW owner */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
+ name),
+ errhint("Must be superuser to change owner of a foreign-data wrapper.")));
+
+ /* New owner must also be a superuser */
+ if (!superuser_arg(newOwnerId))
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to change owner of foreign-data wrapper \"%s\"",
+ name),
+ errhint("The owner of a foreign-data wrapper must be a superuser.")));
+
+ rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
+
+ tup = SearchSysCacheCopy(FOREIGNDATAWRAPPERNAME,
+ CStringGetDatum(name),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("foreign-data wrapper \"%s\" does not exist", name)));
+
+ fdwId = HeapTupleGetOid(tup);
+ form = (Form_pg_foreign_data_wrapper) GETSTRUCT(tup);
+
+ if (form->fdwowner != newOwnerId)
+ {
+ form->fdwowner = newOwnerId;
+
+ simple_heap_update(rel, &tup->t_self, tup);
+ CatalogUpdateIndexes(rel, tup);
+
+ /* Update owner dependency reference */
+ changeDependencyOnOwner(ForeignDataWrapperRelationId,
+ fdwId,
+ newOwnerId);
+ }
+
+ heap_close(rel, NoLock);
+ heap_freetuple(tup);
+}
+
+
+/*
+ * Change foreign server owner
+ */
+void
+AlterForeignServerOwner(const char *name, Oid newOwnerId)
+{
+ HeapTuple tup;
+ Relation rel;
+ Oid srvId;
+ AclResult aclresult;
+ Form_pg_foreign_server form;
+
+ rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
+
+ tup = SearchSysCacheCopy(FOREIGNSERVERNAME,
+ CStringGetDatum(name),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tup))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("server \"%s\" does not exist", name)));
+
+ srvId = HeapTupleGetOid(tup);
+ form = (Form_pg_foreign_server) GETSTRUCT(tup);
+
+ if (form->srvowner != newOwnerId)
+ {
+ /* Superusers can always do it */
+ if (!superuser())
+ {
+ /* Must be owner */
+ if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
+ name);
+
+ /* Must be able to become new owner */
+ check_is_member_of_role(GetUserId(), newOwnerId);
+
+ /* New owner must have USAGE privilege on foreign-data wrapper */
+ aclresult = pg_foreign_data_wrapper_aclcheck(form->srvfdw, newOwnerId, ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ {
+ ForeignDataWrapper *fdw = GetForeignDataWrapper(form->srvfdw);
+
+ aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
+ }
+ }
+
+ form->srvowner = newOwnerId;
+
+ simple_heap_update(rel, &tup->t_self, tup);
+ CatalogUpdateIndexes(rel, tup);
+
+ /* Update owner dependency reference */
+ changeDependencyOnOwner(ForeignServerRelationId, HeapTupleGetOid(tup),
+ newOwnerId);
+ }
+
+ heap_close(rel, NoLock);
+ heap_freetuple(tup);
+}
+
+
+/*
+ * Create a foreign-data wrapper
+ */
+void
+CreateForeignDataWrapper(CreateFdwStmt *stmt)
+{
+ Relation rel;
+ Datum values[Natts_pg_foreign_data_wrapper];
+ bool nulls[Natts_pg_foreign_data_wrapper];
+ HeapTuple tuple;
+ Oid fdwId;
+ Datum fdwoptions = InvalidOid;
+ Oid ownerId;
+ ForeignDataWrapperLibrary *fdwlib;
+
+ /* Must be super user */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to create foreign-data wrapper \"%s\"",
+ stmt->fdwname),
+ errhint("Must be superuser to create a foreign-data wrapper.")));
+
+ /* For now the owner cannot be specified on create. Use effective user ID. */
+ ownerId = GetUserId();
+
+ /*
+ * Check that there is no other foreign-data wrapper by this name.
+ */
+ if (GetForeignDataWrapperByName(stmt->fdwname, true) != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("foreign-data wrapper \"%s\" already exists",
+ stmt->fdwname)));
+
+ /*
+ * Insert tuple into pg_foreign_data_wrapper.
+ */
+ rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
+
+ MemSet(nulls, false, Natts_pg_foreign_data_wrapper);
+
+ values[Anum_pg_foreign_data_wrapper_fdwname - 1] =
+ DirectFunctionCall1(namein, CStringGetDatum(stmt->fdwname));
+ values[Anum_pg_foreign_data_wrapper_fdwowner - 1] = ObjectIdGetDatum(ownerId);
+ values[Anum_pg_foreign_data_wrapper_fdwlibrary - 1] = CStringGetTextDatum(stmt->library);
+ nulls[Anum_pg_foreign_data_wrapper_fdwacl - 1] = true;
+
+ /*
+ * See if the FDW library loads at all. We also might want to use it
+ * later for validating the options.
+ */
+ fdwlib = GetForeignDataWrapperLibrary(stmt->library);
+
+ fdwoptions = transformGenericOptions(0, stmt->options, FdwOpt, NULL,
+ fdwlib->validateOptionList);
+
+ if (OidIsValid(fdwoptions))
+ values[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = fdwoptions;
+ else
+ nulls[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
+
+ tuple = heap_form_tuple(rel->rd_att, values, nulls);
+
+ fdwId = simple_heap_insert(rel, tuple);
+ CatalogUpdateIndexes(rel, tuple);
+
+ heap_freetuple(tuple);
+
+ recordDependencyOnOwner(ForeignDataWrapperRelationId, fdwId, ownerId);
+
+ heap_close(rel, NoLock);
+}
+
+
+/*
+ * Alter foreign-data wrapper
+ */
+void
+AlterForeignDataWrapper(AlterFdwStmt *stmt)
+{
+ Relation rel;
+ HeapTuple tp;
+ Datum repl_val[Natts_pg_foreign_data_wrapper];
+ bool repl_null[Natts_pg_foreign_data_wrapper];
+ bool repl_repl[Natts_pg_foreign_data_wrapper];
+ Oid fdwId;
+ bool isnull;
+ Datum datum;
+ ForeignDataWrapperLibrary *fdwlib;
+
+ /* Must be super user */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to alter foreign-data wrapper \"%s\"",
+ stmt->fdwname),
+ errhint("Must be superuser to alter a foreign-data wrapper.")));
+
+ tp = SearchSysCacheCopy(FOREIGNDATAWRAPPERNAME,
+ CStringGetDatum(stmt->fdwname),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("foreign-data wrapper \"%s\" does not exist", stmt->fdwname)));
+
+ fdwId = HeapTupleGetOid(tp);
+
+ memset(repl_val, 0, sizeof(repl_val));
+ memset(repl_null, false, sizeof(repl_null));
+ memset(repl_repl, false, sizeof(repl_repl));
+
+ if (stmt->library)
+ {
+ /*
+ * New library specified -- load to see if valid.
+ */
+ fdwlib = GetForeignDataWrapperLibrary(stmt->library);
+
+ repl_val[Anum_pg_foreign_data_wrapper_fdwlibrary - 1] = CStringGetTextDatum(stmt->library);
+ repl_repl[Anum_pg_foreign_data_wrapper_fdwlibrary - 1] = true;
+
+ /*
+ * It could be that the options for the FDW, SERVER and USER MAPPING
+ * are no longer valid with the new library. Warn about this.
+ */
+ ereport(WARNING,
+ (errmsg("changing the foreign-data wrapper library can cause "
+ "the options for dependent objects to become invalid")));
+ }
+ else
+ {
+ /*
+ * No LIBRARY clause specified, but we need to load it for validating
+ * options.
+ */
+ datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
+ tp,
+ Anum_pg_foreign_data_wrapper_fdwlibrary,
+ &isnull);
+ fdwlib = GetForeignDataWrapperLibrary(TextDatumGetCString(datum));
+ }
+
+ /*
+ * Options specified, validate and update.
+ */
+ if (stmt->options)
+ {
+ /* Extract the current options */
+ datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
+ tp,
+ Anum_pg_foreign_data_wrapper_fdwoptions,
+ &isnull);
+
+ /* Transform the options */
+ datum = transformGenericOptions(datum, stmt->options, FdwOpt,
+ NULL, fdwlib->validateOptionList);
+
+ if (OidIsValid(datum))
+ repl_val[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = ObjectIdGetDatum(datum);
+ else
+ repl_null[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
+
+ repl_repl[Anum_pg_foreign_data_wrapper_fdwoptions - 1] = true;
+ }
+
+ /* Everything looks good - update the tuple */
+
+ rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
+
+ tp = heap_modify_tuple(tp, RelationGetDescr(rel),
+ repl_val, repl_null, repl_repl);
+
+ simple_heap_update(rel, &tp->t_self, tp);
+ CatalogUpdateIndexes(rel, tp);
+
+ heap_close(rel, RowExclusiveLock);
+ heap_freetuple(tp);
+}
+
+
+/*
+ * Drop foreign-data wrapper
+ */
+void
+RemoveForeignDataWrapper(DropFdwStmt *stmt)
+{
+ Oid fdwId;
+ ObjectAddress object;
+
+ fdwId = GetForeignDataWrapperOidByName(stmt->fdwname, true);
+
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("permission denied to drop foreign-data wrapper \"%s\"",
+ stmt->fdwname),
+ errhint("Must be superuser to drop a foreign-data wrapper.")));
+
+ if (!OidIsValid(fdwId))
+ {
+ if (!stmt->missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("foreign-data wrapper \"%s\" does not exist",
+ stmt->fdwname)));
+
+ /* IF EXISTS specified, just note it */
+ ereport(NOTICE,
+ (errmsg("foreign-data wrapper \"%s\" does not exist, skipping",
+ stmt->fdwname)));
+ return;
+ }
+
+ /*
+ * Do the deletion
+ */
+ object.classId = ForeignDataWrapperRelationId;
+ object.objectId = fdwId;
+ object.objectSubId = 0;
+
+ performDeletion(&object, stmt->behavior);
+}
+
+
+/*
+ * Drop foreign-data wrapper by OID
+ */
+void
+RemoveForeignDataWrapperById(Oid fdwId)
+{
+ HeapTuple tp;
+ Relation rel;
+
+ rel = heap_open(ForeignDataWrapperRelationId, RowExclusiveLock);
+
+ tp = SearchSysCache(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(fdwId),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwId);
+
+ simple_heap_delete(rel, &tp->t_self);
+
+ ReleaseSysCache(tp);
+
+ heap_close(rel, RowExclusiveLock);
+}
+
+
+/*
+ * Create a foreign server
+ */
+void
+CreateForeignServer(CreateForeignServerStmt *stmt)
+{
+ Relation rel;
+ Datum srvoptions = InvalidOid;
+ Datum values[Natts_pg_foreign_server];
+ bool nulls[Natts_pg_foreign_server];
+ HeapTuple tuple;
+ Oid srvId;
+ Oid ownerId;
+ AclResult aclresult;
+ ObjectAddress myself;
+ ObjectAddress referenced;
+ ForeignDataWrapper *fdw;
+
+ /* For now the owner cannot be specified on create. Use effective user ID. */
+ ownerId = GetUserId();
+
+ /*
+ * Check that there is no other foreign server by this name.
+ */
+ if (GetForeignServerByName(stmt->servername, true) != NULL)
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("server \"%s\" already exists",
+ stmt->servername)));
+
+ /*
+ * Check that the FDW exists and that we have USAGE on it.
+ * Also get the actual FDW for option validation etc.
+ */
+ fdw = GetForeignDataWrapperByName(stmt->fdwname, false);
+
+ aclresult = pg_foreign_data_wrapper_aclcheck(fdw->fdwid, ownerId, ACL_USAGE);
+ if (aclresult != ACLCHECK_OK)
+ aclcheck_error(aclresult, ACL_KIND_FDW, fdw->fdwname);
+
+ /*
+ * Insert tuple into pg_foreign_server.
+ */
+ rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
+
+ MemSet(nulls, false, Natts_pg_foreign_server);
+
+ values[Anum_pg_foreign_server_srvname - 1] =
+ DirectFunctionCall1(namein, CStringGetDatum(stmt->servername));
+ values[Anum_pg_foreign_server_srvowner - 1] = ObjectIdGetDatum(ownerId);
+ values[Anum_pg_foreign_server_srvfdw - 1] = ObjectIdGetDatum(fdw->fdwid);
+
+ /* Add server type if supplied */
+ if (stmt->servertype)
+ values[Anum_pg_foreign_server_srvtype - 1] =
+ CStringGetTextDatum(stmt->servertype);
+ else
+ nulls[Anum_pg_foreign_server_srvtype - 1] = true;
+
+ /* Add server version if supplied */
+ if (stmt->version)
+ values[Anum_pg_foreign_server_srvversion - 1] =
+ CStringGetTextDatum(stmt->version);
+ else
+ nulls[Anum_pg_foreign_server_srvversion - 1] = true;
+
+ /* Start with a blank acl */
+ nulls[Anum_pg_foreign_server_srvacl - 1] = true;
+
+ /* Add server options */
+ srvoptions = transformGenericOptions(0, stmt->options, ServerOpt, fdw,
+ fdw->lib->validateOptionList);
+
+ if (OidIsValid(srvoptions))
+ values[Anum_pg_foreign_server_srvoptions - 1] = srvoptions;
+ else
+ nulls[Anum_pg_foreign_server_srvoptions - 1] = true;
+
+ tuple = heap_form_tuple(rel->rd_att, values, nulls);
+
+ srvId = simple_heap_insert(rel, tuple);
+
+ CatalogUpdateIndexes(rel, tuple);
+
+ heap_freetuple(tuple);
+
+ /* Add dependency on FDW and owner */
+ myself.classId = ForeignServerRelationId;
+ myself.objectId = srvId;
+ myself.objectSubId = 0;
+
+ referenced.classId = ForeignDataWrapperRelationId;
+ referenced.objectId = fdw->fdwid;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ recordDependencyOnOwner(ForeignServerRelationId, srvId, ownerId);
+
+ heap_close(rel, NoLock);
+}
+
+
+/*
+ * Alter foreign server
+ */
+void
+AlterForeignServer(AlterForeignServerStmt *stmt)
+{
+ Relation rel;
+ HeapTuple tp;
+ Datum repl_val[Natts_pg_foreign_server];
+ bool repl_null[Natts_pg_foreign_server];
+ bool repl_repl[Natts_pg_foreign_server];
+ Oid srvId;
+ Form_pg_foreign_server srvForm;
+
+ tp = SearchSysCacheCopy(FOREIGNSERVERNAME,
+ CStringGetDatum(stmt->servername),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("server \"%s\" does not exist", stmt->servername)));
+
+ srvId = HeapTupleGetOid(tp);
+ srvForm = (Form_pg_foreign_server) GETSTRUCT(tp);
+
+ /*
+ * Only owner or a superuser can ALTER a SERVER.
+ */
+ if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
+ stmt->servername);
+
+ memset(repl_val, 0, sizeof(repl_val));
+ memset(repl_null, false, sizeof(repl_null));
+ memset(repl_repl, false, sizeof(repl_repl));
+
+ if (stmt->has_version)
+ {
+ /*
+ * Change the server VERSION string.
+ */
+ if (stmt->version)
+ repl_val[Anum_pg_foreign_server_srvversion - 1] =
+ CStringGetTextDatum(stmt->version);
+ else
+ repl_null[Anum_pg_foreign_server_srvversion - 1] = true;
+
+ repl_repl[Anum_pg_foreign_server_srvversion - 1] = true;
+ }
+
+ if (stmt->options)
+ {
+ ForeignDataWrapper *fdw = GetForeignDataWrapper(srvForm->srvfdw);
+ Datum datum;
+ bool isnull;
+
+ /* Extract the current srvoptions */
+ datum = SysCacheGetAttr(FOREIGNSERVEROID,
+ tp,
+ Anum_pg_foreign_server_srvoptions,
+ &isnull);
+
+ /* Prepare the options array */
+ datum = transformGenericOptions(datum, stmt->options, ServerOpt,
+ fdw, fdw->lib->validateOptionList);
+
+ if (OidIsValid(datum))
+ repl_val[Anum_pg_foreign_server_srvoptions - 1] = datum;
+ else
+ repl_null[Anum_pg_foreign_server_srvoptions - 1] = true;
+
+ repl_repl[Anum_pg_foreign_server_srvoptions - 1] = true;
+ }
+
+ /* Everything looks good - update the tuple */
+
+ rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
+
+ tp = heap_modify_tuple(tp, RelationGetDescr(rel),
+ repl_val, repl_null, repl_repl);
+
+ simple_heap_update(rel, &tp->t_self, tp);
+ CatalogUpdateIndexes(rel, tp);
+
+ heap_close(rel, RowExclusiveLock);
+ heap_freetuple(tp);
+}
+
+
+/*
+ * Drop foreign server
+ */
+void
+RemoveForeignServer(DropForeignServerStmt *stmt)
+{
+ Oid srvId;
+ ObjectAddress object;
+
+ srvId = GetForeignServerOidByName(stmt->servername, true);
+
+ if (!OidIsValid(srvId))
+ {
+ /* Server not found, complain or notice */
+ if (!stmt->missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("server \"%s\" does not exist", stmt->servername)));
+
+ /* IF EXISTS specified, just note it */
+ ereport(NOTICE,
+ (errmsg("server \"%s\" does not exist, skipping",
+ stmt->servername)));
+ return;
+ }
+
+ /* Only allow DROP if the server is owned by the user. */
+ if (!pg_foreign_server_ownercheck(srvId, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
+ stmt->servername);
+
+ object.classId = ForeignServerRelationId;
+ object.objectId = srvId;
+ object.objectSubId = 0;
+
+ performDeletion(&object, stmt->behavior);
+}
+
+
+/*
+ * Drop foreign server by OID
+ */
+void
+RemoveForeignServerById(Oid srvId)
+{
+ HeapTuple tp;
+ Relation rel;
+
+ rel = heap_open(ForeignServerRelationId, RowExclusiveLock);
+
+ tp = SearchSysCache(FOREIGNSERVEROID,
+ ObjectIdGetDatum(srvId),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for foreign server %u", srvId);
+
+ simple_heap_delete(rel, &tp->t_self);
+
+ ReleaseSysCache(tp);
+
+ heap_close(rel, RowExclusiveLock);
+}
+
+
+/*
+ * Create user mapping
+ */
+void
+CreateUserMapping(CreateUserMappingStmt *stmt)
+{
+ Relation rel;
+ Datum useoptions = InvalidOid;
+ Datum values[Natts_pg_user_mapping];
+ bool nulls[Natts_pg_user_mapping];
+ HeapTuple tuple;
+ Oid useId;
+ Oid umId;
+ Oid ownerId;
+ ObjectAddress myself;
+ ObjectAddress referenced;
+ ForeignServer *srv;
+ ForeignDataWrapper *fdw;
+
+ ownerId = GetUserId();
+
+ useId = GetUserOidFromMapping(stmt->username, false);
+
+ /*
+ * Check that the server exists and that the we own it.
+ */
+ srv = GetForeignServerByName(stmt->servername, false);
+
+ if (!pg_foreign_server_ownercheck(srv->serverid, ownerId))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
+ stmt->servername);
+
+ /*
+ * Check that the user mapping is unique within server.
+ */
+ umId = GetSysCacheOid(USERMAPPINGUSERSERVER,
+ ObjectIdGetDatum(useId),
+ ObjectIdGetDatum(srv->serverid),
+ 0, 0);
+ if (OidIsValid(umId))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("user mapping \"%s\" already exists for server %s",
+ MappingUserName(useId),
+ stmt->servername)));
+
+ fdw = GetForeignDataWrapper(srv->fdwid);
+
+ /*
+ * Insert tuple into pg_user_mapping.
+ */
+ rel = heap_open(UserMappingRelationId, RowExclusiveLock);
+
+ MemSet(nulls, false, Natts_pg_user_mapping);
+
+ values[Anum_pg_user_mapping_umuser - 1] = ObjectIdGetDatum(useId);
+ values[Anum_pg_user_mapping_umserver - 1] = ObjectIdGetDatum(srv->serverid);
+
+ /* Add user options */
+ useoptions = transformGenericOptions(0, stmt->options, UserMappingOpt,
+ fdw, fdw->lib->validateOptionList);
+
+ if (OidIsValid(useoptions))
+ values[Anum_pg_user_mapping_umoptions - 1] = useoptions;
+ else
+ nulls[Anum_pg_user_mapping_umoptions - 1] = true;
+
+ tuple = heap_form_tuple(rel->rd_att, values, nulls);
+
+ umId = simple_heap_insert(rel, tuple);
+
+ CatalogUpdateIndexes(rel, tuple);
+
+ heap_freetuple(tuple);
+
+ /* Add dependency on the server */
+ myself.classId = UserMappingRelationId;
+ myself.objectId = umId;
+ myself.objectSubId = 0;
+
+ referenced.classId = ForeignServerRelationId;
+ referenced.objectId = srv->serverid;
+ referenced.objectSubId = 0;
+ recordDependencyOn(&myself, &referenced, DEPENDENCY_NORMAL);
+
+ if (OidIsValid(useId))
+ /* Record the mapped user dependency */
+ recordDependencyOnOwner(UserMappingRelationId, umId, useId);
+
+ heap_close(rel, NoLock);
+}
+
+
+/*
+ * Alter user mapping
+ */
+void
+AlterUserMapping(AlterUserMappingStmt *stmt)
+{
+ Relation rel;
+ HeapTuple tp;
+ Datum repl_val[Natts_pg_user_mapping];
+ bool repl_null[Natts_pg_user_mapping];
+ bool repl_repl[Natts_pg_user_mapping];
+ Oid useId;
+ Oid umId;
+ ForeignServer *srv;
+
+ useId = GetUserOidFromMapping(stmt->username, false);
+ srv = GetForeignServerByName(stmt->servername, false);
+
+ umId = GetSysCacheOid(USERMAPPINGUSERSERVER,
+ ObjectIdGetDatum(useId),
+ ObjectIdGetDatum(srv->serverid),
+ 0, 0);
+ if (!OidIsValid(umId))
+ {
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("user mapping \"%s\" does not exist for the server",
+ MappingUserName(useId))));
+ }
+
+ /*
+ * Must be owner of the server to alter user mapping.
+ */
+ if (!pg_foreign_server_ownercheck(srv->serverid, GetUserId()))
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
+ stmt->servername);
+
+ tp = SearchSysCacheCopy(USERMAPPINGOID,
+ ObjectIdGetDatum(umId),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for user mapping %u", umId);
+
+ memset(repl_val, 0, sizeof(repl_val));
+ memset(repl_null, false, sizeof(repl_null));
+ memset(repl_repl, false, sizeof(repl_repl));
+
+ if (stmt->options)
+ {
+ ForeignDataWrapper *fdw;
+ Datum datum;
+ bool isnull;
+
+ /*
+ * Process the options.
+ */
+
+ fdw = GetForeignDataWrapper(srv->fdwid);
+
+ datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
+ tp,
+ Anum_pg_user_mapping_umoptions,
+ &isnull);
+
+ /* Prepare the options array */
+ datum = transformGenericOptions(datum, stmt->options, UserMappingOpt,
+ fdw, fdw->lib->validateOptionList);
+
+ if (OidIsValid(datum))
+ repl_val[Anum_pg_user_mapping_umoptions - 1] = datum;
+ else
+ repl_null[Anum_pg_user_mapping_umoptions - 1] = true;
+
+ repl_repl[Anum_pg_user_mapping_umoptions - 1] = true;
+ }
+
+ /* Everything looks good - update the tuple */
+
+ rel = heap_open(UserMappingRelationId, RowExclusiveLock);
+
+ tp = heap_modify_tuple(tp, RelationGetDescr(rel),
+ repl_val, repl_null, repl_repl);
+
+ simple_heap_update(rel, &tp->t_self, tp);
+ CatalogUpdateIndexes(rel, tp);
+
+ heap_close(rel, RowExclusiveLock);
+ heap_freetuple(tp);
+}
+
+
+/*
+ * Drop user mapping
+ */
+void
+RemoveUserMapping(DropUserMappingStmt *stmt)
+{
+ ObjectAddress object;
+ Oid useId;
+ Oid umId;
+ ForeignServer *srv;
+
+ useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
+ srv = GetForeignServerByName(stmt->servername, true);
+
+ if (stmt->username && !OidIsValid(useId))
+ {
+ /*
+ * IF EXISTS specified, role not found and not public.
+ * Notice this and leave.
+ */
+ elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
+ return;
+ }
+
+ if (!srv)
+ {
+ if (!stmt->missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("server \"%s\" does not exist",
+ stmt->servername)));
+ /* IF EXISTS, just note it */
+ ereport(NOTICE, (errmsg("server does not exist, skipping")));
+ return;
+ }
+
+ umId = GetSysCacheOid(USERMAPPINGUSERSERVER,
+ ObjectIdGetDatum(useId),
+ ObjectIdGetDatum(srv->serverid),
+ 0, 0);
+
+ if (!OidIsValid(umId))
+ {
+ if (!stmt->missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("user mapping \"%s\" does not exist for the server",
+ MappingUserName(useId))));
+
+ /* IF EXISTS specified, just note it */
+ ereport(NOTICE,
+ (errmsg("user mapping \"%s\" does not exist for the server, skipping",
+ MappingUserName(useId))));
+ return;
+ }
+
+ /*
+ * Only allow DROP if we own the server.
+ */
+ if (!pg_foreign_server_ownercheck(srv->serverid, GetUserId()))
+ {
+ aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_FOREIGN_SERVER,
+ srv->servername);
+ }
+
+ /*
+ * Do the deletion
+ */
+ object.classId = UserMappingRelationId;
+ object.objectId = umId;
+ object.objectSubId = 0;
+
+ performDeletion(&object, DROP_CASCADE);
+}
+
+
+/*
+ * Drop user mapping by OID. This is called to clean up dependencies.
+ */
+void
+RemoveUserMappingById(Oid umId)
+{
+ HeapTuple tp;
+ Relation rel;
+
+ rel = heap_open(UserMappingRelationId, RowExclusiveLock);
+
+ tp = SearchSysCache(USERMAPPINGOID,
+ ObjectIdGetDatum(umId),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for user mapping %u", umId);
+
+ simple_heap_delete(rel, &tp->t_self);
+
+ ReleaseSysCache(tp);
+
+ heap_close(rel, RowExclusiveLock);
+}
--- /dev/null
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for foreign
+#
+# IDENTIFICATION
+# $PostgreSQL: pgsql/src/backend/foreign/Makefile,v 1.1 2008/12/19 16:25:17 petere Exp $
+#
+#-------------------------------------------------------------------------
+
+subdir = src/backend/foreign
+top_builddir = ../../..
+include $(top_builddir)/src/Makefile.global
+
+OBJS= foreign.o
+
+include $(top_srcdir)/src/backend/common.mk
+
+FDW = dummy postgresql
+
+$(addsuffix -fdw,all install installdirs uninstall distprep):
+ for dir in $(FDW); do $(MAKE) -C $$dir `echo $@ | sed 's/-fdw$$//'` || exit; done
+
+clean distclean maintainer-clean:
+ for dir in $(FDW); do $(MAKE) -C $$dir $@ || exit; done
--- /dev/null
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for dummy foreign-data wrapper
+#
+# IDENTIFICATION
+# $PostgreSQL: pgsql/src/backend/foreign/dummy/Makefile,v 1.1 2008/12/19 16:25:17 petere Exp $
+#
+#-------------------------------------------------------------------------
+
+subdir = src/backend/foreign/dummy
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+NAME = dummy_fdw
+OBJS = dummy_fdw.o
+
+include $(top_srcdir)/src/Makefile.shlib
+
+all: all-shared-lib
+
+install: all install-lib
+
+installdirs: installdirs-lib
+
+clean distclean maintainer-clean: clean-lib
+ rm -f $(OBJS)
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * dummy_fdw.c
+ * "dummy" foreign-data wrapper
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/foreign/dummy/dummy_fdw.c,v 1.1 2008/12/19 16:25:17 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "foreign/foreign.h"
+
+PG_MODULE_MAGIC;
+
+/*
+ * This looks like a complete waste right now, but it is useful for
+ * testing, and will become more interesting as more parts of the
+ * interface are implemented.
+ */
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * foreign.c
+ * support for foreign-data wrappers, servers and user mappings.
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/foreign/foreign.c,v 1.1 2008/12/19 16:25:17 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "access/reloptions.h"
+#include "catalog/namespace.h"
+#include "catalog/pg_foreign_data_wrapper.h"
+#include "catalog/pg_foreign_server.h"
+#include "catalog/pg_type.h"
+#include "catalog/pg_user_mapping.h"
+#include "foreign/foreign.h"
+#include "funcapi.h"
+#include "miscadmin.h"
+#include "nodes/parsenodes.h"
+#include "utils/acl.h"
+#include "utils/array.h"
+#include "utils/builtins.h"
+#include "utils/lsyscache.h"
+#include "utils/memutils.h"
+#include "utils/syscache.h"
+
+
+extern Datum pg_options_to_table(PG_FUNCTION_ARGS);
+
+
+/* list of currently loaded foreign-data wrapper interfaces */
+static List *loaded_fdw_interfaces = NIL;
+
+
+/*
+ * GetForeignDataWrapperLibrary - return the named FDW library. If it
+ * is already loaded, use that. Otherwise allocate, initialize, and
+ * store in cache.
+ */
+ForeignDataWrapperLibrary *
+GetForeignDataWrapperLibrary(const char *libname)
+{
+ MemoryContext oldcontext;
+ void *libhandle = NULL;
+ ForeignDataWrapperLibrary *fdwl = NULL;
+ ListCell *cell;
+
+ /* See if we have the FDW library is already loaded */
+ foreach (cell, loaded_fdw_interfaces)
+ {
+ fdwl = lfirst(cell);
+ if (strcmp(fdwl->libname, libname) == 0)
+ return fdwl;
+ }
+
+ /*
+ * We don't have it yet, so load and add. Attempt a load_file()
+ * first to filter out any missing or unloadable libraries.
+ */
+ load_file(libname, false);
+
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+
+ fdwl = palloc(sizeof(*fdwl));
+ fdwl->libname = pstrdup(libname);
+ loaded_fdw_interfaces = lappend(loaded_fdw_interfaces, fdwl);
+
+ MemoryContextSwitchTo(oldcontext);
+
+ /*
+ * Now look up the foreign data wrapper functions.
+ */
+#define LOOKUP_FUNCTION(name) \
+ (void *)(libhandle ? \
+ lookup_external_function(libhandle, name) \
+ : load_external_function(fdwl->libname, name, false, &libhandle))
+
+ fdwl->validateOptionList = LOOKUP_FUNCTION("_pg_validateOptionList");
+
+ return fdwl;
+}
+
+
+/*
+ * GetForeignDataWrapper - look up the foreign-data wrapper by OID.
+ *
+ * Here we also deal with loading the FDW library and looking up the
+ * actual functions.
+ */
+ForeignDataWrapper *
+GetForeignDataWrapper(Oid fdwid)
+{
+ Form_pg_foreign_data_wrapper fdwform;
+ ForeignDataWrapper *fdw;
+ Datum datum;
+ HeapTuple tp;
+ bool isnull;
+
+ tp = SearchSysCache(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(fdwid),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for foreign-data wrapper %u", fdwid);
+
+ fdwform = (Form_pg_foreign_data_wrapper) GETSTRUCT(tp);
+
+ fdw = palloc(sizeof(ForeignDataWrapper));
+ fdw->fdwid = fdwid;
+ fdw->owner = fdwform->fdwowner;
+ fdw->fdwname = pstrdup(NameStr(fdwform->fdwname));
+
+ /* Extract library name */
+ datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
+ tp,
+ Anum_pg_foreign_data_wrapper_fdwlibrary,
+ &isnull);
+ fdw->fdwlibrary = pstrdup(TextDatumGetCString(datum));
+
+ fdw->lib = GetForeignDataWrapperLibrary(fdw->fdwlibrary);
+
+ /* Extract the options */
+ datum = SysCacheGetAttr(FOREIGNDATAWRAPPEROID,
+ tp,
+ Anum_pg_foreign_data_wrapper_fdwoptions,
+ &isnull);
+ fdw->options = untransformRelOptions(datum);
+
+ ReleaseSysCache(tp);
+
+ return fdw;
+}
+
+
+/*
+ * GetForeignDataWrapperOidByName - look up the foreign-data wrapper
+ * OID by name.
+ */
+Oid
+GetForeignDataWrapperOidByName(const char *fdwname, bool missing_ok)
+{
+ Oid fdwId;
+
+ fdwId = GetSysCacheOid(FOREIGNDATAWRAPPERNAME,
+ CStringGetDatum(fdwname),
+ 0, 0, 0);
+
+ if (!OidIsValid(fdwId) && !missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("foreign-data wrapper \"%s\" does not exist", fdwname)));
+
+ return fdwId;
+}
+
+
+/*
+ * GetForeignDataWrapperByName - look up the foreign-data wrapper
+ * definition by name.
+ */
+ForeignDataWrapper *
+GetForeignDataWrapperByName(const char *fdwname, bool missing_ok)
+{
+ Oid fdwId = GetForeignDataWrapperOidByName(fdwname, missing_ok);
+
+ if (!OidIsValid(fdwId) && missing_ok)
+ return NULL;
+
+ return GetForeignDataWrapper(fdwId);
+}
+
+
+/*
+ * GetForeignServer - look up the foreign server definition.
+ */
+ForeignServer *
+GetForeignServer(Oid serverid)
+{
+ Form_pg_foreign_server serverform;
+ ForeignServer *server;
+ HeapTuple tp;
+ Datum datum;
+ bool isnull;
+
+ tp = SearchSysCache(FOREIGNSERVEROID,
+ ObjectIdGetDatum(serverid),
+ 0, 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ elog(ERROR, "cache lookup failed for foreign server %u", serverid);
+
+ serverform = (Form_pg_foreign_server) GETSTRUCT(tp);
+
+ server = palloc(sizeof(ForeignServer));
+ server->serverid = serverid;
+ server->servername = pstrdup(NameStr(serverform->srvname));
+ server->owner = serverform->srvowner;
+ server->fdwid = serverform->srvfdw;
+
+ /* Extract server type */
+ datum = SysCacheGetAttr(FOREIGNSERVEROID,
+ tp,
+ Anum_pg_foreign_server_srvtype,
+ &isnull);
+ server->servertype = isnull ? NULL : pstrdup(TextDatumGetCString(datum));
+
+ /* Extract server version */
+ datum = SysCacheGetAttr(FOREIGNSERVEROID,
+ tp,
+ Anum_pg_foreign_server_srvversion,
+ &isnull);
+ server->serverversion = isnull ? NULL : pstrdup(TextDatumGetCString(datum));
+
+ /* Extract the srvoptions */
+ datum = SysCacheGetAttr(FOREIGNSERVEROID,
+ tp,
+ Anum_pg_foreign_server_srvoptions,
+ &isnull);
+
+ /* untransformRelOptions does exactly what we want - avoid duplication */
+ server->options = untransformRelOptions(datum);
+
+ ReleaseSysCache(tp);
+
+ return server;
+}
+
+
+/*
+ * GetForeignServerByName - look up the foreign server oid by name.
+ */
+Oid
+GetForeignServerOidByName(const char *srvname, bool missing_ok)
+{
+ Oid serverid;
+
+ serverid = GetSysCacheOid(FOREIGNSERVERNAME,
+ CStringGetDatum(srvname),
+ 0, 0, 0);
+
+ if (!OidIsValid(serverid) && !missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("server \"%s\" does not exist", srvname)));
+
+ return serverid;
+}
+
+
+/*
+ * GetForeignServerByName - look up the foreign server definition by name.
+ */
+ForeignServer *
+GetForeignServerByName(const char *srvname, bool missing_ok)
+{
+ Oid serverid = GetForeignServerOidByName(srvname, missing_ok);
+
+ if (!OidIsValid(serverid) && missing_ok)
+ return NULL;
+
+ return GetForeignServer(serverid);
+}
+
+
+/*
+ * GetUserMapping - look up the user mapping.
+ *
+ * If no mapping is found for the supplied user, we also look for
+ * PUBLIC mappings (userid == InvalidOid).
+ */
+UserMapping *
+GetUserMapping(Oid userid, Oid serverid)
+{
+ Form_pg_user_mapping umform;
+ Datum datum;
+ HeapTuple tp;
+ bool isnull;
+ UserMapping *um;
+
+ tp = SearchSysCache(USERMAPPINGUSERSERVER,
+ ObjectIdGetDatum(userid),
+ ObjectIdGetDatum(serverid),
+ 0, 0);
+
+ if (!HeapTupleIsValid(tp))
+ {
+ /* Not found for the specific user -- try PUBLIC */
+ tp = SearchSysCache(USERMAPPINGUSERSERVER,
+ ObjectIdGetDatum(InvalidOid),
+ ObjectIdGetDatum(serverid),
+ 0, 0);
+ }
+
+ if (!HeapTupleIsValid(tp))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("user mapping not found for \"%s\"",
+ MappingUserName(userid))));
+
+ umform = (Form_pg_user_mapping) GETSTRUCT(tp);
+
+ /* Extract the umoptions */
+ datum = SysCacheGetAttr(USERMAPPINGUSERSERVER,
+ tp,
+ Anum_pg_user_mapping_umoptions,
+ &isnull);
+
+ um = palloc(sizeof(UserMapping));
+ um->userid = userid;
+ um->serverid = serverid;
+ um->options = untransformRelOptions(datum);
+
+ ReleaseSysCache(tp);
+
+ return um;
+}
+
+
+/*
+ * deflist_to_tuplestore - Helper function to convert DefElem list to
+ * tuplestore usable in SRF.
+ */
+static void
+deflist_to_tuplestore(ReturnSetInfo *rsinfo, List *options)
+{
+ ListCell *cell;
+ TupleDesc tupdesc;
+ Tuplestorestate *tupstore;
+ Datum values[2];
+ bool nulls[2] = { 0 };
+ MemoryContext per_query_ctx;
+ MemoryContext oldcontext;
+
+ /* check to see if caller supports us returning a tuplestore */
+ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("set-valued function called in context that cannot accept a set")));
+ if (!(rsinfo->allowedModes & SFRM_Materialize))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("materialize mode required, but it is not allowed in this context")));
+
+ per_query_ctx = rsinfo->econtext->ecxt_per_query_memory;
+ oldcontext = MemoryContextSwitchTo(per_query_ctx);
+
+ /*
+ * Now prepare the result set.
+ */
+ tupdesc = CreateTupleDescCopy(rsinfo->expectedDesc);
+ tupstore = tuplestore_begin_heap(true, false, work_mem);
+ rsinfo->returnMode = SFRM_Materialize;
+ rsinfo->setResult = tupstore;
+ rsinfo->setDesc = tupdesc;
+
+ foreach (cell, options)
+ {
+ DefElem *def = lfirst(cell);
+
+ values[0] = CStringGetTextDatum(def->defname);
+ values[1] = CStringGetTextDatum(((Value *)def->arg)->val.str);
+ tuplestore_putvalues(tupstore, tupdesc, values, nulls);
+ }
+
+ /* clean up and return the tuplestore */
+ tuplestore_donestoring(tupstore);
+
+ MemoryContextSwitchTo(oldcontext);
+}
+
+
+/*
+ * Convert options array to name/value table. Useful for information
+ * schema and pg_dump.
+ */
+Datum
+pg_options_to_table(PG_FUNCTION_ARGS)
+{
+ Datum array = PG_GETARG_DATUM(0);
+
+ deflist_to_tuplestore((ReturnSetInfo *) fcinfo->resultinfo, untransformRelOptions(array));
+
+ return (Datum) 0;
+}
--- /dev/null
+#-------------------------------------------------------------------------
+#
+# Makefile--
+# Makefile for postgresql foreign-data wrapper
+#
+# IDENTIFICATION
+# $PostgreSQL: pgsql/src/backend/foreign/postgresql/Makefile,v 1.1 2008/12/19 16:25:17 petere Exp $
+#
+#-------------------------------------------------------------------------
+
+subdir = src/backend/foreign/postgresql
+top_builddir = ../../../..
+include $(top_builddir)/src/Makefile.global
+
+NAME = postgresql_fdw
+OBJS = postgresql_fdw.o
+
+include $(top_srcdir)/src/Makefile.shlib
+
+all: all-shared-lib
+
+install: all install-lib
+
+installdirs: installdirs-lib
+
+clean distclean maintainer-clean: clean-lib
+ rm -f $(OBJS)
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * postgresql_fdw.c
+ * foreign-data wrapper for postgresql (libpq) connections.
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * $PostgreSQL: pgsql/src/backend/foreign/postgresql/postgresql_fdw.c,v 1.1 2008/12/19 16:25:17 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#include "postgres.h"
+
+#include "fmgr.h"
+#include "lib/stringinfo.h"
+#include "nodes/value.h"
+#include "nodes/parsenodes.h"
+#include "nodes/makefuncs.h"
+#include "foreign/foreign.h"
+
+PG_MODULE_MAGIC;
+
+
+/*
+ * Describes the valid options for postgresql FDW, server and user mapping.
+ */
+typedef struct ConnectionOptions {
+ const char *optname; /* Option name */
+ GenericOptionFlags optflags; /* Option usage bitmap */
+} ConnectionOptions;
+
+/*
+ * Copied from fe-connect.c PQconninfoOptions.
+ *
+ * The list is small - don't bother with bsearch if it stays so.
+ */
+static ConnectionOptions libpq_conninfo_options[] = {
+ { "authtype", ServerOpt },
+ { "service", ServerOpt },
+ { "user", UserMappingOpt },
+ { "password", UserMappingOpt },
+ { "connect_timeout", ServerOpt },
+ { "dbname", ServerOpt },
+ { "host", ServerOpt },
+ { "hostaddr", ServerOpt },
+ { "port", ServerOpt },
+ { "tty", ServerOpt },
+ { "options", ServerOpt },
+ { "requiressl", ServerOpt },
+ { "sslmode", ServerOpt },
+ { "gsslib", ServerOpt },
+ { NULL, InvalidOpt }
+};
+
+void _PG_fini(void);
+
+
+/*
+ * Check if the provided option is one of libpq conninfo options.
+ * We look at only options with matching flags.
+ */
+static bool
+is_conninfo_option(const char *option, GenericOptionFlags flags)
+{
+ ConnectionOptions *opt;
+
+ for (opt = libpq_conninfo_options; opt->optname != NULL; opt++)
+ if (flags & opt->optflags && strcmp(opt->optname, option) == 0)
+ return true;
+ return false;
+}
+
+/*
+ * Validate the generic option given to SERVER or USER MAPPING.
+ * Raise an ERROR if the option or its value is considered
+ * invalid.
+ *
+ * Valid server options are all libpq conninfo options except
+ * user and password -- these may only appear in USER MAPPING options.
+ */
+void
+_pg_validateOptionList(ForeignDataWrapper *fdw, GenericOptionFlags flags,
+ List *options)
+{
+ ListCell *cell;
+
+ foreach (cell, options)
+ {
+ DefElem *def = lfirst(cell);
+
+ if (!is_conninfo_option(def->defname, flags))
+ {
+ ConnectionOptions *opt;
+ StringInfoData buf;
+ const char *objtype;
+
+ /*
+ * Unknown option specified, complain about it. Provide a hint
+ * with list of valid options for the object.
+ */
+ initStringInfo(&buf);
+ for (opt = libpq_conninfo_options; opt->optname != NULL; opt++)
+ if (flags & opt->optflags)
+ appendStringInfo(&buf, "%s%s", (buf.len > 0) ? ", " : "",
+ opt->optname);
+
+ if (flags & ServerOpt)
+ objtype = "server";
+ else if (flags & UserMappingOpt)
+ objtype = "user mapping";
+ else if (flags & FdwOpt)
+ objtype = "foreign-data wrapper";
+ else
+ objtype = "???";
+
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("invalid option \"%s\" to %s", def->defname, objtype),
+ errhint("valid %s options are: %s", objtype, buf.data)));
+ }
+ }
+}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.415 2008/12/04 17:51:26 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.416 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
return newnode;
}
+static OptionDefElem *
+_copyOptionDefElem(OptionDefElem *from)
+{
+ OptionDefElem *newnode = makeNode(OptionDefElem);
+
+ COPY_SCALAR_FIELD(alter_op);
+ COPY_NODE_FIELD(def);
+
+ return newnode;
+}
+
static LockingClause *
_copyLockingClause(LockingClause *from)
{
return newnode;
}
+static CreateFdwStmt *
+_copyCreateFdwStmt(CreateFdwStmt *from)
+{
+ CreateFdwStmt *newnode = makeNode(CreateFdwStmt);
+
+ COPY_STRING_FIELD(fdwname);
+ COPY_STRING_FIELD(library);
+ COPY_NODE_FIELD(options);
+
+ return newnode;
+}
+
+static AlterFdwStmt *
+_copyAlterFdwStmt(AlterFdwStmt *from)
+{
+ AlterFdwStmt *newnode = makeNode(AlterFdwStmt);
+
+ COPY_STRING_FIELD(fdwname);
+ COPY_STRING_FIELD(library);
+ COPY_NODE_FIELD(options);
+
+ return newnode;
+}
+
+static DropFdwStmt *
+_copyDropFdwStmt(DropFdwStmt *from)
+{
+ DropFdwStmt *newnode = makeNode(DropFdwStmt);
+
+ COPY_STRING_FIELD(fdwname);
+ COPY_SCALAR_FIELD(missing_ok);
+ COPY_SCALAR_FIELD(behavior);
+
+ return newnode;
+}
+
+static CreateForeignServerStmt *
+_copyCreateForeignServerStmt(CreateForeignServerStmt *from)
+{
+ CreateForeignServerStmt *newnode = makeNode(CreateForeignServerStmt);
+
+ COPY_STRING_FIELD(servername);
+ COPY_STRING_FIELD(servertype);
+ COPY_STRING_FIELD(version);
+ COPY_STRING_FIELD(fdwname);
+ COPY_NODE_FIELD(options);
+
+ return newnode;
+}
+
+static AlterForeignServerStmt *
+_copyAlterForeignServerStmt(AlterForeignServerStmt *from)
+{
+ AlterForeignServerStmt *newnode = makeNode(AlterForeignServerStmt);
+
+ COPY_STRING_FIELD(servername);
+ COPY_STRING_FIELD(version);
+ COPY_NODE_FIELD(options);
+ COPY_SCALAR_FIELD(has_version);
+
+ return newnode;
+}
+
+static DropForeignServerStmt *
+_copyDropForeignServerStmt(DropForeignServerStmt *from)
+{
+ DropForeignServerStmt *newnode = makeNode(DropForeignServerStmt);
+
+ COPY_STRING_FIELD(servername);
+ COPY_SCALAR_FIELD(missing_ok);
+ COPY_SCALAR_FIELD(behavior);
+
+ return newnode;
+}
+
+static CreateUserMappingStmt *
+_copyCreateUserMappingStmt(CreateUserMappingStmt *from)
+{
+ CreateUserMappingStmt *newnode = makeNode(CreateUserMappingStmt);
+
+ COPY_STRING_FIELD(username);
+ COPY_STRING_FIELD(servername);
+ COPY_NODE_FIELD(options);
+
+ return newnode;
+}
+
+static AlterUserMappingStmt *
+_copyAlterUserMappingStmt(AlterUserMappingStmt *from)
+{
+ AlterUserMappingStmt *newnode = makeNode(AlterUserMappingStmt);
+
+ COPY_STRING_FIELD(username);
+ COPY_STRING_FIELD(servername);
+ COPY_NODE_FIELD(options);
+
+ return newnode;
+}
+
+static DropUserMappingStmt *
+_copyDropUserMappingStmt(DropUserMappingStmt *from)
+{
+ DropUserMappingStmt *newnode = makeNode(DropUserMappingStmt);
+
+ COPY_STRING_FIELD(username);
+ COPY_STRING_FIELD(servername);
+ COPY_SCALAR_FIELD(missing_ok);
+
+ return newnode;
+}
+
static CreateTrigStmt *
_copyCreateTrigStmt(CreateTrigStmt *from)
{
case T_DropTableSpaceStmt:
retval = _copyDropTableSpaceStmt(from);
break;
+ case T_CreateFdwStmt:
+ retval = _copyCreateFdwStmt(from);
+ break;
+ case T_AlterFdwStmt:
+ retval = _copyAlterFdwStmt(from);
+ break;
+ case T_DropFdwStmt:
+ retval = _copyDropFdwStmt(from);
+ break;
+ case T_CreateForeignServerStmt:
+ retval = _copyCreateForeignServerStmt(from);
+ break;
+ case T_AlterForeignServerStmt:
+ retval = _copyAlterForeignServerStmt(from);
+ break;
+ case T_DropForeignServerStmt:
+ retval = _copyDropForeignServerStmt(from);
+ break;
+ case T_CreateUserMappingStmt:
+ retval = _copyCreateUserMappingStmt(from);
+ break;
+ case T_AlterUserMappingStmt:
+ retval = _copyAlterUserMappingStmt(from);
+ break;
+ case T_DropUserMappingStmt:
+ retval = _copyDropUserMappingStmt(from);
+ break;
case T_CreateTrigStmt:
retval = _copyCreateTrigStmt(from);
break;
case T_DefElem:
retval = _copyDefElem(from);
break;
+ case T_OptionDefElem:
+ retval = _copyOptionDefElem(from);
+ break;
case T_LockingClause:
retval = _copyLockingClause(from);
break;
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.340 2008/12/04 17:51:26 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.341 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
return true;
}
+static bool
+_equalCreateFdwStmt(CreateFdwStmt *a, CreateFdwStmt *b)
+{
+ COMPARE_STRING_FIELD(fdwname);
+ COMPARE_STRING_FIELD(library);
+ COMPARE_NODE_FIELD(options);
+
+ return true;
+}
+
+static bool
+_equalAlterFdwStmt(AlterFdwStmt *a, AlterFdwStmt *b)
+{
+ COMPARE_STRING_FIELD(fdwname);
+ COMPARE_STRING_FIELD(library);
+ COMPARE_NODE_FIELD(options);
+
+ return true;
+}
+
+static bool
+_equalDropFdwStmt(DropFdwStmt *a, DropFdwStmt *b)
+{
+ COMPARE_STRING_FIELD(fdwname);
+ COMPARE_SCALAR_FIELD(missing_ok);
+ COMPARE_SCALAR_FIELD(behavior);
+
+ return true;
+}
+
+static bool
+_equalCreateForeignServerStmt(CreateForeignServerStmt *a, CreateForeignServerStmt *b)
+{
+ COMPARE_STRING_FIELD(servername);
+ COMPARE_STRING_FIELD(servertype);
+ COMPARE_STRING_FIELD(version);
+ COMPARE_STRING_FIELD(fdwname);
+ COMPARE_NODE_FIELD(options);
+
+ return true;
+}
+
+static bool
+_equalAlterForeignServerStmt(AlterForeignServerStmt *a, AlterForeignServerStmt *b)
+{
+ COMPARE_STRING_FIELD(servername);
+ COMPARE_STRING_FIELD(version);
+ COMPARE_NODE_FIELD(options);
+ COMPARE_SCALAR_FIELD(has_version);
+
+ return true;
+}
+
+static bool
+_equalDropForeignServerStmt(DropForeignServerStmt *a, DropForeignServerStmt *b)
+{
+ COMPARE_STRING_FIELD(servername);
+ COMPARE_SCALAR_FIELD(missing_ok);
+ COMPARE_SCALAR_FIELD(behavior);
+
+ return true;
+}
+
+static bool
+_equalCreateUserMappingStmt(CreateUserMappingStmt *a, CreateUserMappingStmt *b)
+{
+ COMPARE_STRING_FIELD(username);
+ COMPARE_STRING_FIELD(servername);
+ COMPARE_NODE_FIELD(options);
+
+ return true;
+}
+
+static bool
+_equalAlterUserMappingStmt(AlterUserMappingStmt *a, AlterUserMappingStmt *b)
+{
+ COMPARE_STRING_FIELD(username);
+ COMPARE_STRING_FIELD(servername);
+ COMPARE_NODE_FIELD(options);
+
+ return true;
+}
+
+static bool
+_equalDropUserMappingStmt(DropUserMappingStmt *a, DropUserMappingStmt *b)
+{
+ COMPARE_STRING_FIELD(username);
+ COMPARE_STRING_FIELD(servername);
+ COMPARE_SCALAR_FIELD(missing_ok);
+
+ return true;
+}
+
static bool
_equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b)
{
return true;
}
+static bool
+_equalOptionDefElem(OptionDefElem *a, OptionDefElem *b)
+{
+ COMPARE_SCALAR_FIELD(alter_op);
+ COMPARE_NODE_FIELD(def);
+
+ return true;
+}
+
static bool
_equalLockingClause(LockingClause *a, LockingClause *b)
{
case T_DropTableSpaceStmt:
retval = _equalDropTableSpaceStmt(a, b);
break;
+ case T_CreateFdwStmt:
+ retval = _equalCreateFdwStmt(a, b);
+ break;
+ case T_AlterFdwStmt:
+ retval = _equalAlterFdwStmt(a, b);
+ break;
+ case T_DropFdwStmt:
+ retval = _equalDropFdwStmt(a, b);
+ break;
+ case T_CreateForeignServerStmt:
+ retval = _equalCreateForeignServerStmt(a, b);
+ break;
+ case T_AlterForeignServerStmt:
+ retval = _equalAlterForeignServerStmt(a, b);
+ break;
+ case T_DropForeignServerStmt:
+ retval = _equalDropForeignServerStmt(a, b);
+ break;
+ case T_CreateUserMappingStmt:
+ retval = _equalCreateUserMappingStmt(a, b);
+ break;
+ case T_AlterUserMappingStmt:
+ retval = _equalAlterUserMappingStmt(a, b);
+ break;
+ case T_DropUserMappingStmt:
+ retval = _equalDropUserMappingStmt(a, b);
+ break;
case T_CreateTrigStmt:
retval = _equalCreateTrigStmt(a, b);
break;
case T_DefElem:
retval = _equalDefElem(a, b);
break;
+ case T_OptionDefElem:
+ retval = _equalOptionDefElem(a, b);
+ break;
case T_LockingClause:
retval = _equalLockingClause(a, b);
break;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.60 2008/09/01 20:42:44 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/nodes/makefuncs.c,v 1.61 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
res->arg = arg;
return res;
}
+
+/*
+ * makeOptionDefElem -
+ * build an OptionDefElem node
+ */
+OptionDefElem *
+makeOptionDefElem(int op, DefElem *def)
+{
+ OptionDefElem *res = makeNode(OptionDefElem);
+ res->alter_op = op;
+ res->def = def;
+ return res;
+}
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.645 2008/12/18 18:20:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.646 2008/12/19 16:25:17 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
FunctionParameterMode fun_param_mode;
FuncWithArgs *funwithargs;
DefElem *defelt;
+ OptionDefElem *optdef;
SortBy *sortby;
JoinExpr *jexpr;
IndexElem *ielem;
}
%type <node> stmt schema_stmt
- AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterGroupStmt
+ AlterDatabaseStmt AlterDatabaseSetStmt AlterDomainStmt AlterFdwStmt
+ AlterForeignServerStmt AlterGroupStmt
AlterObjectSchemaStmt AlterOwnerStmt AlterSeqStmt AlterTableStmt
- AlterUserStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
+ AlterUserStmt AlterUserMappingStmt AlterUserSetStmt AlterRoleStmt AlterRoleSetStmt
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
CreateDomainStmt CreateGroupStmt CreateOpClassStmt
CreateOpFamilyStmt AlterOpFamilyStmt CreatePLangStmt
CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
- CreateAssertStmt CreateTrigStmt CreateUserStmt CreateRoleStmt
+ CreateFdwStmt CreateForeignServerStmt CreateAssertStmt CreateTrigStmt
+ CreateUserStmt CreateUserMappingStmt CreateRoleStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt DiscardStmt
DropGroupStmt DropOpClassStmt DropOpFamilyStmt DropPLangStmt DropStmt
DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropRoleStmt
- DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt
+ DropUserStmt DropdbStmt DropTableSpaceStmt DropFdwStmt
+ DropForeignServerStmt DropUserMappingStmt ExplainStmt FetchStmt
GrantStmt GrantRoleStmt IndexStmt InsertStmt ListenStmt LoadStmt
LockStmt NotifyStmt ExplainableStmt PreparableStmt
CreateFunctionStmt AlterFunctionStmt ReindexStmt RemoveAggrStmt
%type <list> OptRoleList
%type <defelt> OptRoleElem
+%type <str> opt_type
+%type <str> foreign_server_version opt_foreign_server_version
+%type <str> auth_ident
+
%type <str> OptSchemaName
%type <list> OptSchemaEltList
prep_type_clause
execute_param_clause using_clause returning_clause
enum_val_list table_func_column_list
+ create_generic_options alter_generic_options
%type <range> OptTempTableName
%type <into> into_clause create_as_target
%type <range> relation_expr_opt_alias
%type <target> target_el single_set_clause set_target insert_column_item
+%type <str> generic_option_name
+%type <node> generic_option_arg
+%type <defelt> generic_option_elem
+%type <optdef> alter_generic_option_elem
+%type <list> generic_option_list alter_generic_option_list
+
%type <typnam> Typename SimpleTypename ConstTypename
GenericType Numeric opt_float
Character ConstCharacter
KEY
LANCOMPILER LANGUAGE LARGE_P LAST_P LEADING LEAST LEFT LEVEL
- LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
+ LIBRARY LIKE LIMIT LISTEN LOAD LOCAL LOCALTIME LOCALTIMESTAMP LOCATION
LOCK_P LOGIN_P
MAPPING MATCH MAXVALUE MINUTE_P MINVALUE MODE MONTH_P MOVE
NOCREATEROLE NOCREATEUSER NOINHERIT NOLOGIN_P NONE NOSUPERUSER
NOT NOTHING NOTIFY NOTNULL NOWAIT NULL_P NULLIF NULLS_P NUMERIC
- OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OR
+ OBJECT_P OF OFF OFFSET OIDS OLD ON ONLY OPERATOR OPTION OPTIONS OR
ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNED OWNER
PARSER PARTIAL PASSWORD PLACING PLANS POSITION
REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
SAVEPOINT SCHEMA SCROLL SEARCH SECOND_P SECURITY SELECT SEQUENCE
- SERIALIZABLE SESSION SESSION_USER SET SETOF SHARE
+ SERIALIZABLE SERVER SESSION SESSION_USER SET SETOF SHARE
SHOW SIMILAR SIMPLE SMALLINT SOME STABLE STANDALONE_P START STATEMENT
STATISTICS STDIN STDOUT STORAGE STRICT_P STRIP_P SUBSTRING SUPERUSER_P
SYMMETRIC SYSID SYSTEM_P
VACUUM VALID VALIDATOR VALUE_P VALUES VARCHAR VARIADIC VARYING
VERBOSE VERSION_P VIEW VOLATILE
- WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRITE
+ WHEN WHERE WHITESPACE_P WITH WITHOUT WORK WRAPPER WRITE
XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
XMLPI XMLROOT XMLSERIALIZE
AlterDatabaseStmt
| AlterDatabaseSetStmt
| AlterDomainStmt
+ | AlterFdwStmt
+ | AlterForeignServerStmt
| AlterFunctionStmt
| AlterGroupStmt
| AlterObjectSchemaStmt
| AlterRoleStmt
| AlterTSConfigurationStmt
| AlterTSDictionaryStmt
+ | AlterUserMappingStmt
| AlterUserSetStmt
| AlterUserStmt
| AnalyzeStmt
| CreateCastStmt
| CreateConversionStmt
| CreateDomainStmt
+ | CreateFdwStmt
+ | CreateForeignServerStmt
| CreateFunctionStmt
| CreateGroupStmt
| CreateOpClassStmt
| CreateTrigStmt
| CreateRoleStmt
| CreateUserStmt
+ | CreateUserMappingStmt
| CreatedbStmt
| DeallocateStmt
| DeclareCursorStmt
| DiscardStmt
| DropAssertStmt
| DropCastStmt
+ | DropFdwStmt
+ | DropForeignServerStmt
| DropGroupStmt
| DropOpClassStmt
| DropOpFamilyStmt
| DropTrigStmt
| DropRoleStmt
| DropUserStmt
+ | DropUserMappingStmt
| DropdbStmt
| ExecuteStmt
| ExplainStmt
}
;
+/*****************************************************************************
+ *
+ * QUERY:
+ * CREATE FOREIGN DATA WRAPPER name LIBRARY 'library_name' LANGUAGE C
+ *
+ *****************************************************************************/
+
+CreateFdwStmt: CREATE FOREIGN DATA_P WRAPPER name LIBRARY Sconst LANGUAGE ColId create_generic_options
+ {
+ CreateFdwStmt *n = makeNode(CreateFdwStmt);
+ n->fdwname = $5;
+ n->library = $7;
+ n->options = $10;
+ $$ = (Node *) n;
+
+ if (pg_strcasecmp($9, "C") != 0)
+ ereport(ERROR,
+ (errcode(ERRCODE_SYNTAX_ERROR),
+ errmsg("language for foreign-data wrapper must be C"),
+ scanner_errposition(@9)));
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * DROP FOREIGN DATA WRAPPER name
+ *
+ ****************************************************************************/
+
+DropFdwStmt: DROP FOREIGN DATA_P WRAPPER name opt_drop_behavior
+ {
+ DropFdwStmt *n = makeNode(DropFdwStmt);
+ n->fdwname = $5;
+ n->missing_ok = false;
+ n->behavior = $6;
+ $$ = (Node *) n;
+ }
+ | DROP FOREIGN DATA_P WRAPPER IF_P EXISTS name opt_drop_behavior
+ {
+ DropFdwStmt *n = makeNode(DropFdwStmt);
+ n->fdwname = $7;
+ n->missing_ok = true;
+ n->behavior = $8;
+ $$ = (Node *) n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * ALTER FOREIGN DATA WRAPPER name
+ *
+ ****************************************************************************/
+
+AlterFdwStmt: ALTER FOREIGN DATA_P WRAPPER name LIBRARY Sconst alter_generic_options
+ {
+ AlterFdwStmt *n = makeNode(AlterFdwStmt);
+ n->fdwname = $5;
+ n->library = $7;
+ n->options = $8;
+ $$ = (Node *) n;
+ }
+ | ALTER FOREIGN DATA_P WRAPPER name LIBRARY Sconst
+ {
+ AlterFdwStmt *n = makeNode(AlterFdwStmt);
+ n->fdwname = $5;
+ n->library = $7;
+ $$ = (Node *) n;
+ }
+ | ALTER FOREIGN DATA_P WRAPPER name alter_generic_options
+ {
+ AlterFdwStmt *n = makeNode(AlterFdwStmt);
+ n->fdwname = $5;
+ n->options = $6;
+ $$ = (Node *) n;
+ }
+ ;
+
+/* Options definition for CREATE FDW, SERVER and USER MAPPING */
+create_generic_options:
+ OPTIONS '(' generic_option_list ')' { $$ = $3; }
+ | /*EMPTY*/ { $$ = NIL; }
+ ;
+
+generic_option_list: generic_option_elem
+ {
+ $$ = list_make1(makeOptionDefElem(ALTER_OPT_ADD, $1));
+ }
+ | generic_option_list ',' generic_option_elem
+ {
+ $$ = lappend($1, makeOptionDefElem(ALTER_OPT_ADD, $3));
+ }
+ ;
+
+/* Options definition for ALTER FDW, SERVER and USER MAPPING */
+alter_generic_options:
+ OPTIONS '(' alter_generic_option_list ')' { $$ = $3; }
+ ;
+
+alter_generic_option_list:
+ alter_generic_option_elem
+ {
+ $$ = list_make1($1);
+ }
+ | generic_option_elem
+ {
+ $$ = list_make1(makeOptionDefElem(ALTER_OPT_ADD, $1));
+ }
+ | alter_generic_option_list ',' alter_generic_option_elem
+ {
+ $$ = lappend($1, $3);
+ }
+ | alter_generic_option_list ',' generic_option_elem
+ {
+ $$ = lappend($1, makeOptionDefElem(ALTER_OPT_ADD, $3));
+ }
+ ;
+
+alter_generic_option_elem:
+ ADD_P generic_option_elem
+ {
+ $$ = makeOptionDefElem(ALTER_OPT_ADD, $2);
+ }
+ | SET generic_option_elem
+ {
+ $$ = makeOptionDefElem(ALTER_OPT_SET, $2);
+ }
+ | DROP generic_option_name
+ {
+ $$ = makeOptionDefElem(ALTER_OPT_DROP,
+ makeDefElem($2, NULL));
+ }
+ ;
+
+generic_option_elem:
+ generic_option_name generic_option_arg { $$ = makeDefElem($1, $2); }
+ ;
+
+generic_option_name:
+ attr_name { $$ = $1; }
+ ;
+
+generic_option_arg:
+ Sconst { $$ = (Node *)makeString($1); }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * CREATE SERVER name [TYPE] [VERSION] [OPTIONS]
+ *
+ *****************************************************************************/
+
+CreateForeignServerStmt: CREATE SERVER name opt_type opt_foreign_server_version
+ FOREIGN DATA_P WRAPPER name create_generic_options
+ {
+ CreateForeignServerStmt *n = makeNode(CreateForeignServerStmt);
+ n->servername = $3;
+ n->servertype = $4;
+ n->version = $5;
+ n->fdwname = $9;
+ n->options = $10;
+ $$ = (Node *) n;
+ }
+ ;
+
+opt_type:
+ TYPE_P Sconst { $$ = $2; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+
+foreign_server_version:
+ VERSION_P Sconst { $$ = $2; }
+ | VERSION_P NULL_P { $$ = NULL; }
+ ;
+
+opt_foreign_server_version:
+ foreign_server_version { $$ = $1; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * DROP SERVER name
+ *
+ ****************************************************************************/
+
+DropForeignServerStmt: DROP SERVER name opt_drop_behavior
+ {
+ DropForeignServerStmt *n = makeNode(DropForeignServerStmt);
+ n->servername = $3;
+ n->missing_ok = false;
+ n->behavior = $4;
+ $$ = (Node *) n;
+ }
+ | DROP SERVER IF_P EXISTS name opt_drop_behavior
+ {
+ DropForeignServerStmt *n = makeNode(DropForeignServerStmt);
+ n->servername = $5;
+ n->missing_ok = true;
+ n->behavior = $6;
+ $$ = (Node *) n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * ALTER SERVER name [VERSION] [OPTIONS]
+ *
+ ****************************************************************************/
+
+AlterForeignServerStmt: ALTER SERVER name foreign_server_version alter_generic_options
+ {
+ AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt);
+ n->servername = $3;
+ n->version = $4;
+ n->options = $5;
+ n->has_version = true;
+ $$ = (Node *) n;
+ }
+ | ALTER SERVER name foreign_server_version
+ {
+ AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt);
+ n->servername = $3;
+ n->version = $4;
+ n->has_version = true;
+ $$ = (Node *) n;
+ }
+ | ALTER SERVER name alter_generic_options
+ {
+ AlterForeignServerStmt *n = makeNode(AlterForeignServerStmt);
+ n->servername = $3;
+ n->options = $4;
+ $$ = (Node *) n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY:
+ * CREATE USER MAPPING FOR auth_ident SERVER name [OPTIONS]
+ *
+ *****************************************************************************/
+
+CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options
+ {
+ CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt);
+ n->username = $5;
+ n->servername = $7;
+ n->options = $8;
+ $$ = (Node *) n;
+ }
+ ;
+
+/* User mapping authorization identifier */
+auth_ident:
+ CURRENT_USER { $$ = "current_user"; }
+ | USER { $$ = "current_user"; }
+ | RoleId { $$ = (strcmp($1, "public") == 0) ? NULL : $1 }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * DROP USER MAPPING FOR auth_ident SERVER name
+ *
+ ****************************************************************************/
+
+DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
+ {
+ DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
+ n->username = $5;
+ n->servername = $7;
+ n->missing_ok = false;
+ $$ = (Node *) n;
+ }
+ | DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name
+ {
+ DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
+ n->username = $7;
+ n->servername = $9;
+ n->missing_ok = true;
+ $$ = (Node *) n;
+ }
+ ;
+
+/*****************************************************************************
+ *
+ * QUERY :
+ * ALTER USER MAPPING FOR auth_ident SERVER name OPTIONS
+ *
+ ****************************************************************************/
+
+AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options
+ {
+ AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt);
+ n->username = $5;
+ n->servername = $7;
+ n->options = $8;
+ $$ = (Node *) n;
+ }
+ ;
+
/*****************************************************************************
*
* QUERIES :
n->objs = $2;
$$ = n;
}
+ | FOREIGN DATA_P WRAPPER name_list
+ {
+ PrivTarget *n = makeNode(PrivTarget);
+ n->objtype = ACL_OBJECT_FDW;
+ n->objs = $4;
+ $$ = n;
+ }
+ | FOREIGN SERVER name_list
+ {
+ PrivTarget *n = makeNode(PrivTarget);
+ n->objtype = ACL_OBJECT_FOREIGN_SERVER;
+ n->objs = $3;
+ $$ = n;
+ }
| FUNCTION function_with_argtypes_list
{
PrivTarget *n = makeNode(PrivTarget);
n->newowner = $8;
$$ = (Node *)n;
}
+ | ALTER FOREIGN DATA_P WRAPPER name OWNER TO RoleId
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_FDW;
+ n->object = list_make1(makeString($5));
+ n->newowner = $8;
+ $$ = (Node *)n;
+ }
+ | ALTER SERVER name OWNER TO RoleId
+ {
+ AlterOwnerStmt *n = makeNode(AlterOwnerStmt);
+ n->objectType = OBJECT_FOREIGN_SERVER;
+ n->object = list_make1(makeString($3));
+ n->newowner = $6;
+ $$ = (Node *)n;
+ }
;
| INVOKER
| ISOLATION
| KEY
+ | LIBRARY
| LANCOMPILER
| LANGUAGE
| LARGE_P
| OIDS
| OPERATOR
| OPTION
+ | OPTIONS
| OWNED
| OWNER
| PARSER
| ROWS
| RULE
| SAVEPOINT
+ | SERVER
| SCHEMA
| SCROLL
| SEARCH
| WHITESPACE_P
| WITHOUT
| WORK
+ | WRAPPER
| WRITE
| XML_P
| YEAR_P
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.205 2008/10/27 09:37:47 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.206 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
{"least", LEAST, COL_NAME_KEYWORD},
{"left", LEFT, TYPE_FUNC_NAME_KEYWORD},
{"level", LEVEL, UNRESERVED_KEYWORD},
+ {"library", LIBRARY, UNRESERVED_KEYWORD},
{"like", LIKE, TYPE_FUNC_NAME_KEYWORD},
{"limit", LIMIT, RESERVED_KEYWORD},
{"listen", LISTEN, UNRESERVED_KEYWORD},
{"only", ONLY, RESERVED_KEYWORD},
{"operator", OPERATOR, UNRESERVED_KEYWORD},
{"option", OPTION, UNRESERVED_KEYWORD},
+ {"options", OPTIONS, UNRESERVED_KEYWORD},
{"or", OR, RESERVED_KEYWORD},
{"order", ORDER, RESERVED_KEYWORD},
{"out", OUT_P, COL_NAME_KEYWORD},
{"select", SELECT, RESERVED_KEYWORD},
{"sequence", SEQUENCE, UNRESERVED_KEYWORD},
{"serializable", SERIALIZABLE, UNRESERVED_KEYWORD},
+ {"server", SERVER, UNRESERVED_KEYWORD},
{"session", SESSION, UNRESERVED_KEYWORD},
{"session_user", SESSION_USER, RESERVED_KEYWORD},
{"set", SET, UNRESERVED_KEYWORD},
{"with", WITH, RESERVED_KEYWORD},
{"without", WITHOUT, UNRESERVED_KEYWORD},
{"work", WORK, UNRESERVED_KEYWORD},
+ {"wrapper", WRAPPER, UNRESERVED_KEYWORD},
{"write", WRITE, UNRESERVED_KEYWORD},
{"xml", XML_P, UNRESERVED_KEYWORD},
{"xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD},
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.302 2008/12/04 17:51:26 petere Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.303 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
case T_ReassignOwnedStmt:
case T_AlterTSDictionaryStmt:
case T_AlterTSConfigurationStmt:
+ case T_CreateFdwStmt:
+ case T_AlterFdwStmt:
+ case T_DropFdwStmt:
+ case T_CreateForeignServerStmt:
+ case T_AlterForeignServerStmt:
+ case T_DropForeignServerStmt:
+ case T_CreateUserMappingStmt:
+ case T_AlterUserMappingStmt:
+ case T_DropUserMappingStmt:
ereport(ERROR,
(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
errmsg("transaction is read-only")));
DropTableSpace((DropTableSpaceStmt *) parsetree);
break;
+ case T_CreateFdwStmt:
+ CreateForeignDataWrapper((CreateFdwStmt *) parsetree);
+ break;
+
+ case T_AlterFdwStmt:
+ AlterForeignDataWrapper((AlterFdwStmt *) parsetree);
+ break;
+
+ case T_DropFdwStmt:
+ RemoveForeignDataWrapper((DropFdwStmt *) parsetree);
+ break;
+
+ case T_CreateForeignServerStmt:
+ CreateForeignServer((CreateForeignServerStmt *) parsetree);
+ break;
+
+ case T_AlterForeignServerStmt:
+ AlterForeignServer((AlterForeignServerStmt *) parsetree);
+ break;
+
+ case T_DropForeignServerStmt:
+ RemoveForeignServer((DropForeignServerStmt *) parsetree);
+ break;
+
+ case T_CreateUserMappingStmt:
+ CreateUserMapping((CreateUserMappingStmt *) parsetree);
+ break;
+
+ case T_AlterUserMappingStmt:
+ AlterUserMapping((AlterUserMappingStmt *) parsetree);
+ break;
+
+ case T_DropUserMappingStmt:
+ RemoveUserMapping((DropUserMappingStmt *) parsetree);
+ break;
+
case T_DropStmt:
{
DropStmt *stmt = (DropStmt *) parsetree;
tag = "DROP TABLESPACE";
break;
+ case T_CreateFdwStmt:
+ tag = "CREATE FOREIGN DATA WRAPPER";
+ break;
+
+ case T_AlterFdwStmt:
+ tag = "ALTER FOREIGN DATA WRAPPER";
+ break;
+
+ case T_DropFdwStmt:
+ tag = "DROP FOREIGN DATA WRAPPER";
+ break;
+
+ case T_CreateForeignServerStmt:
+ tag = "CREATE SERVER";
+ break;
+
+ case T_AlterForeignServerStmt:
+ tag = "ALTER SERVER";
+ break;
+
+ case T_DropForeignServerStmt:
+ tag = "DROP SERVER";
+ break;
+
+ case T_CreateUserMappingStmt:
+ tag = "CREATE USER MAPPING";
+ break;
+
+ case T_AlterUserMappingStmt:
+ tag = "ALTER USER MAPPING";
+ break;
+
+ case T_DropUserMappingStmt:
+ tag = "DROP USER MAPPING";
+ break;
+
case T_DropStmt:
switch (((DropStmt *) parsetree)->removeType)
{
case OBJECT_TSDICTIONARY:
tag = "ALTER TEXT SEARCH DICTIONARY";
break;
+ case OBJECT_FDW:
+ tag = "ALTER FOREIGN DATA WRAPPER";
+ break;
+ case OBJECT_FOREIGN_SERVER:
+ tag = "ALTER SERVER";
+ break;
default:
tag = "???";
break;
lev = LOGSTMT_DDL;
break;
+ case T_CreateFdwStmt:
+ case T_AlterFdwStmt:
+ case T_DropFdwStmt:
+ case T_CreateForeignServerStmt:
+ case T_AlterForeignServerStmt:
+ case T_DropForeignServerStmt:
+ case T_CreateUserMappingStmt:
+ case T_AlterUserMappingStmt:
+ case T_DropUserMappingStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_DropStmt:
lev = LOGSTMT_DDL;
break;
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.143 2008/12/15 18:09:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.144 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "commands/tablespace.h"
+#include "foreign/foreign.h"
#include "miscadmin.h"
#include "utils/acl.h"
#include "utils/builtins.h"
world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_TABLESPACE;
break;
+ case ACL_OBJECT_FDW:
+ world_default = ACL_NO_RIGHTS;
+ owner_default = ACL_ALL_RIGHTS_FDW;
+ break;
+ case ACL_OBJECT_FOREIGN_SERVER:
+ world_default = ACL_NO_RIGHTS;
+ owner_default = ACL_ALL_RIGHTS_FOREIGN_SERVER;
+ break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
}
+/*
+ * has_foreign_data_wrapper_privilege variants
+ * These are all named "has_foreign_data_wrapper_privilege" at the SQL level.
+ * They take various combinations of foreign-data wrapper name,
+ * fdw OID, user name, user OID, or implicit user = current_user.
+ *
+ * The result is a boolean value: true if user has the indicated
+ * privilege, false if not. The variants that take an OID return
+ * NULL if the OID doesn't exist.
+ */
+
+/*
+ * has_foreign_data_wrapper_privilege
+ * Check user privileges on a foreign-data wrapper.
+ */
+static Datum
+has_foreign_data_wrapper_privilege(Oid roleid, Oid fdwid, text *priv_type_text)
+{
+ AclResult aclresult;
+ AclMode mode = ACL_NO_RIGHTS;
+ char *priv_type = text_to_cstring(priv_type_text);
+
+ if (pg_strcasecmp(priv_type, "USAGE") == 0)
+ mode = ACL_USAGE;
+ else if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
+ mode = ACL_GRANT_OPTION_FOR(ACL_USAGE);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized privilege type: \"%s\"", priv_type)));
+
+ aclresult = pg_foreign_data_wrapper_aclcheck(fdwid, roleid, mode);
+
+ PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_foreign_data_wrapper_privilege_name_name
+ * Check user privileges on a foreign-data wrapper given
+ * name username, text fdwname, and text priv name.
+ */
+Datum
+has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS)
+{
+ Name username = PG_GETARG_NAME(0);
+ char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(1));
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+
+ return has_foreign_data_wrapper_privilege(get_roleid_checked(NameStr(*username)),
+ GetForeignDataWrapperOidByName(fdwname, false),
+ priv_type_text);
+}
+
+/*
+ * has_foreign_data_wrapper_privilege_name
+ * Check user privileges on a foreign-data wrapper given
+ * text fdwname and text priv name.
+ * current_user is assumed
+ */
+Datum
+has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS)
+{
+ char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(0));
+ text *priv_type_text = PG_GETARG_TEXT_P(1);
+
+ return has_foreign_data_wrapper_privilege(GetUserId(),
+ GetForeignDataWrapperOidByName(fdwname, false),
+ priv_type_text);
+}
+
+/*
+ * has_foreign_data_wrapper_privilege_name_id
+ * Check user privileges on a foreign-data wrapper given
+ * name usename, foreign-data wrapper oid, and text priv name.
+ */
+Datum
+has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
+{
+ Name username = PG_GETARG_NAME(0);
+ Oid fdwid = PG_GETARG_OID(1);
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+
+ if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(fdwid),
+ 0, 0, 0))
+ PG_RETURN_NULL();
+
+ return has_foreign_data_wrapper_privilege(get_roleid_checked(NameStr(*username)),
+ fdwid, priv_type_text);
+}
+
+/*
+ * has_foreign_data_wrapper_privilege_id
+ * Check user privileges on a foreign-data wrapper given
+ * foreign-data wrapper oid, and text priv name.
+ * current_user is assumed
+ */
+Datum
+has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
+{
+ Oid fdwid = PG_GETARG_OID(0);
+ text *priv_type_text = PG_GETARG_TEXT_P(1);
+
+ if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(fdwid),
+ 0, 0, 0))
+ PG_RETURN_NULL();
+
+ return has_foreign_data_wrapper_privilege(GetUserId(), fdwid,
+ priv_type_text);
+}
+
+/*
+ * has_foreign_data_wrapper_privilege_id_name
+ * Check user privileges on a foreign-data wrapper given
+ * roleid, text fdwname, and text priv name.
+ */
+Datum
+has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS)
+{
+ Oid roleid = PG_GETARG_OID(0);
+ char *fdwname = text_to_cstring(PG_GETARG_TEXT_P(1));
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+
+ return has_foreign_data_wrapper_privilege(roleid,
+ GetForeignDataWrapperOidByName(fdwname, false),
+ priv_type_text);
+}
+
+/*
+ * has_foreign_data_wrapper_privilege_id_id
+ * Check user privileges on a foreign-data wrapper given
+ * roleid, fdw oid, and text priv name.
+ */
+Datum
+has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
+{
+ Oid roleid = PG_GETARG_OID(0);
+ Oid fdwid = PG_GETARG_OID(1);
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+
+ if (!SearchSysCacheExists(FOREIGNDATAWRAPPEROID,
+ ObjectIdGetDatum(fdwid),
+ 0, 0, 0))
+ PG_RETURN_NULL();
+
+ return has_foreign_data_wrapper_privilege(roleid, fdwid, priv_type_text);
+}
+
+
/*
* has_function_privilege variants
* These are all named "has_function_privilege" at the SQL level.
return ACL_NO_RIGHTS; /* keep compiler quiet */
}
+/*
+ * has_server_privilege variants
+ * These are all named "has_server_privilege" at the SQL level.
+ * They take various combinations of foreign server name,
+ * server OID, user name, user OID, or implicit user = current_user.
+ *
+ * The result is a boolean value: true if user has the indicated
+ * privilege, false if not.
+ */
+
+/*
+ * has_server_privilege
+ * Check user privileges on a foreign server.
+ */
+static Datum
+has_server_privilege(Oid roleid, Oid serverid, text *priv_type_text)
+{
+ AclResult aclresult;
+ AclMode mode = ACL_NO_RIGHTS;
+ char *priv_type = text_to_cstring(priv_type_text);
+
+ if (pg_strcasecmp(priv_type, "USAGE") == 0)
+ mode = ACL_USAGE;
+ else if (pg_strcasecmp(priv_type, "USAGE WITH GRANT OPTION") == 0)
+ mode = ACL_GRANT_OPTION_FOR(ACL_USAGE);
+ else
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ errmsg("unrecognized privilege type: \"%s\"", priv_type)));
+
+ aclresult = pg_foreign_server_aclcheck(serverid, roleid, mode);
+
+ PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
+}
+
+/*
+ * has_server_privilege_name_name
+ * Check user privileges on a foreign server given
+ * name username, text servername, and text priv name.
+ */
+Datum
+has_server_privilege_name_name(PG_FUNCTION_ARGS)
+{
+ Name username = PG_GETARG_NAME(0);
+ char *servername = text_to_cstring(PG_GETARG_TEXT_P(1));
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+
+ return has_server_privilege(get_roleid_checked(NameStr(*username)),
+ GetForeignServerOidByName(servername, false),
+ priv_type_text);
+}
+
+/*
+ * has_server_privilege_name
+ * Check user privileges on a foreign server given
+ * text servername and text priv name.
+ * current_user is assumed
+ */
+Datum
+has_server_privilege_name(PG_FUNCTION_ARGS)
+{
+ char *servername = text_to_cstring(PG_GETARG_TEXT_P(0));
+ text *priv_type_text = PG_GETARG_TEXT_P(1);
+
+ return has_server_privilege(GetUserId(),
+ GetForeignServerOidByName(servername, false),
+ priv_type_text);
+}
+
+/*
+ * has_server_privilege_name_id
+ * Check user privileges on a foreign server given
+ * name usename, foreign server oid, and text priv name.
+ */
+Datum
+has_server_privilege_name_id(PG_FUNCTION_ARGS)
+{
+ Name username = PG_GETARG_NAME(0);
+ Oid serverid = PG_GETARG_OID(1);
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+
+ if (!SearchSysCacheExists(FOREIGNSERVEROID,
+ ObjectIdGetDatum(serverid),
+ 0, 0, 0))
+ PG_RETURN_NULL();
+
+ return has_server_privilege(get_roleid_checked(NameStr(*username)), serverid,
+ priv_type_text);
+}
+
+/*
+ * has_server_privilege_id
+ * Check user privileges on a foreign server given
+ * server oid, and text priv name.
+ * current_user is assumed
+ */
+Datum
+has_server_privilege_id(PG_FUNCTION_ARGS)
+{
+ Oid serverid = PG_GETARG_OID(0);
+ text *priv_type_text = PG_GETARG_TEXT_P(1);
+
+ if (!SearchSysCacheExists(FOREIGNSERVEROID,
+ ObjectIdGetDatum(serverid),
+ 0, 0, 0))
+ PG_RETURN_NULL();
+
+ return has_server_privilege(GetUserId(), serverid, priv_type_text);
+}
+
+/*
+ * has_server_privilege_id_name
+ * Check user privileges on a foreign server given
+ * roleid, text servername, and text priv name.
+ */
+Datum
+has_server_privilege_id_name(PG_FUNCTION_ARGS)
+{
+ Oid roleid = PG_GETARG_OID(0);
+ char *servername = text_to_cstring(PG_GETARG_TEXT_P(1));
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+
+ return has_server_privilege(roleid,
+ GetForeignServerOidByName(servername, false),
+ priv_type_text);
+}
+
+/*
+ * has_server_privilege_id_id
+ * Check user privileges on a foreign server given
+ * roleid, server oid, and text priv name.
+ */
+Datum
+has_server_privilege_id_id(PG_FUNCTION_ARGS)
+{
+ Oid roleid = PG_GETARG_OID(0);
+ Oid serverid = PG_GETARG_OID(1);
+ text *priv_type_text = PG_GETARG_TEXT_P(2);
+
+ if (!SearchSysCacheExists(FOREIGNSERVEROID,
+ ObjectIdGetDatum(serverid),
+ 0, 0, 0))
+ PG_RETURN_NULL();
+
+ return has_server_privilege(roleid, serverid, priv_type_text);
+}
+
+
/*
* has_tablespace_privilege variants
* These are all named "has_tablespace_privilege" at the SQL level.
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.117 2008/06/19 00:46:05 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/cache/syscache.c,v 1.118 2008/12/19 16:25:17 petere Exp $
*
* NOTES
* These routines allow the parser/planner/executor to perform
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
#include "catalog/pg_enum.h"
+#include "catalog/pg_foreign_data_wrapper.h"
+#include "catalog/pg_foreign_server.h"
#include "catalog/pg_language.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_ts_parser.h"
#include "catalog/pg_ts_template.h"
#include "catalog/pg_type.h"
+#include "catalog/pg_user_mapping.h"
#include "utils/rel.h"
#include "utils/syscache.h"
},
256
},
+ {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPERNAME */
+ ForeignDataWrapperNameIndexId,
+ 0,
+ 1,
+ {
+ Anum_pg_foreign_data_wrapper_fdwname,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {ForeignDataWrapperRelationId, /* FOREIGNDATAWRAPPEROID */
+ ForeignDataWrapperOidIndexId,
+ 0,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 8
+ },
+ {ForeignServerRelationId, /* FOREIGNSERVERNAME */
+ ForeignServerNameIndexId,
+ 0,
+ 1,
+ {
+ Anum_pg_foreign_server_srvname,
+ 0,
+ 0,
+ 0
+ },
+ 32
+ },
+ {ForeignServerRelationId, /* FOREIGNSERVEROID */
+ ForeignServerOidIndexId,
+ 0,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 32
+ },
{IndexRelationId, /* INDEXRELID */
IndexRelidIndexId,
Anum_pg_index_indrelid,
0
},
1024
+ },
+ {UserMappingRelationId, /* USERMAPPINGOID */
+ UserMappingOidIndexId,
+ 0,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 128
+ },
+ {UserMappingRelationId, /* USERMAPPINGUSERSERVER */
+ UserMappingUserServerIndexId,
+ 0,
+ 2,
+ {
+ Anum_pg_user_mapping_umuser,
+ Anum_pg_user_mapping_umserver,
+ 0,
+ 0
+ },
+ 128
}
};
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.104 2008/05/09 23:32:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/common.c,v 1.105 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
TSTemplateInfo *tmplinfo;
TSDictInfo *dictinfo;
TSConfigInfo *cfginfo;
+ FdwInfo *fdwinfo;
+ ForeignServerInfo *srvinfo;
int numNamespaces;
int numAggregates;
int numInherits;
int numTSTemplates;
int numTSDicts;
int numTSConfigs;
+ int numForeignDataWrappers;
+ int numForeignServers;
if (g_verbose)
write_msg(NULL, "reading schemas\n");
write_msg(NULL, "reading user-defined text search configurations\n");
cfginfo = getTSConfigurations(&numTSConfigs);
+ if (g_verbose)
+ write_msg(NULL, "reading user-defined foreign-data wrappers\n");
+ fdwinfo = getForeignDataWrappers(&numForeignDataWrappers);
+
+ if (g_verbose)
+ write_msg(NULL, "reading user-defined foreign servers\n");
+ srvinfo = getForeignServers(&numForeignServers);
+
if (g_verbose)
write_msg(NULL, "reading user-defined operator families\n");
opfinfo = getOpfamilies(&numOpfamilies);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.41 2008/09/08 00:47:40 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.42 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
}
else if (strcmp(type, "TABLESPACE") == 0)
CONVERT_PRIV('C', "CREATE");
+ else if (strcmp(type, "FOREIGN DATA WRAPPER") == 0)
+ CONVERT_PRIV('U', "USAGE");
+ else if (strcmp(type, "SERVER") == 0)
+ CONVERT_PRIV('U', "USAGE");
else
abort();
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.158 2008/09/05 23:53:42 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.159 2008/12/19 16:25:17 petere Exp $
*
*-------------------------------------------------------------------------
*/
/* objects named by just a name */
if (strcmp(type, "DATABASE") == 0 ||
strcmp(type, "PROCEDURAL LANGUAGE") == 0 ||
- strcmp(type, "SCHEMA") == 0)
+ strcmp(type, "SCHEMA") == 0 ||
+ strcmp(type, "FOREIGN DATA WRAPPER") == 0 ||
+ strcmp(type, "SERVER") == 0 ||
+ strcmp(type, "USER MAPPING") == 0)
{
appendPQExpBuffer(buf, "%s %s", type, fmtId(te->tag));
return;
strcmp(te->desc, "VIEW") == 0 ||
strcmp(te->desc, "SEQUENCE") == 0 ||
strcmp(te->desc, "TEXT SEARCH DICTIONARY") == 0 ||
- strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0)
+ strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0 ||
+ strcmp(te->desc, "FOREIGN DATA WRAPPER") == 0 ||
+ strcmp(te->desc, "SERVER") == 0)
{
PQExpBuffer temp = createPQExpBuffer();
strcmp(te->desc, "FK CONSTRAINT") == 0 ||
strcmp(te->desc, "INDEX") == 0 ||
strcmp(te->desc, "RULE") == 0 ||
- strcmp(te->desc, "TRIGGER") == 0)
+ strcmp(te->desc, "TRIGGER") == 0 ||
+ strcmp(te->desc, "USER MAPPING") == 0)
{
/* these object types don't have separate owners */
}
* by PostgreSQL
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.508 2008/12/18 18:20:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.509 2008/12/19 16:25:18 petere Exp $
*
*-------------------------------------------------------------------------
*/
static void dumpTSDictionary(Archive *fout, TSDictInfo *dictinfo);
static void dumpTSTemplate(Archive *fout, TSTemplateInfo *tmplinfo);
static void dumpTSConfig(Archive *fout, TSConfigInfo *cfginfo);
+static void dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo);
+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 dumpACL(Archive *fout, CatalogId objCatId, DumpId objDumpId,
const char *type, const char *name,
return cfginfo;
}
+/*
+ * getForeignDataWrappers:
+ * read all foreign-data wrappers in the system catalogs and return
+ * them in the FdwInfo* structure
+ *
+ * numForeignDataWrappers is set to the number of fdws read in
+ */
+FdwInfo *
+getForeignDataWrappers(int *numForeignDataWrappers)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ FdwInfo *fdwinfo;
+ int i_oid;
+ int i_fdwname;
+ int i_rolname;
+ int i_fdwlibrary;
+ int i_fdwacl;
+ int i_fdwoptions;
+
+ /* Before 8.4, there are no foreign-data wrappers */
+ if (g_fout->remoteVersion < 80400)
+ {
+ *numForeignDataWrappers = 0;
+ return NULL;
+ }
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT oid, fdwname, "
+ "(%s fdwowner) as rolname, fdwlibrary, fdwacl,"
+ "array_to_string(ARRAY(select option_name || ' ' || quote_literal(option_value) from pg_options_to_table(fdwoptions)), ', ') AS fdwoptions "
+ "FROM pg_foreign_data_wrapper",
+ username_subquery);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numForeignDataWrappers = ntups;
+
+ fdwinfo = (FdwInfo *) malloc(ntups * sizeof(FdwInfo));
+
+ i_oid = PQfnumber(res, "oid");
+ i_fdwname = PQfnumber(res, "fdwname");
+ i_rolname = PQfnumber(res, "rolname");
+ i_fdwlibrary = PQfnumber(res, "fdwlibrary");
+ i_fdwacl = PQfnumber(res, "fdwacl");
+ i_fdwoptions = PQfnumber(res, "fdwoptions");
+
+ for (i = 0; i < ntups; i++)
+ {
+ fdwinfo[i].dobj.objType = DO_FDW;
+ fdwinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&fdwinfo[i].dobj);
+ fdwinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_fdwname));
+ fdwinfo[i].dobj.namespace = NULL;
+ fdwinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
+ fdwinfo[i].fdwlibrary = strdup(PQgetvalue(res, i, i_fdwlibrary));
+ fdwinfo[i].fdwoptions = strdup(PQgetvalue(res, i, i_fdwoptions));
+ fdwinfo[i].fdwacl = strdup(PQgetvalue(res, i, i_fdwacl));
+
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(fdwinfo[i].dobj));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return fdwinfo;
+}
+
+/*
+ * getForeignServers:
+ * read all foreign servers in the system catalogs and return
+ * them in the ForeignServerInfo * structure
+ *
+ * numForeignServers is set to the number of servers read in
+ */
+ForeignServerInfo *
+getForeignServers(int *numForeignServers)
+{
+ PGresult *res;
+ int ntups;
+ int i;
+ PQExpBuffer query = createPQExpBuffer();
+ ForeignServerInfo *srvinfo;
+ int i_oid;
+ int i_srvname;
+ int i_rolname;
+ int i_srvfdw;
+ int i_srvtype;
+ int i_srvversion;
+ int i_srvacl;
+ int i_srvoptions;
+
+ /* Before 8.4, there are no foreign servers */
+ if (g_fout->remoteVersion < 80400)
+ {
+ *numForeignServers = 0;
+ return NULL;
+ }
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema("pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT oid, srvname, "
+ "(%s srvowner) as rolname, "
+ "srvfdw, srvtype, srvversion, srvacl,"
+ "array_to_string(ARRAY(select option_name || ' ' || quote_literal(option_value) from pg_options_to_table(srvoptions)), ', ') as srvoptions "
+ "FROM pg_foreign_server",
+ username_subquery);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ *numForeignServers = ntups;
+
+ srvinfo = (ForeignServerInfo *) malloc(ntups * sizeof(ForeignServerInfo));
+
+ i_oid = PQfnumber(res, "oid");
+ i_srvname = PQfnumber(res, "srvname");
+ i_rolname = PQfnumber(res, "rolname");
+ i_srvfdw = PQfnumber(res, "srvfdw");
+ i_srvtype = PQfnumber(res, "srvtype");
+ i_srvversion = PQfnumber(res, "srvversion");
+ i_srvacl = PQfnumber(res, "srvacl");
+ i_srvoptions = PQfnumber(res, "srvoptions");
+
+ for (i = 0; i < ntups; i++)
+ {
+ srvinfo[i].dobj.objType = DO_FOREIGN_SERVER;
+ srvinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&srvinfo[i].dobj);
+ srvinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_srvname));
+ srvinfo[i].dobj.namespace = NULL;
+ srvinfo[i].rolname = strdup(PQgetvalue(res, i, i_rolname));
+ srvinfo[i].srvfdw = atooid(PQgetvalue(res, i, i_srvfdw));
+ srvinfo[i].srvtype = strdup(PQgetvalue(res, i, i_srvtype));
+ srvinfo[i].srvversion = strdup(PQgetvalue(res, i, i_srvversion));
+ srvinfo[i].srvoptions = strdup(PQgetvalue(res, i, i_srvoptions));
+ srvinfo[i].srvacl = strdup(PQgetvalue(res, i, i_srvacl));
+
+ /* Decide whether we want to dump it */
+ selectDumpableObject(&(srvinfo[i].dobj));
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+
+ return srvinfo;
+}
/*
* dumpComment --
case DO_TSCONFIG:
dumpTSConfig(fout, (TSConfigInfo *) dobj);
break;
+ case DO_FDW:
+ dumpForeignDataWrapper(fout, (FdwInfo *) dobj);
+ break;
+ case DO_FOREIGN_SERVER:
+ dumpForeignServer(fout, (ForeignServerInfo *) dobj);
+ break;
case DO_BLOBS:
ArchiveEntry(fout, dobj->catId, dobj->dumpId,
dobj->name, NULL, NULL, "",
destroyPQExpBuffer(query);
}
+/*
+ * dumpForeignDataWrapper
+ * write out a single foreign-data wrapper definition
+ */
+static void
+dumpForeignDataWrapper(Archive *fout, FdwInfo *fdwinfo)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+ char *namecopy;
+
+ /* Skip if not to be dumped */
+ if (!fdwinfo->dobj.dump || dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+
+ appendPQExpBuffer(q, "CREATE FOREIGN DATA WRAPPER %s LIBRARY '%s' LANGUAGE C",
+ fmtId(fdwinfo->dobj.name), fdwinfo->fdwlibrary);
+ if (fdwinfo->fdwoptions && strlen(fdwinfo->fdwoptions) > 0)
+ appendPQExpBuffer(q, " OPTIONS (%s)", fdwinfo->fdwoptions);
+
+ appendPQExpBuffer(q, ";\n");
+
+ appendPQExpBuffer(delq, "DROP FOREIGN DATA WRAPPER %s;\n",
+ fmtId(fdwinfo->dobj.name));
+
+ ArchiveEntry(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
+ fdwinfo->dobj.name,
+ NULL,
+ NULL,
+ fdwinfo->rolname,
+ false, "FOREIGN DATA WRAPPER", q->data, delq->data, NULL,
+ fdwinfo->dobj.dependencies, fdwinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Handle the ACL */
+ namecopy = strdup(fmtId(fdwinfo->dobj.name));
+ dumpACL(fout, fdwinfo->dobj.catId, fdwinfo->dobj.dumpId,
+ "FOREIGN DATA WRAPPER",
+ namecopy, fdwinfo->dobj.name,
+ NULL, fdwinfo->rolname,
+ fdwinfo->fdwacl);
+ free(namecopy);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+}
+
+/*
+ * dumpForeignServer
+ * write out a foreign server definition
+ */
+static void
+dumpForeignServer(Archive *fout, ForeignServerInfo *srvinfo)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+ PQExpBuffer query;
+ PGresult *res;
+ int ntups;
+ char *namecopy;
+ char *fdwname;
+
+ /* Skip if not to be dumped */
+ if (!srvinfo->dobj.dump || dataOnly)
+ return;
+
+ q = createPQExpBuffer();
+ delq = createPQExpBuffer();
+ query = createPQExpBuffer();
+
+ /* look up the foreign-data wrapper */
+ appendPQExpBuffer(query, "SELECT fdwname "
+ "FROM pg_foreign_data_wrapper w "
+ "WHERE w.oid = '%u'",
+ srvinfo->srvfdw);
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+ ntups = PQntuples(res);
+ if (ntups != 1)
+ {
+ write_msg(NULL, "query returned %d rows instead of one: %s\n",
+ ntups, query->data);
+ exit_nicely();
+ }
+ fdwname = PQgetvalue(res, 0, 0);
+
+ appendPQExpBuffer(q, "CREATE SERVER %s", fmtId(srvinfo->dobj.name));
+ if (srvinfo->srvtype && strlen(srvinfo->srvtype) > 0)
+ appendPQExpBuffer(q, " TYPE '%s'", srvinfo->srvtype);
+ if (srvinfo->srvversion && strlen(srvinfo->srvversion) > 0)
+ appendPQExpBuffer(q, " VERSION '%s'", srvinfo->srvversion);
+
+ appendPQExpBuffer(q, " FOREIGN DATA WRAPPER ");
+ appendPQExpBuffer(q, "%s", fmtId(fdwname));
+
+ if (srvinfo->srvoptions && strlen(srvinfo->srvoptions) > 0)
+ appendPQExpBuffer(q, " OPTIONS (%s)", srvinfo->srvoptions);
+
+ appendPQExpBuffer(q, ";\n");
+
+ appendPQExpBuffer(delq, "DROP SERVER %s;\n",
+ fmtId(srvinfo->dobj.name));
+
+ ArchiveEntry(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
+ srvinfo->dobj.name,
+ NULL,
+ NULL,
+ srvinfo->rolname,
+ false, "SERVER", q->data, delq->data, NULL,
+ srvinfo->dobj.dependencies, srvinfo->dobj.nDeps,
+ NULL, NULL);
+
+ /* Handle the ACL */
+ namecopy = strdup(fmtId(srvinfo->dobj.name));
+ dumpACL(fout, srvinfo->dobj.catId, srvinfo->dobj.dumpId,
+ "SERVER",
+ namecopy, srvinfo->dobj.name,
+ NULL, srvinfo->rolname,
+ srvinfo->srvacl);
+ free(namecopy);
+
+ /* Dump user mappings */
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "SERVER %s", fmtId(srvinfo->dobj.name));
+ dumpUserMappings(fout, q->data,
+ srvinfo->dobj.name, NULL,
+ srvinfo->rolname,
+ srvinfo->dobj.catId, srvinfo->dobj.dumpId);
+
+ destroyPQExpBuffer(q);
+ destroyPQExpBuffer(delq);
+}
+
+/*
+ * dumpUserMappings
+ *
+ * This routine is used to dump any user mappings associated with the
+ * server handed to this routine. Should be called after ArchiveEntry()
+ * for the server.
+ */
+static void
+dumpUserMappings(Archive *fout, const char *target,
+ const char *servername, const char *namespace,
+ const char *owner,
+ CatalogId catalogId, DumpId dumpId)
+{
+ PQExpBuffer q;
+ PQExpBuffer delq;
+ PQExpBuffer query;
+ PQExpBuffer tag;
+ PGresult *res;
+ int ntups;
+ int i_umuser;
+ int i_umoptions;
+ int i;
+
+ q = createPQExpBuffer();
+ tag = createPQExpBuffer();
+ delq = createPQExpBuffer();
+ query = createPQExpBuffer();
+
+ appendPQExpBuffer(query,
+ "SELECT (%s umuser) AS umuser, "
+ "array_to_string(ARRAY(SELECT option_name || ' ' || quote_literal(option_value) FROM pg_options_to_table(umoptions)), ', ') AS umoptions\n"
+ "FROM pg_user_mapping WHERE umserver=%u",
+ username_subquery,
+ catalogId.oid);
+
+ res = PQexec(g_conn, query->data);
+ check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+ i_umuser = PQfnumber(res, "umuser");
+ i_umoptions = PQfnumber(res, "umoptions");
+
+ for (i = 0; i < ntups; i++)
+ {
+ char *umuser;
+ char *umoptions;
+
+ umuser = PQgetvalue(res, i, i_umuser);
+ umoptions = PQgetvalue(res, i, i_umoptions);
+
+ resetPQExpBuffer(q);
+ appendPQExpBuffer(q, "CREATE USER MAPPING FOR %s", fmtId(umuser));
+ appendPQExpBuffer(q, " SERVER %s", fmtId(servername));
+
+ if (umoptions && strlen(umoptions) > 0)
+ appendPQExpBuffer(q, " OPTIONS (%s)", umoptions);
+
+ appendPQExpBuffer(q, ";\n");
+
+ resetPQExpBuffer(delq);
+ appendPQExpBuffer(delq, "DROP USER MAPPING FOR %s SERVER %s;\n", fmtId(umuser), fmtId(servername));
+
+ resetPQExpBuffer(tag);
+ appendPQExpBuffer(tag, "USER MAPPING %s %s", fmtId(umuser), target);
+
+ ArchiveEntry(fout, nilCatalogId, createDumpId(),
+ tag->data,
+ namespace,
+ NULL,
+ owner, false,
+ "USER MAPPING", q->data,
+ delq->data, NULL,
+ &dumpId, 1,
+ NULL, NULL);
+ }
+
+ PQclear(res);
+
+ destroyPQExpBuffer(query);
+ destroyPQExpBuffer(delq);
+ destroyPQExpBuffer(q);
+}
/*----------
* Write out grant/revoke information
* Portions Copyright (c) 1996-2008, 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.143 2008/11/09 21:24:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.144 2008/12/19 16:25:18 petere Exp $
*
*-------------------------------------------------------------------------
*/
DO_TSDICT,
DO_TSTEMPLATE,
DO_TSCONFIG,
+ DO_FDW,
+ DO_FOREIGN_SERVER,
DO_BLOBS,
DO_BLOB_COMMENTS
} DumpableObjectType;
Oid cfgparser;
} TSConfigInfo;
+typedef struct _fdwInfo
+{
+ DumpableObject dobj;
+ char *rolname;
+ char *fdwlibrary;
+ char *fdwoptions;
+ char *fdwacl;
+} FdwInfo;
+
+typedef struct _foreignServerInfo
+{
+ DumpableObject dobj;
+ char *rolname;
+ Oid srvfdw;
+ char *srvtype;
+ char *srvversion;
+ char *srvacl;
+ char *srvoptions;
+} ForeignServerInfo;
+
/* global decls */
extern bool force_quotes; /* double-quotes for identifiers flag */
extern bool g_verbose; /* verbose flag */
extern TSDictInfo *getTSDictionaries(int *numTSDicts);
extern TSTemplateInfo *getTSTemplates(int *numTSTemplates);
extern TSConfigInfo *getTSConfigurations(int *numTSConfigs);
+extern FdwInfo *getForeignDataWrappers(int *numForeignDataWrappers);
+extern ForeignServerInfo *getForeignServers(int *numForeignServers);
#endif /* PG_DUMP_H */
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.21 2008/09/08 15:26:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump_sort.c,v 1.22 2008/12/19 16:25:18 petere Exp $
*
*-------------------------------------------------------------------------
*/
4, /* DO_TSDICT */
3, /* DO_TSTEMPLATE */
5, /* DO_TSCONFIG */
+ 3, /* DO_FDW */
+ 4, /* DO_FOREIGN_SERVER */
10, /* DO_BLOBS */
11 /* DO_BLOB_COMMENTS */
};
6, /* DO_TSDICT */
5, /* DO_TSTEMPLATE */
7, /* DO_TSCONFIG */
+ 3, /* DO_FDW */
+ 4, /* DO_FOREIGN_SERVER */
14, /* DO_BLOBS */
15 /* DO_BLOB_COMMENTS */
};
"TEXT SEARCH CONFIGURATION %s (ID %d OID %u)",
obj->name, obj->dumpId, obj->catId.oid);
return;
+ case DO_FDW:
+ snprintf(buf, bufsize,
+ "FOREIGN DATA WRAPPER %s (ID %d OID %u)",
+ obj->name, obj->dumpId, obj->catId.oid);
+ return;
+ case DO_FOREIGN_SERVER:
+ snprintf(buf, bufsize,
+ "FOREIGN SERVER %s (ID %d OID %u)",
+ obj->name, obj->dumpId, obj->catId.oid);
+ return;
case DO_BLOBS:
snprintf(buf, bufsize,
"BLOBS (ID %d)",
*
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.198 2008/11/21 20:14:27 mha Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.199 2008/12/19 16:25:18 petere Exp $
*/
#include "postgres_fe.h"
#include "command.h"
break;
}
break;
-
+ case 'e': /* SQL/MED subsystem */
+ switch(cmd[2])
+ {
+ case 's':
+ success = listForeignServers(pattern, show_verbose);
+ break;
+ case 'u':
+ success = listUserMappings(pattern, show_verbose);
+ break;
+ case 'w':
+ success = listForeignDataWrappers(pattern, show_verbose);
+ break;
+ default:
+ status = PSQL_CMD_UNKNOWN;
+ break;
+ }
+ break;
default:
status = PSQL_CMD_UNKNOWN;
}
*
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.189 2008/12/19 14:39:58 alvherre Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.190 2008/12/19 16:25:18 petere Exp $
*/
#include "postgres_fe.h"
PQclear(res);
return true;
}
+
+
+/*
+ * \dew
+ *
+ * Describes foreign-data wrappers
+ */
+bool
+listForeignDataWrappers(const char *pattern, bool verbose)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+
+ initPQExpBuffer(&buf);
+ printfPQExpBuffer(&buf,
+ "SELECT fdwname AS \"%s\",\n"
+ " pg_catalog.pg_get_userbyid(fdwowner) AS \"%s\",\n"
+ " fdwlibrary AS \"%s\"\n",
+ gettext_noop("Name"),
+ gettext_noop("Owner"),
+ gettext_noop("Library"));
+
+ if (verbose)
+ appendPQExpBuffer(&buf,
+ ",\n fdwacl AS \"%s\","
+ " fdwoptions AS \"%s\"",
+ gettext_noop("Access privileges"),
+ gettext_noop("Options"));
+
+ appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_foreign_data_wrapper WHERE 1=1\n");
+
+ processSQLNamePattern(pset.db, &buf, pattern, true, false,
+ NULL, "fdwname", NULL, NULL);
+
+ appendPQExpBuffer(&buf, "ORDER BY 1;");
+
+ res = PSQLexec(buf.data, false);
+ termPQExpBuffer(&buf);
+ if (!res)
+ return false;
+
+ myopt.nullPrint = NULL;
+ myopt.title = _("List of foreign-data wrappers");
+ myopt.translate_header = true;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+
+ PQclear(res);
+ return true;
+}
+
+/*
+ * \des
+ *
+ * Describes servers.
+ */
+bool
+listForeignServers(const char *pattern, bool verbose)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+
+ initPQExpBuffer(&buf);
+ printfPQExpBuffer(&buf,
+ "SELECT s.srvname AS \"%s\",\n"
+ " pg_catalog.pg_get_userbyid(s.srvowner) AS \"%s\",\n"
+ " f.fdwname AS \"%s\"\n",
+ gettext_noop("Name"),
+ gettext_noop("Owner"),
+ gettext_noop("Foreign-data wrapper"));
+
+ if (verbose)
+ appendPQExpBuffer(&buf,
+ ",\n s.srvacl AS \"%s\","
+ " s.srvtype AS \"%s\","
+ " s.srvversion AS \"%s\","
+ " s.srvoptions AS \"%s\"",
+ gettext_noop("Access privileges"),
+ gettext_noop("Type"),
+ gettext_noop("Version"),
+ gettext_noop("Options"));
+
+ appendPQExpBuffer(&buf,
+ "\nFROM pg_foreign_server s\n"
+ "JOIN pg_catalog.pg_foreign_data_wrapper f ON f.oid=s.srvfdw\n");
+
+ processSQLNamePattern(pset.db, &buf, pattern, true, false,
+ NULL, "s.srvname", NULL, NULL);
+
+ appendPQExpBuffer(&buf, "ORDER BY 1;");
+
+ res = PSQLexec(buf.data, false);
+ termPQExpBuffer(&buf);
+ if (!res)
+ return false;
+
+ myopt.nullPrint = NULL;
+ myopt.title = _("List of foreign servers");
+ myopt.translate_header = true;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+
+ PQclear(res);
+ return true;
+}
+
+/*
+ * \deu
+ *
+ * Describes user mappings.
+ */
+bool
+listUserMappings(const char *pattern, bool verbose)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+
+ initPQExpBuffer(&buf);
+ printfPQExpBuffer(&buf,
+ "SELECT um.srvname AS \"%s\",\n"
+ " um.usename AS \"%s\"",
+ gettext_noop("Server"),
+ gettext_noop("Username"));
+
+ if (verbose)
+ appendPQExpBuffer(&buf,
+ ",\n um.umoptions AS \"%s\"",
+ gettext_noop("Options"));
+
+ appendPQExpBuffer(&buf, "\nFROM pg_catalog.pg_user_mappings um WHERE 1=1\n");
+
+ processSQLNamePattern(pset.db, &buf, pattern, true, false,
+ NULL, "um.srvname", "um.usename", NULL);
+
+ appendPQExpBuffer(&buf, "ORDER BY 1, 2;");
+
+ res = PSQLexec(buf.data, false);
+ termPQExpBuffer(&buf);
+ if (!res)
+ return false;
+
+ myopt.nullPrint = NULL;
+ myopt.title = _("List of user mappings");
+ myopt.translate_header = true;
+
+ printQuery(res, &myopt, pset.queryFout, pset.logfile);
+
+ PQclear(res);
+ return true;
+}
*
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.35 2008/01/01 19:45:56 momjian Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.36 2008/12/19 16:25:18 petere Exp $
*/
#ifndef DESCRIBE_H
#define DESCRIBE_H
/* \dn */
extern bool listSchemas(const char *pattern, bool verbose);
+/* \dew */
+extern bool listForeignDataWrappers(const char *pattern, bool verbose);
+
+/* \des */
+extern bool listForeignServers(const char *pattern, bool verbose);
+
+/* \deu */
+extern bool listUserMappings(const char *pattern, bool verbose);
+
#endif /* DESCRIBE_H */
*
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.131 2008/11/06 15:18:36 tgl Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.132 2008/12/19 16:25:18 petere Exp $
*/
#include "postgres_fe.h"
fprintf(output, _(" \\dC [PATTERN] list casts\n"));
fprintf(output, _(" \\dd [PATTERN] show comment for object\n"));
fprintf(output, _(" \\dD [PATTERN] list domains\n"));
+ fprintf(output, _(" \\des [PATTERN] list foreign servers (add \"+\" for more detail)\n"));
+ fprintf(output, _(" \\deu [PATTERN] list user mappings (add \"+\" for more detail)\n"));
+ fprintf(output, _(" \\dew [PATTERN] list foreign-data wrappers (add \"+\" for more detail)\n"));
fprintf(output, _(" \\df [PATTERN] list functions (add \"+\" for more detail)\n"));
fprintf(output, _(" \\dF [PATTERN] list text search configurations (add \"+\" for more detail)\n"));
fprintf(output, _(" \\dFd [PATTERN] list text search dictionaries (add \"+\" for more detail)\n"));
*
* Copyright (c) 2000-2008, PostgreSQL Global Development Group
*
- * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.177 2008/11/20 14:04:46 petere Exp $
+ * $PostgreSQL: pgsql/src/bin/psql/tab-complete.c,v 1.178 2008/12/19 16:25:18 petere Exp $
*/
/*----------------------------------------------------------------------
"SELECT pg_catalog.quote_ident(tmplname) FROM pg_catalog.pg_ts_template "\
" WHERE substring(pg_catalog.quote_ident(tmplname),1,%d)='%s'"
+#define Query_for_list_of_fdws \
+" SELECT pg_catalog.quote_ident(fdwname) "\
+" FROM pg_catalog.pg_foreign_data_wrapper "\
+" WHERE substring(pg_catalog.quote_ident(fdwname),1,%d)='%s'"
+
+#define Query_for_list_of_servers \
+" SELECT pg_catalog.quote_ident(srvname) "\
+" FROM pg_catalog.pg_foreign_server "\
+" WHERE substring(pg_catalog.quote_ident(srvname),1,%d)='%s'"
+
+#define Query_for_list_of_user_mappings \
+" SELECT pg_catalog.quote_ident(usename) "\
+" FROM pg_catalog.pg_user_mappings "\
+" WHERE substring(pg_catalog.quote_ident(usename),1,%d)='%s'"
+
/*
* This is a list of all "things" in Pgsql, which can show up after CREATE or
* DROP; and there is also a query to get a list of them.
{"DATABASE", Query_for_list_of_databases},
{"DICTIONARY", Query_for_list_of_ts_dictionaries, NULL, true},
{"DOMAIN", NULL, &Query_for_list_of_domains},
+ {"FOREIGN DATA WRAPPER", NULL, NULL},
{"FUNCTION", NULL, &Query_for_list_of_functions},
{"GROUP", Query_for_list_of_roles},
{"LANGUAGE", Query_for_list_of_languages},
{"RULE", "SELECT pg_catalog.quote_ident(rulename) FROM pg_catalog.pg_rules WHERE substring(pg_catalog.quote_ident(rulename),1,%d)='%s'"},
{"SCHEMA", Query_for_list_of_schemas},
{"SEQUENCE", NULL, &Query_for_list_of_sequences},
+ {"SERVER", Query_for_list_of_servers},
{"TABLE", NULL, &Query_for_list_of_tables},
{"TABLESPACE", Query_for_list_of_tablespaces},
{"TEMP", NULL, NULL}, /* for CREATE TEMP TABLE ... */
{"TYPE", NULL, &Query_for_list_of_datatypes},
{"UNIQUE", NULL, NULL}, /* for CREATE UNIQUE INDEX ... */
{"USER", Query_for_list_of_roles},
+ {"USER MAPPING FOR", NULL, NULL},
{"VIEW", NULL, &Query_for_list_of_views},
{NULL, NULL, NULL, false} /* end of list */
};
static const char *const backslash_commands[] = {
"\\a", "\\connect", "\\C", "\\cd", "\\copy", "\\copyright",
- "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\df",
+ "\\d", "\\da", "\\db", "\\dc", "\\dC", "\\dd", "\\dD", "\\des", "\\deu", "\\dew", "\\df",
"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl",
"\\dn", "\\do", "\\dp", "\\ds", "\\dS", "\\dt", "\\dT", "\\dv", "\\du",
"\\e", "\\echo", "\\encoding",
pg_strcasecmp(prev3_wd, "TABLE") != 0)
{
static const char *const list_ALTER[] =
- {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FUNCTION",
- "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "ROLE", "SCHEMA", "SEQUENCE", "TABLE",
- "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "VIEW", NULL};
+ {"AGGREGATE", "CONVERSION", "DATABASE", "DOMAIN", "FOREIGN DATA WRAPPER", "FUNCTION",
+ "GROUP", "INDEX", "LANGUAGE", "OPERATOR", "ROLE", "SCHEMA", "SERVER", "SEQUENCE", "TABLE",
+ "TABLESPACE", "TEXT SEARCH", "TRIGGER", "TYPE", "USER", "USER MAPPING FOR", "VIEW", NULL};
COMPLETE_WITH_LIST(list_ALTER);
}
COMPLETE_WITH_LIST(list_ALTERDATABASE);
}
+ /* ALTER FOREIGN DATA WRAPPER <name> */
+ else if (pg_strcasecmp(prev5_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
+ pg_strcasecmp(prev3_wd, "DATA") == 0 &&
+ pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
+ {
+ static const char *const list_ALTER_FDW[] =
+ {"LIBRARY", "OPTIONS", "OWNER TO", NULL};
+
+ COMPLETE_WITH_LIST(list_ALTER_FDW);
+ }
+
/* ALTER INDEX <name> */
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
pg_strcasecmp(prev2_wd, "INDEX") == 0)
/* ALTER USER,ROLE <name> */
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
(pg_strcasecmp(prev2_wd, "USER") == 0 ||
pg_strcasecmp(prev2_wd, "ROLE") == 0))
{
COMPLETE_WITH_LIST(list_ALTERSEQUENCE2);
}
+ /* ALTER SERVER <name> */
+ else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
+ pg_strcasecmp(prev2_wd, "SERVER") == 0)
+ {
+ static const char *const list_ALTER_SERVER[] =
+ {"VERSION", "OPTIONS", "OWNER TO", NULL};
+
+ COMPLETE_WITH_LIST(list_ALTER_SERVER);
+ }
/* ALTER VIEW <name> */
else if (pg_strcasecmp(prev3_wd, "ALTER") == 0 &&
pg_strcasecmp(prev2_wd, "VIEW") == 0)
pg_strcasecmp(prev_wd, "TEMPLATE") == 0)
COMPLETE_WITH_QUERY(Query_for_list_of_template_databases);
+ /* CREATE FOREIGN DATA WRAPPER */
+ else if (pg_strcasecmp(prev5_wd, "CREATE") == 0 &&
+ pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
+ pg_strcasecmp(prev3_wd, "DATA") == 0 &&
+ pg_strcasecmp(prev2_wd, "WRAPPER") == 0)
+ COMPLETE_WITH_CONST("LIBRARY");
+
+ else if (pg_strcasecmp(prev5_wd, "DATA") == 0 &&
+ pg_strcasecmp(prev4_wd, "WRAPPER") == 0 &&
+ pg_strcasecmp(prev2_wd, "LIBRARY") == 0)
+ COMPLETE_WITH_CONST("LANGUAGE C");
+
/* CREATE INDEX */
/* First off we complete CREATE UNIQUE with "INDEX" */
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
pg_strcasecmp(prev_wd, "TO") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables, NULL);
+/* CREATE SERVER <name> */
+ else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
+ pg_strcasecmp(prev2_wd, "SERVER") == 0)
+ {
+ static const char *const list_CREATE_SERVER[] =
+ {"TYPE", "VERSION", "FOREIGN DATA WRAPPER", NULL};
+
+ COMPLETE_WITH_LIST(list_CREATE_SERVER);
+ }
+
/* CREATE TABLE */
/* Complete "CREATE TEMP/TEMPORARY" with the possible temp objects */
else if (pg_strcasecmp(prev2_wd, "CREATE") == 0 &&
/* CREATE ROLE,USER,GROUP */
else if (pg_strcasecmp(prev3_wd, "CREATE") == 0 &&
+ !(pg_strcasecmp(prev2_wd, "USER") == 0 && pg_strcasecmp(prev_wd, "MAPPING") == 0) &&
(pg_strcasecmp(prev2_wd, "ROLE") == 0 ||
pg_strcasecmp(prev2_wd, "GROUP") == 0 || pg_strcasecmp(prev2_wd, "USER") == 0))
{
pg_strcasecmp(prev2_wd, "LANGUAGE") == 0 ||
pg_strcasecmp(prev2_wd, "SCHEMA") == 0 ||
pg_strcasecmp(prev2_wd, "SEQUENCE") == 0 ||
+ pg_strcasecmp(prev2_wd, "SERVER") == 0 ||
pg_strcasecmp(prev2_wd, "TABLE") == 0 ||
pg_strcasecmp(prev2_wd, "TYPE") == 0 ||
pg_strcasecmp(prev2_wd, "VIEW") == 0)) ||
(pg_strcasecmp(prev4_wd, "DROP") == 0 &&
pg_strcasecmp(prev3_wd, "AGGREGATE") == 0 &&
prev_wd[strlen(prev_wd) - 1] == ')') ||
+ (pg_strcasecmp(prev5_wd, "DROP") == 0 &&
+ pg_strcasecmp(prev4_wd, "FOREIGN") == 0 &&
+ pg_strcasecmp(prev3_wd, "DATA") == 0 &&
+ pg_strcasecmp(prev2_wd, "WRAPPER") == 0) ||
(pg_strcasecmp(prev5_wd, "DROP") == 0 &&
pg_strcasecmp(prev4_wd, "TEXT") == 0 &&
pg_strcasecmp(prev3_wd, "SEARCH") == 0 &&
COMPLETE_WITH_LIST(list_FROMIN);
}
+/* FOREIGN DATA WRAPPER */
+ /* applies in ALTER/DROP FDW and in CREATE SERVER */
+ else if (pg_strcasecmp(prev4_wd, "CREATE") != 0 &&
+ pg_strcasecmp(prev3_wd, "FOREIGN") == 0 &&
+ pg_strcasecmp(prev2_wd, "DATA") == 0 &&
+ pg_strcasecmp(prev_wd, "WRAPPER") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
+
/* GRANT && REVOKE*/
/* Complete GRANT/REVOKE with a list of privileges */
else if (pg_strcasecmp(prev_wd, "GRANT") == 0 ||
pg_strcasecmp(prev_wd, "ON") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tsv,
" UNION SELECT 'DATABASE'"
+ " UNION SELECT 'FOREIGN DATA WRAPPER'"
+ " UNION SELECT 'FOREIGN SERVER'"
" UNION SELECT 'FUNCTION'"
" UNION SELECT 'LANGUAGE'"
" UNION SELECT 'SCHEMA'"
else if (pg_strcasecmp(prev_wd, "NOTIFY") == 0)
COMPLETE_WITH_QUERY("SELECT pg_catalog.quote_ident(relname) FROM pg_catalog.pg_listener WHERE substring(pg_catalog.quote_ident(relname),1,%d)='%s'");
+/* OPTIONS */
+ else if (pg_strcasecmp(prev_wd, "OPTIONS") == 0)
+ COMPLETE_WITH_CONST("(");
+
/* OWNER TO - complete with available roles */
else if (pg_strcasecmp(prev2_wd, "OWNER") == 0 &&
pg_strcasecmp(prev_wd, "TO") == 0)
pg_strcasecmp(prev4_wd, "UPDATE") == 0)
COMPLETE_WITH_CONST("=");
+/* USER MAPPING */
+ else if ((pg_strcasecmp(prev3_wd, "ALTER") == 0 ||
+ pg_strcasecmp(prev3_wd, "CREATE") == 0 ||
+ pg_strcasecmp(prev3_wd, "DROP") == 0) &&
+ pg_strcasecmp(prev2_wd, "USER") == 0 &&
+ pg_strcasecmp(prev_wd, "MAPPING") == 0)
+ COMPLETE_WITH_CONST("FOR");
+ else if (pg_strcasecmp(prev4_wd, "CREATE") == 0 &&
+ pg_strcasecmp(prev3_wd, "USER") == 0 &&
+ pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
+ pg_strcasecmp(prev_wd, "FOR") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_roles);
+ else if ((pg_strcasecmp(prev4_wd, "ALTER") == 0 ||
+ pg_strcasecmp(prev4_wd, "DROP") == 0) &&
+ pg_strcasecmp(prev3_wd, "USER") == 0 &&
+ pg_strcasecmp(prev2_wd, "MAPPING") == 0 &&
+ pg_strcasecmp(prev_wd, "FOR") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
+ else if ((pg_strcasecmp(prev5_wd, "CREATE") == 0 ||
+ pg_strcasecmp(prev5_wd, "ALTER") == 0 ||
+ pg_strcasecmp(prev5_wd, "DROP") == 0) &&
+ pg_strcasecmp(prev4_wd, "USER") == 0 &&
+ pg_strcasecmp(prev3_wd, "MAPPING") == 0 &&
+ pg_strcasecmp(prev2_wd, "FOR") == 0)
+ COMPLETE_WITH_CONST("SERVER");
+
/*
* VACUUM [ FULL | FREEZE ] [ VERBOSE ] [ table ]
* VACUUM [ FULL | FREEZE ] [ VERBOSE ] ANALYZE [ table [ (column [, ...] ) ] ]
COMPLETE_WITH_QUERY(Query_for_list_of_tablespaces);
else if (strcmp(prev_wd, "\\dD") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_domains, NULL);
+ else if (strcmp(prev_wd, "\\des") == 0 || strcmp(prev_wd, "\\des+") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_servers);
+ else if (strcmp(prev_wd, "\\deu") == 0 || strcmp(prev_wd, "\\deu+") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_user_mappings);
+ else if (strcmp(prev_wd, "\\dew") == 0 || strcmp(prev_wd, "\\dew+") == 0)
+ COMPLETE_WITH_QUERY(Query_for_list_of_fdws);
else if (strcmp(prev_wd, "\\df") == 0 || strcmp(prev_wd, "\\df+") == 0)
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_functions, NULL);
else if (strcmp(prev_wd, "\\dF") == 0 || strcmp(prev_wd, "\\dF+") == 0)
* "Catalog version number" for PostgreSQL.
*
* The catalog version number is used to flag incompatible changes in
- * the PostgreSQL system catalogs. Whenever anyone changes the format of
+ * the PostgreSQL system catalogs. Whenever anyone changes the format of
* a system catalog relation, or adds, deletes, or modifies standard
* catalog entries in such a way that an updated backend wouldn't work
* with an old database (or vice versa), the catalog version number
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.511 2008/12/04 17:51:27 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.512 2008/12/19 16:25:18 petere Exp $
*
*-------------------------------------------------------------------------
*/
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200812041
+#define CATALOG_VERSION_NO 200812191
#endif
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.36 2008/06/08 22:41:04 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/dependency.h,v 1.37 2008/12/19 16:25:18 petere Exp $
*
*-------------------------------------------------------------------------
*/
OCLASS_ROLE, /* pg_authid */
OCLASS_DATABASE, /* pg_database */
OCLASS_TBLSPACE, /* pg_tablespace */
+ OCLASS_FDW, /* pg_foreign_data_wrapper */
+ OCLASS_FOREIGN_SERVER, /* pg_foreign_server */
+ OCLASS_USER_MAPPING, /* pg_user_mapping */
MAX_OCLASS /* MUST BE LAST */
} ObjectClass;
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.103 2008/06/19 00:46:06 alvherre Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.104 2008/12/19 16:25:18 petere Exp $
*
*-------------------------------------------------------------------------
*/
DECLARE_UNIQUE_INDEX(pg_type_typname_nsp_index, 2704, on pg_type using btree(typname name_ops, typnamespace oid_ops));
#define TypeNameNspIndexId 2704
+DECLARE_UNIQUE_INDEX(pg_foreign_data_wrapper_oid_index, 112, on pg_foreign_data_wrapper using btree(oid oid_ops));
+#define ForeignDataWrapperOidIndexId 112
+
+DECLARE_UNIQUE_INDEX(pg_foreign_data_wrapper_name_index, 548, on pg_foreign_data_wrapper using btree(fdwname name_ops));
+#define ForeignDataWrapperNameIndexId 548
+
+DECLARE_UNIQUE_INDEX(pg_foreign_server_oid_index, 113, on pg_foreign_server using btree(oid oid_ops));
+#define ForeignServerOidIndexId 113
+
+DECLARE_UNIQUE_INDEX(pg_foreign_server_name_index, 549, on pg_foreign_server using btree(srvname name_ops));
+#define ForeignServerNameIndexId 549
+
+DECLARE_UNIQUE_INDEX(pg_user_mapping_oid_index, 174, on pg_user_mapping using btree(oid oid_ops));
+#define UserMappingOidIndexId 174
+
+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
+
/* last step of initialization script: build the indexes declared above */
BUILD_INDICES
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * pg_foreign_data_wrapper.h
+ * definition of the system "foreign-data wrapper" relation (pg_foreign_data_wrapper)
+ * along with the relation's initial contents.
+ *
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/catalog/pg_foreign_data_wrapper.h,v 1.1 2008/12/19 16:25:18 petere Exp $
+ *
+ * NOTES
+ * the genbki.sh script reads this file and generates .bki
+ * information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_FOREIGN_DATA_WRAPPER_H
+#define PG_FOREIGN_DATA_WRAPPER_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ * pg_foreign_data_wrapper definition. cpp turns this into
+ * typedef struct FormData_pg_foreign_data_wrapper
+ * ----------------
+ */
+#define ForeignDataWrapperRelationId 2328
+
+CATALOG(pg_foreign_data_wrapper,2328)
+{
+ NameData fdwname; /* foreign-data wrapper name */
+ Oid fdwowner; /* FDW owner */
+
+ /* VARIABLE LENGTH FIELDS start here. */
+
+ text fdwlibrary; /* FDW shared library location */
+ aclitem fdwacl[1]; /* access permissions */
+ text fdwoptions[1]; /* FDW options */
+} FormData_pg_foreign_data_wrapper;
+
+/* ----------------
+ * Form_pg_fdw corresponds to a pointer to a tuple with
+ * the format of pg_fdw relation.
+ * ----------------
+ */
+typedef FormData_pg_foreign_data_wrapper *Form_pg_foreign_data_wrapper;
+
+/* ----------------
+ * compiler constants for pg_fdw
+ * ----------------
+ */
+
+#define Natts_pg_foreign_data_wrapper 5
+#define Anum_pg_foreign_data_wrapper_fdwname 1
+#define Anum_pg_foreign_data_wrapper_fdwowner 2
+#define Anum_pg_foreign_data_wrapper_fdwlibrary 3
+#define Anum_pg_foreign_data_wrapper_fdwacl 4
+#define Anum_pg_foreign_data_wrapper_fdwoptions 5
+
+#endif /* PG_FOREIGN_DATA_WRAPPER_H */
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * pg_foreign_server.h
+ * definition of the system "foreign server" relation (pg_foreign_server)
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/catalog/pg_foreign_server.h,v 1.1 2008/12/19 16:25:18 petere Exp $
+ *
+ * NOTES
+ * the genbki.sh script reads this file and generates .bki
+ * information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_FOREIGN_SERVER_H
+#define PG_FOREIGN_SERVER_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ * pg_foreign_server definition. cpp turns this into
+ * typedef struct FormData_pg_foreign_server
+ * ----------------
+ */
+#define ForeignServerRelationId 1417
+
+CATALOG(pg_foreign_server,1417)
+{
+ NameData srvname; /* foreign server name */
+ Oid srvowner; /* server owner */
+ Oid srvfdw; /* server FDW */
+
+ /*
+ * VARIABLE LENGTH FIELDS start here. These fields may be NULL, too.
+ */
+ text srvtype;
+ text srvversion;
+ aclitem srvacl[1]; /* access permissions */
+ text srvoptions[1]; /* FDW-specific options */
+} FormData_pg_foreign_server;
+
+/* ----------------
+ * Form_pg_foreign_server corresponds to a pointer to a tuple with
+ * the format of pg_foreign_server relation.
+ * ----------------
+ */
+typedef FormData_pg_foreign_server *Form_pg_foreign_server;
+
+/* ----------------
+ * compiler constants for pg_foreign_server
+ * ----------------
+ */
+
+#define Natts_pg_foreign_server 7
+#define Anum_pg_foreign_server_srvname 1
+#define Anum_pg_foreign_server_srvowner 2
+#define Anum_pg_foreign_server_srvfdw 3
+#define Anum_pg_foreign_server_srvtype 4
+#define Anum_pg_foreign_server_srvversion 5
+#define Anum_pg_foreign_server_srvacl 6
+#define Anum_pg_foreign_server_srvoptions 7
+
+#endif /* PG_FOREIGN_SERVER_H */
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.531 2008/12/18 18:20:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.532 2008/12/19 16:25:18 petere Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
DATA(insert OID = 2395 ( has_tablespace_privilege PGNSP PGUID 12 1 0 0 f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_tablespace_privilege_id _null_ _null_ _null_ ));
DESCR("current user privilege on tablespace by tablespace oid");
+DATA(insert OID = 3000 ( has_foreign_data_wrapper_privilege PGNSP PGUID 12 1 0 0 f f t f s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_name_name _null_ _null_ _null_ ));
+DESCR("user privilege on foreign data wrapper by username, foreign data wrapper name");
+DATA(insert OID = 3001 ( has_foreign_data_wrapper_privilege PGNSP PGUID 12 1 0 0 f f t f s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_name_id _null_ _null_ _null_ ));
+DESCR("user privilege on foreign data wrapper by username, foreign data wrapper oid");
+DATA(insert OID = 3002 ( has_foreign_data_wrapper_privilege PGNSP PGUID 12 1 0 0 f f t f s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_id_name _null_ _null_ _null_ ));
+DESCR("user privilege on foreign data wrapper by user oid, foreign data wrapper name");
+DATA(insert OID = 3003 ( has_foreign_data_wrapper_privilege PGNSP PGUID 12 1 0 0 f f t f s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_id_id _null_ _null_ _null_ ));
+DESCR("user privilege on foreign data wrapper by user oid, foreign data wrapper oid");
+DATA(insert OID = 3004 ( has_foreign_data_wrapper_privilege PGNSP PGUID 12 1 0 0 f f t f s 2 0 16 "25 25" _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_name _null_ _null_ _null_ ));
+DESCR("current user privilege on foreign data wrapper by foreign data wrapper name");
+DATA(insert OID = 3005 ( has_foreign_data_wrapper_privilege PGNSP PGUID 12 1 0 0 f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_foreign_data_wrapper_privilege_id _null_ _null_ _null_ ));
+DESCR("current user privilege on foreign data wrapper by foreign data wrapper oid");
+
+DATA(insert OID = 3006 ( has_server_privilege PGNSP PGUID 12 1 0 0 f f t f s 3 0 16 "19 25 25" _null_ _null_ _null_ _null_ has_server_privilege_name_name _null_ _null_ _null_ ));
+DESCR("user privilege on server by username, server name");
+DATA(insert OID = 3007 ( has_server_privilege PGNSP PGUID 12 1 0 0 f f t f s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ has_server_privilege_name_id _null_ _null_ _null_ ));
+DESCR("user privilege on server by username, server oid");
+DATA(insert OID = 3008 ( has_server_privilege PGNSP PGUID 12 1 0 0 f f t f s 3 0 16 "26 25 25" _null_ _null_ _null_ _null_ has_server_privilege_id_name _null_ _null_ _null_ ));
+DESCR("user privilege on server by user oid, server name");
+DATA(insert OID = 3009 ( has_server_privilege PGNSP PGUID 12 1 0 0 f f t f s 3 0 16 "26 26 25" _null_ _null_ _null_ _null_ has_server_privilege_id_id _null_ _null_ _null_ ));
+DESCR("user privilege on server by user oid, server oid");
+DATA(insert OID = 3010 ( has_server_privilege PGNSP PGUID 12 1 0 0 f f t f s 2 0 16 "25 25" _null_ _null_ _null_ _null_ has_server_privilege_name _null_ _null_ _null_ ));
+DESCR("current user privilege on server by server name");
+DATA(insert OID = 3011 ( has_server_privilege PGNSP PGUID 12 1 0 0 f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_server_privilege_id _null_ _null_ _null_ ));
+DESCR("current user privilege on server by server oid");
+
DATA(insert OID = 2705 ( pg_has_role PGNSP PGUID 12 1 0 0 f f t f s 3 0 16 "19 19 25" _null_ _null_ _null_ _null_ pg_has_role_name_name _null_ _null_ _null_ ));
DESCR("user privilege on role by username, role name");
DATA(insert OID = 2706 ( pg_has_role PGNSP PGUID 12 1 0 0 f f t f s 3 0 16 "19 26 25" _null_ _null_ _null_ _null_ pg_has_role_name_id _null_ _null_ _null_ ));
DATA(insert OID = 2987 ( btrecordcmp PGNSP PGUID 12 1 0 0 f f t f i 2 0 23 "2249 2249" _null_ _null_ _null_ _null_ btrecordcmp _null_ _null_ _null_ ));
DESCR("btree less-equal-greater");
+DATA(insert OID = 2998 ( pg_options_to_table PGNSP PGUID 12 1 3 0 f f t t s 1 0 2249 "1009" "{1009,25,25}" "{i,o,o}" "{options_array,option_name,option_value}" _null_ pg_options_to_table _null_ _null_ _null_ ));
+DESCR("convert generic options array to name/value table");
+
/*
* Symbolic values for provolatile column: these indicate whether the result
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * pg_user_mapping.h
+ * definition of the system "user mapping" relation (pg_user_mapping)
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * $PostgreSQL: pgsql/src/include/catalog/pg_user_mapping.h,v 1.1 2008/12/19 16:25:19 petere Exp $
+ *
+ * NOTES
+ * the genbki.sh script reads this file and generates .bki
+ * information from the DATA() statements.
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef PG_USER_MAPPING_H
+#define PG_USER_MAPPING_H
+
+#include "catalog/genbki.h"
+
+/* ----------------
+ * pg_user_mapping definition. cpp turns this into
+ * typedef struct FormData_pg_user_mapping
+ * ----------------
+ */
+#define UserMappingRelationId 1418
+
+CATALOG(pg_user_mapping,1418)
+{
+ Oid umuser; /* Id of the user, InvalidOid if PUBLIC is wanted */
+ Oid umserver; /* server of this mapping */
+
+ /*
+ * VARIABLE LENGTH FIELDS start here. These fields may be NULL, too.
+ */
+
+ text umoptions[1]; /* user mapping options */
+} FormData_pg_user_mapping;
+
+/* ----------------
+ * Form_pg_user_mapping corresponds to a pointer to a tuple with
+ * the format of pg_user_mapping relation.
+ * ----------------
+ */
+typedef FormData_pg_user_mapping *Form_pg_user_mapping;
+
+/* ----------------
+ * compiler constants for pg_user_mapping
+ * ----------------
+ */
+
+#define Natts_pg_user_mapping 3
+#define Anum_pg_user_mapping_umuser 1
+#define Anum_pg_user_mapping_umserver 2
+#define Anum_pg_user_mapping_umoptions 3
+
+#endif /* PG_USER_MAPPING_H */
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.90 2008/12/04 17:51:27 petere Exp $
+ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.91 2008/12/19 16:25:19 petere Exp $
*
*-------------------------------------------------------------------------
*/
extern text *serialize_deflist(List *deflist);
extern List *deserialize_deflist(Datum txt);
+/* commands/foreigncmds.c */
+extern void AlterForeignServerOwner(const char *name, Oid newOwnerId);
+extern void AlterForeignDataWrapperOwner(const char *name, Oid newOwnerId);
+extern void CreateForeignDataWrapper(CreateFdwStmt *stmt);
+extern void AlterForeignDataWrapper(AlterFdwStmt *stmt);
+extern void RemoveForeignDataWrapper(DropFdwStmt *stmt);
+extern void RemoveForeignDataWrapperById(Oid fdwId);
+extern void CreateForeignServer(CreateForeignServerStmt *stmt);
+extern void AlterForeignServer(AlterForeignServerStmt *stmt);
+extern void RemoveForeignServer(DropForeignServerStmt *stmt);
+extern void RemoveForeignServerById(Oid srvId);
+extern void CreateUserMapping(CreateUserMappingStmt *stmt);
+extern void AlterUserMapping(AlterUserMappingStmt *stmt);
+extern void RemoveUserMapping(DropUserMappingStmt *stmt);
+extern void RemoveUserMappingById(Oid umId);
+
/* support routines in commands/define.c */
extern char *case_translate_language_name(const char *input);
--- /dev/null
+/*-------------------------------------------------------------------------
+ *
+ * foreign.h
+ * support for foreign-data wrappers, servers and user mappings.
+ *
+ *
+ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
+ *
+ * $PostgreSQL: pgsql/src/include/foreign/foreign.h,v 1.1 2008/12/19 16:25:19 petere Exp $
+ *
+ *-------------------------------------------------------------------------
+ */
+#ifndef FOREIGN_H
+#define FOREIGN_H
+
+#include "nodes/parsenodes.h"
+#include "nodes/pg_list.h"
+
+
+/* Helper for obtaining username for user mapping */
+#define MappingUserName(userid) \
+ (OidIsValid(userid) ? GetUserNameFromId(userid) : "public")
+
+
+/*
+ * Generic option types for validation.
+ * NB! Thes are treated as flags, so use only powers of two here.
+ */
+typedef enum {
+ InvalidOpt = 0,
+ ServerOpt = 1, /* options applicable to SERVER */
+ UserMappingOpt = 2, /* options for USER MAPPING */
+ FdwOpt = 4, /* options for FOREIGN DATA WRAPPER */
+} GenericOptionFlags;
+
+typedef struct ForeignDataWrapperLibrary ForeignDataWrapperLibrary;
+
+typedef struct ForeignDataWrapper
+{
+ Oid fdwid; /* FDW Oid */
+ Oid owner; /* FDW owner user Oid */
+ char *fdwname; /* Name of the FDW */
+ char *fdwlibrary; /* Library name */
+ List *options; /* fdwoptions as DefElem list */
+
+ ForeignDataWrapperLibrary *lib; /* interface to the FDW functions */
+} ForeignDataWrapper;
+
+typedef struct ForeignServer
+{
+ Oid serverid; /* server Oid */
+ Oid fdwid; /* foreign-data wrapper */
+ Oid owner; /* server owner user Oid */
+ char *servername; /* name of the server */
+ char *servertype; /* server type, optional */
+ char *serverversion; /* server version, optional */
+ List *options; /* srvoptions as DefElem list */
+} ForeignServer;
+
+typedef struct UserMapping
+{
+ Oid userid; /* local user Oid */
+ Oid serverid; /* server Oid */
+ List *options; /* useoptions as DefElem list */
+} UserMapping;
+
+
+/*
+ * Foreign-data wrapper library function types.
+ */
+typedef void (*OptionListValidatorFunc)(ForeignDataWrapper *,
+ GenericOptionFlags,
+ List *);
+
+/*
+ * Interface functions to the foreign-data wrapper. This is decoupled
+ * from the FDW as there maybe several FDW-s accessing the same library.
+ */
+struct ForeignDataWrapperLibrary
+{
+ char *libname; /* name of the library file */
+
+ OptionListValidatorFunc validateOptionList;
+};
+
+
+extern ForeignServer *GetForeignServer(Oid serverid);
+extern ForeignServer *GetForeignServerByName(const char *name, bool missing_ok);
+extern Oid GetForeignServerOidByName(const char *name, bool missing_ok);
+extern UserMapping *GetUserMapping(Oid userid, Oid serverid);
+extern ForeignDataWrapper *GetForeignDataWrapper(Oid fdwid);
+extern ForeignDataWrapper *GetForeignDataWrapperByName(const char *name,
+ bool missing_ok);
+extern Oid GetForeignDataWrapperOidByName(const char *name, bool missing_ok);
+extern ForeignDataWrapperLibrary *GetForeignDataWrapperLibrary(const char *libname);
+
+/* Foreign data wrapper interface functions */
+extern void _pg_validateOptionList(ForeignDataWrapper *fdw,
+ GenericOptionFlags flags, List *options);
+
+#endif /* FOREIGN_H */
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.63 2008/09/01 20:42:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/makefuncs.h,v 1.64 2008/12/19 16:25:19 petere Exp $
*
*-------------------------------------------------------------------------
*/
extern DefElem *makeDefElem(char *name, Node *arg);
+extern OptionDefElem *makeOptionDefElem(int op, DefElem *def);
+
#endif /* MAKEFUNC_H */
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.215 2008/11/22 22:47:06 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.216 2008/12/19 16:25:19 petere Exp $
*
*-------------------------------------------------------------------------
*/
T_CreateEnumStmt,
T_AlterTSDictionaryStmt,
T_AlterTSConfigurationStmt,
+ T_CreateFdwStmt,
+ T_AlterFdwStmt,
+ T_DropFdwStmt,
+ T_CreateForeignServerStmt,
+ T_AlterForeignServerStmt,
+ T_DropForeignServerStmt,
+ T_CreateUserMappingStmt,
+ T_AlterUserMappingStmt,
+ T_DropUserMappingStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
T_IndexElem,
T_Constraint,
T_DefElem,
+ T_OptionDefElem,
T_RangeTblEntry,
T_SortGroupClause,
T_FkConstraint,
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.383 2008/12/18 18:20:35 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.384 2008/12/19 16:25:19 petere Exp $
*
*-------------------------------------------------------------------------
*/
SORTBY_NULLS_LAST
} SortByNulls;
+/* Alter operations for generic options */
+typedef enum AlterOptionOp
+{
+ ALTER_OPT_DROP = -1,
+ ALTER_OPT_SET,
+ ALTER_OPT_ADD
+} AlterOptionOp;
/*
* Grantable rights are encoded so that we can OR them together in a bitmask.
#define ACL_REFERENCES (1<<5)
#define ACL_TRIGGER (1<<6)
#define ACL_EXECUTE (1<<7) /* for functions */
-#define ACL_USAGE (1<<8) /* for languages and namespaces */
+#define ACL_USAGE (1<<8) /* for languages, namespaces, FDWs, and servers */
#define ACL_CREATE (1<<9) /* for namespaces and databases */
#define ACL_CREATE_TEMP (1<<10) /* for databases */
#define ACL_CONNECT (1<<11) /* for databases */
Node *arg; /* a (Value *) or a (TypeName *) */
} DefElem;
+/*
+ * Option definition. Used in options definition lists, with optional alter
+ * operation.
+ */
+typedef struct OptionDefElem
+{
+ NodeTag type;
+ AlterOptionOp alter_op; /* Alter operation: ADD/SET/DROP */
+ DefElem *def; /* The actual definition */
+} OptionDefElem;
+
/*
* LockingClause - raw representation of FOR UPDATE/SHARE options
*
OBJECT_CONVERSION,
OBJECT_DATABASE,
OBJECT_DOMAIN,
+ OBJECT_FDW,
+ OBJECT_FOREIGN_SERVER,
OBJECT_FUNCTION,
OBJECT_INDEX,
OBJECT_LANGUAGE,
ACL_OBJECT_RELATION, /* table, view */
ACL_OBJECT_SEQUENCE, /* sequence */
ACL_OBJECT_DATABASE, /* database */
+ ACL_OBJECT_FDW, /* foreign-data wrapper */
+ ACL_OBJECT_FOREIGN_SERVER, /* foreign server */
ACL_OBJECT_FUNCTION, /* function */
ACL_OBJECT_LANGUAGE, /* procedural language */
ACL_OBJECT_NAMESPACE, /* namespace */
bool missing_ok; /* skip error if missing? */
} DropTableSpaceStmt;
+/* ----------------------
+ * Create/Drop FOREIGN DATA WRAPPER Statements
+ * ----------------------
+ */
+
+typedef struct CreateFdwStmt
+{
+ NodeTag type;
+ char *fdwname; /* foreign-data wrapper name */
+ char *library; /* libray name */
+ List *options; /* generic options to FDW */
+} CreateFdwStmt;
+
+typedef struct AlterFdwStmt
+{
+ NodeTag type;
+ char *fdwname; /* foreign-data wrapper name */
+ char *library; /* libray name */
+ List *options; /* generic options to FDW */
+} AlterFdwStmt;
+
+typedef struct DropFdwStmt
+{
+ NodeTag type;
+ char *fdwname; /* foreign-data wrapper name */
+ bool missing_ok; /* don't complain if missing */
+ DropBehavior behavior; /* drop behavior - cascade/restrict */
+} DropFdwStmt;
+
+/* ----------------------
+ * Create/Drop FOREIGN SERVER Statements
+ * ----------------------
+ */
+
+typedef struct CreateForeignServerStmt
+{
+ NodeTag type;
+ char *servername; /* server name */
+ char *servertype; /* optional server type */
+ char *version; /* optional server version */
+ char *fdwname; /* FDW name */
+ List *options; /* generic options to server */
+} CreateForeignServerStmt;
+
+typedef struct AlterForeignServerStmt
+{
+ NodeTag type;
+ char *servername; /* server name */
+ char *version; /* optional server version */
+ List *options; /* generic options to server */
+ bool has_version; /* version specified */
+} AlterForeignServerStmt;
+
+typedef struct DropForeignServerStmt
+{
+ NodeTag type;
+ char *servername; /* server name */
+ bool missing_ok; /* ignore missing servers */
+ DropBehavior behavior; /* drop behavior - cascade/restrict */
+} DropForeignServerStmt;
+
+/* ----------------------
+ * Create/Drop USER MAPPING Statements
+ * ----------------------
+ */
+
+typedef struct CreateUserMappingStmt
+{
+ NodeTag type;
+ char *username; /* username or PUBLIC/CURRENT_USER */
+ char *servername; /* server name */
+ List *options; /* generic options to server */
+} CreateUserMappingStmt;
+
+typedef struct AlterUserMappingStmt
+{
+ NodeTag type;
+ char *username; /* username or PUBLIC/CURRENT_USER */
+ char *servername; /* server name */
+ List *options; /* generic options to server */
+} AlterUserMappingStmt;
+
+typedef struct DropUserMappingStmt
+{
+ NodeTag type;
+ char *username; /* username or PUBLIC/CURRENT_USER */
+ char *servername; /* server name */
+ bool missing_ok; /* ignore missing mappings */
+} DropUserMappingStmt;
+
/* ----------------------
* Create/Drop TRIGGER Statements
* ----------------------
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.104 2008/09/08 00:47:41 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.105 2008/12/19 16:25:19 petere Exp $
*
* NOTES
* An ACL array is simply an array of AclItems, representing the union
#define ACL_ALL_RIGHTS_RELATION (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_TRUNCATE|ACL_REFERENCES|ACL_TRIGGER)
#define ACL_ALL_RIGHTS_SEQUENCE (ACL_USAGE|ACL_SELECT|ACL_UPDATE)
#define ACL_ALL_RIGHTS_DATABASE (ACL_CREATE|ACL_CREATE_TEMP|ACL_CONNECT)
+#define ACL_ALL_RIGHTS_FDW (ACL_USAGE)
+#define ACL_ALL_RIGHTS_FOREIGN_SERVER (ACL_USAGE)
#define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE)
#define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE)
#define ACL_ALL_RIGHTS_NAMESPACE (ACL_USAGE|ACL_CREATE)
ACL_KIND_TABLESPACE, /* pg_tablespace */
ACL_KIND_TSDICTIONARY, /* pg_ts_dict */
ACL_KIND_TSCONFIGURATION, /* pg_ts_config */
+ ACL_KIND_FDW, /* pg_foreign_data_wrapper */
+ ACL_KIND_FOREIGN_SERVER, /* pg_foreign_server */
MAX_ACL_KIND /* MUST BE LAST */
} AclObjectKind;
AclMode mask, AclMaskHow how);
extern AclMode pg_tablespace_aclmask(Oid spc_oid, Oid roleid,
AclMode mask, AclMaskHow how);
+extern AclMode pg_foreign_data_wrapper_aclmask(Oid fdw_oid, Oid roleid,
+ AclMode mask, AclMaskHow how);
+extern AclMode pg_foreign_server_aclmask(Oid srv_oid, Oid roleid,
+ AclMode mask, AclMaskHow how);
extern AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode);
extern AclResult pg_database_aclcheck(Oid db_oid, Oid roleid, AclMode mode);
extern AclResult pg_language_aclcheck(Oid lang_oid, Oid roleid, AclMode mode);
extern AclResult pg_namespace_aclcheck(Oid nsp_oid, Oid roleid, AclMode mode);
extern AclResult pg_tablespace_aclcheck(Oid spc_oid, Oid roleid, AclMode mode);
+extern AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode);
+extern AclResult pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode);
extern void aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
const char *objectname);
extern bool pg_conversion_ownercheck(Oid conv_oid, Oid roleid);
extern bool pg_ts_dict_ownercheck(Oid dict_oid, Oid roleid);
extern bool pg_ts_config_ownercheck(Oid cfg_oid, Oid roleid);
+extern bool pg_foreign_server_ownercheck(Oid srv_oid, Oid roleid);
#endif /* ACL_H */
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.327 2008/12/04 17:51:28 petere Exp $
+ * $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.328 2008/12/19 16:25:19 petere Exp $
*
*-------------------------------------------------------------------------
*/
extern Datum has_database_privilege_id_id(PG_FUNCTION_ARGS);
extern Datum has_database_privilege_name(PG_FUNCTION_ARGS);
extern Datum has_database_privilege_id(PG_FUNCTION_ARGS);
+extern Datum has_foreign_data_wrapper_privilege_name_name(PG_FUNCTION_ARGS);
+extern Datum has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS);
+extern Datum has_foreign_data_wrapper_privilege_id_name(PG_FUNCTION_ARGS);
+extern Datum has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS);
+extern Datum has_foreign_data_wrapper_privilege_name(PG_FUNCTION_ARGS);
+extern Datum has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS);
extern Datum has_function_privilege_name_name(PG_FUNCTION_ARGS);
extern Datum has_function_privilege_name_id(PG_FUNCTION_ARGS);
extern Datum has_function_privilege_id_name(PG_FUNCTION_ARGS);
extern Datum has_schema_privilege_id_id(PG_FUNCTION_ARGS);
extern Datum has_schema_privilege_name(PG_FUNCTION_ARGS);
extern Datum has_schema_privilege_id(PG_FUNCTION_ARGS);
+extern Datum has_server_privilege_name_name(PG_FUNCTION_ARGS);
+extern Datum has_server_privilege_name_id(PG_FUNCTION_ARGS);
+extern Datum has_server_privilege_id_name(PG_FUNCTION_ARGS);
+extern Datum has_server_privilege_id_id(PG_FUNCTION_ARGS);
+extern Datum has_server_privilege_name(PG_FUNCTION_ARGS);
+extern Datum has_server_privilege_id(PG_FUNCTION_ARGS);
extern Datum has_tablespace_privilege_name_name(PG_FUNCTION_ARGS);
extern Datum has_tablespace_privilege_name_id(PG_FUNCTION_ARGS);
extern Datum has_tablespace_privilege_id_name(PG_FUNCTION_ARGS);
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.72 2008/05/07 01:04:49 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/syscache.h,v 1.73 2008/12/19 16:25:19 petere Exp $
*
*-------------------------------------------------------------------------
*/
DATABASEOID,
ENUMOID,
ENUMTYPOIDNAME,
+ FOREIGNDATAWRAPPERNAME,
+ FOREIGNDATAWRAPPEROID,
+ FOREIGNSERVERNAME,
+ FOREIGNSERVEROID,
INDEXRELID,
LANGNAME,
LANGOID,
TSTEMPLATENAMENSP,
TSTEMPLATEOID,
TYPENAMENSP,
- TYPEOID
+ TYPEOID,
+ USERMAPPINGOID,
+ USERMAPPINGUSERSERVER
};
extern void InitCatalogCache(void);
--- /dev/null
+--
+-- Test foreign-data wrapper and server management.
+--
+-- Clean up in case a prior regression run failed
+-- Suppress NOTICE messages when roles don't exist
+SET client_min_messages TO 'error';
+DROP ROLE IF EXISTS foreign_data_user, regress_test_role, regress_test_role2, regress_test_role_super, regress_test_indirect, unpriviled_role;
+RESET client_min_messages;
+CREATE ROLE foreign_data_user LOGIN SUPERUSER;
+SET SESSION AUTHORIZATION 'foreign_data_user';
+CREATE ROLE regress_test_role;
+CREATE ROLE regress_test_role2;
+CREATE ROLE regress_test_role_super SUPERUSER;
+CREATE ROLE regress_test_indirect;
+CREATE ROLE unprivileged_role;
+CREATE FOREIGN DATA WRAPPER dummy LIBRARY 'dummy_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER postgresql LIBRARY 'postgresql_fdw' LANGUAGE C;
+-- At this point we should have 2 built-in wrappers and no servers.
+SELECT fdwname, fdwlibrary, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3;
+ fdwname | fdwlibrary | fdwoptions
+------------+----------------+------------
+ dummy | dummy_fdw |
+ postgresql | postgresql_fdw |
+(2 rows)
+
+SELECT srvname, srvoptions FROM pg_foreign_server;
+ srvname | srvoptions
+---------+------------
+(0 rows)
+
+SELECT * FROM pg_user_mapping;
+ umuser | umserver | umoptions
+--------+----------+-----------
+(0 rows)
+
+-- CREATE FOREIGN DATA WRAPPER
+CREATE FOREIGN DATA WRAPPER foo LIBRARY '' LANGUAGE C; -- ERROR
+ERROR: could not access file "": No such file or directory
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql' LANGUAGE C;
+DROP FOREIGN DATA WRAPPER foo;
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C;
+\dew
+ List of foreign-data wrappers
+ Name | Owner | Library
+------------+-------------------+----------------
+ dummy | foreign_data_user | dummy_fdw
+ foo | foreign_data_user | dummy_fdw
+ postgresql | foreign_data_user | postgresql_fdw
+(3 rows)
+
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C; -- duplicate
+ERROR: foreign-data wrapper "foo" already exists
+CREATE FOREIGN DATA WRAPPER "Foo" LIBRARY 'dummy_fdw' LANGUAGE C;
+DROP FOREIGN DATA WRAPPER "Foo";
+DROP FOREIGN DATA WRAPPER foo;
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1');
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+-------------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | foreign_data_user | dummy_fdw | | {testing=1}
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+DROP FOREIGN DATA WRAPPER foo;
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1', testing '2'); -- ERROR
+ERROR: option "testing" provided more than once
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1', another '2');
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+-----------------------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | foreign_data_user | dummy_fdw | | {testing=1,another=2}
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+DROP FOREIGN DATA WRAPPER foo;
+SET ROLE regress_test_role;
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+ERROR: permission denied to create foreign-data wrapper "foo"
+HINT: Must be superuser to create a foreign-data wrapper.
+RESET ROLE;
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'postgresql_fdw' LANGUAGE C;
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+---------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | foreign_data_user | postgresql_fdw | |
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+-- ALTER FOREIGN DATA WRAPPER
+ALTER FOREIGN DATA WRAPPER foo LIBRARY ''; -- ERROR
+ERROR: could not access file "": No such file or directory
+ALTER FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql';
+WARNING: changing the foreign-data wrapper library can cause the options for dependent objects to become invalid
+ALTER FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw';
+WARNING: changing the foreign-data wrapper library can cause the options for dependent objects to become invalid
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+---------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | foreign_data_user | dummy_fdw | |
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (a '1', b '2');
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (SET c '4'); -- ERROR
+ERROR: option "c" not found
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (DROP c); -- ERROR
+ERROR: option "c" not found
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD x '1', DROP x);
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+-----------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | foreign_data_user | dummy_fdw | | {a=1,b=2}
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (DROP a, SET b '3', ADD c '4');
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+-----------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | foreign_data_user | dummy_fdw | | {b=3,c=4}
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (a '2');
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (b '4'); -- ERROR
+ERROR: option "b" provided more than once
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+---------------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | foreign_data_user | dummy_fdw | | {b=3,c=4,a=2}
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+SET ROLE regress_test_role;
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD d '5'); -- ERROR
+ERROR: permission denied to alter foreign-data wrapper "foo"
+HINT: Must be superuser to alter a foreign-data wrapper.
+SET ROLE regress_test_role_super;
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD d '5');
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+-------------------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | foreign_data_user | dummy_fdw | | {b=3,c=4,a=2,d=5}
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+ALTER FOREIGN DATA WRAPPER foo OWNER TO regress_test_role; -- ERROR
+ERROR: permission denied to change owner of foreign-data wrapper "foo"
+HINT: The owner of a foreign-data wrapper must be a superuser.
+ALTER FOREIGN DATA WRAPPER foo OWNER TO regress_test_role_super;
+ALTER ROLE regress_test_role_super NOSUPERUSER;
+SET ROLE regress_test_role_super;
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD e '6'); -- ERROR
+ERROR: permission denied to alter foreign-data wrapper "foo"
+HINT: Must be superuser to alter a foreign-data wrapper.
+RESET ROLE;
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------------+----------------+-------------------+-------------------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | regress_test_role_super | dummy_fdw | | {b=3,c=4,a=2,d=5}
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+-- DROP FOREIGN DATA WRAPPER
+DROP FOREIGN DATA WRAPPER nonexistent; -- ERROR
+ERROR: foreign-data wrapper "nonexistent" does not exist
+DROP FOREIGN DATA WRAPPER IF EXISTS nonexistent;
+NOTICE: foreign-data wrapper "nonexistent" does not exist, skipping
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------------+----------------+-------------------+-------------------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | regress_test_role_super | dummy_fdw | | {b=3,c=4,a=2,d=5}
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+DROP ROLE regress_test_role_super; -- ERROR
+ERROR: role "regress_test_role_super" cannot be dropped because some objects depend on it
+DETAIL: owner of foreign-data wrapper foo
+SET ROLE regress_test_role_super;
+DROP FOREIGN DATA WRAPPER foo; -- ERROR
+ERROR: permission denied to drop foreign-data wrapper "foo"
+HINT: Must be superuser to drop a foreign-data wrapper.
+RESET ROLE;
+ALTER ROLE regress_test_role_super SUPERUSER;
+DROP FOREIGN DATA WRAPPER foo;
+DROP ROLE regress_test_role_super;
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+---------
+ dummy | foreign_data_user | dummy_fdw | |
+ postgresql | foreign_data_user | postgresql_fdw | |
+(2 rows)
+
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C;
+CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
+CREATE USER MAPPING FOR current_user SERVER s1;
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+---------
+ dummy | foreign_data_user | dummy_fdw | |
+ foo | foreign_data_user | dummy_fdw | |
+ postgresql | foreign_data_user | postgresql_fdw | |
+(3 rows)
+
+\des+
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | Options
+------+-------------------+----------------------+-------------------+------+---------+---------
+ s1 | foreign_data_user | foo | | | |
+(1 row)
+
+\deu+
+ List of user mappings
+ Server | Username | Options
+--------+-------------------+---------
+ s1 | foreign_data_user |
+(1 row)
+
+DROP FOREIGN DATA WRAPPER foo; -- ERROR
+ERROR: cannot drop foreign-data wrapper foo because other objects depend on it
+DETAIL: server s1 depends on foreign-data wrapper foo
+user mapping for foreign_data_user depends on server s1
+HINT: Use DROP ... CASCADE to drop the dependent objects too.
+SET ROLE regress_test_role;
+DROP FOREIGN DATA WRAPPER foo CASCADE; -- ERROR
+ERROR: permission denied to drop foreign-data wrapper "foo"
+HINT: Must be superuser to drop a foreign-data wrapper.
+RESET ROLE;
+DROP FOREIGN DATA WRAPPER foo CASCADE;
+NOTICE: drop cascades to 2 other objects
+DETAIL: drop cascades to server s1
+drop cascades to user mapping for foreign_data_user
+\dew+
+ List of foreign-data wrappers
+ Name | Owner | Library | Access privileges | Options
+------------+-------------------+----------------+-------------------+---------
+ dummy | foreign_data_user | dummy_fdw | |
+ postgresql | foreign_data_user | postgresql_fdw | |
+(2 rows)
+
+\des+
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | Options
+------+-------+----------------------+-------------------+------+---------+---------
+(0 rows)
+
+\deu+
+ List of user mappings
+ Server | Username | Options
+--------+----------+---------
+(0 rows)
+
+-- exercise CREATE SERVER
+CREATE SERVER s1 FOREIGN DATA WRAPPER foo; -- ERROR
+ERROR: foreign-data wrapper "foo" does not exist
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (test_wrapper 'true');
+CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
+CREATE SERVER s1 FOREIGN DATA WRAPPER foo; -- ERROR
+ERROR: server "s1" already exists
+CREATE SERVER s2 FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
+CREATE SERVER s3 TYPE 'oracle' FOREIGN DATA WRAPPER foo;
+CREATE SERVER s4 TYPE 'oracle' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
+CREATE SERVER s5 VERSION '15.0' FOREIGN DATA WRAPPER foo;
+CREATE SERVER s6 VERSION '16.0' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
+CREATE SERVER "S6" FOREIGN DATA WRAPPER foo OPTIONS (mixed_case_names 'true');
+CREATE SERVER s7 TYPE 'oracle' VERSION '17.0' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
+CREATE SERVER s8 FOREIGN DATA WRAPPER postgresql OPTIONS (foo '1'); -- ERROR
+ERROR: invalid option "foo" to server
+HINT: valid server options are: authtype, service, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib
+CREATE SERVER s8 FOREIGN DATA WRAPPER postgresql OPTIONS (host 'localhost', dbname 's8db');
+\des+
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | Options
+------+-------------------+----------------------+-------------------+--------+---------+------------------------------
+ S6 | foreign_data_user | foo | | | | {mixed_case_names=true}
+ s1 | foreign_data_user | foo | | | |
+ s2 | foreign_data_user | foo | | | | {host=a,dbname=b}
+ s3 | foreign_data_user | foo | | oracle | |
+ s4 | foreign_data_user | foo | | oracle | | {host=a,dbname=b}
+ s5 | foreign_data_user | foo | | | 15.0 |
+ s6 | foreign_data_user | foo | | | 16.0 | {host=a,dbname=b}
+ s7 | foreign_data_user | foo | | oracle | 17.0 | {host=a,dbname=b}
+ s8 | foreign_data_user | postgresql | | | | {host=localhost,dbname=s8db}
+(9 rows)
+
+SET ROLE regress_test_role;
+CREATE SERVER st1 FOREIGN DATA WRAPPER foo; -- ERROR: no usage on FDW
+ERROR: permission denied for foreign-data wrapper foo
+RESET ROLE;
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role;
+SET ROLE regress_test_role;
+CREATE SERVER st1 FOREIGN DATA WRAPPER foo;
+RESET ROLE;
+\des+
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | Options
+------+-------------------+----------------------+-------------------+--------+---------+------------------------------
+ S6 | foreign_data_user | foo | | | | {mixed_case_names=true}
+ s1 | foreign_data_user | foo | | | |
+ s2 | foreign_data_user | foo | | | | {host=a,dbname=b}
+ s3 | foreign_data_user | foo | | oracle | |
+ s4 | foreign_data_user | foo | | oracle | | {host=a,dbname=b}
+ s5 | foreign_data_user | foo | | | 15.0 |
+ s6 | foreign_data_user | foo | | | 16.0 | {host=a,dbname=b}
+ s7 | foreign_data_user | foo | | oracle | 17.0 | {host=a,dbname=b}
+ s8 | foreign_data_user | postgresql | | | | {host=localhost,dbname=s8db}
+ st1 | regress_test_role | foo | | | |
+(10 rows)
+
+REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM regress_test_role;
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_indirect;
+SET ROLE regress_test_role;
+CREATE SERVER st2 FOREIGN DATA WRAPPER foo; -- ERROR
+ERROR: permission denied for foreign-data wrapper foo
+RESET ROLE;
+GRANT regress_test_indirect TO regress_test_role;
+SET ROLE regress_test_role;
+CREATE SERVER st2 FOREIGN DATA WRAPPER foo;
+\des+
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | Options
+------+-------------------+----------------------+-------------------+--------+---------+------------------------------
+ S6 | foreign_data_user | foo | | | | {mixed_case_names=true}
+ s1 | foreign_data_user | foo | | | |
+ s2 | foreign_data_user | foo | | | | {host=a,dbname=b}
+ s3 | foreign_data_user | foo | | oracle | |
+ s4 | foreign_data_user | foo | | oracle | | {host=a,dbname=b}
+ s5 | foreign_data_user | foo | | | 15.0 |
+ s6 | foreign_data_user | foo | | | 16.0 | {host=a,dbname=b}
+ s7 | foreign_data_user | foo | | oracle | 17.0 | {host=a,dbname=b}
+ s8 | foreign_data_user | postgresql | | | | {host=localhost,dbname=s8db}
+ st1 | regress_test_role | foo | | | |
+ st2 | regress_test_role | foo | | | |
+(11 rows)
+
+RESET ROLE;
+REVOKE regress_test_indirect FROM regress_test_role;
+-- ALTER SERVER
+ALTER SERVER s0; -- ERROR
+ERROR: syntax error at or near ";"
+LINE 1: ALTER SERVER s0;
+ ^
+ALTER SERVER s0 OPTIONS (a '1'); -- ERROR
+ERROR: server "s0" does not exist
+ALTER SERVER s1 VERSION '1.0' OPTIONS (servername 's1');
+ALTER SERVER s2 VERSION '1.1';
+ALTER SERVER s3 OPTIONS (tnsname 'orcl', port '1521');
+GRANT USAGE ON FOREIGN SERVER s1 TO regress_test_role;
+GRANT USAGE ON FOREIGN SERVER s6 TO regress_test_role2 WITH GRANT OPTION;
+\des+
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | Options
+------+-------------------+----------------------+---------------------------------------------------------------------------------+--------+---------+------------------------------
+ S6 | foreign_data_user | foo | | | | {mixed_case_names=true}
+ s1 | foreign_data_user | foo | {foreign_data_user=U/foreign_data_user,regress_test_role=U/foreign_data_user} | | 1.0 | {servername=s1}
+ s2 | foreign_data_user | foo | | | 1.1 | {host=a,dbname=b}
+ s3 | foreign_data_user | foo | | oracle | | {tnsname=orcl,port=1521}
+ s4 | foreign_data_user | foo | | oracle | | {host=a,dbname=b}
+ s5 | foreign_data_user | foo | | | 15.0 |
+ s6 | foreign_data_user | foo | {foreign_data_user=U/foreign_data_user,regress_test_role2=U*/foreign_data_user} | | 16.0 | {host=a,dbname=b}
+ s7 | foreign_data_user | foo | | oracle | 17.0 | {host=a,dbname=b}
+ s8 | foreign_data_user | postgresql | | | | {host=localhost,dbname=s8db}
+ st1 | regress_test_role | foo | | | |
+ st2 | regress_test_role | foo | | | |
+(11 rows)
+
+SET ROLE regress_test_role;
+ALTER SERVER s1 VERSION '1.1'; -- ERROR
+ERROR: must be owner of foreign server s1
+ALTER SERVER s1 OWNER TO regress_test_role; -- ERROR
+ERROR: must be owner of foreign server s1
+RESET ROLE;
+ALTER SERVER s1 OWNER TO regress_test_role;
+GRANT regress_test_role2 TO regress_test_role;
+SET ROLE regress_test_role;
+ALTER SERVER s1 VERSION '1.1';
+ALTER SERVER s1 OWNER TO regress_test_role2; -- ERROR
+ERROR: permission denied for foreign-data wrapper foo
+RESET ROLE;
+ALTER SERVER s8 OPTIONS (foo '1'); -- ERROR option validation
+ERROR: invalid option "foo" to server
+HINT: valid server options are: authtype, service, connect_timeout, dbname, host, hostaddr, port, tty, options, requiressl, sslmode, gsslib
+ALTER SERVER s8 OPTIONS (connect_timeout '30', SET dbname 'db1', DROP host);
+SET ROLE regress_test_role;
+ALTER SERVER s1 OWNER TO regress_test_indirect; -- ERROR
+ERROR: must be member of role "regress_test_indirect"
+RESET ROLE;
+GRANT regress_test_indirect TO regress_test_role;
+SET ROLE regress_test_role;
+ALTER SERVER s1 OWNER TO regress_test_indirect;
+RESET ROLE;
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_indirect;
+SET ROLE regress_test_role;
+ALTER SERVER s1 OWNER TO regress_test_indirect;
+RESET ROLE;
+DROP ROLE regress_test_indirect; -- ERROR
+ERROR: role "regress_test_indirect" cannot be dropped because some objects depend on it
+DETAIL: owner of server s1
+access to foreign-data wrapper foo
+\des+
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper | Access privileges | Type | Version | Options
+------+-----------------------+----------------------+---------------------------------------------------------------------------------+--------+---------+---------------------------------
+ S6 | foreign_data_user | foo | | | | {mixed_case_names=true}
+ s1 | regress_test_indirect | foo | {foreign_data_user=U/foreign_data_user,regress_test_role=U/foreign_data_user} | | 1.1 | {servername=s1}
+ s2 | foreign_data_user | foo | | | 1.1 | {host=a,dbname=b}
+ s3 | foreign_data_user | foo | | oracle | | {tnsname=orcl,port=1521}
+ s4 | foreign_data_user | foo | | oracle | | {host=a,dbname=b}
+ s5 | foreign_data_user | foo | | | 15.0 |
+ s6 | foreign_data_user | foo | {foreign_data_user=U/foreign_data_user,regress_test_role2=U*/foreign_data_user} | | 16.0 | {host=a,dbname=b}
+ s7 | foreign_data_user | foo | | oracle | 17.0 | {host=a,dbname=b}
+ s8 | foreign_data_user | postgresql | | | | {dbname=db1,connect_timeout=30}
+ st1 | regress_test_role | foo | | | |
+ st2 | regress_test_role | foo | | | |
+(11 rows)
+
+-- DROP SERVER
+DROP SERVER nonexistent; -- ERROR
+ERROR: server "nonexistent" does not exist
+DROP SERVER IF EXISTS nonexistent;
+NOTICE: server "nonexistent" does not exist, skipping
+\des
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper
+------+-----------------------+----------------------
+ S6 | foreign_data_user | foo
+ s1 | regress_test_indirect | foo
+ s2 | foreign_data_user | foo
+ s3 | foreign_data_user | foo
+ s4 | foreign_data_user | foo
+ s5 | foreign_data_user | foo
+ s6 | foreign_data_user | foo
+ s7 | foreign_data_user | foo
+ s8 | foreign_data_user | postgresql
+ st1 | regress_test_role | foo
+ st2 | regress_test_role | foo
+(11 rows)
+
+SET ROLE regress_test_role;
+DROP SERVER s2; -- ERROR
+ERROR: must be owner of foreign server s2
+DROP SERVER s1;
+RESET ROLE;
+\des
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper
+------+-------------------+----------------------
+ S6 | foreign_data_user | foo
+ s2 | foreign_data_user | foo
+ s3 | foreign_data_user | foo
+ s4 | foreign_data_user | foo
+ s5 | foreign_data_user | foo
+ s6 | foreign_data_user | foo
+ s7 | foreign_data_user | foo
+ s8 | foreign_data_user | postgresql
+ st1 | regress_test_role | foo
+ st2 | regress_test_role | foo
+(10 rows)
+
+ALTER SERVER s2 OWNER TO regress_test_role;
+SET ROLE regress_test_role;
+DROP SERVER s2;
+RESET ROLE;
+\des
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper
+------+-------------------+----------------------
+ S6 | foreign_data_user | foo
+ s3 | foreign_data_user | foo
+ s4 | foreign_data_user | foo
+ s5 | foreign_data_user | foo
+ s6 | foreign_data_user | foo
+ s7 | foreign_data_user | foo
+ s8 | foreign_data_user | postgresql
+ st1 | regress_test_role | foo
+ st2 | regress_test_role | foo
+(9 rows)
+
+CREATE USER MAPPING FOR current_user SERVER s3;
+\deu
+ List of user mappings
+ Server | Username
+--------+-------------------
+ s3 | foreign_data_user
+(1 row)
+
+DROP SERVER s3; -- ERROR
+ERROR: cannot drop server s3 because other objects depend on it
+DETAIL: user mapping for foreign_data_user depends on server s3
+HINT: Use DROP ... CASCADE to drop the dependent objects too.
+DROP SERVER s3 CASCADE;
+NOTICE: drop cascades to user mapping for foreign_data_user
+\des
+ List of foreign servers
+ Name | Owner | Foreign-data wrapper
+------+-------------------+----------------------
+ S6 | foreign_data_user | foo
+ s4 | foreign_data_user | foo
+ s5 | foreign_data_user | foo
+ s6 | foreign_data_user | foo
+ s7 | foreign_data_user | foo
+ s8 | foreign_data_user | postgresql
+ st1 | regress_test_role | foo
+ st2 | regress_test_role | foo
+(8 rows)
+
+\deu
+List of user mappings
+ Server | Username
+--------+----------
+(0 rows)
+
+-- CREATE USER MAPPING
+CREATE USER MAPPING FOR baz SERVER s1; -- ERROR
+ERROR: role "baz" does not exist
+CREATE USER MAPPING FOR current_user SERVER s1; -- ERROR
+ERROR: server "s1" does not exist
+CREATE USER MAPPING FOR current_user SERVER s4;
+CREATE USER MAPPING FOR user SERVER s4; -- ERROR duplicate
+ERROR: user mapping "foreign_data_user" already exists for server s4
+CREATE USER MAPPING FOR public SERVER s4 OPTIONS (mapping 'is public');
+CREATE USER MAPPING FOR user SERVER s8 OPTIONS (username 'test', password 'secret'); -- ERROR
+ERROR: invalid option "username" to user mapping
+HINT: valid user mapping options are: user, password
+CREATE USER MAPPING FOR user SERVER s8 OPTIONS (user 'test', password 'secret');
+ALTER SERVER s5 OWNER TO regress_test_role;
+ALTER SERVER s6 OWNER TO regress_test_indirect;
+SET ROLE regress_test_role;
+CREATE USER MAPPING FOR current_user SERVER s5;
+CREATE USER MAPPING FOR current_user SERVER s6 OPTIONS (username 'test');
+CREATE USER MAPPING FOR current_user SERVER s7; -- ERROR
+ERROR: must be owner of foreign server s7
+CREATE USER MAPPING FOR public SERVER s8; -- ERROR
+ERROR: must be owner of foreign server s8
+RESET ROLE;
+CREATE USER MAPPING FOR current_user SERVER "S6" OPTIONS (username 'test_mixed_case');
+ALTER SERVER st1 OWNER TO regress_test_indirect;
+SET ROLE regress_test_role;
+CREATE USER MAPPING FOR current_user SERVER st1 OPTIONS (username 'bob', password 'boo');
+CREATE USER MAPPING FOR public SERVER st1;
+RESET ROLE;
+\deu
+ List of user mappings
+ Server | Username
+--------+-------------------
+ S6 | foreign_data_user
+ s4 | foreign_data_user
+ s4 | public
+ s5 | regress_test_role
+ s6 | regress_test_role
+ s8 | foreign_data_user
+ st1 | public
+ st1 | regress_test_role
+(8 rows)
+
+-- ALTER USER MAPPING
+ALTER USER MAPPING FOR bob SERVER s4 OPTIONS (gotcha 'true'); -- ERROR
+ERROR: role "bob" does not exist
+ALTER USER MAPPING FOR user SERVER ss4 OPTIONS (gotcha 'true'); -- ERROR
+ERROR: server "ss4" does not exist
+ALTER USER MAPPING FOR public SERVER s5 OPTIONS (gotcha 'true'); -- ERROR
+ERROR: user mapping "public" does not exist for the server
+ALTER USER MAPPING FOR current_user SERVER s8 OPTIONS (username 'test'); -- ERROR
+ERROR: invalid option "username" to user mapping
+HINT: valid user mapping options are: user, password
+ALTER USER MAPPING FOR current_user SERVER s8 OPTIONS (DROP user, SET password 'public');
+SET ROLE regress_test_role;
+ALTER USER MAPPING FOR current_user SERVER s5 OPTIONS (ADD modified '1');
+ALTER USER MAPPING FOR public SERVER s4 OPTIONS (ADD modified '1'); -- ERROR
+ERROR: must be owner of foreign server s4
+ALTER USER MAPPING FOR public SERVER st1 OPTIONS (ADD modified '1');
+RESET ROLE;
+\deu+
+ List of user mappings
+ Server | Username | Options
+--------+-------------------+-----------------------------
+ S6 | foreign_data_user | {username=test_mixed_case}
+ s4 | foreign_data_user |
+ s4 | public | {"mapping=is public"}
+ s5 | regress_test_role | {modified=1}
+ s6 | regress_test_role | {username=test}
+ s8 | foreign_data_user | {password=public}
+ st1 | public | {modified=1}
+ st1 | regress_test_role | {username=bob,password=boo}
+(8 rows)
+
+-- DROP USER MAPPING
+DROP USER MAPPING FOR bob SERVER s4; -- ERROR
+ERROR: role "bob" does not exist
+DROP USER MAPPING FOR user SERVER ss4;
+ERROR: server "ss4" does not exist
+DROP USER MAPPING FOR public SERVER s7; -- ERROR
+ERROR: user mapping "public" does not exist for the server
+DROP USER MAPPING IF EXISTS FOR bob SERVER s4;
+NOTICE: role "bob" does not exist, skipping
+DROP USER MAPPING IF EXISTS FOR user SERVER ss4;
+NOTICE: server does not exist, skipping
+DROP USER MAPPING IF EXISTS FOR public SERVER s7;
+NOTICE: user mapping "public" does not exist for the server, skipping
+CREATE USER MAPPING FOR public SERVER s8;
+SET ROLE regress_test_role;
+DROP USER MAPPING FOR public SERVER s8; -- ERROR
+ERROR: must be owner of foreign server s8
+RESET ROLE;
+DROP SERVER s7;
+\deu
+ List of user mappings
+ Server | Username
+--------+-------------------
+ S6 | foreign_data_user
+ s4 | foreign_data_user
+ s4 | public
+ s5 | regress_test_role
+ s6 | regress_test_role
+ s8 | foreign_data_user
+ s8 | public
+ st1 | public
+ st1 | regress_test_role
+(9 rows)
+
+-- Information schema
+SELECT * FROM information_schema.foreign_data_wrappers ORDER BY 1, 2;
+ foreign_data_wrapper_catalog | foreign_data_wrapper_name | authorization_identifier | library_name | foreign_data_wrapper_language
+------------------------------+---------------------------+--------------------------+----------------+-------------------------------
+ regression | dummy | foreign_data_user | dummy_fdw | c
+ regression | foo | foreign_data_user | dummy_fdw | c
+ regression | postgresql | foreign_data_user | postgresql_fdw | c
+(3 rows)
+
+SELECT * FROM information_schema.foreign_data_wrapper_options ORDER BY 1, 2, 3;
+ foreign_data_wrapper_catalog | foreign_data_wrapper_name | option_name | option_value
+------------------------------+---------------------------+--------------+--------------
+ regression | foo | test_wrapper | true
+(1 row)
+
+SELECT * FROM information_schema.foreign_servers ORDER BY 1, 2;
+ foreign_server_catalog | foreign_server_name | foreign_data_wrapper_catalog | foreign_data_wrapper_name | foreign_server_type | foreign_server_version | authorization_identifier
+------------------------+---------------------+------------------------------+---------------------------+---------------------+------------------------+--------------------------
+ regression | S6 | regression | foo | | | foreign_data_user
+ regression | s4 | regression | foo | oracle | | foreign_data_user
+ regression | s5 | regression | foo | | 15.0 | regress_test_role
+ regression | s6 | regression | foo | | 16.0 | regress_test_indirect
+ regression | s8 | regression | postgresql | | | foreign_data_user
+ regression | st1 | regression | foo | | | regress_test_indirect
+ regression | st2 | regression | foo | | | regress_test_role
+(7 rows)
+
+SELECT * FROM information_schema.foreign_server_options ORDER BY 1, 2, 3;
+ foreign_server_catalog | foreign_server_name | option_name | option_value
+------------------------+---------------------+------------------+--------------
+ regression | S6 | mixed_case_names | true
+ regression | s4 | dbname | b
+ regression | s4 | host | a
+ regression | s6 | dbname | b
+ regression | s6 | host | a
+ regression | s8 | connect_timeout | 30
+ regression | s8 | dbname | db1
+(7 rows)
+
+SELECT * FROM information_schema.user_mappings ORDER BY 1, 2, 3;
+ authorization_identifier | foreign_server_catalog | foreign_server_name
+--------------------------+------------------------+---------------------
+ PUBLIC | regression | s4
+ PUBLIC | regression | s8
+ PUBLIC | regression | st1
+ foreign_data_user | regression | S6
+ foreign_data_user | regression | s4
+ foreign_data_user | regression | s8
+ regress_test_role | regression | s5
+ regress_test_role | regression | s6
+ regress_test_role | regression | st1
+(9 rows)
+
+SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4;
+ authorization_identifier | foreign_server_catalog | foreign_server_name | option_name | option_value
+--------------------------+------------------------+---------------------+-------------+-----------------
+ PUBLIC | regression | s4 | mapping | is public
+ PUBLIC | regression | st1 | modified | 1
+ foreign_data_user | regression | S6 | username | test_mixed_case
+ foreign_data_user | regression | s8 | password | public
+ regress_test_role | regression | s5 | modified | 1
+ regress_test_role | regression | s6 | username | test
+ regress_test_role | regression | st1 | password | boo
+ regress_test_role | regression | st1 | username | bob
+(8 rows)
+
+SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+ grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable
+-------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+--------------
+ foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
+ foreign_data_user | foreign_data_user | regression | | s6 | FOREIGN SERVER | USAGE | NO
+ foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
+ foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
+(4 rows)
+
+SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+ grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable
+-------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+--------------
+ foreign_data_user | foreign_data_user | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
+ foreign_data_user | foreign_data_user | regression | | s6 | FOREIGN SERVER | USAGE | NO
+ foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
+ foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
+(4 rows)
+
+SET ROLE regress_test_role;
+SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4;
+ authorization_identifier | foreign_server_catalog | foreign_server_name | option_name | option_value
+--------------------------+------------------------+---------------------+-------------+--------------
+ PUBLIC | regression | st1 | modified | 1
+ regress_test_role | regression | s5 | modified | 1
+ regress_test_role | regression | s6 | username | test
+ regress_test_role | regression | st1 | password | boo
+ regress_test_role | regression | st1 | username | bob
+(5 rows)
+
+SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+ grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable
+-------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+--------------
+ foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
+ foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
+(2 rows)
+
+SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+ grantor | grantee | object_catalog | object_schema | object_name | object_type | privilege_type | is_grantable
+-------------------+-----------------------+----------------+---------------+-------------+----------------------+----------------+--------------
+ foreign_data_user | regress_test_indirect | regression | | foo | FOREIGN DATA WRAPPER | USAGE | NO
+ foreign_data_user | regress_test_role2 | regression | | s6 | FOREIGN SERVER | USAGE | YES
+(2 rows)
+
+DROP USER MAPPING FOR current_user SERVER st1;
+RESET ROLE;
+-- has_foreign_data_wrapper_privilege
+SELECT has_foreign_data_wrapper_privilege('regress_test_role',
+ (SELECT oid FROM pg_foreign_data_wrapper WHERE fdwname='foo'), 'USAGE');
+ has_foreign_data_wrapper_privilege
+------------------------------------
+ t
+(1 row)
+
+SELECT has_foreign_data_wrapper_privilege('regress_test_role', 'foo', 'USAGE');
+ has_foreign_data_wrapper_privilege
+------------------------------------
+ t
+(1 row)
+
+SELECT has_foreign_data_wrapper_privilege(
+ (SELECT oid FROM pg_roles WHERE rolname='regress_test_role'),
+ (SELECT oid FROM pg_foreign_data_wrapper WHERE fdwname='foo'), 'USAGE');
+ has_foreign_data_wrapper_privilege
+------------------------------------
+ t
+(1 row)
+
+SELECT has_foreign_data_wrapper_privilege(
+ (SELECT oid FROM pg_foreign_data_wrapper WHERE fdwname='foo'), 'USAGE');
+ has_foreign_data_wrapper_privilege
+------------------------------------
+ t
+(1 row)
+
+SELECT has_foreign_data_wrapper_privilege(
+ (SELECT oid FROM pg_roles WHERE rolname='regress_test_role'), 'foo', 'USAGE');
+ has_foreign_data_wrapper_privilege
+------------------------------------
+ t
+(1 row)
+
+SELECT has_foreign_data_wrapper_privilege('foo', 'USAGE');
+ has_foreign_data_wrapper_privilege
+------------------------------------
+ t
+(1 row)
+
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role;
+SELECT has_foreign_data_wrapper_privilege('regress_test_role', 'foo', 'USAGE');
+ has_foreign_data_wrapper_privilege
+------------------------------------
+ t
+(1 row)
+
+-- has_server_privilege
+SELECT has_server_privilege('regress_test_role',
+ (SELECT oid FROM pg_foreign_server WHERE srvname='s8'), 'USAGE');
+ has_server_privilege
+----------------------
+ f
+(1 row)
+
+SELECT has_server_privilege('regress_test_role', 's8', 'USAGE');
+ has_server_privilege
+----------------------
+ f
+(1 row)
+
+SELECT has_server_privilege(
+ (SELECT oid FROM pg_roles WHERE rolname='regress_test_role'),
+ (SELECT oid FROM pg_foreign_server WHERE srvname='s8'), 'USAGE');
+ has_server_privilege
+----------------------
+ f
+(1 row)
+
+SELECT has_server_privilege(
+ (SELECT oid FROM pg_foreign_server WHERE srvname='s8'), 'USAGE');
+ has_server_privilege
+----------------------
+ t
+(1 row)
+
+SELECT has_server_privilege(
+ (SELECT oid FROM pg_roles WHERE rolname='regress_test_role'), 's8', 'USAGE');
+ has_server_privilege
+----------------------
+ f
+(1 row)
+
+SELECT has_server_privilege('s8', 'USAGE');
+ has_server_privilege
+----------------------
+ t
+(1 row)
+
+GRANT USAGE ON FOREIGN SERVER s8 TO regress_test_role;
+SELECT has_server_privilege('regress_test_role', 's8', 'USAGE');
+ has_server_privilege
+----------------------
+ t
+(1 row)
+
+REVOKE USAGE ON FOREIGN SERVER s8 FROM regress_test_role;
+GRANT USAGE ON FOREIGN SERVER s4 TO regress_test_role;
+DROP USER MAPPING FOR public SERVER s4;
+ALTER SERVER s6 OPTIONS (DROP host, DROP dbname);
+ALTER USER MAPPING FOR regress_test_role SERVER s6 OPTIONS (DROP username);
+ALTER FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql';
+WARNING: changing the foreign-data wrapper library can cause the options for dependent objects to become invalid
+ALTER FOREIGN DATA WRAPPER foo LIBRARY 'default_fdw';
+ERROR: could not access file "default_fdw": No such file or directory
+-- Privileges
+SET ROLE unprivileged_role;
+CREATE FOREIGN DATA WRAPPER foobar LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+ERROR: permission denied to create foreign-data wrapper "foobar"
+HINT: Must be superuser to create a foreign-data wrapper.
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (gotcha 'true'); -- ERROR
+ERROR: permission denied to alter foreign-data wrapper "foo"
+HINT: Must be superuser to alter a foreign-data wrapper.
+ALTER FOREIGN DATA WRAPPER foo OWNER TO unprivileged_role; -- ERROR
+ERROR: permission denied to change owner of foreign-data wrapper "foo"
+HINT: Must be superuser to change owner of a foreign-data wrapper.
+DROP FOREIGN DATA WRAPPER foo; -- ERROR
+ERROR: permission denied to drop foreign-data wrapper "foo"
+HINT: Must be superuser to drop a foreign-data wrapper.
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role; -- ERROR
+ERROR: permission denied for foreign-data wrapper foo
+CREATE SERVER s9 FOREIGN DATA WRAPPER foo; -- ERROR
+ERROR: permission denied for foreign-data wrapper foo
+ALTER SERVER s4 VERSION '0.5'; -- ERROR
+ERROR: must be owner of foreign server s4
+ALTER SERVER s4 OWNER TO unprivileged_role; -- ERROR
+ERROR: must be owner of foreign server s4
+DROP SERVER s4; -- ERROR
+ERROR: must be owner of foreign server s4
+GRANT USAGE ON FOREIGN SERVER s4 TO regress_test_role; -- ERROR
+ERROR: permission denied for foreign server s4
+CREATE USER MAPPING FOR public SERVER s4; -- ERROR
+ERROR: must be owner of foreign server s4
+ALTER USER MAPPING FOR regress_test_role SERVER s6 OPTIONS (gotcha 'true'); -- ERROR
+ERROR: must be owner of foreign server s6
+DROP USER MAPPING FOR regress_test_role SERVER s6; -- ERROR
+ERROR: must be owner of foreign server s6
+RESET ROLE;
+GRANT USAGE ON FOREIGN DATA WRAPPER postgresql TO unprivileged_role;
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO unprivileged_role WITH GRANT OPTION;
+SET ROLE unprivileged_role;
+CREATE FOREIGN DATA WRAPPER foobar LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+ERROR: permission denied to create foreign-data wrapper "foobar"
+HINT: Must be superuser to create a foreign-data wrapper.
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (gotcha 'true'); -- ERROR
+ERROR: permission denied to alter foreign-data wrapper "foo"
+HINT: Must be superuser to alter a foreign-data wrapper.
+DROP FOREIGN DATA WRAPPER foo; -- ERROR
+ERROR: permission denied to drop foreign-data wrapper "foo"
+HINT: Must be superuser to drop a foreign-data wrapper.
+GRANT USAGE ON FOREIGN DATA WRAPPER postgresql TO regress_test_role; -- WARNING
+WARNING: no privileges were granted for "postgresql"
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role;
+CREATE SERVER s9 FOREIGN DATA WRAPPER postgresql;
+ALTER SERVER s6 VERSION '0.5'; -- ERROR
+ERROR: must be owner of foreign server s6
+DROP SERVER s6; -- ERROR
+ERROR: must be owner of foreign server s6
+GRANT USAGE ON FOREIGN SERVER s6 TO regress_test_role; -- ERROR
+ERROR: permission denied for foreign server s6
+GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role;
+CREATE USER MAPPING FOR public SERVER s6; -- ERROR
+ERROR: must be owner of foreign server s6
+CREATE USER MAPPING FOR public SERVER s9;
+ALTER USER MAPPING FOR regress_test_role SERVER s6 OPTIONS (gotcha 'true'); -- ERROR
+ERROR: must be owner of foreign server s6
+DROP USER MAPPING FOR regress_test_role SERVER s6; -- ERROR
+ERROR: must be owner of foreign server s6
+RESET ROLE;
+REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM unprivileged_role; -- ERROR
+ERROR: dependent privileges exist
+HINT: Use CASCADE to revoke them too.
+REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM unprivileged_role CASCADE;
+SET ROLE unprivileged_role;
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role; -- ERROR
+ERROR: permission denied for foreign-data wrapper foo
+CREATE SERVER s10 FOREIGN DATA WRAPPER foo; -- ERROR
+ERROR: permission denied for foreign-data wrapper foo
+ALTER SERVER s9 VERSION '1.1';
+GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role;
+CREATE USER MAPPING FOR current_user SERVER s9;
+DROP SERVER s9 CASCADE;
+NOTICE: drop cascades to 2 other objects
+DETAIL: drop cascades to user mapping for public
+drop cascades to user mapping for unprivileged_role
+RESET ROLE;
+CREATE SERVER s9 FOREIGN DATA WRAPPER foo;
+GRANT USAGE ON FOREIGN SERVER s9 TO unprivileged_role;
+SET ROLE unprivileged_role;
+ALTER SERVER s9 VERSION '1.2'; -- ERROR
+ERROR: must be owner of foreign server s9
+GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role; -- WARNING
+WARNING: no privileges were granted for "s9"
+CREATE USER MAPPING FOR current_user SERVER s9; -- ERROR
+ERROR: must be owner of foreign server s9
+DROP SERVER s9 CASCADE; -- ERROR
+ERROR: must be owner of foreign server s9
+RESET ROLE;
+-- Cleanup
+DROP ROLE regress_test_role; -- ERROR
+ERROR: role "regress_test_role" cannot be dropped because some objects depend on it
+DETAIL: access to server s4
+access to foreign-data wrapper foo
+owner of user mapping for regress_test_role
+owner of user mapping for regress_test_role
+owner of server s5
+owner of server st2
+DROP SERVER s5 CASCADE;
+NOTICE: drop cascades to user mapping for regress_test_role
+DROP SERVER st1 CASCADE;
+NOTICE: drop cascades to user mapping for public
+DROP SERVER st2;
+DROP USER MAPPING FOR regress_test_role SERVER s6;
+DROP FOREIGN DATA WRAPPER foo CASCADE;
+NOTICE: drop cascades to 6 other objects
+DETAIL: drop cascades to server s4
+drop cascades to user mapping for foreign_data_user
+drop cascades to server s6
+drop cascades to server S6
+drop cascades to user mapping for foreign_data_user
+drop cascades to server s9
+DROP SERVER s8 CASCADE;
+NOTICE: drop cascades to 2 other objects
+DETAIL: drop cascades to user mapping for foreign_data_user
+drop cascades to user mapping for public
+DROP ROLE regress_test_indirect;
+DROP ROLE regress_test_role;
+DROP ROLE unprivileged_role; -- ERROR
+ERROR: role "unprivileged_role" cannot be dropped because some objects depend on it
+DETAIL: access to foreign-data wrapper postgresql
+REVOKE ALL ON FOREIGN DATA WRAPPER postgresql FROM unprivileged_role;
+DROP ROLE unprivileged_role;
+DROP ROLE regress_test_role2;
+DROP FOREIGN DATA WRAPPER postgresql CASCADE;
+DROP FOREIGN DATA WRAPPER dummy CASCADE;
+\c
+DROP ROLE foreign_data_user;
+-- At this point we should have no wrappers, no servers, and no mappings.
+SELECT fdwname, fdwlibrary, fdwoptions FROM pg_foreign_data_wrapper;
+ fdwname | fdwlibrary | fdwoptions
+---------+------------+------------
+(0 rows)
+
+SELECT srvname, srvoptions FROM pg_foreign_server;
+ srvname | srvoptions
+---------+------------
+(0 rows)
+
+SELECT * FROM pg_user_mapping;
+ umuser | umserver | umoptions
+--------+----------+-----------
+(0 rows)
+
pg_timezone_abbrevs | SELECT pg_timezone_abbrevs.abbrev, pg_timezone_abbrevs.utc_offset, pg_timezone_abbrevs.is_dst FROM pg_timezone_abbrevs() pg_timezone_abbrevs(abbrev, utc_offset, is_dst);
pg_timezone_names | SELECT pg_timezone_names.name, pg_timezone_names.abbrev, pg_timezone_names.utc_offset, pg_timezone_names.is_dst FROM pg_timezone_names() pg_timezone_names(name, abbrev, utc_offset, is_dst);
pg_user | SELECT pg_shadow.usename, pg_shadow.usesysid, pg_shadow.usecreatedb, pg_shadow.usesuper, pg_shadow.usecatupd, '********'::text AS passwd, pg_shadow.valuntil, pg_shadow.useconfig FROM pg_shadow;
+ pg_user_mappings | SELECT u.oid AS umid, s.oid AS srvid, s.srvname, u.umuser, CASE WHEN (u.umuser = (0)::oid) THEN 'public'::name ELSE a.rolname END AS usename, CASE WHEN (pg_has_role(s.srvowner, 'USAGE'::text) OR has_server_privilege(s.oid, 'USAGE'::text)) THEN u.umoptions ELSE NULL::text[] END AS umoptions FROM ((pg_user_mapping u LEFT JOIN pg_authid a ON ((a.oid = u.umuser))) JOIN pg_foreign_server s ON ((u.umserver = s.oid)));
pg_views | SELECT n.nspname AS schemaname, c.relname AS viewname, pg_get_userbyid(c.relowner) AS viewowner, pg_get_viewdef(c.oid) AS definition FROM (pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'v'::"char");
rtest_v1 | SELECT rtest_t1.a, rtest_t1.b FROM rtest_t1;
rtest_vcomp | SELECT x.part, (x.size * y.factor) AS size_in_cm FROM rtest_comp x, rtest_unitfact y WHERE (x.unit = y.unit);
shoelace_obsolete | SELECT shoelace.sl_name, shoelace.sl_avail, shoelace.sl_color, shoelace.sl_len, shoelace.sl_unit, shoelace.sl_len_cm FROM shoelace WHERE (NOT (EXISTS (SELECT shoe.shoename FROM shoe WHERE (shoe.slcolor = shoelace.sl_color))));
street | SELECT r.name, r.thepath, c.cname FROM ONLY road r, real_city c WHERE (c.outline ## r.thepath);
toyemp | SELECT emp.name, emp.age, emp.location, (12 * emp.salary) AS annualsal FROM emp;
-(50 rows)
+(51 rows)
SELECT tablename, rulename, definition FROM pg_rules
ORDER BY tablename, rulename;
pg_depend | t
pg_description | t
pg_enum | t
+ pg_foreign_data_wrapper | t
+ pg_foreign_server | t
pg_index | t
pg_inherits | t
pg_language | t
pg_ts_parser | t
pg_ts_template | t
pg_type | t
+ pg_user_mapping | t
point_tbl | f
polygon_tbl | t
ramp | f
timetz_tbl | f
tinterval_tbl | f
varchar_tbl | f
-(138 rows)
+(141 rows)
--
-- another sanity check: every system catalog that has OIDs should have
# ----------
-# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.50 2008/10/31 09:17:16 heikki Exp $
+# $PostgreSQL: pgsql/src/test/regress/parallel_schedule,v 1.51 2008/12/19 16:25:19 petere Exp $
#
# By convention, we put no more than twenty tests in any one parallel group;
# this limits the number of connections needed to run the tests.
# ----------
# Another group of parallel tests
# ----------
-test: select_views portals_p2 rules foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts
+test: select_views portals_p2 rules foreign_key cluster dependency guc bitmapops combocid tsearch tsdicts foreign_data
# ----------
# Another group of parallel tests
-# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.47 2008/10/31 09:17:16 heikki Exp $
+# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.48 2008/12/19 16:25:19 petere Exp $
# This should probably be in an order similar to parallel_schedule.
test: boolean
test: char
test: without_oid
test: conversion
test: tsdicts
+test: foreign_data
test: truncate
test: alter_table
test: sequence
--- /dev/null
+--
+-- Test foreign-data wrapper and server management.
+--
+
+-- Clean up in case a prior regression run failed
+
+-- Suppress NOTICE messages when roles don't exist
+SET client_min_messages TO 'error';
+
+DROP ROLE IF EXISTS foreign_data_user, regress_test_role, regress_test_role2, regress_test_role_super, regress_test_indirect, unpriviled_role;
+
+RESET client_min_messages;
+
+CREATE ROLE foreign_data_user LOGIN SUPERUSER;
+SET SESSION AUTHORIZATION 'foreign_data_user';
+
+CREATE ROLE regress_test_role;
+CREATE ROLE regress_test_role2;
+CREATE ROLE regress_test_role_super SUPERUSER;
+CREATE ROLE regress_test_indirect;
+CREATE ROLE unprivileged_role;
+
+CREATE FOREIGN DATA WRAPPER dummy LIBRARY 'dummy_fdw' LANGUAGE C;
+CREATE FOREIGN DATA WRAPPER postgresql LIBRARY 'postgresql_fdw' LANGUAGE C;
+
+-- At this point we should have 2 built-in wrappers and no servers.
+SELECT fdwname, fdwlibrary, fdwoptions FROM pg_foreign_data_wrapper ORDER BY 1, 2, 3;
+SELECT srvname, srvoptions FROM pg_foreign_server;
+SELECT * FROM pg_user_mapping;
+
+-- CREATE FOREIGN DATA WRAPPER
+CREATE FOREIGN DATA WRAPPER foo LIBRARY '' LANGUAGE C; -- ERROR
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql' LANGUAGE C;
+DROP FOREIGN DATA WRAPPER foo;
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C;
+\dew
+
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C; -- duplicate
+CREATE FOREIGN DATA WRAPPER "Foo" LIBRARY 'dummy_fdw' LANGUAGE C;
+DROP FOREIGN DATA WRAPPER "Foo";
+DROP FOREIGN DATA WRAPPER foo;
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1');
+\dew+
+
+DROP FOREIGN DATA WRAPPER foo;
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1', testing '2'); -- ERROR
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (testing '1', another '2');
+\dew+
+
+DROP FOREIGN DATA WRAPPER foo;
+SET ROLE regress_test_role;
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+RESET ROLE;
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'postgresql_fdw' LANGUAGE C;
+\dew+
+
+-- ALTER FOREIGN DATA WRAPPER
+ALTER FOREIGN DATA WRAPPER foo LIBRARY ''; -- ERROR
+ALTER FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql';
+ALTER FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw';
+\dew+
+
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (a '1', b '2');
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (SET c '4'); -- ERROR
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (DROP c); -- ERROR
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD x '1', DROP x);
+\dew+
+
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (DROP a, SET b '3', ADD c '4');
+\dew+
+
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (a '2');
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (b '4'); -- ERROR
+\dew+
+
+SET ROLE regress_test_role;
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD d '5'); -- ERROR
+SET ROLE regress_test_role_super;
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD d '5');
+\dew+
+
+ALTER FOREIGN DATA WRAPPER foo OWNER TO regress_test_role; -- ERROR
+ALTER FOREIGN DATA WRAPPER foo OWNER TO regress_test_role_super;
+ALTER ROLE regress_test_role_super NOSUPERUSER;
+SET ROLE regress_test_role_super;
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (ADD e '6'); -- ERROR
+RESET ROLE;
+\dew+
+
+-- DROP FOREIGN DATA WRAPPER
+DROP FOREIGN DATA WRAPPER nonexistent; -- ERROR
+DROP FOREIGN DATA WRAPPER IF EXISTS nonexistent;
+\dew+
+
+DROP ROLE regress_test_role_super; -- ERROR
+SET ROLE regress_test_role_super;
+DROP FOREIGN DATA WRAPPER foo; -- ERROR
+RESET ROLE;
+ALTER ROLE regress_test_role_super SUPERUSER;
+DROP FOREIGN DATA WRAPPER foo;
+DROP ROLE regress_test_role_super;
+\dew+
+
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C;
+CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
+CREATE USER MAPPING FOR current_user SERVER s1;
+\dew+
+\des+
+\deu+
+DROP FOREIGN DATA WRAPPER foo; -- ERROR
+SET ROLE regress_test_role;
+DROP FOREIGN DATA WRAPPER foo CASCADE; -- ERROR
+RESET ROLE;
+DROP FOREIGN DATA WRAPPER foo CASCADE;
+\dew+
+\des+
+\deu+
+
+-- exercise CREATE SERVER
+CREATE SERVER s1 FOREIGN DATA WRAPPER foo; -- ERROR
+CREATE FOREIGN DATA WRAPPER foo LIBRARY 'dummy_fdw' LANGUAGE C OPTIONS (test_wrapper 'true');
+CREATE SERVER s1 FOREIGN DATA WRAPPER foo;
+CREATE SERVER s1 FOREIGN DATA WRAPPER foo; -- ERROR
+CREATE SERVER s2 FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
+CREATE SERVER s3 TYPE 'oracle' FOREIGN DATA WRAPPER foo;
+CREATE SERVER s4 TYPE 'oracle' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
+CREATE SERVER s5 VERSION '15.0' FOREIGN DATA WRAPPER foo;
+CREATE SERVER s6 VERSION '16.0' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
+CREATE SERVER "S6" FOREIGN DATA WRAPPER foo OPTIONS (mixed_case_names 'true');
+CREATE SERVER s7 TYPE 'oracle' VERSION '17.0' FOREIGN DATA WRAPPER foo OPTIONS (host 'a', dbname 'b');
+CREATE SERVER s8 FOREIGN DATA WRAPPER postgresql OPTIONS (foo '1'); -- ERROR
+CREATE SERVER s8 FOREIGN DATA WRAPPER postgresql OPTIONS (host 'localhost', dbname 's8db');
+\des+
+SET ROLE regress_test_role;
+CREATE SERVER st1 FOREIGN DATA WRAPPER foo; -- ERROR: no usage on FDW
+RESET ROLE;
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role;
+SET ROLE regress_test_role;
+CREATE SERVER st1 FOREIGN DATA WRAPPER foo;
+RESET ROLE;
+\des+
+
+REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM regress_test_role;
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_indirect;
+SET ROLE regress_test_role;
+CREATE SERVER st2 FOREIGN DATA WRAPPER foo; -- ERROR
+RESET ROLE;
+GRANT regress_test_indirect TO regress_test_role;
+SET ROLE regress_test_role;
+CREATE SERVER st2 FOREIGN DATA WRAPPER foo;
+\des+
+RESET ROLE;
+REVOKE regress_test_indirect FROM regress_test_role;
+
+-- ALTER SERVER
+ALTER SERVER s0; -- ERROR
+ALTER SERVER s0 OPTIONS (a '1'); -- ERROR
+ALTER SERVER s1 VERSION '1.0' OPTIONS (servername 's1');
+ALTER SERVER s2 VERSION '1.1';
+ALTER SERVER s3 OPTIONS (tnsname 'orcl', port '1521');
+GRANT USAGE ON FOREIGN SERVER s1 TO regress_test_role;
+GRANT USAGE ON FOREIGN SERVER s6 TO regress_test_role2 WITH GRANT OPTION;
+\des+
+SET ROLE regress_test_role;
+ALTER SERVER s1 VERSION '1.1'; -- ERROR
+ALTER SERVER s1 OWNER TO regress_test_role; -- ERROR
+RESET ROLE;
+ALTER SERVER s1 OWNER TO regress_test_role;
+GRANT regress_test_role2 TO regress_test_role;
+SET ROLE regress_test_role;
+ALTER SERVER s1 VERSION '1.1';
+ALTER SERVER s1 OWNER TO regress_test_role2; -- ERROR
+RESET ROLE;
+ALTER SERVER s8 OPTIONS (foo '1'); -- ERROR option validation
+ALTER SERVER s8 OPTIONS (connect_timeout '30', SET dbname 'db1', DROP host);
+SET ROLE regress_test_role;
+ALTER SERVER s1 OWNER TO regress_test_indirect; -- ERROR
+RESET ROLE;
+GRANT regress_test_indirect TO regress_test_role;
+SET ROLE regress_test_role;
+ALTER SERVER s1 OWNER TO regress_test_indirect;
+RESET ROLE;
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_indirect;
+SET ROLE regress_test_role;
+ALTER SERVER s1 OWNER TO regress_test_indirect;
+RESET ROLE;
+DROP ROLE regress_test_indirect; -- ERROR
+\des+
+
+-- DROP SERVER
+DROP SERVER nonexistent; -- ERROR
+DROP SERVER IF EXISTS nonexistent;
+\des
+SET ROLE regress_test_role;
+DROP SERVER s2; -- ERROR
+DROP SERVER s1;
+RESET ROLE;
+\des
+ALTER SERVER s2 OWNER TO regress_test_role;
+SET ROLE regress_test_role;
+DROP SERVER s2;
+RESET ROLE;
+\des
+CREATE USER MAPPING FOR current_user SERVER s3;
+\deu
+DROP SERVER s3; -- ERROR
+DROP SERVER s3 CASCADE;
+\des
+\deu
+
+-- CREATE USER MAPPING
+CREATE USER MAPPING FOR baz SERVER s1; -- ERROR
+CREATE USER MAPPING FOR current_user SERVER s1; -- ERROR
+CREATE USER MAPPING FOR current_user SERVER s4;
+CREATE USER MAPPING FOR user SERVER s4; -- ERROR duplicate
+CREATE USER MAPPING FOR public SERVER s4 OPTIONS (mapping 'is public');
+CREATE USER MAPPING FOR user SERVER s8 OPTIONS (username 'test', password 'secret'); -- ERROR
+CREATE USER MAPPING FOR user SERVER s8 OPTIONS (user 'test', password 'secret');
+ALTER SERVER s5 OWNER TO regress_test_role;
+ALTER SERVER s6 OWNER TO regress_test_indirect;
+SET ROLE regress_test_role;
+CREATE USER MAPPING FOR current_user SERVER s5;
+CREATE USER MAPPING FOR current_user SERVER s6 OPTIONS (username 'test');
+CREATE USER MAPPING FOR current_user SERVER s7; -- ERROR
+CREATE USER MAPPING FOR public SERVER s8; -- ERROR
+RESET ROLE;
+CREATE USER MAPPING FOR current_user SERVER "S6" OPTIONS (username 'test_mixed_case');
+
+ALTER SERVER st1 OWNER TO regress_test_indirect;
+SET ROLE regress_test_role;
+CREATE USER MAPPING FOR current_user SERVER st1 OPTIONS (username 'bob', password 'boo');
+CREATE USER MAPPING FOR public SERVER st1;
+RESET ROLE;
+\deu
+
+-- ALTER USER MAPPING
+ALTER USER MAPPING FOR bob SERVER s4 OPTIONS (gotcha 'true'); -- ERROR
+ALTER USER MAPPING FOR user SERVER ss4 OPTIONS (gotcha 'true'); -- ERROR
+ALTER USER MAPPING FOR public SERVER s5 OPTIONS (gotcha 'true'); -- ERROR
+ALTER USER MAPPING FOR current_user SERVER s8 OPTIONS (username 'test'); -- ERROR
+ALTER USER MAPPING FOR current_user SERVER s8 OPTIONS (DROP user, SET password 'public');
+SET ROLE regress_test_role;
+ALTER USER MAPPING FOR current_user SERVER s5 OPTIONS (ADD modified '1');
+ALTER USER MAPPING FOR public SERVER s4 OPTIONS (ADD modified '1'); -- ERROR
+ALTER USER MAPPING FOR public SERVER st1 OPTIONS (ADD modified '1');
+RESET ROLE;
+\deu+
+
+-- DROP USER MAPPING
+DROP USER MAPPING FOR bob SERVER s4; -- ERROR
+DROP USER MAPPING FOR user SERVER ss4;
+DROP USER MAPPING FOR public SERVER s7; -- ERROR
+DROP USER MAPPING IF EXISTS FOR bob SERVER s4;
+DROP USER MAPPING IF EXISTS FOR user SERVER ss4;
+DROP USER MAPPING IF EXISTS FOR public SERVER s7;
+CREATE USER MAPPING FOR public SERVER s8;
+SET ROLE regress_test_role;
+DROP USER MAPPING FOR public SERVER s8; -- ERROR
+RESET ROLE;
+DROP SERVER s7;
+\deu
+
+-- Information schema
+
+SELECT * FROM information_schema.foreign_data_wrappers ORDER BY 1, 2;
+SELECT * FROM information_schema.foreign_data_wrapper_options ORDER BY 1, 2, 3;
+SELECT * FROM information_schema.foreign_servers ORDER BY 1, 2;
+SELECT * FROM information_schema.foreign_server_options ORDER BY 1, 2, 3;
+SELECT * FROM information_schema.user_mappings ORDER BY 1, 2, 3;
+SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4;
+SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+SET ROLE regress_test_role;
+SELECT * FROM information_schema.user_mapping_options ORDER BY 1, 2, 3, 4;
+SELECT * FROM information_schema.usage_privileges WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+SELECT * FROM information_schema.role_usage_grants WHERE object_type LIKE 'FOREIGN%' ORDER BY 1, 2, 3, 4, 5;
+DROP USER MAPPING FOR current_user SERVER st1;
+RESET ROLE;
+
+
+-- has_foreign_data_wrapper_privilege
+SELECT has_foreign_data_wrapper_privilege('regress_test_role',
+ (SELECT oid FROM pg_foreign_data_wrapper WHERE fdwname='foo'), 'USAGE');
+SELECT has_foreign_data_wrapper_privilege('regress_test_role', 'foo', 'USAGE');
+SELECT has_foreign_data_wrapper_privilege(
+ (SELECT oid FROM pg_roles WHERE rolname='regress_test_role'),
+ (SELECT oid FROM pg_foreign_data_wrapper WHERE fdwname='foo'), 'USAGE');
+SELECT has_foreign_data_wrapper_privilege(
+ (SELECT oid FROM pg_foreign_data_wrapper WHERE fdwname='foo'), 'USAGE');
+SELECT has_foreign_data_wrapper_privilege(
+ (SELECT oid FROM pg_roles WHERE rolname='regress_test_role'), 'foo', 'USAGE');
+SELECT has_foreign_data_wrapper_privilege('foo', 'USAGE');
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role;
+SELECT has_foreign_data_wrapper_privilege('regress_test_role', 'foo', 'USAGE');
+
+-- has_server_privilege
+SELECT has_server_privilege('regress_test_role',
+ (SELECT oid FROM pg_foreign_server WHERE srvname='s8'), 'USAGE');
+SELECT has_server_privilege('regress_test_role', 's8', 'USAGE');
+SELECT has_server_privilege(
+ (SELECT oid FROM pg_roles WHERE rolname='regress_test_role'),
+ (SELECT oid FROM pg_foreign_server WHERE srvname='s8'), 'USAGE');
+SELECT has_server_privilege(
+ (SELECT oid FROM pg_foreign_server WHERE srvname='s8'), 'USAGE');
+SELECT has_server_privilege(
+ (SELECT oid FROM pg_roles WHERE rolname='regress_test_role'), 's8', 'USAGE');
+SELECT has_server_privilege('s8', 'USAGE');
+GRANT USAGE ON FOREIGN SERVER s8 TO regress_test_role;
+SELECT has_server_privilege('regress_test_role', 's8', 'USAGE');
+REVOKE USAGE ON FOREIGN SERVER s8 FROM regress_test_role;
+
+GRANT USAGE ON FOREIGN SERVER s4 TO regress_test_role;
+DROP USER MAPPING FOR public SERVER s4;
+ALTER SERVER s6 OPTIONS (DROP host, DROP dbname);
+ALTER USER MAPPING FOR regress_test_role SERVER s6 OPTIONS (DROP username);
+ALTER FOREIGN DATA WRAPPER foo LIBRARY 'plpgsql';
+ALTER FOREIGN DATA WRAPPER foo LIBRARY 'default_fdw';
+
+-- Privileges
+SET ROLE unprivileged_role;
+CREATE FOREIGN DATA WRAPPER foobar LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (gotcha 'true'); -- ERROR
+ALTER FOREIGN DATA WRAPPER foo OWNER TO unprivileged_role; -- ERROR
+DROP FOREIGN DATA WRAPPER foo; -- ERROR
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role; -- ERROR
+CREATE SERVER s9 FOREIGN DATA WRAPPER foo; -- ERROR
+ALTER SERVER s4 VERSION '0.5'; -- ERROR
+ALTER SERVER s4 OWNER TO unprivileged_role; -- ERROR
+DROP SERVER s4; -- ERROR
+GRANT USAGE ON FOREIGN SERVER s4 TO regress_test_role; -- ERROR
+CREATE USER MAPPING FOR public SERVER s4; -- ERROR
+ALTER USER MAPPING FOR regress_test_role SERVER s6 OPTIONS (gotcha 'true'); -- ERROR
+DROP USER MAPPING FOR regress_test_role SERVER s6; -- ERROR
+RESET ROLE;
+
+GRANT USAGE ON FOREIGN DATA WRAPPER postgresql TO unprivileged_role;
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO unprivileged_role WITH GRANT OPTION;
+SET ROLE unprivileged_role;
+CREATE FOREIGN DATA WRAPPER foobar LIBRARY 'dummy_fdw' LANGUAGE C; -- ERROR
+ALTER FOREIGN DATA WRAPPER foo OPTIONS (gotcha 'true'); -- ERROR
+DROP FOREIGN DATA WRAPPER foo; -- ERROR
+GRANT USAGE ON FOREIGN DATA WRAPPER postgresql TO regress_test_role; -- WARNING
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role;
+CREATE SERVER s9 FOREIGN DATA WRAPPER postgresql;
+ALTER SERVER s6 VERSION '0.5'; -- ERROR
+DROP SERVER s6; -- ERROR
+GRANT USAGE ON FOREIGN SERVER s6 TO regress_test_role; -- ERROR
+GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role;
+CREATE USER MAPPING FOR public SERVER s6; -- ERROR
+CREATE USER MAPPING FOR public SERVER s9;
+ALTER USER MAPPING FOR regress_test_role SERVER s6 OPTIONS (gotcha 'true'); -- ERROR
+DROP USER MAPPING FOR regress_test_role SERVER s6; -- ERROR
+RESET ROLE;
+
+REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM unprivileged_role; -- ERROR
+REVOKE USAGE ON FOREIGN DATA WRAPPER foo FROM unprivileged_role CASCADE;
+SET ROLE unprivileged_role;
+GRANT USAGE ON FOREIGN DATA WRAPPER foo TO regress_test_role; -- ERROR
+CREATE SERVER s10 FOREIGN DATA WRAPPER foo; -- ERROR
+ALTER SERVER s9 VERSION '1.1';
+GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role;
+CREATE USER MAPPING FOR current_user SERVER s9;
+DROP SERVER s9 CASCADE;
+RESET ROLE;
+CREATE SERVER s9 FOREIGN DATA WRAPPER foo;
+GRANT USAGE ON FOREIGN SERVER s9 TO unprivileged_role;
+SET ROLE unprivileged_role;
+ALTER SERVER s9 VERSION '1.2'; -- ERROR
+GRANT USAGE ON FOREIGN SERVER s9 TO regress_test_role; -- WARNING
+CREATE USER MAPPING FOR current_user SERVER s9; -- ERROR
+DROP SERVER s9 CASCADE; -- ERROR
+RESET ROLE;
+
+-- Cleanup
+DROP ROLE regress_test_role; -- ERROR
+DROP SERVER s5 CASCADE;
+DROP SERVER st1 CASCADE;
+DROP SERVER st2;
+DROP USER MAPPING FOR regress_test_role SERVER s6;
+DROP FOREIGN DATA WRAPPER foo CASCADE;
+DROP SERVER s8 CASCADE;
+DROP ROLE regress_test_indirect;
+DROP ROLE regress_test_role;
+DROP ROLE unprivileged_role; -- ERROR
+REVOKE ALL ON FOREIGN DATA WRAPPER postgresql FROM unprivileged_role;
+DROP ROLE unprivileged_role;
+DROP ROLE regress_test_role2;
+DROP FOREIGN DATA WRAPPER postgresql CASCADE;
+DROP FOREIGN DATA WRAPPER dummy CASCADE;
+\c
+DROP ROLE foreign_data_user;
+
+-- At this point we should have no wrappers, no servers, and no mappings.
+SELECT fdwname, fdwlibrary, fdwoptions FROM pg_foreign_data_wrapper;
+SELECT srvname, srvoptions FROM pg_foreign_server;
+SELECT * FROM pg_user_mapping;