|
490 | 490 | $node_publisher->stop('fast');
|
491 | 491 | $node_subscriber->stop('fast');
|
492 | 492 |
|
| 493 | +# The bug was that when an ERROR was caught and handled by a (PL/pgSQL) |
| 494 | +# function, the apply worker reset the replication origin but continued |
| 495 | +# processing subsequent changes. So, we fail to update the replication origin |
| 496 | +# during further apply operations. This can lead to the apply worker requesting |
| 497 | +# the changes that have been applied again after restarting. |
| 498 | + |
| 499 | +$node_publisher->rotate_logfile(); |
| 500 | +$node_publisher->start(); |
| 501 | + |
| 502 | +$node_subscriber->rotate_logfile(); |
| 503 | +$node_subscriber->start(); |
| 504 | + |
| 505 | +# Set up a publication with a table |
| 506 | +$node_publisher->safe_psql( |
| 507 | + 'postgres', qq( |
| 508 | + CREATE TABLE t1 (a int); |
| 509 | + CREATE PUBLICATION regress_pub FOR TABLE t1; |
| 510 | +)); |
| 511 | + |
| 512 | +# Set up a subscription which subscribes the publication |
| 513 | +$node_subscriber->safe_psql( |
| 514 | + 'postgres', qq( |
| 515 | + CREATE TABLE t1 (a int); |
| 516 | + CREATE SUBSCRIPTION regress_sub CONNECTION '$publisher_connstr' PUBLICATION regress_pub; |
| 517 | +)); |
| 518 | + |
| 519 | +$node_subscriber->wait_for_subscription_sync($node_publisher, 'regress_sub'); |
| 520 | + |
| 521 | +# Create an AFTER INSERT trigger on the table that raises and subsequently |
| 522 | +# handles an exception. Subsequent insertions will trigger this exception, |
| 523 | +# causing the apply worker to invoke its error callback with an ERROR. However, |
| 524 | +# since the error is caught within the trigger, the apply worker will continue |
| 525 | +# processing changes. |
| 526 | +$node_subscriber->safe_psql( |
| 527 | + 'postgres', q{ |
| 528 | +CREATE FUNCTION handle_exception_trigger() |
| 529 | +RETURNS TRIGGER AS $$ |
| 530 | +BEGIN |
| 531 | + BEGIN |
| 532 | + -- Raise an exception |
| 533 | + RAISE EXCEPTION 'This is a test exception'; |
| 534 | + EXCEPTION |
| 535 | + WHEN OTHERS THEN |
| 536 | + RETURN NEW; |
| 537 | + END; |
| 538 | +
|
| 539 | + RETURN NEW; |
| 540 | +END; |
| 541 | +$$ LANGUAGE plpgsql; |
| 542 | +
|
| 543 | +CREATE TRIGGER silent_exception_trigger |
| 544 | +AFTER INSERT OR UPDATE ON t1 |
| 545 | +FOR EACH ROW |
| 546 | +EXECUTE FUNCTION handle_exception_trigger(); |
| 547 | +
|
| 548 | +ALTER TABLE t1 ENABLE ALWAYS TRIGGER silent_exception_trigger; |
| 549 | +}); |
| 550 | + |
| 551 | +# Obtain current remote_lsn value to check its advancement later |
| 552 | +my $remote_lsn = $node_subscriber->safe_psql('postgres', |
| 553 | + "SELECT remote_lsn FROM pg_replication_origin_status os, pg_subscription s WHERE os.external_id = 'pg_' || s.oid AND s.subname = 'regress_sub'" |
| 554 | +); |
| 555 | + |
| 556 | +# Insert a tuple to replicate changes |
| 557 | +$node_publisher->safe_psql('postgres', "INSERT INTO t1 VALUES (1);"); |
| 558 | +$node_publisher->wait_for_catchup('regress_sub'); |
| 559 | + |
| 560 | +# Confirms the origin can be advanced |
| 561 | +$result = $node_subscriber->safe_psql('postgres', |
| 562 | + "SELECT remote_lsn > '$remote_lsn' FROM pg_replication_origin_status os, pg_subscription s WHERE os.external_id = 'pg_' || s.oid AND s.subname = 'regress_sub'" |
| 563 | +); |
| 564 | +is($result, 't', |
| 565 | + 'remote_lsn has advanced for apply worker raising an exception'); |
| 566 | + |
| 567 | +$node_publisher->stop('fast'); |
| 568 | +$node_subscriber->stop('fast'); |
| 569 | + |
493 | 570 | done_testing();
|
0 commit comments