@@ -1121,7 +1121,6 @@ sub psql
1121
1121
my $exc_save = $@ ;
1122
1122
if ($exc_save )
1123
1123
{
1124
-
1125
1124
# IPC::Run::run threw an exception. re-throw unless it's a
1126
1125
# timeout, which we'll handle by testing is_expired
1127
1126
die $exc_save
@@ -1173,7 +1172,7 @@ sub psql
1173
1172
if $ret == 1;
1174
1173
die " connection error: '$$stderr '\n while running '@psql_params '"
1175
1174
if $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 ' "
1177
1176
if $ret == 3;
1178
1177
die " psql returns $ret : '$$stderr '\n while running '@psql_params '" ;
1179
1178
}
@@ -1325,6 +1324,175 @@ sub run_log
1325
1324
TestLib::run_log(@_ );
1326
1325
}
1327
1326
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 ) : (' ' ,) x scalar (@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
+
1328
1496
=pod
1329
1497
1330
1498
=back
0 commit comments