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