From 767dcd0f3669d2701d9f94a0112108be34071c38 Mon Sep 17 00:00:00 2001
From: Marcos Magueta <maguetamarcos@gmail.com>
Date: Wed, 21 Jan 2026 17:11:24 -0300
Subject: [PATCH 2/5] Add pg_dump support for XMLSCHEMA objects

---
 src/bin/pg_dump/common.c             |   3 +
 src/bin/pg_dump/pg_backup_archiver.c |   1 +
 src/bin/pg_dump/pg_dump.c            | 128 +++++++++++++++++++++++++++
 src/bin/pg_dump/pg_dump.h            |   8 ++
 4 files changed, 140 insertions(+)

diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
index 349b47c8e29..651cf674365 100644
--- a/src/bin/pg_dump/common.c
+++ b/src/bin/pg_dump/common.c
@@ -182,6 +182,9 @@ getSchemaData(Archive *fout, int *numTablesPtr)
 	pg_log_info("reading user-defined conversions");
 	getConversions(fout);
 
+	pg_log_info("reading XML schemas");
+	getXmlSchemas(fout);
+
 	pg_log_info("reading type casts");
 	getCasts(fout);
 
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
index 4a63f7392ae..3175083edb0 100644
--- a/src/bin/pg_dump/pg_backup_archiver.c
+++ b/src/bin/pg_dump/pg_backup_archiver.c
@@ -3816,6 +3816,7 @@ _getObjectDescription(PQExpBuffer buf, const TocEntry *te)
 		strcmp(type, "TEXT SEARCH CONFIGURATION") == 0 ||
 		strcmp(type, "TYPE") == 0 ||
 		strcmp(type, "VIEW") == 0 ||
+		strcmp(type, "XMLSCHEMA") == 0 ||
 	/* non-schema-specified objects */
 		strcmp(type, "DATABASE") == 0 ||
 		strcmp(type, "PROCEDURAL LANGUAGE") == 0 ||
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 687dc98e46d..9a531ff3e8c 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -310,6 +310,7 @@ static void dumpAccessMethod(Archive *fout, const AccessMethodInfo *aminfo);
 static void dumpOpclass(Archive *fout, const OpclassInfo *opcinfo);
 static void dumpOpfamily(Archive *fout, const OpfamilyInfo *opfinfo);
 static void dumpCollation(Archive *fout, const CollInfo *collinfo);
+static void dumpXmlSchema(Archive *fout, const XmlSchemaInfo * xmlschemainfo);
 static void dumpConversion(Archive *fout, const ConvInfo *convinfo);
 static void dumpRule(Archive *fout, const RuleInfo *rinfo);
 static void dumpAgg(Archive *fout, const AggInfo *agginfo);
@@ -6563,6 +6564,62 @@ getConversions(Archive *fout)
 	destroyPQExpBuffer(query);
 }
 
