diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml
index f8001551e695bcb176ba7001337d70c09619d4f5..db7cd1d1f3b3a1d6c3de246f5f5cc5128ed9870d 100644
--- a/doc/src/sgml/func.sgml
+++ b/doc/src/sgml/func.sgml
@@ -1,4 +1,4 @@
-<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.371 2007/03/25 11:56:01 ishii Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.372 2007/04/01 09:00:24 petere Exp $ -->
 
  <chapter id="functions">
   <title>Functions and Operators</title>
@@ -11427,7 +11427,7 @@ cursor_to_xml(cursor refcursor, count int, nulls boolean, tableforest boolean, t
     query whose text is passed as parameter
     <parameter>query</parameter> and maps the result set.
     <function>cursor_to_xml</function> fetches the indicated number of
-    rows from the cursor specificed by the parameter
+    rows from the cursor specified by the parameter
     <parameter>cursor</parameter>.  This variant is recommendable if
     large tables have to be mapped, because the result value is built
     up in memory by each function.
@@ -11492,7 +11492,7 @@ cursor_to_xml(cursor refcursor, count int, nulls boolean, tableforest boolean, t
     values should be included in the output.  If true, null values in
     columns are represented as
 <screen><![CDATA[
-<columname xsi:nil="true"/>
+<columnname xsi:nil="true"/>
 ]]></screen>
     where <literal>xsi</literal> is the XML namespace prefix for XML
     Schema Instance.  An appropriate namespace declaration will be
@@ -11530,6 +11530,65 @@ query_to_xml_and_xmlschema(query text, nulls boolean, tableforest boolean, targe
 </synopsis>
    </para>
 
+   <para>
+    In addition, the following functions are available to produce
+    analogous mappings of entire schemas or the entire current
+    database.
+<synopsis>
+schema_to_xml(schema name, nulls boolean, tableforest boolean, targetns text)
+schema_to_xmlschema(schema name, nulls boolean, tableforest boolean, targetns text)
+schema_to_xml_and_xmlschema(schema name, nulls boolean, tableforest boolean, targetns text)
+
+database_to_xml(nulls boolean, tableforest boolean, targetns text)
+database_to_xmlschema(nulls boolean, tableforest boolean, targetns text)
+database_to_xml_and_xmlschema(nulls boolean, tableforest boolean, targetns text)
+</synopsis>
+
+    Note that these potentially produce a lot of data, which needs to
+    be built up in memory.  When requesting content mappings of large
+    schemas or databases, it may be worthwhile to consider mapping the
+    tables separately instead, possibly even through a cursor.
+   </para>
+
+   <para>
+    The result of a schema content mapping looks like this:
+
+<screen><![CDATA[
+<schemaname>
+
+table1-mapping
+
+table2-mapping
+
+...
+
+</schemaname>]]></screen>
+
+    where the format of a table mapping depends on the
+    <parameter>tableforest</parameter> parameter as explained above.
+   </para>
+
+   <para>
+    The result of a database content mapping looks like this:
+
+<screen><![CDATA[
+<dbname>
+
+<schema1name>
+  ...
+</schema1name>
+
+<schema2name>
+  ...
+</schema2name>
+
+...
+
+</dbname>]]></screen>
+
+    where the schema mapping is as above.
+   </para>
+
    <para>
     As an example for using the output produced by these functions,
     <xref linkend="xslt-xml-html"> shows an XSLT stylesheet that
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index e9c94968011bb1c69531c03f907914d6b6ff00cf..55be759c9e331bdfd2a8cdfb58639d90b2f209c8 100644
--- a/src/backend/utils/adt/xml.c
+++ b/src/backend/utils/adt/xml.c
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.37 2007/03/22 20:26:30 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.38 2007/04/01 09:00:25 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -95,12 +95,14 @@ static text		*xml_xmlnodetoxmltype(xmlNodePtr cur);
 
 #endif /* USE_LIBXML */
 
-static StringInfo query_to_xml_internal(const char *query, char *tablename, const char *xmlschema, bool nulls, bool tableforest, const char *targetns);
+static StringInfo query_to_xml_internal(const char *query, char *tablename, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level);
 static const char * map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tableforest, const char *targetns);
+static const char * map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool tableforest, const char *targetns);
+static const char * map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tableforest, const char *targetns);
 static const char * map_sql_type_to_xml_name(Oid typeoid, int typmod);
-static const char * map_sql_typecoll_to_xmlschema_types(TupleDesc tupdesc);
+static const char * map_sql_typecoll_to_xmlschema_types(List *tupdesc_list);
 static const char * map_sql_type_to_xmlschema_type(Oid typeoid, int typmod);
-static void SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool nulls, bool tableforest, const char *targetns);
+static void SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool nulls, bool tableforest, const char *targetns, bool top_level);
 
 
 XmlBinaryType xmlbinary;
