OSDN Git Service

Move exprType(), exprTypmod(), expression_tree_walker(), and related routines
[pg-rex/syncrep.git] / src / backend / utils / adt / xml.c
index 622d4e0..fd0c0ee 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.66 2008/01/12 10:50:03 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.76 2008/08/25 22:42:34 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  */
 
 /*
- * Note on memory management: Via callbacks, libxml is told to use
- * palloc and friends for memory management.  Sometimes, libxml
- * allocates global structures in the hope that it can reuse them
- * later on, but if "later" is much later, the memory context
- * management of PostgreSQL will have blown those structures away
- * without telling libxml about it.  Therefore, it is important to
- * call xmlCleanupParser() or perhaps some other cleanup function
- * after using such functions, for example something from
- * libxml/parser.h or libxml/xmlsave.h.  Unfortunately, you cannot
- * readily tell from the API documentation when that happens, so
- * careful evaluation is necessary when introducing new libxml APIs
- * here.
+ * Notes on memory management:
+ *
+ * Via callbacks, libxml is told to use palloc and friends for memory
+ * management, within a context that we reset at transaction end (and also at
+ * subtransaction abort) to prevent memory leaks.  Resetting at transaction or
+ * subtransaction abort is necessary since we might have thrown a longjmp
+ * while some data structures were not linked from anywhere persistent.
+ * Resetting at transaction commit might not be necessary, but seems a good
+ * idea to forestall long-term leaks.
+ *
+ * Sometimes libxml allocates global structures in the hope that it can reuse
+ * them later on.  Therefore, before resetting LibxmlContext, we must tell
+ * libxml to discard any global data it has.  The libxml API documentation is
+ * not very good about specifying this, but for now we assume that
+ * xmlCleanupParser() will get rid of anything we need to worry about.
+ *
+ * We use palloc --- which will throw a longjmp on error --- for allocation
+ * callbacks that officially should act like malloc, ie, return NULL on
+ * out-of-memory.  This is a bit risky since there is a chance of leaving
+ * persistent libxml data structures in an inconsistent partially-constructed
+ * state, perhaps leading to crash in xmlCleanupParser().  However, as of
+ * early 2008 it is *known* that libxml can crash on out-of-memory due to
+ * inadequate checks for NULL returns, so this behavior seems the lesser
+ * of two evils.
  */
 
 #include "postgres.h"
 #include "mb/pg_wchar.h"
 #include "miscadmin.h"
 #include "nodes/execnodes.h"
-#include "parser/parse_expr.h"
+#include "nodes/nodeFuncs.h"
 #include "utils/array.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/datetime.h"
 #include "utils/lsyscache.h"
 #include "utils/memutils.h"
-#include "access/tupmacs.h"
 #include "utils/xml.h"
 
 
 /* GUC variables */
-XmlBinaryType xmlbinary;
-XmlOptionType xmloption;
+int xmlbinary;
+int xmloption;
 
 #ifdef USE_LIBXML
 
 static StringInfo xml_err_buf = NULL;
+static MemoryContext LibxmlContext = NULL;
 
 static void xml_init(void);
+static void xml_memory_init(void);
+static void xml_memory_cleanup(void);
 static void *xml_palloc(size_t size);
 static void *xml_repalloc(void *ptr, size_t size);
 static void xml_pfree(void *ptr);
@@ -126,10 +140,6 @@ static void SPI_sql_row_to_xmlelement(int rownum, StringInfo result,
                         errhint("You need to rebuild PostgreSQL using --with-libxml.")))
 
 
-#define _textin(str) DirectFunctionCall1(textin, CStringGetDatum(str))
-#define _textout(x) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(x)))
-
-
 /* from SQL/XML:2003 section 4.7 */
 #define NAMESPACE_XSD "http://www.w3.org/2001/XMLSchema"
 #define NAMESPACE_XSI "http://www.w3.org/2001/XMLSchema-instance"
@@ -153,19 +163,22 @@ xmlChar_to_encoding(xmlChar * encoding_name)
 #endif
 
 
+/*
+ * xml_in uses a plain C string to VARDATA conversion, so for the time being
+ * we use the conversion function for the text datatype.
+ *
+ * This is only acceptable so long as xmltype and text use the same
+ * representation.
+ */
 Datum
 xml_in(PG_FUNCTION_ARGS)
 {
 #ifdef USE_LIBXML
        char       *s = PG_GETARG_CSTRING(0);
-       size_t          len;
        xmltype    *vardata;
        xmlDocPtr       doc;
 
-       len = strlen(s);
-       vardata = palloc(len + VARHDRSZ);
-       SET_VARSIZE(vardata, len + VARHDRSZ);
-       memcpy(VARDATA(vardata), s, len);
+       vardata = (xmltype *) cstring_to_text(s);
 
        /*
         * Parse the data to check if it is well-formed XML data.  Assume that
@@ -185,6 +198,13 @@ xml_in(PG_FUNCTION_ARGS)
 #define PG_XML_DEFAULT_VERSION "1.0"
 
 
+/*
+ * xml_out_internal uses a plain VARDATA to C string conversion, so for the
+ * time being we use the conversion function for the text datatype.
+ *
+ * This is only acceptable so long as xmltype and text use the same
+ * representation.
+ */
 static char *
 xml_out_internal(xmltype *x, pg_enc target_encoding)
 {
@@ -198,10 +218,8 @@ xml_out_internal(xmltype *x, pg_enc target_encoding)
        int                     res_code;
 #endif
 
-       len = VARSIZE(x) - VARHDRSZ;
-       str = palloc(len + 1);
-       memcpy(str, VARDATA(x), len);
-       str[len] = '\0';
+       str = text_to_cstring((text *) x);
+       len = strlen(str);
 
 #ifdef USE_LIBXML
        if ((res_code = parse_xml_decl((xmlChar *) str,
@@ -300,13 +318,7 @@ xml_recv(PG_FUNCTION_ARGS)
        if (newstr != str)
        {
                pfree(result);
-
-               nbytes = strlen(newstr);
-
-               result = palloc(nbytes + VARHDRSZ);
-               SET_VARSIZE(result, nbytes + VARHDRSZ);
-               memcpy(VARDATA(result), newstr, nbytes);
-
+               result = (xmltype *) cstring_to_text(newstr);
                pfree(newstr);
        }
 
@@ -350,30 +362,14 @@ appendStringInfoText(StringInfo str, const text *t)
 static xmltype *
 stringinfo_to_xmltype(StringInfo buf)
 {
-       int32           len;
-       xmltype    *result;
-
-       len = buf->len + VARHDRSZ;
-       result = palloc(len);
-       SET_VARSIZE(result, len);
-       memcpy(VARDATA(result), buf->data, buf->len);
-
-       return result;
+       return (xmltype *) cstring_to_text_with_len(buf->data, buf->len);
 }
 
 
 static xmltype *
 cstring_to_xmltype(const char *string)
 {
-       int32           len;
-       xmltype    *result;
-
-       len = strlen(string) + VARHDRSZ;
-       result = palloc(len);
-       SET_VARSIZE(result, len);
-       memcpy(VARDATA(result), string, len - VARHDRSZ);
-
-       return result;
+       return (xmltype *) cstring_to_text(string);
 }
 
 
@@ -381,15 +377,8 @@ cstring_to_xmltype(const char *string)
 static xmltype *
 xmlBuffer_to_xmltype(xmlBufferPtr buf)
 {
-       int32           len;
-       xmltype    *result;
-
-       len = xmlBufferLength(buf) + VARHDRSZ;
-       result = palloc(len);
-       SET_VARSIZE(result, len);
-       memcpy(VARDATA(result), xmlBufferContent(buf), len - VARHDRSZ);
-
-       return result;
+       return (xmltype *) cstring_to_text_with_len((char *) xmlBufferContent(buf),
+                                                                                               xmlBufferLength(buf));
 }
 #endif
 
@@ -455,9 +444,7 @@ xmlconcat(List *args)
                char       *str;
 
                len = VARSIZE(x) - VARHDRSZ;
-               str = palloc(len + 1);
-               memcpy(str, VARDATA(x), len);
-               str[len] = '\0';
+               str = text_to_cstring((text *) x);
 
                parse_xml_decl((xmlChar *) str, &len, &version, NULL, &standalone);
 
@@ -698,7 +685,7 @@ xmlpi(char *target, text *arg, bool arg_is_null, bool *result_is_null)
        {
                char       *string;
 
-               string = _textout(arg);
+               string = text_to_cstring(arg);
                if (strstr(string, "?>") != NULL)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_XML_PROCESSING_INSTRUCTION),
@@ -732,9 +719,7 @@ xmlroot(xmltype *data, text *version, int standalone)
        StringInfoData buf;
 
        len = VARSIZE(data) - VARHDRSZ;
-       str = palloc(len + 1);
-       memcpy(str, VARDATA(data), len);
-       str[len] = '\0';
+       str = text_to_cstring((text *) data);
 
        parse_xml_decl((xmlChar *) str, &len, &orig_version, NULL, &orig_standalone);
 
@@ -773,101 +758,19 @@ xmlroot(xmltype *data, text *version, int standalone)
 
 /*
  * Validate document (given as string) against DTD (given as external link)
- * TODO !!! use text instead of cstring for second arg
- * TODO allow passing DTD as a string value (not only as an URI)
- * TODO redesign (see comment with '!!!' below)
+ *
+ * This has been removed because it is a security hole: unprivileged users
+ * should not be able to use Postgres to fetch arbitrary external files,
+ * which unfortunately is exactly what libxml is willing to do with the DTD
+ * parameter.
  */
 Datum
 xmlvalidate(PG_FUNCTION_ARGS)
 {
-#ifdef USE_LIBXML
-       text       *data = PG_GETARG_TEXT_P(0);
-       text       *dtdOrUri = PG_GETARG_TEXT_P(1);
-       bool            result = false;
-       xmlParserCtxtPtr ctxt = NULL;
-       xmlDocPtr       doc = NULL;
-       xmlDtdPtr       dtd = NULL;
-
-       xml_init();
-
-       /* We use a PG_TRY block to ensure libxml parser is cleaned up on error */
-       PG_TRY();
-       {
-               xmlInitParser();
-               ctxt = xmlNewParserCtxt();
-               if (ctxt == NULL)
-                       xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
-                                               "could not allocate parser context");
-
-               doc = xmlCtxtReadMemory(ctxt, (char *) VARDATA(data),
-                                                               VARSIZE(data) - VARHDRSZ,
-                                                               NULL, NULL, 0);
-               if (doc == NULL)
-                       xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
-                                               "could not parse XML data");
-
-#if 0
-               uri = xmlCreateURI();
-               elog(NOTICE, "dtd - %s", dtdOrUri);
-               dtd = palloc(sizeof(xmlDtdPtr));
-               uri = xmlParseURI(dtdOrUri);
-               if (uri == NULL)
-                       xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
-                                               "not implemented yet... (TODO)");
-               else
-#endif
-                       dtd = xmlParseDTD(NULL, xml_text2xmlChar(dtdOrUri));
-
-               if (dtd == NULL)
-                       xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
-                                               "could not load DTD");
-
-               if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) == 1)
-                       result = true;
-
-               if (!result)
-                       xml_ereport(NOTICE, ERRCODE_INVALID_XML_DOCUMENT,
-                                               "validation against DTD failed");
-
-#if 0
-               if (uri)
-                       xmlFreeURI(uri);
-               uri = NULL;
-#endif
-               if (dtd)
-                       xmlFreeDtd(dtd);
-               dtd = NULL;
-               if (doc)
-                       xmlFreeDoc(doc);
-               doc = NULL;
-               if (ctxt)
-                       xmlFreeParserCtxt(ctxt);
-               ctxt = NULL;
-               xmlCleanupParser();
-       }
-       PG_CATCH();
-       {
-#if 0
-               if (uri)
-                       xmlFreeURI(uri);
-#endif
-               if (dtd)
-                       xmlFreeDtd(dtd);
-               if (doc)
-                       xmlFreeDoc(doc);
-               if (ctxt)
-                       xmlFreeParserCtxt(ctxt);
-               xmlCleanupParser();
-
-               PG_RE_THROW();
-       }
-       PG_END_TRY();
-
-       PG_RETURN_BOOL(result);
-#else                                                  /* not USE_LIBXML */
-       NO_XML_SUPPORT();
+       ereport(ERROR,
+                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                        errmsg("xmlvalidate is not implemented")));
        return 0;
