Commit ce554810 authored by Bruce Momjian's avatar Bruce Momjian

Post-PG 10 beta1 pgperltidy run

parent a6fd7b7a
...@@ -92,7 +92,8 @@ if ($opt{v}) ...@@ -92,7 +92,8 @@ if ($opt{v})
if ($opt{e}) if ($opt{e})
{ {
my @plan = map { "$_->[0]\n" } @{$dbi->selectall_arrayref("explain $sql")}; my @plan =
map { "$_->[0]\n" } @{ $dbi->selectall_arrayref("explain $sql") };
print @plan; print @plan;
} }
......
...@@ -80,10 +80,11 @@ sub Catalogs ...@@ -80,10 +80,11 @@ sub Catalogs
{ {
$catalog{natts} = $1; $catalog{natts} = $1;
} }
elsif (/^DATA\(insert(\s+OID\s+=\s+(\d+))?\s+\(\s*(.*)\s*\)\s*\)$/) elsif (
/^DATA\(insert(\s+OID\s+=\s+(\d+))?\s+\(\s*(.*)\s*\)\s*\)$/)
{ {
check_natts($filename, $catalog{natts}, $3, check_natts($filename, $catalog{natts}, $3, $input_file,
$input_file, $input_line_number); $input_line_number);
push @{ $catalog{data} }, { oid => $2, bki_values => $3 }; push @{ $catalog{data} }, { oid => $2, bki_values => $3 };
} }
...@@ -256,14 +257,15 @@ sub check_natts ...@@ -256,14 +257,15 @@ sub check_natts
{ {
my ($catname, $natts, $bki_val, $file, $line) = @_; my ($catname, $natts, $bki_val, $file, $line) = @_;
die "Could not find definition for Natts_${catname} before start of DATA() in $file\n" die
unless defined $natts; "Could not find definition for Natts_${catname} before start of DATA() in $file\n"
unless defined $natts;
my $nfields = scalar(SplitDataLine($bki_val)); my $nfields = scalar(SplitDataLine($bki_val));
die sprintf die sprintf
"Wrong number of attributes in DATA() entry at %s:%d (expected %d but got %d)\n", "Wrong number of attributes in DATA() entry at %s:%d (expected %d but got %d)\n",
$file, $line, $natts, $nfields $file, $line, $natts, $nfields
unless $natts == $nfields; unless $natts == $nfields;
} }
......
...@@ -163,11 +163,13 @@ foreach my $catname (@{ $catalogs->{names} }) ...@@ -163,11 +163,13 @@ foreach my $catname (@{ $catalogs->{names} })
# Split line into tokens without interpreting their meaning. # Split line into tokens without interpreting their meaning.
my %bki_values; my %bki_values;
@bki_values{@attnames} = Catalog::SplitDataLine($row->{bki_values}); @bki_values{@attnames} =
Catalog::SplitDataLine($row->{bki_values});
# Perform required substitutions on fields # Perform required substitutions on fields
foreach my $att (keys %bki_values) foreach my $att (keys %bki_values)
{ {
# Substitute constant values we acquired above. # Substitute constant values we acquired above.
# (It's intentional that this can apply to parts of a field). # (It's intentional that this can apply to parts of a field).
$bki_values{$att} =~ s/\bPGUID\b/$BOOTSTRAP_SUPERUSERID/g; $bki_values{$att} =~ s/\bPGUID\b/$BOOTSTRAP_SUPERUSERID/g;
...@@ -178,9 +180,9 @@ foreach my $catname (@{ $catalogs->{names} }) ...@@ -178,9 +180,9 @@ foreach my $catname (@{ $catalogs->{names} })
# just do nothing (regprocin will complain). # just do nothing (regprocin will complain).
if ($bki_attr{$att}->{type} eq 'regproc') if ($bki_attr{$att}->{type} eq 'regproc')
{ {
my $procoid = $regprocoids{$bki_values{$att}}; my $procoid = $regprocoids{ $bki_values{$att} };
$bki_values{$att} = $procoid $bki_values{$att} = $procoid
if defined($procoid) && $procoid ne 'MULTIPLE'; if defined($procoid) && $procoid ne 'MULTIPLE';
} }
} }
...@@ -188,13 +190,13 @@ foreach my $catname (@{ $catalogs->{names} }) ...@@ -188,13 +190,13 @@ foreach my $catname (@{ $catalogs->{names} })
# This relies on the order we process the files in! # This relies on the order we process the files in!
if ($catname eq 'pg_proc') if ($catname eq 'pg_proc')
{ {
if (defined($regprocoids{$bki_values{proname}})) if (defined($regprocoids{ $bki_values{proname} }))
{ {
$regprocoids{$bki_values{proname}} = 'MULTIPLE'; $regprocoids{ $bki_values{proname} } = 'MULTIPLE';
} }
else else
{ {
$regprocoids{$bki_values{proname}} = $row->{oid}; $regprocoids{ $bki_values{proname} } = $row->{oid};
} }
} }
...@@ -211,7 +213,7 @@ foreach my $catname (@{ $catalogs->{names} }) ...@@ -211,7 +213,7 @@ foreach my $catname (@{ $catalogs->{names} })
printf $bki "insert %s( %s )\n", $oid, printf $bki "insert %s( %s )\n", $oid,
join(' ', @bki_values{@attnames}); join(' ', @bki_values{@attnames});
# Write comments to postgres.description and postgres.shdescription # Write comments to postgres.description and postgres.shdescription
if (defined $row->{descr}) if (defined $row->{descr})
{ {
printf $descr "%s\t%s\t0\t%s\n", $row->{oid}, $catname, printf $descr "%s\t%s\t0\t%s\n", $row->{oid}, $catname,
...@@ -459,7 +461,8 @@ sub bki_insert ...@@ -459,7 +461,8 @@ sub bki_insert
my $row = shift; my $row = shift;
my @attnames = @_; my @attnames = @_;
my $oid = $row->{oid} ? "OID = $row->{oid} " : ''; my $oid = $row->{oid} ? "OID = $row->{oid} " : '';
my $bki_values = join ' ', map { $_ eq '' ? '""' : $_ } map $row->{$_}, @attnames; my $bki_values = join ' ', map { $_ eq '' ? '""' : $_ } map $row->{$_},
@attnames;
printf $bki "insert %s( %s )\n", $oid, $bki_values; printf $bki "insert %s( %s )\n", $oid, $bki_values;
} }
...@@ -474,9 +477,9 @@ sub emit_schemapg_row ...@@ -474,9 +477,9 @@ sub emit_schemapg_row
$row->{attidentity} ||= '\0'; $row->{attidentity} ||= '\0';
# Supply appropriate quoting for these fields. # Supply appropriate quoting for these fields.
$row->{attname} = q|{"| . $row->{attname} . q|"}|; $row->{attname} = q|{"| . $row->{attname} . q|"}|;
$row->{attstorage} = q|'| . $row->{attstorage} . q|'|; $row->{attstorage} = q|'| . $row->{attstorage} . q|'|;
$row->{attalign} = q|'| . $row->{attalign} . q|'|; $row->{attalign} = q|'| . $row->{attalign} . q|'|;
$row->{attidentity} = q|'| . $row->{attidentity} . q|'|; $row->{attidentity} = q|'| . $row->{attidentity} . q|'|;
# We don't emit initializers for the variable length fields at all. # We don't emit initializers for the variable length fields at all.
......
...@@ -149,7 +149,8 @@ while (my ($kcat, $kcat_id) = each(%keyword_categories)) ...@@ -149,7 +149,8 @@ while (my ($kcat, $kcat_id) = each(%keyword_categories))
# Now read in kwlist.h # Now read in kwlist.h
open(my $kwlist, '<', $kwlist_filename) || die("Could not open : $kwlist_filename"); open(my $kwlist, '<', $kwlist_filename)
|| die("Could not open : $kwlist_filename");
my $prevkwstring = ''; my $prevkwstring = '';
my $bare_kwname; my $bare_kwname;
......
...@@ -58,6 +58,7 @@ foreach my $column (@{ $catalogs->{pg_proc}->{columns} }) ...@@ -58,6 +58,7 @@ foreach my $column (@{ $catalogs->{pg_proc}->{columns} })
my $data = $catalogs->{pg_proc}->{data}; my $data = $catalogs->{pg_proc}->{data};
foreach my $row (@$data) foreach my $row (@$data)
{ {
# Split line into tokens without interpreting their meaning. # Split line into tokens without interpreting their meaning.
my %bki_values; my %bki_values;
@bki_values{@attnames} = Catalog::SplitDataLine($row->{bki_values}); @bki_values{@attnames} = Catalog::SplitDataLine($row->{bki_values});
...@@ -75,14 +76,17 @@ foreach my $row (@$data) ...@@ -75,14 +76,17 @@ foreach my $row (@$data)
} }
# Emit headers for both files # Emit headers for both files
my $tmpext = ".tmp$$"; my $tmpext = ".tmp$$";
my $oidsfile = $output_path . 'fmgroids.h'; my $oidsfile = $output_path . 'fmgroids.h';
my $protosfile = $output_path . 'fmgrprotos.h'; my $protosfile = $output_path . 'fmgrprotos.h';
my $tabfile = $output_path . 'fmgrtab.c'; my $tabfile = $output_path . 'fmgrtab.c';
open my $ofh, '>', $oidsfile . $tmpext or die "Could not open $oidsfile$tmpext: $!"; open my $ofh, '>', $oidsfile . $tmpext
open my $pfh, '>', $protosfile . $tmpext or die "Could not open $protosfile$tmpext: $!"; or die "Could not open $oidsfile$tmpext: $!";
open my $tfh, '>', $tabfile . $tmpext or die "Could not open $tabfile$tmpext: $!"; open my $pfh, '>', $protosfile . $tmpext
or die "Could not open $protosfile$tmpext: $!";
open my $tfh, '>', $tabfile . $tmpext
or die "Could not open $tabfile$tmpext: $!";
print $ofh print $ofh
qq|/*------------------------------------------------------------------------- qq|/*-------------------------------------------------------------------------
...@@ -218,9 +222,9 @@ close($pfh); ...@@ -218,9 +222,9 @@ close($pfh);
close($tfh); close($tfh);
# Finally, rename the completed files into place. # Finally, rename the completed files into place.
Catalog::RenameTempFile($oidsfile, $tmpext); Catalog::RenameTempFile($oidsfile, $tmpext);
Catalog::RenameTempFile($protosfile, $tmpext); Catalog::RenameTempFile($protosfile, $tmpext);
Catalog::RenameTempFile($tabfile, $tmpext); Catalog::RenameTempFile($tabfile, $tmpext);
sub usage sub usage
{ {
......
...@@ -35,9 +35,10 @@ my $all = &read_source("BIG5.TXT"); ...@@ -35,9 +35,10 @@ my $all = &read_source("BIG5.TXT");
# Load CP950.TXT # Load CP950.TXT
my $cp950txt = &read_source("CP950.TXT"); my $cp950txt = &read_source("CP950.TXT");
foreach my $i (@$cp950txt) { foreach my $i (@$cp950txt)
{
my $code = $i->{code}; my $code = $i->{code};
my $ucs = $i->{ucs}; my $ucs = $i->{ucs};
# Pick only the ETEN extended characters in the range 0xf9d6 - 0xf9dc # Pick only the ETEN extended characters in the range 0xf9d6 - 0xf9dc
# from CP950.TXT # from CP950.TXT
...@@ -46,22 +47,24 @@ foreach my $i (@$cp950txt) { ...@@ -46,22 +47,24 @@ foreach my $i (@$cp950txt) {
&& $code >= 0xf9d6 && $code >= 0xf9d6
&& $code <= 0xf9dc) && $code <= 0xf9dc)
{ {
push @$all, {code => $code, push @$all,
ucs => $ucs, { code => $code,
comment => $i->{comment}, ucs => $ucs,
direction => BOTH, comment => $i->{comment},
f => $i->{f}, direction => BOTH,
l => $i->{l} }; f => $i->{f},
l => $i->{l} };
} }
} }
foreach my $i (@$all) { foreach my $i (@$all)
{
my $code = $i->{code}; my $code = $i->{code};
my $ucs = $i->{ucs}; my $ucs = $i->{ucs};
# BIG5.TXT maps several BIG5 characters to U+FFFD. The UTF-8 to BIG5 mapping can # BIG5.TXT maps several BIG5 characters to U+FFFD. The UTF-8 to BIG5 mapping can
# contain only one of them. XXX: Doesn't really make sense to include any of them, # contain only one of them. XXX: Doesn't really make sense to include any of them,
# but for historical reasons, we map the first one of them. # but for historical reasons, we map the first one of them.
if ($i->{ucs} == 0xFFFD && $i->{code} != 0xA15A) if ($i->{ucs} == 0xFFFD && $i->{code} != 0xA15A)
{ {
$i->{direction} = TO_UNICODE; $i->{direction} = TO_UNICODE;
......
...@@ -38,8 +38,10 @@ while (<$in>) ...@@ -38,8 +38,10 @@ while (<$in>)
# a lot of extra characters on top of the GB2312 character set that # a lot of extra characters on top of the GB2312 character set that
# EUC_CN encodes. Filter out those extra characters. # EUC_CN encodes. Filter out those extra characters.
next if (($code & 0xFF) < 0xA1); next if (($code & 0xFF) < 0xA1);
next if (!($code >= 0xA100 && $code <= 0xA9FF || next
$code >= 0xB000 && $code <= 0xF7FF)); if (
!( $code >= 0xA100 && $code <= 0xA9FF
|| $code >= 0xB000 && $code <= 0xF7FF));
next if ($code >= 0xA2A1 && $code <= 0xA2B0); next if ($code >= 0xA2A1 && $code <= 0xA2B0);
next if ($code >= 0xA2E3 && $code <= 0xA2E4); next if ($code >= 0xA2E3 && $code <= 0xA2E4);
...@@ -67,13 +69,12 @@ while (<$in>) ...@@ -67,13 +69,12 @@ while (<$in>)
$ucs = 0x2015; $ucs = 0x2015;
} }
push @mapping, { push @mapping,
ucs => $ucs, { ucs => $ucs,
code => $code, code => $code,
direction => BOTH, direction => BOTH,
f => $in_file, f => $in_file,
l => $. l => $. };
};
} }
close($in); close($in);
......
...@@ -24,6 +24,7 @@ while (my $line = <$in>) ...@@ -24,6 +24,7 @@ while (my $line = <$in>)
{ {
if ($line =~ /^0x(.*)[ \t]*U\+(.*)\+(.*)[ \t]*#(.*)$/) if ($line =~ /^0x(.*)[ \t]*U\+(.*)\+(.*)[ \t]*#(.*)$/)
{ {
# combined characters # combined characters
my ($c, $u1, $u2) = ($1, $2, $3); my ($c, $u1, $u2) = ($1, $2, $3);
my $rest = "U+" . $u1 . "+" . $u2 . $4; my $rest = "U+" . $u1 . "+" . $u2 . $4;
...@@ -31,17 +32,18 @@ while (my $line = <$in>) ...@@ -31,17 +32,18 @@ while (my $line = <$in>)
my $ucs1 = hex($u1); my $ucs1 = hex($u1);
my $ucs2 = hex($u2); my $ucs2 = hex($u2);
push @all, { direction => BOTH, push @all,
ucs => $ucs1, { direction => BOTH,
ucs_second => $ucs2, ucs => $ucs1,
code => $code, ucs_second => $ucs2,
comment => $rest, code => $code,
f => $in_file, comment => $rest,
l => $. f => $in_file,
}; l => $. };
} }
elsif ($line =~ /^0x(.*)[ \t]*U\+(.*)[ \t]*#(.*)$/) elsif ($line =~ /^0x(.*)[ \t]*U\+(.*)[ \t]*#(.*)$/)
{ {
# non-combined characters # non-combined characters
my ($c, $u, $rest) = ($1, $2, "U+" . $2 . $3); my ($c, $u, $rest) = ($1, $2, "U+" . $2 . $3);
my $ucs = hex($u); my $ucs = hex($u);
...@@ -49,13 +51,13 @@ while (my $line = <$in>) ...@@ -49,13 +51,13 @@ while (my $line = <$in>)
next if ($code < 0x80 && $ucs < 0x80); next if ($code < 0x80 && $ucs < 0x80);
push @all, { direction => BOTH, push @all,
ucs => $ucs, { direction => BOTH,
code => $code, ucs => $ucs,
comment => $rest, code => $code,
f => $in_file, comment => $rest,
l => $. f => $in_file,
}; l => $. };
} }
} }
close($in); close($in);
......
...@@ -31,10 +31,24 @@ foreach my $i (@$mapping) ...@@ -31,10 +31,24 @@ foreach my $i (@$mapping)
} }
# Some extra characters that are not in KSX1001.TXT # Some extra characters that are not in KSX1001.TXT
push @$mapping,( push @$mapping,
{direction => BOTH, ucs => 0x20AC, code => 0xa2e6, comment => '# EURO SIGN', f => $this_script, l => __LINE__}, ( { direction => BOTH,
{direction => BOTH, ucs => 0x00AE, code => 0xa2e7, comment => '# REGISTERED SIGN', f => $this_script, l => __LINE__ }, ucs => 0x20AC,
{direction => BOTH, ucs => 0x327E, code => 0xa2e8, comment => '# CIRCLED HANGUL IEUNG U', f => $this_script, l => __LINE__ } code => 0xa2e6,
); comment => '# EURO SIGN',
f => $this_script,
l => __LINE__ },
{ direction => BOTH,
ucs => 0x00AE,
code => 0xa2e7,
comment => '# REGISTERED SIGN',
f => $this_script,
l => __LINE__ },
{ direction => BOTH,
ucs => 0x327E,
code => 0xa2e8,
comment => '# CIRCLED HANGUL IEUNG U',
f => $this_script,
l => __LINE__ });
print_conversion_tables($this_script, "EUC_KR", $mapping); print_conversion_tables($this_script, "EUC_KR", $mapping);
...@@ -28,8 +28,8 @@ my @extras; ...@@ -28,8 +28,8 @@ my @extras;
foreach my $i (@$mapping) foreach my $i (@$mapping)
{ {
my $ucs = $i->{ucs}; my $ucs = $i->{ucs};
my $code = $i->{code}; my $code = $i->{code};
my $origcode = $i->{code}; my $origcode = $i->{code};
my $plane = ($code & 0x1f0000) >> 16; my $plane = ($code & 0x1f0000) >> 16;
...@@ -52,14 +52,13 @@ foreach my $i (@$mapping) ...@@ -52,14 +52,13 @@ foreach my $i (@$mapping)
# Some codes are mapped twice in the EUC_TW to UTF-8 table. # Some codes are mapped twice in the EUC_TW to UTF-8 table.
if ($origcode >= 0x12121 && $origcode <= 0x20000) if ($origcode >= 0x12121 && $origcode <= 0x20000)
{ {
push @extras, { push @extras,
ucs => $i->{ucs}, { ucs => $i->{ucs},
code => ($i->{code} + 0x8ea10000), code => ($i->{code} + 0x8ea10000),
rest => $i->{rest}, rest => $i->{rest},
direction => TO_UNICODE, direction => TO_UNICODE,
f => $i->{f}, f => $i->{f},
l => $i->{l} l => $i->{l} };
};
} }
} }
......
...@@ -35,13 +35,12 @@ while (<$in>) ...@@ -35,13 +35,12 @@ while (<$in>)
my $code = hex($c); my $code = hex($c);
if ($code >= 0x80 && $ucs >= 0x0080) if ($code >= 0x80 && $ucs >= 0x0080)
{ {
push @mapping, { push @mapping,
ucs => $ucs, { ucs => $ucs,
code => $code, code => $code,
direction => BOTH, direction => BOTH,
f => $in_file, f => $in_file,
l => $. l => $. };
};
} }
} }
close($in); close($in);
......
...@@ -25,10 +25,24 @@ my $this_script = $0; ...@@ -25,10 +25,24 @@ my $this_script = $0;
my $mapping = &read_source("JOHAB.TXT"); my $mapping = &read_source("JOHAB.TXT");
# Some extra characters that are not in JOHAB.TXT # Some extra characters that are not in JOHAB.TXT
push @$mapping, ( push @$mapping,
{direction => BOTH, ucs => 0x20AC, code => 0xd9e6, comment => '# EURO SIGN', f => $this_script, l => __LINE__ }, ( { direction => BOTH,
{direction => BOTH, ucs => 0x00AE, code => 0xd9e7, comment => '# REGISTERED SIGN', f => $this_script, l => __LINE__ }, ucs => 0x20AC,
{direction => BOTH, ucs => 0x327E, code => 0xd9e8, comment => '# CIRCLED HANGUL IEUNG U', f => $this_script, l => __LINE__ } code => 0xd9e6,
); comment => '# EURO SIGN',
f => $this_script,
l => __LINE__ },
{ direction => BOTH,
ucs => 0x00AE,
code => 0xd9e7,
comment => '# REGISTERED SIGN',
f => $this_script,
l => __LINE__ },
{ direction => BOTH,
ucs => 0x327E,
code => 0xd9e8,
comment => '# CIRCLED HANGUL IEUNG U',
f => $this_script,
l => __LINE__ });
print_conversion_tables($this_script, "JOHAB", $mapping); print_conversion_tables($this_script, "JOHAB", $mapping);
...@@ -24,6 +24,7 @@ while (my $line = <$in>) ...@@ -24,6 +24,7 @@ while (my $line = <$in>)
{ {
if ($line =~ /^0x(.*)[ \t]*U\+(.*)\+(.*)[ \t]*#(.*)$/) if ($line =~ /^0x(.*)[ \t]*U\+(.*)\+(.*)[ \t]*#(.*)$/)
{ {
# combined characters # combined characters
my ($c, $u1, $u2) = ($1, $2, $3); my ($c, $u1, $u2) = ($1, $2, $3);
my $rest = "U+" . $u1 . "+" . $u2 . $4; my $rest = "U+" . $u1 . "+" . $u2 . $4;
...@@ -31,18 +32,18 @@ while (my $line = <$in>) ...@@ -31,18 +32,18 @@ while (my $line = <$in>)
my $ucs1 = hex($u1); my $ucs1 = hex($u1);
my $ucs2 = hex($u2); my $ucs2 = hex($u2);
push @mapping, { push @mapping,
code => $code, { code => $code,
ucs => $ucs1, ucs => $ucs1,
ucs_second => $ucs2, ucs_second => $ucs2,
comment => $rest, comment => $rest,
direction => BOTH, direction => BOTH,
f => $in_file, f => $in_file,
l => $. l => $. };
};
} }
elsif ($line =~ /^0x(.*)[ \t]*U\+(.*)[ \t]*#(.*)$/) elsif ($line =~ /^0x(.*)[ \t]*U\+(.*)[ \t]*#(.*)$/)
{ {
# non-combined characters # non-combined characters
my ($c, $u, $rest) = ($1, $2, "U+" . $2 . $3); my ($c, $u, $rest) = ($1, $2, "U+" . $2 . $3);
my $ucs = hex($u); my $ucs = hex($u);
...@@ -66,14 +67,13 @@ while (my $line = <$in>) ...@@ -66,14 +67,13 @@ while (my $line = <$in>)
$direction = BOTH; $direction = BOTH;
} }
push @mapping, { push @mapping,
code => $code, { code => $code,
ucs => $ucs, ucs => $ucs,
comment => $rest, comment => $rest,
direction => $direction, direction => $direction,
f => $in_file, f => $in_file,
l => $. l => $. };
};
} }
} }
close($in); close($in);
......
...@@ -18,33 +18,71 @@ my $this_script = $0; ...@@ -18,33 +18,71 @@ my $this_script = $0;
my $mapping = read_source("CP932.TXT"); my $mapping = read_source("CP932.TXT");
# Drop these SJIS codes from the source for UTF8=>SJIS conversion # Drop these SJIS codes from the source for UTF8=>SJIS conversion
my @reject_sjis =( my @reject_sjis = (
0xed40..0xeefc, 0x8754..0x875d, 0x878a, 0x8782, 0xed40 .. 0xeefc, 0x8754 .. 0x875d, 0x878a, 0x8782,
0x8784, 0xfa5b, 0xfa54, 0x8790..0x8792, 0x8795..0x8797, 0x8784, 0xfa5b, 0xfa54, 0x8790 .. 0x8792,
0x879a..0x879c 0x8795 .. 0x8797, 0x879a .. 0x879c);
);
foreach my $i (@$mapping) foreach my $i (@$mapping)
{ {
my $code = $i->{code}; my $code = $i->{code};
my $ucs = $i->{ucs}; my $ucs = $i->{ucs};
if (grep {$code == $_} @reject_sjis) if (grep { $code == $_ } @reject_sjis)
{ {
$i->{direction} = TO_UNICODE; $i->{direction} = TO_UNICODE;
} }
} }
# Add these UTF8->SJIS pairs to the table. # Add these UTF8->SJIS pairs to the table.
push @$mapping, ( push @$mapping,
{direction => FROM_UNICODE, ucs => 0x00a2, code => 0x8191, comment => '# CENT SIGN', f => $this_script, l => __LINE__ }, ( { direction => FROM_UNICODE,
{direction => FROM_UNICODE, ucs => 0x00a3, code => 0x8192, comment => '# POUND SIGN', f => $this_script, l => __LINE__ }, ucs => 0x00a2,
{direction => FROM_UNICODE, ucs => 0x00a5, code => 0x5c, comment => '# YEN SIGN', f => $this_script, l => __LINE__ }, code => 0x8191,
{direction => FROM_UNICODE, ucs => 0x00ac, code => 0x81ca, comment => '# NOT SIGN', f => $this_script, l => __LINE__ }, comment => '# CENT SIGN',
{direction => FROM_UNICODE, ucs => 0x2016, code => 0x8161, comment => '# DOUBLE VERTICAL LINE', f => $this_script, l => __LINE__ }, f => $this_script,
{direction => FROM_UNICODE, ucs => 0x203e, code => 0x7e, comment => '# OVERLINE', f => $this_script, l => __LINE__ }, l => __LINE__ },
{direction => FROM_UNICODE, ucs => 0x2212, code => 0x817c, comment => '# MINUS SIGN', f => $this_script, l => __LINE__ }, { direction => FROM_UNICODE,
{direction => FROM_UNICODE, ucs => 0x301c, code => 0x8160, comment => '# WAVE DASH', f => $this_script, l => __LINE__ } ucs => 0x00a3,
); code => 0x8192,
comment => '# POUND SIGN',
f => $this_script,
l => __LINE__ },
{ direction => FROM_UNICODE,
ucs => 0x00a5,
code => 0x5c,
comment => '# YEN SIGN',
f => $this_script,
l => __LINE__ },
{ direction => FROM_UNICODE,
ucs => 0x00ac,
code => 0x81ca,
comment => '# NOT SIGN',
f => $this_script,
l => __LINE__ },
{ direction => FROM_UNICODE,
ucs => 0x2016,
code => 0x8161,
comment => '# DOUBLE VERTICAL LINE',
f => $this_script,
l => __LINE__ },
{ direction => FROM_UNICODE,
ucs => 0x203e,
code => 0x7e,
comment => '# OVERLINE',
f => $this_script,
l => __LINE__ },
{ direction => FROM_UNICODE,
ucs => 0x2212,
code => 0x817c,
comment => '# MINUS SIGN',
f => $this_script,
l => __LINE__ },
{ direction => FROM_UNICODE,
ucs => 0x301c,
code => 0x8160,
comment => '# WAVE DASH',
f => $this_script,
l => __LINE__ });
print_conversion_tables($this_script, "SJIS", $mapping); print_conversion_tables($this_script, "SJIS", $mapping);
...@@ -38,18 +38,23 @@ while (<$in>) ...@@ -38,18 +38,23 @@ while (<$in>)
if ($code >= 0x80 && $ucs >= 0x0080) if ($code >= 0x80 && $ucs >= 0x0080)
{ {
push @mapping, { push @mapping,
ucs => $ucs, { ucs => $ucs,
code => $code, code => $code,
direction => BOTH, direction => BOTH,
f => $in_file, f => $in_file,
l => $. l => $. };
};
} }
} }
close($in); close($in);
# One extra character that's not in the source file. # One extra character that's not in the source file.
push @mapping, { direction => BOTH, code => 0xa2e8, ucs => 0x327e, comment => 'CIRCLED HANGUL IEUNG U', f => $this_script, l => __LINE__ }; push @mapping,
{ direction => BOTH,
code => 0xa2e8,
ucs => 0x327e,
comment => 'CIRCLED HANGUL IEUNG U',
f => $this_script,
l => __LINE__ };
print_conversion_tables($this_script, "UHC", \@mapping); print_conversion_tables($this_script, "UHC", \@mapping);
This diff is collapsed.
...@@ -38,6 +38,7 @@ mkdir $datadir; ...@@ -38,6 +38,7 @@ mkdir $datadir;
# make sure we run one successful test without a TZ setting so we test # make sure we run one successful test without a TZ setting so we test
# initdb's time zone setting code # initdb's time zone setting code
{ {
# delete local only works from perl 5.12, so use the older way to do this # delete local only works from perl 5.12, so use the older way to do this
local (%ENV) = %ENV; local (%ENV) = %ENV;
delete $ENV{TZ}; delete $ENV{TZ};
......
...@@ -37,10 +37,9 @@ $node->command_fails( ...@@ -37,10 +37,9 @@ $node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/backup" ], [ 'pg_basebackup', '-D', "$tempdir/backup" ],
'pg_basebackup fails because of WAL configuration'); 'pg_basebackup fails because of WAL configuration');
ok(! -d "$tempdir/backup", 'backup directory was cleaned up'); ok(!-d "$tempdir/backup", 'backup directory was cleaned up');
$node->command_fails( $node->command_fails([ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
[ 'pg_basebackup', '-D', "$tempdir/backup", '-n' ],
'failing run with no-clean option'); 'failing run with no-clean option');
ok(-d "$tempdir/backup", 'backup directory was created and left behind'); ok(-d "$tempdir/backup", 'backup directory was created and left behind');
...@@ -53,7 +52,9 @@ close $conf; ...@@ -53,7 +52,9 @@ close $conf;
$node->restart; $node->restart;
# Write some files to test that they are not copied. # Write some files to test that they are not copied.
foreach my $filename (qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)) foreach my $filename (
qw(backup_label tablespace_map postgresql.auto.conf.tmp current_logfiles.tmp)
)
{ {
open my $file, '>>', "$pgdata/$filename"; open my $file, '>>', "$pgdata/$filename";
print $file "DONOTCOPY"; print $file "DONOTCOPY";
...@@ -71,7 +72,9 @@ is_deeply( ...@@ -71,7 +72,9 @@ is_deeply(
'no WAL files copied'); 'no WAL files copied');
# Contents of these directories should not be copied. # Contents of these directories should not be copied.
foreach my $dirname (qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)) foreach my $dirname (
qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots pg_stat_tmp pg_subtrans)
)
{ {
is_deeply( is_deeply(
[ sort(slurp_dir("$tempdir/backup/$dirname/")) ], [ sort(slurp_dir("$tempdir/backup/$dirname/")) ],
...@@ -80,14 +83,16 @@ foreach my $dirname (qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots ...@@ -80,14 +83,16 @@ foreach my $dirname (qw(pg_dynshmem pg_notify pg_replslot pg_serial pg_snapshots
} }
# These files should not be copied. # These files should not be copied.
foreach my $filename (qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp)) foreach my $filename (
qw(postgresql.auto.conf.tmp postmaster.opts postmaster.pid tablespace_map current_logfiles.tmp)
)
{ {
ok(! -f "$tempdir/backup/$filename", "$filename not copied"); ok(!-f "$tempdir/backup/$filename", "$filename not copied");
} }
# Make sure existing backup_label was ignored. # Make sure existing backup_label was ignored.
isnt(slurp_file("$tempdir/backup/backup_label"), 'DONOTCOPY', isnt(slurp_file("$tempdir/backup/backup_label"),
'existing backup_label not copied'); 'DONOTCOPY', 'existing backup_label not copied');
$node->command_ok( $node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/backup2", '--waldir', [ 'pg_basebackup', '-D', "$tempdir/backup2", '--waldir',
...@@ -124,7 +129,8 @@ $node->command_fails( ...@@ -124,7 +129,8 @@ $node->command_fails(
my $superlongname = "superlongname_" . ("x" x 100); my $superlongname = "superlongname_" . ("x" x 100);
my $superlongpath = "$pgdata/$superlongname"; my $superlongpath = "$pgdata/$superlongname";
open my $file, '>', "$superlongpath" or die "unable to create file $superlongpath"; open my $file, '>', "$superlongpath"
or die "unable to create file $superlongpath";
close $file; close $file;
$node->command_fails( $node->command_fails(
[ 'pg_basebackup', '-D', "$tempdir/tarbackup_l1", '-Ft' ], [ 'pg_basebackup', '-D', "$tempdir/tarbackup_l1", '-Ft' ],
...@@ -141,9 +147,9 @@ SKIP: ...@@ -141,9 +147,9 @@ SKIP:
$node->stop; $node->stop;
rename("$pgdata/pg_replslot", "$tempdir/pg_replslot") rename("$pgdata/pg_replslot", "$tempdir/pg_replslot")
or BAIL_OUT "could not move $pgdata/pg_replslot"; or BAIL_OUT "could not move $pgdata/pg_replslot";
symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot") symlink("$tempdir/pg_replslot", "$pgdata/pg_replslot")
or BAIL_OUT "could not symlink to $pgdata/pg_replslot"; or BAIL_OUT "could not symlink to $pgdata/pg_replslot";
$node->start; $node->start;
...@@ -183,7 +189,8 @@ SKIP: ...@@ -183,7 +189,8 @@ SKIP:
"tablespace symlink was updated"); "tablespace symlink was updated");
closedir $dh; closedir $dh;
ok(-d "$tempdir/backup1/pg_replslot", 'pg_replslot symlink copied as directory'); ok( -d "$tempdir/backup1/pg_replslot",
'pg_replslot symlink copied as directory');
mkdir "$tempdir/tbl=spc2"; mkdir "$tempdir/tbl=spc2";
$node->safe_psql('postgres', "DROP TABLE test1;"); $node->safe_psql('postgres', "DROP TABLE test1;");
...@@ -222,7 +229,8 @@ like( ...@@ -222,7 +229,8 @@ like(
qr/^primary_conninfo = '.*port=$port.*'\n/m, qr/^primary_conninfo = '.*port=$port.*'\n/m,
'recovery.conf sets primary_conninfo'); 'recovery.conf sets primary_conninfo');
$node->command_ok([ 'pg_basebackup', '-D', "$tempdir/backupxd" ], $node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/backupxd" ],
'pg_basebackup runs in default xlog mode'); 'pg_basebackup runs in default xlog mode');
ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")), ok(grep(/^[0-9A-F]{24}$/, slurp_dir("$tempdir/backupxd/pg_wal")),
'WAL files copied'); 'WAL files copied');
...@@ -242,7 +250,9 @@ $node->command_ok( ...@@ -242,7 +250,9 @@ $node->command_ok(
'pg_basebackup -X stream runs in tar mode'); 'pg_basebackup -X stream runs in tar mode');
ok(-f "$tempdir/backupxst/pg_wal.tar", "tar file was created"); ok(-f "$tempdir/backupxst/pg_wal.tar", "tar file was created");
$node->command_ok( $node->command_ok(
[ 'pg_basebackup', '-D', "$tempdir/backupnoslot", '-X', 'stream', '--no-slot' ], [ 'pg_basebackup', '-D',
"$tempdir/backupnoslot", '-X',
'stream', '--no-slot' ],
'pg_basebackup -X stream runs with --no-slot'); 'pg_basebackup -X stream runs with --no-slot');
$node->command_fails( $node->command_fails(
......
...@@ -12,7 +12,8 @@ my $node = get_new_node('main'); ...@@ -12,7 +12,8 @@ my $node = get_new_node('main');
# Initialize node without replication settings # Initialize node without replication settings
$node->init(allows_streaming => 1, has_archiving => 1); $node->init(allows_streaming => 1, has_archiving => 1);
$node->append_conf('postgresql.conf', q{ $node->append_conf(
'postgresql.conf', q{
wal_level = 'logical' wal_level = 'logical'
max_replication_slots = 4 max_replication_slots = 4
max_wal_senders = 4 max_wal_senders = 4
...@@ -22,25 +23,34 @@ log_error_verbosity = verbose ...@@ -22,25 +23,34 @@ log_error_verbosity = verbose
$node->dump_info; $node->dump_info;
$node->start; $node->start;
$node->command_fails(['pg_recvlogical'], $node->command_fails(['pg_recvlogical'], 'pg_recvlogical needs a slot name');
'pg_recvlogical needs a slot name'); $node->command_fails([ 'pg_recvlogical', '-S', 'test' ],
$node->command_fails(['pg_recvlogical', '-S', 'test'],
'pg_recvlogical needs a database'); 'pg_recvlogical needs a database');
$node->command_fails(['pg_recvlogical', '-S', 'test', '-d', 'postgres'], $node->command_fails([ 'pg_recvlogical', '-S', 'test', '-d', 'postgres' ],
'pg_recvlogical needs an action'); 'pg_recvlogical needs an action');
$node->command_fails(['pg_recvlogical', '-S', 'test', '-d', $node->connstr('postgres'), '--start'], $node->command_fails(
[ 'pg_recvlogical', '-S',
'test', '-d',
$node->connstr('postgres'), '--start' ],
'no destination file'); 'no destination file');
$node->command_ok(['pg_recvlogical', '-S', 'test', '-d', $node->connstr('postgres'), '--create-slot'], $node->command_ok(
[ 'pg_recvlogical', '-S',
'test', '-d',
$node->connstr('postgres'), '--create-slot' ],
'slot created'); 'slot created');
my $slot = $node->slot('test'); my $slot = $node->slot('test');
isnt($slot->{'restart_lsn'}, '', 'restart lsn is defined for new slot'); isnt($slot->{'restart_lsn'}, '', 'restart lsn is defined for new slot');
$node->psql('postgres', 'CREATE TABLE test_table(x integer)'); $node->psql('postgres', 'CREATE TABLE test_table(x integer)');
$node->psql('postgres', 'INSERT INTO test_table(x) SELECT y FROM generate_series(1, 10) a(y);'); $node->psql('postgres',
my $nextlsn = $node->safe_psql('postgres', 'SELECT pg_current_wal_insert_lsn()'); 'INSERT INTO test_table(x) SELECT y FROM generate_series(1, 10) a(y);');
my $nextlsn =
$node->safe_psql('postgres', 'SELECT pg_current_wal_insert_lsn()');
chomp($nextlsn); chomp($nextlsn);
$node->command_ok(['pg_recvlogical', '-S', 'test', '-d', $node->connstr('postgres'), '--start', '--endpos', "$nextlsn", '--no-loop', '-f', '-'], $node->command_ok(
[ 'pg_recvlogical', '-S', 'test', '-d', $node->connstr('postgres'),
'--start', '--endpos', "$nextlsn", '--no-loop', '-f', '-' ],
'replayed a transaction'); 'replayed a transaction');
...@@ -22,7 +22,7 @@ command_ok([ $ENV{PG_REGRESS}, '--config-auth', "$tempdir/data" ], ...@@ -22,7 +22,7 @@ command_ok([ $ENV{PG_REGRESS}, '--config-auth', "$tempdir/data" ],
'configure authentication'); 'configure authentication');
open my $conf, '>>', "$tempdir/data/postgresql.conf"; open my $conf, '>>', "$tempdir/data/postgresql.conf";
print $conf "fsync = off\n"; print $conf "fsync = off\n";
if (! $windows_os) if (!$windows_os)
{ {
print $conf "listen_addresses = ''\n"; print $conf "listen_addresses = ''\n";
print $conf "unix_socket_directories = '$tempdir_short'\n"; print $conf "unix_socket_directories = '$tempdir_short'\n";
...@@ -32,8 +32,7 @@ else ...@@ -32,8 +32,7 @@ else
print $conf "listen_addresses = '127.0.0.1'\n"; print $conf "listen_addresses = '127.0.0.1'\n";
} }
close $conf; close $conf;
command_ok([ 'pg_ctl', 'start', '-D', "$tempdir/data" ], command_ok([ 'pg_ctl', 'start', '-D', "$tempdir/data" ], 'pg_ctl start');
'pg_ctl start');
# sleep here is because Windows builds can't check postmaster.pid exactly, # sleep here is because Windows builds can't check postmaster.pid exactly,
# so they may mistake a pre-existing postmaster.pid for one created by the # so they may mistake a pre-existing postmaster.pid for one created by the
...@@ -42,12 +41,12 @@ command_ok([ 'pg_ctl', 'start', '-D', "$tempdir/data" ], ...@@ -42,12 +41,12 @@ command_ok([ 'pg_ctl', 'start', '-D', "$tempdir/data" ],
sleep 3 if ($windows_os); sleep 3 if ($windows_os);
command_fails([ 'pg_ctl', 'start', '-D', "$tempdir/data" ], command_fails([ 'pg_ctl', 'start', '-D', "$tempdir/data" ],
'second pg_ctl start fails'); 'second pg_ctl start fails');
command_ok([ 'pg_ctl', 'stop', '-D', "$tempdir/data" ], command_ok([ 'pg_ctl', 'stop', '-D', "$tempdir/data" ], 'pg_ctl stop');
'pg_ctl stop');
command_fails([ 'pg_ctl', 'stop', '-D', "$tempdir/data" ], command_fails([ 'pg_ctl', 'stop', '-D', "$tempdir/data" ],
'second pg_ctl stop fails'); 'second pg_ctl stop fails');
command_ok([ 'pg_ctl', 'restart', '-D', "$tempdir/data" ], command_ok(
[ 'pg_ctl', 'restart', '-D', "$tempdir/data" ],
'pg_ctl restart with server not running'); 'pg_ctl restart with server not running');
command_ok([ 'pg_ctl', 'restart', '-D', "$tempdir/data" ], command_ok([ 'pg_ctl', 'restart', '-D', "$tempdir/data" ],
'pg_ctl restart with server running'); 'pg_ctl restart with server running');
......
...@@ -7,49 +7,55 @@ use Test::More tests => 12; ...@@ -7,49 +7,55 @@ use Test::More tests => 12;
my $tempdir = TestLib::tempdir; my $tempdir = TestLib::tempdir;
command_fails_like([ 'pg_ctl', '-D', "$tempdir/nonexistent", 'promote' ], command_fails_like(
qr/directory .* does not exist/, [ 'pg_ctl', '-D', "$tempdir/nonexistent", 'promote' ],
'pg_ctl promote with nonexistent directory'); qr/directory .* does not exist/,
'pg_ctl promote with nonexistent directory');
my $node_primary = get_new_node('primary'); my $node_primary = get_new_node('primary');
$node_primary->init(allows_streaming => 1); $node_primary->init(allows_streaming => 1);
command_fails_like([ 'pg_ctl', '-D', $node_primary->data_dir, 'promote' ], command_fails_like(
qr/PID file .* does not exist/, [ 'pg_ctl', '-D', $node_primary->data_dir, 'promote' ],
'pg_ctl promote of not running instance fails'); qr/PID file .* does not exist/,
'pg_ctl promote of not running instance fails');
$node_primary->start; $node_primary->start;
command_fails_like([ 'pg_ctl', '-D', $node_primary->data_dir, 'promote' ], command_fails_like(
qr/not in standby mode/, [ 'pg_ctl', '-D', $node_primary->data_dir, 'promote' ],
'pg_ctl promote of primary instance fails'); qr/not in standby mode/,
'pg_ctl promote of primary instance fails');
my $node_standby = get_new_node('standby'); my $node_standby = get_new_node('standby');
$node_primary->backup('my_backup'); $node_primary->backup('my_backup');
$node_standby->init_from_backup($node_primary, 'my_backup', has_streaming => 1); $node_standby->init_from_backup($node_primary, 'my_backup',
has_streaming => 1);
$node_standby->start; $node_standby->start;
is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'), is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'),
't', 'standby is in recovery'); 't', 'standby is in recovery');
command_ok([ 'pg_ctl', '-D', $node_standby->data_dir, '-W', 'promote' ], command_ok([ 'pg_ctl', '-D', $node_standby->data_dir, '-W', 'promote' ],
'pg_ctl -W promote of standby runs'); 'pg_ctl -W promote of standby runs');
ok($node_standby->poll_query_until('postgres', 'SELECT NOT pg_is_in_recovery()'), ok( $node_standby->poll_query_until(
'promoted standby is not in recovery'); 'postgres', 'SELECT NOT pg_is_in_recovery()'),
'promoted standby is not in recovery');
# same again with default wait option # same again with default wait option
$node_standby = get_new_node('standby2'); $node_standby = get_new_node('standby2');
$node_standby->init_from_backup($node_primary, 'my_backup', has_streaming => 1); $node_standby->init_from_backup($node_primary, 'my_backup',
has_streaming => 1);
$node_standby->start; $node_standby->start;
is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'), is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'),
't', 'standby is in recovery'); 't', 'standby is in recovery');
command_ok([ 'pg_ctl', '-D', $node_standby->data_dir, 'promote' ], command_ok([ 'pg_ctl', '-D', $node_standby->data_dir, 'promote' ],
'pg_ctl promote of standby runs'); 'pg_ctl promote of standby runs');
# no wait here # no wait here
is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'), is($node_standby->safe_psql('postgres', 'SELECT pg_is_in_recovery()'),
'f', 'promoted standby is not in recovery'); 'f', 'promoted standby is not in recovery');
This diff is collapsed.
...@@ -91,8 +91,8 @@ $node->safe_psql($dbname1, 'CREATE TABLE t0()'); ...@@ -91,8 +91,8 @@ $node->safe_psql($dbname1, 'CREATE TABLE t0()');
# XXX no printed message when this fails, just SIGPIPE termination # XXX no printed message when this fails, just SIGPIPE termination
$node->command_ok( $node->command_ok(
[ 'pg_dump', '-Fd', '--no-sync', '-j2', '-f', $dirfmt, [ 'pg_dump', '-Fd', '--no-sync', '-j2', '-f', $dirfmt, '-U', $dbname1,
'-U', $dbname1, $node->connstr($dbname1) ], $node->connstr($dbname1) ],
'parallel dump'); 'parallel dump');
# recreate $dbname1 for restore test # recreate $dbname1 for restore test
......
...@@ -30,4 +30,4 @@ $node->issues_sql_like( ...@@ -30,4 +30,4 @@ $node->issues_sql_like(
'cluster specific table'); 'cluster specific table');
$node->command_ok([qw(clusterdb --echo --verbose dbname=template1)], $node->command_ok([qw(clusterdb --echo --verbose dbname=template1)],
'clusterdb with connection string'); 'clusterdb with connection string');
...@@ -44,8 +44,10 @@ $node->issues_sql_like( ...@@ -44,8 +44,10 @@ $node->issues_sql_like(
'reindex with verbose output'); 'reindex with verbose output');
$node->command_ok([qw(reindexdb --echo --table=pg_am dbname=template1)], $node->command_ok([qw(reindexdb --echo --table=pg_am dbname=template1)],
'reindexdb table with connection string'); 'reindexdb table with connection string');
$node->command_ok([qw(reindexdb --echo dbname=template1)], $node->command_ok(
'reindexdb database with connection string'); [qw(reindexdb --echo dbname=template1)],
$node->command_ok([qw(reindexdb --echo --system dbname=template1)], 'reindexdb database with connection string');
'reindexdb system with connection string'); $node->command_ok(
[qw(reindexdb --echo --system dbname=template1)],
'reindexdb system with connection string');
...@@ -34,4 +34,4 @@ $node->issues_sql_like( ...@@ -34,4 +34,4 @@ $node->issues_sql_like(
qr/statement: ANALYZE;/, qr/statement: ANALYZE;/,
'vacuumdb -Z'); 'vacuumdb -Z');
$node->command_ok([qw(vacuumdb -Z --table=pg_am dbname=template1)], $node->command_ok([qw(vacuumdb -Z --table=pg_am dbname=template1)],
'vacuumdb with connection string'); 'vacuumdb with connection string');
...@@ -11,28 +11,31 @@ use Test::More tests => 3; ...@@ -11,28 +11,31 @@ use Test::More tests => 3;
# interpret everything as UTF8. We're going to use byte sequences # interpret everything as UTF8. We're going to use byte sequences
# that aren't valid UTF-8 strings, so that would fail. Use LATIN1, # that aren't valid UTF-8 strings, so that would fail. Use LATIN1,
# which accepts any byte and has a conversion from each byte to UTF-8. # which accepts any byte and has a conversion from each byte to UTF-8.
$ENV{LC_ALL} = 'C'; $ENV{LC_ALL} = 'C';
$ENV{PGCLIENTENCODING} = 'LATIN1'; $ENV{PGCLIENTENCODING} = 'LATIN1';
# Create database names covering the range of LATIN1 characters and # Create database names covering the range of LATIN1 characters and
# run the utilities' --all options over them. # run the utilities' --all options over them.
my $dbname1 = generate_ascii_string(1, 63); # contains '=' my $dbname1 = generate_ascii_string(1, 63); # contains '='
my $dbname2 = generate_ascii_string(67, 129); # skip 64-66 to keep length to 62 my $dbname2 =
generate_ascii_string(67, 129); # skip 64-66 to keep length to 62
my $dbname3 = generate_ascii_string(130, 192); my $dbname3 = generate_ascii_string(130, 192);
my $dbname4 = generate_ascii_string(193, 255); my $dbname4 = generate_ascii_string(193, 255);
my $node = get_new_node('main'); my $node = get_new_node('main');
$node->init(extra => ['--locale=C', '--encoding=LATIN1']); $node->init(extra => [ '--locale=C', '--encoding=LATIN1' ]);
$node->start; $node->start;
foreach my $dbname ($dbname1, $dbname2, $dbname3, $dbname4, 'CamelCase') foreach my $dbname ($dbname1, $dbname2, $dbname3, $dbname4, 'CamelCase')
{ {
$node->run_log(['createdb', $dbname]); $node->run_log([ 'createdb', $dbname ]);
} }
$node->command_ok([qw(vacuumdb --all --echo --analyze-only)], $node->command_ok(
'vacuumdb --all with unusual database names'); [qw(vacuumdb --all --echo --analyze-only)],
'vacuumdb --all with unusual database names');
$node->command_ok([qw(reindexdb --all --echo)], $node->command_ok([qw(reindexdb --all --echo)],
'reindexdb --all with unusual database names'); 'reindexdb --all with unusual database names');
$node->command_ok([qw(clusterdb --all --echo --verbose)], $node->command_ok(
'clusterdb --all with unusual database names'); [qw(clusterdb --all --echo --verbose)],
'clusterdb --all with unusual database names');
...@@ -32,9 +32,11 @@ close $FH; ...@@ -32,9 +32,11 @@ close $FH;
# and character decomposition mapping # and character decomposition mapping
my @characters = (); my @characters = ();
my %character_hash = (); my %character_hash = ();
open($FH, '<', "UnicodeData.txt") or die "Could not open UnicodeData.txt: $!."; open($FH, '<', "UnicodeData.txt")
or die "Could not open UnicodeData.txt: $!.";
while (my $line = <$FH>) while (my $line = <$FH>)
{ {
# Split the line wanted and get the fields needed: # Split the line wanted and get the fields needed:
# - Unicode code value # - Unicode code value
# - Canonical Combining Class # - Canonical Combining Class
...@@ -141,6 +143,7 @@ foreach my $char (@characters) ...@@ -141,6 +143,7 @@ foreach my $char (@characters)
if ($decomp_size == 2) if ($decomp_size == 2)
{ {
# Should this be used for recomposition? # Should this be used for recomposition?
if ($compat) if ($compat)
{ {
...@@ -173,6 +176,7 @@ foreach my $char (@characters) ...@@ -173,6 +176,7 @@ foreach my $char (@characters)
} }
elsif ($decomp_size == 1 && length($first_decomp) <= 4) elsif ($decomp_size == 1 && length($first_decomp) <= 4)
{ {
# The decomposition consists of a single codepoint, and it fits # The decomposition consists of a single codepoint, and it fits
# in a uint16, so we can store it "inline" in the main table. # in a uint16, so we can store it "inline" in the main table.
$flags .= " | DECOMP_INLINE"; $flags .= " | DECOMP_INLINE";
...@@ -201,6 +205,7 @@ foreach my $char (@characters) ...@@ -201,6 +205,7 @@ foreach my $char (@characters)
print $OUTPUT "," unless ($code eq $last_code); print $OUTPUT "," unless ($code eq $last_code);
if ($comment ne "") if ($comment ne "")
{ {
# If the line is wide already, indent the comment with one tab, # If the line is wide already, indent the comment with one tab,
# otherwise with two. This is to make the output match the way # otherwise with two. This is to make the output match the way
# pgindent would mangle it. (This is quite hacky. To do this # pgindent would mangle it. (This is quite hacky. To do this
......
...@@ -35,7 +35,8 @@ while (<$regress_in_fh>) ...@@ -35,7 +35,8 @@ while (<$regress_in_fh>)
} }
# restore STDOUT/ERR so we can print the outcome to the user # restore STDOUT/ERR so we can print the outcome to the user
open(STDERR, ">&", $olderr_fh) or die; # can't complain as STDERR is still duped open(STDERR, ">&", $olderr_fh)
or die; # can't complain as STDERR is still duped
open(STDOUT, ">&", $oldout_fh) or die "can't restore STDOUT: $!"; open(STDOUT, ">&", $oldout_fh) or die "can't restore STDOUT: $!";
# just in case # just in case
......
...@@ -52,7 +52,8 @@ sub ::encode_array_constructor ...@@ -52,7 +52,8 @@ sub ::encode_array_constructor
{ {
package PostgreSQL::InServer; ## no critic (RequireFilenameMatchesPackage); package PostgreSQL::InServer
; ## no critic (RequireFilenameMatchesPackage);
use strict; use strict;
use warnings; use warnings;
......
# src/pl/plperl/plc_trusted.pl # src/pl/plperl/plc_trusted.pl
package PostgreSQL::InServer::safe; ## no critic (RequireFilenameMatchesPackage); package PostgreSQL::InServer::safe
; ## no critic (RequireFilenameMatchesPackage);
# Load widely useful pragmas into plperl to make them available. # Load widely useful pragmas into plperl to make them available.
# #
......
...@@ -11,7 +11,7 @@ use warnings; ...@@ -11,7 +11,7 @@ use warnings;
use PostgresNode; use PostgresNode;
use TestLib; use TestLib;
use Test::More; use Test::More;
if ($windows_os) if ($windows_os)
{ {
plan skip_all => "authentication tests cannot run on Windows"; plan skip_all => "authentication tests cannot run on Windows";
} }
...@@ -25,7 +25,7 @@ else ...@@ -25,7 +25,7 @@ else
# and then execute a reload to refresh it. # and then execute a reload to refresh it.
sub reset_pg_hba sub reset_pg_hba
{ {
my $node = shift; my $node = shift;
my $hba_method = shift; my $hba_method = shift;
unlink($node->data_dir . '/pg_hba.conf'); unlink($node->data_dir . '/pg_hba.conf');
...@@ -36,17 +36,18 @@ sub reset_pg_hba ...@@ -36,17 +36,18 @@ sub reset_pg_hba
# Test access for a single role, useful to wrap all tests into one. # Test access for a single role, useful to wrap all tests into one.
sub test_role sub test_role
{ {
my $node = shift; my $node = shift;
my $role = shift; my $role = shift;
my $method = shift; my $method = shift;
my $expected_res = shift; my $expected_res = shift;
my $status_string = 'failed'; my $status_string = 'failed';
$status_string = 'success' if ($expected_res eq 0); $status_string = 'success' if ($expected_res eq 0);
my $res = $node->psql('postgres', 'SELECT 1', extra_params => ['-U', $role]); my $res =
$node->psql('postgres', 'SELECT 1', extra_params => [ '-U', $role ]);
is($res, $expected_res, is($res, $expected_res,
"authentication $status_string for method $method, role $role"); "authentication $status_string for method $method, role $role");
} }
# Initialize master node # Initialize master node
...@@ -56,27 +57,30 @@ $node->start; ...@@ -56,27 +57,30 @@ $node->start;
# Create 3 roles with different password methods for each one. The same # Create 3 roles with different password methods for each one. The same
# password is used for all of them. # password is used for all of them.
$node->safe_psql('postgres', "SET password_encryption='scram-sha-256'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';"); $node->safe_psql('postgres',
$node->safe_psql('postgres', "SET password_encryption='md5'; CREATE ROLE md5_role LOGIN PASSWORD 'pass';"); "SET password_encryption='scram-sha-256'; CREATE ROLE scram_role LOGIN PASSWORD 'pass';"
);
$node->safe_psql('postgres',
"SET password_encryption='md5'; CREATE ROLE md5_role LOGIN PASSWORD 'pass';");
$ENV{"PGPASSWORD"} = 'pass'; $ENV{"PGPASSWORD"} = 'pass';
# For "trust" method, all users should be able to connect. # For "trust" method, all users should be able to connect.
reset_pg_hba($node, 'trust'); reset_pg_hba($node, 'trust');
test_role($node, 'scram_role', 'trust', 0); test_role($node, 'scram_role', 'trust', 0);
test_role($node, 'md5_role', 'trust', 0); test_role($node, 'md5_role', 'trust', 0);
# For plain "password" method, all users should also be able to connect. # For plain "password" method, all users should also be able to connect.
reset_pg_hba($node, 'password'); reset_pg_hba($node, 'password');
test_role($node, 'scram_role', 'password', 0); test_role($node, 'scram_role', 'password', 0);
test_role($node, 'md5_role', 'password', 0); test_role($node, 'md5_role', 'password', 0);
# For "scram-sha-256" method, user "scram_role" should be able to connect. # For "scram-sha-256" method, user "scram_role" should be able to connect.
reset_pg_hba($node, 'scram-sha-256'); reset_pg_hba($node, 'scram-sha-256');
test_role($node, 'scram_role', 'scram-sha-256', 0); test_role($node, 'scram_role', 'scram-sha-256', 0);
test_role($node, 'md5_role', 'scram-sha-256', 2); test_role($node, 'md5_role', 'scram-sha-256', 2);
# For "md5" method, all users should be able to connect (SCRAM # For "md5" method, all users should be able to connect (SCRAM
# authentication will be performed for the user with a scram verifier.) # authentication will be performed for the user with a scram verifier.)
reset_pg_hba($node, 'md5'); reset_pg_hba($node, 'md5');
test_role($node, 'scram_role', 'md5', 0); test_role($node, 'scram_role', 'md5', 0);
test_role($node, 'md5_role', 'md5', 0); test_role($node, 'md5_role', 'md5', 0);
...@@ -8,7 +8,7 @@ use warnings; ...@@ -8,7 +8,7 @@ use warnings;
use PostgresNode; use PostgresNode;
use TestLib; use TestLib;
use Test::More; use Test::More;
if ($windows_os) if ($windows_os)
{ {
plan skip_all => "authentication tests cannot run on Windows"; plan skip_all => "authentication tests cannot run on Windows";
} }
...@@ -21,7 +21,7 @@ else ...@@ -21,7 +21,7 @@ else
# and then execute a reload to refresh it. # and then execute a reload to refresh it.
sub reset_pg_hba sub reset_pg_hba
{ {
my $node = shift; my $node = shift;
my $hba_method = shift; my $hba_method = shift;
unlink($node->data_dir . '/pg_hba.conf'); unlink($node->data_dir . '/pg_hba.conf');
...@@ -32,24 +32,26 @@ sub reset_pg_hba ...@@ -32,24 +32,26 @@ sub reset_pg_hba
# Test access for a single role, useful to wrap all tests into one. # Test access for a single role, useful to wrap all tests into one.
sub test_login sub test_login
{ {
my $node = shift; my $node = shift;
my $role = shift; my $role = shift;
my $password = shift; my $password = shift;
my $expected_res = shift; my $expected_res = shift;
my $status_string = 'failed'; my $status_string = 'failed';
$status_string = 'success' if ($expected_res eq 0); $status_string = 'success' if ($expected_res eq 0);
$ENV{"PGPASSWORD"} = $password; $ENV{"PGPASSWORD"} = $password;
my $res = $node->psql('postgres', 'SELECT 1', extra_params => ['-U', $role]); my $res =
$node->psql('postgres', 'SELECT 1', extra_params => [ '-U', $role ]);
is($res, $expected_res, is($res, $expected_res,
"authentication $status_string for role $role with password $password"); "authentication $status_string for role $role with password $password"
);
} }
# Initialize master node. Force UTF-8 encoding, so that we can use non-ASCII # Initialize master node. Force UTF-8 encoding, so that we can use non-ASCII
# characters in the passwords below. # characters in the passwords below.
my $node = get_new_node('master'); my $node = get_new_node('master');
$node->init(extra => ['--locale=C', '--encoding=UTF8']); $node->init(extra => [ '--locale=C', '--encoding=UTF8' ]);
$node->start; $node->start;
# These tests are based on the example strings from RFC4013.txt, # These tests are based on the example strings from RFC4013.txt,
...@@ -66,8 +68,9 @@ $node->start; ...@@ -66,8 +68,9 @@ $node->start;
# 7 <U+0627><U+0031> Error - bidirectional check # 7 <U+0627><U+0031> Error - bidirectional check
# Create test roles. # Create test roles.
$node->safe_psql('postgres', $node->safe_psql(
"SET password_encryption='scram-sha-256'; 'postgres',
"SET password_encryption='scram-sha-256';
SET client_encoding='utf8'; SET client_encoding='utf8';
CREATE ROLE saslpreptest1_role LOGIN PASSWORD 'IX'; CREATE ROLE saslpreptest1_role LOGIN PASSWORD 'IX';
CREATE ROLE saslpreptest4a_role LOGIN PASSWORD 'a'; CREATE ROLE saslpreptest4a_role LOGIN PASSWORD 'a';
...@@ -80,23 +83,23 @@ CREATE ROLE saslpreptest7_role LOGIN PASSWORD E'foo\\u0627\\u0031bar'; ...@@ -80,23 +83,23 @@ CREATE ROLE saslpreptest7_role LOGIN PASSWORD E'foo\\u0627\\u0031bar';
reset_pg_hba($node, 'scram-sha-256'); reset_pg_hba($node, 'scram-sha-256');
# Check that #1 and #5 are treated the same as just 'IX' # Check that #1 and #5 are treated the same as just 'IX'
test_login($node, 'saslpreptest1_role', "I\xc2\xadX", 0); test_login($node, 'saslpreptest1_role', "I\xc2\xadX", 0);
test_login($node, 'saslpreptest1_role', "\xe2\x85\xa8", 0); test_login($node, 'saslpreptest1_role', "\xe2\x85\xa8", 0);
# but different from lower case 'ix' # but different from lower case 'ix'
test_login($node, 'saslpreptest1_role', "ix", 2); test_login($node, 'saslpreptest1_role', "ix", 2);
# Check #4 # Check #4
test_login($node, 'saslpreptest4a_role', "a", 0); test_login($node, 'saslpreptest4a_role', "a", 0);
test_login($node, 'saslpreptest4a_role', "\xc2\xaa", 0); test_login($node, 'saslpreptest4a_role', "\xc2\xaa", 0);
test_login($node, 'saslpreptest4b_role', "a", 0); test_login($node, 'saslpreptest4b_role', "a", 0);
test_login($node, 'saslpreptest4b_role', "\xc2\xaa", 0); test_login($node, 'saslpreptest4b_role', "\xc2\xaa", 0);
# Check #6 and #7 - In PostgreSQL, contrary to the spec, if the password # Check #6 and #7 - In PostgreSQL, contrary to the spec, if the password
# contains prohibited characters, we use it as is, without normalization. # contains prohibited characters, we use it as is, without normalization.
test_login($node, 'saslpreptest6_role', "foo\x07bar", 0); test_login($node, 'saslpreptest6_role', "foo\x07bar", 0);
test_login($node, 'saslpreptest6_role', "foobar", 2); test_login($node, 'saslpreptest6_role', "foobar", 2);
test_login($node, 'saslpreptest7_role', "foo\xd8\xa71bar", 0); test_login($node, 'saslpreptest7_role', "foo\xd8\xa71bar", 0);
test_login($node, 'saslpreptest7_role', "foo1\xd8\xa7bar", 2); test_login($node, 'saslpreptest7_role', "foo1\xd8\xa7bar", 2);
test_login($node, 'saslpreptest7_role', "foobar", 2); test_login($node, 'saslpreptest7_role', "foobar", 2);
...@@ -44,8 +44,7 @@ is($master_ts, $standby_ts, "standby gives same value as master"); ...@@ -44,8 +44,7 @@ is($master_ts, $standby_ts, "standby gives same value as master");
$master->append_conf('postgresql.conf', 'track_commit_timestamp = off'); $master->append_conf('postgresql.conf', 'track_commit_timestamp = off');
$master->restart; $master->restart;
$master->safe_psql('postgres', 'checkpoint'); $master->safe_psql('postgres', 'checkpoint');
$master_lsn = $master_lsn = $master->safe_psql('postgres', 'select pg_current_wal_lsn()');
$master->safe_psql('postgres', 'select pg_current_wal_lsn()');
$standby->poll_query_until('postgres', $standby->poll_query_until('postgres',
qq{SELECT '$master_lsn'::pg_lsn <= pg_last_wal_replay_lsn()}) qq{SELECT '$master_lsn'::pg_lsn <= pg_last_wal_replay_lsn()})
or die "slave never caught up"; or die "slave never caught up";
......
...@@ -22,12 +22,12 @@ like( ...@@ -22,12 +22,12 @@ like(
($ret, $stdout, $stderr) = ($ret, $stdout, $stderr) =
$node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('1');]); $node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('1');]);
is($ret, 0, 'getting ts of BootstrapTransactionId succeeds'); is($ret, 0, 'getting ts of BootstrapTransactionId succeeds');
is($stdout, '', 'timestamp of BootstrapTransactionId is null'); is($stdout, '', 'timestamp of BootstrapTransactionId is null');
($ret, $stdout, $stderr) = ($ret, $stdout, $stderr) =
$node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('2');]); $node_master->psql('postgres', qq[SELECT pg_xact_commit_timestamp('2');]);
is($ret, 0, 'getting ts of FrozenTransactionId succeeds'); is($ret, 0, 'getting ts of FrozenTransactionId succeeds');
is($stdout, '', 'timestamp of FrozenTransactionId is null'); is($stdout, '', 'timestamp of FrozenTransactionId is null');
# Since FirstNormalTransactionId will've occurred during initdb, long before we # Since FirstNormalTransactionId will've occurred during initdb, long before we
......
...@@ -41,12 +41,9 @@ my $tempdir_short = TestLib::tempdir_short; ...@@ -41,12 +41,9 @@ my $tempdir_short = TestLib::tempdir_short;
my %pgdump_runs = ( my %pgdump_runs = (
binary_upgrade => { binary_upgrade => {
dump_cmd => [ dump_cmd => [
'pg_dump', 'pg_dump', '--no-sync',
'--no-sync', "--file=$tempdir/binary_upgrade.sql", '--schema-only',
"--file=$tempdir/binary_upgrade.sql", '--binary-upgrade', '--dbname=postgres', ], },
'--schema-only',
'--binary-upgrade',
'--dbname=postgres', ], },
clean => { clean => {
dump_cmd => [ dump_cmd => [
'pg_dump', "--file=$tempdir/clean.sql", 'pg_dump', "--file=$tempdir/clean.sql",
...@@ -63,19 +60,16 @@ my %pgdump_runs = ( ...@@ -63,19 +60,16 @@ my %pgdump_runs = (
'postgres', ], }, 'postgres', ], },
column_inserts => { column_inserts => {
dump_cmd => [ dump_cmd => [
'pg_dump', 'pg_dump', '--no-sync',
'--no-sync', "--file=$tempdir/column_inserts.sql", '-a',
"--file=$tempdir/column_inserts.sql", '--column-inserts', 'postgres', ], },
'-a',
'--column-inserts',
'postgres', ], },
createdb => { createdb => {
dump_cmd => [ dump_cmd => [
'pg_dump', 'pg_dump',
'--no-sync', '--no-sync',
"--file=$tempdir/createdb.sql", "--file=$tempdir/createdb.sql",
'-C', '-C',
'-R', # no-op, just for testing '-R', # no-op, just for testing
'postgres', ], }, 'postgres', ], },
data_only => { data_only => {
dump_cmd => [ dump_cmd => [
...@@ -83,7 +77,7 @@ my %pgdump_runs = ( ...@@ -83,7 +77,7 @@ my %pgdump_runs = (
'--no-sync', '--no-sync',
"--file=$tempdir/data_only.sql", "--file=$tempdir/data_only.sql",
'-a', '-a',
'-v', # no-op, just make sure it works '-v', # no-op, just make sure it works
'postgres', ], }, 'postgres', ], },
defaults => { defaults => {
dump_cmd => [ 'pg_dump', '-f', "$tempdir/defaults.sql", 'postgres', ], dump_cmd => [ 'pg_dump', '-f', "$tempdir/defaults.sql", 'postgres', ],
...@@ -126,52 +120,35 @@ my %pgdump_runs = ( ...@@ -126,52 +120,35 @@ my %pgdump_runs = (
"$tempdir/defaults_tar_format.tar", ], }, "$tempdir/defaults_tar_format.tar", ], },
pg_dumpall_globals => { pg_dumpall_globals => {
dump_cmd => [ dump_cmd => [
'pg_dumpall', 'pg_dumpall', '--no-sync',
'--no-sync', "--file=$tempdir/pg_dumpall_globals.sql", '-g', ], },
"--file=$tempdir/pg_dumpall_globals.sql",
'-g', ],
},
no_privs => { no_privs => {
dump_cmd => [ dump_cmd => [
'pg_dump', 'pg_dump', '--no-sync',
'--no-sync', "--file=$tempdir/no_privs.sql", '-x',
"--file=$tempdir/no_privs.sql",
'-x',
'postgres', ], }, 'postgres', ], },
no_owner => { no_owner => {
dump_cmd => [ dump_cmd => [
'pg_dump', 'pg_dump', '--no-sync',
'--no-sync', "--file=$tempdir/no_owner.sql", '-O',
"--file=$tempdir/no_owner.sql",
'-O',
'postgres', ], }, 'postgres', ], },
schema_only => { schema_only => {
dump_cmd => [ dump_cmd => [
'pg_dump', 'pg_dump', '--no-sync', "--file=$tempdir/schema_only.sql",
'--no-sync', '-s', 'postgres', ], },
"--file=$tempdir/schema_only.sql",
'-s',
'postgres', ],
},
section_pre_data => { section_pre_data => {
dump_cmd => [ dump_cmd => [
'pg_dump', 'pg_dump', '--no-sync',
'--no-sync', "--file=$tempdir/section_pre_data.sql", '--section=pre-data',
"--file=$tempdir/section_pre_data.sql",
'--section=pre-data',
'postgres', ], }, 'postgres', ], },
section_data => { section_data => {
dump_cmd => [ dump_cmd => [
'pg_dump', 'pg_dump', '--no-sync',
'--no-sync', "--file=$tempdir/section_data.sql", '--section=data',
"--file=$tempdir/section_data.sql",
'--section=data',
'postgres', ], }, 'postgres', ], },
section_post_data => { section_post_data => {
dump_cmd => [ dump_cmd => [
'pg_dump', 'pg_dump', '--no-sync', "--file=$tempdir/section_post_data.sql",
'--no-sync',
"--file=$tempdir/section_post_data.sql",
'--section=post-data', 'postgres', ], },); '--section=post-data', 'postgres', ], },);
############################################################### ###############################################################
...@@ -492,9 +469,8 @@ my %tests = ( ...@@ -492,9 +469,8 @@ my %tests = (
pg_dumpall_globals => 1, pg_dumpall_globals => 1,
section_post_data => 1, }, }, section_post_data => 1, }, },
'GRANT SELECT(col2) ON regress_pg_dump_table TO regress_dump_test_role' 'GRANT SELECT(col2) ON regress_pg_dump_table TO regress_dump_test_role' =>
=> { { create_order => 4,
create_order => 4,
create_sql => 'GRANT SELECT(col2) ON regress_pg_dump_table create_sql => 'GRANT SELECT(col2) ON regress_pg_dump_table
TO regress_dump_test_role;', TO regress_dump_test_role;',
regexp => qr/^ regexp => qr/^
......
...@@ -729,7 +729,7 @@ sub restart ...@@ -729,7 +729,7 @@ sub restart
my $name = $self->name; my $name = $self->name;
print "### Restarting node \"$name\"\n"; print "### Restarting node \"$name\"\n";
TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile, TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile,
'restart'); 'restart');
$self->_update_pid(1); $self->_update_pid(1);
} }
...@@ -750,7 +750,7 @@ sub promote ...@@ -750,7 +750,7 @@ sub promote
my $name = $self->name; my $name = $self->name;
print "### Promoting node \"$name\"\n"; print "### Promoting node \"$name\"\n";
TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile, TestLib::system_or_bail('pg_ctl', '-D', $pgdata, '-l', $logfile,
'promote'); 'promote');
} }
# Internal routine to enable streaming replication on a standby node. # Internal routine to enable streaming replication on a standby node.
...@@ -846,6 +846,7 @@ sub _update_pid ...@@ -846,6 +846,7 @@ sub _update_pid
$self->{_pid} = undef; $self->{_pid} = undef;
print "# No postmaster PID for node \"$name\"\n"; print "# No postmaster PID for node \"$name\"\n";
# Complain if we expected to find a pidfile. # Complain if we expected to find a pidfile.
BAIL_OUT("postmaster.pid unexpectedly not present") if $is_running; BAIL_OUT("postmaster.pid unexpectedly not present") if $is_running;
} }
...@@ -1140,10 +1141,12 @@ sub psql ...@@ -1140,10 +1141,12 @@ sub psql
my $exc_save = $@; my $exc_save = $@;
if ($exc_save) if ($exc_save)
{ {
# IPC::Run::run threw an exception. re-throw unless it's a # IPC::Run::run threw an exception. re-throw unless it's a
# timeout, which we'll handle by testing is_expired # timeout, which we'll handle by testing is_expired
die $exc_save die $exc_save
if (blessed($exc_save) || $exc_save !~ /^\Q$timeout_exception\E/); if (blessed($exc_save)
|| $exc_save !~ /^\Q$timeout_exception\E/);
$ret = undef; $ret = undef;
...@@ -1191,7 +1194,8 @@ sub psql ...@@ -1191,7 +1194,8 @@ sub psql
if $ret == 1; if $ret == 1;
die "connection error: '$$stderr'\nwhile running '@psql_params'" die "connection error: '$$stderr'\nwhile running '@psql_params'"
if $ret == 2; if $ret == 2;
die "error running SQL: '$$stderr'\nwhile running '@psql_params' with sql '$sql'" die
"error running SQL: '$$stderr'\nwhile running '@psql_params' with sql '$sql'"
if $ret == 3; if $ret == 3;
die "psql returns $ret: '$$stderr'\nwhile running '@psql_params'"; die "psql returns $ret: '$$stderr'\nwhile running '@psql_params'";
} }
...@@ -1362,15 +1366,17 @@ mode must be specified. ...@@ -1362,15 +1366,17 @@ mode must be specified.
sub lsn sub lsn
{ {
my ($self, $mode) = @_; my ($self, $mode) = @_;
my %modes = ('insert' => 'pg_current_wal_insert_lsn()', my %modes = (
'flush' => 'pg_current_wal_flush_lsn()', 'insert' => 'pg_current_wal_insert_lsn()',
'write' => 'pg_current_wal_lsn()', 'flush' => 'pg_current_wal_flush_lsn()',
'receive' => 'pg_last_wal_receive_lsn()', 'write' => 'pg_current_wal_lsn()',
'replay' => 'pg_last_wal_replay_lsn()'); 'receive' => 'pg_last_wal_receive_lsn()',
'replay' => 'pg_last_wal_replay_lsn()');
$mode = '<undef>' if !defined($mode); $mode = '<undef>' if !defined($mode);
die "unknown mode for 'lsn': '$mode', valid modes are " . join(', ', keys %modes) die "unknown mode for 'lsn': '$mode', valid modes are "
if !defined($modes{$mode}); . join(', ', keys %modes)
if !defined($modes{$mode});
my $result = $self->safe_psql('postgres', "SELECT $modes{$mode}"); my $result = $self->safe_psql('postgres', "SELECT $modes{$mode}");
chomp($result); chomp($result);
...@@ -1409,18 +1415,29 @@ sub wait_for_catchup ...@@ -1409,18 +1415,29 @@ sub wait_for_catchup
{ {
my ($self, $standby_name, $mode, $target_lsn) = @_; my ($self, $standby_name, $mode, $target_lsn) = @_;
$mode = defined($mode) ? $mode : 'replay'; $mode = defined($mode) ? $mode : 'replay';
my %valid_modes = ( 'sent' => 1, 'write' => 1, 'flush' => 1, 'replay' => 1 ); my %valid_modes =
die "unknown mode $mode for 'wait_for_catchup', valid modes are " . join(', ', keys(%valid_modes)) unless exists($valid_modes{$mode}); ('sent' => 1, 'write' => 1, 'flush' => 1, 'replay' => 1);
die "unknown mode $mode for 'wait_for_catchup', valid modes are "
. join(', ', keys(%valid_modes))
unless exists($valid_modes{$mode});
# Allow passing of a PostgresNode instance as shorthand # Allow passing of a PostgresNode instance as shorthand
if ( blessed( $standby_name ) && $standby_name->isa("PostgresNode") ) if (blessed($standby_name) && $standby_name->isa("PostgresNode"))
{ {
$standby_name = $standby_name->name; $standby_name = $standby_name->name;
} }
die 'target_lsn must be specified' unless defined($target_lsn); die 'target_lsn must be specified' unless defined($target_lsn);
print "Waiting for replication conn " . $standby_name . "'s " . $mode . "_lsn to pass " . $target_lsn . " on " . $self->name . "\n"; print "Waiting for replication conn "
my $query = qq[SELECT '$target_lsn' <= ${mode}_lsn FROM pg_catalog.pg_stat_replication WHERE application_name = '$standby_name';]; . $standby_name . "'s "
. $mode
. "_lsn to pass "
. $target_lsn . " on "
. $self->name . "\n";
my $query =
qq[SELECT '$target_lsn' <= ${mode}_lsn FROM pg_catalog.pg_stat_replication WHERE application_name = '$standby_name';];
$self->poll_query_until('postgres', $query) $self->poll_query_until('postgres', $query)
or die "timed out waiting for catchup, current location is " . ($self->safe_psql('postgres', $query) || '(unknown)'); or die "timed out waiting for catchup, current location is "
. ($self->safe_psql('postgres', $query) || '(unknown)');
print "done\n"; print "done\n";
} }
...@@ -1453,10 +1470,17 @@ sub wait_for_slot_catchup ...@@ -1453,10 +1470,17 @@ sub wait_for_slot_catchup
die "valid modes are restart, confirmed_flush"; die "valid modes are restart, confirmed_flush";
} }
die 'target lsn must be specified' unless defined($target_lsn); die 'target lsn must be specified' unless defined($target_lsn);
print "Waiting for replication slot " . $slot_name . "'s " . $mode . "_lsn to pass " . $target_lsn . " on " . $self->name . "\n"; print "Waiting for replication slot "
my $query = qq[SELECT '$target_lsn' <= ${mode}_lsn FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name';]; . $slot_name . "'s "
. $mode
. "_lsn to pass "
. $target_lsn . " on "
. $self->name . "\n";
my $query =
qq[SELECT '$target_lsn' <= ${mode}_lsn FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name';];
$self->poll_query_until('postgres', $query) $self->poll_query_until('postgres', $query)
or die "timed out waiting for catchup, current location is " . ($self->safe_psql('postgres', $query) || '(unknown)'); or die "timed out waiting for catchup, current location is "
. ($self->safe_psql('postgres', $query) || '(unknown)');
print "done\n"; print "done\n";
} }
...@@ -1485,18 +1509,23 @@ null columns. ...@@ -1485,18 +1509,23 @@ null columns.
sub query_hash sub query_hash
{ {
my ($self, $dbname, $query, @columns) = @_; my ($self, $dbname, $query, @columns) = @_;
die 'calls in array context for multi-row results not supported yet' if (wantarray); die 'calls in array context for multi-row results not supported yet'
if (wantarray);
# Replace __COLUMNS__ if found # Replace __COLUMNS__ if found
substr($query, index($query, '__COLUMNS__'), length('__COLUMNS__')) = join(', ', @columns) substr($query, index($query, '__COLUMNS__'), length('__COLUMNS__')) =
if index($query, '__COLUMNS__') >= 0; join(', ', @columns)
if index($query, '__COLUMNS__') >= 0;
my $result = $self->safe_psql($dbname, $query); my $result = $self->safe_psql($dbname, $query);
# hash slice, see http://stackoverflow.com/a/16755894/398670 . # hash slice, see http://stackoverflow.com/a/16755894/398670 .
# #
# Fills the hash with empty strings produced by x-operator element # Fills the hash with empty strings produced by x-operator element
# duplication if result is an empty row # duplication if result is an empty row
# #
my %val; my %val;
@val{@columns} = $result ne '' ? split(qr/\|/, $result) : ('',) x scalar(@columns); @val{@columns} =
$result ne '' ? split(qr/\|/, $result) : ('',) x scalar(@columns);
return \%val; return \%val;
} }
...@@ -1518,8 +1547,14 @@ either. ...@@ -1518,8 +1547,14 @@ either.
sub slot sub slot
{ {
my ($self, $slot_name) = @_; my ($self, $slot_name) = @_;
my @columns = ('plugin', 'slot_type', 'datoid', 'database', 'active', 'active_pid', 'xmin', 'catalog_xmin', 'restart_lsn'); my @columns = (
return $self->query_hash('postgres', "SELECT __COLUMNS__ FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name'", @columns); 'plugin', 'slot_type', 'datoid', 'database',
'active', 'active_pid', 'xmin', 'catalog_xmin',
'restart_lsn');
return $self->query_hash(
'postgres',
"SELECT __COLUMNS__ FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name'",
@columns);
} }
=pod =pod
...@@ -1543,29 +1578,36 @@ to check for timeout. retval is undef on timeout. ...@@ -1543,29 +1578,36 @@ to check for timeout. retval is undef on timeout.
sub pg_recvlogical_upto sub pg_recvlogical_upto
{ {
my ($self, $dbname, $slot_name, $endpos, $timeout_secs, %plugin_options) = @_; my ($self, $dbname, $slot_name, $endpos, $timeout_secs, %plugin_options) =
@_;
my ($stdout, $stderr); my ($stdout, $stderr);
my $timeout_exception = 'pg_recvlogical timed out'; my $timeout_exception = 'pg_recvlogical timed out';
die 'slot name must be specified' unless defined($slot_name); die 'slot name must be specified' unless defined($slot_name);
die 'endpos must be specified' unless defined($endpos); die 'endpos must be specified' unless defined($endpos);
my @cmd = ('pg_recvlogical', '-S', $slot_name, '--dbname', $self->connstr($dbname)); my @cmd = (
'pg_recvlogical', '-S', $slot_name, '--dbname',
$self->connstr($dbname));
push @cmd, '--endpos', $endpos; push @cmd, '--endpos', $endpos;
push @cmd, '-f', '-', '--no-loop', '--start'; push @cmd, '-f', '-', '--no-loop', '--start';
while (my ($k, $v) = each %plugin_options) while (my ($k, $v) = each %plugin_options)
{ {
die "= is not permitted to appear in replication option name" if ($k =~ qr/=/); die "= is not permitted to appear in replication option name"
if ($k =~ qr/=/);
push @cmd, "-o", "$k=$v"; push @cmd, "-o", "$k=$v";
} }
my $timeout; my $timeout;
$timeout = IPC::Run::timeout($timeout_secs, exception => $timeout_exception ) if $timeout_secs; $timeout =
IPC::Run::timeout($timeout_secs, exception => $timeout_exception)
if $timeout_secs;
my $ret = 0; my $ret = 0;
do { do
{
local $@; local $@;
eval { eval {
IPC::Run::run(\@cmd, ">", \$stdout, "2>", \$stderr, $timeout); IPC::Run::run(\@cmd, ">", \$stdout, "2>", \$stderr, $timeout);
...@@ -1574,6 +1616,7 @@ sub pg_recvlogical_upto ...@@ -1574,6 +1616,7 @@ sub pg_recvlogical_upto
my $exc_save = $@; my $exc_save = $@;
if ($exc_save) if ($exc_save)
{ {
# IPC::Run::run threw an exception. re-throw unless it's a # IPC::Run::run threw an exception. re-throw unless it's a
# timeout, which we'll handle by testing is_expired # timeout, which we'll handle by testing is_expired
die $exc_save die $exc_save
...@@ -1584,8 +1627,9 @@ sub pg_recvlogical_upto ...@@ -1584,8 +1627,9 @@ sub pg_recvlogical_upto
die "Got timeout exception '$exc_save' but timer not expired?!" die "Got timeout exception '$exc_save' but timer not expired?!"
unless $timeout->is_expired; unless $timeout->is_expired;
die "$exc_save waiting for endpos $endpos with stdout '$stdout', stderr '$stderr'" die
unless wantarray; "$exc_save waiting for endpos $endpos with stdout '$stdout', stderr '$stderr'"
unless wantarray;
} }
}; };
...@@ -1598,7 +1642,9 @@ sub pg_recvlogical_upto ...@@ -1598,7 +1642,9 @@ sub pg_recvlogical_upto
} }
else else
{ {
die "pg_recvlogical exited with code '$ret', stdout '$stdout' and stderr '$stderr'" if $ret; die
"pg_recvlogical exited with code '$ret', stdout '$stdout' and stderr '$stderr'"
if $ret;
return $stdout; return $stdout;
} }
} }
......
...@@ -17,6 +17,7 @@ use File::Spec; ...@@ -17,6 +17,7 @@ use File::Spec;
use File::Temp (); use File::Temp ();
use IPC::Run; use IPC::Run;
use SimpleTee; use SimpleTee;
# specify a recent enough version of Test::More to support the note() function # specify a recent enough version of Test::More to support the note() function
use Test::More 0.82; use Test::More 0.82;
...@@ -91,8 +92,8 @@ INIT ...@@ -91,8 +92,8 @@ INIT
# Hijack STDOUT and STDERR to the log file # Hijack STDOUT and STDERR to the log file
open(my $orig_stdout, '>&', \*STDOUT); open(my $orig_stdout, '>&', \*STDOUT);
open(my $orig_stderr, '>&', \*STDERR); open(my $orig_stderr, '>&', \*STDERR);
open(STDOUT, '>&', $testlog); open(STDOUT, '>&', $testlog);
open(STDERR, '>&', $testlog); open(STDERR, '>&', $testlog);
# The test output (ok ...) needs to be printed to the original STDOUT so # The test output (ok ...) needs to be printed to the original STDOUT so
# that the 'prove' program can parse it, and display it to the user in # that the 'prove' program can parse it, and display it to the user in
......
This diff is collapsed.
...@@ -22,8 +22,7 @@ sub test_recovery_standby ...@@ -22,8 +22,7 @@ sub test_recovery_standby
foreach my $param_item (@$recovery_params) foreach my $param_item (@$recovery_params)
{ {
$node_standby->append_conf( $node_standby->append_conf('recovery.conf', qq($param_item));
'recovery.conf', qq($param_item));
} }
$node_standby->start; $node_standby->start;
...@@ -71,8 +70,8 @@ my ($lsn2, $recovery_txid) = split /\|/, $ret; ...@@ -71,8 +70,8 @@ my ($lsn2, $recovery_txid) = split /\|/, $ret;
# More data, with recovery target timestamp # More data, with recovery target timestamp
$node_master->safe_psql('postgres', $node_master->safe_psql('postgres',
"INSERT INTO tab_int VALUES (generate_series(2001,3000))"); "INSERT INTO tab_int VALUES (generate_series(2001,3000))");
$ret = $node_master->safe_psql('postgres', $ret =
"SELECT pg_current_wal_lsn(), now();"); $node_master->safe_psql('postgres', "SELECT pg_current_wal_lsn(), now();");
my ($lsn3, $recovery_time) = split /\|/, $ret; my ($lsn3, $recovery_time) = split /\|/, $ret;
# Even more data, this time with a recovery target name # Even more data, this time with a recovery target name
...@@ -87,7 +86,8 @@ $node_master->safe_psql('postgres', ...@@ -87,7 +86,8 @@ $node_master->safe_psql('postgres',
# And now for a recovery target LSN # And now for a recovery target LSN
$node_master->safe_psql('postgres', $node_master->safe_psql('postgres',
"INSERT INTO tab_int VALUES (generate_series(4001,5000))"); "INSERT INTO tab_int VALUES (generate_series(4001,5000))");
my $recovery_lsn = $node_master->safe_psql('postgres', "SELECT pg_current_wal_lsn()"); my $recovery_lsn =
$node_master->safe_psql('postgres', "SELECT pg_current_wal_lsn()");
my $lsn5 = my $lsn5 =
$node_master->safe_psql('postgres', "SELECT pg_current_wal_lsn();"); $node_master->safe_psql('postgres', "SELECT pg_current_wal_lsn();");
......
...@@ -34,7 +34,8 @@ $node_master->safe_psql('postgres', ...@@ -34,7 +34,8 @@ $node_master->safe_psql('postgres',
"CREATE TABLE tab_int AS SELECT generate_series(1,1000) AS a"); "CREATE TABLE tab_int AS SELECT generate_series(1,1000) AS a");
# Wait until standby has replayed enough data on standby 1 # Wait until standby has replayed enough data on standby 1
$node_master->wait_for_catchup($node_standby_1, 'replay', $node_master->lsn('write')); $node_master->wait_for_catchup($node_standby_1, 'replay',
$node_master->lsn('write'));
# Stop and remove master, and promote standby 1, switching it to a new timeline # Stop and remove master, and promote standby 1, switching it to a new timeline
$node_master->teardown_node; $node_master->teardown_node;
...@@ -55,7 +56,8 @@ $node_standby_2->restart; ...@@ -55,7 +56,8 @@ $node_standby_2->restart;
# to ensure that the timeline switch has been done. # to ensure that the timeline switch has been done.
$node_standby_1->safe_psql('postgres', $node_standby_1->safe_psql('postgres',
"INSERT INTO tab_int VALUES (generate_series(1001,2000))"); "INSERT INTO tab_int VALUES (generate_series(1001,2000))");
$node_standby_1->wait_for_catchup($node_standby_2, 'replay', $node_standby_1->lsn('write')); $node_standby_1->wait_for_catchup($node_standby_2, 'replay',
$node_standby_1->lsn('write'));
my $result = my $result =
$node_standby_2->safe_psql('postgres', "SELECT count(*) FROM tab_int"); $node_standby_2->safe_psql('postgres', "SELECT count(*) FROM tab_int");
......
...@@ -50,8 +50,7 @@ while ($remaining-- > 0) ...@@ -50,8 +50,7 @@ while ($remaining-- > 0)
# Done waiting? # Done waiting?
my $replay_status = $node_standby->safe_psql('postgres', my $replay_status = $node_standby->safe_psql('postgres',
"SELECT (pg_last_wal_replay_lsn() - '$until_lsn'::pg_lsn) >= 0" "SELECT (pg_last_wal_replay_lsn() - '$until_lsn'::pg_lsn) >= 0");
);
last if $replay_status eq 't'; last if $replay_status eq 't';
# No, sleep some more. # No, sleep some more.
......
...@@ -14,21 +14,27 @@ use Config; ...@@ -14,21 +14,27 @@ use Config;
my $node_master = get_new_node('master'); my $node_master = get_new_node('master');
$node_master->init(allows_streaming => 1); $node_master->init(allows_streaming => 1);
$node_master->append_conf( $node_master->append_conf(
'postgresql.conf', qq( 'postgresql.conf', qq(
wal_level = logical wal_level = logical
)); ));
$node_master->start; $node_master->start;
my $backup_name = 'master_backup'; my $backup_name = 'master_backup';
$node_master->safe_psql('postgres', qq[CREATE TABLE decoding_test(x integer, y text);]); $node_master->safe_psql('postgres',
qq[CREATE TABLE decoding_test(x integer, y text);]);
$node_master->safe_psql('postgres', qq[SELECT pg_create_logical_replication_slot('test_slot', 'test_decoding');]); $node_master->safe_psql('postgres',
qq[SELECT pg_create_logical_replication_slot('test_slot', 'test_decoding');]);
$node_master->safe_psql('postgres', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(1,10) s;]); $node_master->safe_psql('postgres',
qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(1,10) s;]
);
# Basic decoding works # Basic decoding works
my($result) = $node_master->safe_psql('postgres', qq[SELECT pg_logical_slot_get_changes('test_slot', NULL, NULL);]); my ($result) = $node_master->safe_psql('postgres',
is(scalar(my @foobar = split /^/m, $result), 12, 'Decoding produced 12 rows inc BEGIN/COMMIT'); qq[SELECT pg_logical_slot_get_changes('test_slot', NULL, NULL);]);
is(scalar(my @foobar = split /^/m, $result),
12, 'Decoding produced 12 rows inc BEGIN/COMMIT');
# If we immediately crash the server we might lose the progress we just made # If we immediately crash the server we might lose the progress we just made
# and replay the same changes again. But a clean shutdown should never repeat # and replay the same changes again. But a clean shutdown should never repeat
...@@ -36,13 +42,16 @@ is(scalar(my @foobar = split /^/m, $result), 12, 'Decoding produced 12 rows inc ...@@ -36,13 +42,16 @@ is(scalar(my @foobar = split /^/m, $result), 12, 'Decoding produced 12 rows inc
$node_master->restart('fast'); $node_master->restart('fast');
# There are no new writes, so the result should be empty. # There are no new writes, so the result should be empty.
$result = $node_master->safe_psql('postgres', qq[SELECT pg_logical_slot_get_changes('test_slot', NULL, NULL);]); $result = $node_master->safe_psql('postgres',
qq[SELECT pg_logical_slot_get_changes('test_slot', NULL, NULL);]);
chomp($result); chomp($result);
is($result, '', 'Decoding after fast restart repeats no rows'); is($result, '', 'Decoding after fast restart repeats no rows');
# Insert some rows and verify that we get the same results from pg_recvlogical # Insert some rows and verify that we get the same results from pg_recvlogical
# and the SQL interface. # and the SQL interface.
$node_master->safe_psql('postgres', qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(1,4) s;]); $node_master->safe_psql('postgres',
qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(1,4) s;]
);
my $expected = q{BEGIN my $expected = q{BEGIN
table public.decoding_test: INSERT: x[integer]:1 y[text]:'1' table public.decoding_test: INSERT: x[integer]:1 y[text]:'1'
...@@ -51,59 +60,91 @@ table public.decoding_test: INSERT: x[integer]:3 y[text]:'3' ...@@ -51,59 +60,91 @@ table public.decoding_test: INSERT: x[integer]:3 y[text]:'3'
table public.decoding_test: INSERT: x[integer]:4 y[text]:'4' table public.decoding_test: INSERT: x[integer]:4 y[text]:'4'
COMMIT}; COMMIT};
my $stdout_sql = $node_master->safe_psql('postgres', qq[SELECT data FROM pg_logical_slot_peek_changes('test_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');]); my $stdout_sql = $node_master->safe_psql('postgres',
qq[SELECT data FROM pg_logical_slot_peek_changes('test_slot', NULL, NULL, 'include-xids', '0', 'skip-empty-xacts', '1');]
);
is($stdout_sql, $expected, 'got expected output from SQL decoding session'); is($stdout_sql, $expected, 'got expected output from SQL decoding session');
my $endpos = $node_master->safe_psql('postgres', "SELECT lsn FROM pg_logical_slot_peek_changes('test_slot', NULL, NULL) ORDER BY lsn DESC LIMIT 1;"); my $endpos = $node_master->safe_psql('postgres',
"SELECT lsn FROM pg_logical_slot_peek_changes('test_slot', NULL, NULL) ORDER BY lsn DESC LIMIT 1;"
);
print "waiting to replay $endpos\n"; print "waiting to replay $endpos\n";
my $stdout_recv = $node_master->pg_recvlogical_upto('postgres', 'test_slot', $endpos, 10, 'include-xids' => '0', 'skip-empty-xacts' => '1'); my $stdout_recv = $node_master->pg_recvlogical_upto(
'postgres', 'test_slot', $endpos, 10,
'include-xids' => '0',
'skip-empty-xacts' => '1');
chomp($stdout_recv); chomp($stdout_recv);
is($stdout_recv, $expected, 'got same expected output from pg_recvlogical decoding session'); is($stdout_recv, $expected,
'got same expected output from pg_recvlogical decoding session');
$stdout_recv = $node_master->pg_recvlogical_upto('postgres', 'test_slot', $endpos, 10, 'include-xids' => '0', 'skip-empty-xacts' => '1'); $stdout_recv = $node_master->pg_recvlogical_upto(
'postgres', 'test_slot', $endpos, 10,
'include-xids' => '0',
'skip-empty-xacts' => '1');
chomp($stdout_recv); chomp($stdout_recv);
is($stdout_recv, '', 'pg_recvlogical acknowledged changes, nothing pending on slot'); is($stdout_recv, '',
'pg_recvlogical acknowledged changes, nothing pending on slot');
$node_master->safe_psql('postgres', 'CREATE DATABASE otherdb'); $node_master->safe_psql('postgres', 'CREATE DATABASE otherdb');
is($node_master->psql('otherdb', "SELECT lsn FROM pg_logical_slot_peek_changes('test_slot', NULL, NULL) ORDER BY lsn DESC LIMIT 1;"), 3, is( $node_master->psql(
'otherdb',
"SELECT lsn FROM pg_logical_slot_peek_changes('test_slot', NULL, NULL) ORDER BY lsn DESC LIMIT 1;"
),
3,
'replaying logical slot from another database fails'); 'replaying logical slot from another database fails');
$node_master->safe_psql('otherdb', qq[SELECT pg_create_logical_replication_slot('otherdb_slot', 'test_decoding');]); $node_master->safe_psql('otherdb',
qq[SELECT pg_create_logical_replication_slot('otherdb_slot', 'test_decoding');]
);
# make sure you can't drop a slot while active # make sure you can't drop a slot while active
SKIP: SKIP:
{ {
# some Windows Perls at least don't like IPC::Run's start/kill_kill regime.
# some Windows Perls at least don't like IPC::Run's start/kill_kill regime.
skip "Test fails on Windows perl", 2 if $Config{osname} eq 'MSWin32'; skip "Test fails on Windows perl", 2 if $Config{osname} eq 'MSWin32';
my $pg_recvlogical = IPC::Run::start(['pg_recvlogical', '-d', $node_master->connstr('otherdb'), '-S', 'otherdb_slot', '-f', '-', '--start']); my $pg_recvlogical = IPC::Run::start(
$node_master->poll_query_until('otherdb', "SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'otherdb_slot' AND active_pid IS NOT NULL)"); [ 'pg_recvlogical', '-d', $node_master->connstr('otherdb'),
is($node_master->psql('postgres', 'DROP DATABASE otherdb'), 3, '-S', 'otherdb_slot', '-f', '-', '--start' ]);
'dropping a DB with inactive logical slots fails'); $node_master->poll_query_until('otherdb',
"SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'otherdb_slot' AND active_pid IS NOT NULL)"
);
is($node_master->psql('postgres', 'DROP DATABASE otherdb'),
3, 'dropping a DB with inactive logical slots fails');
$pg_recvlogical->kill_kill; $pg_recvlogical->kill_kill;
is($node_master->slot('otherdb_slot')->{'slot_name'}, undef, is($node_master->slot('otherdb_slot')->{'slot_name'},
'logical slot still exists'); undef, 'logical slot still exists');
} }
$node_master->poll_query_until('otherdb', "SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'otherdb_slot' AND active_pid IS NULL)"); $node_master->poll_query_until('otherdb',
is($node_master->psql('postgres', 'DROP DATABASE otherdb'), 0, "SELECT EXISTS (SELECT 1 FROM pg_replication_slots WHERE slot_name = 'otherdb_slot' AND active_pid IS NULL)"
'dropping a DB with inactive logical slots succeeds'); );
is($node_master->slot('otherdb_slot')->{'slot_name'}, undef, is($node_master->psql('postgres', 'DROP DATABASE otherdb'),
'logical slot was actually dropped with DB'); 0, 'dropping a DB with inactive logical slots succeeds');
is($node_master->slot('otherdb_slot')->{'slot_name'},
undef, 'logical slot was actually dropped with DB');
# Restarting a node with wal_level = logical that has existing # Restarting a node with wal_level = logical that has existing
# slots must succeed, but decoding from those slots must fail. # slots must succeed, but decoding from those slots must fail.
$node_master->safe_psql('postgres', 'ALTER SYSTEM SET wal_level = replica'); $node_master->safe_psql('postgres', 'ALTER SYSTEM SET wal_level = replica');
is($node_master->safe_psql('postgres', 'SHOW wal_level'), 'logical', 'wal_level is still logical before restart'); is($node_master->safe_psql('postgres', 'SHOW wal_level'),
'logical', 'wal_level is still logical before restart');
$node_master->restart; $node_master->restart;
is($node_master->safe_psql('postgres', 'SHOW wal_level'), 'replica', 'wal_level is replica'); is($node_master->safe_psql('postgres', 'SHOW wal_level'),
isnt($node_master->slot('test_slot')->{'catalog_xmin'}, '0', 'replica', 'wal_level is replica');
'restored slot catalog_xmin is nonzero'); isnt($node_master->slot('test_slot')->{'catalog_xmin'},
is($node_master->psql('postgres', qq[SELECT pg_logical_slot_get_changes('test_slot', NULL, NULL);]), 3, '0', 'restored slot catalog_xmin is nonzero');
is( $node_master->psql(
'postgres',
qq[SELECT pg_logical_slot_get_changes('test_slot', NULL, NULL);]),
3,
'reading from slot with wal_level < logical fails'); 'reading from slot with wal_level < logical fails');
is($node_master->psql('postgres', q[SELECT pg_drop_replication_slot('test_slot')]), 0, is( $node_master->psql(
'postgres', q[SELECT pg_drop_replication_slot('test_slot')]),
0,
'can drop logical slot while wal_level = replica'); 'can drop logical slot while wal_level = replica');
is($node_master->slot('test_slot')->{'catalog_xmin'}, '', 'slot was dropped'); is($node_master->slot('test_slot')->{'catalog_xmin'}, '', 'slot was dropped');
......
...@@ -176,20 +176,20 @@ standby4|1|potential), ...@@ -176,20 +176,20 @@ standby4|1|potential),
# Check that standby1 and standby2 are chosen as sync standbys # Check that standby1 and standby2 are chosen as sync standbys
# based on their priorities. # based on their priorities.
test_sync_state( test_sync_state(
$node_master, qq(standby1|1|sync $node_master, qq(standby1|1|sync
standby2|2|sync standby2|2|sync
standby4|0|async), standby4|0|async),
'priority-based sync replication specified by FIRST keyword', 'priority-based sync replication specified by FIRST keyword',
'FIRST 2(standby1, standby2)'); 'FIRST 2(standby1, standby2)');
# Check that all the listed standbys are considered as candidates # Check that all the listed standbys are considered as candidates
# for sync standbys in a quorum-based sync replication. # for sync standbys in a quorum-based sync replication.
test_sync_state( test_sync_state(
$node_master, qq(standby1|1|quorum $node_master, qq(standby1|1|quorum
standby2|1|quorum standby2|1|quorum
standby4|0|async), standby4|0|async),
'2 quorum and 1 async', '2 quorum and 1 async',
'ANY 2(standby1, standby2)'); 'ANY 2(standby1, standby2)');
# Start Standby3 which will be considered in 'quorum' state. # Start Standby3 which will be considered in 'quorum' state.
$node_standby_3->start; $node_standby_3->start;
...@@ -197,9 +197,9 @@ $node_standby_3->start; ...@@ -197,9 +197,9 @@ $node_standby_3->start;
# Check that the setting of 'ANY 2(*)' chooses all standbys as # Check that the setting of 'ANY 2(*)' chooses all standbys as
# candidates for quorum sync standbys. # candidates for quorum sync standbys.
test_sync_state( test_sync_state(
$node_master, qq(standby1|1|quorum $node_master, qq(standby1|1|quorum
standby2|1|quorum standby2|1|quorum
standby3|1|quorum standby3|1|quorum
standby4|1|quorum), standby4|1|quorum),
'all standbys are considered as candidates for quorum sync standbys', 'all standbys are considered as candidates for quorum sync standbys',
'ANY 2(*)'); 'ANY 2(*)');
...@@ -12,7 +12,8 @@ use Test::More tests => 1; ...@@ -12,7 +12,8 @@ use Test::More tests => 1;
my $node_master = get_new_node('master'); my $node_master = get_new_node('master');
$node_master->init(allows_streaming => 1); $node_master->init(allows_streaming => 1);
$node_master->append_conf('postgresql.conf', qq{ $node_master->append_conf(
'postgresql.conf', qq{
fsync = on fsync = on
wal_log_hints = on wal_log_hints = on
max_prepared_transactions = 5 max_prepared_transactions = 5
...@@ -29,7 +30,8 @@ $node_standby->init_from_backup($node_master, 'master_backup', ...@@ -29,7 +30,8 @@ $node_standby->init_from_backup($node_master, 'master_backup',
has_streaming => 1); has_streaming => 1);
$node_standby->start; $node_standby->start;
$node_master->psql('postgres', qq{ $node_master->psql(
'postgres', qq{
create table testtab (a int, b char(100)); create table testtab (a int, b char(100));
insert into testtab select generate_series(1,1000), 'foo'; insert into testtab select generate_series(1,1000), 'foo';
insert into testtab select generate_series(1,1000), 'foo'; insert into testtab select generate_series(1,1000), 'foo';
...@@ -37,7 +39,8 @@ delete from testtab where ctid > '(8,0)'; ...@@ -37,7 +39,8 @@ delete from testtab where ctid > '(8,0)';
}); });
# Take a lock on the table to prevent following vacuum from truncating it # Take a lock on the table to prevent following vacuum from truncating it
$node_master->psql('postgres', qq{ $node_master->psql(
'postgres', qq{
begin; begin;
lock table testtab in row share mode; lock table testtab in row share mode;
prepare transaction 'p1'; prepare transaction 'p1';
...@@ -51,7 +54,8 @@ $node_master->psql('postgres', 'checkpoint'); ...@@ -51,7 +54,8 @@ $node_master->psql('postgres', 'checkpoint');
# Now do some more insert/deletes, another vacuum to ensure full-page writes # Now do some more insert/deletes, another vacuum to ensure full-page writes
# are done # are done
$node_master->psql('postgres', qq{ $node_master->psql(
'postgres', qq{
insert into testtab select generate_series(1,1000), 'foo'; insert into testtab select generate_series(1,1000), 'foo';
delete from testtab where ctid > '(8,0)'; delete from testtab where ctid > '(8,0)';
vacuum verbose testtab; vacuum verbose testtab;
...@@ -61,25 +65,25 @@ vacuum verbose testtab; ...@@ -61,25 +65,25 @@ vacuum verbose testtab;
$node_standby->psql('postgres', 'checkpoint'); $node_standby->psql('postgres', 'checkpoint');
# Release the lock, vacuum again which should lead to truncation # Release the lock, vacuum again which should lead to truncation
$node_master->psql('postgres', qq{ $node_master->psql(
'postgres', qq{
rollback prepared 'p1'; rollback prepared 'p1';
vacuum verbose testtab; vacuum verbose testtab;
}); });
$node_master->psql('postgres', 'checkpoint'); $node_master->psql('postgres', 'checkpoint');
my $until_lsn = my $until_lsn =
$node_master->safe_psql('postgres', "SELECT pg_current_wal_lsn();"); $node_master->safe_psql('postgres', "SELECT pg_current_wal_lsn();");
# Wait long enough for standby to receive and apply all WAL # Wait long enough for standby to receive and apply all WAL
my $caughtup_query = my $caughtup_query =
"SELECT '$until_lsn'::pg_lsn <= pg_last_wal_replay_lsn()"; "SELECT '$until_lsn'::pg_lsn <= pg_last_wal_replay_lsn()";
$node_standby->poll_query_until('postgres', $caughtup_query) $node_standby->poll_query_until('postgres', $caughtup_query)
or die "Timed out while waiting for standby to catch up"; or die "Timed out while waiting for standby to catch up";
# Promote the standby # Promote the standby
$node_standby->promote; $node_standby->promote;
$node_standby->poll_query_until('postgres', $node_standby->poll_query_until('postgres', "SELECT NOT pg_is_in_recovery()")
"SELECT NOT pg_is_in_recovery()")
or die "Timed out while waiting for promotion of standby"; or die "Timed out while waiting for promotion of standby";
$node_standby->psql('postgres', 'checkpoint'); $node_standby->psql('postgres', 'checkpoint');
...@@ -87,6 +91,8 @@ $node_standby->psql('postgres', 'checkpoint'); ...@@ -87,6 +91,8 @@ $node_standby->psql('postgres', 'checkpoint');
$node_standby->restart; $node_standby->restart;
# Insert should work on standby # Insert should work on standby
is($node_standby->psql('postgres', is( $node_standby->psql(
qq{insert into testtab select generate_series(1,1000), 'foo';}), 'postgres',
0, 'INSERT succeeds with truncated relation FSM'); qq{insert into testtab select generate_series(1,1000), 'foo';}),
0,
'INSERT succeeds with truncated relation FSM');
...@@ -9,7 +9,8 @@ use Test::More tests => 12; ...@@ -9,7 +9,8 @@ use Test::More tests => 12;
# Setup master node # Setup master node
my $node_master = get_new_node("master"); my $node_master = get_new_node("master");
$node_master->init(allows_streaming => 1); $node_master->init(allows_streaming => 1);
$node_master->append_conf('postgresql.conf', qq( $node_master->append_conf(
'postgresql.conf', qq(
max_prepared_transactions = 10 max_prepared_transactions = 10
log_checkpoints = true log_checkpoints = true
)); ));
...@@ -19,17 +20,19 @@ $node_master->psql('postgres', "CREATE TABLE t_009_tbl (id int)"); ...@@ -19,17 +20,19 @@ $node_master->psql('postgres', "CREATE TABLE t_009_tbl (id int)");
# Setup slave node # Setup slave node
my $node_slave = get_new_node('slave'); my $node_slave = get_new_node('slave');
$node_slave->init_from_backup($node_master, 'master_backup', has_streaming => 1); $node_slave->init_from_backup($node_master, 'master_backup',
has_streaming => 1);
$node_slave->start; $node_slave->start;
# Switch to synchronous replication # Switch to synchronous replication
$node_master->append_conf('postgresql.conf', qq( $node_master->append_conf(
'postgresql.conf', qq(
synchronous_standby_names = '*' synchronous_standby_names = '*'
)); ));
$node_master->psql('postgres', "SELECT pg_reload_conf()"); $node_master->psql('postgres', "SELECT pg_reload_conf()");
my $psql_out = ''; my $psql_out = '';
my $psql_rc = ''; my $psql_rc = '';
############################################################################### ###############################################################################
# Check that we can commit and abort transaction after soft restart. # Check that we can commit and abort transaction after soft restart.
...@@ -38,7 +41,8 @@ my $psql_rc = ''; ...@@ -38,7 +41,8 @@ my $psql_rc = '';
# files. # files.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
INSERT INTO t_009_tbl VALUES (42); INSERT INTO t_009_tbl VALUES (42);
SAVEPOINT s1; SAVEPOINT s1;
...@@ -64,7 +68,8 @@ is($psql_rc, '0', 'Rollback prepared transaction after restart'); ...@@ -64,7 +68,8 @@ is($psql_rc, '0', 'Rollback prepared transaction after restart');
# transaction using dedicated WAL records. # transaction using dedicated WAL records.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
CHECKPOINT; CHECKPOINT;
BEGIN; BEGIN;
INSERT INTO t_009_tbl VALUES (42); INSERT INTO t_009_tbl VALUES (42);
...@@ -89,7 +94,8 @@ is($psql_rc, '0', 'Rollback prepared transaction after teardown'); ...@@ -89,7 +94,8 @@ is($psql_rc, '0', 'Rollback prepared transaction after teardown');
# Check that WAL replay can handle several transactions with same GID name. # Check that WAL replay can handle several transactions with same GID name.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
CHECKPOINT; CHECKPOINT;
BEGIN; BEGIN;
INSERT INTO t_009_tbl VALUES (42); INSERT INTO t_009_tbl VALUES (42);
...@@ -113,7 +119,8 @@ is($psql_rc, '0', 'Replay several transactions with same GID'); ...@@ -113,7 +119,8 @@ is($psql_rc, '0', 'Replay several transactions with same GID');
# while replaying transaction commits. # while replaying transaction commits.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
INSERT INTO t_009_tbl VALUES (42); INSERT INTO t_009_tbl VALUES (42);
SAVEPOINT s1; SAVEPOINT s1;
...@@ -122,7 +129,8 @@ $node_master->psql('postgres', " ...@@ -122,7 +129,8 @@ $node_master->psql('postgres', "
COMMIT PREPARED 'xact_009_1';"); COMMIT PREPARED 'xact_009_1';");
$node_master->teardown_node; $node_master->teardown_node;
$node_master->start; $node_master->start;
$psql_rc = $node_master->psql('postgres', " $psql_rc = $node_master->psql(
'postgres', "
BEGIN; BEGIN;
INSERT INTO t_009_tbl VALUES (42); INSERT INTO t_009_tbl VALUES (42);
SAVEPOINT s1; SAVEPOINT s1;
...@@ -138,24 +146,28 @@ $node_master->psql('postgres', "COMMIT PREPARED 'xact_009_1'"); ...@@ -138,24 +146,28 @@ $node_master->psql('postgres', "COMMIT PREPARED 'xact_009_1'");
# Check that WAL replay will cleanup its shared memory state on running slave. # Check that WAL replay will cleanup its shared memory state on running slave.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
INSERT INTO t_009_tbl VALUES (42); INSERT INTO t_009_tbl VALUES (42);
SAVEPOINT s1; SAVEPOINT s1;
INSERT INTO t_009_tbl VALUES (43); INSERT INTO t_009_tbl VALUES (43);
PREPARE TRANSACTION 'xact_009_1'; PREPARE TRANSACTION 'xact_009_1';
COMMIT PREPARED 'xact_009_1';"); COMMIT PREPARED 'xact_009_1';");
$node_slave->psql('postgres', "SELECT count(*) FROM pg_prepared_xacts", $node_slave->psql(
stdout => \$psql_out); 'postgres',
"SELECT count(*) FROM pg_prepared_xacts",
stdout => \$psql_out);
is($psql_out, '0', is($psql_out, '0',
"Cleanup of shared memory state on running standby without checkpoint"); "Cleanup of shared memory state on running standby without checkpoint");
############################################################################### ###############################################################################
# Same as in previous case, but let's force checkpoint on slave between # Same as in previous case, but let's force checkpoint on slave between
# prepare and commit to use on-disk twophase files. # prepare and commit to use on-disk twophase files.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
INSERT INTO t_009_tbl VALUES (42); INSERT INTO t_009_tbl VALUES (42);
SAVEPOINT s1; SAVEPOINT s1;
...@@ -163,16 +175,19 @@ $node_master->psql('postgres', " ...@@ -163,16 +175,19 @@ $node_master->psql('postgres', "
PREPARE TRANSACTION 'xact_009_1';"); PREPARE TRANSACTION 'xact_009_1';");
$node_slave->psql('postgres', "CHECKPOINT"); $node_slave->psql('postgres', "CHECKPOINT");
$node_master->psql('postgres', "COMMIT PREPARED 'xact_009_1'"); $node_master->psql('postgres', "COMMIT PREPARED 'xact_009_1'");
$node_slave->psql('postgres', "SELECT count(*) FROM pg_prepared_xacts", $node_slave->psql(
stdout => \$psql_out); 'postgres',
"SELECT count(*) FROM pg_prepared_xacts",
stdout => \$psql_out);
is($psql_out, '0', is($psql_out, '0',
"Cleanup of shared memory state on running standby after checkpoint"); "Cleanup of shared memory state on running standby after checkpoint");
############################################################################### ###############################################################################
# Check that prepared transactions can be committed on promoted slave. # Check that prepared transactions can be committed on promoted slave.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
INSERT INTO t_009_tbl VALUES (42); INSERT INTO t_009_tbl VALUES (42);
SAVEPOINT s1; SAVEPOINT s1;
...@@ -180,8 +195,7 @@ $node_master->psql('postgres', " ...@@ -180,8 +195,7 @@ $node_master->psql('postgres', "
PREPARE TRANSACTION 'xact_009_1';"); PREPARE TRANSACTION 'xact_009_1';");
$node_master->teardown_node; $node_master->teardown_node;
$node_slave->promote; $node_slave->promote;
$node_slave->poll_query_until('postgres', $node_slave->poll_query_until('postgres', "SELECT NOT pg_is_in_recovery()")
"SELECT NOT pg_is_in_recovery()")
or die "Timed out while waiting for promotion of standby"; or die "Timed out while waiting for promotion of standby";
$psql_rc = $node_slave->psql('postgres', "COMMIT PREPARED 'xact_009_1'"); $psql_rc = $node_slave->psql('postgres', "COMMIT PREPARED 'xact_009_1'");
...@@ -190,7 +204,8 @@ is($psql_rc, '0', "Restore of prepared transaction on promoted slave"); ...@@ -190,7 +204,8 @@ is($psql_rc, '0', "Restore of prepared transaction on promoted slave");
# change roles # change roles
($node_master, $node_slave) = ($node_slave, $node_master); ($node_master, $node_slave) = ($node_slave, $node_master);
$node_slave->enable_streaming($node_master); $node_slave->enable_streaming($node_master);
$node_slave->append_conf('recovery.conf', qq( $node_slave->append_conf(
'recovery.conf', qq(
recovery_target_timeline='latest' recovery_target_timeline='latest'
)); ));
$node_slave->start; $node_slave->start;
...@@ -202,7 +217,8 @@ $node_slave->start; ...@@ -202,7 +217,8 @@ $node_slave->start;
# consistent. # consistent.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
INSERT INTO t_009_tbl VALUES (42); INSERT INTO t_009_tbl VALUES (42);
SAVEPOINT s1; SAVEPOINT s1;
...@@ -211,19 +227,21 @@ $node_master->psql('postgres', " ...@@ -211,19 +227,21 @@ $node_master->psql('postgres', "
$node_master->stop; $node_master->stop;
$node_slave->restart; $node_slave->restart;
$node_slave->promote; $node_slave->promote;
$node_slave->poll_query_until('postgres', $node_slave->poll_query_until('postgres', "SELECT NOT pg_is_in_recovery()")
"SELECT NOT pg_is_in_recovery()")
or die "Timed out while waiting for promotion of standby"; or die "Timed out while waiting for promotion of standby";
$node_slave->psql('postgres', "SELECT count(*) FROM pg_prepared_xacts", $node_slave->psql(
stdout => \$psql_out); 'postgres',
"SELECT count(*) FROM pg_prepared_xacts",
stdout => \$psql_out);
is($psql_out, '1', is($psql_out, '1',
"Restore prepared transactions from files with master down"); "Restore prepared transactions from files with master down");
# restore state # restore state
($node_master, $node_slave) = ($node_slave, $node_master); ($node_master, $node_slave) = ($node_slave, $node_master);
$node_slave->enable_streaming($node_master); $node_slave->enable_streaming($node_master);
$node_slave->append_conf('recovery.conf', qq( $node_slave->append_conf(
'recovery.conf', qq(
recovery_target_timeline='latest' recovery_target_timeline='latest'
)); ));
$node_slave->start; $node_slave->start;
...@@ -234,7 +252,8 @@ $node_master->psql('postgres', "COMMIT PREPARED 'xact_009_1'"); ...@@ -234,7 +252,8 @@ $node_master->psql('postgres', "COMMIT PREPARED 'xact_009_1'");
# restart while master is down. # restart while master is down.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
INSERT INTO t_009_tbl VALUES (242); INSERT INTO t_009_tbl VALUES (242);
SAVEPOINT s1; SAVEPOINT s1;
...@@ -245,19 +264,21 @@ $node_master->stop; ...@@ -245,19 +264,21 @@ $node_master->stop;
$node_slave->teardown_node; $node_slave->teardown_node;
$node_slave->start; $node_slave->start;
$node_slave->promote; $node_slave->promote;
$node_slave->poll_query_until('postgres', $node_slave->poll_query_until('postgres', "SELECT NOT pg_is_in_recovery()")
"SELECT NOT pg_is_in_recovery()")
or die "Timed out while waiting for promotion of standby"; or die "Timed out while waiting for promotion of standby";
$node_slave->psql('postgres', "SELECT count(*) FROM pg_prepared_xacts", $node_slave->psql(
stdout => \$psql_out); 'postgres',
"SELECT count(*) FROM pg_prepared_xacts",
stdout => \$psql_out);
is($psql_out, '1', is($psql_out, '1',
"Restore prepared transactions from records with master down"); "Restore prepared transactions from records with master down");
# restore state # restore state
($node_master, $node_slave) = ($node_slave, $node_master); ($node_master, $node_slave) = ($node_slave, $node_master);
$node_slave->enable_streaming($node_master); $node_slave->enable_streaming($node_master);
$node_slave->append_conf('recovery.conf', qq( $node_slave->append_conf(
'recovery.conf', qq(
recovery_target_timeline='latest' recovery_target_timeline='latest'
)); ));
$node_slave->start; $node_slave->start;
...@@ -269,7 +290,8 @@ $node_master->psql('postgres', "COMMIT PREPARED 'xact_009_1'"); ...@@ -269,7 +290,8 @@ $node_master->psql('postgres', "COMMIT PREPARED 'xact_009_1'");
# XLOG_STANDBY_LOCK wal record. # XLOG_STANDBY_LOCK wal record.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
CREATE TABLE t_009_tbl2 (id int); CREATE TABLE t_009_tbl2 (id int);
SAVEPOINT s1; SAVEPOINT s1;
...@@ -280,6 +302,8 @@ $node_master->psql('postgres', " ...@@ -280,6 +302,8 @@ $node_master->psql('postgres', "
CHECKPOINT; CHECKPOINT;
COMMIT PREPARED 'xact_009_1';"); COMMIT PREPARED 'xact_009_1';");
$node_slave->psql('postgres', "SELECT count(*) FROM pg_prepared_xacts", $node_slave->psql(
stdout => \$psql_out); 'postgres',
"SELECT count(*) FROM pg_prepared_xacts",
stdout => \$psql_out);
is($psql_out, '0', "Replay prepared transaction with DDL"); is($psql_out, '0', "Replay prepared transaction with DDL");
...@@ -34,7 +34,8 @@ my ($stdout, $stderr, $ret); ...@@ -34,7 +34,8 @@ my ($stdout, $stderr, $ret);
# Initialize master node # Initialize master node
my $node_master = get_new_node('master'); my $node_master = get_new_node('master');
$node_master->init(allows_streaming => 1, has_archiving => 1); $node_master->init(allows_streaming => 1, has_archiving => 1);
$node_master->append_conf('postgresql.conf', q[ $node_master->append_conf(
'postgresql.conf', q[
wal_level = 'logical' wal_level = 'logical'
max_replication_slots = 3 max_replication_slots = 3
max_wal_senders = 2 max_wal_senders = 2
...@@ -60,8 +61,7 @@ $node_master->safe_psql('postgres', ...@@ -60,8 +61,7 @@ $node_master->safe_psql('postgres',
# the same physical copy trick, so: # the same physical copy trick, so:
$node_master->safe_psql('postgres', 'CREATE DATABASE dropme;'); $node_master->safe_psql('postgres', 'CREATE DATABASE dropme;');
$node_master->safe_psql('dropme', $node_master->safe_psql('dropme',
"SELECT pg_create_logical_replication_slot('dropme_slot', 'test_decoding');" "SELECT pg_create_logical_replication_slot('dropme_slot', 'test_decoding');");
);
$node_master->safe_psql('postgres', 'CHECKPOINT;'); $node_master->safe_psql('postgres', 'CHECKPOINT;');
...@@ -76,20 +76,23 @@ $node_replica->init_from_backup( ...@@ -76,20 +76,23 @@ $node_replica->init_from_backup(
$node_master, $backup_name, $node_master, $backup_name,
has_streaming => 1, has_streaming => 1,
has_restoring => 1); has_restoring => 1);
$node_replica->append_conf( $node_replica->append_conf('recovery.conf',
'recovery.conf', q[primary_slot_name = 'phys_slot']); q[primary_slot_name = 'phys_slot']);
$node_replica->start; $node_replica->start;
# If we drop 'dropme' on the master, the standby should drop the # If we drop 'dropme' on the master, the standby should drop the
# db and associated slot. # db and associated slot.
is($node_master->psql('postgres', 'DROP DATABASE dropme'), 0, is($node_master->psql('postgres', 'DROP DATABASE dropme'),
'dropped DB with logical slot OK on master'); 0, 'dropped DB with logical slot OK on master');
$node_master->wait_for_catchup($node_replica, 'replay', $node_master->lsn('insert')); $node_master->wait_for_catchup($node_replica, 'replay',
is($node_replica->safe_psql('postgres', q[SELECT 1 FROM pg_database WHERE datname = 'dropme']), '', $node_master->lsn('insert'));
is( $node_replica->safe_psql(
'postgres', q[SELECT 1 FROM pg_database WHERE datname = 'dropme']),
'',
'dropped DB dropme on standby'); 'dropped DB dropme on standby');
is($node_master->slot('dropme_slot')->{'slot_name'}, undef, is($node_master->slot('dropme_slot')->{'slot_name'},
'logical slot was actually dropped on standby'); undef, 'logical slot was actually dropped on standby');
# Back to testing failover... # Back to testing failover...
$node_master->safe_psql('postgres', $node_master->safe_psql('postgres',
...@@ -109,19 +112,22 @@ is($stdout, 'before_basebackup', ...@@ -109,19 +112,22 @@ is($stdout, 'before_basebackup',
# from the master to make sure its hot_standby_feedback # from the master to make sure its hot_standby_feedback
# has locked in a catalog_xmin on the physical slot, and that # has locked in a catalog_xmin on the physical slot, and that
# any xmin is < the catalog_xmin # any xmin is < the catalog_xmin
$node_master->poll_query_until('postgres', q[ $node_master->poll_query_until(
'postgres', q[
SELECT catalog_xmin IS NOT NULL SELECT catalog_xmin IS NOT NULL
FROM pg_replication_slots FROM pg_replication_slots
WHERE slot_name = 'phys_slot' WHERE slot_name = 'phys_slot'
]); ]);
my $phys_slot = $node_master->slot('phys_slot'); my $phys_slot = $node_master->slot('phys_slot');
isnt($phys_slot->{'xmin'}, '', isnt($phys_slot->{'xmin'}, '', 'xmin assigned on physical slot of master');
'xmin assigned on physical slot of master'); isnt($phys_slot->{'catalog_xmin'},
isnt($phys_slot->{'catalog_xmin'}, '', '', 'catalog_xmin assigned on physical slot of master');
'catalog_xmin assigned on physical slot of master');
# Ignore wrap-around here, we're on a new cluster: # Ignore wrap-around here, we're on a new cluster:
cmp_ok($phys_slot->{'xmin'}, '>=', $phys_slot->{'catalog_xmin'}, cmp_ok(
'xmin on physical slot must not be lower than catalog_xmin'); $phys_slot->{'xmin'}, '>=',
$phys_slot->{'catalog_xmin'},
'xmin on physical slot must not be lower than catalog_xmin');
$node_master->safe_psql('postgres', 'CHECKPOINT'); $node_master->safe_psql('postgres', 'CHECKPOINT');
...@@ -162,23 +168,30 @@ COMMIT ...@@ -162,23 +168,30 @@ COMMIT
BEGIN BEGIN
table public.decoding: INSERT: blah[text]:'after failover' table public.decoding: INSERT: blah[text]:'after failover'
COMMIT); COMMIT);
is($stdout, $final_expected_output_bb, 'decoded expected data from slot before_basebackup'); is($stdout, $final_expected_output_bb,
'decoded expected data from slot before_basebackup');
is($stderr, '', 'replay from slot before_basebackup produces no stderr'); is($stderr, '', 'replay from slot before_basebackup produces no stderr');
# So far we've peeked the slots, so when we fetch the same info over # So far we've peeked the slots, so when we fetch the same info over
# pg_recvlogical we should get complete results. First, find out the commit lsn # pg_recvlogical we should get complete results. First, find out the commit lsn
# of the last transaction. There's no max(pg_lsn), so: # of the last transaction. There's no max(pg_lsn), so:
my $endpos = $node_replica->safe_psql('postgres', "SELECT lsn FROM pg_logical_slot_peek_changes('before_basebackup', NULL, NULL) ORDER BY lsn DESC LIMIT 1;"); my $endpos = $node_replica->safe_psql('postgres',
"SELECT lsn FROM pg_logical_slot_peek_changes('before_basebackup', NULL, NULL) ORDER BY lsn DESC LIMIT 1;"
);
# now use the walsender protocol to peek the slot changes and make sure we see # now use the walsender protocol to peek the slot changes and make sure we see
# the same results. # the same results.
$stdout = $node_replica->pg_recvlogical_upto('postgres', 'before_basebackup', $stdout = $node_replica->pg_recvlogical_upto(
$endpos, 30, 'include-xids' => '0', 'skip-empty-xacts' => '1'); 'postgres', 'before_basebackup',
$endpos, 30,
'include-xids' => '0',
'skip-empty-xacts' => '1');
# walsender likes to add a newline # walsender likes to add a newline
chomp($stdout); chomp($stdout);
is($stdout, $final_expected_output_bb, 'got same output from walsender via pg_recvlogical on before_basebackup'); is($stdout, $final_expected_output_bb,
'got same output from walsender via pg_recvlogical on before_basebackup');
$node_replica->teardown_node(); $node_replica->teardown_node();
...@@ -7,9 +7,10 @@ use PostgresNode; ...@@ -7,9 +7,10 @@ use PostgresNode;
use TestLib; use TestLib;
use Test::More; use Test::More;
use Config; use Config;
if ($Config{osname} eq 'MSWin32') if ($Config{osname} eq 'MSWin32')
{ {
# some Windows Perls at least don't like IPC::Run's start/kill_kill regime.
# some Windows Perls at least don't like IPC::Run's start/kill_kill regime.
plan skip_all => "Test fails on Windows perl"; plan skip_all => "Test fails on Windows perl";
} }
else else
...@@ -28,8 +29,14 @@ my ($stdin, $stdout, $stderr) = ('', '', ''); ...@@ -28,8 +29,14 @@ my ($stdin, $stdout, $stderr) = ('', '', '');
# an xact to be in-progress when we crash and we need to know # an xact to be in-progress when we crash and we need to know
# its xid. # its xid.
my $tx = IPC::Run::start( my $tx = IPC::Run::start(
['psql', '-X', '-qAt', '-v', 'ON_ERROR_STOP=1', '-f', '-', '-d', $node->connstr('postgres')], [ 'psql', '-X', '-qAt', '-v', 'ON_ERROR_STOP=1', '-f', '-', '-d',
'<', \$stdin, '>', \$stdout, '2>', \$stderr); $node->connstr('postgres') ],
'<',
\$stdin,
'>',
\$stdout,
'2>',
\$stderr);
$stdin .= q[ $stdin .= q[
BEGIN; BEGIN;
CREATE TABLE mine(x integer); CREATE TABLE mine(x integer);
...@@ -41,16 +48,19 @@ $tx->pump until $stdout =~ /[[:digit:]]+[\r\n]$/; ...@@ -41,16 +48,19 @@ $tx->pump until $stdout =~ /[[:digit:]]+[\r\n]$/;
my $xid = $stdout; my $xid = $stdout;
chomp($xid); chomp($xid);
is($node->safe_psql('postgres', qq[SELECT txid_status('$xid');]), 'in progress', 'own xid is in-progres'); is($node->safe_psql('postgres', qq[SELECT txid_status('$xid');]),
'in progress', 'own xid is in-progres');
# Crash and restart the postmaster # Crash and restart the postmaster
$node->stop('immediate'); $node->stop('immediate');
$node->start; $node->start;
# Make sure we really got a new xid # Make sure we really got a new xid
cmp_ok($node->safe_psql('postgres', 'SELECT txid_current()'), '>', $xid, cmp_ok($node->safe_psql('postgres', 'SELECT txid_current()'),
'new xid after restart is greater'); '>', $xid, 'new xid after restart is greater');
# and make sure we show the in-progress xact as aborted # and make sure we show the in-progress xact as aborted
is($node->safe_psql('postgres', qq[SELECT txid_status('$xid');]), 'aborted', 'xid is aborted after crash'); is($node->safe_psql('postgres', qq[SELECT txid_status('$xid');]),
'aborted', 'xid is aborted after crash');
$tx->kill_kill; $tx->kill_kill;
...@@ -9,7 +9,8 @@ use Test::More tests => 12; ...@@ -9,7 +9,8 @@ use Test::More tests => 12;
# Setup master node # Setup master node
my $node_master = get_new_node("master"); my $node_master = get_new_node("master");
$node_master->init(allows_streaming => 1); $node_master->init(allows_streaming => 1);
$node_master->append_conf('postgresql.conf', qq( $node_master->append_conf(
'postgresql.conf', qq(
max_prepared_transactions = 10 max_prepared_transactions = 10
log_checkpoints = true log_checkpoints = true
)); ));
...@@ -19,24 +20,27 @@ $node_master->psql('postgres', "CREATE TABLE t_012_tbl (id int)"); ...@@ -19,24 +20,27 @@ $node_master->psql('postgres', "CREATE TABLE t_012_tbl (id int)");
# Setup slave node # Setup slave node
my $node_slave = get_new_node('slave'); my $node_slave = get_new_node('slave');
$node_slave->init_from_backup($node_master, 'master_backup', has_streaming => 1); $node_slave->init_from_backup($node_master, 'master_backup',
has_streaming => 1);
$node_slave->start; $node_slave->start;
# Switch to synchronous replication # Switch to synchronous replication
$node_master->append_conf('postgresql.conf', qq( $node_master->append_conf(
'postgresql.conf', qq(
synchronous_standby_names = '*' synchronous_standby_names = '*'
)); ));
$node_master->psql('postgres', "SELECT pg_reload_conf()"); $node_master->psql('postgres', "SELECT pg_reload_conf()");
my $psql_out = ''; my $psql_out = '';
my $psql_rc = ''; my $psql_rc = '';
############################################################################### ###############################################################################
# Check that replay will correctly set SUBTRANS and properly advance nextXid # Check that replay will correctly set SUBTRANS and properly advance nextXid
# so that it won't conflict with savepoint xids. # so that it won't conflict with savepoint xids.
############################################################################### ###############################################################################
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
DELETE FROM t_012_tbl; DELETE FROM t_012_tbl;
INSERT INTO t_012_tbl VALUES (43); INSERT INTO t_012_tbl VALUES (43);
...@@ -55,7 +59,8 @@ $node_master->psql('postgres', " ...@@ -55,7 +59,8 @@ $node_master->psql('postgres', "
$node_master->stop; $node_master->stop;
$node_master->start; $node_master->start;
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
-- here we can get xid of previous savepoint if nextXid -- here we can get xid of previous savepoint if nextXid
-- wasn't properly advanced -- wasn't properly advanced
BEGIN; BEGIN;
...@@ -63,8 +68,10 @@ $node_master->psql('postgres', " ...@@ -63,8 +68,10 @@ $node_master->psql('postgres', "
ROLLBACK; ROLLBACK;
COMMIT PREPARED 'xact_012_1';"); COMMIT PREPARED 'xact_012_1';");
$node_master->psql('postgres', "SELECT count(*) FROM t_012_tbl", $node_master->psql(
stdout => \$psql_out); 'postgres',
"SELECT count(*) FROM t_012_tbl",
stdout => \$psql_out);
is($psql_out, '6', "Check nextXid handling for prepared subtransactions"); is($psql_out, '6', "Check nextXid handling for prepared subtransactions");
############################################################################### ###############################################################################
...@@ -75,7 +82,8 @@ is($psql_out, '6', "Check nextXid handling for prepared subtransactions"); ...@@ -75,7 +82,8 @@ is($psql_out, '6', "Check nextXid handling for prepared subtransactions");
$node_master->psql('postgres', "DELETE FROM t_012_tbl"); $node_master->psql('postgres', "DELETE FROM t_012_tbl");
# Function borrowed from src/test/regress/sql/hs_primary_extremes.sql # Function borrowed from src/test/regress/sql/hs_primary_extremes.sql
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
CREATE OR REPLACE FUNCTION hs_subxids (n integer) CREATE OR REPLACE FUNCTION hs_subxids (n integer)
RETURNS void RETURNS void
LANGUAGE plpgsql LANGUAGE plpgsql
...@@ -87,39 +95,48 @@ $node_master->psql('postgres', " ...@@ -87,39 +95,48 @@ $node_master->psql('postgres', "
RETURN; RETURN;
EXCEPTION WHEN raise_exception THEN NULL; END; EXCEPTION WHEN raise_exception THEN NULL; END;
\$\$;"); \$\$;");
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
SELECT hs_subxids(127); SELECT hs_subxids(127);
COMMIT;"); COMMIT;");
$node_master->wait_for_catchup($node_slave, 'replay', $node_master->lsn('insert')); $node_master->wait_for_catchup($node_slave, 'replay',
$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", $node_master->lsn('insert'));
stdout => \$psql_out); $node_slave->psql(
'postgres',
"SELECT coalesce(sum(id),-1) FROM t_012_tbl",
stdout => \$psql_out);
is($psql_out, '8128', "Visible"); is($psql_out, '8128', "Visible");
$node_master->stop; $node_master->stop;
$node_slave->promote; $node_slave->promote;
$node_slave->poll_query_until('postgres', $node_slave->poll_query_until('postgres', "SELECT NOT pg_is_in_recovery()")
"SELECT NOT pg_is_in_recovery()")
or die "Timed out while waiting for promotion of standby"; or die "Timed out while waiting for promotion of standby";
$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", $node_slave->psql(
stdout => \$psql_out); 'postgres',
"SELECT coalesce(sum(id),-1) FROM t_012_tbl",
stdout => \$psql_out);
is($psql_out, '8128', "Visible"); is($psql_out, '8128', "Visible");
# restore state # restore state
($node_master, $node_slave) = ($node_slave, $node_master); ($node_master, $node_slave) = ($node_slave, $node_master);
$node_slave->enable_streaming($node_master); $node_slave->enable_streaming($node_master);
$node_slave->append_conf('recovery.conf', qq( $node_slave->append_conf(
'recovery.conf', qq(
recovery_target_timeline='latest' recovery_target_timeline='latest'
)); ));
$node_slave->start; $node_slave->start;
$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", $node_slave->psql(
stdout => \$psql_out); 'postgres',
"SELECT coalesce(sum(id),-1) FROM t_012_tbl",
stdout => \$psql_out);
is($psql_out, '8128', "Visible"); is($psql_out, '8128', "Visible");
$node_master->psql('postgres', "DELETE FROM t_012_tbl"); $node_master->psql('postgres', "DELETE FROM t_012_tbl");
# Function borrowed from src/test/regress/sql/hs_primary_extremes.sql # Function borrowed from src/test/regress/sql/hs_primary_extremes.sql
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
CREATE OR REPLACE FUNCTION hs_subxids (n integer) CREATE OR REPLACE FUNCTION hs_subxids (n integer)
RETURNS void RETURNS void
LANGUAGE plpgsql LANGUAGE plpgsql
...@@ -131,67 +148,87 @@ $node_master->psql('postgres', " ...@@ -131,67 +148,87 @@ $node_master->psql('postgres', "
RETURN; RETURN;
EXCEPTION WHEN raise_exception THEN NULL; END; EXCEPTION WHEN raise_exception THEN NULL; END;
\$\$;"); \$\$;");
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
SELECT hs_subxids(127); SELECT hs_subxids(127);
PREPARE TRANSACTION 'xact_012_1';"); PREPARE TRANSACTION 'xact_012_1';");
$node_master->wait_for_catchup($node_slave, 'replay', $node_master->lsn('insert')); $node_master->wait_for_catchup($node_slave, 'replay',
$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", $node_master->lsn('insert'));
stdout => \$psql_out); $node_slave->psql(
'postgres',
"SELECT coalesce(sum(id),-1) FROM t_012_tbl",
stdout => \$psql_out);
is($psql_out, '-1', "Not visible"); is($psql_out, '-1', "Not visible");
$node_master->stop; $node_master->stop;
$node_slave->promote; $node_slave->promote;
$node_slave->poll_query_until('postgres', $node_slave->poll_query_until('postgres', "SELECT NOT pg_is_in_recovery()")
"SELECT NOT pg_is_in_recovery()")
or die "Timed out while waiting for promotion of standby"; or die "Timed out while waiting for promotion of standby";
$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", $node_slave->psql(
stdout => \$psql_out); 'postgres',
"SELECT coalesce(sum(id),-1) FROM t_012_tbl",
stdout => \$psql_out);
is($psql_out, '-1', "Not visible"); is($psql_out, '-1', "Not visible");
# restore state # restore state
($node_master, $node_slave) = ($node_slave, $node_master); ($node_master, $node_slave) = ($node_slave, $node_master);
$node_slave->enable_streaming($node_master); $node_slave->enable_streaming($node_master);
$node_slave->append_conf('recovery.conf', qq( $node_slave->append_conf(
'recovery.conf', qq(
recovery_target_timeline='latest' recovery_target_timeline='latest'
)); ));
$node_slave->start; $node_slave->start;
$psql_rc = $node_master->psql('postgres', "COMMIT PREPARED 'xact_012_1'"); $psql_rc = $node_master->psql('postgres', "COMMIT PREPARED 'xact_012_1'");
is($psql_rc, '0', "Restore of PGPROC_MAX_CACHED_SUBXIDS+ prepared transaction on promoted slave"); is($psql_rc, '0',
"Restore of PGPROC_MAX_CACHED_SUBXIDS+ prepared transaction on promoted slave"
$node_master->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", );
stdout => \$psql_out);
$node_master->psql(
'postgres',
"SELECT coalesce(sum(id),-1) FROM t_012_tbl",
stdout => \$psql_out);
is($psql_out, '8128', "Visible"); is($psql_out, '8128', "Visible");
$node_master->psql('postgres', "DELETE FROM t_012_tbl"); $node_master->psql('postgres', "DELETE FROM t_012_tbl");
$node_master->psql('postgres', " $node_master->psql(
'postgres', "
BEGIN; BEGIN;
SELECT hs_subxids(201); SELECT hs_subxids(201);
PREPARE TRANSACTION 'xact_012_1';"); PREPARE TRANSACTION 'xact_012_1';");
$node_master->wait_for_catchup($node_slave, 'replay', $node_master->lsn('insert')); $node_master->wait_for_catchup($node_slave, 'replay',
$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", $node_master->lsn('insert'));
stdout => \$psql_out); $node_slave->psql(
'postgres',
"SELECT coalesce(sum(id),-1) FROM t_012_tbl",
stdout => \$psql_out);
is($psql_out, '-1', "Not visible"); is($psql_out, '-1', "Not visible");
$node_master->stop; $node_master->stop;
$node_slave->promote; $node_slave->promote;
$node_slave->poll_query_until('postgres', $node_slave->poll_query_until('postgres', "SELECT NOT pg_is_in_recovery()")
"SELECT NOT pg_is_in_recovery()")
or die "Timed out while waiting for promotion of standby"; or die "Timed out while waiting for promotion of standby";
$node_slave->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", $node_slave->psql(
stdout => \$psql_out); 'postgres',
"SELECT coalesce(sum(id),-1) FROM t_012_tbl",
stdout => \$psql_out);
is($psql_out, '-1', "Not visible"); is($psql_out, '-1', "Not visible");
# restore state # restore state
($node_master, $node_slave) = ($node_slave, $node_master); ($node_master, $node_slave) = ($node_slave, $node_master);
$node_slave->enable_streaming($node_master); $node_slave->enable_streaming($node_master);
$node_slave->append_conf('recovery.conf', qq( $node_slave->append_conf(
'recovery.conf', qq(
recovery_target_timeline='latest' recovery_target_timeline='latest'
)); ));
$node_slave->start; $node_slave->start;
$psql_rc = $node_master->psql('postgres', "ROLLBACK PREPARED 'xact_012_1'"); $psql_rc = $node_master->psql('postgres', "ROLLBACK PREPARED 'xact_012_1'");
is($psql_rc, '0', "Rollback of PGPROC_MAX_CACHED_SUBXIDS+ prepared transaction on promoted slave"); is($psql_rc, '0',
"Rollback of PGPROC_MAX_CACHED_SUBXIDS+ prepared transaction on promoted slave"
$node_master->psql('postgres', "SELECT coalesce(sum(id),-1) FROM t_012_tbl", );
stdout => \$psql_out);
$node_master->psql(
'postgres',
"SELECT coalesce(sum(id),-1) FROM t_012_tbl",
stdout => \$psql_out);
is($psql_out, '-1', "Not visible"); is($psql_out, '-1', "Not visible");
...@@ -74,12 +74,12 @@ sub configure_test_server_for_ssl ...@@ -74,12 +74,12 @@ sub configure_test_server_for_ssl
open my $sslconf, '>', "$pgdata/sslconfig.conf"; open my $sslconf, '>', "$pgdata/sslconfig.conf";
close $sslconf; close $sslconf;
# Copy all server certificates and keys, and client root cert, to the data dir # Copy all server certificates and keys, and client root cert, to the data dir
copy_files("ssl/server-*.crt", $pgdata); copy_files("ssl/server-*.crt", $pgdata);
copy_files("ssl/server-*.key", $pgdata); copy_files("ssl/server-*.key", $pgdata);
chmod(0600, glob "$pgdata/server-*.key") or die $!; chmod(0600, glob "$pgdata/server-*.key") or die $!;
copy_files("ssl/root+client_ca.crt", $pgdata); copy_files("ssl/root+client_ca.crt", $pgdata);
copy_files("ssl/root_ca.crt", $pgdata); copy_files("ssl/root_ca.crt", $pgdata);
copy_files("ssl/root+client.crl", $pgdata); copy_files("ssl/root+client.crl", $pgdata);
# Stop and restart server to load new listen_addresses. # Stop and restart server to load new listen_addresses.
...@@ -95,10 +95,11 @@ sub switch_server_cert ...@@ -95,10 +95,11 @@ sub switch_server_cert
{ {
my $node = $_[0]; my $node = $_[0];
my $certfile = $_[1]; my $certfile = $_[1];
my $cafile = $_[2] || "root+client_ca"; my $cafile = $_[2] || "root+client_ca";
my $pgdata = $node->data_dir; my $pgdata = $node->data_dir;
note "reloading server with certfile \"$certfile\" and cafile \"$cafile\""; note
"reloading server with certfile \"$certfile\" and cafile \"$cafile\"";
open my $sslconf, '>', "$pgdata/sslconfig.conf"; open my $sslconf, '>', "$pgdata/sslconfig.conf";
print $sslconf "ssl=on\n"; print $sslconf "ssl=on\n";
...@@ -117,10 +118,10 @@ sub configure_hba_for_ssl ...@@ -117,10 +118,10 @@ sub configure_hba_for_ssl
my $serverhost = $_[1]; my $serverhost = $_[1];
my $pgdata = $node->data_dir; my $pgdata = $node->data_dir;
# Only accept SSL connections from localhost. Our tests don't depend on this # Only accept SSL connections from localhost. Our tests don't depend on this
# but seems best to keep it as narrow as possible for security reasons. # but seems best to keep it as narrow as possible for security reasons.
# #
# When connecting to certdb, also check the client certificate. # When connecting to certdb, also check the client certificate.
open my $hba, '>', "$pgdata/pg_hba.conf"; open my $hba, '>', "$pgdata/pg_hba.conf";
print $hba print $hba
"# TYPE DATABASE USER ADDRESS METHOD\n"; "# TYPE DATABASE USER ADDRESS METHOD\n";
......
This diff is collapsed.
...@@ -17,7 +17,7 @@ $node_subscriber->init(allows_streaming => 'logical'); ...@@ -17,7 +17,7 @@ $node_subscriber->init(allows_streaming => 'logical');
$node_subscriber->start; $node_subscriber->start;
# Create some preexisting content on publisher # Create some preexisting content on publisher
my $ddl = qq( my $ddl = qq(
CREATE EXTENSION hstore WITH SCHEMA public; CREATE EXTENSION hstore WITH SCHEMA public;
CREATE TABLE public.tst_one_array ( CREATE TABLE public.tst_one_array (
a INTEGER PRIMARY KEY, a INTEGER PRIMARY KEY,
...@@ -103,7 +103,8 @@ $node_publisher->safe_psql('postgres', ...@@ -103,7 +103,8 @@ $node_publisher->safe_psql('postgres',
my $appname = 'tap_sub'; my $appname = 'tap_sub';
$node_subscriber->safe_psql('postgres', $node_subscriber->safe_psql('postgres',
"CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub WITH (slot_name = tap_sub_slot)"); "CREATE SUBSCRIPTION tap_sub CONNECTION '$publisher_connstr application_name=$appname' PUBLICATION tap_pub WITH (slot_name = tap_sub_slot)"
);
# Wait for subscriber to finish initialization # Wait for subscriber to finish initialization
my $caughtup_query = my $caughtup_query =
...@@ -118,7 +119,8 @@ $node_subscriber->poll_query_until('postgres', $synced_query) ...@@ -118,7 +119,8 @@ $node_subscriber->poll_query_until('postgres', $synced_query)
or die "Timed out while waiting for subscriber to synchronize data"; or die "Timed out while waiting for subscriber to synchronize data";
# Insert initial test data # Insert initial test data
$node_publisher->safe_psql('postgres', qq( $node_publisher->safe_psql(
'postgres', qq(
-- test_tbl_one_array_col -- test_tbl_one_array_col
INSERT INTO tst_one_array (a, b) VALUES INSERT INTO tst_one_array (a, b) VALUES
(1, '{1, 2, 3}'), (1, '{1, 2, 3}'),
...@@ -248,7 +250,8 @@ $node_publisher->poll_query_until('postgres', $caughtup_query) ...@@ -248,7 +250,8 @@ $node_publisher->poll_query_until('postgres', $caughtup_query)
or die "Timed out while waiting for subscriber to catch up"; or die "Timed out while waiting for subscriber to catch up";
# Check the data on subscriber # Check the data on subscriber
my $result = $node_subscriber->safe_psql('postgres', qq( my $result = $node_subscriber->safe_psql(
'postgres', qq(
SET timezone = '+2'; SET timezone = '+2';
SELECT a, b FROM tst_one_array ORDER BY a; SELECT a, b FROM tst_one_array ORDER BY a;
SELECT a, b, c, d FROM tst_arrays ORDER BY a; SELECT a, b, c, d FROM tst_arrays ORDER BY a;
...@@ -266,7 +269,7 @@ my $result = $node_subscriber->safe_psql('postgres', qq( ...@@ -266,7 +269,7 @@ my $result = $node_subscriber->safe_psql('postgres', qq(
SELECT a, b FROM tst_hstore ORDER BY a; SELECT a, b FROM tst_hstore ORDER BY a;
)); ));
is($result, '1|{1,2,3} is( $result, '1|{1,2,3}
2|{2,3,1} 2|{2,3,1}
3|{3,2,1} 3|{3,2,1}
4|{4,3,2} 4|{4,3,2}
...@@ -331,10 +334,11 @@ e|{d,NULL} ...@@ -331,10 +334,11 @@ e|{d,NULL}
2|"zzz"=>"foo" 2|"zzz"=>"foo"
3|"123"=>"321" 3|"123"=>"321"
4|"yellow horse"=>"moaned"', 4|"yellow horse"=>"moaned"',
'check replicated inserts on subscriber'); 'check replicated inserts on subscriber');
# Run batch of updates # Run batch of updates
$node_publisher->safe_psql('postgres', qq( $node_publisher->safe_psql(
'postgres', qq(
UPDATE tst_one_array SET b = '{4, 5, 6}' WHERE a = 1; UPDATE tst_one_array SET b = '{4, 5, 6}' WHERE a = 1;
UPDATE tst_one_array SET b = '{4, 5, 6, 1}' WHERE a > 3; UPDATE tst_one_array SET b = '{4, 5, 6, 1}' WHERE a > 3;
UPDATE tst_arrays SET b = '{"1a", "2b", "3c"}', c = '{1.0, 2.0, 3.0}', d = '{"1 day 1 second", "2 days 2 seconds", "3 days 3 second"}' WHERE a = '{1, 2, 3}'; UPDATE tst_arrays SET b = '{"1a", "2b", "3c"}', c = '{1.0, 2.0, 3.0}', d = '{"1 day 1 second", "2 days 2 seconds", "3 days 3 second"}' WHERE a = '{1, 2, 3}';
...@@ -368,7 +372,8 @@ $node_publisher->poll_query_until('postgres', $caughtup_query) ...@@ -368,7 +372,8 @@ $node_publisher->poll_query_until('postgres', $caughtup_query)
or die "Timed out while waiting for subscriber to catch up"; or die "Timed out while waiting for subscriber to catch up";
# Check the data on subscriber # Check the data on subscriber
$result = $node_subscriber->safe_psql('postgres', qq( $result = $node_subscriber->safe_psql(
'postgres', qq(
SET timezone = '+2'; SET timezone = '+2';
SELECT a, b FROM tst_one_array ORDER BY a; SELECT a, b FROM tst_one_array ORDER BY a;
SELECT a, b, c, d FROM tst_arrays ORDER BY a; SELECT a, b, c, d FROM tst_arrays ORDER BY a;
...@@ -386,7 +391,7 @@ $result = $node_subscriber->safe_psql('postgres', qq( ...@@ -386,7 +391,7 @@ $result = $node_subscriber->safe_psql('postgres', qq(
SELECT a, b FROM tst_hstore ORDER BY a; SELECT a, b FROM tst_hstore ORDER BY a;
)); ));
is($result, '1|{4,5,6} is( $result, '1|{4,5,6}
2|{2,3,1} 2|{2,3,1}
3|{3,2,1} 3|{3,2,1}
4|{4,5,6,1} 4|{4,5,6,1}
...@@ -451,10 +456,11 @@ e|{e,d} ...@@ -451,10 +456,11 @@ e|{e,d}
2|"updated"=>"value" 2|"updated"=>"value"
3|"also"=>"updated" 3|"also"=>"updated"
4|"yellow horse"=>"moaned"', 4|"yellow horse"=>"moaned"',
'check replicated updates on subscriber'); 'check replicated updates on subscriber');
# Run batch of deletes # Run batch of deletes
$node_publisher->safe_psql('postgres', qq( $node_publisher->safe_psql(
'postgres', qq(
DELETE FROM tst_one_array WHERE a = 1; DELETE FROM tst_one_array WHERE a = 1;
DELETE FROM tst_one_array WHERE b = '{2, 3, 1}'; DELETE FROM tst_one_array WHERE b = '{2, 3, 1}';
DELETE FROM tst_arrays WHERE a = '{1, 2, 3}'; DELETE FROM tst_arrays WHERE a = '{1, 2, 3}';
...@@ -487,7 +493,8 @@ $node_publisher->poll_query_until('postgres', $caughtup_query) ...@@ -487,7 +493,8 @@ $node_publisher->poll_query_until('postgres', $caughtup_query)
or die "Timed out while waiting for subscriber to catch up"; or die "Timed out while waiting for subscriber to catch up";
# Check the data on subscriber # Check the data on subscriber
$result = $node_subscriber->safe_psql('postgres', qq( $result = $node_subscriber->safe_psql(
'postgres', qq(
SET timezone = '+2'; SET timezone = '+2';
SELECT a, b FROM tst_one_array ORDER BY a; SELECT a, b FROM tst_one_array ORDER BY a;
SELECT a, b, c, d FROM tst_arrays ORDER BY a; SELECT a, b, c, d FROM tst_arrays ORDER BY a;
...@@ -505,7 +512,7 @@ $result = $node_subscriber->safe_psql('postgres', qq( ...@@ -505,7 +512,7 @@ $result = $node_subscriber->safe_psql('postgres', qq(
SELECT a, b FROM tst_hstore ORDER BY a; SELECT a, b FROM tst_hstore ORDER BY a;
)); ));
is($result, '3|{3,2,1} is( $result, '3|{3,2,1}
4|{4,5,6,1} 4|{4,5,6,1}
5|{4,5,6,1} 5|{4,5,6,1}
{3,1,2}|{c,a,b}|{3.3,1.1,2.2}|{"3 years","1 year","2 years"} {3,1,2}|{c,a,b}|{3.3,1.1,2.2}|{"3 years","1 year","2 years"}
...@@ -539,7 +546,7 @@ e|{e,d} ...@@ -539,7 +546,7 @@ e|{e,d}
2|"updated"=>"value" 2|"updated"=>"value"
3|"also"=>"updated" 3|"also"=>"updated"
4|"yellow horse"=>"moaned"', 4|"yellow horse"=>"moaned"',
'check replicated deletes on subscriber'); 'check replicated deletes on subscriber');
$node_subscriber->stop('fast'); $node_subscriber->stop('fast');
$node_publisher->stop('fast'); $node_publisher->stop('fast');
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment