Tablespaces. Alternate database locations are dead, long live tablespaces.

There are various things left to do: contrib dbsize and oid2name modules
need work, and so does the documentation.  Also someone should think about
COMMENT ON TABLESPACE and maybe RENAME TABLESPACE.  Also initlocation is
dead, it just doesn't know it yet.

Gavin Sherry and Tom Lane.
This commit is contained in:
Tom Lane 2004-06-18 06:14:31 +00:00
parent 474875f443
commit 2467394ee1
94 changed files with 3765 additions and 1588 deletions

View File

@ -1,6 +1,6 @@
<!-- <!--
Documentation of the system catalogs, directed toward PostgreSQL developers Documentation of the system catalogs, directed toward PostgreSQL developers
$PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.87 2004/06/16 01:26:33 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/catalogs.sgml,v 2.88 2004/06/18 06:13:02 tgl Exp $
--> -->
<chapter id="catalogs"> <chapter id="catalogs">
@ -178,6 +178,11 @@
<entry>planner statistics</entry> <entry>planner statistics</entry>
</row> </row>
<row>
<entry><link linkend="catalog-pg-tablespace"><structname>pg_tablespace</structname></link></entry>
<entry>tablespaces within this database cluster</entry>
</row>
<row> <row>
<entry><link linkend="catalog-pg-trigger"><structname>pg_trigger</structname></link></entry> <entry><link linkend="catalog-pg-trigger"><structname>pg_trigger</structname></link></entry>
<entry>triggers</entry> <entry>triggers</entry>
@ -1058,6 +1063,17 @@
<entry>Name of the on-disk file of this relation; 0 if none</entry> <entry>Name of the on-disk file of this relation; 0 if none</entry>
</row> </row>
<row>
<entry><structfield>reltablespace</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-tablespace"><structname>pg_tablespace</structname></link>.oid</literal></entry>
<entry>
The tablespace in which this relation is stored. If zero,
the database's default tablespace is implied. (Not meaningful
if the relation has no on-disk file.)
</entry>
</row>
<row> <row>
<entry><structfield>relpages</structfield></entry> <entry><structfield>relpages</structfield></entry>
<entry><type>int4</type></entry> <entry><type>int4</type></entry>
@ -1602,13 +1618,15 @@
</row> </row>
<row> <row>
<entry><structfield>datpath</structfield></entry> <entry><structfield>dattablespace</structfield></entry>
<entry><type>text</type></entry> <entry><type>oid</type></entry>
<entry></entry> <entry><literal><link linkend="catalog-pg-tablespace"><structname>pg_tablespace</structname></link>.oid</literal></entry>
<entry> <entry>
If the database is stored at an alternative location then this The default tablespace for the database.
records the location. It's either an environment variable name Within this database, all tables for which
or an absolute path, depending how it was entered. <structname>pg_class</>.<structfield>reltablespace</> is zero
will be stored in this tablespace; in particular, all the non-shared
system catalogs will be there.
</entry> </entry>
</row> </row>
@ -2386,6 +2404,17 @@
<entry>Owner of the namespace</entry> <entry>Owner of the namespace</entry>
</row> </row>
<row>
<entry><structfield>nsptablespace</structfield></entry>
<entry><type>oid</type></entry>
<entry><literal><link linkend="catalog-pg-tablespace"><structname>pg_tablespace</structname></link>.oid</literal></entry>
<entry>
The default tablespace in which to place relations created in this
namespace. If zero, the database's default tablespace is implied.
(Changing this does not affect pre-existing relations.)
</entry>
</row>
<row> <row>
<entry><structfield>nspacl</structfield></entry> <entry><structfield>nspacl</structfield></entry>
<entry><type>aclitem[]</type></entry> <entry><type>aclitem[]</type></entry>
@ -3232,6 +3261,73 @@
</sect1> </sect1>
<sect1 id="catalog-pg-tablespace">
<title><structname>pg_tablespace</structname></title>
<indexterm zone="catalog-pg-tablespace">
<primary>pg_tablespace</primary>
</indexterm>
<para>
The catalog <structname>pg_tablespace</structname> stores information
about the available tablespaces. Tables can be placed in particular
tablespaces to aid administration of disk layout.
</para>
<para>
Unlike most system catalogs, <structname>pg_tablespace</structname>
is shared across all databases of a cluster: there is only one
copy of <structname>pg_tablespace</structname> per cluster, not
one per database.
</para>
<table>
<title><structname>pg_tablespace</> 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>spcname</structfield></entry>
<entry><type>name</type></entry>
<entry></entry>
<entry>Tablespace name</entry>
</row>
<row>
<entry><structfield>spcowner</structfield></entry>
<entry><type>int4</type></entry>
<entry><literal><link linkend="catalog-pg-shadow"><structname>pg_shadow</structname></link>.usesysid</literal></entry>
<entry>Owner of the tablespace, usually the user who created it</entry>
</row>
<row>
<entry><structfield>spclocation</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
<entry>Location (directory path) of the tablespace</entry>
</row>
<row>
<entry><structfield>spcacl</structfield></entry>
<entry><type>aclitem[]</type></entry>
<entry></entry>
<entry>Access privileges</entry>
</row>
</tbody>
</tgroup>
</table>
</sect1>
<sect1 id="catalog-pg-trigger"> <sect1 id="catalog-pg-trigger">
<title><structname>pg_trigger</structname></title> <title><structname>pg_trigger</structname></title>

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/manage-ag.sgml,v 2.29 2003/11/29 19:51:37 pgsql Exp $ $PostgreSQL: pgsql/doc/src/sgml/manage-ag.sgml,v 2.30 2004/06/18 06:13:02 tgl Exp $
--> -->
<chapter id="managing-databases"> <chapter id="managing-databases">
@ -298,6 +298,11 @@ ALTER DATABASE mydb SET geqo TO off;
<sect1 id="manage-ag-alternate-locs"> <sect1 id="manage-ag-alternate-locs">
<title>Alternative Locations</title> <title>Alternative Locations</title>
<para>
XXX this is entirely dead now, and needs to be replaced by a DBA-level
description of tablespaces.
</para>
<para> <para>
It is possible to create a database in a location other than the It is possible to create a database in a location other than the
default location for the installation. But remember that all database access default location for the installation. But remember that all database access
@ -368,21 +373,6 @@ CREATE DATABASE <replaceable>name</> WITH LOCATION '<replaceable>location</>';
Databases created in alternative locations can be Databases created in alternative locations can be
accessed and dropped like any other database. accessed and dropped like any other database.
</para> </para>
<note>
<para>
It can also be possible to specify absolute paths directly to the
<command>CREATE DATABASE</> command without defining environment
variables. This is disallowed by default because it is a security
risk. To allow it, you must compile <productname>PostgreSQL</> with
the C preprocessor macro <literal>ALLOW_ABSOLUTE_DBPATHS</>
defined. One way to do this is to run the compilation step like
this:
<programlisting>
gmake CPPFLAGS=-DALLOW_ABSOLUTE_DBPATHS all
</programlisting>
</para>
</note>
</sect1> </sect1>
<sect1 id="manage-ag-dropdb"> <sect1 id="manage-ag-dropdb">

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.56 2004/04/20 01:11:49 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/allfiles.sgml,v 1.57 2004/06/18 06:13:05 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
Complete list of usable sgml source files in this directory. Complete list of usable sgml source files in this directory.
--> -->
@ -44,6 +44,7 @@ Complete list of usable sgml source files in this directory.
<!entity createSequence system "create_sequence.sgml"> <!entity createSequence system "create_sequence.sgml">
<!entity createTable system "create_table.sgml"> <!entity createTable system "create_table.sgml">
<!entity createTableAs system "create_table_as.sgml"> <!entity createTableAs system "create_table_as.sgml">
<!entity createTableSpace system "create_tablespace.sgml">
<!entity createTrigger system "create_trigger.sgml"> <!entity createTrigger system "create_trigger.sgml">
<!entity createType system "create_type.sgml"> <!entity createType system "create_type.sgml">
<!entity createUser system "create_user.sgml"> <!entity createUser system "create_user.sgml">
@ -66,6 +67,7 @@ Complete list of usable sgml source files in this directory.
<!entity dropSchema system "drop_schema.sgml"> <!entity dropSchema system "drop_schema.sgml">
<!entity dropSequence system "drop_sequence.sgml"> <!entity dropSequence system "drop_sequence.sgml">
<!entity dropTable system "drop_table.sgml"> <!entity dropTable system "drop_table.sgml">
<!entity dropTableSpace system "drop_tablespace.sgml">
<!entity dropTrigger system "drop_trigger.sgml"> <!entity dropTrigger system "drop_trigger.sgml">
<!entity dropType system "drop_type.sgml"> <!entity dropType system "drop_type.sgml">
<!entity dropUser system "drop_user.sgml"> <!entity dropUser system "drop_user.sgml">

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_database.sgml,v 1.38 2004/03/23 02:47:35 neilc Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_database.sgml,v 1.39 2004/06/18 06:13:05 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -22,9 +22,9 @@ PostgreSQL documentation
<synopsis> <synopsis>
CREATE DATABASE <replaceable class="PARAMETER">name</replaceable> CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
[ [ WITH ] [ OWNER [=] <replaceable class="parameter">dbowner</replaceable> ] [ [ WITH ] [ OWNER [=] <replaceable class="parameter">dbowner</replaceable> ]
[ LOCATION [=] '<replaceable class="parameter">dbpath</replaceable>' ]
[ TEMPLATE [=] <replaceable class="parameter">template</replaceable> ] [ TEMPLATE [=] <replaceable class="parameter">template</replaceable> ]
[ ENCODING [=] <replaceable class="parameter">encoding</replaceable> ] ] [ ENCODING [=] <replaceable class="parameter">encoding</replaceable> ]
[ TABLESPACE [=] <replaceable class="parameter">tablespace</replaceable> ] ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
@ -50,29 +50,6 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
privilege can only create databases owned by themselves. privilege can only create databases owned by themselves.
</para> </para>
<para>
An alternative location can be specified in order to,
for example, store the database on a different disk.
The path must have been prepared with the
<xref linkend="APP-INITLOCATION" endterm="APP-INITLOCATION-title">
command.
</para>
<para>
If the path name does not contain a slash, it is interpreted
as an environment variable name, which must be known to the
server process. This way the database administrator can
exercise control over locations in which databases can be created.
(A customary choice is, e.g., <envar>PGDATA2</envar>.)
If the server is compiled with <literal>ALLOW_ABSOLUTE_DBPATHS</literal>
(not so by default), absolute path names, as identified by
a leading slash
(e.g., <filename>/usr/local/pgsql/data</filename>),
are allowed as well.
In either case, the final path name must be absolute and must not
contain any single quotes.
</para>
<para> <para>
By default, the new database will be created by cloning the standard By default, the new database will be created by cloning the standard
system database <literal>template1</>. A different template can be system database <literal>template1</>. A different template can be
@ -83,13 +60,7 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
version of <productname>PostgreSQL</productname>. This is useful version of <productname>PostgreSQL</productname>. This is useful
if you wish to avoid copying if you wish to avoid copying
any installation-local objects that may have been added to any installation-local objects that may have been added to
<literal>template1</>. <literal>template1</>.
</para>
<para>
The optional encoding parameter allows selection of the database
encoding. When not specified, it defaults to the encoding used by
the selected template database.
</para> </para>
</refsect1> </refsect1>
@ -101,7 +72,7 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
<term><replaceable class="parameter">name</replaceable></term> <term><replaceable class="parameter">name</replaceable></term>
<listitem> <listitem>
<para> <para>
The name of a database to create. The name of a database to create.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -110,18 +81,8 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
<listitem> <listitem>
<para> <para>
The name of the database user who will own the new database, The name of the database user who will own the new database,
or <literal>DEFAULT</literal> to use the default (namely, the or <literal>DEFAULT</literal> to use the default (namely, the
user executing the command). user executing the command).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">dbpath</replaceable></term>
<listitem>
<para>
An alternate file-system location in which to store the new database,
specified as a string literal;
or <literal>DEFAULT</literal> to use the default location.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -130,8 +91,8 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
<listitem> <listitem>
<para> <para>
The name of the template from which to create the new database, The name of the template from which to create the new database,
or <literal>DEFAULT</literal> to use the default template or <literal>DEFAULT</literal> to use the default template
(<literal>template1</literal>). (<literal>template1</literal>).
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -139,12 +100,24 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
<term><replaceable class="parameter">encoding</replaceable></term> <term><replaceable class="parameter">encoding</replaceable></term>
<listitem> <listitem>
<para> <para>
Character set encoding to use in the new database. Specify Character set encoding to use in the new database. Specify
a string constant (e.g., <literal>'SQL_ASCII'</literal>), a string constant (e.g., <literal>'SQL_ASCII'</literal>),
or an integer encoding number, or <literal>DEFAULT</literal> or an integer encoding number, or <literal>DEFAULT</literal>
to use the default encoding. The character sets supported by the to use the default encoding. The character sets supported by the
<productname>PostgreSQL</productname> server are described in <productname>PostgreSQL</productname> server are described in
<xref linkend="multibyte-charset-supported">. <xref linkend="multibyte-charset-supported">.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">tablespace</replaceable></term>
<listitem>
<para>
Specifies the default tablespace for the new database.
If not specified, the same tablespace that is default for
the template database is used. See
<xref linkend="sql-createtablespace" endterm="sql-createtablespace-title">
for more information.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -167,9 +140,7 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
<para> <para>
Errors along the line of <quote>could not initialize database directory</> Errors along the line of <quote>could not initialize database directory</>
are most likely related to insufficient permissions on the data are most likely related to insufficient permissions on the data
directory, a full disk, or other file system problems. When using an directory, a full disk, or other file system problems.
alternate location, the user under
which the database server is running must have access to the location.
</para> </para>
<para> <para>
@ -181,13 +152,6 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
wrapper program around this command, provided for convenience. wrapper program around this command, provided for convenience.
</para> </para>
<para>
There are security issues involved with using alternate database
locations specified with absolute path names; this is why the feature
is not enabled by default. See <xref
linkend="manage-ag-alternate-locs"> for more information.
</para>
<para> <para>
Although it is possible to copy a database other than <literal>template1</> Although it is possible to copy a database other than <literal>template1</>
by specifying its name as the template, this is not (yet) intended as by specifying its name as the template, this is not (yet) intended as
@ -205,24 +169,6 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
<programlisting> <programlisting>
CREATE DATABASE lusiadas; CREATE DATABASE lusiadas;
</programlisting>
</para>
<para>
To create a new database in an alternate area
<filename>~/private_db</filename>, execute the following from the
shell:
<programlisting>
mkdir private_db
initlocation ~/private_db
</programlisting>
Then execute the following from within a
<application>psql</application> session:
<programlisting>
CREATE DATABASE elsewhere WITH LOCATION '/home/olly/private_db';
</programlisting> </programlisting>
</para> </para>
</refsect1> </refsect1>

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.47 2004/04/20 12:53:28 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.48 2004/06/18 06:13:05 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -22,6 +22,7 @@ PostgreSQL documentation
<synopsis> <synopsis>
CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <replaceable class="parameter">table</replaceable> [ USING <replaceable class="parameter">method</replaceable> ] CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <replaceable class="parameter">table</replaceable> [ USING <replaceable class="parameter">method</replaceable> ]
( { <replaceable class="parameter">column</replaceable> | ( <replaceable class="parameter">expression</replaceable> ) } [ <replaceable class="parameter">opclass</replaceable> ] [, ...] ) ( { <replaceable class="parameter">column</replaceable> | ( <replaceable class="parameter">expression</replaceable> ) } [ <replaceable class="parameter">opclass</replaceable> ] [, ...] )
[ TABLESPACE <replaceable class="parameter">tablespace</replaceable> ]
[ WHERE <replaceable class="parameter">predicate</replaceable> ] [ WHERE <replaceable class="parameter">predicate</replaceable> ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
@ -78,7 +79,7 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<para> <para>
Indexes are not used for <literal>IS NULL</> clauses by default. Indexes are not used for <literal>IS NULL</> clauses by default.
The best way to use indexes in such cases is to create a partial index The best way to use indexes in such cases is to create a partial index
using an <literal>IS NULL</> comparison. using an <literal>IS NULL</> comparison.
</para> </para>
@ -109,11 +110,11 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<term><literal>UNIQUE</literal></term> <term><literal>UNIQUE</literal></term>
<listitem> <listitem>
<para> <para>
Causes the system to check for Causes the system to check for
duplicate values in the table when the index is created (if data duplicate values in the table when the index is created (if data
already exist) and each time data is added. Attempts to already exist) and each time data is added. Attempts to
insert or update data which would result in duplicate entries insert or update data which would result in duplicate entries
will generate an error. will generate an error.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -122,9 +123,9 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<term><replaceable class="parameter">name</replaceable></term> <term><replaceable class="parameter">name</replaceable></term>
<listitem> <listitem>
<para> <para>
The name of the index to be created. No schema name can be included The name of the index to be created. No schema name can be included
here; the index is always created in the same schema as its parent here; the index is always created in the same schema as its parent
table. table.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -133,7 +134,7 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<term><replaceable class="parameter">table</replaceable></term> <term><replaceable class="parameter">table</replaceable></term>
<listitem> <listitem>
<para> <para>
The name (possibly schema-qualified) of the table to be indexed. The name (possibly schema-qualified) of the table to be indexed.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -154,7 +155,7 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<term><replaceable class="parameter">column</replaceable></term> <term><replaceable class="parameter">column</replaceable></term>
<listitem> <listitem>
<para> <para>
The name of a column of the table. The name of a column of the table.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -163,10 +164,10 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<term><replaceable class="parameter">expression</replaceable></term> <term><replaceable class="parameter">expression</replaceable></term>
<listitem> <listitem>
<para> <para>
An expression based on one or more columns of the table. The An expression based on one or more columns of the table. The
expression usually must be written with surrounding parentheses, expression usually must be written with surrounding parentheses,
as shown in the syntax. However, the parentheses may be omitted as shown in the syntax. However, the parentheses may be omitted
if the expression has the form of a function call. if the expression has the form of a function call.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -175,7 +176,17 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<term><replaceable class="parameter">opclass</replaceable></term> <term><replaceable class="parameter">opclass</replaceable></term>
<listitem> <listitem>
<para> <para>
The name of an operator class. See below for details. The name of an operator class. See below for details.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">tablespace</replaceable></term>
<listitem>
<para>
The tablespace in which to create the index. If not specified,
the tablespace of the parent table is used.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -184,10 +195,11 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
<term><replaceable class="parameter">predicate</replaceable></term> <term><replaceable class="parameter">predicate</replaceable></term>
<listitem> <listitem>
<para> <para>
The constraint expression for a partial index. The constraint expression for a partial index.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
@ -260,7 +272,7 @@ SELECT * FROM points
--> -->
</refsect1> </refsect1>
<refsect1> <refsect1>
<title>Compatibility</title> <title>Compatibility</title>

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_schema.sgml,v 1.11 2004/01/11 05:46:58 neilc Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_schema.sgml,v 1.12 2004/06/18 06:13:05 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -12,7 +12,7 @@ PostgreSQL documentation
<refnamediv> <refnamediv>
<refname>CREATE SCHEMA</refname> <refname>CREATE SCHEMA</refname>
<refpurpose>define a new schema</refpurpose> <refpurpose>define a new schema</refpurpose>
</refnamediv> </refnamediv>
<indexterm zone="sql-createschema"> <indexterm zone="sql-createschema">
<primary>CREATE SCHEMA</primary> <primary>CREATE SCHEMA</primary>
@ -20,8 +20,8 @@ PostgreSQL documentation
<refsynopsisdiv> <refsynopsisdiv>
<synopsis> <synopsis>
CREATE SCHEMA <replaceable class="parameter">schemaname</replaceable> [ AUTHORIZATION <replaceable class="parameter">username</replaceable> ] [ <replaceable class="parameter">schema_element</replaceable> [ ... ] ] CREATE SCHEMA <replaceable class="parameter">schemaname</replaceable> [ AUTHORIZATION <replaceable class="parameter">username</replaceable> ] [ TABLESPACE <replaceable class="parameter">tablespace</replaceable> ] [ <replaceable class="parameter">schema_element</replaceable> [ ... ] ]
CREATE SCHEMA AUTHORIZATION <replaceable class="parameter">username</replaceable> [ <replaceable class="parameter">schema_element</replaceable> [ ... ] ] CREATE SCHEMA AUTHORIZATION <replaceable class="parameter">username</replaceable> [ TABLESPACE <replaceable class="parameter">tablespace</replaceable> ] [ <replaceable class="parameter">schema_element</replaceable> [ ... ] ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
@ -54,7 +54,7 @@ CREATE SCHEMA AUTHORIZATION <replaceable class="parameter">username</replaceable
all the created objects will be owned by that user. all the created objects will be owned by that user.
</para> </para>
</refsect1> </refsect1>
<refsect1> <refsect1>
<title>Parameters</title> <title>Parameters</title>
@ -63,8 +63,8 @@ CREATE SCHEMA AUTHORIZATION <replaceable class="parameter">username</replaceable
<term><replaceable class="parameter">schemaname</replaceable></term> <term><replaceable class="parameter">schemaname</replaceable></term>
<listitem> <listitem>
<para> <para>
The name of a schema to be created. If this is omitted, the user name The name of a schema to be created. If this is omitted, the user name
is used as the schema name. is used as the schema name.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -74,8 +74,19 @@ CREATE SCHEMA AUTHORIZATION <replaceable class="parameter">username</replaceable
<listitem> <listitem>
<para> <para>
The name of the user who will own the schema. If omitted, The name of the user who will own the schema. If omitted,
defaults to the user executing the command. Only superusers defaults to the user executing the command. Only superusers
may create schemas owned by users other than themselves. may create schemas owned by users other than themselves.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">tablespace</replaceable></term>
<listitem>
<para>
The name of the tablespace that is to be the default tablespace
for all new objects created in the schema. If not supplied, the schema
will inherit the default tablespace of the database.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -102,8 +113,10 @@ CREATE SCHEMA AUTHORIZATION <replaceable class="parameter">username</replaceable
<para> <para>
To create a schema, the invoking user must have the To create a schema, the invoking user must have the
<literal>CREATE</> privilege for the current database. (Of course, <literal>CREATE</> privilege for the current database.
superusers bypass this check.) Also, the <literal>TABLESPACE</> option requires having
<literal>CREATE</> privilege for the specified tablespace.
(Of course, superusers bypass these checks.)
</para> </para>
</refsect1> </refsect1>
@ -181,7 +194,8 @@ CREATE VIEW hollywood.winners AS
<simplelist type="inline"> <simplelist type="inline">
<member><xref linkend="sql-alterschema" endterm="sql-alterschema-title"></member> <member><xref linkend="sql-alterschema" endterm="sql-alterschema-title"></member>
<member><xref linkend="sql-dropschema" endterm="sql-dropschema-title"></member> <member><xref linkend="sql-dropschema" endterm="sql-dropschema-title"></member>
</simplelist> <member><xref linkend="sql-createtablespace" endterm="sql-createtablespace-title"></member>
</simplelist>
</refsect1> </refsect1>
</refentry> </refentry>

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_sequence.sgml,v 1.39 2003/11/29 19:51:38 pgsql Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_sequence.sgml,v 1.40 2004/06/18 06:13:05 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -12,7 +12,7 @@ PostgreSQL documentation
<refnamediv> <refnamediv>
<refname>CREATE SEQUENCE</refname> <refname>CREATE SEQUENCE</refname>
<refpurpose>define a new sequence generator</refpurpose> <refpurpose>define a new sequence generator</refpurpose>
</refnamediv> </refnamediv>
<indexterm zone="sql-createsequence"> <indexterm zone="sql-createsequence">
<primary>CREATE SEQUENCE</primary> <primary>CREATE SEQUENCE</primary>
@ -23,6 +23,7 @@ PostgreSQL documentation
CREATE [ TEMPORARY | TEMP ] SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ] CREATE [ TEMPORARY | TEMP ] SEQUENCE <replaceable class="parameter">name</replaceable> [ INCREMENT [ BY ] <replaceable class="parameter">increment</replaceable> ]
[ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ] [ MINVALUE <replaceable class="parameter">minvalue</replaceable> | NO MINVALUE ] [ MAXVALUE <replaceable class="parameter">maxvalue</replaceable> | NO MAXVALUE ]
[ START [ WITH ] <replaceable class="parameter">start</replaceable> ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ] [ START [ WITH ] <replaceable class="parameter">start</replaceable> ] [ CACHE <replaceable class="parameter">cache</replaceable> ] [ [ NO ] CYCLE ]
[ TABLESPACE <replaceable class="parameter">tablespace</replaceable> ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
@ -193,6 +194,19 @@ SELECT * FROM <replaceable>name</replaceable>;
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><replaceable class="parameter">tablespace</replaceable></term>
<listitem>
<para>
The optional clause <literal>TABLESPACE</> <replaceable
class="parameter">tablespace</replaceable> specifies
the tablespace in which to create the sequence. If this clause
is not supplied, the tablespace of the sequence's schema will be used.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
@ -268,7 +282,7 @@ CREATE SEQUENCE serial START 101;
Select the next number from this sequence: Select the next number from this sequence:
<programlisting> <programlisting>
SELECT nextval('serial'); SELECT nextval('serial');
nextval nextval
--------- ---------
114 114

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.81 2004/05/19 23:10:43 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/create_table.sgml,v 1.82 2004/06/18 06:13:05 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -28,6 +28,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable class="PAR
[ INHERITS ( <replaceable>parent_table</replaceable> [, ... ] ) ] [ INHERITS ( <replaceable>parent_table</replaceable> [, ... ] ) ]
[ WITH OIDS | WITHOUT OIDS ] [ WITH OIDS | WITHOUT OIDS ]
[ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ] [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
[ TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ]
where <replaceable class="PARAMETER">column_constraint</replaceable> is: where <replaceable class="PARAMETER">column_constraint</replaceable> is:
@ -48,7 +49,7 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
[ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ] } [ MATCH FULL | MATCH PARTIAL | MATCH SIMPLE ] [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ] }
[ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ] [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
</synopsis> </synopsis>
</refsynopsisdiv> </refsynopsisdiv>
<refsect1 id="SQL-CREATETABLE-description"> <refsect1 id="SQL-CREATETABLE-description">
@ -321,7 +322,7 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><literal>UNIQUE</> (column constraint)</term> <term><literal>UNIQUE</> (column constraint)</term>
<term><literal>UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )</> (table constraint)</term> <term><literal>UNIQUE ( <replaceable class="PARAMETER">column_name</replaceable> [, ... ] )</> (table constraint)</term>
@ -405,9 +406,9 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
<term><literal>REFERENCES <replaceable class="parameter">reftable</replaceable> [ ( <replaceable class="parameter">refcolumn</replaceable> ) ] [ MATCH <replaceable class="parameter">matchtype</replaceable> ] [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ]</literal> (column constraint)</term> <term><literal>REFERENCES <replaceable class="parameter">reftable</replaceable> [ ( <replaceable class="parameter">refcolumn</replaceable> ) ] [ MATCH <replaceable class="parameter">matchtype</replaceable> ] [ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON UPDATE <replaceable class="parameter">action</replaceable> ]</literal> (column constraint)</term>
<term><literal>FOREIGN KEY ( <replaceable class="parameter">column</replaceable> [, ... ] ) <term><literal>FOREIGN KEY ( <replaceable class="parameter">column</replaceable> [, ... ] )
REFERENCES <replaceable class="parameter">reftable</replaceable> [ ( <replaceable class="parameter">refcolumn</replaceable> [, ... ] ) ] REFERENCES <replaceable class="parameter">reftable</replaceable> [ ( <replaceable class="parameter">refcolumn</replaceable> [, ... ] ) ]
[ MATCH <replaceable class="parameter">matchtype</replaceable> ] [ MATCH <replaceable class="parameter">matchtype</replaceable> ]
[ ON DELETE <replaceable class="parameter">action</replaceable> ] [ ON DELETE <replaceable class="parameter">action</replaceable> ]
[ ON UPDATE <replaceable class="parameter">action</replaceable> ]</literal> [ ON UPDATE <replaceable class="parameter">action</replaceable> ]</literal>
(table constraint)</term> (table constraint)</term>
@ -514,7 +515,7 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><literal>DEFERRABLE</literal></term> <term><literal>DEFERRABLE</literal></term>
<term><literal>NOT DEFERRABLE</literal></term> <term><literal>NOT DEFERRABLE</literal></term>
@ -553,7 +554,7 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
<listitem> <listitem>
<para> <para>
The behavior of temporary tables at the end of a transaction The behavior of temporary tables at the end of a transaction
block can be controlled using <literal>ON COMMIT</literal>. block can be controlled using <literal>ON COMMIT</literal>.
The three options are: The three options are:
<variablelist> <variablelist>
@ -561,19 +562,19 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
<term><literal>PRESERVE ROWS</literal></term> <term><literal>PRESERVE ROWS</literal></term>
<listitem> <listitem>
<para> <para>
No special action is taken at the ends of transactions. No special action is taken at the ends of transactions.
This is the default behavior. This is the default behavior.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry> <varlistentry>
<term><literal>DELETE ROWS</literal></term> <term><literal>DELETE ROWS</literal></term>
<listitem> <listitem>
<para> <para>
All rows in the temporary table will be deleted at the All rows in the temporary table will be deleted at the
end of each transaction block. Essentially, an automatic end of each transaction block. Essentially, an automatic
<xref linkend="sql-truncate"> is done at each commit. <xref linkend="sql-truncate"> is done at each commit.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -583,7 +584,7 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
<listitem> <listitem>
<para> <para>
The temporary table will be dropped at the end of the current The temporary table will be dropped at the end of the current
transaction block. transaction block.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
@ -591,8 +592,20 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term><literal>TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable></literal></term>
<listitem>
<para>
The <replaceable class="PARAMETER">tablespace</replaceable> is the name
of the tablespace in which the new table is to be created. If not
supplied, the default tablespace of the table's schema will be used.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>
<refsect1 id="SQL-CREATETABLE-notes"> <refsect1 id="SQL-CREATETABLE-notes">
<title>Notes</title> <title>Notes</title>
@ -696,7 +709,7 @@ CREATE TABLE films (
); );
</programlisting> </programlisting>
</para> </para>
<para> <para>
Define a check column constraint: Define a check column constraint:
@ -719,7 +732,7 @@ CREATE TABLE distributors (
); );
</programlisting> </programlisting>
</para> </para>
<para> <para>
Define a primary key table constraint for the table Define a primary key table constraint for the table
<structname>films</>. Primary key table constraints can be defined <structname>films</>. Primary key table constraints can be defined
@ -749,7 +762,7 @@ CREATE TABLE distributors (
did integer, did integer,
name varchar(40), name varchar(40),
PRIMARY KEY(did) PRIMARY KEY(did)
); );
</programlisting> </programlisting>
<programlisting> <programlisting>
@ -812,7 +825,7 @@ CREATE TABLE distributors (
</para> </para>
</refsect1> </refsect1>
<refsect1 id="SQL-CREATETABLE-compatibility"> <refsect1 id="SQL-CREATETABLE-compatibility">
<title id="SQL-CREATETABLE-compatibility-title">Compatibility</title> <title id="SQL-CREATETABLE-compatibility-title">Compatibility</title>
@ -827,7 +840,7 @@ CREATE TABLE distributors (
<para> <para>
Although the syntax of <literal>CREATE TEMPORARY TABLE</literal> Although the syntax of <literal>CREATE TEMPORARY TABLE</literal>
resembles that of the SQL standard, the effect is not the same. In the resembles that of the SQL standard, the effect is not the same. In the
standard, standard,
temporary tables are defined just once and automatically exist (starting temporary tables are defined just once and automatically exist (starting
with empty contents) in every session that needs them. with empty contents) in every session that needs them.
<productname>PostgreSQL</productname> instead <productname>PostgreSQL</productname> instead
@ -889,7 +902,7 @@ CREATE TABLE distributors (
column, its presence is simply noise. column, its presence is simply noise.
</para> </para>
</refsect2> </refsect2>
<refsect2> <refsect2>
<title>Inheritance</title> <title>Inheritance</title>
@ -923,6 +936,15 @@ CREATE TABLE distributors (
DROP COLUMN</>, so it seems cleaner to ignore this spec restriction. DROP COLUMN</>, so it seems cleaner to ignore this spec restriction.
</para> </para>
</refsect2> </refsect2>
<refsect2>
<title>TABLESPACE</title>
<para>
The <productname>PostgreSQL</productname> concept of tablespaces is not
standard.
</para>
</refsect2>
</refsect1> </refsect1>
@ -932,6 +954,7 @@ CREATE TABLE distributors (
<simplelist type="inline"> <simplelist type="inline">
<member><xref linkend="sql-altertable" endterm="sql-altertable-title"></member> <member><xref linkend="sql-altertable" endterm="sql-altertable-title"></member>
<member><xref linkend="sql-droptable" endterm="sql-droptable-title"></member> <member><xref linkend="sql-droptable" endterm="sql-droptable-title"></member>
<member><xref linkend="sql-createtablespace" endterm="sql-createtablespace-title"></member>
</simplelist> </simplelist>
</refsect1> </refsect1>
</refentry> </refentry>

View File

@ -0,0 +1,156 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_tablespace.sgml,v 1.1 2004/06/18 06:13:05 tgl Exp $
PostgreSQL documentation
-->
<refentry id="SQL-CREATETABLESPACE">
<refmeta>
<refentrytitle id="sql-createtablespace-title">CREATE TABLESPACE</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>CREATE TABLESPACE</refname>
<refpurpose>define a new tablespace</refpurpose>
</refnamediv>
<indexterm zone="sql-createtablespace">
<primary>CREATE TABLESPACE</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
CREATE TABLESPACE <replaceable class="parameter">tablespacename</replaceable> [ OWNER <replaceable class="parameter">username</replaceable> ] LOCATION '<replaceable class="parameter">directory</replaceable>'
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>CREATE TABLESPACE</command> registers a new cluster-wide
tablespace. The tablespace name must be distinct from the name of any
existing tablespace in the database cluster.
</para>
<para>
A tablespace allows superusers to define an alternative location on the
file system where the data files representing database objects
(such as tables and indexes) may reside.
</para>
<para>
A user with appropriate privileges can pass
<replaceable class="parameter">tablespacename</> to <command>CREATE
DATABASE</>, <command>CREATE SCHEMA</>, <command>CREATE TABLE</>,
<command>CREATE INDEX</> or <command>CREATE SEQUENCE</> to have the data
files for these objects stored within the specified tablespace.
</para>
</refsect1>
<refsect1>
<title>Parameters</title>
<variablelist>
<varlistentry>
<term><replaceable class="parameter">tablespacename</replaceable></term>
<listitem>
<para>
The name of a tablespace to be created.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">username</replaceable></term>
<listitem>
<para>
The name of the user who will own the tablespace. If omitted,
defaults to the user executing the command. Only superusers
may create tablespaces, but they can assign ownership of tablespaces
to non-superusers.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">directory</replaceable></term>
<listitem>
<para>
The directory that will be used for the tablespace. The directory
must be empty and must be owned by the
<productname>PostgreSQL</> system user. The directory must be
specified by an absolute path name.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Notes</title>
<para>
Tablespaces are only supported on systems that support symbolic links.
</para>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
Create a tablespace <literal>dbspace</> at <literal>/data/dbs</>:
<programlisting>
CREATE TABLESPACE dbspace LOCATION '/data/dbs';
</programlisting>
</para>
<para>
Create a tablespace <literal>indexspace</> at <literal>/data/indexes</>
owned by user <literal>genevieve</>:
<programlisting>
CREATE TABLESPACE indexspace OWNER genevieve LOCATION '/data/indexes';
</programlisting>
</para>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
<command>CREATE TABLESPACE</command> is a <productname>PostgreSQL</>
extension.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-createdatabase" endterm="sql-createdatabase-title"></member>
<member><xref linkend="sql-createschema" endterm="sql-createschema-title"></member>
<member><xref linkend="sql-createtable" endterm="sql-createtable-title"></member>
<member><xref linkend="sql-createindex" endterm="sql-createindex-title"></member>
<member><xref linkend="sql-createsequence" endterm="sql-createsequence-title"></member>
<member><xref linkend="sql-droptablespace" endterm="sql-droptablespace-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->

View File

@ -0,0 +1,103 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/drop_tablespace.sgml,v 1.1 2004/06/18 06:13:05 tgl Exp $
PostgreSQL documentation
-->
<refentry id="SQL-DROPTABLESPACE">
<refmeta>
<refentrytitle id="SQL-DROPTABLESPACE-TITLE">DROP TABLESPACE</refentrytitle>
<refmiscinfo>SQL - Language Statements</refmiscinfo>
</refmeta>
<refnamediv>
<refname>DROP TABLESPACE</refname>
<refpurpose>remove a tablespace</refpurpose>
</refnamediv>
<indexterm zone="sql-droptablespace">
<primary>DROP TABLESPACE</primary>
</indexterm>
<refsynopsisdiv>
<synopsis>
DROP TABLESPACE <replaceable class="PARAMETER">tablespacename</replaceable>
</synopsis>
</refsynopsisdiv>
<refsect1>
<title>Description</title>
<para>
<command>DROP TABLESPACE</command> removes a tablespace from the system.
</para>
<para>
A tablespace can only be dropped by its owner or a superuser.
The tablespace must be empty of all database objects before it can be
dropped. It is possible that objects in other databases may still reside
in the tablespace even if no objects in the current database are using
the tablespace.
</para>
</refsect1>
<refsect1>
<title>Parameters</title>
<variablelist>
<varlistentry>
<term><replaceable class="PARAMETER">tablespacename</replaceable></term>
<listitem>
<para>
The name of a tablespace.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>
<refsect1>
<title>Examples</title>
<para>
To remove tablespace <literal>mystuff</literal> from the system:
<programlisting>
DROP TABLESPACE mystuff;
</programlisting>
</para>
</refsect1>
<refsect1>
<title>Compatibility</title>
<para>
<command>DROP TABLESPACE</command> is a <productname>PostgreSQL</>
extension.
</para>
</refsect1>
<refsect1>
<title>See Also</title>
<simplelist type="inline">
<member><xref linkend="sql-createtablespace" endterm="sql-createtablespace-title"></member>
</simplelist>
</refsect1>
</refentry>
<!-- Keep this comment at the end of the file
Local variables:
mode: sgml
sgml-omittag:nil
sgml-shorttag:t
sgml-minimize-attributes:nil
sgml-always-quote-attributes:t
sgml-indent-step:1
sgml-indent-data:t
sgml-parent-document:nil
sgml-default-dtd-file:"../reference.ced"
sgml-exposed-tags:nil
sgml-local-catalogs:"/usr/lib/sgml/catalog"
sgml-local-ecat-files:nil
End:
-->

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.40 2004/06/01 21:49:21 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/grant.sgml,v 1.41 2004/06/18 06:13:05 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -29,6 +29,10 @@ GRANT { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
ON DATABASE <replaceable>dbname</replaceable> [, ...] ON DATABASE <replaceable>dbname</replaceable> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ] TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
GRANT { CREATE | ALL [ PRIVILEGES ] }
ON TABLESPACE <replaceable>tablespacename</> [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
GRANT { EXECUTE | ALL [ PRIVILEGES ] } GRANT { EXECUTE | ALL [ PRIVILEGES ] }
ON FUNCTION <replaceable>funcname</replaceable> ([<replaceable>type</replaceable>, ...]) [, ...] ON FUNCTION <replaceable>funcname</replaceable> ([<replaceable>type</replaceable>, ...]) [, ...]
TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ] TO { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
@ -87,7 +91,7 @@ GRANT { { CREATE | USAGE } [,...] | ALL [ PRIVILEGES ] }
<para> <para>
Depending on the type of object, the initial default privileges may Depending on the type of object, the initial default privileges may
include granting some privileges to <literal>PUBLIC</literal>. include granting some privileges to <literal>PUBLIC</literal>.
The default is no public access for tables and schemas; The default is no public access for tables, schemas, and tablespaces;
<literal>TEMP</> table creation privilege for databases; <literal>TEMP</> table creation privilege for databases;
<literal>EXECUTE</> privilege for functions; and <literal>EXECUTE</> privilege for functions; and
<literal>USAGE</> privilege for languages. <literal>USAGE</> privilege for languages.
@ -184,6 +188,12 @@ GRANT { { CREATE | USAGE } [,...] | ALL [ PRIVILEGES ] }
<para> <para>
For databases, allows new schemas to be created within the database. For databases, allows new schemas to be created within the database.
</para> </para>
<para>
For tablespaces, allows tables to be created within the tablespace,
and allows databases and schemas to be created that have the tablespace
as their default tablespace. (Note that revoking this privilege
will not alter the behavior of existing databases and schemas.)
</para>
<para> <para>
For schemas, allows new objects to be created within the schema. For schemas, allows new objects to be created within the schema.
To rename an existing object, you must own the object <emphasis>and</> To rename an existing object, you must own the object <emphasis>and</>
@ -223,7 +233,7 @@ GRANT { { CREATE | USAGE } [,...] | ALL [ PRIVILEGES ] }
of privilege that is applicable to procedural languages. of privilege that is applicable to procedural languages.
</para> </para>
<para> <para>
For schemas, allows access to objects contained in the specified For schemas, allows access to objects contained in the specified
schema (assuming that the objects' own privilege requirements are schema (assuming that the objects' own privilege requirements are
also met). Essentially this allows the grantee to <quote>look up</> also met). Essentially this allows the grantee to <quote>look up</>
objects within the schema. objects within the schema.
@ -385,7 +395,7 @@ GRANT ALL PRIVILEGES ON kinds TO manuel;
<refsect1 id="sql-grant-compatibility"> <refsect1 id="sql-grant-compatibility">
<title>Compatibility</title> <title>Compatibility</title>
<para> <para>
According to the SQL standard, the <literal>PRIVILEGES</literal> According to the SQL standard, the <literal>PRIVILEGES</literal>
key word in <literal>ALL PRIVILEGES</literal> is required. The key word in <literal>ALL PRIVILEGES</literal> is required. The
@ -412,7 +422,7 @@ GRANT <replaceable class="PARAMETER">privileges</replaceable>
<para> <para>
The <literal>RULE</literal> privilege, and privileges on The <literal>RULE</literal> privilege, and privileges on
databases, schemas, languages, and sequences are databases, tablespaces, schemas, languages, and sequences are
<productname>PostgreSQL</productname> extensions. <productname>PostgreSQL</productname> extensions.
</para> </para>
</refsect1> </refsect1>

File diff suppressed because it is too large Load Diff

View File

@ -1,5 +1,5 @@
<!-- <!--
$PostgreSQL: pgsql/doc/src/sgml/ref/revoke.sgml,v 1.30 2004/06/01 21:49:21 tgl Exp $ $PostgreSQL: pgsql/doc/src/sgml/ref/revoke.sgml,v 1.31 2004/06/18 06:13:05 tgl Exp $
PostgreSQL documentation PostgreSQL documentation
--> -->
@ -33,6 +33,12 @@ REVOKE [ GRANT OPTION FOR ]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...] FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ] [ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ]
{ CREATE | ALL [ PRIVILEGES ] }
ON TABLESPACE <replaceable>tablespacename</replaceable> [, ...]
FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
[ CASCADE | RESTRICT ]
REVOKE [ GRANT OPTION FOR ] REVOKE [ GRANT OPTION FOR ]
{ EXECUTE | ALL [ PRIVILEGES ] } { EXECUTE | ALL [ PRIVILEGES ] }
ON FUNCTION <replaceable>funcname</replaceable> ([<replaceable>type</replaceable>, ...]) [, ...] ON FUNCTION <replaceable>funcname</replaceable> ([<replaceable>type</replaceable>, ...]) [, ...]

View File

@ -1,5 +1,5 @@
<!-- reference.sgml <!-- reference.sgml
$PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.47 2004/04/20 01:14:55 momjian Exp $ $PostgreSQL: pgsql/doc/src/sgml/reference.sgml,v 1.48 2004/06/18 06:13:02 tgl Exp $
PostgreSQL Reference Manual PostgreSQL Reference Manual
--> -->
@ -76,6 +76,7 @@ PostgreSQL Reference Manual
&createSequence; &createSequence;
&createTable; &createTable;
&createTableAs; &createTableAs;
&createTableSpace;
&createTrigger; &createTrigger;
&createType; &createType;
&createUser; &createUser;
@ -98,6 +99,7 @@ PostgreSQL Reference Manual
&dropSchema; &dropSchema;
&dropSequence; &dropSequence;
&dropTable; &dropTable;
&dropTableSpace;
&dropTrigger; &dropTrigger;
&dropType; &dropType;
&dropUser; &dropUser;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.168 2004/05/27 17:12:37 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/heap/heapam.c,v 1.169 2004/06/18 06:13:09 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
@ -2630,8 +2630,8 @@ heap_undo(XLogRecPtr lsn, XLogRecord *record)
static void static void
out_target(char *buf, xl_heaptid *target) out_target(char *buf, xl_heaptid *target)
{ {
sprintf(buf + strlen(buf), "node %u/%u; tid %u/%u", sprintf(buf + strlen(buf), "rel %u/%u/%u; tid %u/%u",
target->node.tblNode, target->node.relNode, target->node.spcNode, target->node.dbNode, target->node.relNode,
ItemPointerGetBlockNumber(&(target->tid)), ItemPointerGetBlockNumber(&(target->tid)),
ItemPointerGetOffsetNumber(&(target->tid))); ItemPointerGetOffsetNumber(&(target->tid)));
} }
@ -2673,8 +2673,9 @@ heap_desc(char *buf, uint8 xl_info, char *rec)
{ {
xl_heap_clean *xlrec = (xl_heap_clean *) rec; xl_heap_clean *xlrec = (xl_heap_clean *) rec;
sprintf(buf + strlen(buf), "clean: node %u/%u; blk %u", sprintf(buf + strlen(buf), "clean: rel %u/%u/%u; blk %u",
xlrec->node.tblNode, xlrec->node.relNode, xlrec->block); xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block);
} }
else else
strcat(buf, "UNKNOWN"); strcat(buf, "UNKNOWN");

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.13 2004/06/02 17:28:17 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/nbtree/nbtxlog.c,v 1.14 2004/06/18 06:13:11 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -803,8 +803,8 @@ btree_undo(XLogRecPtr lsn, XLogRecord *record)
static void static void
out_target(char *buf, xl_btreetid *target) out_target(char *buf, xl_btreetid *target)
{ {
sprintf(buf + strlen(buf), "node %u/%u; tid %u/%u", sprintf(buf + strlen(buf), "rel %u/%u/%u; tid %u/%u",
target->node.tblNode, target->node.relNode, target->node.spcNode, target->node.dbNode, target->node.relNode,
ItemPointerGetBlockNumber(&(target->tid)), ItemPointerGetBlockNumber(&(target->tid)),
ItemPointerGetOffsetNumber(&(target->tid))); ItemPointerGetOffsetNumber(&(target->tid)));
} }
@ -884,8 +884,9 @@ btree_desc(char *buf, uint8 xl_info, char *rec)
{ {
xl_btree_delete *xlrec = (xl_btree_delete *) rec; xl_btree_delete *xlrec = (xl_btree_delete *) rec;
sprintf(buf + strlen(buf), "delete: node %u/%u; blk %u", sprintf(buf + strlen(buf), "delete: rel %u/%u/%u; blk %u",
xlrec->node.tblNode, xlrec->node.relNode, xlrec->block); xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode, xlrec->block);
break; break;
} }
case XLOG_BTREE_DELETE_PAGE: case XLOG_BTREE_DELETE_PAGE:
@ -903,8 +904,9 @@ btree_desc(char *buf, uint8 xl_info, char *rec)
{ {
xl_btree_newroot *xlrec = (xl_btree_newroot *) rec; xl_btree_newroot *xlrec = (xl_btree_newroot *) rec;
sprintf(buf + strlen(buf), "newroot: node %u/%u; root %u lev %u", sprintf(buf + strlen(buf), "newroot: rel %u/%u/%u; root %u lev %u",
xlrec->node.tblNode, xlrec->node.relNode, xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode,
xlrec->rootblk, xlrec->level); xlrec->rootblk, xlrec->level);
break; break;
} }
@ -912,8 +914,9 @@ btree_desc(char *buf, uint8 xl_info, char *rec)
{ {
xl_btree_newmeta *xlrec = (xl_btree_newmeta *) rec; xl_btree_newmeta *xlrec = (xl_btree_newmeta *) rec;
sprintf(buf + strlen(buf), "newmeta: node %u/%u; root %u lev %u fast %u lev %u", sprintf(buf + strlen(buf), "newmeta: rel %u/%u/%u; root %u lev %u fast %u lev %u",
xlrec->node.tblNode, xlrec->node.relNode, xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->node.relNode,
xlrec->meta.root, xlrec->meta.level, xlrec->meta.root, xlrec->meta.level,
xlrec->meta.fastroot, xlrec->meta.fastlevel); xlrec->meta.fastroot, xlrec->meta.fastlevel);
break; break;
@ -922,9 +925,9 @@ btree_desc(char *buf, uint8 xl_info, char *rec)
{ {
xl_btree_newpage *xlrec = (xl_btree_newpage *) rec; xl_btree_newpage *xlrec = (xl_btree_newpage *) rec;
sprintf(buf + strlen(buf), "newpage: node %u/%u; page %u", sprintf(buf + strlen(buf), "newpage: rel %u/%u/%u; page %u",
xlrec->node.tblNode, xlrec->node.relNode, xlrec->node.spcNode, xlrec->node.dbNode,
xlrec->blkno); xlrec->node.relNode, xlrec->blkno);
break; break;
} }
default: default:

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.30 2004/02/11 22:55:24 tgl Exp $ * $PostgreSQL: pgsql/src/backend/access/transam/xlogutils.c,v 1.31 2004/06/18 06:13:15 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -354,7 +354,7 @@ XLogOpenRelation(bool redo, RmgrId rmid, RelFileNode rnode)
* though, since we are presumably running by ourselves and can't * though, since we are presumably running by ourselves and can't
* have any lock conflicts ... * have any lock conflicts ...
*/ */
res->reldata.rd_lockInfo.lockRelId.dbId = rnode.tblNode; res->reldata.rd_lockInfo.lockRelId.dbId = rnode.dbNode;
res->reldata.rd_lockInfo.lockRelId.relId = rnode.relNode; res->reldata.rd_lockInfo.lockRelId.relId = rnode.relNode;
hentry = (XLogRelCacheEntry *) hentry = (XLogRelCacheEntry *)

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.69 2004/06/03 02:08:02 tgl Exp $ * $PostgreSQL: pgsql/src/backend/bootstrap/bootparse.y,v 1.70 2004/06/18 06:13:17 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -31,6 +31,7 @@
#include "catalog/pg_attribute.h" #include "catalog/pg_attribute.h"
#include "catalog/pg_class.h" #include "catalog/pg_class.h"
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_tablespace.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
@ -181,6 +182,7 @@ Boot_CreateStmt:
boot_reldesc = heap_create(LexIDStr($5), boot_reldesc = heap_create(LexIDStr($5),
PG_CATALOG_NAMESPACE, PG_CATALOG_NAMESPACE,
$3 ? GLOBALTABLESPACE_OID : 0,
tupdesc, tupdesc,
$3, $3,
true, true,
@ -193,6 +195,7 @@ Boot_CreateStmt:
id = heap_create_with_catalog(LexIDStr($5), id = heap_create_with_catalog(LexIDStr($5),
PG_CATALOG_NAMESPACE, PG_CATALOG_NAMESPACE,
$3 ? GLOBALTABLESPACE_OID : 0,
tupdesc, tupdesc,
RELKIND_RELATION, RELKIND_RELATION,
$3, $3,
@ -239,6 +242,7 @@ Boot_DeclareIndexStmt:
DefineIndex(makeRangeVar(NULL, LexIDStr($5)), DefineIndex(makeRangeVar(NULL, LexIDStr($5)),
LexIDStr($3), LexIDStr($3),
LexIDStr($7), LexIDStr($7),
NULL,
$9, $9,
NULL, NIL, NULL, NIL,
false, false, false, false, false, false,
@ -255,6 +259,7 @@ Boot_DeclareUniqueIndexStmt:
DefineIndex(makeRangeVar(NULL, LexIDStr($6)), DefineIndex(makeRangeVar(NULL, LexIDStr($6)),
LexIDStr($4), LexIDStr($4),
LexIDStr($8), LexIDStr($8),
NULL,
$10, $10,
NULL, NIL, NULL, NIL,
true, false, false, true, false, false,

View File

@ -2,7 +2,7 @@
# #
# Makefile for backend/catalog # Makefile for backend/catalog
# #
# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.50 2004/01/04 05:57:21 tgl Exp $ # $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.51 2004/06/18 06:13:19 tgl Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -32,7 +32,7 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \ pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \ pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \ pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
pg_depend.h indexing.h \ pg_tablespace.h pg_depend.h indexing.h \
) )
pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include) pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include)
@ -59,5 +59,5 @@ installdirs:
uninstall-data: uninstall-data:
rm -f $(addprefix $(DESTDIR)$(datadir)/, $(BKIFILES) system_views.sql information_schema.sql sql_features.txt) rm -f $(addprefix $(DESTDIR)$(datadir)/, $(BKIFILES) system_views.sql information_schema.sql sql_features.txt)
clean: clean:
rm -f SUBSYS.o $(OBJS) $(BKIFILES) rm -f SUBSYS.o $(OBJS) $(BKIFILES)

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.103 2004/06/01 21:49:22 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.104 2004/06/18 06:13:19 tgl Exp $
* *
* NOTES * NOTES
* See acl.h. * See acl.h.
@ -31,6 +31,7 @@
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_proc.h" #include "catalog/pg_proc.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/parse_func.h" #include "parser/parse_func.h"
@ -45,6 +46,7 @@ static void ExecuteGrantStmt_Database(GrantStmt *stmt);
static void ExecuteGrantStmt_Function(GrantStmt *stmt); static void ExecuteGrantStmt_Function(GrantStmt *stmt);
static void ExecuteGrantStmt_Language(GrantStmt *stmt); static void ExecuteGrantStmt_Language(GrantStmt *stmt);
static void ExecuteGrantStmt_Namespace(GrantStmt *stmt); static void ExecuteGrantStmt_Namespace(GrantStmt *stmt);
static void ExecuteGrantStmt_Tablespace(GrantStmt *stmt);
static const char *privilege_to_string(AclMode privilege); static const char *privilege_to_string(AclMode privilege);
@ -207,12 +209,16 @@ ExecuteGrantStmt(GrantStmt *stmt)
case ACL_OBJECT_NAMESPACE: case ACL_OBJECT_NAMESPACE:
ExecuteGrantStmt_Namespace(stmt); ExecuteGrantStmt_Namespace(stmt);
break; break;
case ACL_OBJECT_TABLESPACE:
ExecuteGrantStmt_Tablespace(stmt);
break;
default: default:
elog(ERROR, "unrecognized GrantStmt.objtype: %d", elog(ERROR, "unrecognized GrantStmt.objtype: %d",
(int) stmt->objtype); (int) stmt->objtype);
} }
} }
static void static void
ExecuteGrantStmt_Relation(GrantStmt *stmt) ExecuteGrantStmt_Relation(GrantStmt *stmt)
{ {
@ -1009,6 +1015,163 @@ ExecuteGrantStmt_Namespace(GrantStmt *stmt)
} }
} }
static void
ExecuteGrantStmt_Tablespace(GrantStmt *stmt)
{
AclMode privileges;
bool all_privs;
ListCell *i;
if (linitial_int(stmt->privileges) == ACL_ALL_RIGHTS)
{
all_privs = true;
privileges = ACL_ALL_RIGHTS_TABLESPACE;
}
else
{
all_privs = false;
privileges = ACL_NO_RIGHTS;
foreach(i, stmt->privileges)
{
AclMode priv = lfirst_int(i);
if (priv & ~((AclMode) ACL_ALL_RIGHTS_TABLESPACE))
ereport(ERROR,
(errcode(ERRCODE_INVALID_GRANT_OPERATION),
errmsg("invalid privilege type %s for tablespace",
privilege_to_string(priv))));
privileges |= priv;
}
}
foreach(i, stmt->objects)
{
char *spcname = strVal(lfirst(i));
Relation relation;
ScanKeyData entry[1];
HeapScanDesc scan;
HeapTuple tuple;
Form_pg_tablespace pg_tablespace_tuple;
Datum aclDatum;
bool isNull;
AclMode my_goptions;
AclMode this_privileges;
Acl *old_acl;
Acl *new_acl;
AclId grantorId;
AclId ownerId;
HeapTuple newtuple;
Datum values[Natts_pg_tablespace];
char nulls[Natts_pg_tablespace];
char replaces[Natts_pg_tablespace];
relation = heap_openr(TableSpaceRelationName, RowExclusiveLock);
ScanKeyInit(&entry[0],
Anum_pg_tablespace_spcname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(spcname));
scan = heap_beginscan(relation, SnapshotNow, 1, entry);
tuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace \"%s\" does not exist", spcname)));
pg_tablespace_tuple = (Form_pg_tablespace) GETSTRUCT(tuple);
ownerId = pg_tablespace_tuple->spcowner;
grantorId = select_grantor(ownerId);
/*
* Must be owner or have some privilege on the object (per spec,
* any privilege will get you by here). The owner is always
* treated as having all grant options.
*/
if (pg_tablespace_ownercheck(HeapTupleGetOid(tuple), GetUserId()))
my_goptions = ACL_ALL_RIGHTS_TABLESPACE;
else
{
AclMode my_rights;
my_rights = pg_tablespace_aclmask(HeapTupleGetOid(tuple),
GetUserId(),
ACL_ALL_RIGHTS_TABLESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_TABLESPACE),
ACLMASK_ALL);
if (my_rights == ACL_NO_RIGHTS)
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
spcname);
my_goptions = ACL_OPTION_TO_PRIVS(my_rights);
}
/*
* Restrict the operation to what we can actually grant or revoke,
* and issue a warning if appropriate. (For REVOKE this isn't quite
* what the spec says to do: the spec seems to want a warning only
* if no privilege bits actually change in the ACL. In practice
* that behavior seems much too noisy, as well as inconsistent with
* the GRANT case.)
*/
this_privileges = privileges & my_goptions;
if (stmt->is_grant)
{
if (this_privileges == 0)
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
errmsg("no privileges were granted")));
else if (!all_privs && this_privileges != privileges)
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
errmsg("not all privileges were granted")));
}
else
{
if (this_privileges == 0)
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
errmsg("no privileges could be revoked")));
else if (!all_privs && this_privileges != privileges)
ereport(WARNING,
(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
errmsg("not all privileges could be revoked")));
}
/*
* If there's no ACL, substitute the proper default.
*/
aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
RelationGetDescr(relation), &isNull);
if (isNull)
old_acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
else
/* get a detoasted copy of the ACL */
old_acl = DatumGetAclPCopy(aclDatum);
new_acl = merge_acl_with_grant(old_acl, stmt->is_grant,
stmt->grant_option, stmt->behavior,
stmt->grantees, this_privileges,
grantorId, ownerId);
/* finished building new ACL value, now insert it */
MemSet(values, 0, sizeof(values));
MemSet(nulls, ' ', sizeof(nulls));
MemSet(replaces, ' ', sizeof(replaces));
replaces[Anum_pg_tablespace_spcacl - 1] = 'r';
values[Anum_pg_tablespace_spcacl - 1] = PointerGetDatum(new_acl);
newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
simple_heap_update(relation, &newtuple->t_self, newtuple);
/* keep the catalog indexes up to date */
CatalogUpdateIndexes(relation, newtuple);
pfree(new_acl);
heap_endscan(scan);
heap_close(relation, RowExclusiveLock);
}
}
static const char * static const char *
privilege_to_string(AclMode privilege) privilege_to_string(AclMode privilege)
@ -1112,7 +1275,9 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
/* ACL_KIND_OPCLASS */ /* ACL_KIND_OPCLASS */
gettext_noop("permission denied for operator class %s"), gettext_noop("permission denied for operator class %s"),
/* ACL_KIND_CONVERSION */ /* ACL_KIND_CONVERSION */
gettext_noop("permission denied for conversion %s") gettext_noop("permission denied for conversion %s"),
/* ACL_KIND_TABLESPACE */
gettext_noop("permission denied for tablespace %s")
}; };
static const char *const not_owner_msg[MAX_ACL_KIND] = static const char *const not_owner_msg[MAX_ACL_KIND] =
@ -1134,7 +1299,9 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
/* ACL_KIND_OPCLASS */ /* ACL_KIND_OPCLASS */
gettext_noop("must be owner of operator class %s"), gettext_noop("must be owner of operator class %s"),
/* ACL_KIND_CONVERSION */ /* ACL_KIND_CONVERSION */
gettext_noop("must be owner of conversion %s") gettext_noop("must be owner of conversion %s"),
/* ACL_KIND_TABLESPACE */
gettext_noop("must be owner of tablespace %s")
}; };
@ -1545,6 +1712,80 @@ pg_namespace_aclmask(Oid nsp_oid, AclId userid,
return result; return result;
} }
/*
* Exported routine for examining a user's privileges for a tablespace
*/
AclMode
pg_tablespace_aclmask(Oid spc_oid, AclId userid,
AclMode mask, AclMaskHow how)
{
AclMode result;
Relation pg_tablespace;
ScanKeyData entry[1];
HeapScanDesc scan;
HeapTuple tuple;
Datum aclDatum;
bool isNull;
Acl *acl;
AclId ownerId;
/*
* Only shared relations can be stored in global space; don't let
* even superusers override this
*/
if (spc_oid == GLOBALTABLESPACE_OID && !IsBootstrapProcessingMode())
return 0;
/* Otherwise, superusers bypass all permission checking. */
if (superuser_arg(userid))
return mask;
/*
* Get the tablespace's ACL from pg_tablespace
*
* There's no syscache for pg_tablespace, so must look the hard way
*/
pg_tablespace = heap_openr(TableSpaceRelationName, AccessShareLock);
ScanKeyInit(&entry[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry);
tuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace with OID %u does not exist", spc_oid)));
ownerId = ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner;
aclDatum = heap_getattr(tuple, Anum_pg_tablespace_spcacl,
RelationGetDescr(pg_tablespace), &isNull);
if (isNull)
{
/* No ACL, so build default ACL */
acl = acldefault(ACL_OBJECT_TABLESPACE, ownerId);
aclDatum = (Datum) 0;
}
else
{
/* detoast ACL if necessary */
acl = DatumGetAclP(aclDatum);
}
result = aclmask(acl, userid, ownerId, mask, how);
/* if we have a detoasted copy, free it */
if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
heap_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return result;
}
/* /*
* Exported routine for checking a user's access privileges to a table * Exported routine for checking a user's access privileges to a table
@ -1610,6 +1851,18 @@ pg_namespace_aclcheck(Oid nsp_oid, AclId userid, AclMode mode)
return ACLCHECK_NO_PRIV; return ACLCHECK_NO_PRIV;
} }
/*
* Exported routine for checking a user's access privileges to a tablespace
*/
AclResult
pg_tablespace_aclcheck(Oid spc_oid, AclId userid, AclMode mode)
{
if (pg_tablespace_aclmask(spc_oid, userid, mode, ACLMASK_ANY) != 0)
return ACLCHECK_OK;
else
return ACLCHECK_NO_PRIV;
}
/* /*
* Ownership check for a relation (specified by OID). * Ownership check for a relation (specified by OID).
@ -1751,6 +2004,45 @@ pg_namespace_ownercheck(Oid nsp_oid, AclId userid)
return userid == owner_id; return userid == owner_id;
} }
/*
* Ownership check for a tablespace (specified by OID).
*/
bool
pg_tablespace_ownercheck(Oid spc_oid, AclId userid)
{
Relation pg_tablespace;
ScanKeyData entry[1];
HeapScanDesc scan;
HeapTuple spctuple;
int32 spcowner;
/* Superusers bypass all permission checking. */
if (superuser_arg(userid))
return true;
/* There's no syscache for pg_tablespace, so must look the hard way */
pg_tablespace = heap_openr(TableSpaceRelationName, AccessShareLock);
ScanKeyInit(&entry[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
scan = heap_beginscan(pg_tablespace, SnapshotNow, 1, entry);
spctuple = heap_getnext(scan, ForwardScanDirection);
if (!HeapTupleIsValid(spctuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace with OID %u does not exist", spc_oid)));
spcowner = ((Form_pg_tablespace) GETSTRUCT(spctuple))->spcowner;
heap_endscan(scan);
heap_close(pg_tablespace, AccessShareLock);
return userid == spcowner;
}
/* /*
* Ownership check for an operator class (specified by OID). * Ownership check for an operator class (specified by OID).
*/ */
@ -1780,9 +2072,8 @@ pg_opclass_ownercheck(Oid opc_oid, AclId userid)
return userid == owner_id; return userid == owner_id;
} }
/* /*
* Ownership check for database (specified as OID) * Ownership check for a database (specified by OID).
*/ */
bool bool
pg_database_ownercheck(Oid db_oid, AclId userid) pg_database_ownercheck(Oid db_oid, AclId userid)

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.51 2004/01/06 18:07:31 neilc Exp $ * $PostgreSQL: pgsql/src/backend/catalog/catalog.c,v 1.52 2004/06/18 06:13:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -20,30 +20,48 @@
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "catalog/pg_tablespace.h"
#include "miscadmin.h" #include "miscadmin.h"
#define OIDCHARS 10 /* max chars printed by %u */
/* /*
* relpath - construct path to a relation's file * relpath - construct path to a relation's file
* *
* Result is a palloc'd string. * Result is a palloc'd string.
*/ */
char * char *
relpath(RelFileNode rnode) relpath(RelFileNode rnode)
{ {
int pathlen;
char *path; char *path;
if (rnode.tblNode == (Oid) 0) /* "global tablespace" */ if (rnode.spcNode == GLOBALTABLESPACE_OID)
{ {
/* Shared system relations live in {datadir}/global */ /* Shared system relations live in {datadir}/global */
path = (char *) palloc(strlen(DataDir) + 8 + sizeof(NameData) + 1); Assert(rnode.dbNode == 0);
sprintf(path, "%s/global/%u", DataDir, rnode.relNode); pathlen = strlen(DataDir) + 8 + OIDCHARS + 1;
path = (char *) palloc(pathlen);
snprintf(path, pathlen, "%s/global/%u",
DataDir, rnode.relNode);
}
else if (rnode.spcNode == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
pathlen = strlen(DataDir) + 6 + OIDCHARS + 1 + OIDCHARS + 1;
path = (char *) palloc(pathlen);
snprintf(path, pathlen, "%s/base/%u/%u",
DataDir, rnode.dbNode, rnode.relNode);
} }
else else
{ {
path = (char *) palloc(strlen(DataDir) + 6 + 2 * sizeof(NameData) + 3); /* All other tablespaces are accessed via symlinks */
sprintf(path, "%s/base/%u/%u", DataDir, rnode.tblNode, rnode.relNode); pathlen = strlen(DataDir) + 16 + OIDCHARS + 1 + OIDCHARS + 1 + OIDCHARS + 1;
path = (char *) palloc(pathlen);
snprintf(path, pathlen, "%s/pg_tablespaces/%u/%u/%u",
DataDir, rnode.spcNode, rnode.dbNode, rnode.relNode);
} }
return path; return path;
} }
@ -52,23 +70,39 @@ relpath(RelFileNode rnode)
* GetDatabasePath - construct path to a database dir * GetDatabasePath - construct path to a database dir
* *
* Result is a palloc'd string. * Result is a palloc'd string.
*
* XXX this must agree with relpath()!
*/ */
char * char *
GetDatabasePath(Oid tblNode) GetDatabasePath(Oid dbNode, Oid spcNode)
{ {
int pathlen;
char *path; char *path;
if (tblNode == (Oid) 0) /* "global tablespace" */ if (spcNode == GLOBALTABLESPACE_OID)
{ {
/* Shared system relations live in {datadir}/global */ /* Shared system relations live in {datadir}/global */
path = (char *) palloc(strlen(DataDir) + 8); Assert(dbNode == 0);
sprintf(path, "%s/global", DataDir); pathlen = strlen(DataDir) + 7 + 1;
path = (char *) palloc(pathlen);
snprintf(path, pathlen, "%s/global",
DataDir);
}
else if (spcNode == DEFAULTTABLESPACE_OID)
{
/* The default tablespace is {datadir}/base */
pathlen = strlen(DataDir) + 6 + OIDCHARS + 1;
path = (char *) palloc(pathlen);
snprintf(path, pathlen, "%s/base/%u",
DataDir, dbNode);
} }
else else
{ {
path = (char *) palloc(strlen(DataDir) + 6 + sizeof(NameData) + 1); /* All other tablespaces are accessed via symlinks */
sprintf(path, "%s/base/%u", DataDir, tblNode); pathlen = strlen(DataDir) + 16 + OIDCHARS + 1 + OIDCHARS + 1;
path = (char *) palloc(pathlen);
snprintf(path, pathlen, "%s/pg_tablespaces/%u/%u",
DataDir, spcNode, dbNode);
} }
return path; return path;
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.270 2004/06/10 17:55:53 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/heap.c,v 1.271 2004/06/18 06:13:19 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
@ -43,6 +43,7 @@
#include "catalog/pg_statistic.h" #include "catalog/pg_statistic.h"
#include "catalog/pg_type.h" #include "catalog/pg_type.h"
#include "commands/tablecmds.h" #include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
@ -203,15 +204,14 @@ SystemAttributeByName(const char *attname, bool relhasoids)
Relation Relation
heap_create(const char *relname, heap_create(const char *relname,
Oid relnamespace, Oid relnamespace,
Oid reltablespace,
TupleDesc tupDesc, TupleDesc tupDesc,
bool shared_relation, bool shared_relation,
bool storage_create, bool storage_create,
bool allow_system_table_mods) bool allow_system_table_mods)
{ {
Oid relid; Oid relid;
Oid dbid = shared_relation ? InvalidOid : MyDatabaseId;
bool nailme = false; bool nailme = false;
RelFileNode rnode;
Relation rel; Relation rel;
/* /*
@ -260,27 +260,23 @@ heap_create(const char *relname,
relid = RelOid_pg_group; relid = RelOid_pg_group;
else if (strcmp(DatabaseRelationName, relname) == 0) else if (strcmp(DatabaseRelationName, relname) == 0)
relid = RelOid_pg_database; relid = RelOid_pg_database;
else if (strcmp(TableSpaceRelationName, relname) == 0)
relid = RelOid_pg_tablespace;
else else
relid = newoid(); relid = newoid();
} }
else else
relid = newoid(); relid = newoid();
/*
* For now, the physical identifier of the relation is the same as the
* logical identifier.
*/
rnode.tblNode = dbid;
rnode.relNode = relid;
/* /*
* build the relcache entry. * build the relcache entry.
*/ */
rel = RelationBuildLocalRelation(relname, rel = RelationBuildLocalRelation(relname,
relnamespace, relnamespace,
tupDesc, tupDesc,
relid, dbid, relid,
rnode, reltablespace,
shared_relation,
nailme); nailme);
/* /*
@ -296,6 +292,16 @@ heap_create(const char *relname,
void void
heap_storage_create(Relation rel) heap_storage_create(Relation rel)
{ {
/*
* We may be using the target table space for the first time in this
* database, so create a per-database subdirectory if needed.
*
* XXX it might be better to do this right in smgrcreate...
*/
TablespaceCreateDbspace(rel->rd_node.spcNode, rel->rd_node.dbNode);
/*
* Now we can make the file.
*/
Assert(rel->rd_smgr == NULL); Assert(rel->rd_smgr == NULL);
rel->rd_smgr = smgropen(rel->rd_node); rel->rd_smgr = smgropen(rel->rd_node);
smgrcreate(rel->rd_smgr, rel->rd_istemp, false); smgrcreate(rel->rd_smgr, rel->rd_istemp, false);
@ -692,6 +698,7 @@ AddNewRelationType(const char *typeName,
Oid Oid
heap_create_with_catalog(const char *relname, heap_create_with_catalog(const char *relname,
Oid relnamespace, Oid relnamespace,
Oid reltablespace,
TupleDesc tupdesc, TupleDesc tupdesc,
char relkind, char relkind,
bool shared_relation, bool shared_relation,
@ -726,6 +733,7 @@ heap_create_with_catalog(const char *relname,
*/ */
new_rel_desc = heap_create(relname, new_rel_desc = heap_create(relname,
relnamespace, relnamespace,
reltablespace,
tupdesc, tupdesc,
shared_relation, shared_relation,
(relkind != RELKIND_VIEW && (relkind != RELKIND_VIEW &&

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.233 2004/05/31 19:24:05 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/index.c,v 1.234 2004/06/18 06:13:19 tgl Exp $
* *
* *
* INTERFACE ROUTINES * INTERFACE ROUTINES
@ -467,6 +467,7 @@ index_create(Oid heapRelationId,
const char *indexRelationName, const char *indexRelationName,
IndexInfo *indexInfo, IndexInfo *indexInfo,
Oid accessMethodObjectId, Oid accessMethodObjectId,
Oid tableSpaceId,
Oid *classObjectId, Oid *classObjectId,
bool primary, bool primary,
bool isconstraint, bool isconstraint,
@ -539,6 +540,7 @@ index_create(Oid heapRelationId,
*/ */
indexRelation = heap_create(indexRelationName, indexRelation = heap_create(indexRelationName,
namespaceId, namespaceId,
tableSpaceId,
indexTupDesc, indexTupDesc,
shared_relation, shared_relation,
true, true,

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.66 2004/05/28 16:17:14 tgl Exp $ * $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.67 2004/06/18 06:13:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1668,7 +1668,7 @@ InitTempTableNamespace(void)
* that access the temp namespace for my own backend skip * that access the temp namespace for my own backend skip
* permissions checks on it. * permissions checks on it.
*/ */
namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID); namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID, 0);
/* Advance command counter to make namespace visible */ /* Advance command counter to make namespace visible */
CommandCounterIncrement(); CommandCounterIncrement();
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_namespace.c,v 1.8 2003/11/29 19:51:46 pgsql Exp $ * $PostgreSQL: pgsql/src/backend/catalog/pg_namespace.c,v 1.9 2004/06/18 06:13:19 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -27,7 +27,7 @@
* --------------- * ---------------
*/ */
Oid Oid
NamespaceCreate(const char *nspName, int32 ownerSysId) NamespaceCreate(const char *nspName, int32 ownerSysId, Oid nspTablespace)
{ {
Relation nspdesc; Relation nspdesc;
HeapTuple tup; HeapTuple tup;
@ -59,6 +59,7 @@ NamespaceCreate(const char *nspName, int32 ownerSysId)
namestrcpy(&nname, nspName); namestrcpy(&nname, nspName);
values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname); values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
values[Anum_pg_namespace_nspowner - 1] = Int32GetDatum(ownerSysId); values[Anum_pg_namespace_nspowner - 1] = Int32GetDatum(ownerSysId);
values[Anum_pg_namespace_nsptablespace - 1] = Int32GetDatum(nspTablespace);
nulls[Anum_pg_namespace_nspacl - 1] = 'n'; nulls[Anum_pg_namespace_nspacl - 1] = 'n';
nspdesc = heap_openr(NamespaceRelationName, RowExclusiveLock); nspdesc = heap_openr(NamespaceRelationName, RowExclusiveLock);

View File

@ -4,7 +4,7 @@
# Makefile for backend/commands # Makefile for backend/commands
# #
# IDENTIFICATION # IDENTIFICATION
# $PostgreSQL: pgsql/src/backend/commands/Makefile,v 1.33 2003/11/29 19:51:47 pgsql Exp $ # $PostgreSQL: pgsql/src/backend/commands/Makefile,v 1.34 2004/06/18 06:13:22 tgl Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -17,8 +17,8 @@ OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
dbcommands.o define.o explain.o functioncmds.o \ dbcommands.o define.o explain.o functioncmds.o \
indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \ indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
portalcmds.o prepare.o proclang.o \ portalcmds.o prepare.o proclang.o \
schemacmds.o sequence.o tablecmds.o trigger.o typecmds.o user.o \ schemacmds.o sequence.o tablecmds.o tablespace.o trigger.o \
vacuum.o vacuumlazy.o variable.o view.o typecmds.o user.o vacuum.o vacuumlazy.o variable.o view.o
all: SUBSYS.o all: SUBSYS.o

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.125 2004/05/31 19:24:05 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/cluster.c,v 1.126 2004/06/18 06:13:22 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -568,6 +568,7 @@ make_new_heap(Oid OIDOldHeap, const char *NewName)
OIDNewHeap = heap_create_with_catalog(NewName, OIDNewHeap = heap_create_with_catalog(NewName,
RelationGetNamespace(OldHeap), RelationGetNamespace(OldHeap),
OldHeap->rd_rel->reltablespace,
tupdesc, tupdesc,
OldHeap->rd_rel->relkind, OldHeap->rd_rel->relkind,
OldHeap->rd_rel->relisshared, OldHeap->rd_rel->relisshared,

View File

@ -9,13 +9,12 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.135 2004/06/10 22:26:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.136 2004/06/18 06:13:22 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
#include "postgres.h" #include "postgres.h"
#include <errno.h>
#include <fcntl.h> #include <fcntl.h>
#include <unistd.h> #include <unistd.h>
#include <sys/stat.h> #include <sys/stat.h>
@ -26,9 +25,12 @@
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "catalog/pg_tablespace.h"
#include "catalog/indexing.h" #include "catalog/indexing.h"
#include "commands/comment.h" #include "commands/comment.h"
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
#include "commands/tablespace.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "storage/fd.h" #include "storage/fd.h"
#include "storage/freespace.h" #include "storage/freespace.h"
@ -41,32 +43,24 @@
#include "utils/lsyscache.h" #include "utils/lsyscache.h"
#include "utils/syscache.h" #include "utils/syscache.h"
#include "mb/pg_wchar.h" /* encoding check */
/* non-export function prototypes */ /* non-export function prototypes */
static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP, static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP, int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP, TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
char *dbpath); Oid *dbTablespace);
static bool have_createdb_privilege(void); static bool have_createdb_privilege(void);
static char *resolve_alt_dbpath(const char *dbpath, Oid dboid); static void remove_dbtablespaces(Oid db_id);
static bool remove_dbdirs(const char *real_loc, const char *altloc);
/* /*
* CREATE DATABASE * CREATE DATABASE
*/ */
void void
createdb(const CreatedbStmt *stmt) createdb(const CreatedbStmt *stmt)
{ {
char *nominal_loc; HeapScanDesc scan;
char *alt_loc; Relation rel;
char *target_dir;
char src_loc[MAXPGPATH];
#ifndef WIN32
char buf[2 * MAXPGPATH + 100];
#endif
Oid src_dboid; Oid src_dboid;
AclId src_owner; AclId src_owner;
int src_encoding; int src_encoding;
@ -74,7 +68,8 @@ createdb(const CreatedbStmt *stmt)
Oid src_lastsysoid; Oid src_lastsysoid;
TransactionId src_vacuumxid; TransactionId src_vacuumxid;
TransactionId src_frozenxid; TransactionId src_frozenxid;
char src_dbpath[MAXPGPATH]; Oid src_deftablespace;
Oid dst_deftablespace;
Relation pg_database_rel; Relation pg_database_rel;
HeapTuple tuple; HeapTuple tuple;
TupleDesc pg_database_dsc; TupleDesc pg_database_dsc;
@ -83,22 +78,35 @@ createdb(const CreatedbStmt *stmt)
Oid dboid; Oid dboid;
AclId datdba; AclId datdba;
ListCell *option; ListCell *option;
DefElem *dtablespacename = NULL;
DefElem *downer = NULL; DefElem *downer = NULL;
DefElem *dpath = NULL;
DefElem *dtemplate = NULL; DefElem *dtemplate = NULL;
DefElem *dencoding = NULL; DefElem *dencoding = NULL;
char *dbname = stmt->dbname; char *dbname = stmt->dbname;
char *dbowner = NULL; char *dbowner = NULL;
char *dbpath = NULL;
char *dbtemplate = NULL; char *dbtemplate = NULL;
int encoding = -1; int encoding = -1;
#ifndef WIN32
char buf[2 * MAXPGPATH + 100];
#endif
/* don't call this in a transaction block */
PreventTransactionChain((void *) stmt, "CREATE DATABASE");
/* Extract options from the statement node tree */ /* Extract options from the statement node tree */
foreach(option, stmt->options) foreach(option, stmt->options)
{ {
DefElem *defel = (DefElem *) lfirst(option); DefElem *defel = (DefElem *) lfirst(option);
if (strcmp(defel->defname, "owner") == 0) if (strcmp(defel->defname, "tablespace") == 0)
{
if (dtablespacename)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
dtablespacename = defel;
}
else if (strcmp(defel->defname, "owner") == 0)
{ {
if (downer) if (downer)
ereport(ERROR, ereport(ERROR,
@ -106,14 +114,6 @@ createdb(const CreatedbStmt *stmt)
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
downer = defel; downer = defel;
} }
else if (strcmp(defel->defname, "location") == 0)
{
if (dpath)
ereport(ERROR,
(errcode(ERRCODE_SYNTAX_ERROR),
errmsg("conflicting or redundant options")));
dpath = defel;
}
else if (strcmp(defel->defname, "template") == 0) else if (strcmp(defel->defname, "template") == 0)
{ {
if (dtemplate) if (dtemplate)
@ -130,6 +130,13 @@ createdb(const CreatedbStmt *stmt)
errmsg("conflicting or redundant options"))); errmsg("conflicting or redundant options")));
dencoding = defel; dencoding = defel;
} }
else if (strcmp(defel->defname, "location") == 0)
{
ereport(WARNING,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("LOCATION is not supported anymore"),
errhint("Consider using tablespaces instead.")));
}
else else
elog(ERROR, "option \"%s\" not recognized", elog(ERROR, "option \"%s\" not recognized",
defel->defname); defel->defname);
@ -137,8 +144,6 @@ createdb(const CreatedbStmt *stmt)
if (downer && downer->arg) if (downer && downer->arg)
dbowner = strVal(downer->arg); dbowner = strVal(downer->arg);
if (dpath && dpath->arg)
dbpath = strVal(dpath->arg);
if (dtemplate && dtemplate->arg) if (dtemplate && dtemplate->arg)
dbtemplate = strVal(dtemplate->arg); dbtemplate = strVal(dtemplate->arg);
if (dencoding && dencoding->arg) if (dencoding && dencoding->arg)
@ -195,17 +200,6 @@ createdb(const CreatedbStmt *stmt)
errmsg("must be superuser to create database for another user"))); errmsg("must be superuser to create database for another user")));
} }
/* don't call this in a transaction block */
PreventTransactionChain((void *) stmt, "CREATE DATABASE");
/* alternate location requires symlinks */
#ifndef HAVE_SYMLINK
if (dbpath != NULL)
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("cannot use an alternative location on this platform")));
#endif
/* /*
* Check for db name conflict. There is a race condition here, since * Check for db name conflict. There is a race condition here, since
* another backend could create the same DB name before we commit. * another backend could create the same DB name before we commit.
@ -227,8 +221,7 @@ createdb(const CreatedbStmt *stmt)
if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding, if (!get_db_info(dbtemplate, &src_dboid, &src_owner, &src_encoding,
&src_istemplate, &src_lastsysoid, &src_istemplate, &src_lastsysoid,
&src_vacuumxid, &src_frozenxid, &src_vacuumxid, &src_frozenxid, &src_deftablespace))
src_dbpath))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE), (errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("template database \"%s\" does not exist", dbtemplate))); errmsg("template database \"%s\" does not exist", dbtemplate)));
@ -246,14 +239,6 @@ createdb(const CreatedbStmt *stmt)
dbtemplate))); dbtemplate)));
} }
/*
* Determine physical path of source database
*/
alt_loc = resolve_alt_dbpath(src_dbpath, src_dboid);
if (!alt_loc)
alt_loc = GetDatabasePath(src_dboid);
strcpy(src_loc, alt_loc);
/* /*
* The source DB can't have any active backends, except this one * The source DB can't have any active backends, except this one
* (exception is to allow CREATE DB while connected to template1). * (exception is to allow CREATE DB while connected to template1).
@ -276,45 +261,39 @@ createdb(const CreatedbStmt *stmt)
(errcode(ERRCODE_WRONG_OBJECT_TYPE), (errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("invalid server encoding %d", encoding))); errmsg("invalid server encoding %d", encoding)));
/* Resolve default tablespace for new database */
if (dtablespacename && dtablespacename->arg)
{
char *tablespacename;
AclResult aclresult;
tablespacename = strVal(dtablespacename->arg);
dst_deftablespace = get_tablespace_oid(tablespacename);
if (!OidIsValid(dst_deftablespace))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace \"%s\" does not exist",
tablespacename)));
/* check permissions */
aclresult = pg_tablespace_aclcheck(dst_deftablespace, GetUserId(),
ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
tablespacename);
}
else
{
/* Use template database's default tablespace */
dst_deftablespace = src_deftablespace;
/* Note there is no additional permission check in this path */
}
/* /*
* Preassign OID for pg_database tuple, so that we can compute db * Preassign OID for pg_database tuple, so that we can compute db
* path. * path.
*/ */
dboid = newoid(); dboid = newoid();
/*
* Compute nominal location (where we will try to access the
* database), and resolve alternate physical location if one is
* specified.
*
* If an alternate location is specified but is the same as the normal
* path, just drop the alternate-location spec (this seems friendlier
* than erroring out). We must test this case to avoid creating a
* circular symlink below.
*/
nominal_loc = GetDatabasePath(dboid);
alt_loc = resolve_alt_dbpath(dbpath, dboid);
if (alt_loc && strcmp(alt_loc, nominal_loc) == 0)
{
alt_loc = NULL;
dbpath = NULL;
}
if (strchr(nominal_loc, '\''))
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
errmsg("database path may not contain single quotes")));
if (alt_loc && strchr(alt_loc, '\''))
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
errmsg("database path may not contain single quotes")));
if (strchr(src_loc, '\''))
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
errmsg("database path may not contain single quotes")));
/* ... otherwise we'd be open to shell exploits below */
/* /*
* Force dirty buffers out to disk, to ensure source database is * Force dirty buffers out to disk, to ensure source database is
* up-to-date for the copy. (We really only need to flush buffers for * up-to-date for the copy. (We really only need to flush buffers for
@ -324,74 +303,89 @@ createdb(const CreatedbStmt *stmt)
/* /*
* Close virtual file descriptors so the kernel has more available for * Close virtual file descriptors so the kernel has more available for
* the mkdir() and system() calls below. * the system() calls below.
*/ */
closeAllVfds(); closeAllVfds();
/* /*
* Check we can create the target directory --- but then remove it * Iterate through all tablespaces of the template database, and
* because we rely on cp(1) to create it for real. * copy each one to the new database.
*/
target_dir = alt_loc ? alt_loc : nominal_loc;
if (mkdir(target_dir, S_IRWXU) != 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create database directory \"%s\": %m",
target_dir)));
if (rmdir(target_dir) != 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not remove temporary directory \"%s\": %m",
target_dir)));
/* Make the symlink, if needed */
if (alt_loc)
{
#ifdef HAVE_SYMLINK /* already throws error above */
if (symlink(alt_loc, nominal_loc) != 0)
#endif
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not link file \"%s\" to \"%s\": %m",
nominal_loc, alt_loc)));
}
/*
* Copy the template database to the new location
* *
* XXX use of cp really makes this code pretty grotty, particularly * If we are trying to change the default tablespace of the template,
* with respect to lack of ability to report errors well. Someday * we require that the template not have any files in the new default
* rewrite to do it for ourselves. * tablespace. This avoids the need to merge two subdirectories.
* This could probably be improved later.
*/ */
#ifndef WIN32 rel = heap_openr(TableSpaceRelationName, AccessShareLock);
/* We might need to use cp -R one day for portability */ scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
snprintf(buf, sizeof(buf), "cp -r '%s' '%s'", src_loc, target_dir); while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
if (system(buf) != 0)
{ {
if (remove_dbdirs(nominal_loc, alt_loc)) Oid srctablespace = HeapTupleGetOid(tuple);
Oid dsttablespace;
char *srcpath;
char *dstpath;
struct stat st;
/* No need to copy global tablespace */
if (srctablespace == GLOBALTABLESPACE_OID)
continue;
srcpath = GetDatabasePath(src_dboid, srctablespace);
if (stat(srcpath, &st) < 0 || !S_ISDIR(st.st_mode))
{
/* Assume we can ignore it */
pfree(srcpath);
continue;
}
if (srctablespace == src_deftablespace)
dsttablespace = dst_deftablespace;
else
dsttablespace = srctablespace;
dstpath = GetDatabasePath(dboid, dsttablespace);
if (stat(dstpath, &st) == 0 || errno != ENOENT)
{
remove_dbtablespaces(dboid);
ereport(ERROR,
(errmsg("could not initialize database directory"),
errdetail("Directory \"%s\" already exists.", dstpath)));
}
#ifndef WIN32
/*
* Copy this subdirectory to the new location
*
* XXX use of cp really makes this code pretty grotty, particularly
* with respect to lack of ability to report errors well. Someday
* rewrite to do it for ourselves.
*/
/* We might need to use cp -R one day for portability */
snprintf(buf, sizeof(buf), "cp -r '%s' '%s'",
srcpath, dstpath);
if (system(buf) != 0)
{
remove_dbtablespaces(dboid);
ereport(ERROR, ereport(ERROR,
(errmsg("could not initialize database directory"), (errmsg("could not initialize database directory"),
errdetail("Failing system command was: %s", buf), errdetail("Failing system command was: %s", buf),
errhint("Look in the postmaster's stderr log for more information."))); errhint("Look in the postmaster's stderr log for more information.")));
else }
ereport(ERROR,
(errmsg("could not initialize database directory; delete failed as well"),
errdetail("Failing system command was: %s", buf),
errhint("Look in the postmaster's stderr log for more information.")));
}
#else /* WIN32 */ #else /* WIN32 */
if (copydir(src_loc, target_dir) != 0) if (copydir(srcpath, dstpath) != 0)
{ {
/* copydir should already have given details of its troubles */ /* copydir should already have given details of its troubles */
if (remove_dbdirs(nominal_loc, alt_loc)) remove_dbtablespaces(dboid);
ereport(ERROR, ereport(ERROR,
(errmsg("could not initialize database directory"))); (errmsg("could not initialize database directory")));
else }
ereport(ERROR,
(errmsg("could not initialize database directory; delete failed as well")));
}
#endif /* WIN32 */ #endif /* WIN32 */
}
heap_endscan(scan);
heap_close(rel, AccessShareLock);
/* /*
* Now OK to grab exclusive lock on pg_database. * Now OK to grab exclusive lock on pg_database.
@ -403,7 +397,7 @@ createdb(const CreatedbStmt *stmt)
{ {
/* Don't hold lock while doing recursive remove */ /* Don't hold lock while doing recursive remove */
heap_close(pg_database_rel, AccessExclusiveLock); heap_close(pg_database_rel, AccessExclusiveLock);
remove_dbdirs(nominal_loc, alt_loc); remove_dbtablespaces(dboid);
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_DATABASE), (errcode(ERRCODE_DUPLICATE_DATABASE),
errmsg("database \"%s\" already exists", dbname))); errmsg("database \"%s\" already exists", dbname)));
@ -427,9 +421,7 @@ createdb(const CreatedbStmt *stmt)
new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid); new_record[Anum_pg_database_datlastsysoid - 1] = ObjectIdGetDatum(src_lastsysoid);
new_record[Anum_pg_database_datvacuumxid - 1] = TransactionIdGetDatum(src_vacuumxid); new_record[Anum_pg_database_datvacuumxid - 1] = TransactionIdGetDatum(src_vacuumxid);
new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid); new_record[Anum_pg_database_datfrozenxid - 1] = TransactionIdGetDatum(src_frozenxid);
/* do not set datpath to null, GetRawDatabaseInfo won't cope */ new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
new_record[Anum_pg_database_datpath - 1] =
DirectFunctionCall1(textin, CStringGetDatum(dbpath ? dbpath : ""));
/* /*
* We deliberately set datconfig and datacl to defaults (NULL), rather * We deliberately set datconfig and datacl to defaults (NULL), rather
@ -471,14 +463,13 @@ dropdb(const char *dbname)
int4 db_owner; int4 db_owner;
bool db_istemplate; bool db_istemplate;
Oid db_id; Oid db_id;
char *alt_loc;
char *nominal_loc;
char dbpath[MAXPGPATH];
Relation pgdbrel; Relation pgdbrel;
SysScanDesc pgdbscan; SysScanDesc pgdbscan;
ScanKeyData key; ScanKeyData key;
HeapTuple tup; HeapTuple tup;
PreventTransactionChain((void *) dbname, "DROP DATABASE");
AssertArg(dbname); AssertArg(dbname);
if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0) if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0)
@ -486,8 +477,6 @@ dropdb(const char *dbname)
(errcode(ERRCODE_OBJECT_IN_USE), (errcode(ERRCODE_OBJECT_IN_USE),
errmsg("cannot drop the currently open database"))); errmsg("cannot drop the currently open database")));
PreventTransactionChain((void *) dbname, "DROP DATABASE");
/* /*
* Obtain exclusive lock on pg_database. We need this to ensure that * Obtain exclusive lock on pg_database. We need this to ensure that
* no new backend starts up in the target database while we are * no new backend starts up in the target database while we are
@ -500,7 +489,7 @@ dropdb(const char *dbname)
pgdbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock); pgdbrel = heap_openr(DatabaseRelationName, AccessExclusiveLock);
if (!get_db_info(dbname, &db_id, &db_owner, NULL, if (!get_db_info(dbname, &db_id, &db_owner, NULL,
&db_istemplate, NULL, NULL, NULL, dbpath)) &db_istemplate, NULL, NULL, NULL, NULL))
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE), (errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("database \"%s\" does not exist", dbname))); errmsg("database \"%s\" does not exist", dbname)));
@ -519,9 +508,6 @@ dropdb(const char *dbname)
(errcode(ERRCODE_WRONG_OBJECT_TYPE), (errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("cannot drop a template database"))); errmsg("cannot drop a template database")));
nominal_loc = GetDatabasePath(db_id);
alt_loc = resolve_alt_dbpath(dbpath, db_id);
/* /*
* Check for active backends in the target database. * Check for active backends in the target database.
*/ */
@ -585,9 +571,9 @@ dropdb(const char *dbname)
FreeSpaceMapForgetDatabase(db_id); FreeSpaceMapForgetDatabase(db_id);
/* /*
* Remove the database's subdirectory and everything in it. * Remove all tablespace subdirs belonging to the database.
*/ */
remove_dbdirs(nominal_loc, alt_loc); remove_dbtablespaces(db_id);
/* /*
* Force dirty buffers out to disk, so that newly-connecting backends * Force dirty buffers out to disk, so that newly-connecting backends
@ -831,7 +817,7 @@ static bool
get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP, get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP, int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP, TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
char *dbpath) Oid *dbTablespace)
{ {
Relation relation; Relation relation;
ScanKeyData scanKey; ScanKeyData scanKey;
@ -880,28 +866,9 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
/* limit of frozen XIDs */ /* limit of frozen XIDs */
if (dbFrozenXidP) if (dbFrozenXidP)
*dbFrozenXidP = dbform->datfrozenxid; *dbFrozenXidP = dbform->datfrozenxid;
/* database path (as registered in pg_database) */ /* default tablespace for this database */
if (dbpath) if (dbTablespace)
{ *dbTablespace = dbform->dattablespace;
Datum datum;
bool isnull;
datum = heap_getattr(tuple,
Anum_pg_database_datpath,
RelationGetDescr(relation),
&isnull);
if (!isnull)
{
text *pathtext = DatumGetTextP(datum);
int pathlen = VARSIZE(pathtext) - VARHDRSZ;
Assert(pathlen >= 0 && pathlen < MAXPGPATH);
strncpy(dbpath, VARDATA(pathtext), pathlen);
*(dbpath + pathlen) = '\0';
}
else
strcpy(dbpath, "");
}
} }
systable_endscan(scan); systable_endscan(scan);
@ -930,105 +897,60 @@ have_createdb_privilege(void)
return retval; return retval;
} }
/*
static char * * Remove tablespace directories
resolve_alt_dbpath(const char *dbpath, Oid dboid) *
* We don't know what tablespaces db_id is using, so iterate through all
* tablespaces removing <tablespace>/db_id
*/
static void
remove_dbtablespaces(Oid db_id)
{ {
const char *prefix; Relation rel;
char *ret; HeapScanDesc scan;
size_t len; HeapTuple tuple;
char buf[MAXPGPATH + 100];
if (dbpath == NULL || dbpath[0] == '\0') rel = heap_openr(TableSpaceRelationName, AccessShareLock);
return NULL; scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
if (first_dir_separator(dbpath))
{ {
if (!is_absolute_path(dbpath)) Oid dsttablespace = HeapTupleGetOid(tuple);
ereport(ERROR, char *dstpath;
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), struct stat st;
errmsg("relative paths are not allowed as database locations")));
#ifndef ALLOW_ABSOLUTE_DBPATHS
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("absolute paths are not allowed as database locations")));
#endif
prefix = dbpath;
}
else
{
/* must be environment variable */
char *var = getenv(dbpath);
if (!var) /* Don't mess with the global tablespace */
ereport(ERROR, if (dsttablespace == GLOBALTABLESPACE_OID)
(errcode(ERRCODE_UNDEFINED_OBJECT), continue;
errmsg("postmaster environment variable \"%s\" not found",
dbpath)));
if (!is_absolute_path(var))
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
errmsg("postmaster environment variable \"%s\" must be absolute path",
dbpath)));
prefix = var;
}
len = strlen(prefix) + 6 + sizeof(Oid) * 8 + 1; dstpath = GetDatabasePath(db_id, dsttablespace);
if (len >= MAXPGPATH - 100)
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
errmsg("alternative path is too long")));
ret = palloc(len); if (stat(dstpath, &st) < 0 || !S_ISDIR(st.st_mode))
snprintf(ret, len, "%s/base/%u", prefix, dboid);
return ret;
}
static bool
remove_dbdirs(const char *nominal_loc, const char *alt_loc)
{
const char *target_dir;
char buf[MAXPGPATH + 100];
bool success = true;
target_dir = alt_loc ? alt_loc : nominal_loc;
/*
* Close virtual file descriptors so the kernel has more available for
* the system() call below.
*/
closeAllVfds();
if (alt_loc)
{
/* remove symlink */
if (unlink(nominal_loc) != 0)
{ {
ereport(WARNING, /* Assume we can ignore it */
(errcode_for_file_access(), pfree(dstpath);
errmsg("could not remove file \"%s\": %m", nominal_loc))); continue;
success = false;
} }
}
#ifndef WIN32 #ifndef WIN32
snprintf(buf, sizeof(buf), "rm -rf '%s'", target_dir); snprintf(buf, sizeof(buf), "rm -rf '%s'", dstpath);
#else #else
snprintf(buf, sizeof(buf), "rmdir /s /q \"%s\"", target_dir); snprintf(buf, sizeof(buf), "rmdir /s /q \"%s\"", dstpath);
#endif #endif
if (system(buf) != 0)
if (system(buf) != 0) {
{ ereport(WARNING,
ereport(WARNING,
(errmsg("could not remove database directory \"%s\"", (errmsg("could not remove database directory \"%s\"",
target_dir), dstpath),
errdetail("Failing system command was: %s", buf), errdetail("Failing system command was: %s", buf),
errhint("Look in the postmaster's stderr log for more information."))); errhint("Look in the postmaster's stderr log for more information.")));
success = false; }
pfree(dstpath);
} }
return success; heap_endscan(scan);
heap_close(rel, AccessShareLock);
} }
@ -1075,7 +997,7 @@ get_database_oid(const char *dbname)
/* /*
* get_database_name - given a database OID, look up the name * get_database_name - given a database OID, look up the name
* *
* Returns InvalidOid if database name not found. * Returns a palloc'd string, or NULL if no such database.
* *
* This is not actually used in this file, but is exported for use elsewhere. * This is not actually used in this file, but is exported for use elsewhere.
*/ */

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.121 2004/06/10 17:55:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.122 2004/06/18 06:13:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -27,6 +27,7 @@
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/tablecmds.h" #include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
@ -64,6 +65,8 @@ static bool relationHasPrimaryKey(Relation rel);
* 'indexRelationName': the name for the new index, or NULL to indicate * 'indexRelationName': the name for the new index, or NULL to indicate
* that a nonconflicting default name should be picked. * that a nonconflicting default name should be picked.
* 'accessMethodName': name of the AM to use. * 'accessMethodName': name of the AM to use.
* 'tableSpaceName': name of the tablespace to create the index in.
* NULL specifies using the same tablespace as the parent relation.
* 'attributeList': a list of IndexElem specifying columns and expressions * 'attributeList': a list of IndexElem specifying columns and expressions
* to index on. * to index on.
* 'predicate': the partial-index condition, or NULL if none. * 'predicate': the partial-index condition, or NULL if none.
@ -83,6 +86,7 @@ void
DefineIndex(RangeVar *heapRelation, DefineIndex(RangeVar *heapRelation,
char *indexRelationName, char *indexRelationName,
char *accessMethodName, char *accessMethodName,
char *tableSpaceName,
List *attributeList, List *attributeList,
Expr *predicate, Expr *predicate,
List *rangetable, List *rangetable,
@ -98,6 +102,7 @@ DefineIndex(RangeVar *heapRelation,
Oid accessMethodId; Oid accessMethodId;
Oid relationId; Oid relationId;
Oid namespaceId; Oid namespaceId;
Oid tablespaceId;
Relation rel; Relation rel;
HeapTuple tuple; HeapTuple tuple;
Form_pg_am accessMethodForm; Form_pg_am accessMethodForm;
@ -151,6 +156,29 @@ DefineIndex(RangeVar *heapRelation,
get_namespace_name(namespaceId)); get_namespace_name(namespaceId));
} }
/* Determine tablespace to use */
if (tableSpaceName)
{
AclResult aclresult;
tablespaceId = get_tablespace_oid(tableSpaceName);
if (!OidIsValid(tablespaceId))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace \"%s\" does not exist",
tableSpaceName)));
/* check permissions */
aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
tableSpaceName);
} else {
/* Use the parent rel's tablespace */
tablespaceId = get_rel_tablespace(relationId);
/* Note there is no additional permission check in this path */
}
/* /*
* Select name for index if caller didn't specify * Select name for index if caller didn't specify
*/ */
@ -335,7 +363,7 @@ DefineIndex(RangeVar *heapRelation,
indexRelationName, RelationGetRelationName(rel)))); indexRelationName, RelationGetRelationName(rel))));
index_create(relationId, indexRelationName, index_create(relationId, indexRelationName,
indexInfo, accessMethodId, classObjectId, indexInfo, accessMethodId, tablespaceId, classObjectId,
primary, isconstraint, primary, isconstraint,
allowSystemTableMods, skip_build); allowSystemTableMods, skip_build);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.18 2004/05/26 04:41:11 neilc Exp $ * $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.19 2004/06/18 06:13:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -23,6 +23,7 @@
#include "catalog/pg_namespace.h" #include "catalog/pg_namespace.h"
#include "commands/dbcommands.h" #include "commands/dbcommands.h"
#include "commands/schemacmds.h" #include "commands/schemacmds.h"
#include "commands/tablespace.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "parser/analyze.h" #include "parser/analyze.h"
#include "tcop/utility.h" #include "tcop/utility.h"
@ -41,6 +42,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
const char *schemaName = stmt->schemaname; const char *schemaName = stmt->schemaname;
const char *authId = stmt->authid; const char *authId = stmt->authid;
Oid namespaceId; Oid namespaceId;
Oid tablespaceId;
List *parsetree_list; List *parsetree_list;
ListCell *parsetree_item; ListCell *parsetree_item;
const char *owner_name; const char *owner_name;
@ -100,8 +102,33 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
errmsg("unacceptable schema name \"%s\"", schemaName), errmsg("unacceptable schema name \"%s\"", schemaName),
errdetail("The prefix \"pg_\" is reserved for system schemas."))); errdetail("The prefix \"pg_\" is reserved for system schemas.")));
/*
* Select default tablespace for schema. If not given, use zero
* which implies the database's default tablespace.
*/
if (stmt->tablespacename)
{
AclResult aclresult;
tablespaceId = get_tablespace_oid(stmt->tablespacename);
if (!OidIsValid(tablespaceId))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace \"%s\" does not exist",
stmt->tablespacename)));
/* check permissions */
aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
stmt->tablespacename);
} else {
tablespaceId = InvalidOid;
/* note there is no permission check in this path */
}
/* Create the schema's namespace */ /* Create the schema's namespace */
namespaceId = NamespaceCreate(schemaName, owner_userid); namespaceId = NamespaceCreate(schemaName, owner_userid, tablespaceId);
/* Advance cmd counter to make the namespace visible */ /* Advance cmd counter to make the namespace visible */
CommandCounterIncrement(); CommandCounterIncrement();

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.111 2004/05/26 04:41:11 neilc Exp $ * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.112 2004/06/18 06:13:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -180,6 +180,7 @@ DefineSequence(CreateSeqStmt *seq)
stmt->constraints = NIL; stmt->constraints = NIL;
stmt->hasoids = MUST_NOT_HAVE_OIDS; stmt->hasoids = MUST_NOT_HAVE_OIDS;
stmt->oncommit = ONCOMMIT_NOOP; stmt->oncommit = ONCOMMIT_NOOP;
stmt->tablespacename = seq->tablespacename;
seqoid = DefineRelation(stmt, RELKIND_SEQUENCE); seqoid = DefineRelation(stmt, RELKIND_SEQUENCE);
@ -1071,8 +1072,8 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record)
buffer = XLogReadBuffer(true, reln, 0); buffer = XLogReadBuffer(true, reln, 0);
if (!BufferIsValid(buffer)) if (!BufferIsValid(buffer))
elog(PANIC, "seq_redo: can't read block of %u/%u", elog(PANIC, "seq_redo: can't read block 0 of rel %u/%u/%u",
xlrec->node.tblNode, xlrec->node.relNode); xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
page = (Page) BufferGetPage(buffer); page = (Page) BufferGetPage(buffer);
@ -1114,6 +1115,6 @@ seq_desc(char *buf, uint8 xl_info, char *rec)
return; return;
} }
sprintf(buf + strlen(buf), "node %u/%u", sprintf(buf + strlen(buf), "rel %u/%u/%u",
xlrec->node.tblNode, xlrec->node.relNode); xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.115 2004/06/10 18:34:45 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.116 2004/06/18 06:13:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -33,6 +33,7 @@
#include "commands/cluster.h" #include "commands/cluster.h"
#include "commands/defrem.h" #include "commands/defrem.h"
#include "commands/tablecmds.h" #include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
@ -258,6 +259,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
Oid namespaceId; Oid namespaceId;
List *schema = stmt->tableElts; List *schema = stmt->tableElts;
Oid relationId; Oid relationId;
Oid tablespaceId;
Relation rel; Relation rel;
TupleDesc descriptor; TupleDesc descriptor;
List *inheritOids; List *inheritOids;
@ -301,6 +303,31 @@ DefineRelation(CreateStmt *stmt, char relkind)
get_namespace_name(namespaceId)); get_namespace_name(namespaceId));
} }
/*
* Select tablespace to use. If not specified, use containing schema's
* default tablespace (which may in turn default to database's default).
*/
if (stmt->tablespacename)
{
AclResult aclresult;
tablespaceId = get_tablespace_oid(stmt->tablespacename);
if (!OidIsValid(tablespaceId))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace \"%s\" does not exist",
stmt->tablespacename)));
/* check permissions */
aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),
ACL_CREATE);
if (aclresult != ACLCHECK_OK)
aclcheck_error(aclresult, ACL_KIND_TABLESPACE,
stmt->tablespacename);
} else {
tablespaceId = get_namespace_tablespace(namespaceId);
/* note no permission check on tablespace in this case */
}
/* /*
* Look up inheritance ancestors and generate relation schema, * Look up inheritance ancestors and generate relation schema,
* including inherited attributes. * including inherited attributes.
@ -379,6 +406,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
relationId = heap_create_with_catalog(relname, relationId = heap_create_with_catalog(relname,
namespaceId, namespaceId,
tablespaceId,
descriptor, descriptor,
relkind, relkind,
false, false,
@ -1770,7 +1798,7 @@ ATController(Relation rel, List *cmds, bool recurse)
/* /*
* ATPrepCmd * ATPrepCmd
* *
* Traffic cop for ALTER TABLE Phase 1 operations, including simple * Traffic cop for ALTER TABLE Phase 1 operations, including simple
* recursion and permission checks. * recursion and permission checks.
* *
* Caller must have acquired AccessExclusiveLock on relation already. * Caller must have acquired AccessExclusiveLock on relation already.
@ -2679,7 +2707,7 @@ find_composite_type_dependencies(Oid typeOid, const char *origTblName)
} }
/* /*
* ALTER TABLE ADD COLUMN * ALTER TABLE ADD COLUMN
* *
* Adds an additional attribute to a relation making the assumption that * Adds an additional attribute to a relation making the assumption that
@ -3521,6 +3549,7 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
DefineIndex(stmt->relation, /* relation */ DefineIndex(stmt->relation, /* relation */
stmt->idxname, /* index name */ stmt->idxname, /* index name */
stmt->accessMethod, /* am name */ stmt->accessMethod, /* am name */
stmt->tableSpace,
stmt->indexParams, /* parameters */ stmt->indexParams, /* parameters */
(Expr *) stmt->whereClause, (Expr *) stmt->whereClause,
stmt->rangetable, stmt->rangetable,
@ -3566,7 +3595,7 @@ ATExecAddConstraint(AlteredTableInfo *tab, Relation rel, Node *newConstraint)
list_make1(constr)); list_make1(constr));
/* Add each constraint to Phase 3's queue */ /* Add each constraint to Phase 3's queue */
foreach(lcon, newcons) foreach(lcon, newcons)
{ {
CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon); CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
NewConstraint *newcon; NewConstraint *newcon;
@ -3643,7 +3672,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
int16 fkattnum[INDEX_MAX_KEYS]; int16 fkattnum[INDEX_MAX_KEYS];
Oid pktypoid[INDEX_MAX_KEYS]; Oid pktypoid[INDEX_MAX_KEYS];
Oid fktypoid[INDEX_MAX_KEYS]; Oid fktypoid[INDEX_MAX_KEYS];
Oid opclasses[INDEX_MAX_KEYS]; Oid opclasses[INDEX_MAX_KEYS];
int i; int i;
int numfks, int numfks,
numpks; numpks;
@ -3791,7 +3820,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
* will be incurred to check FK validity. * will be incurred to check FK validity.
*/ */
if (!op_in_opclass(oprid(o), opclasses[i])) if (!op_in_opclass(oprid(o), opclasses[i]))
ereport(WARNING, ereport(WARNING,
(errmsg("foreign key constraint \"%s\" " (errmsg("foreign key constraint \"%s\" "
"will require costly sequential scans", "will require costly sequential scans",
fkconstraint->constr_name), fkconstraint->constr_name),
@ -4565,7 +4594,7 @@ ATPrepAlterColumnType(List **wqueue,
/* /*
* Add a work queue item to make ATRewriteTable update the column * Add a work queue item to make ATRewriteTable update the column
* contents. * contents.
*/ */
newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue)); newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
newval->attnum = attnum; newval->attnum = attnum;
newval->expr = (Expr *) transform; newval->expr = (Expr *) transform;
@ -5272,6 +5301,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
*/ */
toast_relid = heap_create_with_catalog(toast_relname, toast_relid = heap_create_with_catalog(toast_relname,
PG_TOAST_NAMESPACE, PG_TOAST_NAMESPACE,
rel->rd_rel->reltablespace,
tupdesc, tupdesc,
RELKIND_TOASTVALUE, RELKIND_TOASTVALUE,
shared_relation, shared_relation,
@ -5309,7 +5339,9 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
classObjectId[1] = INT4_BTREE_OPS_OID; classObjectId[1] = INT4_BTREE_OPS_OID;
toast_idxid = index_create(toast_relid, toast_idxname, indexInfo, toast_idxid = index_create(toast_relid, toast_idxname, indexInfo,
BTREE_AM_OID, classObjectId, BTREE_AM_OID,
rel->rd_rel->reltablespace,
classObjectId,
true, false, true, false); true, false, true, false);
/* /*

View File

@ -0,0 +1,660 @@
/*-------------------------------------------------------------------------
*
* tablespace.c
* Commands to manipulate table spaces
*
*
* Tablespaces in PostgreSQL are designed to allow users to determine
* where the data file(s) for a given database object reside on the file
* system.
*
* A tablespace represents a directory on the file system. At tablespace
* creation time, the directory must be empty. To simplify things and
* remove the possibility of having file name conflicts, we isolate
* files within a tablespace into database-specific subdirectories.
*
* To support file access via the information given in RelFileNode, we
* maintain a symbolic-link map in $PGDATA/pg_tablespaces. The symlinks are
* named by tablespace OIDs and point to the actual tablespace directories.
* Thus the full path to an arbitrary file is
* $PGDATA/pg_tablespaces/spcoid/dboid/relfilenode
*
* There are two tablespaces created at initdb time: global (for shared
* tables) and default (for everything else). For backwards compatibility
* and to remain functional on platforms without symlinks, these tablespaces
* are accessed specially: they are respectively
* $PGDATA/global/relfilenode
* $PGDATA/base/dboid/relfilenode
*
* The implementation is designed to be backwards compatible. For this reason
* (and also as a feature unto itself) when a user creates an object without
* specifying a tablespace, we look at the object's parent and place
* the object in the parent's tablespace. The hierarchy is as follows:
* database > schema > table > index
*
* To allow CREATE DATABASE to give a new database a default tablespace
* that's different from the template database's default, we make the
* provision that a zero in pg_class.reltablespace means the database's
* default tablespace. Without this, CREATE DATABASE would have to go in
* and munge the system catalogs of the new database. This special meaning
* of zero also applies in pg_namespace.nsptablespace.
*
*
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.1 2004/06/18 06:13:23 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include <unistd.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "access/heapam.h"
#include "catalog/catalog.h"
#include "catalog/catname.h"
#include "catalog/indexing.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_tablespace.h"
#include "commands/tablespace.h"
#include "miscadmin.h"
#include "storage/fd.h"
#include "storage/smgr.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#include "utils/syscache.h"
static void set_short_version(const char *path);
static bool directory_is_empty(const char *path);
/*
* Each database using a table space is isolated into its own name space
* by a subdirectory named for the database OID. On first creation of an
* object in the tablespace, create the subdirectory. If the subdirectory
* already exists, just fall through quietly.
*
* If tablespaces are not supported, this is just a no-op; CREATE DATABASE
* is expected to create the default subdirectory for the database.
*/
void
TablespaceCreateDbspace(Oid spcNode, Oid dbNode)
{
#ifdef HAVE_SYMLINK
struct stat st;
char *dir;
/*
* The global tablespace doesn't have per-database subdirectories,
* so nothing to do for it.
*/
if (spcNode == GLOBALTABLESPACE_OID)
return;
Assert(OidIsValid(spcNode));
Assert(OidIsValid(dbNode));
dir = GetDatabasePath(dbNode, spcNode);
if (stat(dir, &st) < 0)
{
if (errno == ENOENT)
{
/*
* Acquire ExclusiveLock on pg_tablespace to ensure that no
* DROP TABLESPACE or TablespaceCreateDbspace is running
* concurrently. Simple reads from pg_tablespace are OK.
*/
Relation rel;
rel = heap_openr(TableSpaceRelationName, ExclusiveLock);
/*
* Recheck to see if someone created the directory while
* we were waiting for lock.
*/
if (stat(dir, &st) == 0 && S_ISDIR(st.st_mode))
{
/* need not do anything */
}
else
{
/* OK, go for it */
if (mkdir(dir, S_IRWXU) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create directory \"%s\": %m",
dir)));
}
/* OK to drop the exclusive lock */
heap_close(rel, ExclusiveLock);
}
else
{
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not stat directory \"%s\": %m", dir)));
}
}
else
{
/* be paranoid */
if (!S_ISDIR(st.st_mode))
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("\"%s\" exists but is not a directory",
dir)));
}
pfree(dir);
#endif /* HAVE_SYMLINK */
}
/*
* Create a table space
*
* Only superusers can create a tablespace. This seems a reasonable restriction
* since we're determining the system layout and, anyway, we probably have
* root if we're doing this kind of activity
*/
void
CreateTableSpace(CreateTableSpaceStmt *stmt)
{
#ifdef HAVE_SYMLINK
Relation rel;
Datum values[Natts_pg_tablespace];
char nulls[Natts_pg_tablespace];
HeapTuple tuple;
Oid tablespaceoid;
char *location;
char *linkloc;
AclId ownerid;
/* validate */
/* don't call this in a transaction block */
PreventTransactionChain((void *) stmt, "CREATE TABLESPACE");
/* Must be super user */
if (!superuser())
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("permission denied to create tablespace \"%s\"",
stmt->tablespacename),
errhint("Must be superuser to create a tablespace.")));
/* However, the eventual owner of the tablespace need not be */
if (stmt->owner)
{
/* No need to check result, get_usesysid() does that */
ownerid = get_usesysid(stmt->owner);
}
else
ownerid = GetUserId();
/* Unix-ify the offered path, and strip any trailing slashes */
location = pstrdup(stmt->location);
canonicalize_path(location);
/* disallow quotes, else CREATE DATABASE would be at risk */
if (strchr(location, '\''))
ereport(ERROR,
(errcode(ERRCODE_INVALID_NAME),
errmsg("tablespace location may not contain single quotes")));
/*
* Allowing relative paths seems risky
*
* this also helps us ensure that location is not empty or whitespace
*/
if (!is_absolute_path(location))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("tablespace location must be an absolute path")));
/*
* Check that location isn't too long. Remember that we're going to append
* '/<dboid>/<relid>.<nnn>' (XXX but do we ever form the whole path
* explicitly? This may be overly conservative.)
*/
if (strlen(location) >= (MAXPGPATH - 1 - 10 - 1 - 10 - 1 - 10))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("tablespace location \"%s\" is too long",
location)));
/*
* Check that there is no other tablespace by this name. (The
* unique index would catch this anyway, but might as well give
* a friendlier message.)
*/
if (OidIsValid(get_tablespace_oid(stmt->tablespacename)))
ereport(ERROR,
(errcode(ERRCODE_DUPLICATE_OBJECT),
errmsg("tablespace \"%s\" already exists",
stmt->tablespacename)));
/*
* Insert tuple into pg_tablespace. The purpose of doing this first
* is to lock the proposed tablename against other would-be creators.
* The insertion will roll back if we find problems below.
*/
rel = heap_openr(TableSpaceRelationName, RowExclusiveLock);
MemSet(nulls, ' ', Natts_pg_tablespace);
values[Anum_pg_tablespace_spcname - 1] =
DirectFunctionCall1(namein, CStringGetDatum(stmt->tablespacename));
values[Anum_pg_tablespace_spcowner - 1] =
Int32GetDatum(ownerid);
values[Anum_pg_tablespace_spclocation - 1] =
DirectFunctionCall1(textin, CStringGetDatum(location));
nulls[Anum_pg_tablespace_spcacl - 1] = 'n';
tuple = heap_formtuple(rel->rd_att, values, nulls);
tablespaceoid = newoid();
HeapTupleSetOid(tuple, tablespaceoid);
simple_heap_insert(rel, tuple);
CatalogUpdateIndexes(rel, tuple);
heap_freetuple(tuple);
/*
* Attempt to coerce target directory to safe permissions. If this
* fails, it doesn't exist or has the wrong owner.
*/
if (chmod(location, 0700) != 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not set permissions on directory \"%s\": %m",
location)));
/*
* Check the target directory is empty.
*/
if (!directory_is_empty(location))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("directory \"%s\" is not empty",
location)));
/*
* Create the PG_VERSION file in the target directory. This has several
* purposes: to make sure we can write in the directory, to prevent
* someone from creating another tablespace pointing at the same
* directory (the emptiness check above will fail), and to label
* tablespace directories by PG version.
*/
set_short_version(location);
/*
* All seems well, create the symlink
*/
linkloc = (char *) palloc(strlen(DataDir) + 16 + 10 + 1);
sprintf(linkloc, "%s/pg_tablespaces/%u", DataDir, tablespaceoid);
if (symlink(location, linkloc) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not create symbolic link \"%s\": %m",
linkloc)));
pfree(linkloc);
pfree(location);
heap_close(rel, RowExclusiveLock);
#else /* !HAVE_SYMLINK */
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("tablespaces are not supported on this platform")));
#endif /* HAVE_SYMLINK */
}
/*
* Drop a table space
*
* Be careful to check that the tablespace is empty.
*/
void
DropTableSpace(DropTableSpaceStmt *stmt)
{
#ifdef HAVE_SYMLINK
char *tablespacename = stmt->tablespacename;
HeapScanDesc scandesc;
Relation rel;
HeapTuple tuple;
ScanKeyData entry[1];
char *location;
Oid tablespaceoid;
DIR *dirdesc;
struct dirent *de;
char *subfile;
/* don't call this in a transaction block */
PreventTransactionChain((void *) stmt, "DROP TABLESPACE");
/*
* Acquire ExclusiveLock on pg_tablespace to ensure that no one else
* is trying to do DROP TABLESPACE or TablespaceCreateDbspace concurrently.
*/
rel = heap_openr(TableSpaceRelationName, ExclusiveLock);
/*
* Find the target tuple
*/
ScanKeyInit(&entry[0],
Anum_pg_tablespace_spcname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(tablespacename));
scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
tuple = heap_getnext(scandesc, ForwardScanDirection);
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("tablespace \"%s\" does not exist",
tablespacename)));
tablespaceoid = HeapTupleGetOid(tuple);
/* Must be superuser or owner */
if (GetUserId() != ((Form_pg_tablespace) GETSTRUCT(tuple))->spcowner &&
!superuser())
aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
tablespacename);
/* Disallow drop of the standard tablespaces, even by superuser */
if (tablespaceoid == GLOBALTABLESPACE_OID ||
tablespaceoid == DEFAULTTABLESPACE_OID)
aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
tablespacename);
location = (char *) palloc(strlen(DataDir) + 16 + 10 + 1);
sprintf(location, "%s/pg_tablespaces/%u", DataDir, tablespaceoid);
/*
* Check if the tablespace still contains any files. We try to rmdir
* each per-database directory we find in it. rmdir failure implies
* there are still files in that subdirectory, so give up. (We do not
* have to worry about undoing any already completed rmdirs, since
* the next attempt to use the tablespace from that database will simply
* recreate the subdirectory via TablespaceCreateDbspace.)
*
* Since we hold exclusive lock, no one else should be creating any
* fresh subdirectories in parallel. It is possible that new files
* are being created within subdirectories, though, so the rmdir
* call could fail. Worst consequence is a less friendly error message.
*/
dirdesc = AllocateDir(location);
if (dirdesc == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m",
location)));
errno = 0;
while ((de = readdir(dirdesc)) != NULL)
{
/* Note we ignore PG_VERSION for the nonce */
if (strcmp(de->d_name, ".") == 0 ||
strcmp(de->d_name, "..") == 0 ||
strcmp(de->d_name, "PG_VERSION") == 0)
{
errno = 0;
continue;
}
subfile = palloc(strlen(location) + 1 + strlen(de->d_name) + 1);
sprintf(subfile, "%s/%s", location, de->d_name);
/* This check is just to deliver a friendlier error message */
if (!directory_is_empty(subfile))
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("tablespace \"%s\" is not empty",
tablespacename)));
/* Do the real deed */
if (rmdir(subfile) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not delete directory \"%s\": %m",
subfile)));
pfree(subfile);
}
#ifdef WIN32
/* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
not in released version */
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read directory \"%s\": %m",
location)));
FreeDir(dirdesc);
/*
* Okay, try to unlink PG_VERSION and then remove the symlink.
*/
subfile = palloc(strlen(location) + 11 + 1);
sprintf(subfile, "%s/PG_VERSION", location);
if (unlink(subfile) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not unlink file \"%s\": %m",
subfile)));
if (unlink(location) < 0)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not unlink symbolic link \"%s\": %m",
location)));
pfree(subfile);
pfree(location);
/*
* We have successfully destroyed the infrastructure ... there is
* now no way to roll back the DROP ... so proceed to remove the
* pg_tablespace tuple.
*/
simple_heap_delete(rel, &tuple->t_self);
heap_endscan(scandesc);
heap_close(rel, ExclusiveLock);
#else /* !HAVE_SYMLINK */
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("tablespaces are not supported on this platform")));
#endif /* HAVE_SYMLINK */
}
/*
* write out the PG_VERSION file in the specified directory
*/
static void
set_short_version(const char *path)
{
char *short_version;
bool gotdot = false;
int end;
char *fullname;
FILE *version_file;
/* Construct short version string (should match initdb.c) */
short_version = pstrdup(PG_VERSION);
for (end = 0; short_version[end] != '\0'; end++)
{
if (short_version[end] == '.')
{
Assert(end != 0);
if (gotdot)
break;
else
gotdot = true;
}
else if (short_version[end] < '0' || short_version[end] > '9')
{
/* gone past digits and dots */
break;
}
}
Assert(end > 0 && short_version[end - 1] != '.' && gotdot);
short_version[end] = '\0';
/* Now write the file */
fullname = palloc(strlen(path) + 11 + 1);
sprintf(fullname, "%s/PG_VERSION", path);
version_file = AllocateFile(fullname, PG_BINARY_W);
if (version_file == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m",
fullname)));
fprintf(version_file, "%s\n", short_version);
if (FreeFile(version_file))
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not write to file \"%s\": %m",
fullname)));
pfree(fullname);
pfree(short_version);
}
/*
* Check if a directory is empty.
*/
static bool
directory_is_empty(const char *path)
{
DIR *dirdesc;
struct dirent *de;
dirdesc = AllocateDir(path);
if (dirdesc == NULL)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not open directory \"%s\": %m",
path)));
errno = 0;
while ((de = readdir(dirdesc)) != NULL)
{
if (strcmp(de->d_name, ".") == 0 ||
strcmp(de->d_name, "..") == 0)
{
errno = 0;
continue;
}
FreeDir(dirdesc);
return false;
}
#ifdef WIN32
/* This fix is in mingw cvs (runtime/mingwex/dirent.c rev 1.4), but
not in released version */
if (GetLastError() == ERROR_NO_MORE_FILES)
errno = 0;
#endif
if (errno)
ereport(ERROR,
(errcode_for_file_access(),
errmsg("could not read directory \"%s\": %m",
path)));
FreeDir(dirdesc);
return true;
}
/*
* get_tablespace_oid - given a tablespace name, look up the OID
*
* Returns InvalidOid if tablespace name not found.
*/
Oid
get_tablespace_oid(const char *tablespacename)
{
Oid result;
Relation rel;
HeapScanDesc scandesc;
HeapTuple tuple;
ScanKeyData entry[1];
/* Search pg_tablespace */
rel = heap_openr(TableSpaceRelationName, AccessShareLock);
ScanKeyInit(&entry[0],
Anum_pg_tablespace_spcname,
BTEqualStrategyNumber, F_NAMEEQ,
CStringGetDatum(tablespacename));
scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
tuple = heap_getnext(scandesc, ForwardScanDirection);
if (HeapTupleIsValid(tuple))
result = HeapTupleGetOid(tuple);
else
result = InvalidOid;
heap_endscan(scandesc);
heap_close(rel, AccessShareLock);
return result;
}
/*
* get_tablespace_name - given a tablespace OID, look up the name
*
* Returns a palloc'd string, or NULL if no such tablespace.
*/
char *
get_tablespace_name(Oid spc_oid)
{
char *result;
Relation rel;
HeapScanDesc scandesc;
HeapTuple tuple;
ScanKeyData entry[1];
/* Search pg_tablespace */
rel = heap_openr(TableSpaceRelationName, AccessShareLock);
ScanKeyInit(&entry[0],
ObjectIdAttributeNumber,
BTEqualStrategyNumber, F_OIDEQ,
ObjectIdGetDatum(spc_oid));
scandesc = heap_beginscan(rel, SnapshotNow, 1, entry);
tuple = heap_getnext(scandesc, ForwardScanDirection);
/* We assume that there can be at most one matching tuple */
if (HeapTupleIsValid(tuple))
result = pstrdup(NameStr(((Form_pg_tablespace) GETSTRUCT(tuple))->spcname));
else
result = NULL;
heap_endscan(scandesc);
heap_close(rel, AccessShareLock);
return result;
}

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.59 2004/06/10 17:55:56 tgl Exp $ * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.60 2004/06/18 06:13:23 tgl Exp $
* *
* DESCRIPTION * DESCRIPTION
* The "DefineFoo" routines take the parse tree and pick out the * The "DefineFoo" routines take the parse tree and pick out the
@ -1110,8 +1110,8 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist)
errmsg("composite type must have at least one attribute"))); errmsg("composite type must have at least one attribute")));
/* /*
* now create the parameters for keys/inheritance etc. All of them are * now set the parameters for keys/inheritance etc. All of these
* nil... * are uninteresting for composite types...
*/ */
createStmt->relation = (RangeVar *) typevar; createStmt->relation = (RangeVar *) typevar;
createStmt->tableElts = coldeflist; createStmt->tableElts = coldeflist;
@ -1119,6 +1119,7 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist)
createStmt->constraints = NIL; createStmt->constraints = NIL;
createStmt->hasoids = MUST_NOT_HAVE_OIDS; createStmt->hasoids = MUST_NOT_HAVE_OIDS;
createStmt->oncommit = ONCOMMIT_NOOP; createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
/* /*
* finally create the relation... * finally create the relation...

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.82 2004/05/26 04:41:13 neilc Exp $ * $PostgreSQL: pgsql/src/backend/commands/view.c,v 1.83 2004/06/18 06:13:23 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -134,8 +134,8 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
else else
{ {
/* /*
* now create the parameters for keys/inheritance etc. All of them * now set the parameters for keys/inheritance etc. All of these
* are nil... * are uninteresting for views...
*/ */
createStmt->relation = (RangeVar *) relation; createStmt->relation = (RangeVar *) relation;
createStmt->tableElts = attrList; createStmt->tableElts = attrList;
@ -143,6 +143,7 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
createStmt->constraints = NIL; createStmt->constraints = NIL;
createStmt->hasoids = MUST_NOT_HAVE_OIDS; createStmt->hasoids = MUST_NOT_HAVE_OIDS;
createStmt->oncommit = ONCOMMIT_NOOP; createStmt->oncommit = ONCOMMIT_NOOP;
createStmt->tablespacename = NULL;
/* /*
* finally create the relation (this will error out if there's an * finally create the relation (this will error out if there's an

View File

@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.233 2004/05/30 23:40:26 neilc Exp $ * $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.234 2004/06/18 06:13:26 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -779,6 +779,7 @@ InitPlan(QueryDesc *queryDesc, bool explainOnly)
intoRelationId = heap_create_with_catalog(intoName, intoRelationId = heap_create_with_catalog(intoName,
namespaceId, namespaceId,
InvalidOid,
tupdesc, tupdesc,
RELKIND_RELATION, RELKIND_RELATION,
false, false,

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.285 2004/06/09 19:08:15 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.286 2004/06/18 06:13:28 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1753,6 +1753,7 @@ _copyCreateStmt(CreateStmt *from)
COPY_NODE_FIELD(constraints); COPY_NODE_FIELD(constraints);
COPY_SCALAR_FIELD(hasoids); COPY_SCALAR_FIELD(hasoids);
COPY_SCALAR_FIELD(oncommit); COPY_SCALAR_FIELD(oncommit);
COPY_STRING_FIELD(tablespacename);
return newnode; return newnode;
} }
@ -1836,6 +1837,7 @@ _copyIndexStmt(IndexStmt *from)
COPY_STRING_FIELD(idxname); COPY_STRING_FIELD(idxname);
COPY_NODE_FIELD(relation); COPY_NODE_FIELD(relation);
COPY_STRING_FIELD(accessMethod); COPY_STRING_FIELD(accessMethod);
COPY_STRING_FIELD(tableSpace);
COPY_NODE_FIELD(indexParams); COPY_NODE_FIELD(indexParams);
COPY_NODE_FIELD(whereClause); COPY_NODE_FIELD(whereClause);
COPY_NODE_FIELD(rangetable); COPY_NODE_FIELD(rangetable);
@ -2146,6 +2148,7 @@ _copyCreateSeqStmt(CreateSeqStmt *from)
COPY_NODE_FIELD(sequence); COPY_NODE_FIELD(sequence);
COPY_NODE_FIELD(options); COPY_NODE_FIELD(options);
COPY_STRING_FIELD(tablespacename);
return newnode; return newnode;
} }
@ -2193,6 +2196,28 @@ _copyVariableResetStmt(VariableResetStmt *from)
return newnode; return newnode;
} }
static CreateTableSpaceStmt *
_copyCreateTableSpaceStmt(CreateTableSpaceStmt *from)
{
CreateTableSpaceStmt *newnode = makeNode(CreateTableSpaceStmt);
COPY_STRING_FIELD(tablespacename);
COPY_STRING_FIELD(owner);
COPY_STRING_FIELD(location);
return newnode;
}
static DropTableSpaceStmt *
_copyDropTableSpaceStmt(DropTableSpaceStmt *from)
{
DropTableSpaceStmt *newnode = makeNode(DropTableSpaceStmt);
COPY_STRING_FIELD(tablespacename);
return newnode;
}
static CreateTrigStmt * static CreateTrigStmt *
_copyCreateTrigStmt(CreateTrigStmt *from) _copyCreateTrigStmt(CreateTrigStmt *from)
{ {
@ -2371,6 +2396,7 @@ _copyCreateSchemaStmt(CreateSchemaStmt *from)
COPY_STRING_FIELD(schemaname); COPY_STRING_FIELD(schemaname);
COPY_STRING_FIELD(authid); COPY_STRING_FIELD(authid);
COPY_STRING_FIELD(tablespacename);
COPY_NODE_FIELD(schemaElts); COPY_NODE_FIELD(schemaElts);
return newnode; return newnode;
@ -2914,6 +2940,12 @@ copyObject(void *from)
case T_VariableResetStmt: case T_VariableResetStmt:
retval = _copyVariableResetStmt(from); retval = _copyVariableResetStmt(from);
break; break;
case T_CreateTableSpaceStmt:
retval = _copyCreateTableSpaceStmt(from);
break;
case T_DropTableSpaceStmt:
retval = _copyDropTableSpaceStmt(from);
break;
case T_CreateTrigStmt: case T_CreateTrigStmt:
retval = _copyCreateTrigStmt(from); retval = _copyCreateTrigStmt(from);
break; break;

View File

@ -18,7 +18,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.224 2004/06/09 19:08:15 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.225 2004/06/18 06:13:28 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -835,6 +835,7 @@ _equalCreateStmt(CreateStmt *a, CreateStmt *b)
COMPARE_NODE_FIELD(constraints); COMPARE_NODE_FIELD(constraints);
COMPARE_SCALAR_FIELD(hasoids); COMPARE_SCALAR_FIELD(hasoids);
COMPARE_SCALAR_FIELD(oncommit); COMPARE_SCALAR_FIELD(oncommit);
COMPARE_STRING_FIELD(tablespacename);
return true; return true;
} }
@ -904,6 +905,7 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b)
COMPARE_STRING_FIELD(idxname); COMPARE_STRING_FIELD(idxname);
COMPARE_NODE_FIELD(relation); COMPARE_NODE_FIELD(relation);
COMPARE_STRING_FIELD(accessMethod); COMPARE_STRING_FIELD(accessMethod);
COMPARE_STRING_FIELD(tableSpace);
COMPARE_NODE_FIELD(indexParams); COMPARE_NODE_FIELD(indexParams);
COMPARE_NODE_FIELD(whereClause); COMPARE_NODE_FIELD(whereClause);
COMPARE_NODE_FIELD(rangetable); COMPARE_NODE_FIELD(rangetable);
@ -1164,6 +1166,7 @@ _equalCreateSeqStmt(CreateSeqStmt *a, CreateSeqStmt *b)
{ {
COMPARE_NODE_FIELD(sequence); COMPARE_NODE_FIELD(sequence);
COMPARE_NODE_FIELD(options); COMPARE_NODE_FIELD(options);
COMPARE_STRING_FIELD(tablespacename);
return true; return true;
} }
@ -1203,6 +1206,24 @@ _equalVariableResetStmt(VariableResetStmt *a, VariableResetStmt *b)
return true; return true;
} }
static bool
_equalCreateTableSpaceStmt(CreateTableSpaceStmt *a, CreateTableSpaceStmt *b)
{
COMPARE_STRING_FIELD(tablespacename);
COMPARE_STRING_FIELD(owner);
COMPARE_STRING_FIELD(location);
return true;
}
static bool
_equalDropTableSpaceStmt(DropTableSpaceStmt *a, DropTableSpaceStmt *b)
{
COMPARE_STRING_FIELD(tablespacename);
return true;
}
static bool static bool
_equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b) _equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b)
{ {
@ -1352,6 +1373,7 @@ _equalCreateSchemaStmt(CreateSchemaStmt *a, CreateSchemaStmt *b)
{ {
COMPARE_STRING_FIELD(schemaname); COMPARE_STRING_FIELD(schemaname);
COMPARE_STRING_FIELD(authid); COMPARE_STRING_FIELD(authid);
COMPARE_STRING_FIELD(tablespacename);
COMPARE_NODE_FIELD(schemaElts); COMPARE_NODE_FIELD(schemaElts);
return true; return true;
@ -2052,6 +2074,12 @@ equal(void *a, void *b)
case T_VariableResetStmt: case T_VariableResetStmt:
retval = _equalVariableResetStmt(a, b); retval = _equalVariableResetStmt(a, b);
break; break;
case T_CreateTableSpaceStmt:
retval = _equalCreateTableSpaceStmt(a, b);
break;
case T_DropTableSpaceStmt:
retval = _equalDropTableSpaceStmt(a, b);
break;
case T_CreateTrigStmt: case T_CreateTrigStmt:
retval = _equalCreateTrigStmt(a, b); retval = _equalCreateTrigStmt(a, b);
break; break;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.239 2004/06/09 19:08:15 tgl Exp $ * $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.240 2004/06/18 06:13:28 tgl Exp $
* *
* NOTES * NOTES
* Every node type that can appear in stored rules' parsetrees *must* * Every node type that can appear in stored rules' parsetrees *must*
@ -1128,7 +1128,7 @@ _outInClauseInfo(StringInfo str, InClauseInfo *node)
static void static void
_outCreateStmt(StringInfo str, CreateStmt *node) _outCreateStmt(StringInfo str, CreateStmt *node)
{ {
WRITE_NODE_TYPE("CREATE"); WRITE_NODE_TYPE("CREATESTMT");
WRITE_NODE_FIELD(relation); WRITE_NODE_FIELD(relation);
WRITE_NODE_FIELD(tableElts); WRITE_NODE_FIELD(tableElts);
@ -1136,16 +1136,18 @@ _outCreateStmt(StringInfo str, CreateStmt *node)
WRITE_NODE_FIELD(constraints); WRITE_NODE_FIELD(constraints);
WRITE_ENUM_FIELD(hasoids, ContainsOids); WRITE_ENUM_FIELD(hasoids, ContainsOids);
WRITE_ENUM_FIELD(oncommit, OnCommitAction); WRITE_ENUM_FIELD(oncommit, OnCommitAction);
WRITE_STRING_FIELD(tablespacename);
} }
static void static void
_outIndexStmt(StringInfo str, IndexStmt *node) _outIndexStmt(StringInfo str, IndexStmt *node)
{ {
WRITE_NODE_TYPE("INDEX"); WRITE_NODE_TYPE("INDEXSTMT");
WRITE_STRING_FIELD(idxname); WRITE_STRING_FIELD(idxname);
WRITE_NODE_FIELD(relation); WRITE_NODE_FIELD(relation);
WRITE_STRING_FIELD(accessMethod); WRITE_STRING_FIELD(accessMethod);
WRITE_STRING_FIELD(tableSpace);
WRITE_NODE_FIELD(indexParams); WRITE_NODE_FIELD(indexParams);
WRITE_NODE_FIELD(whereClause); WRITE_NODE_FIELD(whereClause);
WRITE_NODE_FIELD(rangetable); WRITE_NODE_FIELD(rangetable);

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.305 2004/06/10 17:55:58 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.306 2004/06/18 06:13:31 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -874,6 +874,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
seqstmt = makeNode(CreateSeqStmt); seqstmt = makeNode(CreateSeqStmt);
seqstmt->sequence = makeRangeVar(snamespace, sname); seqstmt->sequence = makeRangeVar(snamespace, sname);
seqstmt->options = NIL; seqstmt->options = NIL;
seqstmt->tablespacename = NULL;
cxt->blist = lappend(cxt->blist, seqstmt); cxt->blist = lappend(cxt->blist, seqstmt);
@ -1199,6 +1200,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
index->relation = cxt->relation; index->relation = cxt->relation;
index->accessMethod = DEFAULT_INDEX_TYPE; index->accessMethod = DEFAULT_INDEX_TYPE;
index->tableSpace = NULL;
index->indexParams = NIL; index->indexParams = NIL;
index->whereClause = NULL; index->whereClause = NULL;

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.461 2004/06/09 19:08:17 tgl Exp $ * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.462 2004/06/18 06:13:31 tgl Exp $
* *
* HISTORY * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
@ -136,12 +136,12 @@ static void doNegateFloat(Value *v);
AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
CreateDomainStmt CreateGroupStmt CreateOpClassStmt CreatePLangStmt CreateDomainStmt CreateGroupStmt CreateOpClassStmt CreatePLangStmt
CreateSchemaStmt CreateSeqStmt CreateStmt CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
CreateAssertStmt CreateTrigStmt CreateUserStmt CreateAssertStmt CreateTrigStmt CreateUserStmt
CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt
DropGroupStmt DropOpClassStmt DropPLangStmt DropStmt DropGroupStmt DropOpClassStmt DropPLangStmt DropStmt
DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt
DropUserStmt DropdbStmt ExplainStmt FetchStmt DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt
GrantStmt IndexStmt InsertStmt ListenStmt LoadStmt GrantStmt IndexStmt InsertStmt ListenStmt LoadStmt
LockStmt NotifyStmt ExplainableStmt PreparableStmt LockStmt NotifyStmt ExplainableStmt PreparableStmt
CreateFunctionStmt ReindexStmt RemoveAggrStmt CreateFunctionStmt ReindexStmt RemoveAggrStmt
@ -324,6 +324,7 @@ static void doNegateFloat(Value *v);
%type <list> constraints_set_list %type <list> constraints_set_list
%type <boolean> constraints_set_mode %type <boolean> constraints_set_mode
%type <str> OptTableSpace OptTableSpaceOwner
/* /*
@ -384,7 +385,7 @@ static void doNegateFloat(Value *v);
ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNER ORDER OUT_P OUTER_P OVERLAPS OVERLAY OWNER
PARTIAL PASSWORD PATH_P PENDANT PLACING POSITION PARTIAL PASSWORD PATH_P PENDANT PLACING POSITION
PRECISION PRESERVE PREPARE PRIMARY PRECISION PRESERVE PREPARE PRIMARY
PRIOR PRIVILEGES PROCEDURAL PROCEDURE PRIOR PRIVILEGES PROCEDURAL PROCEDURE
QUOTE QUOTE
@ -398,7 +399,7 @@ static void doNegateFloat(Value *v);
SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT
STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SYSID STATISTICS STDIN STDOUT STORAGE STRICT_P SUBSTRING SYSID
TABLE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP TABLE TABLESPACE TEMP TEMPLATE TEMPORARY THEN TIME TIMESTAMP
TO TOAST TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P TO TOAST TRAILING TRANSACTION TREAT TRIGGER TRIM TRUE_P
TRUNCATE TRUSTED TYPE_P TRUNCATE TRUSTED TYPE_P
@ -513,6 +514,7 @@ stmt :
| CreateSchemaStmt | CreateSchemaStmt
| CreateSeqStmt | CreateSeqStmt
| CreateStmt | CreateStmt
| CreateTableSpaceStmt
| CreateTrigStmt | CreateTrigStmt
| CreateUserStmt | CreateUserStmt
| CreatedbStmt | CreatedbStmt
@ -527,6 +529,7 @@ stmt :
| DropPLangStmt | DropPLangStmt
| DropRuleStmt | DropRuleStmt
| DropStmt | DropStmt
| DropTableSpaceStmt
| DropTrigStmt | DropTrigStmt
| DropUserStmt | DropUserStmt
| DropdbStmt | DropdbStmt
@ -781,7 +784,7 @@ DropGroupStmt:
*****************************************************************************/ *****************************************************************************/
CreateSchemaStmt: CreateSchemaStmt:
CREATE SCHEMA OptSchemaName AUTHORIZATION UserId OptSchemaEltList CREATE SCHEMA OptSchemaName AUTHORIZATION UserId OptTableSpace OptSchemaEltList
{ {
CreateSchemaStmt *n = makeNode(CreateSchemaStmt); CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* One can omit the schema name or the authorization id. */ /* One can omit the schema name or the authorization id. */
@ -790,16 +793,18 @@ CreateSchemaStmt:
else else
n->schemaname = $5; n->schemaname = $5;
n->authid = $5; n->authid = $5;
n->schemaElts = $6; n->tablespacename = $6;
n->schemaElts = $7;
$$ = (Node *)n; $$ = (Node *)n;
} }
| CREATE SCHEMA ColId OptSchemaEltList | CREATE SCHEMA ColId OptTableSpace OptSchemaEltList
{ {
CreateSchemaStmt *n = makeNode(CreateSchemaStmt); CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
/* ...but not both */ /* ...but not both */
n->schemaname = $3; n->schemaname = $3;
n->authid = NULL; n->authid = NULL;
n->schemaElts = $4; n->tablespacename = $4;
n->schemaElts = $5;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
@ -1277,7 +1282,7 @@ alter_table_cmd:
n->name = $3; n->name = $3;
$$ = (Node *)n; $$ = (Node *)n;
} }
/* ALTER TABLE <name> SET WITHOUT CLUSTER */ /* ALTER TABLE <name> SET WITHOUT CLUSTER */
| SET WITHOUT CLUSTER | SET WITHOUT CLUSTER
{ {
AlterTableCmd *n = makeNode(AlterTableCmd); AlterTableCmd *n = makeNode(AlterTableCmd);
@ -1464,7 +1469,7 @@ opt_using:
*****************************************************************************/ *****************************************************************************/
CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')' CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
OptInherit OptWithOids OnCommitOption OptInherit OptWithOids OnCommitOption OptTableSpace
{ {
CreateStmt *n = makeNode(CreateStmt); CreateStmt *n = makeNode(CreateStmt);
$4->istemp = $2; $4->istemp = $2;
@ -1474,10 +1479,11 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
n->constraints = NIL; n->constraints = NIL;
n->hasoids = $9; n->hasoids = $9;
n->oncommit = $10; n->oncommit = $10;
n->tablespacename = $11;
$$ = (Node *)n; $$ = (Node *)n;
} }
| CREATE OptTemp TABLE qualified_name OF qualified_name | CREATE OptTemp TABLE qualified_name OF qualified_name
'(' OptTableElementList ')' OptWithOids OnCommitOption '(' OptTableElementList ')' OptWithOids OnCommitOption OptTableSpace
{ {
/* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied /* SQL99 CREATE TABLE OF <UDT> (cols) seems to be satisfied
* by our inheritance capabilities. Let's try it... * by our inheritance capabilities. Let's try it...
@ -1490,6 +1496,7 @@ CreateStmt: CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
n->constraints = NIL; n->constraints = NIL;
n->hasoids = $10; n->hasoids = $10;
n->oncommit = $11; n->oncommit = $11;
n->tablespacename = $12;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
@ -1901,6 +1908,10 @@ OnCommitOption: ON COMMIT DROP { $$ = ONCOMMIT_DROP; }
| /*EMPTY*/ { $$ = ONCOMMIT_NOOP; } | /*EMPTY*/ { $$ = ONCOMMIT_NOOP; }
; ;
OptTableSpace: TABLESPACE name { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
/* /*
* Note: CREATE TABLE ... AS SELECT ... is just another spelling for * Note: CREATE TABLE ... AS SELECT ... is just another spelling for
@ -1979,12 +1990,13 @@ CreateAsElement:
*****************************************************************************/ *****************************************************************************/
CreateSeqStmt: CreateSeqStmt:
CREATE OptTemp SEQUENCE qualified_name OptSeqList CREATE OptTemp SEQUENCE qualified_name OptSeqList OptTableSpace
{ {
CreateSeqStmt *n = makeNode(CreateSeqStmt); CreateSeqStmt *n = makeNode(CreateSeqStmt);
$4->istemp = $2; $4->istemp = $2;
n->sequence = $4; n->sequence = $4;
n->options = $5; n->options = $5;
n->tablespacename = $6;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
@ -2134,6 +2146,45 @@ opt_procedural:
| /*EMPTY*/ {} | /*EMPTY*/ {}
; ;
/*****************************************************************************
*
* QUERY:
* CREATE TABLESPACE tablespace LOCATION '/path/to/tablespace/'
*
*****************************************************************************/
CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
{
CreateTableSpaceStmt *n = makeNode(CreateTableSpaceStmt);
n->tablespacename = $3;
n->owner = $4;
n->location = $6;
$$ = (Node *) n;
}
;
OptTableSpaceOwner: OWNER name { $$ = $2; }
| /*EMPTY */ { $$ = NULL; }
;
/*****************************************************************************
*
* QUERY :
* DROP TABLESPACE <tablespace>
*
* No need for drop behaviour as we cannot implement dependencies for
* objects in other databases; we can only support RESTRICT.
*
****************************************************************************/
DropTableSpaceStmt: DROP TABLESPACE name
{
DropTableSpaceStmt *n = makeNode(DropTableSpaceStmt);
n->tablespacename = $3;
$$ = (Node *) n;
}
;
/***************************************************************************** /*****************************************************************************
* *
* QUERIES : * QUERIES :
@ -2735,7 +2786,7 @@ CommentStmt:
n->objargs = NIL; n->objargs = NIL;
n->comment = $7; n->comment = $7;
$$ = (Node *) n; $$ = (Node *) n;
} }
; ;
comment_type: comment_type:
@ -3026,6 +3077,13 @@ privilege_target:
n->objs = $2; n->objs = $2;
$$ = n; $$ = n;
} }
| TABLESPACE name_list
{
PrivTarget *n = makeNode(PrivTarget);
n->objtype = ACL_OBJECT_TABLESPACE;
n->objs = $2;
$$ = n;
}
; ;
@ -3092,12 +3150,14 @@ function_with_argtypes:
* QUERY: * QUERY:
* create index <indexname> on <relname> * create index <indexname> on <relname>
* [ using <access> ] "(" ( <col> [ using <opclass> ] )+ ")" * [ using <access> ] "(" ( <col> [ using <opclass> ] )+ ")"
* [ where <predicate> ] * [ tablespace <tablespacename> ] [ where <predicate> ]
* *
* Note: we cannot put TABLESPACE clause after WHERE clause unless we are
* willing to make TABLESPACE a fully reserved word.
*****************************************************************************/ *****************************************************************************/
IndexStmt: CREATE index_opt_unique INDEX index_name ON qualified_name IndexStmt: CREATE index_opt_unique INDEX index_name ON qualified_name
access_method_clause '(' index_params ')' where_clause access_method_clause '(' index_params ')' OptTableSpace where_clause
{ {
IndexStmt *n = makeNode(IndexStmt); IndexStmt *n = makeNode(IndexStmt);
n->unique = $2; n->unique = $2;
@ -3105,7 +3165,8 @@ IndexStmt: CREATE index_opt_unique INDEX index_name ON qualified_name
n->relation = $6; n->relation = $6;
n->accessMethod = $7; n->accessMethod = $7;
n->indexParams = $9; n->indexParams = $9;
n->whereClause = $11; n->tableSpace = $11;
n->whereClause = $12;
$$ = (Node *)n; $$ = (Node *)n;
} }
; ;
@ -3896,7 +3957,15 @@ createdb_opt_list:
; ;
createdb_opt_item: createdb_opt_item:
LOCATION opt_equal Sconst TABLESPACE opt_equal name
{
$$ = makeDefElem("tablespace", (Node *)makeString($3));
}
| TABLESPACE opt_equal DEFAULT
{
$$ = makeDefElem("tablespace", NULL);
}
| LOCATION opt_equal Sconst
{ {
$$ = makeDefElem("location", (Node *)makeString($3)); $$ = makeDefElem("location", (Node *)makeString($3));
} }
@ -6801,7 +6870,7 @@ subquery_Op:
{ $$ = list_make1(makeString("!~~*")); } { $$ = list_make1(makeString("!~~*")); }
/* cannot put SIMILAR TO here, because SIMILAR TO is a hack. /* cannot put SIMILAR TO here, because SIMILAR TO is a hack.
* the regular expression is preprocessed by a function (similar_escape), * the regular expression is preprocessed by a function (similar_escape),
* and the ~ operator for posix regular expressions is used. * and the ~ operator for posix regular expressions is used.
* x SIMILAR TO y -> x ~ similar_escape(y) * x SIMILAR TO y -> x ~ similar_escape(y)
* this transformation is made on the fly by the parser upwards. * this transformation is made on the fly by the parser upwards.
* however the SubLink structure which handles any/some/all stuff * however the SubLink structure which handles any/some/all stuff
@ -6978,7 +7047,7 @@ in_expr: select_with_parens
* COALESCE(a,b,...) * COALESCE(a,b,...)
* same as CASE WHEN a IS NOT NULL THEN a WHEN b IS NOT NULL THEN b ... END * same as CASE WHEN a IS NOT NULL THEN a WHEN b IS NOT NULL THEN b ... END
* - thomas 1998-11-09 * - thomas 1998-11-09
* *
* NULLIF and COALESCE have become first class nodes to * NULLIF and COALESCE have become first class nodes to
* prevent double evaluation of arguments. * prevent double evaluation of arguments.
* - Kris Jurka 2003-02-11 * - Kris Jurka 2003-02-11
@ -7565,6 +7634,7 @@ unreserved_keyword:
| STORAGE | STORAGE
| SYSID | SYSID
| STRICT_P | STRICT_P
| TABLESPACE
| TEMP | TEMP
| TEMPLATE | TEMPLATE
| TEMPORARY | TEMPORARY

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.149 2004/04/21 00:34:18 momjian Exp $ * $PostgreSQL: pgsql/src/backend/parser/keywords.c,v 1.150 2004/06/18 06:13:31 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -297,6 +297,7 @@ static const ScanKeyword ScanKeywords[] = {
{"substring", SUBSTRING}, {"substring", SUBSTRING},
{"sysid", SYSID}, {"sysid", SYSID},
{"table", TABLE}, {"table", TABLE},
{"tablespace", TABLESPACE},
{"temp", TEMP}, {"temp", TEMP},
{"template", TEMPLATE}, {"template", TEMPLATE},
{"temporary", TEMPORARY}, {"temporary", TEMPORARY},

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.170 2004/06/11 16:43:23 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/buffer/bufmgr.c,v 1.171 2004/06/18 06:13:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -654,7 +654,7 @@ BufferSync(int percent, int maxpages)
*/ */
dirty_buffers = (BufferDesc **) palloc(NBuffers * sizeof(BufferDesc *)); dirty_buffers = (BufferDesc **) palloc(NBuffers * sizeof(BufferDesc *));
buftags = (BufferTag *) palloc(NBuffers * sizeof(BufferTag)); buftags = (BufferTag *) palloc(NBuffers * sizeof(BufferTag));
LWLockAcquire(BufMgrLock, LW_EXCLUSIVE); LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
num_buffer_dirty = StrategyDirtyBufferList(dirty_buffers, buftags, num_buffer_dirty = StrategyDirtyBufferList(dirty_buffers, buftags,
NBuffers); NBuffers);
@ -832,9 +832,10 @@ AtEOXact_Buffers(bool isCommit)
if (isCommit) if (isCommit)
elog(WARNING, elog(WARNING,
"buffer refcount leak: [%03d] " "buffer refcount leak: [%03d] "
"(rel=%u/%u, blockNum=%u, flags=0x%x, refcount=%u %d)", "(rel=%u/%u/%u, blockNum=%u, flags=0x%x, refcount=%u %d)",
i, i,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode, buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
buf->tag.rnode.relNode,
buf->tag.blockNum, buf->flags, buf->tag.blockNum, buf->flags,
buf->refcount, PrivateRefCount[i]); buf->refcount, PrivateRefCount[i]);
@ -1137,9 +1138,10 @@ recheck:
{ {
/* the sole pin should be ours */ /* the sole pin should be ours */
if (bufHdr->refcount != 1 || PrivateRefCount[i - 1] == 0) if (bufHdr->refcount != 1 || PrivateRefCount[i - 1] == 0)
elog(FATAL, "block %u of %u/%u is still referenced (private %d, global %u)", elog(FATAL, "block %u of %u/%u/%u is still referenced (private %d, global %u)",
bufHdr->tag.blockNum, bufHdr->tag.blockNum,
bufHdr->tag.rnode.tblNode, bufHdr->tag.rnode.spcNode,
bufHdr->tag.rnode.dbNode,
bufHdr->tag.rnode.relNode, bufHdr->tag.rnode.relNode,
PrivateRefCount[i - 1], bufHdr->refcount); PrivateRefCount[i - 1], bufHdr->refcount);
/* Make sure it will be released */ /* Make sure it will be released */
@ -1180,13 +1182,7 @@ DropBuffers(Oid dbid)
{ {
bufHdr = &BufferDescriptors[i - 1]; bufHdr = &BufferDescriptors[i - 1];
recheck: recheck:
if (bufHdr->tag.rnode.dbNode == dbid)
/*
* We know that currently database OID is tblNode but this
* probably will be changed in future and this func will be used
* to drop tablespace buffers.
*/
if (bufHdr->tag.rnode.tblNode == dbid)
{ {
/* /*
* If there is I/O in progress, better wait till it's done; * If there is I/O in progress, better wait till it's done;
@ -1243,10 +1239,11 @@ PrintBufferDescs(void)
for (i = 0; i < NBuffers; ++i, ++buf) for (i = 0; i < NBuffers; ++i, ++buf)
{ {
elog(LOG, elog(LOG,
"[%02d] (freeNext=%d, freePrev=%d, rel=%u/%u, " "[%02d] (freeNext=%d, freePrev=%d, rel=%u/%u/%u, "
"blockNum=%u, flags=0x%x, refcount=%u %d)", "blockNum=%u, flags=0x%x, refcount=%u %d)",
i, buf->freeNext, buf->freePrev, i, buf->freeNext, buf->freePrev,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode, buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
buf->tag.rnode.relNode,
buf->tag.blockNum, buf->flags, buf->tag.blockNum, buf->flags,
buf->refcount, PrivateRefCount[i]); buf->refcount, PrivateRefCount[i]);
} }
@ -1257,9 +1254,9 @@ PrintBufferDescs(void)
/* interactive backend */ /* interactive backend */
for (i = 0; i < NBuffers; ++i, ++buf) for (i = 0; i < NBuffers; ++i, ++buf)
{ {
printf("[%-2d] (%u/%u, %u) flags=0x%x, refcount=%u %d)\n", printf("[%-2d] (%u/%u/%u, %u) flags=0x%x, refcount=%u %d)\n",
i, buf->tag.rnode.tblNode, buf->tag.rnode.relNode, i, buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
buf->tag.blockNum, buf->tag.rnode.relNode, buf->tag.blockNum,
buf->flags, buf->refcount, PrivateRefCount[i]); buf->flags, buf->refcount, PrivateRefCount[i]);
} }
} }
@ -1278,10 +1275,11 @@ PrintPinnedBufs(void)
{ {
if (PrivateRefCount[i] > 0) if (PrivateRefCount[i] > 0)
elog(WARNING, elog(WARNING,
"[%02d] (freeNext=%d, freePrev=%d, rel=%u/%u, " "[%02d] (freeNext=%d, freePrev=%d, rel=%u/%u/%u, "
"blockNum=%u, flags=0x%x, refcount=%u %d)", "blockNum=%u, flags=0x%x, refcount=%u %d)",
i, buf->freeNext, buf->freePrev, i, buf->freeNext, buf->freePrev,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode, buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
buf->tag.rnode.relNode,
buf->tag.blockNum, buf->flags, buf->tag.blockNum, buf->flags,
buf->refcount, PrivateRefCount[i]); buf->refcount, PrivateRefCount[i]);
} }
@ -1464,11 +1462,11 @@ IncrBufferRefCount_Debug(char *file, int line, Buffer buffer)
BufferDesc *buf = &BufferDescriptors[buffer - 1]; BufferDesc *buf = &BufferDescriptors[buffer - 1];
fprintf(stderr, fprintf(stderr,
"PIN(Incr) %d rel = %u/%u, blockNum = %u, " "PIN(Incr) %d rel = %u/%u/%u, blockNum = %u, "
"refcount = %d, file: %s, line: %d\n", "refcount = %d, file: %s, line: %d\n",
buffer, buffer,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode, buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
buf->tag.blockNum, buf->tag.rnode.relNode, buf->tag.blockNum,
PrivateRefCount[buffer - 1], file, line); PrivateRefCount[buffer - 1], file, line);
} }
} }
@ -1484,11 +1482,11 @@ ReleaseBuffer_Debug(char *file, int line, Buffer buffer)
BufferDesc *buf = &BufferDescriptors[buffer - 1]; BufferDesc *buf = &BufferDescriptors[buffer - 1];
fprintf(stderr, fprintf(stderr,
"UNPIN(Rel) %d rel = %u/%u, blockNum = %u, " "UNPIN(Rel) %d rel = %u/%u/%u, blockNum = %u, "
"refcount = %d, file: %s, line: %d\n", "refcount = %d, file: %s, line: %d\n",
buffer, buffer,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode, buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
buf->tag.blockNum, buf->tag.rnode.relNode, buf->tag.blockNum,
PrivateRefCount[buffer - 1], file, line); PrivateRefCount[buffer - 1], file, line);
} }
} }
@ -1513,11 +1511,11 @@ ReleaseAndReadBuffer_Debug(char *file,
BufferDesc *buf = &BufferDescriptors[buffer - 1]; BufferDesc *buf = &BufferDescriptors[buffer - 1];
fprintf(stderr, fprintf(stderr,
"UNPIN(Rel&Rd) %d rel = %u/%u, blockNum = %u, " "UNPIN(Rel&Rd) %d rel = %u/%u/%u, blockNum = %u, "
"refcount = %d, file: %s, line: %d\n", "refcount = %d, file: %s, line: %d\n",
buffer, buffer,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode, buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
buf->tag.blockNum, buf->tag.rnode.relNode, buf->tag.blockNum,
PrivateRefCount[buffer - 1], file, line); PrivateRefCount[buffer - 1], file, line);
} }
if (ShowPinTrace && BufferIsLocal(buffer) && is_userbuffer(buffer)) if (ShowPinTrace && BufferIsLocal(buffer) && is_userbuffer(buffer))
@ -1525,11 +1523,11 @@ ReleaseAndReadBuffer_Debug(char *file,
BufferDesc *buf = &BufferDescriptors[b - 1]; BufferDesc *buf = &BufferDescriptors[b - 1];
fprintf(stderr, fprintf(stderr,
"PIN(Rel&Rd) %d rel = %u/%u, blockNum = %u, " "PIN(Rel&Rd) %d rel = %u/%u/%u, blockNum = %u, "
"refcount = %d, file: %s, line: %d\n", "refcount = %d, file: %s, line: %d\n",
b, b,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode, buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
buf->tag.blockNum, buf->tag.rnode.relNode, buf->tag.blockNum,
PrivateRefCount[b - 1], file, line); PrivateRefCount[b - 1], file, line);
} }
return b; return b;
@ -1890,9 +1888,10 @@ AbortBufferIO(void)
{ {
ereport(WARNING, ereport(WARNING,
(errcode(ERRCODE_IO_ERROR), (errcode(ERRCODE_IO_ERROR),
errmsg("could not write block %u of %u/%u", errmsg("could not write block %u of %u/%u/%u",
buf->tag.blockNum, buf->tag.blockNum,
buf->tag.rnode.tblNode, buf->tag.rnode.spcNode,
buf->tag.rnode.dbNode,
buf->tag.rnode.relNode), buf->tag.rnode.relNode),
errdetail("Multiple failures --- write error may be permanent."))); errdetail("Multiple failures --- write error may be permanent.")));
} }
@ -1912,7 +1911,9 @@ buffer_write_error_callback(void *arg)
BufferDesc *bufHdr = (BufferDesc *) arg; BufferDesc *bufHdr = (BufferDesc *) arg;
if (bufHdr != NULL) if (bufHdr != NULL)
errcontext("writing block %u of relation %u/%u", errcontext("writing block %u of relation %u/%u/%u",
bufHdr->tag.blockNum, bufHdr->tag.blockNum,
bufHdr->tag.rnode.tblNode, bufHdr->tag.rnode.relNode); bufHdr->tag.rnode.spcNode,
bufHdr->tag.rnode.dbNode,
bufHdr->tag.rnode.relNode);
} }

