Skip to content

Commit d9e1c97

Browse files
committed
Handle content and document options in xmlparse() correctly.
1 parent 859b8dd commit d9e1c97

File tree

4 files changed

+65
-68
lines changed

4 files changed

+65
-68
lines changed

src/backend/utils/adt/xml.c

Lines changed: 27 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2006, 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.5 2006/12/24 18:25:58 tgl Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.6 2006/12/28 03:17:38 petere Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -58,7 +58,7 @@ static void xml_errorHandler(void *ctxt, const char *msg, ...);
5858
static void xml_ereport_by_code(int level, int sqlcode,
5959
const char *msg, int errcode);
6060
static xmlChar *xml_text2xmlChar(text *in);
61-
static xmlDocPtr xml_parse(text *data, int opts, bool is_document);
61+
static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespace);
6262

6363
#endif /* USE_LIBXML */
6464

@@ -86,7 +86,7 @@ xml_in(PG_FUNCTION_ARGS)
8686
* that ERROR occurred if parsing failed. Do we need DTD
8787
* validation (if DTD exists)?
8888
*/
89-
xml_parse(vardata, XML_PARSE_DTDATTR | XML_PARSE_DTDVALID, false);
89+
xml_parse(vardata, false, true);
9090

9191
PG_RETURN_XML_P(vardata);
9292
#else
@@ -179,18 +179,7 @@ xmltype *
179179
xmlparse(text *data, bool is_document, bool preserve_whitespace)
180180
{
181181
#ifdef USE_LIBXML
182-
if (!preserve_whitespace)
183-
ereport(WARNING,
184-
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
185-
errmsg("XMLPARSE with STRIP WHITESPACE is not implemented")));
186-
187-
/*
188-
* Note, that here we try to apply DTD defaults
189-
* (XML_PARSE_DTDATTR) according to SQL/XML:10.16.7.d: 'Default
190-
* valies defined by internal DTD are applied'. As for external
191-
* DTDs, we try to support them too, (see SQL/XML:10.16.7.e)
192-
*/
193-
xml_parse(data, XML_PARSE_DTDATTR, is_document);
182+
xml_parse(data, is_document, preserve_whitespace);
194183

195184
return (xmltype *) data;
196185
#else
@@ -421,27 +410,18 @@ xml_init(void)
421410

422411
/*
423412
* Convert a C string to XML internal representation
424-
* (same things as for TEXT, but with checking the data for well-formedness
425-
* and, moreover, validation against DTD, if needed).
426-
* NOTICE: We use TEXT type as internal storage type. In the future,
427-
* we plan to create own storage type (maybe several types/strategies)
428-
* TODO predefined DTDs / XSDs and validation
429-
* TODO validation against XML Schema
413+
*
430414
* TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c)
431415
* TODO what about internal URI for docs? (see PG_XML_DEFAULT_URI below)
432416
*/
433417
static xmlDocPtr
434-
xml_parse(text *data, int opts, bool is_document)
418+
xml_parse(text *data, bool is_document, bool preserve_whitespace)
435419
{
436-
bool validationFailed = false;
437420
int res_code;
438421
int32 len;
439422
xmlChar *string;
440423
xmlParserCtxtPtr ctxt = NULL;
441424
xmlDocPtr doc = NULL;
442-
#ifdef XML_DEBUG_DTD_CONST
443-
xmlDtdPtr dtd = NULL;
444-
#endif
445425

446426
len = VARSIZE(data) - VARHDRSZ; /* will be useful later */
447427
string = xml_text2xmlChar(data);
@@ -456,51 +436,40 @@ xml_parse(text *data, int opts, bool is_document)
456436
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
457437
"could not allocate parser context", ctxt);
458438

459-
/* first, we try to parse the string as XML doc, then, as XML chunk */
460-
if (len >= 5 && strncmp((char *) string, "<?xml", 5) == 0)
439+
if (is_document)
461440
{
462-
/* consider it as DOCUMENT */
441+
/*
442+
* Note, that here we try to apply DTD defaults
443+
* (XML_PARSE_DTDATTR) according to SQL/XML:10.16.7.d:
444+
* 'Default valies defined by internal DTD are applied'.
445+
* As for external DTDs, we try to support them too, (see
446+
* SQL/XML:10.16.7.e)
447+
*/
463448
doc = xmlCtxtReadMemory(ctxt, (char *) string, len,
464-
PG_XML_DEFAULT_URI, NULL, opts);
449+
PG_XML_DEFAULT_URI, NULL,
450+
XML_PARSE_NOENT | XML_PARSE_DTDATTR
451+
| (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
465452
if (doc == NULL)
466453
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
467-
"could not parse XML data", ctxt);
454+
"invalid XML document", ctxt);
468455
}
469456
else
470457
{
471-
/* attempt to parse the string as if it is an XML fragment */
472458
doc = xmlNewDoc(NULL);
459+
460+
/*
461+
* FIXME: An XMLDecl is supposed to be accepted before the
462+
* content, but libxml doesn't allow this. Parse that
463+
* ourselves?
464+
*/
465+
473466
/* TODO resolve: xmlParseBalancedChunkMemory assumes that string is UTF8 encoded! */
474467
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, string, NULL);
475468
if (res_code != 0)
476-
xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
477-
"could not parse XML data", res_code);
469+
xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_CONTENT,
470+
"invalid XML content", res_code);
478471
}
479472

