diff --git a/doc/src/sgml/plperl.sgml b/doc/src/sgml/plperl.sgml
index 5a134c75bba02ddfed0e08ff2c8e02ada598c31f..4d28bd2d984315af01a17ce12d143158fef98a46 100644
--- a/doc/src/sgml/plperl.sgml
+++ b/doc/src/sgml/plperl.sgml
@@ -1,5 +1,5 @@
 <!--
-$PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.23 2004/05/16 23:22:06 neilc Exp $
+$PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.24 2004/07/21 20:22:57 momjian Exp $
 -->
 
  <chapter id="plperl">
@@ -34,9 +34,10 @@ $PostgreSQL: pgsql/doc/src/sgml/plperl.sgml,v 2.23 2004/05/16 23:22:06 neilc Exp
   <note>
    <para>
     Users of source packages must specially enable the build of
-    PL/Perl during the installation process.  (Refer to the installation
-    instructions for more information.)  Users of binary packages
-    might find PL/Perl in a separate subpackage.
+    PL/Perl during the installation process.  (Refer to <xref
+    linkend="install-short"> for more information.)  Users of
+    binary packages might find PL/Perl in a separate subpackage.
+
    </para>
   </note>
 
@@ -54,7 +55,7 @@ $$ LANGUAGE plperl;
    The body of the function is ordinary Perl code. Since the body of
    the function is treated as a string by
    <productname>PostgreSQL</productname>, it can be specified using
-   dollar quoting (as shown above), or via the usual single quote
+   dollar quoting (as shown above), or via the legacy single quote
    syntax (see <xref linkend="sql-syntax-strings"> for more
    information).
   </para>
@@ -79,19 +80,22 @@ $$ LANGUAGE plperl;
   </para>
 
   <para>
-   If an SQL null value<indexterm><primary>null value</><secondary
-   sortas="PL/Perl">in PL/Perl</></indexterm> is passed to a function,
-   the argument value will appear as <quote>undefined</> in Perl.  The
-   above function definition will not behave very nicely with null
-   inputs (in fact, it will act as though they are zeroes).  We could
-   add <literal>STRICT</> to the function definition to make
-   <productname>PostgreSQL</productname> do something more reasonable:
-   if a null value is passed, the function will not be called at all,
-   but will just return a null result automatically.  Alternatively,
-   we could check for undefined inputs in the function body.  For
-   example, suppose that we wanted <function>perl_max</function> with
-   one null and one non-null argument to return the non-null argument,
-   rather than a null value:
+   If an SQL <literal>NULL</literal> value<indexterm><primary>null
+    value</><secondary sortas="PL/Perl">in PL/Perl</></indexterm> is
+    passed to a function, the argument value will appear as
+    <quote>undefined</> in Perl.  The above function definition will not
+    behave very nicely with <literal>NULL</literal> inputs (in fact, it
+    will act as though they are zeroes).  We could add <literal>STRICT</>
+    to the function definition to make
+    <productname>PostgreSQL</productname> do something more reasonable: if
+    a <literal>NULL</literal> value is passed, the function will not be
+    called at all, but will just return a <literal>NULL</literal> result
+    automatically.  Alternatively, we could check for undefined inputs in
+    the function body.  For example, suppose that we wanted
+    <function>perl_max</function> with one <literal>NULL</literal> and one
+    non-<literal>NULL</literal> argument to return the
+    non-<literal>NULL</literal> argument, rather than a
+    <literal>NULL</literal> value:
 
 <programlisting>
 CREATE FUNCTION perl_max (integer, integer) RETURNS integer AS $$
@@ -108,9 +112,9 @@ $$ LANGUAGE plperl;
   </para>
 
   <para>
-   As shown above, to return an SQL null value from a PL/Perl
-   function, return an undefined value.  This can be done whether the
-   function is strict or not.
+    As shown above, to return an SQL <literal>NULL</literal> value from
+    a PL/Perl function, return an undefined value.  This can be done
+    whether the function is strict or not.
   </para>
 
   <para>
@@ -127,7 +131,7 @@ CREATE TABLE employee (
 
 CREATE FUNCTION empcomp(employee) RETURNS integer AS $$
     my ($emp) = @_;
-    return $emp->{'basesalary'} + $emp->{'bonus'};
+    return $emp->{basesalary} + $emp->{bonus};
 $$ LANGUAGE plperl;
 
 SELECT name, empcomp(employee) FROM employee;
@@ -135,35 +139,9 @@ SELECT name, empcomp(employee) FROM employee;
   </para>
 
   <para>
-   There is currently no support for returning a composite-type result
-   value.
+   There is now support for returning a composite-type result value.
   </para>
 
-  <tip>
-   <para>
-    Because the function body is passed as an SQL string literal to
-    <command>CREATE FUNCTION</command>, you have to use dollar quoting
-    or escape single quotes and backslashes within your Perl source,
-    typically by doubling them.  Another possible approach is to avoid
-    writing single quotes by using Perl's extended quoting operators
-    (<literal>q[]</literal>, <literal>qq[]</literal>,
-    <literal>qw[]</literal>).
-   </para>
-  </tip>
- </sect1>
-
- <sect1 id="plperl-data">
-  <title>Data Values in PL/Perl</title>
-
-  <para>
-   The argument values supplied to a PL/Perl function's code are
-   simply the input arguments converted to text form (just as if they
-   had been displayed by a <command>SELECT</command> statement).
-   Conversely, the <literal>return</> command will accept any string
-   that is acceptable input format for the function's declared return
-   type.  So, the PL/Perl programmer can manipulate data values as if
-   they were just text.
-  </para>
  </sect1>
 
  <sect1 id="plperl-database">
@@ -171,25 +149,77 @@ SELECT name, empcomp(employee) FROM employee;
 
   <para>
    Access to the database itself from your Perl function can be done via
-   an experimental module <ulink
+   spi_exec_query, or via an experimental module <ulink
    url="http://www.cpan.org/modules/by-module/DBD/APILOS/"><literal>DBD::PgSPI</literal></ulink>
    (also available at <ulink url="http://www.cpan.org/SITES.html"><acronym>CPAN</>
-   mirror sites</ulink>). This module makes available a
+   mirror sites</ulink>).  This module makes available a
    <acronym>DBI</>-compliant database-handle named
    <varname>$pg_dbh</varname> that can be used to perform queries
    with normal <acronym>DBI</> syntax.<indexterm><primary>DBI</></indexterm>
+
   </para>
 
   <para>
-   PL/Perl itself presently provides only one additional Perl command:
+   PL/Perl itself presently provides two additional Perl commands:
 
    <variablelist>
     <varlistentry>