View File

@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.55 2004/05/31 20:31:33 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/buffer/localbuf.c,v 1.56 2004/06/18 06:13:33 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -236,10 +236,10 @@ AtEOXact_LocalBuffers(bool isCommit)
if (isCommit) if (isCommit)
elog(WARNING, elog(WARNING,
"local buffer leak: [%03d] (rel=%u/%u, blockNum=%u, flags=0x%x, refcount=%u %d)", "local buffer leak: [%03d] (rel=%u/%u/%u, blockNum=%u, flags=0x%x, refcount=%u %d)",
i, i,
buf->tag.rnode.tblNode, buf->tag.rnode.relNode, buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
buf->tag.blockNum, buf->flags, buf->tag.rnode.relNode, buf->tag.blockNum, buf->flags,
buf->refcount, LocalRefCount[i]); buf->refcount, LocalRefCount[i]);
LocalRefCount[i] = 0; LocalRefCount[i] = 0;

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.31 2004/06/05 19:48:08 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/freespace/freespace.c,v 1.32 2004/06/18 06:13:34 tgl Exp $
* *
* *
* NOTES: * NOTES:
@ -658,9 +658,6 @@ FreeSpaceMapForgetRel(RelFileNode *rel)
* *
* This is called during DROP DATABASE. As above, might as well reclaim * This is called during DROP DATABASE. As above, might as well reclaim
* map space sooner instead of later. * map space sooner instead of later.
*
* XXX when we implement tablespaces, target Oid will need to be tablespace
* ID not database ID.
*/ */
void void
FreeSpaceMapForgetDatabase(Oid dbid) FreeSpaceMapForgetDatabase(Oid dbid)
@ -672,7 +669,7 @@ FreeSpaceMapForgetDatabase(Oid dbid)
for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = nextrel) for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = nextrel)
{ {
nextrel = fsmrel->nextUsage; /* in case we delete it */ nextrel = fsmrel->nextUsage; /* in case we delete it */
if (fsmrel->key.tblNode == dbid) if (fsmrel->key.dbNode == dbid)
delete_fsm_rel(fsmrel); delete_fsm_rel(fsmrel);
} }
LWLockRelease(FreeSpaceLock); LWLockRelease(FreeSpaceLock);
@ -1847,8 +1844,9 @@ DumpFreeSpace(void)
for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage) for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage)
{ {
relNum++; relNum++;
fprintf(stderr, "Map %d: rel %u/%u isIndex %d avgRequest %u lastPageCount %d nextPage %d\nMap= ", fprintf(stderr, "Map %d: rel %u/%u/%u isIndex %d avgRequest %u lastPageCount %d nextPage %d\nMap= ",
relNum, fsmrel->key.tblNode, fsmrel->key.relNode, relNum,
fsmrel->key.spcNode, fsmrel->key.dbNode, fsmrel->key.relNode,
(int) fsmrel->isIndex, fsmrel->avgRequest, (int) fsmrel->isIndex, fsmrel->avgRequest,
fsmrel->lastPageCount, fsmrel->nextPage); fsmrel->lastPageCount, fsmrel->nextPage);
if (fsmrel->isIndex) if (fsmrel->isIndex)

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/smgr/md.c,v 1.107 2004/06/02 17:28:18 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/smgr/md.c,v 1.108 2004/06/18 06:13:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -363,8 +363,9 @@ mdopen(SMgrRelation reln, bool allowNotFound)
return NULL; return NULL;
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open relation %u/%u: %m", errmsg("could not open relation %u/%u/%u: %m",
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode))); reln->smgr_rnode.relNode)));
} }
} }
@ -765,9 +766,10 @@ mdsync(void)
{ {
ereport(LOG, ereport(LOG,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not fsync segment %u of relation %u/%u: %m", errmsg("could not fsync segment %u of relation %u/%u/%u: %m",
entry->segno, entry->segno,
entry->rnode.tblNode, entry->rnode.spcNode,
entry->rnode.dbNode,
entry->rnode.relNode))); entry->rnode.relNode)));
return false; return false;
} }
@ -945,9 +947,10 @@ _mdfd_getseg(SMgrRelation reln, BlockNumber blkno, bool allowNotFound)
return NULL; return NULL;
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not open segment %u of relation %u/%u (target block %u): %m", errmsg("could not open segment %u of relation %u/%u/%u (target block %u): %m",
nextsegno, nextsegno,
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode, reln->smgr_rnode.relNode,
blkno))); blkno)));
} }