@@ -1657,11 +1659,126 @@ _SPI_strdup(const char *s)
 }
 
 
+/*
+ * SQL to XML mapping functions
+ *
+ * What follows below is intentionally organized so that you can read
+ * along in the SQL/XML:2003 standard.  The functions are mostly split
+ * up and ordered they way the clauses lay out in the standards
+ * document, and the identifiers are also aligned with the standard
+ * text.  (SQL/XML:2006 appears to be ordered differently,
+ * unfortunately.)
+ *
+ * There are many things going on there:
+ *
+ * There are two kinds of mappings: Mapping SQL data (table contents)
+ * to XML documents, and mapping SQL structure (the "schema") to XML
+ * Schema.  And there are functions that do both at the same time.
+ *
+ * Then you can map a database, a schema, or a table, each in both
+ * ways.  This breaks down recursively: Mapping a database invokes
+ * mapping schemas, which invokes mapping tables, which invokes
+ * mapping rows, which invokes mapping columns, although you can't
+ * call the last two from the outside.  Because of this, there are a
+ * number of xyz_internal() functions which are to be called both from
+ * the function manager wrapper and from some upper layer in a
+ * recursive call.
+ *
+ * See the documentation about what the common function arguments
+ * nulls, tableforest, and targetns mean.
+ *
+ * Some style guidelines for XML output: Use double quotes for quoting
+ * XML attributes.  Indent XML elements by two spaces, but remember
+ * that a lot of code is called recursively at different levels, so
+ * it's better not to indent rather than create output that indents
+ * and outdents weirdly.  Add newlines to make the output look nice.
+ */
+
+
+/*
+ * Visibility of objects for XML mappings; see SQL/XML:2003 section
+ * 4.8.5.
+ */
+
+/*
+ * Given a query, which must return type oid as first column, produce
+ * a list of Oids with the query results.
+ */
+static List *
+query_to_oid_list(const char *query)
+{
+	int			i;
+	List	   *list = NIL;
+
+	SPI_execute(query, true, 0);
+
+	for (i = 0; i < SPI_processed; i++)
+	{
+		Oid oid;
+		bool isnull;
+
+		oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull));
+		if (isnull)
+			continue;
+		list = lappend_oid(list, oid);
+	}
+
+	return list;
+}
+
+
+static List *
+schema_get_xml_visible_tables(Oid nspid)
+{
+	StringInfoData query;
+
+	initStringInfo(&query);
+	appendStringInfo(&query, "SELECT oid FROM pg_class WHERE relnamespace = %u AND relkind IN ('r', 'v') AND has_table_privilege (oid, 'SELECT') ORDER BY relname;", nspid);
+
+	return query_to_oid_list(query.data);
+}
+
+
+/* 
+ * Including the system schemas is probably not useful for a database
+ * mapping.
+ */
+#define XML_VISIBLE_SCHEMAS_EXCLUDE "nspname LIKE 'pg_%' ESCAPE '' OR nspname = 'information_schema'"
+
+#define XML_VISIBLE_SCHEMAS "SELECT oid FROM pg_namespace WHERE has_schema_privilege (oid, 'USAGE') AND NOT (" XML_VISIBLE_SCHEMAS_EXCLUDE ")"
+
+
+static List *
+database_get_xml_visible_schemas(void)
+{
+	return query_to_oid_list(XML_VISIBLE_SCHEMAS " ORDER BY nspname;");
+}
+
+
+static List *
+database_get_xml_visible_tables(void)
+{
+	/* At the moment there is no order required here. */
+	return query_to_oid_list("SELECT oid FROM pg_class WHERE relkind IN ('r', 'v') AND has_table_privilege (pg_class.oid, 'SELECT') AND relnamespace IN (" XML_VISIBLE_SCHEMAS ");");
+}
+
+
 /*
  * Map SQL table to XML and/or XML Schema document; see SQL/XML:2003
  * section 9.3.
  */
 
+static StringInfo
+table_to_xml_internal(Oid relid, bool nulls, bool tableforest, const char *targetns, bool top_level)
+{
+	StringInfoData query;
+
+	initStringInfo(&query);
+	appendStringInfo(&query, "SELECT * FROM %s", DatumGetCString(DirectFunctionCall1(regclassout, ObjectIdGetDatum(relid))));
+	return query_to_xml_internal(query.data, get_rel_name(relid), NULL, nulls, tableforest, targetns, top_level);
+}
+
+
 Datum
 table_to_xml(PG_FUNCTION_ARGS)
 {
@@ -1670,12 +1787,7 @@ table_to_xml(PG_FUNCTION_ARGS)
 	bool		tableforest = PG_GETARG_BOOL(2);
 	const char *targetns = _textout(PG_GETARG_TEXT_P(3));
 
-	StringInfoData query;
-
-	initStringInfo(&query);
-	appendStringInfo(&query, "SELECT * FROM %s", DatumGetCString(DirectFunctionCall1(regclassout, ObjectIdGetDatum(relid))));
-
-	PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query.data, get_rel_name(relid), NULL, nulls, tableforest, targetns)));
+	PG_RETURN_XML_P(stringinfo_to_xmltype(table_to_xml_internal(relid, nulls, tableforest, targetns, true)));
 }
 
 