+     <indexterm>
+      <primary>spi_exec_query</primary>
+      <secondary>in PL/Perl</secondary>
+     </indexterm>
      <indexterm>
       <primary>elog</primary>
       <secondary>in PL/Perl</secondary>
      </indexterm>
 
+     <term><function>spi_exec_query(</> [ <replaceable>SELECT query</replaceable> [, <replaceable>max_rows</replaceable>]] | [<replaceable>non-SELECT query</replaceable>] ) </term>
+     <listitem>
+       <para>
+        Here is an example of a SELECT query with the optional maximum
+number of rows.
+<programlisting>
+$rv = spi_exec_query('SELECT * from my_table', 5);
+</programlisting>
+
+This returns up to 5 rows from my_table.
+       </para>
+       <para>
+If my_table has a column my_column, it would be accessed as
+<programlisting>
+$foo = $rv->{rows}[$i]->{my_column};
+</programlisting>
+       </para>
+       <para>
+The number of rows actually returned would be:
+<programlisting>
+$nrows = @{$rv->{rows}};
+</programlisting>
+       </para>
+       <para>
+Here is an example using a non-SELECT statement.
+<programlisting>
+$query = "INSERT INTO my_table VALUES (1, 'test')";
+$rv = spi_exec_query($query);
+</programlisting>
+
+You can then access status (SPI_OK_INSERT, e.g.) like this.
+<programlisting>
+$res = $rv->{status};
+</programlisting>
+
+       </para>
+       <para>
+To get the rows affected, do:
+<programlisting>
+$nrows = $rv->{rows};
+</programlisting>
+       </para>
+
+     </listitem>
+
+    </varlistentry>
+    <varlistentry>
      <term><function>elog</> <replaceable>level</replaceable>, <replaceable>msg</replaceable></term>
      <listitem>
       <para>
@@ -206,6 +236,111 @@ SELECT name, empcomp(employee) FROM employee;
   </para>
  </sect1>
 
+ <sect1 id="plperl-data">
+  <title>Data Values in PL/Perl</title>
+
+  <para>
+   The argument values supplied to a PL/Perl function's code are
+   simply the input arguments converted to text form (just as if they
+   had been displayed by a <command>SELECT</command> statement).
+   Conversely, the <literal>return</> command will accept any string
+   that is acceptable input format for the function's declared return
+   type.  So, the PL/Perl programmer can manipulate data values as if
+   they were just text.
+  </para>
+
+  <para>
+   PL/Perl can now return rowsets and composite types, and rowsets of
+composite types.
+  </para>
+
+  <para>
+   Here is an example of a PL/Perl function returning a rowset of a row type:
+<programlisting>
+CREATE TABLE test (
+       i int,
+       v varchar
+);
+
+INSERT INTO test (i, v) VALUES (1,'first line');
+INSERT INTO test (i, v) VALUES (2,'second line');
+INSERT INTO test (i, v) VALUES (3,'third line');
+INSERT INTO test (i, v) VALUES (4,'immortal');
+
+create function test_munge() returns setof test language plperl as $$
+    my $res = [];
+    my $rv = spi_exec_query('select i,v from test;');
+    my $status = $rv->{status};
+    my $rows = @{$rv->{rows}};
+    my $processed = $rv->{processed};
+    foreach my $rn (0..$rows-1) {
+        my $row = $rv->{rows}[$rn];
+        $row->{i} += 200 if defined($row->{i});
+        $row->{v} =~ tr/A-Za-z/a-zA-Z/ if (defined($row->{v}));
+        push @$res,$row;
+    }
+    return $res;
+$$;
+
+select * from test_munge();
+</programlisting>
+  </para>
+
+  <para>
+   Here is an example of a PL/Perl function returning a composite type:
+  <programlisting>
+CREATE TYPE testrowperl AS (f1 integer, f2 text, f3 text);
+
+CREATE OR REPLACE FUNCTION perl_row() RETURNS testrowperl AS $$
+
+ return {f2 => 'hello', f1 => 1, f3 => 'world'};
+
+$$ LANGUAGE plperl;
+  </programlisting>
+  </para>
+
+  <para>
+  Here is an example of a PL/Perl function returning a rowset of a composite type.
+  <programlisting>
+CREATE TYPE testsetperl AS (f1 integer, f2 text, f3 text);
+
+CREATE OR REPLACE FUNCTION perl_set() RETURNS SETOF testsetperl AS $$
+ return[
+        {f1 => 1, f2 => 'hello', f3 =>  'world'},
+        {f1 => 2, f2 => 'hello', f3 =>  'postgres'},
+        {f1 => 3, f2 => 'hello', f3 =>  'plperl'}
+       ];
+$$  LANGUAGE plperl;
+  </programlisting>
+  </para>
+ </sect1>
+ <sect1 id="plperl-global">
+  <title>Global Values in PL/Perl</title>
+  <para>
+  You can use the %_SHARED to store data between function calls.  WHY
+IS THIS A HASH, AND NOT A HASH REF?
+  </para>
+  <para>
+For example:
+<programlisting>
+CREATE OR REPLACE FUNCTION set_var(TEXT) RETURNS TEXT AS $$
+    $_SHARED{first} = 'Hello, PL/Perl!';
+    return 'ok';
+$$ LANGUAGE plperl;
+
+CREATE OR REPLACE FUNCTION get_var() RETURNS text AS $$
+    return $_SHARED{first};
+$$ LANGUAGE plperl;
+
+SELECT set_var('hello plperl');
+SELECT get_var();
+</programlisting>
+
+  </para>
+   
+
+ </sect1>
+
  <sect1 id="plperl-trusted">
   <title>Trusted and Untrusted PL/Perl</title>
 
@@ -266,9 +401,69 @@ $$ LANGUAGE plperl;
    <literal>plperlu</>, execution would succeed.
   </para>
  </sect1>
+ <sect1 id="plperl-triggers">
+  <title>PL/Perl Triggers</title>
+
+  <para>
+   PL/Perl can now be used to write trigger functions using the
+<varname>$_TD</varname> hash reference.
+  </para>
+
+  <para>
+   Some useful parts of the $_TD hash reference are:
+
+<programlisting>
+$_TD->{new}{foo} # NEW value of column foo
+$_TD->{old}{bar} # OLD value of column bar
+$_TD{name}       # Name of the trigger being called
+$_TD{event}      # INSERT, UPDATE, DELETE or UNKNOWN
+$_TD{when}       # BEFORE, AFTER or UNKNOWN
+$_TD{level}      # ROW, STATEMENT or UNKNOWN
+$_TD{relid}      # Relation ID of the table on which the trigger occurred.
+$_TD{relname}    # Name of the table on which the trigger occurred.
+@{$_TD{argv}}    # Array of arguments to the trigger function.  May be empty.
+$_TD{argc}       # Number of arguments to the trigger.  Why is this here?
+</programlisting>
+
+  </para>
+
+  <para>
+   Triggers can return one of the following:
+<programlisting>
+return;   -- Executes the statement
+SKIP;     -- Doesn't execute the statement
+MODIFY; -- Says it modified a NEW row
+</programlisting>
+  </para>
+
+  <para>
+Here is an example of a trigger function, illustrating some of the
+above.
+<programlisting>
+CREATE TABLE test (
+        i int,
+        v varchar
+);
+
+CREATE OR REPLACE FUNCTION valid_id() RETURNS trigger AS $$
+    if (($_TD->{new}{i}>=100) || ($_TD->{new}{i}<=0)) {
+        return "SKIP";   # Skip INSERT/UPDATE command
+    } elsif ($_TD->{new}{v} ne "immortal") {
+        $_TD->{new}{v} .= "(modified by trigger)";
+        return "MODIFY"; # Modify tuple and proceed INSERT/UPDATE command
+    } else {
+        return;      # Proceed INSERT/UPDATE command
+    }
+$$ LANGUAGE plperl;
+
+CREATE TRIGGER "test_valid_id_trig" BEFORE INSERT OR UPDATE ON test
+FOR EACH ROW EXECUTE PROCEDURE "valid_id"();
+</programlisting>
+  </para>
+ </sect1>
 
  <sect1 id="plperl-missing">
-  <title>Missing Features</title>
+  <title>Limitations and Missing Features</title>
 
   <para>
    The following features are currently missing from PL/Perl, but they
@@ -278,26 +473,25 @@ $$ LANGUAGE plperl;
     <listitem>
      <para>
       PL/Perl functions cannot call each other directly (because they
-      are anonymous subroutines inside Perl).  There's presently no
-      way for them to share global variables, either.
+      are anonymous subroutines inside Perl).
      </para>
     </listitem>
 
     <listitem>
      <para>
-      PL/Perl cannot be used to write trigger
-      functions.<indexterm><primary>trigger</><secondary>in
-      PL/Perl</></indexterm>
+      <application>Full SPI</application> is not yet implemented.
      </para>
     </listitem>
-
     <listitem>
-     <para>
-      <application>DBD::PgSPI</applicatioN> or similar capability
-      should be integrated into the standard
-      <productname>PostgreSQL</productname> distribution.
-     </para>
+      <para>
+        In the current implementation, if you are fetching or
+        returning very large datasets, you should be aware that these
+        will all go into memory.  Future features will help with this.
+        In the meantime, we suggest that you not use pl/perl if you
+        will fetch or return very large result sets.
+      </para>
     </listitem>
+
    </itemizedlist>
   </para>
  </sect1>
diff --git a/src/backend/Makefile b/src/backend/Makefile
index b106353abc43361f45f048fb0c743669de92a837..bee3ea44b671e85705e4a14da88be2ef372eadcc 100644
--- a/src/backend/Makefile
+++ b/src/backend/Makefile
@@ -4,7 +4,7 @@
 #
 # Copyright (c) 1994, Regents of the University of California
 #
-# $PostgreSQL: pgsql/src/backend/Makefile,v 1.101 2004/07/19 17:03:56 tgl Exp $
+# $PostgreSQL: pgsql/src/backend/Makefile,v 1.102 2004/07/21 20:22:58 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -29,13 +29,13 @@ endif
 
 ##########################################################################
 
-all: submake-libpgport postgres $(POSTGRES_IMP)
+all: submake-libpgport submake-libpq postgres $(POSTGRES_IMP)
 
 ifneq ($(PORTNAME), cygwin)
 ifneq ($(PORTNAME), win32)
 
 postgres: $(OBJS)
-	$(CC) $(CFLAGS) $(LDFLAGS) $(export_dynamic) $^ $(LIBS) -o $@
+	$(CC) $(CFLAGS) $(LDFLAGS) -I $(libpq_srcdir) $(export_dynamic) $^ $(LIBS)  $(libpq) -o $@
 
 endif
 endif
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 4e219df4f5b703d447171b5ef612ccbfc9d77b62..43f694886313d09238fec6a4ce16c4c80c604e0a 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.187 2004/07/17 03:28:37 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/bootstrap/bootstrap.c,v 1.188 2004/07/21 20:22:58 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -34,6 +34,7 @@
 #include "libpq/pqsignal.h"
 #include "miscadmin.h"
 #include "postmaster/bgwriter.h"
+#include "postmaster/pg_autovacuum.h"
 #include "storage/freespace.h"
 #include "storage/ipc.h"
 #include "storage/pg_shmem.h"
@@ -355,6 +356,9 @@ BootstrapMain(int argc, char *argv[])
 			case BS_XLOG_BGWRITER:
 				statmsg = "writer process";
 				break;
+			case BS_XLOG_AUTOVAC:
+				statmsg = "auto vacuum process";
+				break;
 			default:
 				statmsg = "??? process";
 				break;
@@ -391,6 +395,9 @@ BootstrapMain(int argc, char *argv[])
 			case BS_XLOG_BGWRITER:
 				InitDummyProcess(DUMMY_PROC_BGWRITER);
 				break;
+			case BS_XLOG_AUTOVAC:
+				InitDummyProcess(DUMMY_PROC_AUTOVAC);
+				break;
 
 			default:
 				InitDummyProcess(DUMMY_PROC_DEFAULT);
@@ -427,6 +434,12 @@ BootstrapMain(int argc, char *argv[])
 			BackgroundWriterMain();
 			proc_exit(1);		/* should never return */
 
+		case BS_XLOG_AUTOVAC:
+			/* don't set signals, autovac has its own agenda */
+			InitXLOGAccess();
+			AutoVacMain();
+			proc_exit(1);		/* should never return */
+		
 		default:
 			elog(PANIC, "unrecognized XLOG op: %d", xlogop);
 			proc_exit(1);
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
index c63168a9bd5a8a93af0ef7ae8be81a49091bd651..4ed03b1d644775585c79728eeed54de956a65cfe 100644
--- a/src/backend/catalog/Makefile
+++ b/src/backend/catalog/Makefile
@@ -2,7 +2,7 @@
 #
 # Makefile for backend/catalog
 #
-# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.51 2004/06/18 06:13:19 tgl Exp $
+# $PostgreSQL: pgsql/src/backend/catalog/Makefile,v 1.52 2004/07/21 20:22:59 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -32,7 +32,7 @@ POSTGRES_BKI_SRCS := $(addprefix $(top_srcdir)/src/include/catalog/,\
 	pg_language.h pg_largeobject.h pg_aggregate.h pg_statistic.h \
 	pg_rewrite.h pg_trigger.h pg_listener.h pg_description.h pg_cast.h \
 	pg_namespace.h pg_conversion.h pg_database.h pg_shadow.h pg_group.h \
