]> granicus.if.org Git - postgresql/commitdiff
Ensure that xpath() escapes special characters in string values.
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 20 Jul 2011 22:44:09 +0000 (18:44 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 20 Jul 2011 22:44:35 +0000 (18:44 -0400)
Without this it's possible for the output to not be legal XML, as
illustrated by the added regression test cases.

NB: this change will need to be called out as an incompatibility in the
9.2 release notes, since it's possible somebody was relying on the old
behavior, even though it's clearly wrong.

Florian Pflug, reviewed by Radoslaw Smogura

src/backend/utils/adt/xml.c
src/test/regress/expected/xml.out
src/test/regress/expected/xml_1.out
src/test/regress/sql/xml.sql

index 6786cd91bb553aa88fb5aedfa0ed19ba78cb999e..c07232575e21a1f42d56d1f4f818d8f13b7994a2 100644 (file)
@@ -3537,7 +3537,11 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
                str = xmlXPathCastNodeToString(cur);
                PG_TRY();
                {
-                       result = (xmltype *) cstring_to_text((char *) str);
+                       /* Here we rely on XML having the same representation as TEXT */
+                       char   *escaped = escape_xml((char *) str);
+
+                       result = (xmltype *) cstring_to_text(escaped);
+                       pfree(escaped);
                }
                PG_CATCH();
                {
index 379777aced811a3eb0b9d6a455795da4a04ed13a..5cd602107b22a241dc307584c39bba1efce329e6 100644 (file)
@@ -589,6 +589,18 @@ SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
  {<b>two</b>,<b>etc</b>}
 (1 row)
 
+SELECT xpath('//text()', '<root>&lt;</root>');
+ xpath  
+--------
+ {&lt;}
+(1 row)
+
+SELECT xpath('//@value', '<root value="&lt;"/>');
+ xpath  
+--------
+ {&lt;}
+(1 row)
+
 -- Test xmlexists and xpath_exists
 SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
  xmlexists 
index 1f17bffc0b2088f2afbb1f9793ea1247a79cbedd..53675f5536fb0fde4149e54c00c347c33b28c37d 100644 (file)
@@ -504,6 +504,18 @@ LINE 1: SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>'...
                             ^
 DETAIL:  This functionality requires the server to be built with libxml support.
 HINT:  You need to rebuild PostgreSQL using --with-libxml.
+SELECT xpath('//text()', '<root>&lt;</root>');
+ERROR:  unsupported XML feature
+LINE 1: SELECT xpath('//text()', '<root>&lt;</root>');
+                                 ^
+DETAIL:  This functionality requires the server to be built with libxml support.
+HINT:  You need to rebuild PostgreSQL using --with-libxml.
+SELECT xpath('//@value', '<root value="&lt;"/>');
+ERROR:  unsupported XML feature
+LINE 1: SELECT xpath('//@value', '<root value="&lt;"/>');
+                                 ^
+DETAIL:  This functionality requires the server to be built with libxml support.
+HINT:  You need to rebuild PostgreSQL using --with-libxml.
 -- Test xmlexists and xpath_exists
 SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
 ERROR:  unsupported XML feature
index f4e423618ecdae34f24a38177ddb337f7ee17183..3270e15721459a30060d02dd6d4cd04a4582cdd1 100644 (file)
@@ -175,6 +175,8 @@ SELECT xpath('', '<!-- error -->');
 SELECT xpath('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
 SELECT xpath('//loc:piece/@id', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
 SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
+SELECT xpath('//text()', '<root>&lt;</root>');
+SELECT xpath('//@value', '<root value="&lt;"/>');
 
 -- Test xmlexists and xpath_exists
 SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');