pg_xml_errorhandling.v2.patch
application/octet-stream
Filename: pg_xml_errorhandling.v2.patch
Type: application/octet-stream
Part: 0
diff --git a/configure b/configure
index 9b8cb48..c4c535c 100755
*** a/configure
--- b/configure
*************** with_gnu_ld
*** 850,855 ****
--- 850,856 ----
enable_largefile
enable_float4_byval
enable_float8_byval
+ enable_float8_byval
'
ac_precious_vars='build_alias
host_alias
*************** LDFLAGS
*** 860,865 ****
--- 861,867 ----
LIBS
CPPFLAGS
CPP
+ CPPFLAGS
LDFLAGS_EX
LDFLAGS_SL
DOCBOOKSTYLE'
*************** done
*** 5740,5745 ****
--- 5742,5812 ----
esac
done
fi
+
+ # Cannot use AC_CHECK_FUNC because xmlStructuredErrorContext may be a
+ # macro if threading support is enabled in libxml2
+ { $as_echo "$as_me:$LINENO: checking for xmlStructuredErrorContext" >&5
+ $as_echo_n "checking for xmlStructuredErrorContext... " >&6; }
+ if test "${pgac_cv_libxml_structerrctx+set}" = set; then
+ $as_echo_n "(cached) " >&6
+ else
+ cat >conftest.$ac_ext <<_ACEOF
+ /* confdefs.h. */
+ _ACEOF
+ cat confdefs.h >>conftest.$ac_ext
+ cat >>conftest.$ac_ext <<_ACEOF
+ /* end confdefs.h. */
+ #include <libxml/globals.h>
+ int
+ main ()
+ {
+ void* d = xmlStructuredErrorContext
+ ;
+ return 0;
+ }
+ _ACEOF
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { (ac_try="$ac_link"
+ case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+ esac
+ eval ac_try_echo="\"\$as_me:$LINENO: $ac_try_echo\""
+ $as_echo "$ac_try_echo") >&5
+ (eval "$ac_link") 2>conftest.er1
+ ac_status=$?
+ grep -v '^ *+' conftest.er1 >conftest.err
+ rm -f conftest.er1
+ cat conftest.err >&5
+ $as_echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_test_x conftest$ac_exeext
+ }; then
+ pgac_cv_libxml_structerrctx=yes
+ else
+ $as_echo "$as_me: failed program was:" >&5
+ sed 's/^/| /' conftest.$ac_ext >&5
+
+ pgac_cv_libxml_structerrctx=no
+ fi
+
+ rm -rf conftest.dSYM
+ rm -f core conftest.err conftest.$ac_objext conftest_ipa8_conftest.oo \
+ conftest$ac_exeext conftest.$ac_ext
+ fi
+ { $as_echo "$as_me:$LINENO: result: $pgac_cv_libxml_structerrctx" >&5
+ $as_echo "$pgac_cv_libxml_structerrctx" >&6; }
+ if test x"$pgac_cv_libxml_structerrctx" = x"yes"; then
+
+ cat >>confdefs.h <<\_ACEOF
+ #define HAVE_LIBXML2_XMLSTRUCTUREDERRORCONTEXT 1
+ _ACEOF
+
+ fi
fi
diff --git a/configure.in b/configure.in
index e873c7b..6f9f0c4 100644
*** a/configure.in
--- b/configure.in
*************** if test "$with_libxml" = yes ; then
*** 741,746 ****
--- 741,759 ----
esac
done
fi
+
+ # Cannot use AC_CHECK_FUNC because xmlStructuredErrorContext may be a
+ # macro if threading support is enabled in libxml2
+ AC_CACHE_CHECK([for xmlStructuredErrorContext], pgac_cv_libxml_structerrctx,
+ [AC_TRY_LINK([#include <libxml/globals.h>],
+ [void* d = xmlStructuredErrorContext],
+ [pgac_cv_libxml_structerrctx=yes],
+ [pgac_cv_libxml_structerrctx=no])])
+ if test x"$pgac_cv_libxml_structerrctx" = x"yes"; then
+ AC_DEFINE(HAVE_LIBXML2_XMLSTRUCTUREDERRORCONTEXT,
+ 1,
+ [Define to 1 if your libxml has xmlStructuredErrorContext.])
+ fi
fi
AC_SUBST(with_libxml)
diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c
index 44c600e..f3417ab 100644
*** a/contrib/xml2/xpath.c
--- b/contrib/xml2/xpath.c
*************** Datum xpath_table(PG_FUNCTION_ARGS);
*** 38,44 ****
/* exported for use by xslt_proc.c */
! void pgxml_parser_init(void);
/* workspace for pgxml_xpath() */
--- 38,44 ----
/* exported for use by xslt_proc.c */
! void pgxml_parser_init(PgXmlStrictnessType strictness);
/* workspace for pgxml_xpath() */
*************** static void cleanup_workspace(xpath_work
*** 70,79 ****
* Initialize for xml parsing.
*/
void
! pgxml_parser_init(void)
{
/* Set up error handling (we share the core's error handler) */
! pg_xml_init();
/* Initialize libxml */
xmlInitParser();
--- 70,79 ----
* Initialize for xml parsing.
*/
void
! pgxml_parser_init(PgXmlStrictnessType strictness)
{
/* Set up error handling (we share the core's error handler) */
! pg_xml_init_errorhandling(strictness);
/* Initialize libxml */
xmlInitParser();
*************** xml_is_well_formed(PG_FUNCTION_ARGS)
*** 100,113 ****
text *t = PG_GETARG_TEXT_P(0); /* document buffer */
int32 docsize = VARSIZE(t) - VARHDRSZ;
xmlDocPtr doctree;
! pgxml_parser_init();
doctree = xmlParseMemory((char *) VARDATA(t), docsize);
! if (doctree == NULL)
! PG_RETURN_BOOL(false); /* i.e. not well-formed */
xmlFreeDoc(doctree);
! PG_RETURN_BOOL(true);
}
--- 100,116 ----
text *t = PG_GETARG_TEXT_P(0); /* document buffer */
int32 docsize = VARSIZE(t) - VARHDRSZ;
xmlDocPtr doctree;
+ bool result;
! pgxml_parser_init(PG_XML_STRICTNESS_LEGACY);
doctree = xmlParseMemory((char *) VARDATA(t), docsize);
! result = (doctree != NULL);
xmlFreeDoc(doctree);
!
! pg_xml_done();
!
! PG_RETURN_BOOL(result);
}
*************** pgxml_xpath(text *document, xmlChar *xpa
*** 406,416 ****
workspace->ctxt = NULL;
workspace->res = NULL;
! pgxml_parser_init();
workspace->doctree = xmlParseMemory((char *) VARDATA(document), docsize);
! if (workspace->doctree == NULL)
return NULL; /* not well-formed */
workspace->ctxt = xmlXPathNewContext(workspace->doctree);
workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
--- 409,421 ----
workspace->ctxt = NULL;
workspace->res = NULL;
! pgxml_parser_init(PG_XML_STRICTNESS_LEGACY);
workspace->doctree = xmlParseMemory((char *) VARDATA(document), docsize);
! if (workspace->doctree == NULL) {
! pg_xml_done();
return NULL; /* not well-formed */
+ }
workspace->ctxt = xmlXPathNewContext(workspace->doctree);
workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree);
*************** pgxml_xpath(text *document, xmlChar *xpa
*** 420,425 ****
--- 425,431 ----
if (comppath == NULL)
{
cleanup_workspace(workspace);
+ pg_xml_done();
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"XPath Syntax Error");
}
*************** pgxml_xpath(text *document, xmlChar *xpa
*** 433,438 ****
--- 439,446 ----
if (res == NULL)
cleanup_workspace(workspace);
+ pg_xml_done();
+
return res;
}
*************** xpath_table(PG_FUNCTION_ARGS)
*** 659,665 ****
* 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();
/* For each row i.e. document returned from SPI */
for (i = 0; i < proc; i++)
--- 667,673 ----
* 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(PG_XML_STRICTNESS_LEGACY);
/* For each row i.e. document returned from SPI */
for (i = 0; i < proc; i++)
*************** xpath_table(PG_FUNCTION_ARGS)
*** 720,725 ****
--- 728,734 ----
if (comppath == NULL)
{
xmlFreeDoc(doctree);
+ pg_xml_done();
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"XPath Syntax Error");
}
*************** xpath_table(PG_FUNCTION_ARGS)
*** 784,789 ****
--- 793,800 ----
pfree(xmldoc);
}
+ pg_xml_done();
+
tuplestore_donestoring(tupstore);
SPI_finish();
diff --git a/contrib/xml2/xslt_proc.c b/contrib/xml2/xslt_proc.c
index f8f7d72..0ebca21 100644
*** a/contrib/xml2/xslt_proc.c
--- b/contrib/xml2/xslt_proc.c
*************** Datum xslt_process(PG_FUNCTION_ARGS);
*** 38,44 ****
#ifdef USE_LIBXSLT
/* declarations to come from xpath.c */
! extern void pgxml_parser_init(void);
/* local defs */
static const char **parse_params(text *paramstr);
--- 38,44 ----
#ifdef USE_LIBXSLT
/* declarations to come from xpath.c */
! extern void pgxml_parser_init(PgXmlStrictnessType strictness);
/* local defs */
static const char **parse_params(text *paramstr);
*************** xslt_process(PG_FUNCTION_ARGS)
*** 77,83 ****
}
/* Setup parser */
! pgxml_parser_init();
/* Check to see if document is a file or a literal */
--- 77,83 ----
}
/* Setup parser */
! pgxml_parser_init(PG_XML_STRICTNESS_LEGACY);
/* Check to see if document is a file or a literal */
*************** xslt_process(PG_FUNCTION_ARGS)
*** 86,94 ****
else
doctree = xmlParseFile(text_to_cstring(doct));
! if (doctree == NULL)
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"error parsing XML document");
/* Same for stylesheet */
if (VARDATA(ssheet)[0] == '<')
--- 86,96 ----
else
doctree = xmlParseFile(text_to_cstring(doct));
! if (doctree == NULL) {
! pg_xml_done();
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"error parsing XML document");
+ }
/* Same for stylesheet */
if (VARDATA(ssheet)[0] == '<')
*************** xslt_process(PG_FUNCTION_ARGS)
*** 98,103 ****
--- 100,106 ----
if (ssdoc == NULL)
{
xmlFreeDoc(doctree);
+ pg_xml_done();
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"error parsing stylesheet as XML document");
}
*************** xslt_process(PG_FUNCTION_ARGS)
*** 112,117 ****
--- 115,121 ----
{
xmlFreeDoc(doctree);
xsltCleanupGlobals();
+ pg_xml_done();
xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION,
"failed to parse stylesheet");
}
*************** xslt_process(PG_FUNCTION_ARGS)
*** 125,130 ****
--- 129,136 ----
xsltCleanupGlobals();
+ pg_xml_done();
+
if (resstat < 0)
PG_RETURN_NULL();
diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c
index 702b9e3..a09c13e 100644
*** a/src/backend/utils/adt/xml.c
--- b/src/backend/utils/adt/xml.c
*************** int xmloption;
*** 84,92 ****
#ifdef USE_LIBXML
static StringInfo xml_err_buf = NULL;
! static void xml_errorHandler(void *ctxt, const char *msg,...);
static void xml_ereport_by_code(int level, int sqlcode,
const char *msg, int errcode);
--- 84,107 ----
#ifdef USE_LIBXML
+ #define XML_CHECK_AND_EREPORT(assertion,level,sqlcode,msg) \
+ if (pg_xml_erroroccurred() || !(assertion)) { \
+ xml_ereport(level, sqlcode, msg); \
+ } \
+ else { \
+ }
+
+ static bool xml_error_initialized = false;
+ static xmlStructuredErrorFunc xml_structuredErrorFunc_saved = NULL;
+ static void* xml_structuredErrorContext_saved = NULL;
+
+ static PgXmlStrictnessType xml_strictness = PG_XML_STRICTNESS_NONE;
+ static bool xml_err_occurred;
static StringInfo xml_err_buf = NULL;
! static void xml_errorHandler(void* data, xmlErrorPtr error);
! static void appendStringInfoLineSeparator(StringInfo str);
! static void chopStringInfoNewlines(StringInfo str);
static void xml_ereport_by_code(int level, int sqlcode,
const char *msg, int errcode);
*************** xmlelement(XmlExprState *xmlExpr, ExprCo
*** 597,614 ****
}
/* now safe to run libxml */
! pg_xml_init();
PG_TRY();
{
buf = xmlBufferCreate();
! if (!buf)
! xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate xmlBuffer");
writer = xmlNewTextWriterMemory(buf, 0);
! if (!writer)
! xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate xmlTextWriter");
xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name);
--- 612,627 ----
}
/* now safe to run libxml */
! pg_xml_init(PG_XML_STRICTNESS_ALL);
PG_TRY();
{
buf = xmlBufferCreate();
! XML_CHECK_AND_EREPORT(buf != NULL, ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate xmlBuffer");
writer = xmlNewTextWriterMemory(buf, 0);
! XML_CHECK_AND_EREPORT(writer != NULL, ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate xmlTextWriter");
xmlTextWriterStartElement(writer, (xmlChar *) xexpr->name);
*************** xmlelement(XmlExprState *xmlExpr, ExprCo
*** 644,655 ****
--- 657,673 ----
xmlFreeTextWriter(writer);
if (buf)
xmlBufferFree(buf);
+
+ pg_xml_done();
+
PG_RE_THROW();
}
PG_END_TRY();
xmlBufferFree(buf);
+ pg_xml_done();
+
return result;
#else
NO_XML_SUPPORT();
*************** xml_is_document(xmltype *arg)
*** 843,865 ****
#ifdef USE_LIBXML
/*
! * pg_xml_init --- set up for use of libxml
*
* This should be called by each function that is about to use libxml
! * facilities. It has two responsibilities: verify compatibility with the
! * loaded libxml version (done on first call in a session) and establish
! * or re-establish our libxml error handler. The latter needs to be done
! * anytime we might have passed control to add-on modules (eg libperl) which
! * might have set their own error handler for libxml.
! *
! * This is exported for use by contrib/xml2, as well as other code that might
! * wish to share use of this module's libxml error handler.
! *
! * TODO: xmlChar is utf8-char, make proper tuning (initdb with enc!=utf8 and
! * check)
*/
void
! pg_xml_init(void)
{
static bool first_time = true;
--- 861,875 ----
#ifdef USE_LIBXML
/*
! * pg_xml_init_library --- setup for use of libxml
*
* This should be called by each function that is about to use libxml
! * facilities but doesn't require error handling. It initializes libxml
! * and verifies compatibility with the loaded libxml version (done on first
! * call in a session).
*/
void
! pg_xml_init_library(void)
{
static bool first_time = true;
*************** pg_xml_init(void)
*** 882,890 ****
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
xml_err_buf = makeStringInfo();
MemoryContextSwitchTo(oldcontext);
!
! /* Now that xml_err_buf exists, safe to call xml_errorHandler */
! xmlSetGenericErrorFunc(NULL, xml_errorHandler);
#ifdef USE_LIBXMLCONTEXT
/* Set up memory allocation our way, too */
--- 892,898 ----
oldcontext = MemoryContextSwitchTo(TopMemoryContext);
xml_err_buf = makeStringInfo();
MemoryContextSwitchTo(oldcontext);
! xml_err_occurred = false;
#ifdef USE_LIBXMLCONTEXT
/* Set up memory allocation our way, too */
*************** pg_xml_init(void)
*** 896,916 ****
first_time = false;
}
! else
! {
! /* Reset pre-existing buffer to empty */
! Assert(xml_err_buf != NULL);
! resetStringInfo(xml_err_buf);
! /*
! * We re-establish the error callback function every time. This makes
! * it safe for other subsystems (PL/Perl, say) to also use libxml with
! * their own callbacks ... so long as they likewise set up the
! * callbacks on every use. It's cheap enough to not be worth worrying
! * about, anyway.
! */
! xmlSetGenericErrorFunc(NULL, xml_errorHandler);
}
}
--- 904,1008 ----
first_time = false;
}
! }
! /*
! * pg_xml_init --- set up for use of libxml and register an error handler
! *
! * This should be called by each function that is about to use libxml
! * facilities and requires error handling. It initialized libxml with
! * pg_xml_init_library() and establishes our libxml error handler.
! * The strictness determines which errors are reported and which are ignored
! *
! * pg_xml_done() *must* be called after the caller is done using libxml
! * to restore the original error handler.
! *
! * This is exported for use by contrib/xml2, as well as other code that might
! * wish to share use of this module's libxml error handler.
! *
! * TODO: xmlChar is utf8-char, make proper tuning (initdb with enc!=utf8 and
! * check)
! */
! void
! pg_xml_init(PgXmlStrictnessType strictness)
! {
! pg_xml_init_library();
!
! Assert(strictness != PG_XML_STRICTNESS_NONE);
!
! /* Imbalanced calls of pg_xml_init() and pg_xml_done() */
! Assert(!xml_error_initialized);
! Assert(xml_strictness == PG_XML_STRICTNESS_NONE);
!
! /* Set strictness level */
! xml_strictness = strictness;
!
! /* Reset pre-existing buffer to empty */
! Assert(xml_err_buf != NULL);
! resetStringInfo(xml_err_buf);
! xml_err_occurred = false;
!
! /* Save original error handler and install ours. libxml originally didn't
! * distinguish between the context for generic and for structured error
! * handler. If we're using such an libxml version, we must thus save
! * the generic error context, even though we're using a structured
! * error handler.
! */
! xml_structuredErrorFunc_saved = xmlStructuredError;
! #if HAVE_LIBXML2_XMLSTRUCTUREDERRORCONTEXT
! xml_structuredErrorContext_saved = xmlStructuredErrorContext;
! #else
! xml_structuredErrorContext_saved = xmlGenericErrorContext;
! #endif
! xmlSetStructuredErrorFunc(NULL, xml_errorHandler);
!
! xml_error_initialized = true;
! }
!
!
! /*
! * pg_xml_done --- restore libxml state after pg_xml_init().
! *
! * This must be called if pg_xml_init() was called with a
! * purpose other than PG_XML_STRICTNESS_NONE. Resets libxml's global state
! * (i.e. the structured error handler) to the original state.
! *
! * It is OK to call xml_ereport() after pg_xml_done() -
! * pg_xml_done() leaves xml_err_buf as it is.
! */
! void
! pg_xml_done(void)
! {
! /* Imbalanced calls of pg_xml_init() and pg_xml_done(). */
! Assert(xml_error_initialized);
! Assert(xml_strictness != PG_XML_STRICTNESS_NONE);
!
! /* Errors should have been dealt with */
! Assert(!xml_err_occurred);
!
! xmlSetStructuredErrorFunc(xml_structuredErrorContext_saved,
! xml_structuredErrorFunc_saved);
! xml_strictness = PG_XML_STRICTNESS_NONE;
! xml_error_initialized = false;
! }
!
!
!
! /*
! * pg_xml_erroroccurred() --- Test and reset the error flag.
! *
! * Returns true if an libxml error occurred after the last call of
! * this function.
! */
! bool
! pg_xml_erroroccurred(void)
! {
! if (xml_err_occurred) {
! xml_err_occurred = false;
! return true;
}
+
+ return false;
}
*************** parse_xml_decl(const xmlChar *str, size_
*** 969,975 ****
int utf8char;
int utf8len;
! pg_xml_init();
/* Initialize output arguments to "not present" */
if (version)
--- 1061,1071 ----
int utf8char;
int utf8len;
! /* Only initialize libxml. We don't need error handling here,
! * but we do need to make sure libxml is initialized before
! * calling any of its functions
! */
! pg_xml_init_library();
/* Initialize output arguments to "not present" */
if (version)
*************** static bool
*** 1123,1130 ****
print_xml_decl(StringInfo buf, const xmlChar *version,
pg_enc encoding, int standalone)
{
- pg_xml_init(); /* why is this here? */
-
if ((version && strcmp((char *) version, PG_XML_DEFAULT_VERSION) != 0)
|| (encoding && encoding != PG_UTF8)
|| standalone != -1)
--- 1219,1224 ----
*************** xml_parse(text *data, XmlOptionType xmlo
*** 1175,1182 ****
int32 len;
xmlChar *string;
xmlChar *utf8string;
! xmlParserCtxtPtr ctxt;
! xmlDocPtr doc;
len = VARSIZE(data) - VARHDRSZ; /* will be useful later */
string = xml_text2xmlChar(data);
--- 1269,1276 ----
int32 len;
xmlChar *string;
xmlChar *utf8string;
! xmlParserCtxtPtr ctxt = NULL;
! xmlDocPtr doc = NULL;
len = VARSIZE(data) - VARHDRSZ; /* will be useful later */
string = xml_text2xmlChar(data);
*************** xml_parse(text *data, XmlOptionType xmlo
*** 1187,1203 ****
PG_UTF8);
/* Start up libxml and its parser (no-ops if already done) */
! pg_xml_init();
xmlInitParser();
- ctxt = xmlNewParserCtxt();
- if (ctxt == NULL)
- xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
- "could not allocate parser context");
-
/* Use a TRY block to ensure the ctxt is released */
PG_TRY();
{
if (xmloption_arg == XMLOPTION_DOCUMENT)
{
/*
--- 1281,1296 ----
PG_UTF8);
/* Start up libxml and its parser (no-ops if already done) */
! pg_xml_init(PG_XML_STRICTNESS_WELLFORMED);
xmlInitParser();
/* Use a TRY block to ensure the ctxt is released */
PG_TRY();
{
+ ctxt = xmlNewParserCtxt();
+ XML_CHECK_AND_EREPORT(ctxt != NULL, ERROR, ERRCODE_OUT_OF_MEMORY,
+ "could not allocate parser context");
+
if (xmloption_arg == XMLOPTION_DOCUMENT)
{
/*
*************** xml_parse(text *data, XmlOptionType xmlo
*** 1212,1220 ****
"UTF-8",
XML_PARSE_NOENT | XML_PARSE_DTDATTR
| (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
! if (doc == NULL)
! xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
! "invalid XML document");
}
else
{
--- 1305,1312 ----
"UTF-8",
XML_PARSE_NOENT | XML_PARSE_DTDATTR
| (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
! XML_CHECK_AND_EREPORT(doc != NULL, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
! "invalid XML document");
}
else
{
*************** xml_parse(text *data, XmlOptionType xmlo
*** 1237,1259 ****
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
utf8string + count, NULL);
! if (res_code != 0)
! {
! xmlFreeDoc(doc);
! xml_ereport(ERROR, ERRCODE_INVALID_XML_CONTENT,
! "invalid XML content");
! }
}
}
PG_CATCH();
{
! xmlFreeParserCtxt(ctxt);
PG_RE_THROW();
}
PG_END_TRY();
xmlFreeParserCtxt(ctxt);
return doc;
}
--- 1329,1355 ----
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
utf8string + count, NULL);
! XML_CHECK_AND_EREPORT(res_code == 0, ERROR, ERRCODE_INVALID_XML_CONTENT,
! "invalid XML content");
}
}
PG_CATCH();
{
! if (doc != NULL)
! xmlFreeDoc(doc);
! if (ctxt != NULL)
! xmlFreeParserCtxt(ctxt);
!
! pg_xml_done();
!
PG_RE_THROW();
}
PG_END_TRY();
xmlFreeParserCtxt(ctxt);
+ pg_xml_done();
+
return doc;
}
*************** xml_ereport(int level, int sqlcode, cons
*** 1354,1366 ****
if (detail)
{
- size_t len;
-
- /* libxml error messages end in '\n'; get rid of it */
- len = strlen(detail);
- if (len > 0 && detail[len - 1] == '\n')
- detail[len - 1] = '\0';
-
ereport(level,
(errcode(sqlcode),
errmsg("%s", msg),
--- 1450,1455 ----
*************** xml_ereport(int level, int sqlcode, cons
*** 1376,1402 ****
/*
! * Error handler for libxml error messages
*/
static void
! xml_errorHandler(void *ctxt, const char *msg,...)
{
! /* Append the formatted text to xml_err_buf */
! for (;;)
{
! va_list args;
! bool success;
- /* Try to format the data. */
- va_start(args, msg);
- 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);
}
}
--- 1465,1623 ----
/*
! * Append a newline after removing all existing trailing newlines
*/
static void
! appendStringInfoLineSeparator(StringInfo str)
{
! chopStringInfoNewlines(str);
!
! if (str->len > 0)
! appendStringInfoChar(str, '\n');
! }
!
!
! /*
! * Remove all trailing newlines
! */
! static void
! chopStringInfoNewlines(StringInfo str)
! {
! while ((str->len > 0) &&
! (str->data[str->len-1] == '\n'))
{
! str->data[--str->len] = '\0';
! }
! }
! /*
! * Error handler for libxml errors and warnings
! */
! static void
! xml_errorHandler(void* data, xmlErrorPtr error)
! {
! int domain;
! int level;
! StringInfo errorBuf = makeStringInfo();
!
! /* Get parser and input context */
! xmlParserCtxtPtr ctxt = (xmlParserCtxtPtr) error->ctxt;
! xmlParserInputPtr input = (ctxt != NULL) ? ctxt->input : NULL;
! xmlNodePtr node = error->node;
! const xmlChar* name = ((node != NULL) && (node->type == XML_ELEMENT_NODE)) ?
! node->name : NULL;
!
! /* Older libxml versions report some errors differently.
! * First, some errors were previously reported as
! * coming from the parser domain but are now reported as
! * coming from the namespace domain.
! * Second, some warnings were upgraded to errors.
! * We attempt to compensate for that here
! */
! domain = error->domain;
! level = error->level;
! switch (error->code) {
! case XML_WAR_NS_URI:
! level = XML_ERR_ERROR;
! domain = XML_FROM_NAMESPACE;
break;
! case XML_ERR_NS_DECL_ERROR:
! case XML_WAR_NS_URI_RELATIVE:
! case XML_WAR_NS_COLUMN:
! case XML_NS_ERR_XML_NAMESPACE:
! case XML_NS_ERR_UNDEFINED_NAMESPACE:
! case XML_NS_ERR_QNAME:
! case XML_NS_ERR_ATTRIBUTE_REDEFINED:
! case XML_NS_ERR_EMPTY:
! domain = XML_FROM_NAMESPACE;
! break;
! }
!
! /* Decide whether to act on the error or not */
! switch (domain) {
! case XML_FROM_PARSER:
! case XML_FROM_NONE:
! case XML_FROM_MEMORY:
! case XML_FROM_IO:
! /* Accept regardless of the parsing purpose */
! break;
!
! default:
! /* Ignore during well-formedness check */
! if (xml_strictness == PG_XML_STRICTNESS_WELLFORMED)
! return;
! break;
! }
!
! /* Append error message to xml_err_buf */
! if (error->line > 0)
! appendStringInfo(errorBuf, "line %d: ", error->line);
! if (name != NULL)
! appendStringInfo(errorBuf, "element %s: ", name);
! appendStringInfo(errorBuf, "%s", error->message);
!
! /* Append context information to xml_err_buf.
! * xmlParserPrintFileContext() uses the *generic* error handle to
! * write the context. Since we don't want to duplicate libxml
! * functionality here, we setup a generic error handler temporarily
! */
! if (input != NULL)
! {
! /* Save generic error func and setup the xml_err_buf
! * appender as generic error func. This should work because
! * appendStringInfo() has essentially the same signature as
! * xmlGenericErrorFunc().
! */
! xmlGenericErrorFunc errFuncSaved = xmlGenericError;
! void* errCtxSaved = xmlGenericErrorContext;
! xmlSetGenericErrorFunc(errorBuf, (xmlGenericErrorFunc)appendStringInfo);
!
! /* Generic context information */
! appendStringInfoLineSeparator(errorBuf);
! xmlParserPrintFileContext(input);
!
! /* Restore generic error func */
! xmlSetGenericErrorFunc(errCtxSaved, errFuncSaved);
! }
!
! chopStringInfoNewlines(errorBuf);
!
! /* Legacy error handling. The error flag is never set. Exists because
! * the xml2 contrib module uses our error-handling infrastructure, but
! * we don't want to change its behaviour since it's deprecated anyway.
! * This is also why we don't distinguish between notices, warnings
! * and errors here - the old-style generic error handler wouldn't
! * have done that either.
! */
! if (xml_strictness == PG_XML_STRICTNESS_LEGACY)
! {
! appendStringInfoLineSeparator(xml_err_buf);
! appendStringInfoString(xml_err_buf, errorBuf->data);
! return;
! }
!
! /* We don't want to ereport() here because that'd probably leave
! * libxml in an inconsistent state. Instead, we remember the
! * error and ereport() from xml_ereport().
! *
! * Warnings and notices are reported immediatly since they don't cause a
! * longjmp() out of libxml.
! */
! if (level >= XML_ERR_ERROR)
! {
! appendStringInfoLineSeparator(xml_err_buf);
! appendStringInfoString(xml_err_buf, errorBuf->data);
! xml_err_occurred = true;
! }
! else if (level >= XML_ERR_WARNING)
! {
! ereport(WARNING, (errmsg("%s", errorBuf->data)));
! }
! else
! {
! ereport(NOTICE, (errmsg("%s", errorBuf->data)));
}
}
*************** map_sql_value_to_xml_value(Datum value,
*** 1756,1773 ****
xmlTextWriterPtr writer = NULL;
char *result;
! pg_xml_init();
PG_TRY();
{
buf = xmlBufferCreate();
! if (!buf)
! xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate xmlBuffer");
writer = xmlNewTextWriterMemory(buf, 0);
! if (!writer)
! xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate xmlTextWriter");
if (xmlbinary == XMLBINARY_BASE64)
xmlTextWriterWriteBase64(writer, VARDATA_ANY(bstr),
--- 1977,1992 ----
xmlTextWriterPtr writer = NULL;
char *result;
! pg_xml_init(PG_XML_STRICTNESS_ALL);
PG_TRY();
{
buf = xmlBufferCreate();
! XML_CHECK_AND_EREPORT(buf != NULL, ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate xmlBuffer");
writer = xmlNewTextWriterMemory(buf, 0);
! XML_CHECK_AND_EREPORT(writer != NULL, ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate xmlTextWriter");
if (xmlbinary == XMLBINARY_BASE64)
xmlTextWriterWriteBase64(writer, VARDATA_ANY(bstr),
*************** map_sql_value_to_xml_value(Datum value,
*** 1788,1799 ****
--- 2007,2023 ----
xmlFreeTextWriter(writer);
if (buf)
xmlBufferFree(buf);
+
+ pg_xml_done();
+
PG_RE_THROW();
}
PG_END_TRY();
xmlBufferFree(buf);
+ pg_xml_done();
+
return result;
}
#endif /* USE_LIBXML */
*************** xpath_internal(text *xpath_expr_text, xm
*** 3381,3387 ****
memcpy(xpath_expr, VARDATA(xpath_expr_text), xpath_len);
xpath_expr[xpath_len] = '\0';
! pg_xml_init();
xmlInitParser();
PG_TRY();
--- 3605,3611 ----
memcpy(xpath_expr, VARDATA(xpath_expr_text), xpath_len);
xpath_expr[xpath_len] = '\0';
! pg_xml_init(PG_XML_STRICTNESS_ALL);
xmlInitParser();
PG_TRY();
*************** xpath_internal(text *xpath_expr_text, xm
*** 3391,3411 ****
* command execution are possible)
*/
ctxt = xmlNewParserCtxt();
! if (ctxt == NULL)
! xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate parser context");
doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
! if (doc == NULL)
! xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
! "could not parse XML document");
xpathctx = xmlXPathNewContext(doc);
! if (xpathctx == NULL)
! xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate XPath context");
xpathctx->node = xmlDocGetRootElement(doc);
! if (xpathctx->node == NULL)
! xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
! "could not find root XML element");
/* register namespaces, if any */
if (ns_count > 0)
--- 3615,3631 ----
* command execution are possible)
*/
ctxt = xmlNewParserCtxt();
! XML_CHECK_AND_EREPORT(ctxt != NULL, ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate parser context");
doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
! XML_CHECK_AND_EREPORT(doc != NULL, ERROR, ERRCODE_INVALID_XML_DOCUMENT,
! "could not parse XML document");
xpathctx = xmlXPathNewContext(doc);
! XML_CHECK_AND_EREPORT(xpathctx != NULL, ERROR, ERRCODE_OUT_OF_MEMORY,
! "could not allocate XPath context");
xpathctx->node = xmlDocGetRootElement(doc);
! XML_CHECK_AND_EREPORT(xpathctx->node != NULL, ERROR, ERRCODE_INTERNAL_ERROR,
! "could not find root XML element");
/* register namespaces, if any */
if (ns_count > 0)
*************** xpath_internal(text *xpath_expr_text, xm
*** 3432,3440 ****
}
xpathcomp = xmlXPathCompile(xpath_expr);
! if (xpathcomp == NULL) /* TODO: show proper XPath error details */
! xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
! "invalid XPath expression");
/*
* Version 2.6.27 introduces a function named
--- 3652,3659 ----
}
xpathcomp = xmlXPathCompile(xpath_expr);
! XML_CHECK_AND_EREPORT(xpathcomp != NULL, ERROR, ERRCODE_INTERNAL_ERROR,
! "invalid XPath expression");
/*
* Version 2.6.27 introduces a function named
*************** xpath_internal(text *xpath_expr_text, xm
*** 3444,3452 ****
* the same.
*/
xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
! if (xpathobj == NULL) /* TODO: reason? */
! xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
! "could not create XPath object");
/* return empty array in cases when nothing is found */
if (xpathobj->nodesetval == NULL)
--- 3663,3670 ----
* the same.
*/
xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
! XML_CHECK_AND_EREPORT(xpathobj != NULL, ERROR, ERRCODE_INTERNAL_ERROR,
! "could not create XPath object");
/* return empty array in cases when nothing is found */
if (xpathobj->nodesetval == NULL)
*************** xpath_internal(text *xpath_expr_text, xm
*** 3481,3486 ****
--- 3699,3707 ----
xmlFreeDoc(doc);
if (ctxt)
xmlFreeParserCtxt(ctxt);
+
+ pg_xml_done();
+
PG_RE_THROW();
}
PG_END_TRY();
*************** xpath_internal(text *xpath_expr_text, xm
*** 3490,3495 ****
--- 3711,3718 ----
xmlXPathFreeContext(xpathctx);
xmlFreeDoc(doc);
xmlFreeParserCtxt(ctxt);
+
+ pg_xml_done();
}
#endif /* USE_LIBXML */
diff --git a/src/include/utils/xml.h b/src/include/utils/xml.h
index 6359cd6..bc4a74d 100644
*** a/src/include/utils/xml.h
--- b/src/include/utils/xml.h
*************** typedef enum
*** 68,74 ****
XML_STANDALONE_OMITTED
} XmlStandaloneType;
! extern void pg_xml_init(void);
extern void xml_ereport(int level, int sqlcode, const char *msg);
extern xmltype *xmlconcat(List *args);
extern xmltype *xmlelement(XmlExprState *xmlExpr, ExprContext *econtext);
--- 68,87 ----
XML_STANDALONE_OMITTED
} XmlStandaloneType;
! typedef enum
! {
! PG_XML_STRICTNESS_NONE /* No error handling */,
! PG_XML_STRICTNESS_LEGACY /* Ignore notices/warnings/errors unless
! * function result indicates error condition
! */,
! PG_XML_STRICTNESS_WELLFORMED/* Ignore non-parser notices/warnings/errors */,
! PG_XML_STRICTNESS_ALL /* Report all notices/warnings/errors */,
! } PgXmlStrictnessType;
!
! extern void pg_xml_init_library(void);
! extern void pg_xml_init(PgXmlStrictnessType strictness);
! extern void pg_xml_done(void);
! extern bool pg_xml_erroroccurred(void);
extern void xml_ereport(int level, int sqlcode, const char *msg);
extern xmltype *xmlconcat(List *args);
extern xmltype *xmlelement(XmlExprState *xmlExpr, ExprContext *econtext);
diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out
index eaa5a74..364ce51 100644
*** a/src/test/regress/expected/xml.out
--- b/src/test/regress/expected/xml.out
*************** INSERT INTO xmltest VALUES (3, '<wrong')
*** 8,14 ****
ERROR: invalid XML content
LINE 1: INSERT INTO xmltest VALUES (3, '<wrong');
^
! DETAIL: Entity: line 1: parser error : Couldn't find end of Start Tag wrong line 1
<wrong
^
SELECT * FROM xmltest;
--- 8,14 ----
ERROR: invalid XML content
LINE 1: INSERT INTO xmltest VALUES (3, '<wrong');
^
! DETAIL: line 1: Couldn't find end of Start Tag wrong line 1
<wrong
^
SELECT * FROM xmltest;
*************** SELECT xmlconcat('bad', '<syntax');
*** 62,68 ****
ERROR: invalid XML content
LINE 1: SELECT xmlconcat('bad', '<syntax');
^
! DETAIL: Entity: line 1: parser error : Couldn't find end of Start Tag syntax line 1
<syntax
^
SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
--- 62,68 ----
ERROR: invalid XML content
LINE 1: SELECT xmlconcat('bad', '<syntax');
^
! DETAIL: line 1: Couldn't find end of Start Tag syntax line 1
<syntax
^
SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
*************** SELECT xmlparse(content '<abc>x</abc>');
*** 206,214 ****
<abc>x</abc>
(1 row)
SELECT xmlparse(document 'abc');
ERROR: invalid XML document
! DETAIL: Entity: line 1: parser error : Start tag expected, '<' not found
abc
^
SELECT xmlparse(document '<abc>x</abc>');
--- 206,259 ----
<abc>x</abc>
(1 row)
+ SELECT xmlparse(content '<invalidentity>&</invalidentity>');
+ ERROR: invalid XML content
+ DETAIL: line 1: xmlParseEntityRef: no name
+ <invalidentity>&</invalidentity>
+ ^
+ line 1: chunk is not well balanced
+ <invalidentity>&</invalidentity>
+ ^
+ SELECT xmlparse(content '<undefinedentity>&idontexist;</undefinedentity>');
+ ERROR: invalid XML content
+ DETAIL: line 1: Entity 'idontexist' not defined
+ <undefinedentity>&idontexist;</undefinedentity>
+ ^
+ line 1: chunk is not well balanced
+ <undefinedentity>&idontexist;</undefinedentity>
+ ^
+ SELECT xmlparse(content '<invalidns xmlns=''<''/>');
+ xmlparse
+ ---------------------------
+ <invalidns xmlns='<'/>
+ (1 row)
+
+ SELECT xmlparse(content '<relativens xmlns=''relative''/>');
+ xmlparse
+ --------------------------------
+ <relativens xmlns='relative'/>
+ (1 row)
+
+ SELECT xmlparse(content '<twoerrors>&idontexist;</unbalanced>');
+ ERROR: invalid XML content
+ DETAIL: line 1: Entity 'idontexist' not defined
+ <twoerrors>&idontexist;</unbalanced>
+ ^
+ line 1: Opening and ending tag mismatch: twoerrors line 1 and unbalanced
+ <twoerrors>&idontexist;</unbalanced>
+ ^
+ line 1: chunk is not well balanced
+ <twoerrors>&idontexist;</unbalanced>
+ ^
+ SELECT xmlparse(content '<nosuchprefix:tag/>');
+ xmlparse
+ ---------------------
+ <nosuchprefix:tag/>
+ (1 row)
+
SELECT xmlparse(document 'abc');
ERROR: invalid XML document
! DETAIL: line 1: Start tag expected, '<' not found
abc
^
SELECT xmlparse(document '<abc>x</abc>');
*************** SELECT xmlparse(document '<abc>x</abc>')
*** 217,222 ****
--- 262,309 ----
<abc>x</abc>
(1 row)
+ SELECT xmlparse(document '<invalidentity>&</abc>');
+ ERROR: invalid XML document
+ DETAIL: line 1: xmlParseEntityRef: no name
+ <invalidentity>&</abc>
+ ^
+ line 1: Opening and ending tag mismatch: invalidentity line 1 and abc
+ <invalidentity>&</abc>
+ ^
+ SELECT xmlparse(document '<undefinedentity>&idontexist;</abc>');
+ ERROR: invalid XML document
+ DETAIL: line 1: Entity 'idontexist' not defined
+ <undefinedentity>&idontexist;</abc>
+ ^
+ line 1: Opening and ending tag mismatch: undefinedentity line 1 and abc
+ <undefinedentity>&idontexist;</abc>
+ ^
+ SELECT xmlparse(document '<invalidns xmlns=''<''/>');
+ xmlparse
+ ---------------------------
+ <invalidns xmlns='<'/>
+ (1 row)
+
+ SELECT xmlparse(document '<relativens xmlns=''relative''/>');
+ xmlparse
+ --------------------------------
+ <relativens xmlns='relative'/>
+ (1 row)
+
+ SELECT xmlparse(document '<twoerrors>&idontexist;</unbalanced>');
+ ERROR: invalid XML document
+ DETAIL: line 1: Entity 'idontexist' not defined
+ <twoerrors>&idontexist;</unbalanced>
+ ^
+ line 1: Opening and ending tag mismatch: twoerrors line 1 and unbalanced
+ <twoerrors>&idontexist;</unbalanced>
+ ^
+ SELECT xmlparse(document '<nosuchprefix:tag/>');
+ xmlparse
+ ---------------------
+ <nosuchprefix:tag/>
+ (1 row)
+
SELECT xmlpi(name foo);
xmlpi
---------
*************** SELECT '<>' IS NOT DOCUMENT;
*** 379,385 ****
ERROR: invalid XML content
LINE 1: SELECT '<>' IS NOT DOCUMENT;
^
! DETAIL: Entity: line 1: parser error : StartTag: invalid element name
<>
^
SELECT xmlagg(data) FROM xmltest;
--- 466,472 ----
ERROR: invalid XML content
LINE 1: SELECT '<>' IS NOT DOCUMENT;
^
! DETAIL: line 1: StartTag: invalid element name
<>
^
SELECT xmlagg(data) FROM xmltest;
*************** EXECUTE foo ('bad');
*** 425,431 ****
ERROR: invalid XML document
LINE 1: EXECUTE foo ('bad');
^
! DETAIL: Entity: line 1: parser error : Start tag expected, '<' not found
bad
^
SET XML OPTION CONTENT;
--- 512,518 ----
ERROR: invalid XML document
LINE 1: EXECUTE foo ('bad');
^
! DETAIL: line 1: Start tag expected, '<' not found
bad
^
SET XML OPTION CONTENT;
*************** SELECT xml_is_well_formed('<pg:foo xmlns
*** 679,684 ****
--- 766,801 ----
t
(1 row)
+ SELECT xml_is_well_formed('<invalidentity>&</abc>');
+ xml_is_well_formed
+ --------------------
+ f
+ (1 row)
+
+ SELECT xml_is_well_formed('<undefinedentity>&idontexist;</abc>');
+ xml_is_well_formed
+ --------------------
+ f
+ (1 row)
+
+ SELECT xml_is_well_formed('<invalidns xmlns=''<''/>');
+ xml_is_well_formed
+ --------------------
+ t
+ (1 row)
+
+ SELECT xml_is_well_formed('<relativens xmlns=''relative''/>');
+ xml_is_well_formed
+ --------------------
+ t
+ (1 row)
+
+ SELECT xml_is_well_formed('<twoerrors>&idontexist;</unbalanced>');
+ xml_is_well_formed
+ --------------------
+ f
+ (1 row)
+
SET xmloption TO CONTENT;
SELECT xml_is_well_formed('abc');
xml_is_well_formed
*************** SELECT xml_is_well_formed('abc');
*** 686,688 ****
--- 803,838 ----
t
(1 row)
+ -- Since xpath() deals with namespaces, it's a bit stricter about
+ -- what's well-formed and what's not. If we don't obey these rules
+ -- (i.e. ignore namespace-related errors from libxml), xpath()
+ -- fails in subtle ways. The following would for example produce
+ -- the xml value
+ -- <invalidns xmlns='<'/>
+ -- which is invalid beecause '<' may not appear un-escaped in
+ -- attribute values.
+ -- Since different libxml versions emit slightly different
+ -- error messages, we suppress them
+ \set VERBOSITY terse
+ SELECT xpath('/*', '<invalidns xmlns=''<''/>');
+ ERROR: could not parse XML document
+ \set VERBOSITY default
+ -- Again, the XML isn't well-formed for namespace purposes
+ SELECT xpath('/*', '<nosuchprefix:tag/>');
+ ERROR: could not parse XML document
+ DETAIL: line 1: Namespace prefix nosuchprefix on tag is not defined
+ <nosuchprefix:tag/>
+ ^
+ CONTEXT: SQL function "xpath" statement 1
+ -- XPath deprecates relative namespaces, but they're not supposed to
+ -- thrown an error, only a warning.
+ SELECT xpath('/*', '<relativens xmlns=''relative''/>');
+ WARNING: line 1: xmlns: URI relative is not absolute
+ <relativens xmlns='relative'/>
+ ^
+ CONTEXT: SQL function "xpath" statement 1
+ xpath
+ --------------------------------------
+ {"<relativens xmlns=\"relative\"/>"}
+ (1 row)
+
diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out
index 711b435..75e78a0 100644
*** a/src/test/regress/expected/xml_1.out
--- b/src/test/regress/expected/xml_1.out
*************** SELECT xmlparse(content '<abc>x</abc>');
*** 172,177 ****
--- 172,201 ----
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(content '<invalidentity>&</invalidentity>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(content '<undefinedentity>&idontexist;</undefinedentity>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(content '<invalidns xmlns=''<''/>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(content '<relativens xmlns=''relative''/>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(content '<twoerrors>&idontexist;</unbalanced>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(content '<nosuchprefix:tag/>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
SELECT xmlparse(document 'abc');
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
*************** SELECT xmlparse(document '<abc>x</abc>')
*** 180,185 ****
--- 204,233 ----
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(document '<invalidentity>&</abc>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(document '<undefinedentity>&idontexist;</abc>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(document '<invalidns xmlns=''<''/>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(document '<relativens xmlns=''relative''/>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(document '<twoerrors>&idontexist;</unbalanced>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xmlparse(document '<nosuchprefix:tag/>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
SELECT xmlpi(name foo);
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
*************** SELECT xml_is_well_formed('<pg:foo xmlns
*** 627,634 ****
--- 675,731 ----
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xml_is_well_formed('<invalidentity>&</abc>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xml_is_well_formed('<undefinedentity>&idontexist;</abc>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xml_is_well_formed('<invalidns xmlns=''<''/>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xml_is_well_formed('<relativens xmlns=''relative''/>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ SELECT xml_is_well_formed('<twoerrors>&idontexist;</unbalanced>');
+ ERROR: unsupported XML feature
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
SET xmloption TO CONTENT;
SELECT xml_is_well_formed('abc');
ERROR: unsupported XML feature
DETAIL: This functionality requires the server to be built with libxml support.
HINT: You need to rebuild PostgreSQL using --with-libxml.
+ -- Since xpath() deals with namespaces, it's a bit stricter about
+ -- what's well-formed and what's not. If we don't obey these rules
+ -- (i.e. ignore namespace-related errors from libxml), xpath()
+ -- fails in subtle ways. The following would for example produce
+ -- the xml value
+ -- <invalidns xmlns='<'/>
+ -- which is invalid beecause '<' may not appear un-escaped in
+ -- attribute values.
+ -- Since different libxml versions emit slightly different
+ -- error messages, we suppress them
+ \set VERBOSITY terse
+ SELECT xpath('/*', '<invalidns xmlns=''<''/>');
+ ERROR: unsupported XML feature at character 20
+ \set VERBOSITY default
+ -- Again, the XML isn't well-formed for namespace purposes
+ SELECT xpath('/*', '<nosuchprefix:tag/>');
+ ERROR: unsupported XML feature
+ LINE 1: SELECT xpath('/*', '<nosuchprefix:tag/>');
+ ^
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
+ -- XPath deprecates relative namespaces, but they're not supposed to
+ -- thrown an error, only a warning.
+ SELECT xpath('/*', '<relativens xmlns=''relative''/>');
+ ERROR: unsupported XML feature
+ LINE 1: SELECT xpath('/*', '<relativens xmlns=''relative''/>');
+ ^
+ DETAIL: This functionality requires the server to be built with libxml support.
+ HINT: You need to rebuild PostgreSQL using --with-libxml.
diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql
index 717a1e7..b1a3a2c 100644
*** a/src/test/regress/sql/xml.sql
--- b/src/test/regress/sql/xml.sql
*************** SELECT xmlelement(name foo, xmlattribute
*** 62,70 ****
--- 62,82 ----
SELECT xmlparse(content 'abc');
SELECT xmlparse(content '<abc>x</abc>');
+ SELECT xmlparse(content '<invalidentity>&</invalidentity>');
+ SELECT xmlparse(content '<undefinedentity>&idontexist;</undefinedentity>');
+ SELECT xmlparse(content '<invalidns xmlns=''<''/>');
+ SELECT xmlparse(content '<relativens xmlns=''relative''/>');
+ SELECT xmlparse(content '<twoerrors>&idontexist;</unbalanced>');
+ SELECT xmlparse(content '<nosuchprefix:tag/>');
SELECT xmlparse(document 'abc');
SELECT xmlparse(document '<abc>x</abc>');
+ SELECT xmlparse(document '<invalidentity>&</abc>');
+ SELECT xmlparse(document '<undefinedentity>&idontexist;</abc>');
+ SELECT xmlparse(document '<invalidns xmlns=''<''/>');
+ SELECT xmlparse(document '<relativens xmlns=''relative''/>');
+ SELECT xmlparse(document '<twoerrors>&idontexist;</unbalanced>');
+ SELECT xmlparse(document '<nosuchprefix:tag/>');
SELECT xmlpi(name foo);
*************** SELECT xml_is_well_formed('<foo><bar>baz
*** 208,213 ****
--- 220,251 ----
SELECT xml_is_well_formed('<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
SELECT xml_is_well_formed('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</my:foo>');
SELECT xml_is_well_formed('<pg:foo xmlns:pg="http://postgresql.org/stuff">bar</pg:foo>');
+ SELECT xml_is_well_formed('<invalidentity>&</abc>');
+ SELECT xml_is_well_formed('<undefinedentity>&idontexist;</abc>');
+ SELECT xml_is_well_formed('<invalidns xmlns=''<''/>');
+ SELECT xml_is_well_formed('<relativens xmlns=''relative''/>');
+ SELECT xml_is_well_formed('<twoerrors>&idontexist;</unbalanced>');
SET xmloption TO CONTENT;
SELECT xml_is_well_formed('abc');
+
+ -- Since xpath() deals with namespaces, it's a bit stricter about
+ -- what's well-formed and what's not. If we don't obey these rules
+ -- (i.e. ignore namespace-related errors from libxml), xpath()
+ -- fails in subtle ways. The following would for example produce
+ -- the xml value
+ -- <invalidns xmlns='<'/>
+ -- which is invalid beecause '<' may not appear un-escaped in
+ -- attribute values.
+ -- Since different libxml versions emit slightly different
+ -- error messages, we suppress them
+ \set VERBOSITY terse
+ SELECT xpath('/*', '<invalidns xmlns=''<''/>');
+ \set VERBOSITY default
+
+ -- Again, the XML isn't well-formed for namespace purposes
+ SELECT xpath('/*', '<nosuchprefix:tag/>');
+
+ -- XPath deprecates relative namespaces, but they're not supposed to
+ -- thrown an error, only a warning.
+ SELECT xpath('/*', '<relativens xmlns=''relative''/>');