+/*
+ * getXmlSchemas:
+ *	  get information about all XML schemas in the system catalogs
+ */
+void
+getXmlSchemas(Archive *fout)
+{
+	PGresult   *res;
+	int			ntups;
+	int			i;
+	PQExpBuffer query;
+	XmlSchemaInfo *xmlschemainfo;
+	int			i_tableoid;
+	int			i_oid;
+	int			i_schemaname;
+	int			i_schemanamespace;
+	int			i_schemaowner;
+
+	query = createPQExpBuffer();
+
+	appendPQExpBufferStr(query, "SELECT tableoid, oid, schemaname, "
+						 "schemanamespace, "
+						 "schemaowner "
+						 "FROM pg_xmlschema");
+
+	res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+	ntups = PQntuples(res);
+
+	xmlschemainfo = (XmlSchemaInfo *) pg_malloc(ntups * sizeof(XmlSchemaInfo));
+
+	i_tableoid = PQfnumber(res, "tableoid");
+	i_oid = PQfnumber(res, "oid");
+	i_schemaname = PQfnumber(res, "schemaname");
+	i_schemanamespace = PQfnumber(res, "schemanamespace");
+	i_schemaowner = PQfnumber(res, "schemaowner");
+
+	for (i = 0; i < ntups; i++)
+	{
+		xmlschemainfo[i].dobj.objType = DO_XMLSCHEMA;
+		xmlschemainfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+		xmlschemainfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+		AssignDumpId(&xmlschemainfo[i].dobj);
+		xmlschemainfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_schemaname));
+		xmlschemainfo[i].dobj.namespace =
+			findNamespace(atooid(PQgetvalue(res, i, i_schemanamespace)));
+		xmlschemainfo[i].rolname = getRoleName(PQgetvalue(res, i, i_schemaowner));
+
+		selectDumpableObject(&(xmlschemainfo[i].dobj), fout);
+	}
+
+	PQclear(res);
+
+	destroyPQExpBuffer(query);
+}
+
 /*
  * getAccessMethods:
  *	  get information about all user-defined access methods
@@ -11710,6 +11767,9 @@ dumpDumpableObject(Archive *fout, DumpableObject *dobj)
 		case DO_CONVERSION:
 			dumpConversion(fout, (const ConvInfo *) dobj);
 			break;
+		case DO_XMLSCHEMA:
+			dumpXmlSchema(fout, (const XmlSchemaInfo *) dobj);
+			break;
 		case DO_TABLE:
 			dumpTable(fout, (const TableInfo *) dobj);
 			break;
@@ -15235,6 +15295,73 @@ dumpCollation(Archive *fout, const CollInfo *collinfo)
 	free(qcollname);
 }
 
+/*
+ * dumpXmlSchema
+ *	  write out a single XML schema definition
+ */
+static void
+dumpXmlSchema(Archive *fout, const XmlSchemaInfo * xmlschemainfo)
+{
+	DumpOptions *dopt = fout->dopt;
+	PQExpBuffer query;
+	PQExpBuffer q;
+	PQExpBuffer delq;
+	char	   *qxmlschemaname;
+	PGresult   *res;
+	int			i_schemadata;
+	char	   *schemadata;
+
+	if (!dopt->dumpSchema)
+		return;
+
+	query = createPQExpBuffer();
+	q = createPQExpBuffer();
+	delq = createPQExpBuffer();
+
+	qxmlschemaname = pg_strdup(fmtId(xmlschemainfo->dobj.name));
+
+	appendPQExpBuffer(query,
+					  "SELECT schemadata "
+					  "FROM pg_catalog.pg_xmlschema "
+					  "WHERE oid = '%u'::pg_catalog.oid",
+					  xmlschemainfo->dobj.catId.oid);
+
+	res = ExecuteSqlQueryForSingleRow(fout, query->data);
+
+	i_schemadata = PQfnumber(res, "schemadata");
+	schemadata = PQgetvalue(res, 0, i_schemadata);
+
+	appendPQExpBuffer(delq, "DROP XMLSCHEMA %s;\n",
+					  fmtQualifiedDumpable(xmlschemainfo));
+
+	appendPQExpBuffer(q, "CREATE XMLSCHEMA %s AS ",
+					  fmtQualifiedDumpable(xmlschemainfo));
+	appendStringLiteralAH(q, schemadata, fout);
+	appendPQExpBufferStr(q, ";\n");
+
+	if (xmlschemainfo->dobj.dump & DUMP_COMPONENT_DEFINITION)
+		ArchiveEntry(fout, xmlschemainfo->dobj.catId, xmlschemainfo->dobj.dumpId,
+					 ARCHIVE_OPTS(.tag = xmlschemainfo->dobj.name,
+								  .namespace = xmlschemainfo->dobj.namespace->dobj.name,
+								  .owner = xmlschemainfo->rolname,
+								  .description = "XMLSCHEMA",
+								  .section = SECTION_PRE_DATA,
+								  .createStmt = q->data,
+								  .dropStmt = delq->data));
+
+	if (xmlschemainfo->dobj.dump & DUMP_COMPONENT_COMMENT)
+		dumpComment(fout, "XMLSCHEMA", qxmlschemaname,
+					xmlschemainfo->dobj.namespace->dobj.name, xmlschemainfo->rolname,
+					xmlschemainfo->dobj.catId, 0, xmlschemainfo->dobj.dumpId);
+
+	PQclear(res);
+
+	destroyPQExpBuffer(query);
+	destroyPQExpBuffer(q);
+	destroyPQExpBuffer(delq);
+	free(qxmlschemaname);
+}
+
 /*
  * dumpConversion
  *	  write out a single conversion definition
@@ -20177,6 +20304,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs,
 			case DO_OPFAMILY:
 			case DO_COLLATION:
 			case DO_CONVERSION:
+			case DO_XMLSCHEMA:
 			case DO_TABLE:
 			case DO_TABLE_ATTACH:
 			case DO_ATTRDEF:
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
index 4c4b14e5fc7..bc1cf5a00d2 100644
--- a/src/bin/pg_dump/pg_dump.h
+++ b/src/bin/pg_dump/pg_dump.h
@@ -50,6 +50,7 @@ typedef enum
 	DO_OPFAMILY,
 	DO_COLLATION,
 	DO_CONVERSION,
+	DO_XMLSCHEMA,
 	DO_TABLE,
 	DO_TABLE_ATTACH,
 	DO_ATTRDEF,
@@ -299,6 +300,12 @@ typedef struct _convInfo
 	const char *rolname;
 } ConvInfo;
 
+typedef struct _xmlSchemaInfo
+{
+	DumpableObject dobj;
+	const char *rolname;
+}			XmlSchemaInfo;
+
 typedef struct _tableInfo
 {
 	/*
@@ -797,6 +804,7 @@ extern void getOpclasses(Archive *fout);
 extern void getOpfamilies(Archive *fout);
 extern void getCollations(Archive *fout);
 extern void getConversions(Archive *fout);
+extern void getXmlSchemas(Archive *fout);
 extern TableInfo *getTables(Archive *fout, int *numTables);
 extern void getOwnedSeqs(Archive *fout, TableInfo tblinfo[], int numTables);
 extern InhInfo *getInherits(Archive *fout, int *numInherits);
-- 
2.51.2

