]> 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:22 +0000 (19:10 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 3 Mar 2010 19:10:22 +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 1ce031fa37f49da6739948c5869b414bdc6477c9..5fcfa7b1e184366f1c71cc3ce5778ead6c8ad237 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $PostgreSQL: pgsql/contrib/xml2/xpath.c,v 1.28 2010/03/01 05:16:35 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/xml2/xpath.c,v 1.29 2010/03/03 19:10:22 tgl Exp $
  *
  * Parser interface for DOM-based parser (libxml) rather than
  * stream-based SAX-type parser
@@ -12,6 +12,7 @@
 #include "lib/stringinfo.h"
 #include "miscadmin.h"
 #include "utils/builtins.h"
+#include "utils/xml.h"
 
 /* libxml includes */
 
@@ -35,15 +36,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);
@@ -55,62 +53,6 @@ static xmlChar *pgxml_texttoxmlchar(text *textstring);
 
 static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath);
 
-/* Global variables */
-static char *pgxml_errorMsg = NULL;            /* overall error message */
-
-
-/*
- * 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.
@@ -118,9 +60,8 @@ elog_error(const char *explain, bool force)
 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();
@@ -466,7 +407,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. */
@@ -519,8 +461,6 @@ pgxml_result_to_text(xmlXPathObjectPtr res,
        /* Free various storage */
        xmlFree(xpresstr);
 
-       elog_error("XPath error", false);
-
        return xpres;
 }
 
@@ -691,10 +631,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();
 
@@ -751,14 +689,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 9b71766fcebd8275637278a730835c45bf582f4a..8bd9e401fa20a1a744518e3aac2590cc03414b05 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $PostgreSQL: pgsql/contrib/xml2/xslt_proc.c,v 1.19 2010/03/01 18:07:59 tgl Exp $
+ * $PostgreSQL: pgsql/contrib/xml2/xslt_proc.c,v 1.20 2010/03/03 19:10:22 tgl Exp $
  *
  * XSLT processing functions (requiring libxslt)
  *
@@ -12,6 +12,7 @@
 #include "funcapi.h"
 #include "miscadmin.h"
 #include "utils/builtins.h"
+#include "utils/xml.h"
 
 #ifdef USE_LIBXSLT
 
@@ -38,7 +39,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 */
@@ -88,11 +88,8 @@ xslt_process(PG_FUNCTION_ARGS)
                doctree = xmlParseFile(text_to_cstring(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] == '<')
@@ -102,8 +99,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);
@@ -116,8 +113,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);