-	pg_tablespace.h pg_depend.h indexing.h \
+	pg_tablespace.h pg_depend.h pg_autovacuum.h indexing.h \
     )
 
 pg_includes := $(sort -I$(top_srcdir)/src/include -I$(top_builddir)/src/include)
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index 9e2eca9b2ee1816e53520618732a323f73db7e29..e94d7155e75867e7163a1cc8bcc3dbac049a4159 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -3,7 +3,7 @@
  *
  * Copyright 1996-2003, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.6 2004/04/26 15:24:41 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/catalog/system_views.sql,v 1.7 2004/07/21 20:22:59 momjian Exp $
  */
 
 CREATE VIEW pg_user AS 
@@ -41,22 +41,26 @@ CREATE VIEW pg_tables AS
     SELECT 
         N.nspname AS schemaname, 
         C.relname AS tablename, 
+	     T.spcname AS tablespace,
         pg_get_userbyid(C.relowner) AS tableowner, 
         C.relhasindex AS hasindexes, 
         C.relhasrules AS hasrules, 
         (C.reltriggers > 0) AS hastriggers 
     FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) 
+         LEFT JOIN pg_tablespace T ON (T.oid = C.reltablespace)
     WHERE C.relkind = 'r';
 
 CREATE VIEW pg_indexes AS 
     SELECT 
         N.nspname AS schemaname, 
         C.relname AS tablename, 
+        T.spcname AS tablespace,
         I.relname AS indexname, 
         pg_get_indexdef(I.oid) AS indexdef 
     FROM pg_index X JOIN pg_class C ON (C.oid = X.indrelid) 
          JOIN pg_class I ON (I.oid = X.indexrelid) 
          LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace) 
+		   LEFT JOIN pg_tablespace T ON (T.oid = C.reltablespace)
     WHERE C.relkind = 'r' AND I.relkind = 'i';
 
 CREATE VIEW pg_stats AS 
diff --git a/src/backend/postmaster/Makefile b/src/backend/postmaster/Makefile
index 10d7cfcb8ef37a48d79ec161b0ac63e725228b6f..d41790e0f79c5450c2df1866e6f389d6b25cfdd8 100644
--- a/src/backend/postmaster/Makefile
+++ b/src/backend/postmaster/Makefile
@@ -4,7 +4,7 @@
 #    Makefile for src/backend/postmaster
 #
 # IDENTIFICATION
-#    $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.16 2004/07/19 02:47:08 tgl Exp $
+#    $PostgreSQL: pgsql/src/backend/postmaster/Makefile,v 1.17 2004/07/21 20:22:59 momjian Exp $
 #
 #-------------------------------------------------------------------------
 
@@ -12,7 +12,7 @@ subdir = src/backend/postmaster
 top_builddir = ../../..
 include $(top_builddir)/src/Makefile.global
 
-OBJS = postmaster.o bgwriter.o pgstat.o pgarch.o
+OBJS = postmaster.o bgwriter.o pgstat.o pgarch.o pg_autovacuum.o
 
 all: SUBSYS.o
 
diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c
index d08d02c2cf6e90c0f7320ac88ad65a1dba0c1553..661451411f42551882a3074560d8cff545311544 100644
--- a/src/backend/postmaster/postmaster.c
+++ b/src/backend/postmaster/postmaster.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.412 2004/07/19 02:47:08 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.413 2004/07/21 20:22:59 momjian Exp $
  *
  * NOTES
  *
@@ -55,12 +55,6 @@
  *		The Postmaster cleans up after backends if they have an emergency
  *		exit and/or core dump.
  *
- * Error Reporting:
- *		Use write_stderr() only for reporting "interactive" errors
- *		(essentially, bogus arguments on the command line).  Once the
- *		postmaster is launched, use ereport().  In particular, don't use
- *		write_stderr() for anything that occurs after pmdaemonize.
- *
  *-------------------------------------------------------------------------
  */
 
@@ -200,6 +194,7 @@ char	   *preload_libraries_string = NULL;
 static pid_t StartupPID = 0,
 			BgWriterPID = 0,
 			PgArchPID = 0,
+			AutoVacPID = 0,
 			PgStatPID = 0;
 
 /* Startup/shutdown state */
@@ -269,6 +264,7 @@ static void SignalChildren(int signal);
 static int	CountChildren(void);
 static bool CreateOptsFile(int argc, char *argv[], char *fullprogname);
 static pid_t StartChildProcess(int xlop);
+static void postmaster_error(const char *fmt,...);
 
 #ifdef EXEC_BACKEND
 
@@ -299,6 +295,7 @@ static void ShmemBackendArrayRemove(pid_t pid);
 
 #define StartupDataBase()		StartChildProcess(BS_XLOG_STARTUP)
 #define StartBackgroundWriter() StartChildProcess(BS_XLOG_BGWRITER)
+#define StartAutoVac() StartChildProcess(BS_XLOG_AUTOVAC)
 
 
 /*
@@ -385,7 +382,7 @@ PostmasterMain(int argc, char *argv[])
 #ifdef USE_ASSERT_CHECKING
 				SetConfigOption("debug_assertions", optarg, PGC_POSTMASTER, PGC_S_ARGV);
 #else
-				write_stderr("%s: assert checking is not compiled in\n", progname);
+				postmaster_error("assert checking is not compiled in");
 #endif
 				break;
 			case 'a':
@@ -509,8 +506,9 @@ PostmasterMain(int argc, char *argv[])
 				}
 
 			default:
-				write_stderr("Try \"%s --help\" for more information.\n",
-							 progname);
+				fprintf(stderr,
+					gettext("Try \"%s --help\" for more information.\n"),
+						progname);
 				ExitPostmaster(1);
 		}
 	}
@@ -520,10 +518,10 @@ PostmasterMain(int argc, char *argv[])
 	 */
 	if (optind < argc)
 	{
-		write_stderr("%s: invalid argument: \"%s\"\n",
-					 progname, argv[optind]);
-		write_stderr("Try \"%s --help\" for more information.\n",
-					 progname);
+		postmaster_error("invalid argument: \"%s\"", argv[optind]);
+		fprintf(stderr,
+				gettext("Try \"%s --help\" for more information.\n"),
+				progname);
 		ExitPostmaster(1);
 	}
 
@@ -594,13 +592,13 @@ PostmasterMain(int argc, char *argv[])
 		 * for lack of buffers.  The specific choices here are somewhat
 		 * arbitrary.
 		 */
