From 6bd356c33a3cf3a49313dc8638ea4bb066c4cf37 Mon Sep 17 00:00:00 2001 From: Stephen Frost Date: Fri, 6 May 2016 14:06:50 -0400 Subject: [PATCH] Add TAP tests for pg_dump This TAP test suite will create a new cluster, populate it based on the 'create_sql' values in the '%tests' hash, run all of the runs defined in the '%pgdump_runs' hash, and then for each test in the '%tests' hash, compare each run's output the the regular expression defined for the test under the 'like' and 'unlike' functions, as appropriate. While this test suite covers a fair bit of ground (67% of pg_dump.c and quite a bit of the other files in src/bin/pg_dump), there is still quite a bit which remains to be added to provide better code coverage. Still, this is quite a bit better than we had, and has found a few bugs already (note that the CREATE TRANSFORM test is commented out, as it is currently failing). Idea for using the TAP system from Tom, though all of the code is mine. --- src/bin/pg_dump/Makefile | 3 + src/bin/pg_dump/pg_dump.c | 2 +- src/bin/pg_dump/t/001_basic.pl | 42 + src/bin/pg_dump/t/002_pg_dump.pl | 2859 +++++++++++++++++ src/test/modules/Makefile | 1 + src/test/modules/test_pg_dump/.gitignore | 4 + src/test/modules/test_pg_dump/Makefile | 25 + src/test/modules/test_pg_dump/README | 2 + .../test_pg_dump/expected/test_pg_dump.out | 6 + .../modules/test_pg_dump/sql/test_pg_dump.sql | 1 + src/test/modules/test_pg_dump/t/001_base.pl | 535 +++ .../test_pg_dump/test_pg_dump--1.0.sql | 15 + .../modules/test_pg_dump/test_pg_dump.control | 3 + 13 files changed, 3497 insertions(+), 1 deletion(-) create mode 100644 src/bin/pg_dump/t/001_basic.pl create mode 100644 src/bin/pg_dump/t/002_pg_dump.pl create mode 100644 src/test/modules/test_pg_dump/.gitignore create mode 100644 src/test/modules/test_pg_dump/Makefile create mode 100644 src/test/modules/test_pg_dump/README create mode 100644 src/test/modules/test_pg_dump/expected/test_pg_dump.out create mode 100644 src/test/modules/test_pg_dump/sql/test_pg_dump.sql create mode 100644 src/test/modules/test_pg_dump/t/001_base.pl create mode 100644 src/test/modules/test_pg_dump/test_pg_dump--1.0.sql create mode 100644 src/test/modules/test_pg_dump/test_pg_dump.control diff --git a/src/bin/pg_dump/Makefile b/src/bin/pg_dump/Makefile index 95967893d8..260804b5a7 100644 --- a/src/bin/pg_dump/Makefile +++ b/src/bin/pg_dump/Makefile @@ -42,6 +42,9 @@ install: all installdirs installdirs: $(MKDIR_P) '$(DESTDIR)$(bindir)' +check: + $(prove_check) + uninstall: rm -f $(addprefix '$(DESTDIR)$(bindir)'/, pg_dump$(X) pg_restore$(X) pg_dumpall$(X)) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 6e2610fa3f..1267afbce9 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -1564,7 +1564,7 @@ selectDumpableExtension(ExtensionInfo *extinfo, DumpOptions *dopt) * those changes preserved. */ if (dopt->binary_upgrade && extinfo->dobj.catId.oid < (Oid) FirstNormalObjectId) - extinfo->dobj.dump = DUMP_COMPONENT_ACL; + extinfo->dobj.dump = extinfo->dobj.dump_contains = DUMP_COMPONENT_ACL; else extinfo->dobj.dump = extinfo->dobj.dump_contains = dopt->include_everything ? DUMP_COMPONENT_ALL : diff --git a/src/bin/pg_dump/t/001_basic.pl b/src/bin/pg_dump/t/001_basic.pl new file mode 100644 index 0000000000..1411ef7a27 --- /dev/null +++ b/src/bin/pg_dump/t/001_basic.pl @@ -0,0 +1,42 @@ +use strict; +use warnings; + +use Config; +use PostgresNode; +use TestLib; +use Test::More tests => 15; + +my $tempdir = TestLib::tempdir; +my $tempdir_short = TestLib::tempdir_short; + +######################################### +# Basic checks + +program_help_ok('pg_dump'); +program_version_ok('pg_dump'); +program_options_handling_ok('pg_dump'); + +######################################### +# Test various invalid options and disallowed combinations +# Doesn't require a PG instance to be set up, so do this first. + +command_exit_is([ 'pg_dump', 'qqq', 'abc' ], + 1, 'pg_dump: too many command-line arguments (first is "asd")'); + +command_exit_is([ 'pg_dump', '-s', '-a' ], + 1, 'pg_dump: options -s/--schema-only and -a/--data-only cannot be used together'); + +command_exit_is([ 'pg_dump', '-c', '-a' ], + 1, 'pg_dump: options -c/--clean and -a/--data-only cannot be used together'); + +command_exit_is([ 'pg_dump', '--inserts', '-o' ], + 1, 'pg_dump: options --inserts/--column-inserts and -o/--oids cannot be used together'); + +command_exit_is([ 'pg_dump', '--if-exists' ], + 1, 'pg_dump: option --if-exists requires option -c/--clean'); + +command_exit_is([ 'pg_dump', '-j' ], + 1, 'pg_dump: option requires an argument -- \'j\''); + +command_exit_is([ 'pg_dump', '-j3' ], + 1, 'pg_dump: parallel backup only supported by the directory format'); diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl new file mode 100644 index 0000000000..4270042250 --- /dev/null +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -0,0 +1,2859 @@ +use strict; +use warnings; + +use Config; +use PostgresNode; +use TestLib; +use Test::More; + +my $tempdir = TestLib::tempdir; +my $tempdir_short = TestLib::tempdir_short; + +############################################################### +# Definition of the pg_dump runs to make. +# +# Each of these runs are named and those names are used below +# to define how each test should (or shouldn't) treat a result +# from a given run. +# +# test_key indicates that a given run should simply use the same +# set of like/unlike tests as another run, and which run that is. +# +# dump_cmd is the pg_dump command to run, which is an array of +# the full command and arguments to run. Note that this is run +# using $node->command_ok(), so the port does not need to be +# specified and is pulled from $PGPORT, which is set by the +# PostgresNode system. +# +# restore_cmd is the pg_restore command to run, if any. Note +# that this should generally be used when the pg_dump goes to +# a non-text file and that the restore can then be used to +# generate a text file to run through the tests from the +# non-text file generated by pg_dump. +# +# TODO: Have pg_restore actually restore to an independent +# database and then pg_dump *that* database (or something along +# those lines) to validate that part of the process. + +my %pgdump_runs = ( + binary_upgrade => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/binary_upgrade.sql", + '--schema-only', + '--binary-upgrade', + '-d', 'postgres', # alternative way to specify database + ], + }, + clean => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/clean.sql", + '-c', + '-d', 'postgres', # alternative way to specify database + ], + }, + clean_if_exists => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/clean_if_exists.sql", + '-c', + '--if-exists', + '-E', 'UTF8', # no-op, just tests that option is accepted + 'postgres', + ], + }, + column_inserts => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/column_inserts.sql", + '-a', + '--column-inserts', + 'postgres', + ], + }, + createdb => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/createdb.sql", + '-C', + '-R', # no-op, just for testing + 'postgres', + ], + }, + data_only => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/data_only.sql", + '-a', + '-v', # no-op, just make sure it works + 'postgres', + ], + }, + defaults => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/defaults.sql", + 'postgres', + ], + }, + defaults_custom_format => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', + '-Fc', + '-Z6', + '-f', "$tempdir/defaults_custom_format.dump", + 'postgres', + ], + restore_cmd => [ + 'pg_restore', + '-f', "$tempdir/defaults_custom_format.sql", + "$tempdir/defaults_custom_format.dump", + ], + }, + defaults_dir_format => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', + '-Fd', + '-f', "$tempdir/defaults_dir_format", + 'postgres', + ], + restore_cmd => [ + 'pg_restore', + '-f', "$tempdir/defaults_dir_format.sql", + "$tempdir/defaults_dir_format", + ], + }, + defaults_parallel => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', + '-Fd', + '-j2', + '-f', "$tempdir/defaults_parallel", + 'postgres', + ], + restore_cmd => [ + 'pg_restore', + '-f', "$tempdir/defaults_parallel.sql", + "$tempdir/defaults_parallel", + ], + }, + defaults_tar_format => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', + '-Ft', + '-f', "$tempdir/defaults_tar_format.tar", + 'postgres', + ], + restore_cmd => [ + 'pg_restore', + '-f', "$tempdir/defaults_tar_format.sql", + "$tempdir/defaults_tar_format.tar", + ], + }, + exclude_dump_test_schema => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/exclude_dump_test_schema.sql", + '-N', 'dump_test', + 'postgres', + ], + }, + exclude_test_table => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/exclude_test_table.sql", + '-T', 'dump_test.test_table', + 'postgres', + ], + }, + exclude_test_table_data => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/exclude_test_table_data.sql", + '--exclude-table-data=dump_test.test_table', + 'postgres', + ], + }, + pg_dumpall_globals => { + dump_cmd => [ + 'pg_dumpall', + '-f', "$tempdir/pg_dumpall_globals.sql", + '-g', + ], + }, + no_privs => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/no_privs.sql", + '-x', + 'postgres', + ], + }, + no_owner => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/no_owner.sql", + '-O', + 'postgres', + ], + }, + only_dump_test_schema => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/only_dump_test_schema.sql", + '-n', 'dump_test', + 'postgres', + ], + }, + only_dump_test_table => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/only_dump_test_table.sql", + '-t', 'dump_test.test_table', + '--lock-wait-timeout=1000000', + 'postgres', + ], + }, + role => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/role.sql", + '--role=dump_test', + '--schema=dump_test_second_schema', + 'postgres', + ], + }, + schema_only => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/schema_only.sql", + '-s', + 'postgres', + ], + }, + section_pre_data => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/section_pre_data.sql", + '--section=pre-data', + 'postgres', + ], + }, + section_data => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/section_data.sql", + '--section=data', + 'postgres', + ], + }, + section_post_data => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/section_post_data.sql", + '--section=post-data', + 'postgres', + ], + }, + test_schema_plus_blobs => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/test_schema_plus_blobs.sql", + '-n', 'dump_test', + '-b', + 'postgres', + ], + }, +); + +############################################################### +# Definition of the tests to run. +# +# Each test is defined using the log message that will be used. +# +# A regexp should be defined for each test which provides the +# basis for the test. That regexp will be run against the output +# file of each of the runs which the test is to be run against +# and the success of the result will depend on if the regexp +# result matches the expected 'like' or 'unlike' case. +# +# For each test, there are two sets of runs defined, one for +# the 'like' tests and one for the 'unlike' tests. 'like' +# essentially means "the regexp for this test must match the +# output file". 'unlike' is the opposite. +# +# There are a few 'catch-all' tests which can be used to have +# a single, simple, test to over a range of other tests. For +# example, there is a '^CREATE ' test, which is used for the +# 'data-only' test as there should never be any kind of CREATE +# statement in a 'data-only' run. Without the catch-all, we +# would have to list the 'data-only' run in each and every +# 'CREATE xxxx' test, which would be a lot of additional tests. +# +# Note that it makes no sense for the same run to ever be listed +# in both 'like' and 'unlike' categories. +# +# There can then be a 'create_sql' and 'create_order' for a +# given test. The 'create_sql' commands are collected up in +# 'create_order' and then run against the database prior to any +# of the pg_dump runs happening. This is what "seeds" the +# system with objects to be dumped out. +# +# Building of this hash takes a bit of time as all of the regexps +# included in it are compiled. This greatly improves performance +# as the regexps are used for each run the test applies to. + +my %tests = ( + 'ALTER DEFAULT PRIVILEGES FOR ROLE dump_test' => { + create_order => 14, + create_sql => 'ALTER DEFAULT PRIVILEGES + FOR ROLE dump_test IN SCHEMA dump_test + GRANT SELECT ON TABLES TO dump_test;', + regexp => qr/^ + \QALTER DEFAULT PRIVILEGES \E + \QFOR ROLE dump_test IN SCHEMA dump_test \E + \QGRANT SELECT ON TABLES TO dump_test;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + no_privs => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_pre_data => 1, + section_data => 1, + }, + }, + 'ALTER ROLE dump_test' => { + regexp => qr/^ + \QALTER ROLE dump_test WITH \E + \QNOSUPERUSER INHERIT NOCREATEROLE NOCREATEDB NOLOGIN \E + \QNOREPLICATION NOBYPASSRLS;\E + $/xm, + like => { + pg_dumpall_globals => 1, + }, + unlike => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + }, + 'ALTER FUNCTION dump_test.pltestlang_call_handler() OWNER TO' => { + regexp => qr/^ + \QALTER FUNCTION dump_test.pltestlang_call_handler() \E + \QOWNER TO \E + .*;$/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + }, + }, + 'ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO' => { + regexp => qr/^ALTER PROCEDURAL LANGUAGE pltestlang OWNER TO .*;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'ALTER SCHEMA dump_test OWNER TO' => { + regexp => qr/^ALTER SCHEMA dump_test OWNER TO .*;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + }, + }, + 'ALTER SCHEMA dump_test_second_schema OWNER TO' => { + regexp => qr/^ALTER SCHEMA dump_test_second_schema OWNER TO .*;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'ALTER TABLE ONLY test_table ADD CONSTRAINT ... PRIMARY KEY' => { + regexp => qr/^ + \QALTER TABLE ONLY test_table\E \n^\s+ + \QADD CONSTRAINT test_table_pkey PRIMARY KEY (col1);\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + section_pre_data => 1, + section_data => 1, + }, + }, + 'ALTER TABLE test_table OWNER TO' => { + regexp => qr/^ALTER TABLE test_table OWNER TO .*;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + exclude_test_table => 1, + }, + }, + 'ALTER TABLE test_table ENABLE ROW LEVEL SECURITY' => { + create_order => 23, + create_sql => 'ALTER TABLE dump_test.test_table + ENABLE ROW LEVEL SECURITY;', + regexp => qr/^ALTER TABLE test_table ENABLE ROW LEVEL SECURITY;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + section_pre_data => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + }, + }, + 'ALTER TABLE test_second_table OWNER TO' => { + regexp => qr/^ALTER TABLE test_second_table OWNER TO .*;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + }, + }, + 'ALTER TABLE test_third_table OWNER TO' => { + regexp => qr/^ALTER TABLE test_third_table OWNER TO .*;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + # catch-all for ALTER ... OWNER (except LARGE OBJECTs) + 'ALTER ... OWNER commands (except LARGE OBJECTs)' => { + regexp => qr/^ALTER (?!LARGE OBJECT)(.*) OWNER TO .*;$/m, + like => { }, # use more-specific options above + unlike => { + column_inserts => 1, + data_only => 1, + section_data => 1, + }, + }, + # catch-all for ALTER ... OWNER + 'ALTER ... OWNER commands' => { + regexp => qr/^ALTER .* OWNER TO .*;$/m, + like => { }, # use more-specific options above + unlike => { + no_owner => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'BLOB load (contents are of test_table)' => { + create_order => 14, + create_sql => + "\\o '$tempdir/large_object_test.sql'\n" + . "table dump_test.test_table;\n" + . "\\o\n" + . "\\lo_import '$tempdir/large_object_test.sql'\n", + regexp => qr/^ + \QSELECT pg_catalog.lo_open\E \('\d+',\ \d+\);\n + \QSELECT pg_catalog.lowrite(0, \E + \Q'\x310a320a330a340a350a360a370a380a390a');\E\n + \QSELECT pg_catalog.lo_close(0);\E + $/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + section_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + binary_upgrade => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_post_data => 1, + }, + }, + 'COMMENT ON DATABASE postgres' => { + regexp => qr/^COMMENT ON DATABASE postgres IS .*;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + }, + }, + 'COMMENT ON EXTENSION plpgsql' => { + regexp => qr/^COMMENT ON EXTENSION plpgsql IS .*;$/m, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + binary_upgrade => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + }, + }, + 'COMMENT ON TABLE dump_test.test_table' => { + create_order => 36, + create_sql => 'COMMENT ON TABLE dump_test.test_table + IS \'comment on table\';', + regexp => qr/^COMMENT ON TABLE test_table IS 'comment on table';$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + exclude_test_table => 1, + }, + }, + 'COMMENT ON COLUMN dump_test.test_table.col1' => { + create_order => 36, + create_sql => 'COMMENT ON COLUMN dump_test.test_table.col1 + IS \'comment on column\';', + regexp => qr/^ + \QCOMMENT ON COLUMN test_table.col1 IS 'comment on column';\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + exclude_test_table => 1, + }, + }, + 'COMMENT ON COLUMN dump_test.composite.f1' => { + create_order => 44, + create_sql => 'COMMENT ON COLUMN dump_test.composite.f1 + IS \'comment on column of type\';', + regexp => qr/^ + \QCOMMENT ON COLUMN composite.f1 IS 'comment on column of type';\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + }, + }, + # catch-all for COMMENTs + 'COMMENT commands' => { + regexp => qr/^COMMENT ON /m, + like => { }, # use more-specific options above + unlike => { + column_inserts => 1, + data_only => 1, + pg_dumpall_globals => 1, + section_data => 1, + section_post_data => 1, + }, + }, + 'COPY test_table' => { + create_order => 4, + create_sql => + 'INSERT INTO dump_test.test_table (col1) ' + . 'SELECT generate_series FROM generate_series(1,9);', + regexp => qr/^ + \QCOPY test_table (col1) FROM stdin;\E + \n(?:\d\n){9}\\\.\n + $/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + data_only => 1, + defaults => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + section_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + }, + }, + 'COPY fk_reference_test_table' => { + create_order => 22, + create_sql => + 'INSERT INTO dump_test.fk_reference_test_table (col1) ' + . 'SELECT generate_series FROM generate_series(1,5);', + regexp => qr/^ + \QCOPY fk_reference_test_table (col1) FROM stdin;\E + \n(?:\d\n){5}\\\.\n + $/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + data_only => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + section_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + }, + }, + 'COPY fk_reference_test_table second' => { + regexp => qr/^ + \QCOPY test_table (col1) FROM stdin;\E + \n(?:\d\n){9}\\\.\n.* + \QCOPY fk_reference_test_table (col1) FROM stdin;\E + \n(?:\d\n){5}\\\.\n + $/xms, + like => { + data_only => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + }, + }, + 'COPY test_second_table' => { + create_order => 7, + create_sql => + 'INSERT INTO dump_test.test_second_table (col1, col2) ' + . 'SELECT generate_series, generate_series::text ' + . 'FROM generate_series(1,9);', + regexp => qr/^ + \QCOPY test_second_table (col1, col2) FROM stdin;\E + \n(?:\d\t\d\n){9}\\\.\n + $/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + data_only => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + section_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + }, + }, + 'COPY test_third_table' => { + create_order => 12, + create_sql => + 'INSERT INTO dump_test_second_schema.test_third_table (col1) ' + . 'SELECT generate_series FROM generate_series(1,9);', + regexp => qr/^ + \QCOPY test_third_table (col1) FROM stdin;\E + \n(?:\d\n){9}\\\.\n + $/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + data_only => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + section_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'INSERT INTO test_table' => { + regexp => qr/^ + (?:INSERT\ INTO\ test_table\ \(col1\)\ VALUES\ \(\d\);\n){9} + $/xm, + like => { + column_inserts => 1, + }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + data_only => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + section_data => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'INSERT INTO test_second_table' => { + regexp => qr/^ + (?:INSERT\ INTO\ test_second_table\ \(col1,\ col2\) + \ VALUES\ \(\d,\ '\d'\);\n){9}$/xm, + like => { + column_inserts => 1, + }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + data_only => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + section_data => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'INSERT INTO test_third_table' => { + regexp => qr/^ + (?:INSERT\ INTO\ test_third_table\ \(col1\) + \ VALUES\ \(\d\);\n){9}$/xm, + like => { + column_inserts => 1, + }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + data_only => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + section_data => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'COPY ... commands' => { # catch-all for COPY + regexp => qr/^COPY /m, + like => { }, # use more-specific options above + unlike => { + binary_upgrade => 1, + column_inserts => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_post_data => 1, + }, + }, + 'CREATE ROLE dump_test' => { + create_order => 1, + create_sql => 'CREATE ROLE dump_test;', + regexp => qr/^CREATE ROLE dump_test;$/m, + like => { + pg_dumpall_globals => 1, + }, + unlike => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + }, + 'CREATE DATABASE postgres' => { + regexp => qr/^ + \QCREATE DATABASE postgres WITH TEMPLATE = template0 \E + .*;$/xm, + like => { + createdb => 1, + }, + unlike => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + }, + 'CREATE EXTENSION ... plpgsql' => { + regexp => qr/^ + \QCREATE EXTENSION IF NOT EXISTS plpgsql WITH SCHEMA pg_catalog;\E + $/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + binary_upgrade => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + }, + 'CREATE AGGREGATE dump_test.newavg' => { + create_order => 25, + create_sql => 'CREATE AGGREGATE dump_test.newavg ( + sfunc = int4_avg_accum, + basetype = int4, + stype = _int8, + finalfunc = int8_avg, + initcond1 = \'{0,0}\' + );', + regexp => qr/^ + \QCREATE AGGREGATE newavg(integer) (\E + \n\s+\QSFUNC = int4_avg_accum,\E + \n\s+\QSTYPE = bigint[],\E + \n\s+\QINITCOND = '{0,0}',\E + \n\s+\QFINALFUNC = int8_avg\E + \n\);$/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE DOMAIN dump_test.us_postal_code' => { + create_order => 29, + create_sql => 'CREATE DOMAIN dump_test.us_postal_code AS TEXT + CHECK(VALUE ~ \'^\d{5}$\' OR + VALUE ~ \'^\d{5}-\d{4}$\');', + regexp => qr/^ + \QCREATE DOMAIN us_postal_code AS text\E + \n\s+ + \QCONSTRAINT us_postal_code_check CHECK \E + \Q(((VALUE ~ '^\d{5}\E + \$\Q'::text) OR (VALUE ~ '^\d{5}-\d{4}\E\$ + \Q'::text)));\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE FUNCTION dump_test.pltestlang_call_handler' => { + create_order => 17, + create_sql => 'CREATE FUNCTION dump_test.pltestlang_call_handler() + RETURNS LANGUAGE_HANDLER AS \'$libdir/plpgsql\', + \'plpgsql_call_handler\' LANGUAGE C;', + regexp => qr/^ + \QCREATE FUNCTION pltestlang_call_handler() \E + \QRETURNS language_handler\E + \n\s+\QLANGUAGE c\E + \n\s+AS\ \'\$ + \Qlibdir\/plpgsql', 'plpgsql_call_handler';\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE FUNCTION dump_test.trigger_func' => { + create_order => 30, + create_sql => 'CREATE FUNCTION dump_test.trigger_func() + RETURNS trigger LANGUAGE plpgsql + AS $$ BEGIN RETURN NULL; END;$$;', + regexp => qr/^ + \QCREATE FUNCTION trigger_func() RETURNS trigger\E + \n\s+\QLANGUAGE plpgsql\E + \n\s+AS\ \$\$ + \Q BEGIN RETURN NULL; END;\E + \$\$;$/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE FUNCTION dump_test.event_trigger_func' => { + create_order => 32, + create_sql => 'CREATE FUNCTION dump_test.event_trigger_func() + RETURNS event_trigger LANGUAGE plpgsql + AS $$ BEGIN RETURN; END;$$;', + regexp => qr/^ + \QCREATE FUNCTION event_trigger_func() RETURNS event_trigger\E + \n\s+\QLANGUAGE plpgsql\E + \n\s+AS\ \$\$ + \Q BEGIN RETURN; END;\E + \$\$;$/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE EVENT TRIGGER test_event_trigger' => { + create_order => 33, + create_sql => 'CREATE EVENT TRIGGER test_event_trigger + ON ddl_command_start + EXECUTE PROCEDURE dump_test.event_trigger_func();', + regexp => qr/^ + \QCREATE EVENT TRIGGER test_event_trigger \E + \QON ddl_command_start\E + \n\s+\QEXECUTE PROCEDURE dump_test.event_trigger_func();\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_post_data => 1, + }, + unlike => { + section_pre_data => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + test_schema_plus_blobs => 1, + }, + }, + 'CREATE TRIGGER test_trigger' => { + create_order => 31, + create_sql => 'CREATE TRIGGER test_trigger + BEFORE INSERT ON dump_test.test_table + FOR EACH ROW WHEN (NEW.col1 > 10) + EXECUTE PROCEDURE dump_test.trigger_func();', + regexp => qr/^ + \QCREATE TRIGGER test_trigger BEFORE INSERT ON test_table \E + \QFOR EACH ROW WHEN ((new.col1 > 10)) \E + \QEXECUTE PROCEDURE trigger_func();\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + section_pre_data => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + }, + }, + 'CREATE TYPE dump_test.planets AS ENUM' => { + create_order => 37, + create_sql => 'CREATE TYPE dump_test.planets + AS ENUM ( \'venus\', \'earth\', \'mars\' );', + regexp => qr/^ + \QCREATE TYPE planets AS ENUM (\E + \n\s+'venus', + \n\s+'earth', + \n\s+'mars' + \n\);$/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE TYPE dump_test.planets AS ENUM pg_upgrade' => { + regexp => qr/^ + \QCREATE TYPE planets AS ENUM (\E + \n\);.*^ + \QALTER TYPE dump_test.planets ADD VALUE 'venus';\E + \n.*^ + \QALTER TYPE dump_test.planets ADD VALUE 'earth';\E + \n.*^ + \QALTER TYPE dump_test.planets ADD VALUE 'mars';\E + \n$/xms, + like => { + binary_upgrade => 1, + }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE TYPE dump_test.textrange AS RANGE' => { + create_order => 38, + create_sql => 'CREATE TYPE dump_test.textrange + AS RANGE (subtype=text, collation="C");', + regexp => qr/^ + \QCREATE TYPE textrange AS RANGE (\E + \n\s+\Qsubtype = text,\E + \n\s+\Qcollation = pg_catalog."C"\E + \n\);/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE TYPE dump_test.int42' => { + create_order => 39, + create_sql => 'CREATE TYPE dump_test.int42;', + regexp => qr/^CREATE TYPE int42;/m, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE FUNCTION dump_test.int42_in' => { + create_order => 40, + create_sql => 'CREATE FUNCTION dump_test.int42_in(cstring) + RETURNS dump_test.int42 AS \'int4in\' + LANGUAGE internal STRICT IMMUTABLE;', + regexp => qr/^ + \QCREATE FUNCTION int42_in(cstring) RETURNS int42\E + \n\s+\QLANGUAGE internal IMMUTABLE STRICT\E + \n\s+AS\ \$\$int4in\$\$; + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE FUNCTION dump_test.int42_out' => { + create_order => 41, + create_sql => 'CREATE FUNCTION dump_test.int42_out(dump_test.int42) + RETURNS cstring AS \'int4out\' + LANGUAGE internal STRICT IMMUTABLE;', + regexp => qr/^ + \QCREATE FUNCTION int42_out(int42) RETURNS cstring\E + \n\s+\QLANGUAGE internal IMMUTABLE STRICT\E + \n\s+AS\ \$\$int4out\$\$; + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE TYPE dump_test.int42 populated' => { + create_order => 42, + create_sql => 'CREATE TYPE dump_test.int42 ( + internallength = 4, + input = dump_test.int42_in, + output = dump_test.int42_out, + alignment = int4, + default = 42, + passedbyvalue);', + regexp => qr/^ + \QCREATE TYPE int42 (\E + \n\s+\QINTERNALLENGTH = 4,\E + \n\s+\QINPUT = int42_in,\E + \n\s+\QOUTPUT = int42_out,\E + \n\s+\QDEFAULT = '42',\E + \n\s+\QALIGNMENT = int4,\E + \n\s+\QSTORAGE = plain,\E + \n\s+PASSEDBYVALUE\n\); + $/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE TYPE dump_test.composite' => { + create_order => 43, + create_sql => 'CREATE TYPE dump_test.composite AS ( + f1 int, + f2 dump_test.int42 + );', + regexp => qr/^ + \QCREATE TYPE composite AS (\E + \n\s+\Qf1 integer,\E + \n\s+\Qf2 int42\E + \n\); + $/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE FOREIGN DATA WRAPPER dummy' => { + create_order => 35, + create_sql => 'CREATE FOREIGN DATA WRAPPER dummy;', + regexp => qr/CREATE FOREIGN DATA WRAPPER dummy;/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + }, + 'CREATE SERVER s1 FOREIGN DATA WRAPPER dummy' => { + create_order => 36, + create_sql => 'CREATE SERVER s1 FOREIGN DATA WRAPPER dummy;', + regexp => qr/CREATE SERVER s1 FOREIGN DATA WRAPPER dummy;/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + }, +####################################### +# Currently broken. +####################################### +# +# 'CREATE TRANSFORM FOR int' => { +# create_order => 34, +# create_sql => 'CREATE TRANSFORM FOR int LANGUAGE SQL (FROM SQL WITH FUNCTION varchar_transform(internal), TO SQL WITH FUNCTION int4recv(internal));', +# regexp => qr/CREATE TRANSFORM FOR int LANGUAGE SQL \(FROM SQL WITH FUNCTION varchar_transform\(internal\), TO SQL WITH FUNCTION int4recv\(internal\)\);/m, +# like => { +# binary_upgrade => 1, +# clean => 1, +# clean_if_exists => 1, +# createdb => 1, +# defaults => 1, +# exclude_dump_test_schema => 1, +# exclude_test_table => 1, +# exclude_test_table_data => 1, +# no_privs => 1, +# no_owner => 1, +# schema_only => 1, +# section_post_data => 1, +# }, +# unlike => { +# section_pre_data => 1, +# only_dump_test_schema => 1, +# only_dump_test_table => 1, +# pg_dumpall_globals => 1, +# test_schema_plus_blobs => 1, +# }, +# }, + 'CREATE LANGUAGE pltestlang' => { + create_order => 18, + create_sql => 'CREATE LANGUAGE pltestlang + HANDLER dump_test.pltestlang_call_handler;', + regexp => qr/^ + \QCREATE PROCEDURAL LANGUAGE pltestlang \E + \QHANDLER pltestlang_call_handler;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + only_dump_test_schema => 1, + test_schema_plus_blobs => 1, + }, + }, + 'CREATE MATERIALIZED VIEW matview' => { + create_order => 20, + create_sql => 'CREATE MATERIALIZED VIEW dump_test.matview (col1) AS + SELECT * FROM dump_test.test_table;', + regexp => qr/^ + \QCREATE MATERIALIZED VIEW matview AS\E + \n\s+\QSELECT test_table.col1\E + \n\s+\QFROM test_table\E + \n\s+\QWITH NO DATA;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE MATERIALIZED VIEW matview_second' => { + create_order => 21, + create_sql => 'CREATE MATERIALIZED VIEW + dump_test.matview_second (col1) AS + SELECT * FROM dump_test.matview;', + regexp => qr/^ + \QCREATE MATERIALIZED VIEW matview_second AS\E + \n\s+\QSELECT matview.col1\E + \n\s+\QFROM matview\E + \n\s+\QWITH NO DATA;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE POLICY p1 ON test_table' => { + create_order => 22, + create_sql => 'CREATE POLICY p1 ON dump_test.test_table + USING (true) + WITH CHECK (true);', + regexp => qr/^ + \QCREATE POLICY p1 ON test_table FOR ALL TO PUBLIC \E + \QUSING (true) WITH CHECK (true);\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + section_pre_data => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + }, + }, + 'CREATE POLICY p2 ON test_table FOR SELECT' => { + create_order => 24, + create_sql => 'CREATE POLICY p2 ON dump_test.test_table + FOR SELECT TO dump_test USING (true);', + regexp => qr/^ + \QCREATE POLICY p2 ON test_table FOR SELECT TO dump_test \E + \QUSING (true);\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + section_pre_data => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + }, + }, + 'CREATE POLICY p3 ON test_table FOR INSERT' => { + create_order => 25, + create_sql => 'CREATE POLICY p3 ON dump_test.test_table + FOR INSERT TO dump_test WITH CHECK (true);', + regexp => qr/^ + \QCREATE POLICY p3 ON test_table FOR INSERT \E + \QTO dump_test WITH CHECK (true);\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + section_pre_data => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + }, + }, + 'CREATE POLICY p4 ON test_table FOR UPDATE' => { + create_order => 26, + create_sql => 'CREATE POLICY p4 ON dump_test.test_table FOR UPDATE + TO dump_test USING (true) WITH CHECK (true);', + regexp => qr/^ + \QCREATE POLICY p4 ON test_table FOR UPDATE TO dump_test \E + \QUSING (true) WITH CHECK (true);\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + section_pre_data => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + }, + }, + 'CREATE POLICY p5 ON test_table FOR DELETE' => { + create_order => 27, + create_sql => 'CREATE POLICY p5 ON dump_test.test_table + FOR DELETE TO dump_test USING (true);', + regexp => qr/^ + \QCREATE POLICY p5 ON test_table FOR DELETE \E + \QTO dump_test USING (true);\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + section_pre_data => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + }, + }, + 'CREATE SCHEMA dump_test' => { + create_order => 2, + create_sql => 'CREATE SCHEMA dump_test;', + regexp => qr/^CREATE SCHEMA dump_test;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE SCHEMA dump_test_second_schema' => { + create_order => 9, + create_sql => 'CREATE SCHEMA dump_test_second_schema;', + regexp => qr/^CREATE SCHEMA dump_test_second_schema;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + }, + 'CREATE TABLE test_table' => { + create_order => 3, + create_sql => 'CREATE TABLE dump_test.test_table ( + col1 serial primary key, + CHECK (col1 <= 1000) + );', + regexp => qr/^ + \QCREATE TABLE test_table (\E + \n\s+\Qcol1 integer NOT NULL,\E + \n\s+\QCONSTRAINT test_table_col1_check CHECK \E + \Q((col1 <= 1000))\E + \n\);$/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE TABLE fk_reference_test_table' => { + create_order => 21, + create_sql => 'CREATE TABLE dump_test.fk_reference_test_table ( + col1 int primary key references dump_test.test_table + );', + regexp => qr/^ + \QCREATE TABLE fk_reference_test_table (\E + \n\s+\Qcol1 integer NOT NULL\E + \n\); + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE TABLE test_second_table' => { + create_order => 6, + create_sql => 'CREATE TABLE dump_test.test_second_table ( + col1 int, + col2 text + );', + regexp => qr/^ + \QCREATE TABLE test_second_table (\E + \n\s+\Qcol1 integer,\E + \n\s+\Qcol2 text\E + \n\); + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE TABLE test_third_table' => { + create_order => 11, + create_sql => 'CREATE TABLE dump_test_second_schema.test_third_table ( + col1 serial + );', + regexp => qr/^ + \QCREATE TABLE test_third_table (\E + \n\s+\Qcol1 integer NOT NULL\E + \n\); + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + }, + 'CREATE SEQUENCE test_table_col1_seq' => { + regexp => qr/^ + \QCREATE SEQUENCE test_table_col1_seq\E + \n\s+\QSTART WITH 1\E + \n\s+\QINCREMENT BY 1\E + \n\s+\QNO MINVALUE\E + \n\s+\QNO MAXVALUE\E + \n\s+\QCACHE 1;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE SEQUENCE test_third_table_col1_seq' => { + regexp => qr/^ + \QCREATE SEQUENCE test_third_table_col1_seq\E + \n\s+\QSTART WITH 1\E + \n\s+\QINCREMENT BY 1\E + \n\s+\QNO MINVALUE\E + \n\s+\QNO MAXVALUE\E + \n\s+\QCACHE 1;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + test_schema_plus_blobs => 1, + }, + }, + 'CREATE UNIQUE INDEX test_third_table_idx ON test_third_table' => { + create_order => 13, + create_sql => 'CREATE UNIQUE INDEX test_third_table_idx + ON dump_test_second_schema.test_third_table (col1);', + regexp => qr/^ + \QCREATE UNIQUE INDEX test_third_table_idx \E + \QON test_third_table USING btree (col1);\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_post_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + test_schema_plus_blobs => 1, + }, + }, + 'CREATE ... commands' => { # catch-all for CREATE + regexp => qr/^CREATE /m, + like => { }, # use more-specific options above + unlike => { + column_inserts => 1, + data_only => 1, + section_data => 1, + }, + }, + 'DROP EXTENSION plpgsql' => { + regexp => qr/^DROP EXTENSION plpgsql;$/m, + like => { + clean => 1, + }, + unlike => { + clean_if_exists => 1, + }, + }, + 'DROP FUNCTION dump_test.pltestlang_call_handler()' => { + regexp => qr/^DROP FUNCTION dump_test\.pltestlang_call_handler\(\);$/m, + like => { + clean => 1, + }, + unlike => { + clean_if_exists => 1, + }, + }, + 'DROP LANGUAGE pltestlang' => { + regexp => qr/^DROP PROCEDURAL LANGUAGE pltestlang;$/m, + like => { + clean => 1, + }, + unlike => { + clean_if_exists => 1, + }, + }, + 'DROP SCHEMA dump_test' => { + regexp => qr/^DROP SCHEMA dump_test;$/m, + like => { + clean => 1, + }, + unlike => { + clean_if_exists => 1, + }, + }, + 'DROP SCHEMA dump_test_second_schema' => { + regexp => qr/^DROP SCHEMA dump_test_second_schema;$/m, + like => { + clean => 1, + }, + unlike => { + clean_if_exists => 1, + }, + }, + 'DROP TABLE test_table' => { + regexp => qr/^DROP TABLE dump_test\.test_table;$/m, + like => { + clean => 1, + }, + unlike => { + clean_if_exists => 1, + }, + }, + 'DROP TABLE fk_reference_test_table' => { + regexp => qr/^DROP TABLE dump_test\.fk_reference_test_table;$/m, + like => { + clean => 1, + }, + unlike => { + clean_if_exists => 1, + }, + }, + 'DROP TABLE test_second_table' => { + regexp => qr/^DROP TABLE dump_test\.test_second_table;$/m, + like => { + clean => 1, + }, + unlike => { + clean_if_exists => 1, + }, + }, + 'DROP TABLE test_third_table' => { + regexp => qr/^DROP TABLE dump_test_second_schema\.test_third_table;$/m, + like => { + clean => 1, + }, + unlike => { + clean_if_exists => 1, + }, + }, + 'DROP EXTENSION IF EXISTS plpgsql' => { + regexp => qr/^DROP EXTENSION IF EXISTS plpgsql;$/m, + like => { + clean_if_exists => 1, + }, + unlike => { + clean => 1, + }, + }, + 'DROP FUNCTION IF EXISTS dump_test.pltestlang_call_handler()' => { + regexp => qr/^ + \QDROP FUNCTION IF EXISTS dump_test.pltestlang_call_handler();\E + $/xm, + like => { + clean_if_exists => 1, + }, + unlike => { + clean => 1, + }, + }, + 'DROP LANGUAGE IF EXISTS pltestlang' => { + regexp => qr/^DROP PROCEDURAL LANGUAGE IF EXISTS pltestlang;$/m, + like => { + clean_if_exists => 1, + }, + unlike => { + clean => 1, + }, + }, + 'DROP SCHEMA IF EXISTS dump_test' => { + regexp => qr/^DROP SCHEMA IF EXISTS dump_test;$/m, + like => { + clean_if_exists => 1, + }, + unlike => { + clean => 1, + }, + }, + 'DROP SCHEMA IF EXISTS dump_test_second_schema' => { + regexp => qr/^DROP SCHEMA IF EXISTS dump_test_second_schema;$/m, + like => { + clean_if_exists => 1, + }, + unlike => { + clean => 1, + }, + }, + 'DROP TABLE IF EXISTS test_table' => { + regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_table;$/m, + like => { + clean_if_exists => 1, + }, + unlike => { + clean => 1, + }, + }, + 'DROP TABLE IF EXISTS test_second_table' => { + regexp => qr/^DROP TABLE IF EXISTS dump_test\.test_second_table;$/m, + like => { + clean_if_exists => 1, + }, + unlike => { + clean => 1, + }, + }, + 'DROP TABLE IF EXISTS test_third_table' => { + regexp => qr/^ + \QDROP TABLE IF EXISTS dump_test_second_schema.test_third_table;\E + $/xm, + like => { + clean_if_exists => 1, + }, + unlike => { + clean => 1, + }, + }, + 'DROP ... commands' => { # catch-all for DROP + regexp => qr/^DROP /m, + like => { }, # use more-specific options above + unlike => { + binary_upgrade => 1, + column_inserts => 1, + createdb => 1, + data_only => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + schema_only => 1, + }, + }, + 'GRANT USAGE ON SCHEMA dump_test_second_schema' => { + create_order => 10, + create_sql => 'GRANT USAGE ON SCHEMA dump_test_second_schema + TO dump_test;', + regexp => qr/^ + \QGRANT USAGE ON SCHEMA dump_test_second_schema TO dump_test;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + test_schema_plus_blobs => 1, + }, + }, + 'GRANT SELECT ON TABLE test_table' => { + create_order => 5, + create_sql => 'GRANT SELECT ON TABLE dump_test.test_table + TO dump_test;', + regexp => qr/^GRANT SELECT ON TABLE test_table TO dump_test;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table_data => 1, + no_owner => 1, + only_dump_test_schema => 1, + only_dump_test_table => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + exclude_test_table => 1, + pg_dumpall_globals => 1, + }, + }, + 'GRANT SELECT ON TABLE test_third_table' => { + create_order => 19, + create_sql => 'GRANT SELECT ON + TABLE dump_test_second_schema.test_third_table + TO dump_test;', + regexp => qr/^GRANT SELECT ON TABLE test_third_table TO dump_test;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + test_schema_plus_blobs => 1, + }, + }, + 'GRANT ALL ON SEQUENCE test_third_table_col1_seq' => { + create_order => 28, + create_sql => 'GRANT ALL ON SEQUENCE + dump_test_second_schema.test_third_table_col1_seq + TO dump_test;', + regexp => qr/^ + \QGRANT ALL ON SEQUENCE test_third_table_col1_seq TO dump_test;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + test_schema_plus_blobs => 1, + }, + }, + 'GRANT INSERT(col1) ON TABLE test_second_table' => { + create_order => 8, + create_sql => 'GRANT INSERT (col1) ON TABLE dump_test.test_second_table + TO dump_test;', + regexp => qr/^ + \QGRANT INSERT(col1) ON TABLE test_second_table TO dump_test;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + only_dump_test_schema => 1, + schema_only => 1, + section_pre_data => 1, + test_schema_plus_blobs => 1, + }, + unlike => { + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + }, + }, + 'GRANT EXECUTE ON FUNCTION pg_sleep() TO dump_test' => { + create_order => 16, + create_sql => 'GRANT EXECUTE ON FUNCTION pg_sleep(float8) + TO dump_test;', + regexp => qr/^ + \QGRANT ALL ON FUNCTION pg_sleep(double precision) TO dump_test;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'GRANT SELECT (proname ...) ON TABLE pg_proc TO public' => { + create_order => 46, + create_sql => 'GRANT SELECT ( + tableoid, + oid, + proname, + pronamespace, + proowner, + prolang, + procost, + prorows, + provariadic, + protransform, + proisagg, + proiswindow, + prosecdef, + proleakproof, + proisstrict, + proretset, + provolatile, + proparallel, + pronargs, + pronargdefaults, + prorettype, + proargtypes, + proallargtypes, + proargmodes, + proargnames, + proargdefaults, + protrftypes, + prosrc, + probin, + proconfig, + proacl + ) ON TABLE pg_proc TO public;', + regexp => qr/ + \QGRANT SELECT(tableoid) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(oid) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proname) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(pronamespace) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proowner) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(prolang) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(procost) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(prorows) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(provariadic) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(protransform) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proisagg) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proiswindow) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(prosecdef) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proleakproof) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proisstrict) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proretset) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(provolatile) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proparallel) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(pronargs) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(pronargdefaults) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(prorettype) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proargtypes) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proallargtypes) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proargmodes) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proargnames) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proargdefaults) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(protrftypes) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(prosrc) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(probin) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proconfig) ON TABLE pg_proc TO PUBLIC;\E\n.* + \QGRANT SELECT(proacl) ON TABLE pg_proc TO PUBLIC;\E$/xms, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'GRANT commands' => { # catch-all for GRANT commands + regexp => qr/^GRANT /m, + like => { }, # use more-specific options above + unlike => { + column_inserts => 1, + data_only => 1, + no_privs => 1, + section_data => 1, + }, + }, + 'REFRESH MATERIALIZED VIEW matview' => { + regexp => qr/^REFRESH MATERIALIZED VIEW matview;$/m, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + test_schema_plus_blobs => 1, + section_post_data => 1, + }, + unlike => { + binary_upgrade => 1, + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + }, + }, + 'REFRESH MATERIALIZED VIEW matview_second' => { + regexp => qr/^ + \QREFRESH MATERIALIZED VIEW matview;\E + \n.* + \QREFRESH MATERIALIZED VIEW matview_second;\E + $/xms, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_privs => 1, + no_owner => 1, + only_dump_test_schema => 1, + test_schema_plus_blobs => 1, + section_post_data => 1, + }, + unlike => { + binary_upgrade => 1, + exclude_dump_test_schema => 1, + only_dump_test_table => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + }, + }, + 'REVOKE EXECUTE ON FUNCTION pg_sleep() FROM public' => { + create_order => 15, + create_sql => 'REVOKE EXECUTE ON FUNCTION pg_sleep(float8) + FROM public;', + regexp => qr/^ + \QREVOKE ALL ON FUNCTION pg_sleep(double precision) FROM PUBLIC;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'REVOKE SELECT ON TABLE pg_proc FROM public' => { + create_order => 45, + create_sql => 'REVOKE SELECT ON TABLE pg_proc FROM public;', + regexp => qr/^REVOKE SELECT ON TABLE pg_proc FROM PUBLIC;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'REVOKE CREATE ON SCHEMA public FROM public' => { + create_order => 16, + create_sql => 'REVOKE CREATE ON SCHEMA public FROM public;', + regexp => qr/^ + \QREVOKE ALL ON SCHEMA public FROM PUBLIC;\E + \n\QGRANT USAGE ON SCHEMA public TO PUBLIC;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'REVOKE USAGE ON LANGUAGE plpgsql FROM public' => { + create_order => 16, + create_sql => 'REVOKE USAGE ON LANGUAGE plpgsql FROM public;', + regexp => qr/^REVOKE ALL ON LANGUAGE plpgsql FROM PUBLIC;$/m, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_dump_test_schema => 1, + exclude_test_table => 1, + exclude_test_table_data => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + only_dump_test_schema => 1, + only_dump_test_table => 1, + test_schema_plus_blobs => 1, + }, + }, + 'REVOKE commands' => { # catch-all for REVOKE commands + regexp => qr/^REVOKE /m, + like => { }, # use more-specific options above + unlike => { + column_inserts => 1, + data_only => 1, + no_privs => 1, + pg_dumpall_globals => 1, + }, + }, +); + +######################################### +# Create a PG instance to test actually dumping from + +my $node = get_new_node('main'); +$node->init; +$node->start; + +my $port = $node->port; + +# Start with 2 because of command_exit_is() tests below +my $num_tests = 2; + +foreach my $run (sort keys %pgdump_runs) { + my $test_key = $run; + + # Each run of pg_dump is a test itself + $num_tests++; + + # If there is a restore cmd, that's another test + if ($pgdump_runs{$run}->{restore_cmd}) { + $num_tests++; + } + + if ($pgdump_runs{$run}->{test_key}) { + $test_key = $pgdump_runs{$run}->{test_key}; + } + + # Then count all the tests run against each run + foreach my $test (sort keys %tests) { + if ($tests{$test}->{like}->{$test_key}) { + $num_tests++; + } + + if ($tests{$test}->{unlike}->{$test_key}) { + $num_tests++; + } + } +} +plan tests => $num_tests; + +######################################### +# Set up schemas, tables, etc, to be dumped. + +# Build up the create statements +my $create_sql = ''; + +foreach my $test ( + sort { + if ($tests{$a}->{create_order} and $tests{$b}->{create_order}) { + $tests{$a}->{create_order} <=> $tests{$b}->{create_order}; + } elsif ($tests{$a}->{create_order}) { + -1; + } elsif ($tests{$b}->{create_order}) { + 1; + } else { + 0; + } + } keys %tests) { + if ($tests{$test}->{create_sql}) { + $create_sql .= $tests{$test}->{create_sql}; + } +} + +# Send the combined set of commands to psql +$node->safe_psql('postgres', $create_sql); + +######################################### +# Test connecting to a non-existent database + +command_exit_is([ 'pg_dump', '-p', "$port", 'qqq' ], + 1, 'pg_dump: [archiver (db)] connection to database "qqq" failed: FATAL: database "qqq" does not exist'); + +command_exit_is([ 'pg_dump', '-p', "$port", '--role=dump_test' ], + 1, 'pg_dump: [archiver (db)] query failed: ERROR: permission denied for'); + +######################################### +# Run all runs + +foreach my $run (sort keys %pgdump_runs) { + + my $test_key = $run; + + $node->command_ok(\@{ $pgdump_runs{$run}->{dump_cmd} }, "$run: pg_dump runs"); + + if ($pgdump_runs{$run}->{restore_cmd}) { + $node->command_ok(\@{ $pgdump_runs{$run}->{restore_cmd} }, "$run: pg_restore runs"); + } + + if ($pgdump_runs{$run}->{test_key}) { + $test_key = $pgdump_runs{$run}->{test_key}; + } + + my $output_file = slurp_file("$tempdir/${run}.sql"); + + ######################################### + # Run all tests where this run is included + # as either a 'like' or 'unlike' test. + + foreach my $test (sort keys %tests) { + if ($tests{$test}->{like}->{$test_key}) { + like($output_file, $tests{$test}->{regexp}, "$run: dumps $test"); + } + + if ($tests{$test}->{unlike}->{$test_key}) { + unlike($output_file, $tests{$test}->{regexp}, "$run: does not dump $test"); + } + } +} + +######################################### +# Stop the database instance, which will be removed at the end of the tests. + +$node->stop('fast'); diff --git a/src/test/modules/Makefile b/src/test/modules/Makefile index 9b935521f4..892662755a 100644 --- a/src/test/modules/Makefile +++ b/src/test/modules/Makefile @@ -12,6 +12,7 @@ SUBDIRS = \ test_ddl_deparse \ test_extensions \ test_parser \ + test_pg_dump \ test_rls_hooks \ test_shm_mq \ worker_spi diff --git a/src/test/modules/test_pg_dump/.gitignore b/src/test/modules/test_pg_dump/.gitignore new file mode 100644 index 0000000000..5dcb3ff972 --- /dev/null +++ b/src/test/modules/test_pg_dump/.gitignore @@ -0,0 +1,4 @@ +# Generated subdirectories +/log/ +/results/ +/tmp_check/ diff --git a/src/test/modules/test_pg_dump/Makefile b/src/test/modules/test_pg_dump/Makefile new file mode 100644 index 0000000000..0eb3b5f988 --- /dev/null +++ b/src/test/modules/test_pg_dump/Makefile @@ -0,0 +1,25 @@ +# src/test/modules/test_rls_hooks/Makefile + +MODULE_big = test_pg_dump +PGFILEDESC = "test_pg_dump - Test pg_dump with an extension" + +EXTENSION = test_pg_dump +DATA = test_pg_dump--1.0.sql + +REGRESS = test_pg_dump + +check: prove-check + +prove-check: + $(prove_check) + +ifdef USE_PGXS +PG_CONFIG = pg_config +PGXS := $(shell $(PG_CONFIG) --pgxs) +include $(PGXS) +else +subdir = src/test/modules/test_pg_dump +top_builddir = ../../../.. +include $(top_builddir)/src/Makefile.global +include $(top_srcdir)/contrib/contrib-global.mk +endif diff --git a/src/test/modules/test_pg_dump/README b/src/test/modules/test_pg_dump/README new file mode 100644 index 0000000000..e6c78b822c --- /dev/null +++ b/src/test/modules/test_pg_dump/README @@ -0,0 +1,2 @@ +test_pg_dump is an extension explicitly to test pg_dump when +extensions are present in the system. diff --git a/src/test/modules/test_pg_dump/expected/test_pg_dump.out b/src/test/modules/test_pg_dump/expected/test_pg_dump.out new file mode 100644 index 0000000000..360caa2cb3 --- /dev/null +++ b/src/test/modules/test_pg_dump/expected/test_pg_dump.out @@ -0,0 +1,6 @@ +SELECT 1; + ?column? +---------- + 1 +(1 row) + diff --git a/src/test/modules/test_pg_dump/sql/test_pg_dump.sql b/src/test/modules/test_pg_dump/sql/test_pg_dump.sql new file mode 100644 index 0000000000..e0ac49d1ec --- /dev/null +++ b/src/test/modules/test_pg_dump/sql/test_pg_dump.sql @@ -0,0 +1 @@ +SELECT 1; diff --git a/src/test/modules/test_pg_dump/t/001_base.pl b/src/test/modules/test_pg_dump/t/001_base.pl new file mode 100644 index 0000000000..9a65da1d6a --- /dev/null +++ b/src/test/modules/test_pg_dump/t/001_base.pl @@ -0,0 +1,535 @@ +use strict; +use warnings; + +use Config; +use PostgresNode; +use TestLib; +use Test::More; + +my $tempdir = TestLib::tempdir; +my $tempdir_short = TestLib::tempdir_short; + +############################################################### +# This structure is based off of the src/bin/pg_dump/t test +# suite. +############################################################### +# Definition of the pg_dump runs to make. +# +# Each of these runs are named and those names are used below +# to define how each test should (or shouldn't) treat a result +# from a given run. +# +# test_key indicates that a given run should simply use the same +# set of like/unlike tests as another run, and which run that is. +# +# dump_cmd is the pg_dump command to run, which is an array of +# the full command and arguments to run. Note that this is run +# using $node->command_ok(), so the port does not need to be +# specified and is pulled from $PGPORT, which is set by the +# PostgresNode system. +# +# restore_cmd is the pg_restore command to run, if any. Note +# that this should generally be used when the pg_dump goes to +# a non-text file and that the restore can then be used to +# generate a text file to run through the tests from the +# non-text file generated by pg_dump. +# +# TODO: Have pg_restore actually restore to an independent +# database and then pg_dump *that* database (or something along +# those lines) to validate that part of the process. + +my %pgdump_runs = ( + binary_upgrade => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/binary_upgrade.sql", + '--schema-only', + '--binary-upgrade', + '-d', 'postgres', # alternative way to specify database + ], + }, + clean => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/clean.sql", + '-c', + '-d', 'postgres', # alternative way to specify database + ], + }, + clean_if_exists => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/clean_if_exists.sql", + '-c', + '--if-exists', + '-E', 'UTF8', # no-op, just tests that option is accepted + 'postgres', + ], + }, + column_inserts => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/column_inserts.sql", + '-a', + '--column-inserts', + 'postgres', + ], + }, + createdb => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/createdb.sql", + '-C', + '-R', # no-op, just for testing + 'postgres', + ], + }, + data_only => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/data_only.sql", + '-a', + '-v', # no-op, just make sure it works + 'postgres', + ], + }, + defaults => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/defaults.sql", + 'postgres', + ], + }, + defaults_custom_format => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', + '-Fc', + '-Z6', + '-f', "$tempdir/defaults_custom_format.dump", + 'postgres', + ], + restore_cmd => [ + 'pg_restore', + '-f', "$tempdir/defaults_custom_format.sql", + "$tempdir/defaults_custom_format.dump", + ], + }, + defaults_dir_format => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', + '-Fd', + '-f', "$tempdir/defaults_dir_format", + 'postgres', + ], + restore_cmd => [ + 'pg_restore', + '-f', "$tempdir/defaults_dir_format.sql", + "$tempdir/defaults_dir_format", + ], + }, + defaults_parallel => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', + '-Fd', + '-j2', + '-f', "$tempdir/defaults_parallel", + 'postgres', + ], + restore_cmd => [ + 'pg_restore', + '-f', "$tempdir/defaults_parallel.sql", + "$tempdir/defaults_parallel", + ], + }, + defaults_tar_format => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', + '-Ft', + '-f', "$tempdir/defaults_tar_format.tar", + 'postgres', + ], + restore_cmd => [ + 'pg_restore', + '-f', "$tempdir/defaults_tar_format.sql", + "$tempdir/defaults_tar_format.tar", + ], + }, + pg_dumpall_globals => { + dump_cmd => [ + 'pg_dumpall', + '-f', "$tempdir/pg_dumpall_globals.sql", + '-g', + ], + }, + no_privs => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/no_privs.sql", + '-x', + 'postgres', + ], + }, + no_owner => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/no_owner.sql", + '-O', + 'postgres', + ], + }, + schema_only => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/schema_only.sql", + '-s', + 'postgres', + ], + }, + section_pre_data => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/section_pre_data.sql", + '--section=pre-data', + 'postgres', + ], + }, + section_data => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/section_data.sql", + '--section=data', + 'postgres', + ], + }, + section_post_data => { + dump_cmd => [ + 'pg_dump', + '-f', "$tempdir/section_post_data.sql", + '--section=post-data', + 'postgres', + ], + }, +); + +############################################################### +# Definition of the tests to run. +# +# Each test is defined using the log message that will be used. +# +# A regexp should be defined for each test which provides the +# basis for the test. That regexp will be run against the output +# file of each of the runs which the test is to be run against +# and the success of the result will depend on if the regexp +# result matches the expected 'like' or 'unlike' case. +# +# For each test, there are two sets of runs defined, one for +# the 'like' tests and one for the 'unlike' tests. 'like' +# essentially means "the regexp for this test must match the +# output file". 'unlike' is the opposite. +# +# There are a few 'catch-all' tests which can be used to have +# a single, simple, test to over a range of other tests. For +# example, there is a '^CREATE ' test, which is used for the +# 'data-only' test as there should never be any kind of CREATE +# statement in a 'data-only' run. Without the catch-all, we +# would have to list the 'data-only' run in each and every +# 'CREATE xxxx' test, which would be a lot of additional tests. +# +# Note that it makes no sense for the same run to ever be listed +# in both 'like' and 'unlike' categories. +# +# There can then be a 'create_sql' and 'create_order' for a +# given test. The 'create_sql' commands are collected up in +# 'create_order' and then run against the database prior to any +# of the pg_dump runs happening. This is what "seeds" the +# system with objects to be dumped out. +# +# Building of this hash takes a bit of time as all of the regexps +# included in it are compiled. This greatly improves performance +# as the regexps are used for each run the test applies to. + +my %tests = ( + 'CREATE EXTENSION test_pg_dump' => { + create_order => 2, + create_sql => 'CREATE EXTENSION test_pg_dump;', + regexp => qr/^ + \QCREATE EXTENSION IF NOT EXISTS test_pg_dump WITH SCHEMA public;\E + $/xm, + like => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + binary_upgrade => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'CREATE ROLE dump_test' => { + create_order => 1, + create_sql => 'CREATE ROLE dump_test;', + regexp => qr/^CREATE ROLE dump_test;$/m, + like => { + pg_dumpall_globals => 1, + }, + unlike => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, + }, + }, + 'CREATE TABLE regress_pg_dump_table' => { + regexp => qr/^ + \QCREATE TABLE regress_pg_dump_table (\E + \n\s+\Qcol1 integer,\E + \n\s+\Qcol2 integer\E + \n\);$/xm, + like => { + binary_upgrade => 1, + }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_privs => 1, + no_owner => 1, + pg_dumpall_globals => 1, + schema_only => 1, + section_pre_data => 1, + section_post_data => 1, + }, + }, + 'COMMENT ON EXTENSION test_pg_dump' => { + regexp => qr/^ + \QCOMMENT ON EXTENSION test_pg_dump \E + \QIS 'Test pg_dump with an extension';\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_privs => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'GRANT SELECT ON TABLE regress_pg_dump_table' => { + regexp => qr/^ + \QSELECT binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT SELECT ON TABLE regress_pg_dump_table TO dump_test;\E\n + \QSELECT binary_upgrade_set_record_init_privs(false);\E + $/xms, + like => { + binary_upgrade => 1, + }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + no_privs => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'GRANT SELECT(col1) ON regress_pg_dump_table' => { + regexp => qr/^ + \QSELECT binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT SELECT(col1) ON TABLE regress_pg_dump_table TO PUBLIC;\E\n + \QSELECT binary_upgrade_set_record_init_privs(false);\E + $/xms, + like => { + binary_upgrade => 1, + }, + unlike => { + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + no_privs => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'GRANT SELECT(col2) ON regress_pg_dump_table TO dump_test' => { + create_order => 4, + create_sql => 'GRANT SELECT(col2) ON regress_pg_dump_table + TO dump_test;', + regexp => qr/^ + \QGRANT SELECT(col2) ON TABLE regress_pg_dump_table TO dump_test;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + no_privs => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, + 'REVOKE SELECT(col1) ON regress_pg_dump_table' => { + create_order => 3, + create_sql => 'REVOKE SELECT(col1) ON regress_pg_dump_table + FROM PUBLIC;', + regexp => qr/^ + \QREVOKE SELECT(col1) ON TABLE regress_pg_dump_table FROM PUBLIC;\E + $/xm, + like => { + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + no_owner => 1, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { + no_privs => 1, + pg_dumpall_globals => 1, + section_post_data => 1, + }, + }, +); + +######################################### +# Create a PG instance to test actually dumping from + +my $node = get_new_node('main'); +$node->init; +$node->start; + +my $port = $node->port; + +my $num_tests = 0; + +foreach my $run (sort keys %pgdump_runs) { + my $test_key = $run; + + # Each run of pg_dump is a test itself + $num_tests++; + + # If there is a restore cmd, that's another test + if ($pgdump_runs{$run}->{restore_cmd}) { + $num_tests++; + } + + if ($pgdump_runs{$run}->{test_key}) { + $test_key = $pgdump_runs{$run}->{test_key}; + } + + # Then count all the tests run against each run + foreach my $test (sort keys %tests) { + if ($tests{$test}->{like}->{$test_key}) { + $num_tests++; + } + + if ($tests{$test}->{unlike}->{$test_key}) { + $num_tests++; + } + } +} +plan tests => $num_tests; + +######################################### +# Set up schemas, tables, etc, to be dumped. + +# Build up the create statements +my $create_sql = ''; + +foreach my $test ( + sort { + if ($tests{$a}->{create_order} and $tests{$b}->{create_order}) { + $tests{$a}->{create_order} <=> $tests{$b}->{create_order}; + } elsif ($tests{$a}->{create_order}) { + -1; + } elsif ($tests{$b}->{create_order}) { + 1; + } else { + 0; + } + } keys %tests) { + if ($tests{$test}->{create_sql}) { + $create_sql .= $tests{$test}->{create_sql}; + } +} + +# Send the combined set of commands to psql +$node->safe_psql('postgres', $create_sql); + +######################################### +# Run all runs + +foreach my $run (sort keys %pgdump_runs) { + + my $test_key = $run; + + $node->command_ok(\@{ $pgdump_runs{$run}->{dump_cmd} }, "$run: pg_dump runs"); + + if ($pgdump_runs{$run}->{restore_cmd}) { + $node->command_ok(\@{ $pgdump_runs{$run}->{restore_cmd} }, "$run: pg_restore runs"); + } + + if ($pgdump_runs{$run}->{test_key}) { + $test_key = $pgdump_runs{$run}->{test_key}; + } + + my $output_file = slurp_file("$tempdir/${run}.sql"); + + ######################################### + # Run all tests where this run is included + # as either a 'like' or 'unlike' test. + + foreach my $test (sort keys %tests) { + if ($tests{$test}->{like}->{$test_key}) { + like($output_file, $tests{$test}->{regexp}, "$run: dumps $test"); + } + + if ($tests{$test}->{unlike}->{$test_key}) { + unlike($output_file, $tests{$test}->{regexp}, "$run: does not dump $test"); + } + } +} + +######################################### +# Stop the database instance, which will be removed at the end of the tests. + +$node->stop('fast'); diff --git a/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql b/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql new file mode 100644 index 0000000000..d1ec58d023 --- /dev/null +++ b/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql @@ -0,0 +1,15 @@ +/* src/test/modules/test_pg_dump/test_pg_dump--1.0.sql */ + +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "CREATE EXTENSION test_pg_dump" to load this file. \quit + +CREATE TABLE regress_pg_dump_table ( + col1 int, + col2 int +); + +GRANT SELECT ON regress_pg_dump_table TO dump_test; +GRANT SELECT(col1) ON regress_pg_dump_table TO public; + +GRANT SELECT(col2) ON regress_pg_dump_table TO dump_test; +REVOKE SELECT(col2) ON regress_pg_dump_table FROM dump_test; diff --git a/src/test/modules/test_pg_dump/test_pg_dump.control b/src/test/modules/test_pg_dump/test_pg_dump.control new file mode 100644 index 0000000000..fe3450db76 --- /dev/null +++ b/src/test/modules/test_pg_dump/test_pg_dump.control @@ -0,0 +1,3 @@ +comment = 'Test pg_dump with an extension' +default_version = '1.0' +relocatable = true