OSDN Git Service

Some code review for xml.c:
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 6 Nov 2007 03:06:28 +0000 (03:06 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 6 Nov 2007 03:06:28 +0000 (03:06 +0000)
Add some more xml_init() calls that might not be necessary, but seem like a
good idea to avoid possible problems like we saw in xmlelement().
Fix unsafe assumption that you can keep using the tupledesc of a relcache
entry you don't have open.
Add missing error checks for SearchSysCache failure.
Get rid of handwritten array traversal in xpath() and O(N^2), broken-for-nulls
array access code in map_sql_value_to_xml_value(), in favor of using
deconstruct_array.
Manually adjust a lot of line breaks in places where the code is otherwise
gonna look pretty awful after pg_indent hacks it up (original author seems to
have liked to lay out code for a 200-column window).

src/backend/utils/adt/xml.c

index 5f5654c..9e9d0e1 100644 (file)
@@ -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.50 2007/11/05 22:23:07 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.51 2007/11/06 03:06:28 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -86,27 +86,38 @@ static void    *xml_palloc(size_t size);
 static void    *xml_repalloc(void *ptr, size_t size);
 static void    xml_pfree(void *ptr);
 static char    *xml_pstrdup(const char *string);
-static void    xml_ereport(int level, int sqlcode,
-                                                       const char *msg);
+static void    xml_ereport(int level, int sqlcode, const char *msg);
 static void    xml_errorHandler(void *ctxt, const char *msg, ...);
 static void    xml_ereport_by_code(int level, int sqlcode,
                                                                        const char *msg, int errcode);
 static xmlChar *xml_text2xmlChar(text *in);
-static int             parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **encoding, int *standalone);
-static bool            print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone);
-static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding);
+static int             parse_xml_decl(const xmlChar *str, size_t *lenp,
+                                                          xmlChar **version, xmlChar **encoding, int *standalone);
+static bool            print_xml_decl(StringInfo buf, const xmlChar *version,
+                                                          pg_enc encoding, int standalone);
+static xmlDocPtr xml_parse(text *data, XmlOptionType xmloption_arg,
+                                                  bool preserve_whitespace, xmlChar *encoding);
 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, 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 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(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, bool top_level);
+static void SPI_sql_row_to_xmlelement(int rownum, StringInfo result,
+                                                 char *tablename, bool nulls, bool tableforest,
+                                                 const char *targetns, bool top_level);
 
 #define NO_XML_SUPPORT() \
        ereport(ERROR, \
@@ -194,7 +205,8 @@ xml_out_internal(xmltype *x, pg_enc target_encoding)
        str[len] = '\0';
 
 #ifdef USE_LIBXML
-       if ((res_code = parse_xml_decl((xmlChar *) str, &len, &version, &encoding, &standalone)) == 0)
+       if ((res_code = parse_xml_decl((xmlChar *) str,
+                                                                  &len, &version, &encoding, &standalone)) == 0)
        {
                StringInfoData buf;
 
@@ -388,17 +400,23 @@ xmlcomment(PG_FUNCTION_ARGS)
 {
 #ifdef USE_LIBXML
        text *arg = PG_GETARG_TEXT_P(0);
+       char *argdata = VARDATA(arg);
        int len =  VARSIZE(arg) - VARHDRSZ;
        StringInfoData buf;
        int i;
 
        /* check for "--" in string or "-" at the end */
        for (i = 1; i < len; i++)
-               if ((VARDATA(arg)[i] == '-' && VARDATA(arg)[i - 1] == '-')
-                       || (VARDATA(arg)[i] == '-' && i == len - 1))
-                                       ereport(ERROR,
-                                                       (errcode(ERRCODE_INVALID_XML_COMMENT),
-                                                        errmsg("invalid XML comment")));
+       {
+               if (argdata[i] == '-' && argdata[i - 1] == '-')
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_INVALID_XML_COMMENT),
+                                        errmsg("invalid XML comment")));
+       }
+       if (len > 0 && argdata[len - 1] == '-')
+               ereport(ERROR,
+                               (errcode(ERRCODE_INVALID_XML_COMMENT),
+                                errmsg("invalid XML comment")));
 
        initStringInfo(&buf);
        appendStringInfo(&buf, "<!--");
