From b7741d5f02cee5bef210f6975c850b70123f75a4 Mon Sep 17 00:00:00 2001
From: "Jonathan Gonzalez V." <jonathan.abdiel@gmail.com>
Date: Sun, 5 Oct 2025 18:11:56 +0200
Subject: [PATCH v1 1/1] Introduce a new function pg_get_publication_ddl() that
 returns the CREATE ddl statement for a giving PUBLICATION.

The functions accepts a publication name or OID indistinctively,
thuse, provides an easy way to call the function as a user or from
inside the Postgres code or any SQL statement.

Comprhensive regression tests are included covering various
possible situations for a given publication.

Signed-off-by: Jonathan Gonzalez V. <jonathan.abdiel@gmail.com>
---
 doc/src/sgml/func/func-info.sgml              |  45 ++++
 src/backend/utils/adt/ruleutils.c             | 247 ++++++++++++++++++
 src/include/catalog/pg_proc.dat               |   8 +
 src/test/regress/expected/publication_ddl.out | 211 +++++++++++++++
 src/test/regress/parallel_schedule            |   4 +
 src/test/regress/sql/publication_ddl.sql      | 121 +++++++++
 6 files changed, 636 insertions(+)
 create mode 100644 src/test/regress/expected/publication_ddl.out
 create mode 100644 src/test/regress/sql/publication_ddl.sql

diff --git a/doc/src/sgml/func/func-info.sgml b/doc/src/sgml/func/func-info.sgml
index 175f18315cd..600534ff11f 100644
--- a/doc/src/sgml/func/func-info.sgml
+++ b/doc/src/sgml/func/func-info.sgml
@@ -3830,4 +3830,49 @@ acl      | {postgres=arwdDxtm/postgres,foo=r/postgres}
 
   </sect2>
 
+  <sect2 id="functions-get-object-ddl">
+   <title>Get Object DDL Functions</title>
+
+   <para>
+    The functions shown in <xref linkend="functions-get-object-ddl-table"/>
+    print the DDL statements for various database objects.
+    (This is a decompiled reconstruction, not the original text
+    of the command.)
+   </para>
+
+   <table id="functions-get-object-ddl-table">
+    <title>Get Object DDL Functions</title>
+    <tgroup cols="1">
+     <thead>
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        Function
+       </para>
+       <para>
+        Description
+       </para></entry>
+      </row>
+     </thead>
+
+     <tbody>
+      <row>
+       <entry role="func_table_entry"><para role="func_signature">
+        <indexterm>
+         <primary>pg_get_publication_ddl</primary>
+        </indexterm>
+        <function>pg_get_publication_ddl</function> ( <parameter>publication</parameter> <type>text</type> or <type>oid</type> )
+        <returnvalue>text</returnvalue>
+       </para>
+       <para>
+        Recreate the CREATE statement for a giving PUBLICATION.
+        The result is a complete <command>CREATE PUBLICATION</command> statement.
+       </para></entry>
+      </row>
+     </tbody>
+    </tgroup>
+   </table>
+
+  </sect2>
+
+
   </sect1>
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 033b625f3fc..b4e06d3f883 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -30,10 +30,12 @@
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_depend.h"
 #include "catalog/pg_language.h"
+#include "catalog/pg_namespace_d.h"
 #include "catalog/pg_opclass.h"
 #include "catalog/pg_operator.h"
 #include "catalog/pg_partitioned_table.h"
 #include "catalog/pg_proc.h"
+#include "catalog/pg_publication_rel.h"
 #include "catalog/pg_statistic_ext.h"
 #include "catalog/pg_trigger.h"
 #include "catalog/pg_type.h"
@@ -546,6 +548,7 @@ static void get_json_table_nested_columns(TableFunc *tf, JsonTablePlan *plan,
 										  deparse_context *context,
 										  bool showimplicit,
 										  bool needcomma);
+static Datum pg_do_publication_ddl(Publication *pub);
 
 #define only_marker(rte)  ((rte)->inh ? "" : "ONLY ")
 
@@ -13743,3 +13746,247 @@ get_range_partbound_string(List *bound_datums)
 
 	return buf.data;
 }
+
+/*
+ * pg_do_publication_ddl
+ *   Common code to get the DDL fro a PUBLICATION
+ *   by pg_get_publication_ddl and pg_get_publication_ddl_name
+ */
+Datum
+pg_do_publication_ddl(Publication *pub)
+{
+	StringInfo	buf;
+	List	   *publications;
+	List	   *pub_schemas;
+	bool		first_perm;
+
+	if (pub == NULL)
+		return (Datum) NULL;
+
+	publications = GetPublicationRelations(pub->oid, PUBLICATION_PART_ALL);
+	pub_schemas = GetPublicationSchemas(pub->oid);
+
+	buf = makeStringInfo();
+
+	/*
+	 * we add the publication name, this isn't covered by the schema, yet?
+	 */
+	appendStringInfo(buf, "CREATE PUBLICATION %s", quote_identifier(pub->name));
+
+	/*
+	 * having all tables or all sequence means there's not publications per
+	 * table
+	 */
+	if (pub->alltables || pub->allsequences)
+	{
+		appendStringInfo(buf, " FOR ");
+
+		if (pub->alltables)
+			appendStringInfo(buf, "ALL TABLES");
+
+		/* The sequence are published only on versions 19+ */
+		if (pub->allsequences)
+			appendStringInfo(buf,
+							 "%sALL SEQUENCE",
+							 pub->alltables ? ", " : " ");
+	}
+	else if (publications != NIL)
+	{
+
+		ListCell   *pub_cell;
+		Relation	rel;
+		char	   *schemaname = NULL;
+		char	   *tablename;
+		bool		first = true;
+
+		appendStringInfo(buf, " FOR TABLE ");
+
+		/*
+		 * publication an have relations of tables, in schema or current
+		 * schema
+		 *
+		 */
+		foreach(pub_cell, publications)
+		{
+			HeapTuple	pubtuple = NULL;
+			Datum		columns;
+			Datum		conditions;
+			bool		cols_nulls,
+						condition_nulls;
+
+			/* Open the table relation for this publication */
+			rel = relation_open(pub_cell->oid_value, AccessShareLock);
+			tablename = RelationGetRelationName(rel);
+
+			if (RelationGetNamespace(rel) != PG_PUBLIC_NAMESPACE)
+				schemaname = get_namespace_name(RelationGetNamespace(rel));
+
+			appendStringInfo(buf, "%s%s",
+							 first ? "" : ", ",
+							 quote_qualified_identifier(schemaname, tablename));
+			first = false;
+
+			pubtuple = SearchSysCacheCopy2(PUBLICATIONRELMAP,
+										   ObjectIdGetDatum(rel->rd_id),
+										   ObjectIdGetDatum(pub->oid));
+			columns = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple,
+									  Anum_pg_publication_rel_prattrs,
+									  &cols_nulls);
+
+			conditions = SysCacheGetAttr(PUBLICATIONRELMAP, pubtuple,
+										 Anum_pg_publication_rel_prqual,
+										 &condition_nulls);
+
+			/* If no null, means we have a list of columns to publish */
+			if (!cols_nulls)
+			{
+				ArrayType  *arr;
+				int			ncolumns;
+				int16	   *cols;
+				bool		fcol = true;
+
+				arr = DatumGetArrayTypeP(columns);
+				ncolumns = ARR_DIMS(arr)[0];
+				cols = (int16 *) ARR_DATA_PTR(arr);
+
+				appendStringInfoChar(buf, '(');
+				for (int i = 0; i < ncolumns; i++)
+				{
+					appendStringInfo(buf, "%s%s",
+									 fcol ? "" : ", ",
+									 get_attname(rel->rd_id, cols[i], true));
+					fcol = false;
+				}
+				appendStringInfoChar(buf, ')');
+			}
+
+			/*
+			 * If there's a condition goes after the columns but if there's no
+			 * column we can have conditions too
+			 */
+			if (!condition_nulls)
+			{
+				Node	   *node;
+				List	   *context;
+				char	   *str;
+
+				node = stringToNode(TextDatumGetCString(conditions));
+				context = deparse_context_for(
+											  get_relation_name(rel->rd_id),
+											  rel->rd_id);
+				str = deparse_expression_pretty(
+												node, context, false, false,
+												GET_PRETTY_FLAGS(false), 0);
+
+				appendStringInfo(buf, " WHERE %s ", str);
+			}
+
+			/* Close the relation */
+			relation_close(rel, AccessShareLock);
+		}
+	}
+
+	/* if we have schemas, for sure this will go right before the WITH */
+	if (pub_schemas != NIL)
+	{
+		ListCell   *schema_cell;
+		bool		first_schema = true;
+
+		/*
+		 * schemas can be preceeded by a list of tables
+		 */
+		appendStringInfo(buf, "%s TABLES IN SCHEMA",
+						 publications == NIL ? " FOR" : ",");
+
+		/* schemas can be one or a list */
+		foreach(schema_cell, pub_schemas)
+		{
+			appendStringInfo(buf, "%s %s",
+							 first_schema ? "" : ",",
+							 quote_identifier(get_namespace_name(schema_cell->oid_value)));
+			first_schema = false;
+		}
+	}
+
+	/* always add the WITH options */
+	appendStringInfo(buf, " WITH (");
+
+	/* publish string */
+	appendStringInfo(buf, "publish='");
+
+	/*
+	 * we need to know if we're the second permission added to prefix with a
+	 * ", " string
+	 */
+	first_perm = true;
+	if (pub->pubactions.pubinsert)
+	{
+		/*
+		 * by precedence we know that the insert will always be first, no need
+		 * to check previous values
+		 */
+		appendStringInfo(buf, "insert");
+		first_perm = false;
+	}
+
+	if (pub->pubactions.pubupdate)
+	{
+		appendStringInfo(buf, "%supdate", first_perm ? "" : ", ");
+		first_perm = false;
+	}
+	if (pub->pubactions.pubdelete)
+	{
+		appendStringInfo(buf, "%sdelete", first_perm ? "" : ", ");
+		first_perm = false;
+	}
+
+	if (pub->pubactions.pubtruncate)
+	{
+		appendStringInfo(buf, "%struncate", first_perm ? "" : ", ");
+	}
+
+	appendStringInfo(buf, "', ");
+
+	/* publish_generated_columns string */
+	appendStringInfo(buf, "publish_generated_columns='%s', ",
+					 pub->pubgencols_type == PUBLISH_GENCOLS_NONE ? "none" : "stored");
+
+	/* publish_via_partition_root value */
+	appendStringInfo(buf, "publish_via_partition_root='%s')",
+					 pub->pubviaroot ? "true" : "false");
+
+	/* the statement should always finish with a ; */
+	appendStringInfoChar(buf, ';');
+
+	PG_RETURN_TEXT_P(string_to_text(buf->data));
+}
+
+/*
+ * pg_get_publication_ddl_name
+ *   Get the CREATE statement for PUBLICATION by name
+ */
+Datum
+pg_get_publication_ddl_name(PG_FUNCTION_ARGS)
+{
+	char	   *pub_name = text_to_cstring(PG_GETARG_TEXT_PP(0));
+	Publication *pub;
+
+	pub = GetPublicationByName(pub_name, false);
+
+	return pg_do_publication_ddl(pub);
+}
+
+/*
+ * pg_get_publication_ddl
+ *   Get the CREATE statement for PUBLICATION by OID
+ */
+Datum
+pg_get_publication_ddl(PG_FUNCTION_ARGS)
+{
+	Oid			pub_oid = PG_GETARG_OID(0);
+	Publication *pub;
+
+	pub = GetPublication(pub_oid);
+
+	return pg_do_publication_ddl(pub);
+}
diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat
index 2ac69bf2df5..7bbb1d2751f 100644
--- a/src/include/catalog/pg_proc.dat
+++ b/src/include/catalog/pg_proc.dat
@@ -12336,6 +12336,14 @@
   proname => 'pg_relation_is_publishable', provolatile => 's',
   prorettype => 'bool', proargtypes => 'regclass',
   prosrc => 'pg_relation_is_publishable' },