-		write_stderr("%s: the number of buffers (-B) must be at least twice the number of allowed connections (-N) and at least 16\n", progname);
+		postmaster_error("the number of buffers (-B) must be at least twice the number of allowed connections (-N) and at least 16");
 		ExitPostmaster(1);
 	}
 
 	if (ReservedBackends >= MaxBackends)
 	{
-		write_stderr("%s: superuser_reserved_connections must be less than max_connections\n", progname);
+		postmaster_error("superuser_reserved_connections must be less than max_connections");
 		ExitPostmaster(1);
 	}
 
@@ -609,7 +607,7 @@ PostmasterMain(int argc, char *argv[])
 	 */
 	if (!CheckDateTokenTables())
 	{
-		write_stderr("%s: invalid datetoken tables, please fix\n", progname);
+		postmaster_error("invalid datetoken tables, please fix");
 		ExitPostmaster(1);
 	}
 
@@ -829,7 +827,7 @@ PostmasterMain(int argc, char *argv[])
 	 * CAUTION: when changing this list, check for side-effects on the signal
 	 * handling setup of child processes.  See tcop/postgres.c,
 	 * bootstrap/bootstrap.c, postmaster/bgwriter.c, postmaster/pgarch.c,
-	 * and postmaster/pgstat.c.
+	 * postmaster/pgstat.c, and postmaster/pg_autovacuum.c.
 	 */
 	pqinitmask();
 	PG_SETMASK(&BlockSig);
@@ -978,10 +976,11 @@ checkDataDir(const char *checkdir)
 	fp = AllocateFile(path, PG_BINARY_R);
 	if (fp == NULL)
 	{
-		write_stderr("%s: could not find the database system\n"
-					 "Expected to find it in the directory \"%s\",\n"
-					 "but could not open file \"%s\": %s\n",
-					 progname, checkdir, path, strerror(errno));
+		fprintf(stderr,
+				gettext("%s: could not find the database system\n"
+						"Expected to find it in the directory \"%s\",\n"
+						"but could not open file \"%s\": %s\n"),
+				progname, checkdir, path, strerror(errno));
 		ExitPostmaster(2);
 	}
 	FreeFile(fp);
@@ -1024,8 +1023,8 @@ pmdaemonize(void)
 	pid = fork();
 	if (pid == (pid_t) -1)
 	{
-		write_stderr("%s: could not fork background process: %s\n",
-					 progname, strerror(errno));
+		postmaster_error("could not fork background process: %s",
+						 strerror(errno));
 		ExitPostmaster(1);
 	}
 	else if (pid)
@@ -1046,8 +1045,8 @@ pmdaemonize(void)
 #ifdef HAVE_SETSID
 	if (setsid() < 0)
 	{
-		write_stderr("%s: could not dissociate from controlling TTY: %s\n",
-					 progname, strerror(errno));
+		postmaster_error("could not dissociate from controlling TTY: %s",
+						 strerror(errno));
 		ExitPostmaster(1);
 	}
 #endif
@@ -1114,9 +1113,9 @@ ServerLoop(void)
 	int			nSockets;
 	time_t		now,
 				last_touch_time;
-	struct timeval earlier,
+	struct 		timeval earlier,
 				later;
-	struct timezone tz;
+	struct 		timezone tz;
 
 	gettimeofday(&earlier, &tz);
 	last_touch_time = time(NULL);
@@ -1220,6 +1219,35 @@ ServerLoop(void)
 				kill(BgWriterPID, SIGUSR2);
 		}
 
+		/*
+		 * If no AutoVacuum process is running, and we are not in
+		 * a state that prevents it, start one.  It doesn't matter if this
+		 * fails, we'll just try again later.
+		 */
+		if (autovacuum_start_daemon)
+		{
+			if (pgstat_collect_tuplelevel)
+			{
+				if (AutoVacPID == 0 && StartupPID == 0 && !FatalError)
+				{
+					AutoVacPID = StartAutoVac();
+					if(pgstat_collect_resetonpmstart)
+						elog(WARNING,"pg_autovacuum: stats_reset_on_server_start should be disabled for optimal performance");
+					
+					/* If shutdown is pending, set it going */
+					if (Shutdown > NoShutdown && AutoVacPID != 0)
+						kill(AutoVacPID, SIGUSR2);
+				}
+			}
+			else
+				elog(WARNING, "pg_autovacuum: autovac is enabled, but requires stats_row_level which is not enabled");
+		}	
+		else if(AutoVacPID > 0)
+			kill(AutoVacPID, SIGUSR2);
+			
+		if (!autovacuum_start_daemon)
+			elog(DEBUG1, "pg_autovacuum: not enabled");
+			
 		/* If we have lost the archiver, try to start a new one */
 		if (XLogArchivingActive() && PgArchPID == 0 && 
             StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
@@ -1587,6 +1615,21 @@ processCancelRequest(Port *port, void *pkt)
 	backendPID = (int) ntohl(canc->backendPID);
 	cancelAuthCode = (long) ntohl(canc->cancelAuthCode);
 
+	if (backendPID == BgWriterPID)
+	{
+		ereport(DEBUG2,
+				(errmsg_internal("ignoring cancel request for bgwriter process %d",
+								 backendPID)));
+		return;
+	}
+	if (backendPID == AutoVacPID)
+	{
+		ereport(DEBUG2,
+				(errmsg_internal("ignoring cancel request for autovacuum process %d",
+								 backendPID)));
+		return;
+	}
+
 	/*
 	 * See if we have a matching backend.  In the EXEC_BACKEND case, we
 	 * can no longer access the postmaster's own backend list, and must
@@ -1770,6 +1813,8 @@ SIGHUP_handler(SIGNAL_ARGS)
 			kill(BgWriterPID, SIGHUP);
 		if (PgArchPID != 0)
 			kill(PgArchPID, SIGHUP);
+		if (AutoVacPID != 0)
+			kill(AutoVacPID, SIGHUP);
 		/* PgStatPID does not currently need SIGHUP */
 		load_hba();
 		load_ident();
@@ -1831,6 +1876,10 @@ pmdie(SIGNAL_ARGS)
 			/* Tell pgarch to shut down too; nothing left for it to do */
 			if (PgArchPID != 0)
 				kill(PgArchPID, SIGQUIT);
+			/* I don't think we need to Start the autovac process if not running */
+			/* And tell it to shut down */
+			if (AutoVacPID != 0)
+				kill(AutoVacPID, SIGUSR2);
 			/* Tell pgstat to shut down too; nothing left for it to do */
 			if (PgStatPID != 0)
 				kill(PgStatPID, SIGQUIT);
@@ -1878,6 +1927,9 @@ pmdie(SIGNAL_ARGS)
 			/* Tell pgarch to shut down too; nothing left for it to do */
 			if (PgArchPID != 0)
 				kill(PgArchPID, SIGQUIT);
+			/* And tell it to shut down */
+			if (AutoVacPID != 0)
+				kill(AutoVacPID, SIGUSR2);
 			/* Tell pgstat to shut down too; nothing left for it to do */
 			if (PgStatPID != 0)
 				kill(PgStatPID, SIGQUIT);
@@ -1898,6 +1950,8 @@ pmdie(SIGNAL_ARGS)
 				kill(BgWriterPID, SIGQUIT);
 			if (PgArchPID != 0)
 				kill(PgArchPID, SIGQUIT);
+			if (AutoVacPID != 0)
+				kill(AutoVacPID, SIGQUIT);
 			if (PgStatPID != 0)
 				kill(PgStatPID, SIGQUIT);
 			if (DLGetHead(BackendList))
@@ -2040,9 +2094,35 @@ reaper(SIGNAL_ARGS)
 			if (XLogArchivingActive() &&
 				StartupPID == 0 && !FatalError && Shutdown == NoShutdown)
 				PgArchPID = pgarch_start();
+			/*
+			 * Shutdown autovac if a shutdown request was pending.
+			 */
+			if (Shutdown > NoShutdown && AutoVacPID != 0)
+				kill(AutoVacPID, SIGUSR2);
+
 			continue;
 		}
 
