CREATE TABLE xmltest (
    id int,
    data xml
);
INSERT INTO xmltest VALUES (1, '<value>one</value>');
INSERT INTO xmltest VALUES (2, '<value>two</value>');
INSERT INTO xmltest VALUES (3, '<wrong');
ERROR:  invalid XML content
LINE 1: INSERT INTO xmltest VALUES (3, '<wrong');
                                       ^
DETAIL:  Entity: line 1: parser error : Couldn't find end of Start Tag wrong line 1
<wrong
      ^
SELECT * FROM xmltest;
 id |        data        
----+--------------------
  1 | <value>one</value>
  2 | <value>two</value>
(2 rows)

SELECT xmlcomment('test');
 xmlcomment  
-------------
 <!--test-->
(1 row)

SELECT xmlcomment('-test');
  xmlcomment  
--------------
 <!---test-->
(1 row)

SELECT xmlcomment('test-');
ERROR:  invalid XML comment
SELECT xmlcomment('--test');
ERROR:  invalid XML comment
SELECT xmlcomment('te st');
  xmlcomment  
--------------
 <!--te st-->
(1 row)

SELECT xmlconcat(xmlcomment('hello'),
                 xmlelement(NAME qux, 'foo'),
                 xmlcomment('world'));
               xmlconcat                
----------------------------------------
 <!--hello--><qux>foo</qux><!--world-->
(1 row)

SELECT xmlconcat('hello', 'you');
 xmlconcat 
-----------
 helloyou
(1 row)

SELECT xmlconcat(1, 2);
ERROR:  argument of XMLCONCAT must be type xml, not type integer
LINE 1: SELECT xmlconcat(1, 2);
                         ^
SELECT xmlconcat('bad', '<syntax');
ERROR:  invalid XML content
LINE 1: SELECT xmlconcat('bad', '<syntax');
                                ^
DETAIL:  Entity: line 1: parser error : Couldn't find end of Start Tag syntax line 1
<syntax
       ^
SELECT xmlconcat('<foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
  xmlconcat   
--------------
 <foo/><bar/>
(1 row)

SELECT xmlconcat('<?xml version="1.1"?><foo/>', NULL, '<?xml version="1.1" standalone="no"?><bar/>');
             xmlconcat             
-----------------------------------
 <?xml version="1.1"?><foo/><bar/>
(1 row)

SELECT xmlconcat(NULL);
 xmlconcat 
-----------
 
(1 row)

SELECT xmlconcat(NULL, NULL);
 xmlconcat 
-----------
 
(1 row)

SELECT xmlelement(name element,
                  xmlattributes (1 as one, 'deuce' as two),
                  'content');
                   xmlelement                   
------------------------------------------------
 <element one="1" two="deuce">content</element>
(1 row)

SELECT xmlelement(name element,
                  xmlattributes ('unnamed and wrong'));
ERROR:  unnamed XML attribute value must be a column reference
LINE 2:                   xmlattributes ('unnamed and wrong'));
                                         ^
SELECT xmlelement(name element, xmlelement(name nested, 'stuff'));
                xmlelement                 
-------------------------------------------
 <element><nested>stuff</nested></element>
(1 row)

SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
                              xmlelement                              
----------------------------------------------------------------------
 <employee><name>sharon</name><age>25</age><pay>1000</pay></employee>
 <employee><name>sam</name><age>30</age><pay>2000</pay></employee>
 <employee><name>bill</name><age>20</age><pay>1000</pay></employee>
 <employee><name>jeff</name><age>23</age><pay>600</pay></employee>
 <employee><name>cim</name><age>30</age><pay>400</pay></employee>
 <employee><name>linda</name><age>19</age><pay>100</pay></employee>
(6 rows)

