1
2# Copyright (c) 2021, PostgreSQL Global Development Group
3
4use strict;
5use warnings;
6
7use PostgresNode;
8use TestLib;
9use Test::More;
10
11if ($TestLib::is_msys2)
12{
13	plan skip_all => 'High bit name tests fail on Msys2';
14}
15else
16{
17	plan tests => 14;
18}
19
20# We're going to use byte sequences that aren't valid UTF-8 strings.  Use
21# LATIN1, which accepts any byte and has a conversion from each byte to UTF-8.
22$ENV{LC_ALL}           = 'C';
23$ENV{PGCLIENTENCODING} = 'LATIN1';
24
25# Create database and user names covering the range of LATIN1
26# characters, for use in a connection string by pg_dumpall.  Skip ','
27# because of pg_regress --create-role, skip [\n\r] because pg_dumpall
28# does not allow them.  We also skip many ASCII letters, to keep the
29# total number of tested characters to what will fit in four names.
30# The odds of finding something interesting by testing all ASCII letters
31# seem too small to justify the cycles of testing a fifth name.
32my $dbname1 =
33    'regression'
34  . generate_ascii_string(1,  9)
35  . generate_ascii_string(11, 12)
36  . generate_ascii_string(14, 33)
37  . ($TestLib::windows_os ? '' : '"x"')   # IPC::Run mishandles '"' on Windows
38  . generate_ascii_string(35, 43)         # skip ','
39  . generate_ascii_string(45, 54);
40my $dbname2 = 'regression' . generate_ascii_string(55, 65)    # skip 'B'-'W'
41  . generate_ascii_string(88,  99)                            # skip 'd'-'w'
42  . generate_ascii_string(120, 149);
43my $dbname3 = 'regression' . generate_ascii_string(150, 202);
44my $dbname4 = 'regression' . generate_ascii_string(203, 255);
45
46(my $username1 = $dbname1) =~ s/^regression/regress_/;
47(my $username2 = $dbname2) =~ s/^regression/regress_/;
48(my $username3 = $dbname3) =~ s/^regression/regress_/;
49(my $username4 = $dbname4) =~ s/^regression/regress_/;
50
51my $src_bootstrap_super = 'regress_postgres';
52my $dst_bootstrap_super = 'boot';
53
54my $node = get_new_node('main');
55$node->init(extra =>
56	  [ '-U', $src_bootstrap_super, '--locale=C', '--encoding=LATIN1' ]);
57
58# prep pg_hba.conf and pg_ident.conf
59$node->run_log(
60	[
61		$ENV{PG_REGRESS},     '--config-auth',
62		$node->data_dir,      '--user',
63		$src_bootstrap_super, '--create-role',
64		"$username1,$username2,$username3,$username4"
65	]);
66$node->start;
67
68my $backupdir = $node->backup_dir;
69my $discard   = "$backupdir/discard.sql";
70my $plain     = "$backupdir/plain.sql";
71my $dirfmt    = "$backupdir/dirfmt";
72
73$node->run_log([ 'createdb', '-U', $src_bootstrap_super, $dbname1 ]);
74$node->run_log(
75	[ 'createuser', '-U', $src_bootstrap_super, '-s', $username1 ]);
76$node->run_log([ 'createdb', '-U', $src_bootstrap_super, $dbname2 ]);
77$node->run_log(
78	[ 'createuser', '-U', $src_bootstrap_super, '-s', $username2 ]);
79$node->run_log([ 'createdb', '-U', $src_bootstrap_super, $dbname3 ]);
80$node->run_log(
81	[ 'createuser', '-U', $src_bootstrap_super, '-s', $username3 ]);
82$node->run_log([ 'createdb', '-U', $src_bootstrap_super, $dbname4 ]);
83$node->run_log(
84	[ 'createuser', '-U', $src_bootstrap_super, '-s', $username4 ]);
85
86
87# For these tests, pg_dumpall -r is used because it produces a short
88# dump.
89$node->command_ok(
90	[
91		'pg_dumpall', '-r', '-f', $discard, '--dbname',
92		$node->connstr($dbname1),
93		'-U', $username4
94	],
95	'pg_dumpall with long ASCII name 1');
96$node->command_ok(
97	[
98		'pg_dumpall', '--no-sync', '-r', '-f', $discard, '--dbname',
99		$node->connstr($dbname2),
100		'-U', $username3
101	],
102	'pg_dumpall with long ASCII name 2');
103$node->command_ok(
104	[
105		'pg_dumpall', '--no-sync', '-r', '-f', $discard, '--dbname',
106		$node->connstr($dbname3),
107		'-U', $username2
108	],
109	'pg_dumpall with long ASCII name 3');
110$node->command_ok(
111	[
112		'pg_dumpall', '--no-sync', '-r', '-f', $discard, '--dbname',
113		$node->connstr($dbname4),
114		'-U', $username1
115	],
116	'pg_dumpall with long ASCII name 4');
117$node->command_ok(
118	[
119		'pg_dumpall',         '-U',
120		$src_bootstrap_super, '--no-sync',
121		'-r',                 '-l',
122		'dbname=template1'
123	],
124	'pg_dumpall -l accepts connection string');
125
126$node->run_log([ 'createdb', '-U', $src_bootstrap_super, "foo\n\rbar" ]);
127
128# not sufficient to use -r here
129$node->command_fails(
130	[ 'pg_dumpall', '-U', $src_bootstrap_super, '--no-sync', '-f', $discard ],
131	'pg_dumpall with \n\r in database name');
132$node->run_log([ 'dropdb', '-U', $src_bootstrap_super, "foo\n\rbar" ]);
133
134
135# make a table, so the parallel worker has something to dump
136$node->safe_psql(
137	$dbname1,
138	'CREATE TABLE t0()',
139	extra_params => [ '-U', $src_bootstrap_super ]);
140
141# XXX no printed message when this fails, just SIGPIPE termination
142$node->command_ok(
143	[
144		'pg_dump', '-Fd', '--no-sync', '-j2', '-f', $dirfmt, '-U', $username1,
145		$node->connstr($dbname1)
146	],
147	'parallel dump');
148
149# recreate $dbname1 for restore test
150$node->run_log([ 'dropdb',   '-U', $src_bootstrap_super, $dbname1 ]);
151$node->run_log([ 'createdb', '-U', $src_bootstrap_super, $dbname1 ]);
152
153$node->command_ok(
154	[
155		'pg_restore', '-v', '-d',       'template1',
156		'-j2',        '-U', $username1, $dirfmt
157	],
158	'parallel restore');
159
160$node->run_log([ 'dropdb', '-U', $src_bootstrap_super, $dbname1 ]);
161
162$node->command_ok(
163	[
164		'pg_restore', '-C',  '-v', '-d',
165		'template1',  '-j2', '-U', $username1,
166		$dirfmt
167	],
168	'parallel restore with create');
169
170
171$node->command_ok(
172	[ 'pg_dumpall', '--no-sync', '-f', $plain, '-U', $username1 ],
173	'take full dump');
174system_log('cat', $plain);
175my ($stderr, $result);
176my $restore_super = qq{regress_a'b\\c=d\\ne"f};
177$restore_super =~ s/"//g
178  if $TestLib::windows_os;    # IPC::Run mishandles '"' on Windows
179
180
181# Restore full dump through psql using environment variables for
182# dbname/user connection parameters
183
184my $envar_node = get_new_node('destination_envar');
185$envar_node->init(
186	extra =>
187	  [ '-U', $dst_bootstrap_super, '--locale=C', '--encoding=LATIN1' ],
188	auth_extra =>
189	  [ '--user', $dst_bootstrap_super, '--create-role', $restore_super ]);
190$envar_node->start;
191
192# make superuser for restore
193$envar_node->run_log(
194	[ 'createuser', '-U', $dst_bootstrap_super, '-s', $restore_super ]);
195
196{
197	local $ENV{PGPORT} = $envar_node->port;
198	local $ENV{PGUSER} = $restore_super;
199	$result = run_log([ 'psql', '-X', '-f', $plain ], '2>', \$stderr);
200}
201ok($result,
202	'restore full dump using environment variables for connection parameters'
203);
204is($stderr, '', 'no dump errors');
205
206
207# Restore full dump through psql using command-line options for
208# dbname/user connection parameters.  "\connect dbname=" forgets
209# user/port from command line.
210
211my $cmdline_node = get_new_node('destination_cmdline');
212$cmdline_node->init(
213	extra =>
214	  [ '-U', $dst_bootstrap_super, '--locale=C', '--encoding=LATIN1' ],
215	auth_extra =>
216	  [ '--user', $dst_bootstrap_super, '--create-role', $restore_super ]);
217$cmdline_node->start;
218$cmdline_node->run_log(
219	[ 'createuser', '-U', $dst_bootstrap_super, '-s', $restore_super ]);
220{
221	$result = run_log(
222		[
223			'psql',         '-p', $cmdline_node->port, '-U',
224			$restore_super, '-X', '-f',                $plain
225		],
226		'2>',
227		\$stderr);
228}
229ok($result,
230	'restore full dump with command-line options for connection parameters');
231is($stderr, '', 'no dump errors');
232