diff options
author | Tom Lane | 2022-11-03 16:01:57 +0000 |
---|---|---|
committer | Tom Lane | 2022-11-03 16:01:57 +0000 |
commit | 5f3cec77b1b5d79100b127d0555a3e3d42e464da (patch) | |
tree | ed70005ece3c95b07a41ccab53dee42db4d8386b | |
parent | 19cefebe71ea2a2dca12c01f607375637fa7ea28 (diff) |
Avoid crash after function syntax error in a replication worker.
If a syntax error occurred in a SQL-language or PL/pgSQL-language
CREATE FUNCTION or DO command executed in a logical replication worker,
we'd suffer a null pointer dereference or assertion failure. That
seems like a rather contrived case, but nonetheless worth fixing.
The cause is that function_parse_error_transpose assumes it must be
executing within the context of a Portal, but logical/worker.c
doesn't create a Portal since it's not running the standard executor.
We can just back off the hard Assert check and make it fail gracefully
if there's not an ActivePortal. (I have a feeling that the aggressive
check here was my fault originally, probably because I wasn't sure if
the case would always hold and wanted to find out. Well, now we know.)
The hazard seems to exist in all branches that have logical replication,
so back-patch to v10.
Maxim Orlov, Anton Melnikov, Masahiko Sawada, Tom Lane
Discussion: https://postgr.es/m/[email protected]
Discussion: https://postgr.es/m/[email protected]
-rw-r--r-- | src/backend/catalog/pg_proc.c | 20 |
1 files changed, 15 insertions, 5 deletions
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index afe48293287..056524d9993 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -977,7 +977,6 @@ function_parse_error_transpose(const char *prosrc) { int origerrposition; int newerrposition; - const char *queryText; /* * Nothing to do unless we are dealing with a syntax error that has a @@ -995,11 +994,22 @@ function_parse_error_transpose(const char *prosrc) } /* We can get the original query text from the active portal (hack...) */ - Assert(ActivePortal && ActivePortal->status == PORTAL_ACTIVE); - queryText = ActivePortal->sourceText; + if (ActivePortal && ActivePortal->status == PORTAL_ACTIVE) + { + const char *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); + } + else + { + /* + * Quietly give up if no ActivePortal. This is an unusual situation + * but it can happen in, e.g., logical replication workers. + */ + newerrposition = -1; + } if (newerrposition > 0) { |