public inbox for [email protected]  
help / color / mirror / Atom feed
From: Chao Li <[email protected]>
To: Postgres hackers <[email protected]>
Subject: Fix a server crash problem from pg_get_database_ddl
Date: Wed, 15 Apr 2026 13:51:31 +0800
Message-ID: <[email protected]> (raw)

Hi,

While doing some testing, I hit a server crash:
```
2026-04-15 11:30:17.377 CST [98179] LOG:  client backend (PID 41260) was terminated by signal 11: Segmentation fault: 11
2026-04-15 11:30:17.377 CST [98179] DETAIL:  Failed process was running: SELECT * FROM pg_get_database_ddl('db1'::regdatabase);
2026-04-15 11:30:17.377 CST [98179] LOG:  terminating any other active server processes
2026-04-15 11:30:17.380 CST [44361] FATAL:  the database system is in recovery mode
```

After debugging it, I found that the crash happened because I had mistakenly deleted the tablespace entry directly from pg_tablespace, and pg_get_database_ddl_internal() calls get_tablespace_name() without checking whether the return value is NULL.

So this doesn't seem like a bug a normal user could hit. It is more like a superuser-only mistake that creates an invalid catalog state. I think that even in such an edge case, we should raise a proper error instead of crashing the backend.

BTW, I have verified that in this case, ALTER DATABASE ... SET TABLESPACE can move the database to a valid tablespace and recover from the issue.

This patch fixes that by checking for a NULL result and throwing an error.

Best regards,
--
Chao Li (Evan)
HighGo Software Co., Ltd.
https://www.highgo.com/






Attachments:

  [application/octet-stream] v1-0001-ddlutils-error-out-when-pg_get_database_ddl-sees-.patch (1.4K, 2-v1-0001-ddlutils-error-out-when-pg_get_database_ddl-sees-.patch)
  download | inline diff:
From 4529c77c01bd0a2f1718c6dc45a2896191b72001 Mon Sep 17 00:00:00 2001
From: "Chao Li (Evan)" <[email protected]>
Date: Wed, 15 Apr 2026 13:32:12 +0800
Subject: [PATCH v1] ddlutils: error out when pg_get_database_ddl() sees a
 missing tablespace

pg_get_database_ddl_internal() calls get_tablespace_name() for a
database's dattablespace, and then passes the result to
pg_strcasecmp() without checking for NULL first.

Fix that by detecting the missing tablespace explicitly and raising an
ERROR with ERRCODE_UNDEFINED_OBJECT.

Author: Chao Li <[email protected]>
Reviewed-by:
Discussion: https://postgr.es/m/
---
 src/backend/utils/adt/ddlutils.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/src/backend/utils/adt/ddlutils.c b/src/backend/utils/adt/ddlutils.c
index c4f9f86c43e..6ab354e42f6 100644
--- a/src/backend/utils/adt/ddlutils.c
+++ b/src/backend/utils/adt/ddlutils.c
@@ -976,6 +976,13 @@ pg_get_database_ddl_internal(Oid dbid, bool pretty,
 	{
 		char	   *spcname = get_tablespace_name(dbform->dattablespace);
 
+		if (spcname == NULL)
+			ereport(ERROR,
+					errcode(ERRCODE_UNDEFINED_OBJECT),
+					errmsg("tablespace with OID %u does not exist",
+							dbform->dattablespace),
+					errhint("To recover, try ALTER DATABASE ... SET TABLESPACE ... to a valid tablespace."));
+
 		if (pg_strcasecmp(spcname, "pg_default") != 0)
 			append_ddl_option(&buf, pretty, 4, "TABLESPACE = %s",
 							  quote_identifier(spcname));
-- 
2.50.1 (Apple Git-155)



view thread (10+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected]
  Subject: Re: Fix a server crash problem from pg_get_database_ddl
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox