@@ -1121,7 +1121,6 @@ sub psql
11211121my $exc_save =$@ ;
11221122if ($exc_save )
11231123{
1124-
11251124# IPC::Run::run threw an exception. re-throw unless it's a
11261125# timeout, which we'll handle by testing is_expired
11271126die $exc_save
@@ -1173,7 +1172,7 @@ sub psql
11731172if $ret == 1;
11741173die " connection error: '$$stderr '\n while running '@psql_params '"
11751174if $ret == 2;
1176- die " error running SQL: '$$stderr '\n while running '@psql_params '"
1175+ die " error running SQL: '$$stderr '\n while running '@psql_params ' with sql ' $sql ' "
11771176if $ret == 3;
11781177die " psql returns$ret : '$$stderr '\n while running '@psql_params '" ;
11791178}
@@ -1325,6 +1324,175 @@ sub run_log
13251324TestLib::run_log(@_ );
13261325}
13271326
1327+ =pod $node->lsn(mode)
1328+
1329+ Look up xlog positions on the server:
1330+
1331+ * insert position (master only, error on replica)
1332+ * write position (master only, error on replica)
1333+ * flush position
1334+ * receive position (always undef on master)
1335+ * replay position
1336+
1337+ mode must be specified.
1338+
1339+ =cut
1340+
1341+ sub lsn
1342+ {
1343+ my ($self ,$mode ) =@_ ;
1344+ my %modes = (' insert' => ' pg_current_xlog_insert_location()' ,
1345+ ' flush' => ' pg_current_xlog_flush_location()' ,
1346+ ' write' => ' pg_current_xlog_location()' ,
1347+ ' receive' => ' pg_last_xlog_receive_location()' ,
1348+ ' replay' => ' pg_last_xlog_replay_location()' );
1349+
1350+ $mode =' <undef>' if !defined ($mode );
1351+ die " unknown mode for 'lsn': '$mode ', valid modes are" .join (' ,' ,keys %modes )
1352+ if !defined ($modes {$mode });
1353+
1354+ my $result =$self -> safe_psql(' postgres' ," SELECT$modes {$mode }" );
1355+ chomp ($result );
1356+ if ($result eq ' ' )
1357+ {
1358+ return undef ;
1359+ }
1360+ else
1361+ {
1362+ return $result ;
1363+ }
1364+ }
1365+
1366+ =pod $node->wait_for_catchup(standby_name, mode, target_lsn)
1367+
1368+ Wait for the node with application_name standby_name (usually from node->name)
1369+ until its replication position in pg_stat_replication equals or passes the
1370+ upstream's xlog insert point at the time this function is called. By default
1371+ the replay_location is waited for, but 'mode' may be specified to wait for any
1372+ of sent|write|flush|replay.
1373+
1374+ If there is no active replication connection from this peer, waits until
1375+ poll_query_until timeout.
1376+
1377+ Requires that the 'postgres' db exists and is accessible.
1378+
1379+ target_lsn may be any arbitrary lsn, but is typically $master_node->lsn('insert').
1380+
1381+ This is not a test. It die()s on failure.
1382+
1383+ =cut
1384+
1385+ sub wait_for_catchup
1386+ {
1387+ my ($self ,$standby_name ,$mode ,$target_lsn ) =@_ ;
1388+ $mode =defined ($mode ) ?$mode :' replay' ;
1389+ my %valid_modes = (' sent' => 1,' write' => 1,' flush' => 1,' replay' => 1 );
1390+ die " unknown mode$mode for 'wait_for_catchup', valid modes are" .join (' ,' ,keys (%valid_modes ))unless exists ($valid_modes {$mode });
1391+ # Allow passing of a PostgresNode instance as shorthand
1392+ if ( blessed($standby_name ) &&$standby_name -> isa(" PostgresNode" ) )
1393+ {
1394+ $standby_name =$standby_name -> name;
1395+ }
1396+ die ' target_lsn must be specified' unless defined ($target_lsn );
1397+ print " Waiting for replication conn" .$standby_name ." 's" .$mode ." _location to pass" .$target_lsn ." on" .$self -> name ." \n " ;
1398+ my $query =qq[ SELECT '$target_lsn ' <=${mode} _location FROM pg_catalog.pg_stat_replication WHERE application_name = '$standby_name ';] ;
1399+ $self -> poll_query_until(' postgres' ,$query )
1400+ or die " timed out waiting for catchup, current position is" . ($self -> safe_psql(' postgres' ,$query ) ||' (unknown)' );
1401+ print " done\n " ;
1402+ }
1403+
1404+ =pod $node->wait_for_slot_catchup(slot_name, mode, target_lsn)
1405+
1406+ Wait for the named replication slot to equal or pass the supplied target_lsn.
1407+ The position used is the restart_lsn unless mode is given, in which case it may
1408+ be 'restart' or 'confirmed_flush'.
1409+
1410+ Requires that the 'postgres' db exists and is accessible.
1411+
1412+ This is not a test. It die()s on failure.
1413+
1414+ If the slot is not active, will time out after poll_query_until's timeout.
1415+
1416+ target_lsn may be any arbitrary lsn, but is typically $master_node->lsn('insert').
1417+
1418+ Note that for logical slots, restart_lsn is held down by the oldest in-progress tx.
1419+
1420+ =cut
1421+
1422+ sub wait_for_slot_catchup
1423+ {
1424+ my ($self ,$slot_name ,$mode ,$target_lsn ) =@_ ;
1425+ $mode =defined ($mode ) ?$mode :' restart' ;
1426+ if (!($mode eq ' restart' ||$mode eq ' confirmed_flush' ))
1427+ {
1428+ die " valid modes are restart, confirmed_flush" ;
1429+ }
1430+ die ' target lsn must be specified' unless defined ($target_lsn );
1431+ print " Waiting for replication slot" .$slot_name ." 's" .$mode ." _lsn to pass" .$target_lsn ." on" .$self -> name ." \n " ;
1432+ my $query =qq[ SELECT '$target_lsn ' <=${mode} _lsn FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name ';] ;
1433+ $self -> poll_query_until(' postgres' ,$query )
1434+ or die " timed out waiting for catchup, current position is" . ($self -> safe_psql(' postgres' ,$query ) ||' (unknown)' );
1435+ print " done\n " ;
1436+ }
1437+
1438+ =pod $node->query_hash($dbname, $query, @columns)
1439+
1440+ Execute $query on $dbname, replacing any appearance of the string __COLUMNS__
1441+ within the query with a comma-separated list of @columns.
1442+
1443+ If __COLUMNS__ does not appear in the query, its result columns must EXACTLY
1444+ match the order and number (but not necessarily alias) of supplied @columns.
1445+
1446+ The query must return zero or one rows.
1447+
1448+ Return a hash-ref representation of the results of the query, with any empty
1449+ or null results as defined keys with an empty-string value. There is no way
1450+ to differentiate between null and empty-string result fields.
1451+
1452+ If the query returns zero rows, return a hash with all columns empty. There
1453+ is no way to differentiate between zero rows returned and a row with only
1454+ null columns.
1455+
1456+ =cut
1457+
1458+ sub query_hash
1459+ {
1460+ my ($self ,$dbname ,$query ,@columns ) =@_ ;
1461+ die ' calls in array context for multi-row results not supported yet' if (wantarray );
1462+ # Replace __COLUMNS__ if found
1463+ substr ($query ,index ($query ,' __COLUMNS__' ),length (' __COLUMNS__' )) =join (' ,' ,@columns )
1464+ if index ($query ,' __COLUMNS__' ) >= 0;
1465+ my $result =$self -> safe_psql($dbname ,$query );
1466+ # hash slice, see http://stackoverflow.com/a/16755894/398670 .
1467+ #
1468+ # Fills the hash with empty strings produced by x-operator element
1469+ # duplication if result is an empty row
1470+ #
1471+ my %val ;
1472+ @val {@columns } =$result ne ' ' ?split (qr /\| / ,$result ) : (' ' ,) xscalar (@columns );
1473+ return \%val ;
1474+ }
1475+
1476+ =pod $node->slot(slot_name)
1477+
1478+ Return hash-ref of replication slot data for the named slot, or a hash-ref with
1479+ all values '' if not found. Does not differentiate between null and empty string
1480+ for fields, no field is ever undef.
1481+
1482+ The restart_lsn and confirmed_flush_lsn fields are returned verbatim, and also
1483+ as a 2-list of [highword, lowword] integer. Since we rely on Perl 5.8.8 we can't
1484+ "use bigint", it's from 5.20, and we can't assume we have Math::Bigint from CPAN
1485+ either.
1486+
1487+ =cut
1488+
1489+ sub slot
1490+ {
1491+ my ($self ,$slot_name ) =@_ ;
1492+ my @columns = (' plugin' ,' slot_type' ,' datoid' ,' database' ,' active' ,' active_pid' ,' xmin' ,' catalog_xmin' ,' restart_lsn' );
1493+ return $self -> query_hash(' postgres' ," SELECT __COLUMNS__ FROM pg_catalog.pg_replication_slots WHERE slot_name = '$slot_name '" ,@columns );
1494+ }
1495+
13281496=pod
13291497
13301498=back