]> granicus.if.org Git - postgresql/commitdiff
Tablespaces. Alternate database locations are dead, long live tablespaces.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 18 Jun 2004 06:14:31 +0000 (06:14 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 18 Jun 2004 06:14:31 +0000 (06:14 +0000)
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.

94 files changed:
doc/src/sgml/catalogs.sgml
doc/src/sgml/manage-ag.sgml
doc/src/sgml/ref/allfiles.sgml
doc/src/sgml/ref/create_database.sgml
doc/src/sgml/ref/create_index.sgml
doc/src/sgml/ref/create_schema.sgml
doc/src/sgml/ref/create_sequence.sgml
doc/src/sgml/ref/create_table.sgml
doc/src/sgml/ref/create_tablespace.sgml [new file with mode: 0644]
doc/src/sgml/ref/drop_tablespace.sgml [new file with mode: 0644]
doc/src/sgml/ref/grant.sgml
doc/src/sgml/ref/psql-ref.sgml
doc/src/sgml/ref/revoke.sgml
doc/src/sgml/reference.sgml
src/backend/access/heap/heapam.c
src/backend/access/nbtree/nbtxlog.c
src/backend/access/transam/xlogutils.c
src/backend/bootstrap/bootparse.y
src/backend/catalog/Makefile
src/backend/catalog/aclchk.c
src/backend/catalog/catalog.c
src/backend/catalog/heap.c
src/backend/catalog/index.c
src/backend/catalog/namespace.c
src/backend/catalog/pg_namespace.c
src/backend/commands/Makefile
src/backend/commands/cluster.c
src/backend/commands/dbcommands.c
src/backend/commands/indexcmds.c
src/backend/commands/schemacmds.c
src/backend/commands/sequence.c
src/backend/commands/tablecmds.c
src/backend/commands/tablespace.c [new file with mode: 0644]
src/backend/commands/typecmds.c
src/backend/commands/view.c
src/backend/executor/execMain.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/backend/parser/keywords.c
src/backend/storage/buffer/bufmgr.c
src/backend/storage/buffer/localbuf.c
src/backend/storage/freespace/freespace.c
src/backend/storage/smgr/md.c
src/backend/storage/smgr/smgr.c
src/backend/tcop/utility.c
src/backend/utils/adt/acl.c
src/backend/utils/adt/ruleutils.c
src/backend/utils/cache/inval.c
src/backend/utils/cache/lsyscache.c
src/backend/utils/cache/relcache.c
src/backend/utils/init/globals.c
src/backend/utils/init/miscinit.c
src/backend/utils/init/postinit.c
src/backend/utils/misc/database.c
src/bin/initdb/initdb.c
src/bin/pg_dump/dumputils.c
src/bin/pg_dump/pg_dump.c
src/bin/pg_dump/pg_dump.h
src/bin/pg_dump/pg_dumpall.c
src/bin/psql/command.c
src/bin/psql/describe.c
src/bin/psql/describe.h
src/bin/psql/help.c
src/include/catalog/catalog.h
src/include/catalog/catname.h
src/include/catalog/catversion.h
src/include/catalog/heap.h
src/include/catalog/index.h
src/include/catalog/indexing.h
src/include/catalog/pg_attribute.h
src/include/catalog/pg_class.h
src/include/catalog/pg_database.h
src/include/catalog/pg_namespace.h
src/include/catalog/pg_tablespace.h [new file with mode: 0644]
src/include/catalog/pg_type.h
src/include/commands/defrem.h
src/include/commands/tablespace.h [new file with mode: 0644]
src/include/miscadmin.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/storage/buf_internals.h
src/include/storage/relfilenode.h
src/include/utils/acl.h
src/include/utils/lsyscache.h
src/include/utils/relcache.h
src/test/regress/GNUmakefile
src/test/regress/expected/sanity_check.out
src/test/regress/input/tablespace.source [new file with mode: 0644]
src/test/regress/output/tablespace.source [new file with mode: 0644]
src/test/regress/parallel_schedule
src/test/regress/serial_schedule

index 84ae3cb205f543b56d909a0125ac3becd92ec7a3..36695e6811f80e35344a382578dbcc7630493753 100644 (file)
@@ -1,6 +1,6 @@
 <!--
  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">
       <entry>planner statistics</entry>
      </row>
 
+     <row>
+      <entry><link linkend="catalog-pg-tablespace"><structname>pg_tablespace</structname></link></entry>
+      <entry>tablespaces within this database cluster</entry>
+     </row>
+
      <row>
       <entry><link linkend="catalog-pg-trigger"><structname>pg_trigger</structname></link></entry>
       <entry>triggers</entry>
       <entry>Name of the on-disk file of this relation; 0 if none</entry>
      </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>
       <entry><structfield>relpages</structfield></entry>
       <entry><type>int4</type></entry>
      </row>
 
      <row>
-      <entry><structfield>datpath</structfield></entry>
-      <entry><type>text</type></entry>
-      <entry></entry>
+      <entry><structfield>dattablespace</structfield></entry>
+      <entry><type>oid</type></entry>
+      <entry><literal><link linkend="catalog-pg-tablespace"><structname>pg_tablespace</structname></link>.oid</literal></entry>
       <entry>
-       If the database is stored at an alternative location then this
-       records the location.  It's either an environment variable name
-       or an absolute path, depending how it was entered.
+       The default tablespace for the database.
+       Within this database, all tables for which
+       <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>
      </row>
 
       <entry>Owner of the namespace</entry>
      </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>
       <entry><structfield>nspacl</structfield></entry>
       <entry><type>aclitem[]</type></entry>
  </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">
   <title><structname>pg_trigger</structname></title>
 
index df6d85afab1090a2fc0f8781f2ebca31cf8ac91f..34737ffd4fe9cdf9f8a61b4572665d6da0a77235 100644 (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">
@@ -298,6 +298,11 @@ ALTER DATABASE mydb SET geqo TO off;
  <sect1 id="manage-ag-alternate-locs">
   <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>
     It is possible to create a database in a location other than the
     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
     accessed and dropped like any other database.
    </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 id="manage-ag-dropdb">
index a44e21e69eca570947382d6100cdc90950421f2f..352a21c292dd88c4d80ed7157903100be9700597 100644 (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
 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 createTable        system "create_table.sgml">
 <!entity createTableAs      system "create_table_as.sgml">
+<!entity createTableSpace   system "create_tablespace.sgml">
 <!entity createTrigger      system "create_trigger.sgml">
 <!entity createType         system "create_type.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 dropSequence       system "drop_sequence.sgml">
 <!entity dropTable          system "drop_table.sgml">
+<!entity dropTableSpace     system "drop_tablespace.sgml">
 <!entity dropTrigger        system "drop_trigger.sgml">
 <!entity dropType           system "drop_type.sgml">
 <!entity dropUser           system "drop_user.sgml">
index 065ee479366af5d1606b8eae8ff4af1f900fbe19..deb76d30f5072d059ba8dae1011d3d4d9ea33339 100644 (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
 -->
 
@@ -22,9 +22,9 @@ PostgreSQL documentation
 <synopsis>
 CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
     [ [ WITH ] [ OWNER [=] <replaceable class="parameter">dbowner</replaceable> ]
-           [ LOCATION [=] '<replaceable class="parameter">dbpath</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>
  </refsynopsisdiv>
 
@@ -50,29 +50,6 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
    privilege can only create databases owned by themselves.
   </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>
    By default, the new database will be created by cloning the standard
    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
    if you wish to avoid copying
    any installation-local objects that may have been added to
-   <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.
+   <literal>template1</>.
   </para>
  </refsect1>
 
@@ -101,7 +72,7 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
-       The name of a database to create.
+        The name of a database to create.
        </para>
       </listitem>
      </varlistentry>
@@ -110,41 +81,43 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
       <listitem>
        <para>
         The name of the database user who will own the new database,
-       or <literal>DEFAULT</literal> to use the default (namely, the
-       user executing the command).
+        or <literal>DEFAULT</literal> to use the default (namely, the
+        user executing the command).
        </para>
       </listitem>
      </varlistentry>
      <varlistentry>
-      <term><replaceable class="parameter">dbpath</replaceable></term>
+      <term><replaceable class="parameter">template</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.
+        The name of the template from which to create the new database,
+        or <literal>DEFAULT</literal> to use the default template
+        (<literal>template1</literal>).
        </para>
       </listitem>
      </varlistentry>
      <varlistentry>
-      <term><replaceable class="parameter">template</replaceable></term>
+      <term><replaceable class="parameter">encoding</replaceable></term>
       <listitem>
        <para>
-        The name of the template from which to create the new database,
-       or <literal>DEFAULT</literal> to use the default template
-       (<literal>template1</literal>).
+        Character set encoding to use in the new database.  Specify
+        a string constant (e.g., <literal>'SQL_ASCII'</literal>),
+        or an integer encoding number, or <literal>DEFAULT</literal>
+        to use the default encoding. The character sets supported by the
+        <productname>PostgreSQL</productname> server are described in
+        <xref linkend="multibyte-charset-supported">.
        </para>
       </listitem>
      </varlistentry>
      <varlistentry>
-      <term><replaceable class="parameter">encoding</replaceable></term>
+      <term><replaceable class="parameter">tablespace</replaceable></term>
       <listitem>
        <para>
-    Character set encoding to use in the new database.  Specify
-       a string constant (e.g., <literal>'SQL_ASCII'</literal>),
-       or an integer encoding number, or <literal>DEFAULT</literal>
-       to use the default encoding. The character sets supported by the
-       <productname>PostgreSQL</productname> server are described in
-       <xref linkend="multibyte-charset-supported">.
+        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>
       </listitem>
      </varlistentry>
@@ -167,9 +140,7 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
    <para>
     Errors along the line of <quote>could not initialize database directory</>
     are most likely related to insufficient permissions on the data
-    directory, a full disk, or other file system problems.  When using an
-    alternate location, the user under
-    which the database server is running must have access to the location.
+    directory, a full disk, or other file system problems.
    </para>
 
    <para>
@@ -181,13 +152,6 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
     wrapper program around this command, provided for convenience.
    </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>
    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
@@ -205,24 +169,6 @@ CREATE DATABASE <replaceable class="PARAMETER">name</replaceable>
 
 <programlisting>
 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>
   </para>
  </refsect1>
index bfde61ee6c7b1e1fb0a85e37f4bdd6ff2d7c752e..93ae0c1c8165e698d295e3c3306997bf50c37ec6 100644 (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
 -->
 
@@ -22,6 +22,7 @@ PostgreSQL documentation
 <synopsis>
 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> ] [, ...] )
+    [ TABLESPACE <replaceable class="parameter">tablespace</replaceable> ]
     [ WHERE <replaceable class="parameter">predicate</replaceable> ]
 </synopsis>
  </refsynopsisdiv>
@@ -78,7 +79,7 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
 
   <para>
    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.
   </para>
 
@@ -109,11 +110,11 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
       <term><literal>UNIQUE</literal></term>
       <listitem>
        <para>
-       Causes the system to check for
-       duplicate values in the table when the index is created (if data
-       already exist) and each time data is added. Attempts to
-       insert or update data which would result in duplicate entries
-       will generate an error.
+        Causes the system to check for
+        duplicate values in the table when the index is created (if data
+        already exist) and each time data is added. Attempts to
+        insert or update data which would result in duplicate entries
+        will generate an error.
        </para>
       </listitem>
      </varlistentry>
@@ -122,9 +123,9 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
       <term><replaceable class="parameter">name</replaceable></term>
       <listitem>
        <para>
-       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
-       table.
+        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
+        table.
        </para>
       </listitem>
      </varlistentry>
@@ -133,7 +134,7 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
       <term><replaceable class="parameter">table</replaceable></term>
       <listitem>
        <para>
-       The name (possibly schema-qualified) of the table to be indexed.
+        The name (possibly schema-qualified) of the table to be indexed.
        </para>
       </listitem>
      </varlistentry>
@@ -154,7 +155,7 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
       <term><replaceable class="parameter">column</replaceable></term>
       <listitem>
        <para>
-       The name of a column of the table.
+        The name of a column of the table.
        </para>
       </listitem>
      </varlistentry>
@@ -163,10 +164,10 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
       <term><replaceable class="parameter">expression</replaceable></term>
       <listitem>
        <para>
-       An expression based on one or more columns of the table.  The
-       expression usually must be written with surrounding parentheses,
-       as shown in the syntax.  However, the parentheses may be omitted
-       if the expression has the form of a function call.
+        An expression based on one or more columns of the table.  The
+        expression usually must be written with surrounding parentheses,
+        as shown in the syntax.  However, the parentheses may be omitted
+        if the expression has the form of a function call.
        </para>
       </listitem>
      </varlistentry>
@@ -175,7 +176,17 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
       <term><replaceable class="parameter">opclass</replaceable></term>
       <listitem>
        <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>
       </listitem>
      </varlistentry>
@@ -184,10 +195,11 @@ CREATE [ UNIQUE ] INDEX <replaceable class="parameter">name</replaceable> ON <re
       <term><replaceable class="parameter">predicate</replaceable></term>
       <listitem>
        <para>
-       The constraint expression for a partial index.
+        The constraint expression for a partial index.
        </para>
       </listitem>
      </varlistentry>
+
     </variablelist>
  </refsect1>
 
@@ -260,7 +272,7 @@ SELECT * FROM points
 -->
 
  </refsect1>
+
  <refsect1>
   <title>Compatibility</title>
 
index 807f358d1f99a19e50d033e9418ae1ae81aeaf0b..8668612cc6aaa97cf273874e93bac21d196a1b6b 100644 (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
 -->
 
@@ -12,7 +12,7 @@ PostgreSQL documentation
  <refnamediv>
   <refname>CREATE SCHEMA</refname>
   <refpurpose>define a new schema</refpurpose>
- </refnamediv> 
+ </refnamediv>
 
  <indexterm zone="sql-createschema">
   <primary>CREATE SCHEMA</primary>
@@ -20,8 +20,8 @@ PostgreSQL documentation
 
  <refsynopsisdiv>
 <synopsis>
-CREATE SCHEMA <replaceable class="parameter">schemaname</replaceable> [ AUTHORIZATION <replaceable class="parameter">username</replaceable> ] [ <replaceable class="parameter">schema_element</replaceable> [ ... ] ]
-CREATE SCHEMA 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> [ TABLESPACE <replaceable class="parameter">tablespace</replaceable> ] [ <replaceable class="parameter">schema_element</replaceable> [ ... ] ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -54,7 +54,7 @@ CREATE SCHEMA AUTHORIZATION <replaceable class="parameter">username</replaceable
    all the created objects will be owned by that user.
   </para>
  </refsect1>
-  
+
  <refsect1>
   <title>Parameters</title>
 
@@ -63,8 +63,8 @@ CREATE SCHEMA AUTHORIZATION <replaceable class="parameter">username</replaceable
       <term><replaceable class="parameter">schemaname</replaceable></term>
       <listitem>
        <para>
-       The name of a schema to be created.  If this is omitted, the user name
-       is used as the schema name.
+        The name of a schema to be created.  If this is omitted, the user name
+        is used as the schema name.
        </para>
       </listitem>
      </varlistentry>
@@ -74,8 +74,19 @@ CREATE SCHEMA AUTHORIZATION <replaceable class="parameter">username</replaceable
       <listitem>
        <para>
         The name of the user who will own the schema.  If omitted,
-       defaults to the user executing the command.  Only superusers
-       may create schemas owned by users other than themselves.
+        defaults to the user executing the command.  Only superusers
+        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>
       </listitem>
      </varlistentry>
@@ -102,8 +113,10 @@ CREATE SCHEMA AUTHORIZATION <replaceable class="parameter">username</replaceable
 
   <para>
    To create a schema, the invoking user must have the
-   <literal>CREATE</> privilege for the current database.  (Of course,
-   superusers bypass this check.)
+   <literal>CREATE</> privilege for the current database.
+   Also, the <literal>TABLESPACE</> option requires having
+   <literal>CREATE</> privilege for the specified tablespace.
+   (Of course, superusers bypass these checks.)
   </para>
  </refsect1>
 
@@ -181,7 +194,8 @@ CREATE VIEW hollywood.winners AS
   <simplelist type="inline">
    <member><xref linkend="sql-alterschema" endterm="sql-alterschema-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>
 
 </refentry>
index de5fd180f765f9e1825728757f33e4d98a148497..de9fa57ee14f7fdc560354011ddb084e7df1d561 100644 (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
 -->
 
@@ -12,7 +12,7 @@ PostgreSQL documentation
  <refnamediv>
   <refname>CREATE SEQUENCE</refname>
   <refpurpose>define a new sequence generator</refpurpose>
- </refnamediv> 
+ </refnamediv>
 
  <indexterm zone="sql-createsequence">
   <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> ]
     [ 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 ]
+    [ TABLESPACE <replaceable class="parameter">tablespace</replaceable> ]
 </synopsis>
  </refsynopsisdiv>
 
@@ -193,6 +194,19 @@ SELECT * FROM <replaceable>name</replaceable>;
      </para>
     </listitem>
    </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>
  </refsect1>
 
@@ -268,7 +282,7 @@ CREATE SEQUENCE serial START 101;
    Select the next number from this sequence:
 <programlisting>
 SELECT nextval('serial');
-    
+
  nextval
 ---------
      114
index 511aacc73f3347b341e387165a0a7154005b8bbe..40462752f11adfa2cc8f16ccf4321d966abef088 100644 (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
 -->
 
@@ -28,6 +28,7 @@ CREATE [ [ GLOBAL | LOCAL ] { TEMPORARY | TEMP } ] TABLE <replaceable class="PAR
 [ INHERITS ( <replaceable>parent_table</replaceable> [, ... ] ) ]
 [ WITH OIDS | WITHOUT OIDS ]
 [ ON COMMIT { PRESERVE ROWS | DELETE ROWS | DROP } ]
+[ TABLESPACE <replaceable class="PARAMETER">tablespace</replaceable> ]
 
 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> ] }
 [ DEFERRABLE | NOT DEFERRABLE ] [ INITIALLY DEFERRED | INITIALLY IMMEDIATE ]
 </synopsis>
-  
+
  </refsynopsisdiv>
 
  <refsect1 id="SQL-CREATETABLE-description">
@@ -321,7 +322,7 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
      </para>
     </listitem>
    </varlistentry>
-   
+
    <varlistentry>
     <term><literal>UNIQUE</> (column 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>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> ]
-    [ ON DELETE <replaceable class="parameter">action</replaceable> ] 
+    [ ON DELETE <replaceable class="parameter">action</replaceable> ]
     [ ON UPDATE <replaceable class="parameter">action</replaceable> ]</literal>
     (table constraint)</term>
 
@@ -514,7 +515,7 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
      </para>
     </listitem>
    </varlistentry>
-   
+
    <varlistentry>
     <term><literal>DEFERRABLE</literal></term>
     <term><literal>NOT DEFERRABLE</literal></term>
@@ -553,7 +554,7 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
     <listitem>
      <para>
       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:
 
       <variablelist>
@@ -561,19 +562,19 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
         <term><literal>PRESERVE ROWS</literal></term>
         <listitem>
          <para>
-         No special action is taken at the ends of transactions.
-         This is the default behavior.
+          No special action is taken at the ends of transactions.
+          This is the default behavior.
          </para>
-       </listitem>
+        </listitem>
        </varlistentry>
-           
+
        <varlistentry>
         <term><literal>DELETE ROWS</literal></term>
         <listitem>
          <para>
           All rows in the temporary table will be deleted at the
           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>
         </listitem>
        </varlistentry>
@@ -583,7 +584,7 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
         <listitem>
          <para>
           The temporary table will be dropped at the end of the current
-         transaction block.
+          transaction block.
          </para>
         </listitem>
        </varlistentry>
@@ -591,8 +592,20 @@ and <replaceable class="PARAMETER">table_constraint</replaceable> is:
      </para>
     </listitem>
    </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>
- </refsect1>    
+ </refsect1>
 
  <refsect1 id="SQL-CREATETABLE-notes">
   <title>Notes</title>
@@ -696,7 +709,7 @@ CREATE TABLE films (
 );
 </programlisting>
   </para>
-  
+
   <para>
    Define a check column constraint:
 
@@ -719,7 +732,7 @@ CREATE TABLE distributors (
 );
 </programlisting>
   </para>
+
   <para>
    Define a primary key table constraint for the table
    <structname>films</>.  Primary key table constraints can be defined
@@ -749,7 +762,7 @@ CREATE TABLE distributors (
     did     integer,
     name    varchar(40),
     PRIMARY KEY(did)
-); 
+);
 </programlisting>
 
 <programlisting>
@@ -812,7 +825,7 @@ CREATE TABLE distributors (
   </para>
 
  </refsect1>
+
  <refsect1 id="SQL-CREATETABLE-compatibility">
   <title id="SQL-CREATETABLE-compatibility-title">Compatibility</title>
 
@@ -827,7 +840,7 @@ CREATE TABLE distributors (
    <para>
     Although the syntax of <literal>CREATE TEMPORARY TABLE</literal>
     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
     with empty contents) in every session that needs them.
     <productname>PostgreSQL</productname> instead
@@ -889,7 +902,7 @@ CREATE TABLE distributors (
     column, its presence is simply noise.
    </para>
   </refsect2>
-   
+
   <refsect2>
    <title>Inheritance</title>
 
@@ -923,6 +936,15 @@ CREATE TABLE distributors (
     DROP COLUMN</>, so it seems cleaner to ignore this spec restriction.
    </para>
   </refsect2>
+
+  <refsect2>
+   <title>TABLESPACE</title>
+
+   <para>
+    The <productname>PostgreSQL</productname> concept of tablespaces is not
+    standard.
+   </para>
+  </refsect2>
  </refsect1>
 
 
@@ -932,6 +954,7 @@ CREATE TABLE distributors (
   <simplelist type="inline">
    <member><xref linkend="sql-altertable" endterm="sql-altertable-title"></member>
    <member><xref linkend="sql-droptable" endterm="sql-droptable-title"></member>
+   <member><xref linkend="sql-createtablespace" endterm="sql-createtablespace-title"></member>
   </simplelist>
  </refsect1>
 </refentry>
diff --git a/doc/src/sgml/ref/create_tablespace.sgml b/doc/src/sgml/ref/create_tablespace.sgml
new file mode 100644 (file)
index 0000000..9f670a8
--- /dev/null
@@ -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:
+-->
diff --git a/doc/src/sgml/ref/drop_tablespace.sgml b/doc/src/sgml/ref/drop_tablespace.sgml
new file mode 100644 (file)
index 0000000..ba84152
--- /dev/null
@@ -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:
+-->
index 25ba6e29bd619fc12c44072825d33bd62f993af3..a6a2d4d994e3e5c760e7905994253096ad9e6843 100644 (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
 -->
 
@@ -29,6 +29,10 @@ GRANT { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] }
     ON DATABASE <replaceable>dbname</replaceable> [, ...]
     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 ] }
     ON FUNCTION <replaceable>funcname</replaceable> ([<replaceable>type</replaceable>, ...]) [, ...]
     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>
    Depending on the type of object, the initial default privileges may
    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>EXECUTE</> privilege for functions; and
    <literal>USAGE</> privilege for languages.
@@ -184,6 +188,12 @@ GRANT { { CREATE | USAGE } [,...] | ALL [ PRIVILEGES ] }
       <para>
        For databases, allows new schemas to be created within the database.
       </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>
        For schemas, allows new objects to be created within the schema.
        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.
       </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
        also met).  Essentially this allows the grantee to <quote>look up</>
        objects within the schema.
@@ -385,7 +395,7 @@ GRANT ALL PRIVILEGES ON kinds TO manuel;
 
  <refsect1 id="sql-grant-compatibility">
   <title>Compatibility</title>
-    
+
    <para>
     According to the SQL standard, the <literal>PRIVILEGES</literal>
     key word in <literal>ALL PRIVILEGES</literal> is required.  The
@@ -412,7 +422,7 @@ GRANT <replaceable class="PARAMETER">privileges</replaceable>
 
    <para>
     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.
    </para>
  </refsect1>
index dee5a60e68c0c146761552b26eac1f2f29ef8722..17ce7a2f39179fbf35746386fd1dc433e0f61dd7 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.115 2004/04/22 17:38:14 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/ref/psql-ref.sgml,v 1.116 2004/06/18 06:13:05 tgl Exp $
 PostgreSQL documentation
 -->
 
@@ -71,7 +71,7 @@ PostgreSQL documentation
       </para>
       </listitem>
     </varlistentry>
-       
+
     <varlistentry>
       <term><option>-c <replaceable class="parameter">command</replaceable></></term>
       <term><option>--command <replaceable class="parameter">command</replaceable></></term>
@@ -208,7 +208,7 @@ PostgreSQL documentation
       </para>
       </listitem>
     </varlistentry>
+
     <varlistentry>
       <term><option>-l</></term>
       <term><option>--list</></term>
@@ -287,7 +287,7 @@ PostgreSQL documentation
       </para>
       </listitem>
     </varlistentry>
+
     <varlistentry>
       <term><option>-s</></term>
       <term><option>--single-step</></term>
@@ -343,7 +343,7 @@ PostgreSQL documentation
       </para>
       </listitem>
     </varlistentry>
+
     <varlistentry>
       <term><option>-u</></term>
       <listitem>
@@ -370,7 +370,7 @@ PostgreSQL documentation
       Connect to the database as the user <replaceable
       class="parameter">username</replaceable> instead of the default.
       (You must have permission to do so, of course.)
-      </para> 
+      </para>
       </listitem>
     </varlistentry>
 
@@ -491,7 +491,7 @@ PostgreSQL documentation
     not belong to any option it will be interpreted as the database name
     (or the user name, if the database name is also given). Not all
     these options are required, defaults do apply. If you omit the host
-    name, <application>psql</> will connect via a Unix domain socket 
+    name, <application>psql</> will connect via a Unix domain socket
     to a server on the local host, or via TCP/IP to <literal>localhost</> on machines
     that don't have unix domain sockets. The default port number is compile-time determined.
     Since the database server uses the same default, you will not have
@@ -565,9 +565,9 @@ testdb=>
     </para>
 
     <para>
-    The format of a <application>psql</application> command is the backslash, 
+    The format of a <application>psql</application> command is the backslash,
     followed immediately by a command verb, then any arguments. The arguments
-    are separated from the command verb and each other by any number of 
+    are separated from the command verb and each other by any number of
     whitespace characters.
     </para>
 
@@ -629,10 +629,10 @@ testdb=>
         <term><literal>\a</literal></term>
         <listitem>
         <para>
-       If the current table output format is unaligned, it is switched to aligned.
-       If it is not unaligned, it is set to unaligned. This command is
-       kept for backwards compatibility. See <command>\pset</command> for a
-       general solution.
+        If the current table output format is unaligned, it is switched to aligned.
+        If it is not unaligned, it is set to unaligned. This command is
+        kept for backwards compatibility. See <command>\pset</command> for a
+        general solution.
         </para>
         </listitem>
       </varlistentry>
@@ -641,16 +641,16 @@ testdb=>
        <term><literal>\cd [ <replaceable>directory</replaceable> ]</literal></term>
        <listitem>
         <para>
-        Changes the current working directory to
-        <replaceable>directory</replaceable>. Without argument, changes
-        to the current user's home directory.
+         Changes the current working directory to
+         <replaceable>directory</replaceable>. Without argument, changes
+         to the current user's home directory.
         </para>
 
-       <tip>
-        <para>
-         To print your current working directory, use <literal>\!pwd</literal>.
-        </para>
-       </tip>
+        <tip>
+         <para>
+          To print your current working directory, use <literal>\!pwd</literal>.
+         </para>
+        </tip>
        </listitem>
       </varlistentry>
 
@@ -673,43 +673,43 @@ testdb=>
         <term><literal>\connect</literal> (or <literal>\c</literal>) <literal>[ <replaceable class="parameter">dbname</replaceable> [ <replaceable class="parameter">username</replaceable> ] ]</literal></term>
         <listitem>
         <para>
-       Establishes a connection to a new database and/or under a user
-       name. The previous connection is closed. If <replaceable
-       class="parameter">dbname</replaceable> is <literal>-</literal>
-       the current database name is assumed.
-       </para>
+        Establishes a connection to a new database and/or under a user
+        name. The previous connection is closed. If <replaceable
+        class="parameter">dbname</replaceable> is <literal>-</literal>
+        the current database name is assumed.
+        </para>
 
-       <para>
-       If <replaceable class="parameter">username</replaceable> is
-       omitted the current user name is assumed. </para>
+        <para>
+        If <replaceable class="parameter">username</replaceable> is
+        omitted the current user name is assumed. </para>
 
-       <para>
-       As a special rule, <command>\connect</command> without any
-       arguments will connect to the default database as the default
-       user (as you would have gotten by starting
-       <application>psql</application> without any arguments).
-       </para>
+        <para>
+        As a special rule, <command>\connect</command> without any
+        arguments will connect to the default database as the default
+        user (as you would have gotten by starting
+        <application>psql</application> without any arguments).
+        </para>
 
-       <para>
-       If the connection attempt failed (wrong user name, access
-       denied, etc.), the previous connection will be kept if and only
-       if <application>psql</application> is in interactive mode. When
-       executing a non-interactive script, processing will immediately
-       stop with an error. This distinction was chosen as a user
-       convenience against typos on the one hand, and a safety
-       mechanism that scripts are not accidentally acting on the wrong
-       database on the other hand.
-       </para>
+        <para>
+        If the connection attempt failed (wrong user name, access
+        denied, etc.), the previous connection will be kept if and only
+        if <application>psql</application> is in interactive mode. When
+        executing a non-interactive script, processing will immediately
+        stop with an error. This distinction was chosen as a user
+        convenience against typos on the one hand, and a safety
+        mechanism that scripts are not accidentally acting on the wrong
+        database on the other hand.
+        </para>
         </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>\copy <replaceable class="parameter">table</replaceable>
-       [ ( <replaceable class="parameter">column_list</replaceable> ) ]
+        [ ( <replaceable class="parameter">column_list</replaceable> ) ]
         { <literal>from</literal> | <literal>to</literal> }
-       { <replaceable class="parameter">filename</replaceable> | stdin | stdout | pstdin | pstdout }
-        [ with ] 
-            [ oids ] 
+        { <replaceable class="parameter">filename</replaceable> | stdin | stdout | pstdin | pstdout }
+        [ with ]
+            [ oids ]
             [ delimiter [ as ] '<replaceable class="parameter">character</replaceable>' ]
             [ null [ as ] '<replaceable class="parameter">string</replaceable>' ]
             [ csv [ quote [ as ] '<replaceable class="parameter">character</replaceable>' ]
@@ -729,37 +729,37 @@ testdb=>
         This means that file accessibility and privileges are those of
         the local user, not the server, and no SQL superuser
         privileges are required.
-       </para>
-
-       <para>
-       The syntax of the command is similar to that of the
-       <acronym>SQL</acronym> <xref linkend="sql-copy"
-       endterm="sql-copy-title"> command.  Note that, because of this,
-       special parsing rules apply to the <command>\copy</command>
-       command. In particular, the variable substitution rules and
-       backslash escapes do not apply.
-       </para>
-
-       <para>
-       <literal>\copy <replaceable
-       class="parameter">table</replaceable> from <replaceable
-       class="parameter">stdin | stdout</replaceable></literal>
-       reads/writes based on the command input and output respectively.
-       All rows are read from the same source that issued the command,
-       continuing until <literal>\.</literal> is read or the stream
-       reaches <acronym>EOF</>. Output is sent to the same place as
-       command output. To read/write from
-       <application>psql</application>'s standard input or output, use
-       <literal>pstdin</> or <literal>pstdout</>. This option is useful
-       for populating tables in-line within a SQL script file.
-       </para>
+        </para>
+
+        <para>
+        The syntax of the command is similar to that of the
+        <acronym>SQL</acronym> <xref linkend="sql-copy"
+        endterm="sql-copy-title"> command.  Note that, because of this,
+        special parsing rules apply to the <command>\copy</command>
+        command. In particular, the variable substitution rules and
+        backslash escapes do not apply.
+        </para>
+
+        <para>
+        <literal>\copy <replaceable
+        class="parameter">table</replaceable> from <replaceable
+        class="parameter">stdin | stdout</replaceable></literal>
+        reads/writes based on the command input and output respectively.
+        All rows are read from the same source that issued the command,
+        continuing until <literal>\.</literal> is read or the stream
+        reaches <acronym>EOF</>. Output is sent to the same place as
+        command output. To read/write from
+        <application>psql</application>'s standard input or output, use
+        <literal>pstdin</> or <literal>pstdout</>. This option is useful
+        for populating tables in-line within a SQL script file.
+        </para>
 
         <tip>
         <para>
-       This operation is not as efficient as the <acronym>SQL</acronym>
-       <command>COPY</command> command because all data must pass
-       through the client/server connection. For large
-       amounts of data the <acronym>SQL</acronym> command may be preferable.
+        This operation is not as efficient as the <acronym>SQL</acronym>
+        <command>COPY</command> command because all data must pass
+        through the client/server connection. For large
+        amounts of data the <acronym>SQL</acronym> command may be preferable.
         </para>
         </tip>
 
@@ -782,32 +782,32 @@ testdb=>
 
         <listitem>
         <para>
-       For each relation (table, view, index, or sequence) matching the
-       <replaceable class="parameter">pattern</replaceable>, show all
-       columns, their types, and any special
-       attributes such as <literal>NOT NULL</literal> or defaults, if
-       any. Associated indexes, constraints, rules, and triggers are
-       also shown, as is the view definition if the relation is a view.
-       (<quote>Matching the pattern</> is defined below.)
-       </para>
+        For each relation (table, view, index, or sequence) matching the
+        <replaceable class="parameter">pattern</replaceable>, show all
+        columns, their types, and any special
+        attributes such as <literal>NOT NULL</literal> or defaults, if
+        any. Associated indexes, constraints, rules, and triggers are
+        also shown, as is the view definition if the relation is a view.
+        (<quote>Matching the pattern</> is defined below.)
+        </para>
 
-       <para>
-       The command form <literal>\d+</literal> is identical, except that
-       more information is displayed: any comments associated with the
-       columns of the table are shown, as is the presence of OIDs in the
-       table.
-       </para>
+        <para>
+        The command form <literal>\d+</literal> is identical, except that
+        more information is displayed: any comments associated with the
+        columns of the table are shown, as is the presence of OIDs in the
+        table.
+        </para>
 
-       <note>
-       <para>
-       If <command>\d</command> is used without a
-       <replaceable class="parameter">pattern</replaceable> argument, it is
-       equivalent to <command>\dtvs</command> which will show a list of
-       all tables, views, and sequences. This is purely a convenience
-       measure.
-       </para>
-       </note>
-       </listitem>
+        <note>
+        <para>
+        If <command>\d</command> is used without a
+        <replaceable class="parameter">pattern</replaceable> argument, it is
+        equivalent to <command>\dtvs</command> which will show a list of
+        all tables, views, and sequences. This is purely a convenience
+        measure.
+        </para>
+        </note>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
@@ -824,14 +824,27 @@ testdb=>
       </varlistentry>
 
 
+      <varlistentry>
+        <term><literal>\db [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
+
+        <listitem>
+        <para>
+        Lists all available tablespaces. If <replaceable
+        class="parameter">pattern</replaceable>
+        is specified, only tablespaces whose names match the pattern are shown.
+        </para>
+        </listitem>
+      </varlistentry>
+
+
       <varlistentry>
         <term><literal>\dc [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
         <listitem>
         <para>
         Lists all available conversions between character-set encodings.
-       If <replaceable class="parameter">pattern</replaceable>
+        If <replaceable class="parameter">pattern</replaceable>
         is specified, only conversions whose names match the pattern are
-       listed.
+        listed.
         </para>
         </listitem>
       </varlistentry>
@@ -853,8 +866,8 @@ testdb=>
         <para>
         Shows the descriptions of objects matching the <replaceable
         class="parameter">pattern</replaceable>, or of all visible objects if
-       no argument is given.  But in either case, only objects that have
-       a description are listed.
+        no argument is given.  But in either case, only objects that have
+        a description are listed.
         (<quote>Object</quote> covers aggregates, functions, operators,
         types, relations (tables, views, indexes, sequences, large
         objects), rules, and triggers.) For example:
@@ -899,7 +912,7 @@ testdb=>
         return types. If <replaceable
         class="parameter">pattern</replaceable>
         is specified, only functions whose names match the pattern are shown.
-       If the form <literal>\df+</literal> is used, additional information about
+        If the form <literal>\df+</literal> is used, additional information about
         each function, including language and description, is shown.
         </para>
 
@@ -912,8 +925,8 @@ testdb=>
 
         <para>
         To reduce clutter, <literal>\df</> does not show data type I/O
-       functions.  This is implemented by ignoring functions that accept
-       or return type <type>cstring</>.
+        functions.  This is implemented by ignoring functions that accept
+        or return type <type>cstring</>.
         </para>
         </note>
 
@@ -936,36 +949,36 @@ testdb=>
       <varlistentry>
         <term><literal>\distvS [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
 
-       <listitem>
-       <para>
-       This is not the actual command name: the letters
-       <literal>i</literal>, <literal>s</literal>, <literal>t</literal>,
-       <literal>v</literal>, <literal>S</literal> stand for index,
-       sequence, table, view, and system table, respectively. You can
-       specify any or all of these letters, in any order, to obtain a
-       listing of all the matching objects.  The letter S restricts the
-       listing to system objects; without <literal>S</literal>, only
-       non-system objects are shown.  If <literal>+</literal> is appended
-       to the command name, each object is listed with its associated
-       description, if any.
-       </para>
+        <listitem>
+        <para>
+        This is not the actual command name: the letters
+        <literal>i</literal>, <literal>s</literal>, <literal>t</literal>,
+        <literal>v</literal>, <literal>S</literal> stand for index,
+        sequence, table, view, and system table, respectively. You can
+        specify any or all of these letters, in any order, to obtain a
+        listing of all the matching objects.  The letter S restricts the
+        listing to system objects; without <literal>S</literal>, only
+        non-system objects are shown.  If <literal>+</literal> is appended
+        to the command name, each object is listed with its associated
+        description, if any.
+        </para>
 
-       <para>
-       If <replaceable class="parameter">pattern</replaceable> is
-       specified, only objects whose names match the pattern are listed.
-       </para>
-       </listitem>
+        <para>
+        If <replaceable class="parameter">pattern</replaceable> is
+        specified, only objects whose names match the pattern are listed.
+        </para>
+        </listitem>
       </varlistentry>
 
 
       <varlistentry>
         <term><literal>\dl</literal></term>
-       <listitem>
-       <para>
-       This is an alias for <command>\lo_list</command>, which shows a
-       list of large objects.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        This is an alias for <command>\lo_list</command>, which shows a
+        list of large objects.
+        </para>
+        </listitem>
       </varlistentry>
 
 
@@ -988,8 +1001,8 @@ testdb=>
         <listitem>
         <para>
         Lists available operators with their operand and return types.
-       If <replaceable class="parameter">pattern</replaceable> is
-       specified, only operators whose names match the pattern are listed.
+        If <replaceable class="parameter">pattern</replaceable> is
+        specified, only operators whose names match the pattern are listed.
         </para>
         </listitem>
       </varlistentry>
@@ -997,21 +1010,21 @@ testdb=>
 
       <varlistentry>
         <term><literal>\dp [ <replaceable class="parameter">pattern</replaceable> ]</literal></term>
-       <listitem>
-       <para>
+        <listitem>
+        <para>
         Produces a list of all available tables, views and sequences with their
         associated access privileges.
-       If <replaceable class="parameter">pattern</replaceable> is
-       specified, only tables, views and sequences whose names match the pattern are listed.
-       </para>
+        If <replaceable class="parameter">pattern</replaceable> is
+        specified, only tables, views and sequences whose names match the pattern are listed.
+        </para>
 
-       <para>
-       The commands <xref linkend="SQL-GRANT"> and
-       <xref linkend="SQL-REVOKE">
-       are used to set access privileges.  See <xref linkend="SQL-GRANT">
-       for more information.
-       </para>
-       </listitem>
+        <para>
+        The commands <xref linkend="SQL-GRANT"> and
+        <xref linkend="SQL-REVOKE">
+        are used to set access privileges.  See <xref linkend="SQL-GRANT">
+        for more information.
+        </para>
+        </listitem>
       </varlistentry>
 
 
@@ -1076,7 +1089,7 @@ testdb=>
       <varlistentry>
         <term><literal>\echo <replaceable class="parameter">text</replaceable> [ ... ]</literal></term>
         <listitem>
-       <para>
+        <para>
         Prints the arguments to the standard output, separated by one
         space and followed by a newline. This can be useful to
         intersperse information in the output of scripts. For example:
@@ -1086,16 +1099,16 @@ Tue Oct 26 21:40:57 CEST 1999
 </programlisting>
         If the first argument is an unquoted <literal>-n</literal> the the trailing
         newline is not written.
-       </para>
+        </para>
 
-       <tip>
-       <para>
-       If you use the <command>\o</command> command to redirect your
-       query output you may wish to use <command>\qecho</command>
-       instead of this command.
-       </para>
-       </tip>
-       </listitem>
+        <tip>
+        <para>
+        If you use the <command>\o</command> command to redirect your
+        query output you may wish to use <command>\qecho</command>
+        instead of this command.
+        </para>
+        </tip>
+        </listitem>
       </varlistentry>
 
 
@@ -1155,13 +1168,13 @@ Tue Oct 26 21:40:57 CEST 1999
         <acronym>SQL</acronym> commands is shown.
         </para>
 
-       <note>
-       <para>
-       To simplify typing, commands that consists of several words do
-       not have to be quoted. Thus it is fine to type <userinput>\help
-       alter table</userinput>.
-       </para>
-       </note> 
+        <note>
+        <para>
+        To simplify typing, commands that consists of several words do
+        not have to be quoted. Thus it is fine to type <userinput>\help
+        alter table</userinput>.
+        </para>
+        </note>
         </listitem>
       </varlistentry>
 
@@ -1170,11 +1183,11 @@ Tue Oct 26 21:40:57 CEST 1999
         <term><literal>\H</literal></term>
         <listitem>
         <para>
-       Turns on <acronym>HTML</acronym> query output format. If the
-       <acronym>HTML</acronym> format is already on, it is switched
-       back to the default aligned text format. This command is for
-       compatibility and convenience, but see <command>\pset</command>
-       about setting other output options.
+        Turns on <acronym>HTML</acronym> query output format. If the
+        <acronym>HTML</acronym> format is already on, it is switched
+        back to the default aligned text format. This command is for
+        compatibility and convenience, but see <command>\pset</command>
+        about setting other output options.
         </para>
         </listitem>
       </varlistentry>
@@ -1188,13 +1201,13 @@ Tue Oct 26 21:40:57 CEST 1999
         class="parameter">filename</replaceable> and executes it as
         though it had been typed on the keyboard.
         </para>
-       <note>
-       <para>
-       If you want to see the lines on the screen as they are read you
-       must set the variable <varname>ECHO</varname> to
-       <literal>all</literal>.
-       </para>
-       </note>
+        <note>
+        <para>
+        If you want to see the lines on the screen as they are read you
+        must set the variable <varname>ECHO</varname> to
+        <literal>all</literal>.
+        </para>
+        </note>
         </listitem>
       </varlistentry>
 
@@ -1215,83 +1228,83 @@ Tue Oct 26 21:40:57 CEST 1999
       <varlistentry>
         <term><literal>\lo_export <replaceable class="parameter">loid</replaceable> <replaceable class="parameter">filename</replaceable></literal></term>
 
-       <listitem>
-       <para>
-       Reads the large object with <acronym>OID</acronym> <replaceable
-       class="parameter">loid</replaceable> from the database and
-       writes it to <replaceable
-       class="parameter">filename</replaceable>. Note that this is
-       subtly different from the server function
-       <function>lo_export</function>, which acts with the permissions
-       of the user that the database server runs as and on the server's
-       file system.
-       </para>
-       <tip>
-       <para>
-       Use <command>\lo_list</command> to find out the large object's
-       <acronym>OID</acronym>.
-       </para>
-       </tip>
-       </listitem>
+        <listitem>
+        <para>
+        Reads the large object with <acronym>OID</acronym> <replaceable
+        class="parameter">loid</replaceable> from the database and
+        writes it to <replaceable
+        class="parameter">filename</replaceable>. Note that this is
+        subtly different from the server function
+        <function>lo_export</function>, which acts with the permissions
+        of the user that the database server runs as and on the server's
+        file system.
+        </para>
+        <tip>
+        <para>
+        Use <command>\lo_list</command> to find out the large object's
+        <acronym>OID</acronym>.
+        </para>
+        </tip>
+        </listitem>
       </varlistentry>
 
 
       <varlistentry>
         <term><literal>\lo_import <replaceable class="parameter">filename</replaceable> [ <replaceable class="parameter">comment</replaceable> ]</literal></term>
 
-       <listitem>
-       <para>
-       Stores the file into a <productname>PostgreSQL</productname>
-       large object. Optionally, it associates the given
-       comment with the object. Example:
+        <listitem>
+        <para>
+        Stores the file into a <productname>PostgreSQL</productname>
+        large object. Optionally, it associates the given
+        comment with the object. Example:
 <programlisting>
 foo=> <userinput>\lo_import '/home/peter/pictures/photo.xcf' 'a picture of me'</userinput>
 lo_import 152801
 </programlisting>
-       The response indicates that the large object received object ID
-       152801 which one ought to remember if one wants to access the
-       object ever again. For that reason it is recommended to always
-       associate a human-readable comment with every object. Those can
-       then be seen with the <command>\lo_list</command> command.
-       </para>
+        The response indicates that the large object received object ID
+        152801 which one ought to remember if one wants to access the
+        object ever again. For that reason it is recommended to always
+        associate a human-readable comment with every object. Those can
+        then be seen with the <command>\lo_list</command> command.
+        </para>
 
-       <para>
-       Note that this command is subtly different from the server-side
-       <function>lo_import</function> because it acts as the local user
-       on the local file system, rather than the server's user and file
-       system.
-       </para>
-       </listitem>
+        <para>
+        Note that this command is subtly different from the server-side
+        <function>lo_import</function> because it acts as the local user
+        on the local file system, rather than the server's user and file
+        system.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>\lo_list</literal></term>
-       <listitem>
-       <para>
-       Shows a list of all <productname>PostgreSQL</productname>
-       large objects currently stored in the database,
-       along with any comments provided for them.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        Shows a list of all <productname>PostgreSQL</productname>
+        large objects currently stored in the database,
+        along with any comments provided for them.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>\lo_unlink <replaceable class="parameter">loid</replaceable></literal></term>
 
-       <listitem>
-       <para>
-       Deletes the large object with <acronym>OID</acronym>
-       <replaceable class="parameter">loid</replaceable> from the
-       database.
-       </para>
+        <listitem>
+        <para>
+        Deletes the large object with <acronym>OID</acronym>
+        <replaceable class="parameter">loid</replaceable> from the
+        database.
+        </para>
 
-       <tip>
-       <para>
-       Use <command>\lo_list</command> to find out the large object's
-       <acronym>OID</acronym>.
-       </para>
-       </tip>
-       </listitem>
+        <tip>
+        <para>
+        Use <command>\lo_list</command> to find out the large object's
+        <acronym>OID</acronym>.
+        </para>
+        </tip>
+        </listitem>
       </varlistentry>
 
 
@@ -1307,20 +1320,20 @@ lo_import 152801
         specified, the query output will be reset to the standard output.
         </para>
 
-       <para>
-       <quote>Query results</quote> includes all tables, command
-       responses, and notices obtained from the database server, as
-       well as output of various backslash commands that query the
-       database (such as <command>\d</command>), but not error
-       messages.
-       </para>
+        <para>
+        <quote>Query results</quote> includes all tables, command
+        responses, and notices obtained from the database server, as
+        well as output of various backslash commands that query the
+        database (such as <command>\d</command>), but not error
+        messages.
+        </para>
 
-       <tip>
-       <para>
-       To intersperse text output in between query results, use
-       <command>\qecho</command>.
-       </para>
-       </tip>
+        <tip>
+        <para>
+        To intersperse text output in between query results, use
+        <command>\qecho</command>.
+        </para>
+        </tip>
         </listitem>
       </varlistentry>
 
@@ -1338,210 +1351,210 @@ lo_import 152801
       <varlistentry>
         <term><literal>\pset <replaceable class="parameter">parameter</replaceable> [ <replaceable class="parameter">value</replaceable> ]</literal></term>
 
-       <listitem>
-       <para>
-       This command sets options affecting the output of query result
-       tables. <replaceable class="parameter">parameter</replaceable>
-       describes which option is to be set. The semantics of
-       <replaceable class="parameter">value</replaceable> depend
-       thereon.
-       </para>
-
-       <para>
-       Adjustable printing options are:
-       <variablelist>
-         <varlistentry>
-         <term><literal>format</literal></term>
-         <listitem>
-         <para>
-         Sets the output format to one of <literal>unaligned</literal>,
-         <literal>aligned</literal>, <literal>html</literal>, or
-         <literal>latex</literal>. Unique abbreviations are allowed.
-         (That would mean one letter is enough.)
-         </para>
-
-         <para>
-         <quote>Unaligned</quote> writes all columns of a row on a
-         line, separated by the currently active field separator. This
-         is intended to create output that might be intended to be read
-         in by other programs (tab-separated, comma-separated).
-         <quote>Aligned</quote> mode is the standard, human-readable,
-         nicely formatted text output that is default. The
-         <quote><acronym>HTML</acronym></quote> and
-         <quote>LaTeX</quote> modes put out tables that are intended to
-         be included in documents using the respective mark-up
-         language. They are not complete documents! (This might not be
-         so dramatic in <acronym>HTML</acronym>, but in LaTeX you must
-         have a complete document wrapper.)
-         </para>
-         </listitem>
+        <listitem>
+        <para>
+        This command sets options affecting the output of query result
+        tables. <replaceable class="parameter">parameter</replaceable>
+        describes which option is to be set. The semantics of
+        <replaceable class="parameter">value</replaceable> depend
+        thereon.
+        </para>
+
+        <para>
+        Adjustable printing options are:
+        <variablelist>
+          <varlistentry>
+          <term><literal>format</literal></term>
+          <listitem>
+          <para>
+          Sets the output format to one of <literal>unaligned</literal>,
+          <literal>aligned</literal>, <literal>html</literal>, or
+          <literal>latex</literal>. Unique abbreviations are allowed.
+          (That would mean one letter is enough.)
+          </para>
+
+          <para>
+          <quote>Unaligned</quote> writes all columns of a row on a
+          line, separated by the currently active field separator. This
+          is intended to create output that might be intended to be read
+          in by other programs (tab-separated, comma-separated).
+          <quote>Aligned</quote> mode is the standard, human-readable,
+          nicely formatted text output that is default. The
+          <quote><acronym>HTML</acronym></quote> and
+          <quote>LaTeX</quote> modes put out tables that are intended to
+          be included in documents using the respective mark-up
+          language. They are not complete documents! (This might not be
+          so dramatic in <acronym>HTML</acronym>, but in LaTeX you must
+          have a complete document wrapper.)
+          </para>
+          </listitem>
           </varlistentry>
 
-         <varlistentry>
-         <term><literal>border</literal></term>
-         <listitem>
-         <para>
-         The second argument must be a number. In general, the higher
-         the number the more borders and lines the tables will have,
-         but this depends on the particular format. In
-         <acronym>HTML</acronym> mode, this will translate directly
-         into the <literal>border=...</literal> attribute, in the
-         others only values 0 (no border), 1 (internal dividing lines),
-         and 2 (table frame) make sense.
-         </para>
-         </listitem>
-         </varlistentry>
-
-         <varlistentry>
-         <term><literal>expanded</literal> (or <literal>x</literal>)</term>
-         <listitem>
-         <para>
-         Toggles between regular and expanded format. When expanded
-         format is enabled, all output has two columns with the column
-         name on the left and the data on the right. This mode is
-         useful if the data wouldn't fit on the screen in the normal
-         <quote>horizontal</quote> mode.
-         </para>
-
-         <para>
-         Expanded mode is supported by all four output formats.
-         </para>
-         </listitem>
-         </varlistentry>
-
-         <varlistentry>
-         <term><literal>null</literal></term>
-         <listitem>
-         <para>
-         The second argument is a string that should be printed
-         whenever a column is null. The default is not to print
-         anything, which can easily be mistaken for, say, an empty
-         string. Thus, one might choose to write <literal>\pset null
-         '(null)'</literal>.
-         </para>
-         </listitem>
-         </varlistentry>
-
-         <varlistentry>
-         <term><literal>fieldsep</literal></term>
-         <listitem>
-         <para>
-         Specifies the field separator to be used in unaligned output
-         mode. That way one can create, for example, tab- or
-         comma-separated output, which other programs might prefer. To
-         set a tab as field separator, type <literal>\pset fieldsep
-         '\t'</literal>. The default field separator is
-         <literal>'|'</literal> (a vertical bar).
-         </para>
-         </listitem>
-         </varlistentry>
-
-         <varlistentry>
-         <term><literal>footer</literal></term>
-         <listitem>
-         <para>
-         Toggles the display of the default footer <literal>(x
-         rows)</literal>.
-         </para>
-         </listitem>
-         </varlistentry>
-
-         <varlistentry>
-         <term><literal>recordsep</literal></term>
-         <listitem>
-         <para>
+          <varlistentry>
+          <term><literal>border</literal></term>
+          <listitem>
+          <para>
+          The second argument must be a number. In general, the higher
+          the number the more borders and lines the tables will have,
+          but this depends on the particular format. In
+          <acronym>HTML</acronym> mode, this will translate directly
+          into the <literal>border=...</literal> attribute, in the
+          others only values 0 (no border), 1 (internal dividing lines),
+          and 2 (table frame) make sense.
+          </para>
+          </listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term><literal>expanded</literal> (or <literal>x</literal>)</term>
+          <listitem>
+          <para>
+          Toggles between regular and expanded format. When expanded
+          format is enabled, all output has two columns with the column
+          name on the left and the data on the right. This mode is
+          useful if the data wouldn't fit on the screen in the normal
+          <quote>horizontal</quote> mode.
+          </para>
+
+          <para>
+          Expanded mode is supported by all four output formats.
+          </para>
+          </listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term><literal>null</literal></term>
+          <listitem>
+          <para>
+          The second argument is a string that should be printed
+          whenever a column is null. The default is not to print
+          anything, which can easily be mistaken for, say, an empty
+          string. Thus, one might choose to write <literal>\pset null
+          '(null)'</literal>.
+          </para>
+          </listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term><literal>fieldsep</literal></term>
+          <listitem>
+          <para>
+          Specifies the field separator to be used in unaligned output
+          mode. That way one can create, for example, tab- or
+          comma-separated output, which other programs might prefer. To
+          set a tab as field separator, type <literal>\pset fieldsep
+          '\t'</literal>. The default field separator is
+          <literal>'|'</literal> (a vertical bar).
+          </para>
+          </listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term><literal>footer</literal></term>
+          <listitem>
+          <para>
+          Toggles the display of the default footer <literal>(x
+          rows)</literal>.
+          </para>
+          </listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term><literal>recordsep</literal></term>
+          <listitem>
+          <para>
           Specifies the record (line) separator to use in unaligned
           output mode. The default is a newline character.
-         </para>
-         </listitem>
-         </varlistentry>
-
-         <varlistentry>
-         <term><literal>tuples_only</literal> (or <literal>t</literal>)</term>
-         <listitem>
-         <para>
-         Toggles between tuples only and full display. Full display may
-         show extra information such as column headers, titles, and
-         various footers. In tuples only mode, only actual table data
-         is shown.
-         </para>
-         </listitem>
-         </varlistentry>
-
-         <varlistentry>
-         <term><literal>title [ <replaceable class="parameter">text</replaceable> ]</literal></term>
-         <listitem>
-         <para>
-         Sets the table title for any subsequently printed tables. This
-         can be used to give your output descriptive tags. If no
-         argument is given, the title is unset.
-         </para>
-         </listitem>
-         </varlistentry>
-
-         <varlistentry>
-         <term><literal>tableattr</literal> (or <literal>T</literal>) <literal>[ <replaceable class="parameter">text</replaceable> ]</literal></term>
-         <listitem>
-         <para>
-         Allows you to specify any attributes to be placed inside the
-         <acronym>HTML</acronym> <sgmltag>table</sgmltag> tag. This
-         could for example be <literal>cellpadding</literal> or
-         <literal>bgcolor</literal>. Note that you probably don't want
-         to specify <literal>border</literal> here, as that is already
-         taken care of by <literal>\pset border</literal>.
-         </para>
-         </listitem>
-         </varlistentry>
-
-
-         <varlistentry>
-         <term><literal>pager</literal></term>
-         <listitem>
-         <para>
-         Controls use of a pager for query and <application>psql</>
-         help output. If the environment variable <envar>PAGER</envar>
-         is set, the output is piped to the specified program.
-         Otherwise a platform-dependent default (such as
-         <filename>more</filename>) is used.
-         </para>
-
-         <para>
-         When the pager is off, the pager is not used. When the pager
-         is on, the pager is used only when appropriate, i.e. the
-         output is to a terminal and will not fit on the screen.
-         (<application>psql</> does not do a perfect job of estimating
-         when to use the pager.) <literal>\pset pager</> turns the
-         pager on and off. Pager can also be set to <literal>always</>,
-         which causes the pager to be always used.
-         </para>
-         </listitem>
-         </varlistentry>
-       </variablelist>
-        </para>
-
-        <para>
-       Illustrations on how these different formats look can be seen in
-       the <xref linkend="APP-PSQL-examples"
-       endterm="APP-PSQL-examples-title"> section.
-       </para>
-
-       <tip>
-       <para>
-       There are various shortcut commands for <command>\pset</command>. See
-       <command>\a</command>, <command>\C</command>, <command>\H</command>,
-       <command>\t</command>, <command>\T</command>, and <command>\x</command>.
-       </para>
-       </tip>
-
-       <note>
-       <para>
-       It is an error to call <command>\pset</command> without
-       arguments. In the future this call might show the current status
-       of all printing options.
-       </para>
-       </note>
-
-       </listitem>
+          </para>
+          </listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term><literal>tuples_only</literal> (or <literal>t</literal>)</term>
+          <listitem>
+          <para>
+          Toggles between tuples only and full display. Full display may
+          show extra information such as column headers, titles, and
+          various footers. In tuples only mode, only actual table data
+          is shown.
+          </para>
+          </listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term><literal>title [ <replaceable class="parameter">text</replaceable> ]</literal></term>
+          <listitem>
+          <para>
+          Sets the table title for any subsequently printed tables. This
+          can be used to give your output descriptive tags. If no
+          argument is given, the title is unset.
+          </para>
+          </listitem>
+          </varlistentry>
+
+          <varlistentry>
+          <term><literal>tableattr</literal> (or <literal>T</literal>) <literal>[ <replaceable class="parameter">text</replaceable> ]</literal></term>
+          <listitem>
+          <para>
+          Allows you to specify any attributes to be placed inside the
+          <acronym>HTML</acronym> <sgmltag>table</sgmltag> tag. This
+          could for example be <literal>cellpadding</literal> or
+          <literal>bgcolor</literal>. Note that you probably don't want
+          to specify <literal>border</literal> here, as that is already
+          taken care of by <literal>\pset border</literal>.
+          </para>
+          </listitem>
+          </varlistentry>
+
+
+          <varlistentry>
+          <term><literal>pager</literal></term>
+          <listitem>
+          <para>
+          Controls use of a pager for query and <application>psql</>
+          help output. If the environment variable <envar>PAGER</envar>
+          is set, the output is piped to the specified program.
+          Otherwise a platform-dependent default (such as
+          <filename>more</filename>) is used.
+          </para>
+
+          <para>
+          When the pager is off, the pager is not used. When the pager
+          is on, the pager is used only when appropriate, i.e. the
+          output is to a terminal and will not fit on the screen.
+          (<application>psql</> does not do a perfect job of estimating
+          when to use the pager.) <literal>\pset pager</> turns the
+          pager on and off. Pager can also be set to <literal>always</>,
+          which causes the pager to be always used.
+          </para>
+          </listitem>
+          </varlistentry>
+        </variablelist>
+        </para>
+
+        <para>
+        Illustrations on how these different formats look can be seen in
+        the <xref linkend="APP-PSQL-examples"
+        endterm="APP-PSQL-examples-title"> section.
+        </para>
+
+        <tip>
+        <para>
+        There are various shortcut commands for <command>\pset</command>. See
+        <command>\a</command>, <command>\C</command>, <command>\H</command>,
+        <command>\t</command>, <command>\T</command>, and <command>\x</command>.
+        </para>
+        </tip>
+
+        <note>
+        <para>
+        It is an error to call <command>\pset</command> without
+        arguments. In the future this call might show the current status
+        of all printing options.
+        </para>
+        </note>
+
+        </listitem>
       </varlistentry>
 
 
@@ -1559,9 +1572,9 @@ lo_import 152801
         <term><literal>\qecho <replaceable class="parameter">text</replaceable> [ ... ] </literal></term>
         <listitem>
         <para>
-       This command is identical to <command>\echo</command> except
-       that all output will be written to the query output channel, as
-       set by <command>\o</command>.
+        This command is identical to <command>\echo</command> except
+        that all output will be written to the query output channel, as
+        set by <command>\o</command>.
         </para>
         </listitem>
       </varlistentry>
@@ -1589,14 +1602,14 @@ lo_import 152801
         <acronym>GNU</acronym> history library.
         </para>
 
-       <note>
-       <para>
-       In the current version, it is no longer necessary to save the
-       command history, since that will be done automatically on
-       program termination. The history is also loaded automatically
-       every time <application>psql</application> starts up.
-       </para>
-       </note>
+        <note>
+        <para>
+        In the current version, it is no longer necessary to save the
+        command history, since that will be done automatically on
+        program termination. The history is also loaded automatically
+        every time <application>psql</application> starts up.
+        </para>
+        </note>
         </listitem>
       </varlistentry>
 
@@ -1604,37 +1617,37 @@ lo_import 152801
       <varlistentry>
         <term><literal>\set [ <replaceable class="parameter">name</replaceable> [ <replaceable class="parameter">value</replaceable> [ ... ] ] ]</literal></term>
 
-       <listitem>
-       <para>
-       Sets the internal variable <replaceable
-       class="parameter">name</replaceable> to <replaceable
-       class="parameter">value</replaceable> or, if more than one value
-       is given, to the concatenation of all of them. If no second
-       argument is given, the variable is just set with no value. To
-       unset a variable, use the <command>\unset</command> command.
-       </para>
-
-       <para>
-       Valid variable names can contain characters, digits, and
-       underscores. See the section <xref
-       linkend="APP-PSQL-variables"
-       endterm="APP-PSQL-variables-title"> below for details.
-       Variable names are case-sensitive.
-       </para>
-
-       <para>
-       Although you are welcome to set any variable to anything you
-       want, <application>psql</application> treats several variables
-       as special. They are documented in the section about variables.
-       </para>
-
-       <note>
-       <para>
-       This command is totally separate from the <acronym>SQL</acronym>
-       command <xref linkend="SQL-SET" endterm="SQL-SET-title">.
-       </para>
-       </note>
-       </listitem>
+        <listitem>
+        <para>
+        Sets the internal variable <replaceable
+        class="parameter">name</replaceable> to <replaceable
+        class="parameter">value</replaceable> or, if more than one value
+        is given, to the concatenation of all of them. If no second
+        argument is given, the variable is just set with no value. To
+        unset a variable, use the <command>\unset</command> command.
+        </para>
+
+        <para>
+        Valid variable names can contain characters, digits, and
+        underscores. See the section <xref
+        linkend="APP-PSQL-variables"
+        endterm="APP-PSQL-variables-title"> below for details.
+        Variable names are case-sensitive.
+        </para>
+
+        <para>
+        Although you are welcome to set any variable to anything you
+        want, <application>psql</application> treats several variables
+        as special. They are documented in the section about variables.
+        </para>
+
+        <note>
+        <para>
+        This command is totally separate from the <acronym>SQL</acronym>
+        command <xref linkend="SQL-SET" endterm="SQL-SET-title">.
+        </para>
+        </note>
+        </listitem>
       </varlistentry>
 
 
@@ -1691,7 +1704,7 @@ lo_import 152801
         <listitem>
         <para>
         Toggles extended table formatting mode. As such it is equivalent to
-       <literal>\pset expanded</literal>.
+        <literal>\pset expanded</literal>.
        </para>
        </listitem>
       </varlistentry>
@@ -1703,20 +1716,20 @@ lo_import 152801
         <para>
         Produces a list of all available tables, views and sequences with their
         associated access privileges.
-       If a <replaceable class="parameter">pattern</replaceable> is
-       specified, only tables,views and sequences whose names match the pattern are listed.
-       </para>
+        If a <replaceable class="parameter">pattern</replaceable> is
+        specified, only tables,views and sequences whose names match the pattern are listed.
+        </para>
 
-       <para>
-       The commands <xref linkend="SQL-GRANT"> and
-       <xref linkend="SQL-REVOKE">
-       are used to set access privileges.  See <xref linkend="SQL-GRANT">
-       for more information.
-       </para>
+        <para>
+        The commands <xref linkend="SQL-GRANT"> and
+        <xref linkend="SQL-REVOKE">
+        are used to set access privileges.  See <xref linkend="SQL-GRANT">
+        for more information.
+        </para>
 
-       <para>
-       This is an alias for <command>\dp</command> (<quote>display
-       privileges</quote>).
+        <para>
+        This is an alias for <command>\dp</command> (<quote>display
+        privileges</quote>).
         </para>
         </listitem>
       </varlistentry>
@@ -1764,7 +1777,7 @@ lo_import 152801
    A pattern that contains an (unquoted) dot is interpreted as a schema
    name pattern followed by an object name pattern.  For example,
    <literal>\dt foo*.bar*</> displays all tables in schemas whose name
-   starts with <literal>foo</> and whose table name 
+   starts with <literal>foo</> and whose table name
    starts with <literal>bar</>.  If no dot appears, then the pattern
    matches only objects that are visible in the current schema search path.
   </para>
@@ -1847,96 +1860,96 @@ bar
        <secondary>psql</secondary>
       </indexterm>
         <term><varname>AUTOCOMMIT</varname></term>
-       <listitem>
-       <para>
-       When <literal>on</> (the default), each SQL command is automatically
-       committed upon successful completion.  To postpone commit in this
-       mode, you must enter a <command>BEGIN</> or <command>START
-       TRANSACTION</> SQL command.  When <literal>off</> or unset, SQL
-       commands are not committed until you explicitly issue
-       <command>COMMIT</> or <command>END</>.  The autocommit-off
-       mode works by issuing an implicit <command>BEGIN</> for you, just
-       before any command that is not already in a transaction block and
-       is not itself a <command>BEGIN</> or other transaction-control
-       command.
-       </para>
-
-       <note>
-       <para>
-        In autocommit-off mode, you must explicitly abandon any failed
-        transaction by entering <command>ABORT</> or <command>ROLLBACK</>.
-        Also keep in mind that if you exit the session
-        without committing, your work will be lost.
-       </para>
-       </note>
-
-       <note>
-       <para>
-        The autocommit-on mode is <productname>PostgreSQL</>'s traditional
-        behavior, but autocommit-off is closer to the SQL spec.  If you
-        prefer autocommit-off, you may wish to set it in the system-wide
-         <filename>psqlrc</filename> or your 
+        <listitem>
+        <para>
+        When <literal>on</> (the default), each SQL command is automatically
+        committed upon successful completion.  To postpone commit in this
+        mode, you must enter a <command>BEGIN</> or <command>START
+        TRANSACTION</> SQL command.  When <literal>off</> or unset, SQL
+        commands are not committed until you explicitly issue
+        <command>COMMIT</> or <command>END</>.  The autocommit-off
+        mode works by issuing an implicit <command>BEGIN</> for you, just
+        before any command that is not already in a transaction block and
+        is not itself a <command>BEGIN</> or other transaction-control
+        command.
+        </para>
+
+        <note>
+        <para>
+         In autocommit-off mode, you must explicitly abandon any failed
+         transaction by entering <command>ABORT</> or <command>ROLLBACK</>.
+         Also keep in mind that if you exit the session
+         without committing, your work will be lost.
+        </para>
+        </note>
+
+        <note>
+        <para>
+         The autocommit-on mode is <productname>PostgreSQL</>'s traditional
+         behavior, but autocommit-off is closer to the SQL spec.  If you
+         prefer autocommit-off, you may wish to set it in the system-wide
+         <filename>psqlrc</filename> or your
          <filename>.psqlrc</filename> file.
-       </para>
-       </note>
-       </listitem>
+        </para>
+        </note>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>DBNAME</varname></term>
-       <listitem>
-       <para>
+        <listitem>
+        <para>
         The name of the database you are currently connected to. This is
         set every time you connect to a database (including program
         start-up), but can be unset.
-       </para>
-       </listitem>
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>ECHO</varname></term>
-       <listitem>
-       <para>
-       If set to <literal>all</literal>, all lines
-       entered or from a script are written to the standard output
-       before they are parsed or executed. To select this behavior on program
-       start-up, use the switch <option>-a</option>. If set to
-       <literal>queries</literal>,
-       <application>psql</application> merely prints all queries as
-       they are sent to the server. The switch for this is
-       <option>-e</option>.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        If set to <literal>all</literal>, all lines
+        entered or from a script are written to the standard output
+        before they are parsed or executed. To select this behavior on program
+        start-up, use the switch <option>-a</option>. If set to
+        <literal>queries</literal>,
+        <application>psql</application> merely prints all queries as
+        they are sent to the server. The switch for this is
+        <option>-e</option>.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>ECHO_HIDDEN</varname></term>
-       <listitem>
-       <para>
-       When this variable is set and a backslash command queries the
-       database, the query is first shown. This way you can study the
-       <productname>PostgreSQL</productname> internals and provide
-       similar functionality in your own programs. (To select this behavior
-       on program start-up, use the switch <option>-E</option>.)  If you set
-       the variable to the value <literal>noexec</literal>, the queries are
-       just shown but are not actually sent to the server and executed.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        When this variable is set and a backslash command queries the
+        database, the query is first shown. This way you can study the
+        <productname>PostgreSQL</productname> internals and provide
+        similar functionality in your own programs. (To select this behavior
+        on program start-up, use the switch <option>-E</option>.)  If you set
+        the variable to the value <literal>noexec</literal>, the queries are
+        just shown but are not actually sent to the server and executed.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>ENCODING</varname></term>
-       <listitem>
-       <para>
+        <listitem>
+        <para>
         The current client character set encoding.
-       </para>
-       </listitem>
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>HISTCONTROL</varname></term>
-       <listitem>
-       <para>
+        <listitem>
+        <para>
          If this variable is set to <literal>ignorespace</literal>,
          lines which begin with a space are not entered into the history
          list. If set to a value of <literal>ignoredups</literal>, lines
@@ -1944,47 +1957,47 @@ bar
          <literal>ignoreboth</literal> combines the two options. If
          unset, or if set to any other value than those above, all lines
          read in interactive mode are saved on the history list.
-       </para>
+        </para>
         <note>
         <para>
         This feature was shamelessly plagiarized from
         <application>Bash</application>.
         </para>
         </note>
-       </listitem>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>HISTSIZE</varname></term>
-       <listitem>
-       <para>
+        <listitem>
+        <para>
         The number of commands to store in the command history. The
         default value is 500.
-       </para>
+        </para>
         <note>
         <para>
         This feature was shamelessly plagiarized from
         <application>Bash</application>.
         </para>
         </note>
-       </listitem>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>HOST</varname></term>
-       <listitem>
-       <para>
+        <listitem>
+        <para>
         The database server host you are currently connected to. This is
         set every time you connect to a database (including program
         start-up), but can be unset.
-       </para>
-       </listitem>
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>IGNOREEOF</varname></term>
-       <listitem>
-       <para>
+        <listitem>
+        <para>
          If unset, sending an <acronym>EOF</> character (usually
          <keycombo action="simul"><keycap>Control</><keycap>D</></>)
          to an interactive session of <application>psql</application>
@@ -1992,125 +2005,125 @@ bar
          that many <acronym>EOF</> characters are ignored before the
          application terminates.  If the variable is set but has no
          numeric value, the default is 10.
-       </para>
+        </para>
         <note>
         <para>
         This feature was shamelessly plagiarized from
         <application>Bash</application>.
         </para>
         </note>
-       </listitem>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>LASTOID</varname></term>
-       <listitem>
-       <para>
+        <listitem>
+        <para>
         The value of the last affected OID, as returned from an
         <command>INSERT</command> or <command>lo_insert</command>
         command. This variable is only guaranteed to be valid until
         after the result of the next <acronym>SQL</acronym> command has
         been displayed.
-       </para>
-       </listitem>
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>ON_ERROR_STOP</varname></term>
-       <listitem>
-       <para>
-       By default, if non-interactive scripts encounter an error, such
-       as a malformed <acronym>SQL</acronym> command or internal
-       meta-command, processing continues. This has been the
-       traditional behavior of <application>psql</application> but it
-       is sometimes not desirable. If this variable is set, script
-       processing will immediately terminate. If the script was called
-       from another script it will terminate in the same fashion. If
-       the outermost script was not called from an interactive
-       <application>psql</application> session but rather using the
-       <option>-f</option> option, <application>psql</application> will
-       return error code 3, to distinguish this case from fatal error
-       conditions (error code 1).
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        By default, if non-interactive scripts encounter an error, such
+        as a malformed <acronym>SQL</acronym> command or internal
+        meta-command, processing continues. This has been the
+        traditional behavior of <application>psql</application> but it
+        is sometimes not desirable. If this variable is set, script
+        processing will immediately terminate. If the script was called
+        from another script it will terminate in the same fashion. If
+        the outermost script was not called from an interactive
+        <application>psql</application> session but rather using the
+        <option>-f</option> option, <application>psql</application> will
+        return error code 3, to distinguish this case from fatal error
+        conditions (error code 1).
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>PORT</varname></term>
-       <listitem>
-       <para>
+        <listitem>
+        <para>
         The database server port to which you are currently connected.
         This is set every time you connect to a database (including
         program start-up), but can be unset.
-       </para>
-       </listitem>
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>PROMPT1</varname></term>
         <term><varname>PROMPT2</varname></term>
         <term><varname>PROMPT3</varname></term>
-       <listitem>
-       <para>
-       These specify what the prompts <application>psql</application>
-       issues should look like. See <xref
-       linkend="APP-PSQL-prompting"
-       endterm="APP-PSQL-prompting-title"> below.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        These specify what the prompts <application>psql</application>
+        issues should look like. See <xref
+        linkend="APP-PSQL-prompting"
+        endterm="APP-PSQL-prompting-title"> below.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>QUIET</varname></term>
-       <listitem>
-       <para>
-       This variable is equivalent to the command line option
-       <option>-q</option>. It is probably not too useful in
-       interactive mode.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        This variable is equivalent to the command line option
+        <option>-q</option>. It is probably not too useful in
+        interactive mode.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>SINGLELINE</varname></term>
-       <listitem>
-       <para>
-       This variable is equivalent to the command line option
-       <option>-S</option>.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        This variable is equivalent to the command line option
+        <option>-S</option>.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>SINGLESTEP</varname></term>
-       <listitem>
-       <para>
-       This variable is equivalent to the command line option
-       <option>-s</option>.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        This variable is equivalent to the command line option
+        <option>-s</option>.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>USER</varname></term>
-       <listitem>
-       <para>
+        <listitem>
+        <para>
         The database user you are currently connected as. This is set
         every time you connect to a database (including program
         start-up), but can be unset.
-       </para>
-       </listitem>
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><varname>VERBOSITY</varname></term>
-       <listitem>
-       <para>
-       This variable can be set to the values <literal>default</>,
-       <literal>verbose</>, or <literal>terse</> to control the verbosity
-       of error reports.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        This variable can be set to the values <literal>default</>,
+        <literal>verbose</>, or <literal>terse</> to control the verbosity
+        of error reports.
+        </para>
+        </listitem>
       </varlistentry>
 
     </variablelist>
@@ -2211,7 +2224,7 @@ testdb=> <userinput>\set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\'
     <variablelist>
       <varlistentry>
         <term><literal>%M</literal></term>
-       <listitem>
+        <listitem>
          <para>
           The full host name (with domain name) of the database server,
           or <literal>[local]</literal> if the connection is over a Unix
@@ -2225,7 +2238,7 @@ testdb=> <userinput>\set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\'
 
       <varlistentry>
         <term><literal>%m</literal></term>
-       <listitem>
+        <listitem>
          <para>
           The host name of the database server, truncated at the
           first dot, or <literal>[local]</literal> if the connection is
@@ -2236,12 +2249,12 @@ testdb=> <userinput>\set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\'
 
       <varlistentry>
         <term><literal>%&gt;</literal></term>
-       <listitem><para>The port number at which the database server is listening.</para></listitem>
+        <listitem><para>The port number at which the database server is listening.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>%n</literal></term>
-       <listitem>
+        <listitem>
          <para>
           The database session user name.  (The expansion of this
           value might change during a database session as the result
@@ -2253,18 +2266,18 @@ testdb=> <userinput>\set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\'
 
       <varlistentry>
         <term><literal>%/</literal></term>
-       <listitem><para>The name of the current database.</para></listitem>
+        <listitem><para>The name of the current database.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>%~</literal></term>
-       <listitem><para>Like <literal>%/</literal>, but the output is <literal>~</literal>
+        <listitem><para>Like <literal>%/</literal>, but the output is <literal>~</literal>
          (tilde) if the database is your default database.</para></listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>%#</literal></term>
-       <listitem>
+        <listitem>
          <para>
           If the session user is a database superuser, then a
           <literal>#</literal>, otherwise a <literal>&gt;</literal>.
@@ -2277,75 +2290,75 @@ testdb=> <userinput>\set content '\'' `sed -e "s/'/\\\\\\'/g" < my_file.txt` '\'
 
       <varlistentry>
         <term><literal>%R</literal></term>
-       <listitem>
-       <para>
-       In prompt 1 normally <literal>=</literal>, but <literal>^</literal> if
-       in single-line mode, and <literal>!</literal> if the session is
-       disconnected from the database (which can happen if
-       <command>\connect</command> fails). In prompt 2 the sequence is
-       replaced by <literal>-</literal>, <literal>*</literal>, a single quote,
-       or a double quote, depending on whether
-       <application>psql</application> expects more input because the
-       command wasn't terminated yet, because you are inside a
-       <literal>/* ... */</literal> comment, or because you are inside
-       a quote. In prompt 3 the sequence doesn't produce anything.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        In prompt 1 normally <literal>=</literal>, but <literal>^</literal> if
+        in single-line mode, and <literal>!</literal> if the session is
+        disconnected from the database (which can happen if
+        <command>\connect</command> fails). In prompt 2 the sequence is
+        replaced by <literal>-</literal>, <literal>*</literal>, a single quote,
+        or a double quote, depending on whether
+        <application>psql</application> expects more input because the
+        command wasn't terminated yet, because you are inside a
+        <literal>/* ... */</literal> comment, or because you are inside
+        a quote. In prompt 3 the sequence doesn't produce anything.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>%x</literal></term>
-       <listitem>
-       <para>
-       Transaction status: an empty string when not in a transaction
-       block, or <literal>*</> when in a transaction block, or
-       <literal>!</> when in a failed transaction block, or <literal>?</>
-       when the transaction state is indeterminate (for example, because
-       there is no connection).
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        Transaction status: an empty string when not in a transaction
+        block, or <literal>*</> when in a transaction block, or
+        <literal>!</> when in a failed transaction block, or <literal>?</>
+        when the transaction state is indeterminate (for example, because
+        there is no connection).
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>%</literal><replaceable class="parameter">digits</replaceable></term>
-       <listitem>
-       <para>
-       The character with the indicated numeric code is substituted.
-       If <replaceable class="parameter">digits</replaceable> starts
-       with <literal>0x</literal> the rest of the characters are
-       interpreted as hexadecimal; otherwise if the first digit is
-       <literal>0</literal> the digits are interpreted as octal;
-       otherwise the digits are read as a decimal number.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        The character with the indicated numeric code is substituted.
+        If <replaceable class="parameter">digits</replaceable> starts
+        with <literal>0x</literal> the rest of the characters are
+        interpreted as hexadecimal; otherwise if the first digit is
+        <literal>0</literal> the digits are interpreted as octal;
+        otherwise the digits are read as a decimal number.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>%:</literal><replaceable class="parameter">name</replaceable><literal>:</literal></term>
-       <listitem>
-       <para>
-       The value of the <application>psql</application> variable
-       <replaceable class="parameter">name</replaceable>. See the
-       section <xref linkend="APP-PSQL-variables"
-       endterm="APP-PSQL-variables-title"> for details.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        The value of the <application>psql</application> variable
+        <replaceable class="parameter">name</replaceable>. See the
+        section <xref linkend="APP-PSQL-variables"
+        endterm="APP-PSQL-variables-title"> for details.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>%`</literal><replaceable class="parameter">command</replaceable><literal>`</literal></term>
-       <listitem>
-       <para>
-       The output of <replaceable
-       class="parameter">command</replaceable>, similar to ordinary
-       <quote>back-tick</quote> substitution.
-       </para>
-       </listitem>
+        <listitem>
+        <para>
+        The output of <replaceable
+        class="parameter">command</replaceable>, similar to ordinary
+        <quote>back-tick</quote> substitution.
+        </para>
+        </listitem>
       </varlistentry>
 
       <varlistentry>
         <term><literal>%[</literal> ... <literal>%]</literal></term>
-       <listitem>
+        <listitem>
          <para>
          Prompts may contain terminal control characters which, for
          example, change the color, background, or style of the prompt
@@ -2360,8 +2373,8 @@ testdb=> \set PROMPT1 '%[%033[1;33;40m%]%n@%/%R%[%033[0m%#%] '
 </programlisting>
          results in a boldfaced (<literal>1;</literal>) yellow-on-black
          (<literal>33;40</literal>) prompt on VT100-compatible, color-capable
-        terminals.
-       </para>
+         terminals.
+        </para>
         </listitem>
       </varlistentry>
 
@@ -2505,10 +2518,10 @@ $endif
     <para>
      Before starting up, <application>psql</application> attempts to
      read and execute commands from the the system-wide
-     <filename>psqlrc</filename> file and the  
+     <filename>psqlrc</filename> file and the
      <filename>$HOME/.psqlrc</filename> file in the user's home
-     directory.  See <filename><replaceable>PREFIX</>/share/psqlrc.sample</> 
-     for information on setting up the system-wide file.  It could be used 
+     directory.  See <filename><replaceable>PREFIX</>/share/psqlrc.sample</>
+     for information on setting up the system-wide file.  It could be used
      to set up the client or the server to taste (using the <command>\set
      </command> and <command>SET</command> commands).
     </para>
index 096a813b7f028ae89f9fa99c3ecb5de2a1359efe..c6cd587ade71641a99a501df6e5607e10900a6cf 100644 (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
 -->
 
@@ -33,6 +33,12 @@ REVOKE [ GRANT OPTION FOR ]
     FROM { <replaceable class="PARAMETER">username</replaceable> | GROUP <replaceable class="PARAMETER">groupname</replaceable> | PUBLIC } [, ...]
     [ 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 ]
     { EXECUTE | ALL [ PRIVILEGES ] }
     ON FUNCTION <replaceable>funcname</replaceable> ([<replaceable>type</replaceable>, ...]) [, ...]
index 03df5920566043b36a8f429554b0edc7f3fff104..100c69bde93be436d4799d993d9bf0547770322e 100644 (file)
@@ -1,5 +1,5 @@
 <!-- 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
 -->
@@ -76,6 +76,7 @@ PostgreSQL Reference Manual
    &createSequence;
    &createTable;
    &createTableAs;
+   &createTableSpace;
    &createTrigger;
    &createType;
    &createUser;
@@ -98,6 +99,7 @@ PostgreSQL Reference Manual
    &dropSchema;
    &dropSequence;
    &dropTable;
+   &dropTableSpace;
    &dropTrigger;
    &dropType;
    &dropUser;
index cb1e68930531500028e3b1f1f98c8b3fa6db9ec6..8e595c18cb88d06b0397e161960d4318bc6ff9ce 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -2630,8 +2630,8 @@ heap_undo(XLogRecPtr lsn, XLogRecord *record)
 static void
 out_target(char *buf, xl_heaptid *target)
 {
-       sprintf(buf + strlen(buf), "node %u/%u; tid %u/%u",
-                       target->node.tblNode, target->node.relNode,
+       sprintf(buf + strlen(buf), "rel %u/%u/%u; tid %u/%u",
+                       target->node.spcNode, target->node.dbNode, target->node.relNode,
                        ItemPointerGetBlockNumber(&(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;
 
-               sprintf(buf + strlen(buf), "clean: node %u/%u; blk %u",
-                               xlrec->node.tblNode, xlrec->node.relNode, xlrec->block);
+               sprintf(buf + strlen(buf), "clean: rel %u/%u/%u; blk %u",
+                               xlrec->node.spcNode, xlrec->node.dbNode,
+                               xlrec->node.relNode, xlrec->block);
        }
        else
                strcat(buf, "UNKNOWN");
index ed398b32da5bb0a72e2b38d3da81537b34cbf684..3cb2f3836d26e791342f97ee3c197fbf484be6e9 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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
 out_target(char *buf, xl_btreetid *target)
 {
-       sprintf(buf + strlen(buf), "node %u/%u; tid %u/%u",
-                       target->node.tblNode, target->node.relNode,
+       sprintf(buf + strlen(buf), "rel %u/%u/%u; tid %u/%u",
+                       target->node.spcNode, target->node.dbNode, target->node.relNode,
                        ItemPointerGetBlockNumber(&(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;
 
-                               sprintf(buf + strlen(buf), "delete: node %u/%u; blk %u",
-                                xlrec->node.tblNode, xlrec->node.relNode, xlrec->block);
+                               sprintf(buf + strlen(buf), "delete: rel %u/%u/%u; blk %u",
+                                               xlrec->node.spcNode, xlrec->node.dbNode,
+                                               xlrec->node.relNode, xlrec->block);
                                break;
                        }
                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;
 
-                               sprintf(buf + strlen(buf), "newroot: node %u/%u; root %u lev %u",
-                                               xlrec->node.tblNode, xlrec->node.relNode,
+                               sprintf(buf + strlen(buf), "newroot: rel %u/%u/%u; root %u lev %u",
+                                               xlrec->node.spcNode, xlrec->node.dbNode,
+                                               xlrec->node.relNode,
                                                xlrec->rootblk, xlrec->level);
                                break;
                        }
@@ -912,8 +914,9 @@ btree_desc(char *buf, uint8 xl_info, char *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",
-                                               xlrec->node.tblNode, xlrec->node.relNode,
+                               sprintf(buf + strlen(buf), "newmeta: rel %u/%u/%u; root %u lev %u fast %u lev %u",
+                                               xlrec->node.spcNode, xlrec->node.dbNode,
+                                               xlrec->node.relNode,
                                                xlrec->meta.root, xlrec->meta.level,
                                                xlrec->meta.fastroot, xlrec->meta.fastlevel);
                                break;
@@ -922,9 +925,9 @@ btree_desc(char *buf, uint8 xl_info, char *rec)
                        {
                                xl_btree_newpage *xlrec = (xl_btree_newpage *) rec;
 
-                               sprintf(buf + strlen(buf), "newpage: node %u/%u; page %u",
-                                               xlrec->node.tblNode, xlrec->node.relNode,
-                                               xlrec->blkno);
+                               sprintf(buf + strlen(buf), "newpage: rel %u/%u/%u; page %u",
+                                               xlrec->node.spcNode, xlrec->node.dbNode,
+                                               xlrec->node.relNode, xlrec->blkno);
                                break;
                        }
                default:
index a7c8d3bf52b2c8902fa709907ee2917491e59d89..a58902e76f6b50ec86e71777163de8483173c20d 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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
                 * 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;
 
                hentry = (XLogRelCacheEntry *)
index cbc8ff6e53996c83cb7682aac69e30143c5552af..7b712bd555b51370d79985f61c786d762bb10b1a 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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_class.h"
 #include "catalog/pg_namespace.h"
+#include "catalog/pg_tablespace.h"
 #include "commands/defrem.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
@@ -181,6 +182,7 @@ Boot_CreateStmt:
 
                                                boot_reldesc = heap_create(LexIDStr($5),
                                                                                                   PG_CATALOG_NAMESPACE,
+                                                                                                  $3 ? GLOBALTABLESPACE_OID : 0,
                                                                                                   tupdesc,
                                                                                                   $3,
                                                                                                   true,
@@ -193,6 +195,7 @@ Boot_CreateStmt:
 
                                                id = heap_create_with_catalog(LexIDStr($5),
                                                                                                          PG_CATALOG_NAMESPACE,
+                                                                                                         $3 ? GLOBALTABLESPACE_OID : 0,
                                                                                                          tupdesc,
                                                                                                          RELKIND_RELATION,
                                                                                                          $3,
@@ -239,6 +242,7 @@ Boot_DeclareIndexStmt:
                                        DefineIndex(makeRangeVar(NULL, LexIDStr($5)),
                                                                LexIDStr($3),
                                                                LexIDStr($7),
+                                                               NULL,
                                                                $9,
                                                                NULL, NIL,
                                                                false, false, false,
@@ -255,6 +259,7 @@ Boot_DeclareUniqueIndexStmt:
                                        DefineIndex(makeRangeVar(NULL, LexIDStr($6)),
                                                                LexIDStr($4),
                                                                LexIDStr($8),
+                                                               NULL,
                                                                $10,
                                                                NULL, NIL,
                                                                true, false, false,
index 0a68cb661af3fcd899a71c66d043d58e93b76e03..c63168a9bd5a8a93af0ef7ae8be81a49091bd651 100644 (file)
@@ -2,7 +2,7 @@
 #
 # 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_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_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)
@@ -59,5 +59,5 @@ installdirs:
 uninstall-data:
        rm -f $(addprefix $(DESTDIR)$(datadir)/, $(BKIFILES) system_views.sql information_schema.sql sql_features.txt)
 
-clean: 
+clean:
        rm -f SUBSYS.o $(OBJS) $(BKIFILES)
index de74a422b7891a83cef070fb43c34aac2c00f5ca..6c966b89b273216c243d7776010cef5da90bdb0d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
  *       See acl.h.
@@ -31,6 +31,7 @@
 #include "catalog/pg_operator.h"
 #include "catalog/pg_proc.h"
 #include "catalog/pg_shadow.h"
+#include "catalog/pg_tablespace.h"
 #include "catalog/pg_type.h"
 #include "miscadmin.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_Language(GrantStmt *stmt);
 static void ExecuteGrantStmt_Namespace(GrantStmt *stmt);
+static void ExecuteGrantStmt_Tablespace(GrantStmt *stmt);
 
 static const char *privilege_to_string(AclMode privilege);
 
@@ -207,12 +209,16 @@ ExecuteGrantStmt(GrantStmt *stmt)
                case ACL_OBJECT_NAMESPACE:
                        ExecuteGrantStmt_Namespace(stmt);
                        break;
+               case ACL_OBJECT_TABLESPACE:
+                       ExecuteGrantStmt_Tablespace(stmt);
+                       break;
                default:
                        elog(ERROR, "unrecognized GrantStmt.objtype: %d",
                                 (int) stmt->objtype);
        }
 }
 
+
 static void
 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 *
 privilege_to_string(AclMode privilege)
@@ -1112,7 +1275,9 @@ static const char *const no_priv_msg[MAX_ACL_KIND] =
        /* ACL_KIND_OPCLASS */
        gettext_noop("permission denied for operator class %s"),
        /* 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] =
@@ -1134,7 +1299,9 @@ static const char *const not_owner_msg[MAX_ACL_KIND] =
        /* ACL_KIND_OPCLASS */
        gettext_noop("must be owner of operator class %s"),
        /* 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;
 }
 
+/*
+ * 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
@@ -1610,6 +1851,18 @@ pg_namespace_aclcheck(Oid nsp_oid, AclId userid, AclMode mode)
                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).
@@ -1751,6 +2004,45 @@ pg_namespace_ownercheck(Oid nsp_oid, AclId userid)
        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).
  */
@@ -1780,9 +2072,8 @@ pg_opclass_ownercheck(Oid opc_oid, AclId userid)
        return userid == owner_id;
 }
 
-
 /*
- * Ownership check for database (specified as OID)
+ * Ownership check for a database (specified by OID).
  */
 bool
 pg_database_ownercheck(Oid db_oid, AclId userid)
index afea81a976cff439f82dc9044e7f65fa84177725..32d4d33d89a57f1e35f6497ffe5cfae5400d209d 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
 #include "catalog/catalog.h"
 #include "catalog/catname.h"
 #include "catalog/pg_namespace.h"
+#include "catalog/pg_tablespace.h"
 #include "miscadmin.h"
 
 
+#define OIDCHARS       10                      /* max chars printed by %u */
+
+
 /*
  * relpath                     - construct path to a relation's file
  *
  * Result is a palloc'd string.
  */
-
 char *
 relpath(RelFileNode rnode)
 {
+       int                     pathlen;
        char       *path;
 
-       if (rnode.tblNode == (Oid) 0)           /* "global tablespace" */
+       if (rnode.spcNode == GLOBALTABLESPACE_OID)
        {
                /* Shared system relations live in {datadir}/global */
-               path = (char *) palloc(strlen(DataDir) + 8 + sizeof(NameData) + 1);
-               sprintf(path, "%s/global/%u", DataDir, rnode.relNode);
+               Assert(rnode.dbNode == 0);
+               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
        {
-               path = (char *) palloc(strlen(DataDir) + 6 + 2 * sizeof(NameData) + 3);
-               sprintf(path, "%s/base/%u/%u", DataDir, rnode.tblNode, rnode.relNode);
+               /* All other tablespaces are accessed via symlinks */
+               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;
 }
@@ -52,23 +70,39 @@ relpath(RelFileNode rnode)
  * GetDatabasePath                     - construct path to a database dir
  *
  * Result is a palloc'd string.
+ *
+ * XXX this must agree with relpath()!
  */
-
 char *
-GetDatabasePath(Oid tblNode)
+GetDatabasePath(Oid dbNode, Oid spcNode)
 {
+       int                     pathlen;
        char       *path;
 
-       if (tblNode == (Oid) 0)         /* "global tablespace" */
+       if (spcNode == GLOBALTABLESPACE_OID)
        {
                /* Shared system relations live in {datadir}/global */
-               path = (char *) palloc(strlen(DataDir) + 8);
-               sprintf(path, "%s/global", DataDir);
+               Assert(dbNode == 0);
+               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
        {
-               path = (char *) palloc(strlen(DataDir) + 6 + sizeof(NameData) + 1);
-               sprintf(path, "%s/base/%u", DataDir, tblNode);
+               /* All other tablespaces are accessed via symlinks */
+               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;
 }
index a4cc33d4c9d2c041e142931e5feb5589d801768e..68ea6f45f69e295164d061c250edddcb8b77ecb2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -43,6 +43,7 @@
 #include "catalog/pg_statistic.h"
 #include "catalog/pg_type.h"
 #include "commands/tablecmds.h"
+#include "commands/tablespace.h"
 #include "commands/trigger.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
@@ -203,15 +204,14 @@ SystemAttributeByName(const char *attname, bool relhasoids)
 Relation
 heap_create(const char *relname,
                        Oid relnamespace,
+                       Oid reltablespace,
                        TupleDesc tupDesc,
                        bool shared_relation,
                        bool storage_create,
                        bool allow_system_table_mods)
 {
        Oid                     relid;
-       Oid                     dbid = shared_relation ? InvalidOid : MyDatabaseId;
        bool            nailme = false;
-       RelFileNode rnode;
        Relation        rel;
 
        /*
@@ -260,27 +260,23 @@ heap_create(const char *relname,
                        relid = RelOid_pg_group;
                else if (strcmp(DatabaseRelationName, relname) == 0)
                        relid = RelOid_pg_database;
+               else if (strcmp(TableSpaceRelationName, relname) == 0)
+                       relid = RelOid_pg_tablespace;
                else
                        relid = newoid();
        }
        else
                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.
         */
        rel = RelationBuildLocalRelation(relname,
                                                                         relnamespace,
                                                                         tupDesc,
-                                                                        relid, dbid,
-                                                                        rnode,
+                                                                        relid,
+                                                                        reltablespace,
+                                                                        shared_relation,
                                                                         nailme);
 
        /*
@@ -296,6 +292,16 @@ heap_create(const char *relname,
 void
 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);
        rel->rd_smgr = smgropen(rel->rd_node);
        smgrcreate(rel->rd_smgr, rel->rd_istemp, false);
@@ -692,6 +698,7 @@ AddNewRelationType(const char *typeName,
 Oid
 heap_create_with_catalog(const char *relname,
                                                 Oid relnamespace,
+                                                Oid reltablespace,
                                                 TupleDesc tupdesc,
                                                 char relkind,
                                                 bool shared_relation,
@@ -726,6 +733,7 @@ heap_create_with_catalog(const char *relname,
         */
        new_rel_desc = heap_create(relname,
                                                           relnamespace,
+                                                          reltablespace,
                                                           tupdesc,
                                                           shared_relation,
                                                           (relkind != RELKIND_VIEW &&
index 8ada0915bd29a9fa1e603b4a8fd39e5dd6b77458..581799fc5f555f561b77066903302dff8cc3bfff 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -467,6 +467,7 @@ index_create(Oid heapRelationId,
                         const char *indexRelationName,
                         IndexInfo *indexInfo,
                         Oid accessMethodObjectId,
+                        Oid tableSpaceId,
                         Oid *classObjectId,
                         bool primary,
                         bool isconstraint,
@@ -539,6 +540,7 @@ index_create(Oid heapRelationId,
         */
        indexRelation = heap_create(indexRelationName,
                                                                namespaceId,
+                                                               tableSpaceId,
                                                                indexTupDesc,
                                                                shared_relation,
                                                                true,
index c7535508a7397198e87bd83bc5f3306db4fbcae8..b412023fe2873ed62edd4eb10cc9976693f02358 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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
                 * permissions checks on it.
                 */
-               namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID);
+               namespaceId = NamespaceCreate(namespaceName, BOOTSTRAP_USESYSID, 0);
                /* Advance command counter to make namespace visible */
                CommandCounterIncrement();
        }
index c3546f9068f9ed08a810a2cfb358dd6bb78f4493..c600ac2a84d80aef0b5eb2553df9e4a50d05ad25 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
-NamespaceCreate(const char *nspName, int32 ownerSysId)
+NamespaceCreate(const char *nspName, int32 ownerSysId, Oid nspTablespace)
 {
        Relation        nspdesc;
        HeapTuple       tup;
@@ -59,6 +59,7 @@ NamespaceCreate(const char *nspName, int32 ownerSysId)
        namestrcpy(&nname, nspName);
        values[Anum_pg_namespace_nspname - 1] = NameGetDatum(&nname);
        values[Anum_pg_namespace_nspowner - 1] = Int32GetDatum(ownerSysId);
+       values[Anum_pg_namespace_nsptablespace - 1] = Int32GetDatum(nspTablespace);
        nulls[Anum_pg_namespace_nspacl - 1] = 'n';
 
        nspdesc = heap_openr(NamespaceRelationName, RowExclusiveLock);
index 0c450beac3cd814879a19a538a42fc3f3d1747ae..644fd1d655d7acfba3a317dd2a24b5ed08629978 100644 (file)
@@ -4,7 +4,7 @@
 #    Makefile for backend/commands
 #
 # 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 \
        indexcmds.o lockcmds.o operatorcmds.o opclasscmds.o \
        portalcmds.o prepare.o proclang.o \
-       schemacmds.o sequence.o tablecmds.o trigger.o typecmds.o user.o \
-       vacuum.o vacuumlazy.o variable.o view.o
+       schemacmds.o sequence.o tablecmds.o tablespace.o trigger.o \
+       typecmds.o user.o vacuum.o vacuumlazy.o variable.o view.o
 
 all: SUBSYS.o
 
index 0483eaf2d3c33a17f142762baa7e0e8075089072..d81771c7a043d11825eac041d9f59bb40a25ed83 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * 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,
                                                                                  RelationGetNamespace(OldHeap),
+                                                 OldHeap->rd_rel->reltablespace,
                                                                                  tupdesc,
                                                                                  OldHeap->rd_rel->relkind,
                                                                                  OldHeap->rd_rel->relisshared,
index 337ec5395fbe9ad639740cb45536d4b763843ef6..8fbebecd8744beb6a059e442ec6fe471b249d075 100644 (file)
@@ -9,13 +9,12 @@
  *
  *
  * 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 <errno.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/stat.h>
 #include "catalog/catalog.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_shadow.h"
+#include "catalog/pg_tablespace.h"
 #include "catalog/indexing.h"
 #include "commands/comment.h"
 #include "commands/dbcommands.h"
+#include "commands/tablespace.h"
+#include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "storage/fd.h"
 #include "storage/freespace.h"
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 
-#include "mb/pg_wchar.h"               /* encoding check */
-
 
 /* non-export function prototypes */
 static bool get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
                        int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
                        TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
-                       char *dbpath);
+                       Oid *dbTablespace);
 static bool have_createdb_privilege(void);
-static char *resolve_alt_dbpath(const char *dbpath, Oid dboid);
-static bool remove_dbdirs(const char *real_loc, const char *altloc);
+static void remove_dbtablespaces(Oid db_id);
+
 
 /*
  * CREATE DATABASE
  */
-
 void
 createdb(const CreatedbStmt *stmt)
 {
-       char       *nominal_loc;
-       char       *alt_loc;
-       char       *target_dir;
-       char            src_loc[MAXPGPATH];
-#ifndef WIN32
-       char            buf[2 * MAXPGPATH + 100];
-#endif
+       HeapScanDesc scan;
+       Relation        rel;
        Oid                     src_dboid;
        AclId           src_owner;
        int                     src_encoding;
@@ -74,7 +68,8 @@ createdb(const CreatedbStmt *stmt)
        Oid                     src_lastsysoid;
        TransactionId src_vacuumxid;
        TransactionId src_frozenxid;
-       char            src_dbpath[MAXPGPATH];
+       Oid                     src_deftablespace;
+       Oid                     dst_deftablespace;
        Relation        pg_database_rel;
        HeapTuple       tuple;
        TupleDesc       pg_database_dsc;
@@ -83,36 +78,41 @@ createdb(const CreatedbStmt *stmt)
        Oid                     dboid;
        AclId           datdba;
        ListCell   *option;
+       DefElem    *dtablespacename = NULL;
        DefElem    *downer = NULL;
-       DefElem    *dpath = NULL;
        DefElem    *dtemplate = NULL;
        DefElem    *dencoding = NULL;
        char       *dbname = stmt->dbname;
        char       *dbowner = NULL;
-       char       *dbpath = NULL;
        char       *dbtemplate = NULL;
        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 */
        foreach(option, stmt->options)
        {
                DefElem    *defel = (DefElem *) lfirst(option);
 
-               if (strcmp(defel->defname, "owner") == 0)
+               if (strcmp(defel->defname, "tablespace") == 0)
                {
-                       if (downer)
+                       if (dtablespacename)
                                ereport(ERROR,
                                                (errcode(ERRCODE_SYNTAX_ERROR),
                                                 errmsg("conflicting or redundant options")));
-                       downer = defel;
+                       dtablespacename = defel;
                }
-               else if (strcmp(defel->defname, "location") == 0)
+               else if (strcmp(defel->defname, "owner") == 0)
                {
-                       if (dpath)
+                       if (downer)
                                ereport(ERROR,
                                                (errcode(ERRCODE_SYNTAX_ERROR),
                                                 errmsg("conflicting or redundant options")));
-                       dpath = defel;
+                       downer = defel;
                }
                else if (strcmp(defel->defname, "template") == 0)
                {
@@ -130,6 +130,13 @@ createdb(const CreatedbStmt *stmt)
                                                 errmsg("conflicting or redundant options")));
                        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
                        elog(ERROR, "option \"%s\" not recognized",
                                 defel->defname);
@@ -137,8 +144,6 @@ createdb(const CreatedbStmt *stmt)
 
        if (downer && downer->arg)
                dbowner = strVal(downer->arg);
-       if (dpath && dpath->arg)
-               dbpath = strVal(dpath->arg);
        if (dtemplate && dtemplate->arg)
                dbtemplate = strVal(dtemplate->arg);
        if (dencoding && dencoding->arg)
@@ -195,17 +200,6 @@ createdb(const CreatedbStmt *stmt)
                                         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
         * 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,
                                         &src_istemplate, &src_lastsysoid,
-                                        &src_vacuumxid, &src_frozenxid,
-                                        src_dbpath))
+                                        &src_vacuumxid, &src_frozenxid, &src_deftablespace))
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_DATABASE),
                                 errmsg("template database \"%s\" does not exist", dbtemplate)));
@@ -246,14 +239,6 @@ createdb(const CreatedbStmt *stmt)
                                                        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
         * (exception is to allow CREATE DB while connected to template1).
@@ -276,45 +261,39 @@ createdb(const CreatedbStmt *stmt)
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                 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
         * path.
         */
        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
         * 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
-        * the mkdir() and system() calls below.
+        * the system() calls below.
         */
        closeAllVfds();
 
        /*
-        * Check we can create the target directory --- but then remove it
-        * because we rely on cp(1) to create it for real.
+        * Iterate through all tablespaces of the template database, and
+        * copy each one to the new database.
+        *
+        * If we are trying to change the default tablespace of the template,
+        * we require that the template not have any files in the new default
+        * tablespace.  This avoids the need to merge two subdirectories.
+        * This could probably be improved later.
         */
-       target_dir = alt_loc ? alt_loc : nominal_loc;
+       rel = heap_openr(TableSpaceRelationName, AccessShareLock);
+       scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
+       while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
+       {
+               Oid             srctablespace = HeapTupleGetOid(tuple);
+               Oid             dsttablespace;
+               char   *srcpath;
+               char   *dstpath;
+               struct stat st;
 
-       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)));
+               /* No need to copy global tablespace */
+               if (srctablespace == GLOBALTABLESPACE_OID)
+                       continue;
 
-       /* Make the symlink, if needed */
-       if (alt_loc)
-       {
-#ifdef HAVE_SYMLINK                            /* already throws error above */
-               if (symlink(alt_loc, nominal_loc) != 0)
-#endif
+               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,
-                                       (errcode_for_file_access(),
-                                        errmsg("could not link file \"%s\" to \"%s\": %m",
-                                                       nominal_loc, alt_loc)));
-       }
+                                       (errmsg("could not initialize database directory"),
+                                        errdetail("Directory \"%s\" already exists.", dstpath)));
+               }
 
-       /*
-        * Copy the template database 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.
-        */
 #ifndef WIN32
-       /* We might need to use cp -R one day for portability */
-       snprintf(buf, sizeof(buf), "cp -r '%s' '%s'", src_loc, target_dir);
-       if (system(buf) != 0)
-       {
-               if (remove_dbdirs(nominal_loc, alt_loc))
+               /*
+                * 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,
                                        (errmsg("could not initialize database directory"),
                                         errdetail("Failing system command was: %s", buf),
                                         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 */
-       if (copydir(src_loc, target_dir) != 0)
-       {
-               /* copydir should already have given details of its troubles */
-               if (remove_dbdirs(nominal_loc, alt_loc))
+               if (copydir(srcpath, dstpath) != 0)
+               {
+                       /* copydir should already have given details of its troubles */
+                       remove_dbtablespaces(dboid);
                        ereport(ERROR,
                                        (errmsg("could not initialize database directory")));
-               else
-                       ereport(ERROR,
-                                       (errmsg("could not initialize database directory; delete failed as well")));
-       }
+               }
 #endif /* WIN32 */
+       }
+       heap_endscan(scan);
+       heap_close(rel, AccessShareLock);
 
        /*
         * 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 */
                heap_close(pg_database_rel, AccessExclusiveLock);
-               remove_dbdirs(nominal_loc, alt_loc);
+               remove_dbtablespaces(dboid);
                ereport(ERROR,
                                (errcode(ERRCODE_DUPLICATE_DATABASE),
                                 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_datvacuumxid - 1] = TransactionIdGetDatum(src_vacuumxid);
        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_datpath - 1] =
-               DirectFunctionCall1(textin, CStringGetDatum(dbpath ? dbpath : ""));
+       new_record[Anum_pg_database_dattablespace - 1] = ObjectIdGetDatum(dst_deftablespace);
 
        /*
         * We deliberately set datconfig and datacl to defaults (NULL), rather
@@ -471,14 +463,13 @@ dropdb(const char *dbname)
        int4            db_owner;
        bool            db_istemplate;
        Oid                     db_id;
-       char       *alt_loc;
-       char       *nominal_loc;
-       char            dbpath[MAXPGPATH];
        Relation        pgdbrel;
        SysScanDesc pgdbscan;
        ScanKeyData key;
        HeapTuple       tup;
 
+       PreventTransactionChain((void *) dbname, "DROP DATABASE");
+
        AssertArg(dbname);
 
        if (strcmp(dbname, get_database_name(MyDatabaseId)) == 0)
@@ -486,8 +477,6 @@ dropdb(const char *dbname)
                                (errcode(ERRCODE_OBJECT_IN_USE),
                                 errmsg("cannot drop the currently open database")));
 
-       PreventTransactionChain((void *) dbname, "DROP DATABASE");
-
        /*
         * Obtain exclusive lock on pg_database.  We need this to ensure that
         * 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);
 
        if (!get_db_info(dbname, &db_id, &db_owner, NULL,
-                                        &db_istemplate, NULL, NULL, NULL, dbpath))
+                                        &db_istemplate, NULL, NULL, NULL, NULL))
                ereport(ERROR,
                                (errcode(ERRCODE_UNDEFINED_DATABASE),
                                 errmsg("database \"%s\" does not exist", dbname)));
@@ -519,9 +508,6 @@ dropdb(const char *dbname)
                                (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                 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.
         */
@@ -585,9 +571,9 @@ dropdb(const char *dbname)
        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
@@ -831,7 +817,7 @@ static bool
 get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
                        int *encodingP, bool *dbIsTemplateP, Oid *dbLastSysOidP,
                        TransactionId *dbVacuumXidP, TransactionId *dbFrozenXidP,
-                       char *dbpath)
+                       Oid *dbTablespace)
 {
        Relation        relation;
        ScanKeyData scanKey;
@@ -880,28 +866,9 @@ get_db_info(const char *name, Oid *dbIdP, int4 *ownerIdP,
                /* limit of frozen XIDs */
                if (dbFrozenXidP)
                        *dbFrozenXidP = dbform->datfrozenxid;
-               /* database path (as registered in pg_database) */
-               if (dbpath)
-               {
-                       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, "");
-               }
+               /* default tablespace for this database */
+               if (dbTablespace)
+                       *dbTablespace = dbform->dattablespace;
        }
 
        systable_endscan(scan);
@@ -930,105 +897,60 @@ have_createdb_privilege(void)
        return retval;
 }
 
-
-static char *
-resolve_alt_dbpath(const char *dbpath, Oid dboid)
+/*
+ * Remove tablespace directories
+ *
+ * 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;
-       char       *ret;
-       size_t          len;
-
-       if (dbpath == NULL || dbpath[0] == '\0')
-               return NULL;
-
-       if (first_dir_separator(dbpath))
-       {
-               if (!is_absolute_path(dbpath))
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                        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
+       Relation rel;
+       HeapScanDesc scan;
+       HeapTuple tuple;
+       char buf[MAXPGPATH + 100];
+
+       rel = heap_openr(TableSpaceRelationName, AccessShareLock);
+       scan = heap_beginscan(rel, SnapshotNow, 0, NULL);
+       while ((tuple = heap_getnext(scan, ForwardScanDirection)) != NULL)
        {
-               /* must be environment variable */
-               char       *var = getenv(dbpath);
-
-               if (!var)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_UNDEFINED_OBJECT),
-                          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;
-       }
+               Oid             dsttablespace = HeapTupleGetOid(tuple);
+               char   *dstpath;
+               struct stat st;
 
-       len = strlen(prefix) + 6 + sizeof(Oid) * 8 + 1;
-       if (len >= MAXPGPATH - 100)
-               ereport(ERROR,
-                               (errcode(ERRCODE_INVALID_NAME),
-                                errmsg("alternative path is too long")));
+               /* Don't mess with the global tablespace */
+               if (dsttablespace == GLOBALTABLESPACE_OID)
+                       continue;
 
-       ret = palloc(len);
-       snprintf(ret, len, "%s/base/%u", prefix, dboid);
+               dstpath = GetDatabasePath(db_id, dsttablespace);
 
-       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)
+               if (stat(dstpath, &st) < 0 || !S_ISDIR(st.st_mode))
                {
-                       ereport(WARNING,
-                                       (errcode_for_file_access(),
-                                        errmsg("could not remove file \"%s\": %m", nominal_loc)));
-                       success = false;
+                       /* Assume we can ignore it */
+                       pfree(dstpath);
+                       continue;
                }
-       }
 
 #ifndef WIN32
-       snprintf(buf, sizeof(buf), "rm -rf '%s'", target_dir);
+               snprintf(buf, sizeof(buf), "rm -rf '%s'", dstpath);
 #else
-       snprintf(buf, sizeof(buf), "rmdir /s /q \"%s\"", target_dir);
+               snprintf(buf, sizeof(buf), "rmdir /s /q \"%s\"", dstpath);
 #endif
-
-       if (system(buf) != 0)
-       {
-               ereport(WARNING,
+               if (system(buf) != 0)
+               {
+                       ereport(WARNING,
                                (errmsg("could not remove database directory \"%s\"",
-                                               target_dir),
+                                               dstpath),
                                 errdetail("Failing system command was: %s", buf),
                                 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
  *
- * 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.
  */
index d141c83c1bf517fc72b44ac9488e9335df41fed4..43d9aabd046159df658f55ed385dddf144a68541 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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/defrem.h"
 #include "commands/tablecmds.h"
+#include "commands/tablespace.h"
 #include "executor/executor.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
@@ -64,6 +65,8 @@ static bool relationHasPrimaryKey(Relation rel);
  * 'indexRelationName': the name for the new index, or NULL to indicate
  *             that a nonconflicting default name should be picked.
  * '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
  *             to index on.
  * 'predicate': the partial-index condition, or NULL if none.
@@ -83,6 +86,7 @@ void
 DefineIndex(RangeVar *heapRelation,
                        char *indexRelationName,
                        char *accessMethodName,
+                       char *tableSpaceName,
                        List *attributeList,
                        Expr *predicate,
                        List *rangetable,
@@ -98,6 +102,7 @@ DefineIndex(RangeVar *heapRelation,
        Oid                     accessMethodId;
        Oid                     relationId;
        Oid                     namespaceId;
+       Oid                     tablespaceId;
        Relation        rel;
        HeapTuple       tuple;
        Form_pg_am      accessMethodForm;
@@ -151,6 +156,29 @@ DefineIndex(RangeVar *heapRelation,
                                                   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
         */
@@ -335,7 +363,7 @@ DefineIndex(RangeVar *heapRelation,
                                                indexRelationName, RelationGetRelationName(rel))));
 
        index_create(relationId, indexRelationName,
-                                indexInfo, accessMethodId, classObjectId,
+                                indexInfo, accessMethodId, tablespaceId, classObjectId,
                                 primary, isconstraint,
                                 allowSystemTableMods, skip_build);
 
index 18a212271ea27160ec6a22af0acebf3b203aedaa..8366ea634a024345550839f5456455a515afa3a3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 "commands/dbcommands.h"
 #include "commands/schemacmds.h"
+#include "commands/tablespace.h"
 #include "miscadmin.h"
 #include "parser/analyze.h"
 #include "tcop/utility.h"
@@ -41,6 +42,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
        const char *schemaName = stmt->schemaname;
        const char *authId = stmt->authid;
        Oid                     namespaceId;
+       Oid                     tablespaceId;
        List       *parsetree_list;
        ListCell   *parsetree_item;
        const char *owner_name;
@@ -100,8 +102,33 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
                                 errmsg("unacceptable schema name \"%s\"", schemaName),
                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 */
-       namespaceId = NamespaceCreate(schemaName, owner_userid);
+       namespaceId = NamespaceCreate(schemaName, owner_userid, tablespaceId);
 
        /* Advance cmd counter to make the namespace visible */
        CommandCounterIncrement();
index 351813b5decb055027428ac4444ac59b3ef8912a..1b6538b539c4d06bc8b99a692855ca65aa412d8f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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->hasoids = MUST_NOT_HAVE_OIDS;
        stmt->oncommit = ONCOMMIT_NOOP;
+       stmt->tablespacename = seq->tablespacename;
 
        seqoid = DefineRelation(stmt, RELKIND_SEQUENCE);
 
@@ -1071,8 +1072,8 @@ seq_redo(XLogRecPtr lsn, XLogRecord *record)
 
        buffer = XLogReadBuffer(true, reln, 0);
        if (!BufferIsValid(buffer))
-               elog(PANIC, "seq_redo: can't read block of %u/%u",
-                        xlrec->node.tblNode, xlrec->node.relNode);
+               elog(PANIC, "seq_redo: can't read block 0 of rel %u/%u/%u",
+                        xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
 
        page = (Page) BufferGetPage(buffer);
 
@@ -1114,6 +1115,6 @@ seq_desc(char *buf, uint8 xl_info, char *rec)
                return;
        }
 
-       sprintf(buf + strlen(buf), "node %u/%u",
-                       xlrec->node.tblNode, xlrec->node.relNode);
+       sprintf(buf + strlen(buf), "rel %u/%u/%u",
+                       xlrec->node.spcNode, xlrec->node.dbNode, xlrec->node.relNode);
 }
index 3979335313b75ca141732e5d5440b0d9a03a1da1..8fd07e396aee850737729d63d7a16f133097a8e0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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/defrem.h"
 #include "commands/tablecmds.h"
+#include "commands/tablespace.h"
 #include "commands/trigger.h"
 #include "executor/executor.h"
 #include "lib/stringinfo.h"
@@ -258,6 +259,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
        Oid                     namespaceId;
        List       *schema = stmt->tableElts;
        Oid                     relationId;
+       Oid                     tablespaceId;
        Relation        rel;
        TupleDesc       descriptor;
        List       *inheritOids;
@@ -301,6 +303,31 @@ DefineRelation(CreateStmt *stmt, char relkind)
                                                   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,
         * including inherited attributes.
@@ -379,6 +406,7 @@ DefineRelation(CreateStmt *stmt, char relkind)
 
        relationId = heap_create_with_catalog(relname,
                                                                                  namespaceId,
+                                                                                 tablespaceId,
                                                                                  descriptor,
                                                                                  relkind,
                                                                                  false,
@@ -1770,7 +1798,7 @@ ATController(Relation rel, List *cmds, bool recurse)
 /*
  * 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.
  *
  * 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
  *
  * Adds an additional attribute to a relation making the assumption that
@@ -3521,6 +3549,7 @@ ATExecAddIndex(AlteredTableInfo *tab, Relation rel,
        DefineIndex(stmt->relation,             /* relation */
                                stmt->idxname,          /* index name */
                                stmt->accessMethod, /* am name */
+                               stmt->tableSpace,
                                stmt->indexParams,      /* parameters */
                                (Expr *) stmt->whereClause,
                                stmt->rangetable,
@@ -3566,7 +3595,7 @@ ATExecAddConstraint(AlteredTableInfo *tab, Relation rel, Node *newConstraint)
                                                                                                                list_make1(constr));
                                        /* Add each constraint to Phase 3's queue */
                                        foreach(lcon, newcons)
-                                       { 
+                                       {
                                                CookedConstraint *ccon = (CookedConstraint *) lfirst(lcon);
                                                NewConstraint *newcon;
 
@@ -3643,7 +3672,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
        int16           fkattnum[INDEX_MAX_KEYS];
        Oid                     pktypoid[INDEX_MAX_KEYS];
        Oid                     fktypoid[INDEX_MAX_KEYS];
-       Oid         opclasses[INDEX_MAX_KEYS];
+       Oid                     opclasses[INDEX_MAX_KEYS];
        int                     i;
        int                     numfks,
                                numpks;
@@ -3791,7 +3820,7 @@ ATAddForeignKeyConstraint(AlteredTableInfo *tab, Relation rel,
                 * will be incurred to check FK validity.
                 */
                if (!op_in_opclass(oprid(o), opclasses[i]))
-                       ereport(WARNING, 
+                       ereport(WARNING,
                                        (errmsg("foreign key constraint \"%s\" "
                                                        "will require costly sequential scans",
                                                        fkconstraint->constr_name),
@@ -4565,7 +4594,7 @@ ATPrepAlterColumnType(List **wqueue,
        /*
         * Add a work queue item to make ATRewriteTable update the column
         * contents.
-        */ 
+        */
        newval = (NewColumnValue *) palloc0(sizeof(NewColumnValue));
        newval->attnum = attnum;
        newval->expr = (Expr *) transform;
@@ -5272,6 +5301,7 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
         */
        toast_relid = heap_create_with_catalog(toast_relname,
                                                                                   PG_TOAST_NAMESPACE,
+                                                                                  rel->rd_rel->reltablespace,
                                                                                   tupdesc,
                                                                                   RELKIND_TOASTVALUE,
                                                                                   shared_relation,
@@ -5309,7 +5339,9 @@ AlterTableCreateToastTable(Oid relOid, bool silent)
        classObjectId[1] = INT4_BTREE_OPS_OID;
 
        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);
 
        /*
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
new file mode 100644 (file)
index 0000000..d412389
--- /dev/null
@@ -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;
+}
index a64617d08d4f76b0bb840a7b9dba664bd50d1d93..d087ad8895cb4145c8e3bce3d0f85caa12c9f22e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
  *       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")));
 
        /*
-        * now create the parameters for keys/inheritance etc. All of them are
-        * nil...
+        * now set the parameters for keys/inheritance etc. All of these
+        * are uninteresting for composite types...
         */
        createStmt->relation = (RangeVar *) typevar;
        createStmt->tableElts = coldeflist;
@@ -1119,6 +1119,7 @@ DefineCompositeType(const RangeVar *typevar, List *coldeflist)
        createStmt->constraints = NIL;
        createStmt->hasoids = MUST_NOT_HAVE_OIDS;
        createStmt->oncommit = ONCOMMIT_NOOP;
+       createStmt->tablespacename = NULL;
 
        /*
         * finally create the relation...
index 4c27bd67199113ab98da4576010f54b6241eea88..679712196992301c08fa5747ba0fbeff145f6524 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
        {
                /*
-                * now create the parameters for keys/inheritance etc. All of them
-                * are nil...
+                * now set the parameters for keys/inheritance etc. All of these
+                * are uninteresting for views...
                 */
                createStmt->relation = (RangeVar *) relation;
                createStmt->tableElts = attrList;
@@ -143,6 +143,7 @@ DefineVirtualRelation(const RangeVar *relation, List *tlist, bool replace)
                createStmt->constraints = NIL;
                createStmt->hasoids = MUST_NOT_HAVE_OIDS;
                createStmt->oncommit = ONCOMMIT_NOOP;
+               createStmt->tablespacename = NULL;
 
                /*
                 * finally create the relation (this will error out if there's an
index 4099ef0a791c24a1ab454fc788eec7ab58ab9bc2..6f0f22a32213105ef3c018b8e16c6f34eac91474 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * 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,
                                                                                                  namespaceId,
+                                                                                                 InvalidOid,
                                                                                                  tupdesc,
                                                                                                  RELKIND_RELATION,
                                                                                                  false,
index bfcb82447d8e8c48ea0cbe6f2327b490d9a71c1e..90983e6db0ba53339c9410de907c8b402ea4beff 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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_SCALAR_FIELD(hasoids);
        COPY_SCALAR_FIELD(oncommit);
+       COPY_STRING_FIELD(tablespacename);
 
        return newnode;
 }
@@ -1836,6 +1837,7 @@ _copyIndexStmt(IndexStmt *from)
        COPY_STRING_FIELD(idxname);
        COPY_NODE_FIELD(relation);
        COPY_STRING_FIELD(accessMethod);
+       COPY_STRING_FIELD(tableSpace);
        COPY_NODE_FIELD(indexParams);
        COPY_NODE_FIELD(whereClause);
        COPY_NODE_FIELD(rangetable);
@@ -2146,6 +2148,7 @@ _copyCreateSeqStmt(CreateSeqStmt *from)
 
        COPY_NODE_FIELD(sequence);
        COPY_NODE_FIELD(options);
+       COPY_STRING_FIELD(tablespacename);
 
        return newnode;
 }
@@ -2193,6 +2196,28 @@ _copyVariableResetStmt(VariableResetStmt *from)
        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 *
 _copyCreateTrigStmt(CreateTrigStmt *from)
 {
@@ -2371,6 +2396,7 @@ _copyCreateSchemaStmt(CreateSchemaStmt *from)
 
        COPY_STRING_FIELD(schemaname);
        COPY_STRING_FIELD(authid);
+       COPY_STRING_FIELD(tablespacename);
        COPY_NODE_FIELD(schemaElts);
 
        return newnode;
@@ -2914,6 +2940,12 @@ copyObject(void *from)
                case T_VariableResetStmt:
                        retval = _copyVariableResetStmt(from);
                        break;
+               case T_CreateTableSpaceStmt:
+                       retval = _copyCreateTableSpaceStmt(from);
+                       break;
+               case T_DropTableSpaceStmt:
+                       retval = _copyDropTableSpaceStmt(from);
+                       break;
                case T_CreateTrigStmt:
                        retval = _copyCreateTrigStmt(from);
                        break;
index fec550836b30f9afc3359a56b7975f482da3d01e..47ec31577274487b3dc6e0c5fcec1cd941086adb 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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_SCALAR_FIELD(hasoids);
        COMPARE_SCALAR_FIELD(oncommit);
+       COMPARE_STRING_FIELD(tablespacename);
 
        return true;
 }
@@ -904,6 +905,7 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b)
        COMPARE_STRING_FIELD(idxname);
        COMPARE_NODE_FIELD(relation);
        COMPARE_STRING_FIELD(accessMethod);
+       COMPARE_STRING_FIELD(tableSpace);
        COMPARE_NODE_FIELD(indexParams);
        COMPARE_NODE_FIELD(whereClause);
        COMPARE_NODE_FIELD(rangetable);
@@ -1164,6 +1166,7 @@ _equalCreateSeqStmt(CreateSeqStmt *a, CreateSeqStmt *b)
 {
        COMPARE_NODE_FIELD(sequence);
        COMPARE_NODE_FIELD(options);
+       COMPARE_STRING_FIELD(tablespacename);
 
        return true;
 }
@@ -1203,6 +1206,24 @@ _equalVariableResetStmt(VariableResetStmt *a, VariableResetStmt *b)
        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
 _equalCreateTrigStmt(CreateTrigStmt *a, CreateTrigStmt *b)
 {
@@ -1352,6 +1373,7 @@ _equalCreateSchemaStmt(CreateSchemaStmt *a, CreateSchemaStmt *b)
 {
        COMPARE_STRING_FIELD(schemaname);
        COMPARE_STRING_FIELD(authid);
+       COMPARE_STRING_FIELD(tablespacename);
        COMPARE_NODE_FIELD(schemaElts);
 
        return true;
@@ -2052,6 +2074,12 @@ equal(void *a, void *b)
                case T_VariableResetStmt:
                        retval = _equalVariableResetStmt(a, b);
                        break;
+               case T_CreateTableSpaceStmt:
+                       retval = _equalCreateTableSpaceStmt(a, b);
+                       break;
+               case T_DropTableSpaceStmt:
+                       retval = _equalDropTableSpaceStmt(a, b);
+                       break;
                case T_CreateTrigStmt:
                        retval = _equalCreateTrigStmt(a, b);
                        break;
index 1984ced756ffdcd11b147b161808fa3d99a89a67..087ebb39a159cb977842931ba15ba7cb4e72c596 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
  *       Every node type that can appear in stored rules' parsetrees *must*
@@ -1128,7 +1128,7 @@ _outInClauseInfo(StringInfo str, InClauseInfo *node)
 static void
 _outCreateStmt(StringInfo str, CreateStmt *node)
 {
-       WRITE_NODE_TYPE("CREATE");
+       WRITE_NODE_TYPE("CREATESTMT");
 
        WRITE_NODE_FIELD(relation);
        WRITE_NODE_FIELD(tableElts);
@@ -1136,16 +1136,18 @@ _outCreateStmt(StringInfo str, CreateStmt *node)
        WRITE_NODE_FIELD(constraints);
        WRITE_ENUM_FIELD(hasoids, ContainsOids);
        WRITE_ENUM_FIELD(oncommit, OnCommitAction);
+       WRITE_STRING_FIELD(tablespacename);
 }
 
 static void
 _outIndexStmt(StringInfo str, IndexStmt *node)
 {
-       WRITE_NODE_TYPE("INDEX");
+       WRITE_NODE_TYPE("INDEXSTMT");
 
        WRITE_STRING_FIELD(idxname);
        WRITE_NODE_FIELD(relation);
        WRITE_STRING_FIELD(accessMethod);
+       WRITE_STRING_FIELD(tableSpace);
        WRITE_NODE_FIELD(indexParams);
        WRITE_NODE_FIELD(whereClause);
        WRITE_NODE_FIELD(rangetable);
index e5537e26ae99355426e6795a32ce14e444af28d4..5450103156217bbd92747aa07b9b3b6375a346ad 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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->sequence = makeRangeVar(snamespace, sname);
                seqstmt->options = NIL;
+               seqstmt->tablespacename = NULL;
 
                cxt->blist = lappend(cxt->blist, seqstmt);
 
@@ -1199,6 +1200,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
 
                index->relation = cxt->relation;
                index->accessMethod = DEFAULT_INDEX_TYPE;
+               index->tableSpace = NULL;
                index->indexParams = NIL;
                index->whereClause = NULL;
 
index 07a882f3db50906fadf17cd2e9255b30226a6ab1..9dc53604c61f2ed5cb66e06fc417c732fb32992d 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * 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
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -136,12 +136,12 @@ static void doNegateFloat(Value *v);
                AnalyzeStmt ClosePortalStmt ClusterStmt CommentStmt
                ConstraintsSetStmt CopyStmt CreateAsStmt CreateCastStmt
                CreateDomainStmt CreateGroupStmt CreateOpClassStmt CreatePLangStmt
-               CreateSchemaStmt CreateSeqStmt CreateStmt
+               CreateSchemaStmt CreateSeqStmt CreateStmt CreateTableSpaceStmt
                CreateAssertStmt CreateTrigStmt CreateUserStmt
                CreatedbStmt DeclareCursorStmt DefineStmt DeleteStmt
                DropGroupStmt DropOpClassStmt DropPLangStmt DropStmt
                DropAssertStmt DropTrigStmt DropRuleStmt DropCastStmt
-               DropUserStmt DropdbStmt ExplainStmt FetchStmt
+               DropUserStmt DropdbStmt DropTableSpaceStmt ExplainStmt FetchStmt
                GrantStmt IndexStmt InsertStmt ListenStmt LoadStmt
                LockStmt NotifyStmt ExplainableStmt PreparableStmt
                CreateFunctionStmt ReindexStmt RemoveAggrStmt
@@ -324,6 +324,7 @@ static void doNegateFloat(Value *v);
 
 %type <list>   constraints_set_list
 %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
 
        PARTIAL PASSWORD PATH_P PENDANT PLACING POSITION
-       PRECISION PRESERVE PREPARE PRIMARY 
+       PRECISION PRESERVE PREPARE PRIMARY
        PRIOR PRIVILEGES PROCEDURAL PROCEDURE
 
        QUOTE
@@ -398,7 +399,7 @@ static void doNegateFloat(Value *v);
        SHOW SIMILAR SIMPLE SMALLINT SOME STABLE START STATEMENT
        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
        TRUNCATE TRUSTED TYPE_P
 
@@ -513,6 +514,7 @@ stmt :
                        | CreateSchemaStmt
                        | CreateSeqStmt
                        | CreateStmt
+                       | CreateTableSpaceStmt
                        | CreateTrigStmt
                        | CreateUserStmt
                        | CreatedbStmt
@@ -527,6 +529,7 @@ stmt :
                        | DropPLangStmt
                        | DropRuleStmt
                        | DropStmt
+                       | DropTableSpaceStmt
                        | DropTrigStmt
                        | DropUserStmt
                        | DropdbStmt
@@ -781,7 +784,7 @@ DropGroupStmt:
  *****************************************************************************/
 
 CreateSchemaStmt:
-                       CREATE SCHEMA OptSchemaName AUTHORIZATION UserId OptSchemaEltList
+                       CREATE SCHEMA OptSchemaName AUTHORIZATION UserId OptTableSpace OptSchemaEltList
                                {
                                        CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
                                        /* One can omit the schema name or the authorization id. */
@@ -790,16 +793,18 @@ CreateSchemaStmt:
                                        else
                                                n->schemaname = $5;
                                        n->authid = $5;
-                                       n->schemaElts = $6;
+                                       n->tablespacename = $6;
+                                       n->schemaElts = $7;
                                        $$ = (Node *)n;
                                }
-                       | CREATE SCHEMA ColId OptSchemaEltList
+                       | CREATE SCHEMA ColId OptTableSpace OptSchemaEltList
                                {
                                        CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
                                        /* ...but not both */
                                        n->schemaname = $3;
                                        n->authid = NULL;
-                                       n->schemaElts = $4;
+                                       n->tablespacename = $4;
+                                       n->schemaElts = $5;
                                        $$ = (Node *)n;
                                }
                ;
@@ -1277,7 +1282,7 @@ alter_table_cmd:
                                        n->name = $3;
                                        $$ = (Node *)n;
                                }
-                       /* ALTER TABLE <name> SET WITHOUT CLUSTER */ 
+                       /* ALTER TABLE <name> SET WITHOUT CLUSTER */
                        | SET WITHOUT CLUSTER
                                {
                                        AlterTableCmd *n = makeNode(AlterTableCmd);
@@ -1464,7 +1469,7 @@ opt_using:
  *****************************************************************************/
 
 CreateStmt:    CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
-                       OptInherit OptWithOids OnCommitOption
+                       OptInherit OptWithOids OnCommitOption OptTableSpace
                                {
                                        CreateStmt *n = makeNode(CreateStmt);
                                        $4->istemp = $2;
@@ -1474,10 +1479,11 @@ CreateStmt:     CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
                                        n->constraints = NIL;
                                        n->hasoids = $9;
                                        n->oncommit = $10;
+                                       n->tablespacename = $11;
                                        $$ = (Node *)n;
                                }
                | 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
                                         * by our inheritance capabilities. Let's try it...
@@ -1490,6 +1496,7 @@ CreateStmt:       CREATE OptTemp TABLE qualified_name '(' OptTableElementList ')'
                                        n->constraints = NIL;
                                        n->hasoids = $10;
                                        n->oncommit = $11;
+                                       n->tablespacename = $12;
                                        $$ = (Node *)n;
                                }
                ;
@@ -1901,6 +1908,10 @@ OnCommitOption:  ON COMMIT DROP                          { $$ = ONCOMMIT_DROP; }
                        | /*EMPTY*/                                             { $$ = ONCOMMIT_NOOP; }
                ;
 
+OptTableSpace:   TABLESPACE name                                       { $$ = $2; }
+                       | /*EMPTY*/                                                             { $$ = NULL; }
+               ;
+
 
 /*
  * Note: CREATE TABLE ... AS SELECT ... is just another spelling for
@@ -1979,12 +1990,13 @@ CreateAsElement:
  *****************************************************************************/
 
 CreateSeqStmt:
-                       CREATE OptTemp SEQUENCE qualified_name OptSeqList
+                       CREATE OptTemp SEQUENCE qualified_name OptSeqList OptTableSpace
                                {
                                        CreateSeqStmt *n = makeNode(CreateSeqStmt);
                                        $4->istemp = $2;
                                        n->sequence = $4;
                                        n->options = $5;
+                                       n->tablespacename = $6;
                                        $$ = (Node *)n;
                                }
                ;
@@ -2134,6 +2146,45 @@ opt_procedural:
                        | /*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 :
@@ -2735,7 +2786,7 @@ CommentStmt:
                                        n->objargs = NIL;
                                        n->comment = $7;
                                        $$ = (Node *) n;
-                               }                               
+                               }
                ;
 
 comment_type:
@@ -3026,6 +3077,13 @@ privilege_target:
                                        n->objs = $2;
                                        $$ = 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:
  *                             create index <indexname> on <relname>
  *                               [ 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
-                       access_method_clause '(' index_params ')' where_clause
+                       access_method_clause '(' index_params ')' OptTableSpace where_clause
                                {
                                        IndexStmt *n = makeNode(IndexStmt);
                                        n->unique = $2;
@@ -3105,7 +3165,8 @@ IndexStmt:        CREATE index_opt_unique INDEX index_name ON qualified_name
                                        n->relation = $6;
                                        n->accessMethod = $7;
                                        n->indexParams = $9;
-                                       n->whereClause = $11;
+                                       n->tableSpace = $11;
+                                       n->whereClause = $12;
                                        $$ = (Node *)n;
                                }
                ;
@@ -3896,7 +3957,15 @@ createdb_opt_list:
                ;
 
 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));
                                }
@@ -6801,7 +6870,7 @@ subquery_Op:
                                        { $$ = list_make1(makeString("!~~*")); }
 /* cannot put SIMILAR TO here, because SIMILAR TO is a hack.
  * 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)
  * this transformation is made on the fly by the parser upwards.
  * however the SubLink structure which handles any/some/all stuff
@@ -6978,7 +7047,7 @@ in_expr:  select_with_parens
  *     COALESCE(a,b,...)
  * same as CASE WHEN a IS NOT NULL THEN a WHEN b IS NOT NULL THEN b ... END
  * - thomas 1998-11-09
- * 
+ *
  * NULLIF and COALESCE have become first class nodes to
  * prevent double evaluation of arguments.
  * - Kris Jurka 2003-02-11
@@ -7565,6 +7634,7 @@ unreserved_keyword:
                        | STORAGE
                        | SYSID
                        | STRICT_P
+                       | TABLESPACE
                        | TEMP
                        | TEMPLATE
                        | TEMPORARY
index a3c765a1952857128ff19cb034d9ada14cf69d16..a89f8da7d4ece07765c81037fbff52f38933ee63 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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},
        {"sysid", SYSID},
        {"table", TABLE},
+       {"tablespace", TABLESPACE},
        {"temp", TEMP},
        {"template", TEMPLATE},
        {"temporary", TEMPORARY},
index da1998a0d50c19226eaf4e3d3d538205f5111242..725b79cad388786a6c46fffcafa468f54ea06ab0 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 *));
        buftags = (BufferTag *) palloc(NBuffers * sizeof(BufferTag));
-       
+
        LWLockAcquire(BufMgrLock, LW_EXCLUSIVE);
        num_buffer_dirty = StrategyDirtyBufferList(dirty_buffers, buftags,
                                                                                           NBuffers);
@@ -832,9 +832,10 @@ AtEOXact_Buffers(bool isCommit)
                        if (isCommit)
                                elog(WARNING,
                                         "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,
-                                        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->refcount, PrivateRefCount[i]);
 
@@ -1137,9 +1138,10 @@ recheck:
                        {
                                /* the sole pin should be ours */
                                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.rnode.tblNode,
+                                                bufHdr->tag.rnode.spcNode,
+                                                bufHdr->tag.rnode.dbNode,
                                                 bufHdr->tag.rnode.relNode,
                                                 PrivateRefCount[i - 1], bufHdr->refcount);
                                /* Make sure it will be released */
@@ -1180,13 +1182,7 @@ DropBuffers(Oid dbid)
        {
                bufHdr = &BufferDescriptors[i - 1];
 recheck:
-
-               /*
-                * 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 (bufHdr->tag.rnode.dbNode == dbid)
                {
                        /*
                         * 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)
                {
                        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)",
                                 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->refcount, PrivateRefCount[i]);
                }
@@ -1257,9 +1254,9 @@ PrintBufferDescs(void)
                /* interactive backend */
                for (i = 0; i < NBuffers; ++i, ++buf)
                {
-                       printf("[%-2d] (%u/%u, %u) flags=0x%x, refcount=%u %d)\n",
-                                  i, buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
-                                  buf->tag.blockNum,
+                       printf("[%-2d] (%u/%u/%u, %u) flags=0x%x, refcount=%u %d)\n",
+                                  i, buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
+                                  buf->tag.rnode.relNode, buf->tag.blockNum,
                                   buf->flags, buf->refcount, PrivateRefCount[i]);
                }
        }
@@ -1278,10 +1275,11 @@ PrintPinnedBufs(void)
        {
                if (PrivateRefCount[i] > 0)
                        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)",
                                 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->refcount, PrivateRefCount[i]);
        }
@@ -1464,11 +1462,11 @@ IncrBufferRefCount_Debug(char *file, int line, Buffer buffer)
                BufferDesc *buf = &BufferDescriptors[buffer - 1];
 
                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",
                                buffer,
-                               buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
-                               buf->tag.blockNum,
+                               buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
+                               buf->tag.rnode.relNode, buf->tag.blockNum,
                                PrivateRefCount[buffer - 1], file, line);
        }
 }
@@ -1484,11 +1482,11 @@ ReleaseBuffer_Debug(char *file, int line, Buffer buffer)
                BufferDesc *buf = &BufferDescriptors[buffer - 1];
 
                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",
                                buffer,
-                               buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
-                               buf->tag.blockNum,
+                               buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
+                               buf->tag.rnode.relNode, buf->tag.blockNum,
                                PrivateRefCount[buffer - 1], file, line);
        }
 }
@@ -1513,11 +1511,11 @@ ReleaseAndReadBuffer_Debug(char *file,
                BufferDesc *buf = &BufferDescriptors[buffer - 1];
 
                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",
                                buffer,
-                               buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
-                               buf->tag.blockNum,
+                               buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
+                               buf->tag.rnode.relNode, buf->tag.blockNum,
                                PrivateRefCount[buffer - 1], file, line);
        }
        if (ShowPinTrace && BufferIsLocal(buffer) && is_userbuffer(buffer))
@@ -1525,11 +1523,11 @@ ReleaseAndReadBuffer_Debug(char *file,
                BufferDesc *buf = &BufferDescriptors[b - 1];
 
                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",
                                b,
-                               buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
-                               buf->tag.blockNum,
+                               buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
+                               buf->tag.rnode.relNode, buf->tag.blockNum,
                                PrivateRefCount[b - 1], file, line);
        }
        return b;
@@ -1890,9 +1888,10 @@ AbortBufferIO(void)
                        {
                                ereport(WARNING,
                                                (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.rnode.tblNode,
+                                                               buf->tag.rnode.spcNode,
+                                                               buf->tag.rnode.dbNode,
                                                                buf->tag.rnode.relNode),
                                                 errdetail("Multiple failures --- write error may be permanent.")));
                        }
@@ -1912,7 +1911,9 @@ buffer_write_error_callback(void *arg)
        BufferDesc *bufHdr = (BufferDesc *) arg;
 
        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.rnode.tblNode, bufHdr->tag.rnode.relNode);
+                                  bufHdr->tag.rnode.spcNode,
+                                  bufHdr->tag.rnode.dbNode,
+                                  bufHdr->tag.rnode.relNode);
 }
index 95e86e955d19a5cddefca88828c4e9a6f4a7bd02..f4d1163f16ac061b06c55f7a1b8eb9730bda9eed 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * 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)
                                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,
-                                        buf->tag.rnode.tblNode, buf->tag.rnode.relNode,
-                                        buf->tag.blockNum, buf->flags,
+                                        buf->tag.rnode.spcNode, buf->tag.rnode.dbNode,
+                                        buf->tag.rnode.relNode, buf->tag.blockNum, buf->flags,
                                         buf->refcount, LocalRefCount[i]);
 
                        LocalRefCount[i] = 0;
index 527ad8496ab63c6d5f44d7be9dd6612eb0481e13..28815e6d77fb8d0c4cc077b7375ce827c163f11a 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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:
@@ -658,9 +658,6 @@ FreeSpaceMapForgetRel(RelFileNode *rel)
  *
  * This is called during DROP DATABASE.  As above, might as well reclaim
  * map space sooner instead of later.
- *
- * XXX when we implement tablespaces, target Oid will need to be tablespace
- * ID not database ID.
  */
 void
 FreeSpaceMapForgetDatabase(Oid dbid)
@@ -672,7 +669,7 @@ FreeSpaceMapForgetDatabase(Oid dbid)
        for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = nextrel)
        {
                nextrel = fsmrel->nextUsage;    /* in case we delete it */
-               if (fsmrel->key.tblNode == dbid)
+               if (fsmrel->key.dbNode == dbid)
                        delete_fsm_rel(fsmrel);
        }
        LWLockRelease(FreeSpaceLock);
@@ -1847,8 +1844,9 @@ DumpFreeSpace(void)
        for (fsmrel = FreeSpaceMap->usageList; fsmrel; fsmrel = fsmrel->nextUsage)
        {
                relNum++;
-               fprintf(stderr, "Map %d: rel %u/%u isIndex %d avgRequest %u lastPageCount %d nextPage %d\nMap= ",
-                               relNum, fsmrel->key.tblNode, fsmrel->key.relNode,
+               fprintf(stderr, "Map %d: rel %u/%u/%u isIndex %d avgRequest %u lastPageCount %d nextPage %d\nMap= ",
+                               relNum,
+                               fsmrel->key.spcNode, fsmrel->key.dbNode, fsmrel->key.relNode,
                                (int) fsmrel->isIndex, fsmrel->avgRequest,
                                fsmrel->lastPageCount, fsmrel->nextPage);
                if (fsmrel->isIndex)
index 4f0d241215d05d96fb9d01dad6ddf78698638571..b0d667b836936f0b895ffbdcd444dd8fba1492e1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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;
                        ereport(ERROR,
                                        (errcode_for_file_access(),
-                                        errmsg("could not open relation %u/%u: %m",
-                                                       reln->smgr_rnode.tblNode,
+                                        errmsg("could not open relation %u/%u/%u: %m",
+                                                       reln->smgr_rnode.spcNode,
+                                                       reln->smgr_rnode.dbNode,
                                                        reln->smgr_rnode.relNode)));
                }
        }
@@ -765,9 +766,10 @@ mdsync(void)
                                {
                                        ereport(LOG,
                                                        (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->rnode.tblNode,
+                                                                       entry->rnode.spcNode,
+                                                                       entry->rnode.dbNode,
                                                                        entry->rnode.relNode)));
                                        return false;
                                }
@@ -945,9 +947,10 @@ _mdfd_getseg(SMgrRelation reln, BlockNumber blkno, bool allowNotFound)
                                        return NULL;
                                ereport(ERROR,
                                                (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,
-                                                               reln->smgr_rnode.tblNode,
+                                                               reln->smgr_rnode.spcNode,
+                                                               reln->smgr_rnode.dbNode,
                                                                reln->smgr_rnode.relNode,
                                                                blkno)));
                        }
index 8977f026e4f781976a6995d836cb322624141d22..c7783d878f258de072df54996c60e5f57b378fcc 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * 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))
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not close relation %u/%u: %m",
-                                               reln->smgr_rnode.tblNode,
+                                errmsg("could not close relation %u/%u/%u: %m",
+                                               reln->smgr_rnode.spcNode,
+                                               reln->smgr_rnode.dbNode,
                                                reln->smgr_rnode.relNode)));
 
        if (hash_search(SMgrRelationHash,
@@ -308,8 +309,9 @@ smgrcreate(SMgrRelation reln, bool isTemp, bool isRedo)
        if (! (*(smgrsw[reln->smgr_which].smgr_create)) (reln, isRedo))
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not create relation %u/%u: %m",
-                                               reln->smgr_rnode.tblNode,
+                                errmsg("could not create relation %u/%u/%u: %m",
+                                               reln->smgr_rnode.spcNode,
+                                               reln->smgr_rnode.dbNode,
                                                reln->smgr_rnode.relNode)));
 
        if (isRedo)
@@ -427,8 +429,9 @@ smgr_internal_unlink(RelFileNode rnode, int which, bool isTemp, bool isRedo)
        if (! (*(smgrsw[which].smgr_unlink)) (rnode, isRedo))
                ereport(WARNING,
                                (errcode_for_file_access(),
-                                errmsg("could not unlink relation %u/%u: %m",
-                                               rnode.tblNode,
+                                errmsg("could not unlink relation %u/%u/%u: %m",
+                                               rnode.spcNode,
+                                               rnode.dbNode,
                                                rnode.relNode)));
 }
 
@@ -447,8 +450,9 @@ smgrextend(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
                                                                                                         isTemp))
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not extend relation %u/%u: %m",
-                                               reln->smgr_rnode.tblNode,
+                                errmsg("could not extend relation %u/%u/%u: %m",
+                                               reln->smgr_rnode.spcNode,
+                                               reln->smgr_rnode.dbNode,
                                                reln->smgr_rnode.relNode),
                                 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))
                ereport(ERROR,
                                (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,
-                                               reln->smgr_rnode.tblNode,
+                                               reln->smgr_rnode.spcNode,
+                                               reln->smgr_rnode.dbNode,
                                                reln->smgr_rnode.relNode)));
 }
 
@@ -491,9 +496,10 @@ smgrwrite(SMgrRelation reln, BlockNumber blocknum, char *buffer, bool isTemp)
                                                                                                        isTemp))
                ereport(ERROR,
                                (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,
-                                               reln->smgr_rnode.tblNode,
+                                               reln->smgr_rnode.spcNode,
+                                               reln->smgr_rnode.dbNode,
                                                reln->smgr_rnode.relNode)));
 }
 