@@ -422,20 +440,19 @@ xmltype *
 xmlconcat(List *args)
 {
 #ifdef USE_LIBXML
-       StringInfoData buf;
-       ListCell   *v;
-
        int                     global_standalone = 1;
        xmlChar    *global_version = NULL;
        bool            global_version_no_value = false;
+       StringInfoData buf;
+       ListCell   *v;
 
        initStringInfo(&buf);
        foreach(v, args)
        {
+               xmltype    *x = DatumGetXmlP(PointerGetDatum(lfirst(v)));
                size_t          len;
                xmlChar    *version;
                int                     standalone;
-               xmltype    *x = DatumGetXmlP(PointerGetDatum(lfirst(v)));
                char       *str;
 
                len = VARSIZE(x) - VARHDRSZ;
@@ -468,7 +485,7 @@ xmlconcat(List *args)
                initStringInfo(&buf2);
 
                print_xml_decl(&buf2,
-                                          (!global_version_no_value && global_version) ? global_version : NULL,
+                                          (!global_version_no_value) ? global_version : NULL,
                                           0,
                                           global_standalone);
 
@@ -500,7 +517,8 @@ xmlconcat2(PG_FUNCTION_ARGS)
        else if (PG_ARGISNULL(1))
                PG_RETURN_XML_P(PG_GETARG_XML_P(0));
        else
-               PG_RETURN_XML_P(xmlconcat(list_make2(PG_GETARG_XML_P(0), PG_GETARG_XML_P(1))));
+               PG_RETURN_XML_P(xmlconcat(list_make2(PG_GETARG_XML_P(0),
+                                                                                        PG_GETARG_XML_P(1))));
 }
 
 
@@ -680,8 +698,7 @@ xmlpi(char *target, text *arg, bool arg_is_null, bool *result_is_null)
        {
                char *string;
 
-               string = DatumGetCString(DirectFunctionCall1(textout,
-                                                                                                        PointerGetDatum(arg)));
+               string = _textout(arg);
                if (strstr(string, "?>") != NULL)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
@@ -971,17 +988,24 @@ xml_init(void)
  * to complete this.
  */
 
-#define CHECK_XML_SPACE(p) if (!xmlIsBlank_ch(*(p))) return XML_ERR_SPACE_REQUIRED
-#define SKIP_XML_SPACE(p) while (xmlIsBlank_ch(*(p))) (p)++
+#define CHECK_XML_SPACE(p) \
+       do { \
+               if (!xmlIsBlank_ch(*(p))) \
+                       return XML_ERR_SPACE_REQUIRED; \
+       } while (0)
+
+#define SKIP_XML_SPACE(p) \
+       while (xmlIsBlank_ch(*(p))) (p)++
 
 static int
-parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **encoding, int *standalone)
+parse_xml_decl(const xmlChar *str,size_t *lenp,
+                          xmlChar **version, xmlChar **encoding, int *standalone)
 {
        const xmlChar *p;
        const xmlChar *save_p;
        size_t          len;
 
-       p = str;
+       xml_init();
 
        if (version)
                *version = NULL;
@@ -990,6 +1014,8 @@ parse_xml_decl(const xmlChar *str, size_t *lenp, xmlChar **version, xmlChar **en
        if (standalone)
                *standalone = -1;
 
+       p = str;
+
        if (xmlStrncmp(p, (xmlChar *)"<?xml", 5) != 0)
                goto finished;
 
@@ -1119,8 +1145,11 @@ finished:
  * which is the default version specified in SQL:2003.
  */
 static bool
-print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int standalone)
+print_xml_decl(StringInfo buf, const xmlChar *version,
+                          pg_enc encoding, int standalone)
 {
+       xml_init();
+
        if ((version && strcmp((char *) version, PG_XML_DEFAULT_VERSION) != 0)
                || (encoding && encoding != PG_UTF8)
                || standalone != -1)
@@ -1133,11 +1162,14 @@ print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int stan
                        appendStringInfo(buf, " version=\"%s\"", PG_XML_DEFAULT_VERSION);
 
                if (encoding && encoding != PG_UTF8)
+               {
                        /*
                         * XXX might be useful to convert this to IANA names
                         * (ISO-8859-1 instead of LATIN1 etc.); needs field experience
                         */
-                       appendStringInfo(buf, " encoding=\"%s\"", pg_encoding_to_char(encoding));
+                       appendStringInfo(buf, " encoding=\"%s\"",
+                                                        pg_encoding_to_char(encoding));
+               }
 
                if (standalone == 1)
                        appendStringInfoString(buf, " standalone=\"yes\"");
@@ -1155,10 +1187,12 @@ print_xml_decl(StringInfo buf, const xmlChar *version, pg_enc encoding, int stan
 /*
  * Convert a C string to XML internal representation
  *
- * TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c)
+ * TODO maybe, libxml2's xmlreader is better? (do not construct DOM,
+ * yet do not use SAX - see xml_reader.c)
  */
 static xmlDocPtr
-xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace, xmlChar *encoding)
+xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
+                 xmlChar *encoding)
 {
        int32                           len;
        xmlChar                         *string;
@@ -1305,8 +1339,7 @@ xml_pstrdup(const char *string)
  * any, as detail.
  */
 static void
-xml_ereport(int level, int sqlcode,
-                       const char *msg)
+xml_ereport(int level, int sqlcode, const char *msg)
 {
        char *detail;
 
@@ -1458,7 +1491,8 @@ is_valid_xml_namechar(pg_wchar c)
  * Map SQL identifier to XML name; see SQL/XML:2003 section 9.1.
  */
 char *
-map_sql_identifier_to_xml_name(char *ident, bool fully_escaped, bool escape_period)
+map_sql_identifier_to_xml_name(char *ident, bool fully_escaped,
+                                                          bool escape_period)
 {
 #ifdef USE_LIBXML
        StringInfoData buf;
@@ -1592,36 +1626,38 @@ map_sql_value_to_xml_value(Datum value, Oid type)
 
        if (type_is_array(type))
        {
-               int i;
                ArrayType *array;
                Oid elmtype;
                int16 elmlen;
                bool elmbyval;
                char elmalign;
+               int                     num_elems;
+               Datum      *elem_values;
+               bool       *elem_nulls;
+               int i;
 
                array = DatumGetArrayTypeP(value);
-
-               /* TODO: need some code-fu here to remove this limitation */
-               if (ARR_NDIM(array) != 1)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                                        errmsg("only supported for one-dimensional array")));
-
                elmtype = ARR_ELEMTYPE(array);
                get_typlenbyvalalign(elmtype, &elmlen, &elmbyval, &elmalign);
 
-               for (i = ARR_LBOUND(array)[0];
-                        i < ARR_LBOUND(array)[0] + ARR_DIMS(array)[0];
-                        i++)
-               {
-                       Datum subval;
-                       bool isnull;
+               deconstruct_array(array, elmtype,
+                                                 elmlen, elmbyval, elmalign,
+                                                 &elem_values, &elem_nulls,
+                                                 &num_elems);
 
-                       subval = array_ref(array, 1, &i, -1, elmlen, elmbyval, elmalign, &isnull);
+               for (i = 0; i < num_elems; i++)
+               {
+                       if (elem_nulls[i])
+                               continue;
                        appendStringInfoString(&buf, "<element>");
-                       appendStringInfoString(&buf, map_sql_value_to_xml_value(subval, elmtype));
+                       appendStringInfoString(&buf,
+                                                                  map_sql_value_to_xml_value(elem_values[i],
+                                                                                                                         elmtype));
                        appendStringInfoString(&buf, "</element>");
                }
+
+               pfree(elem_values);
+               pfree(elem_nulls);
        }
        else
        {
@@ -1719,6 +1755,8 @@ map_sql_value_to_xml_value(Datum value, Oid type)
                        xmlTextWriterPtr writer;
                        char *result;
 
+                       xml_init();
+
                        buf = xmlBufferCreate();
                        writer = xmlNewTextWriterMemory(buf, 0);
 
@@ -1825,13 +1863,15 @@ query_to_oid_list(const char *query)
 
        for (i = 0; i < SPI_processed; i++)
        {
-               Oid oid;
+               Datum oid;
                bool isnull;
 
-               oid = DatumGetObjectId(SPI_getbinval(SPI_tuptable->vals[i], SPI_tuptable->tupdesc, 1, &isnull));
-               if (isnull)
-                       continue;
-               list = lappend_oid(list, oid);
+               oid = SPI_getbinval(SPI_tuptable->vals[i],
+                                                       SPI_tuptable->tupdesc,
+                                                       1,
+                                                       &isnull);
+               if (!isnull)
+                       list = lappend_oid(list, DatumGetObjectId(oid));
        }
 
        return list;
@@ -1854,9 +1894,9 @@ schema_get_xml_visible_tables(Oid nspid)
  * 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_EXCLUDE "(nspname ~ '^pg_' OR nspname = 'information_schema')"
 
-#define XML_VISIBLE_SCHEMAS "SELECT oid FROM pg_catalog.pg_namespace WHERE pg_catalog.has_schema_privilege (oid, 'USAGE') AND NOT (" XML_VISIBLE_SCHEMAS_EXCLUDE ")"
+#define XML_VISIBLE_SCHEMAS "SELECT oid FROM pg_catalog.pg_namespace WHERE pg_catalog.has_schema_privilege (oid, 'USAGE') AND NOT " XML_VISIBLE_SCHEMAS_EXCLUDE
 
 
 static List *
@@ -1880,13 +1920,19 @@ database_get_xml_visible_tables(void)
  */
 
 static StringInfo
-table_to_xml_internal(Oid relid, bool nulls, bool tableforest, const char *targetns, bool top_level)
+table_to_xml_internal(Oid relid,
+                                         const char *xmlschema, 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);
+       appendStringInfo(&query, "SELECT * FROM %s",
+                                        DatumGetCString(DirectFunctionCall1(regclassout,
+                                                                                               ObjectIdGetDatum(relid))));
+       return query_to_xml_internal(query.data, get_rel_name(relid),
+                                                                xmlschema, nulls, tableforest,
+                                                                targetns, top_level);
 }
 
 
@@ -1898,7 +1944,9 @@ table_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(table_to_xml_internal(relid, nulls, tableforest, targetns, true)));
+       PG_RETURN_XML_P(stringinfo_to_xmltype(table_to_xml_internal(relid, NULL,
+                                                                                                               nulls, tableforest,
+                                                                                                               targetns, true)));
 }
 
 
@@ -1910,7 +1958,9 @@ 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, true)));
+       PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL,
+                                                                                                       NULL, nulls, tableforest,
+                                                                                                       targetns, true)));
 }
 
 
@@ -1938,7 +1988,8 @@ 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, true);
+               SPI_sql_row_to_xmlelement(i, &result, NULL, nulls,
+                                                                 tableforest, targetns, true);
 
        SPI_finish();
 
@@ -1957,9 +2008,11 @@ cursor_to_xml(PG_FUNCTION_ARGS)
  * 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)
+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);
@@ -1991,7 +2044,9 @@ xmldata_root_element_end(StringInfo result, const char *eltname)
 
 
 static StringInfo
-query_to_xml_internal(const char *query, char *tablename, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
+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;
@@ -2011,13 +2066,15 @@ query_to_xml_internal(const char *query, char *tablename, const char *xmlschema,
                                 errmsg("invalid query")));
 
        if (!tableforest)
-               xmldata_root_element_start(result, xmltn, xmlschema, targetns, top_level);
+               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, top_level);
+               SPI_sql_row_to_xmlelement(i, result, tablename, nulls,
+                                                                 tableforest, targetns, top_level);
 
        if (!tableforest)
                xmldata_root_element_end(result, xmltn);
@@ -2035,12 +2092,12 @@ table_to_xmlschema(PG_FUNCTION_ARGS)
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
        const char *targetns = _textout(PG_GETARG_TEXT_P(3));
-
        const char *result;
        Relation rel;
 
        rel = heap_open(relid, AccessShareLock);
-       result = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls, tableforest, targetns);
+       result = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls,
+                                                                               tableforest, targetns);
        heap_close(rel, NoLock);
 
        PG_RETURN_XML_P(cstring_to_xmltype(result));
@@ -2054,7 +2111,6 @@ query_to_xmlschema(PG_FUNCTION_ARGS)
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
        const char *targetns = _textout(PG_GETARG_TEXT_P(3));
-
        const char *result;
        SPIPlanPtr      plan;
        Portal          portal;
