Index: doc/src/sgml/catalogs.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/catalogs.sgml,v
retrieving revision 2.194
diff -c -p -r2.194 catalogs.sgml
*** doc/src/sgml/catalogs.sgml	4 Feb 2009 21:30:41 -0000	2.194
--- doc/src/sgml/catalogs.sgml	5 Feb 2009 18:32:40 -0000
***************
*** 89,99 ****
       </row>
  
       <row>
-       <entry><link linkend="catalog-pg-autovacuum"><structname>pg_autovacuum</structname></link></entry>
-       <entry>per-relation autovacuum configuration parameters</entry>
-      </row>
- 
-      <row>
        <entry><link linkend="catalog-pg-cast"><structname>pg_cast</structname></link></entry>
        <entry>casts (data type conversions)</entry>
       </row>
--- 89,94 ----
***************
*** 1256,1433 ****
   </sect1>
  
  
-  <sect1 id="catalog-pg-autovacuum">
-   <title><structname>pg_autovacuum</structname></title>
- 
-   <indexterm zone="catalog-pg-autovacuum">
-    <primary>pg_autovacuum</primary>
-   </indexterm>
- 
-   <indexterm zone="catalog-pg-autovacuum">
-    <primary>autovacuum</primary>
-    <secondary>table-specific configuration</secondary>
-   </indexterm>
- 
-   <para>
-    The catalog <structname>pg_autovacuum</structname> stores optional
-    per-relation configuration parameters for the autovacuum daemon.
-    If there is an entry here for a particular relation, the given
-    parameters will be used for autovacuuming that table.  If no entry
-    is present, the system-wide defaults will be used. For more information
-    about the autovacuum daemon, see <xref linkend="autovacuum">.
-   </para>
- 
-   <note>
-    <para>
-     It is likely that <structname>pg_autovacuum</structname> will disappear
-     in a future release, with the information instead being kept in
-     <structname>pg_class</>.<structfield>reloptions</> entries.
-    </para>
-   </note>
- 
-   <table>
-    <title><structname>pg_autovacuum</> Columns</title>
- 
-    <tgroup cols="4">
-     <thead>
-      <row>
-       <entry>Name</entry>
-       <entry>Type</entry>
-       <entry>References</entry>
-       <entry>Description</entry>
-      </row>
-     </thead>
- 
-     <tbody>
-      <row>
-       <entry><structfield>vacrelid</structfield></entry>
-       <entry><type>oid</type></entry>
-       <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry>
-       <entry>The table this entry is for</entry>
-      </row>
- 
-      <row>
-       <entry><structfield>enabled</structfield></entry>
-       <entry><type>bool</type></entry>
-       <entry></entry>
-       <entry>If false, this table will not be autovacuumed, except
-        to prevent transaction ID wraparound</entry>
-      </row>
- 
-      <row>
-       <entry><structfield>vac_base_thresh</structfield></entry>
-       <entry><type>integer</type></entry>
-       <entry></entry>
-       <entry>Minimum number of modified tuples before vacuum</entry>
-      </row>
- 
-      <row>
-       <entry><structfield>vac_scale_factor</structfield></entry>
-       <entry><type>float4</type></entry>
-       <entry></entry>
-       <entry>Multiplier for <structfield>reltuples</> to add to
-        <structfield>vac_base_thresh</></entry>
-      </row>
- 
-      <row>
-       <entry><structfield>anl_base_thresh</structfield></entry>
-       <entry><type>integer</type></entry>
-       <entry></entry>
-       <entry>Minimum number of modified tuples before analyze</entry>
-      </row>
- 
-      <row>
-       <entry><structfield>anl_scale_factor</structfield></entry>
-       <entry><type>float4</type></entry>
-       <entry></entry>
-       <entry>Multiplier for <structfield>reltuples</> to add to
-        <structfield>anl_base_thresh</></entry>
-      </row>
- 
-      <row>
-       <entry><structfield>vac_cost_delay</structfield></entry>
-       <entry><type>integer</type></entry>
-       <entry></entry>
-       <entry>Custom <varname>vacuum_cost_delay</> parameter</entry>
-      </row>
- 
-      <row>
-       <entry><structfield>vac_cost_limit</structfield></entry>
-       <entry><type>integer</type></entry>
-       <entry></entry>
-       <entry>Custom <varname>vacuum_cost_limit</> parameter</entry>
-      </row>
- 
-      <row>
-       <entry><structfield>freeze_min_age</structfield></entry>
-       <entry><type>integer</type></entry>
-       <entry></entry>
-       <entry>Custom <varname>vacuum_freeze_min_age</> parameter</entry>
-      </row>
- 
-      <row>
-       <entry><structfield>freeze_max_age</structfield></entry>
-       <entry><type>integer</type></entry>
-       <entry></entry>
-       <entry>Custom <varname>autovacuum_freeze_max_age</> parameter</entry>
-      </row>
- 
-      <row>
-       <entry><structfield>freeze_table_age</structfield></entry>
-       <entry><type>integer</type></entry>
-       <entry></entry>
-       <entry>Custom <varname>vacuum_freeze_table_age</> parameter</entry>
-      </row>
-     </tbody>
-    </tgroup>
-   </table>
- 
-   <para>
-    The autovacuum daemon will initiate a <command>VACUUM</> operation
-    on a particular table when the number of updated or deleted tuples
-    exceeds <structfield>vac_base_thresh</structfield> plus
-    <structfield>vac_scale_factor</structfield> times the number of
-    live tuples currently estimated to be in the relation.
-    Similarly, it will initiate an <command>ANALYZE</> operation
-    when the number of inserted, updated or deleted tuples
-    exceeds <structfield>anl_base_thresh</structfield> plus
-    <structfield>anl_scale_factor</structfield> times the number of
-    live tuples currently estimated to be in the relation.
-   </para>
- 
-   <para>
-    Also, the autovacuum daemon will perform a <command>VACUUM</> operation
-    to prevent transaction ID wraparound if the table's
-    <structname>pg_class</>.<structfield>relfrozenxid</> field attains an age
-    of more than <structfield>freeze_max_age</> transactions, whether the table
-    has been changed or not, even if
-    <structname>pg_autovacuum</>.<structfield>enabled</> is set to
-    <literal>false</> for it.  The system will launch autovacuum to perform
-    such <command>VACUUM</>s even if autovacuum is otherwise disabled.
-    See <xref linkend="vacuum-for-wraparound"> for more about wraparound
-    prevention.
-   </para>
- 
-   <para>
-    Any of the numerical fields can contain <literal>-1</> (or indeed
-    any negative value) to indicate that the system-wide default should
-    be used for this particular value.  Observe that the
-    <structfield>vac_cost_delay</> variable inherits its default value from the
-    <xref linkend="guc-autovacuum-vacuum-cost-delay"> configuration parameter,
-    or from <xref linkend="guc-vacuum-cost-delay"> if the former is set to a
-    negative value.  The same applies to <structfield>vac_cost_limit</>.
-    Also, autovacuum will ignore attempts to set a per-table
-    <structfield>freeze_max_age</> larger than the system-wide setting (it can
-    only be set smaller), and the <structfield>freeze_min_age</> value will be
-    limited to half the system-wide <xref
-    linkend="guc-autovacuum-freeze-max-age"> setting.  Note that while you
-    can set <structfield>freeze_max_age</> very small, or even zero, this
-    is usually unwise since it will force frequent vacuuming.
-   </para>
- 
-  </sect1>
- 
- 
   <sect1 id="catalog-pg-cast">
    <title><structname>pg_cast</structname></title>
  
--- 1251,1256 ----
Index: doc/src/sgml/config.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/config.sgml,v
retrieving revision 1.206
diff -c -p -r1.206 config.sgml
*** doc/src/sgml/config.sgml	16 Jan 2009 13:27:23 -0000	1.206
--- doc/src/sgml/config.sgml	29 Jan 2009 17:23:12 -0000
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3547,3554 ****
          The default is 50 tuples.
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries in
!         <structname>pg_autovacuum</>.
         </para>
        </listitem>
       </varlistentry>
--- 3547,3554 ----
          The default is 50 tuples.
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries by
!         changing storage parameters.
         </para>
        </listitem>
       </varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3565,3572 ****
          The default is 50 tuples.
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries in
!         <structname>pg_autovacuum</>.
         </para>
        </listitem>
       </varlistentry>
--- 3565,3572 ----
          The default is 50 tuples.
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries by
!         changing storage parameters.
         </para>
        </listitem>
       </varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3584,3591 ****
          The default is 0.2 (20% of table size).
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries in
!         <structname>pg_autovacuum</>.
         </para>
        </listitem>
       </varlistentry>
--- 3584,3591 ----
          The default is 0.2 (20% of table size).
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries by
!         changing storage parameters.
         </para>
        </listitem>
       </varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3603,3610 ****
          The default is 0.1 (10% of table size).
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries in
!         <structname>pg_autovacuum</>.
         </para>
        </listitem>
       </varlistentry>
--- 3603,3610 ----
          The default is 0.1 (10% of table size).
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries by
!         changing storage parameters.
         </para>
        </listitem>
       </varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3624,3631 ****
          autovacuum is otherwise disabled.
          The default is 200 million transactions.
          This parameter can only be set at server start, but the setting
!         can be reduced for individual tables by entries in
!         <structname>pg_autovacuum</>.
          For more information see <xref linkend="vacuum-for-wraparound">.
         </para>
        </listitem>
--- 3624,3631 ----
          autovacuum is otherwise disabled.
          The default is 200 million transactions.
          This parameter can only be set at server start, but the setting
!         can be reduced for individual tables by entries by
!         changing storage parameters.
          For more information see <xref linkend="vacuum-for-wraparound">.
         </para>
        </listitem>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3645,3652 ****
          The default value is 20 milliseconds.
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries in
!         <structname>pg_autovacuum</>.
         </para>
        </listitem>
       </varlistentry>
--- 3645,3652 ----
          The default value is 20 milliseconds.
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries by
!         changing storage parameters.
         </para>
        </listitem>
       </varlistentry>
*************** COPY postgres_log FROM '/full/path/to/lo
*** 3667,3674 ****
          each worker never exceeds the limit on this variable.
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries in
!         <structname>pg_autovacuum</>.
         </para>
        </listitem>
       </varlistentry>
--- 3667,3674 ----
          each worker never exceeds the limit on this variable.
          This parameter can only be set in the <filename>postgresql.conf</>
          file or on the server command line.
!         This setting can be overridden for individual tables by entries by
!         changing storage parameters.
         </para>
        </listitem>
       </varlistentry>
Index: doc/src/sgml/maintenance.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/maintenance.sgml,v
retrieving revision 1.89
diff -c -p -r1.89 maintenance.sgml
*** doc/src/sgml/maintenance.sgml	16 Jan 2009 13:27:23 -0000	1.89
--- doc/src/sgml/maintenance.sgml	5 Feb 2009 21:04:54 -0000
*************** HINT:  Stop the postmaster and use a sta
*** 573,579 ****
     <para>
      Tables whose <structfield>relfrozenxid</> value is more than
      <varname>autovacuum_freeze_max_age</> transactions old are always
!     vacuumed.  Otherwise, if the number of tuples obsoleted since the last
      <command>VACUUM</command> exceeds the <quote>vacuum threshold</quote>, the
      table is vacuumed.  The vacuum threshold is defined as:
  <programlisting>
--- 573,581 ----
     <para>
      Tables whose <structfield>relfrozenxid</> value is more than
      <varname>autovacuum_freeze_max_age</> transactions old are always
!     vacuumed (this also applies to those tables whose freeze max age has
!     been modified via storage parameters; see below).  Otherwise, if the
!     number of tuples obsoleted since the last
      <command>VACUUM</command> exceeds the <quote>vacuum threshold</quote>, the
      table is vacuumed.  The vacuum threshold is defined as:
  <programlisting>
*************** analyze threshold = analyze base thresho
*** 604,669 ****
     <para>
      The default thresholds and scale factors are taken from
      <filename>postgresql.conf</filename>, but it is possible to override them
!     on a table-by-table basis by making entries in the system catalog
!     <link
!     linkend="catalog-pg-autovacuum"><structname>pg_autovacuum</></link>.
!     If a <structname>pg_autovacuum</structname> row exists for a particular
!     table, the settings it specifies are applied; otherwise the global
!     settings are used.  See <xref linkend="runtime-config-autovacuum"> for
      more details on the global settings.
     </para>
  
     <para>
!     Besides the base threshold values and scale factors, there are five
!     more parameters that can be set for each table in
!     <structname>pg_autovacuum</structname>.
!     The first, <structname>pg_autovacuum</>.<structfield>enabled</>,
      can be set to <literal>false</literal> to instruct the autovacuum daemon
      to skip that particular table entirely.  In this case
      autovacuum will only touch the table if it must do so
      to prevent transaction ID wraparound.
!     The next two parameters, the vacuum cost delay
!     (<structname>pg_autovacuum</structname>.<structfield>vac_cost_delay</structfield>)
!     and the vacuum cost limit
!     (<structname>pg_autovacuum</structname>.<structfield>vac_cost_limit</structfield>),
!     are used to set table-specific values for the
!     <xref linkend="runtime-config-resource-vacuum-cost" endterm="runtime-config-resource-vacuum-cost-title">
      feature.
!     The last two parameters,
!     (<structname>pg_autovacuum</structname>.<structfield>freeze_min_age</structfield>)
!     and
!     (<structname>pg_autovacuum</structname>.<structfield>freeze_max_age</structfield>),
!     are used to set table-specific values for
!     <xref linkend="guc-vacuum-freeze-min-age"> and
!     <xref linkend="guc-autovacuum-freeze-max-age"> respectively.
     </para>
  
     <para>
!     If any of the values in <structname>pg_autovacuum</structname>
!     are set to a negative number, or if a row is not present at all in
!     <structname>pg_autovacuum</structname> for any particular table, the
!     corresponding values from <filename>postgresql.conf</filename> are used.
     </para>
  
     <para>
-     There is not currently any support for making
-     <structname>pg_autovacuum</structname> entries, except by doing
-     manual <command>INSERT</>s into the catalog.  This feature will be
-     improved in future releases, and it is likely that the catalog
-     definition will change.
-    </para>
- 
-    <caution>
-     <para>
-      The contents of the <structname>pg_autovacuum</structname> system
-      catalog are currently not saved in database dumps created by the
-      tools <application>pg_dump</> and <application>pg_dumpall</>.  If
-      you want to preserve them across a dump/reload cycle, make sure
-      you dump the catalog manually.
-     </para>
-    </caution>
- 
-    <para>
      When multiple workers are running, the cost limit is
      <quote>balanced</quote> among all the running workers, so that the
      total impact on the system is the same, regardless of the number
--- 606,651 ----
     <para>
      The default thresholds and scale factors are taken from
      <filename>postgresql.conf</filename>, but it is possible to override them
!     on a table-by-table basis by specifying storage parameters.  If a setting
!     has been changed via storage parameters, that value is used; otherwise the
!     global settings are used. See <xref linkend="runtime-config-autovacuum"> for
      more details on the global settings.
     </para>
  
     <para>
!     Besides the base threshold values and scale factors, there are six
!     more autovacuum parameters that can be set for each table via
!     storage parameters.
!     The first parameter, <literal>autovacuum_enabled</>,
      can be set to <literal>false</literal> to instruct the autovacuum daemon
      to skip that particular table entirely.  In this case
      autovacuum will only touch the table if it must do so
      to prevent transaction ID wraparound.
!     The next two parameters,
!     <literal>autovacuum_vac_cost_delay</literal> and
!     <literal>autovacuum_vac_cost_limit</literal>, are used to set
!     table-specific values for the
!     <xref linkend="runtime-config-resource-vacuum-cost"
!     endterm="runtime-config-resource-vacuum-cost-title">
      feature.
