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;