View File

@ -11,7 +11,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.73 2004/06/02 17:28:18 tgl Exp $ * $PostgreSQL: pgsql/src/backend/storage/smgr/smgr.c,v 1.74 2004/06/18 06:13:37 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -227,8 +227,9 @@ smgrclose(SMgrRelation reln)
if (! (*(smgrsw[reln->smgr_which].smgr_close)) (reln)) if (! (*(smgrsw[reln->smgr_which].smgr_close)) (reln))
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not close relation %u/%u: %m", errmsg("could not close relation %u/%u/%u: %m",
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode))); reln->smgr_rnode.relNode)));
if (hash_search(SMgrRelationHash, if (hash_search(SMgrRelationHash,
@ -308,8 +309,9 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
if (! (*(smgrsw[reln->smgr_which].smgr_create)) (reln, isRedo)) if (! (*(smgrsw[reln->smgr_which].smgr_create)) (reln, isRedo))
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not create relation %u/%u: %m", errmsg("could not create relation %u/%u/%u: %m",
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode))); reln->smgr_rnode.relNode)));
if (isRedo) if (isRedo)
@ -427,8 +429,9 @@ smgr_internal_unlink(RelFileNode rnode, int which, bool isTemp, bool isRedo)
if (! (*(smgrsw[which].smgr_unlink)) (rnode, isRedo)) if (! (*(smgrsw[which].smgr_unlink)) (rnode, isRedo))
ereport(WARNING, ereport(WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not unlink relation %u/%u: %m", errmsg("could not unlink relation %u/%u/%u: %m",
rnode.tblNode, rnode.spcNode,
rnode.dbNode,
rnode.relNode))); rnode.relNode)));
} }
@ -447,8 +450,9 @@ smgrextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
isTemp)) isTemp))
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not extend relation %u/%u: %m", errmsg("could not extend relation %u/%u/%u: %m",
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode), reln->smgr_rnode.relNode),
errhint("Check free disk space."))); errhint("Check free disk space.")));
} }
@ -467,9 +471,10 @@ smgrread(SMgrRelation reln, BlockNumber blocknum, char *buffer)
if (! (*(smgrsw[reln->smgr_which].smgr_read)) (reln, blocknum, buffer)) if (! (*(smgrsw[reln->smgr_which].smgr_read)) (reln, blocknum, buffer))
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not read block %u of relation %u/%u: %m", errmsg("could not read block %u of relation %u/%u/%u: %m",
blocknum, blocknum,
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode))); reln->smgr_rnode.relNode)));
} }
@ -491,9 +496,10 @@ smgrwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
isTemp)) isTemp))
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not write block %u of relation %u/%u: %m", errmsg("could not write block %u of relation %u/%u/%u: %m",
blocknum, blocknum,
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode))); reln->smgr_rnode.relNode)));
} }
@ -520,8 +526,9 @@ smgrnblocks(SMgrRelation reln)
if (nblocks == InvalidBlockNumber) if (nblocks == InvalidBlockNumber)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not count blocks of relation %u/%u: %m", errmsg("could not count blocks of relation %u/%u/%u: %m",
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode))); reln->smgr_rnode.relNode)));
return nblocks; return nblocks;
@ -552,8 +559,9 @@ smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
if (newblks == InvalidBlockNumber) if (newblks == InvalidBlockNumber)
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not truncate relation %u/%u to %u blocks: %m", errmsg("could not truncate relation %u/%u/%u to %u blocks: %m",
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode, reln->smgr_rnode.relNode,
nblocks))); nblocks)));
@ -607,8 +615,9 @@ smgrimmedsync(SMgrRelation reln)
if (! (*(smgrsw[reln->smgr_which].smgr_immedsync)) (reln)) if (! (*(smgrsw[reln->smgr_which].smgr_immedsync)) (reln))
ereport(ERROR, ereport(ERROR,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not sync relation %u/%u: %m", errmsg("could not sync relation %u/%u/%u: %m",
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode))); reln->smgr_rnode.relNode)));
} }
@ -775,8 +784,9 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
if (newblks == InvalidBlockNumber) if (newblks == InvalidBlockNumber)
ereport(WARNING, ereport(WARNING,
(errcode_for_file_access(), (errcode_for_file_access(),
errmsg("could not truncate relation %u/%u to %u blocks: %m", errmsg("could not truncate relation %u/%u/%u to %u blocks: %m",
reln->smgr_rnode.tblNode, reln->smgr_rnode.spcNode,
reln->smgr_rnode.dbNode,
reln->smgr_rnode.relNode, reln->smgr_rnode.relNode,
xlrec->blkno))); xlrec->blkno)));
} }
@ -800,16 +810,17 @@ smgr_desc(char *buf, uint8 xl_info, char *rec)
{ {
xl_smgr_create *xlrec = (xl_smgr_create *) rec; xl_smgr_create *xlrec = (xl_smgr_create *) rec;
sprintf(buf + strlen(buf), "file create: %u/%u", sprintf(buf + strlen(buf), "file create: %u/%u/%u",
xlrec->rnode.tblNode, xlrec->rnode.relNode); xlrec->rnode.spcNode, xlrec->rnode.dbNode,
xlrec->rnode.relNode);
} }
else if (info == XLOG_SMGR_TRUNCATE) else if (info == XLOG_SMGR_TRUNCATE)
{ {
xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec; xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
sprintf(buf + strlen(buf), "file truncate: %u/%u to %u blocks", sprintf(buf + strlen(buf), "file truncate: %u/%u/%u to %u blocks",
xlrec->rnode.tblNode, xlrec->rnode.relNode, xlrec->rnode.spcNode, xlrec->rnode.dbNode,
xlrec->blkno); xlrec->rnode.relNode, xlrec->blkno);
} }
else else
strcat(buf, "UNKNOWN"); strcat(buf, "UNKNOWN");

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.218 2004/05/29 22:48:20 tgl Exp $ * $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.219 2004/06/18 06:13:38 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -36,6 +36,7 @@
#include "commands/schemacmds.h" #include "commands/schemacmds.h"
#include "commands/sequence.h" #include "commands/sequence.h"
#include "commands/tablecmds.h" #include "commands/tablecmds.h"
#include "commands/tablespace.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "commands/typecmds.h" #include "commands/typecmds.h"
#include "commands/user.h" #include "commands/user.h"
@ -258,6 +259,7 @@ check_xact_readonly(Node *parsetree)
case T_CreateSchemaStmt: case T_CreateSchemaStmt:
case T_CreateSeqStmt: case T_CreateSeqStmt:
case T_CreateStmt: case T_CreateStmt:
case T_CreateTableSpaceStmt:
case T_CreateTrigStmt: case T_CreateTrigStmt:
case T_CompositeTypeStmt: case T_CompositeTypeStmt:
case T_CreateUserStmt: case T_CreateUserStmt:
@ -266,6 +268,7 @@ check_xact_readonly(Node *parsetree)
case T_DropCastStmt: case T_DropCastStmt:
case T_DropStmt: case T_DropStmt:
case T_DropdbStmt: case T_DropdbStmt:
case T_DropTableSpaceStmt:
case T_RemoveFuncStmt: case T_RemoveFuncStmt:
case T_DropGroupStmt: case T_DropGroupStmt:
case T_DropPLangStmt: case T_DropPLangStmt:
@ -404,6 +407,14 @@ ProcessUtility(Node *parsetree,
} }
break; break;
case T_CreateTableSpaceStmt:
CreateTableSpace((CreateTableSpaceStmt *) parsetree);
break;
case T_DropTableSpaceStmt:
DropTableSpace((DropTableSpaceStmt *) parsetree);
break;
case T_DropStmt: case T_DropStmt:
{ {
DropStmt *stmt = (DropStmt *) parsetree; DropStmt *stmt = (DropStmt *) parsetree;
@ -636,6 +647,7 @@ ProcessUtility(Node *parsetree,
DefineIndex(stmt->relation, /* relation */ DefineIndex(stmt->relation, /* relation */
stmt->idxname, /* index name */ stmt->idxname, /* index name */
stmt->accessMethod, /* am name */ stmt->accessMethod, /* am name */
stmt->tableSpace,
stmt->indexParams, /* parameters */ stmt->indexParams, /* parameters */
(Expr *) stmt->whereClause, (Expr *) stmt->whereClause,
stmt->rangetable, stmt->rangetable,
@ -1153,6 +1165,14 @@ CreateCommandTag(Node *parsetree)
tag = "CREATE TABLE"; tag = "CREATE TABLE";
break; break;
case T_CreateTableSpaceStmt:
tag = "CREATE TABLESPACE";
break;
case T_DropTableSpaceStmt:
tag = "DROP TABLESPACE";
break;
case T_DropStmt: case T_DropStmt:
switch (((DropStmt *) parsetree)->removeType) switch (((DropStmt *) parsetree)->removeType)
{ {
@ -1224,6 +1244,9 @@ CreateCommandTag(Node *parsetree)
case OBJECT_SCHEMA: case OBJECT_SCHEMA:
tag = "ALTER SCHEMA"; tag = "ALTER SCHEMA";
break; break;
case OBJECT_TABLESPACE:
tag = "ALTER TABLESPACE";
break;
case OBJECT_TRIGGER: case OBJECT_TRIGGER:
tag = "ALTER TRIGGER"; tag = "ALTER TRIGGER";
break; break;

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.105 2004/06/01 21:49:22 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.106 2004/06/18 06:13:49 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -539,6 +539,10 @@ acldefault(GrantObjectType objtype, AclId ownerid)
world_default = ACL_NO_RIGHTS; world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_NAMESPACE; owner_default = ACL_ALL_RIGHTS_NAMESPACE;
break; break;
case ACL_OBJECT_TABLESPACE:
world_default = ACL_NO_RIGHTS;
owner_default = ACL_ALL_RIGHTS_TABLESPACE;
break;
default: default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype); elog(ERROR, "unrecognized objtype: %d", (int) objtype);
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */ world_default = ACL_NO_RIGHTS; /* keep compiler quiet */

View File

@ -3,7 +3,7 @@
* back to source text * back to source text
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.172 2004/06/16 01:26:47 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.173 2004/06/18 06:13:49 tgl Exp $
* *
* This software is copyrighted by Jan Wieck - Hamburg. * This software is copyrighted by Jan Wieck - Hamburg.
* *
@ -53,6 +53,7 @@
#include "catalog/pg_operator.h" #include "catalog/pg_operator.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "catalog/pg_trigger.h" #include "catalog/pg_trigger.h"
#include "commands/tablespace.h"
#include "executor/spi.h" #include "executor/spi.h"
#include "lib/stringinfo.h" #include "lib/stringinfo.h"
#include "nodes/makefuncs.h" #include "nodes/makefuncs.h"
@ -767,6 +768,23 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
{ {
appendStringInfoChar(&buf, ')'); appendStringInfoChar(&buf, ')');
/*
* If the index is in a different tablespace from its parent,
* tell about that
*/
if (OidIsValid(idxrelrec->reltablespace) &&
idxrelrec->reltablespace != get_rel_tablespace(indrelid))
{
char *spcname = get_tablespace_name(idxrelrec->reltablespace);
if (spcname) /* just paranoia... */
{
appendStringInfo(&buf, " TABLESPACE %s",
quote_identifier(spcname));
pfree(spcname);
}
}
/* /*
* If it's a partial index, decompile and append the predicate * If it's a partial index, decompile and append the predicate
*/ */

View File

@ -74,7 +74,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.61 2004/05/06 16:10:57 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/cache/inval.c,v 1.62 2004/06/18 06:13:52 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -308,7 +308,7 @@ AddRelcacheInvalidationMessage(InvalidationListHeader *hdr,
/* We assume dbId need not be checked because it will never change */ /* We assume dbId need not be checked because it will never change */
/* relfilenode fields must be checked to support reassignment */ /* relfilenode fields must be checked to support reassignment */
ProcessMessageList(hdr->rclist, ProcessMessageList(hdr->rclist,
if (msg->rc.relId == relId && if (msg->rc.relId == relId &&
RelFileNodeEquals(msg->rc.physId, physId)) return); RelFileNodeEquals(msg->rc.physId, physId)) return);
/* OK, add the item */ /* OK, add the item */
@ -555,14 +555,18 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
databaseId = InvalidOid; databaseId = InvalidOid;
else else
databaseId = MyDatabaseId; databaseId = MyDatabaseId;
rnode.tblNode = databaseId; /* XXX change for tablespaces */ if (classtup->reltablespace)
rnode.spcNode = classtup->reltablespace;
else
rnode.spcNode = MyDatabaseTableSpace;
rnode.dbNode = databaseId;
rnode.relNode = classtup->relfilenode; rnode.relNode = classtup->relfilenode;
/* /*
* Note: during a pg_class row update that assigns a new relfilenode * Note: during a pg_class row update that assigns a new relfilenode
* value, we will be called on both the old and new tuples, and thus * or reltablespace value, we will be called on both the old and new
* will broadcast invalidation messages showing both the old and new * tuples, and thus will broadcast invalidation messages showing both
* relfilenode values. This ensures that other backends will close * the old and new RelFileNode values. This ensures that other
* smgr references to the old relfilenode file. * backends will close smgr references to the old file.
*/ */
} }
else if (tupleRelId == RelOid_pg_attribute) else if (tupleRelId == RelOid_pg_attribute)
@ -580,7 +584,8 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
*/ */
databaseId = MyDatabaseId; databaseId = MyDatabaseId;
/* We assume no smgr cache flush is needed, either */ /* We assume no smgr cache flush is needed, either */
rnode.tblNode = InvalidOid; rnode.spcNode = InvalidOid;
rnode.dbNode = InvalidOid;
rnode.relNode = InvalidOid; rnode.relNode = InvalidOid;
} }
else else
@ -760,7 +765,11 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
databaseId = InvalidOid; databaseId = InvalidOid;
else else
databaseId = MyDatabaseId; databaseId = MyDatabaseId;
rnode.tblNode = databaseId; /* XXX change for tablespaces */ if (classtup->reltablespace)
rnode.spcNode = classtup->reltablespace;
else
rnode.spcNode = MyDatabaseTableSpace;
rnode.dbNode = databaseId;
rnode.relNode = classtup->relfilenode; rnode.relNode = classtup->relfilenode;
RegisterRelcacheInvalidation(databaseId, relationId, rnode); RegisterRelcacheInvalidation(databaseId, relationId, rnode);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.113 2004/06/06 00:41:27 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/cache/lsyscache.c,v 1.114 2004/06/18 06:13:52 tgl Exp $
* *
* NOTES * NOTES
* Eventually, the index information should go through here, too. * Eventually, the index information should go through here, too.
@ -985,6 +985,34 @@ get_rel_namespace(Oid relid)
return InvalidOid; return InvalidOid;
} }
/*
* get_rel_tablespace
* Returns the pg_tablespace OID associated with a given relation.
*
* Note: failure return is InvalidOid, which cannot be distinguished from
* "default tablespace for this database", but that seems OK.
*/
Oid
get_rel_tablespace(Oid relid)
{
HeapTuple tp;
tp = SearchSysCache(RELOID,
ObjectIdGetDatum(relid),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_class reltup = (Form_pg_class) GETSTRUCT(tp);
Oid result;
result = reltup->reltablespace;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/* /*
* get_rel_type_id * get_rel_type_id
* *
@ -1980,6 +2008,34 @@ get_namespace_name(Oid nspid)
return NULL; return NULL;
} }
/*
* get_namespace_tablespace
* Returns the default tablespace of a given namespace
*
* Note: failure return is InvalidOid, which cannot be distinguished from
* "default tablespace for this database", but that seems OK.
*/
Oid
get_namespace_tablespace(Oid nspid)
{
HeapTuple tp;
tp = SearchSysCache(NAMESPACEOID,
ObjectIdGetDatum(nspid),
0, 0, 0);
if (HeapTupleIsValid(tp))
{
Form_pg_namespace nsptup = (Form_pg_namespace) GETSTRUCT(tp);
Oid result;
result = nsptup->nsptablespace;
ReleaseSysCache(tp);
return result;
}
else
return InvalidOid;
}
/* ---------- PG_SHADOW CACHE ---------- */ /* ---------- PG_SHADOW CACHE ---------- */
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.204 2004/05/30 23:40:37 neilc Exp $ * $PostgreSQL: pgsql/src/backend/utils/cache/relcache.c,v 1.205 2004/06/18 06:13:52 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -260,6 +260,7 @@ static void RelationBuildTupleDesc(RelationBuildDescInfo buildinfo,
Relation relation); Relation relation);
static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo, static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,
Relation oldrelation); Relation oldrelation);
static void RelationInitPhysicalAddr(Relation relation);
static void AttrDefaultFetch(Relation relation); static void AttrDefaultFetch(Relation relation);
static void CheckConstraintFetch(Relation relation); static void CheckConstraintFetch(Relation relation);
static List *insert_ordered_oid(List *list, Oid datum); static List *insert_ordered_oid(List *list, Oid datum);
@ -873,11 +874,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
*/ */
RelationInitLockInfo(relation); /* see lmgr.c */ RelationInitLockInfo(relation); /* see lmgr.c */
if (relation->rd_rel->relisshared) /*
relation->rd_node.tblNode = InvalidOid; * initialize physical addressing information for the relation
else */
relation->rd_node.tblNode = MyDatabaseId; RelationInitPhysicalAddr(relation);
relation->rd_node.relNode = relation->rd_rel->relfilenode;
/* make sure relation is marked as having no open file yet */ /* make sure relation is marked as having no open file yet */
relation->rd_smgr = NULL; relation->rd_smgr = NULL;
@ -892,6 +892,23 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
return relation; return relation;
} }
/*
* Initialize the physical addressing info (RelFileNode) for a relcache entry
*/
static void
RelationInitPhysicalAddr(Relation relation)
{
if (relation->rd_rel->reltablespace)
relation->rd_node.spcNode = relation->rd_rel->reltablespace;
else
relation->rd_node.spcNode = MyDatabaseTableSpace;
if (relation->rd_rel->relisshared)
relation->rd_node.dbNode = InvalidOid;
else
relation->rd_node.dbNode = MyDatabaseId;
relation->rd_node.relNode = relation->rd_rel->relfilenode;
}
/* /*
* Initialize index-access-method support data for an index relation * Initialize index-access-method support data for an index relation
*/ */
@ -1343,18 +1360,17 @@ formrdesc(const char *relationName,
* initialize relation id from info in att array (my, this is ugly) * initialize relation id from info in att array (my, this is ugly)
*/ */
RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid; RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid;
relation->rd_rel->relfilenode = RelationGetRelid(relation);
/* /*
* initialize the relation's lock manager and RelFileNode information * initialize the relation lock manager information
*/ */
RelationInitLockInfo(relation); /* see lmgr.c */ RelationInitLockInfo(relation); /* see lmgr.c */
if (relation->rd_rel->relisshared) /*
relation->rd_node.tblNode = InvalidOid; * initialize physical addressing information for the relation
else */
relation->rd_node.tblNode = MyDatabaseId; RelationInitPhysicalAddr(relation);
relation->rd_node.relNode =
relation->rd_rel->relfilenode = RelationGetRelid(relation);
/* /*
* initialize the rel-has-index flag, using hardwired knowledge * initialize the rel-has-index flag, using hardwired knowledge
@ -1570,7 +1586,8 @@ RelationReloadClassinfo(Relation relation)
relation->rd_id); relation->rd_id);
relp = (Form_pg_class) GETSTRUCT(pg_class_tuple); relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE); memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
relation->rd_node.relNode = relp->relfilenode; /* Now we can recalculate physical address */
RelationInitPhysicalAddr(relation);
heap_freetuple(pg_class_tuple); heap_freetuple(pg_class_tuple);
relation->rd_targblock = InvalidBlockNumber; relation->rd_targblock = InvalidBlockNumber;
/* Okay, now it's valid again */ /* Okay, now it's valid again */
@ -2040,8 +2057,9 @@ Relation
RelationBuildLocalRelation(const char *relname, RelationBuildLocalRelation(const char *relname,
Oid relnamespace, Oid relnamespace,
TupleDesc tupDesc, TupleDesc tupDesc,
Oid relid, Oid dbid, Oid relid,
RelFileNode rnode, Oid reltablespace,
bool shared_relation,
bool nailit) bool nailit)
{ {
Relation rel; Relation rel;
@ -2125,20 +2143,23 @@ RelationBuildLocalRelation(const char *relname,
/* /*
* Insert relation physical and logical identifiers (OIDs) into the * Insert relation physical and logical identifiers (OIDs) into the
* right places. * right places. Note that the physical ID (relfilenode) is initially
* the same as the logical ID (OID).
*/ */
rel->rd_rel->relisshared = (dbid == InvalidOid); rel->rd_rel->relisshared = shared_relation;
RelationGetRelid(rel) = relid; RelationGetRelid(rel) = relid;
for (i = 0; i < natts; i++) for (i = 0; i < natts; i++)
rel->rd_att->attrs[i]->attrelid = relid; rel->rd_att->attrs[i]->attrelid = relid;
rel->rd_node = rnode; rel->rd_rel->relfilenode = relid;
rel->rd_rel->relfilenode = rnode.relNode; rel->rd_rel->reltablespace = reltablespace;
RelationInitLockInfo(rel); /* see lmgr.c */ RelationInitLockInfo(rel); /* see lmgr.c */
RelationInitPhysicalAddr(rel);
/* /*
* Okay to insert into the relcache hash tables. * Okay to insert into the relcache hash tables.
*/ */
@ -3053,16 +3074,12 @@ load_relcache_init_file(void)
MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info)); MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info));
/* /*
* Make sure database ID is correct. This is needed in case the * Recompute lock and physical addressing info. This is needed in
* pg_internal.init file was copied from some other database by * case the pg_internal.init file was copied from some other database
* CREATE DATABASE. * by CREATE DATABASE.
*/ */
if (rel->rd_rel->relisshared)
rel->rd_node.tblNode = InvalidOid;
else
rel->rd_node.tblNode = MyDatabaseId;
RelationInitLockInfo(rel); RelationInitLockInfo(rel);
RelationInitPhysicalAddr(rel);
} }
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/globals.c,v 1.90 2004/05/30 17:58:12 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/init/globals.c,v 1.91 2004/06/18 06:13:54 tgl Exp $
* *
* NOTES * NOTES
* Globals used all over the place should be declared here and not * Globals used all over the place should be declared here and not
@ -58,6 +58,8 @@ BackendId MyBackendId = InvalidBackendId;
char *DatabasePath = NULL; char *DatabasePath = NULL;
Oid MyDatabaseId = InvalidOid; Oid MyDatabaseId = InvalidOid;
Oid MyDatabaseTableSpace = InvalidOid;
pid_t PostmasterPid = 0; pid_t PostmasterPid = 0;
/* /*

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.126 2004/05/30 23:40:38 neilc Exp $ * $PostgreSQL: pgsql/src/backend/utils/init/miscinit.c,v 1.127 2004/06/18 06:13:54 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -157,7 +157,6 @@ void
SetDataDir(const char *dir) SetDataDir(const char *dir)
{ {
char *new; char *new;
int newlen;
AssertArg(dir); AssertArg(dir);
@ -212,13 +211,7 @@ SetDataDir(const char *dir)
* Strip any trailing slash. Not strictly necessary, but avoids * Strip any trailing slash. Not strictly necessary, but avoids
* generating funny-looking paths to individual files. * generating funny-looking paths to individual files.
*/ */
newlen = strlen(new); canonicalize_path(new);
if (newlen > 1 && (new[newlen - 1] == '/'
#ifdef WIN32
|| new[newlen - 1] == '\\'
#endif
))
new[newlen - 1] = '\0';
if (DataDir) if (DataDir)
free(DataDir); free(DataDir);

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.133 2004/05/29 22:48:21 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.134 2004/06/18 06:13:54 tgl Exp $
* *
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
@ -26,6 +26,7 @@
#include "catalog/namespace.h" #include "catalog/namespace.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_shadow.h" #include "catalog/pg_shadow.h"
#include "catalog/pg_tablespace.h"
#include "commands/trigger.h" #include "commands/trigger.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
@ -239,12 +240,12 @@ InitPostgres(const char *dbname, const char *username)
if (bootstrap) if (bootstrap)
{ {
MyDatabaseId = TemplateDbOid; MyDatabaseId = TemplateDbOid;
SetDatabasePath(GetDatabasePath(MyDatabaseId)); MyDatabaseTableSpace = DEFAULTTABLESPACE_OID;
SetDatabasePath(GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace));
} }
else else
{ {
char *fullpath, char *fullpath;
datpath[MAXPGPATH];
/* /*
* Formerly we validated DataDir here, but now that's done * Formerly we validated DataDir here, but now that's done
@ -252,11 +253,11 @@ InitPostgres(const char *dbname, const char *username)
*/ */
/* /*
* Find oid and path of the database we're about to open. Since * Find oid and tablespace of the database we're about to open.
* we're not yet up and running we have to use the hackish * Since we're not yet up and running we have to use the hackish
* GetRawDatabaseInfo. * GetRawDatabaseInfo.
*/ */
GetRawDatabaseInfo(dbname, &MyDatabaseId, datpath); GetRawDatabaseInfo(dbname, &MyDatabaseId, &MyDatabaseTableSpace);
if (!OidIsValid(MyDatabaseId)) if (!OidIsValid(MyDatabaseId))
ereport(FATAL, ereport(FATAL,
@ -264,7 +265,7 @@ InitPostgres(const char *dbname, const char *username)
errmsg("database \"%s\" does not exist", errmsg("database \"%s\" does not exist",
dbname))); dbname)));
fullpath = GetDatabasePath(MyDatabaseId); fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace);
/* Verify the database path */ /* Verify the database path */

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/misc/database.c,v 1.60 2004/01/22 20:57:39 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/misc/database.c,v 1.61 2004/06/18 06:13:56 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -21,6 +21,7 @@
#include "catalog/catname.h" #include "catalog/catname.h"
#include "catalog/catalog.h" #include "catalog/catalog.h"
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_tablespace.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "utils/syscache.h" #include "utils/syscache.h"
@ -29,12 +30,13 @@ static bool PhonyHeapTupleSatisfiesNow(HeapTupleHeader tuple);
/* -------------------------------- /* --------------------------------
* GetRawDatabaseInfo() -- Find the OID and path of the database. * GetRawDatabaseInfo() -- Find the OID and tablespace of the database.
* *
* The database's oid forms half of the unique key for the system * We need both the OID and the default tablespace in order to find
* caches and lock tables. We therefore want it initialized before * the database's system catalogs. Moreover the database's OID forms
* we open any relations, since opening relations puts things in the * half of the unique key for the system caches and lock tables, so
* cache. To get around this problem, this code opens and scans the * we must have it before we can use any of the cache mechanisms.
* To get around these problems, this code opens and scans the
* pg_database relation by hand. * pg_database relation by hand.
* *
* This code knows way more than it should about the layout of * This code knows way more than it should about the layout of
@ -43,19 +45,21 @@ static bool PhonyHeapTupleSatisfiesNow(HeapTupleHeader tuple);
* -------------------------------- * --------------------------------
*/ */
void void
GetRawDatabaseInfo(const char *name, Oid *db_id, char *path) GetRawDatabaseInfo(const char *name, Oid *db_id, Oid *db_tablespace)
{ {
int dbfd; int dbfd;
int nbytes; int nbytes;
int pathlen;
HeapTupleData tup; HeapTupleData tup;
Form_pg_database tup_db;
Page pg; Page pg;
char *dbfname; char *dbfname;
Form_pg_database tup_db;
RelFileNode rnode; RelFileNode rnode;
rnode.tblNode = 0; /* hard-wired path to pg_database */
rnode.spcNode = GLOBALTABLESPACE_OID;
rnode.dbNode = 0;
rnode.relNode = RelOid_pg_database; rnode.relNode = RelOid_pg_database;
dbfname = relpath(rnode); dbfname = relpath(rnode);
if ((dbfd = open(dbfname, O_RDONLY | PG_BINARY, 0)) < 0) if ((dbfd = open(dbfname, O_RDONLY | PG_BINARY, 0)) < 0)
@ -121,7 +125,7 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
* committed and dead tuples to be marked with correct states. * committed and dead tuples to be marked with correct states.
* *
* XXX wouldn't it be better to let new backends read the * XXX wouldn't it be better to let new backends read the
* database OID from a flat file, handled the same way we * database info from a flat file, handled the same way we
* handle the password relation? * handle the password relation?
*/ */
if (!PhonyHeapTupleSatisfiesNow(tup.t_data)) if (!PhonyHeapTupleSatisfiesNow(tup.t_data))
@ -134,15 +138,9 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
if (strcmp(name, NameStr(tup_db->datname)) == 0) if (strcmp(name, NameStr(tup_db->datname)) == 0)
{ {
/* Found it; extract the OID and the database path. */ /* Found it; extract the db's OID and tablespace. */
*db_id = HeapTupleGetOid(&tup); *db_id = HeapTupleGetOid(&tup);
pathlen = VARSIZE(&(tup_db->datpath)) - VARHDRSZ; *db_tablespace = tup_db->dattablespace;
if (pathlen < 0)
pathlen = 0; /* pure paranoia */
if (pathlen >= MAXPGPATH)
pathlen = MAXPGPATH - 1; /* more paranoia */
strncpy(path, VARDATA(&(tup_db->datpath)), pathlen);
path[pathlen] = '\0';
goto done; goto done;
} }
} }
@ -150,7 +148,7 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
/* failed to find it... */ /* failed to find it... */
*db_id = InvalidOid; *db_id = InvalidOid;
*path = '\0'; *db_tablespace = InvalidOid;
done: done:
close(dbfd); close(dbfd);