@@ -520,8 +526,9 @@ smgrnblocks(SMgrRelation reln)
        if (nblocks == InvalidBlockNumber)
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not count blocks of relation %u/%u: %m",
-                                               reln->smgr_rnode.tblNode,
+                                errmsg("could not count blocks of relation %u/%u/%u: %m",
+                                               reln->smgr_rnode.spcNode,
+                                               reln->smgr_rnode.dbNode,
                                                reln->smgr_rnode.relNode)));
 
        return nblocks;
@@ -552,8 +559,9 @@ smgrtruncate(SMgrRelation reln, BlockNumber nblocks, bool isTemp)
        if (newblks == InvalidBlockNumber)
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not truncate relation %u/%u to %u blocks: %m",
-                                               reln->smgr_rnode.tblNode,
+                                errmsg("could not truncate relation %u/%u/%u to %u blocks: %m",
+                                               reln->smgr_rnode.spcNode,
+                                               reln->smgr_rnode.dbNode,
                                                reln->smgr_rnode.relNode,
                                                nblocks)));
 
@@ -607,8 +615,9 @@ smgrimmedsync(SMgrRelation reln)
        if (! (*(smgrsw[reln->smgr_which].smgr_immedsync)) (reln))
                ereport(ERROR,
                                (errcode_for_file_access(),
-                                errmsg("could not sync relation %u/%u: %m",
-                                               reln->smgr_rnode.tblNode,
+                                errmsg("could not sync relation %u/%u/%u: %m",
+                                               reln->smgr_rnode.spcNode,
+                                               reln->smgr_rnode.dbNode,
                                                reln->smgr_rnode.relNode)));
 }
 