@@ -2062,7 +2118,9 @@ query_to_xmlschema(PG_FUNCTION_ARGS)
        SPI_connect();
        plan = SPI_prepare(query, 0, NULL);
        portal = SPI_cursor_open(NULL, plan, NULL, NULL, true);
-       result = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc, InvalidOid, nulls, tableforest, targetns));
+       result = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc,
+                                                                                                       InvalidOid, nulls,
+                                                                                                       tableforest, targetns));
        SPI_cursor_close(portal);
        SPI_finish();
 
@@ -2077,7 +2135,6 @@ cursor_to_xmlschema(PG_FUNCTION_ARGS)
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
        const char *targetns = _textout(PG_GETARG_TEXT_P(3));
-
        const char *xmlschema;
        Portal          portal;
 
@@ -2088,7 +2145,9 @@ cursor_to_xmlschema(PG_FUNCTION_ARGS)
                                (errcode(ERRCODE_UNDEFINED_CURSOR),
                                 errmsg("cursor \"%s\" does not exist", name)));
 
-       xmlschema = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc, InvalidOid, nulls, tableforest, targetns));
+       xmlschema = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc,
+                                                                                                          InvalidOid, nulls,
+                                                                                                          tableforest, targetns));
        SPI_finish();
 
        PG_RETURN_XML_P(cstring_to_xmltype(xmlschema));
@@ -2102,19 +2161,17 @@ table_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
        const char *targetns = _textout(PG_GETARG_TEXT_P(3));
-
-       StringInfoData query;
        Relation        rel;
        const char *xmlschema;
 
        rel = heap_open(relid, AccessShareLock);
-       xmlschema = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls, tableforest, targetns);
+       xmlschema = map_sql_table_to_xmlschema(rel->rd_att, relid, nulls,
+                                                                                  tableforest, targetns);
        heap_close(rel, NoLock);
 
-       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, true)));
+       PG_RETURN_XML_P(stringinfo_to_xmltype(table_to_xml_internal(relid,
+                                                                                       xmlschema, nulls, tableforest,
+                                                                                       targetns, true)));
 }
 
 
@@ -2133,11 +2190,14 @@ query_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
        SPI_connect();
        plan = SPI_prepare(query, 0, NULL);
        portal = SPI_cursor_open(NULL, plan, NULL, NULL, true);
-       xmlschema = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc, InvalidOid, nulls, tableforest, targetns));
+       xmlschema = _SPI_strdup(map_sql_table_to_xmlschema(portal->tupDesc,
+                                                                  InvalidOid, nulls, tableforest, targetns));
        SPI_cursor_close(portal);
        SPI_finish();
 
-       PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL, xmlschema, nulls, tableforest, targetns, true)));
+       PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL,
+                                                                       xmlschema, nulls, tableforest,
+                                                                       targetns, true)));
 }
 
 
@@ -2147,14 +2207,16 @@ query_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
  */
 
 static StringInfo
-schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, bool tableforest, const char *targetns, bool top_level)
+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);
+       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);
@@ -2173,7 +2235,8 @@ schema_to_xml_internal(Oid nspid, const char *xmlschema, bool nulls, bool tablef
                Oid relid = lfirst_oid(cell);
                StringInfo subres;
 
-               subres = table_to_xml_internal(relid, nulls, tableforest, targetns, false);
+               subres = table_to_xml_internal(relid, NULL, nulls, tableforest,
+                                                                          targetns, false);
 
                appendStringInfoString(result, subres->data);
                appendStringInfoChar(result, '\n');
@@ -2202,7 +2265,8 @@ schema_to_xml(PG_FUNCTION_ARGS)
        schemaname = NameStr(*name);
        nspid = LookupExplicitNamespace(schemaname);
 
-       PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xml_internal(nspid, NULL, nulls, tableforest, targetns, true)));
+       PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xml_internal(nspid, NULL,
+                                                                                nulls, tableforest, targetns, true)));
 }
 
 
@@ -2229,13 +2293,13 @@ xsd_schema_element_start(StringInfo result, const char *targetns)
 static void
 xsd_schema_element_end(StringInfo result)
 {
-       appendStringInfoString(result,
-                                                  "</xsd:schema>");
+       appendStringInfoString(result, "</xsd:schema>");
 }
 
 
 static StringInfo
-schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tableforest, const char *targetns)
+schema_to_xmlschema_internal(const char *schemaname, bool nulls,
+                                                        bool tableforest, const char *targetns)
 {
        Oid                     nspid;
        List       *relid_list;
@@ -2259,7 +2323,7 @@ schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tablefores
                Relation rel;
 
                rel = heap_open(lfirst_oid(cell), AccessShareLock);
-               tupdesc_list = lappend(tupdesc_list, rel->rd_att);
+               tupdesc_list = lappend(tupdesc_list, CreateTupleDescCopy(rel->rd_att));
                heap_close(rel, NoLock);
        }
 
@@ -2267,7 +2331,8 @@ schema_to_xmlschema_internal(const char *schemaname, bool nulls, bool tablefores
                                                   map_sql_typecoll_to_xmlschema_types(tupdesc_list));
 
        appendStringInfoString(result,
-                                                  map_sql_schema_to_xmlschema_types(nspid, relid_list, nulls, tableforest, targetns));
+                                                  map_sql_schema_to_xmlschema_types(nspid, relid_list,
+                                                                                                                        nulls, tableforest, targetns));
 
        xsd_schema_element_end(result);
 
@@ -2285,7 +2350,8 @@ schema_to_xmlschema(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(schema_to_xmlschema_internal(NameStr(*name), nulls, tableforest, targetns)));
+       PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xmlschema_internal(NameStr(*name),
+                                                                                          nulls, tableforest, targetns)));
 }
 
 
@@ -2296,7 +2362,6 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
        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;