SELECT xmlelement(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
ERROR:  XML attribute name "a" appears more than once
LINE 1: ...ment(name duplicate, xmlattributes(1 as a, 2 as b, 3 as a));
                                                              ^
SELECT xmlelement(name num, 37);
  xmlelement   
---------------
 <num>37</num>
(1 row)

SELECT xmlelement(name foo, text 'bar');
   xmlelement   
----------------
 <foo>bar</foo>
(1 row)

SELECT xmlelement(name foo, xml 'bar');
   xmlelement   
----------------
 <foo>bar</foo>
(1 row)

SELECT xmlelement(name foo, text 'b<a/>r');
       xmlelement        
-------------------------
 <foo>b&lt;a/&gt;r</foo>
(1 row)

SELECT xmlelement(name foo, xml 'b<a/>r');
    xmlelement     
-------------------
 <foo>b<a/>r</foo>
(1 row)

SELECT xmlelement(name foo, array[1, 2, 3]);
                               xmlelement                                
-------------------------------------------------------------------------
 <foo><element>1</element><element>2</element><element>3</element></foo>
(1 row)

SET xmlbinary TO base64;
SELECT xmlelement(name foo, bytea 'bar');
   xmlelement    
-----------------
 <foo>YmFy</foo>
(1 row)

SET xmlbinary TO hex;
SELECT xmlelement(name foo, bytea 'bar');
    xmlelement     
-------------------
 <foo>626172</foo>
(1 row)

SELECT xmlelement(name foo, xmlattributes(true as bar));
    xmlelement     
-------------------
 <foo bar="true"/>
(1 row)

SELECT xmlelement(name foo, xmlattributes('2009-04-09 00:24:37'::timestamp as bar));
            xmlelement            
----------------------------------
 <foo bar="2009-04-09T00:24:37"/>
(1 row)

SELECT xmlelement(name foo, xmlattributes('infinity'::timestamp as bar));
ERROR:  timestamp out of range
DETAIL:  XML does not support infinite timestamp values.
SELECT xmlelement(name foo, xmlattributes('<>&"''' as funny, xml 'b<a/>r' as funnier));
                         xmlelement                         
------------------------------------------------------------
 <foo funny="&lt;&gt;&amp;&quot;'" funnier="b&lt;a/&gt;r"/>
(1 row)

SELECT xmlparse(content 'abc');
 xmlparse 
----------
 abc
(1 row)

SELECT xmlparse(content '<abc>x</abc>');
   xmlparse   
--------------
 <abc>x</abc>
(1 row)

SELECT xmlparse(document 'abc');
ERROR:  invalid XML document
DETAIL:  Entity: line 1: parser error : Start tag expected, '<' not found
abc
^
SELECT xmlparse(document '<abc>x</abc>');
   xmlparse   
--------------
 <abc>x</abc>
(1 row)

SELECT xmlpi(name foo);
  xmlpi  
---------
 <?foo?>
(1 row)

SELECT xmlpi(name xml);
ERROR:  invalid XML processing instruction
DETAIL:  XML processing instruction target name cannot be "xml".
SELECT xmlpi(name xmlstuff);
    xmlpi     
--------------
 <?xmlstuff?>
(1 row)

SELECT xmlpi(name foo, 'bar');
    xmlpi    
-------------
 <?foo bar?>
(1 row)

SELECT xmlpi(name foo, 'in?>valid');
ERROR:  invalid XML processing instruction
DETAIL:  XML processing instruction cannot contain "?>".
SELECT xmlpi(name foo, null);
 xmlpi 
-------
 
(1 row)

SELECT xmlpi(name xml, null);
ERROR:  invalid XML processing instruction
DETAIL:  XML processing instruction target name cannot be "xml".
SELECT xmlpi(name xmlstuff, null);
 xmlpi 
-------
 
(1 row)

SELECT xmlpi(name "xml-stylesheet", 'href="mystyle.css" type="text/css"');
                         xmlpi                         
-------------------------------------------------------
 <?xml-stylesheet href="mystyle.css" type="text/css"?>
(1 row)

SELECT xmlpi(name foo, '   bar');
    xmlpi    
-------------
 <?foo bar?>
(1 row)

SELECT xmlroot(xml '<foo/>', version no value, standalone no value);
 xmlroot 
---------
 <foo/>
(1 row)

SELECT xmlroot(xml '<foo/>', version '2.0');
           xmlroot           
-----------------------------
 <?xml version="2.0"?><foo/>
(1 row)

SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
                   xmlroot                    
----------------------------------------------
 <?xml version="1.0" standalone="yes"?><foo/>
(1 row)

SELECT xmlroot(xml '<?xml version="1.1"?><foo/>', version no value, standalone yes);
                   xmlroot                    
----------------------------------------------
 <?xml version="1.0" standalone="yes"?><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('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no);
                   xmlroot                   
---------------------------------------------
 <?xml version="1.0" standalone="no"?><foo/>
(1 row)

SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value, standalone no value);
 xmlroot 
---------
 <foo/>
(1 row)

SELECT xmlroot('<?xml version="1.1" standalone="yes"?><foo/>', version no value);
                   xmlroot                    
----------------------------------------------
 <?xml version="1.0" standalone="yes"?><foo/>
(1 row)

SELECT xmlroot (
  xmlelement (
    name gazonk,
    xmlattributes (
      'val' AS name,
      1 + 1 AS num
    ),
    xmlelement (
      NAME qux,
      'foo'
    )
  ),
  version '1.0',
  standalone yes
);
                                         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(20)) FROM xmltest;
    xmlserialize    
