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.
This commit is contained in:
Tom Lane 2010-03-03 19:10:22 +00:00
parent 8bf14182cf
commit 5e47403be3
2 changed files with 19 additions and 84 deletions

View 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. */

View 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);