mirror of
https://github.com/postgres/postgres.git
synced 2025-04-29 13:56:47 +03:00
Handle content and document options in xmlparse() correctly.
This commit is contained in:
parent
859b8dd51a
commit
d9e1c97feb
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
|
||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.5 2006/12/24 18:25:58 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.6 2006/12/28 03:17:38 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -58,7 +58,7 @@ static void xml_errorHandler(void *ctxt, const char *msg, ...);
|
|||||||
static void xml_ereport_by_code(int level, int sqlcode,
|
static void xml_ereport_by_code(int level, int sqlcode,
|
||||||
const char *msg, int errcode);
|
const char *msg, int errcode);
|
||||||
static xmlChar *xml_text2xmlChar(text *in);
|
static xmlChar *xml_text2xmlChar(text *in);
|
||||||
static xmlDocPtr xml_parse(text *data, int opts, bool is_document);
|
static xmlDocPtr xml_parse(text *data, bool is_document, bool preserve_whitespace);
|
||||||
|
|
||||||
#endif /* USE_LIBXML */
|
#endif /* USE_LIBXML */
|
||||||
|
|
||||||
@ -86,7 +86,7 @@ xml_in(PG_FUNCTION_ARGS)
|
|||||||
* that ERROR occurred if parsing failed. Do we need DTD
|
* that ERROR occurred if parsing failed. Do we need DTD
|
||||||
* validation (if DTD exists)?
|
* validation (if DTD exists)?
|
||||||
*/
|
*/
|
||||||
xml_parse(vardata, XML_PARSE_DTDATTR | XML_PARSE_DTDVALID, false);
|
xml_parse(vardata, false, true);
|
||||||
|
|
||||||
PG_RETURN_XML_P(vardata);
|
PG_RETURN_XML_P(vardata);
|
||||||
#else
|
#else
|
||||||
@ -179,18 +179,7 @@ xmltype *
|
|||||||
xmlparse(text *data, bool is_document, bool preserve_whitespace)
|
xmlparse(text *data, bool is_document, bool preserve_whitespace)
|
||||||
{
|
{
|
||||||
#ifdef USE_LIBXML
|
#ifdef USE_LIBXML
|
||||||
if (!preserve_whitespace)
|
xml_parse(data, is_document, preserve_whitespace);
|
||||||
ereport(WARNING,
|
|
||||||
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
||||||
errmsg("XMLPARSE with STRIP WHITESPACE is not implemented")));
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Note, that here we try to apply DTD defaults
|
|
||||||
* (XML_PARSE_DTDATTR) according to SQL/XML:10.16.7.d: 'Default
|
|
||||||
* valies defined by internal DTD are applied'. As for external
|
|
||||||
* DTDs, we try to support them too, (see SQL/XML:10.16.7.e)
|
|
||||||
*/
|
|
||||||
xml_parse(data, XML_PARSE_DTDATTR, is_document);
|
|
||||||
|
|
||||||
return (xmltype *) data;
|
return (xmltype *) data;
|
||||||
#else
|
#else
|
||||||
@ -421,27 +410,18 @@ xml_init(void)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* Convert a C string to XML internal representation
|
* Convert a C string to XML internal representation
|
||||||
* (same things as for TEXT, but with checking the data for well-formedness
|
*
|
||||||
* and, moreover, validation against DTD, if needed).
|
|
||||||
* NOTICE: We use TEXT type as internal storage type. In the future,
|
|
||||||
* we plan to create own storage type (maybe several types/strategies)
|
|
||||||
* TODO predefined DTDs / XSDs and validation
|
|
||||||
* TODO validation against XML Schema
|
|
||||||
* TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c)
|
* TODO maybe, libxml2's xmlreader is better? (do not construct DOM, yet do not use SAX - see xml_reader.c)
|
||||||
* TODO what about internal URI for docs? (see PG_XML_DEFAULT_URI below)
|
* TODO what about internal URI for docs? (see PG_XML_DEFAULT_URI below)
|
||||||
*/
|
*/
|
||||||
static xmlDocPtr
|
static xmlDocPtr
|
||||||
xml_parse(text *data, int opts, bool is_document)
|
xml_parse(text *data, bool is_document, bool preserve_whitespace)
|
||||||
{
|
{
|
||||||
bool validationFailed = false;
|
|
||||||
int res_code;
|
int res_code;
|
||||||
int32 len;
|
int32 len;
|
||||||
xmlChar *string;
|
xmlChar *string;
|
||||||
xmlParserCtxtPtr ctxt = NULL;
|
xmlParserCtxtPtr ctxt = NULL;
|
||||||
xmlDocPtr doc = NULL;
|
xmlDocPtr doc = NULL;
|
||||||
#ifdef XML_DEBUG_DTD_CONST
|
|
||||||
xmlDtdPtr dtd = NULL;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
len = VARSIZE(data) - VARHDRSZ; /* will be useful later */
|
len = VARSIZE(data) - VARHDRSZ; /* will be useful later */
|
||||||
string = xml_text2xmlChar(data);
|
string = xml_text2xmlChar(data);
|
||||||
@ -456,51 +436,40 @@ xml_parse(text *data, int opts, bool is_document)
|
|||||||
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
|
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
|
||||||
"could not allocate parser context", ctxt);
|
"could not allocate parser context", ctxt);
|
||||||
|
|
||||||
/* first, we try to parse the string as XML doc, then, as XML chunk */
|
if (is_document)
|
||||||
if (len >= 5 && strncmp((char *) string, "<?xml", 5) == 0)
|
|
||||||
{
|
{
|
||||||
/* consider it as DOCUMENT */
|
/*
|
||||||
|
* Note, that here we try to apply DTD defaults
|
||||||
|
* (XML_PARSE_DTDATTR) according to SQL/XML:10.16.7.d:
|
||||||
|
* 'Default valies defined by internal DTD are applied'.
|
||||||
|
* As for external DTDs, we try to support them too, (see
|
||||||
|
* SQL/XML:10.16.7.e)
|
||||||
|
*/
|
||||||
doc = xmlCtxtReadMemory(ctxt, (char *) string, len,
|
doc = xmlCtxtReadMemory(ctxt, (char *) string, len,
|
||||||
PG_XML_DEFAULT_URI, NULL, opts);
|
PG_XML_DEFAULT_URI, NULL,
|
||||||
|
XML_PARSE_NOENT | XML_PARSE_DTDATTR
|
||||||
|
| (preserve_whitespace ? 0 : XML_PARSE_NOBLANKS));
|
||||||
if (doc == NULL)
|
if (doc == NULL)
|
||||||
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
||||||
"could not parse XML data", ctxt);
|
"invalid XML document", ctxt);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* attempt to parse the string as if it is an XML fragment */
|
|
||||||
doc = xmlNewDoc(NULL);
|
doc = xmlNewDoc(NULL);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: An XMLDecl is supposed to be accepted before the
|
||||||
|
* content, but libxml doesn't allow this. Parse that
|
||||||
|
* ourselves?
|
||||||
|
*/
|
||||||
|
|
||||||
/* TODO resolve: xmlParseBalancedChunkMemory assumes that string is UTF8 encoded! */
|
/* TODO resolve: xmlParseBalancedChunkMemory assumes that string is UTF8 encoded! */
|
||||||
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, string, NULL);
|
res_code = xmlParseBalancedChunkMemory(doc, NULL, NULL, 0, string, NULL);
|
||||||
if (res_code != 0)
|
if (res_code != 0)
|
||||||
xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
xml_ereport_by_code(ERROR, ERRCODE_INVALID_XML_CONTENT,
|
||||||
"could not parse XML data", res_code);
|
"invalid XML content", res_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef XML_DEBUG_DTD_CONST
|
|
||||||
dtd = xmlParseDTD(NULL, (xmlChar *) XML_DEBUG_DTD_CONST);
|
|
||||||
if (dtd == NULL)
|
|
||||||
xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
|
|
||||||
"could not parse DTD data", ctxt);
|
|
||||||
if (xmlValidateDtd(xmlNewValidCtxt(), doc, dtd) != 1)
|
|
||||||
validationFailed = true;
|
|
||||||
#else
|
|
||||||
/* if dtd for our xml data is detected... */
|
|
||||||
if ((doc->intSubset != NULL) || (doc->extSubset != NULL))
|
|
||||||
{
|
|
||||||
/* assume inline DTD exists - validation should be performed */
|
|
||||||
if (ctxt->valid == 0)
|
|
||||||
{
|
|
||||||
/* DTD exists, but validator reported 'validation failed' */
|
|
||||||
validationFailed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (validationFailed)
|
|
||||||
xml_ereport(WARNING, ERRCODE_INVALID_XML_DOCUMENT,
|
|
||||||
"validation against DTD failed", ctxt);
|
|
||||||
|
|
||||||
/* TODO encoding issues
|
/* TODO encoding issues
|
||||||
* (thoughts:
|
* (thoughts:
|
||||||
* CASE:
|
* CASE:
|
||||||
@ -517,10 +486,6 @@ xml_parse(text *data, int opts, bool is_document)
|
|||||||
* ) */
|
* ) */
|
||||||
/* ... */
|
/* ... */
|
||||||
|
|
||||||
#ifdef XML_DEBUG_DTD_CONST
|
|
||||||
if (dtd)
|
|
||||||
xmlFreeDtd(dtd);
|
|
||||||
#endif
|
|
||||||
if (doc)
|
if (doc)
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
if (ctxt)
|
if (ctxt)
|
||||||
@ -529,10 +494,6 @@ xml_parse(text *data, int opts, bool is_document)
|
|||||||
}
|
}
|
||||||
PG_CATCH();
|
PG_CATCH();
|
||||||
{
|
{
|
||||||
#ifdef XML_DEBUG_DTD_CONST
|
|
||||||
if (dtd)
|
|
||||||
xmlFreeDtd(dtd);
|
|
||||||
#endif
|
|
||||||
if (doc)
|
if (doc)
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
if (ctxt)
|
if (ctxt)
|
||||||
|
@ -5,7 +5,7 @@ CREATE TABLE xmltest (
|
|||||||
INSERT INTO xmltest VALUES (1, '<value>one</value>');
|
INSERT INTO xmltest VALUES (1, '<value>one</value>');
|
||||||
INSERT INTO xmltest VALUES (2, '<value>two</value>');
|
INSERT INTO xmltest VALUES (2, '<value>two</value>');
|
||||||
INSERT INTO xmltest VALUES (3, '<wrong');
|
INSERT INTO xmltest VALUES (3, '<wrong');
|
||||||
ERROR: could not parse XML data
|
ERROR: invalid XML content
|
||||||
DETAIL: Expected '>'
|
DETAIL: Expected '>'
|
||||||
SELECT * FROM xmltest;
|
SELECT * FROM xmltest;
|
||||||
id | data
|
id | data
|
||||||
@ -53,7 +53,7 @@ SELECT xmlconcat('hello', 'you');
|
|||||||
SELECT xmlconcat(1, 2);
|
SELECT xmlconcat(1, 2);
|
||||||
ERROR: argument of XMLCONCAT must be type xml, not type integer
|
ERROR: argument of XMLCONCAT must be type xml, not type integer
|
||||||
SELECT xmlconcat('bad', '<syntax');
|
SELECT xmlconcat('bad', '<syntax');
|
||||||
ERROR: could not parse XML data
|
ERROR: invalid XML content
|
||||||
DETAIL: Expected '>'
|
DETAIL: Expected '>'
|
||||||
SELECT xmlelement(name element,
|
SELECT xmlelement(name element,
|
||||||
xmlattributes (1 as one, 'deuce' as two),
|
xmlattributes (1 as one, 'deuce' as two),
|
||||||
@ -85,6 +85,27 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
|
|||||||
|
|
||||||
SELECT xmlelement(name wrong, 37);
|
SELECT xmlelement(name wrong, 37);
|
||||||
ERROR: argument of XMLELEMENT must be type xml, not type integer
|
ERROR: argument of XMLELEMENT must be type xml, not type integer
|
||||||
|
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: Start tag expected, '<' not found.
|
||||||
|
SELECT xmlparse(document '<abc>x</abc>');
|
||||||
|
xmlparse
|
||||||
|
--------------
|
||||||
|
<abc>x</abc>
|
||||||
|
(1 row)
|
||||||
|
|
||||||
SELECT xmlpi(name foo);
|
SELECT xmlpi(name foo);
|
||||||
xmlpi
|
xmlpi
|
||||||
---------
|
---------
|
||||||
|
@ -46,6 +46,14 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
|
|||||||
ERROR: no XML support in this installation
|
ERROR: no XML support in this installation
|
||||||
SELECT xmlelement(name wrong, 37);
|
SELECT xmlelement(name wrong, 37);
|
||||||
ERROR: no XML support in this installation
|
ERROR: no XML support in this installation
|
||||||
|
SELECT xmlparse(content 'abc');
|
||||||
|
ERROR: no XML support in this installation
|
||||||
|
SELECT xmlparse(content '<abc>x</abc>');
|
||||||
|
ERROR: no XML support in this installation
|
||||||
|
SELECT xmlparse(document 'abc');
|
||||||
|
ERROR: no XML support in this installation
|
||||||
|
SELECT xmlparse(document '<abc>x</abc>');
|
||||||
|
ERROR: no XML support in this installation
|
||||||
SELECT xmlpi(name foo);
|
SELECT xmlpi(name foo);
|
||||||
ERROR: no XML support in this installation
|
ERROR: no XML support in this installation
|
||||||
SELECT xmlpi(name xmlstuff);
|
SELECT xmlpi(name xmlstuff);
|
||||||
|
@ -40,6 +40,13 @@ SELECT xmlelement(name employee, xmlforest(name, age, salary as pay)) FROM emp;
|
|||||||
SELECT xmlelement(name wrong, 37);
|
SELECT xmlelement(name wrong, 37);
|
||||||
|
|
||||||
|
|
||||||
|
SELECT xmlparse(content 'abc');
|
||||||
|
SELECT xmlparse(content '<abc>x</abc>');
|
||||||
|
|
||||||
|
SELECT xmlparse(document 'abc');
|
||||||
|
SELECT xmlparse(document '<abc>x</abc>');
|
||||||
|
|
||||||
|
|
||||||
SELECT xmlpi(name foo);
|
SELECT xmlpi(name foo);
|
||||||
SELECT xmlpi(name xmlstuff);
|
SELECT xmlpi(name xmlstuff);
|
||||||
SELECT xmlpi(name foo, 'bar');
|
SELECT xmlpi(name foo, 'bar');
|
||||||
|
Loading…
x
Reference in New Issue
Block a user