Skip to content

Commit a9747be

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 4506d18 commit a9747be

File tree

3 files changed

+66
-36
lines changed

3 files changed

+66
-36
lines changed

src/backend/utils/adt/xml.c

Lines changed: 66 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -757,7 +757,7 @@ xmltotext_with_options(xmltype *data, XmlOptionType xmloption_arg, bool indent)
757757

758758
/* This attaches root to doc, so we need not free it separately. */
759759
xmlDocSetRootElement(doc, root);
760-
xmlAddChild(root, content_nodes);
760+
xmlAddChildList(root, content_nodes);
761761

762762
/*
763763
* We use this node to insert newlines in the dump. Note: in at
@@ -1696,9 +1696,9 @@ xml_doctype_in_content(const xmlChar *str)
16961696
* XmlOptionType actually used to parse the input (typically the same as
16971697
* xmloption_arg, but a DOCTYPE node in the input can force DOCUMENT mode).
16981698
*
1699-
* If parsed_nodes isn't NULL and the input is not an XML document, the list
1700-
* of parsed nodes from the xmlParseBalancedChunkMemory call will be returned
1701-
* to *parsed_nodes.
1699+
* If parsed_nodes isn't NULL and we parse in CONTENT mode, the list
1700+
* of parsed nodes from the xmlParseInNodeContext call will be returned
1701+
* to *parsed_nodes. (It is caller's responsibility to free that.)
17021702
*
17031703
* Errors normally result in ereport(ERROR), but if escontext is an
17041704
* ErrorSaveContext, then "safe" errors are reported there instead, and the
@@ -1750,6 +1750,7 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
17501750
PG_TRY();
17511751
{
17521752
bool parse_as_document = false;
1753+
int options;
17531754
int res_code;
17541755
size_t count = 0;
17551756
xmlChar *version = NULL;
@@ -1758,11 +1759,6 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
17581759
/* Any errors here are reported as hard ereport's */
17591760
xmlInitParser();
17601761

1761-
ctxt = xmlNewParserCtxt();
1762-
if (ctxt == NULL || xmlerrcxt->err_occurred)
1763-
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
1764-
"could not allocate parser context");
1765-
17661762
/* Decide whether to parse as document or content */
17671763
if (xmloption_arg == XMLOPTION_DOCUMENT)
17681764
parse_as_document = true;
@@ -1785,6 +1781,18 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
17851781
parse_as_document = true;
17861782
}
17871783

1784+
/*
1785+
* Select parse options.
1786+
*
1787+
* Note that here we try to apply DTD defaults (XML_PARSE_DTDATTR)
1788+
* according to SQL/XML:2008 GR 10.16.7.d: 'Default values defined by
1789+
* internal DTD are applied'. As for external DTDs, we try to support
1790+
* them too (see SQL/XML:2008 GR 10.16.7.e), but that doesn't really
1791+
* happen because xmlPgEntityLoader prevents it.
1792+
*/
1793+
options = XML_PARSE_NOENT | XML_PARSE_DTDATTR
1794+
| (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS);
1795+
17881796
/* initialize output parameters */
17891797
if (parsed_xmloptiontype != NULL)
17901798
*parsed_xmloptiontype = parse_as_document ? XMLOPTION_DOCUMENT :
@@ -1794,18 +1802,16 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
17941802

17951803
if (parse_as_document)
17961804
{
1797-
/*
1798-
* Note, that here we try to apply DTD defaults
1799-
* (XML_PARSE_DTDATTR) according to SQL/XML:2008 GR 10.16.7.d:
1800-
* 'Default values defined by internal DTD are applied'. As for
1801-
* external DTDs, we try to support them too, (see SQL/XML:2008 GR
1802-
* 10.16.7.e)
1803-
*/
1805+
ctxt = xmlNewParserCtxt();
1806+
if (ctxt == NULL || xmlerrcxt->err_occurred)
1807+
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
1808+
"could not allocate parser context");
1809+
18041810
doc = xmlCtxtReadDoc(ctxt, utf8string,
1805-
NULL,
1811+
NULL, /* no URL */
18061812
"UTF-8",
1807-
XML_PARSE_NOENT | XML_PARSE_DTDATTR
1808-
| (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
1813+
options);
1814+
18091815
if (doc == NULL || xmlerrcxt->err_occurred)
18101816
{
18111817
/* Use original option to decide which error code to report */
@@ -1822,6 +1828,9 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
18221828
}
18231829
else
18241830
{
1831+
xmlNodePtr root;
1832+
1833+
/* set up document with empty root node to be the context node */
18251834
doc = xmlNewDoc(version);
18261835
if (doc == NULL || xmlerrcxt->err_occurred)
18271836
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
@@ -1834,19 +1843,38 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
18341843
"could not allocate XML document");
18351844
doc->standalone = standalone;
18361845

1846+
root = xmlNewNode(NULL, (const xmlChar *) "content-root");
1847+
if (root == NULL || xmlerrcxt->err_occurred)
1848+
xml_ereport(xmlerrcxt, ERROR, ERRCODE_OUT_OF_MEMORY,
1849+
"could not allocate xml node");
1850+
/* This attaches root to doc, so we need not free it separately. */
1851+
xmlDocSetRootElement(doc, root);
1852+
18371853
/* allow empty content */
18381854
if (*(utf8string + count))
18391855
{
1840-
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0,
1841-
utf8string + count,
1842-
parsed_nodes);
1843-
if (res_code != 0 || xmlerrcxt->err_occurred)
1856+
xmlNodePtr node_list = NULL;
1857+
xmlParserErrors res;
1858+
1859+
res = xmlParseInNodeContext(root,
1860+
(char *) utf8string + count,
1861+
strlen((char *) utf8string + count),
1862+
options,
1863+
&node_list);
1864+
1865+
if (res != XML_ERR_OK || xmlerrcxt->err_occurred)
18441866
{
1867+
xmlFreeNodeList(node_list);
18451868
xml_errsave(escontext, xmlerrcxt,
18461869
ERRCODE_INVALID_XML_CONTENT,
18471870
"invalid XML content");
18481871
goto fail;
18491872
}
1873+
1874+
if (parsed_nodes != NULL)
1875+
*parsed_nodes = node_list;
1876+
else
1877+
xmlFreeNodeList(node_list);
18501878
}
18511879
}
18521880