!     <literal>autovacuum_freeze_min_age</literal>,
!     <literal>autovacuum_freeze_max_age</literal> and
!     <literal>autovacuum_freeze_table_age</literal> are used to set
!     values for <xref linkend="guc-vacuum-freeze-min-age">,
!     <xref linkend="guc-autovacuum-freeze-max-age"> and
!     <xref linkend="guc-vacuum-freeze-table-age"> respectively.
     </para>
  
     <para>
!     The <literal>WITH</literal> clause of <xref linkend="sql-createtable">
!     can be used to change autovacuum parameters on table creation; see
!     <xref linkend="sql-createtable-storage-parameters"
!     endterm="sql-createtable-storage-parameters-title"> for more information.
!     They can be modified afterwards with the <literal>SET</literal> and
!     <literal>RESET</literal> clauses of <xref linkend="sql-altertable">.
     </para>
  
     <para>
      When multiple workers are running, the cost limit is
      <quote>balanced</quote> among all the running workers, so that the
      total impact on the system is the same, regardless of the number
Index: doc/src/sgml/ref/alter_index.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/ref/alter_index.sgml,v
retrieving revision 1.14
diff -c -p -r1.14 alter_index.sgml
*** doc/src/sgml/ref/alter_index.sgml	14 Nov 2008 10:22:45 -0000	1.14
--- doc/src/sgml/ref/alter_index.sgml	29 Jan 2009 17:23:12 -0000
*************** ALTER INDEX <replaceable class="PARAMETE
*** 75,80 ****
--- 75,90 ----
      </listitem>
     </varlistentry>
  
+      <varlistentry>
+       <term><replaceable class="PARAMETER">value</replaceable></term>
+       <listitem>
+        <para>
+         The new value for a storage parameter.
+         This might be a number or a word depending on the parameter.
+        </para>
+       </listitem>
+      </varlistentry>
+ 
     <varlistentry>
      <term><literal>RESET ( <replaceable class="PARAMETER">storage_parameter</replaceable> [, ... ] )</literal></term>
      <listitem>
Index: doc/src/sgml/ref/create_table.sgml
===================================================================
RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/ref/create_table.sgml,v
retrieving revision 1.112
diff -c -p -r1.112 create_table.sgml
*** doc/src/sgml/ref/create_table.sgml	2 Feb 2009 19:31:38 -0000	1.112
--- doc/src/sgml/ref/create_table.sgml	5 Feb 2009 21:14:17 -0000
*************** and <replaceable class="PARAMETER">table
*** 697,703 ****
     <variablelist>
  
     <varlistentry>
!     <term><literal>FILLFACTOR</></term>
      <listitem>
       <para>
        The fillfactor for a table is a percentage between 10 and 100.
--- 697,703 ----
     <variablelist>
  
     <varlistentry>
!     <term><literal>fillfactor</> (<type>integer</>)</term>
      <listitem>
       <para>
        The fillfactor for a table is a percentage between 10 and 100.
*************** and <replaceable class="PARAMETER">table
*** 715,721 ****
     </varlistentry>
  
     <varlistentry>
!     <term><literal>TOAST.FILLFACTOR</literal></term>
      <listitem>
       <para>
        Same as above, for the supplementary storage table, if any; see
--- 715,721 ----
     </varlistentry>
  
     <varlistentry>
!     <term><literal>toast.fillfactor</literal></term>
      <listitem>
       <para>
        Same as above, for the supplementary storage table, if any; see
*************** and <replaceable class="PARAMETER">table
*** 724,729 ****
--- 724,846 ----
      </listitem>
     </varlistentry>
  
+    <varlistentry>
+     <term><literal>autovacuum_enabled</> (<type>boolean</>)</term>
+     <listitem>
+      <para>
+      Enables or disables the autovacuum daemon on a particular table.
+      If true, the autovacuum daemon will initiate a <command>VACUUM</> operation
+      on a particular table when the number of updated or deleted tuples exceeds 
+      <literal>autovacuum_vac_threshold</> plus 
+      <literal>autovacuum_vac_scale_factor</> times the number of live tuples 
+      currently estimated to be in the relation.
+      Similarly, it will initiate an <command>ANALYZE</> operation when the
+      number of inserted, updated or deleted tuples exceeds
+      <literal>autovacuum_anl_threshold</> plus 
+      <literal>autovacuum_anl_scale_factor</> times the number of live tuples 
+      currently estimated to be in the relation.
+      If false, this table will not be autovacuumed, except to prevent
+      transaction Id wraparound. See <xref linkend="vacuum-for-wraparound"> for
+      more about wraparound prevention.
+      Observe that this variable inherits its value from the <xref
+      linkend="guc-autovacuum">.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term><literal>autovacuum_vacuum_threshold</> (<type>integer</>)</term>
+     <listitem>
+      <para>
+      Minimum number of updated or deleted tuples before initiate a
+      <command>VACUUM</> operation on a particular table. 
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term><literal>autovacuum_vacuum_scale_factor</> (<type>float4</>)</term>
+     <listitem>
+      <para>
+      Multiplier for <structfield>reltuples</> to add to
+      <literal>autovacuum_vacuum_threshold</>.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term><literal>autovacuum_analyze_threshold</> (<type>integer</>)</term>
+     <listitem>
+      <para>
+      Minimum number of inserted, updated, or deleted tuples before initiate an
+      <command>ANALYZE</> operation on a particular table.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term><literal>autovacuum_analyze_scale_factor</> (<type>float4</>)</term>
+     <listitem>
+      <para>
+      Multiplier for <structfield>reltuples</> to add to
+      <literal>autovacuum_analyze_threshold</>.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term><literal>autovacuum_vacuum_cost_delay</> (<type>integer</>)</term>
+     <listitem>
+      <para>
+      Custom <xref linkend="guc-autovacuum-vacuum-cost-delay"> parameter.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term><literal>autovacuum_vacuum_cost_limit</> (<type>integer</>)</term>
+     <listitem>
+      <para>
+      Custom <xref linkend="guc-autovacuum-vacuum-cost-limit"> parameter.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term><literal>autovacuum_freeze_min_age</> (<type>integer</>)</term>
+     <listitem>
+      <para>
+      Custom <xref linkend="guc-vacuum-freeze-min-age"> parameter. Note that
+      autovacuum will ignore attempts to set a per-table
+      <literal>autovacuum_freeze_min_age</> larger than the half system-wide 
+      <xref linkend="guc-autovacuum-freeze-max-age"> setting.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term><literal>autovacuum_freeze_max_age</> (<type>integer</>)</term>
+     <listitem>
+      <para>
+      Custom <xref linkend="guc-autovacuum-freeze-max-age"> parameter. Note that
+      autovacuum will ignore attempts to set a per-table
+      <literal>autovacuum_freeze_max_age</> larger than the system-wide setting
+      (it can only be set smaller). Note that while you can set
+      <literal>autovacuum_freeze_max_age</> very small, or even zero, this is
+      usually unwise since it will force frequent vacuuming.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
+    <varlistentry>
+     <term><literal>autovacuum_freeze_table_age</literal> (<type>integer</type>)</term>
+     <listitem>
+      <para>
+       Custom <xref linkend="guc-vacuum-freeze-table-age"> parameter.
+      </para>
+     </listitem>
+    </varlistentry>
+ 
     </variablelist>
  
    </refsect2>
Index: src/backend/access/common/reloptions.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/access/common/reloptions.c,v
retrieving revision 1.20
diff -c -p -r1.20 reloptions.c
*** src/backend/access/common/reloptions.c	2 Feb 2009 19:31:38 -0000	1.20
--- src/backend/access/common/reloptions.c	5 Feb 2009 21:23:01 -0000
***************
*** 48,53 ****
--- 48,61 ----
  
  static relopt_bool boolRelOpts[] =
  {
+ 	{
+ 		{
+ 			"autovacuum_enabled",
+ 			"Enables autovacuum in this relation",
+ 			RELOPT_KIND_HEAP
+ 		},
+ 		true
+ 	},
  	/* list terminator */
  	{ { NULL } }
  };
*************** static relopt_int intRelOpts[] =
*** 86,97 ****
--- 94,176 ----
  		},
  		GIST_DEFAULT_FILLFACTOR, GIST_MIN_FILLFACTOR, 100
  	},
+ 	{
+ 		{
+ 			"autovacuum_vacuum_threshold",
+ 			"Minimum number of tuple updates or deletes prior to vacuum",
+ 			RELOPT_KIND_HEAP
+ 		},
+ 		50, 0, INT_MAX
+ 	},
+ 	{
+ 		{
+ 			"autovacuum_analyze_threshold",
+ 			"Minimum number of tuple inserts, updates or deletes prior to analyze",
+ 			RELOPT_KIND_HEAP
+ 		},
+ 		50, 0, INT_MAX
+ 	},
+ 	{
+ 		{
+ 			"autovacuum_vacuum_cost_delay",
+ 			"Vacuum cost delay in milliseconds, for autovacuum",
+ 			RELOPT_KIND_HEAP
+ 		},
+ 		20, 0, 1000
+ 	},
+ 	{
+ 		{
+ 			"autovacuum_vacuum_cost_limit",
+ 			"Vacuum cost amount available before napping, for autovacuum",
+ 			RELOPT_KIND_HEAP
+ 		},
+ 		200, 1, 10000
+ 	},
+ 	{
+ 		{
+ 			"autovacuum_freeze_min_age",
+ 			"Minimum age at which VACUUM should freeze a table row, for autovacuum",
+ 			RELOPT_KIND_HEAP
+ 		},
+ 		100000000, 0, 1000000000
+ 	},
+ 	{
+ 		{
+ 			"autovacuum_freeze_max_age",
+ 			"Age at which to autovacuum a table to prevent transaction ID wraparound",
+ 			RELOPT_KIND_HEAP
+ 		},
+ 		200000000, 100000000, 2000000000
+ 	},
+ 	{
+ 		{
+ 			"autovacuum_freeze_table_age",
+ 			"Age at which VACUUM should perform a full table sweep to replace old Xid values with FrozenXID",
+ 			RELOPT_KIND_HEAP
+ 		}, 150000000, 0, 2000000000
+ 	},
  	/* list terminator */
  	{ { NULL } }
  };
  
  static relopt_real realRelOpts[] =
  {
+ 	{
+ 		{
+ 			"autovacuum_vacuum_scale_factor",
+ 			"Number of tuple updates or deletes prior to vacuum as a fraction of reltuples",
+ 			RELOPT_KIND_HEAP
+ 		},
+ 		0.2, 0.0, 100.0
+ 	},
+ 	{
+ 		{
+ 			"autovacuum_analyze_scale_factor",
+ 			"Number of tuple inserts, updates or deletes prior to analyze as a fraction of reltuples",
+ 			RELOPT_KIND_HEAP
+ 		},
+ 		0.1, 0.0, 100.0
+ 	},
  	/* list terminator */
  	{ { NULL } }
  };
*************** fillRelOptions(void *rdopts, Size basesi
*** 973,979 ****
  
  
  /*
!  * Option parser for anything that uses StdRdOptions (i.e. fillfactor only)
   */
  bytea *
  default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
--- 1052,1059 ----
  
  
  /*
!  * Option parser for anything that uses StdRdOptions (i.e. fillfactor and
!  * autovacuum)
   */
  bytea *
  default_reloptions(Datum reloptions, bool validate, relopt_kind kind)
*************** default_reloptions(Datum reloptions, boo
*** 982,988 ****
  	StdRdOptions   *rdopts;
  	int				numoptions;
  	relopt_parse_elt tab[] = {
! 		{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)}
  	};
  
  	options = parseRelOptions(reloptions, validate, kind, &numoptions);
--- 1062,1088 ----
  	StdRdOptions   *rdopts;
  	int				numoptions;
  	relopt_parse_elt tab[] = {
! 		{"fillfactor", RELOPT_TYPE_INT, offsetof(StdRdOptions, fillfactor)},
! 		{"autovacuum_enabled", RELOPT_TYPE_BOOL,
! 			offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, enabled)},
! 		{"autovacuum_vacuum_threshold", RELOPT_TYPE_INT,
! 			offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_threshold)},
! 		{"autovacuum_analyze_threshold", RELOPT_TYPE_INT,
! 			offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_threshold)},
! 		{"autovacuum_vacuum_cost_delay", RELOPT_TYPE_INT,
! 			offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_delay)},
! 		{"autovacuum_vacuum_cost_limit", RELOPT_TYPE_INT,
! 			offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_cost_limit)},
! 		{"autovacuum_freeze_min_age", RELOPT_TYPE_INT,
! 			offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_min_age)},
! 		{"autovacuum_freeze_max_age", RELOPT_TYPE_INT,
! 			offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_max_age)},
! 		{"autovacuum_freeze_table_age", RELOPT_TYPE_INT,
! 			offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, freeze_table_age)},
! 		{"autovacuum_vacuum_scale_factor", RELOPT_TYPE_REAL,
! 			offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, vacuum_scale_factor)},
! 		{"autovacuum_analyze_scale_factor", RELOPT_TYPE_REAL,
! 			offsetof(StdRdOptions, autovacuum) + offsetof(AutoVacOpts, analyze_scale_factor)}
  	};
  
  	options = parseRelOptions(reloptions, validate, kind, &numoptions);
Index: src/backend/catalog/Makefile
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/Makefile,v
retrieving revision 1.68
diff -c -p -r1.68 Makefile
*** src/backend/catalog/Makefile	19 Dec 2008 16:25:16 -0000	1.68
--- src/backend/catalog/Makefile	29 Jan 2009 17:23:12 -0000
*************** all: $(BKIFILES)
*** 26,32 ****
  # indexing.h had better be last, and toasting.h just before it.
  
  POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
! 	pg_proc.h pg_type.h pg_attribute.h pg_class.h pg_autovacuum.h \
  	pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
  	pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
  	pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
--- 26,32 ----
  # indexing.h had better be last, and toasting.h just before it.
  
  POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\
! 	pg_proc.h pg_type.h pg_attribute.h pg_class.h \
  	pg_attrdef.h pg_constraint.h pg_inherits.h pg_index.h pg_operator.h \
  	pg_opfamily.h pg_opclass.h pg_am.h pg_amop.h pg_amproc.h \
  	pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
Index: src/backend/postmaster/autovacuum.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/postmaster/autovacuum.c,v
retrieving revision 1.92
diff -c -p -r1.92 autovacuum.c
*** src/backend/postmaster/autovacuum.c	16 Jan 2009 13:27:24 -0000	1.92
--- src/backend/postmaster/autovacuum.c	5 Feb 2009 21:40:31 -0000
***************
*** 69,80 ****
  
  #include "access/genam.h"
  #include "access/heapam.h"
  #include "access/transam.h"
  #include "access/xact.h"
  #include "catalog/dependency.h"
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
- #include "catalog/pg_autovacuum.h"
  #include "catalog/pg_database.h"
  #include "commands/dbcommands.h"
  #include "commands/vacuum.h"
--- 69,80 ----
  
  #include "access/genam.h"
  #include "access/heapam.h"
+ #include "access/reloptions.h"
  #include "access/transam.h"
  #include "access/xact.h"
  #include "catalog/dependency.h"
  #include "catalog/indexing.h"
  #include "catalog/namespace.h"
  #include "catalog/pg_database.h"
  #include "commands/dbcommands.h"
  #include "commands/vacuum.h"
***************
*** 88,93 ****
--- 88,94 ----
  #include "storage/bufmgr.h"
  #include "storage/fd.h"
  #include "storage/ipc.h"
+ #include "storage/lmgr.h"
  #include "storage/pmsignal.h"
  #include "storage/proc.h"
  #include "storage/procarray.h"
*************** typedef struct av_relation
*** 165,177 ****
  {
  	Oid			ar_toastrelid;	/* hash key - must be first */
  	Oid			ar_relid;
  } av_relation;
  
  /* struct to keep track of tables to vacuum and/or analyze, after rechecking */
  typedef struct autovac_table
  {
  	Oid			at_relid;
- 	Oid			at_toastrelid;
  	bool		at_dovacuum;
  	bool		at_doanalyze;
  	int			at_freeze_min_age;
--- 166,180 ----
  {
  	Oid			ar_toastrelid;	/* hash key - must be first */
  	Oid			ar_relid;
+ 	bool		ar_hasrelopts;
+ 	AutoVacOpts	ar_reloptions;	/* copy of AutoVacOpts from the main table's
+ 								   reloptions, or NULL if none */
  } av_relation;
  
  /* struct to keep track of tables to vacuum and/or analyze, after rechecking */
  typedef struct autovac_table
  {
  	Oid			at_relid;
  	bool		at_dovacuum;
  	bool		at_doanalyze;
  	int			at_freeze_min_age;
*************** static void autovac_balance_cost(void);
*** 282,297 ****
  static void do_autovacuum(void);
  static void FreeWorkerInfo(int code, Datum arg);
  
! static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map);
! static void relation_needs_vacanalyze(Oid relid, Form_pg_autovacuum avForm,
  						  Form_pg_class classForm,
! 						  PgStat_StatTabEntry *tabentry, bool *dovacuum,
! 						  bool *doanalyze, bool *wraparound);
  
  static void autovacuum_do_vac_analyze(autovac_table *tab,
  						  BufferAccessStrategy bstrategy);
! static HeapTuple get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid,
! 											   HTAB *table_toast_map);
  static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
  						  PgStat_StatDBEntry *shared,
  						  PgStat_StatDBEntry *dbentry);
--- 285,301 ----
  static void do_autovacuum(void);
  static void FreeWorkerInfo(int code, Datum arg);
  
! static autovac_table *table_recheck_autovac(Oid relid, HTAB *table_toast_map,
! 					  TupleDesc pg_class_desc);
! static void relation_needs_vacanalyze(Oid relid, AutoVacOpts *relopts,
  						  Form_pg_class classForm,
! 						  PgStat_StatTabEntry *tabentry,
! 						  bool *dovacuum, bool *doanalyze, bool *wraparound);
  
  static void autovacuum_do_vac_analyze(autovac_table *tab,
  						  BufferAccessStrategy bstrategy);
! static AutoVacOpts *extract_autovac_opts(HeapTuple tup,
! 					 TupleDesc pg_class_desc);
  static PgStat_StatTabEntry *get_pgstat_tabentry_relid(Oid relid, bool isshared,
  						  PgStat_StatDBEntry *shared,
  						  PgStat_StatDBEntry *dbentry);
*************** get_database_list(void)
*** 1816,1823 ****
  static void
  do_autovacuum(void)
  {
! 	Relation	classRel,
! 				avRel;
  	HeapTuple	tuple;
  	HeapScanDesc relScan;
  	Form_pg_database dbForm;
--- 1820,1826 ----
  static void
  do_autovacuum(void)
  {
! 	Relation	classRel;
  	HeapTuple	tuple;
  	HeapScanDesc relScan;
  	Form_pg_database dbForm;
*************** do_autovacuum(void)
*** 1829,1834 ****
--- 1832,1838 ----
  	PgStat_StatDBEntry *dbentry;
  	BufferAccessStrategy bstrategy;
  	ScanKeyData	key;
+ 	TupleDesc	pg_class_desc;
  
  	/*
  	 * StartTransactionCommand and CommitTransactionCommand will automatically
*************** do_autovacuum(void)
*** 1890,1901 ****
  	shared = pgstat_fetch_stat_dbentry(InvalidOid);
  
  	classRel = heap_open(RelationRelationId, AccessShareLock);
! 	avRel = heap_open(AutovacuumRelationId, AccessShareLock);
  
  	/* create hash table for toast <-> main relid mapping */
  	MemSet(&ctl, 0, sizeof(ctl));
  	ctl.keysize = sizeof(Oid);
! 	ctl.entrysize = sizeof(Oid) * 2;
  	ctl.hash = oid_hash;
  
  	table_toast_map = hash_create("TOAST to main relid map",
--- 1894,1907 ----
  	shared = pgstat_fetch_stat_dbentry(InvalidOid);
  
  	classRel = heap_open(RelationRelationId, AccessShareLock);
! 
! 	/* create a copy so we can use it after closing pg_class */
! 	pg_class_desc = CreateTupleDescCopy(RelationGetDescr(classRel));
  
  	/* create hash table for toast <-> main relid mapping */
  	MemSet(&ctl, 0, sizeof(ctl));
  	ctl.keysize = sizeof(Oid);
! 	ctl.entrysize = sizeof(av_relation);
  	ctl.hash = oid_hash;
  
  	table_toast_map = hash_create("TOAST to main relid map",
*************** do_autovacuum(void)
*** 1909,1917 ****
  	 * We do this in two passes: on the first one we collect the list of
  	 * plain relations, and on the second one we collect TOAST tables.
  	 * The reason for doing the second pass is that during it we want to use
! 	 * the main relation's pg_autovacuum entry if the TOAST table does not have
! 	 * any, and we cannot obtain it unless we know beforehand what's the main
! 	 * table OID.
  	 *
  	 * We need to check TOAST tables separately because in cases with short,
  	 * wide tables there might be proportionally much more activity in the
--- 1915,1923 ----
  	 * We do this in two passes: on the first one we collect the list of
  	 * plain relations, and on the second one we collect TOAST tables.
  	 * The reason for doing the second pass is that during it we want to use
! 	 * the main relation's pg_class.reloptions entry if the TOAST table does
! 	 * not have any, and we cannot obtain it unless we know beforehand what's
! 	 * the main table OID.
  	 *
  	 * We need to check TOAST tables separately because in cases with short,
  	 * wide tables there might be proportionally much more activity in the
*************** do_autovacuum(void)
*** 1931,1939 ****
  	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
  	{
  		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
- 		Form_pg_autovacuum avForm = NULL;
  		PgStat_StatTabEntry *tabentry;
! 		HeapTuple	avTup;
  		Oid			relid;
  		bool		dovacuum;
  		bool		doanalyze;
--- 1937,1944 ----
  	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
  	{
  		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
  		PgStat_StatTabEntry *tabentry;
! 		AutoVacOpts *relopts;
  		Oid			relid;
  		bool		dovacuum;
  		bool		doanalyze;
*************** do_autovacuum(void)
*** 1942,1958 ****
  
  		relid = HeapTupleGetOid(tuple);
  
! 		/* Fetch the pg_autovacuum tuple for the relation, if any */
! 		avTup = get_pg_autovacuum_tuple_relid(avRel, relid, NULL);
! 		if (HeapTupleIsValid(avTup))
! 			avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
! 
! 		/* Fetch the pgstat entry for this table */
  		tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
  											 shared, dbentry);
  
  		/* Check if it needs vacuum or analyze */
! 		relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
  								  &dovacuum, &doanalyze, &wraparound);
  
  		/*
--- 1947,1959 ----
  
  		relid = HeapTupleGetOid(tuple);
  
! 		/* Fetch reloptions and the pgstat entry for this table */
! 		relopts = extract_autovac_opts(tuple, pg_class_desc);
  		tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
  											 shared, dbentry);
  
  		/* Check if it needs vacuum or analyze */
! 		relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
  								  &dovacuum, &doanalyze, &wraparound);
  
  		/*
*************** do_autovacuum(void)
*** 1998,2004 ****
  		}
  		else
  		{
! 			/* Plain relations that need work are added to table_oids */
  			if (dovacuum || doanalyze)
  				table_oids = lappend_oid(table_oids, relid);
  
--- 1999,2005 ----
  		}
  		else
  		{
! 			/* relations that need work are added to table_oids */
  			if (dovacuum || doanalyze)
  				table_oids = lappend_oid(table_oids, relid);
  
*************** do_autovacuum(void)
*** 2020,2031 ****
  				{
  					/* hash_search already filled in the key */
  					hentry->ar_relid = relid;
  				}
  			}
  		}
- 
- 		if (HeapTupleIsValid(avTup))
- 			heap_freetuple(avTup);
  	}
  
  	heap_endscan(relScan);
--- 2021,2036 ----
  				{
  					/* hash_search already filled in the key */
  					hentry->ar_relid = relid;
+ 					hentry->ar_hasrelopts = false;
+ 					if (relopts != NULL)
+ 					{
+ 						hentry->ar_hasrelopts = true;
+ 						memcpy(&hentry->ar_reloptions, relopts,
+ 							   sizeof(AutoVacOpts));
+ 					}
  				}
  			}
  		}
  	}
  
  	heap_endscan(relScan);
*************** do_autovacuum(void)
*** 2040,2049 ****
  	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
  	{
  		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
- 		Form_pg_autovacuum avForm = NULL;
  		PgStat_StatTabEntry *tabentry;
- 		HeapTuple   avTup;
  		Oid         relid;
  		bool		dovacuum;
  		bool		doanalyze;
  		bool		wraparound;
--- 2045,2053 ----
  	while ((tuple = heap_getnext(relScan, ForwardScanDirection)) != NULL)
  	{
  		Form_pg_class classForm = (Form_pg_class) GETSTRUCT(tuple);
  		PgStat_StatTabEntry *tabentry;
  		Oid         relid;
+ 		AutoVacOpts *relopts = NULL;
  		bool		dovacuum;
  		bool		doanalyze;
  		bool		wraparound;
*************** do_autovacuum(void)
*** 2057,2073 ****
  
  		relid = HeapTupleGetOid(tuple);
  
! 		/* Fetch the pg_autovacuum tuple for this rel */
! 		avTup = get_pg_autovacuum_tuple_relid(avRel, relid, table_toast_map);
  
! 		if (HeapTupleIsValid(avTup))
! 			avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
  
  		/* Fetch the pgstat entry for this table */
  		tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
  											 shared, dbentry);
  
! 		relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
  								  &dovacuum, &doanalyze, &wraparound);
  
  		/* ignore analyze for toast tables */
--- 2061,2086 ----
  
  		relid = HeapTupleGetOid(tuple);
  
! 		/*
! 		 * fetch reloptions -- if this toast table does not have them,
! 		 * try the main rel
! 		 */
! 		relopts = extract_autovac_opts(tuple, pg_class_desc);
! 		if (relopts == NULL)
! 		{
! 			av_relation		*hentry;
! 			bool			found;
  
! 			hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
! 			if (found && hentry->ar_hasrelopts)
! 				relopts = &hentry->ar_reloptions;
! 		}
  
  		/* Fetch the pgstat entry for this table */
  		tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
  											 shared, dbentry);
  
! 		relation_needs_vacanalyze(relid, relopts, classForm, tabentry,
  								  &dovacuum, &doanalyze, &wraparound);
  
  		/* ignore analyze for toast tables */
*************** do_autovacuum(void)
*** 2076,2082 ****
  	}
  
  	heap_endscan(relScan);
- 	heap_close(avRel, AccessShareLock);
  	heap_close(classRel, AccessShareLock);
  
  	/*
--- 2089,2094 ----
*************** do_autovacuum(void)
*** 2163,2172 ****
  		 * condition is not closed but it is very small.
  		 */
  		MemoryContextSwitchTo(AutovacMemCxt);
! 		tab = table_recheck_autovac(relid, table_toast_map);
  		if (tab == NULL)
  		{
! 			/* someone else vacuumed the table */
  			LWLockRelease(AutovacuumScheduleLock);
  			continue;
  		}
--- 2175,2184 ----
  		 * condition is not closed but it is very small.
  		 */
  		MemoryContextSwitchTo(AutovacMemCxt);
! 		tab = table_recheck_autovac(relid, table_toast_map, pg_class_desc);
  		if (tab == NULL)
  		{
! 			/* someone else vacuumed the table, or it went away */
  			LWLockRelease(AutovacuumScheduleLock);
  			continue;
  		}
*************** deleted:
*** 2292,2340 ****
  }
  
  /*
!  * Returns a copy of the pg_autovacuum tuple for the given relid, or NULL if
!  * there isn't any.  avRel is pg_autovacuum, already open and suitably locked.
   *
!  * If table_toast_map is not null, use it to find an alternative OID with which
!  * to search a pg_autovacuum entry, if the passed relid does not yield one
!  * directly.
   */
! static HeapTuple
! get_pg_autovacuum_tuple_relid(Relation avRel, Oid relid,
! 							  HTAB *table_toast_map)
  {
! 	ScanKeyData entry[1];
! 	SysScanDesc avScan;
! 	HeapTuple	avTup;
  
! 	ScanKeyInit(&entry[0],
! 				Anum_pg_autovacuum_vacrelid,
! 				BTEqualStrategyNumber, F_OIDEQ,
! 				ObjectIdGetDatum(relid));
  
! 	avScan = systable_beginscan(avRel, AutovacuumRelidIndexId, true,
! 								SnapshotNow, 1, entry);
! 
! 	avTup = systable_getnext(avScan);
! 
! 	if (HeapTupleIsValid(avTup))
! 		avTup = heap_copytuple(avTup);
! 
! 	systable_endscan(avScan);
! 
! 	if (!HeapTupleIsValid(avTup) && table_toast_map != NULL)
! 	{
! 		av_relation		*hentry;
! 		bool		found;
! 
! 		hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
! 		if (found)
! 			/* avoid second recursion */
! 			avTup = get_pg_autovacuum_tuple_relid(avRel, hentry->ar_relid,
! 												  NULL);
! 	}
  
! 	return avTup;
  }
  
  /*
--- 2304,2332 ----
  }
  
  /*
!  * extract_autovac_opts
   *
!  * Given a relation's pg_class tuple, return the AutoVacOpts portion of
!  * reloptions, if set; otherwise, return NULL.
   */
