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 5f5654c232aeaca4e0fa92345b680b7c5444ec0a..9e9d0e1af559dd2b2e1365f6a17c70da5aab5092 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;