diff options
Diffstat (limited to 'contrib/xml2/xpath.c')
-rw-r--r-- | contrib/xml2/xpath.c | 131 |
1 files changed, 93 insertions, 38 deletions
diff --git a/contrib/xml2/xpath.c b/contrib/xml2/xpath.c index 44c600e1348..2ddee59fcb7 100644 --- a/contrib/xml2/xpath.c +++ b/contrib/xml2/xpath.c @@ -38,7 +38,7 @@ Datum xpath_table(PG_FUNCTION_ARGS); /* exported for use by xslt_proc.c */ -void pgxml_parser_init(void); +PgXmlErrorContext *pgxml_parser_init(PgXmlStrictness strictness); /* workspace for pgxml_xpath() */ @@ -68,18 +68,27 @@ static void cleanup_workspace(xpath_workspace *workspace); /* * Initialize for xml parsing. + * + * As with the underlying pg_xml_init function, calls to this MUST be followed + * by a PG_TRY block that guarantees that pg_xml_done is called. */ -void -pgxml_parser_init(void) +PgXmlErrorContext * +pgxml_parser_init(PgXmlStrictness strictness) { + PgXmlErrorContext *xmlerrcxt; + /* Set up error handling (we share the core's error handler) */ - pg_xml_init(); + xmlerrcxt = pg_xml_init(strictness); + + /* Note: we're assuming an elog cannot be thrown by the following calls */ /* Initialize libxml */ xmlInitParser(); xmlSubstituteEntitiesDefault(1); xmlLoadExtDtdDefaultValue = 1; + + return xmlerrcxt; } @@ -98,16 +107,33 @@ Datum xml_is_well_formed(PG_FUNCTION_ARGS) { text *t = PG_GETARG_TEXT_P(0); /* document buffer */ + bool result = false; int32 docsize = VARSIZE(t) - VARHDRSZ; xmlDocPtr doctree; + PgXmlErrorContext *xmlerrcxt; + + xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); + + PG_TRY(); + { + doctree = xmlParseMemory((char *) VARDATA(t), docsize); + + result = (doctree != NULL); + + if (doctree != NULL) + xmlFreeDoc(doctree); + } + PG_CATCH(); + { + pg_xml_done(xmlerrcxt, true); - pgxml_parser_init(); + PG_RE_THROW(); + } + PG_END_TRY(); - doctree = xmlParseMemory((char *) VARDATA(t), docsize); - if (doctree == NULL) - PG_RETURN_BOOL(false); /* i.e. not well-formed */ - xmlFreeDoc(doctree); - PG_RETURN_BOOL(true); + pg_xml_done(xmlerrcxt, false); + + PG_RETURN_BOOL(result); } @@ -399,41 +425,52 @@ static xmlXPathObjectPtr pgxml_xpath(text *document, xmlChar *xpath, xpath_workspace *workspace) { int32 docsize = VARSIZE(document) - VARHDRSZ; - xmlXPathObjectPtr res; + PgXmlErrorContext *xmlerrcxt; xmlXPathCompExprPtr comppath; workspace->doctree = NULL; workspace->ctxt = NULL; workspace->res = NULL; - pgxml_parser_init(); + xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); - workspace->doctree = xmlParseMemory((char *) VARDATA(document), docsize); - if (workspace->doctree == NULL) - return NULL; /* not well-formed */ + PG_TRY(); + { + workspace->doctree = xmlParseMemory((char *) VARDATA(document), + docsize); + if (workspace->doctree != NULL) + { + workspace->ctxt = xmlXPathNewContext(workspace->doctree); + workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree); - workspace->ctxt = xmlXPathNewContext(workspace->doctree); - workspace->ctxt->node = xmlDocGetRootElement(workspace->doctree); + /* compile the path */ + comppath = xmlXPathCompile(xpath); + if (comppath == NULL) + xml_ereport(xmlerrcxt, ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, + "XPath Syntax Error"); - /* compile the path */ - comppath = xmlXPathCompile(xpath); - if (comppath == NULL) + /* Now evaluate the path expression. */ + workspace->res = xmlXPathCompiledEval(comppath, workspace->ctxt); + + xmlXPathFreeCompExpr(comppath); + } + } + PG_CATCH(); { cleanup_workspace(workspace); - xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, - "XPath Syntax Error"); - } - /* Now evaluate the path expression. */ - res = xmlXPathCompiledEval(comppath, workspace->ctxt); - workspace->res = res; + pg_xml_done(xmlerrcxt, true); - xmlXPathFreeCompExpr(comppath); + PG_RE_THROW(); + } + PG_END_TRY(); - if (res == NULL) + if (workspace->res == NULL) cleanup_workspace(workspace); - return res; + pg_xml_done(xmlerrcxt, false); + + return workspace->res; } /* Clean up after processing the result of pgxml_xpath() */ @@ -534,6 +571,8 @@ xpath_table(PG_FUNCTION_ARGS) * document */ bool had_values; /* To determine end of nodeset results */ StringInfoData query_buf; + PgXmlErrorContext *xmlerrcxt; + volatile xmlDocPtr doctree = NULL; /* We only have a valid tuple description in table function mode */ if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo)) @@ -659,14 +698,15 @@ xpath_table(PG_FUNCTION_ARGS) * 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(); + xmlerrcxt = pgxml_parser_init(PG_XML_STRICTNESS_LEGACY); + PG_TRY(); + { /* For each row i.e. document returned from SPI */ for (i = 0; i < proc; i++) { char *pkey; char *xmldoc; - xmlDocPtr doctree; xmlXPathContextPtr ctxt; xmlXPathObjectPtr res; xmlChar *resstr; @@ -718,11 +758,9 @@ xpath_table(PG_FUNCTION_ARGS) /* compile the path */ comppath = xmlXPathCompile(xpaths[j]); if (comppath == NULL) - { - xmlFreeDoc(doctree); - xml_ereport(ERROR, ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, + xml_ereport(xmlerrcxt, ERROR, + ERRCODE_EXTERNAL_ROUTINE_EXCEPTION, "XPath Syntax Error"); - } /* Now evaluate the path expression. */ res = xmlXPathCompiledEval(comppath, ctxt); @@ -737,8 +775,7 @@ xpath_table(PG_FUNCTION_ARGS) if (res->nodesetval != NULL && rownr < res->nodesetval->nodeNr) { - resstr = - xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]); + resstr = xmlXPathCastNodeToString(res->nodesetval->nodeTab[rownr]); had_values = true; } else @@ -776,13 +813,31 @@ xpath_table(PG_FUNCTION_ARGS) } while (had_values); } - xmlFreeDoc(doctree); + if (doctree != NULL) + xmlFreeDoc(doctree); + doctree = NULL; if (pkey) pfree(pkey); if (xmldoc) pfree(xmldoc); } + } + PG_CATCH(); + { + if (doctree != NULL) + xmlFreeDoc(doctree); + + pg_xml_done(xmlerrcxt, true); + + PG_RE_THROW(); + } + PG_END_TRY(); + + if (doctree != NULL) + xmlFreeDoc(doctree); + + pg_xml_done(xmlerrcxt, false); tuplestore_donestoring(tupstore); |