-#endif   /* not USE_LIBXML */
 }
 
 
@@ -915,6 +818,19 @@ xml_is_document(xmltype *arg)
 }
 
 
+/*
+ * xml cleanup function for transaction end.  This is also called on
+ * subtransaction abort; see notes at top of file for rationale.
+ */
+void
+AtEOXact_xml(void)
+{
+#ifdef USE_LIBXML
+       xml_memory_cleanup();
+#endif
+}
+
+
 #ifdef USE_LIBXML
 
 /*
@@ -953,7 +869,7 @@ xml_init(void)
                xmlSetGenericErrorFunc(NULL, xml_errorHandler);
 
                /* Set up memory allocation our way, too */
-               xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
+               xml_memory_init();
 
                /* Check library compatibility */
                LIBXML_TEST_VERSION;
@@ -974,7 +890,7 @@ xml_init(void)
                 * about, anyway.
                 */
                xmlSetGenericErrorFunc(NULL, xml_errorHandler);
-               xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
+               xml_memory_init();
        }
 }
 
@@ -1207,7 +1123,7 @@ print_xml_decl(StringInfo buf, const xmlChar * version,
  * 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)
+ * yet do not use SAX - see xmlreader.c)
  */
 static xmlDocPtr
 xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
@@ -1216,8 +1132,8 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
        int32           len;
        xmlChar    *string;
        xmlChar    *utf8string;