@@ -775,8 +784,9 @@ smgr_redo(XLogRecPtr lsn, XLogRecord *record)
                if (newblks == InvalidBlockNumber)
                        ereport(WARNING,
                                        (errcode_for_file_access(),
-                                        errmsg("could not truncate relation %u/%u to %u blocks: %m",
-                                                       reln->smgr_rnode.tblNode,
+                                        errmsg("could not truncate relation %u/%u/%u to %u blocks: %m",
+                                                       reln->smgr_rnode.spcNode,
+                                                       reln->smgr_rnode.dbNode,
                                                        reln->smgr_rnode.relNode,
                                                        xlrec->blkno)));
        }
@@ -800,16 +810,17 @@ smgr_desc(char *buf, uint8 xl_info, char *rec)
        {
                xl_smgr_create *xlrec = (xl_smgr_create *) rec;
 
-               sprintf(buf + strlen(buf), "file create: %u/%u",
-                               xlrec->rnode.tblNode, xlrec->rnode.relNode);
+               sprintf(buf + strlen(buf), "file create: %u/%u/%u",
+                               xlrec->rnode.spcNode, xlrec->rnode.dbNode,
+                               xlrec->rnode.relNode);
        }
        else if (info == XLOG_SMGR_TRUNCATE)
        {
                xl_smgr_truncate *xlrec = (xl_smgr_truncate *) rec;
 
-               sprintf(buf + strlen(buf), "file truncate: %u/%u to %u blocks",
-                               xlrec->rnode.tblNode, xlrec->rnode.relNode,
-                               xlrec->blkno);
+               sprintf(buf + strlen(buf), "file truncate: %u/%u/%u to %u blocks",
+                               xlrec->rnode.spcNode, xlrec->rnode.dbNode,
+                               xlrec->rnode.relNode, xlrec->blkno);
        }
        else
                strcat(buf, "UNKNOWN");