+		/*
+		 * Was it the autovac?
+		 */
+		if (AutoVacPID != 0 && pid == AutoVacPID)
+		{
+			AutoVacPID = 0;
+			if (exitstatus != 0)
+			{
+				/*
+				* Any unexpected exit of the autovacuum is treated as a crash.
+				* FIXME: This is useful for debugging autovac, but I think it should be 
+				* ripped out before final patch, autovac shouldn't crash the postmaster
+				*/
+				LogChildExit(LOG, gettext("pg_autovacuum process"),
+							pid, exitstatus);
+				HandleChildCrash(pid, exitstatus);
+				continue;
+			}
+		}
+		
 		/*
 		 * Was it the statistics collector?  If so, just try to start a new
 		 * one; no need to force reset of the rest of the system.  (If fail,
@@ -2072,7 +2152,7 @@ reaper(SIGNAL_ARGS)
 		 * StartupDataBase.  (We can ignore the archiver and stats processes
 		 * here since they are not connected to shmem.)
 		 */
-		if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0)
+		if (DLGetHead(BackendList) || StartupPID != 0 || BgWriterPID != 0 || AutoVacPID != 0)
 			goto reaper_done;
 		ereport(LOG,
 			(errmsg("all server processes terminated; reinitializing")));
@@ -2095,6 +2175,9 @@ reaper(SIGNAL_ARGS)
 		/* And tell it to shut down */
 		if (BgWriterPID != 0)
 			kill(BgWriterPID, SIGUSR2);
+		/* Tell AutoVac to shut down */
+		if (AutoVacPID != 0)
+			kill(AutoVacPID, SIGUSR2);
 	}
 
 reaper_done:
@@ -2254,6 +2337,20 @@ HandleChildCrash(int pid,
 	}
 
 	FatalError = true;
+
+	/* Take care of the autovacuum too */
+	if (pid == AutoVacPID)
+		AutoVacPID = 0;
+	else if (AutoVacPID != 0 && !FatalError)
+	{
+		ereport(DEBUG2,
+				(errmsg_internal("sending %s to process %d",
+								 (SendStop ? "SIGSTOP" : "SIGQUIT"),
+								 (int) AutoVacPID)));
+		kill(AutoVacPID, (SendStop ? SIGSTOP : SIGQUIT));
+	}
+
+	FatalError = true;
 }
 
 /*
@@ -3240,6 +3337,10 @@ StartChildProcess(int xlop)
 				ereport(LOG,
 						(errmsg("could not fork background writer process: %m")));
 				break;
+			case BS_XLOG_AUTOVAC:
+				ereport(LOG,
+						(errmsg("could not fork auto vacuum process: %m")));
+				break;
 			default:
 				ereport(LOG,
 						(errmsg("could not fork process: %m")));
@@ -3294,6 +3395,24 @@ CreateOptsFile(int argc, char *argv[], char *fullprogname)
 	return true;
 }
 
+/*
+ * This should be used only for reporting "interactive" errors (essentially,
+ * bogus arguments on the command line).  Once the postmaster is launched,
+ * use ereport.  In particular, don't use this for anything that occurs
+ * after pmdaemonize.
+ */
+static void
+postmaster_error(const char *fmt,...)
+{
+	va_list		ap;
+
+	fprintf(stderr, "%s: ", progname);
+	va_start(ap, fmt);
+	vfprintf(stderr, gettext(fmt), ap);
+	va_end(ap);
+	fprintf(stderr, "\n");
+}
+
 
 #ifdef EXEC_BACKEND
 
@@ -3733,7 +3852,7 @@ win32_sigchld_waiter(LPVOID param)
 	if (r == WAIT_OBJECT_0)
 		pg_queue_signal(SIGCHLD);
 	else
-		write_stderr("ERROR: failed to wait on child process handle: %d\n",
+		fprintf(stderr, "ERROR: failed to wait on child process handle: %d\n",
 				(int) GetLastError());
 	CloseHandle(procHandle);
 	return 0;
diff --git a/src/backend/utils/misc/guc.c b/src/backend/utils/misc/guc.c
index bc723e19606ef7107eccf861e28a6c0aa7ab24d5..ca0deb86c118365f1be375b286e0113105cf795c 100644
--- a/src/backend/utils/misc/guc.c
+++ b/src/backend/utils/misc/guc.c
@@ -10,7 +10,7 @@
  * Written by Peter Eisentraut <peter_e@gmx.net>.
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.221 2004/07/19 21:39:47 momjian Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/misc/guc.c,v 1.222 2004/07/21 20:23:01 momjian Exp $
  *
  *--------------------------------------------------------------------
  */
@@ -43,7 +43,9 @@
 #include "optimizer/prep.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
+#include "pgstat.h"
 #include "postmaster/bgwriter.h"
+#include "postmaster/pg_autovacuum.h"
 #include "postmaster/postmaster.h"
 #include "storage/bufmgr.h"
 #include "storage/fd.h"
@@ -55,7 +57,6 @@
 #include "utils/builtins.h"
 #include "utils/memutils.h"
 #include "utils/pg_locale.h"
-#include "pgstat.h"
 
 char *guc_pgdata;
 char *guc_hbafile;
@@ -642,6 +643,14 @@ static struct config_bool ConfigureNamesBool[] =
 		&pgstat_collect_blocklevel,
 		false, NULL, NULL
 	},
