# Copyright (c) 2026, PostgreSQL Global Development Group

# Reproduce replication-origin session corruption when a TRUNCATE trigger
# resets an origin while ALTER SUBSCRIPTION ... REFRESH TABLE is running.
use strict;
use warnings FATAL => 'all';
use PostgreSQL::Test::Cluster;
use PostgreSQL::Test::Utils;
use Test::More;

my $publisher = PostgreSQL::Test::Cluster->new('publisher');
$publisher->init(allows_streaming => 'logical');
$publisher->start;

my $subscriber = PostgreSQL::Test::Cluster->new('subscriber');
$subscriber->init(allows_streaming => 'logical');
$subscriber->start;

my $connstr = $publisher->connstr . ' dbname=postgres';

$publisher->safe_psql(
	'postgres', qq(
CREATE TABLE tab_origin (id int primary key);
CREATE PUBLICATION pub_origin FOR TABLE tab_origin;
));

$subscriber->safe_psql(
	'postgres', qq(
CREATE TABLE tab_origin (id int primary key);
CREATE SUBSCRIPTION sub_origin CONNECTION '$connstr' PUBLICATION pub_origin WITH (enabled = false);

CREATE FUNCTION reset_origin_on_truncate() RETURNS trigger
  LANGUAGE plpgsql AS \$\$
BEGIN
  PERFORM pg_replication_origin_session_reset();
  RETURN NULL;
END
\$\$;

CREATE TRIGGER reset_origin BEFORE TRUNCATE ON tab_origin
  FOR EACH STATEMENT EXECUTE FUNCTION reset_origin_on_truncate();
));

my $log_offset = -s $subscriber->logfile;
my $ret = $subscriber->psql(
	'postgres', qq(
SELECT pg_replication_origin_create('tap_origin');
SELECT pg_replication_origin_session_setup('tap_origin');
ALTER SUBSCRIPTION sub_origin REFRESH TABLE tab_origin;
));

isnt($ret, 0, 'origin-resetting trigger terminates the backend');
$subscriber->stop('immediate', fail_ok => 1);
$subscriber->start;

my $log = slurp_file($subscriber->logfile, $log_offset);
like(
	$log,
	qr/(?:session_replication_state != NULL|terminated by signal)/,
	'server log records replication-origin assertion or process crash');

$subscriber->stop('fast');
$publisher->stop('fast');

done_testing();