index 4d6c246cea1a8ba483f14670889e1abc881d834b..d12cf0d750f9303cfb40face12b6878f7ef16624 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * 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/sequence.h"
 #include "commands/tablecmds.h"
+#include "commands/tablespace.h"
 #include "commands/trigger.h"
 #include "commands/typecmds.h"
 #include "commands/user.h"
@@ -258,6 +259,7 @@ check_xact_readonly(Node *parsetree)
                case T_CreateSchemaStmt:
                case T_CreateSeqStmt:
                case T_CreateStmt:
+               case T_CreateTableSpaceStmt:
                case T_CreateTrigStmt:
                case T_CompositeTypeStmt:
                case T_CreateUserStmt:
@@ -266,6 +268,7 @@ check_xact_readonly(Node *parsetree)
                case T_DropCastStmt:
                case T_DropStmt:
                case T_DropdbStmt:
+               case T_DropTableSpaceStmt:
                case T_RemoveFuncStmt:
                case T_DropGroupStmt:
                case T_DropPLangStmt:
@@ -404,6 +407,14 @@ ProcessUtility(Node *parsetree,
                        }
                        break;
 
+               case T_CreateTableSpaceStmt:
+                       CreateTableSpace((CreateTableSpaceStmt *) parsetree);
+                       break;
+
+               case T_DropTableSpaceStmt:
+                       DropTableSpace((DropTableSpaceStmt *) parsetree);
+                       break;
+
                case T_DropStmt:
                        {
                                DropStmt   *stmt = (DropStmt *) parsetree;
@@ -636,6 +647,7 @@ ProcessUtility(Node *parsetree,
                                DefineIndex(stmt->relation,             /* relation */
                                                        stmt->idxname,          /* index name */
                                                        stmt->accessMethod, /* am name */
+                                                       stmt->tableSpace,
                                                        stmt->indexParams,      /* parameters */
                                                        (Expr *) stmt->whereClause,
                                                        stmt->rangetable,
@@ -1153,6 +1165,14 @@ CreateCommandTag(Node *parsetree)
                        tag = "CREATE TABLE";
                        break;
 
+               case T_CreateTableSpaceStmt:
+                       tag = "CREATE TABLESPACE";
+                       break;
+
+               case T_DropTableSpaceStmt:
+                       tag = "DROP TABLESPACE";
+                       break;
+
                case T_DropStmt:
                        switch (((DropStmt *) parsetree)->removeType)
                        {
@@ -1224,6 +1244,9 @@ CreateCommandTag(Node *parsetree)
                                case OBJECT_SCHEMA:
                                        tag = "ALTER SCHEMA";
                                        break;
+                               case OBJECT_TABLESPACE:
+                                       tag = "ALTER TABLESPACE";
+                                       break;
                                case OBJECT_TRIGGER:
                                        tag = "ALTER TRIGGER";
                                        break;
index d02683245acd2ec3fe92f6b480b1639cc2c4f842..4b13e318be6c69c8025356f0e9f7f6e8f2d1a91d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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;
                        owner_default = ACL_ALL_RIGHTS_NAMESPACE;
                        break;
+               case ACL_OBJECT_TABLESPACE:
+                       world_default = ACL_NO_RIGHTS;
+                       owner_default = ACL_ALL_RIGHTS_TABLESPACE;
+                       break;
                default:
                        elog(ERROR, "unrecognized objtype: %d", (int) objtype);
                        world_default = ACL_NO_RIGHTS;          /* keep compiler quiet */
index 4caaabd62cdd53c1e250a8238d8dc6e35830a58f..1a2fe54d7ace4c19861fd9b4a7f1de1a849c2341 100644 (file)
@@ -3,7 +3,7 @@
  *                             back to source text
  *
  * 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.
  *
@@ -53,6 +53,7 @@
 #include "catalog/pg_operator.h"
 #include "catalog/pg_shadow.h"
 #include "catalog/pg_trigger.h"
+#include "commands/tablespace.h"
 #include "executor/spi.h"
 #include "lib/stringinfo.h"
 #include "nodes/makefuncs.h"
@@ -767,6 +768,23 @@ pg_get_indexdef_worker(Oid indexrelid, int colno, int prettyFlags)
        {
                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
                 */
index 7b00f0531e2c56f221e2afdbbe7b50f58d964142..ea958a27b46be097fc8ae701593bc3659207897e 100644 (file)
@@ -74,7 +74,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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 */
        /* relfilenode fields must be checked to support reassignment */
        ProcessMessageList(hdr->rclist,
-                                          if (msg->rc.relId == relId && 
+                                          if (msg->rc.relId == relId &&
                                                   RelFileNodeEquals(msg->rc.physId, physId)) return);
 
        /* OK, add the item */
@@ -555,14 +555,18 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
                        databaseId = InvalidOid;
                else
                        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;
                /*
                 * 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
-                * will broadcast invalidation messages showing both the old and new
-                * relfilenode values.  This ensures that other backends will close
-                * smgr references to the old relfilenode file.
+                * or reltablespace value, we will be called on both the old and new
+                * tuples, and thus will broadcast invalidation messages showing both
+                * the old and new RelFileNode values.  This ensures that other
+                * backends will close smgr references to the old file.
                 */
        }
        else if (tupleRelId == RelOid_pg_attribute)
@@ -580,7 +584,8 @@ PrepareForTupleInvalidation(Relation relation, HeapTuple tuple,
                 */
                databaseId = MyDatabaseId;
                /* We assume no smgr cache flush is needed, either */
-               rnode.tblNode = InvalidOid;
+               rnode.spcNode = InvalidOid;
+               rnode.dbNode = InvalidOid;
                rnode.relNode = InvalidOid;
        }
        else
@@ -760,7 +765,11 @@ CacheInvalidateRelcacheByTuple(HeapTuple classTuple)
                databaseId = InvalidOid;
        else
                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;
 
        RegisterRelcacheInvalidation(databaseId, relationId, rnode);
index d51d1c18925bf5e14aa7d609568691b14ceb98ea..1621982502abf4226cc63bf9342633499dd0e39e 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * 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
  *       Eventually, the index information should go through here, too.
@@ -985,6 +985,34 @@ get_rel_namespace(Oid relid)
                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
  *
@@ -1980,6 +2008,34 @@ get_namespace_name(Oid nspid)
                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 ----------                                    */
 
 /*
index 4221976f0b168b711b62bb49938dd0134965c188..ee8b46407e1b75fe52092b064194ce70705d780c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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);
 static Relation RelationBuildDesc(RelationBuildDescInfo buildinfo,
                                  Relation oldrelation);
+static void RelationInitPhysicalAddr(Relation relation);
 static void AttrDefaultFetch(Relation relation);
 static void CheckConstraintFetch(Relation relation);
 static List *insert_ordered_oid(List *list, Oid datum);
@@ -873,11 +874,10 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
         */
        RelationInitLockInfo(relation);         /* see lmgr.c */
 
-       if (relation->rd_rel->relisshared)
-               relation->rd_node.tblNode = InvalidOid;
-       else
-               relation->rd_node.tblNode = MyDatabaseId;
-       relation->rd_node.relNode = relation->rd_rel->relfilenode;
+       /*
+        * initialize physical addressing information for the relation
+        */
+       RelationInitPhysicalAddr(relation);
 
        /* make sure relation is marked as having no open file yet */
        relation->rd_smgr = NULL;
@@ -892,6 +892,23 @@ RelationBuildDesc(RelationBuildDescInfo buildinfo,
        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
  */
@@ -1343,18 +1360,17 @@ formrdesc(const char *relationName,
         * initialize relation id from info in att array (my, this is ugly)
         */
        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 */
 
-       if (relation->rd_rel->relisshared)
-               relation->rd_node.tblNode = InvalidOid;
-       else
-               relation->rd_node.tblNode = MyDatabaseId;
-       relation->rd_node.relNode =
-               relation->rd_rel->relfilenode = RelationGetRelid(relation);
+       /*
+        * initialize physical addressing information for the relation
+        */
+       RelationInitPhysicalAddr(relation);
 
        /*
         * initialize the rel-has-index flag, using hardwired knowledge
@@ -1570,7 +1586,8 @@ RelationReloadClassinfo(Relation relation)
                         relation->rd_id);
        relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
        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);
        relation->rd_targblock = InvalidBlockNumber;
        /* Okay, now it's valid again */
@@ -2040,8 +2057,9 @@ Relation
 RelationBuildLocalRelation(const char *relname,
                                                   Oid relnamespace,
                                                   TupleDesc tupDesc,
-                                                  Oid relid, Oid dbid,
-                                                  RelFileNode rnode,
+                                                  Oid relid,
+                                                  Oid reltablespace,
+                                                  bool shared_relation,
                                                   bool nailit)
 {
        Relation        rel;
@@ -2125,20 +2143,23 @@ RelationBuildLocalRelation(const char *relname,
 
        /*
         * 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;
 
        for (i = 0; i < natts; i++)
                rel->rd_att->attrs[i]->attrelid = relid;
 
-       rel->rd_node = rnode;
-       rel->rd_rel->relfilenode = rnode.relNode;
+       rel->rd_rel->relfilenode = relid;
+       rel->rd_rel->reltablespace = reltablespace;
 
        RelationInitLockInfo(rel);      /* see lmgr.c */
 
+       RelationInitPhysicalAddr(rel);
+
        /*
         * 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));
 
                /*
-                * Make sure database ID is correct.  This is needed in case the
-                * pg_internal.init file was copied from some other database by
-                * CREATE DATABASE.
+                * Recompute lock and physical addressing info.  This is needed in
+                * case the pg_internal.init file was copied from some other database
+                * by CREATE DATABASE.
                 */
-               if (rel->rd_rel->relisshared)
-                       rel->rd_node.tblNode = InvalidOid;
-               else
-                       rel->rd_node.tblNode = MyDatabaseId;
-
                RelationInitLockInfo(rel);
+               RelationInitPhysicalAddr(rel);
        }
 
        /*
index 3a5d33724a4de0d385293436af147ff7454e6109..4f0f8b67c24cbf0270ff8059dc4197dfdf4b71c8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
  *       Globals used all over the place should be declared here and not
@@ -58,6 +58,8 @@ BackendId     MyBackendId = InvalidBackendId;
 char      *DatabasePath = NULL;
 Oid                    MyDatabaseId = InvalidOid;
 
+Oid                    MyDatabaseTableSpace = InvalidOid;
+
 pid_t          PostmasterPid = 0;
 
 /*
index 6f9ff5aef4dbf71e0e456519bb780766a5a3a08c..b0c5ff82e3863ec2547e5dc186b4c991f7f36bb5 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
 {
        char       *new;
-       int                     newlen;
 
        AssertArg(dir);
 
@@ -212,13 +211,7 @@ SetDataDir(const char *dir)
         * Strip any trailing slash.  Not strictly necessary, but avoids
         * generating funny-looking paths to individual files.
         */
-       newlen = strlen(new);
-       if (newlen > 1 && (new[newlen - 1] == '/'
-#ifdef WIN32
-               || new[newlen - 1] == '\\'
-#endif
-               ))
-               new[newlen - 1] = '\0';
+       canonicalize_path(new);
 
        if (DataDir)
                free(DataDir);
index e80187d57523403ad6ae1bd424f173f58e14d15a..48d28d429f214c9db40423b19a805d4886b12bdd 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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/pg_database.h"
 #include "catalog/pg_shadow.h"
+#include "catalog/pg_tablespace.h"
 #include "commands/trigger.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
@@ -239,12 +240,12 @@ InitPostgres(const char *dbname, const char *username)
        if (bootstrap)
        {
                MyDatabaseId = TemplateDbOid;
-               SetDatabasePath(GetDatabasePath(MyDatabaseId));
+               MyDatabaseTableSpace = DEFAULTTABLESPACE_OID;
+               SetDatabasePath(GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace));
        }
        else
        {
-               char       *fullpath,
-                                       datpath[MAXPGPATH];
+               char       *fullpath;
 
                /*
                 * 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
-                * we're not yet up and running we have to use the hackish
+                * Find oid and tablespace of the database we're about to open.
+                * Since we're not yet up and running we have to use the hackish
                 * GetRawDatabaseInfo.
                 */
-               GetRawDatabaseInfo(dbname, &MyDatabaseId, datpath);
+               GetRawDatabaseInfo(dbname, &MyDatabaseId, &MyDatabaseTableSpace);
 
                if (!OidIsValid(MyDatabaseId))
                        ereport(FATAL,
@@ -264,7 +265,7 @@ InitPostgres(const char *dbname, const char *username)
                                         errmsg("database \"%s\" does not exist",
                                                        dbname)));
 
-               fullpath = GetDatabasePath(MyDatabaseId);
+               fullpath = GetDatabasePath(MyDatabaseId, MyDatabaseTableSpace);
 
                /* Verify the database path */
 
index 37844a03a94d670cdc53e448c8fe33e531b8fc03..1eeb53570400ada55600a8c37dd1ddef31a79d78 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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/catalog.h"
 #include "catalog/pg_database.h"
+#include "catalog/pg_tablespace.h"
 #include "miscadmin.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
- *             caches and lock tables.  We therefore want it initialized before
- *             we open any relations, since opening relations puts things in the
- *             cache.  To get around this problem, this code opens and scans the
+ *             We need both the OID and the default tablespace in order to find
+ *             the database's system catalogs.  Moreover the database's OID forms
+ *             half of the unique key for the system caches and lock tables, so
+ *             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.
  *
  *             This code knows way more than it should about the layout of
@@ -43,19 +45,21 @@ static bool PhonyHeapTupleSatisfiesNow(HeapTupleHeader tuple);
  * --------------------------------
  */
 void
-GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
+GetRawDatabaseInfo(const char *name, Oid *db_id, Oid *db_tablespace)
 {
        int                     dbfd;
        int                     nbytes;
-       int                     pathlen;
        HeapTupleData tup;
+       Form_pg_database tup_db;
        Page            pg;
        char       *dbfname;
-       Form_pg_database tup_db;
        RelFileNode rnode;
 
-       rnode.tblNode = 0;
+       /* hard-wired path to pg_database */
+       rnode.spcNode = GLOBALTABLESPACE_OID;
+       rnode.dbNode = 0;
        rnode.relNode = RelOid_pg_database;
+
        dbfname = relpath(rnode);
 
        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.
                         *
                         * 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?
                         */
                        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)
                        {
-                               /* Found it; extract the OID and the database path. */
+                               /* Found it; extract the db's OID and tablespace. */
                                *db_id = HeapTupleGetOid(&tup);
-                               pathlen = VARSIZE(&(tup_db->datpath)) - VARHDRSZ;
-                               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';
+                               *db_tablespace = tup_db->dattablespace;
                                goto done;
                        }
                }
@@ -150,7 +148,7 @@ GetRawDatabaseInfo(const char *name, Oid *db_id, char *path)
 
        /* failed to find it... */
        *db_id = InvalidOid;
-       *path = '\0';
+       *db_tablespace = InvalidOid;
 
 done:
        close(dbfd);
index 3ded3d8775b46da0f5df87d3910603cd00993c97..44f092fbcc1c5b37d522cdb6c51ddb1fbb8d3553 100644 (file)
@@ -39,7 +39,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  * 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
                                                                 * environment */
        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]);
        set_pglocale_pgservice(argv[0], "initdb");
@@ -2141,7 +2141,7 @@ main(int argc, char *argv[])
        /* Bootstrap template1 */
        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");
 
        /* Create the stuff we don't need to use bootstrap mode for */
index 1dfe7801ec5585d475127f973564d59561596343..7c6fd84c5c49f93a36927cf8b4ca1b08ded26812 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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
- * 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 $).
  *
  * 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)
                appendPQExpBuffer(delimBuf, dqprefix);
 
-       /* 
+       /*
         * Make sure we choose a delimiter which (without the trailing $)
         * 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
@@ -191,7 +191,7 @@ appendStringLiteralDQ(PQExpBuffer buf, const char *str, const char *dqprefix)
  * otherwise use standard quoting.
  */
 void
-appendStringLiteralDQOpt(PQExpBuffer buf, const char *str, 
+appendStringLiteralDQOpt(PQExpBuffer buf, const char *str,
                                                 bool escapeAll, const char *dqprefix)
 {
        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('T', "TEMPORARY");
        }
+       else if (strcmp(type, "TABLESPACE") == 0)
+               CONVERT_PRIV('C', "CREATE");
        else
                abort();
 
@@ -624,7 +626,7 @@ copyAclUserName(PQExpBuffer output, char *input)
                        appendPQExpBufferChar(output, *input++);
                else
                {
-                       /* Otherwise, it's a quoted username */ 
+                       /* Otherwise, it's a quoted username */
                        input++;
                        /* Loop until we come across an unescaped quote */
                        while (!(*input == '"' && *(input + 1) != '"'))
index 292e70a6db8164a14855576e296d22f3f2d37274..c5320177fa3b4704c042e374eef0e7edf2c16b43 100644 (file)
@@ -12,7 +12,7 @@
  *     by PostgreSQL
  *
  * 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_dba,
                                i_encoding,
-                               i_datpath;
+                               i_tablespace;
        CatalogId       dbCatId;
        DumpId          dbDumpId;
        const char *datname,
                           *dba,
                           *encoding,
-                          *datpath;
+                          *tablespace;
 
        datname = PQdb(g_conn);
 
@@ -1181,31 +1181,34 @@ dumpDatabase(Archive *AH)
        selectSourceSchema("pg_catalog");
 
        /* Get the database owner and parameters from pg_database */
-       if (g_fout->remoteVersion >= 70100)
+       if (g_fout->remoteVersion >= 70500)
        {
                appendPQExpBuffer(dbQry, "SELECT tableoid, oid, "
                                                  "(SELECT usename FROM pg_user WHERE usesysid = datdba) as dba, "
                                                  "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 "
                                                  "WHERE datname = ");
                appendStringLiteral(dbQry, datname, true);
        }
        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 "
                                                  "(SELECT oid FROM pg_class WHERE relname = 'pg_database') AS tableoid, "
                                                  "oid, "
                                                  "(SELECT usename FROM pg_user WHERE usesysid = datdba) as dba, "
                                                  "pg_encoding_to_char(encoding) as encoding, "
-                                                 "CASE WHEN length(datpath) > length(datname) THEN "
-                                                 "substr(datpath,1,length(datpath)-length(datname)-1) "
-                                                 "ELSE '' END as datpath "
+                                                 "NULL as tablespace "
                                                  "FROM pg_database "
                                                  "WHERE datname = ");
                appendStringLiteral(dbQry, datname, true);
@@ -1234,26 +1237,25 @@ dumpDatabase(Archive *AH)
        i_oid = PQfnumber(res, "oid");
        i_dba = PQfnumber(res, "dba");
        i_encoding = PQfnumber(res, "encoding");
-       i_datpath = PQfnumber(res, "datpath");
+       i_tablespace = PQfnumber(res, "tablespace");
 
        dbCatId.tableoid = atooid(PQgetvalue(res, 0, i_tableoid));
        dbCatId.oid = atooid(PQgetvalue(res, 0, i_oid));
        dba = PQgetvalue(res, 0, i_dba);
        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",
                                          fmtId(datname));
-       if (strlen(datpath) > 0)
-       {
-               appendPQExpBuffer(creaQry, " LOCATION = ");
-               appendStringLiteral(creaQry, datpath, true);
-       }
        if (strlen(encoding) > 0)
        {
                appendPQExpBuffer(creaQry, " ENCODING = ");
                appendStringLiteral(creaQry, encoding, true);
        }
+       if (strlen(tablespace) > 0 && strcmp(tablespace, "default") != 0)
+       {
+               appendPQExpBuffer(creaQry, " TABLESPACE = %s", fmtId(tablespace));
+       }
        appendPQExpBuffer(creaQry, ";\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)
        {
                PQExpBuffer qry = createPQExpBuffer();
-       
+
                appendPQExpBuffer(qry, "-- ");
                appendPQExpBuffer(qry, msg);
                appendPQExpBuffer(qry, " ");
@@ -1471,6 +1473,7 @@ getNamespaces(int *numNamespaces)
        int                     i_oid;
        int                     i_nspname;
        int                     i_usename;
+       int                     i_nsptablespace;
        int                     i_nspacl;
 
        /*
@@ -1488,6 +1491,7 @@ getNamespaces(int *numNamespaces)
                nsinfo[0].dobj.name = strdup("");
                nsinfo[0].usename = strdup("");
                nsinfo[0].nspacl = strdup("");
+               nsinfo[0].nsptablespace = strdup("");
 
                selectDumpableNamespace(&nsinfo[0]);
 
@@ -1498,6 +1502,7 @@ getNamespaces(int *numNamespaces)
                nsinfo[1].dobj.name = strdup("pg_catalog");
                nsinfo[1].usename = strdup("");
                nsinfo[1].nspacl = strdup("");
+               nsinfo[0].nsptablespace = strdup("");
 
                selectDumpableNamespace(&nsinfo[1]);
 
@@ -1516,10 +1521,21 @@ getNamespaces(int *numNamespaces)
         * we fetch all namespaces including system ones, so that every object
         * we read in can be linked to a containing namespace.
         */
-       appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
-       "(select usename from pg_user where nspowner = usesysid) as usename, "
-                                         "nspacl "
-                                         "FROM pg_namespace");
+       if (g_fout->remoteVersion >= 70500)
+       {
+               appendPQExpBuffer(query, "SELECT tableoid, oid, nspname, "
+               "(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);
        check_sql_result(res, g_conn, query->data, PGRES_TUPLES_OK);
@@ -1533,6 +1549,7 @@ getNamespaces(int *numNamespaces)
        i_nspname = PQfnumber(res, "nspname");
        i_usename = PQfnumber(res, "usename");
        i_nspacl = PQfnumber(res, "nspacl");
+       i_nsptablespace = PQfnumber(res, "nsptablespace");
 
        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].usename = strdup(PQgetvalue(res, i, i_usename));
                nsinfo[i].nspacl = strdup(PQgetvalue(res, i, i_nspacl));
+               nsinfo[i].nsptablespace = strdup(PQgetvalue(res, i, i_nsptablespace));
 
                /* Decide whether to dump this namespace */
                selectDumpableNamespace(&nsinfo[i]);
@@ -2329,6 +2347,7 @@ getTables(int *numTables)
        int                     i_relhasoids;
        int                     i_owning_tab;
        int                     i_owning_col;
+       int                     i_reltablespace;
 
        /* Make sure we are in proper schema */
        selectSourceSchema("pg_catalog");
@@ -2349,7 +2368,7 @@ getTables(int *numTables)
         * columns, etc.
         */
 
-       if (g_fout->remoteVersion >= 70300)
+       if (g_fout->remoteVersion >= 70500)
        {
                /*
                 * Left join to pick up dependency info linking sequences to their
@@ -2362,7 +2381,34 @@ getTables(int *numTables)
                                                  "relchecks, reltriggers, "
                                                  "relhasindex, relhasrules, relhasoids, "
                                                  "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 "
                                                  "left join pg_depend d on "
                                                  "(c.relkind = '%c' and "
@@ -2383,7 +2429,8 @@ getTables(int *numTables)
                                                  "relchecks, reltriggers, "
                                                  "relhasindex, relhasrules, relhasoids, "
                                                  "NULL::oid as owning_tab, "
-                                                 "NULL::int4 as owning_col "
+                                                 "NULL::int4 as owning_col, "
+                                                 "NULL as reltablespace "
                                                  "from pg_class "
                                                  "where relkind in ('%c', '%c', '%c') "
                                                  "order by oid",
@@ -2400,7 +2447,8 @@ getTables(int *numTables)
                                                  "relhasindex, relhasrules, "
                                                  "'t'::bool as relhasoids, "
                                                  "NULL::oid as owning_tab, "
-                                                 "NULL::int4 as owning_col "
+                                                 "NULL::int4 as owning_col, "
+                                                 "NULL as reltablespace "
                                                  "from pg_class "
                                                  "where relkind in ('%c', '%c', '%c') "
                                                  "order by oid",
@@ -2427,7 +2475,8 @@ getTables(int *numTables)
                                                  "relhasindex, relhasrules, "
                                                  "'t'::bool as relhasoids, "
                                                  "NULL::oid as owning_tab, "
-                                                 "NULL::int4 as owning_col "
+                                                 "NULL::int4 as owning_col, "
+                                                 "NULL as reltablespace "
                                                  "from pg_class c "
                                                  "where relkind in ('%c', '%c') "
                                                  "order by oid",
@@ -2467,6 +2516,7 @@ getTables(int *numTables)
        i_relhasoids = PQfnumber(res, "relhasoids");
        i_owning_tab = PQfnumber(res, "owning_tab");
        i_owning_col = PQfnumber(res, "owning_col");
+       i_reltablespace = PQfnumber(res, "reltablespace");
 
        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_col = atoi(PQgetvalue(res, i, i_owning_col));
                }
+               tblinfo[i].reltablespace = strdup(PQgetvalue(res, i, i_reltablespace));
 
                /* other fields were zeroed above */
 
@@ -2768,6 +2819,7 @@ getIndexes(TableInfo tblinfo[], int numTables)
                        indxinfo[j].indextable = tbinfo;
                        indxinfo[j].indexdef = strdup(PQgetvalue(res, j, i_indexdef));
                        indxinfo[j].indnkeys = atoi(PQgetvalue(res, j, i_indnkeys));
+
                        /*
                         * In pre-7.4 releases, indkeys may contain more entries than
                         * 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].coninherited = false;
                                constrinfo[j].separate = true;
-                               
+
                                indxinfo[j].indexconstraint = constrinfo[j].dobj.dumpId;
 
                                /* 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(q, "CREATE SCHEMA %s AUTHORIZATION %s;\n",
+               appendPQExpBuffer(q, "CREATE SCHEMA %s AUTHORIZATION %s",
                                                  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,
                                         nspinfo->dobj.name,
                                         NULL, "",
@@ -5118,7 +5177,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
                if (strcmp(prosrc, "-") != 0)
                {
                        appendPQExpBuffer(asPart, ", ");
-                       /* 
+                       /*
                         * where we have bin, use dollar quoting if allowed and src
                         * 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
         * not dumped.
         */
-       if (funcInfo && 
+       if (funcInfo &&
                strncmp(funcInfo->dobj.namespace->dobj.name, "pg_", 3) != 0 &&
                !funcInfo->dobj.namespace->dump)
                return;
@@ -6001,14 +6060,14 @@ dumpConversion(Archive *fout, ConvInfo *convinfo)
                                          fmtId(convinfo->dobj.name));
 
        appendPQExpBuffer(q, "CREATE %sCONVERSION %s FOR ",
-                                       (condefault) ? "DEFAULT " : "", 
+                                       (condefault) ? "DEFAULT " : "",
                                        fmtId(convinfo->dobj.name));
        appendStringLiteral(q, conforencoding, true);
        appendPQExpBuffer(q, " TO ");
        appendStringLiteral(q, contoencoding, true);
        /* regproc is automatically quoted in 7.3 and above */
        appendPQExpBuffer(q, " FROM %s;\n", conproc);
-       
+
        ArchiveEntry(fout, convinfo->dobj.catId, convinfo->dobj.dumpId,
                                 convinfo->dobj.name,
                                 convinfo->dobj.namespace->dobj.name, convinfo->usename,
@@ -6562,6 +6621,15 @@ dumpTableSchema(Archive *fout, TableInfo *tbinfo)
                        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");
 
                /* Loop dumping statistics and storage statements */
@@ -7227,9 +7295,20 @@ dumpSequence(Archive *fout, TableInfo *tbinfo)
                        appendPQExpBuffer(query, "    NO MINVALUE\n");
 
                appendPQExpBuffer(query,
-                                                 "    CACHE %s%s;\n",
+                                                 "    CACHE %s%s",
                                                  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,
                                         tbinfo->dobj.name,
                                         tbinfo->dobj.namespace->dobj.name, tbinfo->usename,
index 0f335544d5564160cd2bbcdf838b9715cad6b93f..55a25212257c13ac0cd728abd755ff404ee36dcb 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.h,v 1.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;
        char       *usename;            /* name of owner, or empty string */
        char       *nspacl;
+       char       *nsptablespace;      /* default tablespace */
        bool            dump;                   /* true if need to dump definition */
 } NamespaceInfo;
 
@@ -168,6 +169,7 @@ typedef struct _tableInfo
        char       *usename;            /* name of owner, or empty string */
        char       *relacl;
        char            relkind;
+       char       *reltablespace;      /* relation tablespace */
        bool            hasindex;               /* does it have any indexes? */
        bool            hasrules;               /* does it have any rules? */
        bool            hasoids;                /* does it have OIDs? */
index 11678df330395af6a0a7b231018059b20ae812ce..3006505172d3c015dbfc7d6dd341846acf26f26e 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.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 dumpGroups(PGconn *conn);
+static void dumpTablespaces(PGconn *conn);
 static void dumpCreateDB(PGconn *conn);
 static void dumpDatabaseConfig(PGconn *conn, const char *dbname);
 static void dumpUserConfig(PGconn *conn, const char *username);
@@ -231,6 +232,8 @@ main(int argc, char *argv[])
        {
                dumpUsers(conn);
                dumpGroups(conn);
+               if (server_version >= 70500)
+                       dumpTablespaces(conn);
        }
 
        if (!globals_only)
@@ -411,7 +414,68 @@ dumpGroups(PGconn *conn)
        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.
@@ -432,12 +496,22 @@ dumpCreateDB(PGconn *conn)
 
        printf("--\n-- Database creation\n--\n\n");
 
-       if (server_version >= 70300)
+       if (server_version >= 70500)
                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, 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) "
                                                   "WHERE datallowconn ORDER BY 1");
        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=(select datdba from pg_database where datname='template0'))), "
                                                   "pg_encoding_to_char(d.encoding), "
-                                                  "datistemplate, datpath, '' as datacl "
+                                                  "datistemplate, '' as datacl, "
+                                                  "'default' AS dattablespace "
                                                   "FROM pg_database d "
                                                   "WHERE datallowconn ORDER BY 1");
        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
                 * 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), "
                                                   "pg_encoding_to_char(d.encoding), "
                                                   "'f' as datistemplate, "
-                                                  "CASE WHEN length(datpath) > length(datname) THEN "
-                                                  "substr(datpath,1,length(datpath)-length(datname)-1) "
-                                                  "ELSE '' END as datpath, "
-                                                  "'' as datacl "
+                                                  "'' as datacl, "
+                                                  "'default' AS dattablespace "
                                                   "FROM pg_database d "
                                                   "ORDER BY 1");
        }
@@ -480,8 +549,8 @@ dumpCreateDB(PGconn *conn)
                char       *dbowner = PQgetvalue(res, i, 1);
                char       *dbencoding = PQgetvalue(res, i, 2);
                char       *dbistemplate = PQgetvalue(res, i, 3);
-               char       *dbpath = PQgetvalue(res, i, 4);
-               char       *dbacl = PQgetvalue(res, i, 5);
+               char       *dbacl = PQgetvalue(res, i, 4);
+               char       *dbtablespace = PQgetvalue(res, i, 5);
                char       *fdbname;
 
                if (strcmp(dbname, "template1") == 0)
@@ -496,20 +565,21 @@ dumpCreateDB(PGconn *conn)
                        appendPQExpBuffer(buf, "DROP DATABASE %s;\n", fdbname);
 
                appendPQExpBuffer(buf, "CREATE DATABASE %s", fdbname);
