]> granicus.if.org Git - postgresql/commitdiff
Make contrib/xml2 use core xml.c's error handler, when available (that is,
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 3 Mar 2010 19:10:35 +0000 (19:10 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 3 Mar 2010 19:10:35 +0000 (19:10 +0000)
in versions >= 8.3).  The core code is more robust and efficient than what
was there before, and this also reduces risks involved in swapping different
libxml error handler settings.

Before 8.3, there is still some risk of problems if add-on modules such as
Perl invoke libxml without setting their own error handler.  Given the lack
of reports I'm not sure there's a risk in practice, so I didn't take the
step of actually duplicating the core code into older contrib/xml2 branches.
Instead I just tweaked the existing code to ensure it didn't leave a dangling
pointer to short-lived memory when throwing an error.

contrib/xml2/xpath.c
contrib/xml2/xslt_proc.c

index 35907da9853d73c1a5a70be2b362df38ddc870c8..0fdbe9d14fea27dbe0694ccfeb0ef76807d4beb5 100644 (file)
@@ -7,6 +7,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "lib/stringinfo.h"
+#include "utils/xml.h"
 
 /* libxml includes */
 
@@ -30,15 +31,12 @@ Datum               xpath_bool(PG_FUNCTION_ARGS);
 Datum          xpath_list(PG_FUNCTION_ARGS);
 Datum          xpath_table(PG_FUNCTION_ARGS);
 
-/* these are exported for use by xslt_proc.c */
+/* exported for use by xslt_proc.c */
 
-void           elog_error(const char *explain, bool force);
 void           pgxml_parser_init(void);
 
 /* local declarations */
 
-static void pgxml_errorHandler(void *ctxt, const char *msg,...);
-
 static xmlChar *pgxmlNodeSetToText(xmlNodeSetPtr nodeset,
                                   xmlChar *toptagname, xmlChar *septagname,
                                   xmlChar *plainsep);
@@ -50,74 +48,17 @@ static xmlChar *pgxml_texttoxmlchar(text *textstring);
 
 static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath);
 
-/* Global variables */
-static char *pgxml_errorMsg = NULL;            /* overall error message */
-
 #define GET_STR(textp) DatumGetCString(DirectFunctionCall1(textout, PointerGetDatum(textp)))
 
 
-/*
- * The error handling function. This formats an error message and sets
- * a flag - an ereport will be issued prior to return
- */
-static void
-pgxml_errorHandler(void *ctxt, const char *msg,...)
-{
-       char            errbuf[1024];                           /* per line error buffer */
-       va_list         args;
-
-       /* Format the message */
-       va_start(args, msg);
-       vsnprintf(errbuf, sizeof(errbuf), msg, args);
-       va_end(args);
-       /* Store in, or append to, pgxml_errorMsg */
-       if (pgxml_errorMsg == NULL)
-               pgxml_errorMsg = pstrdup(errbuf);
-       else
-       {
-               size_t  oldsize = strlen(pgxml_errorMsg);
-               size_t  newsize = strlen(errbuf);
-
-               /*
-                * We intentionally discard the last char of the existing message,
-                * which should be a carriage return.  (XXX wouldn't it be saner
-                * to keep it?)
-                */
-               pgxml_errorMsg = repalloc(pgxml_errorMsg, oldsize + newsize);
-               memcpy(&pgxml_errorMsg[oldsize - 1], errbuf, newsize);
-               pgxml_errorMsg[oldsize + newsize - 1] = '\0';
-       }
-}
-
-/*
- * This function ereports the current message if any.  If force is true
- * then an error is thrown even if pgxml_errorMsg hasn't been set.
- */
-void
-elog_error(const char *explain, bool force)
-{
-       if (force || pgxml_errorMsg != NULL)
-       {
-               if (pgxml_errorMsg == NULL)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
-                                        errmsg("%s", explain)));
-               else
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_EXTERNAL_ROUTINE_EXCEPTION),
-                                        errmsg("%s: %s", explain, pgxml_errorMsg)));
-       }
-}
-
 /*
  * Initialize for xml parsing.
  */
 void
 pgxml_parser_init(void)
 {
-       /* Set up error handling */
-       pgxml_errorMsg = NULL;
-       xmlSetGenericErrorFunc(NULL, pgxml_errorHandler);
+       /* Set up error handling (we share the core's error handler) */
+       pg_xml_init();
 
        /* Initialize libxml */
        xmlInitParser();
@@ -474,7 +415,8 @@ pgxml_xpath(text *document, xmlChar *xpath)
        if (comppath == NULL)
        {
                xmlFreeDoc(doctree);
-               elog_error("XPath Syntax Error", true);
+               xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+                                       "XPath Syntax Error");
        }
 
        /* Now evaluate the path expression. */