+{ oid => '6122',
+  descr => 'returns the create statement for a publication',
+	proname => 'pg_get_publication_ddl', prorettype => 'text',
+	proargtypes => 'oid', prosrc => 'pg_get_publication_ddl' },
+{ oid => '6123',
+  descr => 'returns the create statement for a publication',
+	proname => 'pg_get_publication_ddl', prorettype => 'text',
+	proargtypes => 'text', prosrc => 'pg_get_publication_ddl_name' },
 
 # rls
 { oid => '3298',
diff --git a/src/test/regress/expected/publication_ddl.out b/src/test/regress/expected/publication_ddl.out
new file mode 100644
index 00000000000..9d162c07d53
--- /dev/null
+++ b/src/test/regress/expected/publication_ddl.out
@@ -0,0 +1,211 @@
+--
+-- Test for DDL statement from:
+-- - pg_get_publication_ddl
+--
+-- supress warning that depends on wal_level
+SET client_min_messages = 'ERROR';
+-- empty publication is possible and allowed
+CREATE PUBLICATION testpub_ddl_1;
+SELECT pg_get_publication_ddl('testpub_ddl_1');
+                                                                  pg_get_publication_ddl                                                                   
+-----------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_1 WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_1'));
+                                                                  pg_get_publication_ddl                                                                   
+-----------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_1 WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+-- create base table to test basic table publication
+CREATE TABLE testpub_ddl_tbl1 (foo int, bar int);
+CREATE TABLE testpub_ddl_tbl2 (foo int, bar int);
+CREATE TABLE testpub_ddl_tbl3 (foo int, bar int, beque int, baz int);
+CREATE TABLE testpub_ddl_tbl4 (foo int, bar int, beque bool);
+CREATE PUBLICATION testpub_ddl_2 FOR TABLE testpub_ddl_tbl1, testpub_ddl_tbl2, testpub_ddl_tbl3 WITH (publish='delete', publish_generated_columns='stored', publish_via_partition_root='true');
+SELECT pg_get_publication_ddl('testpub_ddl_2');
+                                                                                     pg_get_publication_ddl                                                                                      
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_2 FOR TABLE testpub_ddl_tbl1, testpub_ddl_tbl2, testpub_ddl_tbl3 WITH (publish='delete', publish_generated_columns='stored', publish_via_partition_root='true');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_2'));
+                                                                                     pg_get_publication_ddl                                                                                      
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_2 FOR TABLE testpub_ddl_tbl1, testpub_ddl_tbl2, testpub_ddl_tbl3 WITH (publish='delete', publish_generated_columns='stored', publish_via_partition_root='true');
+(1 row)
+
+ALTER PUBLICATION testpub_ddl_2 SET (publish = 'delete, update');
+SELECT pg_get_publication_ddl('testpub_ddl_2');
+                                                                                         pg_get_publication_ddl                                                                                          
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_2 FOR TABLE testpub_ddl_tbl1, testpub_ddl_tbl2, testpub_ddl_tbl3 WITH (publish='update, delete', publish_generated_columns='stored', publish_via_partition_root='true');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_2'));
+                                                                                         pg_get_publication_ddl                                                                                          
+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_2 FOR TABLE testpub_ddl_tbl1, testpub_ddl_tbl2, testpub_ddl_tbl3 WITH (publish='update, delete', publish_generated_columns='stored', publish_via_partition_root='true');
+(1 row)
+
+-- create publication for one table with one column and a condition
+CREATE PUBLICATION testpub_ddl_3 FOR TABLE ONLY testpub_ddl_tbl1 (bar) WHERE (bar = 1);
+SELECT pg_get_publication_ddl('testpub_ddl_3');
+                                                                                           pg_get_publication_ddl                                                                                           
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_3 FOR TABLE testpub_ddl_tbl1(bar) WHERE (bar = 1)  WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_3'));
+                                                                                           pg_get_publication_ddl                                                                                           
+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_3 FOR TABLE testpub_ddl_tbl1(bar) WHERE (bar = 1)  WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+-- create publication for one table with two columns and a condition
+CREATE PUBLICATION testpub_ddl_4 FOR TABLE ONLY testpub_ddl_tbl3 (bar,baz) WHERE (bar = baz);
+SELECT pg_get_publication_ddl('testpub_ddl_4');
+                                                                                              pg_get_publication_ddl                                                                                               
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_4 FOR TABLE testpub_ddl_tbl3(bar, baz) WHERE (bar = baz)  WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_4'));
+                                                                                              pg_get_publication_ddl                                                                                               
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_4 FOR TABLE testpub_ddl_tbl3(bar, baz) WHERE (bar = baz)  WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+-- create publication for one table with two columns and a condition with an expresion
+CREATE PUBLICATION testpub_ddl_5 FOR TABLE ONLY testpub_ddl_tbl4 (bar,beque) WHERE (beque IS TRUE);
+SELECT pg_get_publication_ddl('testpub_ddl_5');
+                                                                                                 pg_get_publication_ddl                                                                                                  
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_5 FOR TABLE testpub_ddl_tbl4(bar, beque) WHERE (beque IS TRUE)  WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_5'));
+                                                                                                 pg_get_publication_ddl                                                                                                  
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_5 FOR TABLE testpub_ddl_tbl4(bar, beque) WHERE (beque IS TRUE)  WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+-- create publication for all tables
+CREATE PUBLICATION testpub_ddl_6 FOR ALL TABLES;
+SELECT pg_get_publication_ddl('testpub_ddl_6');
+                                                                          pg_get_publication_ddl                                                                          
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_6 FOR ALL TABLES WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_6'));
+                                                                          pg_get_publication_ddl                                                                          
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_6 FOR ALL TABLES WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+-- create publation for all tables and all sequences
+CREATE PUBLICATION testpub_ddl_7 FOR ALL TABLES, ALL SEQUENCES;
+SELECT pg_get_publication_ddl('testpub_ddl_7');
+                                                                                 pg_get_publication_ddl                                                                                 
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_7 FOR ALL TABLES, ALL SEQUENCE WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_7'));
+                                                                                 pg_get_publication_ddl                                                                                 
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_7 FOR ALL TABLES, ALL SEQUENCE WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+-- create schema for schema publication
+CREATE SCHEMA pub_schema_test_ddl;
+CREATE TABLE pub_schema_test_ddl.schema_tbl1 (foo int, bar int);
+CREATE TABLE pub_schema_test_ddl.schema_tbl2 (foo int, bar int);
+CREATE TABLE pub_schema_test_ddl.schema_tbl3 (foo int, bar int, baz int);
+-- create a publication for a list of tables
+CREATE PUBLICATION testpub_ddl_8 FOR TABLES IN SCHEMA pub_schema_test_ddl, TABLE pub_schema_test_ddl.schema_tbl1, pub_schema_test_ddl.schema_tbl2;
+SELECT pg_get_publication_ddl('testpub_ddl_8');
+                                                                                                                           pg_get_publication_ddl                                                                                                                           
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_8 FOR TABLE pub_schema_test_ddl.schema_tbl1, pub_schema_test_ddl.schema_tbl2, TABLES IN SCHEMA pub_schema_test_ddl WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_8'));
+                                                                                                                           pg_get_publication_ddl                                                                                                                           
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_8 FOR TABLE pub_schema_test_ddl.schema_tbl1, pub_schema_test_ddl.schema_tbl2, TABLES IN SCHEMA pub_schema_test_ddl WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+-- create publication in schema only for table
+CREATE PUBLICATION testpub_ddl_9 FOR TABLES IN SCHEMA pub_schema_test_ddl, TABLE pub_schema_test_ddl.schema_tbl1;
+SELECT pg_get_publication_ddl('testpub_ddl_9');
+                                                                                                          pg_get_publication_ddl                                                                                                           
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_9 FOR TABLE pub_schema_test_ddl.schema_tbl1, TABLES IN SCHEMA pub_schema_test_ddl WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_9'));
+                                                                                                          pg_get_publication_ddl                                                                                                           
+-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_9 FOR TABLE pub_schema_test_ddl.schema_tbl1, TABLES IN SCHEMA pub_schema_test_ddl WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+-- create publication for all tables in schema
+CREATE PUBLICATION testpub_ddl_10 FOR TABLES IN SCHEMA pub_schema_test_ddl;
+SELECT pg_get_publication_ddl('testpub_ddl_10');
+                                                                                       pg_get_publication_ddl                                                                                        
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_10 FOR TABLES IN SCHEMA pub_schema_test_ddl WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_10'));
+                                                                                       pg_get_publication_ddl                                                                                        
+-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_10 FOR TABLES IN SCHEMA pub_schema_test_ddl WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+-- a new schema for multiple schemas
+CREATE SCHEMA pub_schema_test_ddl_2;
+CREATE TABLE pub_schema_test_ddl_2.schema_tbl1 (foo int, bar int);
+-- create a publication for a list of schemas
+CREATE PUBLICATION testpub_ddl_11 FOR TABLES IN SCHEMA pub_schema_test_ddl, pub_schema_test_ddl_2;
+SELECT pg_get_publication_ddl('testpub_ddl_11');
+                                                                                                   pg_get_publication_ddl                                                                                                   
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_11 FOR TABLES IN SCHEMA pub_schema_test_ddl, pub_schema_test_ddl_2 WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_11'));
+                                                                                                   pg_get_publication_ddl                                                                                                   
+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ CREATE PUBLICATION testpub_ddl_11 FOR TABLES IN SCHEMA pub_schema_test_ddl, pub_schema_test_ddl_2 WITH (publish='insert, update, delete, truncate', publish_generated_columns='none', publish_via_partition_root='false');
+(1 row)
+
+-- cleanup publications
+DROP PUBLICATION testpub_ddl_1;
+DROP PUBLICATION testpub_ddl_2;
+DROP PUBLICATION testpub_ddl_3;
+DROP PUBLICATION testpub_ddl_4;
+DROP PUBLICATION testpub_ddl_5;
+DROP PUBLICATION testpub_ddl_6;
+DROP PUBLICATION testpub_ddl_7;
+DROP PUBLICATION testpub_ddl_8;
+DROP PUBLICATION testpub_ddl_9;
+DROP PUBLICATION testpub_ddl_10;
+DROP PUBLICATION testpub_ddl_11;
+-- cleanup tables
+DROP TABLE testpub_ddl_tbl1;
+DROP TABLE testpub_ddl_tbl2;
+DROP TABLE testpub_ddl_tbl3;
+DROP TABLE testpub_ddl_tbl4;
+-- cleanup tables in schemas
+DROP TABLE  pub_schema_test_ddl.schema_tbl1;
+DROP TABLE  pub_schema_test_ddl.schema_tbl2;
+DROP TABLE  pub_schema_test_ddl.schema_tbl3;
+DROP TABLE  pub_schema_test_ddl_2.schema_tbl1;
+-- cleanup schemas
+DROP SCHEMA pub_schema_test_ddl;
+DROP SCHEMA pub_schema_test_ddl_2;
+RESET client_min_messages;
diff --git a/src/test/regress/parallel_schedule b/src/test/regress/parallel_schedule
index 021d57f66bb..ce5351759b4 100644
--- a/src/test/regress/parallel_schedule
+++ b/src/test/regress/parallel_schedule
@@ -137,6 +137,10 @@ test: event_trigger_login
 # this test also uses event triggers, so likewise run it by itself
 test: fast_default
 
+# run the retail DDL tests at the end make sense to not interrupt with other
+# tests in case the object names are the same to other objects previously used.
+test: publication_ddl
+
 # run tablespace test at the end because it drops the tablespace created during
 # setup that other tests may use.
 test: tablespace
diff --git a/src/test/regress/sql/publication_ddl.sql b/src/test/regress/sql/publication_ddl.sql
new file mode 100644
index 00000000000..e93bcf70692
--- /dev/null
+++ b/src/test/regress/sql/publication_ddl.sql
@@ -0,0 +1,121 @@
+--
+-- Test for DDL statement from:
+-- - pg_get_publication_ddl
+--
+
+-- supress warning that depends on wal_level
+SET client_min_messages = 'ERROR';
+-- empty publication is possible and allowed
+CREATE PUBLICATION testpub_ddl_1;
+
+SELECT pg_get_publication_ddl('testpub_ddl_1');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_1'));
+
+-- create base table to test basic table publication
+CREATE TABLE testpub_ddl_tbl1 (foo int, bar int);
+CREATE TABLE testpub_ddl_tbl2 (foo int, bar int);
+CREATE TABLE testpub_ddl_tbl3 (foo int, bar int, beque int, baz int);
+CREATE TABLE testpub_ddl_tbl4 (foo int, bar int, beque bool);
+
+CREATE PUBLICATION testpub_ddl_2 FOR TABLE testpub_ddl_tbl1, testpub_ddl_tbl2, testpub_ddl_tbl3 WITH (publish='delete', publish_generated_columns='stored', publish_via_partition_root='true');
+
+SELECT pg_get_publication_ddl('testpub_ddl_2');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_2'));
+
+ALTER PUBLICATION testpub_ddl_2 SET (publish = 'delete, update');
+
+SELECT pg_get_publication_ddl('testpub_ddl_2');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_2'));
+
+-- create publication for one table with one column and a condition
+
+CREATE PUBLICATION testpub_ddl_3 FOR TABLE ONLY testpub_ddl_tbl1 (bar) WHERE (bar = 1);
+
+SELECT pg_get_publication_ddl('testpub_ddl_3');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_3'));
+
+-- create publication for one table with two columns and a condition
+
+CREATE PUBLICATION testpub_ddl_4 FOR TABLE ONLY testpub_ddl_tbl3 (bar,baz) WHERE (bar = baz);
+
+SELECT pg_get_publication_ddl('testpub_ddl_4');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_4'));
+
+-- create publication for one table with two columns and a condition with an expresion
+
+CREATE PUBLICATION testpub_ddl_5 FOR TABLE ONLY testpub_ddl_tbl4 (bar,beque) WHERE (beque IS TRUE);
+
+SELECT pg_get_publication_ddl('testpub_ddl_5');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_5'));
+
+-- create publication for all tables
+CREATE PUBLICATION testpub_ddl_6 FOR ALL TABLES;
+
+SELECT pg_get_publication_ddl('testpub_ddl_6');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_6'));
+
+-- create publation for all tables and all sequences
+CREATE PUBLICATION testpub_ddl_7 FOR ALL TABLES, ALL SEQUENCES;
+
+SELECT pg_get_publication_ddl('testpub_ddl_7');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_7'));
+
+-- create schema for schema publication
+CREATE SCHEMA pub_schema_test_ddl;
+CREATE TABLE pub_schema_test_ddl.schema_tbl1 (foo int, bar int);
+CREATE TABLE pub_schema_test_ddl.schema_tbl2 (foo int, bar int);
+CREATE TABLE pub_schema_test_ddl.schema_tbl3 (foo int, bar int, baz int);
+
+-- create a publication for a list of tables
+CREATE PUBLICATION testpub_ddl_8 FOR TABLES IN SCHEMA pub_schema_test_ddl, TABLE pub_schema_test_ddl.schema_tbl1, pub_schema_test_ddl.schema_tbl2;
+SELECT pg_get_publication_ddl('testpub_ddl_8');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_8'));
+
+-- create publication in schema only for table
+CREATE PUBLICATION testpub_ddl_9 FOR TABLES IN SCHEMA pub_schema_test_ddl, TABLE pub_schema_test_ddl.schema_tbl1;
+SELECT pg_get_publication_ddl('testpub_ddl_9');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_9'));
+
+-- create publication for all tables in schema
+CREATE PUBLICATION testpub_ddl_10 FOR TABLES IN SCHEMA pub_schema_test_ddl;
+SELECT pg_get_publication_ddl('testpub_ddl_10');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_10'));
+
+-- a new schema for multiple schemas
+CREATE SCHEMA pub_schema_test_ddl_2;
+CREATE TABLE pub_schema_test_ddl_2.schema_tbl1 (foo int, bar int);
+
+-- create a publication for a list of schemas
+CREATE PUBLICATION testpub_ddl_11 FOR TABLES IN SCHEMA pub_schema_test_ddl, pub_schema_test_ddl_2;
+SELECT pg_get_publication_ddl('testpub_ddl_11');
+SELECT pg_get_publication_ddl((SELECT oid FROM pg_publication WHERE pubname='testpub_ddl_11'));
+
+-- cleanup publications
+DROP PUBLICATION testpub_ddl_1;
+DROP PUBLICATION testpub_ddl_2;
+DROP PUBLICATION testpub_ddl_3;
+DROP PUBLICATION testpub_ddl_4;
+DROP PUBLICATION testpub_ddl_5;
+DROP PUBLICATION testpub_ddl_6;
+DROP PUBLICATION testpub_ddl_7;
+DROP PUBLICATION testpub_ddl_8;
+DROP PUBLICATION testpub_ddl_9;
+DROP PUBLICATION testpub_ddl_10;
+DROP PUBLICATION testpub_ddl_11;
+
+-- cleanup tables
+DROP TABLE testpub_ddl_tbl1;
+DROP TABLE testpub_ddl_tbl2;
+DROP TABLE testpub_ddl_tbl3;
+DROP TABLE testpub_ddl_tbl4;
+
+-- cleanup tables in schemas
+DROP TABLE  pub_schema_test_ddl.schema_tbl1;
+DROP TABLE  pub_schema_test_ddl.schema_tbl2;
+DROP TABLE  pub_schema_test_ddl.schema_tbl3;
+DROP TABLE  pub_schema_test_ddl_2.schema_tbl1;
+
+-- cleanup schemas
+DROP SCHEMA pub_schema_test_ddl;
+DROP SCHEMA pub_schema_test_ddl_2;
+RESET client_min_messages;
-- 
2.51.0