@@ -1687,7 +1799,7 @@ query_to_xml(PG_FUNCTION_ARGS)
 	bool		tableforest = PG_GETARG_BOOL(2);
 	const char *targetns = _textout(PG_GETARG_TEXT_P(3));
 
-	PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL, NULL, nulls, tableforest, targetns)));
+	PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL, NULL, nulls, tableforest, targetns, true)));
 }
 
 
@@ -1715,7 +1827,7 @@ cursor_to_xml(PG_FUNCTION_ARGS)
 
 	SPI_cursor_fetch(portal, true, count);
 	for (i = 0; i < SPI_processed; i++)
-		SPI_sql_row_to_xmlelement(i, &result, NULL, nulls, tableforest, targetns);
+		SPI_sql_row_to_xmlelement(i, &result, NULL, nulls, tableforest, targetns, true);
 
 	SPI_finish();
 
@@ -1723,8 +1835,52 @@ cursor_to_xml(PG_FUNCTION_ARGS)
 }
 
 
+/*
+ * Write the start tag of the root element of a data mapping.
+ *
+ * top_level means that this is the very top level of the eventual
+ * output.  For example, when the user calls table_to_xml, then a call
+ * with a table name to this function is the top level.  When the user
+ * calls database_to_xml, then a call with a schema name to this
+ * function is not the top level.  If top_level is false, then the XML
+ * namespace declarations are omitted, because they supposedly already
+ * appeared earlier in the output.  Repeating them is not wrong, but
+ * it looks ugly.
+*/
+static void
+xmldata_root_element_start(StringInfo result, const char *eltname, const char *xmlschema, const char *targetns, bool top_level)
+{
+	/* This isn't really wrong but currently makes no sense. */
+	Assert(top_level || !xmlschema);
+
+	appendStringInfo(result, "<%s", eltname);
+	if (top_level)
+	{
+		appendStringInfoString(result, " xmlns:xsi=\"" NAMESPACE_XSI "\"");
+		if (strlen(targetns) > 0)
+			appendStringInfo(result, " xmlns=\"%s\"", targetns);
+	}
+	if (xmlschema)
+	{
+		/* FIXME: better targets */
+		if (strlen(targetns) > 0)
+			appendStringInfo(result, " xsi:schemaLocation=\"%s #\"", targetns);
+		else
+			appendStringInfo(result, " xsi:noNamespaceSchemaLocation=\"#\"");
+	}
+	appendStringInfo(result, ">\n\n");
+}
+
+
+static void
+xmldata_root_element_end(StringInfo result, const char *eltname)
+{
+	appendStringInfo(result, "</%s>\n", eltname);
+}
+
+
 static StringInfo
-query_to_xml_internal(const char *query, char *tablename, const char *xmlschema, bool nulls, bool tableforest, const char *targetns)
+query_to_xml_internal(const char *query, char *tablename, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
 {
 	StringInfo	result;
 	char	   *xmltn;
@@ -1744,30 +1900,16 @@ query_to_xml_internal(const char *query, char *tablename, const char *xmlschema,
 				 errmsg("invalid query")));
 
 	if (!tableforest)
-	{
-		appendStringInfo(result, "<%s xmlns:xsi=\"" NAMESPACE_XSI "\"", xmltn);
-		if (strlen(targetns) > 0)
-			appendStringInfo(result, " xmlns=\"%s\"", targetns);
-		if (strlen(targetns) > 0)
-			appendStringInfo(result, " xmlns:xsd=\"%s\"", targetns);
-		if (xmlschema)
-		{
-			if (strlen(targetns) > 0)
-				appendStringInfo(result, " xsi:schemaLocation=\"%s #\"", targetns);
-			else
-				appendStringInfo(result, " xsi:noNamespaceSchemaLocation=\"#\"");
-		}
-		appendStringInfo(result, ">\n\n");
-	}
+		xmldata_root_element_start(result, xmltn, xmlschema, targetns, top_level);
 
 	if (xmlschema)
 		appendStringInfo(result, "%s\n\n", xmlschema);
 
 	for(i = 0; i < SPI_processed; i++)
-		SPI_sql_row_to_xmlelement(i, result, tablename, nulls, tableforest, targetns);
+		SPI_sql_row_to_xmlelement(i, result, tablename, nulls, tableforest, targetns, top_level);
 
 	if (!tableforest)
-		appendStringInfo(result, "</%s>\n", xmltn);
+		xmldata_root_element_end(result, xmltn);
 
 	SPI_finish();
 
@@ -1861,7 +2003,7 @@ table_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
 	initStringInfo(&query);
 	appendStringInfo(&query, "SELECT * FROM %s", DatumGetCString(DirectFunctionCall1(regclassout, ObjectIdGetDatum(relid))));
 
-	PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query.data, get_rel_name(relid), xmlschema, nulls, tableforest, targetns)));
+	PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query.data, get_rel_name(relid), xmlschema, nulls, tableforest, targetns, true)));
 }
 
 
@@ -1884,7 +2026,302 @@ query_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
 	SPI_cursor_close(portal);
 	SPI_finish();
 
-	PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL, xmlschema, nulls, tableforest, targetns)));
+	PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL, xmlschema, nulls, tableforest, targetns, true)));
+}
+
+
+/*
+ * Map SQL schema to XML and/or XML Schema document; see SQL/XML:2003
+ * section 9.4.
+ */
+
+static StringInfo
+schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
+{
+	StringInfo	result;
+	char	   *xmlsn;
+	List	   *relid_list;
+	ListCell   *cell;
+
+	xmlsn = map_sql_identifier_to_xml_name(get_namespace_name(nspid), true, false);
+	result = makeStringInfo();
+
+	xmldata_root_element_start(result, xmlsn, xmlschema, targetns, top_level);
+
+	if (xmlschema)
+		appendStringInfo(result, "%s\n\n", xmlschema);
+
+	SPI_connect();
+
+	relid_list = schema_get_xml_visible_tables(nspid);
+
+	SPI_push();
+
+	foreach(cell, relid_list)
+	{
+		Oid relid = lfirst_oid(cell);
+		StringInfo subres;
+
+		subres = table_to_xml_internal(relid, nulls, tableforest, targetns, false);
+
+		appendStringInfoString(result, subres->data);
+		appendStringInfoChar(result, '\n');
+	}
+
+	SPI_pop();
+	SPI_finish();
+
+	xmldata_root_element_end(result, xmlsn);
+
+	return result;
+}
+
+
+Datum
+schema_to_xml(PG_FUNCTION_ARGS)
+{
+	Name		name = PG_GETARG_NAME(0);
+	bool		nulls = PG_GETARG_BOOL(1);
+	bool		tableforest = PG_GETARG_BOOL(2);
+	const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+
+	char	   *schemaname;
+	Oid			nspid;
+
+	schemaname = NameStr(*name);
+	nspid = LookupExplicitNamespace(schemaname);
+
+	PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xml_internal(nspid, NULL, nulls, tableforest, targetns, true)));
+}
+
+
+/*
+ * Write the start element of the root element of an XML Schema mapping.
+ */
+static void
+xsd_schema_element_start(StringInfo result, const char *targetns)
+{
+	appendStringInfoString(result,
+						   "<xsd:schema\n"
+						   "    xmlns:xsd=\"" NAMESPACE_XSD "\"");
+	if (strlen(targetns) > 0)
+		appendStringInfo(result,
+						 "\n"
+						 "    targetNamespace=\"%s\"\n"
+						 "    elementFormDefault=\"qualified\"",
+						 targetns);
+	appendStringInfoString(result,
+						   ">\n\n");
+}
+
+
+static void
+xsd_schema_element_end(StringInfo result)
+{
+	appendStringInfoString(result,
+						   "</xsd:schema>");
+}
+
+
+static StringInfo
+schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tableforest, const char *targetns)
+{
+	Oid			nspid;
+	List	   *relid_list;
+	List	   *tupdesc_list;
+	ListCell   *cell;
+	StringInfo	result;
+
+	result = makeStringInfo();
+
+	nspid = LookupExplicitNamespace(schemaname);
+
+	xsd_schema_element_start(result, targetns);
+
+	SPI_connect();
+
+	relid_list = schema_get_xml_visible_tables(nspid);
+
+	tupdesc_list = NIL;
+	foreach (cell, relid_list)
+	{
+		Relation rel;
+
+		rel = heap_open(lfirst_oid(cell), AccessShareLock);
+		tupdesc_list = lappend(tupdesc_list, rel->rd_att);
+		heap_close(rel, NoLock);
+	}
+
+	appendStringInfoString(result,
+						   map_sql_typecoll_to_xmlschema_types(tupdesc_list));
+
+	appendStringInfoString(result,
+						   map_sql_schema_to_xmlschema_types(nspid, relid_list, nulls, tableforest, targetns));
+
+	xsd_schema_element_end(result);
+
+	SPI_finish();
+
+	return result;
+}
+
+
+Datum
+schema_to_xmlschema(PG_FUNCTION_ARGS)
+{
+	Name		name = PG_GETARG_NAME(0);
+	bool		nulls = PG_GETARG_BOOL(1);
+	bool		tableforest = PG_GETARG_BOOL(2);
+	const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+
+	PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xmlschema_internal(NameStr(*name), nulls, tableforest, targetns)));
+}
+
+
+Datum
+schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
+{
+	Name		name = PG_GETARG_NAME(0);
+	bool		nulls = PG_GETARG_BOOL(1);
+	bool		tableforest = PG_GETARG_BOOL(2);
+	const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+
+	char	   *schemaname;
+	Oid			nspid;
+	StringInfo	xmlschema;
+
+	schemaname = NameStr(*name);
+	nspid = LookupExplicitNamespace(schemaname);
+
+	xmlschema = schema_to_xmlschema_internal(schemaname, nulls, tableforest, targetns);
+
+	PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xml_internal(nspid, xmlschema->data, nulls, tableforest, targetns, true)));
+}
+
+
+/*
+ * Map SQL database to XML and/or XML Schema document; see SQL/XML:2003
+ * section 9.5.
+ */
+
+static StringInfo
+database_to_xml_internal(const char *xmlschema, bool nulls, bool tableforest, const char *targetns)
+{
+	StringInfo	result;
+	List	   *nspid_list;
+	ListCell   *cell;
+	char	   *xmlcn;
+
+	xmlcn = map_sql_identifier_to_xml_name(get_database_name(MyDatabaseId), true, false);
+	result = makeStringInfo();
+
+	xmldata_root_element_start(result, xmlcn, xmlschema, targetns, true);
+
+	if (xmlschema)
+		appendStringInfo(result, "%s\n\n", xmlschema);
+
+	SPI_connect();
+
+	nspid_list = database_get_xml_visible_schemas();
+
+	SPI_push();
+
+	foreach(cell, nspid_list)
+	{
+		Oid nspid = lfirst_oid(cell);
+		StringInfo subres;
+
+		subres = schema_to_xml_internal(nspid, NULL, nulls, tableforest, targetns, false);
+
+		appendStringInfoString(result, subres->data);
+		appendStringInfoChar(result, '\n');
+	}
+
+	SPI_pop();
+	SPI_finish();
+
+	xmldata_root_element_end(result, xmlcn);
+
+	return result;
+}
+
+
+Datum
+database_to_xml(PG_FUNCTION_ARGS)
+{
+	bool		nulls = PG_GETARG_BOOL(0);
+	bool		tableforest = PG_GETARG_BOOL(1);
+	const char *targetns = _textout(PG_GETARG_TEXT_P(2));
+
+	PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xml_internal(NULL, nulls, tableforest, targetns)));
+}
+
+
+static StringInfo
+database_to_xmlschema_internal(bool nulls, bool tableforest, const char *targetns)
+{
+	List	   *relid_list;
+	List	   *nspid_list;
+	List	   *tupdesc_list;
+	ListCell   *cell;
+	StringInfo	result;
+
+	result = makeStringInfo();
+
+	xsd_schema_element_start(result, targetns);
+
+	SPI_connect();
+
+	relid_list = database_get_xml_visible_tables();
+	nspid_list = database_get_xml_visible_schemas();
+
+	tupdesc_list = NIL;
+	foreach (cell, relid_list)
+	{
+		Relation rel;
+
+		rel = heap_open(lfirst_oid(cell), AccessShareLock);
+		tupdesc_list = lappend(tupdesc_list, rel->rd_att);
+		heap_close(rel, NoLock);
+	}
+
+	appendStringInfoString(result,
+						   map_sql_typecoll_to_xmlschema_types(tupdesc_list));
+
+	appendStringInfoString(result,
+						   map_sql_catalog_to_xmlschema_types(nspid_list, nulls, tableforest, targetns));
+
+	xsd_schema_element_end(result);
+
+	SPI_finish();
+
+	return result;
+}
+
+
+Datum
+database_to_xmlschema(PG_FUNCTION_ARGS)
+{
+	bool		nulls = PG_GETARG_BOOL(0);
+	bool		tableforest = PG_GETARG_BOOL(1);
+	const char *targetns = _textout(PG_GETARG_TEXT_P(2));
+
+	PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xmlschema_internal(nulls, tableforest, targetns)));
+}
+
+
+Datum
+database_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
+{
+	bool		nulls = PG_GETARG_BOOL(0);
+	bool		tableforest = PG_GETARG_BOOL(1);
+	const char *targetns = _textout(PG_GETARG_TEXT_P(2));
+
+	StringInfo	xmlschema;
+
+	xmlschema = database_to_xmlschema_internal(nulls, tableforest, targetns);
+
+	PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xml_internal(xmlschema->data, nulls, tableforest, targetns)));
 }
 
 
