@ -85,11 +85,27 @@ int xmloption;
# ifdef USE_LIBXML
static StringInfo xml_err_buf = NULL ;
static void xml_errorHandler ( void * ctxt , const char * msg , . . . ) ;
/* random number to identify PgXmlErrorContext */
# define ERRCXT_MAGIC 68275028
struct PgXmlErrorContext
{
int magic ;
/* strictness argument passed to pg_xml_init */
PgXmlStrictness strictness ;
/* current error status and accumulated message, if any */
bool err_occurred ;
StringInfoData err_buf ;
/* previous libxml error handling state (saved by pg_xml_init) */
xmlStructuredErrorFunc saved_errfunc ;
void * saved_errcxt ;
} ;
static void xml_errorHandler ( void * data , xmlErrorPtr error ) ;
static void xml_ereport_by_code ( int level , int sqlcode ,
const char * msg , int errcode ) ;
static void chopStringInfoNewlines ( StringInfo str ) ;
static void appendStringInfoLineSeparator ( StringInfo str ) ;
# ifdef USE_LIBXMLCONTEXT
@ -552,8 +568,9 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
int i ;
ListCell * arg ;
ListCell * narg ;
xmlBufferPtr buf = NULL ;
xmlTextWriterPtr writer = NULL ;
PgXmlErrorContext * xmlerrcxt ;
volatile xmlBufferPtr buf = NULL ;
volatile xmlTextWriterPtr writer = NULL ;
/*
* We first evaluate all the arguments , then start up libxml and create
@ -598,17 +615,17 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
}
/* now safe to run libxml */
pg_xml_init ( ) ;
xmlerrcxt = pg_xml_init ( PG_XML_STRICTNESS_ALL ) ;
PG_TRY ( ) ;
{
buf = xmlBufferCreate ( ) ;
if ( ! buf )
xml_ereport ( ERROR , ERRCODE_OUT_OF_MEMORY ,
if ( buf = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_OUT_OF_MEMORY ,
" could not allocate xmlBuffer " ) ;
writer = xmlNewTextWriterMemory ( buf , 0 ) ;
if ( ! writer )
xml_ereport ( ERROR , ERRCODE_OUT_OF_MEMORY ,
if ( writer = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_OUT_OF_MEMORY ,
" could not allocate xmlTextWriter " ) ;
xmlTextWriterStartElement ( writer , ( xmlChar * ) xexpr - > name ) ;
@ -645,12 +662,17 @@ xmlelement(XmlExprState *xmlExpr, ExprContext *econtext)
xmlFreeTextWriter ( writer ) ;
if ( buf )
xmlBufferFree ( buf ) ;
pg_xml_done ( xmlerrcxt , true ) ;
PG_RE_THROW ( ) ;
}
PG_END_TRY ( ) ;
xmlBufferFree ( buf ) ;
pg_xml_done ( xmlerrcxt , false ) ;
return result ;
# else
NO_XML_SUPPORT ( ) ;
@ -800,7 +822,7 @@ xml_is_document(xmltype *arg)
{
# ifdef USE_LIBXML
bool result ;
xmlDocPtr doc = NULL ;
volatile xmlDocPtr doc = NULL ;
MemoryContext ccxt = CurrentMemoryContext ;
/* We want to catch ereport(INVALID_XML_DOCUMENT) and return false */
@ -844,30 +866,24 @@ xml_is_document(xmltype *arg)
# ifdef USE_LIBXML
/*
* pg_xml_init - - - set up for use of libxml
* pg_xml_init_library - - - 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 .
* facilities but doesn ' t require error handling . It initializes libxml
* and verifies compatibility with the loaded libxml version . These are
* once - per - session activities .
*
* TODO : xmlChar is utf8 - char , make proper tuning ( initdb with enc ! = utf8 and
* check )
*/
void
pg_xml_init ( void )
pg_xml_init_library ( void )
{
static bool first_time = true ;
if ( first_time )
{
/* Stuff we need do only once per session */
MemoryContext oldcontext ;
/*
* Currently , we have no pure UTF - 8 support for internals - - check if
@ -879,16 +895,8 @@ pg_xml_init(void)
errdetail ( " libxml2 has incompatible char type: sizeof(char)=%u, sizeof(xmlChar)=%u. " ,
( int ) sizeof ( char ) , ( int ) sizeof ( xmlChar ) ) ) ) ;
/* create error buffer in permanent context */
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 */
/* Set up libxml's memory allocation our way */
xml_memory_init ( ) ;
# endif
@ -897,21 +905,119 @@ pg_xml_init(void)
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 ) ;
}
/*
* 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 initializes libxml with
* pg_xml_init_library ( ) and establishes our libxml error handler .
*
* strictness determines which errors are reported and which are ignored .
*
* Calls to this function MUST be followed by a PG_TRY block that guarantees
* that pg_xml_done ( ) is called during either normal or error exit .
*
* 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 .
*/
PgXmlErrorContext *
pg_xml_init ( PgXmlStrictness strictness )
{
PgXmlErrorContext * errcxt ;
/* Do one-time setup if needed */
pg_xml_init_library ( ) ;
/* Create error handling context structure */
errcxt = ( PgXmlErrorContext * ) palloc ( sizeof ( PgXmlErrorContext ) ) ;
errcxt - > magic = ERRCXT_MAGIC ;
errcxt - > strictness = strictness ;
errcxt - > err_occurred = false ;
initStringInfo ( & errcxt - > err_buf ) ;
/*
* Save original error handler and install ours . libxml originally didn ' t
* distinguish between the contexts for generic and for structured error
* handlers . If we ' re using an old libxml version , we must thus save
* the generic error context , even though we ' re using a structured
* error handler .
*/
errcxt - > saved_errfunc = xmlStructuredError ;
# ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
errcxt - > saved_errcxt = xmlStructuredErrorContext ;
# else
errcxt - > saved_errcxt = xmlGenericErrorContext ;
# endif
xmlSetStructuredErrorFunc ( ( void * ) errcxt , xml_errorHandler ) ;
return errcxt ;
}
/*
* pg_xml_done - - - restore previous libxml error handling
*
* Resets libxml ' s global error - handling state to what it was before
* pg_xml_init ( ) was called .
*
* This routine verifies that all pending errors have been dealt with
* ( in assert - enabled builds , anyway ) .
*/
void
pg_xml_done ( PgXmlErrorContext * errcxt , bool isError )
{
void * cur_errcxt ;
/* An assert seems like enough protection here */
Assert ( errcxt - > magic = = ERRCXT_MAGIC ) ;
/*
* In a normal exit , there should be no un - handled libxml errors . But we
* shouldn ' t try to enforce this during error recovery , since the longjmp
* could have been thrown before xml_ereport had a chance to run .
*/
Assert ( ! errcxt - > err_occurred | | isError ) ;
/*
* Check that libxml ' s global state is correct , warn if not . This is
* a real test and not an Assert because it has a higher probability
* of happening .
*/
# ifdef HAVE_XMLSTRUCTUREDERRORCONTEXT
cur_errcxt = xmlStructuredErrorContext ;
# else
cur_errcxt = xmlGenericErrorContext ;
# endif
if ( cur_errcxt ! = ( void * ) errcxt )
elog ( WARNING , " libxml error handling state is out of sync with xml.c " ) ;
/* Restore the saved handler */
xmlSetStructuredErrorFunc ( errcxt - > saved_errcxt , errcxt - > saved_errfunc ) ;
/*
* Mark the struct as invalid , just in case somebody somehow manages to
* call xml_errorHandler or xml_ereport with it .
*/
errcxt - > magic = 0 ;
/* Release memory */
pfree ( errcxt - > err_buf . data ) ;
pfree ( errcxt ) ;
}
/*
* pg_xml_error_occurred ( ) - - - test the error flag
*/
bool
pg_xml_error_occurred ( PgXmlErrorContext * errcxt )
{
return errcxt - > err_occurred ;
}
@ -970,7 +1076,13 @@ parse_xml_decl(const xmlChar *str, size_t *lenp,
int utf8char ;
int utf8len ;
pg_xml_init ( ) ;
/*
* 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 . Note that this is safe ( and a no - op ) if caller has already
* done pg_xml_init ( ) .
*/
pg_xml_init_library ( ) ;
/* Initialize output arguments to "not present" */
if ( version )
@ -1124,8 +1236,6 @@ static bool
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 )
@ -1176,8 +1286,9 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
int32 len ;
xmlChar * string ;
xmlChar * utf8string ;
xmlParserCtxtPtr ctxt ;
xmlDocPtr doc ;
PgXmlErrorContext * xmlerrcxt ;
volatile xmlParserCtxtPtr ctxt = NULL ;
volatile xmlDocPtr doc = NULL ;
len = VARSIZE ( data ) - VARHDRSZ ; /* will be useful later */
string = xml_text2xmlChar ( data ) ;
@ -1187,18 +1298,19 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
encoding ,
PG_UTF8 ) ;
/* Start up libxml and its parser (no-ops if already done) */
pg_xml_init ( ) ;
xmlInitParser ( ) ;
/* Start up libxml and its parser */
xmlerrcxt = pg_xml_init ( PG_XML_STRICTNESS_WELLFORMED ) ;
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 */
/* Use a TRY block to ensure we clean up correctly */
PG_TRY ( ) ;
{
xmlInitParser ( ) ;
ctxt = xmlNewParserCtxt ( ) ;
if ( ctxt = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_OUT_OF_MEMORY ,
" could not allocate parser context " ) ;
if ( xmloption_arg = = XMLOPTION_DOCUMENT )
{
/*
@ -1213,8 +1325,8 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
" UTF-8 " ,
XML_PARSE_NOENT | XML_PARSE_DTDATTR
| ( preserve_whitespace ? 0 : XML_PARSE_NOBLANKS ) ) ;
if ( doc = = NULL )
xml_ereport ( ERROR , ERRCODE_INVALID_XML_DOCUMENT ,
if ( doc = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_INVALID_XML_DOCUMENT ,
" invalid XML document " ) ;
}
else
@ -1238,23 +1350,28 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
res_code = xmlParseBalancedChunkMemory ( doc , NULL , NULL , 0 ,
utf8string + count , NULL ) ;
if ( res_code ! = 0 )
{
xmlFreeDoc ( doc ) ;
xml_ereport ( ERROR , ERRCODE_INVALID_XML_CONTENT ,
if ( res_code ! = 0 | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_INVALID_XML_CONTENT ,
" invalid XML content " ) ;
}
}
}
PG_CATCH ( ) ;
{
xmlFreeParserCtxt ( ctxt ) ;
if ( doc ! = NULL )
xmlFreeDoc ( doc ) ;
if ( ctxt ! = NULL )
xmlFreeParserCtxt ( ctxt ) ;
pg_xml_done ( xmlerrcxt , true ) ;
PG_RE_THROW ( ) ;
}
PG_END_TRY ( ) ;
xmlFreeParserCtxt ( ctxt ) ;
pg_xml_done ( xmlerrcxt , false ) ;
return doc ;
}
@ -1335,70 +1452,180 @@ xml_pstrdup(const char *string)
* handler . Note that pg_xml_init ( ) * must * have been called previously .
*/
void
xml_ereport ( int level , int sqlcode , const char * msg )
xml_ereport ( PgXmlErrorContext * errcxt , int level , int sqlcode , const char * msg )
{
char * detail ;
/*
* It might seem that we should just pass xml_err_buf - > data directly to
* errdetail . However , we want to clean out xml_err_buf before throwing
* error , in case there is another function using libxml further down the
* call stack .
*/
if ( xml_err_buf - > len > 0 )
{
detail = pstrdup ( xml_err_buf - > data ) ;
resetStringInfo ( xml_err_buf ) ;
}
/* Defend against someone passing us a bogus context struct */
if ( errcxt - > magic ! = ERRCXT_MAGIC )
elog ( ERROR , " xml_ereport called with invalid PgXmlErrorContext " ) ;
/* Flag that the current libxml error has been reported */
errcxt - > err_occurred = false ;
/* Include detail only if we have some text from libxml */
if ( errcxt - > err_buf . len > 0 )
detail = errcxt - > err_buf . data ;
else
detail = NULL ;
if ( detail )
ereport ( level ,
( errcode ( sqlcode ) ,
errmsg_internal ( " %s " , msg ) ,
detail ? errdetail_internal ( " %s " , detail ) : 0 ) ) ;
}
/*
* Error handler for libxml errors and warnings
*/
static void
xml_errorHandler ( void * data , xmlErrorPtr error )
{
PgXmlErrorContext * xmlerrcxt = ( PgXmlErrorContext * ) data ;
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 ;
int domain = error - > domain ;
int level = error - > level ;
StringInfo errorBuf ;
/* Defend against someone passing us a bogus context struct */
if ( xmlerrcxt - > magic ! = ERRCXT_MAGIC )
elog ( ERROR , " xml_errorHandler called with invalid PgXmlErrorContext " ) ;
/*----------
* 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 .
* - - - - - - - - - -
*/
switch ( error - > code )
{
size_t len ;
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 ;
}
/* libxml error messages end in '\n'; get rid of it */
len = strlen ( detail ) ;
if ( len > 0 & & detail [ len - 1 ] = = ' \n ' )
detail [ len - 1 ] = ' \0 ' ;
/* 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 error regardless of the parsing purpose */
break ;
ereport ( level ,
( errcode ( sqlcode ) ,
errmsg_internal ( " %s " , msg ) ,
errdetail_internal ( " %s " , detail ) ) ) ;
default :
/* Ignore error if only doing well-formedness check */
if ( xmlerrcxt - > strictness = = PG_XML_STRICTNESS_WELLFORMED )
return ;
break ;
}
else
/* Prepare error message in errorBuf */
errorBuf = makeStringInfo ( ) ;
if ( error - > line > 0 )
appendStringInfo ( errorBuf , " line %d: " , error - > line ) ;
if ( name ! = NULL )
appendStringInfo ( errorBuf , " element %s: " , name ) ;
appendStringInfoString ( errorBuf , error - > message ) ;
/*
* Append context information to errorBuf .
*
* xmlParserPrintFileContext ( ) uses libxml ' s " generic " error handler to
* write the context . Since we don ' t want to duplicate libxml
* functionality here , we set up a generic error handler temporarily .
*
* We use appendStringInfo ( ) directly as libxml ' s generic error handler .
* This should work because it has essentially the same signature as
* libxml expects , namely ( void * ptr , const char * msg , . . . ) .
*/
if ( input ! = NULL )
{
ereport ( level ,
( errcode ( sqlcode ) ,
errmsg_internal ( " %s " , msg ) ) ) ;
xmlGenericErrorFunc errFuncSaved = xmlGenericError ;
void * errCtxSaved = xmlGenericErrorContext ;
xmlSetGenericErrorFunc ( ( void * ) errorBuf ,
( xmlGenericErrorFunc ) appendStringInfo ) ;
/* Add context information to errorBuf */
appendStringInfoLineSeparator ( errorBuf ) ;
xmlParserPrintFileContext ( input ) ;
/* Restore generic error func */
xmlSetGenericErrorFunc ( errCtxSaved , errFuncSaved ) ;
}
}
/* Get rid of any trailing newlines in errorBuf */
chopStringInfoNewlines ( errorBuf ) ;
/*
* Error handler for libxml error messages
*/
static void
xml_errorHandler ( void * ctxt , const char * msg , . . . )
{
/* Append the formatted text to xml_err_buf */
for ( ; ; )
/*
* Legacy error handling mode . err_occurred is never set , we just add the
* message to err_buf . This mode 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 ( xmlerrcxt - > strictness = = PG_XML_STRICTNESS_LEGACY )
{
va_list args ;
bool success ;
appendStringInfoLineSeparator ( & xmlerrcxt - > err_buf ) ;
appendStringInfoString ( & xmlerrcxt - > err_buf , errorBuf - > data ) ;
/* Try to format the data. */
va_start ( args , msg ) ;
success = appendStringInfoVA ( xml_err_buf , msg , args ) ;
va_end ( args ) ;
pfree ( errorBuf - > data ) ;
pfree ( errorBuf ) ;
return ;
}
if ( success )
break ;
/*
* 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 can be reported immediately since they won ' t cause
* a longjmp ( ) out of libxml .
*/
if ( level > = XML_ERR_ERROR )
{
appendStringInfoLineSeparator ( & xmlerrcxt - > err_buf ) ;
appendStringInfoString ( & xmlerrcxt - > err_buf , errorBuf - > data ) ;
/* Double the buffer size and try again. */
enlargeStringInfo ( xml_err_buf , xml_err_buf - > maxlen ) ;
xmlerrcxt - > err_occurred = true ;
}
else if ( level > = XML_ERR_WARNING )
{
ereport ( WARNING ,
( errmsg_internal ( " %s " , errorBuf - > data ) ) ) ;
}
else
{
ereport ( NOTICE ,
( errmsg_internal ( " %s " , errorBuf - > data ) ) ) ;
}
pfree ( errorBuf - > data ) ;
pfree ( errorBuf ) ;
}
@ -1447,6 +1674,29 @@ xml_ereport_by_code(int level, int sqlcode,
}
/*
* Remove all trailing newlines from a StringInfo string
*/
static void
chopStringInfoNewlines ( StringInfo str )
{
while ( str - > len > 0 & & str - > data [ str - > len - 1 ] = = ' \n ' )
str - > data [ - - str - > len ] = ' \0 ' ;
}
/*
* Append a newline after removing any existing trailing newlines
*/
static void
appendStringInfoLineSeparator ( StringInfo str )
{
chopStringInfoNewlines ( str ) ;
if ( str - > len > 0 )
appendStringInfoChar ( str , ' \n ' ) ;
}
/*
* Convert one char in the current server encoding to a Unicode codepoint .
*/
@ -1753,21 +2003,22 @@ map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
case BYTEAOID :
{
bytea * bstr = DatumGetByteaPP ( value ) ;
xmlBufferPtr buf = NULL ;
xmlTextWriterPtr writer = NULL ;
PgXmlErrorContext * xmlerrcxt ;
volatile xmlBufferPtr buf = NULL ;
volatile xmlTextWriterPtr writer = NULL ;
char * result ;
pg_xml_init ( ) ;
xmlerrcxt = pg_xml_init ( PG_XML_STRICTNESS_ALL ) ;
PG_TRY ( ) ;
{
buf = xmlBufferCreate ( ) ;
if ( ! buf )
xml_ereport ( ERROR , ERRCODE_OUT_OF_MEMORY ,
if ( buf = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_OUT_OF_MEMORY ,
" could not allocate xmlBuffer " ) ;
writer = xmlNewTextWriterMemory ( buf , 0 ) ;
if ( ! writer )
xml_ereport ( ERROR , ERRCODE_OUT_OF_MEMORY ,
if ( writer = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_OUT_OF_MEMORY ,
" could not allocate xmlTextWriter " ) ;
if ( xmlbinary = = XMLBINARY_BASE64 )
@ -1789,12 +2040,17 @@ map_sql_value_to_xml_value(Datum value, Oid type, bool xml_escape_strings)
xmlFreeTextWriter ( writer ) ;
if ( buf )
xmlBufferFree ( buf ) ;
pg_xml_done ( xmlerrcxt , true ) ;
PG_RE_THROW ( ) ;
}
PG_END_TRY ( ) ;
xmlBufferFree ( buf ) ;
pg_xml_done ( xmlerrcxt , false ) ;
return result ;
}
# endif /* USE_LIBXML */
@ -3312,11 +3568,12 @@ static void
xpath_internal ( text * xpath_expr_text , xmltype * data , ArrayType * namespaces ,
int * res_nitems , ArrayBuildState * * astate )
{
xmlParserCtxtPtr ctxt = NULL ;
xmlDocPtr doc = NULL ;
xmlXPathContextPtr xpathctx = NULL ;
xmlXPathCompExprPtr xpathcomp = NULL ;
xmlXPathObjectPtr xpathobj = NULL ;
PgXmlErrorContext * xmlerrcxt ;
volatile xmlParserCtxtPtr ctxt = NULL ;
volatile xmlDocPtr doc = NULL ;
volatile xmlXPathContextPtr xpathctx = NULL ;
volatile xmlXPathCompExprPtr xpathcomp = NULL ;
volatile xmlXPathObjectPtr xpathobj = NULL ;
char * datastr ;
int32 len ;
int32 xpath_len ;
@ -3382,30 +3639,31 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
memcpy ( xpath_expr , VARDATA ( xpath_expr_text ) , xpath_len ) ;
xpath_expr [ xpath_len ] = ' \0 ' ;
pg_xml_init ( ) ;
xmlInitParser ( ) ;
xmlerrcxt = pg_xml_init ( PG_XML_STRICTNESS_ALL ) ;
PG_TRY ( ) ;
{
xmlInitParser ( ) ;
/*
* redundant XML parsing ( two parsings for the same value during one
* command execution are possible )
*/
ctxt = xmlNewParserCtxt ( ) ;
if ( ctxt = = NULL )
xml_ereport ( ERROR , ERRCODE_OUT_OF_MEMORY ,
if ( ctxt = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , 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 ,
if ( doc = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_INVALID_XML_DOCUMENT ,
" could not parse XML document " ) ;
xpathctx = xmlXPathNewContext ( doc ) ;
if ( xpathctx = = NULL )
xml_ereport ( ERROR , ERRCODE_OUT_OF_MEMORY ,
if ( xpathctx = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_OUT_OF_MEMORY ,
" could not allocate XPath context " ) ;
xpathctx - > node = xmlDocGetRootElement ( doc ) ;
if ( xpathctx - > node = = NULL )
xml_ereport ( ERROR , ERRCODE_INTERNAL_ERROR ,
if ( xpathctx - > node = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_INTERNAL_ERROR ,
" could not find root XML element " ) ;
/* register namespaces, if any */
@ -3433,8 +3691,8 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
}
xpathcomp = xmlXPathCompile ( xpath_expr ) ;
if ( xpathcomp = = NULL ) /* TODO: show proper XPath error details */
xml_ereport ( ERROR , ERRCODE_INTERNAL_ERROR ,
if ( xpathcomp = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_INTERNAL_ERROR ,
" invalid XPath expression " ) ;
/*
@ -3445,8 +3703,8 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
* the same .
*/
xpathobj = xmlXPathCompiledEval ( xpathcomp , xpathctx ) ;
if ( xpathobj = = NULL ) /* TODO: reason? */
xml_ereport ( ERROR , ERRCODE_INTERNAL_ERROR ,
if ( xpathobj = = NULL | | xmlerrcxt - > err_occurred )
xml_ereport ( xmlerrcxt , ERROR , ERRCODE_INTERNAL_ERROR ,
" could not create XPath object " ) ;
/* return empty array in cases when nothing is found */
@ -3482,6 +3740,9 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
xmlFreeDoc ( doc ) ;
if ( ctxt )
xmlFreeParserCtxt ( ctxt ) ;
pg_xml_done ( xmlerrcxt , true ) ;
PG_RE_THROW ( ) ;
}
PG_END_TRY ( ) ;
@ -3491,6 +3752,8 @@ xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
xmlXPathFreeContext ( xpathctx ) ;
xmlFreeDoc ( doc ) ;
xmlFreeParserCtxt ( ctxt ) ;
pg_xml_done ( xmlerrcxt , false ) ;
}
# endif /* USE_LIBXML */
@ -3579,7 +3842,7 @@ static bool
wellformed_xml ( text * data , XmlOptionType xmloption_arg )
{
bool result ;
xmlDocPtr doc = NULL ;
volatile xmlDocPtr doc = NULL ;
/* We want to catch any exceptions and return false */
PG_TRY ( ) ;