Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 19749fb

Browse files
committed
Replace xmlroot with a properly functioning version that parses the value,
sets the items, and serializes the value back (rather than adding an arbitrary number of XML preambles as before). The libxml memory management via palloc had to be disabled because it crashes when libxml tries to access memory that was helpfully freed earlier by PostgreSQL. This needs further thought.
1 parent 063560b commit 19749fb

File tree

4 files changed

+103
-28
lines changed

4 files changed

+103
-28
lines changed

src/backend/utils/adt/xml.c

Lines changed: 65 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.10 2007/01/05 22:19:42 momjian Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.11 2007/01/06 19:18:36 petere Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -31,6 +31,7 @@
3131
#include <libxml/tree.h>
3232
#include <libxml/uri.h>
3333
#include <libxml/xmlerror.h>
34+
#include <libxml/xmlsave.h>
3435
#endif /* USE_LIBXML */
3536

3637
#include "fmgr.h"
@@ -49,10 +50,12 @@
4950
static StringInfo xml_err_buf = NULL;
5051

5152
static void xml_init(void);
53+
#ifdef NOT_USED
5254
static void *xml_palloc(size_t size);
5355
static void *xml_repalloc(void *ptr, size_t size);
5456
static void xml_pfree(void *ptr);
5557
static char *xml_pstrdup(const char *string);
58+
#endif
5659
static void xml_ereport(int level, int sqlcode,
5760
const char *msg, void *ctxt);
5861
static void xml_errorHandler(void *ctxt, const char *msg, ...);
@@ -76,6 +79,7 @@ xml_in(PG_FUNCTION_ARGS)
7679
char *s = PG_GETARG_CSTRING(0);
7780
size_t len;
7881
xmltype *vardata;
82+
xmlDocPtr doc;
7983

8084
len = strlen(s);
8185
vardata = palloc(len + VARHDRSZ);
@@ -86,7 +90,8 @@ xml_in(PG_FUNCTION_ARGS)
8690
* Parse the data to check if it is well-formed XML data. Assume
8791
* that ERROR occurred if parsing failed.
8892
*/
89-
xml_parse(vardata, false, true);
93+
doc = xml_parse(vardata, false, true);
94+
xmlFreeDoc(doc);
9095

9196
PG_RETURN_XML_P(vardata);
9297
#else
@@ -120,6 +125,7 @@ xml_recv(PG_FUNCTION_ARGS)
120125
xmltype *result;
121126
char *str;
122127
int nbytes;
128+
xmlDocPtr doc;
123129

124130
str = pq_getmsgtext(buf, buf->len - buf->cursor, &nbytes);
125131

@@ -132,7 +138,8 @@ xml_recv(PG_FUNCTION_ARGS)
132138
* Parse the data to check if it is well-formed XML data. Assume
133139
* that ERROR occurred if parsing failed.
134140
*/
135-
xml_parse(result, false, true);
141+
doc = xml_parse(result, false, true);
142+
xmlFreeDoc(doc);
136143

137144
PG_RETURN_XML_P(result);
138145
#else
@@ -175,6 +182,21 @@ stringinfo_to_xmltype(StringInfo buf)
175182

176183
return result;
177184
}
185+
186+
187+
static xmltype *
188+
xmlBuffer_to_xmltype(xmlBufferPtr buf)
189+
{
190+
int32 len;
191+
xmltype *result;
192+
193+
len = xmlBufferLength(buf) + VARHDRSZ;
194+
result = palloc(len);
195+
VARATT_SIZEP(result) = len;
196+
memcpy(VARDATA(result), xmlBufferContent(buf), len - VARHDRSZ);
197+
198+
return result;
199+
}
178200
#endif
179201

180202

@@ -221,7 +243,10 @@ xmltype *
221243
xmlparse(text *data, bool is_document, bool preserve_whitespace)
222244
{
223245
#ifdef USE_LIBXML
224-
xml_parse(data, is_document, preserve_whitespace);
246+
xmlDocPtr doc;
247+
248+
doc = xml_parse(data, is_document, preserve_whitespace);
249+
xmlFreeDoc(doc);
225250

226251
return (xmltype *) data;
227252
#else
@@ -280,31 +305,38 @@ xmltype *
280305
xmlroot(xmltype *data, text *version, int standalone)
281306
{
282307
#ifdef USE_LIBXML
283-
xmltype *result;
284-
StringInfoData buf;
308+
xmlDocPtr doc;
309+
xmlBufferPtr buffer;
310+
xmlSaveCtxtPtr save;
285311

286-
initStringInfo(&buf);
312+
doc = xml_parse((text *) data, true, true);
287313

288-
/*
289-
* FIXME: This is probably supposed to be cleverer if there
290-
* already is an XML preamble.
291-
*/
292-
appendStringInfo(&buf,"<?xml");
293314
if (version)
315+
doc->version = xmlStrdup(xml_text2xmlChar(version));
316+
else
317+
doc->version = NULL;
318+
319+
switch (standalone)
294320
{
295-
appendStringInfo(&buf, " version=\"");
296-
appendStringInfoText(&buf, version);
297-
appendStringInfo(&buf, "\"");
321+
case 1:
322+
doc->standalone = 1;
323+
break;
324+
case -1:
325+
doc->standalone = 0;
326+
break;
327+
default:
328+
doc->standalone = -1;
329+
break;
298330
}
299-
if (standalone)
300-
appendStringInfo(&buf, " standalone=\"%s\"",
301-
(standalone == 1 ? "yes" : "no"));
302-
appendStringInfo(&buf, "?>");
303-
appendStringInfoText(&buf, (text *) data);
304331

305-
result = stringinfo_to_xmltype(&buf);
306-
pfree(buf.data);
307-
return result;
332+
buffer = xmlBufferCreate();
333+
save = xmlSaveToBuffer(buffer, NULL, 0);
334+
xmlSaveDoc(save, doc);
335+
xmlSaveClose(save);
336+
337+
xmlFreeDoc(doc);
338+
339+
return xmlBuffer_to_xmltype(buffer);
308340
#else
309341
NO_XML_SUPPORT();
310342
return NULL;
@@ -444,7 +476,14 @@ xml_init(void)
444476
/* Now that xml_err_buf exists, safe to call xml_errorHandler */
445477
xmlSetGenericErrorFunc(NULL, xml_errorHandler);
446478

479+
#ifdef NOT_USED
480+
/*
481+
* FIXME: This doesn't work because libxml assumes that whatever
482+
* libxml allocates, only libxml will free, so we can't just drop
483+
* memory contexts behind it. This needs to be refined.
484+
*/
447485
xmlMemSetup(xml_pfree, xml_palloc, xml_repalloc, xml_pstrdup);
486+
#endif
448487
xmlInitParser();
449488
LIBXML_TEST_VERSION;
450489
}
@@ -528,8 +567,6 @@ xml_parse(text *data, bool is_document, bool preserve_whitespace)
528567
* ) */
529568
/* ... */
530569

531-
if (doc)
532-
xmlFreeDoc(doc);
533570
if (ctxt)
534571
xmlFreeParserCtxt(ctxt);
535572
xmlCleanupParser();
@@ -538,6 +575,7 @@ xml_parse(text *data, bool is_document, bool preserve_whitespace)
538575
{
539576
if (doc)
540577
xmlFreeDoc(doc);
578+
doc = NULL;
541579
if (ctxt)
542580
xmlFreeParserCtxt(ctxt);
543581
xmlCleanupParser();
@@ -567,6 +605,7 @@ xml_text2xmlChar(text *in)
567605
}
568606

569607

608+
#ifdef NOT_USED
570609
/*
571610
* Wrappers for memory management functions
572611
*/
@@ -596,6 +635,7 @@ xml_pstrdup(const char *string)
596635
{
597636
return pstrdup(string);
598637
}
638+
#endif /* NOT_USED */
599639

600640

601641
/*

src/test/regress/expected/xml.out

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,30 @@ SELECT xmlpi(name foo, 'bar');
124124
SELECT xmlpi(name foo, 'in?>valid');
125125
ERROR: invalid XML processing instruction
126126
DETAIL: XML processing instruction cannot contain "?>".
127+
SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
128+
xmlroot
129+
-----------------------
130+
<?xml version="1.0"?>
131+
<foo/>
132+
133+
(1 row)
134+
135+
SELECT xmlroot(xml '<foo/>', version '2.0');
136+
xmlroot
137+
-----------------------
138+
<?xml version="2.0"?>
139+
<foo/>
140+
141+
(1 row)
142+
143+
SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no);
144+
xmlroot
145+
---------------------------------------
146+
<?xml version="1.1" standalone="no"?>
147+
<foo/>
148+
149+
(1 row)
150+
127151
SELECT xmlroot (
128152
xmlelement (
129153
name gazonk,
@@ -139,9 +163,11 @@ SELECT xmlroot (
139163
version '1.0',
140164
standalone yes
141165
);
142-
xmlroot
143-
------------------------------------------------------------------------------------------
144-
<?xml version="1.0" standalone="yes"?><gazonk name="val" num="2"><qux>foo</qux></gazonk>
166+
xmlroot
167+
----------------------------------------------------
168+
<?xml version="1.0" standalone="yes"?>
169+
<gazonk name="val" num="2"><qux>foo</qux></gazonk>
170+
145171
(1 row)
146172

147173
SELECT xmlserialize(content data as character varying) FROM xmltest;

src/test/regress/expected/xml_1.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,12 @@ SELECT xmlpi(name foo, 'bar');
6262
ERROR: no XML support in this installation
6363
SELECT xmlpi(name foo, 'in?>valid');
6464
ERROR: no XML support in this installation
65+
SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
66+
ERROR: no XML support in this installation
67+
SELECT xmlroot(xml '<foo/>', version '2.0');
68+
ERROR: no XML support in this installation
69+
SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no);
70+
ERROR: no XML support in this installation
6571
SELECT xmlroot (
6672
xmlelement (
6773
name gazonk,

src/test/regress/sql/xml.sql

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ SELECT xmlpi(name xmlstuff);
5252
SELECT xmlpi(name foo, 'bar');
5353
SELECT xmlpi(name foo, 'in?>valid');
5454

55+
SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
56+
SELECT xmlroot(xml '<foo/>', version '2.0');
57+
SELECT xmlroot(xmlroot(xml '<foo/>', version '1.0'), version '1.1', standalone no);
5558

5659
SELECT xmlroot (
5760
xmlelement (

0 commit comments

Comments
 (0)