+	{
+		{"autovacuum", PGC_SIGHUP, AUTOVACUUM,
+			gettext_noop("Starts the auto vacuum subprocess."),
+			NULL
+		},
+		&autovacuum_start_daemon,
+		false, NULL, NULL	 
+	},
 
 	{
 		{"trace_notify", PGC_USERSET, DEVELOPER_OPTIONS,
@@ -1284,6 +1293,30 @@ static struct config_int ConfigureNamesInt[] =
 		&block_size,
 		BLCKSZ, BLCKSZ, BLCKSZ, NULL, NULL
 	},
+	{
+		{"autovacuum_vacuum_threshold_base", PGC_SIGHUP, AUTOVACUUM,
+			gettext_noop("Minimum number of tuple updates or deletes prior to vacuum."),
+			NULL
+		},
+		&autovacuum_vacuum_base,
+		1000, 0, INT_MAX, NULL, NULL
+	},
+	{
+		{"autovacuum_analyze_threshold_base", PGC_SIGHUP, AUTOVACUUM,
+			gettext_noop("Minimum number of tuple updates or deletes prior to analyze."),
+			NULL
+		},
+		&autovacuum_analyze_base,
+		500, 0, INT_MAX, NULL, NULL
+	},
+	{
+		{"autovacuum_naptime", PGC_SIGHUP, AUTOVACUUM,
+			gettext_noop("Minimum number of tuple updates or deletes prior to analyze."),
+			NULL
+		},
+		&autovacuum_analyze_base,
+		500, 0, INT_MAX, NULL, NULL
+	},
 
 	/* End-of-list marker */
 	{
@@ -1364,6 +1397,22 @@ static struct config_real ConfigureNamesReal[] =
 		&phony_random_seed,
 		0.5, 0.0, 1.0, assign_random_seed, show_random_seed
 	},
+	{
+		{"autovacuum_vacuum_threshold_sf", PGC_SIGHUP, AUTOVACUUM,
+			gettext_noop("Numer of tuple updates or deletes prior to vacuum as a factor of reltuples."),
+			NULL
+		},
+		&autovacuum_vacuum_scaling_factor,
+		2, 0, 100, NULL, NULL
+	},
+	{
+		{"autovacuum_analyze_threshold_sf", PGC_SIGHUP, AUTOVACUUM,
+			gettext_noop("Numer of tuple updates or deletes prior to analyze as a factor of reltuples."),
+			NULL
+		},
+		&autovacuum_analyze_scaling_factor,
+		1, 0, 100, NULL, NULL
+	},
 
 	/* End-of-list marker */
 	{
diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample
index 9dc1ec8d837323d227814062789f9b52c693634e..02c9abbcca34ce8ef8e83271a8c049adbf3b4732 100644
--- a/src/backend/utils/misc/postgresql.conf.sample
+++ b/src/backend/utils/misc/postgresql.conf.sample
@@ -237,6 +237,16 @@
 #stats_reset_on_server_start = true
 
 
+#---------------------------------------------------------------------------
+# VACUUM DAEMON
+#---------------------------------------------------------------------------
+
+#autovacuum = false  # requires stats_row_level = true
+#autovacuum_vacuum_threshold_base = 1000
+#autovacuum_vacuum_threshold_sf = 2
+#autovacuum_analyze_threshold_base = 500
+#autovacuum_analyze_threshold_sf = 1
+
 #---------------------------------------------------------------------------
 # CLIENT CONNECTION DEFAULTS
 #---------------------------------------------------------------------------
diff --git a/src/include/bootstrap/bootstrap.h b/src/include/bootstrap/bootstrap.h
index 21ed48286927ff3470fd93e72000f8ef955f249b..376f6fe447ce4c5fb852ef51580f2149c99d5fd0 100644
--- a/src/include/bootstrap/bootstrap.h
+++ b/src/include/bootstrap/bootstrap.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/bootstrap/bootstrap.h,v 1.35 2004/05/29 22:48:22 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/bootstrap/bootstrap.h,v 1.36 2004/07/21 20:23:03 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -59,5 +59,6 @@ extern void Int_yyerror(const char *str);
 #define BS_XLOG_BOOTSTRAP	1
 #define BS_XLOG_STARTUP		2
 #define BS_XLOG_BGWRITER	3
+#define BS_XLOG_AUTOVAC		4
 
 #endif   /* BOOTSTRAP_H */
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 067d7347866b42da61572e9b672a963a83a8a1fe..8dac1fc362ddb80f49377af00e513723820b05df 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.244 2004/07/12 20:23:51 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.245 2004/07/21 20:23:03 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*							yyyymmddN */
-#define CATALOG_VERSION_NO	200407121
+#define CATALOG_VERSION_NO	200407211
 
 #endif
diff --git a/src/include/postmaster/postmaster.h b/src/include/postmaster/postmaster.h
index 301f7652ffefc70e5b398a0f295dadbb69403679..0b18842133b94df22994d302f1c24434bb6c70ea 100644
--- a/src/include/postmaster/postmaster.h
+++ b/src/include/postmaster/postmaster.h
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/postmaster/postmaster.h,v 1.2 2004/05/30 03:50:15 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/postmaster/postmaster.h,v 1.3 2004/07/21 20:23:04 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -29,6 +29,7 @@ extern char *preload_libraries_string;
 extern bool Log_connections;
 extern bool log_hostname;
 extern char *rendezvous_name;
+extern bool autovacuum_start_daemon; 
 
 #ifdef WIN32
 extern HANDLE PostmasterHandle;
diff --git a/src/include/storage/proc.h b/src/include/storage/proc.h
index 8645fb1fdb55e701a29c558392bd5dc5ed64ad1f..6dec47a2a0fe300faf882fa7a4cca3bc799fdd0d 100644
--- a/src/include/storage/proc.h
+++ b/src/include/storage/proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.69 2004/07/17 03:31:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/storage/proc.h,v 1.70 2004/07/21 20:23:04 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -88,7 +88,8 @@ typedef struct PROC_HDR
 
 #define	DUMMY_PROC_DEFAULT	0
 #define	DUMMY_PROC_BGWRITER	1
-#define	NUM_DUMMY_PROCS		2
+#define	DUMMY_PROC_AUTOVAC	2
+#define	NUM_DUMMY_PROCS		3
 
 
 /* configurable options */
diff --git a/src/include/utils/guc_tables.h b/src/include/utils/guc_tables.h
index d522f6d5e9418097ae31ff5e4fa1570847559a00..b9212060413127603484e8a48067196a702322bf 100644
--- a/src/include/utils/guc_tables.h
+++ b/src/include/utils/guc_tables.h
@@ -7,7 +7,7 @@
  *
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  *
- *	  $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.12 2004/07/01 00:51:44 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/include/utils/guc_tables.h,v 1.13 2004/07/21 20:23:05 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -71,6 +71,7 @@ enum config_group
 	COMPAT_OPTIONS_CLIENT,
 	DEVELOPER_OPTIONS,
 	COMPILE_OPTIONS,
+	AUTOVACUUM,
 	CUSTOM_OPTIONS
 };
 
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index 92548e6f925a44eddd373db8473f583c24b09fb5..4b4a4d08cc337529bb109d4e1efaf014fe12ffa8 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1275,7 +1275,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
          viewname         |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                          definition                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           
 --------------------------+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  iexit                    | SELECT ih.name, ih.thepath, interpt_pp(ih.thepath, r.thepath) AS exit FROM ihighway ih, ramp r WHERE (ih.thepath ## r.thepath);
- pg_indexes               | SELECT n.nspname AS schemaname, c.relname AS tablename, i.relname AS indexname, pg_get_indexdef(i.oid) AS indexdef FROM (((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
+ pg_indexes               | SELECT n.nspname AS schemaname, c.relname AS tablename, t.spcname AS "tablespace", i.relname AS indexname, pg_get_indexdef(i.oid) AS indexdef FROM ((((pg_index x JOIN pg_class c ON ((c.oid = x.indrelid))) JOIN pg_class i ON ((i.oid = x.indexrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace))) WHERE ((c.relkind = 'r'::"char") AND (i.relkind = 'i'::"char"));
  pg_locks                 | SELECT l.relation, l."database", l."transaction", l.pid, l."mode", l.granted FROM pg_lock_status() l(relation oid, "database" oid, "transaction" xid, pid integer, "mode" text, granted boolean);
  pg_rules                 | SELECT n.nspname AS schemaname, c.relname AS tablename, r.rulename, pg_get_ruledef(r.oid) AS definition FROM ((pg_rewrite r JOIN pg_class c ON ((c.oid = r.ev_class))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (r.rulename <> '_RETURN'::name);
  pg_settings              | SELECT a.name, a.setting, a.category, a.short_desc, a.extra_desc, a.context, a.vartype, a.source, a.min_val, a.max_val FROM pg_show_all_settings() a(name text, setting text, category text, short_desc text, extra_desc text, context text, vartype text, source text, min_val text, max_val text);
@@ -1297,7 +1297,7 @@ SELECT viewname, definition FROM pg_views WHERE schemaname <> 'information_schem
  pg_statio_user_sequences | SELECT pg_statio_all_sequences.relid, pg_statio_all_sequences.schemaname, pg_statio_all_sequences.relname, pg_statio_all_sequences.blks_read, pg_statio_all_sequences.blks_hit FROM pg_statio_all_sequences WHERE (((pg_statio_all_sequences.schemaname <> 'pg_catalog'::name) AND (pg_statio_all_sequences.schemaname <> 'pg_toast'::name)) AND (pg_statio_all_sequences.schemaname <> 'information_schema'::name));
  pg_statio_user_tables    | SELECT pg_statio_all_tables.relid, pg_statio_all_tables.schemaname, pg_statio_all_tables.relname, pg_statio_all_tables.heap_blks_read, pg_statio_all_tables.heap_blks_hit, pg_statio_all_tables.idx_blks_read, pg_statio_all_tables.idx_blks_hit, pg_statio_all_tables.toast_blks_read, pg_statio_all_tables.toast_blks_hit, pg_statio_all_tables.tidx_blks_read, pg_statio_all_tables.tidx_blks_hit FROM pg_statio_all_tables WHERE (((pg_statio_all_tables.schemaname <> 'pg_catalog'::name) AND (pg_statio_all_tables.schemaname <> 'pg_toast'::name)) AND (pg_statio_all_tables.schemaname <> 'information_schema'::name));
  pg_stats                 | SELECT nspname AS schemaname, relname AS tablename, attname, stanullfrac AS null_frac, stawidth AS avg_width, stadistinct AS n_distinct, CASE 1 WHEN stakind1 THEN stavalues1 WHEN stakind2 THEN stavalues2 WHEN stakind3 THEN stavalues3 WHEN stakind4 THEN stavalues4 ELSE NULL::"unknown" END AS most_common_vals, CASE 1 WHEN stakind1 THEN stanumbers1 WHEN stakind2 THEN stanumbers2 WHEN stakind3 THEN stanumbers3 WHEN stakind4 THEN stanumbers4 ELSE NULL::real[] END AS most_common_freqs, CASE 2 WHEN stakind1 THEN stavalues1 WHEN stakind2 THEN stavalues2 WHEN stakind3 THEN stavalues3 WHEN stakind4 THEN stavalues4 ELSE NULL::"unknown" END AS histogram_bounds, CASE 3 WHEN stakind1 THEN stanumbers1[1] WHEN stakind2 THEN stanumbers2[1] WHEN stakind3 THEN stanumbers3[1] WHEN stakind4 THEN stanumbers4[1] ELSE NULL::real END AS correlation FROM (((pg_statistic s JOIN pg_class c ON ((c.oid = s.starelid))) JOIN pg_attribute a ON (((c.oid = a.attrelid) AND (a.attnum = s.staattnum)))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE has_table_privilege(c.oid, 'select'::text);
- pg_tables                | SELECT n.nspname AS schemaname, c.relname AS tablename, pg_get_userbyid(c.relowner) AS tableowner, c.relhasindex AS hasindexes, c.relhasrules AS hasrules, (c.reltriggers > 0) AS hastriggers FROM (pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'r'::"char");
+ pg_tables                | SELECT n.nspname AS schemaname, c.relname AS tablename, t.spcname AS "tablespace", pg_get_userbyid(c.relowner) AS tableowner, c.relhasindex AS hasindexes, c.relhasrules AS hasrules, (c.reltriggers > 0) AS hastriggers FROM ((pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace))) WHERE (c.relkind = 'r'::"char");
  pg_user                  | SELECT pg_shadow.usename, pg_shadow.usesysid, pg_shadow.usecreatedb, pg_shadow.usesuper, pg_shadow.usecatupd, '********'::text AS passwd, pg_shadow.valuntil, pg_shadow.useconfig FROM pg_shadow;
  pg_views                 | SELECT n.nspname AS schemaname, c.relname AS viewname, pg_get_userbyid(c.relowner) AS viewowner, pg_get_viewdef(c.oid) AS definition FROM (pg_class c LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))) WHERE (c.relkind = 'v'::"char");
  rtest_v1                 | SELECT rtest_t1.a, rtest_t1.b FROM rtest_t1;