Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vJPGI-0056z0-24 for pgsql-hackers@arkaria.postgresql.org; Thu, 13 Nov 2025 04:48:45 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vJPGE-00GJrG-2a for pgsql-hackers@arkaria.postgresql.org; Thu, 13 Nov 2025 04:48:42 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vJPGE-00GJr6-1b for pgsql-hackers@lists.postgresql.org; Thu, 13 Nov 2025 04:48:42 +0000 Received: from mail-m16.yeah.net ([220.197.32.19]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vJPG8-007TM9-25 for pgsql-hackers@postgresql.org; Thu, 13 Nov 2025 04:48:41 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=yeah.net; s=s110527; h=Message-ID:Date:MIME-Version:Subject:From:To: Content-Type; bh=vNXP5EzJasv7TnWFGmg9h/JOSOASqii9RmuZe6ub2aQ=; b=fbYoyupZdP2dCsIXfVDwUmwSTxUrdSpdCf02CYiSTPVXArJjk7GSsSc4PXnKt9 j025gGgFLECrQgtxEcxTVm33pMMMmcuBGiJAsfu3GRuNe5G9C0TGULUHWSiTGmbe EbWXLf+f0My6J4b7KpGjx0cpJBLTOZoNXf9XCM7v68k1Y= Received: from [192.168.10.60] (unknown []) by gzsmtp1 (Coremail) with SMTP id Mc8vCgBHBQAVYxVpgx8GAQ--.10931S2; Thu, 13 Nov 2025 12:48:22 +0800 (CST) Message-ID: <7daf5cec-4eae-48e0-883e-684476b57531@yeah.net> Date: Thu, 13 Nov 2025 12:48:21 +0800 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: [PATCH] Add pg_get_database_ddl() function to reconstruct CREATE DATABASE statement From: Quan Zongliang To: Akshay Joshi , pgsql-hackers References: Content-Language: en-US In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 8bit X-CM-TRANSID: Mc8vCgBHBQAVYxVpgx8GAQ--.10931S2 X-Coremail-Antispam: 1Uf129KBjvJXoWxJF43WryDtF4ftw1ftr4UCFg_yoWrCw47pr 1fJFW7AryUJry8tr18Jw1UJryUtr15Jw1UKr1UJF18Jr1UAr12qr4qqr409F98JrW8Jw15 XF1UGr1DZryDA3DanT9S1TB71UUUUU7qnTZGkaVYY2UrUUUUjbIjqfuFe4nvWSU5nxnvy2 9KBjDUYxBIdaVFxhVjvjDU0xZFpf9x07jOzVbUUUUU= X-Originating-IP: [111.167.159.4] X-CM-SenderInfo: htxd06xrqjzxxdqjq5hhdkh0dhw/1tbiNBd9oWkVYxctOAAA3i List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On 11/13/25 12:17 PM, Quan Zongliang wrote: > > > On 11/12/25 8:04 PM, Akshay Joshi wrote: >> Hi Hackers, >> >> I’m submitting a patch as part of the broader Retail DDL Functions >> project described by Andrew Dunstan https://www.postgresql.org/ >> message- id/945db7c5-be75-45bf-b55b-cb1e56f2e3e9%40dunslane.net >> > cb1e56f2e3e9%40dunslane.net> >> >> This patch adds a new system function >> pg_get_database_ddl(database_name/ database_oid, pretty), which >> reconstructs the CREATE DATABASE statement for a given database name >> or database oid. When the pretty flag is set to true, the function >> returns a neatly formatted, multi-line DDL statement instead of a >> single-line statement. >> >> *Usage examples:* >> >> 1) SELECT pg_get_database_ddl('test_get_database_ddl_builtin');  -- >> *non-pretty formatted DDL* >> pg_get_database_ddl >> ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- >>    CREATE DATABASE test_get_database_ddl_builtin WITH OWNER = >> regress_ddl_database ENCODING = "UTF8" LC_COLLATE = "C" LC_CTYPE = "C" >> BUILTIN_LOCALE = "C.UTF-8" COLLATION_VERSION = "1" LOCALE_PROVIDER = >> 'builtin' TABLESPACE = pg_default ALLOW_CONNECTIONS = true CONNECTION >> LIMIT = -1; >> >> >> 2) SELECT pg_get_database_ddl('test_get_database_ddl_builtin', true); >> -- *pretty formatted DDL* >> >> CREATE DATABASE test_get_database_ddl_builtin >>           WITH >>           OWNER = regress_ddl_database >>           ENCODING = "UTF8" >>           LC_COLLATE = "C" >>           LC_CTYPE = "C" >>           BUILTIN_LOCALE = "C.UTF-8" >>           COLLATION_VERSION = "1" >>           LOCALE_PROVIDER = 'builtin' >>           TABLESPACE = pg_default >>           ALLOW_CONNECTIONS = true >>           CONNECTION LIMIT = -1; >> >> 3) SELECT pg_get_database_ddl(16835);      -- *non-pretty formatted >> DDL for OID* >> 4) SELECT pg_get_database_ddl(16835, true);  -- *pretty formatted DDL >> for OID* >> >> The patch includes documentation, in-code comments, and regression >> tests, all of which pass successfully. >> * >> **Note:* To run the regression tests, particularly the pg_upgrade >> tests successfully, I had to add a helper function, ddl_filter (in >> database.sql), which removes locale and collation-related information >> from the pg_get_database_ddl output. >> > I think we should check the connection permissions here. Otherwise: > > postgres=> SELECT pg_database_size('testdb'); > ERROR:  permission denied for database testdb > postgres=> SELECT pg_get_database_ddl('testdb'); > >                         pg_get_database_ddl > ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- >  CREATE DATABASE testdb WITH OWNER = quanzl ENCODING = "UTF8" > LC_COLLATE = "zh_CN.UTF-8" LC_CTYPE = "zh_CN.UTF-8" LOCALE_PROVIDER = > 'libc' TABLESPACE = pg_default ALLOW_CONNECTIONS = true CONNECTION LIMIT > = -1; > (1 row) > > Users without connection permissions should not generate DDL. > The "dbOwner" is defined as a null pointer. char *dbOwner = NULL; Later, there might be a risk of it not being assigned a value. if (OidIsValid(dbForm->datdba)) dbOwner = GetUserNameFromId(dbForm->datdba, false); Although there is no problem in normal circumstances here. Many parts of the existing code have not been checked either. Since this possibility exists, it should be checked before using it. Just like the function roles_is_member_of (acl.c). if (dbOwner) get_formatted_string(&buf, prettyFlags, 1, "OWNER = %s", quote_identifier(dbOwner)); > Regards, > Quan Zongliang > >> ----- >> Regards, >> Akshay Joshi >> EDB (EnterpriseDB) >> >> >> > >