+
+               appendPQExpBuffer(buf, " WITH TEMPLATE = template0");
+
                if (strlen(dbowner) != 0)
-                       appendPQExpBuffer(buf, " WITH OWNER = %s",
+                       appendPQExpBuffer(buf, " OWNER = %s",
                                                          fmtId(dbowner));
-               appendPQExpBuffer(buf, " TEMPLATE = template0");
-
-               if (strlen(dbpath) != 0)
-               {
-                       appendPQExpBuffer(buf, " LOCATION = ");
-                       appendStringLiteral(buf, dbpath, true);
-               }
 
                appendPQExpBuffer(buf, " ENCODING = ");
                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");
 
                if (strcmp(dbistemplate, "t") == 0)
index d880afbd2769199f56d6a4d5a471a0c3b0881600..af8c22544843d7b1904a32d0816ef17aae01f1d7 100644 (file)
@@ -3,7 +3,7 @@
  *
  * 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 "command.h"
@@ -301,6 +301,9 @@ exec_command(const char *cmd,
                        case 'a':
                                success = describeAggregates(pattern, show_verbose);
                                break;
+                       case 'b':
+                               success = describeTablespaces(pattern);
+                               break;
                        case 'c':
                                success = listConversions(pattern);
                                break;
index e06c2001581b323dc25d121634c5ce224df6214f..0f75d97d23da15698d051d1e87a20ad9cce4ee54 100644 (file)
@@ -3,7 +3,7 @@
  *
  * 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 "describe.h"
@@ -99,6 +99,45 @@ describeAggregates(const char *pattern, bool verbose)
        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
  * Takes an optional regexp to select particular functions
@@ -351,7 +390,7 @@ permissionsList(const char *pattern)
        printfPQExpBuffer(&buf,
                                          "SELECT n.nspname 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"
                                          "FROM pg_catalog.pg_class c\n"
        "     LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace\n"
index acc841a02b21a141aa0eccb5f3fe73c59ec3a20c..195bf0e557878cc4aafe373ae199d82ad84b4599 100644 (file)
@@ -3,7 +3,7 @@
  *
  * 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
 #define DESCRIBE_H
@@ -13,6 +13,9 @@
 /* \da */
 bool           describeAggregates(const char *pattern, bool verbose);
 
+/* \db */
+bool           describeTablespaces(const char *pattern);
+
 /* \df */
 bool           describeFunctions(const char *pattern, bool verbose);
 
index f7e9022e425727535ec2d36d94caf1f1654684d6..ed9574a22973c6ab0c7bbfb08492b4e3e73fc137 100644 (file)
@@ -3,7 +3,7 @@
  *
  * 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 "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"
                                          "                 list tables/indexes/sequences/views/system tables\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            list casts\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;
                int                     nl_count = 0;
                char            *ch;
-               
+
                /* don't care about trailing spaces */
                len = strlen(topic);
                while (topic[len - 1] == ' ')
index 293e11ef025a8b5b0cc168e1e91d83a0937776f2..15cb6e7ca077a1cf63200c6f0363e3fa03e3c311 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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 *GetDatabasePath(Oid tblNode);
+extern char *GetDatabasePath(Oid dbNode, Oid spcNode);
 
 extern bool IsSystemRelation(Relation relation);
 extern bool IsToastRelation(Relation relation);
index 7b3b99701a93bef15f50f61ab0f6b7f90699e24d..240f4947082d50995c133a72ae873ad6862aaf6b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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  ShadowRelationName "pg_shadow"
 #define  StatisticRelationName "pg_statistic"
+#define  TableSpaceRelationName "pg_tablespace"
 #define  TypeRelationName "pg_type"
 #define  VersionRelationName "pg_version"
 #define  AttrDefaultRelationName "pg_attrdef"
index 6fd25b54f7a16b58c60ce7b4dde2cada442abc73..3ba63bbdea313f77226274081de783eb07a829d8 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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 */
-#define CATALOG_VERSION_NO     200406151
+#define CATALOG_VERSION_NO     200406171
 
 #endif
index 2913d53e521af0c470705dc2cbc7f19c27ae24ff..4ead9728df0464b6eab4e0060b9bdd51922b974e 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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,
                        Oid relnamespace,
+                       Oid reltablespace,
                        TupleDesc tupDesc,
                        bool shared_relation,
                        bool storage_create,
@@ -46,6 +47,7 @@ extern void heap_storage_create(Relation rel);
 
 extern Oid heap_create_with_catalog(const char *relname,
                                                 Oid relnamespace,
+                                                Oid reltablespace,
                                                 TupleDesc tupdesc,
                                                 char relkind,
                                                 bool shared_relation,
index 841387effcca6d9cbb06a669db87357fd5d00084..be27bb98eb67570f866093c944b67ad8a553cbd3 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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,
                         IndexInfo *indexInfo,
                         Oid accessMethodObjectId,
+                        Oid tableSpaceId,
                         Oid *classObjectId,
                         bool primary,
                         bool isconstraint,
index 33c0e0f6a2ffed93482e499fd07d6d8ac7d8b652..c6d2842c78e9684d9898cdae38ad13e662522ef2 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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 ShadowSysidIndex                       "pg_shadow_usesysid_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 TriggerConstrRelidIndex                "pg_trigger_tgconstrrelid_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_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_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 */
 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 */
index 896a06ada86eaf112baed40da976b149695aa109..c3f7ead3af4b10f75989dfa089c11b1b945c5903 100644 (file)
@@ -8,7 +8,7 @@
  * 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_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
  *       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 \
@@ -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 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));
-/* do not mark datpath as toastable; GetRawDatabaseInfo won't cope */
-DATA(insert ( 1262 datpath                     25 -1 -1  9 0 -1 -1 f p i t f f t 0));
+DATA(insert ( 1262 dattablespace       26 -1 4   9 0 -1 -1 t 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 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));
@@ -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, {"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, {"relpages"},     23, -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, {"reltoastrelid"}, 26, -1,     4,      9, 0, -1, -1, true, '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, {"relhasindex"},   16, -1,     1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
-{ 1259, {"relisshared"},   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, {"relnatts"},     21, -1,      2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
-{ 1259, {"relchecks"},    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, {"relukeys"},     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, {"relrefs"},      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, {"relhaspkey"},    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, {"relhassubclass"},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, {"reltablespace"}, 26, -1,     4,      7, 0, -1, -1, true, '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, {"reltuples"},    700, -1,     4,      9, 0, -1, -1, false, '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, {"reltoastidxid"}, 26, -1,     4, 11, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
+{ 1259, {"relhasindex"},   16, -1,     1, 12, 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, {"relkind"},      18, -1,      1, 14, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
+{ 1259, {"relnatts"},     21, -1,      2, 15, 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, {"reltriggers"},   21, -1,     2, 17, 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, {"relfkeys"},     21, -1,      2, 19, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
+{ 1259, {"relrefs"},      21, -1,      2, 20, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
+{ 1259, {"relhasoids"},    16, -1,     1, 21, 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, {"relhasrules"},   16, -1,     1, 23, 0, -1, -1, true, 'p', 'c', true, 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 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 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 relpages                    23 -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 reltoastrelid       26 -1 4   9 0 -1 -1 t 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 relhasindex         16 -1 1  11 0 -1 -1 t p c 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 relkind                     18 -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 relchecks           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 relukeys                    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 relrefs                     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 relhaspkey          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 relhassubclass      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 reltablespace       26 -1 4   7 0 -1 -1 t 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 reltuples      700 -1 4   9 0 -1 -1 f 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 reltoastidxid       26 -1 4  11 0 -1 -1 t p i 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 relisshared         16 -1 1  13 0 -1 -1 t p c 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 relnatts                    21 -1 2  15 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 reltriggers         21 -1 2  17 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 relfkeys                    21 -1 2  19 0 -1 -1 t p s 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 relhasoids          16 -1 1  21 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 relhasrules         16 -1 1  23 0 -1 -1 t p c t 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 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));
@@ -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 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
  *                               to allow a relation OID to be used for transaction
index 8f044b0459ae02408d80018855c1313be9d9b214..bebbc76fa5893153278c904abebcc7061ff8dc6f 100644 (file)
@@ -8,7 +8,7 @@
  * 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_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
  *       the genbki.sh script reads this file and generates .bki
@@ -48,6 +48,7 @@ CATALOG(pg_class) BOOTSTRAP
        int4            relowner;               /* class owner */
        Oid                     relam;                  /* index access method; 0 if not an index */
        Oid                     relfilenode;    /* identifier of physical storage file */
+       Oid                     reltablespace;  /* identifier of table space for relation */
        int4            relpages;               /* # of blocks (not always up-to-date) */
        float4          reltuples;              /* # of tuples (not always up-to-date) */
        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.
  * ----------------
  */
-#define Natts_pg_class_fixed                   23
-#define Natts_pg_class                                 24
+#define Natts_pg_class_fixed                   24
+#define Natts_pg_class                                 25
 #define Anum_pg_class_relname                  1
 #define Anum_pg_class_relnamespace             2
 #define Anum_pg_class_reltype                  3
 #define Anum_pg_class_relowner                 4
 #define Anum_pg_class_relam                            5
 #define Anum_pg_class_relfilenode              6
-#define Anum_pg_class_relpages                 7
-#define Anum_pg_class_reltuples                        8
-#define Anum_pg_class_reltoastrelid            9
-#define Anum_pg_class_reltoastidxid            10
-#define Anum_pg_class_relhasindex              11
-#define Anum_pg_class_relisshared              12
-#define Anum_pg_class_relkind                  13
-#define Anum_pg_class_relnatts                 14
-#define Anum_pg_class_relchecks                        15
-#define Anum_pg_class_reltriggers              16
-#define Anum_pg_class_relukeys                 17
-#define Anum_pg_class_relfkeys                 18
-#define Anum_pg_class_relrefs                  19
-#define Anum_pg_class_relhasoids               20
-#define Anum_pg_class_relhaspkey               21
-#define Anum_pg_class_relhasrules              22
-#define Anum_pg_class_relhassubclass   23
-#define Anum_pg_class_relacl                   24
+#define Anum_pg_class_reltablespace            7
+#define Anum_pg_class_relpages                 8
+#define Anum_pg_class_reltuples                        9
+#define Anum_pg_class_reltoastrelid            10
+#define Anum_pg_class_reltoastidxid            11
+#define Anum_pg_class_relhasindex              12
+#define Anum_pg_class_relisshared              13
+#define Anum_pg_class_relkind                  14
+#define Anum_pg_class_relnatts                 15
+#define Anum_pg_class_relchecks                        16
+#define Anum_pg_class_reltriggers              17
+#define Anum_pg_class_relukeys                 18
+#define Anum_pg_class_relfkeys                 19
+#define Anum_pg_class_relrefs                  20
+#define Anum_pg_class_relhasoids               21
+#define Anum_pg_class_relhaspkey               22
+#define Anum_pg_class_relhasrules              23
+#define Anum_pg_class_relhassubclass   24
+#define Anum_pg_class_relacl                   25
 
 /* ----------------
  *             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 f f r 23 0 0 0 0 0 t f f f _null_ ));
 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 f f r 17 0 0 0 0 0 f f f f _null_ ));
 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 f f r 16 0 0 0 0 0 t f f f _null_ ));
 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("");
-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("");
-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("");
-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("");
-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("");
 
 #define RelOid_pg_type                 1247
@@ -158,6 +162,7 @@ DESCR("");
 #define RelOid_pg_shadow               1260
 #define RelOid_pg_group                        1261
 #define RelOid_pg_database             1262
+#define RelOid_pg_tablespace   1213
 
 /* Xact lock pseudo-table */
 #define XactLockTableId                        376
index 226c5c2f99c045b217d2ba258259d95f9579be2b..9504f1733b6bb070223d68808bbb4bbf6150a547 100644 (file)
@@ -8,7 +8,7 @@
  * 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_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
  *       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 */
        TransactionId datvacuumxid; /* all XIDs before this are vacuumed */
        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) */
        aclitem         datacl[1];              /* access permissions (VAR LENGTH) */
 } FormData_pg_database;
@@ -66,11 +66,11 @@ typedef FormData_pg_database *Form_pg_database;
 #define Anum_pg_database_datlastsysoid 6
 #define Anum_pg_database_datvacuumxid  7
 #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_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");
 #define TemplateDbOid                  1
 
index 68d8dd28fa64bca410c76023149977aaf48769cf..63a4c70837822e175bce4f039756b22d12e13ff0 100644 (file)
@@ -8,7 +8,7 @@
  * 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_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
  *       the genbki.sh script reads this file and generates .bki
@@ -40,6 +40,7 @@ CATALOG(pg_namespace)
 {
        NameData        nspname;
        int4            nspowner;
+       Oid                     nsptablespace;  /* default table space for name space */
        aclitem         nspacl[1];              /* VARIABLE LENGTH FIELD */
 } 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_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 _null_ ));
 DESCR("System catalog schema");
 #define PG_CATALOG_NAMESPACE 11
-DATA(insert OID = 99 ( "pg_toast" PGUID _null_ ));
+DATA(insert OID = 99 ( "pg_toast" PGUID _null_ ));
 DESCR("Reserved schema for TOAST tables");
 #define PG_TOAST_NAMESPACE 99
-DATA(insert OID = 2200 ( "public" PGUID _null_ ));
+DATA(insert OID = 2200 ( "public" PGUID _null_ ));
 DESCR("Standard public schema");
 #define PG_PUBLIC_NAMESPACE 2200
 
@@ -80,6 +82,7 @@ DESCR("Standard public schema");
 /*
  * 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 */
diff --git a/src/include/catalog/pg_tablespace.h b/src/include/catalog/pg_tablespace.h
new file mode 100644 (file)
index 0000000..f05d365
--- /dev/null
@@ -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 */
index 3b9b1dfd5dbda4c70b454d21c7011d6abed10f47..45d92b36277c28e8fa91093994d1906fb143b0b2 100644 (file)
@@ -8,7 +8,7 @@
  * 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_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
  *       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");
 #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 = 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 = 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 = 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 = 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 = 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 = 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 = 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 */
 
index ba7415a582de997b7fdde80cd1557e7d5b17f471..8670a41a763771ba642428c744938e786da3690a 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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,
                        char *indexRelationName,
                        char *accessMethodName,
+                       char *tableSpaceName,
                        List *attributeList,
                        Expr *predicate,
                        List *rangetable,
diff --git a/src/include/commands/tablespace.h b/src/include/commands/tablespace.h
new file mode 100644 (file)
index 0000000..129413a
--- /dev/null
@@ -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 */
index 4561d2fcfb76a9f15ac145659e091f8e3218cbe2..0a508861b270150e2acefae1474f2613789fe3d2 100644 (file)
@@ -13,7 +13,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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
  *       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 MyDatabaseTableSpace;
+
 /*
  * Date/Time Configuration
  *
@@ -224,7 +226,7 @@ extern void check_stack_depth(void);
 extern char *DatabasePath;
 
 /* 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 */
 extern void SetDatabasePath(const char *path);
index b719747e7621d0834e3bb9773ba2fe5ab284f03d..531b7e6c654a3c8ee20016e72dc02584c02aec76 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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_DeallocateStmt,
        T_DeclareCursorStmt,
+       T_CreateTableSpaceStmt,
+       T_DropTableSpaceStmt,
        T_AlterDbOwnerStmt,
 
        T_A_Expr = 800,
index 0da9b3790776b7901c5808e49cbf8936f3f27b52..4c24fe9e27bfbfaccae75ba8e37ef739dc5cef7b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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_SEQUENCE,
        OBJECT_TABLE,
+       OBJECT_TABLESPACE,
        OBJECT_TRIGGER,
        OBJECT_TYPE,
        OBJECT_USER,
@@ -761,6 +762,7 @@ typedef struct CreateSchemaStmt
        NodeTag         type;
        char       *schemaname;         /* the name of the schema to create */
        char       *authid;                     /* the owner of the created schema */
+       char       *tablespacename;     /* default tablespace for schema, or NULL */
        List       *schemaElts;         /* schema components (list of parsenodes) */
 } CreateSchemaStmt;
 
@@ -857,7 +859,8 @@ typedef enum GrantObjectType
        ACL_OBJECT_DATABASE,            /* database */
        ACL_OBJECT_FUNCTION,            /* function */
        ACL_OBJECT_LANGUAGE,            /* procedural language */
-       ACL_OBJECT_NAMESPACE            /* namespace */
+       ACL_OBJECT_NAMESPACE,           /* namespace */
+       ACL_OBJECT_TABLESPACE           /* tablespace */
 } GrantObjectType;
 
 typedef struct GrantStmt
@@ -941,6 +944,7 @@ typedef struct CreateStmt
        List       *constraints;        /* constraints (list of Constraint nodes) */
        ContainsOids   hasoids;         /* should it have OIDs? */
        OnCommitAction oncommit;        /* what do we do at COMMIT? */
+       char       *tablespacename;     /* table space to use, or NULL */
 } CreateStmt;
 
 /* ----------
@@ -1030,6 +1034,26 @@ typedef struct FkConstraint
        bool            skip_validation;        /* skip validation of existing rows? */
 } 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
  * ----------------------