View File

@ -39,7 +39,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* Portions taken from FreeBSD. * Portions taken from FreeBSD.
* *
* $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.37 2004/06/10 22:26:20 momjian Exp $ * $PostgreSQL: pgsql/src/bin/initdb/initdb.c,v 1.38 2004/06/18 06:13:58 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1785,7 +1785,7 @@ main(int argc, char *argv[])
char *pgdenv; /* PGDATA value got from sent to char *pgdenv; /* PGDATA value got from sent to
* environment */ * environment */
char *subdirs[] = char *subdirs[] =
{"global", "pg_xlog", "pg_clog", "base", "base/1"}; {"global", "pg_xlog", "pg_clog", "base", "base/1", "pg_tablespaces"};
progname = get_progname(argv[0]); progname = get_progname(argv[0]);
set_pglocale_pgservice(argv[0], "initdb"); set_pglocale_pgservice(argv[0], "initdb");
@ -2141,7 +2141,7 @@ main(int argc, char *argv[])
/* Bootstrap template1 */ /* Bootstrap template1 */
bootstrap_template1(short_version); bootstrap_template1(short_version);
/* Make the per-database PGVERSION for template1 only after init'ing it */ /* Make the per-database PG_VERSION for template1 only after init'ing it */
set_short_version(short_version, "base/1"); set_short_version(short_version, "base/1");
/* Create the stuff we don't need to use bootstrap mode for */ /* Create the stuff we don't need to use bootstrap mode for */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.12 2004/03/23 22:06:08 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.13 2004/06/18 06:14:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -144,7 +144,7 @@ appendStringLiteral(PQExpBuffer buf, const char *str, bool escapeAll)
/* /*
* Convert a string value to a dollar quoted literal and append it to * Convert a string value to a dollar quoted literal and append it to
* the given buffer. If the dqprefix parameter is not NULL then the * the given buffer. If the dqprefix parameter is not NULL then the
* dollar quote delimiter will begin with that (after the opening $). * dollar quote delimiter will begin with that (after the opening $).
* *
* No escaping is done at all on str, in compliance with the rules * No escaping is done at all on str, in compliance with the rules
@ -162,7 +162,7 @@ appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
if (dqprefix) if (dqprefix)
appendPQExpBuffer(delimBuf, dqprefix); appendPQExpBuffer(delimBuf, dqprefix);
/* /*
* Make sure we choose a delimiter which (without the trailing $) * Make sure we choose a delimiter which (without the trailing $)
* is not present in the string being quoted. We don't check with the * is not present in the string being quoted. We don't check with the
* trailing $ because a string ending in $foo must not be quoted with * trailing $ because a string ending in $foo must not be quoted with
@ -191,7 +191,7 @@ appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
* otherwise use standard quoting. * otherwise use standard quoting.
*/ */
void void
appendStringLiteralDQOpt(PQExpBuffer buf, const char *str, appendStringLiteralDQOpt(PQExpBuffer buf, const char *str,
bool escapeAll, const char *dqprefix) bool escapeAll, const char *dqprefix)
{ {
if (strchr(str, '\'') == NULL && strchr(str, '\\') == NULL) if (strchr(str, '\'') == NULL && strchr(str, '\\') == NULL)
@ -586,6 +586,8 @@ parseAclItem(const char *item, const char *type, const char *name,
CONVERT_PRIV('C', "CREATE"); CONVERT_PRIV('C', "CREATE");
CONVERT_PRIV('T', "TEMPORARY"); CONVERT_PRIV('T', "TEMPORARY");
} }
else if (strcmp(type, "TABLESPACE") == 0)
CONVERT_PRIV('C', "CREATE");
else else
abort(); abort();
@ -624,7 +626,7 @@ copyAclUserName(PQExpBuffer output, char *input)
appendPQExpBufferChar(output, *input++); appendPQExpBufferChar(output, *input++);
else else
{ {
/* Otherwise, it's a quoted username */ /* Otherwise, it's a quoted username */
input++; input++;
/* Loop until we come across an unescaped quote */ /* Loop until we come across an unescaped quote */
while (!(*input == '"' && *(input + 1) != '"')) while (!(*input == '"' && *(input + 1) != '"'))

View File

@ -12,7 +12,7 @@
* by PostgreSQL * by PostgreSQL
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.374 2004/06/07 20:35:57 momjian Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.375 2004/06/18 06:14:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -1164,13 +1164,13 @@ dumpDatabase(Archive *AH)
i_oid, i_oid,
i_dba, i_dba,
i_encoding, i_encoding,
i_datpath; i_tablespace;
CatalogId dbCatId; CatalogId dbCatId;
DumpId dbDumpId; DumpId dbDumpId;
const char *datname, const char *datname,
*dba, *dba,
*encoding, *encoding,
*datpath; *tablespace;
datname = PQdb(g_conn); datname = PQdb(g_conn);
@ -1181,31 +1181,34 @@ dumpDatabase(Archive *AH)
selectSourceSchema("pg_catalog"); selectSourceSchema("pg_catalog");
/* Get the database owner and parameters from pg_database */ /* Get the database owner and parameters from pg_database */
if (g_fout->remoteVersion >= 70100) if (g_fout->remoteVersion >= 70500)
{ {
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, " appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
"(SELECT usename FROM pg_user WHERE usesysid = datdba) as dba, " "(SELECT usename FROM pg_user WHERE usesysid = datdba) as dba, "
"pg_encoding_to_char(encoding) as encoding, " "pg_encoding_to_char(encoding) as encoding, "
"datpath " "(SELECT spcname FROM pg_tablespace t WHERE t.oid = dattablespace) as tablespace "
"FROM pg_database "
"WHERE datname = ");
appendStringLiteral(dbQry, datname, true);
}
else if (g_fout->remoteVersion >= 70100)
{
appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
"(SELECT usename FROM pg_user WHERE usesysid = datdba) as dba, "
"pg_encoding_to_char(encoding) as encoding, "
"NULL as tablespace "
"FROM pg_database " "FROM pg_database "
"WHERE datname = "); "WHERE datname = ");
appendStringLiteral(dbQry, datname, true); appendStringLiteral(dbQry, datname, true);
} }
else else
{ {
/*
* In 7.0, datpath is either the same as datname, or the user-given
* location with "/" and the datname appended. We must strip this
* junk off to produce a correct LOCATION value.
*/
appendPQExpBuffer(dbQry, "SELECT " appendPQExpBuffer(dbQry, "SELECT "
"(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, " "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
"oid, " "oid, "
"(SELECT usename FROM pg_user WHERE usesysid = datdba) as dba, " "(SELECT usename FROM pg_user WHERE usesysid = datdba) as dba, "
"pg_encoding_to_char(encoding) as encoding, " "pg_encoding_to_char(encoding) as encoding, "
"CASE WHEN length(datpath) > length(datname) THEN " "NULL as tablespace "
"substr(datpath,1,length(datpath)-length(datname)-1) "
"ELSE '' END as datpath "
"FROM pg_database " "FROM pg_database "
"WHERE datname = "); "WHERE datname = ");
appendStringLiteral(dbQry, datname, true); appendStringLiteral(dbQry, datname, true);
@ -1234,26 +1237,25 @@ dumpDatabase(Archive *AH)
i_oid = PQfnumber(res, "oid"); i_oid = PQfnumber(res, "oid");
i_dba = PQfnumber(res, "dba"); i_dba = PQfnumber(res, "dba");
i_encoding = PQfnumber(res, "encoding"); i_encoding = PQfnumber(res, "encoding");
i_datpath = PQfnumber(res, "datpath"); i_tablespace = PQfnumber(res, "tablespace");
dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid)); dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid)); dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
dba = PQgetvalue(res, 0, i_dba); dba = PQgetvalue(res, 0, i_dba);
encoding = PQgetvalue(res, 0, i_encoding); encoding = PQgetvalue(res, 0, i_encoding);
datpath = PQgetvalue(res, 0, i_datpath); tablespace = PQgetvalue(res, 0, i_tablespace);
appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0", appendPQExpBuffer(creaQry, "CREATE DATABASE %s WITH TEMPLATE = template0",
fmtId(datname)); fmtId(datname));
if (strlen(datpath) > 0)
{
appendPQExpBuffer(creaQry, " LOCATION = ");
appendStringLiteral(creaQry, datpath, true);
}
if (strlen(encoding) > 0) if (strlen(encoding) > 0)
{ {
appendPQExpBuffer(creaQry, " ENCODING = "); appendPQExpBuffer(creaQry, " ENCODING = ");
appendStringLiteral(creaQry, encoding, true); appendStringLiteral(creaQry, encoding, true);
} }
if (strlen(tablespace) > 0 && strcmp(tablespace, "default") != 0)
{
appendPQExpBuffer(creaQry, " TABLESPACE = %s", fmtId(tablespace));
}
appendPQExpBuffer(creaQry, ";\n"); appendPQExpBuffer(creaQry, ";\n");
appendPQExpBuffer(delQry, "DROP DATABASE %s;\n", appendPQExpBuffer(delQry, "DROP DATABASE %s;\n",
@ -1303,7 +1305,7 @@ dumpTimestamp(Archive *AH, char *msg)
if (strftime(buf, 256, "%Y-%m-%d %H:%M:%S %Z", localtime(&now)) != 0) if (strftime(buf, 256, "%Y-%m-%d %H:%M:%S %Z", localtime(&now)) != 0)
{ {
PQExpBuffer qry = createPQExpBuffer(); PQExpBuffer qry = createPQExpBuffer();
appendPQExpBuffer(qry, "-- "); appendPQExpBuffer(qry, "-- ");
appendPQExpBuffer(qry, msg); appendPQExpBuffer(qry, msg);
appendPQExpBuffer(qry, " "); appendPQExpBuffer(qry, " ");
@ -1471,6 +1473,7 @@ getNamespaces(int *numNamespaces)
int i_oid; int i_oid;
int i_nspname; int i_nspname;
int i_usename; int i_usename;
int i_nsptablespace;
int i_nspacl; int i_nspacl;
/* /*
@ -1488,6 +1491,7 @@ getNamespaces(int *numNamespaces)
nsinfo[0].dobj.name = strdup(""); nsinfo[0].dobj.name = strdup("");
nsinfo[0].usename = strdup(""); nsinfo[0].usename = strdup("");
nsinfo[0].nspacl = strdup(""); nsinfo[0].nspacl = strdup("");
nsinfo[0].nsptablespace = strdup("");
selectDumpableNamespace(&nsinfo[0]); selectDumpableNamespace(&nsinfo[0]);
@ -1498,6 +1502,7 @@ getNamespaces(int *numNamespaces)
nsinfo[1].dobj.name = strdup("pg_catalog"); nsinfo[1].dobj.name = strdup("pg_catalog");
nsinfo[1].usename = strdup(""); nsinfo[1].usename = strdup("");
nsinfo[1].nspacl = strdup(""); nsinfo[1].nspacl = strdup("");
nsinfo[0].nsptablespace = strdup("");
selectDumpableNamespace(&nsinfo[1]); selectDumpableNamespace(&nsinfo[1]);
@ -1516,10 +1521,21 @@ getNamespaces(int *numNamespaces)
* we fetch all namespaces including system ones, so that every object * we fetch all namespaces including system ones, so that every object
* we read in can be linked to a containing namespace. * we read in can be linked to a containing namespace.
*/ */
appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, " if (g_fout->remoteVersion >= 70500)
"(select usename from pg_user where nspowner = usesysid) as usename, " {
"nspacl " appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
"FROM pg_namespace"); "(select usename from pg_user where nspowner = usesysid) as usename, "
"nspacl, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = nsptablespace) AS nsptablespace "
"FROM pg_namespace");
}
else
{
appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
"(select usename from pg_user where nspowner = usesysid) as usename, "
"nspacl, NULL AS nsptablespace "
"FROM pg_namespace");
}
res = PQexec(g_conn, query->data); res = PQexec(g_conn, query->data);
check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK); check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
@ -1533,6 +1549,7 @@ getNamespaces(int *numNamespaces)
i_nspname = PQfnumber(res, "nspname"); i_nspname = PQfnumber(res, "nspname");
i_usename = PQfnumber(res, "usename"); i_usename = PQfnumber(res, "usename");
i_nspacl = PQfnumber(res, "nspacl"); i_nspacl = PQfnumber(res, "nspacl");
i_nsptablespace = PQfnumber(res, "nsptablespace");
for (i = 0; i < ntups; i++) for (i = 0; i < ntups; i++)
{ {
@ -1543,6 +1560,7 @@ getNamespaces(int *numNamespaces)
nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname)); nsinfo[i].dobj.name = strdup(PQgetvalue(res, i, i_nspname));
nsinfo[i].usename = strdup(PQgetvalue(res, i, i_usename)); nsinfo[i].usename = strdup(PQgetvalue(res, i, i_usename));
nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl)); nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
nsinfo[i].nsptablespace = strdup(PQgetvalue(res, i, i_nsptablespace));
/* Decide whether to dump this namespace */ /* Decide whether to dump this namespace */
selectDumpableNamespace(&nsinfo[i]); selectDumpableNamespace(&nsinfo[i]);
@ -2329,6 +2347,7 @@ getTables(int *numTables)
int i_relhasoids; int i_relhasoids;
int i_owning_tab; int i_owning_tab;
int i_owning_col; int i_owning_col;
int i_reltablespace;
/* Make sure we are in proper schema */ /* Make sure we are in proper schema */
selectSourceSchema("pg_catalog"); selectSourceSchema("pg_catalog");
@ -2349,7 +2368,7 @@ getTables(int *numTables)
* columns, etc. * columns, etc.
*/ */
if (g_fout->remoteVersion >= 70300) if (g_fout->remoteVersion >= 70500)
{ {
/* /*
* Left join to pick up dependency info linking sequences to their * Left join to pick up dependency info linking sequences to their
@ -2362,7 +2381,34 @@ getTables(int *numTables)
"relchecks, reltriggers, " "relchecks, reltriggers, "
"relhasindex, relhasrules, relhasoids, " "relhasindex, relhasrules, relhasoids, "
"d.refobjid as owning_tab, " "d.refobjid as owning_tab, "
"d.refobjsubid as owning_col " "d.refobjsubid as owning_col, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = c.reltablespace) AS reltablespace "
"from pg_class c "
"left join pg_depend d on "
"(c.relkind = '%c' and "
"d.classid = c.tableoid and d.objid = c.oid and "
"d.objsubid = 0 and "
"d.refclassid = c.tableoid and d.deptype = 'i') "
"where relkind in ('%c', '%c', '%c') "
"order by c.oid",
RELKIND_SEQUENCE,
RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW);
}
else if (g_fout->remoteVersion >= 70300)
{
/*
* Left join to pick up dependency info linking sequences to their
* serial column, if any
*/
appendPQExpBuffer(query,
"SELECT c.tableoid, c.oid, relname, "
"relacl, relkind, relnamespace, "
"(select usename from pg_user where relowner = usesysid) as usename, "
"relchecks, reltriggers, "
"relhasindex, relhasrules, relhasoids, "
"d.refobjid as owning_tab, "
"d.refobjsubid as owning_col, "
"NULL as reltablespace "
"from pg_class c " "from pg_class c "
"left join pg_depend d on " "left join pg_depend d on "
"(c.relkind = '%c' and " "(c.relkind = '%c' and "
@ -2383,7 +2429,8 @@ getTables(int *numTables)
"relchecks, reltriggers, " "relchecks, reltriggers, "
"relhasindex, relhasrules, relhasoids, " "relhasindex, relhasrules, relhasoids, "
"NULL::oid as owning_tab, " "NULL::oid as owning_tab, "
"NULL::int4 as owning_col " "NULL::int4 as owning_col, "
"NULL as reltablespace "
"from pg_class " "from pg_class "
"where relkind in ('%c', '%c', '%c') " "where relkind in ('%c', '%c', '%c') "
"order by oid", "order by oid",
@ -2400,7 +2447,8 @@ getTables(int *numTables)
"relhasindex, relhasrules, " "relhasindex, relhasrules, "
"'t'::bool as relhasoids, " "'t'::bool as relhasoids, "
"NULL::oid as owning_tab, " "NULL::oid as owning_tab, "
"NULL::int4 as owning_col " "NULL::int4 as owning_col, "
"NULL as reltablespace "
"from pg_class " "from pg_class "
"where relkind in ('%c', '%c', '%c') " "where relkind in ('%c', '%c', '%c') "
"order by oid", "order by oid",
@ -2427,7 +2475,8 @@ getTables(int *numTables)
"relhasindex, relhasrules, " "relhasindex, relhasrules, "
"'t'::bool as relhasoids, " "'t'::bool as relhasoids, "
"NULL::oid as owning_tab, " "NULL::oid as owning_tab, "
"NULL::int4 as owning_col " "NULL::int4 as owning_col, "
"NULL as reltablespace "
"from pg_class c " "from pg_class c "
"where relkind in ('%c', '%c') " "where relkind in ('%c', '%c') "
"order by oid", "order by oid",
@ -2467,6 +2516,7 @@ getTables(int *numTables)
i_relhasoids = PQfnumber(res, "relhasoids"); i_relhasoids = PQfnumber(res, "relhasoids");
i_owning_tab = PQfnumber(res, "owning_tab"); i_owning_tab = PQfnumber(res, "owning_tab");
i_owning_col = PQfnumber(res, "owning_col"); i_owning_col = PQfnumber(res, "owning_col");
i_reltablespace = PQfnumber(res, "reltablespace");
for (i = 0; i < ntups; i++) for (i = 0; i < ntups; i++)
{ {
@ -2495,6 +2545,7 @@ getTables(int *numTables)
tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab)); tblinfo[i].owning_tab = atooid(PQgetvalue(res, i, i_owning_tab));
tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col)); tblinfo[i].owning_col = atoi(PQgetvalue(res, i, i_owning_col));
} }
tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
/* other fields were zeroed above */ /* other fields were zeroed above */
@ -2768,6 +2819,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
indxinfo[j].indextable = tbinfo; indxinfo[j].indextable = tbinfo;
indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef)); indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys)); indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
/* /*
* In pre-7.4 releases, indkeys may contain more entries than * In pre-7.4 releases, indkeys may contain more entries than
* indnkeys says (since indnkeys will be 1 for a functional * indnkeys says (since indnkeys will be 1 for a functional
@ -2805,7 +2857,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
constrinfo[j].conindex = indxinfo[j].dobj.dumpId; constrinfo[j].conindex = indxinfo[j].dobj.dumpId;
constrinfo[j].coninherited = false; constrinfo[j].coninherited = false;
constrinfo[j].separate = true; constrinfo[j].separate = true;
indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId; indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
/* If pre-7.3 DB, better make sure table comes first */ /* If pre-7.3 DB, better make sure table comes first */
@ -4341,9 +4393,16 @@ dumpNamespace(Archive *fout, NamespaceInfo *nspinfo)
{ {
appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname); appendPQExpBuffer(delq, "DROP SCHEMA %s;\n", qnspname);
appendPQExpBuffer(q, "CREATE SCHEMA %s AUTHORIZATION %s;\n", appendPQExpBuffer(q, "CREATE SCHEMA %s AUTHORIZATION %s",
qnspname, fmtId(nspinfo->usename)); qnspname, fmtId(nspinfo->usename));
/* Add tablespace qualifier, if not default */
if (strlen(nspinfo->nsptablespace) != 0)
appendPQExpBuffer(q, " TABLESPACE %s",
fmtId(nspinfo->nsptablespace));
appendPQExpBuffer(q, ";\n");
ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId, ArchiveEntry(fout, nspinfo->dobj.catId, nspinfo->dobj.dumpId,
nspinfo->dobj.name, nspinfo->dobj.name,
NULL, "", NULL, "",
@ -5118,7 +5177,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
if (strcmp(prosrc, "-") != 0) if (strcmp(prosrc, "-") != 0)
{ {
appendPQExpBuffer(asPart, ", "); appendPQExpBuffer(asPart, ", ");
/* /*
* where we have bin, use dollar quoting if allowed and src * where we have bin, use dollar quoting if allowed and src
* contains quote or backslash; else use regular quoting. * contains quote or backslash; else use regular quoting.
*/ */
@ -5281,7 +5340,7 @@ dumpCast(Archive *fout, CastInfo *cast)
* Skip cast if function isn't from pg_ and that namespace is * Skip cast if function isn't from pg_ and that namespace is
* not dumped. * not dumped.
*/ */
if (funcInfo && if (funcInfo &&
strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 && strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
!funcInfo->dobj.namespace->dump) !funcInfo->dobj.namespace->dump)
return; return;
@ -6001,14 +6060,14 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
fmtId(convinfo->dobj.name)); fmtId(convinfo->dobj.name));
appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ", appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
(condefault) ? "DEFAULT " : "", (condefault) ? "DEFAULT " : "",
fmtId(convinfo->dobj.name)); fmtId(convinfo->dobj.name));
appendStringLiteral(q, conforencoding, true); appendStringLiteral(q, conforencoding, true);
appendPQExpBuffer(q, " TO "); appendPQExpBuffer(q, " TO ");
appendStringLiteral(q, contoencoding, true); appendStringLiteral(q, contoencoding, true);
/* regproc is automatically quoted in 7.3 and above */ /* regproc is automatically quoted in 7.3 and above */
appendPQExpBuffer(q, " FROM %s;\n", conproc); appendPQExpBuffer(q, " FROM %s;\n", conproc);
ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId, ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
convinfo->dobj.name, convinfo->dobj.name,
convinfo->dobj.namespace->dobj.name, convinfo->usename, convinfo->dobj.namespace->dobj.name, convinfo->usename,
@ -6562,6 +6621,15 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
appendPQExpBuffer(q, ")"); appendPQExpBuffer(q, ")");
} }
/* Output tablespace clause if necessary */
if (strlen(tbinfo->reltablespace) != 0 &&
strcmp(tbinfo->reltablespace,
tbinfo->dobj.namespace->nsptablespace) != 0)
{
appendPQExpBuffer(q, " TABLESPACE %s",
fmtId(tbinfo->reltablespace));
}
appendPQExpBuffer(q, ";\n"); appendPQExpBuffer(q, ";\n");
/* Loop dumping statistics and storage statements */ /* Loop dumping statistics and storage statements */
@ -7227,9 +7295,20 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
appendPQExpBuffer(query, " NO MINVALUE\n"); appendPQExpBuffer(query, " NO MINVALUE\n");
appendPQExpBuffer(query, appendPQExpBuffer(query,
" CACHE %s%s;\n", " CACHE %s%s",
cache, (cycled ? "\n CYCLE" : "")); cache, (cycled ? "\n CYCLE" : ""));
/* Output tablespace clause if necessary */
if (strlen(tbinfo->reltablespace) != 0 &&
strcmp(tbinfo->reltablespace,
tbinfo->dobj.namespace->nsptablespace) != 0)
{
appendPQExpBuffer(query, " TABLESPACE %s",
fmtId(tbinfo->reltablespace));
}
appendPQExpBuffer(query, ";\n");
ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, ArchiveEntry(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId,
tbinfo->dobj.name, tbinfo->dobj.name,
tbinfo->dobj.namespace->dobj.name, tbinfo->usename, tbinfo->dobj.namespace->dobj.name, tbinfo->usename,

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.108 2004/03/03 21:28:55 tgl Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.109 2004/06/18 06:14:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -98,6 +98,7 @@ typedef struct _namespaceInfo
DumpableObject dobj; DumpableObject dobj;
char *usename; /* name of owner, or empty string */ char *usename; /* name of owner, or empty string */
char *nspacl; char *nspacl;
char *nsptablespace; /* default tablespace */
bool dump; /* true if need to dump definition */ bool dump; /* true if need to dump definition */
} NamespaceInfo; } NamespaceInfo;
@ -168,6 +169,7 @@ typedef struct _tableInfo
char *usename; /* name of owner, or empty string */ char *usename; /* name of owner, or empty string */
char *relacl; char *relacl;
char relkind; char relkind;
char *reltablespace; /* relation tablespace */
bool hasindex; /* does it have any indexes? */ bool hasindex; /* does it have any indexes? */
bool hasrules; /* does it have any rules? */ bool hasrules; /* does it have any rules? */
bool hasoids; /* does it have OIDs? */ bool hasoids; /* does it have OIDs? */

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* *
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.41 2004/06/10 16:35:17 momjian Exp $ * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.42 2004/06/18 06:14:00 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -46,6 +46,7 @@ static void help(void);
static void dumpUsers(PGconn *conn); static void dumpUsers(PGconn *conn);
static void dumpGroups(PGconn *conn); static void dumpGroups(PGconn *conn);
static void dumpTablespaces(PGconn *conn);
static void dumpCreateDB(PGconn *conn); static void dumpCreateDB(PGconn *conn);
static void dumpDatabaseConfig(PGconn *conn, const char *dbname); static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
static void dumpUserConfig(PGconn *conn, const char *username); static void dumpUserConfig(PGconn *conn, const char *username);
@ -231,6 +232,8 @@ main(int argc, char *argv[])
{ {
dumpUsers(conn); dumpUsers(conn);
dumpGroups(conn); dumpGroups(conn);
if (server_version >= 70500)
dumpTablespaces(conn);
} }
if (!globals_only) if (!globals_only)
@ -411,7 +414,68 @@ dumpGroups(PGconn *conn)
printf("\n\n"); printf("\n\n");
} }
/*
* Dump tablespaces.
*/
static void
dumpTablespaces(PGconn *conn)
{
PGresult *res;
int i;
printf("--\n-- Tablespaces\n--\n\n");
/*
* Get all tablespaces except for the system default and global
* tablespaces
*/
res = executeQuery(conn, "SELECT spcname, "
"pg_catalog.pg_get_userbyid(spcowner) AS spcowner, "
"spclocation, spcacl "
"FROM pg_catalog.pg_tablespace "
"WHERE spcname NOT IN ('default', 'global')");
for (i = 0; i < PQntuples(res); i++)
{
PQExpBuffer buf = createPQExpBuffer();
char *spcname = PQgetvalue(res, i, 0);
char *spcowner = PQgetvalue(res, i, 1);
char *spclocation = PQgetvalue(res, i, 2);
char *spcacl = PQgetvalue(res, i, 3);
char *fspcname;
/* needed for buildACLCommands() */
fspcname = strdup(fmtId(spcname));
if (output_clean)
appendPQExpBuffer(buf, "DROP TABLESPACE %s;\n", fspcname);
appendPQExpBuffer(buf, "CREATE TABLESPACE %s", fspcname);
appendPQExpBuffer(buf, " OWNER %s", fmtId(spcowner));
appendPQExpBuffer(buf, " LOCATION ");
appendStringLiteral(buf, spclocation, true);
appendPQExpBuffer(buf, ";\n");
if (!skip_acls &&
!buildACLCommands(fspcname, "TABLESPACE", spcacl, spcowner,
server_version, buf))
{
fprintf(stderr, _("%s: could not parse ACL list (%s) for tablespace \"%s\"\n"),
progname, spcacl, fspcname);
PQfinish(conn);
exit(1);
}
printf("%s", buf->data);
free(fspcname);
destroyPQExpBuffer(buf);
}
PQclear(res);
printf("\n\n");
}
/* /*
* Dump commands to create each database. * Dump commands to create each database.
@ -432,12 +496,22 @@ dumpCreateDB(PGconn *conn)
printf("--\n-- Database creation\n--\n\n"); printf("--\n-- Database creation\n--\n\n");
if (server_version >= 70300) if (server_version >= 70500)
res = executeQuery(conn, res = executeQuery(conn,
"SELECT datname, " "SELECT datname, "
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " "coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), " "pg_encoding_to_char(d.encoding), "
"datistemplate, datpath, datacl " "datistemplate, datacl, "
"(SELECT spcname FROM pg_tablespace t WHERE t.oid = d.dattablespace) AS dattablespace "
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
"WHERE datallowconn ORDER BY 1");
else if (server_version >= 70300)
res = executeQuery(conn,
"SELECT datname, "
"coalesce(usename, (select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), "
"datistemplate, datacl, "
"'default' AS dattablespace "
"FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) " "FROM pg_database d LEFT JOIN pg_shadow u ON (datdba = usesysid) "
"WHERE datallowconn ORDER BY 1"); "WHERE datallowconn ORDER BY 1");
else if (server_version >= 70100) else if (server_version >= 70100)
@ -447,16 +521,13 @@ dumpCreateDB(PGconn *conn)
"(select usename from pg_shadow where usesysid=datdba), " "(select usename from pg_shadow where usesysid=datdba), "
"(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), " "(select usename from pg_shadow where usesysid=(select datdba from pg_database where datname='template0'))), "
"pg_encoding_to_char(d.encoding), " "pg_encoding_to_char(d.encoding), "
"datistemplate, datpath, '' as datacl " "datistemplate, '' as datacl, "
"'default' AS dattablespace "
"FROM pg_database d " "FROM pg_database d "
"WHERE datallowconn ORDER BY 1"); "WHERE datallowconn ORDER BY 1");
else else
{ {
/* /*
* In 7.0, datpath is either the same as datname, or the user-given
* location with "/" and the datname appended. We must strip this
* junk off to produce a correct LOCATION value.
*
* Note: 7.0 fails to cope with sub-select in COALESCE, so just * Note: 7.0 fails to cope with sub-select in COALESCE, so just
* deal with getting a NULL by not printing any OWNER clause. * deal with getting a NULL by not printing any OWNER clause.
*/ */
@ -465,10 +536,8 @@ dumpCreateDB(PGconn *conn)
"(select usename from pg_shadow where usesysid=datdba), " "(select usename from pg_shadow where usesysid=datdba), "
"pg_encoding_to_char(d.encoding), " "pg_encoding_to_char(d.encoding), "
"'f' as datistemplate, " "'f' as datistemplate, "
"CASE WHEN length(datpath) > length(datname) THEN " "'' as datacl, "
"substr(datpath,1,length(datpath)-length(datname)-1) " "'default' AS dattablespace "
"ELSE '' END as datpath, "
"'' as datacl "
"FROM pg_database d " "FROM pg_database d "
"ORDER BY 1"); "ORDER BY 1");
} }
@ -480,8 +549,8 @@ dumpCreateDB(PGconn *conn)
char *dbowner = PQgetvalue(res, i, 1); char *dbowner = PQgetvalue(res, i, 1);
char *dbencoding = PQgetvalue(res, i, 2); char *dbencoding = PQgetvalue(res, i, 2);
char *dbistemplate = PQgetvalue(res, i, 3); char *dbistemplate = PQgetvalue(res, i, 3);
char *dbpath = PQgetvalue(res, i, 4); char *dbacl = PQgetvalue(res, i, 4);
char *dbacl = PQgetvalue(res, i, 5); char *dbtablespace = PQgetvalue(res, i, 5);
char *fdbname; char *fdbname;
if (strcmp(dbname, "template1") == 0) if (strcmp(dbname, "template1") == 0)
@ -496,20 +565,21 @@ dumpCreateDB(PGconn *conn)
appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname); appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname);
appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname); appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
if (strlen(dbowner) != 0)
appendPQExpBuffer(buf, " WITH OWNER = %s",
fmtId(dbowner));
appendPQExpBuffer(buf, " TEMPLATE = template0");
if (strlen(dbpath) != 0) appendPQExpBuffer(buf, " WITH TEMPLATE = template0");
{
appendPQExpBuffer(buf, " LOCATION = "); if (strlen(dbowner) != 0)
appendStringLiteral(buf, dbpath, true); appendPQExpBuffer(buf, " OWNER = %s",
} fmtId(dbowner));
appendPQExpBuffer(buf, " ENCODING = "); appendPQExpBuffer(buf, " ENCODING = ");
appendStringLiteral(buf, dbencoding, true); appendStringLiteral(buf, dbencoding, true);
/* Output tablespace if it isn't default */
if (strcmp(dbtablespace, "default") != 0)
appendPQExpBuffer(buf, " TABLESPACE = %s",
fmtId(dbtablespace));
appendPQExpBuffer(buf, ";\n"); appendPQExpBuffer(buf, ";\n");
if (strcmp(dbistemplate, "t") == 0) if (strcmp(dbistemplate, "t") == 0)

