Skip to content

Commit f68d6aa

Browse files
committed
Make our back branches compatible with libxml2 2.13.x.
This back-patches HEAD commits 066e8ac, 6082b3d, e719248, and 896cd26 into supported branches. Changes: * Use xmlAddChildList not xmlAddChild in XMLSERIALIZE (affects v16 and up only). This was a flat-out coding mistake that we got away with due to lax checking in previous versions of xmlAddChild. * Use xmlParseInNodeContext not xmlParseBalancedChunkMemory. This is to dodge a bug in xmlParseBalancedChunkMemory in libxm2 releases 2.13.0-2.13.2. While that bug is now fixed upstream and will probably never be seen in any production-oriented distro, it is currently a problem on some more-bleeding-edge-friendly platforms. * Suppress "chunk is not well balanced" errors from libxml2, unless it is the only error. This eliminates an error-reporting discrepancy between 2.13 and older releases. This error is almost always redundant with previous errors, if not flat-out inappropriate, which is why 2.13 changed the behavior and why nobody's likely to miss it. Erik Wienhold and Tom Lane, per report from Frank Streitzig. Discussion: https://postgr.es/m/trinity-b0161630-d230-4598-9ebc-7a23acdb37cb-1720186432160@3c-app-gmx-bap25 Discussion: https://postgr.es/m/trinity-361ba18b-541a-4fe7-bc63-655ae3a7d599-1720259822452@3c-app-gmx-bs01
1 parent 468b236 commit f68d6aa

File tree

3 files changed

+58
-31
lines changed

3 files changed

+58
-31
lines changed

src/backend/utils/adt/xml.c

Lines changed: 58 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1544,18 +1544,14 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
15441544
PG_TRY();
15451545
{
15461546
bool parse_as_document = false;
1547+
int options;
15471548
int res_code;
15481549
size_t count = 0;
15491550
xmlChar *version = NULL;
15501551
int standalone = 0;
15511552

15521553
xmlInitParser();
15531554

1554-
ctxt = xmlNewParserCtxt();
1555-
if (ctxt == NULL || xmlerrcxt->err_occurred)
1556-
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
1557-
"could not allocate parser context");
1558-
15591555
/* Decide whether to parse as document or content */
15601556
if (xmloption_arg == XMLOPTION_DOCUMENT)
15611557
parse_as_document = true;
@@ -1574,20 +1570,30 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
15741570
parse_as_document = true;
15751571
}
15761572

1573+
/*
1574+
* Select parse options.
1575+
*
1576+
* Note that here we try to apply DTD defaults (XML_PARSE_DTDATTR)
1577+
* according to SQL/XML:2008 GR 10.16.7.d: 'Default values defined by
1578+
* internal DTD are applied'. As for external DTDs, we try to support
1579+
* them too (see SQL/XML:2008 GR 10.16.7.e), but that doesn't really
1580+
* happen because xmlPgEntityLoader prevents it.
1581+
*/
1582+
options = XML_PARSE_NOENT | XML_PARSE_DTDATTR
1583+
| (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS);
1584+
15771585
if (parse_as_document)
15781586
{
1579-
/*
1580-
* Note, that here we try to apply DTD defaults
1581-
* (XML_PARSE_DTDATTR) according to SQL/XML:2008 GR 10.16.7.d:
1582-
* 'Default values defined by internal DTD are applied'. As for
1583-
* external DTDs, we try to support them too, (see SQL/XML:2008 GR
1584-
* 10.16.7.e)
1585-
*/
1587+
ctxt = xmlNewParserCtxt();
1588+
if (ctxt == NULL || xmlerrcxt->err_occurred)
1589+
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
1590+
"could not allocate parser context");
1591+
15861592
doc = xmlCtxtReadDoc(ctxt, utf8string,
1587-
NULL,
1593+
NULL, /* no URL */
15881594
"UTF-8",
1589-
XML_PARSE_NOENT | XML_PARSE_DTDATTR
1590-
| (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
1595+
options);
1596+
15911597
if (doc == NULL || xmlerrcxt->err_occurred)
15921598
{
15931599
/* Use original option to decide which error code to throw */
@@ -1601,17 +1607,36 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
16011607
}
16021608
else
16031609
{
1610+
xmlNodePtr root;
1611+
1612+
/* set up document with empty root node to be the context node */
16041613
doc = xmlNewDoc(version);
16051614
Assert(doc->encoding == NULL);
16061615
doc->encoding = xmlStrdup((const xmlChar *) "UTF-8");
16071616
doc->standalone = standalone;
16081617

1618+
root = xmlNewNode(NULL, (const xmlChar *) "content-root");
1619+
if (root == NULL || xmlerrcxt->err_occurred)
1620+
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
1621+
"could not allocate xml node");
1622+
/* This attaches root to doc, so we need not free it separately. */
1623+
xmlDocSetRootElement(doc, root);
1624+
16091625
/* allow empty content */
16101626
if (*(utf8string + count))
16111627
{
1612-
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
1613-
utf8string + count, NULL);
1614-
if (res_code != 0 || xmlerrcxt->err_occurred)
1628+
xmlNodePtr node_list = NULL;
1629+
xmlParserErrors res;
1630+
1631+
res = xmlParseInNodeContext(root,
1632+
(char *) utf8string + count,
1633+
strlen((char *) utf8string + count),
1634+
options,
1635+
&node_list);
1636+
1637+
xmlFreeNodeList(node_list);
1638+
1639+
if (res != XML_ERR_OK || xmlerrcxt->err_occurred)
16151640
xml_ereport(xmlerrcxt, ERROR, ERRCODE_INVALID_XML_CONTENT,
16161641
"invalid XML content");
16171642
}
@@ -1630,7 +1655,8 @@ xml_parse(text *data, XmlOptionType xmloption_arg, bool preserve_whitespace,
16301655
}
16311656
PG_END_TRY();
16321657