@@ -1142,6 +1166,7 @@ typedef struct CreateSeqStmt
        NodeTag         type;
        RangeVar   *sequence;           /* the sequence to create */
        List       *options;
+       char       *tablespacename;     /* tablespace, or NULL for default */
 } CreateSeqStmt;
 
 typedef struct AlterSeqStmt
@@ -1322,6 +1347,7 @@ typedef struct IndexStmt
        char       *idxname;            /* name of new index, or NULL for default */
        RangeVar   *relation;           /* relation to build index on */
        char       *accessMethod;       /* name of access method (eg. btree) */
+       char       *tableSpace;         /* tablespace, or NULL to use parent's */
        List       *indexParams;        /* a list of IndexElem */
        Node       *whereClause;        /* qualification (partial-index predicate) */
        List       *rangetable;         /* range table for qual and/or
index 6db4afd58bd1d36b4439116df1fc5cad9cccba4b..4a8b20908e522c58c3dc02fa69eb187e3528be6f 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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) \
 ( \
-       (a).rnode.tblNode = InvalidOid, \
+       (a).rnode.spcNode = InvalidOid, \
+       (a).rnode.dbNode = InvalidOid, \
        (a).rnode.relNode = InvalidOid, \
        (a).blockNum = InvalidBlockNumber \
 )
index 715dc00f7de1f81941c6bb361bf4f8137ad5249c..d430412e67fc566f407acd5b6ad33e6aaa459315 100644 (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
 #define RELFILENODE_H
 
 /*
- * This is all what we need to know to find relation file.
- * tblNode is identificator of tablespace and because of
- * currently our tablespaces are equal to databases this is
- * database OID. relNode is currently relation OID on creation
- * but may be changed later if required. relNode is stored in
- * pg_class.relfilenode.
+ * RelFileNode must provide all that we need to know to physically access
+ * a relation.
+ *
+ * spcNode identifies the tablespace of the relation.  It corresponds to
+ * pg_tablespace.oid.
+ *
+ * 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
 {
-       Oid                     tblNode;                /* tablespace */
+       Oid                     spcNode;                /* tablespace */
+       Oid                     dbNode;                 /* database */
        Oid                     relNode;                /* relation */
 } 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) \
        ((node1).relNode == (node2).relNode && \
-        (node1).tblNode == (node2).tblNode)
+        (node1).dbNode == (node2).dbNode && \
+        (node1).spcNode == (node2).spcNode)
 
-#endif   /* RELFILENODE_H */
+#endif /* RELFILENODE_H */
index f5ac89e2579208c3728ff7b095d92e8f6a164dde..f7779be589d37b0cd78e9c0a3c0abdf77d98fbf7 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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
  *       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_LANGUAGE                (ACL_USAGE)
 #define ACL_ALL_RIGHTS_NAMESPACE       (ACL_USAGE|ACL_CREATE)
+#define ACL_ALL_RIGHTS_TABLESPACE      (ACL_CREATE)
 
 /* operation codes for pg_*_aclmask */
 typedef enum
@@ -213,6 +214,7 @@ typedef enum AclObjectKind
        ACL_KIND_NAMESPACE,                     /* pg_namespace */
        ACL_KIND_OPCLASS,                       /* pg_opclass */
        ACL_KIND_CONVERSION,            /* pg_conversion */
+       ACL_KIND_TABLESPACE,            /* pg_tablespace */
        MAX_ACL_KIND                            /* MUST BE LAST */
 } AclObjectKind;
 
@@ -254,12 +256,15 @@ extern AclMode pg_language_aclmask(Oid lang_oid, AclId userid,
                                                                   AclMode mask, AclMaskHow how);
 extern AclMode pg_namespace_aclmask(Oid nsp_oid, AclId userid,
                                                                        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_database_aclcheck(Oid db_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_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,
                           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_proc_ownercheck(Oid proc_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_database_ownercheck(Oid db_oid, AclId userid);
 extern bool pg_conversion_ownercheck(Oid conv_oid, AclId userid);
index 68fab871bdecfe903f42ffc2cd325ec4ec90468e..10d2104b8d0cfd052a7d912869bc057b385be250 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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 char *get_rel_name(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 char get_rel_relkind(Oid relid);
 extern bool get_typisdefined(Oid typid);
@@ -105,6 +106,7 @@ extern void free_attstatsslot(Oid atttype,
                                  Datum *values, int nvalues,
                                  float4 *numbers, int nnumbers);
 extern char *get_namespace_name(Oid nspid);
+extern Oid     get_namespace_tablespace(Oid nspid);
 extern int32 get_usesysid(const char *username);
 
 #define is_array_type(typid)  (get_element_type(typid) != InvalidOid)
index 848d68b2077c0b4cca11fd1c382467c799b066c8..da82f4f6137af58da78f0e687e3a38ede891a182 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * 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,
                                                   Oid relnamespace,
                                                   TupleDesc tupDesc,
-                                                  Oid relid, Oid dbid,
-                                                  RelFileNode rnode,
+                                                  Oid relid,
+                                                  Oid reltablespace,
+                                                  bool shared_relation,
                                                   bool nailit);
 
 /*
index 61a2f9f790aa0288258b7106054cb9b313bd1b76..1fdd1f1e5c1010454550d24f5cdbcf35fecd97a9 100644 (file)
@@ -7,7 +7,7 @@
 #
 #
 # 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
 
-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)
 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)
 endif
 
+testtablespace := $(abs_builddir)/testtablespace
+
 
 define sed-command
 sed -e 's,@abs_srcdir@,$(abs_srcdir),g' \
     -e 's,@abs_builddir@,$(abs_builddir),g' \
+    -e 's,@testtablespace@,$(testtablespace),g' \
     -e 's/@DLSUFFIX@/$(DLSUFFIX)/g' $< >$@
 endef
 
@@ -125,9 +128,13 @@ all-spi:
 ##
 
 check: all
+       -rm -rf ./testtablespace
+       mkdir ./testtablespace
        $(SHELL) ./pg_regress --temp-install --top-builddir=$(top_builddir) --schedule=$(srcdir)/parallel_schedule --multibyte=$(MULTIBYTE) $(MAXCONNOPT)
 
 installcheck: all
+       -rm -rf ./testtablespace
+       mkdir ./testtablespace
        $(SHELL) ./pg_regress --schedule=$(srcdir)/serial_schedule --multibyte=$(MULTIBYTE)
 
 
@@ -152,6 +159,7 @@ clean distclean maintainer-clean:
        $(MAKE) -C $(contribdir)/spi clean
        rm -f $(output_files) $(input_files) $(DLOBJS) regress.o pg_regress
 # things created by various check targets
+       rm -rf testtablespace
        rm -rf results tmp_check log
        rm -f regression.diffs regression.out regress.out run_check.out
 ifeq ($(PORTNAME), cygwin)
index 87e1943e5a26afcd7636da3821daea04e44ec7bb..00abd941ccfdf6119cb2bed9b58c88ffa974ded8 100644 (file)
@@ -56,13 +56,14 @@ SELECT relname, relhasindex
  pg_rewrite          | t
  pg_shadow           | t
  pg_statistic        | t
+ pg_tablespace       | t
  pg_trigger          | t
  pg_type             | t
  road                | t
  shighway            | t
  tenk1               | t
  tenk2               | t
-(52 rows)
+(53 rows)
 
 --
 -- another sanity check: every system catalog that has OIDs should have
diff --git a/src/test/regress/input/tablespace.source b/src/test/regress/input/tablespace.source
new file mode 100644 (file)
index 0000000..460d443
--- /dev/null
@@ -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;
diff --git a/src/test/regress/output/tablespace.source b/src/test/regress/output/tablespace.source
new file mode 100644 (file)
index 0000000..43044a2
--- /dev/null
@@ -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;
index 035a81543f3154e697fc778522f6d02d95320fe7..b3a4de3b56ff3b2ee792e87c38d6a6ca7cc16bad 100644 (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
 test: geometry
 # Depends on interval, timetz, timestamp, timestamptz, reltime and abstime
-test: horology 
+test: horology
 
 # ----------
 # 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
 test: stats
+
+# run tablespace by itself
+test: tablespace
index 1dd7a03cc7a51daca4745c6d17004bbd5affb075..f8621b404acf4a75eb0e13adc82a10b9cb22f2e5 100644 (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.
 test: boolean
 test: char
@@ -96,3 +96,4 @@ test: sequence
 test: polymorphism
 test: rowtypes
 test: stats
+test: tablespace