@@ -531,8 +473,6 @@ pgxml_result_to_text(xmlXPathObjectPtr res,
        /* Free various storage */
        xmlFree(xpresstr);
 
-       elog_error("XPath error", false);
-
        return xpres;
 }
 
@@ -701,10 +641,8 @@ xpath_table(PG_FUNCTION_ARGS)
        }
 
        /*
-        * Setup the parser. Beware that this must happen in the same context as
-        * the cleanup - which means that any error from here on must do cleanup
-        * to ensure that the entity table doesn't get freed by being out of
-        * context.
+        * Setup the parser.  This should happen after we are done evaluating
+        * the query, in case it calls functions that set up libxml differently.
         */
        pgxml_parser_init();
 
@@ -761,14 +699,14 @@ xpath_table(PG_FUNCTION_ARGS)
                                {
                                        ctxt = xmlXPathNewContext(doctree);
                                        ctxt->node = xmlDocGetRootElement(doctree);
-                                       xmlSetGenericErrorFunc(ctxt, pgxml_errorHandler);
 
                                        /* compile the path */
                                        comppath = xmlXPathCompile(xpaths[j]);
                                        if (comppath == NULL)
                                        {
                                                xmlFreeDoc(doctree);
-                                               elog_error("XPath Syntax Error", true);
+                                               xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+                                                                       "XPath Syntax Error");
                                        }
 
                                        /* Now evaluate the path expression. */
index 120a7bb2008c68e5a75c6dc2210415cf3f69cf9f..830acd42f8c9eef27ebdca58c61895610ff2a012 100644 (file)
@@ -6,6 +6,7 @@
 #include "executor/spi.h"
 #include "funcapi.h"
 #include "miscadmin.h"
+#include "utils/xml.h"
 
 #ifdef USE_LIBXSLT
 
@@ -32,7 +33,6 @@ Datum         xslt_process(PG_FUNCTION_ARGS);
 #ifdef USE_LIBXSLT
 
 /* declarations to come from xpath.c */
-extern void elog_error(const char *explain, bool force);
 extern void pgxml_parser_init(void);
 
 /* local defs */
@@ -86,11 +86,8 @@ xslt_process(PG_FUNCTION_ARGS)
                doctree = xmlParseFile(GET_STR(doct));
 
        if (doctree == NULL)
-       {
-               elog_error("error parsing XML document", false);
-
-               PG_RETURN_NULL();
-       }
+               xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+                                       "error parsing XML document");
 
        /* Same for stylesheet */
        if (VARDATA(ssheet)[0] == '<')
@@ -100,8 +97,8 @@ xslt_process(PG_FUNCTION_ARGS)
                if (ssdoc == NULL)
                {
                        xmlFreeDoc(doctree);
-                       elog_error("error parsing stylesheet as XML document", false);
-                       PG_RETURN_NULL();
+                       xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+                                               "error parsing stylesheet as XML document");
                }
 
                stylesheet = xsltParseStylesheetDoc(ssdoc);
@@ -114,8 +111,8 @@ xslt_process(PG_FUNCTION_ARGS)
        {
                xmlFreeDoc(doctree);
                xsltCleanupGlobals();
-               elog_error("failed to parse stylesheet", false);
-               PG_RETURN_NULL();
+               xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
+                                       "failed to parse stylesheet");
        }
 
        restree = xsltApplyStylesheet(stylesheet, doctree, params);