--------------------
 <value>one</value>
 <value>two</value>
(2 rows)

SELECT xmlserialize(content 'good' as char(10));
 xmlserialize 
--------------
 good      
(1 row)

SELECT xmlserialize(document 'bad' as text);
ERROR:  not an XML document
SELECT xml '<foo>bar</foo>' IS DOCUMENT;
 ?column? 
----------
 t
(1 row)

SELECT xml '<foo>bar</foo><bar>foo</bar>' IS DOCUMENT;
 ?column? 
----------
 f
(1 row)

SELECT xml '<abc/>' IS NOT DOCUMENT;
 ?column? 
----------
 f
(1 row)

SELECT xml 'abc' IS NOT DOCUMENT;
 ?column? 
----------
 t
(1 row)

SELECT '<>' IS NOT DOCUMENT;
ERROR:  invalid XML content
LINE 1: SELECT '<>' IS NOT DOCUMENT;
               ^
DETAIL:  Entity: line 1: parser error : StartTag: invalid element name
<>
 ^
SELECT xmlagg(data) FROM xmltest;
                xmlagg                
--------------------------------------
 <value>one</value><value>two</value>
(1 row)

SELECT xmlagg(data) FROM xmltest WHERE id > 10;
 xmlagg 
--------
 
(1 row)

SELECT xmlelement(name employees, xmlagg(xmlelement(name name, name))) FROM emp;
                                                           xmlelement                                                           
--------------------------------------------------------------------------------------------------------------------------------
 <employees><name>sharon</name><name>sam</name><name>bill</name><name>jeff</name><name>cim</name><name>linda</name></employees>
(1 row)

-- Check mapping SQL identifier to XML name
SELECT xmlpi(name ":::_xml_abc135.%-&_");
                      xmlpi                      
-------------------------------------------------
 <?_x003A_::_x005F_xml_abc135._x0025_-_x0026__?>
(1 row)

SELECT xmlpi(name "123");
     xmlpi     
---------------
 <?_x0031_23?>
(1 row)

PREPARE foo (xml) AS SELECT xmlconcat('<foo/>', $1);
SET XML OPTION DOCUMENT;
EXECUTE foo ('<bar/>');
  xmlconcat   
--------------
 <foo/><bar/>
(1 row)

EXECUTE foo ('bad');
ERROR:  invalid XML document
LINE 1: EXECUTE foo ('bad');
                     ^
DETAIL:  Entity: line 1: parser error : Start tag expected, '<' not found
bad
^
SET XML OPTION CONTENT;
EXECUTE foo ('<bar/>');
  xmlconcat   
--------------
 <foo/><bar/>
(1 row)

EXECUTE foo ('good');
 xmlconcat  
------------
 <foo/>good
(1 row)

-- Test backwards parsing
CREATE VIEW xmlview1 AS SELECT xmlcomment('test');
CREATE VIEW xmlview2 AS SELECT xmlconcat('hello', 'you');
CREATE VIEW xmlview3 AS SELECT xmlelement(name element, xmlattributes (1 as ":one:", 'deuce' as two), 'content&');
CREATE VIEW xmlview4 AS SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
CREATE VIEW xmlview5 AS SELECT xmlparse(content '<abc>x</abc>');
CREATE VIEW xmlview6 AS SELECT xmlpi(name foo, 'bar');
CREATE VIEW xmlview7 AS SELECT xmlroot(xml '<foo/>', version no value, standalone yes);
CREATE VIEW xmlview8 AS SELECT xmlserialize(content 'good' as char(10));
CREATE VIEW xmlview9 AS SELECT xmlserialize(content 'good' as text);
SELECT table_name, view_definition FROM information_schema.views
  WHERE table_name LIKE 'xmlview%' ORDER BY 1;
 table_name |                                                      view_definition                                                       