1633-
xmlFreeParserCtxt(ctxt);
1658+
if (ctxt != NULL)
1659+
xmlFreeParserCtxt(ctxt);
16341660

16351661
pg_xml_done(xmlerrcxt, false);
16361662

@@ -1811,6 +1837,19 @@ xml_errorHandler(void *data, PgXmlErrorPtr error)
18111837
switch (domain)
18121838
{
18131839
case XML_FROM_PARSER:
1840+
1841+
/*
1842+
* XML_ERR_NOT_WELL_BALANCED is typically reported after some
1843+
* other, more on-point error. Furthermore, libxml2 2.13 reports
1844+
* it under a completely different set of rules than prior
1845+
* versions. To avoid cross-version behavioral differences,
1846+
* suppress it so long as we already logged some error.
1847+
*/
1848+
if (error->code == XML_ERR_NOT_WELL_BALANCED &&
1849+
xmlerrcxt->err_occurred)
1850+
return;
1851+
/* fall through */
1852+
18141853
case XML_FROM_NONE:
18151854
case XML_FROM_MEMORY:
18161855
case XML_FROM_IO:

src/test/regress/expected/xml.out

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -223,17 +223,11 @@ ERROR: invalid XML content
223223
DETAIL: line 1: xmlParseEntityRef: no name
224224
<invalidentity>&</invalidentity>
225225
^
226-
line 1: chunk is not well balanced
227-
<invalidentity>&</invalidentity>
228-
^
229226
SELECT xmlparse(content '<undefinedentity>&idontexist;</undefinedentity>');
230227
ERROR: invalid XML content
231228
DETAIL: line 1: Entity 'idontexist' not defined
232229
<undefinedentity>&idontexist;</undefinedentity>
233230
^
234-
line 1: chunk is not well balanced
235-
<undefinedentity>&idontexist;</undefinedentity>
236-
^
237231
SELECT xmlparse(content '<invalidns xmlns=''&lt;''/>');
238232
xmlparse
239233
---------------------------
@@ -252,9 +246,6 @@ DETAIL: line 1: Entity 'idontexist' not defined
252246
<twoerrors>&idontexist;</unbalanced>
253247
^
254248
line 1: Opening and ending tag mismatch: twoerrors line 1 and unbalanced
255-
<twoerrors>&idontexist;</unbalanced>
256-
^
257-
line 1: chunk is not well balanced
258249
<twoerrors>&idontexist;</unbalanced>
259250
^
260251
SELECT xmlparse(content '<nosuchprefix:tag/>');

src/test/regress/expected/xml_2.out

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -219,13 +219,11 @@ ERROR: invalid XML content
219219
DETAIL: line 1: xmlParseEntityRef: no name
220220
<invalidentity>&</invalidentity>
221221
^
222-
line 1: chunk is not well balanced
223222
SELECT xmlparse(content '<undefinedentity>&idontexist;</undefinedentity>');
224223
ERROR: invalid XML content
225224
DETAIL: line 1: Entity 'idontexist' not defined
226225
<undefinedentity>&idontexist;</undefinedentity>
227226
^
228-
line 1: chunk is not well balanced
229227
SELECT xmlparse(content '<invalidns xmlns=''&lt;''/>');
230228
xmlparse
231229
---------------------------
@@ -244,7 +242,6 @@ DETAIL: line 1: Entity 'idontexist' not defined
244242
<twoerrors>&idontexist;</unbalanced>
245243
^
246244
line 1: Opening and ending tag mismatch: twoerrors line 1 and unbalanced
247-
line 1: chunk is not well balanced
248245
SELECT xmlparse(content '<nosuchprefix:tag/>');
249246
xmlparse
250247
---------------------

0 commit comments

Comments
 (0)