View File

@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2003, PostgreSQL Global Development Group * Copyright (c) 2000-2003, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.116 2004/05/07 00:24:58 tgl Exp $ * $PostgreSQL: pgsql/src/bin/psql/command.c,v 1.117 2004/06/18 06:14:04 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "command.h" #include "command.h"
@ -301,6 +301,9 @@ exec_command(const char *cmd,
case 'a': case 'a':
success = describeAggregates(pattern, show_verbose); success = describeAggregates(pattern, show_verbose);
break; break;
case 'b':
success = describeTablespaces(pattern);
break;
case 'c': case 'c':
success = listConversions(pattern); success = listConversions(pattern);
break; break;

View File

@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2003, PostgreSQL Global Development Group * Copyright (c) 2000-2003, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.98 2004/05/07 00:24:58 tgl Exp $ * $PostgreSQL: pgsql/src/bin/psql/describe.c,v 1.99 2004/06/18 06:14:04 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "describe.h" #include "describe.h"
@ -99,6 +99,45 @@ describeAggregates(const char *pattern, bool verbose)
return true; return true;
} }
/* \db
* Takes an optional regexp to select particular tablespaces
*/
bool
describeTablespaces(const char *pattern)
{
PQExpBufferData buf;
PGresult *res;
printQueryOpt myopt = pset.popt;
initPQExpBuffer(&buf);
printfPQExpBuffer(&buf,
"SELECT spcname AS \"%s\",\n"
" pg_catalog.pg_get_userbyid(spcowner) AS \"%s\",\n"
" spclocation AS \"%s\"\n"
"FROM pg_catalog.pg_tablespace\n",
_("Name"), _("Owner"), _("Location"));
processNamePattern(&buf, pattern, false, false,
NULL, "spcname", 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 tablespaces");
printQuery(res, &myopt, pset.queryFout);
PQclear(res);
return true;
}
/* \df /* \df
* Takes an optional regexp to select particular functions * Takes an optional regexp to select particular functions
@ -351,7 +390,7 @@ permissionsList(const char *pattern)
printfPQExpBuffer(&buf, printfPQExpBuffer(&buf,
"SELECT n.nspname as \"%s\",\n" "SELECT n.nspname as \"%s\",\n"
" c.relname as \"%s\",\n" " c.relname as \"%s\",\n"
" CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' END as \"%s\",\n" " CASE c.relkind WHEN 'r' THEN '%s' WHEN 'v' THEN '%s' WHEN 'S' THEN '%s' END as \"%s\",\n"
" c.relacl as \"%s\"\n" " c.relacl as \"%s\"\n"
"FROM pg_catalog.pg_class c\n" "FROM pg_catalog.pg_class c\n"
" LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n" " LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"

View File

@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2003, PostgreSQL Global Development Group * Copyright (c) 2000-2003, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.23 2003/12/01 22:21:54 momjian Exp $ * $PostgreSQL: pgsql/src/bin/psql/describe.h,v 1.24 2004/06/18 06:14:04 tgl Exp $
*/ */
#ifndef DESCRIBE_H #ifndef DESCRIBE_H
#define DESCRIBE_H #define DESCRIBE_H
@ -13,6 +13,9 @@
/* \da */ /* \da */
bool describeAggregates(const char *pattern, bool verbose); bool describeAggregates(const char *pattern, bool verbose);
/* \db */
bool describeTablespaces(const char *pattern);
/* \df */ /* \df */
bool describeFunctions(const char *pattern, bool verbose); bool describeFunctions(const char *pattern, bool verbose);

View File

@ -3,7 +3,7 @@
* *
* Copyright (c) 2000-2003, PostgreSQL Global Development Group * Copyright (c) 2000-2003, PostgreSQL Global Development Group
* *
* $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.87 2004/05/07 00:24:58 tgl Exp $ * $PostgreSQL: pgsql/src/bin/psql/help.c,v 1.88 2004/06/18 06:14:04 tgl Exp $
*/ */
#include "postgres_fe.h" #include "postgres_fe.h"
#include "common.h" #include "common.h"
@ -211,6 +211,7 @@ slashUsage(unsigned short int pager)
fprintf(output, _(" \\d{t|i|s|v|S} [PATTERN] (add \"+\" for more detail)\n" fprintf(output, _(" \\d{t|i|s|v|S} [PATTERN] (add \"+\" for more detail)\n"
" list tables/indexes/sequences/views/system tables\n")); " list tables/indexes/sequences/views/system tables\n"));
fprintf(output, _(" \\da [PATTERN] list aggregate functions\n")); fprintf(output, _(" \\da [PATTERN] list aggregate functions\n"));
fprintf(output, _(" \\db [PATTERN] list tablespaces\n"));
fprintf(output, _(" \\dc [PATTERN] list conversions\n")); fprintf(output, _(" \\dc [PATTERN] list conversions\n"));
fprintf(output, _(" \\dC list casts\n")); fprintf(output, _(" \\dC list casts\n"));
fprintf(output, _(" \\dd [PATTERN] show comment for object\n")); fprintf(output, _(" \\dd [PATTERN] show comment for object\n"));
@ -308,7 +309,7 @@ helpSQL(const char *topic, unsigned short int pager)
size_t len; size_t len;
int nl_count = 0; int nl_count = 0;
char *ch; char *ch;
/* don't care about trailing spaces */ /* don't care about trailing spaces */
len = strlen(topic); len = strlen(topic);
while (topic[len - 1] == ' ') while (topic[len - 1] == ' ')

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.27 2003/11/29 22:40:58 pgsql Exp $ * $PostgreSQL: pgsql/src/include/catalog/catalog.h,v 1.28 2004/06/18 06:14:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -18,7 +18,7 @@
extern char *relpath(RelFileNode rnode); extern char *relpath(RelFileNode rnode);
extern char *GetDatabasePath(Oid tblNode); extern char *GetDatabasePath(Oid dbNode, Oid spcNode);
extern bool IsSystemRelation(Relation relation); extern bool IsSystemRelation(Relation relation);
extern bool IsToastRelation(Relation relation); extern bool IsToastRelation(Relation relation);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catname.h,v 1.31 2003/11/29 22:40:58 pgsql Exp $ * $PostgreSQL: pgsql/src/include/catalog/catname.h,v 1.32 2004/06/18 06:14:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -40,6 +40,7 @@
#define RewriteRelationName "pg_rewrite" #define RewriteRelationName "pg_rewrite"
#define ShadowRelationName "pg_shadow" #define ShadowRelationName "pg_shadow"
#define StatisticRelationName "pg_statistic" #define StatisticRelationName "pg_statistic"
#define TableSpaceRelationName "pg_tablespace"
#define TypeRelationName "pg_type" #define TypeRelationName "pg_type"
#define VersionRelationName "pg_version" #define VersionRelationName "pg_version"
#define AttrDefaultRelationName "pg_attrdef" #define AttrDefaultRelationName "pg_attrdef"

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.236 2004/06/16 01:26:49 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.237 2004/06/18 06:14:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200406151 #define CATALOG_VERSION_NO 200406171
#endif #endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.66 2004/05/05 04:48:47 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/heap.h,v 1.67 2004/06/18 06:14:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -37,6 +37,7 @@ typedef struct CookedConstraint
extern Relation heap_create(const char *relname, extern Relation heap_create(const char *relname,
Oid relnamespace, Oid relnamespace,
Oid reltablespace,
TupleDesc tupDesc, TupleDesc tupDesc,
bool shared_relation, bool shared_relation,
bool storage_create, bool storage_create,
@ -46,6 +47,7 @@ extern void heap_storage_create(Relation rel);
extern Oid heap_create_with_catalog(const char *relname, extern Oid heap_create_with_catalog(const char *relname,
Oid relnamespace, Oid relnamespace,
Oid reltablespace,
TupleDesc tupdesc, TupleDesc tupdesc,
char relkind, char relkind,
bool shared_relation, bool shared_relation,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/index.h,v 1.56 2004/05/08 00:34:49 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/index.h,v 1.57 2004/06/18 06:14:05 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -34,6 +34,7 @@ extern Oid index_create(Oid heapRelationId,
const char *indexRelationName, const char *indexRelationName,
IndexInfo *indexInfo, IndexInfo *indexInfo,
Oid accessMethodObjectId, Oid accessMethodObjectId,
Oid tableSpaceId,
Oid *classObjectId, Oid *classObjectId,
bool primary, bool primary,
bool isconstraint, bool isconstraint,

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.81 2003/11/29 22:40:58 pgsql Exp $ * $PostgreSQL: pgsql/src/include/catalog/indexing.h,v 1.82 2004/06/18 06:14:06 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -70,6 +70,8 @@
#define ShadowNameIndex "pg_shadow_usename_index" #define ShadowNameIndex "pg_shadow_usename_index"
#define ShadowSysidIndex "pg_shadow_usesysid_index" #define ShadowSysidIndex "pg_shadow_usesysid_index"
#define StatisticRelidAttnumIndex "pg_statistic_relid_att_index" #define StatisticRelidAttnumIndex "pg_statistic_relid_att_index"
#define TablespaceNameIndex "pg_tablespace_spcname_index"
#define TablespaceOidIndex "pg_tablespace_oid_index"
#define TriggerConstrNameIndex "pg_trigger_tgconstrname_index" #define TriggerConstrNameIndex "pg_trigger_tgconstrname_index"
#define TriggerConstrRelidIndex "pg_trigger_tgconstrrelid_index" #define TriggerConstrRelidIndex "pg_trigger_tgconstrrelid_index"
#define TriggerRelidNameIndex "pg_trigger_tgrelid_tgname_index" #define TriggerRelidNameIndex "pg_trigger_tgrelid_tgname_index"
@ -166,6 +168,8 @@ DECLARE_UNIQUE_INDEX(pg_rewrite_rel_rulename_index on pg_rewrite using btree(ev_
DECLARE_UNIQUE_INDEX(pg_shadow_usename_index on pg_shadow using btree(usename name_ops)); DECLARE_UNIQUE_INDEX(pg_shadow_usename_index on pg_shadow using btree(usename name_ops));
DECLARE_UNIQUE_INDEX(pg_shadow_usesysid_index on pg_shadow using btree(usesysid int4_ops)); DECLARE_UNIQUE_INDEX(pg_shadow_usesysid_index on pg_shadow using btree(usesysid int4_ops));
DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_index on pg_statistic using btree(starelid oid_ops, staattnum int2_ops)); DECLARE_UNIQUE_INDEX(pg_statistic_relid_att_index on pg_statistic using btree(starelid oid_ops, staattnum int2_ops));
DECLARE_UNIQUE_INDEX(pg_tablespace_oid_index on pg_tablespace using btree(oid oid_ops));
DECLARE_UNIQUE_INDEX(pg_tablespace_spcname_index on pg_tablespace using btree(spcname name_ops));
/* This following index is not used for a cache and is not unique */ /* This following index is not used for a cache and is not unique */
DECLARE_INDEX(pg_trigger_tgconstrname_index on pg_trigger using btree(tgconstrname name_ops)); DECLARE_INDEX(pg_trigger_tgconstrname_index on pg_trigger using btree(tgconstrname name_ops));
/* This following index is not used for a cache and is not unique */ /* This following index is not used for a cache and is not unique */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.109 2004/04/01 21:28:45 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.110 2004/06/18 06:14:06 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -218,7 +218,7 @@ typedef FormData_pg_attribute *Form_pg_attribute;
*/ */
/* ---------------- /* ----------------
* pg_type schema * pg_type
* ---------------- * ----------------
*/ */
#define Schema_pg_type \ #define Schema_pg_type \
@ -290,8 +290,7 @@ DATA(insert ( 1262 datallowconn 16 -1 1 5 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1262 datlastsysoid 26 -1 4 6 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1262 datlastsysoid 26 -1 4 6 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1262 datvacuumxid 28 -1 4 7 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1262 datvacuumxid 28 -1 4 7 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1262 datfrozenxid 28 -1 4 8 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1262 datfrozenxid 28 -1 4 8 0 -1 -1 t p i t f f t 0));
/* do not mark datpath as toastable; GetRawDatabaseInfo won't cope */ DATA(insert ( 1262 dattablespace 26 -1 4 9 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1262 datpath 25 -1 -1 9 0 -1 -1 f p i t f f t 0));
DATA(insert ( 1262 datconfig 1009 -1 -1 10 1 -1 -1 f x i f f f t 0)); DATA(insert ( 1262 datconfig 1009 -1 -1 10 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1262 datacl 1034 -1 -1 11 1 -1 -1 f x i f f f t 0)); DATA(insert ( 1262 datacl 1034 -1 -1 11 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1262 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); DATA(insert ( 1262 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0));
@ -442,24 +441,25 @@ DATA(insert ( 1249 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
{ 1259, {"relowner"}, 23, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ { 1259, {"relowner"}, 23, -1, 4, 4, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1259, {"relam"}, 26, -1, 4, 5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ { 1259, {"relam"}, 26, -1, 4, 5, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1259, {"relfilenode"}, 26, -1, 4, 6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ { 1259, {"relfilenode"}, 26, -1, 4, 6, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1259, {"relpages"}, 23, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ { 1259, {"reltablespace"}, 26, -1, 4, 7, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1259, {"reltuples"}, 700, -1, 4, 8, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \ { 1259, {"relpages"}, 23, -1, 4, 8, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1259, {"reltoastrelid"}, 26, -1, 4, 9, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ { 1259, {"reltuples"}, 700, -1, 4, 9, 0, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
{ 1259, {"reltoastidxid"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \ { 1259, {"reltoastrelid"}, 26, -1, 4, 10, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1259, {"relhasindex"}, 16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1259, {"reltoastidxid"}, 26, -1, 4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1259, {"relisshared"}, 16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1259, {"relhasindex"}, 16, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1259, {"relkind"}, 18, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1259, {"relisshared"}, 16, -1, 1, 13, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1259, {"relnatts"}, 21, -1, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ { 1259, {"relkind"}, 18, -1, 1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1259, {"relchecks"}, 21, -1, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ { 1259, {"relnatts"}, 21, -1, 2, 15, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1259, {"reltriggers"}, 21, -1, 2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ { 1259, {"relchecks"}, 21, -1, 2, 16, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1259, {"relukeys"}, 21, -1, 2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ { 1259, {"reltriggers"}, 21, -1, 2, 17, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1259, {"relfkeys"}, 21, -1, 2, 18, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ { 1259, {"relukeys"}, 21, -1, 2, 18, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1259, {"relrefs"}, 21, -1, 2, 19, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \ { 1259, {"relfkeys"}, 21, -1, 2, 19, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1259, {"relhasoids"}, 16, -1, 1, 20, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1259, {"relrefs"}, 21, -1, 2, 20, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1259, {"relhaspkey"}, 16, -1, 1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1259, {"relhasoids"}, 16, -1, 1, 21, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1259, {"relhasrules"}, 16, -1, 1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1259, {"relhaspkey"}, 16, -1, 1, 22, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1259, {"relhassubclass"},16, -1, 1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \ { 1259, {"relhasrules"}, 16, -1, 1, 23, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1259, {"relacl"}, 1034, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 } { 1259, {"relhassubclass"},16, -1, 1, 24, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1259, {"relacl"}, 1034, -1, -1, 25, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
DATA(insert ( 1259 relname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0)); DATA(insert ( 1259 relname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0));
DATA(insert ( 1259 relnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 relnamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0));
@ -467,24 +467,25 @@ DATA(insert ( 1259 reltype 26 -1 4 3 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 relowner 23 -1 4 4 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 relowner 23 -1 4 4 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 relam 26 -1 4 5 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 relam 26 -1 4 5 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 relfilenode 26 -1 4 6 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 relfilenode 26 -1 4 6 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 relpages 23 -1 4 7 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 reltablespace 26 -1 4 7 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 reltuples 700 -1 4 8 0 -1 -1 f p i t f f t 0)); DATA(insert ( 1259 relpages 23 -1 4 8 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 reltoastrelid 26 -1 4 9 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 reltuples 700 -1 4 9 0 -1 -1 f p i t f f t 0));
DATA(insert ( 1259 reltoastidxid 26 -1 4 10 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 reltoastrelid 26 -1 4 10 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 relhasindex 16 -1 1 11 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 reltoastidxid 26 -1 4 11 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 relisshared 16 -1 1 12 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 relhasindex 16 -1 1 12 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1259 relkind 18 -1 1 13 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 relisshared 16 -1 1 13 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1259 relnatts 21 -1 2 14 0 -1 -1 t p s t f f t 0)); DATA(insert ( 1259 relkind 18 -1 1 14 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1259 relchecks 21 -1 2 15 0 -1 -1 t p s t f f t 0)); DATA(insert ( 1259 relnatts 21 -1 2 15 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1259 reltriggers 21 -1 2 16 0 -1 -1 t p s t f f t 0)); DATA(insert ( 1259 relchecks 21 -1 2 16 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1259 relukeys 21 -1 2 17 0 -1 -1 t p s t f f t 0)); DATA(insert ( 1259 reltriggers 21 -1 2 17 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1259 relfkeys 21 -1 2 18 0 -1 -1 t p s t f f t 0)); DATA(insert ( 1259 relukeys 21 -1 2 18 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1259 relrefs 21 -1 2 19 0 -1 -1 t p s t f f t 0)); DATA(insert ( 1259 relfkeys 21 -1 2 19 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1259 relhasoids 16 -1 1 20 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 relrefs 21 -1 2 20 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1259 relhaspkey 16 -1 1 21 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 relhasoids 16 -1 1 21 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1259 relhasrules 16 -1 1 22 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 relhaspkey 16 -1 1 22 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1259 relhassubclass 16 -1 1 23 0 -1 -1 t p c t f f t 0)); DATA(insert ( 1259 relhasrules 16 -1 1 23 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1259 relacl 1034 -1 -1 24 1 -1 -1 f x i f f f t 0)); DATA(insert ( 1259 relhassubclass 16 -1 1 24 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1259 relacl 1034 -1 -1 25 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1259 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0)); DATA(insert ( 1259 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0));
DATA(insert ( 1259 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));
@ -493,6 +494,23 @@ DATA(insert ( 1259 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0)); DATA(insert ( 1259 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
/* ----------------
* pg_tablespace
* ----------------
*/
DATA(insert ( 1213 spcname 19 -1 NAMEDATALEN 1 0 -1 -1 f p i t f f t 0));
DATA(insert ( 1213 spcowner 23 -1 4 2 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1213 spclocation 25 -1 -1 3 0 -1 -1 f x i t f f t 0));
DATA(insert ( 1213 spcacl 1034 -1 -1 4 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1213 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0));
DATA(insert ( 1213 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1213 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1213 cmin 29 0 4 -4 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1213 xmax 28 0 4 -5 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1213 cmax 29 0 4 -6 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1213 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
/* ---------------- /* ----------------
* pg_xactlock - this is not a real relation, but is a placeholder * pg_xactlock - this is not a real relation, but is a placeholder
* to allow a relation OID to be used for transaction * to allow a relation OID to be used for transaction

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.81 2004/04/01 21:28:45 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.82 2004/06/18 06:14:06 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -48,6 +48,7 @@ CATALOG(pg_class) BOOTSTRAP
int4 relowner; /* class owner */ int4 relowner; /* class owner */
Oid relam; /* index access method; 0 if not an index */ Oid relam; /* index access method; 0 if not an index */
Oid relfilenode; /* identifier of physical storage file */ Oid relfilenode; /* identifier of physical storage file */
Oid reltablespace; /* identifier of table space for relation */
int4 relpages; /* # of blocks (not always up-to-date) */ int4 relpages; /* # of blocks (not always up-to-date) */
float4 reltuples; /* # of tuples (not always up-to-date) */ float4 reltuples; /* # of tuples (not always up-to-date) */
Oid reltoastrelid; /* OID of toast table; 0 if none */ Oid reltoastrelid; /* OID of toast table; 0 if none */
@ -100,32 +101,33 @@ typedef FormData_pg_class *Form_pg_class;
* relacl field. This is a kluge. * relacl field. This is a kluge.
* ---------------- * ----------------
*/ */
#define Natts_pg_class_fixed 23 #define Natts_pg_class_fixed 24
#define Natts_pg_class 24 #define Natts_pg_class 25
#define Anum_pg_class_relname 1 #define Anum_pg_class_relname 1
#define Anum_pg_class_relnamespace 2 #define Anum_pg_class_relnamespace 2
#define Anum_pg_class_reltype 3 #define Anum_pg_class_reltype 3
#define Anum_pg_class_relowner 4 #define Anum_pg_class_relowner 4
#define Anum_pg_class_relam 5 #define Anum_pg_class_relam 5
#define Anum_pg_class_relfilenode 6 #define Anum_pg_class_relfilenode 6
#define Anum_pg_class_relpages 7 #define Anum_pg_class_reltablespace 7
#define Anum_pg_class_reltuples 8 #define Anum_pg_class_relpages 8
#define Anum_pg_class_reltoastrelid 9 #define Anum_pg_class_reltuples 9
#define Anum_pg_class_reltoastidxid 10 #define Anum_pg_class_reltoastrelid 10
#define Anum_pg_class_relhasindex 11 #define Anum_pg_class_reltoastidxid 11
#define Anum_pg_class_relisshared 12 #define Anum_pg_class_relhasindex 12
#define Anum_pg_class_relkind 13 #define Anum_pg_class_relisshared 13
#define Anum_pg_class_relnatts 14 #define Anum_pg_class_relkind 14
#define Anum_pg_class_relchecks 15 #define Anum_pg_class_relnatts 15
#define Anum_pg_class_reltriggers 16 #define Anum_pg_class_relchecks 16
#define Anum_pg_class_relukeys 17 #define Anum_pg_class_reltriggers 17
#define Anum_pg_class_relfkeys 18 #define Anum_pg_class_relukeys 18
#define Anum_pg_class_relrefs 19 #define Anum_pg_class_relfkeys 19
#define Anum_pg_class_relhasoids 20 #define Anum_pg_class_relrefs 20
#define Anum_pg_class_relhaspkey 21 #define Anum_pg_class_relhasoids 21
#define Anum_pg_class_relhasrules 22 #define Anum_pg_class_relhaspkey 22
#define Anum_pg_class_relhassubclass 23 #define Anum_pg_class_relhasrules 23
#define Anum_pg_class_relacl 24 #define Anum_pg_class_relhassubclass 24
#define Anum_pg_class_relacl 25
/* ---------------- /* ----------------
* initial contents of pg_class * initial contents of pg_class
@ -134,21 +136,23 @@ typedef FormData_pg_class *Form_pg_class;
* ---------------- * ----------------
*/ */
DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 f f r 23 0 0 0 0 0 t f f f _null_ )); DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 23 0 0 0 0 0 t f f f _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 f f r 17 0 0 0 0 0 f f f f _null_ )); DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 0 0 0 0 f f f f _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 f f r 16 0 0 0 0 0 t f f f _null_ )); DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 16 0 0 0 0 0 t f f f _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 f f r 24 0 0 0 0 0 t f f f _null_ )); DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 25 0 0 0 0 0 t f f f _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1260 ( pg_shadow PGNSP 86 PGUID 0 1260 0 0 0 0 f t r 8 0 0 0 0 0 f f f f _null_ )); DATA(insert OID = 1260 ( pg_shadow PGNSP 86 PGUID 0 1260 1664 0 0 0 0 f t r 8 0 0 0 0 0 f f f f _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1261 ( pg_group PGNSP 87 PGUID 0 1261 0 0 0 0 f t r 3 0 0 0 0 0 f f f f _null_ )); DATA(insert OID = 1261 ( pg_group PGNSP 87 PGUID 0 1261 1664 0 0 0 0 f t r 3 0 0 0 0 0 f f f f _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 1262 ( pg_database PGNSP 88 PGUID 0 1262 0 0 0 0 f t r 11 0 0 0 0 0 t f f f _null_ )); DATA(insert OID = 1262 ( pg_database PGNSP 88 PGUID 0 1262 1664 0 0 0 0 f t r 11 0 0 0 0 0 t f f f _null_ ));
DESCR(""); DESCR("");
DATA(insert OID = 376 ( pg_xactlock PGNSP 0 PGUID 0 0 0 0 0 0 f t s 1 0 0 0 0 0 f f f f _null_ )); DATA(insert OID = 1213 ( pg_tablespace PGNSP 90 PGUID 0 1213 1664 0 0 0 0 f t r 4 0 0 0 0 0 t f f f _null_ ));
DESCR("");
DATA(insert OID = 376 ( pg_xactlock PGNSP 0 PGUID 0 0 1664 0 0 0 0 f t s 1 0 0 0 0 0 f f f f _null_ ));
DESCR(""); DESCR("");
#define RelOid_pg_type 1247 #define RelOid_pg_type 1247
@ -158,6 +162,7 @@ DESCR("");
#define RelOid_pg_shadow 1260 #define RelOid_pg_shadow 1260
#define RelOid_pg_group 1261 #define RelOid_pg_group 1261
#define RelOid_pg_database 1262 #define RelOid_pg_database 1262
#define RelOid_pg_tablespace 1213
/* Xact lock pseudo-table */ /* Xact lock pseudo-table */
#define XactLockTableId 376 #define XactLockTableId 376

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.31 2004/02/10 01:55:26 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_database.h,v 1.32 2004/06/18 06:14:06 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -41,7 +41,7 @@ CATALOG(pg_database) BOOTSTRAP BKI_SHARED_RELATION
Oid datlastsysoid; /* highest OID to consider a system OID */ Oid datlastsysoid; /* highest OID to consider a system OID */
TransactionId datvacuumxid; /* all XIDs before this are vacuumed */ TransactionId datvacuumxid; /* all XIDs before this are vacuumed */
TransactionId datfrozenxid; /* all XIDs before this are frozen */ TransactionId datfrozenxid; /* all XIDs before this are frozen */
text datpath; /* default database location (VAR LENGTH) */ Oid dattablespace; /* default table space for this DB */
text datconfig[1]; /* database-specific GUC (VAR LENGTH) */ text datconfig[1]; /* database-specific GUC (VAR LENGTH) */
aclitem datacl[1]; /* access permissions (VAR LENGTH) */ aclitem datacl[1]; /* access permissions (VAR LENGTH) */
} FormData_pg_database; } FormData_pg_database;
@ -66,11 +66,11 @@ typedef FormData_pg_database *Form_pg_database;
#define Anum_pg_database_datlastsysoid 6 #define Anum_pg_database_datlastsysoid 6
#define Anum_pg_database_datvacuumxid 7 #define Anum_pg_database_datvacuumxid 7
#define Anum_pg_database_datfrozenxid 8 #define Anum_pg_database_datfrozenxid 8
#define Anum_pg_database_datpath 9 #define Anum_pg_database_dattablespace 9
#define Anum_pg_database_datconfig 10 #define Anum_pg_database_datconfig 10
#define Anum_pg_database_datacl 11 #define Anum_pg_database_datacl 11
DATA(insert OID = 1 ( template1 PGUID ENCODING t t 0 0 0 "" _null_ _null_ )); DATA(insert OID = 1 ( template1 PGUID ENCODING t t 0 0 0 1663 _null_ _null_ ));
DESCR("Default template database"); DESCR("Default template database");
#define TemplateDbOid 1 #define TemplateDbOid 1

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_namespace.h,v 1.11 2003/11/29 22:40:58 pgsql Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_namespace.h,v 1.12 2004/06/18 06:14:06 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -40,6 +40,7 @@ CATALOG(pg_namespace)
{ {
NameData nspname; NameData nspname;
int4 nspowner; int4 nspowner;
Oid nsptablespace; /* default table space for name space */
aclitem nspacl[1]; /* VARIABLE LENGTH FIELD */ aclitem nspacl[1]; /* VARIABLE LENGTH FIELD */
} FormData_pg_namespace; } FormData_pg_namespace;
@ -55,10 +56,11 @@ typedef FormData_pg_namespace *Form_pg_namespace;
* ---------------- * ----------------
*/ */
#define Natts_pg_namespace 3 #define Natts_pg_namespace 4
#define Anum_pg_namespace_nspname 1 #define Anum_pg_namespace_nspname 1
#define Anum_pg_namespace_nspowner 2 #define Anum_pg_namespace_nspowner 2
#define Anum_pg_namespace_nspacl 3 #define Anum_pg_namespace_nsptablespace 3
#define Anum_pg_namespace_nspacl 4
/* ---------------- /* ----------------
@ -66,13 +68,13 @@ typedef FormData_pg_namespace *Form_pg_namespace;
* --------------- * ---------------
*/ */
DATA(insert OID = 11 ( "pg_catalog" PGUID _null_ )); DATA(insert OID = 11 ( "pg_catalog" PGUID 0 _null_ ));
DESCR("System catalog schema"); DESCR("System catalog schema");
#define PG_CATALOG_NAMESPACE 11 #define PG_CATALOG_NAMESPACE 11
DATA(insert OID = 99 ( "pg_toast" PGUID _null_ )); DATA(insert OID = 99 ( "pg_toast" PGUID 0 _null_ ));
DESCR("Reserved schema for TOAST tables"); DESCR("Reserved schema for TOAST tables");
#define PG_TOAST_NAMESPACE 99 #define PG_TOAST_NAMESPACE 99
DATA(insert OID = 2200 ( "public" PGUID _null_ )); DATA(insert OID = 2200 ( "public" PGUID 0 _null_ ));
DESCR("Standard public schema"); DESCR("Standard public schema");
#define PG_PUBLIC_NAMESPACE 2200 #define PG_PUBLIC_NAMESPACE 2200
@ -80,6 +82,7 @@ DESCR("Standard public schema");
/* /*
* prototypes for functions in pg_namespace.c * prototypes for functions in pg_namespace.c
*/ */
extern Oid NamespaceCreate(const char *nspName, int32 ownerSysId); extern Oid NamespaceCreate(const char *nspName, int32 ownerSysId,
Oid nspTablespace);
#endif /* PG_NAMESPACE_H */ #endif /* PG_NAMESPACE_H */

View File

@ -0,0 +1,66 @@
/*-------------------------------------------------------------------------
*
* pg_tablespace.h
* definition of the system "tablespace" relation (pg_tablespace)
* along with the relation's initial contents.
*
*
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_tablespace.h,v 1.1 2004/06/18 06:14:06 tgl Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
* information from the DATA() statements.
*
*-------------------------------------------------------------------------
*/
#ifndef PG_TABLESPACE_H
#define PG_TABLESPACE_H
/* ----------------
* postgres.h contains the system type definitions and the
* CATALOG(), BOOTSTRAP and DATA() sugar words so this file
* can be read by both genbki.sh and the C compiler.
* ----------------
*/
/* ----------------
* pg_tablespace definition. cpp turns this into
* typedef struct FormData_pg_tablespace
* ----------------
*/
CATALOG(pg_tablespace) BOOTSTRAP BKI_SHARED_RELATION
{
NameData spcname; /* tablespace name */
int4 spcowner; /* sysid of owner */
text spclocation; /* physical location (VAR LENGTH) */
aclitem spcacl[1]; /* access permissions (VAR LENGTH) */
} FormData_pg_tablespace;
/* ----------------
* Form_pg_tablespace corresponds to a pointer to a tuple with
* the format of pg_tablespace relation.
* ----------------
*/
typedef FormData_pg_tablespace *Form_pg_tablespace;
/* ----------------
* compiler constants for pg_tablespace
* ----------------
*/
#define Natts_pg_tablespace 4
#define Anum_pg_tablespace_spcname 1
#define Anum_pg_tablespace_spcowner 2
#define Anum_pg_tablespace_spclocation 3
#define Anum_pg_tablespace_spcacl 4
DATA(insert OID = 1663 ( default PGUID "" _null_ ));
DATA(insert OID = 1664 ( global PGUID "" _null_ ));
#define DEFAULTTABLESPACE_OID 1663
#define GLOBALTABLESPACE_OID 1664
#endif /* PG_TABLESPACE_H */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.153 2004/06/06 19:07:01 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_type.h,v 1.154 2004/06/18 06:14:06 tgl Exp $
* *
* NOTES * NOTES
* the genbki.sh script reads this file and generates .bki * the genbki.sh script reads this file and generates .bki
@ -304,13 +304,14 @@ DATA(insert OID = 30 ( oidvector PGNSP PGUID INDEX_MAX_KEYS*4 f b t \054 0 26
DESCR("array of INDEX_MAX_KEYS oids, used in system tables"); DESCR("array of INDEX_MAX_KEYS oids, used in system tables");
#define OIDVECTOROID 30 #define OIDVECTOROID 30
DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c t \054 1247 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 71 ( pg_type PGNSP PGUID -1 f c t \054 1247 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c t \054 1249 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 75 ( pg_attribute PGNSP PGUID -1 f c t \054 1249 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c t \054 1255 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 81 ( pg_proc PGNSP PGUID -1 f c t \054 1255 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c t \054 1259 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 83 ( pg_class PGNSP PGUID -1 f c t \054 1259 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 86 ( pg_shadow PGNSP PGUID -1 f c t \054 1260 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 86 ( pg_shadow PGNSP PGUID -1 f c t \054 1260 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 87 ( pg_group PGNSP PGUID -1 f c t \054 1261 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 87 ( pg_group PGNSP PGUID -1 f c t \054 1261 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 88 ( pg_database PGNSP PGUID -1 f c t \054 1262 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ )); DATA(insert OID = 88 ( pg_database PGNSP PGUID -1 f c t \054 1262 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
DATA(insert OID = 90 ( pg_tablespace PGNSP PGUID -1 f c t \054 1213 0 record_in record_out record_recv record_send - d x f 0 -1 0 _null_ _null_ ));
/* OIDS 100 - 199 */ /* OIDS 100 - 199 */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.57 2004/06/10 17:55:59 tgl Exp $ * $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.58 2004/06/18 06:14:08 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -21,6 +21,7 @@
extern void DefineIndex(RangeVar *heapRelation, extern void DefineIndex(RangeVar *heapRelation,
char *indexRelationName, char *indexRelationName,
char *accessMethodName, char *accessMethodName,
char *tableSpaceName,
List *attributeList, List *attributeList,
Expr *predicate, Expr *predicate,
List *rangetable, List *rangetable,

View File

@ -0,0 +1,29 @@
/*-------------------------------------------------------------------------
*
* tablespace.h
* prototypes for tablespace.c.
*
*
* Portions Copyright (c) 1996-2004, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/commands/tablespace.h,v 1.1 2004/06/18 06:14:08 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef TABLESPACE_H
#define TABLESPACE_H
#include "nodes/parsenodes.h"
extern void CreateTableSpace(CreateTableSpaceStmt *stmt);
extern void DropTableSpace(DropTableSpaceStmt *stmt);
extern void TablespaceCreateDbspace(Oid spcNode, Oid dbNode);
extern Oid get_tablespace_oid(const char *tablespacename);
extern char *get_tablespace_name(Oid spc_oid);
#endif /* TABLESPACE_H */

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.162 2004/05/29 22:48:22 tgl Exp $ * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.163 2004/06/18 06:14:10 tgl Exp $
* *
* NOTES * NOTES
* some of the information in this file should be moved to other files. * some of the information in this file should be moved to other files.
@ -150,6 +150,8 @@ extern char postgres_exec_path[];
*/ */
extern DLLIMPORT Oid MyDatabaseId; extern DLLIMPORT Oid MyDatabaseId;
extern DLLIMPORT Oid MyDatabaseTableSpace;
/* /*
* Date/Time Configuration * Date/Time Configuration
* *
@ -224,7 +226,7 @@ extern void check_stack_depth(void);
extern char *DatabasePath; extern char *DatabasePath;
/* in utils/misc/database.c */ /* in utils/misc/database.c */
extern void GetRawDatabaseInfo(const char *name, Oid *db_id, char *path); extern void GetRawDatabaseInfo(const char *name, Oid *db_id, Oid *db_tablespace);
/* now in utils/init/miscinit.c */ /* now in utils/init/miscinit.c */
extern void SetDatabasePath(const char *path); extern void SetDatabasePath(const char *path);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.157 2004/06/09 19:08:18 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.158 2004/06/18 06:14:11 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -268,6 +268,8 @@ typedef enum NodeTag
T_ExecuteStmt, T_ExecuteStmt,
T_DeallocateStmt, T_DeallocateStmt,
T_DeclareCursorStmt, T_DeclareCursorStmt,
T_CreateTableSpaceStmt,
T_DropTableSpaceStmt,
T_AlterDbOwnerStmt, T_AlterDbOwnerStmt,
T_A_Expr = 800, T_A_Expr = 800,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.258 2004/06/09 19:08:18 tgl Exp $ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.259 2004/06/18 06:14:11 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -742,6 +742,7 @@ typedef enum ObjectType
OBJECT_SCHEMA, OBJECT_SCHEMA,
OBJECT_SEQUENCE, OBJECT_SEQUENCE,
OBJECT_TABLE, OBJECT_TABLE,
OBJECT_TABLESPACE,
OBJECT_TRIGGER, OBJECT_TRIGGER,
OBJECT_TYPE, OBJECT_TYPE,
OBJECT_USER, OBJECT_USER,
@ -761,6 +762,7 @@ typedef struct CreateSchemaStmt
NodeTag type; NodeTag type;
char *schemaname; /* the name of the schema to create */ char *schemaname; /* the name of the schema to create */
char *authid; /* the owner of the created schema */ char *authid; /* the owner of the created schema */
char *tablespacename; /* default tablespace for schema, or NULL */
List *schemaElts; /* schema components (list of parsenodes) */ List *schemaElts; /* schema components (list of parsenodes) */
} CreateSchemaStmt; } CreateSchemaStmt;
@ -857,7 +859,8 @@ typedef enum GrantObjectType
ACL_OBJECT_DATABASE, /* database */ ACL_OBJECT_DATABASE, /* database */
ACL_OBJECT_FUNCTION, /* function */ ACL_OBJECT_FUNCTION, /* function */
ACL_OBJECT_LANGUAGE, /* procedural language */ ACL_OBJECT_LANGUAGE, /* procedural language */
ACL_OBJECT_NAMESPACE /* namespace */ ACL_OBJECT_NAMESPACE, /* namespace */
ACL_OBJECT_TABLESPACE /* tablespace */
} GrantObjectType; } GrantObjectType;
typedef struct GrantStmt typedef struct GrantStmt
@ -941,6 +944,7 @@ typedef struct CreateStmt
List *constraints; /* constraints (list of Constraint nodes) */ List *constraints; /* constraints (list of Constraint nodes) */
ContainsOids hasoids; /* should it have OIDs? */ ContainsOids hasoids; /* should it have OIDs? */
OnCommitAction oncommit; /* what do we do at COMMIT? */ OnCommitAction oncommit; /* what do we do at COMMIT? */
char *tablespacename; /* table space to use, or NULL */
} CreateStmt; } CreateStmt;
/* ---------- /* ----------
@ -1030,6 +1034,26 @@ typedef struct FkConstraint
bool skip_validation; /* skip validation of existing rows? */ bool skip_validation; /* skip validation of existing rows? */
} FkConstraint; } FkConstraint;
/* ----------------------
* Create/Drop Table Space Statements
* ----------------------
*/
typedef struct CreateTableSpaceStmt
{
NodeTag type;
char *tablespacename;
char *owner;
char *location;
} CreateTableSpaceStmt;
typedef struct DropTableSpaceStmt
{
NodeTag type;
char *tablespacename;
} DropTableSpaceStmt;
/* ---------------------- /* ----------------------
* Create/Drop TRIGGER Statements * Create/Drop TRIGGER Statements
* ---------------------- * ----------------------
@ -1142,6 +1166,7 @@ typedef struct CreateSeqStmt
NodeTag type; NodeTag type;
RangeVar *sequence; /* the sequence to create */ RangeVar *sequence; /* the sequence to create */
List *options; List *options;
char *tablespacename; /* tablespace, or NULL for default */
} CreateSeqStmt; } CreateSeqStmt;
typedef struct AlterSeqStmt typedef struct AlterSeqStmt
@ -1322,6 +1347,7 @@ typedef struct IndexStmt
char *idxname; /* name of new index, or NULL for default */ char *idxname; /* name of new index, or NULL for default */
RangeVar *relation; /* relation to build index on */ RangeVar *relation; /* relation to build index on */
char *accessMethod; /* name of access method (eg. btree) */ char *accessMethod; /* name of access method (eg. btree) */
char *tableSpace; /* tablespace, or NULL to use parent's */
List *indexParams; /* a list of IndexElem */ List *indexParams; /* a list of IndexElem */
Node *whereClause; /* qualification (partial-index predicate) */ Node *whereClause; /* qualification (partial-index predicate) */
List *rangetable; /* range table for qual and/or List *rangetable; /* range table for qual and/or

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/storage/buf_internals.h,v 1.70 2004/04/21 18:06:29 tgl Exp $ * $PostgreSQL: pgsql/src/include/storage/buf_internals.h,v 1.71 2004/06/18 06:14:13 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -53,7 +53,8 @@ typedef struct buftag
#define CLEAR_BUFFERTAG(a) \ #define CLEAR_BUFFERTAG(a) \
( \ ( \
(a).rnode.tblNode = InvalidOid, \ (a).rnode.spcNode = InvalidOid, \
(a).rnode.dbNode = InvalidOid, \
(a).rnode.relNode = InvalidOid, \ (a).rnode.relNode = InvalidOid, \
(a).blockNum = InvalidBlockNumber \ (a).blockNum = InvalidBlockNumber \
) )

View File

@ -1,22 +1,60 @@
/*-------------------------------------------------------------------------
*
* relfilenode.h
* Physical access information for relations.
*
*
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/storage/relfilenode.h,v 1.9 2004/06/18 06:14:13 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef RELFILENODE_H #ifndef RELFILENODE_H
#define RELFILENODE_H #define RELFILENODE_H
/* /*
* This is all what we need to know to find relation file. * RelFileNode must provide all that we need to know to physically access
* tblNode is identificator of tablespace and because of * a relation.
* currently our tablespaces are equal to databases this is *
* database OID. relNode is currently relation OID on creation * spcNode identifies the tablespace of the relation. It corresponds to
* but may be changed later if required. relNode is stored in * pg_tablespace.oid.
* pg_class.relfilenode. *
* dbNode identifies the database of the relation. It is zero for
* "shared" relations (those common to all databases of a cluster).
* Nonzero dbNode values correspond to pg_database.oid.
*
* relNode identifies the specific relation. relNode corresponds to
* pg_class.relfilenode (NOT pg_class.oid, because we need to be able
* to assign new physical files to relations in some situations).
* Notice that relNode is only unique within a particular database.
*
* Note: spcNode must be GLOBALTABLESPACE_OID if and only if dbNode is
* zero. We support shared relations only in the "global" tablespace.
*
* Note: in pg_class we allow reltablespace == 0 to denote that the
* relation is stored in its database's "default" tablespace (as
* identified by pg_database.dattablespace). However this shorthand
* is NOT allowed in RelFileNode structs --- the real tablespace ID
* must be supplied when setting spcNode.
*/ */
typedef struct RelFileNode typedef struct RelFileNode
{ {
Oid tblNode; /* tablespace */ Oid spcNode; /* tablespace */
Oid dbNode; /* database */
Oid relNode; /* relation */ Oid relNode; /* relation */
} RelFileNode; } RelFileNode;
/*
* Note: RelFileNodeEquals compares relNode first since that is most likely
* to be different in two unequal RelFileNodes. It is probably redundant
* to compare spcNode if the other two fields are found equal, but do it
* anyway to be sure.
*/
#define RelFileNodeEquals(node1, node2) \ #define RelFileNodeEquals(node1, node2) \
((node1).relNode == (node2).relNode && \ ((node1).relNode == (node2).relNode && \
(node1).tblNode == (node2).tblNode) (node1).dbNode == (node2).dbNode && \
(node1).spcNode == (node2).spcNode)
#endif /* RELFILENODE_H */ #endif /* RELFILENODE_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.70 2004/06/01 21:49:22 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.71 2004/06/18 06:14:21 tgl Exp $
* *
* NOTES * NOTES
* An ACL array is simply an array of AclItems, representing the union * An ACL array is simply an array of AclItems, representing the union
@ -184,6 +184,7 @@ typedef ArrayType IdList;
#define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE) #define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE)
#define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE) #define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE)
#define ACL_ALL_RIGHTS_NAMESPACE (ACL_USAGE|ACL_CREATE) #define ACL_ALL_RIGHTS_NAMESPACE (ACL_USAGE|ACL_CREATE)
#define ACL_ALL_RIGHTS_TABLESPACE (ACL_CREATE)
/* operation codes for pg_*_aclmask */ /* operation codes for pg_*_aclmask */
typedef enum typedef enum
@ -213,6 +214,7 @@ typedef enum AclObjectKind
ACL_KIND_NAMESPACE, /* pg_namespace */ ACL_KIND_NAMESPACE, /* pg_namespace */
ACL_KIND_OPCLASS, /* pg_opclass */ ACL_KIND_OPCLASS, /* pg_opclass */
ACL_KIND_CONVERSION, /* pg_conversion */ ACL_KIND_CONVERSION, /* pg_conversion */
ACL_KIND_TABLESPACE, /* pg_tablespace */
MAX_ACL_KIND /* MUST BE LAST */ MAX_ACL_KIND /* MUST BE LAST */
} AclObjectKind; } AclObjectKind;
@ -254,12 +256,15 @@ extern AclMode pg_language_aclmask(Oid lang_oid, AclId userid,
AclMode mask, AclMaskHow how); AclMode mask, AclMaskHow how);
extern AclMode pg_namespace_aclmask(Oid nsp_oid, AclId userid, extern AclMode pg_namespace_aclmask(Oid nsp_oid, AclId userid,
AclMode mask, AclMaskHow how); AclMode mask, AclMaskHow how);
extern AclMode pg_tablespace_aclmask(Oid spc_oid, AclId userid,
AclMode mask, AclMaskHow how);
extern AclResult pg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode); extern AclResult pg_class_aclcheck(Oid table_oid, AclId userid, AclMode mode);
extern AclResult pg_database_aclcheck(Oid db_oid, AclId userid, AclMode mode); extern AclResult pg_database_aclcheck(Oid db_oid, AclId userid, AclMode mode);
extern AclResult pg_proc_aclcheck(Oid proc_oid, AclId userid, AclMode mode); extern AclResult pg_proc_aclcheck(Oid proc_oid, AclId userid, AclMode mode);
extern AclResult pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode); extern AclResult pg_language_aclcheck(Oid lang_oid, AclId userid, AclMode mode);
extern AclResult pg_namespace_aclcheck(Oid nsp_oid, AclId userid, AclMode mode); extern AclResult pg_namespace_aclcheck(Oid nsp_oid, AclId userid, AclMode mode);
extern AclResult pg_tablespace_aclcheck(Oid spc_oid, AclId userid, AclMode mode);
extern void aclcheck_error(AclResult aclerr, AclObjectKind objectkind, extern void aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
const char *objectname); const char *objectname);
@ -270,6 +275,7 @@ extern bool pg_type_ownercheck(Oid type_oid, AclId userid);
extern bool pg_oper_ownercheck(Oid oper_oid, AclId userid); extern bool pg_oper_ownercheck(Oid oper_oid, AclId userid);
extern bool pg_proc_ownercheck(Oid proc_oid, AclId userid); extern bool pg_proc_ownercheck(Oid proc_oid, AclId userid);
extern bool pg_namespace_ownercheck(Oid nsp_oid, AclId userid); extern bool pg_namespace_ownercheck(Oid nsp_oid, AclId userid);
extern bool pg_tablespace_ownercheck(Oid spc_oid, AclId userid);
extern bool pg_opclass_ownercheck(Oid opc_oid, AclId userid); extern bool pg_opclass_ownercheck(Oid opc_oid, AclId userid);
extern bool pg_database_ownercheck(Oid db_oid, AclId userid); extern bool pg_database_ownercheck(Oid db_oid, AclId userid);
extern bool pg_conversion_ownercheck(Oid conv_oid, AclId userid); extern bool pg_conversion_ownercheck(Oid conv_oid, AclId userid);

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.87 2004/06/06 00:41:28 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/lsyscache.h,v 1.88 2004/06/18 06:14:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -63,6 +63,7 @@ extern Oid get_relname_relid(const char *relname, Oid relnamespace);
extern Oid get_system_catalog_relid(const char *catname); extern Oid get_system_catalog_relid(const char *catname);
extern char *get_rel_name(Oid relid); extern char *get_rel_name(Oid relid);
extern Oid get_rel_namespace(Oid relid); extern Oid get_rel_namespace(Oid relid);
extern Oid get_rel_tablespace(Oid relid);
extern Oid get_rel_type_id(Oid relid); extern Oid get_rel_type_id(Oid relid);
extern char get_rel_relkind(Oid relid); extern char get_rel_relkind(Oid relid);
extern bool get_typisdefined(Oid typid); extern bool get_typisdefined(Oid typid);
@ -105,6 +106,7 @@ extern void free_attstatsslot(Oid atttype,
Datum *values, int nvalues, Datum *values, int nvalues,
float4 *numbers, int nnumbers); float4 *numbers, int nnumbers);
extern char *get_namespace_name(Oid nspid); extern char *get_namespace_name(Oid nspid);
extern Oid get_namespace_tablespace(Oid nspid);
extern int32 get_usesysid(const char *username); extern int32 get_usesysid(const char *username);
#define is_array_type(typid) (get_element_type(typid) != InvalidOid) #define is_array_type(typid) (get_element_type(typid) != InvalidOid)

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/utils/relcache.h,v 1.39 2004/02/10 01:55:27 tgl Exp $ * $PostgreSQL: pgsql/src/include/utils/relcache.h,v 1.40 2004/06/18 06:14:21 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -51,8 +51,9 @@ extern void RelationCacheInitializePhase3(void);
extern Relation RelationBuildLocalRelation(const char *relname, extern Relation RelationBuildLocalRelation(const char *relname,
Oid relnamespace, Oid relnamespace,
TupleDesc tupDesc, TupleDesc tupDesc,
Oid relid, Oid dbid, Oid relid,
RelFileNode rnode, Oid reltablespace,
bool shared_relation,
bool nailit); bool nailit);
/* /*

View File

@ -7,7 +7,7 @@
# #
# #
# IDENTIFICATION # IDENTIFICATION
# $PostgreSQL: pgsql/src/test/regress/GNUmakefile,v 1.46 2004/03/03 04:22:47 momjian Exp $ # $PostgreSQL: pgsql/src/test/regress/GNUmakefile,v 1.47 2004/06/18 06:14:25 tgl Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -67,7 +67,7 @@ all: $(DLOBJS)
# Build test input and expected files # Build test input and expected files
file_list := copy create_function_1 create_function_2 misc constraints file_list := copy create_function_1 create_function_2 misc constraints tablespace
input_files := $(foreach file, $(file_list), sql/$(file).sql) input_files := $(foreach file, $(file_list), sql/$(file).sql)
output_files := $(foreach file, $(file_list), expected/$(file).out) output_files := $(foreach file, $(file_list), expected/$(file).out)
@ -81,10 +81,13 @@ abs_srcdir := $(shell cd $(srcdir) && pwd -W)
abs_builddir := $(shell pwd -W) abs_builddir := $(shell pwd -W)
endif endif
testtablespace := $(abs_builddir)/testtablespace
define sed-command define sed-command
sed -e 's,@abs_srcdir@,$(abs_srcdir),g' \ sed -e 's,@abs_srcdir@,$(abs_srcdir),g' \
-e 's,@abs_builddir@,$(abs_builddir),g' \ -e 's,@abs_builddir@,$(abs_builddir),g' \
-e 's,@testtablespace@,$(testtablespace),g' \
-e 's/@DLSUFFIX@/$(DLSUFFIX)/g' $< >$@ -e 's/@DLSUFFIX@/$(DLSUFFIX)/g' $< >$@
endef endef
@ -125,9 +128,13 @@ all-spi:
## ##
check: all check: all
-rm -rf ./testtablespace
mkdir ./testtablespace
$(SHELL) ./pg_regress --temp-install --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) $(MAXCONNOPT) $(SHELL) ./pg_regress --temp-install --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) $(MAXCONNOPT)
installcheck: all installcheck: all
-rm -rf ./testtablespace
mkdir ./testtablespace
$(SHELL) ./pg_regress --schedule=$(srcdir)/serial_schedule --multibyte=$(MULTIBYTE) $(SHELL) ./pg_regress --schedule=$(srcdir)/serial_schedule --multibyte=$(MULTIBYTE)
@ -152,6 +159,7 @@ clean distclean maintainer-clean:
$(MAKE) -C $(contribdir)/spi clean $(MAKE) -C $(contribdir)/spi clean
rm -f $(output_files) $(input_files) $(DLOBJS) regress.o pg_regress rm -f $(output_files) $(input_files) $(DLOBJS) regress.o pg_regress
# things created by various check targets # things created by various check targets
rm -rf testtablespace
rm -rf results tmp_check log rm -rf results tmp_check log
rm -f regression.diffs regression.out regress.out run_check.out rm -f regression.diffs regression.out regress.out run_check.out
ifeq ($(PORTNAME), cygwin) ifeq ($(PORTNAME), cygwin)

View File

@ -56,13 +56,14 @@ SELECT relname, relhasindex
pg_rewrite | t pg_rewrite | t
pg_shadow | t pg_shadow | t
pg_statistic | t pg_statistic | t
pg_tablespace | t
pg_trigger | t pg_trigger | t
pg_type | t pg_type | t
road | t road | t
shighway | t shighway | t
tenk1 | t tenk1 | t
tenk2 | t tenk2 | t
(52 rows) (53 rows)
-- --
-- another sanity check: every system catalog that has OIDs should have -- another sanity check: every system catalog that has OIDs should have

View File

@ -0,0 +1,36 @@
-- create a tablespace we can use
CREATE TABLESPACE testspace LOCATION '@testtablespace@';
-- create a schema in the tablespace
CREATE SCHEMA testschema TABLESPACE testspace;
-- sanity check
SELECT nspname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_namespace n
where n.nsptablespace = t.oid and n.nspname = 'testschema';
-- try a table
CREATE TABLE testschema.foo (i int);
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'foo';
INSERT INTO testschema.foo VALUES(1);
INSERT INTO testschema.foo VALUES(2);
-- index
CREATE INDEX foo_idx on testschema.foo(i);
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'foo_idx';
-- Will fail with bad path
CREATE TABLESPACE badspace LOCATION '/no/such/location';
-- No such tablespace
CREATE TABLE bar (i int) TABLESPACE nosuchspace;
-- Fail, not empty
DROP TABLESPACE testspace;
DROP SCHEMA testschema CASCADE;
-- Should succeed
DROP TABLESPACE testspace;

View File

@ -0,0 +1,45 @@
-- create a tablespace we can use
CREATE TABLESPACE testspace LOCATION '@testtablespace@';
-- create a schema in the tablespace
CREATE SCHEMA testschema TABLESPACE testspace;
-- sanity check
SELECT nspname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_namespace n
where n.nsptablespace = t.oid and n.nspname = 'testschema';
nspname | spcname
------------+-----------
testschema | testspace
(1 row)
-- try a table
CREATE TABLE testschema.foo (i int);
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'foo';
relname | spcname
---------+-----------
foo | testspace
(1 row)
INSERT INTO testschema.foo VALUES(1);
INSERT INTO testschema.foo VALUES(2);
-- index
CREATE INDEX foo_idx on testschema.foo(i);
SELECT relname, spcname FROM pg_catalog.pg_tablespace t, pg_catalog.pg_class c
where c.reltablespace = t.oid AND c.relname = 'foo_idx';
relname | spcname
---------+-----------
foo_idx | testspace
(1 row)
-- Will fail with bad path
CREATE TABLESPACE badspace LOCATION '/no/such/location';
ERROR: could not set permissions on directory "/no/such/location": No such file or directory
-- No such tablespace
CREATE TABLE bar (i int) TABLESPACE nosuchspace;
ERROR: tablespace "nosuchspace" does not exist
-- Fail, not empty
DROP TABLESPACE testspace;
ERROR: tablespace "testspace" is not empty
DROP SCHEMA testschema CASCADE;
NOTICE: drop cascades to table testschema.foo
-- Should succeed
DROP TABLESPACE testspace;

View File

@ -16,7 +16,7 @@ test: point lseg box path polygon circle date time timetz timestamp timestamptz
# Depends on point, lseg, box, path, polygon and circle # Depends on point, lseg, box, path, polygon and circle
test: geometry test: geometry
# Depends on interval, timetz, timestamp, timestamptz, reltime and abstime # Depends on interval, timetz, timestamp, timestamptz, reltime and abstime
test: horology test: horology
# ---------- # ----------
# These four each depend on the previous one # These four each depend on the previous one
@ -78,3 +78,6 @@ test: limit plpgsql copy2 temp domain rangefuncs prepare without_oid conversion
# run stats by itself because its delay may be insufficient under heavy load # run stats by itself because its delay may be insufficient under heavy load
test: stats test: stats
# run tablespace by itself
test: tablespace

View File

@ -1,4 +1,4 @@
# $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.25 2004/06/06 21:20:46 tgl Exp $ # $PostgreSQL: pgsql/src/test/regress/serial_schedule,v 1.26 2004/06/18 06:14:25 tgl Exp $
# This should probably be in an order similar to parallel_schedule. # This should probably be in an order similar to parallel_schedule.
test: boolean test: boolean
test: char test: char
@ -96,3 +96,4 @@ test: sequence
test: polymorphism test: polymorphism
test: rowtypes test: rowtypes
test: stats test: stats
test: tablespace