------------+----------------------------------------------------------------------------------------------------------------------------
 xmlview1   | SELECT xmlcomment('test'::text) AS xmlcomment;
 xmlview2   | SELECT XMLCONCAT('hello'::xml, 'you'::xml) AS "xmlconcat";
 xmlview3   | SELECT XMLELEMENT(NAME element, XMLATTRIBUTES(1 AS ":one:", 'deuce' AS two), 'content&') AS "xmlelement";
 xmlview4   | SELECT XMLELEMENT(NAME employee, XMLFOREST(emp.name AS name, emp.age AS age, emp.salary AS pay)) AS "xmlelement" FROM emp;
 xmlview5   | SELECT XMLPARSE(CONTENT '<abc>x</abc>'::text STRIP WHITESPACE) AS "xmlparse";
 xmlview6   | SELECT XMLPI(NAME foo, 'bar'::text) AS "xmlpi";
 xmlview7   | SELECT XMLROOT('<foo/>'::xml, VERSION NO VALUE, STANDALONE YES) AS "xmlroot";
 xmlview8   | SELECT (XMLSERIALIZE(CONTENT 'good'::xml AS character(10)))::character(10) AS "xmlserialize";
 xmlview9   | SELECT XMLSERIALIZE(CONTENT 'good'::xml AS text) AS "xmlserialize";
(9 rows)

-- Text XPath expressions evaluation
SELECT xpath('/value', data) FROM xmltest;
        xpath         
----------------------
 {<value>one</value>}
 {<value>two</value>}
(2 rows)

SELECT xpath(NULL, NULL) IS NULL FROM xmltest;
 ?column? 
----------
 t
 t
(2 rows)

SELECT xpath('', '<!-- error -->');
ERROR:  empty XPath expression
CONTEXT:  SQL function "xpath" statement 1
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>');
     xpath      
----------------
 {"number one"}
(1 row)

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']]);
 xpath 
-------
 {1,2}
(1 row)

SELECT xpath('//loc:piece', '<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']]);
                                                                     xpath                                                                      
------------------------------------------------------------------------------------------------------------------------------------------------
 {"<local:piece xmlns:local=\"http://127.0.0.1\" id=\"1\">number one</local:piece>","<local:piece xmlns:local=\"http://127.0.0.1\" id=\"2\"/>"}
(1 row)

SELECT xpath('//loc:piece', '<local:data xmlns:local="http://127.0.0.1" xmlns="http://127.0.0.2"><local:piece id="1"><internal>number one</internal><internal2/></local:piece><local:piece id="2" /></local:data>', ARRAY[ARRAY['loc', 'http://127.0.0.1']]);
                                        xpath                                         
--------------------------------------------------------------------------------------
 {"<local:piece xmlns:local=\"http://127.0.0.1\" xmlns=\"http://127.0.0.2\" id=\"1\">
   <internal>number one</internal>
   <internal2/>
 </local:piece>","<local:piece xmlns:local=\"http://127.0.0.1\" id=\"2\"/>"}
(1 row)

SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
          xpath          
-------------------------
 {<b>two</b>,<b>etc</b>}
(1 row)

-- External entity references should not leak filesystem information.
SELECT XMLPARSE(DOCUMENT '<!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/passwd">]><foo>&c;</foo>');
                            xmlparse                             
-----------------------------------------------------------------
 <!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/passwd">]><foo>&c;</foo>
(1 row)

SELECT XMLPARSE(DOCUMENT '<!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/no.such.file">]><foo>&c;</foo>');
                               xmlparse                                
-----------------------------------------------------------------------
 <!DOCTYPE foo [<!ENTITY c SYSTEM "/etc/no.such.file">]><foo>&c;</foo>
(1 row)

-- This might or might not load the requested DTD, but it mustn't throw error.
SELECT XMLPARSE(DOCUMENT '<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"><chapter>&nbsp;</chapter>');
                                                                       xmlparse                                                                       
------------------------------------------------------------------------------------------------------------------------------------------------------
 <!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd"><chapter>&nbsp;</chapter>
(1 row)