@@ -2304,9 +2369,12 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
        schemaname = NameStr(*name);
        nspid = LookupExplicitNamespace(schemaname);
 
-       xmlschema = schema_to_xmlschema_internal(schemaname, nulls, tableforest, targetns);
+       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)));
+       PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xml_internal(nspid,
+                                                                                        xmlschema->data, nulls,
+                                                                                        tableforest, targetns, true)));
 }
 
 
@@ -2316,14 +2384,16 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
  */
 
 static StringInfo
-database_to_xml_internal(const char *xmlschema, bool nulls, bool tableforest, const char *targetns)
+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);
+       xmlcn = map_sql_identifier_to_xml_name(get_database_name(MyDatabaseId),
+                                                                                  true, false);
        result = makeStringInfo();
 
        xmldata_root_element_start(result, xmlcn, xmlschema, targetns, true);
@@ -2342,7 +2412,8 @@ database_to_xml_internal(const char *xmlschema, bool nulls, bool tableforest, co
                Oid nspid = lfirst_oid(cell);
                StringInfo subres;
 
-               subres = schema_to_xml_internal(nspid, NULL, nulls, tableforest, targetns, false);
+               subres = schema_to_xml_internal(nspid, NULL, nulls,
+                                                                               tableforest, targetns, false);
 
                appendStringInfoString(result, subres->data);
                appendStringInfoChar(result, '\n');
@@ -2364,12 +2435,14 @@ database_to_xml(PG_FUNCTION_ARGS)
        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)));
+       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)
+database_to_xmlschema_internal(bool nulls, bool tableforest,
+                                                          const char *targetns)
 {
        List       *relid_list;
        List       *nspid_list;
@@ -2392,7 +2465,7 @@ database_to_xmlschema_internal(bool nulls, bool tableforest, const char *targetn
                Relation rel;
 
                rel = heap_open(lfirst_oid(cell), AccessShareLock);
-               tupdesc_list = lappend(tupdesc_list, rel->rd_att);
+               tupdesc_list = lappend(tupdesc_list, CreateTupleDescCopy(rel->rd_att));
                heap_close(rel, NoLock);
        }
 
@@ -2417,7 +2490,8 @@ database_to_xmlschema(PG_FUNCTION_ARGS)
        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)));
+       PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xmlschema_internal(nulls,
+                                                                                                        tableforest, targetns)));
 }
 
 
@@ -2427,12 +2501,12 @@ 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)));
+       PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xml_internal(xmlschema->data,
+                                                                                          nulls, tableforest, targetns)));
 }
 
 
@@ -2448,13 +2522,17 @@ map_multipart_sql_identifier_to_xml_name(char *a, char *b, char *c, char *d)
        initStringInfo(&result);
 
        if (a)
-               appendStringInfo(&result, "%s", map_sql_identifier_to_xml_name(a, true, true));
+               appendStringInfo(&result, "%s",
+                                                map_sql_identifier_to_xml_name(a, true, true));
        if (b)
-               appendStringInfo(&result, ".%s", map_sql_identifier_to_xml_name(b, true, true));
+               appendStringInfo(&result, ".%s",
+                                                map_sql_identifier_to_xml_name(b, true, true));
        if (c)
-               appendStringInfo(&result, ".%s", map_sql_identifier_to_xml_name(c, true, true));
+               appendStringInfo(&result, ".%s",
+                                                map_sql_identifier_to_xml_name(c, true, true));
        if (d)
-               appendStringInfo(&result, ".%s", map_sql_identifier_to_xml_name(d, true, true));
+               appendStringInfo(&result, ".%s",
+                                                map_sql_identifier_to_xml_name(d, true, true));
 
        return result.data;
 }
@@ -2468,7 +2546,8 @@ map_multipart_sql_identifier_to_xml_name(char *a, char *b, char *c, char *d)
  * 9.6.
  */
 static const char *
-map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tableforest, const char *targetns)
+map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls,
+                                                  bool tableforest, const char *targetns)
 {
        int                     i;
        char       *xmltn;
@@ -2478,12 +2557,20 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
 
        initStringInfo(&result);
 
-       if (relid)
+       if (OidIsValid(relid))
        {
-               HeapTuple tuple = SearchSysCache(RELOID, ObjectIdGetDatum(relid), 0, 0, 0);
-               Form_pg_class reltuple = (Form_pg_class) GETSTRUCT(tuple);
+               HeapTuple tuple;
+               Form_pg_class reltuple;
+
+               tuple = SearchSysCache(RELOID,
+                                                          ObjectIdGetDatum(relid),
+                                                          0, 0, 0);
+               if (!HeapTupleIsValid(tuple))
+                       elog(ERROR, "cache lookup failed for relation %u", relid);
+               reltuple = (Form_pg_class) GETSTRUCT(tuple);
 
-               xmltn = map_sql_identifier_to_xml_name(NameStr(reltuple->relname), true, false);
+               xmltn = map_sql_identifier_to_xml_name(NameStr(reltuple->relname),
+                                                                                          true, false);
 
                tabletypename = map_multipart_sql_identifier_to_xml_name("TableType",
                                                                                                                                 get_database_name(MyDatabaseId),
@@ -2521,7 +2608,8 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
        for (i = 0; i < tupdesc->natts; i++)
                appendStringInfo(&result,
                                                 "    <xsd:element name=\"%s\" type=\"%s\"%s></xsd:element>\n",
-                                                map_sql_identifier_to_xml_name(NameStr(tupdesc->attrs[i]->attname), true, false),
+                                                map_sql_identifier_to_xml_name(NameStr(tupdesc->attrs[i]->attname),
+                                                                                                               true, false),
                                                 map_sql_type_to_xml_name(tupdesc->attrs[i]->atttypid, -1),
                                                 nulls ? " nillable=\"true\"" : " minOccurs=\"0\"");
 
@@ -2559,20 +2647,26 @@ map_sql_table_to_xmlschema(TupleDesc tupdesc, Oid relid, bool nulls, bool tablef
  * 9.7.
  */
 static const char *
-map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool tableforest, const char *targetns)
+map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls,
+                                                                 bool tableforest, const char *targetns)
 {
+       char       *dbname;
+       char       *nspname;
        char       *xmlsn;
        char       *schematypename;
        StringInfoData result;
        ListCell   *cell;
 
+       dbname = get_database_name(MyDatabaseId);
+       nspname = get_namespace_name(nspid);
+
        initStringInfo(&result);
 
-       xmlsn = map_sql_identifier_to_xml_name(get_namespace_name(nspid), true, false);
+       xmlsn = map_sql_identifier_to_xml_name(nspname, true, false);
 
        schematypename = map_multipart_sql_identifier_to_xml_name("SchemaType",
-                                                                                                                         get_database_name(MyDatabaseId),
-                                                                                                                         get_namespace_name(nspid),
+                                                                                                                         dbname,
+                                                                                                                         nspname,
                                                                                                                          NULL);
 
        appendStringInfo(&result,
@@ -2587,11 +2681,12 @@ map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool
        foreach (cell, relid_list)
        {
                Oid relid = lfirst_oid(cell);
-               char *xmltn = map_sql_identifier_to_xml_name(get_rel_name(relid), true, false);
+               char *relname = get_rel_name(relid);
+               char *xmltn = map_sql_identifier_to_xml_name(relname, 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));
+                                                                                                                                          dbname,
+                                                                                                                                          nspname,
+                                                                                                                                          relname);
 
                if (!tableforest)
                        appendStringInfo(&result,
@@ -2625,19 +2720,23 @@ map_sql_schema_to_xmlschema_types(Oid nspid, List *relid_list, bool nulls, bool
  * 9.8.
  */
 static const char *
-map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tableforest, const char *targetns)
+map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls,
+                                                                  bool tableforest, const char *targetns)
 {
+       char       *dbname;
        char       *xmlcn;
        char       *catalogtypename;
        StringInfoData result;
        ListCell   *cell;
 
+       dbname = get_database_name(MyDatabaseId);
+
        initStringInfo(&result);
 
-       xmlcn = map_sql_identifier_to_xml_name(get_database_name(MyDatabaseId), true, false);
+       xmlcn = map_sql_identifier_to_xml_name(dbname, true, false);
 
        catalogtypename = map_multipart_sql_identifier_to_xml_name("CatalogType",
-                                                                                                                          get_database_name(MyDatabaseId),
+                                                                                                                          dbname,
                                                                                                                           NULL,
                                                                                                                           NULL);
 
@@ -2649,10 +2748,11 @@ map_sql_catalog_to_xmlschema_types(List *nspid_list, bool nulls, bool tablefores
        foreach (cell, nspid_list)
        {
                Oid nspid = lfirst_oid(cell);
-               char *xmlsn = map_sql_identifier_to_xml_name(get_namespace_name(nspid), true, false);
+               char       *nspname = get_namespace_name(nspid);
+               char *xmlsn = map_sql_identifier_to_xml_name(nspname, true, false);
                char *schematypename = map_multipart_sql_identifier_to_xml_name("SchemaType",
-                                                                                                                                               get_database_name(MyDatabaseId),
-                                                                                                                                               get_namespace_name(nspid),
+                                                                                                                                               dbname,
+                                                                                                                                               nspname,
                                                                                                                                                NULL);
 
                appendStringInfo(&result,
@@ -2755,8 +2855,15 @@ map_sql_type_to_xml_name(Oid typeoid, int typmod)
                        break;
                default:
                {
-                       HeapTuple tuple = SearchSysCache(TYPEOID, ObjectIdGetDatum(typeoid), 0, 0, 0);
-                       Form_pg_type typtuple = (Form_pg_type) GETSTRUCT(tuple);
+                       HeapTuple tuple;
+                       Form_pg_type typtuple;
+
+                       tuple = SearchSysCache(TYPEOID,
+                                                                  ObjectIdGetDatum(typeoid),
+                                                                  0, 0, 0);
+                       if (!HeapTupleIsValid(tuple))
+                               elog(ERROR, "cache lookup failed for type %u", typeoid);
+                       typtuple = (Form_pg_type) GETSTRUCT(tuple);
 
                        appendStringInfoString(&result,
                                                                   map_multipart_sql_identifier_to_xml_name((typtuple->typtype == TYPTYPE_DOMAIN) ? "Domain" : "UDT",
@@ -2976,7 +3083,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
                                                                 "  <xsd:restriction base=\"xsd:date\">\n"
                                                                 "    <xsd:pattern value=\"\\p{Nd}{4}-\\p{Nd}{2}-\\p{Nd}{2}\"/>\n"
                                                                 "  </xsd:restriction>\n");
-                                                                break;
+                               break;
 
                        default:
                                if (get_typtype(typeoid) == TYPTYPE_DOMAIN)
@@ -2990,6 +3097,7 @@ map_sql_type_to_xmlschema_type(Oid typeoid, int typmod)
                                                                         "  <xsd:restriction base=\"%s\">\n",
                                                                         map_sql_type_to_xml_name(base_typeoid, base_typmod));
                                }
+                               break;
                }
                appendStringInfo(&result,
                                                 "</xsd:simpleType>\n");
@@ -3004,7 +3112,9 @@ 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, bool top_level)
+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;
@@ -3030,9 +3140,12 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
                Datum colval;
                bool isnull;
 
-               colname = map_sql_identifier_to_xml_name(SPI_fname(SPI_tuptable->tupdesc, i), true, false);
-               colval = SPI_getbinval(SPI_tuptable->vals[rownum], SPI_tuptable->tupdesc, i, &isnull);
-
+               colname = map_sql_identifier_to_xml_name(SPI_fname(SPI_tuptable->tupdesc, i),
+                                                                                                true, false);
+               colval = SPI_getbinval(SPI_tuptable->vals[rownum],
+                                                          SPI_tuptable->tupdesc,
+                                                          i,
+                                                          &isnull);
                if (isnull)
                {
                        if (nulls)
@@ -3040,7 +3153,9 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
                }
                else
                        appendStringInfo(result, "  <%s>%s</%s>\n",
-                                                        colname, map_sql_value_to_xml_value(colval, SPI_gettypeid(SPI_tuptable->tupdesc, i)),
+                                                        colname,
+                                                        map_sql_value_to_xml_value(colval,
+                                                                                                               SPI_gettypeid(SPI_tuptable->tupdesc, i)),
                                                         colname);
        }
 
@@ -3060,9 +3175,10 @@ SPI_sql_row_to_xmlelement(int rownum, StringInfo result, char *tablename, bool n
 
 #ifdef USE_LIBXML
 /* 
- * Convert XML node to text (dump subtree in case of element, return value otherwise)
+ * Convert XML node to text (dump subtree in case of element,
+ * return value otherwise)
  */
-text *
+static text *
 xml_xmlnodetoxmltype(xmlNodePtr cur)
 {
        xmlChar                         *str;
@@ -3093,9 +3209,10 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
 
 /*
  * Evaluate XPath expression and return array of XML values.
- * As we have no support of XQuery sequences yet, this functions seems
+ *
+ * As we have no support of XQuery sequences yet, this function seems
  * to be the most useful one (array of XML functions plays a role of
- * some kind of substritution for XQuery sequences).
+ * some kind of substitution for XQuery sequences).
  *
  * Workaround here: we parse XML data in different way to allow XPath for
  * fragments (see "XPath for fragment" TODO comment inside).
@@ -3107,13 +3224,13 @@ xpath(PG_FUNCTION_ARGS)
        text       *xpath_expr_text = PG_GETARG_TEXT_P(0);
        xmltype    *data = PG_GETARG_XML_P(1);
        ArrayType  *namespaces = PG_GETARG_ARRAYTYPE_P(2);
-
        ArrayBuildState    *astate = NULL;
        xmlParserCtxtPtr        ctxt = NULL;
        xmlDocPtr                       doc = NULL;
        xmlXPathContextPtr      xpathctx = NULL;
        xmlXPathCompExprPtr     xpathcomp = NULL;
        xmlXPathObjectPtr       xpathobj = NULL;
+       char       *datastr;
        int32           len;
        int32           xpath_len;
        xmlChar    *string;
@@ -3121,14 +3238,14 @@ xpath(PG_FUNCTION_ARGS)
        int                     i;
        int                     res_nitems;
        int                     ndim;
+       Datum      *ns_names_uris;
+       bool       *ns_names_uris_nulls;
        int                     ns_count;
-       char      **ns_names;
-       char      **ns_uris;
 
        /*
         * Namespace mappings are passed as text[].  If an empty array is
-        * passed (ndim = 0, "0-dimentional"), then there are no namespace
-        * mappings.  Else, a 2-dimentional array with length of the
+        * passed (ndim = 0, "0-dimensional"), then there are no namespace
+        * mappings.  Else, a 2-dimensional array with length of the
         * second axis being equal to 2 should be passed, i.e., every
         * subarray contains 2 elements, the first element defining the
         * name, the second one the URI.  Example: ARRAY[ARRAY['myns',
@@ -3137,71 +3254,39 @@ xpath(PG_FUNCTION_ARGS)
        ndim = ARR_NDIM(namespaces);
        if (ndim != 0)
        {
-               bits8      *bitmap;
-               int                     bitmask;
-               int16           typlen;
-               bool            typbyval;
-               char            typalign;
-               char       *ptr;
                int                *dims;
 
                dims = ARR_DIMS(namespaces);
 
                if (ndim != 2 || dims[1] != 2)
-                       ereport(ERROR, (errmsg("invalid array for XML namespace mapping"),
-                                                       errdetail("The array must be two-dimensional with length of the second axis equal to 2."),
-                                                       errcode(ERRCODE_DATA_EXCEPTION)));
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_DATA_EXCEPTION),
+                                        errmsg("invalid array for XML namespace mapping"),
+                                        errdetail("The array must be two-dimensional with length of the second axis equal to 2.")));
 
                Assert(ARR_ELEMTYPE(namespaces) == TEXTOID);
 
-               ns_count = ArrayGetNItems(ndim, dims) / 2; /* number of NS mappings */
-               get_typlenbyvalalign(ARR_ELEMTYPE(namespaces),
-                                                        &typlen, &typbyval, &typalign);
-               ns_names = palloc(ns_count * sizeof(char *));
-               ns_uris = palloc(ns_count * sizeof(char *));
-               ptr = ARR_DATA_PTR(namespaces);
-               bitmap = ARR_NULLBITMAP(namespaces);
-               bitmask = 1;
-               for (i = 0; i < ns_count * 2; i++)
-               {
-                       if (bitmap && (*bitmap & bitmask) == 0)
-                               ereport(ERROR, (errmsg("neither namespace name nor URI may be null")));
-                       else
-                       {
-                               if (i % 2 == 0)
-                                       ns_names[i / 2] = DatumGetCString(DirectFunctionCall1(textout,
-                                                                                                                                                 PointerGetDatum(ptr)));
-                               else
-                                       ns_uris[i / 2] = DatumGetCString(DirectFunctionCall1(textout,
-                                                                                                                                                PointerGetDatum(ptr)));
-                               ptr = att_addlength_pointer(ptr, typlen, ptr);
-                               ptr = (char *) att_align_nominal(ptr, typalign);
-                       }
+               deconstruct_array(namespaces, TEXTOID, -1, false, 'i',
+                                                 &ns_names_uris, &ns_names_uris_nulls,
+                                                 &ns_count);
 
-                       /* advance bitmap pointer if any */
-                       if (bitmap)
-                       {
-                               bitmask <<= 1;
-                               if (bitmask == 0x100)
-                               {
-                                       bitmap++;
-                                       bitmask = 1;
-                               }
-                       }
-               }
+               Assert((ns_count % 2) == 0); /* checked above */
+               ns_count /= 2;                  /* count pairs only */
        }
        else
        {
+               ns_names_uris = NULL;
+               ns_names_uris_nulls = NULL;
                ns_count = 0;
-               ns_names = NULL;
-               ns_uris = NULL;
        }
 
+       datastr = VARDATA(data);
        len = VARSIZE(data) - VARHDRSZ;
        xpath_len = VARSIZE(xpath_expr_text) - VARHDRSZ;
        if (xpath_len == 0)
-               ereport(ERROR, (errmsg("empty XPath expression"),
-                                               errcode(ERRCODE_DATA_EXCEPTION)));
+               ereport(ERROR,
+                               (errcode(ERRCODE_DATA_EXCEPTION),
+                                errmsg("empty XPath expression")));
 
        /*
         * To handle both documents and fragments, regardless of the fact
@@ -3210,10 +3295,12 @@ xpath(PG_FUNCTION_ARGS)
         * extend the XPath expression accordingly.  To do it, throw away
         * the XML prolog, if any.
         */
-       if ((len > 4) && xmlStrncmp((xmlChar *) VARDATA(data), (xmlChar *) "<?xml", 5) == 0)
+       if (len >= 5 &&
+               xmlStrncmp((xmlChar *) datastr, (xmlChar *) "<?xml", 5) == 0)
        {
                i = 5;
-               while ((i < len) && (('?' != (VARDATA(data))[i - 1]) || ('>' != (VARDATA(data))[i])))
+               while (i < len &&
+                          !(datastr[i - 1] == '?' && datastr[i] == '>'))
                        i++;
 
                if (i == len)
@@ -3221,14 +3308,17 @@ xpath(PG_FUNCTION_ARGS)
                                                "could not parse XML data");
 
                ++i;
-               string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data) + i, len - i);
+               string = xmlStrncatNew((xmlChar *) "<x>",
+                                                          (xmlChar *) datastr + i, len - i);
        }
        else
-               string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data), len);
+               string = xmlStrncatNew((xmlChar *) "<x>",
+                                                          (xmlChar *) datastr, len);
 
        string = xmlStrncat(string, (xmlChar *) "</x>", 5);
        len += 7;