-       xmlParserCtxtPtr ctxt = NULL;
-       xmlDocPtr       doc = NULL;
+       xmlParserCtxtPtr ctxt;
+       xmlDocPtr       doc;
 
        len = VARSIZE(data) - VARHDRSZ;         /* will be useful later */
        string = xml_text2xmlChar(data);
@@ -1230,94 +1146,108 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
                                                                                   PG_UTF8);
 
        xml_init();
+       xmlInitParser();
+       ctxt = xmlNewParserCtxt();
+       if (ctxt == NULL)
+               xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
+                                       "could not allocate parser context");
 
-       /* We use a PG_TRY block to ensure libxml parser is cleaned up on error */
-       PG_TRY();
+       if (xmloption_arg == XMLOPTION_DOCUMENT)
        {
-               xmlInitParser();
-               ctxt = xmlNewParserCtxt();
-               if (ctxt == NULL)
-                       xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
-                                               "could not allocate parser context");
-
-               if (xmloption_arg == XMLOPTION_DOCUMENT)
-               {
-                       /*
-                        * Note, that here we try to apply DTD defaults
-                        * (XML_PARSE_DTDATTR) according to SQL/XML:10.16.7.d: 'Default
-                        * valies defined by internal DTD are applied'. As for external
-                        * DTDs, we try to support them too, (see SQL/XML:10.16.7.e)
-                        */
-                       doc = xmlCtxtReadDoc(ctxt, utf8string,
-                                                                NULL,
-                                                                "UTF-8",
-                                                                XML_PARSE_NOENT | XML_PARSE_DTDATTR
-                                                  | (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
-                       if (doc == NULL)
-                               xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
-                                                       "invalid XML document");
-               }
-               else
-               {
-                       int                     res_code;
-                       size_t          count;
-                       xmlChar    *version = NULL;
-                       int                     standalone = -1;
-
-                       doc = xmlNewDoc(NULL);
-
-                       res_code = parse_xml_decl(utf8string, &count, &version, NULL, &standalone);
-                       if (res_code != 0)
-                               xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_CONTENT,
-                                  "invalid XML content: invalid XML declaration", res_code);
-
-                       res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, utf8string + count, NULL);
-                       if (res_code != 0)
-                               xml_ereport(ERROR, ERRCODE_INVALID_XML_CONTENT,
-                                                       "invalid XML content");
-
-                       doc->version = xmlStrdup(version);
-                       doc->encoding = xmlStrdup((xmlChar *) "UTF-8");
-                       doc->standalone = standalone;
-               }
-
-               if (ctxt)
-                       xmlFreeParserCtxt(ctxt);
-               ctxt = NULL;
-               xmlCleanupParser();
+               /*
+                * Note, that here we try to apply DTD defaults
+                * (XML_PARSE_DTDATTR) according to SQL/XML:10.16.7.d: 'Default
+                * values defined by internal DTD are applied'. As for external
+                * DTDs, we try to support them too, (see SQL/XML:10.16.7.e)
+                */
+               doc = xmlCtxtReadDoc(ctxt, utf8string,
+                                                        NULL,
+                                                        "UTF-8",
+                                                        XML_PARSE_NOENT | XML_PARSE_DTDATTR
+                                                        | (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
+               if (doc == NULL)
+                       xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
+                                               "invalid XML document");
        }
