diff --git a/src/backend/utils/adt/xml.c b/src/backend/utils/adt/xml.c index 6771360c48abff8acabcb1e0daca8bed388f9e36..ab929eed64720308428a971193373308268170b9 100644 --- a/src/backend/utils/adt/xml.c +++ b/src/backend/utils/adt/xml.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.10 2007/01/05 22:19:42 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.11 2007/01/06 19:18:36 petere Exp $ * *------------------------------------------------------------------------- */ @@ -31,6 +31,7 @@ #include <libxml/tree.h> #include <libxml/uri.h> #include <libxml/xmlerror.h> +#include <libxml/xmlsave.h> #endif /* USE_LIBXML */ #include "fmgr.h" @@ -49,10 +50,12 @@ static StringInfo xml_err_buf = NULL; static void xml_init(void); +#ifdef NOT_USED static void *xml_palloc(size_t size); static void *xml_repalloc(void *ptr, size_t size); static void xml_pfree(void *ptr); static char *xml_pstrdup(const char *string); +#endif static void xml_ereport(int level, int sqlcode, const char *msg, void *ctxt); static void xml_errorHandler(void *ctxt, const char *msg, ...); @@ -76,6 +79,7 @@ xml_in(PG_FUNCTION_ARGS) char *s = PG_GETARG_CSTRING(0); size_t len; xmltype *vardata; + xmlDocPtr doc; len = strlen(s); vardata = palloc(len + VARHDRSZ); @@ -86,7 +90,8 @@ xml_in(PG_FUNCTION_ARGS) * Parse the data to check if it is well-formed XML data. Assume * that ERROR occurred if parsing failed. */ - xml_parse(vardata, false, true); + doc = xml_parse(vardata, false, true); + xmlFreeDoc(doc); PG_RETURN_XML_P(vardata); #else @@ -120,6 +125,7 @@ xml_recv(PG_FUNCTION_ARGS) xmltype *result; char *str; int nbytes; + xmlDocPtr doc; str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes); @@ -132,7 +138,8 @@ xml_recv(PG_FUNCTION_ARGS) * Parse the data to check if it is well-formed XML data. Assume * that ERROR occurred if parsing failed. */ - xml_parse(result, false, true); + doc = xml_parse(result, false, true); + xmlFreeDoc(doc); PG_RETURN_XML_P(result); #else @@ -175,6 +182,21 @@ stringinfo_to_xmltype(StringInfo buf) return result; } + + +static xmltype * +xmlBuffer_to_xmltype(xmlBufferPtr buf) +{ + int32 len; + xmltype *result; + + len = xmlBufferLength(buf) + VARHDRSZ; + result = palloc(len); + VARATT_SIZEP(result) = len; + memcpy(VARDATA(result), xmlBufferContent(buf), len - VARHDRSZ); + + return result; +} #endif @@ -221,7 +243,10 @@ xmltype * xmlparse(text *data, bool is_document, bool preserve_whitespace) { #ifdef USE_LIBXML - xml_parse(data, is_document, preserve_whitespace); + xmlDocPtr doc; + + doc = xml_parse(data, is_document, preserve_whitespace); + xmlFreeDoc(doc); return (xmltype *) data; #else @@ -280,31 +305,38 @@ xmltype * xmlroot(xmltype *data, text *version, int standalone) { #ifdef USE_LIBXML - xmltype *result; - StringInfoData buf; + xmlDocPtr doc; + xmlBufferPtr buffer; + xmlSaveCtxtPtr save; - initStringInfo(&buf); + doc = xml_parse((text *) data, true, true); - /* - * FIXME: This is probably supposed to be cleverer if there - * already is an XML preamble. - */ - appendStringInfo(&buf,"<?xml"); if (version) + doc->version = xmlStrdup(xml_text2xmlChar(version)); + else + doc->version = NULL; + + switch (standalone) { - appendStringInfo(&buf, " version=\""); - appendStringInfoText(&buf, version); - appendStringInfo(&buf, "\""); + case 1: + doc->standalone = 1; + break; + case -1: + doc->standalone = 0; + break; + default: + doc->standalone = -1; + break; } - if (standalone) - appendStringInfo(&buf, " standalone=\"%s\"", - (standalone == 1 ? "yes" : "no")); - appendStringInfo(&buf, "?>"); - appendStringInfoText(&buf, (text *) data); - result = stringinfo_to_xmltype(&buf); - pfree(buf.data); - return result; + buffer = xmlBufferCreate(); + save = xmlSaveToBuffer(buffer, NULL, 0); + xmlSaveDoc(save, doc); + xmlSaveClose(save); + + xmlFreeDoc(doc); + + return xmlBuffer_to_xmltype(buffer); #else NO_XML_SUPPORT(); return NULL; @@ -444,7 +476,14 @@ xml_init(void) /* Now that xml_err_buf exists, safe to call xml_errorHandler */ xmlSetGenericErrorFunc(NULL, xml_errorHandler); +#ifdef NOT_USED + /* + * FIXME: This doesn't work because libxml assumes that whatever + * libxml allocates, only libxml will free, so we can't just drop + * memory contexts behind it. This needs to be refined. + */ xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup); +#endif xmlInitParser(); LIBXML_TEST_VERSION; } @@ -528,8 +567,6 @@ xml_parse(text *data, bool is_document, bool preserve_whitespace) * ) */ /* ... */ - if (doc) - xmlFreeDoc(doc); if (ctxt) xmlFreeParserCtxt(ctxt); xmlCleanupParser(); @@ -538,6 +575,7 @@ xml_parse(text *data, bool is_document, bool preserve_whitespace) { if (doc) xmlFreeDoc(doc); + doc = NULL; if (ctxt) xmlFreeParserCtxt(ctxt); xmlCleanupParser(); @@ -567,6 +605,7 @@ xml_text2xmlChar(text *in) } +#ifdef NOT_USED /* * Wrappers for memory management functions */ @@ -596,6 +635,7 @@ xml_pstrdup(const char *string) { return pstrdup(string); } +#endif /* NOT_USED */ /* diff --git a/src/test/regress/expected/xml.out b/src/test/regress/expected/xml.out index 14744656124008b0a7f24f3d5dff2d295a1bc18a..9ebef1404b91cf32506508b586004d367432a4cc 100644 --- a/src/test/regress/expected/xml.out +++ b/src/test/regress/expected/xml.out @@ -124,6 +124,30 @@ SELECT xmlpi(name foo, 'bar'); SELECT xmlpi(name foo, 'in?>valid'); ERROR: invalid XML processing instruction DETAIL: XML processing instruction cannot contain "?>". +SELECT xmlroot(xml '<foo/>', version no value, standalone no value); + xmlroot +----------------------- + <?xml version="1.0"?> + <foo/> + +(1 row) + +SELECT xmlroot(xml '<foo/>', version '2.0'); + xmlroot +----------------------- + <?xml version="2.0"?> + <foo/> + +(1 row) + +SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no); + xmlroot +--------------------------------------- + <?xml version="1.1" standalone="no"?> + <foo/> + +(1 row) + SELECT xmlroot ( xmlelement ( name gazonk, @@ -139,9 +163,11 @@ SELECT xmlroot ( version '1.0', standalone yes ); - xmlroot ------------------------------------------------------------------------------------------- - <?xml version="1.0" standalone="yes"?><gazonk name="val" num="2"><qux>foo</qux></gazonk> + xmlroot +---------------------------------------------------- + <?xml version="1.0" standalone="yes"?> + <gazonk name="val" num="2"><qux>foo</qux></gazonk> + (1 row) SELECT xmlserialize(content data as character varying) FROM xmltest; diff --git a/src/test/regress/expected/xml_1.out b/src/test/regress/expected/xml_1.out index 259bccbf4ba45aacee75354a9be5ff29e9db35eb..662c0e236a8113bd3003a648680ee33563696781 100644 --- a/src/test/regress/expected/xml_1.out +++ b/src/test/regress/expected/xml_1.out @@ -62,6 +62,12 @@ SELECT xmlpi(name foo, 'bar'); ERROR: no XML support in this installation SELECT xmlpi(name foo, 'in?>valid'); ERROR: no XML support in this installation +SELECT xmlroot(xml '<foo/>', version no value, standalone no value); +ERROR: no XML support in this installation +SELECT xmlroot(xml '<foo/>', version '2.0'); +ERROR: no XML support in this installation +SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no); +ERROR: no XML support in this installation SELECT xmlroot ( xmlelement ( name gazonk, diff --git a/src/test/regress/sql/xml.sql b/src/test/regress/sql/xml.sql index 11db4905c7674b1c756f9edde7a09eebdfaedb33..cf96beab060729ee8b18f5e71778428d45d5561d 100644 --- a/src/test/regress/sql/xml.sql +++ b/src/test/regress/sql/xml.sql @@ -52,6 +52,9 @@ SELECT xmlpi(name xmlstuff); SELECT xmlpi(name foo, 'bar'); SELECT xmlpi(name foo, 'in?>valid'); +SELECT xmlroot(xml '<foo/>', version no value, standalone no value); +SELECT xmlroot(xml '<foo/>', version '2.0'); +SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no); SELECT xmlroot ( xmlelement (