Bring some order and sanity to error handling in the xml patch.
Use a TRY block instead of (inadequate) ad-hoc coding to ensure that libxml is cleaned up after a failure. Report the intended SQLCODE instead of defaulting to XX000. Avoid risking use of a dangling pointer by keeping the persistent error buffer in TopMemoryContext. Be less trusting that error messages don't contain %. This patch doesn't do anything about changing the way the messages are put together --- this is just about mechanism.
This commit is contained in:
parent
e9da20ab4d
commit
57f1630cf0
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.4 2006/12/24 00:57:48 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.5 2006/12/24 18:25:58 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -19,7 +19,8 @@
|
|||||||
* fail. For one thing, this avoids having to manage variant catalog
|
* fail. For one thing, this avoids having to manage variant catalog
|
||||||
* installations. But it also has nice effects such as that you can
|
* installations. But it also has nice effects such as that you can
|
||||||
* dump a database containing XML type data even if the server is not
|
* dump a database containing XML type data even if the server is not
|
||||||
* linked with libxml.
|
* linked with libxml. Thus, make sure xml_out() works even if nothing
|
||||||
|
* else does.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "postgres.h"
|
#include "postgres.h"
|
||||||
@ -36,6 +37,7 @@
|
|||||||
#include "mb/pg_wchar.h"
|
#include "mb/pg_wchar.h"
|
||||||
#include "nodes/execnodes.h"
|
#include "nodes/execnodes.h"
|
||||||
#include "utils/builtins.h"
|
#include "utils/builtins.h"
|
||||||
|
#include "utils/memutils.h"
|
||||||
#include "utils/xml.h"
|
#include "utils/xml.h"
|
||||||
|
|
||||||
|
|
||||||
@ -43,28 +45,27 @@
|
|||||||
|
|
||||||
#define PG_XML_DEFAULT_URI "dummy.xml"
|
#define PG_XML_DEFAULT_URI "dummy.xml"
|
||||||
|
|
||||||
|
static StringInfo xml_err_buf = NULL;
|
||||||
|
|
||||||
static void xml_init(void);
|
static void xml_init(void);
|
||||||
static void *xml_palloc(size_t size);
|
static void *xml_palloc(size_t size);
|
||||||
static void *xml_repalloc(void *ptr, size_t size);
|
static void *xml_repalloc(void *ptr, size_t size);
|
||||||
static void xml_pfree(void *ptr);
|
static void xml_pfree(void *ptr);
|
||||||
static char *xml_pstrdup(const char *string);
|
static char *xml_pstrdup(const char *string);
|
||||||
static void xml_ereport(int level, char *msg, void *ctxt);
|
static void xml_ereport(int level, int sqlcode,
|
||||||
|
const char *msg, void *ctxt);
|
||||||
static void xml_errorHandler(void *ctxt, const char *msg, ...);
|
static void xml_errorHandler(void *ctxt, const char *msg, ...);
|
||||||
static void xml_ereport_by_code(int level, char *msg, int errcode);
|
static void xml_ereport_by_code(int level, int sqlcode,
|
||||||
|
const char *msg, int errcode);
|
||||||
static xmlChar *xml_text2xmlChar(text *in);
|
static xmlChar *xml_text2xmlChar(text *in);
|
||||||
static xmlDocPtr xml_parse(text *data, int opts, bool is_document);
|
static xmlDocPtr xml_parse(text *data, int opts, bool is_document);
|
||||||
|
|
||||||
|
|
||||||
/* Global variables */
|
|
||||||
/* taken from contrib/xml2 */
|
|
||||||
/* FIXME: DO NOT USE global vars !!! */
|
|
||||||
static char *xml_errmsg = NULL; /* overall error message */
|
|
||||||
|
|
||||||
#endif /* USE_LIBXML */
|
#endif /* USE_LIBXML */
|
||||||
|
|
||||||
|
#define NO_XML_SUPPORT() \
|
||||||
#define NO_XML_SUPPORT() ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("no XML support in this installation")))
|
ereport(ERROR, \
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED), \
|
||||||
|
errmsg("no XML support in this installation")))
|
||||||
|
|
||||||
|
|
||||||
Datum
|
Datum
|
||||||
@ -292,54 +293,80 @@ xmlvalidate(PG_FUNCTION_ARGS)
|
|||||||
#ifdef USE_LIBXML
|
#ifdef USE_LIBXML
|
||||||
text *data = PG_GETARG_TEXT_P(0);
|
text *data = PG_GETARG_TEXT_P(0);
|
||||||
text *dtdOrUri = PG_GETARG_TEXT_P(1);
|
text *dtdOrUri = PG_GETARG_TEXT_P(1);
|
||||||
bool result = FALSE;
|
bool result = false;
|
||||||
xmlParserCtxtPtr ctxt; /* the parser context */
|
xmlParserCtxtPtr ctxt = NULL;
|
||||||
xmlDocPtr doc; /* the resulting document tree */
|
xmlDocPtr doc = NULL;
|
||||||
xmlDtdPtr dtd;
|
xmlDtdPtr dtd = NULL;
|
||||||
|
|
||||||
xml_init();
|
xml_init();
|
||||||
|
|
||||||
ctxt = xmlNewParserCtxt();
|
/* We use a PG_TRY block to ensure libxml is cleaned up on error */
|
||||||
if (ctxt == NULL)
|
PG_TRY();
|
||||||
xml_ereport(ERROR, "could not allocate parser context", ctxt);
|
{
|
||||||
doc = xmlCtxtReadMemory(ctxt, (char *) VARDATA(data),
|
ctxt = xmlNewParserCtxt();
|
||||||
VARSIZE(data) - VARHDRSZ, PG_XML_DEFAULT_URI, NULL, 0);
|
if (ctxt == NULL)
|
||||||
if (doc == NULL)
|
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
|
||||||
xml_ereport(ERROR, "could not parse XML data", ctxt);
|
"could not allocate parser context", ctxt);
|
||||||
|
|
||||||
|
doc = xmlCtxtReadMemory(ctxt, (char *) VARDATA(data),
|
||||||
|
VARSIZE(data) - VARHDRSZ,
|
||||||
|
PG_XML_DEFAULT_URI, NULL, 0);
|
||||||
|
if (doc == NULL)
|
||||||
|
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
||||||
|
"could not parse XML data", ctxt);
|
||||||
|
|
||||||
#if 0
|
#if 0
|
||||||
uri = xmlCreateURI();
|
uri = xmlCreateURI();
|
||||||
ereport(NOTICE, (errcode(0),errmsg(" dtd - %s", dtdOrUri)));
|
elog(NOTICE, "dtd - %s", dtdOrUri);
|
||||||
dtd = palloc(sizeof(xmlDtdPtr));
|
dtd = palloc(sizeof(xmlDtdPtr));
|
||||||
uri = xmlParseURI(dtdOrUri);
|
uri = xmlParseURI(dtdOrUri);
|
||||||
if (uri == NULL)
|
if (uri == NULL)
|
||||||
xml_ereport(ERROR, "not implemented yet... (TODO)", ctxt);
|
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
|
||||||
else
|
"not implemented yet... (TODO)", ctxt);
|
||||||
|
else
|
||||||
#endif
|
#endif
|
||||||
dtd = xmlParseDTD(NULL, xml_text2xmlChar(dtdOrUri));
|
dtd = xmlParseDTD(NULL, xml_text2xmlChar(dtdOrUri));
|
||||||
|
|
||||||
if (dtd == NULL)
|
if (dtd == NULL)
|
||||||
|
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
||||||
|
"could not load DTD", ctxt);
|
||||||
|
|
||||||
|
if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) == 1)
|
||||||
|
result = true;
|
||||||
|
|
||||||
|
if (!result)
|
||||||
|
xml_ereport(NOTICE, ERRCODE_INVALID_XML_DOCUMENT,
|
||||||
|
"validation against DTD failed", ctxt);
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
if (uri)
|
||||||
|
xmlFreeURI(uri);
|
||||||
|
#endif
|
||||||
|
if (dtd)
|
||||||
|
xmlFreeDtd(dtd);
|
||||||
|
if (doc)
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
if (ctxt)
|
||||||
|
xmlFreeParserCtxt(ctxt);
|
||||||
|
xmlCleanupParser();
|
||||||
|
}
|
||||||
|
PG_CATCH();
|
||||||
{
|
{
|
||||||
#if 0
|
#if 0
|
||||||
xmlFreeDoc(doc);
|
if (uri)
|
||||||
xmlFreeParserCtxt(ctxt);
|
xmlFreeURI(uri);
|
||||||
#endif
|
#endif
|
||||||
xml_ereport(ERROR, "could not load DTD", ctxt);
|
if (dtd)
|
||||||
|
xmlFreeDtd(dtd);
|
||||||
|
if (doc)
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
if (ctxt)
|
||||||
|
xmlFreeParserCtxt(ctxt);
|
||||||
|
xmlCleanupParser();
|
||||||
|
|
||||||
|
PG_RE_THROW();
|
||||||
}
|
}
|
||||||
|
PG_END_TRY();
|
||||||
if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) == 1)
|
|
||||||
result = TRUE;
|
|
||||||
|
|
||||||
#if 0
|
|
||||||
xmlFreeURI(uri);
|
|
||||||
xmlFreeDtd(dtd);
|
|
||||||
xmlFreeDoc(doc);
|
|
||||||
xmlFreeParserCtxt(ctxt);
|
|
||||||
xmlCleanupParser();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (!result)
|
|
||||||
xml_ereport(NOTICE, "validation against DTD failed", ctxt);
|
|
||||||
|
|
||||||
PG_RETURN_BOOL(result);
|
PG_RETURN_BOOL(result);
|
||||||
#else /* not USE_LIBXML */
|
#else /* not USE_LIBXML */
|
||||||
@ -368,12 +395,27 @@ xml_init(void)
|
|||||||
errdetail("libxml2 has incompatible char type: sizeof(char)=%u, sizeof(xmlChar)=%u.",
|
errdetail("libxml2 has incompatible char type: sizeof(char)=%u, sizeof(xmlChar)=%u.",
|
||||||
(int) sizeof(char), (int) sizeof(xmlChar))));
|
(int) sizeof(char), (int) sizeof(xmlChar))));
|
||||||
|
|
||||||
|
if (xml_err_buf == NULL)
|
||||||
|
{
|
||||||
|
/* First time through: create error buffer in permanent context */
|
||||||
|
MemoryContext oldcontext;
|
||||||
|
|
||||||
|
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
|
||||||
|
xml_err_buf = makeStringInfo();
|
||||||
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Reset pre-existing buffer to empty */
|
||||||
|
xml_err_buf->data[0] = '\0';
|
||||||
|
xml_err_buf->len = 0;
|
||||||
|
}
|
||||||
|
/* Now that xml_err_buf exists, safe to call xml_errorHandler */
|
||||||
|
xmlSetGenericErrorFunc(NULL, xml_errorHandler);
|
||||||
|
|
||||||
xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
|
xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
|
||||||
xmlInitParser();
|
xmlInitParser();
|
||||||
LIBXML_TEST_VERSION;
|
LIBXML_TEST_VERSION;
|
||||||
/* do not flood PG's logfile with libxml error messages - reset error handler*/
|
|
||||||
xmlSetGenericErrorFunc(NULL, xml_errorHandler);
|
|
||||||
xml_errmsg = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -391,106 +433,115 @@ xml_init(void)
|
|||||||
static xmlDocPtr
|
static xmlDocPtr
|
||||||
xml_parse(text *data, int opts, bool is_document)
|
xml_parse(text *data, int opts, bool is_document)
|
||||||
{
|
{
|
||||||
bool validationFailed = FALSE;
|
bool validationFailed = false;
|
||||||
xmlParserCtxtPtr ctxt; /* the parser context */
|
|
||||||
xmlDocPtr doc; /* the resulting document tree */
|
|
||||||
int res_code;
|
int res_code;
|
||||||
int32 len;
|
int32 len;
|
||||||
xmlChar *string;
|
xmlChar *string;
|
||||||
|
xmlParserCtxtPtr ctxt = NULL;
|
||||||
|
xmlDocPtr doc = NULL;
|
||||||
#ifdef XML_DEBUG_DTD_CONST
|
#ifdef XML_DEBUG_DTD_CONST
|
||||||
xmlDtdPtr dtd; /* pointer to DTD */
|
xmlDtdPtr dtd = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
xml_init();
|
|
||||||
|
|
||||||
len = VARSIZE(data) - VARHDRSZ; /* will be useful later */
|
len = VARSIZE(data) - VARHDRSZ; /* will be useful later */
|
||||||
string = xml_text2xmlChar(data);
|
string = xml_text2xmlChar(data);
|
||||||
|
|
||||||
ctxt = xmlNewParserCtxt();
|
xml_init();
|
||||||
if (ctxt == NULL)
|
|
||||||
xml_ereport(ERROR, "could not allocate parser context", ctxt);
|
|
||||||
|
|
||||||
/* first, we try to parse the string as XML doc, then, as XML chunk */
|
/* We use a PG_TRY block to ensure libxml is cleaned up on error */
|
||||||
ereport(DEBUG3, (errmsg("string to parse: %s", string)));
|
PG_TRY();
|
||||||
if (len >= 5 && strncmp((char *) string, "<?xml", 5) == 0)
|
|
||||||
{
|
{
|
||||||
/* consider it as DOCUMENT */
|
ctxt = xmlNewParserCtxt();
|
||||||
doc = xmlCtxtReadMemory(ctxt, (char *) string, len,
|
if (ctxt == NULL)
|
||||||
PG_XML_DEFAULT_URI, NULL, opts);
|
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
|
||||||
if (doc == NULL)
|
"could not allocate parser context", ctxt);
|
||||||
|
|
||||||
|
/* first, we try to parse the string as XML doc, then, as XML chunk */
|
||||||
|
if (len >= 5 && strncmp((char *) string, "<?xml", 5) == 0)
|
||||||
{
|
{
|
||||||
xml_ereport(ERROR, "could not parse XML data", ctxt);
|
/* consider it as DOCUMENT */
|
||||||
#if 0
|
doc = xmlCtxtReadMemory(ctxt, (char *) string, len,
|
||||||
xmlFreeParserCtxt(ctxt);
|
PG_XML_DEFAULT_URI, NULL, opts);
|
||||||
xmlCleanupParser();
|
if (doc == NULL)
|
||||||
ereport(ERROR, (errmsg("could not parse XML data")));
|
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
||||||
#endif
|
"could not parse XML data", ctxt);
|
||||||
}
|
}
|
||||||
}
|
else
|
||||||
else
|
|
||||||
{
|
|
||||||
/* attempt to parse the string as if it is an XML fragment */
|
|
||||||
ereport(DEBUG3, (errmsg("the string is not an XML doc, trying to parse as a CHUNK")));
|
|
||||||
doc = xmlNewDoc(NULL);
|
|
||||||
/* TODO resolve: xmlParseBalancedChunkMemory assumes that string is UTF8 encoded! */
|
|
||||||
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, string, NULL);
|
|
||||||
if (res_code != 0)
|
|
||||||
{
|
{
|
||||||
xmlFreeParserCtxt(ctxt);
|
/* attempt to parse the string as if it is an XML fragment */
|
||||||
xmlCleanupParser();
|
doc = xmlNewDoc(NULL);
|
||||||
xml_ereport_by_code(ERROR, "could not parse XML data", res_code);
|
/* TODO resolve: xmlParseBalancedChunkMemory assumes that string is UTF8 encoded! */
|
||||||
|
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, string, NULL);
|
||||||
|
if (res_code != 0)
|
||||||
|
xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
||||||
|
"could not parse XML data", res_code);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef XML_DEBUG_DTD_CONST
|
#ifdef XML_DEBUG_DTD_CONST
|
||||||
dtd = xmlParseDTD(NULL, (xmlChar *) XML_DEBUG_DTD_CONST);
|
dtd = xmlParseDTD(NULL, (xmlChar *) XML_DEBUG_DTD_CONST);
|
||||||
xml_ereport(DEBUG3, "solid path to DTD was defined for debugging purposes", ctxt);
|
if (dtd == NULL)
|
||||||
if (dtd == NULL)
|
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
||||||
{
|
"could not parse DTD data", ctxt);
|
||||||
xml_ereport(ERROR, "could not parse DTD data", ctxt);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
#else
|
|
||||||
/* if dtd for our xml data is detected... */
|
|
||||||
if ((doc->intSubset != NULL) || (doc->extSubset != NULL))
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
/* assume that inline DTD exists - validation should be performed */
|
|
||||||
#ifdef XML_DEBUG_DTD_CONST
|
|
||||||
if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) != 1)
|
if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) != 1)
|
||||||
|
validationFailed = true;
|
||||||
#else
|
#else
|
||||||
if (ctxt->valid == 0)
|
/* if dtd for our xml data is detected... */
|
||||||
#endif
|
if ((doc->intSubset != NULL) || (doc->extSubset != NULL))
|
||||||
{
|
{
|
||||||
/* DTD exists, but validator reported 'validation failed' */
|
/* assume inline DTD exists - validation should be performed */
|
||||||
validationFailed = TRUE;
|
if (ctxt->valid == 0)
|
||||||
|
{
|
||||||
|
/* DTD exists, but validator reported 'validation failed' */
|
||||||
|
validationFailed = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (validationFailed)
|
||||||
|
xml_ereport(WARNING, ERRCODE_INVALID_XML_DOCUMENT,
|
||||||
|
"validation against DTD failed", ctxt);
|
||||||
|
|
||||||
|
/* TODO encoding issues
|
||||||
|
* (thoughts:
|
||||||
|
* CASE:
|
||||||
|
* - XML data has explicit encoding attribute in its prolog
|
||||||
|
* - if not, assume that enc. of XML data is the same as client's one
|
||||||
|
*
|
||||||
|
* The common rule is to accept the XML data only if its encoding
|
||||||
|
* is the same as encoding of the storage (server's). The other possible
|
||||||
|
* option is to accept all the docs, but DO TRANSFORMATION and, if needed,
|
||||||
|
* change the prolog.
|
||||||
|
*
|
||||||
|
* I think I'd stick the first way (for the 1st version),
|
||||||
|
* it's much simplier (less errors...)
|
||||||
|
* ) */
|
||||||
|
/* ... */
|
||||||
|
|
||||||
|
#ifdef XML_DEBUG_DTD_CONST
|
||||||
|
if (dtd)
|
||||||
|
xmlFreeDtd(dtd);
|
||||||
|
#endif
|
||||||
|
if (doc)
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
if (ctxt)
|
||||||
|
xmlFreeParserCtxt(ctxt);
|
||||||
|
xmlCleanupParser();
|
||||||
}
|
}
|
||||||
|
PG_CATCH();
|
||||||
|
{
|
||||||
|
#ifdef XML_DEBUG_DTD_CONST
|
||||||
|
if (dtd)
|
||||||
|
xmlFreeDtd(dtd);
|
||||||
|
#endif
|
||||||
|
if (doc)
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
if (ctxt)
|
||||||
|
xmlFreeParserCtxt(ctxt);
|
||||||
|
xmlCleanupParser();
|
||||||
|
|
||||||
if (validationFailed)
|
PG_RE_THROW();
|
||||||
xml_ereport(WARNING, "validation against DTD failed", ctxt);
|
}
|
||||||
|
PG_END_TRY();
|
||||||
/* TODO encoding issues
|
|
||||||
* (thoughts:
|
|
||||||
* CASE:
|
|
||||||
* - XML data has explicit encoding attribute in its prolog
|
|
||||||
* - if not, assume that enc. of XML data is the same as client's one
|
|
||||||
*
|
|
||||||
* The common rule is to accept the XML data only if its encoding
|
|
||||||
* is the same as encoding of the storage (server's). The other possible
|
|
||||||
* option is to accept all the docs, but DO TRANSFORMATION and, if needed,
|
|
||||||
* change the prolog.
|
|
||||||
*
|
|
||||||
* I think I'd stick the first way (for the 1st version),
|
|
||||||
* it's much simplier (less errors...)
|
|
||||||
* ) */
|
|
||||||
/* ... */
|
|
||||||
|
|
||||||
xmlFreeParserCtxt(ctxt);
|
|
||||||
xmlCleanupParser();
|
|
||||||
|
|
||||||
ereport(DEBUG3, (errmsg("XML data successfully parsed, encoding: %s",
|
|
||||||
(char *) doc->encoding)));
|
|
||||||
|
|
||||||
return doc;
|
return doc;
|
||||||
}
|
}
|
||||||
@ -549,17 +600,17 @@ xml_pstrdup(const char *string)
|
|||||||
* Adds detail - libxml's native error message, if any.
|
* Adds detail - libxml's native error message, if any.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
xml_ereport(int level, char *msg, void *ctxt)
|
xml_ereport(int level, int sqlcode,
|
||||||
|
const char *msg, void *ctxt)
|
||||||
{
|
{
|
||||||
char *xmlErrDetail;
|
|
||||||
int xmlErrLen, i;
|
|
||||||
xmlErrorPtr libxmlErr = NULL;
|
xmlErrorPtr libxmlErr = NULL;
|
||||||
|
|
||||||
if (xml_errmsg != NULL)
|
if (xml_err_buf->len > 0)
|
||||||
{
|
{
|
||||||
ereport(DEBUG1, (errmsg("%s", xml_errmsg)));
|
ereport(DEBUG1,
|
||||||
pfree(xml_errmsg);
|
(errmsg("%s", xml_err_buf->data)));
|
||||||
xml_errmsg = NULL;
|
xml_err_buf->data[0] = '\0';
|
||||||
|
xml_err_buf->len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ctxt != NULL)
|
if (ctxt != NULL)
|
||||||
@ -567,31 +618,27 @@ xml_ereport(int level, char *msg, void *ctxt)
|
|||||||
|
|
||||||
if (libxmlErr == NULL)
|
if (libxmlErr == NULL)
|
||||||
{
|
{
|
||||||
if (level == ERROR)
|
ereport(level,
|
||||||
{
|
(errcode(sqlcode),
|
||||||
xmlFreeParserCtxt(ctxt);
|
errmsg("%s", msg)));
|
||||||
xmlCleanupParser();
|
|
||||||
}
|
|
||||||
ereport(level, (errmsg(msg)));
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* as usual, libxml error message contains '\n'; get rid of it */
|
/* as usual, libxml error message contains '\n'; get rid of it */
|
||||||
xmlErrLen = strlen(libxmlErr->message); /* - 1; */
|
char *xmlErrDetail;
|
||||||
xmlErrDetail = (char *) palloc(xmlErrLen);
|
int xmlErrLen, i;
|
||||||
|
|
||||||
|
xmlErrDetail = pstrdup(libxmlErr->message);
|
||||||
|
xmlErrLen = strlen(xmlErrDetail);
|
||||||
for (i = 0; i < xmlErrLen; i++)
|
for (i = 0; i < xmlErrLen; i++)
|
||||||
{
|
{
|
||||||
if (libxmlErr->message[i] == '\n')
|
if (xmlErrDetail[i] == '\n')
|
||||||
xmlErrDetail[i] = '.';
|
xmlErrDetail[i] = '.';
|
||||||
else
|
|
||||||
xmlErrDetail[i] = libxmlErr->message[i];
|
|
||||||
}
|
}
|
||||||
if (level == ERROR)
|
ereport(level,
|
||||||
{
|
(errcode(sqlcode),
|
||||||
xmlFreeParserCtxt(ctxt);
|
errmsg("%s", msg),
|
||||||
xmlCleanupParser();
|
errdetail("%s", xmlErrDetail)));
|
||||||
}
|
|
||||||
ereport(level, (errmsg(msg), errdetail("%s", xmlErrDetail)));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -602,25 +649,22 @@ xml_ereport(int level, char *msg, void *ctxt)
|
|||||||
static void
|
static void
|
||||||
xml_errorHandler(void *ctxt, const char *msg,...)
|
xml_errorHandler(void *ctxt, const char *msg,...)
|
||||||
{
|
{
|
||||||
char xml_errbuf[256];
|
/* Append the formatted text to xml_err_buf */
|
||||||
va_list args;
|
for (;;)
|
||||||
|
|
||||||
/* Format this message ... */
|
|
||||||
va_start(args, msg);
|
|
||||||
vsnprintf(xml_errbuf, sizeof(xml_errbuf)-1, msg, args);
|
|
||||||
va_end(args);
|
|
||||||
xml_errbuf[sizeof(xml_errbuf)-1] = '\0';
|
|
||||||
|
|
||||||
/* ... and append to xml_errbuf */
|
|
||||||
if (xml_errmsg == NULL)
|
|
||||||
xml_errmsg = pstrdup(xml_errbuf);
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
int32 xsize = strlen(xml_errmsg);
|
va_list args;
|
||||||
|
bool success;
|
||||||
|
|
||||||
xml_errmsg = repalloc(xml_errmsg,
|
/* Try to format the data. */
|
||||||
(size_t) (xsize + strlen(xml_errbuf) + 1));
|
va_start(args, msg);
|
||||||
strcpy(&xml_errmsg[xsize - 1], xml_errbuf);
|
success = appendStringInfoVA(xml_err_buf, msg, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (success)
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Double the buffer size and try again. */
|
||||||
|
enlargeStringInfo(xml_err_buf, xml_err_buf->maxlen);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -630,17 +674,21 @@ xml_errorHandler(void *ctxt, const char *msg,...)
|
|||||||
* TODO make them closer to recommendations from Postgres manual
|
* TODO make them closer to recommendations from Postgres manual
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
xml_ereport_by_code(int level, char *msg, int code)
|
xml_ereport_by_code(int level, int sqlcode,
|
||||||
|
const char *msg, int code)
|
||||||
{
|
{
|
||||||
const char *det;
|
const char *det;
|
||||||
|
|
||||||
if (code < 0)
|
if (xml_err_buf->len > 0)
|
||||||
{
|
{
|
||||||
ereport(level, (errmsg(msg)));
|
ereport(DEBUG1,
|
||||||
return;
|
(errmsg("%s", xml_err_buf->data)));
|
||||||
|
xml_err_buf->data[0] = '\0';
|
||||||
|
xml_err_buf->len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (code) {
|
switch (code)
|
||||||
|
{
|
||||||
case XML_ERR_INTERNAL_ERROR:
|
case XML_ERR_INTERNAL_ERROR:
|
||||||
det = "libxml internal error";
|
det = "libxml internal error";
|
||||||
break;
|
break;
|
||||||
@ -799,19 +847,14 @@ xml_ereport_by_code(int level, char *msg, int code)
|
|||||||
det = "Closing tag not found";
|
det = "Closing tag not found";
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
det = "Unregistered error (libxml error code: %d)";
|
det = "Unrecognized libxml error code: %d";
|
||||||
ereport(DEBUG1,
|
break;
|
||||||
(errmsg_internal("Check out \"libxml/xmlerror.h\" and bring errcode \"%d\" processing to \"xml.c\".", code)));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (xml_errmsg != NULL)
|
|
||||||
{
|
|
||||||
ereport(DEBUG1, (errmsg("%s", xml_errmsg)));
|
|
||||||
pfree(xml_errmsg);
|
|
||||||
xml_errmsg = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ereport(level, (errmsg(msg), errdetail(det, code)));
|
ereport(level,
|
||||||
|
(errcode(sqlcode),
|
||||||
|
errmsg("%s", msg),
|
||||||
|
errdetail(det, code)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user