-       PG_CATCH();
+       else
        {
-               if (doc)
-                       xmlFreeDoc(doc);
-               if (ctxt)
-                       xmlFreeParserCtxt(ctxt);
-               xmlCleanupParser();
+               int                     res_code;
+               size_t          count;
+               xmlChar    *version = NULL;
+               int                     standalone = -1;
+
+               doc = xmlNewDoc(NULL);
 
-               PG_RE_THROW();
+               res_code = parse_xml_decl(utf8string,
+                                                                 &count, &version, NULL, &standalone);
+               if (res_code != 0)
+                       xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_CONTENT,
+                                                               "invalid XML content: invalid XML declaration",
+                                                               res_code);
+
+               res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
+                                                                                          utf8string + count, NULL);
+               if (res_code != 0)
+                       xml_ereport(ERROR, ERRCODE_INVALID_XML_CONTENT,
+                                               "invalid XML content");
+
+               doc->version = xmlStrdup(version);
+               doc->encoding = xmlStrdup((xmlChar *) "UTF-8");
+               doc->standalone = standalone;
        }
-       PG_END_TRY();
+
+       xmlFreeParserCtxt(ctxt);
 
        return doc;
 }
 
 
 /*
- * xmlChar<->text convertions
+ * xmlChar<->text conversions
  */
 static xmlChar *
 xml_text2xmlChar(text *in)
 {
-       int32           len = VARSIZE(in) - VARHDRSZ;
-       xmlChar    *res;
+       return (xmlChar *) text_to_cstring(in);
+}
 
-       res = palloc(len + 1);
-       memcpy(res, VARDATA(in), len);
-       res[len] = '\0';
 
-       return (res);
+/*
+ * Manage the special context used for all libxml allocations
+ */
+static void
+xml_memory_init(void)
+{
+       /*
+        * Create memory context if not there already.  We make it a child of
+        * TopMemoryContext, even though our current policy is that it doesn't
+        * survive past transaction end, because we want to be really really
+        * sure it doesn't go away before we've called xmlCleanupParser().
+        */
+       if (LibxmlContext == NULL)
+               LibxmlContext = AllocSetContextCreate(TopMemoryContext,
+                                                                                         "LibxmlContext",
+                                                                                         ALLOCSET_DEFAULT_MINSIZE,
+                                                                                         ALLOCSET_DEFAULT_INITSIZE,
+                                                                                         ALLOCSET_DEFAULT_MAXSIZE);
+
+       /* Re-establish the callbacks even if already set */
+       xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
 }
 
+static void
+xml_memory_cleanup(void)
+{
+       if (LibxmlContext != NULL)
+       {
+               /* Give libxml a chance to clean up dangling pointers */
+               xmlCleanupParser();
+
+               /* And flush the context */
+               MemoryContextDelete(LibxmlContext);
+               LibxmlContext = NULL;
+       }
+}
 
 /*
  * Wrappers for memory management functions
@@ -1325,7 +1255,7 @@ xml_text2xmlChar(text *in)
 static void *
 xml_palloc(size_t size)
 {
-       return palloc(size);
+       return MemoryContextAlloc(LibxmlContext, size);
 }
 
 
@@ -1346,7 +1276,7 @@ xml_pfree(void *ptr)
 static char *
 xml_pstrdup(const char *string)
 {
-       return pstrdup(string);
+       return MemoryContextStrdup(LibxmlContext, string);
 }
 
 
@@ -1434,25 +1364,25 @@ xml_ereport_by_code(int level, int sqlcode,
        switch (code)
        {
                case XML_ERR_INVALID_CHAR:
-                       det = "Invalid character value";
+                       det = gettext_noop("Invalid character value.");
                        break;
                case XML_ERR_SPACE_REQUIRED:
-                       det = "Space required";
+                       det = gettext_noop("Space required.");
                        break;
                case XML_ERR_STANDALONE_VALUE:
-                       det = "standalone accepts only 'yes' or 'no'";
+                       det = gettext_noop("standalone accepts only 'yes' or 'no'.");
                        break;
                case XML_ERR_VERSION_MISSING:
-                       det = "Malformed declaration expecting version";
+                       det = gettext_noop("Malformed declaration: missing version.");
                        break;
                case XML_ERR_MISSING_ENCODING:
-                       det = "Missing encoding in text declaration";
+                       det = gettext_noop("Missing encoding in text declaration.");
                        break;
                case XML_ERR_XMLDECL_NOT_FINISHED:
-                       det = "Parsing XML declaration: '?>' expected";
+                       det = gettext_noop("Parsing XML declaration: '?>' expected.");
                        break;
                default:
-                       det = "Unrecognized libxml error code: %d";
+                       det = gettext_noop("Unrecognized libxml error code: %d.");
                        break;
        }
 
@@ -1963,7 +1893,7 @@ table_to_xml(PG_FUNCTION_ARGS)
        Oid                     relid = PG_GETARG_OID(0);
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
 
        PG_RETURN_XML_P(stringinfo_to_xmltype(table_to_xml_internal(relid, NULL,
                                                                                                                  nulls, tableforest,
@@ -1974,10 +1904,10 @@ table_to_xml(PG_FUNCTION_ARGS)
 Datum
 query_to_xml(PG_FUNCTION_ARGS)
 {
-       char       *query = _textout(PG_GETARG_TEXT_P(0));
+       char       *query = text_to_cstring(PG_GETARG_TEXT_PP(0));
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
 
        PG_RETURN_XML_P(stringinfo_to_xmltype(query_to_xml_internal(query, NULL,
                                                                                                        NULL, nulls, tableforest,
@@ -1988,11 +1918,11 @@ query_to_xml(PG_FUNCTION_ARGS)
 Datum
 cursor_to_xml(PG_FUNCTION_ARGS)
 {
-       char       *name = _textout(PG_GETARG_TEXT_P(0));
+       char       *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
        int32           count = PG_GETARG_INT32(1);
        bool            nulls = PG_GETARG_BOOL(2);
        bool            tableforest = PG_GETARG_BOOL(3);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(4));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(4));
 
        StringInfoData result;
        Portal          portal;
@@ -2112,7 +2042,7 @@ table_to_xmlschema(PG_FUNCTION_ARGS)
        Oid                     relid = PG_GETARG_OID(0);
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
        const char *result;
        Relation        rel;
 
@@ -2128,10 +2058,10 @@ table_to_xmlschema(PG_FUNCTION_ARGS)
 Datum
 query_to_xmlschema(PG_FUNCTION_ARGS)
 {
-       char       *query = _textout(PG_GETARG_TEXT_P(0));
+       char       *query = text_to_cstring(PG_GETARG_TEXT_PP(0));
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
        const char *result;
        SPIPlanPtr      plan;
        Portal          portal;
@@ -2157,10 +2087,10 @@ query_to_xmlschema(PG_FUNCTION_ARGS)
 Datum
 cursor_to_xmlschema(PG_FUNCTION_ARGS)
 {
-       char       *name = _textout(PG_GETARG_TEXT_P(0));
+       char       *name = text_to_cstring(PG_GETARG_TEXT_PP(0));
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
        const char *xmlschema;
        Portal          portal;
 
@@ -2186,7 +2116,7 @@ table_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
        Oid                     relid = PG_GETARG_OID(0);
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
        Relation        rel;
        const char *xmlschema;
 
@@ -2204,10 +2134,10 @@ table_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
 Datum
 query_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
 {
-       char       *query = _textout(PG_GETARG_TEXT_P(0));
+       char       *query = text_to_cstring(PG_GETARG_TEXT_PP(0));
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
 
        const char *xmlschema;
        SPIPlanPtr      plan;
@@ -2288,7 +2218,7 @@ schema_to_xml(PG_FUNCTION_ARGS)
        Name            name = PG_GETARG_NAME(0);
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
 
        char       *schemaname;
        Oid                     nspid;
@@ -2379,7 +2309,7 @@ schema_to_xmlschema(PG_FUNCTION_ARGS)
        Name            name = PG_GETARG_NAME(0);
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
 
        PG_RETURN_XML_P(stringinfo_to_xmltype(schema_to_xmlschema_internal(NameStr(*name),
                                                                                         nulls, tableforest, targetns)));
@@ -2392,7 +2322,7 @@ schema_to_xml_and_xmlschema(PG_FUNCTION_ARGS)
        Name            name = PG_GETARG_NAME(0);
        bool            nulls = PG_GETARG_BOOL(1);
        bool            tableforest = PG_GETARG_BOOL(2);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(3));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(3));
        char       *schemaname;
        Oid                     nspid;
        StringInfo      xmlschema;
@@ -2464,7 +2394,7 @@ database_to_xml(PG_FUNCTION_ARGS)
 {
        bool            nulls = PG_GETARG_BOOL(0);
        bool            tableforest = PG_GETARG_BOOL(1);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(2));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(2));
 
        PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xml_internal(NULL, nulls,
                                                                                                        tableforest, targetns)));
@@ -2519,7 +2449,7 @@ database_to_xmlschema(PG_FUNCTION_ARGS)
 {
        bool            nulls = PG_GETARG_BOOL(0);
        bool            tableforest = PG_GETARG_BOOL(1);
-       const char *targetns = _textout(PG_GETARG_TEXT_P(2));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(2));
 
        PG_RETURN_XML_P(stringinfo_to_xmltype(database_to_xmlschema_internal(nulls,
                                                                                                        tableforest, targetns)));
@@ -2531,7 +2461,7 @@ 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));
+       const char *targetns = text_to_cstring(PG_GETARG_TEXT_PP(2));
        StringInfo      xmlschema;
 
        xmlschema = database_to_xmlschema_internal(nulls, tableforest, targetns);
@@ -3217,7 +3147,6 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
 {
        xmlChar    *str;
        xmltype    *result;
-       size_t          len;
        xmlBufferPtr buf;
 
        if (cur->type == XML_ELEMENT_NODE)
@@ -3230,10 +3159,8 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
        else
        {
                str = xmlXPathCastNodeToString(cur);
-               len = strlen((char *) str);
-               result = (text *) palloc(len + VARHDRSZ);
-               SET_VARSIZE(result, len + VARHDRSZ);
-               memcpy(VARDATA(result), str, len);
+               result = (xmltype *) cstring_to_text((char *) str);
+               xmlFree(str);
        }
 
        return result;
@@ -3259,11 +3186,11 @@ xpath(PG_FUNCTION_ARGS)
        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;
+       xmlParserCtxtPtr ctxt;
+       xmlDocPtr       doc;
+       xmlXPathContextPtr xpathctx;
+       xmlXPathCompExprPtr xpathcomp;
+       xmlXPathObjectPtr xpathobj;
        char       *datastr;
        int32           len;
        int32           xpath_len;
@@ -3360,114 +3287,89 @@ xpath(PG_FUNCTION_ARGS)
        xpath_expr[xpath_len + 2] = '\0';
        xpath_len += 2;
 
-       /* We use a PG_TRY block to ensure libxml parser is cleaned up on error */
-       PG_TRY();
-       {
-               xmlInitParser();
+       xmlInitParser();
 
-               /*
-                * redundant XML parsing (two parsings for the same value during one
-                * command execution are possible)
-                */
-               ctxt = xmlNewParserCtxt();
-               if (ctxt == NULL)
-                       xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
-                                               "could not allocate parser context");
-               doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
-               if (doc == NULL)
-                       xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
-                                               "could not parse XML data");
-               xpathctx = xmlXPathNewContext(doc);
-               if (xpathctx == NULL)
-                       xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
-                                               "could not allocate XPath context");
-               xpathctx->node = xmlDocGetRootElement(doc);
-               if (xpathctx->node == NULL)
-                       xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
-                                               "could not find root XML element");
-
-               /* register namespaces, if any */
-               if (ns_count > 0)
+       /*
+        * redundant XML parsing (two parsings for the same value during one
+        * command execution are possible)
+        */
+       ctxt = xmlNewParserCtxt();
+       if (ctxt == NULL)
+               xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
+                                       "could not allocate parser context");
+       doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
+       if (doc == NULL)
+               xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
+                                       "could not parse XML data");
+       xpathctx = xmlXPathNewContext(doc);
+       if (xpathctx == NULL)
+               xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
+                                       "could not allocate XPath context");
+       xpathctx->node = xmlDocGetRootElement(doc);
+       if (xpathctx->node == NULL)
+               xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
+                                       "could not find root XML element");
+
+       /* register namespaces, if any */
+       if (ns_count > 0)
+       {
+               for (i = 0; i < ns_count; i++)
                {
-                       for (i = 0; i < ns_count; 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_name, ns_uri)));
-                       }
+                       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 = TextDatumGetCString(ns_names_uris[i * 2]);
+                       ns_uri = TextDatumGetCString(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_name, ns_uri)));
                }
