fix_assertion_error.patch
application/octet-stream
Filename: fix_assertion_error.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/catalog/pg_proc.c | 9 | 6 |
| src/test/subscription/t/100_bugs.pl | 58 | 0 |
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index a9fe45e347..c98f150fe6 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -1016,7 +1016,7 @@ bool
function_parse_error_transpose(const char *prosrc)
{
int origerrposition;
- int newerrposition;
+ int newerrposition = 0;
const char *queryText;
/*
@@ -1034,12 +1034,15 @@ function_parse_error_transpose(const char *prosrc)
return false;
}
- /* We can get the original query text from the active portal (hack...) */
- Assert(ActivePortal && ActivePortal->status == PORTAL_ACTIVE);
- queryText = ActivePortal->sourceText;
+ if (ActivePortal)
+ {
+ /* We can get the original query text from the active portal (hack...) */
+ Assert(ActivePortal->status == PORTAL_ACTIVE);
+ queryText = ActivePortal->sourceText;
- /* Try to locate the prosrc in the original text */
- newerrposition = match_prosrc_to_query(prosrc, queryText, origerrposition);
+ /* Try to locate the prosrc in the original text */
+ newerrposition = match_prosrc_to_query(prosrc, queryText, origerrposition);
+ }
if (newerrposition > 0)
{
diff --git a/src/test/subscription/t/100_bugs.pl b/src/test/subscription/t/100_bugs.pl
index 6247aa7730..30b38f300e 100644
--- a/src/test/subscription/t/100_bugs.pl
+++ b/src/test/subscription/t/100_bugs.pl
@@ -299,4 +299,62 @@ is( $node_subscriber->safe_psql(
$node_publisher->stop('fast');
$node_subscriber->stop('fast');
+# The bug was that we assumed that there is always an active Portal when
+# handling an error occurring inside the function body of a CREATE FUNCTION.
+# Since the logical replication workers (both apply workers and tablesync
+# workers) do not have an active Portal, it crashes.
+$node_publisher = PostgreSQL::Test::Cluster->new('publisher4');
+$node_publisher->init(allows_streaming => 'logical');
+$node_publisher->start;
+
+$node_subscriber = PostgreSQL::Test::Cluster->new('subscriber4');
+$node_subscriber->init(allows_streaming => 'logical');
+$node_subscriber->start;
+
+$node_publisher->safe_psql(
+ 'postgres', qq{
+ CREATE TABLE test_tab(a int);
+ CREATE PUBLICATION test_pub FOR TABLE test_tab;
+ });
+
+$node_subscriber->safe_psql('postgres', "CREATE TABLE test_tab(a int)");
+
+# Create the trigger function on the table that raises an error while
+# executing the CREATE FUNCTION.
+$node_subscriber->safe_psql(
+ 'postgres', qq{
+CREATE FUNCTION test_trig_func() RETURNS trigger AS
+\$\$
+BEGIN
+ EXECUTE E'CREATE FUNCTION public.errfunc() RETURNS void AS
+ \$body\$
+ SELECT FROM nonexist_table;
+ \$body\$ LANGUAGE sql';
+ RETURN new;
+END;
+\$\$ LANGUAGE plpgsql;
+CREATE TRIGGER test_trig AFTER INSERT ON test_tab FOR EACH ROW EXECUTE PROCEDURE test_trig_func();
+ALTER TABLE test_tab ENABLE REPLICA TRIGGER test_trig;
+ });
+
+# Create the subscription with disable_on_error so that the logical replication
+# stops after the error.
+$publisher_connstr = $node_publisher->connstr . ' dbname=postgres';
+$node_subscriber->safe_psql(
+ 'postgres',
+ "CREATE SUBSCRIPTION test_sub CONNECTION '$publisher_connstr' PUBLICATION test_pub WITH (disable_on_error = 'true')");
+
+# Wait for initial table sync to finish
+$node_subscriber->wait_for_subscription_sync($node_publisher, 'test_sub');
+
+# The insertion leads to the "relation does not exist" error on the subscriber.
+$node_publisher->safe_psql('postgres', "INSERT INTO test_tab VALUES (1)");
+
+$node_subscriber->poll_query_until(
+ 'postgres',
+ "SELECT subenabled IS FALSE FROM pg_subscription WHERE subname = 'test_sub'");
+
+$node_publisher->stop('fast');
+$node_subscriber->stop('fast');
+
done_testing();