480-
#ifdef XML_DEBUG_DTD_CONST
481-
dtd = xmlParseDTD(NULL, (xmlChar *) XML_DEBUG_DTD_CONST);
482-
if (dtd == NULL)
483-
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
484-
"could not parse DTD data", ctxt);
485-
if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) != 1)
486-
validationFailed = true;
487-
#else
488-
/* if dtd for our xml data is detected... */
489-
if ((doc->intSubset != NULL) || (doc->extSubset != NULL))
490-
{
491-
/* assume inline DTD exists - validation should be performed */
492-
if (ctxt->valid == 0)
493-
{
494-
/* DTD exists, but validator reported 'validation failed' */
495-
validationFailed = true;
496-
}
497-
}
498-
#endif
499-
500-
if (validationFailed)
501-
xml_ereport(WARNING, ERRCODE_INVALID_XML_DOCUMENT,
502-
"validation against DTD failed", ctxt);
503-
504473
/* TODO encoding issues
505474
* (thoughts:
506475
* CASE:
@@ -517,10 +486,6 @@ xml_parse(text *data, int opts, bool is_document)
517486
* ) */
518487
/* ... */
519488

520-
#ifdef XML_DEBUG_DTD_CONST
521-
if (dtd)
522-
xmlFreeDtd(dtd);
523-
#endif
524489
if (doc)
525490
xmlFreeDoc(doc);
526491
if (ctxt)
@@ -529,10 +494,6 @@ xml_parse(text *data, int opts, bool is_document)
529494
}
530495
PG_CATCH();
531496
{
532-
#ifdef XML_DEBUG_DTD_CONST
533-
if (dtd)
534-
xmlFreeDtd(dtd);
535-
#endif
536497
if (doc)
537498
xmlFreeDoc(doc);
538499
if (ctxt)

src/test/regress/expected/xml.out

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ CREATE TABLE xmltest (
55
INSERT INTO xmltest VALUES (1, '<value>one</value>');
66
INSERT INTO xmltest VALUES (2, '<value>two</value>');
77
INSERT INTO xmltest VALUES (3, '<wrong');
8-
ERROR: could not parse XML data
8+
ERROR: invalid XML content
99
DETAIL: Expected '>'
1010
SELECT * FROM xmltest;
1111
id | data
@@ -53,7 +53,7 @@ SELECT xmlconcat('hello', 'you');
5353
SELECT xmlconcat(1, 2);
5454
ERROR: argument of XMLCONCAT must be type xml, not type integer
5555
SELECT xmlconcat('bad', '<syntax');
56-
ERROR: could not parse XML data
56+
ERROR: invalid XML content
5757
DETAIL: Expected '>'
5858
SELECT xmlelement(name element,
5959
xmlattributes (1 as one, 'deuce' as two),
@@ -85,6 +85,27 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
8585

8686
SELECT xmlelement(name wrong, 37);
8787
ERROR: argument of XMLELEMENT must be type xml, not type integer
88+
SELECT xmlparse(content 'abc');
89+
xmlparse
90+
----------
91+
abc
92+
(1 row)
93+
94+
SELECT xmlparse(content '<abc>x</abc>');
95+
xmlparse
96+
--------------
97+
<abc>x</abc>
98+
(1 row)
99+
100+
SELECT xmlparse(document 'abc');
101+
ERROR: invalid XML document
102+
DETAIL: Start tag expected, '<' not found.
103+
SELECT xmlparse(document '<abc>x</abc>');
104+
xmlparse
105+
--------------
106+
<abc>x</abc>
107+
(1 row)
108+
88109
SELECT xmlpi(name foo);
89110
xmlpi
90111
---------

src/test/regress/expected/xml_1.out

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
4646
ERROR: no XML support in this installation
4747
SELECT xmlelement(name wrong, 37);
4848
ERROR: no XML support in this installation
49+
SELECT xmlparse(content 'abc');
50+
ERROR: no XML support in this installation
51+
SELECT xmlparse(content '<abc>x</abc>');
52+
ERROR: no XML support in this installation
53+
SELECT xmlparse(document 'abc');
54+
ERROR: no XML support in this installation
55+
SELECT xmlparse(document '<abc>x</abc>');
56+
ERROR: no XML support in this installation
4957
SELECT xmlpi(name foo);
5058
ERROR: no XML support in this installation
5159
SELECT xmlpi(name xmlstuff);

src/test/regress/sql/xml.sql

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,13 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
4040
SELECT xmlelement(name wrong, 37);
4141

4242

43+
SELECT xmlparse(content 'abc');
44+
SELECT xmlparse(content '<abc>x</abc>');
45+
46+
SELECT xmlparse(document 'abc');
47+
SELECT xmlparse(document '<abc>x</abc>');
48+
49+
4350
SELECT xmlpi(name foo);
4451
SELECT xmlpi(name xmlstuff);
4552
SELECT xmlpi(name foo, 'bar');

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