+       }
 
-               xpathcomp = xmlXPathCompile(xpath_expr);
-               if (xpathcomp == NULL)  /* TODO: show proper XPath error details */
-                       xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
-                                               "invalid XPath expression");
-
-               xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
-               if (xpathobj == NULL)   /* TODO: reason? */
-                       ereport(ERROR,
-                                       (errmsg("could not create XPath object")));
-
-               xmlXPathFreeCompExpr(xpathcomp);
-               xpathcomp = NULL;
+       xpathcomp = xmlXPathCompile(xpath_expr);
+       if (xpathcomp == NULL)  /* TODO: show proper XPath error details */
+               xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
+                                       "invalid XPath expression");
 
-               /* return empty array in cases when nothing is found */
-               if (xpathobj->nodesetval == NULL)
-                       res_nitems = 0;
-               else
-                       res_nitems = xpathobj->nodesetval->nodeNr;
+       xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
+       if (xpathobj == NULL)   /* TODO: reason? */
+               ereport(ERROR,
+                               (errmsg("could not create XPath object")));
 
-               if (res_nitems)
-                       for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
-                       {
-                               Datum           elem;
-                               bool            elemisnull = false;
+       xmlXPathFreeCompExpr(xpathcomp);
 
-                               elem = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
-                               astate = accumArrayResult(astate, elem,
-                                                                                 elemisnull, XMLOID,
-                                                                                 CurrentMemoryContext);
-                       }
+       /* return empty array in cases when nothing is found */
+       if (xpathobj->nodesetval == NULL)
+               res_nitems = 0;
+       else
+               res_nitems = xpathobj->nodesetval->nodeNr;
 