@@ -1866,7 +1894,8 @@ xml_parse(text *data, XmlOptionType xmloption_arg,
18661894
}
18671895
PG_END_TRY();
18681896

1869-
xmlFreeParserCtxt(ctxt);
1897+
if (ctxt != NULL)
1898+
xmlFreeParserCtxt(ctxt);
18701899

18711900
pg_xml_done(xmlerrcxt, false);
18721901

@@ -2085,6 +2114,19 @@ xml_errorHandler(void *data, PgXmlErrorPtr error)
20852114
switch (domain)
20862115
{
20872116
case XML_FROM_PARSER:
2117+
2118+
/*
2119+
* XML_ERR_NOT_WELL_BALANCED is typically reported after some
2120+
* other, more on-point error. Furthermore, libxml2 2.13 reports
2121+
* it under a completely different set of rules than prior
2122+
* versions. To avoid cross-version behavioral differences,
2123+
* suppress it so long as we already logged some error.
2124+
*/
2125+
if (error->code == XML_ERR_NOT_WELL_BALANCED &&
2126+
xmlerrcxt->err_occurred)
2127+
return;
2128+
/* fall through */
2129+
20882130
case XML_FROM_NONE:
20892131
case XML_FROM_MEMORY:
20902132
case XML_FROM_IO:

src/test/regress/expected/xml.out

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -254,17 +254,11 @@ ERROR: invalid XML content
254254
DETAIL: line 1: xmlParseEntityRef: no name
255255
<invalidentity>&</invalidentity>
256256
^
257-
line 1: chunk is not well balanced
258-
<invalidentity>&</invalidentity>
259-
^
260257
SELECT xmlparse(content '<undefinedentity>&idontexist;</undefinedentity>');
261258
ERROR: invalid XML content
262259
DETAIL: line 1: Entity 'idontexist' not defined
263260
<undefinedentity>&idontexist;</undefinedentity>
264261
^
265-
line 1: chunk is not well balanced
266-
<undefinedentity>&idontexist;</undefinedentity>
267-
^
268262
SELECT xmlparse(content '<invalidns xmlns=''&lt;''/>');
269263
xmlparse
270264
---------------------------
@@ -283,9 +277,6 @@ DETAIL: line 1: Entity 'idontexist' not defined
283277
<twoerrors>&idontexist;</unbalanced>
284278
^
285279
line 1: Opening and ending tag mismatch: twoerrors line 1 and unbalanced
286-
<twoerrors>&idontexist;</unbalanced>
287-
^
288-
line 1: chunk is not well balanced
289280
<twoerrors>&idontexist;</unbalanced>
290281
^
291282
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
@@ -250,13 +250,11 @@ ERROR: invalid XML content
250250
DETAIL: line 1: xmlParseEntityRef: no name
251251
<invalidentity>&</invalidentity>
252252
^
253-
line 1: chunk is not well balanced
254253
SELECT xmlparse(content '<undefinedentity>&idontexist;</undefinedentity>');
255254
ERROR: invalid XML content
256255
DETAIL: line 1: Entity 'idontexist' not defined
257256
<undefinedentity>&idontexist;</undefinedentity>
258257
^
259-
line 1: chunk is not well balanced
260258
SELECT xmlparse(content '<invalidns xmlns=''&lt;''/>');
261259
xmlparse
262260
---------------------------
@@ -275,7 +273,6 @@ DETAIL: line 1: Entity 'idontexist' not defined
275273
<twoerrors>&idontexist;</unbalanced>
276274
^
277275
line 1: Opening and ending tag mismatch: twoerrors line 1 and unbalanced
278-
line 1: chunk is not well balanced
279276
SELECT xmlparse(content '<nosuchprefix:tag/>');
280277
xmlparse
281278
---------------------

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy