aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2023-06-21 11:07:11 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2023-06-21 11:07:11 -0400
commitcb74f7bec64f3333efa4227f804f72a3c353cd08 (patch)
treefda373e3bd106a78ebd67918306375d36a46e598
parentbd78702ea17e2ff630d718071e26070eff13d750 (diff)
downloadpostgresql-cb74f7bec64f3333efa4227f804f72a3c353cd08.tar.gz
postgresql-cb74f7bec64f3333efa4227f804f72a3c353cd08.zip
Avoid Assert failure when processing empty statement in aborted xact.
exec_parse_message() wants to create a cached plan in all cases, including for empty input. The empty-input path does not have a test for being in an aborted transaction, making it possible that plancache.c will fail due to trying to do database lookups even though there's no real work to do. One solution would be to throw an aborted-transaction error in this path too, but it's not entirely clear whether the lack of such an error was intentional or whether some clients might be relying on non-error behavior. Instead, let's hack plancache.c so that it treats empty statements with the same logic it already had for transaction control commands, ensuring that it can soldier through even in an already-aborted transaction. Per bug #17983 from Alexander Lakhin. Back-patch to all supported branches. Discussion: https://postgr.es/m/17983-da4569fcb878672e@postgresql.org
-rw-r--r--src/backend/utils/cache/plancache.c4
-rw-r--r--src/test/regress/expected/psql.out11
-rw-r--r--src/test/regress/sql/psql.sql8
3 files changed, 22 insertions, 1 deletions
diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 0d6a2956748..21387fba9f1 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -78,9 +78,11 @@
/*
* We must skip "overhead" operations that involve database access when the
* cached plan's subject statement is a transaction control command.
+ * For the convenience of postgres.c, treat empty statements as control
+ * commands too.
*/
#define IsTransactionStmtPlan(plansource) \
- ((plansource)->raw_parse_tree && \
+ ((plansource)->raw_parse_tree == NULL || \
IsA((plansource)->raw_parse_tree->stmt, TransactionStmt))
/*
diff --git a/src/test/regress/expected/psql.out b/src/test/regress/expected/psql.out
index 9855abf2db7..29c6b2dae3b 100644
--- a/src/test/regress/expected/psql.out
+++ b/src/test/regress/expected/psql.out
@@ -237,6 +237,17 @@ SELECT 3 AS x, 'Hello', 4 AS y, true AS "dirty\name" \gdesc \g
3 | Hello | 4 | t
(1 row)
+-- test for server bug #17983 with empty statement in aborted transaction
+set search_path = default;
+begin;
+bogus;
+ERROR: syntax error at or near "bogus"
+LINE 1: bogus;
+ ^
+;
+\gdesc
+The command has no result, or the result has no columns.
+rollback;
-- \gexec
create temporary table gexec_test(a int, b text, c date, d float);
select format('create index on gexec_test(%I)', attname)
diff --git a/src/test/regress/sql/psql.sql b/src/test/regress/sql/psql.sql
index 0a4be827d88..94a54d6fd8d 100644
--- a/src/test/regress/sql/psql.sql
+++ b/src/test/regress/sql/psql.sql
@@ -119,6 +119,14 @@ SELECT 1 AS x, 'Hello', 2 AS y, true AS "dirty\name"
-- all on one line
SELECT 3 AS x, 'Hello', 4 AS y, true AS "dirty\name" \gdesc \g
+-- test for server bug #17983 with empty statement in aborted transaction
+set search_path = default;
+begin;
+bogus;
+;
+\gdesc
+rollback;
+
-- \gexec
create temporary table gexec_test(a int, b text, c date, d float);