-               xmlXPathFreeObject(xpathobj);
-               xpathobj = NULL;
-               xmlXPathFreeContext(xpathctx);
-               xpathctx = NULL;
-               xmlFreeDoc(doc);
-               doc = NULL;
-               xmlFreeParserCtxt(ctxt);
-               ctxt = NULL;
-               xmlCleanupParser();
-       }
-       PG_CATCH();
+       if (res_nitems)
        {
-               if (xpathcomp)
-                       xmlXPathFreeCompExpr(xpathcomp);
-               if (xpathobj)
-                       xmlXPathFreeObject(xpathobj);
-               if (xpathctx)
-                       xmlXPathFreeContext(xpathctx);
-               if (doc)
-                       xmlFreeDoc(doc);
-               if (ctxt)
-                       xmlFreeParserCtxt(ctxt);
-               xmlCleanupParser();
+               for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
+               {
+                       Datum           elem;
+                       bool            elemisnull = false;
 
-               PG_RE_THROW();
+                       elem = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
+                       astate = accumArrayResult(astate, elem,
+                                                                         elemisnull, XMLOID,
+                                                                         CurrentMemoryContext);
+               }
        }
-       PG_END_TRY();
+
+       xmlXPathFreeObject(xpathobj);
+       xmlXPathFreeContext(xpathctx);
+       xmlFreeDoc(doc);
+       xmlFreeParserCtxt(ctxt);
 
        if (res_nitems == 0)
                PG_RETURN_ARRAYTYPE_P(construct_empty_array(XMLOID));