diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:46:48 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-16 19:46:48 +0000 |
commit | 311bcfc6b3acdd6fd152798c7f287ddf74fa2a98 (patch) | |
tree | 0ec307299b1dada3701e42f4ca6eda57d708261e /src/test/modules/test_pg_dump | |
parent | Initial commit. (diff) | |
download | postgresql-15-311bcfc6b3acdd6fd152798c7f287ddf74fa2a98.tar.xz postgresql-15-311bcfc6b3acdd6fd152798c7f287ddf74fa2a98.zip |
Adding upstream version 15.4.upstream/15.4upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/test/modules/test_pg_dump')
-rw-r--r-- | src/test/modules/test_pg_dump/.gitignore | 4 | ||||
-rw-r--r-- | src/test/modules/test_pg_dump/Makefile | 21 | ||||
-rw-r--r-- | src/test/modules/test_pg_dump/README | 4 | ||||
-rw-r--r-- | src/test/modules/test_pg_dump/expected/test_pg_dump.out | 93 | ||||
-rw-r--r-- | src/test/modules/test_pg_dump/sql/test_pg_dump.sql | 108 | ||||
-rw-r--r-- | src/test/modules/test_pg_dump/t/001_base.pl | 844 | ||||
-rw-r--r-- | src/test/modules/test_pg_dump/test_pg_dump--1.0.sql | 62 | ||||
-rw-r--r-- | src/test/modules/test_pg_dump/test_pg_dump.control | 3 |
8 files changed, 1139 insertions, 0 deletions
diff --git a/src/test/modules/test_pg_dump/.gitignore b/src/test/modules/test_pg_dump/.gitignore new file mode 100644 index 0000000..5dcb3ff --- /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 0000000..6123b99 --- /dev/null +++ b/src/test/modules/test_pg_dump/Makefile @@ -0,0 +1,21 @@ +# src/test/modules/test_pg_dump/Makefile + +MODULE = 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 +TAP_TESTS = 1 + +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 0000000..b7c2e33 --- /dev/null +++ b/src/test/modules/test_pg_dump/README @@ -0,0 +1,4 @@ +test_pg_dump is an extension explicitly to test pg_dump when +extensions are present in the system. + +We also make use of this module to test ALTER EXTENSION ADD/DROP. 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 0000000..f14f3a6 --- /dev/null +++ b/src/test/modules/test_pg_dump/expected/test_pg_dump.out @@ -0,0 +1,93 @@ +CREATE ROLE regress_dump_test_role; +CREATE EXTENSION test_pg_dump; +ALTER EXTENSION test_pg_dump ADD DATABASE postgres; -- error +ERROR: cannot add an object of this type to an extension +CREATE TABLE test_pg_dump_t1 (c1 int, junk text); +ALTER TABLE test_pg_dump_t1 DROP COLUMN junk; -- to exercise dropped-col cases +CREATE VIEW test_pg_dump_v1 AS SELECT * FROM test_pg_dump_t1; +CREATE MATERIALIZED VIEW test_pg_dump_mv1 AS SELECT * FROM test_pg_dump_t1; +CREATE SCHEMA test_pg_dump_s1; +CREATE TYPE test_pg_dump_e1 AS ENUM ('abc', 'def'); +CREATE AGGREGATE newavg ( + sfunc = int4_avg_accum, basetype = int4, stype = _int8, + finalfunc = int8_avg, + initcond1 = '{0,0}' +); +CREATE FUNCTION test_pg_dump(int) RETURNS int AS $$ +BEGIN +RETURN abs($1); +END +$$ LANGUAGE plpgsql IMMUTABLE; +CREATE OPERATOR ==== ( + LEFTARG = int, + RIGHTARG = int, + PROCEDURE = int4eq, + COMMUTATOR = ==== +); +CREATE ACCESS METHOD gist2 TYPE INDEX HANDLER gisthandler; +CREATE TYPE casttesttype; +CREATE FUNCTION casttesttype_in(cstring) + RETURNS casttesttype + AS 'textin' + LANGUAGE internal STRICT IMMUTABLE; +NOTICE: return type casttesttype is only a shell +CREATE FUNCTION casttesttype_out(casttesttype) + RETURNS cstring + AS 'textout' + LANGUAGE internal STRICT IMMUTABLE; +NOTICE: argument type casttesttype is only a shell +CREATE TYPE casttesttype ( + internallength = variable, + input = casttesttype_in, + output = casttesttype_out, + alignment = int4 +); +CREATE CAST (text AS casttesttype) WITHOUT FUNCTION; +CREATE FOREIGN DATA WRAPPER dummy; +CREATE SERVER s0 FOREIGN DATA WRAPPER dummy; +CREATE FOREIGN TABLE ft1 ( + c1 integer OPTIONS ("param 1" 'val1') NOT NULL, + c2 text OPTIONS (param2 'val2', param3 'val3') CHECK (c2 <> ''), + c3 date, + CHECK (c3 BETWEEN '1994-01-01'::date AND '1994-01-31'::date) +) SERVER s0 OPTIONS (delimiter ',', quote '"', "be quoted" 'value'); +REVOKE EXECUTE ON FUNCTION test_pg_dump(int) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION test_pg_dump(int) TO regress_dump_test_role; +GRANT SELECT (c1) ON test_pg_dump_t1 TO regress_dump_test_role; +GRANT SELECT ON test_pg_dump_v1 TO regress_dump_test_role; +GRANT USAGE ON FOREIGN DATA WRAPPER dummy TO regress_dump_test_role; +GRANT USAGE ON FOREIGN SERVER s0 TO regress_dump_test_role; +GRANT SELECT (c1) ON ft1 TO regress_dump_test_role; +GRANT SELECT ON ft1 TO regress_dump_test_role; +GRANT UPDATE ON test_pg_dump_mv1 TO regress_dump_test_role; +GRANT USAGE ON SCHEMA test_pg_dump_s1 TO regress_dump_test_role; +GRANT USAGE ON TYPE test_pg_dump_e1 TO regress_dump_test_role; +ALTER EXTENSION test_pg_dump ADD ACCESS METHOD gist2; +ALTER EXTENSION test_pg_dump ADD AGGREGATE newavg(int4); +ALTER EXTENSION test_pg_dump ADD CAST (text AS casttesttype); +ALTER EXTENSION test_pg_dump ADD FOREIGN DATA WRAPPER dummy; +ALTER EXTENSION test_pg_dump ADD FOREIGN TABLE ft1; +ALTER EXTENSION test_pg_dump ADD MATERIALIZED VIEW test_pg_dump_mv1; +ALTER EXTENSION test_pg_dump ADD OPERATOR ==== (int, int); +ALTER EXTENSION test_pg_dump ADD SCHEMA test_pg_dump_s1; +ALTER EXTENSION test_pg_dump ADD SERVER s0; +ALTER EXTENSION test_pg_dump ADD FUNCTION test_pg_dump(int); +ALTER EXTENSION test_pg_dump ADD TABLE test_pg_dump_t1; +ALTER EXTENSION test_pg_dump ADD TYPE test_pg_dump_e1; +ALTER EXTENSION test_pg_dump ADD VIEW test_pg_dump_v1; +REVOKE SELECT (c1) ON test_pg_dump_t1 FROM regress_dump_test_role; +REVOKE SELECT ON test_pg_dump_v1 FROM regress_dump_test_role; +REVOKE USAGE ON FOREIGN DATA WRAPPER dummy FROM regress_dump_test_role; +ALTER EXTENSION test_pg_dump DROP ACCESS METHOD gist2; +ALTER EXTENSION test_pg_dump DROP AGGREGATE newavg(int4); +ALTER EXTENSION test_pg_dump DROP CAST (text AS casttesttype); +ALTER EXTENSION test_pg_dump DROP FOREIGN DATA WRAPPER dummy; +ALTER EXTENSION test_pg_dump DROP FOREIGN TABLE ft1; +ALTER EXTENSION test_pg_dump DROP FUNCTION test_pg_dump(int); +ALTER EXTENSION test_pg_dump DROP MATERIALIZED VIEW test_pg_dump_mv1; +ALTER EXTENSION test_pg_dump DROP OPERATOR ==== (int, int); +ALTER EXTENSION test_pg_dump DROP SCHEMA test_pg_dump_s1; +ALTER EXTENSION test_pg_dump DROP SERVER s0; +ALTER EXTENSION test_pg_dump DROP TABLE test_pg_dump_t1; +ALTER EXTENSION test_pg_dump DROP TYPE test_pg_dump_e1; +ALTER EXTENSION test_pg_dump DROP VIEW test_pg_dump_v1; 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 0000000..a61a7c8 --- /dev/null +++ b/src/test/modules/test_pg_dump/sql/test_pg_dump.sql @@ -0,0 +1,108 @@ +CREATE ROLE regress_dump_test_role; +CREATE EXTENSION test_pg_dump; + +ALTER EXTENSION test_pg_dump ADD DATABASE postgres; -- error + +CREATE TABLE test_pg_dump_t1 (c1 int, junk text); +ALTER TABLE test_pg_dump_t1 DROP COLUMN junk; -- to exercise dropped-col cases +CREATE VIEW test_pg_dump_v1 AS SELECT * FROM test_pg_dump_t1; +CREATE MATERIALIZED VIEW test_pg_dump_mv1 AS SELECT * FROM test_pg_dump_t1; +CREATE SCHEMA test_pg_dump_s1; +CREATE TYPE test_pg_dump_e1 AS ENUM ('abc', 'def'); + +CREATE AGGREGATE newavg ( + sfunc = int4_avg_accum, basetype = int4, stype = _int8, + finalfunc = int8_avg, + initcond1 = '{0,0}' +); + +CREATE FUNCTION test_pg_dump(int) RETURNS int AS $$ +BEGIN +RETURN abs($1); +END +$$ LANGUAGE plpgsql IMMUTABLE; + +CREATE OPERATOR ==== ( + LEFTARG = int, + RIGHTARG = int, + PROCEDURE = int4eq, + COMMUTATOR = ==== +); + +CREATE ACCESS METHOD gist2 TYPE INDEX HANDLER gisthandler; + +CREATE TYPE casttesttype; + +CREATE FUNCTION casttesttype_in(cstring) + RETURNS casttesttype + AS 'textin' + LANGUAGE internal STRICT IMMUTABLE; +CREATE FUNCTION casttesttype_out(casttesttype) + RETURNS cstring + AS 'textout' + LANGUAGE internal STRICT IMMUTABLE; + +CREATE TYPE casttesttype ( + internallength = variable, + input = casttesttype_in, + output = casttesttype_out, + alignment = int4 +); + +CREATE CAST (text AS casttesttype) WITHOUT FUNCTION; + +CREATE FOREIGN DATA WRAPPER dummy; + +CREATE SERVER s0 FOREIGN DATA WRAPPER dummy; + +CREATE FOREIGN TABLE ft1 ( + c1 integer OPTIONS ("param 1" 'val1') NOT NULL, + c2 text OPTIONS (param2 'val2', param3 'val3') CHECK (c2 <> ''), + c3 date, + CHECK (c3 BETWEEN '1994-01-01'::date AND '1994-01-31'::date) +) SERVER s0 OPTIONS (delimiter ',', quote '"', "be quoted" 'value'); + +REVOKE EXECUTE ON FUNCTION test_pg_dump(int) FROM PUBLIC; +GRANT EXECUTE ON FUNCTION test_pg_dump(int) TO regress_dump_test_role; + +GRANT SELECT (c1) ON test_pg_dump_t1 TO regress_dump_test_role; +GRANT SELECT ON test_pg_dump_v1 TO regress_dump_test_role; +GRANT USAGE ON FOREIGN DATA WRAPPER dummy TO regress_dump_test_role; +GRANT USAGE ON FOREIGN SERVER s0 TO regress_dump_test_role; +GRANT SELECT (c1) ON ft1 TO regress_dump_test_role; +GRANT SELECT ON ft1 TO regress_dump_test_role; +GRANT UPDATE ON test_pg_dump_mv1 TO regress_dump_test_role; +GRANT USAGE ON SCHEMA test_pg_dump_s1 TO regress_dump_test_role; +GRANT USAGE ON TYPE test_pg_dump_e1 TO regress_dump_test_role; + +ALTER EXTENSION test_pg_dump ADD ACCESS METHOD gist2; +ALTER EXTENSION test_pg_dump ADD AGGREGATE newavg(int4); +ALTER EXTENSION test_pg_dump ADD CAST (text AS casttesttype); +ALTER EXTENSION test_pg_dump ADD FOREIGN DATA WRAPPER dummy; +ALTER EXTENSION test_pg_dump ADD FOREIGN TABLE ft1; +ALTER EXTENSION test_pg_dump ADD MATERIALIZED VIEW test_pg_dump_mv1; +ALTER EXTENSION test_pg_dump ADD OPERATOR ==== (int, int); +ALTER EXTENSION test_pg_dump ADD SCHEMA test_pg_dump_s1; +ALTER EXTENSION test_pg_dump ADD SERVER s0; +ALTER EXTENSION test_pg_dump ADD FUNCTION test_pg_dump(int); +ALTER EXTENSION test_pg_dump ADD TABLE test_pg_dump_t1; +ALTER EXTENSION test_pg_dump ADD TYPE test_pg_dump_e1; +ALTER EXTENSION test_pg_dump ADD VIEW test_pg_dump_v1; + +REVOKE SELECT (c1) ON test_pg_dump_t1 FROM regress_dump_test_role; +REVOKE SELECT ON test_pg_dump_v1 FROM regress_dump_test_role; +REVOKE USAGE ON FOREIGN DATA WRAPPER dummy FROM regress_dump_test_role; + +ALTER EXTENSION test_pg_dump DROP ACCESS METHOD gist2; +ALTER EXTENSION test_pg_dump DROP AGGREGATE newavg(int4); +ALTER EXTENSION test_pg_dump DROP CAST (text AS casttesttype); +ALTER EXTENSION test_pg_dump DROP FOREIGN DATA WRAPPER dummy; +ALTER EXTENSION test_pg_dump DROP FOREIGN TABLE ft1; +ALTER EXTENSION test_pg_dump DROP FUNCTION test_pg_dump(int); +ALTER EXTENSION test_pg_dump DROP MATERIALIZED VIEW test_pg_dump_mv1; +ALTER EXTENSION test_pg_dump DROP OPERATOR ==== (int, int); +ALTER EXTENSION test_pg_dump DROP SCHEMA test_pg_dump_s1; +ALTER EXTENSION test_pg_dump DROP SERVER s0; +ALTER EXTENSION test_pg_dump DROP TABLE test_pg_dump_t1; +ALTER EXTENSION test_pg_dump DROP TYPE test_pg_dump_e1; +ALTER EXTENSION test_pg_dump DROP VIEW test_pg_dump_v1; 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 0000000..f5da6bf --- /dev/null +++ b/src/test/modules/test_pg_dump/t/001_base.pl @@ -0,0 +1,844 @@ + +# Copyright (c) 2021-2022, PostgreSQL Global Development Group + +use strict; +use warnings; + +use PostgreSQL::Test::Cluster; +use PostgreSQL::Test::Utils; +use Test::More; + +my $tempdir = PostgreSQL::Test::Utils::tempdir; + +############################################################### +# 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 +# PostgreSQL::Test::Cluster 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', '--no-sync', + "--file=$tempdir/binary_upgrade.sql", '--schema-only', + '--binary-upgrade', '--dbname=postgres', + ], + }, + clean => { + dump_cmd => [ + 'pg_dump', "--file=$tempdir/clean.sql", + '-c', '--no-sync', + '--dbname=postgres', + ], + }, + clean_if_exists => { + dump_cmd => [ + 'pg_dump', + '--no-sync', + "--file=$tempdir/clean_if_exists.sql", + '-c', + '--if-exists', + '--encoding=UTF8', # no-op, just tests that option is accepted + 'postgres', + ], + }, + createdb => { + dump_cmd => [ + 'pg_dump', + '--no-sync', + "--file=$tempdir/createdb.sql", + '-C', + '-R', # no-op, just for testing + 'postgres', + ], + }, + data_only => { + dump_cmd => [ + 'pg_dump', + '--no-sync', + "--file=$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', '--no-sync', '-Fc', '-Z6', + "--file=$tempdir/defaults_custom_format.dump", 'postgres', + ], + restore_cmd => [ + 'pg_restore', + "--file=$tempdir/defaults_custom_format.sql", + "$tempdir/defaults_custom_format.dump", + ], + }, + defaults_dir_format => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', '--no-sync', '-Fd', + "--file=$tempdir/defaults_dir_format", 'postgres', + ], + restore_cmd => [ + 'pg_restore', + "--file=$tempdir/defaults_dir_format.sql", + "$tempdir/defaults_dir_format", + ], + }, + defaults_parallel => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', '--no-sync', '-Fd', '-j2', + "--file=$tempdir/defaults_parallel", 'postgres', + ], + restore_cmd => [ + 'pg_restore', + "--file=$tempdir/defaults_parallel.sql", + "$tempdir/defaults_parallel", + ], + }, + defaults_tar_format => { + test_key => 'defaults', + dump_cmd => [ + 'pg_dump', '--no-sync', '-Ft', + "--file=$tempdir/defaults_tar_format.tar", 'postgres', + ], + restore_cmd => [ + 'pg_restore', + "--file=$tempdir/defaults_tar_format.sql", + "$tempdir/defaults_tar_format.tar", + ], + }, + exclude_table => { + dump_cmd => [ + 'pg_dump', + '--exclude-table=regress_table_dumpable', + "--file=$tempdir/exclude_table.sql", + 'postgres', + ], + }, + extension_schema => { + dump_cmd => [ + 'pg_dump', '--schema=public', + "--file=$tempdir/extension_schema.sql", 'postgres', + ], + }, + pg_dumpall_globals => { + dump_cmd => [ + 'pg_dumpall', '--no-sync', + "--file=$tempdir/pg_dumpall_globals.sql", '-g', + ], + }, + no_privs => { + dump_cmd => [ + 'pg_dump', '--no-sync', + "--file=$tempdir/no_privs.sql", '-x', + 'postgres', + ], + }, + no_owner => { + dump_cmd => [ + 'pg_dump', '--no-sync', + "--file=$tempdir/no_owner.sql", '-O', + 'postgres', + ], + }, + schema_only => { + dump_cmd => [ + 'pg_dump', '--no-sync', "--file=$tempdir/schema_only.sql", + '-s', 'postgres', + ], + }, + section_pre_data => { + dump_cmd => [ + 'pg_dump', '--no-sync', + "--file=$tempdir/section_pre_data.sql", '--section=pre-data', + 'postgres', + ], + }, + section_data => { + dump_cmd => [ + 'pg_dump', '--no-sync', + "--file=$tempdir/section_data.sql", '--section=data', + 'postgres', + ], + }, + section_post_data => { + dump_cmd => [ + 'pg_dump', '--no-sync', "--file=$tempdir/section_post_data.sql", + '--section=post-data', 'postgres', + ], + }, + with_extension => { + dump_cmd => [ + 'pg_dump', '--no-sync', "--file=$tempdir/with_extension.sql", + '--extension=test_pg_dump', 'postgres', + ], + }, + + # plgsql in the list blocks the dump of extension test_pg_dump + without_extension => { + dump_cmd => [ + 'pg_dump', '--no-sync', "--file=$tempdir/without_extension.sql", + '--extension=plpgsql', 'postgres', + ], + }, + + # plgsql in the list of extensions blocks the dump of extension + # test_pg_dump. "public" is the schema used by the extension + # test_pg_dump, but none of its objects should be dumped. + without_extension_explicit_schema => { + dump_cmd => [ + 'pg_dump', + '--no-sync', + "--file=$tempdir/without_extension_explicit_schema.sql", + '--extension=plpgsql', + '--schema=public', + 'postgres', + ], + }, + + # plgsql in the list of extensions blocks the dump of extension + # test_pg_dump, but not the dump of objects not dependent on the + # extension located on a schema maintained by the extension. + without_extension_internal_schema => { + dump_cmd => [ + 'pg_dump', + '--no-sync', + "--file=$tempdir/without_extension_internal_schema.sql", + '--extension=plpgsql', + '--schema=regress_pg_dump_schema', + '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. +# The runs listed as 'like' will be checked if they match the +# regexp and, if so, the test passes. All runs which are not +# listed as 'like' will be checked to ensure they don't match +# the regexp; if they do, the test will fail. +# +# The below hashes provide convenience sets of runs. Individual +# runs can be excluded from a general hash by placing that run +# into the 'unlike' section. +# +# 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. + +# Tests which are considered 'full' dumps by pg_dump, but there +# are flags used to exclude specific items (ACLs, blobs, etc). +my %full_runs = ( + binary_upgrade => 1, + clean => 1, + clean_if_exists => 1, + createdb => 1, + defaults => 1, + exclude_table => 1, + no_privs => 1, + no_owner => 1, + with_extension => 1, + without_extension => 1); + +my %tests = ( + 'ALTER EXTENSION test_pg_dump' => { + create_order => 9, + create_sql => + 'ALTER EXTENSION test_pg_dump ADD TABLE regress_pg_dump_table_added;', + regexp => qr/^ + \QCREATE TABLE public.regress_pg_dump_table_added (\E + \n\s+\Qcol1 integer NOT NULL,\E + \n\s+\Qcol2 integer\E + \n\);\n/xm, + like => { binary_upgrade => 1, }, + }, + + '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 + \n/xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { binary_upgrade => 1, without_extension => 1 }, + }, + + 'CREATE ROLE regress_dump_test_role' => { + create_order => 1, + create_sql => 'CREATE ROLE regress_dump_test_role;', + regexp => qr/^CREATE ROLE regress_dump_test_role;\n/m, + like => { pg_dumpall_globals => 1, }, + }, + + 'GRANT ALTER SYSTEM ON PARAMETER full_page_writes TO regress_dump_test_role' + => { + create_order => 2, + create_sql => + 'GRANT ALTER SYSTEM ON PARAMETER full_page_writes TO regress_dump_test_role;', + regexp => + + qr/^GRANT ALTER SYSTEM ON PARAMETER full_page_writes TO regress_dump_test_role;/m, + like => { pg_dumpall_globals => 1, }, + }, + + 'GRANT ALL ON PARAMETER Custom.Knob TO regress_dump_test_role WITH GRANT OPTION' + => { + create_order => 2, + create_sql => + 'GRANT SET, ALTER SYSTEM ON PARAMETER Custom.Knob TO regress_dump_test_role WITH GRANT OPTION;', + regexp => + # "set" plus "alter system" is "all" privileges on parameters + qr/^GRANT ALL ON PARAMETER "custom.knob" TO regress_dump_test_role WITH GRANT OPTION;/m, + like => { pg_dumpall_globals => 1, }, + }, + + 'GRANT ALL ON PARAMETER DateStyle TO regress_dump_test_role' => { + create_order => 2, + create_sql => + 'GRANT ALL ON PARAMETER "DateStyle" TO regress_dump_test_role WITH GRANT OPTION; REVOKE GRANT OPTION FOR ALL ON PARAMETER DateStyle FROM regress_dump_test_role;', + regexp => + # The revoke simplifies the ultimate grant so as to not include "with grant option" + qr/^GRANT ALL ON PARAMETER datestyle TO regress_dump_test_role;/m, + like => { pg_dumpall_globals => 1, }, + }, + + 'CREATE SCHEMA public' => { + regexp => qr/^CREATE SCHEMA public;/m, + like => { + extension_schema => 1, + without_extension_explicit_schema => 1, + }, + }, + + 'CREATE SEQUENCE regress_pg_dump_table_col1_seq' => { + regexp => qr/^ + \QCREATE SEQUENCE public.regress_pg_dump_table_col1_seq\E + \n\s+\QAS integer\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 + \n/xm, + like => { binary_upgrade => 1, }, + }, + + 'CREATE TABLE regress_pg_dump_table_added' => { + create_order => 7, + create_sql => + 'CREATE TABLE regress_pg_dump_table_added (col1 int not null, col2 int);', + regexp => qr/^ + \QCREATE TABLE public.regress_pg_dump_table_added (\E + \n\s+\Qcol1 integer NOT NULL,\E + \n\s+\Qcol2 integer\E + \n\);\n/xm, + like => { binary_upgrade => 1, }, + }, + + 'CREATE SEQUENCE regress_pg_dump_seq' => { + regexp => qr/^ + \QCREATE SEQUENCE public.regress_pg_dump_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 + \n/xm, + like => { binary_upgrade => 1, }, + }, + + 'SETVAL SEQUENCE regress_seq_dumpable' => { + create_order => 6, + create_sql => qq{SELECT nextval('regress_seq_dumpable');}, + regexp => qr/^ + \QSELECT pg_catalog.setval('public.regress_seq_dumpable', 1, true);\E + \n/xm, + like => { + %full_runs, + data_only => 1, + section_data => 1, + extension_schema => 1, + }, + unlike => { without_extension => 1, }, + }, + + 'CREATE TABLE regress_pg_dump_table' => { + regexp => qr/^ + \QCREATE TABLE public.regress_pg_dump_table (\E + \n\s+\Qcol1 integer NOT NULL,\E + \n\s+\Qcol2 integer,\E + \n\s+\QCONSTRAINT regress_pg_dump_table_col2_check CHECK ((col2 > 0))\E + \n\);\n/xm, + like => { binary_upgrade => 1, }, + }, + + 'COPY public.regress_table_dumpable (col1)' => { + regexp => qr/^ + \QCOPY public.regress_table_dumpable (col1) FROM stdin;\E + \n/xm, + like => { + %full_runs, + data_only => 1, + section_data => 1, + extension_schema => 1, + }, + unlike => { + binary_upgrade => 1, + exclude_table => 1, + without_extension => 1, + }, + }, + + 'REVOKE ALL ON FUNCTION wgo_then_no_access' => { + create_order => 3, + create_sql => q{ + DO $$BEGIN EXECUTE format( + 'REVOKE ALL ON FUNCTION wgo_then_no_access() + FROM pg_signal_backend, public, %I', + (SELECT usename + FROM pg_user JOIN pg_proc ON proowner = usesysid + WHERE proname = 'wgo_then_no_access')); END$$;}, + regexp => qr/^ + \QREVOKE ALL ON FUNCTION public.wgo_then_no_access() FROM PUBLIC;\E + \n\QREVOKE ALL ON FUNCTION public.wgo_then_no_access() FROM \E.*; + \n\QREVOKE ALL ON FUNCTION public.wgo_then_no_access() FROM pg_signal_backend;\E + /xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { no_privs => 1, without_extension => 1, }, + }, + + 'REVOKE GRANT OPTION FOR UPDATE ON SEQUENCE wgo_then_regular' => { + create_order => 3, + create_sql => 'REVOKE GRANT OPTION FOR UPDATE ON SEQUENCE + wgo_then_regular FROM pg_signal_backend;', + regexp => qr/^ + \QREVOKE ALL ON SEQUENCE public.wgo_then_regular FROM pg_signal_backend;\E + \n\QGRANT SELECT,UPDATE ON SEQUENCE public.wgo_then_regular TO pg_signal_backend;\E + \n\QGRANT USAGE ON SEQUENCE public.wgo_then_regular TO pg_signal_backend WITH GRANT OPTION;\E + /xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { no_privs => 1, without_extension => 1, }, + }, + + 'CREATE ACCESS METHOD regress_test_am' => { + regexp => qr/^ + \QCREATE ACCESS METHOD regress_test_am TYPE INDEX HANDLER bthandler;\E + \n/xm, + like => { binary_upgrade => 1, }, + }, + + 'COMMENT ON EXTENSION test_pg_dump' => { + regexp => qr/^ + \QCOMMENT ON EXTENSION test_pg_dump \E + \QIS 'Test pg_dump with an extension';\E + \n/xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { without_extension => 1, }, + }, + + 'GRANT SELECT regress_pg_dump_table_added pre-ALTER EXTENSION' => { + create_order => 8, + create_sql => + 'GRANT SELECT ON regress_pg_dump_table_added TO regress_dump_test_role;', + regexp => qr/^ + \QGRANT SELECT ON TABLE public.regress_pg_dump_table_added TO regress_dump_test_role;\E + \n/xm, + like => { binary_upgrade => 1, }, + }, + + 'REVOKE SELECT regress_pg_dump_table_added post-ALTER EXTENSION' => { + create_order => 10, + create_sql => + 'REVOKE SELECT ON regress_pg_dump_table_added FROM regress_dump_test_role;', + regexp => qr/^ + \QREVOKE SELECT ON TABLE public.regress_pg_dump_table_added FROM regress_dump_test_role;\E + \n/xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { no_privs => 1, without_extension => 1, }, + }, + + 'GRANT SELECT ON TABLE regress_pg_dump_table' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT SELECT ON TABLE public.regress_pg_dump_table TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + }, + + 'GRANT SELECT(col1) ON regress_pg_dump_table' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT SELECT(col1) ON TABLE public.regress_pg_dump_table TO PUBLIC;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + }, + + 'GRANT SELECT(col2) ON regress_pg_dump_table TO regress_dump_test_role' + => { + create_order => 4, + create_sql => 'GRANT SELECT(col2) ON regress_pg_dump_table + TO regress_dump_test_role;', + regexp => qr/^ + \QGRANT SELECT(col2) ON TABLE public.regress_pg_dump_table TO regress_dump_test_role;\E + \n/xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { no_privs => 1, without_extension => 1 }, + }, + + 'GRANT USAGE ON regress_pg_dump_table_col1_seq TO regress_dump_test_role' + => { + create_order => 5, + create_sql => 'GRANT USAGE ON SEQUENCE regress_pg_dump_table_col1_seq + TO regress_dump_test_role;', + regexp => qr/^ + \QGRANT USAGE ON SEQUENCE public.regress_pg_dump_table_col1_seq TO regress_dump_test_role;\E + \n/xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { no_privs => 1, without_extension => 1, }, + }, + + 'GRANT USAGE ON regress_pg_dump_seq TO regress_dump_test_role' => { + regexp => qr/^ + \QGRANT USAGE ON SEQUENCE public.regress_pg_dump_seq TO regress_dump_test_role;\E + \n/xm, + like => { binary_upgrade => 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 public.regress_pg_dump_table FROM PUBLIC;\E + \n/xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + }, + unlike => { no_privs => 1, without_extension => 1, }, + }, + + # Objects included in extension part of a schema created by this extension */ + 'CREATE TABLE regress_pg_dump_schema.test_table' => { + regexp => qr/^ + \QCREATE TABLE regress_pg_dump_schema.test_table (\E + \n\s+\Qcol1 integer,\E + \n\s+\Qcol2 integer,\E + \n\s+\QCONSTRAINT test_table_col2_check CHECK ((col2 > 0))\E + \n\);\n/xm, + like => { binary_upgrade => 1, }, + }, + + 'GRANT SELECT ON regress_pg_dump_schema.test_table' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT SELECT ON TABLE regress_pg_dump_schema.test_table TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + }, + + 'CREATE SEQUENCE regress_pg_dump_schema.test_seq' => { + regexp => qr/^ + \QCREATE SEQUENCE regress_pg_dump_schema.test_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 + \n/xm, + like => { binary_upgrade => 1, }, + }, + + 'GRANT USAGE ON regress_pg_dump_schema.test_seq' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT USAGE ON SEQUENCE regress_pg_dump_schema.test_seq TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + }, + + 'CREATE TYPE regress_pg_dump_schema.test_type' => { + regexp => qr/^ + \QCREATE TYPE regress_pg_dump_schema.test_type AS (\E + \n\s+\Qcol1 integer\E + \n\);\n/xm, + like => { binary_upgrade => 1, }, + }, + + 'GRANT USAGE ON regress_pg_dump_schema.test_type' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT ALL ON TYPE regress_pg_dump_schema.test_type TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + }, + + 'CREATE FUNCTION regress_pg_dump_schema.test_func' => { + regexp => qr/^ + \QCREATE FUNCTION regress_pg_dump_schema.test_func() RETURNS integer\E + \n\s+\QLANGUAGE sql\E + \n/xm, + like => { binary_upgrade => 1, }, + }, + + 'GRANT ALL ON regress_pg_dump_schema.test_func' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT ALL ON FUNCTION regress_pg_dump_schema.test_func() TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + }, + + 'CREATE AGGREGATE regress_pg_dump_schema.test_agg' => { + regexp => qr/^ + \QCREATE AGGREGATE regress_pg_dump_schema.test_agg(smallint) (\E + \n\s+\QSFUNC = int2_sum,\E + \n\s+\QSTYPE = bigint\E + \n\);\n/xm, + like => { binary_upgrade => 1, }, + }, + + 'GRANT ALL ON regress_pg_dump_schema.test_agg' => { + regexp => qr/^ + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\E\n + \QGRANT ALL ON FUNCTION regress_pg_dump_schema.test_agg(smallint) TO regress_dump_test_role;\E\n + \QSELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\E + \n/xms, + like => { binary_upgrade => 1, }, + }, + + 'ALTER INDEX pkey DEPENDS ON extension' => { + create_order => 11, + create_sql => + 'CREATE TABLE regress_pg_dump_schema.extdependtab (col1 integer primary key, col2 int); + CREATE INDEX ON regress_pg_dump_schema.extdependtab (col2); + ALTER INDEX regress_pg_dump_schema.extdependtab_col2_idx DEPENDS ON EXTENSION test_pg_dump; + ALTER INDEX regress_pg_dump_schema.extdependtab_pkey DEPENDS ON EXTENSION test_pg_dump;', + regexp => qr/^ + \QALTER INDEX regress_pg_dump_schema.extdependtab_pkey DEPENDS ON EXTENSION test_pg_dump;\E\n + /xms, + like => {%pgdump_runs}, + unlike => { + data_only => 1, + extension_schema => 1, + pg_dumpall_globals => 1, + section_data => 1, + section_pre_data => 1, + # Excludes this schema as extension is not listed. + without_extension_explicit_schema => 1, + }, + }, + + 'ALTER INDEX idx DEPENDS ON extension' => { + regexp => qr/^ + \QALTER INDEX regress_pg_dump_schema.extdependtab_col2_idx DEPENDS ON EXTENSION test_pg_dump;\E\n + /xms, + like => {%pgdump_runs}, + unlike => { + data_only => 1, + extension_schema => 1, + pg_dumpall_globals => 1, + section_data => 1, + section_pre_data => 1, + # Excludes this schema as extension is not listed. + without_extension_explicit_schema => 1, + }, + }, + + # Objects not included in extension, part of schema created by extension + 'CREATE TABLE regress_pg_dump_schema.external_tab' => { + create_order => 4, + create_sql => 'CREATE TABLE regress_pg_dump_schema.external_tab + (col1 int);', + regexp => qr/^ + \QCREATE TABLE regress_pg_dump_schema.external_tab (\E + \n\s+\Qcol1 integer\E + \n\);\n/xm, + like => { + %full_runs, + schema_only => 1, + section_pre_data => 1, + # Excludes the extension and keeps the schema's data. + without_extension_internal_schema => 1, + }, + },); + +######################################### +# Create a PG instance to test actually dumping from + +my $node = PostgreSQL::Test::Cluster->new('main'); +$node->init; +$node->start; + +my $port = $node->port; + +######################################### +# 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) + { + # Run the test listed as a like, unless it is specifically noted + # as an unlike (generally due to an explicit exclusion or similar). + if ($tests{$test}->{like}->{$test_key} + && !defined($tests{$test}->{unlike}->{$test_key})) + { + if (!ok($output_file =~ $tests{$test}->{regexp}, + "$run: should dump $test")) + { + diag("Review $run results in $tempdir"); + } + } + else + { + if (!ok($output_file !~ $tests{$test}->{regexp}, + "$run: should not dump $test")) + { + diag("Review $run results in $tempdir"); + } + } + } +} + +######################################### +# Stop the database instance, which will be removed at the end of the tests. + +$node->stop('fast'); + +done_testing(); 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 0000000..110f7ee --- /dev/null +++ b/src/test/modules/test_pg_dump/test_pg_dump--1.0.sql @@ -0,0 +1,62 @@ +/* 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 serial, + col2 int check (col2 > 0) +); + +CREATE SEQUENCE regress_pg_dump_seq; + +CREATE SEQUENCE regress_seq_dumpable; +SELECT pg_catalog.pg_extension_config_dump('regress_seq_dumpable', ''); + +CREATE TABLE regress_table_dumpable ( + col1 int check (col1 > 0) +); +SELECT pg_catalog.pg_extension_config_dump('regress_table_dumpable', ''); + +CREATE SCHEMA regress_pg_dump_schema; + +GRANT USAGE ON regress_pg_dump_seq TO regress_dump_test_role; + +GRANT SELECT ON regress_pg_dump_table TO regress_dump_test_role; +GRANT SELECT(col1) ON regress_pg_dump_table TO public; + +GRANT SELECT(col2) ON regress_pg_dump_table TO regress_dump_test_role; +REVOKE SELECT(col2) ON regress_pg_dump_table FROM regress_dump_test_role; + +CREATE FUNCTION wgo_then_no_access() RETURNS int LANGUAGE SQL AS 'SELECT 1'; +GRANT ALL ON FUNCTION wgo_then_no_access() + TO pg_signal_backend WITH GRANT OPTION; + +CREATE SEQUENCE wgo_then_regular; +GRANT ALL ON SEQUENCE wgo_then_regular TO pg_signal_backend WITH GRANT OPTION; +REVOKE GRANT OPTION FOR SELECT ON SEQUENCE wgo_then_regular + FROM pg_signal_backend; + +CREATE ACCESS METHOD regress_test_am TYPE INDEX HANDLER bthandler; + +-- Create a set of objects that are part of the schema created by +-- this extension. +CREATE TABLE regress_pg_dump_schema.test_table ( + col1 int, + col2 int check (col2 > 0) +); +GRANT SELECT ON regress_pg_dump_schema.test_table TO regress_dump_test_role; + +CREATE SEQUENCE regress_pg_dump_schema.test_seq; +GRANT USAGE ON regress_pg_dump_schema.test_seq TO regress_dump_test_role; + +CREATE TYPE regress_pg_dump_schema.test_type AS (col1 int); +GRANT USAGE ON TYPE regress_pg_dump_schema.test_type TO regress_dump_test_role; + +CREATE FUNCTION regress_pg_dump_schema.test_func () RETURNS int +AS 'SELECT 1;' LANGUAGE SQL; +GRANT EXECUTE ON FUNCTION regress_pg_dump_schema.test_func() TO regress_dump_test_role; + +CREATE AGGREGATE regress_pg_dump_schema.test_agg(int2) +(SFUNC = int2_sum, STYPE = int8); +GRANT EXECUTE ON FUNCTION regress_pg_dump_schema.test_agg(int2) TO regress_dump_test_role; 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 0000000..fe3450d --- /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 |