Editorial review for partitioning/constraint exclusion documentation.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 4 Nov 2005 23:53:18 +0000 (23:53 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 4 Nov 2005 23:53:18 +0000 (23:53 +0000)
doc/src/sgml/config.sgml
doc/src/sgml/ddl.sgml

index a1c1496cd2ba2a1093509b070d13202c84a7f96b..aabcebd7cd45c845f7bf6f23efefd2b4181bc741 100644 (file)
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.35 2005/11/04 23:13:59 petere Exp $
+$PostgreSQL: pgsql/doc/src/sgml/config.sgml,v 1.36 2005/11/04 23:53:18 tgl Exp $
 -->
 <chapter Id="runtime-config">
   <title>Server Configuration</title>
@@ -1970,13 +1970,13 @@ archive_command = 'copy "%p" /mnt/server/archivedir/"%f"'  # Windows
       <listitem>
        <para>
         Enables or disables the query planner's use of table constraints to
-        limit table access.  The default is <literal>off</>.
+        optimize queries.  The default is <literal>off</>.
        </para>
 
        <para>
         When this parameter is <literal>on</>, the planner compares
         query conditions with table <literal>CHECK</> constraints, and
-        omits scanning tables where the conditions contradict the
+        omits scanning tables for which the conditions contradict the
         constraints.  (Presently this is done only for child tables of
         inheritance scans.)  For example:
 
@@ -2010,7 +2010,7 @@ SELECT * FROM parent WHERE key = 2400;
        </para>
 
        <para>
-        Refer to <xref linkend="ce-partitioning"> for more information
+        Refer to <xref linkend="ddl-partitioning"> for more information
         on using constraint exclusion and partitioning.
        </para>
       </listitem>
index a3c9552117770c344c1db18cd1e78f2f1cd98db7..75aabc3f70fbe0a76e089cf685cb76e7b1396535 100644 (file)
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.49 2005/11/04 23:13:59 petere Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/ddl.sgml,v 1.50 2005/11/04 23:53:18 tgl Exp $ -->
 
 <chapter id="ddl">
  <title>Data Definition</title>
@@ -12,7 +12,7 @@
   Subsequently, we discuss how tables can be organized into
   schemas, and how privileges can be assigned to tables.  Finally,
   we will briefly look at other features that affect the data storage,
-  such as views, functions, and triggers.
+  such as inheritance, views, functions, and triggers.
  </para>
 
  <sect1 id="ddl-basics">
@@ -399,11 +399,9 @@ CREATE TABLE products (
     constraint described in the next section can be used.
    </para>
 
-    <para>
-     Check constraints can also be used to enhance performance with
-     very large tables, when used in conjunction with the <xref
-     linkend="guc-constraint-exclusion"> parameter.  This is discussed
-     in more detail in <xref linkend="ce-partitioning">.
+   <para>
+    Check constraints can be useful for enhancing the performance of
+    partitioned tables.  For details see <xref linkend="ddl-partitioning">.
    </para>
   </sect2>
 
@@ -895,8 +893,8 @@ CREATE TABLE order_items (
      <para>
       The OID of the table containing this row.  This column is
       particularly handy for queries that select from inheritance
-      hierarchies, since without it, it's difficult to tell which
-      individual table a row came from.  The
+      hierarchies (see <xref linkend="ddl-inherit">), since without it,
+      it's difficult to tell which individual table a row came from.  The
       <structfield>tableoid</structfield> can be joined against the
       <structfield>oid</structfield> column of
       <structname>pg_class</structname> to obtain the table name.
@@ -1044,1670 +1042,1698 @@ CREATE TABLE order_items (
    </para>
  </sect1>
 
- <sect1 id="ddl-inherit">
-  <title>Inheritance</title>
-
-   <indexterm>
-    <primary>not-null constraint</primary>
-   </indexterm>
+ <sect1 id="ddl-alter">
+  <title>Modifying Tables</title>
 
-   <indexterm>
-    <primary>constraint</primary>
-    <secondary>NOT NULL</secondary>
-   </indexterm>
+  <indexterm zone="ddl-alter">
+   <primary>table</primary>
+   <secondary>modifying</secondary>
+  </indexterm>
 
   <para>
-   <productname>PostgreSQL</productname> implements table inheritance
-   which can be a useful tool for database designers.  SQL:1999 and
-   later define a type inheritance feature, which differs in many
-   respects from the features described here.
+   When you create a table and you realize that you made a mistake, or
+   the requirements of the application change, then you can drop the
+   table and create it again.  But this is not a convenient option if
+   the table is already filled with data, or if the table is
+   referenced by other database objects (for instance a foreign key
+   constraint).  Therefore <productname>PostgreSQL</productname>
+   provides a family of commands to make modifications to existing
+   tables.  Note that this is conceptually distinct from altering
+   the data contained in the table: here we are interested in altering
+   the definition, or structure, of the table.
   </para>
 
   <para>
-   Let's start with an example: suppose we are trying to build a data
-   model for cities.  Each state has many cities, but only one
-   capital. We want to be able to quickly retrieve the capital city
-   for any particular state. This can be done by creating two tables,
-   one for state capitals and one for cities that are not
-   capitals. However, what happens when we want to ask for data about
-   a city, regardless of whether it is a capital or not? The
-   inheritance feature can help to resolve this problem. We define the
-   <literal>capitals</literal> table so that it inherits from
-   <literal>cities</literal>:
-
-<programlisting>
-CREATE TABLE cities (
-    name            text,
-    population      float,
-    altitude        int     -- in feet
-);
-
-CREATE TABLE capitals (
-    state           char(2)
-) INHERITS (cities);
-</programlisting>
+   You can
+   <itemizedlist spacing="compact">
+    <listitem>
+     <para>Add columns,</para>
+    </listitem>
+    <listitem>
+     <para>Remove columns,</para>
+    </listitem>
+    <listitem>
+     <para>Add constraints,</para>
+    </listitem>
+    <listitem>
+     <para>Remove constraints,</para>
+    </listitem>
+    <listitem>
+     <para>Change default values,</para>
+    </listitem>
+    <listitem>
+     <para>Change column data types,</para>
+    </listitem>
+    <listitem>
+     <para>Rename columns,</para>
+    </listitem>
+    <listitem>
+     <para>Rename tables.</para>
+    </listitem>
+   </itemizedlist>
 
-   In this case, a row of <literal>capitals</> <firstterm>inherits</>
-   all the columns of its parent table, <literal>cities</>. State
-   capitals have an extra attribute, <literal>state</>, that shows
-   their state.
+   All these actions are performed using the
+   <xref linkend="sql-altertable" endterm="sql-altertable-title">
+   command.
   </para>
 
-  <para>
-   In <productname>PostgreSQL</productname>, a table can inherit from
-   zero or more other tables, and a query can reference either all
-   rows of a table or all rows of a table plus all of its descendants.
-   For example, the following query finds the names of all cities,
-   including state capitals, that are located at an altitude over
-   500ft:
+  <sect2>
+   <title>Adding a Column</title>
+
+   <indexterm>
+    <primary>column</primary>
+    <secondary>adding</secondary>
+   </indexterm>
 
+   <para>
+    To add a column, use a command like this:
 <programlisting>
-SELECT name, altitude
-    FROM cities
-    WHERE altitude &gt; 500;
+ALTER TABLE products ADD COLUMN description text;
 </programlisting>
+    The new column is initially filled with whatever default
+    value is given (null if you don't specify a <literal>DEFAULT</> clause).
+   </para>
 
-   which returns:
-
+   <para>
+    You can also define constraints on the column at the same time,
+    using the usual syntax:
 <programlisting>
-   name    | altitude
------------+----------
- Las Vegas |     2174
- Mariposa  |     1953
- Madison   |      845
+ALTER TABLE products ADD COLUMN description text CHECK (description &lt;&gt; '');
 </programlisting>
-  </para>
+    In fact all the options that can be applied to a column description
+    in <command>CREATE TABLE</> can be used here.  Keep in mind however
+    that the default value must satisfy the given constraints, or the
+    <literal>ADD</> will fail.  Alternatively, you can add
+    constraints later (see below) after you've filled in the new column
+    correctly.
+   </para>
+  </sect2>
 
-  <para>
-   On the other hand, the following query finds all the cities that
-   are not state capitals and are situated at an altitude over 500ft:
+  <sect2>
+   <title>Removing a Column</title>
 
-<programlisting>
-SELECT name, altitude
-    FROM ONLY cities
-    WHERE altitude &gt; 500;
+   <indexterm>
+    <primary>column</primary>
+    <secondary>removing</secondary>
+   </indexterm>
 
-   name    | altitude
------------+----------
- Las Vegas |     2174
- Mariposa  |     1953
+   <para>
+    To remove a column, use a command like this:
+<programlisting>
+ALTER TABLE products DROP COLUMN description;
 </programlisting>
-  </para>
+    Whatever data was in the column disappears.  Table constraints involving
+    the column are dropped, too.  However, if the column is referenced by a
+    foreign key constraint of another table,
+    <productname>PostgreSQL</productname> will not silently drop that
+    constraint.  You can authorize dropping everything that depends on
+    the column by adding <literal>CASCADE</>:
+<programlisting>
+ALTER TABLE products DROP COLUMN description CASCADE;
+</programlisting>
+    See <xref linkend="ddl-depend"> for a description of the general
+    mechanism behind this.
+   </para>
+  </sect2>
 
-  <para>
-   Here the <literal>ONLY</literal> keyword indicates that the query
-   should apply only to <literal>cities</literal>, and not any tables
-   below <literal>cities</literal> in the inheritance hierarchy.  Many
-   of the commands that we have already discussed &mdash;
-   <command>SELECT</command>, <command>UPDATE</command> and
-   <command>DELETE</command> &mdash; support the
-   <literal>ONLY</literal> keyword.
-  </para>
+  <sect2>
+   <title>Adding a Constraint</title>
 
-  <note>
-   <title>Inheritance and Permissions</title>
-   <para>
-    Because permissions are not inherited automatically, a user
-    attempting to access a parent table must either have at least the
-    same permission for the child table or must use the
-    <quote>ONLY</quote> notation. If creating a new inheritance
-    relationship in an existing system be careful that this does not
-    create problems.
-   </para>
-  </note>
+   <indexterm>
+    <primary>constraint</primary>
+    <secondary>adding</secondary>
+   </indexterm>
 
-  <para>
-   Inheritance does not automatically propagate data from
-   <command>INSERT</command> or <command>COPY</command> commands to
-   other tables in the inheritance hierarchy. In our example, the
-   following <command>INSERT</command> statement will fail:
+   <para>
+    To add a constraint, the table constraint syntax is used.  For example:
 <programlisting>
-INSERT INTO cities
-(name, population, altitude, state)
-VALUES ('New York', NULL, NULL, 'NY');
+ALTER TABLE products ADD CHECK (name &lt;&gt; '');
+ALTER TABLE products ADD CONSTRAINT some_name UNIQUE (product_no);
+ALTER TABLE products ADD FOREIGN KEY (product_group_id) REFERENCES product_groups;
 </programlisting>
-   We might hope that the data would be somehow routed to the
-   <literal>capitals</literal> table, though this does not happen. If
-   the child has no locally defined columns, then it is possible to
-   route data from the parent to the child using a rule, see <xref
-   linkend="rules-update">.  This is not possible with the above
-   <command>INSERT</> statement because the <literal>state</> column
-   does not exist on both parent and child tables.
-  </para>
-
-  <para>
-   In some cases you may wish to know which table a particular row
-   originated from. There is a system column called
-   <structfield>tableoid</structfield> in each table which can tell you the
-   originating table:
-
+    To add a not-null constraint, which cannot be written as a table
+    constraint, use this syntax:
 <programlisting>
-SELECT c.tableoid, c.name, c.altitude
-FROM cities c
-WHERE c.altitude &gt; 500;
+ALTER TABLE products ALTER COLUMN product_no SET NOT NULL;
 </programlisting>
+   </para>
 
-   which returns:
+   <para>
+    The constraint will be checked immediately, so the table data must
+    satisfy the constraint before it can be added.
+   </para>
+  </sect2>
 
-<programlisting>
- tableoid |   name    | altitude
-----------+-----------+----------
-   139793 | Las Vegas |     2174
-   139793 | Mariposa  |     1953
-   139798 | Madison   |      845
-</programlisting>
+  <sect2>
+   <title>Removing a Constraint</title>
 
-   (If you try to reproduce this example, you will probably get
-   different numeric OIDs.)  By doing a join with
-   <structname>pg_class</> you can see the actual table names:
+   <indexterm>
+    <primary>constraint</primary>
+    <secondary>removing</secondary>
+   </indexterm>
 
+   <para>
+    To remove a constraint you need to know its name.  If you gave it
+    a name then that's easy.  Otherwise the system assigned a
+    generated name, which you need to find out.  The
+    <application>psql</application> command <literal>\d
+    <replaceable>tablename</replaceable></literal> can be helpful
+    here; other interfaces might also provide a way to inspect table
+    details.  Then the command is:
 <programlisting>
-SELECT p.relname, c.name, c.altitude
-FROM cities c, pg_class p
-WHERE c.altitude &gt; 500 and c.tableoid = p.oid;
+ALTER TABLE products DROP CONSTRAINT some_name;
 </programlisting>
+    (If you are dealing with a generated constraint name like <literal>$2</>,
+    don't forget that you'll need to double-quote it to make it a valid
+    identifier.)
+   </para>
 
-   which returns:
+   <para>
+    As with dropping a column, you need to add <literal>CASCADE</> if you
+    want to drop a constraint that something else depends on.  An example
+    is that a foreign key constraint depends on a unique or primary key
+    constraint on the referenced column(s).
+   </para>
 
+   <para>
+    This works the same for all constraint types except not-null
+    constraints. To drop a not null constraint use
 <programlisting>
- relname  |   name    | altitude
-----------+-----------+----------
- cities   | Las Vegas |     2174
- cities   | Mariposa  |     1953
- capitals | Madison   |      845
+ALTER TABLE products ALTER COLUMN product_no DROP NOT NULL;
 </programlisting>
-  </para>
+    (Recall that not-null constraints do not have names.)
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Changing a Column's Default Value</title>
+
+   <indexterm>
+    <primary>default value</primary>
+    <secondary>changing</secondary>
+   </indexterm>
+
+   <para>
+    To set a new default for a column, use a command like this:
+<programlisting>
+ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;
+</programlisting>
+    Note that this doesn't affect any existing rows in the table, it
+    just changes the default for future <command>INSERT</> commands.
+   </para>
+
+   <para>
+    To remove any default value, use
+<programlisting>
+ALTER TABLE products ALTER COLUMN price DROP DEFAULT;
+</programlisting>
+    This is effectively the same as setting the default to null.
+    As a consequence, it is not an error
+    to drop a default where one hadn't been defined, because the
+    default is implicitly the null value.
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Changing a Column's Data Type</title>
+
+   <indexterm>
+    <primary>column data type</primary>
+    <secondary>changing</secondary>
+   </indexterm>
+
+   <para>
+    To convert a column to a different data type, use a command like this:
+<programlisting>
+ALTER TABLE products ALTER COLUMN price TYPE numeric(10,2);
+</programlisting>
+    This will succeed only if each existing entry in the column can be
+    converted to the new type by an implicit cast.  If a more complex
+    conversion is needed, you can add a <literal>USING</> clause that
+    specifies how to compute the new values from the old.
+   </para>
+
+   <para>
+    <productname>PostgreSQL</> will attempt to convert the column's
+    default value (if any) to the new type, as well as any constraints
+    that involve the column.  But these conversions may fail, or may
+    produce surprising results.  It's often best to drop any constraints
+    on the column before altering its type, and then add back suitably
+    modified constraints afterwards.
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Renaming a Column</title>
+
+   <indexterm>
+    <primary>column</primary>
+    <secondary>renaming</secondary>
+   </indexterm>
+
+   <para>
+    To rename a column:
+<programlisting>
+ALTER TABLE products RENAME COLUMN product_no TO product_number;
+</programlisting>
+   </para>
+  </sect2>
+
+  <sect2>
+   <title>Renaming a Table</title>
+
+   <indexterm>
+    <primary>table</primary>
+    <secondary>renaming</secondary>
+   </indexterm>
+
+   <para>
+    To rename a table:
+<programlisting>
+ALTER TABLE products RENAME TO items;
+</programlisting>
+   </para>
+  </sect2>
+ </sect1>
+
+ <sect1 id="ddl-priv">
+  <title>Privileges</title>
+
+  <indexterm zone="ddl-priv">
+   <primary>privilege</primary>
+  </indexterm>
+
+  <indexterm>
+   <primary>permission</primary>
+   <see>privilege</see>
+  </indexterm>
 
   <para>
-   As shown above, a child table may locally define columns as well as
-   inheriting them from their parents.  However, a locally defined
-   column cannot override the data type of an inherited column of the
-   same name.  A table can inherit from a table that has itself
-   inherited from other tables. A table can also inherit from more
-   than one parent table, in which case it inherits the union of the
-   columns defined by the parent tables.  Inherited columns with
-   duplicate names and data types will be merged so that only a single
-   column is stored.
+   When you create a database object, you become its owner.  By
+   default, only the owner of an object can do anything with the
+   object. In order to allow other users to use it,
+   <firstterm>privileges</firstterm> must be granted.  (However,
+   users that have the superuser attribute can always
+   access any object.)
   </para>
 
   <para>
-   Table inheritance can currently only be defined using the <xref
-   linkend="sql-createtable" endterm="sql-createtable-title">
-   statement.  The related statement <literal>CREATE TABLE ... AS
-   SELECT</literal> does not allow inheritance to be specified. There
-   is no way to add an inheritance link to make an existing table into
-   a child table. Similarly, there is no way to remove an inheritance
-   link from a child table once it has been defined, other than using
-   <literal>DROP TABLE</literal>.  A parent table cannot be dropped
-   while any of its children remain. If you wish to remove a table and
-   all of its descendants, then you can do so using the
-   <literal>CASCADE</literal> option of the <xref
-   linkend="sql-droptable" endterm="sql-droptable-title"> statement.
+   There are several different privileges: <literal>SELECT</>,
+   <literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
+   <literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
+   <literal>CREATE</>, <literal>TEMPORARY</>, <literal>EXECUTE</>, and
+   <literal>USAGE</>.  The privileges applicable to a particular
+   object vary depending on the object's type (table, function, etc).
+   For complete information on the different types of privileges
+   supported by <productname>PostgreSQL</productname>, refer to the
+   <xref linkend="sql-grant" endterm="sql-grant-title"> reference
+   page.  The following sections and chapters will also show you how
+   those privileges are used.
   </para>
 
   <para>
-   Check constraints can be defined on tables within an inheritance
-   hierarchy. All check constraints on a parent table are
-   automatically inherited by all of their children. It is currently
-   possible to inherit mutually exclusive check constraints, but that
-   definition quickly shows itself since all attempted row inserts
-   will be rejected.
+   The right to modify or destroy an object is always the privilege of
+   the owner only.
   </para>
 
+  <note>
+   <para>
+    To change the owner of a table, index, sequence, or view, use the
+    <xref linkend="sql-altertable" endterm="sql-altertable-title">
+    command.  There are corresponding <literal>ALTER</> commands for
+    other object types.
+   </para>
+  </note>
+
   <para>
-   <xref linkend="sql-altertable" endterm="sql-altertable-title"> will
-   propogate any changes in data definition on columns or check
-   constraints down the inheritance hierarchy.  Again, dropping
-   columns or constraints on parent tables is only possible when using
-   the <literal>CASCADE</literal> option. <command>ALTER
-   TABLE</command> follows the same rules for duplicate column merging
-   and rejection that apply during <command>CREATE TABLE</command>.
+   To assign privileges, the <command>GRANT</command> command is
+   used. For example, if <literal>joe</literal> is an existing user, and
+   <literal>accounts</literal> is an existing table, the privilege to
+   update the table can be granted with
+<programlisting>
+GRANT UPDATE ON accounts TO joe;
+</programlisting>
+   To grant a privilege to a group, use this syntax:
+<programlisting>
+GRANT SELECT ON accounts TO GROUP staff;
+</programlisting>
+   The special <quote>user</quote> name <literal>PUBLIC</literal> can
+   be used to grant a privilege to every user on the system. Writing
+   <literal>ALL</literal> in place of a specific privilege grants all
+   privileges that are relevant for the object type.
+  </para>
+
+  <para>
+   To revoke a privilege, use the fittingly named
+   <command>REVOKE</command> command:
+<programlisting>
+REVOKE ALL ON accounts FROM PUBLIC;
+</programlisting>
+   The special privileges of the object owner (i.e., the right to do
+   <command>DROP</>, <command>GRANT</>, <command>REVOKE</>, etc.)
+   are always implicit in being the owner,
+   and cannot be granted or revoked.  But the object owner can choose
+   to revoke his own ordinary privileges, for example to make a
+   table read-only for himself as well as others.
+  </para>
+
+  <para>
+   Ordinarily, only the object's owner (or a superuser) can grant or
+   revoke privileges on an object.  However, it is possible to grant a
+   privilege <quote>with grant option</>, which gives the recipient
+   the right to grant it in turn to others.  If the grant option is
+   subsequently revoked then all who received the privilege from that
+   recipient (directly or through a chain of grants) will lose the
+   privilege.  For details see the <xref linkend="sql-grant"
+   endterm="sql-grant-title"> and <xref linkend="sql-revoke"
+   endterm="sql-revoke-title"> reference pages.
+  </para>
+ </sect1>
+
+ <sect1 id="ddl-schemas">
+  <title>Schemas</title>
+
+  <indexterm zone="ddl-schemas">
+   <primary>schema</primary>
+  </indexterm>
+
+  <para>
+   A <productname>PostgreSQL</productname> database cluster
+   contains one or more named databases.  Users and groups of users are
+   shared across the entire cluster, but no other data is shared across
+   databases.  Any given client connection to the server can access
+   only the data in a single database, the one specified in the connection
+   request.
+  </para>
+
+  <note>
+   <para>
+    Users of a cluster do not necessarily have the privilege to access every
+    database in the cluster.  Sharing of user names means that there
+    cannot be different users named, say, <literal>joe</> in two databases
+    in the same cluster; but the system can be configured to allow
+    <literal>joe</> access to only some of the databases.
+   </para>
+  </note>
+
+  <para>
+   A database contains one or more named <firstterm>schemas</>, which
+   in turn contain tables.  Schemas also contain other kinds of named
+   objects, including data types, functions, and operators.  The same
+   object name can be used in different schemas without conflict; for
+   example, both <literal>schema1</> and <literal>myschema</> may
+   contain tables named <literal>mytable</>.  Unlike databases,
+   schemas are not rigidly separated: a user may access objects in any
+   of the schemas in the database he is connected to, if he has
+   privileges to do so.
   </para>
 
   <para>
-   Both parent and child tables can have primary and foreign keys, so
-   that they can take part normally on both the referencing and
-   referenced sides of a foreign key constraint. Indexes may be
-   defined on any of these columns whether or not they are inherited.
-   However, a serious current limitation of the inheritance feature is
-   that indexes (including unique constraints) and foreign key
-   constraints only apply to single tables and do not also index their
-   inheritance children.  This is true on both sides of a foreign key
-   constraint.  Thus, in the terms of the above example:
+   There are several reasons why one might want to use schemas:
 
    <itemizedlist>
     <listitem>
      <para>
-      If we declared <structname>cities</>.<structfield>name</> to be
-      <literal>UNIQUE</> or a <literal>PRIMARY KEY</>, this would not stop the
-      <structname>capitals</> table from having rows with names duplicating
-      rows in <structname>cities</>.  And those duplicate rows would by
-      default show up in queries from <structname>cities</>.  In fact, by
-      default <structname>capitals</> would have no unique constraint at all,
-      and so could contain multiple rows with the same name.
-      You could add a unique constraint to <structname>capitals</>, but this
-      would not prevent duplication compared to <structname>cities</>.
+      To allow many users to use one database without interfering with
+      each other.
      </para>
     </listitem>
 
     <listitem>
      <para>
-      Similarly, if we were to specify that
-      <structname>cities</>.<structfield>name</> <literal>REFERENCES</> some
-      other table, this constraint would not automatically propagate to
-      <structname>capitals</>.  However, it is possible to set up a
-      foreign key such as <structname>capitals</>.<structfield>name</>
-      <literal>REFERENCES</> <structname>states</>.<structfield>name</>.
-      So it is possible to workaround this restriction by manually adding
-      foreign keys to each child table.
+      To organize database objects into logical groups to make them
+      more manageable.
      </para>
     </listitem>
 
     <listitem>
      <para>
-      Specifying that another table's column <literal>REFERENCES
-      cities(name)</> would allow the other table to contain city names, but
-      not capital names.  There is no good workaround for this case.
+      Third-party applications can be put into separate schemas so
+      they cannot collide with the names of other objects.
      </para>
     </listitem>
    </itemizedlist>
 
-   These deficiencies will probably be fixed in some future release,
-   but in the meantime considerable care is needed in deciding whether
-   inheritance is useful for your problem.
-
+   Schemas are analogous to directories at the operating system level,
+   except that schemas cannot be nested.
   </para>
 
-  <note>
-   <title>Deprecated</title>
+  <sect2 id="ddl-schemas-create">
+   <title>Creating a Schema</title>
+
+   <indexterm zone="ddl-schemas-create">
+    <primary>schema</primary>
+    <secondary>creating</secondary>
+   </indexterm>
+
    <para>
-     In previous versions of <productname>PostgreSQL</productname>, the
-     default behavior was not to include child tables in queries. This was
-     found to be error prone and is also in violation of the SQL
-     standard. Under the old syntax, to get the sub-tables you append
-     <literal>*</literal> to the table name. For example:
+    To create a schema, use the command <command>CREATE
+    SCHEMA</command>.  Give the schema a name of your choice.  For
+    example:
 <programlisting>
-SELECT * from cities*;
+CREATE SCHEMA myschema;
 </programlisting>
-     You can still explicitly specify scanning child tables by
-     appending <literal>*</literal>, as well as explicitly specify not
-     scanning child tables by writing <quote>ONLY</quote>.  But
-     beginning in version 7.1, the default behavior for an undecorated
-     table name is to scan its child tables too, whereas before the
-     default was not to do so.  To get the old default behavior,
-     disable the <xref linkend="guc-sql-inheritance"> configuration
-     option.
    </para>
-  </note>
-
-  </sect1>
-
-  <sect1 id="ce-partitioning">
-   <title>Constraint Exclusion and Partitioning</title>
 
    <indexterm>
-    <primary>partitioning</primary>
+    <primary>qualified name</primary>
    </indexterm>
 
    <indexterm>
-    <primary>constraint exclusion</primary>
+    <primary>name</primary>
+    <secondary>qualified</secondary>
    </indexterm>
 
    <para>
-    <productname>PostgreSQL</productname> supports basic table
-    partitioning. This section describes why and how you can implement
-    this as part of your database design.
+    To create or access objects in a schema, write a
+    <firstterm>qualified name</> consisting of the schema name and
+    table name separated by a dot:
+<synopsis>
+<replaceable>schema</><literal>.</><replaceable>table</>
+</synopsis>
+    This works anywhere a table name is expected, including the table
+    modification commands and the data access commands discussed in
+    the following chapters.
+    (For brevity we will speak of tables only, but the same ideas apply
+    to other kinds of named objects, such as types and functions.)
    </para>
 
-   <sect2 id="ce-partitioning-overview">
-     <title>Overview</title>
-
    <para>
-    Currently, partitioning is implemented in conjunction with table
-    inheritance only, though using fully SQL compliant syntax.
-    Table inheritance allows tables to be split into partitions, and
-    constraint exclusion allows partitions to be selectively combined
-    as needed to satisfy a particular <command>SELECT</command>
-    statement. You should be familiar with inheritance (see <xref
-    linkend="ddl-inherit">) before attempting to implement
-    partitioning.
+    Actually, the even more general syntax
+<synopsis>
+<replaceable>database</><literal>.</><replaceable>schema</><literal>.</><replaceable>table</>
+</synopsis>
+    can be used too, but at present this is just for <foreignphrase>pro
+    forma</> compliance with the SQL standard.  If you write a database name,
+    it must be the same as the database you are connected to.
    </para>
 
    <para>
-    Partitioning can provide several benefits:
-   <itemizedlist>
-    <listitem>
-     <para>
-      Query performance can be improved dramatically for certain kinds
-      of queries without the need to maintain costly indexes.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Insert performance can be improved by breaking down a large
-      index into multiple pieces. When an index no longer fits easily
-      in memory, both read and write operations on the index take
-      progressively more disk accesses.
-     </para>
-    </listitem>
+    So to create a table in the new schema, use
+<programlisting>
+CREATE TABLE myschema.mytable (
+ ...
+);
+</programlisting>
+   </para>
 
-    <listitem>
-     <para>
-      Bulk deletes may be avoided altogether by simply removing one of the
-      partitions, if that requirement is planned into the partitioning design.
-     </para>
-    </listitem>
+   <indexterm>
+    <primary>schema</primary>
+    <secondary>removing</secondary>
+   </indexterm>
 
-    <listitem>
-     <para>
-      Seldom-used data can be migrated to cheaper and slower storage media.
-     </para>
-    </listitem>
-   </itemizedlist>
+   <para>
+    To drop a schema if it's empty (all objects in it have been
+    dropped), use
+<programlisting>
+DROP SCHEMA myschema;
+</programlisting>
+    To drop a schema including all contained objects, use
+<programlisting>
+DROP SCHEMA myschema CASCADE;
+</programlisting>
+    See <xref linkend="ddl-depend"> for a description of the general
+    mechanism behind this.
+   </para>
 
-    The benefits will normally be worthwhile only when a table would
-    otherwise be very large. The exact point at which a table will
-    benefit from partitioning depends on the application, although the
-    size of the table should usually exceed the physical memory of the
-    database server.
+   <para>
+    Often you will want to create a schema owned by someone else
+    (since this is one of the ways to restrict the activities of your
+    users to well-defined namespaces).  The syntax for that is:
+<programlisting>
+CREATE SCHEMA <replaceable>schemaname</replaceable> AUTHORIZATION <replaceable>username</replaceable>;
+</programlisting>
+    You can even omit the schema name, in which case the schema name
+    will be the same as the user name.  See <xref
+    linkend="ddl-schemas-patterns"> for how this can be useful.
    </para>
 
    <para>
-    The following partitioning types are supported by
-    <productname>PostgreSQL</productname> &version;:
+    Schema names beginning with <literal>pg_</> are reserved for
+    system purposes and may not be created by users.
+   </para>
+  </sect2>
 
-    <variablelist>
-     <varlistentry>
-      <term>Range Partitioning</term>
+  <sect2 id="ddl-schemas-public">
+   <title>The Public Schema</title>
 
-      <listitem>
-       <para>
-        The table is partitioned along a <quote>range</quote> defined
-        by a single column or set of columns, with no overlap between
-        partitions. Examples might be a date range or a range of
-        identifiers for particular business objects.
-       </para>
-      </listitem>
-     </varlistentry>
+   <indexterm zone="ddl-schemas-public">
+    <primary>schema</primary>
+    <secondary>public</secondary>
+   </indexterm>
 
-     <varlistentry>
-      <term>List Partitioning</term>
+   <para>
+    In the previous sections we created tables without specifying any
+    schema names.  By default, such tables (and other objects) are
+    automatically put into a schema named <quote>public</quote>.  Every new
+    database contains such a schema.  Thus, the following are equivalent:
+<programlisting>
+CREATE TABLE products ( ... );
+</programlisting>
+    and
+<programlisting>
+CREATE TABLE public.products ( ... );
+</programlisting>
+   </para>
+  </sect2>
 
-      <listitem>
-       <para>
-        The table is partitioned by explicitly listing which values
-        relate to each partition.
-       </para>
-      </listitem>
-     </varlistentry>
-    </variablelist>
+  <sect2 id="ddl-schemas-path">
+   <title>The Schema Search Path</title>
 
-    Hash partitioning is not currently supported.
-   </para>
-   </sect2>
+   <indexterm>
+    <primary>search path</primary>
+   </indexterm>
 
-   <sect2 id="ce-partitioning-implementation">
-     <title>Implementing Partitioning</title>
+   <indexterm>
+    <primary>unqualified name</primary>
+   </indexterm>
 
-    <para>
-     Partitioning a table is a straightforward process.  There
-     are a wide range of options for you to consider, so judging exactly
-     when and how to implement partitioning is a more complex topic. We
-     will address that complexity primarily through the examples in this
-     section.
-    </para>
+   <indexterm>
+    <primary>name</primary>
+    <secondary>unqualified</secondary>
+   </indexterm>
 
-    <para>
-     To use partitioning, do the following:
-     <orderedlist spacing=compact>
-      <listitem>
-       <para>
-        Create the <quote>master</quote> table, from which all of the
-        partitions will inherit.
-       </para>
-       <para>
-        This table will contain no data.  Do not define any
-        constraints or keys on this table, unless you intend them to
-        be applied equally to all partitions.
-       </para>
-      </listitem>
+   <para>
+    Qualified names are tedious to write, and it's often best not to
+    wire a particular schema name into applications anyway.  Therefore
+    tables are often referred to by <firstterm>unqualified names</>,
+    which consist of just the table name.  The system determines which table
+    is meant by following a <firstterm>search path</>, which is a list
+    of schemas to look in.  The first matching table in the search path
+    is taken to be the one wanted.  If there is no match in the search
+    path, an error is reported, even if matching table names exist
+    in other schemas in the database.
+   </para>
 
-      <listitem>
-       <para>
-        Create several <quote>child</quote> tables that inherit from
-        the master table.
-       </para>
+   <indexterm>
+    <primary>schema</primary>
+    <secondary>current</secondary>
+   </indexterm>
 
-       <para>
-        We will refer to the child tables as partitions, though they
-        are in every way normal <productname>PostgreSQL</> tables.
-       </para>
-      </listitem>
+   <para>
+    The first schema named in the search path is called the current schema.
+    Aside from being the first schema searched, it is also the schema in
+    which new tables will be created if the <command>CREATE TABLE</>
+    command does not specify a schema name.
+   </para>
 
-      <listitem>
-       <para>
-        Add table constraints to define the allowed values in each partition.
-       </para>
-       <para>
-        Only clauses of the form [COLUMN] [OPERATOR] [CONSTANT(s)] will be used
-        for constraint exclusion. Simple examples would be:
+   <indexterm>
+    <primary>search_path</primary>
+   </indexterm>
+
+   <para>
+    To show the current search path, use the following command:
 <programlisting>
-CHECK ( x = 1 )
-CHECK ( county IN ( 'Oxfordshire','Buckinghamshire','Warwickshire' ))
-CHECK ( outletID BETWEEN 1 AND 99 )
+SHOW search_path;
 </programlisting>
+    In the default setup this returns:
+<screen>
+ search_path
+--------------
+ $user,public
+</screen>
+    The first element specifies that a schema with the same name as
+    the current user is to be searched.  If no such schema exists,
+    the entry is ignored.  The second element refers to the
+    public schema that we have seen already.
+   </para>
 
-        These can be linked together with the Boolean operators
-        <literal>AND</literal> and <literal>OR</literal> to form
-        complex constraints. Note that there is no difference in
-        syntax between range and list partitioning; those terms are
-        descriptive only. Ensure that the set of values in each child
-        table do not overlap.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        Add any other indexes you want to the partitions, bearing in
-        mind that it is always more efficient to add indexes after
-        data has been bulk loaded.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        Optionally, define a rule or trigger to redirect modifications
-        of the master table to the appropriate partition.
-       </para>
-      </listitem>
-
-     </orderedlist>
-    </para>
-
-    <para>
-     For example, suppose we are constructing a database for a large
-     ice cream company. The company measures peak temperatures every
-     day as well as ice cream sales in each region. They have two
-     tables:
-
-<programlisting>
-CREATE TABLE cities (
-    id              int not null,
-    name            text not null,
-    altitude        int            -- in feet
-);
-
-CREATE TABLE measurement (
-    city_id         int not null,
-    logdate         date not null,
-    peaktemp        int,
-    unitsales       int
-);
-</programlisting>
-
-     To reduce the amount of old data that needs to be stored, we
-     decide to only keep the most recent 3 years worth of data. At the
-     beginning of each month we remove the oldest month's data.
-    </para>
-
-    <para>
-     Most queries just access the last week, month or quarter's data,
-     since we need to keep track of sales. As a result we have a large table,
-     yet only the most frequent 10% is accessed. Most of these queries
-     are online reports for various levels of management. These queries access
-     much of the table, so it is difficult to build enough indexes and at
-     the same time allow us to keep loading all of the data fast enough.
-     Yet, the reports are online so we need to respond quickly.
-    </para>
-
-    <para>
-     In this situation we can use partitioning to help us meet all of our
-     different requirements for the measurements table. Following the
-     steps outlined above, partitioning can be enabled as follows:
-    </para>
-
-    <para>
-     <orderedlist spacing=compact>
-      <listitem>
-       <para>
-        The measurement table is our master table.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        Next we create one partition for each month using inheritance:
-
-<programlisting>
-CREATE TABLE measurement_yy04mm02 ( ) INHERITS (measurement);
-CREATE TABLE measurement_yy04mm03 ( ) INHERITS (measurement);
-...
-CREATE TABLE measurement_yy05mm11 ( ) INHERITS (measurement);
-CREATE TABLE measurement_yy05mm12 ( ) INHERITS (measurement);
-CREATE TABLE measurement_yy06mm01 ( ) INHERITS (measurement);
-</programlisting>
-
-        Each of the partitions are complete tables in their own right,
-        but they inherit their definition from the measurement table.
-       </para>
-
-       <para>
-        This solves one of our problems: deleting old data. Each
-        month, all we need to do is perform a <command>DROP
-        TABLE</command> on the oldest table and create a new table to
-        insert into.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        We now add non-overlapping table constraints, so that our
-        table creation script becomes:
-
- <programlisting>
-CREATE TABLE measurement_yy04mm02 (
-    CHECK ( logdate >= DATE '2004-02-01' AND logdate < DATE '2004-03-01' )
-                                    ) INHERITS (measurement);
-CREATE TABLE measurement_yy04mm03 (
-    CHECK ( logdate >= DATE '2004-03-01' AND logdate < DATE '2004-04-01' )
-                                    ) INHERITS (measurement);
-...
-CREATE TABLE measurement_yy05mm11 (
-    CHECK ( logdate >= DATE '2005-11-01' AND logdate < DATE '2005-12-01' )
-                                    ) INHERITS (measurement);
-CREATE TABLE measurement_yy05mm12 (
-    CHECK ( logdate >= DATE '2005-12-01' AND logdate < DATE '2006-01-01' )
-                                    ) INHERITS (measurement);
-CREATE TABLE measurement_yy06mm01 (
-    CHECK ( logdate >= DATE '2006-01-01' AND logdate < DATE '2006-02-01' )
-                                    ) INHERITS (measurement);
-</programlisting>
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        We choose not to add further indexes at this time.
-       </para>
-      </listitem>
-
-      <listitem>
-       <para>
-        Data will be added each day to the latest partition. This
-        allows us to set up a very simple rule to insert data. We must
-        redefine this each month so that it always points to the
-        current partition.
-
-<programlisting>
-CREATE OR REPLACE RULE measurement_current_partition AS
-ON INSERT
-TO measurement
-DO INSTEAD
-    INSERT INTO measurement_yy06mm01 VALUES ( NEW.city_id,
-                                              NEW.logdate,
-                                              NEW.peaktemp,
-                                              NEW.unitsales );
-</programlisting>
-
-        We might want to insert data and have the server automatically
-        locate the partition into which the row should be added. We
-        could do this with a more complex set of rules as shown below.
-
-<programlisting>
-CREATE RULE measurement_insert_yy04mm02 AS
-ON INSERT
-TO measurement WHERE
-    ( logdate >= DATE '2004-02-01' AND logdate < DATE '2004-03-01' )
-DO INSTEAD
-    INSERT INTO measurement_yy04mm02 VALUES ( NEW.city_id,
-                                              NEW.logdate,
-                                              NEW.peaktemp,
-                                              NEW.unitsales );
-...
-CREATE RULE measurement_insert_yy05mm12 AS
-ON INSERT
-TO measurement WHERE
-    ( logdate >= DATE '2005-12-01' AND logdate < DATE '2006-01-01' )
-DO INSTEAD
-    INSERT INTO measurement_yy05mm12 VALUES ( NEW.city_id,
-                                              NEW.logdate,
-                                              NEW.peaktemp,
-                                              NEW.unitsales );
-CREATE RULE measurement_insert_yy06mm01 AS
-ON INSERT
-TO measurement WHERE
-    ( logdate >= DATE '2006-01-01' AND logdate < DATE '2006-02-01' )
-DO INSTEAD
-    INSERT INTO measurement_yy06mm01 VALUES ( NEW.city_id,
-                                              NEW.logdate,
-                                              NEW.peaktemp,
-                                              NEW.unitsales );
-</programlisting>
-
-        Note that the <literal>WHERE</literal> clause in each rule
-        exactly matches those used for the <literal>CHECK</literal>
-        constraints on each partition.
-       </para>
-      </listitem>
-     </orderedlist>
-    </para>
-
-    <para>
-     As we can see, a complex partitioning scheme could require a
-     substantial amount of DDL. In the above example we would be
-     creating a new partition each month, so it may be wise to write a
-     script that generates the required DDL automatically.
-    </para>
-
-   <para>
-    The following caveats apply:
-   <itemizedlist>
-    <listitem>
-     <para>
-      There is currently no way to specify that all of the
-      <literal>CHECK</literal> constraints are mutually
-      exclusive. Care is required by the database designer.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      There is currently no way to specify that rows may not be
-      inserted into the master table. A <literal>CHECK</literal>
-      constraint on the master table will be inherited by all child
-      tables, so that cannot not be used for this purpose.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      For some data types you must explicitly coerce the constant
-      values into the data type of the column. The following constraint
-      will work if <varname>x</varname> is an <type>integer</type>
-      data type, but not if <varname>x</varname> is a
-      <type>bigint</type>:
-<programlisting>
-CHECK ( x = 1 )
-</programlisting>
-      For <type>bigint</type> we must use a constraint like:
-<programlisting>
-CHECK ( x = 1::bigint )
-</programlisting>
-      The problem is not limited to the <type>bigint</type> data type
-      &mdash; it can occur whenever the default data type of the
-      constant does not match the data type of the column to which it
-      is being compared.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      Partitioning can also be arranged using a <literal>UNION
-      ALL</literal> view:
-
-<programlisting>
-CREATE VIEW measurement AS
-          SELECT * FROM measurement_yy04mm02
-UNION ALL SELECT * FROM measurement_yy04mm03
-...
-UNION ALL SELECT * FROM measurement_yy05mm11
-UNION ALL SELECT * FROM measurement_yy05mm12
-UNION ALL SELECT * FROM measurement_yy06mm01;
-</programlisting>
-
-      However, constraint exclusion is currently not supported for
-      partitioned tables defined in this manner.
-     </para>
-    </listitem>
-   </itemizedlist>
-   </para>
-   </sect2>
-
-   <sect2 id="constraint-exclusion-queries">
-    <title>Constraint Exclusion in Queries</title>
-
-   <para>
-    Partitioning can be used to improve query performance when used in
-    conjunction with constraint exclusion. As an example:
-
-<programlisting>
-SET constraint_exclusion=true;
-SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
-</programlisting>
-
-    Without constraint exclusion, the above query would scan each of
-    the partitions of the measurement table. With constraint
-    exclusion, the planner will examine each of the constraints and
-    try to prove that each of the partitions needs to be involved in
-    the query. If the planner is able to refute that for any
-    partition, it excludes the partition from the query plan.
-   </para>
+   <para>
+    The first schema in the search path that exists is the default
+    location for creating new objects.  That is the reason that by
+    default objects are created in the public schema.  When objects
+    are referenced in any other context without schema qualification
+    (table modification, data modification, or query commands) the
+    search path is traversed until a matching object is found.
+    Therefore, in the default configuration, any unqualified access
+    again can only refer to the public schema.
+   </para>
 
    <para>
-    You can use the <command>EXPLAIN</> command to show the difference
-    between a plan with <varname>constraint_exclusion</> on and a plan
-    with it off.
-
-<programlisting>
-SET constraint_exclusion=false;
-EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
-
-                                          QUERY PLAN
------------------------------------------------------------------------------------------------
- Aggregate  (cost=158.66..158.68 rows=1 width=0)
-   ->  Append  (cost=0.00..151.88 rows=2715 width=0)
-         ->  Seq Scan on measurement  (cost=0.00..30.38 rows=543 width=0)
-               Filter: (logdate >= '2006-01-01'::date)
-         ->  Seq Scan on measurement_yy04mm02 measurement  (cost=0.00..30.38 rows=543 width=0)
-               Filter: (logdate >= '2006-01-01'::date)
-         ->  Seq Scan on measurement_yy04mm03 measurement  (cost=0.00..30.38 rows=543 width=0)
-               Filter: (logdate >= '2006-01-01'::date)
-...
-         ->  Seq Scan on measurement_yy05mm12 measurement  (cost=0.00..30.38 rows=543 width=0)
-               Filter: (logdate >= '2006-01-01'::date)
-         ->  Seq Scan on measurement_yy06mm01 measurement  (cost=0.00..30.38 rows=543 width=0)
-               Filter: (logdate >= '2006-01-01'::date)
-</programlisting>
-
-    Now when we enable constraint exclusion, we get a significantly
-    reduced plan but the same result set:
-
-<programlisting>
-SET constraint_exclusion=true;
-EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
-                                          QUERY PLAN
------------------------------------------------------------------------------------------------
- Aggregate  (cost=63.47..63.48 rows=1 width=0)
-   ->  Append  (cost=0.00..60.75 rows=1086 width=0)
-         ->  Seq Scan on measurement  (cost=0.00..30.38 rows=543 width=0)
-               Filter: (logdate >= '2006-01-01'::date)
-         ->  Seq Scan on measurement_yy06mm01 measurement  (cost=0.00..30.38 rows=543 width=0)
-               Filter: (logdate >= '2006-01-01'::date)
-</programlisting>
-
-    Don't forget that you still need to run <command>ANALYZE</command>
-    on each partition individually. A command like this
+    To put our new schema in the path, we use
 <programlisting>
-ANALYZE measurement;
+SET search_path TO myschema,public;
 </programlisting>
-
-    only affects the master table.
-   </para>
-
-   <para>
-    No indexes are required to use constraint exclusion. The
-    partitions should be defined with appropriate <literal>CHECK</>
-    constraints. These are then compared with the predicates of the
-    <command>SELECT</> query to determine which partitions must be
-    scanned.
-   </para>
-
-   <para>
-    The following caveats apply to this release:
-   <itemizedlist>
-    <listitem>
-     <para>
-      Constraint exclusion only works when the query directly matches
-      a constant. A constant bound to a parameterized query will not
-      work in the same way since the plan is fixed and would need to
-      vary with each execution.  Also, stable constants such as
-      <literal>CURRENT_DATE</literal> may not be used, since these are
-      constant only for during the execution of a single query.  Join
-      conditions will not allow constraint exclusion to work either.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      <command>UPDATE</command> and <command>DELETE</command> commands
-      against the master table do not perform constraint exclusion.
-     </para>
-    </listitem>
-
-    <listitem>
-     <para>
-      All constraints on all partitions of the master table are considered for
-      constraint exclusion, so large numbers of partitions are likely to
-      increase query planning time considerably.
-     </para>
-    </listitem>
-
-   </itemizedlist>
+    (We omit the <literal>$user</literal> here because we have no
+    immediate need for it.)  And then we can access the table without
+    schema qualification:
+<programlisting>
+DROP TABLE mytable;
+</programlisting>
+    Also, since <literal>myschema</literal> is the first element in
+    the path, new objects would by default be created in it.
    </para>
 
-   </sect2>
-
- </sect1>
-
- <sect1 id="ddl-alter">
-  <title>Modifying Tables</title>
-
-  <indexterm zone="ddl-alter">
-   <primary>table</primary>
-   <secondary>modifying</secondary>
-  </indexterm>
-
-  <para>
-   When you create a table and you realize that you made a mistake, or
-   the requirements of the application change, then you can drop the
-   table and create it again.  But this is not a convenient option if
-   the table is already filled with data, or if the table is
-   referenced by other database objects (for instance a foreign key
-   constraint).  Therefore <productname>PostgreSQL</productname>
-   provides a family of commands to make modifications to existing
-   tables.  Note that this is conceptually distinct from altering
-   the data contained in the table: here we are interested in altering
-   the definition, or structure, of the table.
-  </para>
-
-  <para>
-   You can
-   <itemizedlist spacing="compact">
-    <listitem>
-     <para>Add columns,</para>
-    </listitem>
-    <listitem>
-     <para>Remove columns,</para>
-    </listitem>
-    <listitem>
-     <para>Add constraints,</para>
-    </listitem>
-    <listitem>
-     <para>Remove constraints,</para>
-    </listitem>
-    <listitem>
-     <para>Change default values,</para>
-    </listitem>
-    <listitem>
-     <para>Change column data types,</para>
-    </listitem>
-    <listitem>
-     <para>Rename columns,</para>
-    </listitem>
-    <listitem>
-     <para>Rename tables.</para>
-    </listitem>
-   </itemizedlist>
-
-   All these actions are performed using the
-   <xref linkend="sql-altertable" endterm="sql-altertable-title">
-   command.
-  </para>
-
-  <sect2>
-   <title>Adding a Column</title>
-
-   <indexterm>
-    <primary>column</primary>
-    <secondary>adding</secondary>
-   </indexterm>
-
    <para>
-    To add a column, use a command like this:
+    We could also have written
 <programlisting>
-ALTER TABLE products ADD COLUMN description text;
+SET search_path TO myschema;
 </programlisting>
-    The new column is initially filled with whatever default
-    value is given (null if you don't specify a <literal>DEFAULT</> clause).
+    Then we no longer have access to the public schema without
+    explicit qualification.  There is nothing special about the public
+    schema except that it exists by default.  It can be dropped, too.
    </para>
 
    <para>
-    You can also define constraints on the column at the same time,
-    using the usual syntax:
+    See also <xref linkend="functions-info"> for other ways to manipulate
+    the schema search path.
+   </para>
+
+   <para>
+    The search path works in the same way for data type names, function names,
+    and operator names as it does for table names.  Data type and function
+    names can be qualified in exactly the same way as table names.  If you
+    need to write a qualified operator name in an expression, there is a
+    special provision: you must write
+<synopsis>
+<literal>OPERATOR(</><replaceable>schema</><literal>.</><replaceable>operator</><literal>)</>
+</synopsis>
+    This is needed to avoid syntactic ambiguity.  An example is
 <programlisting>
-ALTER TABLE products ADD COLUMN description text CHECK (description &lt;&gt; '');
+SELECT 3 OPERATOR(pg_catalog.+) 4;
 </programlisting>
-    In fact all the options that can be applied to a column description
-    in <command>CREATE TABLE</> can be used here.  Keep in mind however
-    that the default value must satisfy the given constraints, or the
-    <literal>ADD</> will fail.  Alternatively, you can add
-    constraints later (see below) after you've filled in the new column
-    correctly.
+    In practice one usually relies on the search path for operators,
+    so as not to have to write anything so ugly as that.
    </para>
   </sect2>
 
-  <sect2>
-   <title>Removing a Column</title>
+  <sect2 id="ddl-schemas-priv">
+   <title>Schemas and Privileges</title>
 
-   <indexterm>
-    <primary>column</primary>
-    <secondary>removing</secondary>
+   <indexterm zone="ddl-schemas-priv">
+    <primary>privilege</primary>
+    <secondary sortas="schemas">for schemas</secondary>
    </indexterm>
 
    <para>
-    To remove a column, use a command like this:
-<programlisting>
-ALTER TABLE products DROP COLUMN description;
-</programlisting>
-    Whatever data was in the column disappears.  Table constraints involving
-    the column are dropped, too.  However, if the column is referenced by a
-    foreign key constraint of another table,
-    <productname>PostgreSQL</productname> will not silently drop that
-    constraint.  You can authorize dropping everything that depends on
-    the column by adding <literal>CASCADE</>:
+    By default, users cannot access any objects in schemas they do not
+    own.  To allow that, the owner of the schema needs to grant the
+    <literal>USAGE</literal> privilege on the schema.  To allow users
+    to make use of the objects in the schema, additional privileges
+    may need to be granted, as appropriate for the object.
+   </para>
+
+   <para>
+    A user can also be allowed to create objects in someone else's
+    schema.  To allow that, the <literal>CREATE</literal> privilege on
+    the schema needs to be granted.  Note that by default, everyone
+    has <literal>CREATE</literal> and <literal>USAGE</literal> privileges on
+    the schema
+    <literal>public</literal>.  This allows all users that are able to
+    connect to a given database to create objects in its
+    <literal>public</literal> schema.  If you do
+    not want to allow that, you can revoke that privilege:
 <programlisting>
-ALTER TABLE products DROP COLUMN description CASCADE;
+REVOKE CREATE ON SCHEMA public FROM PUBLIC;
 </programlisting>
-    See <xref linkend="ddl-depend"> for a description of the general
-    mechanism behind this.
+    (The first <quote>public</quote> is the schema, the second
+    <quote>public</quote> means <quote>every user</quote>.  In the
+    first sense it is an identifier, in the second sense it is a
+    key word, hence the different capitalization; recall the
+    guidelines from <xref linkend="sql-syntax-identifiers">.)
    </para>
   </sect2>
 
-  <sect2>
-   <title>Adding a Constraint</title>
+  <sect2 id="ddl-schemas-catalog">
+   <title>The System Catalog Schema</title>
 
-   <indexterm>
-    <primary>constraint</primary>
-    <secondary>adding</secondary>
+   <indexterm zone="ddl-schemas-catalog">
+    <primary>system catalog</primary>
+    <secondary>schema</secondary>
    </indexterm>
 
    <para>
-    To add a constraint, the table constraint syntax is used.  For example:
-<programlisting>
-ALTER TABLE products ADD CHECK (name &lt;&gt; '');
-ALTER TABLE products ADD CONSTRAINT some_name UNIQUE (product_no);
-ALTER TABLE products ADD FOREIGN KEY (product_group_id) REFERENCES product_groups;
-</programlisting>
-    To add a not-null constraint, which cannot be written as a table
-    constraint, use this syntax:
-<programlisting>
-ALTER TABLE products ALTER COLUMN product_no SET NOT NULL;
-</programlisting>
+    In addition to <literal>public</> and user-created schemas, each
+    database contains a <literal>pg_catalog</> schema, which contains
+    the system tables and all the built-in data types, functions, and
+    operators.  <literal>pg_catalog</> is always effectively part of
+    the search path.  If it is not named explicitly in the path then
+    it is implicitly searched <emphasis>before</> searching the path's
+    schemas.  This ensures that built-in names will always be
+    findable.  However, you may explicitly place
+    <literal>pg_catalog</> at the end of your search path if you
+    prefer to have user-defined names override built-in names.
    </para>
 
    <para>
-    The constraint will be checked immediately, so the table data must
-    satisfy the constraint before it can be added.
+    In <productname>PostgreSQL</productname> versions before 7.3,
+    table names beginning with <literal>pg_</> were reserved.  This is
+    no longer true: you may create such a table name if you wish, in
+    any non-system schema.  However, it's best to continue to avoid
+    such names, to ensure that you won't suffer a conflict if some
+    future version defines a system table named the same as your
+    table.  (With the default search path, an unqualified reference to
+    your table name would be resolved as the system table instead.)
+    System tables will continue to follow the convention of having
+    names beginning with <literal>pg_</>, so that they will not
+    conflict with unqualified user-table names so long as users avoid
+    the <literal>pg_</> prefix.
    </para>
   </sect2>
 
-  <sect2>
-   <title>Removing a Constraint</title>
+  <sect2 id="ddl-schemas-patterns">
+   <title>Usage Patterns</title>
 
-   <indexterm>
-    <primary>constraint</primary>
-    <secondary>removing</secondary>
-   </indexterm>
+   <para>
+    Schemas can be used to organize your data in many ways.  There are
+    a few usage patterns that are recommended and are easily supported by
+    the default configuration:
+    <itemizedlist>
+     <listitem>
+      <para>
+       If you do not create any schemas then all users access the
+       public schema implicitly.  This simulates the situation where
+       schemas are not available at all.  This setup is mainly
+       recommended when there is only a single user or a few cooperating
+       users in a database.  This setup also allows smooth transition
+       from the non-schema-aware world.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       You can create a schema for each user with the same name as
+       that user.  Recall that the default search path starts with
+       <literal>$user</literal>, which resolves to the user name.
+       Therefore, if each user has a separate schema, they access their
+       own schemas by default.
+      </para>
+
+      <para>
+       If you use this setup then you might also want to revoke access
+       to the public schema (or drop it altogether), so users are
+       truly constrained to their own schemas.
+      </para>
+     </listitem>
+
+     <listitem>
+      <para>
+       To install shared applications (tables to be used by everyone,
+       additional functions provided by third parties, etc.), put them
+       into separate schemas.  Remember to grant appropriate
+       privileges to allow the other users to access them.  Users can
+       then refer to these additional objects by qualifying the names
+       with a schema name, or they can put the additional schemas into
+       their search path, as they choose.
+      </para>
+     </listitem>
+    </itemizedlist>
+   </para>
+  </sect2>
+
+  <sect2 id="ddl-schemas-portability">
+   <title>Portability</title>
 
    <para>
-    To remove a constraint you need to know its name.  If you gave it
-    a name then that's easy.  Otherwise the system assigned a
-    generated name, which you need to find out.  The
-    <application>psql</application> command <literal>\d
-    <replaceable>tablename</replaceable></literal> can be helpful
-    here; other interfaces might also provide a way to inspect table
-    details.  Then the command is:
-<programlisting>
-ALTER TABLE products DROP CONSTRAINT some_name;
-</programlisting>
-    (If you are dealing with a generated constraint name like <literal>$2</>,
-    don't forget that you'll need to double-quote it to make it a valid
-    identifier.)
+    In the SQL standard, the notion of objects in the same schema
+    being owned by different users does not exist.  Moreover, some
+    implementations do not allow you to create schemas that have a
+    different name than their owner.  In fact, the concepts of schema
+    and user are nearly equivalent in a database system that
+    implements only the basic schema support specified in the
+    standard.  Therefore, many users consider qualified names to
+    really consist of
+    <literal><replaceable>username</>.<replaceable>tablename</></literal>.
+    This is how <productname>PostgreSQL</productname> will effectively
+    behave if you create a per-user schema for every user.
    </para>
 
    <para>
-    As with dropping a column, you need to add <literal>CASCADE</> if you
-    want to drop a constraint that something else depends on.  An example
-    is that a foreign key constraint depends on a unique or primary key
-    constraint on the referenced column(s).
+    Also, there is no concept of a <literal>public</> schema in the
+    SQL standard.  For maximum conformance to the standard, you should
+    not use (perhaps even remove) the <literal>public</> schema.
    </para>
 
    <para>
-    This works the same for all constraint types except not-null
-    constraints. To drop a not null constraint use
-<programlisting>
-ALTER TABLE products ALTER COLUMN product_no DROP NOT NULL;
-</programlisting>
-    (Recall that not-null constraints do not have names.)
+    Of course, some SQL database systems might not implement schemas
+    at all, or provide namespace support by allowing (possibly
+    limited) cross-database access.  If you need to work with those
+    systems, then maximum portability would be achieved by not using
+    schemas at all.
    </para>
   </sect2>
+ </sect1>
 
-  <sect2>
-   <title>Changing a Column's Default Value</title>
-
-   <indexterm>
-    <primary>default value</primary>
-    <secondary>changing</secondary>
-   </indexterm>
+ <sect1 id="ddl-inherit">
+  <title>Inheritance</title>
 
-   <para>
-    To set a new default for a column, use a command like this:
-<programlisting>
-ALTER TABLE products ALTER COLUMN price SET DEFAULT 7.77;
-</programlisting>
-    Note that this doesn't affect any existing rows in the table, it
-    just changes the default for future <command>INSERT</> commands.
-   </para>
+  <indexterm>
+   <primary>inheritance</primary>
+  </indexterm>
 
-   <para>
-    To remove any default value, use
-<programlisting>
-ALTER TABLE products ALTER COLUMN price DROP DEFAULT;
-</programlisting>
-    This is effectively the same as setting the default to null.
-    As a consequence, it is not an error
-    to drop a default where one hadn't been defined, because the
-    default is implicitly the null value.
-   </para>
-  </sect2>
+  <indexterm>
+   <primary>table</primary>
+   <secondary>inheritance</secondary>
+  </indexterm>
 
-  <sect2>
-   <title>Changing a Column's Data Type</title>
+  <para>
+   <productname>PostgreSQL</productname> implements table inheritance
+   which can be a useful tool for database designers.  (SQL:1999 and
+   later define a type inheritance feature, which differs in many
+   respects from the features described here.)
+  </para>
 
-   <indexterm>
-    <primary>column data type</primary>
-    <secondary>changing</secondary>
-   </indexterm>
+  <para>
+   Let's start with an example: suppose we are trying to build a data
+   model for cities.  Each state has many cities, but only one
+   capital. We want to be able to quickly retrieve the capital city
+   for any particular state. This can be done by creating two tables,
+   one for state capitals and one for cities that are not
+   capitals. However, what happens when we want to ask for data about
+   a city, regardless of whether it is a capital or not? The
+   inheritance feature can help to resolve this problem. We define the
+   <structname>capitals</structname> table so that it inherits from
+   <structname>cities</structname>:
 
-   <para>
-    To convert a column to a different data type, use a command like this:
 <programlisting>
-ALTER TABLE products ALTER COLUMN price TYPE numeric(10,2);
-</programlisting>
-    This will succeed only if each existing entry in the column can be
-    converted to the new type by an implicit cast.  If a more complex
-    conversion is needed, you can add a <literal>USING</> clause that
-    specifies how to compute the new values from the old.
-   </para>
+CREATE TABLE cities (
+    name            text,
+    population      float,
+    altitude        int     -- in feet
+);
 
-   <para>
-    <productname>PostgreSQL</> will attempt to convert the column's
-    default value (if any) to the new type, as well as any constraints
-    that involve the column.  But these conversions may fail, or may
-    produce surprising results.  It's often best to drop any constraints
-    on the column before altering its type, and then add back suitably
-    modified constraints afterwards.
-   </para>
-  </sect2>
+CREATE TABLE capitals (
+    state           char(2)
+) INHERITS (cities);
+</programlisting>
 
-  <sect2>
-   <title>Renaming a Column</title>
+   In this case, the <structname>capitals</> table <firstterm>inherits</>
+   all the columns of its parent table, <structname>cities</>. State
+   capitals also have an extra column, <structfield>state</>, that shows
+   their state.
+  </para>
 
-   <indexterm>
-    <primary>column</primary>
-    <secondary>renaming</secondary>
-   </indexterm>
+  <para>
+   In <productname>PostgreSQL</productname>, a table can inherit from
+   zero or more other tables, and a query can reference either all
+   rows of a table or all rows of a table plus all of its descendant tables.
+   The latter behavior is the default.
+   For example, the following query finds the names of all cities,
+   including state capitals, that are located at an altitude over
+   500ft:
 
-   <para>
-    To rename a column:
 <programlisting>
-ALTER TABLE products RENAME COLUMN product_no TO product_number;
+SELECT name, altitude
+    FROM cities
+    WHERE altitude &gt; 500;
 </programlisting>
-   </para>
-  </sect2>
 
-  <sect2>
-   <title>Renaming a Table</title>
-
-   <indexterm>
-    <primary>table</primary>
-    <secondary>renaming</secondary>
-   </indexterm>
+   Given the sample data from the <productname>PostgreSQL</productname>
+   tutorial (see <xref linkend="tutorial-sql-intro">), this returns:
 
-   <para>
-    To rename a table:
 <programlisting>
-ALTER TABLE products RENAME TO items;
+   name    | altitude
+-----------+----------
+ Las Vegas |     2174
+ Mariposa  |     1953
+ Madison   |      845
 </programlisting>
-   </para>
-  </sect2>
- </sect1>
-
- <sect1 id="ddl-priv">
-  <title>Privileges</title>
+  </para>
 
-  <indexterm zone="ddl-priv">
-   <primary>privilege</primary>
-  </indexterm>
+  <para>
+   On the other hand, the following query finds all the cities that
+   are not state capitals and are situated at an altitude over 500ft:
 
-  <indexterm>
-   <primary>permission</primary>
-   <see>privilege</see>
-  </indexterm>
+<programlisting>
+SELECT name, altitude
+    FROM ONLY cities
+    WHERE altitude &gt; 500;
 
-  <para>
-   When you create a database object, you become its owner.  By
-   default, only the owner of an object can do anything with the
-   object. In order to allow other users to use it,
-   <firstterm>privileges</firstterm> must be granted.  (However,
-   users that have the superuser attribute can always
-   access any object.)
+   name    | altitude
+-----------+----------
+ Las Vegas |     2174
+ Mariposa  |     1953
+</programlisting>
   </para>
 
   <para>
-   There are several different privileges: <literal>SELECT</>,
-   <literal>INSERT</>, <literal>UPDATE</>, <literal>DELETE</>,
-   <literal>RULE</>, <literal>REFERENCES</>, <literal>TRIGGER</>,
-   <literal>CREATE</>, <literal>TEMPORARY</>, <literal>EXECUTE</>, and
-   <literal>USAGE</>.  The privileges applicable to a particular
-   object vary depending on the object's type (table, function, etc).
-   For complete information on the different types of privileges
-   supported by <productname>PostgreSQL</productname>, refer to the
-   <xref linkend="sql-grant" endterm="sql-grant-title"> reference
-   page.  The following sections and chapters will also show you how
-   those privileges are used.
+   Here the <literal>ONLY</literal> keyword indicates that the query
+   should apply only to <structname>cities</structname>, and not any tables
+   below <structname>cities</structname> in the inheritance hierarchy.  Many
+   of the commands that we have already discussed &mdash;
+   <command>SELECT</command>, <command>UPDATE</command> and
+   <command>DELETE</command> &mdash; support the
+   <literal>ONLY</literal> keyword.
   </para>
 
   <para>
-   The right to modify or destroy an object is always the privilege of
-   the owner only.
-  </para>
+   In some cases you may wish to know which table a particular row
+   originated from. There is a system column called
+   <structfield>tableoid</structfield> in each table which can tell you the
+   originating table:
 
-  <note>
-   <para>
-    To change the owner of a table, index, sequence, or view, use the
-    <xref linkend="sql-altertable" endterm="sql-altertable-title">
-    command.  There are corresponding <literal>ALTER</> commands for
-    other object types.
-   </para>
-  </note>
+<programlisting>
+SELECT c.tableoid, c.name, c.altitude
+FROM cities c
+WHERE c.altitude &gt; 500;
+</programlisting>
+
+   which returns:
 
-  <para>
-   To assign privileges, the <command>GRANT</command> command is
-   used. For example, if <literal>joe</literal> is an existing user, and
-   <literal>accounts</literal> is an existing table, the privilege to
-   update the table can be granted with
 <programlisting>
-GRANT UPDATE ON accounts TO joe;
+ tableoid |   name    | altitude
+----------+-----------+----------
+   139793 | Las Vegas |     2174
+   139793 | Mariposa  |     1953
+   139798 | Madison   |      845
 </programlisting>
-   To grant a privilege to a group, use this syntax:
+
+   (If you try to reproduce this example, you will probably get
+   different numeric OIDs.)  By doing a join with
+   <structname>pg_class</> you can see the actual table names:
+
 <programlisting>
-GRANT SELECT ON accounts TO GROUP staff;
+SELECT p.relname, c.name, c.altitude
+FROM cities c, pg_class p
+WHERE c.altitude &gt; 500 and c.tableoid = p.oid;
+</programlisting>
+
+   which returns:
+
+<programlisting>
+ relname  |   name    | altitude
+----------+-----------+----------
+ cities   | Las Vegas |     2174
+ cities   | Mariposa  |     1953
+ capitals | Madison   |      845
 </programlisting>
-   The special <quote>user</quote> name <literal>PUBLIC</literal> can
-   be used to grant a privilege to every user on the system. Writing
-   <literal>ALL</literal> in place of a specific privilege grants all
-   privileges that are relevant for the object type.
   </para>
 
   <para>
-   To revoke a privilege, use the fittingly named
-   <command>REVOKE</command> command:
+   Inheritance does not automatically propagate data from
+   <command>INSERT</command> or <command>COPY</command> commands to
+   other tables in the inheritance hierarchy. In our example, the
+   following <command>INSERT</command> statement will fail:
 <programlisting>
-REVOKE ALL ON accounts FROM PUBLIC;
+INSERT INTO cities (name, population, altitude, state)
+VALUES ('New York', NULL, NULL, 'NY');
 </programlisting>
-   The special privileges of the object owner (i.e., the right to do
-   <command>DROP</>, <command>GRANT</>, <command>REVOKE</>, etc.)
-   are always implicit in being the owner,
-   and cannot be granted or revoked.  But the object owner can choose
-   to revoke his own ordinary privileges, for example to make a
-   table read-only for himself as well as others.
+   We might hope that the data would somehow be routed to the
+   <structname>capitals</structname> table, but this does not happen:
+   <command>INSERT</command> always inserts into exactly the table
+   specified.  In some cases it is possible to redirect the insertion
+   using a rule (see <xref linkend="rules">).  However that does not
+   help for the above case because the <structname>cities</> table
+   does not contain the column <structfield>state</>, and so the
+   command will be rejected before the rule can be applied.
   </para>
 
   <para>
-   Ordinarily, only the object's owner (or a superuser) can grant or
-   revoke privileges on an object.  However, it is possible to grant a
-   privilege <quote>with grant option</>, which gives the recipient
-   the right to grant it in turn to others.  If the grant option is
-   subsequently revoked then all who received the privilege from that
-   recipient (directly or through a chain of grants) will lose the
-   privilege.  For details see the <xref linkend="sql-grant"
-   endterm="sql-grant-title"> and <xref linkend="sql-revoke"
-   endterm="sql-revoke-title"> reference pages.
+   Check constraints can be defined on tables within an inheritance
+   hierarchy. All check constraints on a parent table are
+   automatically inherited by all of its children.  Other types of
+   constraints are not inherited, however.
   </para>
- </sect1>
 
- <sect1 id="ddl-schemas">
-  <title>Schemas</title>
+  <para>
+   A table can inherit from more than one parent table, in which case it has
+   the union of the columns defined by the parent tables.  Any columns
+   declared in the child table's definition are added to these.  If the
+   same column name appears in multiple parent tables, or in both a parent
+   table and the child's definition, then these columns are <quote>merged</>
+   so that there is only one such column in the child table.  To be merged,
+   columns must have the same data types, else an error is raised.  The
+   merged column will have copies of all the check constraints coming from
+   any one of the column definitions it came from.
+  </para>
 
-  <indexterm zone="ddl-schemas">
-   <primary>schema</primary>
-  </indexterm>
+  <para>
+   Table inheritance can currently only be defined using the <xref
+   linkend="sql-createtable" endterm="sql-createtable-title">
+   statement.  The related statement <command>CREATE TABLE AS</command> does
+   not allow inheritance to be specified. There
+   is no way to add an inheritance link to make an existing table into
+   a child table. Similarly, there is no way to remove an inheritance
+   link from a child table once it has been defined, other than by dropping
+   the table completely.  A parent table cannot be dropped
+   while any of its children remain. If you wish to remove a table and
+   all of its descendants, one easy way is to drop the parent table with
+   the <literal>CASCADE</literal> option.
+  </para>
 
   <para>
-   A <productname>PostgreSQL</productname> database cluster
-   contains one or more named databases.  Users and groups of users are
-   shared across the entire cluster, but no other data is shared across
-   databases.  Any given client connection to the server can access
-   only the data in a single database, the one specified in the connection
-   request.
+   <xref linkend="sql-altertable" endterm="sql-altertable-title"> will
+   propagate any changes in column data definitions and check
+   constraints down the inheritance hierarchy.  Again, dropping
+   columns or constraints on parent tables is only possible when using
+   the <literal>CASCADE</literal> option. <command>ALTER
+   TABLE</command> follows the same rules for duplicate column merging
+   and rejection that apply during <command>CREATE TABLE</command>.
   </para>
 
-  <note>
-   <para>
-    Users of a cluster do not necessarily have the privilege to access every
-    database in the cluster.  Sharing of user names means that there
-    cannot be different users named, say, <literal>joe</> in two databases
-    in the same cluster; but the system can be configured to allow
-    <literal>joe</> access to only some of the databases.
-   </para>
-  </note>
+ <sect2 id="ddl-inherit-caveats">
+  <title>Caveats</title>
 
   <para>
-   A database contains one or more named <firstterm>schemas</>, which
-   in turn contain tables.  Schemas also contain other kinds of named
-   objects, including data types, functions, and operators.  The same
-   object name can be used in different schemas without conflict; for
-   example, both <literal>schema1</> and <literal>myschema</> may
-   contain tables named <literal>mytable</>.  Unlike databases,
-   schemas are not rigidly separated: a user may access objects in any
-   of the schemas in the database he is connected to, if he has
-   privileges to do so.
+   Table access permissions are not automatically inherited.  Therefore,
+   a user attempting to access a parent table must either have permissions
+   to do the operation on all its child tables as well, or must use the
+   <literal>ONLY</literal> notation.  When adding a new child table to
+   an existing inheritance hierarchy, be careful to grant all the needed
+   permissions on it.
   </para>
-
   <para>
-   There are several reasons why one might want to use schemas:
+   A serious limitation of the inheritance feature is that indexes (including
+   unique constraints) and foreign key constraints only apply to single
+   tables, not to their inheritance children. This is true on both the
+   referencing and referenced sides of a foreign key constraint. Thus,
+   in the terms of the above example:
 
    <itemizedlist>
     <listitem>
      <para>
-      To allow many users to use one database without interfering with
-      each other.
+      If we declared <structname>cities</>.<structfield>name</> to be
+      <literal>UNIQUE</> or a <literal>PRIMARY KEY</>, this would not stop the
+      <structname>capitals</> table from having rows with names duplicating
+      rows in <structname>cities</>.  And those duplicate rows would by
+      default show up in queries from <structname>cities</>.  In fact, by
+      default <structname>capitals</> would have no unique constraint at all,
+      and so could contain multiple rows with the same name.
+      You could add a unique constraint to <structname>capitals</>, but this
+      would not prevent duplication compared to <structname>cities</>.
      </para>
     </listitem>
 
     <listitem>
      <para>
-      To organize database objects into logical groups to make them
-      more manageable.
+      Similarly, if we were to specify that
+      <structname>cities</>.<structfield>name</> <literal>REFERENCES</> some
+      other table, this constraint would not automatically propagate to
+      <structname>capitals</>.  In this case you could work around it by
+      manually adding the same <literal>REFERENCES</> constraint to
+      <structname>capitals</>.
      </para>
     </listitem>
 
     <listitem>
      <para>
-      Third-party applications can be put into separate schemas so
-      they cannot collide with the names of other objects.
+      Specifying that another table's column <literal>REFERENCES
+      cities(name)</> would allow the other table to contain city names, but
+      not capital names.  There is no good workaround for this case.
      </para>
     </listitem>
    </itemizedlist>
 
-   Schemas are analogous to directories at the operating system level,
-   except that schemas cannot be nested.
+   These deficiencies will probably be fixed in some future release,
+   but in the meantime considerable care is needed in deciding whether
+   inheritance is useful for your problem.
   </para>
 
-  <sect2 id="ddl-schemas-create">
-   <title>Creating a Schema</title>
-
-   <indexterm zone="ddl-schemas-create">
-    <primary>schema</primary>
-    <secondary>creating</secondary>
-   </indexterm>
-
+  <note>
+   <title>Deprecated</title>
    <para>
-    To create a schema, use the command <command>CREATE
-    SCHEMA</command>.  Give the schema a name of your choice.  For
-    example:
+     In previous versions of <productname>PostgreSQL</productname>, the
+     default behavior was not to include child tables in queries. This was
+     found to be error prone and is also in violation of the SQL
+     standard. Under the old syntax, to include the child tables you append
+     <literal>*</literal> to the table name. For example:
 <programlisting>
-CREATE SCHEMA myschema;
+SELECT * from cities*;
 </programlisting>
+     You can still explicitly specify scanning child tables by
+     appending <literal>*</literal>, as well as explicitly specify not
+     scanning child tables by writing <literal>ONLY</literal>.  But
+     beginning in version 7.1, the default behavior for an undecorated
+     table name is to scan its child tables too, whereas before the
+     default was not to do so.  To get the old default behavior,
+     disable the <xref linkend="guc-sql-inheritance"> configuration
+     option.
    </para>
+  </note>
+
+   </sect2>
+  </sect1>
+
+  <sect1 id="ddl-partitioning">
+   <title>Partitioning</title>
 
    <indexterm>
-    <primary>qualified name</primary>
+    <primary>partitioning</primary>
    </indexterm>
 
    <indexterm>
-    <primary>name</primary>
-    <secondary>qualified</secondary>
+    <primary>table</primary>
+    <secondary>partitioning</secondary>
    </indexterm>
 
    <para>
-    To create or access objects in a schema, write a
-    <firstterm>qualified name</> consisting of the schema name and
-    table name separated by a dot:
-<synopsis>
-<replaceable>schema</><literal>.</><replaceable>table</>
-</synopsis>
-    This works anywhere a table name is expected, including the table
-    modification commands and the data access commands discussed in
-    the following chapters.
-    (For brevity we will speak of tables only, but the same ideas apply
-    to other kinds of named objects, such as types and functions.)
+    <productname>PostgreSQL</productname> supports basic table
+    partitioning. This section describes why and how you can implement
+    partitioning as part of your database design.
    </para>
 
+   <sect2 id="ddl-partitioning-overview">
+     <title>Overview</title>
+
    <para>
-    Actually, the even more general syntax
-<synopsis>
-<replaceable>database</><literal>.</><replaceable>schema</><literal>.</><replaceable>table</>
-</synopsis>
-    can be used too, but at present this is just for <foreignphrase>pro
-    forma</> compliance with the SQL standard.  If you write a database name,
-    it must be the same as the database you are connected to.
+    Partitioning refers to splitting what is logically one large table
+    into smaller physical pieces.
+    Partitioning can provide several benefits:
+   <itemizedlist>
+    <listitem>
+     <para>
+      Query performance can be improved dramatically for certain kinds
+      of queries.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Update performance can be improved too, since each piece of the table
+      has indexes smaller than an index on the entire data set would be.
+      When an index no longer fits easily
+      in memory, both read and write operations on the index take
+      progressively more disk accesses.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Bulk deletes may be accomplished by simply removing one of the
+      partitions, if that requirement is planned into the partitioning design.
+      <command>DROP TABLE</> is far faster than a bulk <command>DELETE</>,
+      to say nothing of the ensuing <command>VACUUM</> overhead.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      Seldom-used data can be migrated to cheaper and slower storage media.
+     </para>
+    </listitem>
+   </itemizedlist>
+
+    The benefits will normally be worthwhile only when a table would
+    otherwise be very large. The exact point at which a table will
+    benefit from partitioning depends on the application, although a
+    rule of thumb is that the size of the table should exceed the physical
+    memory of the database server.
    </para>
 
    <para>
-    So to create a table in the new schema, use
-<programlisting>
-CREATE TABLE myschema.mytable (
- ...
-);
-</programlisting>
+    Currently, <productname>PostgreSQL</productname> supports partitioning
+    via table inheritance.  Each partition must be created as a child
+    table of a single parent table.  The parent table itself is normally
+    empty; it exists just to represent the entire data set.  You should be
+    familiar with inheritance (see <xref linkend="ddl-inherit">) before
+    attempting to implement partitioning.
    </para>
 
-   <indexterm>
-    <primary>schema</primary>
-    <secondary>removing</secondary>
-   </indexterm>
+   <para>
+    The following forms of partitioning can be implemented in
+    <productname>PostgreSQL</productname>:
+
+    <variablelist>
+     <varlistentry>
+      <term>Range Partitioning</term>
+
+      <listitem>
+       <para>
+        The table is partitioned into <quote>ranges</quote> defined
+        by a key column or set of columns, with no overlap between
+        the ranges of values assigned to different partitions.  For
+        example one might partition by date ranges, or by ranges of
+        identifiers for particular business objects.
+       </para>
+      </listitem>
+     </varlistentry>
+
+     <varlistentry>
+      <term>List Partitioning</term>
+
+      <listitem>
+       <para>
+        The table is partitioned by explicitly listing which key values
+        appear in each partition.
+       </para>
+      </listitem>
+     </varlistentry>
+    </variablelist>
+
+    Hash partitioning is not currently supported.
+   </para>
+   </sect2>
+
+   <sect2 id="ddl-partitioning-implementation">
+     <title>Implementing Partitioning</title>
+
+    <para>
+     To set up a partitioned table, do the following:
+     <orderedlist spacing=compact>
+      <listitem>
+       <para>
+        Create the <quote>master</quote> table, from which all of the
+        partitions will inherit.
+       </para>
+       <para>
+        This table will contain no data.  Do not define any check
+        constraints on this table, unless you intend them to
+        be applied equally to all partitions.  There is no point
+        in defining any indexes or unique constraints on it, either.
+       </para>
+      </listitem>
+
+      <listitem>
+       <para>
+        Create several <quote>child</quote> tables that each inherit from
+        the master table.  Normally, these tables will not add any columns
+        to the set inherited from the master.
+       </para>
+
+       <para>
+        We will refer to the child tables as partitions, though they
+        are in every way normal <productname>PostgreSQL</> tables.
+       </para>
+      </listitem>
+
+      <listitem>
+       <para>
+        Add table constraints to the partition tables to define the
+        allowed key values in each partition.
+       </para>
 
-   <para>
-    To drop a schema if it's empty (all objects in it have been
-    dropped), use
+       <para>
+        Typical examples would be:
 <programlisting>
-DROP SCHEMA myschema;
+CHECK ( x = 1 )
+CHECK ( county IN ( 'Oxfordshire', 'Buckinghamshire', 'Warwickshire' ))
+CHECK ( outletID >= 100 AND outletID < 200 )
 </programlisting>
-    To drop a schema including all contained objects, use
+        Ensure that the constraints guarantee that there is no overlap
+        between the key values permitted in different partitions.  A common
+        mistake is to set up range constraints like this:
 <programlisting>
-DROP SCHEMA myschema CASCADE;
+CHECK ( outletID BETWEEN 100 AND 200 )
+CHECK ( outletID BETWEEN 200 AND 300 )
 </programlisting>
-    See <xref linkend="ddl-depend"> for a description of the general
-    mechanism behind this.
-   </para>
+        This is wrong since it is not clear which partition the key value
+        200 belongs in.
+       </para>
 
-   <para>
-    Often you will want to create a schema owned by someone else
-    (since this is one of the ways to restrict the activities of your
-    users to well-defined namespaces).  The syntax for that is:
-<programlisting>
-CREATE SCHEMA <replaceable>schemaname</replaceable> AUTHORIZATION <replaceable>username</replaceable>;
-</programlisting>
-    You can even omit the schema name, in which case the schema name
-    will be the same as the user name.  See <xref
-    linkend="ddl-schemas-patterns"> for how this can be useful.
-   </para>
+       <para>
+        Note that there is no difference in
+        syntax between range and list partitioning; those terms are
+        descriptive only.
+       </para>
+      </listitem>
 
-   <para>
-    Schema names beginning with <literal>pg_</> are reserved for
-    system purposes and may not be created by users.
-   </para>
-  </sect2>
+      <listitem>
+       <para>
+        For each partition, create an index on the key column(s),
+        as well as any other indexes you might want.  (The key index is
+        not strictly necessary, but in most scenarios it is helpful.
+        If you intend the key values to be unique then you should
+        always create a unique or primary-key constraint for each
+        partition.)
+       </para>
+      </listitem>
 
-  <sect2 id="ddl-schemas-public">
-   <title>The Public Schema</title>
+      <listitem>
+       <para>
+        Optionally, define a rule or trigger to redirect modifications
+        of the master table to the appropriate partition.
+       </para>
+      </listitem>
 
-   <indexterm zone="ddl-schemas-public">
-    <primary>schema</primary>
-    <secondary>public</secondary>
-   </indexterm>
+      <listitem>
+       <para>
+        Ensure that the <xref linkend="guc-constraint-exclusion">
+        configuration
+        parameter is enabled in <filename>postgresql.conf</>.  Without
+        this, queries will not be optimized as desired.
+       </para>
+      </listitem>
+
+     </orderedlist>
+    </para>
+
+    <para>
+     For example, suppose we are constructing a database for a large
+     ice cream company. The company measures peak temperatures every
+     day as well as ice cream sales in each region. Conceptually,
+     we want a table like this:
 
-   <para>
-    In the previous sections we created tables without specifying any
-    schema names.  By default, such tables (and other objects) are
-    automatically put into a schema named <quote>public</quote>.  Every new
-    database contains such a schema.  Thus, the following are equivalent:
-<programlisting>
-CREATE TABLE products ( ... );
-</programlisting>
-    and
 <programlisting>
-CREATE TABLE public.products ( ... );
+CREATE TABLE measurement (
+    city_id         int not null,
+    logdate         date not null,
+    peaktemp        int,
+    unitsales       int
+);
 </programlisting>
-   </para>
-  </sect2>
 
-  <sect2 id="ddl-schemas-path">
-   <title>The Schema Search Path</title>
+     We know that most queries will access just the last week's, month's or
+     quarter's data, since the main use of this table will be to prepare
+     online reports for management.
+     To reduce the amount of old data that needs to be stored, we
+     decide to only keep the most recent 3 years worth of data. At the
+     beginning of each month we will remove the oldest month's data.
+    </para>
 
-   <indexterm>
-    <primary>search path</primary>
-   </indexterm>
+    <para>
+     In this situation we can use partitioning to help us meet all of our
+     different requirements for the measurements table. Following the
+     steps outlined above, partitioning can be set up as follows:
+    </para>
 
-   <indexterm>
-    <primary>unqualified name</primary>
-   </indexterm>
+    <para>
+     <orderedlist spacing=compact>
+      <listitem>
+       <para>
+        The master table is the <structname>measurement</> table, declared
+        exactly as above.
+       </para>
+      </listitem>
 
-   <indexterm>
-    <primary>name</primary>
-    <secondary>unqualified</secondary>
-   </indexterm>
+      <listitem>
+       <para>
+        Next we create one partition for each active month:
 
-   <para>
-    Qualified names are tedious to write, and it's often best not to
-    wire a particular schema name into applications anyway.  Therefore
-    tables are often referred to by <firstterm>unqualified names</>,
-    which consist of just the table name.  The system determines which table
-    is meant by following a <firstterm>search path</>, which is a list
-    of schemas to look in.  The first matching table in the search path
-    is taken to be the one wanted.  If there is no match in the search
-    path, an error is reported, even if matching table names exist
-    in other schemas in the database.
-   </para>
+<programlisting>
+CREATE TABLE measurement_yy04mm02 ( ) INHERITS (measurement);
+CREATE TABLE measurement_yy04mm03 ( ) INHERITS (measurement);
+...
+CREATE TABLE measurement_yy05mm11 ( ) INHERITS (measurement);
+CREATE TABLE measurement_yy05mm12 ( ) INHERITS (measurement);
+CREATE TABLE measurement_yy06mm01 ( ) INHERITS (measurement);
+</programlisting>
 
-   <indexterm>
-    <primary>schema</primary>
-    <secondary>current</secondary>
-   </indexterm>
+        Each of the partitions are complete tables in their own right,
+        but they inherit their definition from the
+        <structname>measurement</> table.
+       </para>
 
-   <para>
-    The first schema named in the search path is called the current schema.
-    Aside from being the first schema searched, it is also the schema in
-    which new tables will be created if the <command>CREATE TABLE</>
-    command does not specify a schema name.
-   </para>
+       <para>
+        This solves one of our problems: deleting old data. Each
+        month, all we will need to do is perform a <command>DROP
+        TABLE</command> on the oldest child table and create a new
+        child table for the new month's data.
+       </para>
+      </listitem>
 
-   <indexterm>
-    <primary>search_path</primary>
-   </indexterm>
+      <listitem>
+       <para>
+        We must add non-overlapping table constraints, so that our
+        table creation script becomes:
 
-   <para>
-    To show the current search path, use the following command:
-<programlisting>
-SHOW search_path;
+ <programlisting>
+CREATE TABLE measurement_yy04mm02 (
+    CHECK ( logdate >= DATE '2004-02-01' AND logdate < DATE '2004-03-01' )
+) INHERITS (measurement);
+CREATE TABLE measurement_yy04mm03 (
+    CHECK ( logdate >= DATE '2004-03-01' AND logdate < DATE '2004-04-01' )
+) INHERITS (measurement);
+...
+CREATE TABLE measurement_yy05mm11 (
+    CHECK ( logdate >= DATE '2005-11-01' AND logdate < DATE '2005-12-01' )
+) INHERITS (measurement);
+CREATE TABLE measurement_yy05mm12 (
+    CHECK ( logdate >= DATE '2005-12-01' AND logdate < DATE '2006-01-01' )
+) INHERITS (measurement);
+CREATE TABLE measurement_yy06mm01 (
+    CHECK ( logdate >= DATE '2006-01-01' AND logdate < DATE '2006-02-01' )
+) INHERITS (measurement);
 </programlisting>
-    In the default setup this returns:
-<screen>
- search_path
---------------
- $user,public
-</screen>
-    The first element specifies that a schema with the same name as
-    the current user is to be searched.  If no such schema exists,
-    the entry is ignored.  The second element refers to the
-    public schema that we have seen already.
-   </para>
+       </para>
+      </listitem>
 
-   <para>
-    The first schema in the search path that exists is the default
-    location for creating new objects.  That is the reason that by
-    default objects are created in the public schema.  When objects
-    are referenced in any other context without schema qualification
-    (table modification, data modification, or query commands) the
-    search path is traversed until a matching object is found.
-    Therefore, in the default configuration, any unqualified access
-    again can only refer to the public schema.
-   </para>
+      <listitem>
+       <para>
+        We probably need indexes on the key columns too:
 
-   <para>
-    To put our new schema in the path, we use
-<programlisting>
-SET search_path TO myschema,public;
+ <programlisting>
+CREATE INDEX measurement_yy04mm02_logdate ON measurement_yy04mm02 (logdate);
+CREATE INDEX measurement_yy04mm03_logdate ON measurement_yy04mm03 (logdate);
+...
+CREATE INDEX measurement_yy05mm11_logdate ON measurement_yy05mm11 (logdate);
+CREATE INDEX measurement_yy05mm12_logdate ON measurement_yy05mm12 (logdate);
+CREATE INDEX measurement_yy06mm01_logdate ON measurement_yy06mm01 (logdate);
 </programlisting>
-    (We omit the <literal>$user</literal> here because we have no
-    immediate need for it.)  And then we can access the table without
-    schema qualification:
+
+        We choose not to add further indexes at this time.
+       </para>
+      </listitem>
+
+      <listitem>
+       <para>
+        If data will be added only to the latest partition, we can
+        set up a very simple rule to insert data. We must
+        redefine this each month so that it always points to the
+        current partition.
+
 <programlisting>
-DROP TABLE mytable;
+CREATE OR REPLACE RULE measurement_current_partition AS
+ON INSERT TO measurement
+DO INSTEAD
+    INSERT INTO measurement_yy06mm01 VALUES ( NEW.city_id,
+                                              NEW.logdate,
+                                              NEW.peaktemp,
+                                              NEW.unitsales );
 </programlisting>
-    Also, since <literal>myschema</literal> is the first element in
-    the path, new objects would by default be created in it.
-   </para>
 
-   <para>
-    We could also have written
+        We might want to insert data and have the server automatically
+        locate the partition into which the row should be added. We
+        could do this with a more complex set of rules as shown below.
+
 <programlisting>
-SET search_path TO myschema;
+CREATE RULE measurement_insert_yy04mm02 AS
+ON INSERT TO measurement WHERE
+    ( logdate >= DATE '2004-02-01' AND logdate < DATE '2004-03-01' )
+DO INSTEAD
+    INSERT INTO measurement_yy04mm02 VALUES ( NEW.city_id,
+                                              NEW.logdate,
+                                              NEW.peaktemp,
+                                              NEW.unitsales );
+...
+CREATE RULE measurement_insert_yy05mm12 AS
+ON INSERT TO measurement WHERE
+    ( logdate >= DATE '2005-12-01' AND logdate < DATE '2006-01-01' )
+DO INSTEAD
+    INSERT INTO measurement_yy05mm12 VALUES ( NEW.city_id,
+                                              NEW.logdate,
+                                              NEW.peaktemp,
+                                              NEW.unitsales );
+CREATE RULE measurement_insert_yy06mm01 AS
+ON INSERT TO measurement WHERE
+    ( logdate >= DATE '2006-01-01' AND logdate < DATE '2006-02-01' )
+DO INSTEAD
+    INSERT INTO measurement_yy06mm01 VALUES ( NEW.city_id,
+                                              NEW.logdate,
+                                              NEW.peaktemp,
+                                              NEW.unitsales );
 </programlisting>
-    Then we no longer have access to the public schema without
-    explicit qualification.  There is nothing special about the public
-    schema except that it exists by default.  It can be dropped, too.
-   </para>
+
+        Note that the <literal>WHERE</literal> clause in each rule
+        exactly matches the the <literal>CHECK</literal>
+        constraint for its partition.
+       </para>
+      </listitem>
+     </orderedlist>
+    </para>
+
+    <para>
+     As we can see, a complex partitioning scheme could require a
+     substantial amount of DDL. In the above example we would be
+     creating a new partition each month, so it may be wise to write a
+     script that generates the required DDL automatically.
+    </para>
 
    <para>
-    See also <xref linkend="functions-info"> for other ways to manipulate
-    the schema search path.
+    The following caveats apply:
+   <itemizedlist>
+    <listitem>
+     <para>
+      There is currently no way to verify that all of the
+      <literal>CHECK</literal> constraints are mutually
+      exclusive. Care is required by the database designer.
+     </para>
+    </listitem>
+
+    <listitem>
+     <para>
+      There is currently no simple way to specify that rows must not be
+      inserted into the master table. A <literal>CHECK (false)</literal>
+      constraint on the master table would be inherited by all child
+      tables, so that cannot be used for this purpose.  One possibility is
+      to set up an <literal>ON INSERT</> trigger on the master table that
+      always raises an error.  (Alternatively, such a trigger could be
+      used to redirect the data into the proper child table, instead of
+      using a set of rules as suggested above.)
+     </para>
+    </listitem>
+   </itemizedlist>
    </para>
 
    <para>
-    The search path works in the same way for data type names, function names,
-    and operator names as it does for table names.  Data type and function
-    names can be qualified in exactly the same way as table names.  If you
-    need to write a qualified operator name in an expression, there is a
-    special provision: you must write
-<synopsis>
-<literal>OPERATOR(</><replaceable>schema</><literal>.</><replaceable>operator</><literal>)</>
-</synopsis>
-    This is needed to avoid syntactic ambiguity.  An example is
+    Partitioning can also be arranged using a <literal>UNION ALL</literal>
+    view:
+
 <programlisting>
-SELECT 3 OPERATOR(pg_catalog.+) 4;
+CREATE VIEW measurement AS
+          SELECT * FROM measurement_yy04mm02
+UNION ALL SELECT * FROM measurement_yy04mm03
+...
+UNION ALL SELECT * FROM measurement_yy05mm11
+UNION ALL SELECT * FROM measurement_yy05mm12
+UNION ALL SELECT * FROM measurement_yy06mm01;
 </programlisting>
-    In practice one usually relies on the search path for operators,
-    so as not to have to write anything so ugly as that.
+
+    However, constraint exclusion is currently not supported for
+    partitioned tables defined in this manner.  Also, the need to
+    recreate the view adds an extra step to adding and dropping
+    individual partitions of the dataset.
    </para>
-  </sect2>
+   </sect2>
 
-  <sect2 id="ddl-schemas-priv">
-   <title>Schemas and Privileges</title>
+   <sect2 id="ddl-partitioning-constraint-exclusion">
+   <title>Partitioning and Constraint Exclusion</title>
 
-   <indexterm zone="ddl-schemas-priv">
-    <primary>privilege</primary>
-    <secondary sortas="schemas">for schemas</secondary>
+   <indexterm>
+    <primary>constraint exclusion</primary>
    </indexterm>
 
    <para>
-    By default, users cannot access any objects in schemas they do not
-    own.  To allow that, the owner of the schema needs to grant the
-    <literal>USAGE</literal> privilege on the schema.  To allow users
-    to make use of the objects in the schema, additional privileges
-    may need to be granted, as appropriate for the object.
-   </para>
+    <firstterm>Constraint exclusion</> is a query optimization technique
+    that improves performance for partitioned tables defined in the
+    fashion described above.  As an example:
 
-   <para>
-    A user can also be allowed to create objects in someone else's
-    schema.  To allow that, the <literal>CREATE</literal> privilege on
-    the schema needs to be granted.  Note that by default, everyone
-    has <literal>CREATE</literal> and <literal>USAGE</literal> privileges on
-    the schema
-    <literal>public</literal>.  This allows all users that are able to
-    connect to a given database to create objects in its
-    <literal>public</literal> schema.  If you do
-    not want to allow that, you can revoke that privilege:
 <programlisting>
-REVOKE CREATE ON SCHEMA public FROM PUBLIC;
+SET constraint_exclusion = on;
+SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
 </programlisting>
-    (The first <quote>public</quote> is the schema, the second
-    <quote>public</quote> means <quote>every user</quote>.  In the
-    first sense it is an identifier, in the second sense it is a
-    key word, hence the different capitalization; recall the
-    guidelines from <xref linkend="sql-syntax-identifiers">.)
+
+    Without constraint exclusion, the above query would scan each of
+    the partitions of the <structname>measurement</> table. With constraint
+    exclusion enabled, the planner will examine the constraints of each
+    partition and try to prove that the partition need not
+    be scanned because it could not contain any rows meeting the query's
+    <literal>WHERE</> clause.  When the planner can prove this, it
+    excludes the partition from the query plan.
    </para>
-  </sect2>
 
-  <sect2 id="ddl-schemas-catalog">
-   <title>The System Catalog Schema</title>
+   <para>
+    You can use the <command>EXPLAIN</> command to show the difference
+    between a plan with <varname>constraint_exclusion</> on and a plan
+    with it off.  A typical default plan for this type of table setup is:
 
-   <indexterm zone="ddl-schemas-catalog">
-    <primary>system catalog</primary>
-    <secondary>schema</secondary>
-   </indexterm>
+<programlisting>
+SET constraint_exclusion = off;
+EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
 
-   <para>
-    In addition to <literal>public</> and user-created schemas, each
-    database contains a <literal>pg_catalog</> schema, which contains
-    the system tables and all the built-in data types, functions, and
-    operators.  <literal>pg_catalog</> is always effectively part of
-    the search path.  If it is not named explicitly in the path then
-    it is implicitly searched <emphasis>before</> searching the path's
-    schemas.  This ensures that built-in names will always be
-    findable.  However, you may explicitly place
-    <literal>pg_catalog</> at the end of your search path if you
-    prefer to have user-defined names override built-in names.
+                                          QUERY PLAN
+-----------------------------------------------------------------------------------------------
+ Aggregate  (cost=158.66..158.68 rows=1 width=0)
+   ->  Append  (cost=0.00..151.88 rows=2715 width=0)
+         ->  Seq Scan on measurement  (cost=0.00..30.38 rows=543 width=0)
+               Filter: (logdate >= '2006-01-01'::date)
+         ->  Seq Scan on measurement_yy04mm02 measurement  (cost=0.00..30.38 rows=543 width=0)
+               Filter: (logdate >= '2006-01-01'::date)
+         ->  Seq Scan on measurement_yy04mm03 measurement  (cost=0.00..30.38 rows=543 width=0)
+               Filter: (logdate >= '2006-01-01'::date)
+...
+         ->  Seq Scan on measurement_yy05mm12 measurement  (cost=0.00..30.38 rows=543 width=0)
+               Filter: (logdate >= '2006-01-01'::date)
+         ->  Seq Scan on measurement_yy06mm01 measurement  (cost=0.00..30.38 rows=543 width=0)
+               Filter: (logdate >= '2006-01-01'::date)
+</programlisting>
+
+    Some or all of the partitions might use index scans instead of
+    full-table sequential scans, but the point here is that there
+    is no need to scan the older partitions at all to answer this query.
+    When we enable constraint exclusion, we get a significantly
+    reduced plan that will deliver the same answer:
+
+<programlisting>
+SET constraint_exclusion = on;
+EXPLAIN SELECT count(*) FROM measurement WHERE logdate >= DATE '2006-01-01';
+                                          QUERY PLAN
+-----------------------------------------------------------------------------------------------
+ Aggregate  (cost=63.47..63.48 rows=1 width=0)
+   ->  Append  (cost=0.00..60.75 rows=1086 width=0)
+         ->  Seq Scan on measurement  (cost=0.00..30.38 rows=543 width=0)
+               Filter: (logdate >= '2006-01-01'::date)
+         ->  Seq Scan on measurement_yy06mm01 measurement  (cost=0.00..30.38 rows=543 width=0)
+               Filter: (logdate >= '2006-01-01'::date)
+</programlisting>
    </para>
 
    <para>
-    In <productname>PostgreSQL</productname> versions before 7.3,
-    table names beginning with <literal>pg_</> were reserved.  This is
-    no longer true: you may create such a table name if you wish, in
-    any non-system schema.  However, it's best to continue to avoid
-    such names, to ensure that you won't suffer a conflict if some
-    future version defines a system table named the same as your
-    table.  (With the default search path, an unqualified reference to
-    your table name would be resolved as the system table instead.)
-    System tables will continue to follow the convention of having
-    names beginning with <literal>pg_</>, so that they will not
-    conflict with unqualified user-table names so long as users avoid
-    the <literal>pg_</> prefix.
+    Note that constraint exclusion is driven only by <literal>CHECK</>
+    constraints, not by the presence of indexes.  Therefore it isn't
+    necessary to define indexes on the key columns.  Whether an index
+    needs to be created for a given partition depends on whether you
+    expect that queries that scan the partition will generally scan
+    a large part of the partition or just a small part.  An index will
+    be helpful in the latter case but not the former.
    </para>
-  </sect2>
-
-  <sect2 id="ddl-schemas-patterns">
-   <title>Usage Patterns</title>
 
    <para>
-    Schemas can be used to organize your data in many ways.  There are
-    a few usage patterns that are recommended and are easily supported by
-    the default configuration:
-    <itemizedlist>
-     <listitem>
-      <para>
-       If you do not create any schemas then all users access the
-       public schema implicitly.  This simulates the situation where
-       schemas are not available at all.  This setup is mainly
-       recommended when there is only a single user or a few cooperating
-       users in a database.  This setup also allows smooth transition
-       from the non-schema-aware world.
-      </para>
-     </listitem>
-
-     <listitem>
-      <para>
-       You can create a schema for each user with the same name as
-       that user.  Recall that the default search path starts with
-       <literal>$user</literal>, which resolves to the user name.
-       Therefore, if each user has a separate schema, they access their
-       own schemas by default.
-      </para>
+    The following caveats apply:
 
-      <para>
-       If you use this setup then you might also want to revoke access
-       to the public schema (or drop it altogether), so users are
-       truly constrained to their own schemas.
-      </para>
-     </listitem>
+   <itemizedlist>
+    <listitem>
+     <para>
+      Constraint exclusion only works when the query's <literal>WHERE</>
+      clause contains constants.  A parameterized query will not be
+      optimized, since the planner cannot know what partitions the
+      parameter value might select at runtime.  For the same reason,
+      <quote>stable</> functions such as <function>CURRENT_DATE</function>
+      must be avoided.  Joining the partition key to a column of another
+      table will not be optimized, either.
+     </para>
+    </listitem>
 
-     <listitem>
-      <para>
-       To install shared applications (tables to be used by everyone,
-       additional functions provided by third parties, etc.), put them
-       into separate schemas.  Remember to grant appropriate
-       privileges to allow the other users to access them.  Users can
-       then refer to these additional objects by qualifying the names
-       with a schema name, or they can put the additional schemas into
-       their search path, as they choose.
-      </para>
-     </listitem>
-    </itemizedlist>
-   </para>
-  </sect2>
+    <listitem>
+     <para>
+      Avoid cross-datatype comparisons in the <literal>CHECK</>
+      constraints, as the planner will currently fail to prove such
+      conditions false.  For example, the following constraint
+      will work if <varname>x</varname> is an <type>integer</type>
+      column, but not if <varname>x</varname> is a
+      <type>bigint</type>:
+<programlisting>
+CHECK ( x = 1 )
+</programlisting>
+      For a <type>bigint</type> column we must use a constraint like:
+<programlisting>
+CHECK ( x = 1::bigint )
+</programlisting>
+      The problem is not limited to the <type>bigint</type> data type
+      &mdash; it can occur whenever the default data type of the
+      constant does not match the data type of the column to which it
+      is being compared.  Cross-datatype comparisons in the supplied
+      queries are usually OK, just not in the <literal>CHECK</> conditions.
+     </para>
+    </listitem>
 
-  <sect2 id="ddl-schemas-portability">
-   <title>Portability</title>
+    <listitem>
+     <para>
+      <command>UPDATE</command> and <command>DELETE</command> commands
+      against the master table do not currently perform constraint exclusion.
+     </para>
+    </listitem>
 
-   <para>
-    In the SQL standard, the notion of objects in the same schema
-    being owned by different users does not exist.  Moreover, some
-    implementations do not allow you to create schemas that have a
-    different name than their owner.  In fact, the concepts of schema
-    and user are nearly equivalent in a database system that
-    implements only the basic schema support specified in the
-    standard.  Therefore, many users consider qualified names to
-    really consist of
-    <literal><replaceable>username</>.<replaceable>tablename</></literal>.
-    This is how <productname>PostgreSQL</productname> will effectively
-    behave if you create a per-user schema for every user.
-   </para>
+    <listitem>
+     <para>
+      All constraints on all partitions of the master table are considered for
+      constraint exclusion, so large numbers of partitions are likely to
+      increase query planning time considerably.
+     </para>
+    </listitem>
 
-   <para>
-    Also, there is no concept of a <literal>public</> schema in the
-    SQL standard.  For maximum conformance to the standard, you should
-    not use (perhaps even remove) the <literal>public</> schema.
-   </para>
+    <listitem>
+     <para>
+      Don't forget that you still need to run <command>ANALYZE</command>
+      on each partition individually. A command like
+<programlisting>
+ANALYZE measurement;
+</programlisting>
+      will only process the master table.
+     </para>
+    </listitem>
 
-   <para>
-    Of course, some SQL database systems might not implement schemas
-    at all, or provide namespace support by allowing (possibly
-    limited) cross-database access.  If you need to work with those
-    systems, then maximum portability would be achieved by not using
-    schemas at all.
+   </itemizedlist>
    </para>
   </sect2>
  </sect1>
@@ -2798,7 +2824,7 @@ DROP TABLE products CASCADE;
 </screen>
    and all the dependent objects will be removed.  In this case, it
    doesn't remove the orders table, it only removes the foreign key
-   constraint.  (If you want to check what <literal>DROP ... CASCADE</> will do,
+   constraint.  (If you want to check what <command>DROP ... CASCADE</> will do,
    run <command>DROP</> without <literal>CASCADE</> and read the <literal>NOTICE</> messages.)
   </para>