From 5e47403be31fb7501ba6fb6ebda82300a10cf8b2 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 3 Mar 2010 19:10:22 +0000 Subject: [PATCH] Make contrib/xml2 use core xml.c's error handler, when available (that is, 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 | 84 ++++++---------------------------------- contrib/xml2/xslt_proc.c | 19 ++++----- 2 files changed, 19 insertions(+), 84 deletions(-) diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 1ce031fa37..5fcfa7b1e1 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -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. */ diff --git a/contrib/xml2/xslt_proc.c b/contrib/xml2/xslt_proc.c index 9b71766fce..8bd9e401fa 100644 --- a/contrib/xml2/xslt_proc.c +++ b/contrib/xml2/xslt_proc.c @@ -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); -- 2.40.0