! AutoVacOpts *
! extract_autovac_opts(HeapTuple tup, TupleDesc pg_class_desc)
  {
! 	bytea	   *relopts;
! 	AutoVacOpts *av;
  
! 	Assert(((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_RELATION ||
! 		   ((Form_pg_class) GETSTRUCT(tup))->relkind == RELKIND_TOASTVALUE);
  
! 	relopts = extractRelOptions(tup, pg_class_desc, InvalidOid);
! 	if (relopts == NULL)
! 		return NULL;
! 	
! 	av = palloc(sizeof(AutoVacOpts));
! 	memcpy(av, &(((StdRdOptions *) relopts)->autovacuum), sizeof(AutoVacOpts));
! 	pfree(relopts);
  
! 	return av;
  }
  
  /*
*************** get_pgstat_tabentry_relid(Oid relid, boo
*** 2370,2382 ****
   * Note that the returned autovac_table does not have the name fields set.
   */
  static autovac_table *
! table_recheck_autovac(Oid relid, HTAB *table_toast_map)
  {
- 	Form_pg_autovacuum avForm = NULL;
  	Form_pg_class classForm;
  	HeapTuple	classTup;
- 	HeapTuple	avTup;
- 	Relation	avRel;
  	bool		dovacuum;
  	bool		doanalyze;
  	autovac_table *tab = NULL;
--- 2362,2372 ----
   * Note that the returned autovac_table does not have the name fields set.
   */
  static autovac_table *
! table_recheck_autovac(Oid relid, HTAB *table_toast_map,
! 					  TupleDesc pg_class_desc)
  {
  	Form_pg_class classForm;
  	HeapTuple	classTup;
  	bool		dovacuum;
  	bool		doanalyze;
  	autovac_table *tab = NULL;
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2384,2389 ****
--- 2374,2380 ----
  	PgStat_StatDBEntry *shared;
  	PgStat_StatDBEntry *dbentry;
  	bool		wraparound;
+ 	AutoVacOpts	*avopts;
  
  	/* use fresh stats */
  	autovac_refresh_stats();
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2399,2421 ****
  		return NULL;
  	classForm = (Form_pg_class) GETSTRUCT(classTup);
  
! 	/*
! 	 * Fetch the pg_autovacuum entry, if any.  For a toast table, also try the
! 	 * main rel's pg_autovacuum entry if there isn't one for the TOAST table
! 	 * itself.
! 	 */
! 	avRel = heap_open(AutovacuumRelationId, AccessShareLock);
! 	avTup = get_pg_autovacuum_tuple_relid(avRel, relid,
! 			classForm->relkind == RELKIND_TOASTVALUE ? table_toast_map : NULL);
  
! 	if (HeapTupleIsValid(avTup))
! 		avForm = (Form_pg_autovacuum) GETSTRUCT(avTup);
  
  	/* fetch the pgstat table entry */
  	tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
  										 shared, dbentry);
  
! 	relation_needs_vacanalyze(relid, avForm, classForm, tabentry,
  							  &dovacuum, &doanalyze, &wraparound);
  
  	/* ignore ANALYZE for toast tables */
--- 2390,2416 ----
  		return NULL;
  	classForm = (Form_pg_class) GETSTRUCT(classTup);
  
! 	/* 
! 	 * Get the applicable reloptions.  If it is a TOAST table, try to get the
! 	 * main table reloptions if the toast table itself doesn't have.
! 	 */
! 	avopts = extract_autovac_opts(classTup, pg_class_desc);
! 	if (classForm->relkind == RELKIND_TOASTVALUE && 
! 		avopts == NULL && table_toast_map != NULL)
! 	{
! 		av_relation		*hentry;
! 		bool			found;
  
! 		hentry = hash_search(table_toast_map, &relid, HASH_FIND, &found);
! 		if (found && hentry->ar_hasrelopts)
! 			avopts = &hentry->ar_reloptions;
! 	}
  
  	/* fetch the pgstat table entry */
  	tabentry = get_pgstat_tabentry_relid(relid, classForm->relisshared,
  										 shared, dbentry);
  
! 	relation_needs_vacanalyze(relid, avopts, classForm, tabentry,
  							  &dovacuum, &doanalyze, &wraparound);
  
  	/* ignore ANALYZE for toast tables */
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2431,2471 ****
  		int			vac_cost_delay;
  
  		/*
! 		 * Calculate the vacuum cost parameters and the minimum freeze age. If
! 		 * there is a tuple in pg_autovacuum, use it; else, use the GUC
! 		 * defaults.  Note that the fields may contain "-1" (or indeed any
! 		 * negative value), which means use the GUC defaults for each setting.
! 		 * In cost_limit, the value 0 also means to use the value from
! 		 * elsewhere.
! 		 */
! 		if (avForm != NULL)
! 		{
! 			vac_cost_limit = (avForm->vac_cost_limit > 0) ?
! 				avForm->vac_cost_limit :
! 				((autovacuum_vac_cost_limit > 0) ?
! 				 autovacuum_vac_cost_limit : VacuumCostLimit);
! 
! 			vac_cost_delay = (avForm->vac_cost_delay >= 0) ?
! 				avForm->vac_cost_delay :
! 				((autovacuum_vac_cost_delay >= 0) ?
! 				 autovacuum_vac_cost_delay : VacuumCostDelay);
! 
! 			freeze_min_age = (avForm->freeze_min_age >= 0) ?
! 				avForm->freeze_min_age : default_freeze_min_age;
! 
! 			freeze_table_age = (avForm->freeze_table_age >= 0) ?
! 				avForm->freeze_table_age : default_freeze_table_age;
  		}
  		else
  		{
! 			vac_cost_limit = (autovacuum_vac_cost_limit > 0) ?
! 				autovacuum_vac_cost_limit : VacuumCostLimit;
! 
! 			vac_cost_delay = (autovacuum_vac_cost_delay >= 0) ?
  				autovacuum_vac_cost_delay : VacuumCostDelay;
! 
  			freeze_min_age = default_freeze_min_age;
- 
  			freeze_table_age = default_freeze_table_age;
  		}
  
--- 2426,2453 ----
  		int			vac_cost_delay;
  
  		/*
! 		 * Calculate the vacuum cost parameters and the freeze ages.  If there
! 		 * are options set in pg_class.reloptions, use them; in the case of a
! 		 * toast table, try the main table too.  Otherwise use the GUC
! 		 * defaults, autovacuum's own first and plain vacuum second.
! 		 */
! 		if (avopts)
! 		{
! 			vac_cost_delay = avopts->vacuum_cost_delay;
! 			vac_cost_limit = avopts->vacuum_cost_limit;
! 			freeze_min_age = avopts->freeze_min_age;
! 			freeze_table_age = avopts->freeze_table_age;
  		}
  		else
  		{
! 			/* -1 in autovac setting means use plain vacuum_cost_delay */
! 			vac_cost_delay = autovacuum_vac_cost_delay >= 0 ?
  				autovacuum_vac_cost_delay : VacuumCostDelay;
! 			/* 0 or -1 in autovac setting means use plain vacuum_cost_limit */
! 			vac_cost_limit = autovacuum_vac_cost_limit > 0 ?
! 				autovacuum_vac_cost_limit : VacuumCostLimit;
! 			/* these do not have autovacuum-specific settings */
  			freeze_min_age = default_freeze_min_age;
  			freeze_table_age = default_freeze_table_age;
  		}
  
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2483,2491 ****
  		tab->at_datname = NULL;
  	}
  
- 	heap_close(avRel, AccessShareLock);
- 	if (HeapTupleIsValid(avTup))
- 		heap_freetuple(avTup);
  	heap_freetuple(classTup);
  
  	return tab;
--- 2465,2470 ----
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2496,2503 ****
   *
   * Check whether a relation needs to be vacuumed or analyzed; return each into
   * "dovacuum" and "doanalyze", respectively.  Also return whether the vacuum is
!  * being forced because of Xid wraparound.	avForm and tabentry can be NULL,
!  * classForm shouldn't.
   *
   * A table needs to be vacuumed if the number of dead tuples exceeds a
   * threshold.  This threshold is calculated as
--- 2475,2486 ----
   *
   * Check whether a relation needs to be vacuumed or analyzed; return each into
   * "dovacuum" and "doanalyze", respectively.  Also return whether the vacuum is
!  * being forced because of Xid wraparound.
!  *
!  * relopts is a pointer to the AutoVacOpts options (either for itself in the
!  * case of a plain table, or for either itself or its parent table in the case
!  * of a TOAST table), NULL if none; tabentry is the pgstats entry, which can be
!  * NULL.
   *
   * A table needs to be vacuumed if the number of dead tuples exceeds a
   * threshold.  This threshold is calculated as
*************** table_recheck_autovac(Oid relid, HTAB *t
*** 2513,2531 ****
   * We also force vacuum if the table's relfrozenxid is more than freeze_max_age
   * transactions back.
   *
!  * A table whose pg_autovacuum.enabled value is false, is automatically
!  * skipped (unless we have to vacuum it due to freeze_max_age).  Thus
!  * autovacuum can be disabled for specific tables.	Also, when the stats
   * collector does not have data about a table, it will be skipped.
   *
!  * A table whose vac_base_thresh value is <0 takes the base value from the
   * autovacuum_vacuum_threshold GUC variable.  Similarly, a vac_scale_factor
!  * value <0 is substituted with the value of
   * autovacuum_vacuum_scale_factor GUC variable.  Ditto for analyze.
   */
  static void
  relation_needs_vacanalyze(Oid relid,
! 						  Form_pg_autovacuum avForm,
  						  Form_pg_class classForm,
  						  PgStat_StatTabEntry *tabentry,
   /* output params below */
--- 2496,2514 ----
   * We also force vacuum if the table's relfrozenxid is more than freeze_max_age
   * transactions back.
   *
!  * A table whose autovacuum_enabled option is false, is
!  * automatically skipped (unless we have to vacuum it due to freeze_max_age).
!  * Thus autovacuum can be disabled for specific tables.	Also, when the stats
   * collector does not have data about a table, it will be skipped.
   *
!  * A table whose vac_base_thresh value is < 0 takes the base value from the
   * autovacuum_vacuum_threshold GUC variable.  Similarly, a vac_scale_factor
!  * value < 0 is substituted with the value of
   * autovacuum_vacuum_scale_factor GUC variable.  Ditto for analyze.
   */
  static void
  relation_needs_vacanalyze(Oid relid,
! 						  AutoVacOpts *relopts,
  						  Form_pg_class classForm,
  						  PgStat_StatTabEntry *tabentry,
   /* output params below */
*************** relation_needs_vacanalyze(Oid relid,
*** 2534,2542 ****
  						  bool *wraparound)
  {
  	bool		force_vacuum;
  	float4		reltuples;		/* pg_class.reltuples */
  
! 	/* constants from pg_autovacuum or GUC variables */
  	int			vac_base_thresh,
  				anl_base_thresh;
  	float4		vac_scale_factor,
--- 2517,2526 ----
  						  bool *wraparound)
  {
  	bool		force_vacuum;
+ 	bool		av_enabled;
  	float4		reltuples;		/* pg_class.reltuples */
  
! 	/* constants from reloptions or GUC variables */
  	int			vac_base_thresh,
  				anl_base_thresh;
  	float4		vac_scale_factor,
*************** relation_needs_vacanalyze(Oid relid,
*** 2554,2593 ****
  	int			freeze_max_age;
  	TransactionId xidForceLimit;
  
- 	AssertArg(classForm != NULL);
- 	AssertArg(OidIsValid(relid));
- 
  	/*
! 	 * Determine vacuum/analyze equation parameters.  If there is a tuple in
! 	 * pg_autovacuum, use it; else, use the GUC defaults.  Note that the
! 	 * fields may contain "-1" (or indeed any negative value), which means use
! 	 * the GUC defaults for each setting.
! 	 */
! 	if (avForm != NULL)
! 	{
! 		vac_scale_factor = (avForm->vac_scale_factor >= 0) ?
! 			avForm->vac_scale_factor : autovacuum_vac_scale;
! 		vac_base_thresh = (avForm->vac_base_thresh >= 0) ?
! 			avForm->vac_base_thresh : autovacuum_vac_thresh;
! 
! 		anl_scale_factor = (avForm->anl_scale_factor >= 0) ?
! 			avForm->anl_scale_factor : autovacuum_anl_scale;
! 		anl_base_thresh = (avForm->anl_base_thresh >= 0) ?
! 			avForm->anl_base_thresh : autovacuum_anl_thresh;
! 
! 		freeze_max_age = (avForm->freeze_max_age >= 0) ?
! 			Min(avForm->freeze_max_age, autovacuum_freeze_max_age) :
! 			autovacuum_freeze_max_age;
  	}
  	else
  	{
  		vac_scale_factor = autovacuum_vac_scale;
  		vac_base_thresh = autovacuum_vac_thresh;
- 
  		anl_scale_factor = autovacuum_anl_scale;
  		anl_base_thresh = autovacuum_anl_thresh;
- 
  		freeze_max_age = autovacuum_freeze_max_age;
  	}
  
  	/* Force vacuum if table is at risk of wraparound */
--- 2538,2566 ----
  	int			freeze_max_age;
  	TransactionId xidForceLimit;
  
  	/*
! 	 * Determine vacuum/analyze equation parameters.  We have two possible
! 	 * sources: the passed reloptions (which could be a main table or a toast
! 	 * table), or the autovacuum GUC variables.
! 	 */
! 	if (relopts)
! 	{
! 		vac_scale_factor = relopts->vacuum_scale_factor;
! 		vac_base_thresh = relopts->vacuum_threshold;
! 		anl_scale_factor = relopts->analyze_scale_factor;
! 		anl_base_thresh = relopts->analyze_threshold;
! 		freeze_max_age = Min(relopts->freeze_max_age,
! 							 autovacuum_freeze_max_age);
! 		av_enabled = relopts->enabled;
  	}
  	else
  	{
  		vac_scale_factor = autovacuum_vac_scale;
  		vac_base_thresh = autovacuum_vac_thresh;
  		anl_scale_factor = autovacuum_anl_scale;
  		anl_base_thresh = autovacuum_anl_thresh;
  		freeze_max_age = autovacuum_freeze_max_age;
+ 		av_enabled = true;
  	}
  
  	/* Force vacuum if table is at risk of wraparound */
*************** relation_needs_vacanalyze(Oid relid,
*** 2599,2606 ****
  										  xidForceLimit));
  	*wraparound = force_vacuum;
  
! 	/* User disabled it in pg_autovacuum?  (But ignore if at risk) */
! 	if (avForm && !avForm->enabled && !force_vacuum)
  	{
  		*doanalyze = false;
  		*dovacuum = false;
--- 2572,2579 ----
  										  xidForceLimit));
  	*wraparound = force_vacuum;
  
! 	/* User disabled it in pg_class.reloptions?  (But ignore if at risk) */
! 	if (!force_vacuum && !av_enabled)
  	{
  		*doanalyze = false;
  		*dovacuum = false;
Index: src/include/catalog/indexing.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/catalog/indexing.h,v
retrieving revision 1.106
diff -c -p -r1.106 indexing.h
*** src/include/catalog/indexing.h	22 Jan 2009 20:16:08 -0000	1.106
--- src/include/catalog/indexing.h	29 Jan 2009 17:23:12 -0000
*************** DECLARE_UNIQUE_INDEX(pg_auth_members_rol
*** 97,105 ****
  DECLARE_UNIQUE_INDEX(pg_auth_members_member_role_index, 2695, on pg_auth_members using btree(member oid_ops, roleid oid_ops));
  #define AuthMemMemRoleIndexId	2695
  
- DECLARE_UNIQUE_INDEX(pg_autovacuum_vacrelid_index, 1250, on pg_autovacuum using btree(vacrelid oid_ops));
- #define AutovacuumRelidIndexId	1250
- 
  DECLARE_UNIQUE_INDEX(pg_cast_oid_index, 2660, on pg_cast using btree(oid oid_ops));
  #define CastOidIndexId	2660
  DECLARE_UNIQUE_INDEX(pg_cast_source_target_index, 2661, on pg_cast using btree(castsource oid_ops, casttarget oid_ops));
--- 97,102 ----
Index: src/include/utils/rel.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/utils/rel.h,v
retrieving revision 1.111
diff -c -p -r1.111 rel.h
*** src/include/utils/rel.h	1 Jan 2009 17:24:02 -0000	1.111
--- src/include/utils/rel.h	5 Feb 2009 21:23:07 -0000
*************** typedef struct RelationData
*** 214,223 ****
--- 214,239 ----
   * be applied to relations that use this format or a superset for
   * private options data.
   */
+  /* autovacuum-related reloptions. */
+ typedef struct AutoVacOpts
+ {
+ 	bool    enabled;
+ 	int     vacuum_threshold;
+ 	int     analyze_threshold;
+ 	int     vacuum_cost_delay;
+ 	int     vacuum_cost_limit;
+ 	int     freeze_min_age;
+ 	int     freeze_max_age;
+ 	int		freeze_table_age;
+ 	float8  vacuum_scale_factor;
+ 	float8  analyze_scale_factor;
+ } AutoVacOpts;
+ 
  typedef struct StdRdOptions
  {
  	int32		vl_len_;		/* varlena header (do not touch directly!) */
  	int			fillfactor;		/* page fill factor in percent (0..100) */
+ 	AutoVacOpts autovacuum;     /* autovacuum-related options */
  } StdRdOptions;
  
  #define HEAP_MIN_FILLFACTOR			10
Index: src/test/regress/expected/sanity_check.out
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/test/regress/expected/sanity_check.out,v
retrieving revision 1.38
diff -c -p -r1.38 sanity_check.out
*** src/test/regress/expected/sanity_check.out	19 Dec 2008 16:25:19 -0000	1.38
--- src/test/regress/expected/sanity_check.out	29 Jan 2009 17:23:12 -0000
*************** SELECT relname, relhasindex
*** 90,96 ****
   pg_attribute            | t
   pg_auth_members         | t
   pg_authid               | t
-  pg_autovacuum           | t
   pg_cast                 | t
   pg_class                | t
   pg_constraint           | t
--- 90,95 ----
*************** SELECT relname, relhasindex
*** 152,158 ****
   timetz_tbl              | f
   tinterval_tbl           | f
   varchar_tbl             | f
! (141 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
--- 151,157 ----
   timetz_tbl              | f
   tinterval_tbl           | f
   varchar_tbl             | f
! (140 rows)
  
  --
  -- another sanity check: every system catalog that has OIDs should have