@@ -1960,20 +2397,10 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
 		rowtypename = "RowType";
 	}
 
-	appendStringInfoString(&result,
-						   "<xsd:schema\n"
-						   "    xmlns:xsd=\"" NAMESPACE_XSD "\"");
-	if (strlen(targetns) > 0)
-		appendStringInfo(&result,
-						 "\n"
-						 "    targetNamespace=\"%s\"\n"
-						 "    elementFormDefault=\"qualified\"",
-						 targetns);
-	appendStringInfoString(&result,
-						   ">\n\n");
+	xsd_schema_element_start(&result, targetns);
 
 	appendStringInfoString(&result,
-						   map_sql_typecoll_to_xmlschema_types(tupdesc));
+						   map_sql_typecoll_to_xmlschema_types(list_make1(tupdesc)));
 
 	appendStringInfo(&result,
 					 "<xsd:complexType name=\"%s\">\n"
@@ -2010,8 +2437,126 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
 						 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
 						 xmltn, rowtypename);
 
+	xsd_schema_element_end(&result);
+
+	return result.data;
+}
+
+
+/*
+ * Map an SQL schema to XML Schema data types; see SQL/XML section
+ * 9.7.
+ */
+static const char *
+map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool tableforest, const char *targetns)
+{
+	char	   *xmlsn;
+	char	   *schematypename;
+	StringInfoData result;
+	ListCell   *cell;
+
+	initStringInfo(&result);
+
+	xmlsn = map_sql_identifier_to_xml_name(get_namespace_name(nspid), true, false);
+
+	schematypename = map_multipart_sql_identifier_to_xml_name("SchemaType",
+															  get_database_name(MyDatabaseId),
+															  get_namespace_name(nspid),
+															  NULL);
+
+	appendStringInfo(&result,
+					 "<xsd:complexType name=\"%s\">\n", schematypename);
+	if (!tableforest)
+		appendStringInfoString(&result,
+							   "  <xsd:all>\n");
+	else
+		appendStringInfoString(&result,
+							   "  <xsd:sequence>\n");
+
+	foreach (cell, relid_list)
+	{
+		Oid relid = lfirst_oid(cell);
+		char *xmltn = map_sql_identifier_to_xml_name(get_rel_name(relid), true, false);
+		char *tabletypename = map_multipart_sql_identifier_to_xml_name(tableforest ? "RowType" : "TableType",
+																	   get_database_name(MyDatabaseId),
+																	   get_namespace_name(nspid),
+																	   get_rel_name(relid));
+
+		if (!tableforest)
+			appendStringInfo(&result,
+							 "    <xsd:element name=\"%s\" type=\"%s\" />\n",
+							 xmltn, tabletypename);
+		else
+			appendStringInfo(&result,
+							 "    <xsd:element name=\"%s\" type=\"%s\" minOccurs=\"0\" maxOccurs=\"unbounded\" />\n",
+							 xmltn, tabletypename);
+	}
+
+	if (!tableforest)
+		appendStringInfoString(&result,
+							   "  </xsd:all>\n");
+	else
+		appendStringInfoString(&result,
+							   "  </xsd:sequence>\n");
 	appendStringInfoString(&result,
-						   "</xsd:schema>");
+						   "</xsd:complexType>\n\n");
+
+	appendStringInfo(&result,
+					 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
+					 xmlsn, schematypename);
+
+	return result.data;
+}
+
+
+/*
+ * Map an SQL catalog to XML Schema data types; see SQL/XML section
+ * 9.8.
+ */
+static const char *
+map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tableforest, const char *targetns)
+{
+	char	   *xmlcn;
+	char	   *catalogtypename;
+	StringInfoData result;
+	ListCell   *cell;
+
+	initStringInfo(&result);
+
+	xmlcn = map_sql_identifier_to_xml_name(get_database_name(MyDatabaseId), true, false);
+
+	catalogtypename = map_multipart_sql_identifier_to_xml_name("CatalogType",
+															   get_database_name(MyDatabaseId),
+															   NULL,
+															   NULL);
+
+	appendStringInfo(&result,
+					 "<xsd:complexType name=\"%s\">\n", catalogtypename);
+	appendStringInfoString(&result,
+						   "  <xsd:all>\n");
+
+	foreach (cell, nspid_list)
+	{
+		Oid nspid = lfirst_oid(cell);
+		char *xmlsn = map_sql_identifier_to_xml_name(get_namespace_name(nspid), true, false);
+		char *schematypename = map_multipart_sql_identifier_to_xml_name("SchemaType",
+																		get_database_name(MyDatabaseId),
+																		get_namespace_name(nspid),
+																		NULL);
+
+		appendStringInfo(&result,
+						 "    <xsd:element name=\"%s\" type=\"%s\" />\n",
+						 xmlsn, schematypename);
+	}
+
+	appendStringInfoString(&result,
+						   "  </xsd:all>\n");
+	appendStringInfoString(&result,
+						   "</xsd:complexType>\n\n");
+
+	appendStringInfo(&result,
+					 "<xsd:element name=\"%s\" type=\"%s\"/>\n\n",
+					 xmlcn, catalogtypename);
 
 	return result.data;
 }
@@ -2121,41 +2666,41 @@ map_sql_type_to_xml_name(Oid typeoid, int typmod)
  * SQL/XML:2002 section 9.10.
  */
 static const char *
-map_sql_typecoll_to_xmlschema_types(TupleDesc tupdesc)
+map_sql_typecoll_to_xmlschema_types(List *tupdesc_list)
 {
-	Oid		   *uniquetypes;
-	int			i, j;
-	int			len;
+	List	   *uniquetypes = NIL;
+	int			i;
 	StringInfoData result;
+	ListCell   *cell0, *cell1, *cell2;
 
-	initStringInfo(&result);
-
-	uniquetypes = palloc(2 * sizeof(*uniquetypes) * tupdesc->natts);
-	len = 0;
-
-	for (i = 1; i <= tupdesc->natts; i++)
+	foreach (cell0, tupdesc_list)
 	{
-		bool already_done = false;
-		Oid type = SPI_gettypeid(tupdesc, i);
-		for (j = 0; j < len; j++)
-			if (type == uniquetypes[j])
-			{
-				already_done = true;
-				break;
-			}
-		if (already_done)
-			continue;
+		TupleDesc tupdesc = lfirst(cell0);
+
+		for (i = 1; i <= tupdesc->natts; i++)
+		{
+			bool already_done = false;
+			Oid type = SPI_gettypeid(tupdesc, i);
+			foreach (cell1, uniquetypes)
+				if (type == lfirst_oid(cell1))
+				{
+					already_done = true;
+					break;
+				}
+			if (already_done)
+				continue;
 
-		uniquetypes[len++] = type;
+			uniquetypes = lappend_oid(uniquetypes, type);
+		}
 	}
 
 	/* add base types of domains */
-	for (i = 0; i < len; i++)
+	foreach (cell1, uniquetypes)
 	{
 		bool already_done = false;
-		Oid type = getBaseType(uniquetypes[i]);
-		for (j = 0; j < len; j++)
-			if (type == uniquetypes[j])
+		Oid type = getBaseType(lfirst_oid(cell1));
+		foreach (cell2, uniquetypes)
+			if (type == lfirst_oid(cell2))
 			{
 				already_done = true;
 				break;
@@ -2163,11 +2708,13 @@ map_sql_typecoll_to_xmlschema_types(TupleDesc tupdesc)
 		if (already_done)
 			continue;
 
-		uniquetypes[len++] = type;
+		uniquetypes = lappend_oid(uniquetypes, type);
 	}
 
-	for (i = 0; i < len; i++)
-		appendStringInfo(&result, "%s\n", map_sql_type_to_xmlschema_type(uniquetypes[i], -1));
+	initStringInfo(&result);
+
+	foreach (cell1, uniquetypes)
+		appendStringInfo(&result, "%s\n", map_sql_type_to_xmlschema_type(lfirst_oid(cell1), -1));
 
 	return result.data;
 }
@@ -2178,7 +2725,7 @@ map_sql_typecoll_to_xmlschema_types(TupleDesc tupdesc)
  * sections 9.11 and 9.15.
  *
  * (The distinction between 9.11 and 9.15 is basically that 9.15 adds
- * a name attribute, which thsi function does.  The name-less version
+ * a name attribute, which this function does.  The name-less version
  * 9.11 doesn't appear to be required anywhere.)
  */
 static const char *
@@ -2355,7 +2902,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
  * SPI cursor.  See also SQL/XML:2003 section 9.12.
  */
 static void
-SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool nulls, bool tableforest, const char *targetns)
+SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool nulls, bool tableforest, const char *targetns, bool top_level)
 {
 	int			i;
 	char	   *xmltn;
@@ -2371,12 +2918,7 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
 	}
 
 	if (tableforest)
-	{
-		appendStringInfo(result, "<%s xmlns:xsi=\"" NAMESPACE_XSI "\"", xmltn);
-		if (strlen(targetns) > 0)
-			appendStringInfo(result, " xmlns=\"%s\"", targetns);
-		appendStringInfo(result, ">\n");
-	}
+		xmldata_root_element_start(result, xmltn, NULL, targetns, top_level);
 	else
 		appendStringInfoString(result, "<row>\n");
 
@@ -2402,7 +2944,10 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
 	}
 
 	if (tableforest)
-		appendStringInfo(result, "</%s>\n\n", xmltn);
+	{
+		xmldata_root_element_end(result, xmltn);
+		appendStringInfoChar(result, '\n');
+	}
 	else
 		appendStringInfoString(result, "</row>\n\n");
 }
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 713d76fbfaccc13a47e104665f04ba1cb54446a4..252d7460ac7658d18839f84deea29480f6f9b45c 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.452 2007/03/30 18:34:56 mha Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.453 2007/04/01 09:00:25 petere Exp $
  *
  * NOTES
  *	  The script catalog/genbki.sh reads this file and generates .bki
@@ -4100,6 +4100,20 @@ DESCR("map table contents and structure to XML and XML Schema");
 DATA(insert OID = 2930 (  query_to_xml_and_xmlschema  PGNSP PGUID 12 100 0 f f t f s 4 142 "25 16 16 25" _null_ _null_ "{query,nulls,tableforest,targetns}" query_to_xml_and_xmlschema - _null_ ));
 DESCR("map query result and structure to XML and XML Schema");
 
+DATA(insert OID = 2933 (  schema_to_xml               PGNSP PGUID 12 100 0 f f t f s 4 142 "19 16 16 25" _null_ _null_ "{schema,nulls,tableforest,targetns}" schema_to_xml - _null_ ));
+DESCR("map schema contents to XML");
+DATA(insert OID = 2934 (  schema_to_xmlschema         PGNSP PGUID 12 100 0 f f t f s 4 142 "19 16 16 25" _null_ _null_ "{schema,nulls,tableforest,targetns}" schema_to_xmlschema - _null_ ));
+DESCR("map schema structure to XML Schema");
+DATA(insert OID = 2935 (  schema_to_xml_and_xmlschema PGNSP PGUID 12 100 0 f f t f s 4 142 "19 16 16 25" _null_ _null_ "{schema,nulls,tableforest,targetns}" schema_to_xml_and_xmlschema - _null_ ));
+DESCR("map schema contents and structure to XML and XML Schema");
+
+DATA(insert OID = 2936 (  database_to_xml             PGNSP PGUID 12 100 0 f f t f s 3 142 "16 16 25" _null_ _null_ "{nulls,tableforest,targetns}" database_to_xml - _null_ ));
+DESCR("map database contents to XML");
+DATA(insert OID = 2937 (  database_to_xmlschema       PGNSP PGUID 12 100 0 f f t f s 3 142 "16 16 25" _null_ _null_ "{nulls,tableforest,targetns}" database_to_xmlschema - _null_ ));
+DESCR("map database structure to XML Schema");
+DATA(insert OID = 2938 (  database_to_xml_and_xmlschema PGNSP PGUID 12 100 0 f f t f s 3 142 "16 16 25" _null_ _null_ "{nulls,tableforest,targetns}" database_to_xml_and_xmlschema - _null_ ));
+DESCR("map database contents and structure to XML and XML Schema");
+
 DATA(insert OID = 2931 (  xmlpath      PGNSP PGUID 12 1 0 f f f f i 3 143 "25 142 1009" _null_ _null_ _null_ xmlpath - _null_ ));
 DESCR("evaluate XPath expression, with namespaces support");
 DATA(insert OID = 2932 (  xmlpath      PGNSP PGUID 14 1 0 f f f f i 2 143 "25 142" _null_ _null_ _null_ "select pg_catalog.xmlpath($1, $2, NULL)" - _null_ ));
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index ef06e41b92bfc8e6070e48b25a68be6fbc3b5ef2..15ba500d5078654eb8b66a984ceca67e1083138b 100644
--- a/src/include/utils/xml.h
+++ b/src/include/utils/xml.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.17 2007/03/22 20:14:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.18 2007/04/01 09:00:26 petere Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,6 +47,14 @@ extern Datum cursor_to_xmlschema(PG_FUNCTION_ARGS);
 extern Datum table_to_xml_and_xmlschema(PG_FUNCTION_ARGS);
 extern Datum query_to_xml_and_xmlschema(PG_FUNCTION_ARGS);
 
+extern Datum schema_to_xml(PG_FUNCTION_ARGS);
+extern Datum schema_to_xmlschema(PG_FUNCTION_ARGS);
+extern Datum schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS);
+
+extern Datum database_to_xml(PG_FUNCTION_ARGS);
+extern Datum database_to_xmlschema(PG_FUNCTION_ARGS);
+extern Datum database_to_xml_and_xmlschema(PG_FUNCTION_ARGS);
+
 typedef enum
 {
 	XML_STANDALONE_YES,