-       xpath_expr = xmlStrncatNew((xmlChar *) "/x", (xmlChar *) VARDATA(xpath_expr_text), xpath_len);
+       xpath_expr = xmlStrncatNew((xmlChar *) "/x",
+                                                          (xmlChar *) VARDATA(xpath_expr_text), xpath_len);
        xpath_len += 2;
 
        xml_init();
@@ -3259,21 +3349,38 @@ xpath(PG_FUNCTION_ARGS)
                                                "could not find root XML element");
 
                /* register namespaces, if any */
-               if ((ns_count > 0) && ns_names && ns_uris)
+               if (ns_count > 0)
+               {
                        for (i = 0; i < ns_count; i++)
-                               if (0 != xmlXPathRegisterNs(xpathctx, (xmlChar *) ns_names[i], (xmlChar *) ns_uris[i]))
+                       {
+                               char *ns_name;
+                               char *ns_uri;
+
+                               if (ns_names_uris_nulls[i * 2] ||
+                                       ns_names_uris_nulls[i * 2 + 1])
                                        ereport(ERROR,
+                                                       (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
+                                                        errmsg("neither namespace name nor URI may be null")));
+                               ns_name = _textout(ns_names_uris[i * 2]);
+                               ns_uri = _textout(ns_names_uris[i * 2 + 1]);
+                               if (xmlXPathRegisterNs(xpathctx,
+                                                                          (xmlChar *) ns_name,
+                                                                          (xmlChar *) ns_uri) != 0)
+                                       ereport(ERROR, /* is this an internal error??? */
                                                        (errmsg("could not register XML namespace with name \"%s\" and URI \"%s\"",
-                                                                       ns_names[i], ns_uris[i])));
+                                                                       ns_name, ns_uri)));
+                       }
+               }
 
                xpathcomp = xmlXPathCompile(xpath_expr);
-               if (xpathcomp == NULL)
+               if (xpathcomp == NULL)  /* TODO: show proper XPath error details */
                        xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
-                                               "invalid XPath expression"); /* TODO: show proper XPath error details */
+                                               "invalid XPath expression");
 
                xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
-               if (xpathobj == NULL)
-                       ereport(ERROR, (errmsg("could not create XPath object"))); /* TODO: reason? */
+               if (xpathobj == NULL)   /* TODO: reason? */
+                       ereport(ERROR,
+                                       (errmsg("could not create XPath object")));
 
                xmlXPathFreeCompExpr(xpathcomp);
                xpathcomp = NULL;