Commit 3963574d authored by Peter Eisentraut's avatar Peter Eisentraut

XPath fixes:

 - Function renamed to "xpath".
 - Function is now strict, per discussion.
 - Return empty array in case when XPath expression detects nothing
   (previously, NULL was returned in such case), per discussion.
 - (bugfix) Work with fragments with prologue: select xpath('/a',
   '<?xml version="1.0"?><a /><b />'); // now XML datum is always wrapped
   with dummy <x>...</x>, XML prologue simply goes away (if any).
 - Some cleanup.

Nikolay Samokhvalov

Some code cleanup and documentation work by myself.
parent 0c644d2c
<!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.200 2007/05/08 17:02:59 tgl Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/datatype.sgml,v 1.201 2007/05/21 17:10:28 petere Exp $ -->
<chapter id="datatype"> <chapter id="datatype">
<title id="datatype-title">Data Types</title> <title id="datatype-title">Data Types</title>
...@@ -3213,7 +3213,7 @@ SELECT * FROM test; ...@@ -3213,7 +3213,7 @@ SELECT * FROM test;
<sect1 id="datatype-uuid"> <sect1 id="datatype-uuid">
<title><acronym>UUID</acronym> Type</title> <title><acronym>UUID</acronym> Type</title>
<indexterm zone="datatype-xml"> <indexterm zone="datatype-uuid">
<primary>UUID</primary> <primary>UUID</primary>
</indexterm> </indexterm>
...@@ -3289,6 +3289,8 @@ a0eebc999c0b4ef8bb6d6bb9bd380a11 ...@@ -3289,6 +3289,8 @@ a0eebc999c0b4ef8bb6d6bb9bd380a11
value is a full document or only a content fragment. value is a full document or only a content fragment.
</para> </para>
<sect2>
<title>Creating XML Values</title>
<para> <para>
To produce a value of type <type>xml</type> from character data, To produce a value of type <type>xml</type> from character data,
use the function use the function
...@@ -3299,7 +3301,7 @@ XMLPARSE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable>) ...@@ -3299,7 +3301,7 @@ XMLPARSE ( { DOCUMENT | CONTENT } <replaceable>value</replaceable>)
Examples: Examples:
<programlisting><![CDATA[ <programlisting><![CDATA[
XMLPARSE (DOCUMENT '<?xml version="1.0"?><book><title>Manual</title><chapter>...</chapter><book>') XMLPARSE (DOCUMENT '<?xml version="1.0"?><book><title>Manual</title><chapter>...</chapter><book>')
XMLPARSE (CONTENT 'abc<foo>bar</bar><bar>foo</foo>') XMLPARSE (CONTENT 'abc<foo>bar</foo><bar>foo</bar>')
]]></programlisting> ]]></programlisting>
While this is the only way to convert character strings into XML While this is the only way to convert character strings into XML
values according to the SQL standard, the PostgreSQL-specific values according to the SQL standard, the PostgreSQL-specific
...@@ -3351,7 +3353,10 @@ SET xmloption TO { DOCUMENT | CONTENT }; ...@@ -3351,7 +3353,10 @@ SET xmloption TO { DOCUMENT | CONTENT };
The default is <literal>CONTENT</literal>, so all forms of XML The default is <literal>CONTENT</literal>, so all forms of XML
data are allowed. data are allowed.
</para> </para>
</sect2>
<sect2>
<title>Encoding Handling</title>
<para> <para>
Care must be taken when dealing with multiple character encodings Care must be taken when dealing with multiple character encodings
on the client, server, and in the XML data passed through them. on the client, server, and in the XML data passed through them.
...@@ -3398,6 +3403,41 @@ SET xmloption TO { DOCUMENT | CONTENT }; ...@@ -3398,6 +3403,41 @@ SET xmloption TO { DOCUMENT | CONTENT };
processed in UTF-8, computations will be most efficient if the processed in UTF-8, computations will be most efficient if the
server encoding is also UTF-8. server encoding is also UTF-8.
</para> </para>
</sect2>
<sect2>
<title>Accessing XML Values</title>
<para>
The <type>xml</type> data type is unusual in that it does not
provide any comparison operators. This is because there is no
well-defined and universally useful comparison algorithm for XML
data. One consequence of this is that you cannot retrieve rows by
comparing an <type>xml</type> column against a search value. XML
values should therefore typically be accompanied by a separate key
field such as an ID. An alternative solution for comparing XML
values is to convert them to character strings first, but note
that character string comparison has little to do with a useful
XML comparison method.
</para>
<para>
Since there are no comparison operators for the <type>xml</type>
data type, it is not possible to create an index directly on a
column of this type. If speedy searches in XML data are desired,
possible workarounds would be casting the expression to a
character string type and indexing that, or indexing an XPath
expression. The actual query would of course have to be adjusted
to search by the indexed expression.
</para>
<para>
The full-text search module Tsearch2 could also be used to speed
up full-document searches in XML data. The necessary
preprocessing support is, however, not available in the PostgreSQL
distribution in this release.
</para>
</sect2>
</sect1> </sect1>
&array; &array;
......
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.379 2007/05/07 07:53:26 petere Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.380 2007/05/21 17:10:28 petere Exp $ -->
<chapter id="functions"> <chapter id="functions">
<title>Functions and Operators</title> <title>Functions and Operators</title>
...@@ -7512,7 +7512,7 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple ...@@ -7512,7 +7512,7 @@ CREATE TYPE rainbow AS ENUM ('red', 'orange', 'yellow', 'green', 'blue', 'purple
type. The function-like expressions <function>xmlparse</function> type. The function-like expressions <function>xmlparse</function>
and <function>xmlserialize</function> for converting to and from and <function>xmlserialize</function> for converting to and from
type <type>xml</type> are not repeated here. Use of many of these type <type>xml</type> are not repeated here. Use of many of these
<type>xml</type> functions requires the installation to have been built functions requires the installation to have been built
with <command>configure --with-libxml</>. with <command>configure --with-libxml</>.
</para> </para>
...@@ -7848,6 +7848,51 @@ SELECT xmlroot(xmlparse(document '<?xml version="1.1"?><content>abc</content>'), ...@@ -7848,6 +7848,51 @@ SELECT xmlroot(xmlparse(document '<?xml version="1.1"?><content>abc</content>'),
</sect3> </sect3>
</sect2> </sect2>
<sect2 id="functions-xml-processing">
<title>Processing XML</title>
<indexterm>
<primary>XPath</primary>
</indexterm>
<para>
To process values of data type <type>xml</type>, PostgreSQL offers
the function <function>xpath</function>, which evaluates XPath 1.0
expressions.
</para>
<synopsis>
<function>xpath</function>(<replaceable>xpath</replaceable>, <replaceable>xml</replaceable><optional>, <replaceable>nsarray</replaceable></optional>)
</synopsis>
<para>
The function <function>xpath</function> evaluates the XPath
expression <replaceable>xpath</replaceable> against the XML value
<replaceable>xml</replaceable>. It returns an array of XML values
corresponding to the node set produced by the XPath expression.
</para>
<para>
The third argument of the function is an array of namespace
mappings. This array should be a two-dimensional array with the
length of the second axis being equal to 2 (i.e., it should be an
array of arrays, each of which consists of exactly 2 elements).
The first element of each array entry is the namespace name, the
second the namespace URI.
</para>
<para>
Example:
<screen><![CDATA[
SELECT xpath('/my:a/text()', '<my:a xmlns:my="http://example.com">test</my:a>', ARRAY[ARRAY['my', 'http://example.com']]);
xpath
--------
{test}
(1 row)
]]></screen>
</para>
</sect2>
<sect2 id="functions-xml-mapping"> <sect2 id="functions-xml-mapping">
<title>Mapping Tables to XML</title> <title>Mapping Tables to XML</title>
...@@ -8097,75 +8142,6 @@ table2-mapping ...@@ -8097,75 +8142,6 @@ table2-mapping
]]></programlisting> ]]></programlisting>
</figure> </figure>
</sect2> </sect2>
<sect2>
<title>Processing XML</title>
<para>
<acronym>XML</> support is not just the existence of an
<type>xml</type> data type, but a variety of features supported by
a database system. These capabilities include import/export,
indexing, searching, transforming, and <acronym>XML</> to
<acronym>SQL</> mapping. <productname>PostgreSQL</> supports some
but not all of these <acronym>XML</> capabilities. For an
overview of <acronym>XML</> use in databases, see <ulink
url="http://www.rpbourret.com/xml/XMLAndDatabases.htm"></>.
</para>
<variablelist>
<varlistentry>
<term>Indexing</term>
<listitem>
<para>
<filename>contrib/xml2/</> functions can be used in expression
indexes to index specific <acronym>XML</> fields. To index the
full contents of <acronym>XML</> documents, the full-text
indexing tool <filename>contrib/tsearch2/</> can be used. Of
course, Tsearch2 indexes have no <acronym>XML</> awareness so
additional <filename>contrib/xml2/</> checks should be added to
queries.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Searching</term>
<listitem>
<para>
XPath searches are implemented using <filename>contrib/xml2/</>.
It processes <acronym>XML</> text documents and returns results
based on the requested query.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>Transforming</term>
<listitem>
<para>
<filename>contrib/xml2/</> supports <acronym>XSLT</> (Extensible
Stylesheet Language Transformation).
</para>
</listitem>
</varlistentry>
<varlistentry>
<term>XML to SQL Mapping</term>
<listitem>
<para>
This involves converting <acronym>XML</> data to and from
relational structures. <productname>PostgreSQL</> has no
internal support for such mapping, and relies on external tools
to do such conversions.
</para>
</listitem>
</varlistentry>
</variablelist>
</sect2>
</sect1> </sect1>
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, 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.42 2007/04/06 04:21:43 tgl Exp $ * $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.43 2007/05/21 17:10:29 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -2991,85 +2991,89 @@ xml_xmlnodetoxmltype(xmlNodePtr cur) ...@@ -2991,85 +2991,89 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
} }
#endif #endif
/* /*
* Evaluate XPath expression and return array of XML values. * Evaluate XPath expression and return array of XML values.
* As we have no support of XQuery sequences yet, this functions seems * As we have no support of XQuery sequences yet, this functions seems
* to be the most useful one (array of XML functions plays a role of * to be the most useful one (array of XML functions plays a role of
* some kind of substritution for XQuery sequences). * some kind of substritution for XQuery sequences).
*
* Workaround here: we parse XML data in different way to allow XPath for * Workaround here: we parse XML data in different way to allow XPath for
* fragments (see "XPath for fragment" TODO comment inside). * fragments (see "XPath for fragment" TODO comment inside).
*/ */
Datum Datum
xmlpath(PG_FUNCTION_ARGS) xpath(PG_FUNCTION_ARGS)
{ {
#ifdef USE_LIBXML #ifdef USE_LIBXML
text *xpath_expr_text = PG_GETARG_TEXT_P(0);
xmltype *data = PG_GETARG_XML_P(1);
ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
ArrayBuildState *astate = NULL; ArrayBuildState *astate = NULL;
xmlParserCtxtPtr ctxt = NULL; xmlParserCtxtPtr ctxt = NULL;
xmlDocPtr doc = NULL; xmlDocPtr doc = NULL;
xmlXPathContextPtr xpathctx = NULL; xmlXPathContextPtr xpathctx = NULL;
xmlXPathCompExprPtr xpathcomp = NULL; xmlXPathCompExprPtr xpathcomp = NULL;
xmlXPathObjectPtr xpathobj = NULL; xmlXPathObjectPtr xpathobj = NULL;
int32 len, xpath_len; int32 len;
xmlChar *string, *xpath_expr; int32 xpath_len;
bool res_is_null = FALSE; xmlChar *string;
xmlChar *xpath_expr;
int i; int i;
xmltype *data; int res_nitems;
text *xpath_expr_text; int ndim;
ArrayType *namespaces; int ns_count;
int *dims, ndims, ns_count = 0, bitmask = 1; char **ns_names;
char *ptr; char **ns_uris;
/*
* Namespace mappings are passed as text[]. If an empty array is
* passed (ndim = 0, "0-dimentional"), then there are no namespace
* mappings. Else, a 2-dimentional array with length of the
* second axis being equal to 2 should be passed, i.e., every
* subarray contains 2 elements, the first element defining the
* name, the second one the URI. Example: ARRAY[ARRAY['myns',
* 'http://example.com'], ARRAY['myns2', 'http://example2.com']].
*/
ndim = ARR_NDIM(namespaces);
if (ndim != 0)
{
bits8 *bitmap; bits8 *bitmap;
char **ns_names = NULL, **ns_uris = NULL; int bitmask;
int16 typlen; int16 typlen;
bool typbyval; bool typbyval;
char typalign; char typalign;
char *ptr;
int *dims;
/* the function is not strict, we must check first two args */
if (PG_ARGISNULL(0) || PG_ARGISNULL(1))
PG_RETURN_NULL();
xpath_expr_text = PG_GETARG_TEXT_P(0);
data = PG_GETARG_XML_P(1);
/* Namespace mappings passed as text[].
* Assume that 2-dimensional array has been passed,
* the 1st subarray is array of names, the 2nd -- array of URIs,
* example: ARRAY[ARRAY['myns', 'myns2'], ARRAY['http://example.com', 'http://example2.com']].
*/
if (!PG_ARGISNULL(2))
{
namespaces = PG_GETARG_ARRAYTYPE_P(2);
ndims = ARR_NDIM(namespaces);
dims = ARR_DIMS(namespaces); dims = ARR_DIMS(namespaces);
/* Sanity check */ if (ndim != 2 || dims[1] != 2)
if (ndims != 2) ereport(ERROR, (errmsg("invalid array for XML namespace mapping"),
ereport(ERROR, (errmsg("invalid array passed for namespace mappings"), errdetail("The array must be two-dimensional with length of the second axis equal to 2."),
errdetail("Only 2-dimensional array may be used for namespace mappings."))); errcode(ERRCODE_DATA_EXCEPTION)));
Assert(ARR_ELEMTYPE(namespaces) == TEXTOID); Assert(ARR_ELEMTYPE(namespaces) == TEXTOID);
ns_count = ArrayGetNItems(ndims, dims) / 2; ns_count = ArrayGetNItems(ndim, dims) / 2; /* number of NS mappings */
get_typlenbyvalalign(ARR_ELEMTYPE(namespaces), get_typlenbyvalalign(ARR_ELEMTYPE(namespaces),
&typlen, &typbyval, &typalign); &typlen, &typbyval, &typalign);
ns_names = (char **) palloc(ns_count * sizeof(char *)); ns_names = palloc(ns_count * sizeof(char *));
ns_uris = (char **) palloc(ns_count * sizeof(char *)); ns_uris = palloc(ns_count * sizeof(char *));
ptr = ARR_DATA_PTR(namespaces); ptr = ARR_DATA_PTR(namespaces);
bitmap = ARR_NULLBITMAP(namespaces); bitmap = ARR_NULLBITMAP(namespaces);
bitmask = 1; bitmask = 1;
for (i = 0; i < ns_count * 2; i++) for (i = 0; i < ns_count * 2; i++)
{ {
if (bitmap && (*bitmap & bitmask) == 0) if (bitmap && (*bitmap & bitmask) == 0)
ereport(ERROR, (errmsg("neither namespace nor URI may be NULL"))); /* TODO: better message */ ereport(ERROR, (errmsg("neither namespace name nor URI may be null")));
else else
{ {
if (i < ns_count) if (i % 2 == 0)
ns_names[i] = DatumGetCString(DirectFunctionCall1(textout, ns_names[i / 2] = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(ptr))); PointerGetDatum(ptr)));
else else
ns_uris[i - ns_count] = DatumGetCString(DirectFunctionCall1(textout, ns_uris[i / 2] = DatumGetCString(DirectFunctionCall1(textout,
PointerGetDatum(ptr))); PointerGetDatum(ptr)));
ptr = att_addlength_pointer(ptr, typlen, ptr); ptr = att_addlength_pointer(ptr, typlen, ptr);
ptr = (char *) att_align_nominal(ptr, typalign); ptr = (char *) att_align_nominal(ptr, typalign);
...@@ -3087,37 +3091,55 @@ xmlpath(PG_FUNCTION_ARGS) ...@@ -3087,37 +3091,55 @@ xmlpath(PG_FUNCTION_ARGS)
} }
} }
} }
else
{
ns_count = 0;
ns_names = NULL;
ns_uris = NULL;
}
len = VARSIZE(data) - VARHDRSZ; len = VARSIZE(data) - VARHDRSZ;
xpath_len = VARSIZE(xpath_expr_text) - VARHDRSZ; xpath_len = VARSIZE(xpath_expr_text) - VARHDRSZ;
if (xpath_len == 0) if (xpath_len == 0)
ereport(ERROR, (errmsg("empty XPath expression"))); ereport(ERROR, (errmsg("empty XPath expression"),
errcode(ERRCODE_DATA_EXCEPTION)));
if (xmlStrncmp((xmlChar *) VARDATA(data), (xmlChar *) "<?xml", 5) == 0) /*
* To handle both documents and fragments, regardless of the fact
* whether the XML datum has a single root (XML well-formedness),
* we wrap the XML datum in a dummy element (<x>...</x>) and
* extend the XPath expression accordingly. To do it, throw away
* the XML prolog, if any.
*/
if ((len > 4) && xmlStrncmp((xmlChar *) VARDATA(data), (xmlChar *) "<?xml", 5) == 0)
{ {
string = palloc(len + 1); i = 5;
memcpy(string, VARDATA(data), len); while ((i < len) && (('?' != (VARDATA(data))[i - 1]) || ('>' != (VARDATA(data))[i])))
string[len] = '\0'; i++;
xpath_expr = palloc(xpath_len + 1);
memcpy(xpath_expr, VARDATA(xpath_expr_text), xpath_len); if (i == len)
xpath_expr[xpath_len] = '\0'; xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
"could not parse XML data");
++i;
string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data) + i, len - i);
} }
else else
{
/* use "<x>...</x>" as dummy root element to enable XPath for fragments */
/* TODO: (XPath for fragment) find better solution to work with XML fragment! */
string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data), len); string = xmlStrncatNew((xmlChar *) "<x>", (xmlChar *) VARDATA(data), len);
string = xmlStrncat(string, (xmlChar *) "</x>", 5); string = xmlStrncat(string, (xmlChar *) "</x>", 5);
len += 7; len += 7;
xpath_expr = xmlStrncatNew((xmlChar *) "/x", (xmlChar *) VARDATA(xpath_expr_text), xpath_len); xpath_expr = xmlStrncatNew((xmlChar *) "/x", (xmlChar *) VARDATA(xpath_expr_text), xpath_len);
len += 2; xpath_len += 2;
}
xml_init(); xml_init();
PG_TRY(); PG_TRY();
{ {
/* redundant XML parsing (two parsings for the same value in the same session are possible) */ /*
* redundant XML parsing (two parsings for the same value *
* during one command execution are possible)
*/
ctxt = xmlNewParserCtxt(); ctxt = xmlNewParserCtxt();
if (ctxt == NULL) if (ctxt == NULL)
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR, xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
...@@ -3140,7 +3162,8 @@ xmlpath(PG_FUNCTION_ARGS) ...@@ -3140,7 +3162,8 @@ xmlpath(PG_FUNCTION_ARGS)
for (i = 0; i < ns_count; i++) for (i = 0; i < ns_count; i++)
if (0 != xmlXPathRegisterNs(xpathctx, (xmlChar *) ns_names[i], (xmlChar *) ns_uris[i])) if (0 != xmlXPathRegisterNs(xpathctx, (xmlChar *) ns_names[i], (xmlChar *) ns_uris[i]))
ereport(ERROR, ereport(ERROR,
(errmsg("could not register XML namespace with prefix=\"%s\" and href=\"%s\"", ns_names[i], ns_uris[i]))); (errmsg("could not register XML namespace with name \"%s\" and URI \"%s\"",
ns_names[i], ns_uris[i])));
xpathcomp = xmlXPathCompile(xpath_expr); xpathcomp = xmlXPathCompile(xpath_expr);
if (xpathcomp == NULL) if (xpathcomp == NULL)
...@@ -3150,17 +3173,15 @@ xmlpath(PG_FUNCTION_ARGS) ...@@ -3150,17 +3173,15 @@ xmlpath(PG_FUNCTION_ARGS)
xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx); xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
xmlXPathFreeCompExpr(xpathcomp); xmlXPathFreeCompExpr(xpathcomp);
if (xpathobj == NULL) if (xpathobj == NULL)
ereport(ERROR, (errmsg("could not create XPath object"))); ereport(ERROR, (errmsg("could not create XPath object"))); /* TODO: reason? */
/* return empty array in cases when nothing is found */
if (xpathobj->nodesetval == NULL) if (xpathobj->nodesetval == NULL)
res_is_null = TRUE; res_nitems = 0;
else
if (!res_is_null && xpathobj->nodesetval->nodeNr == 0) res_nitems = xpathobj->nodesetval->nodeNr;
/* TODO maybe empty array should be here, not NULL? (if so -- fix segfault) */
/*PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext));*/
res_is_null = TRUE;
if (!res_is_null) if (res_nitems)
for (i = 0; i < xpathobj->nodesetval->nodeNr; i++) for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
{ {
Datum elem; Datum elem;
...@@ -3195,14 +3216,10 @@ xmlpath(PG_FUNCTION_ARGS) ...@@ -3195,14 +3216,10 @@ xmlpath(PG_FUNCTION_ARGS)
} }
PG_END_TRY(); PG_END_TRY();
if (res_is_null) if (res_nitems == 0)
{ PG_RETURN_ARRAYTYPE_P(construct_empty_array(XMLOID));
PG_RETURN_NULL();
}
else else
{
PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext)); PG_RETURN_ARRAYTYPE_P(makeArrayResult(astate, CurrentMemoryContext));
}
#else #else
NO_XML_SUPPORT(); NO_XML_SUPPORT();
return 0; return 0;
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, 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/include/catalog/catversion.h,v 1.406 2007/05/11 17:57:13 tgl Exp $ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.407 2007/05/21 17:10:29 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -53,6 +53,6 @@ ...@@ -53,6 +53,6 @@
*/ */
/* yyyymmddN */ /* yyyymmddN */
#define CATALOG_VERSION_NO 200705111 #define CATALOG_VERSION_NO 200705211
#endif #endif
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, 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/include/catalog/pg_proc.h,v 1.455 2007/05/08 18:56:48 neilc Exp $ * $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.456 2007/05/21 17:10:29 petere Exp $
* *
* NOTES * NOTES
* The script catalog/genbki.sh reads this file and generates .bki * The script catalog/genbki.sh reads this file and generates .bki
...@@ -4116,9 +4116,9 @@ DESCR("map database structure to XML Schema"); ...@@ -4116,9 +4116,9 @@ DESCR("map database structure to XML Schema");
DATA(insert OID = 2938 ( database_to_xml_and_xmlschema PGNSP PGUID 12 100 0 f f t f s 3 142 "16 16 25" _null_ _null_ "{nulls,tableforest,targetns}" database_to_xml_and_xmlschema - _null_ )); DATA(insert OID = 2938 ( database_to_xml_and_xmlschema PGNSP PGUID 12 100 0 f f t f s 3 142 "16 16 25" _null_ _null_ "{nulls,tableforest,targetns}" database_to_xml_and_xmlschema - _null_ ));
DESCR("map database contents and structure to XML and XML Schema"); DESCR("map database contents and structure to XML and XML Schema");
DATA(insert OID = 2931 ( xmlpath PGNSP PGUID 12 1 0 f f f f i 3 143 "25 142 1009" _null_ _null_ _null_ xmlpath - _null_ )); DATA(insert OID = 2931 ( xpath PGNSP PGUID 12 1 0 f f t f i 3 143 "25 142 1009" _null_ _null_ _null_ xpath - _null_ ));
DESCR("evaluate XPath expression, with namespaces support"); DESCR("evaluate XPath expression, with namespaces support");
DATA(insert OID = 2932 ( xmlpath PGNSP PGUID 14 1 0 f f f f i 2 143 "25 142" _null_ _null_ _null_ "select pg_catalog.xmlpath($1, $2, NULL)" - _null_ )); DATA(insert OID = 2932 ( xpath PGNSP PGUID 14 1 0 f f t f i 2 143 "25 142" _null_ _null_ _null_ "select pg_catalog.xpath($1, $2, ''{}''::_text)" - _null_ ));
DESCR("evaluate XPath expression"); DESCR("evaluate XPath expression");
/* uuid */ /* uuid */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2007, 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/include/utils/xml.h,v 1.18 2007/04/01 09:00:26 petere Exp $ * $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.19 2007/05/21 17:10:29 petere Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -36,7 +36,7 @@ extern Datum xmlconcat2(PG_FUNCTION_ARGS); ...@@ -36,7 +36,7 @@ extern Datum xmlconcat2(PG_FUNCTION_ARGS);
extern Datum texttoxml(PG_FUNCTION_ARGS); extern Datum texttoxml(PG_FUNCTION_ARGS);
extern Datum xmltotext(PG_FUNCTION_ARGS); extern Datum xmltotext(PG_FUNCTION_ARGS);
extern Datum xmlvalidate(PG_FUNCTION_ARGS); extern Datum xmlvalidate(PG_FUNCTION_ARGS);
extern Datum xmlpath(PG_FUNCTION_ARGS); extern Datum xpath(PG_FUNCTION_ARGS);
extern Datum table_to_xml(PG_FUNCTION_ARGS); extern Datum table_to_xml(PG_FUNCTION_ARGS);
extern Datum query_to_xml(PG_FUNCTION_ARGS); extern Datum query_to_xml(PG_FUNCTION_ARGS);
......
...@@ -402,37 +402,37 @@ SELECT table_name, view_definition FROM information_schema.views ...@@ -402,37 +402,37 @@ SELECT table_name, view_definition FROM information_schema.views
(9 rows) (9 rows)
-- Text XPath expressions evaluation -- Text XPath expressions evaluation
SELECT xmlpath('/value', data) FROM xmltest; SELECT xpath('/value', data) FROM xmltest;
xmlpath xpath
---------------------- ----------------------
{<value>one</value>} {<value>one</value>}
{<value>two</value>} {<value>two</value>}
(2 rows) (2 rows)
SELECT xmlpath(NULL, NULL) IS NULL FROM xmltest; SELECT xpath(NULL, NULL) IS NULL FROM xmltest;
?column? ?column?
---------- ----------
t t
t t
(2 rows) (2 rows)
SELECT xmlpath('', '<!-- error -->'); SELECT xpath('', '<!-- error -->');
ERROR: empty XPath expression ERROR: empty XPath expression
CONTEXT: SQL function "xmlpath" statement 1 CONTEXT: SQL function "xpath" statement 1
SELECT xmlpath('//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('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
xmlpath xpath
---------------- ----------------
{"number one"} {"number one"}
(1 row) (1 row)
SELECT xmlpath('//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'], ARRAY['http://127.0.0.1']]); 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']]);
xmlpath xpath
--------- -------
{1,2} {1,2}
(1 row) (1 row)
SELECT xmlpath('//b', '<a>one <b>two</b> three <b>etc</b></a>'); SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
xmlpath xpath
------------------------- -------------------------
{<b>two</b>,<b>etc</b>} {<b>two</b>,<b>etc</b>}
(1 row) (1 row)
......
...@@ -326,29 +326,29 @@ SELECT table_name, view_definition FROM information_schema.views ...@@ -326,29 +326,29 @@ SELECT table_name, view_definition FROM information_schema.views
(2 rows) (2 rows)
-- Text XPath expressions evaluation -- Text XPath expressions evaluation
SELECT xmlpath('/value', data) FROM xmltest; SELECT xpath('/value', data) FROM xmltest;
xmlpath xpath
--------- -------
(0 rows) (0 rows)
SELECT xmlpath(NULL, NULL) IS NULL FROM xmltest; SELECT xpath(NULL, NULL) IS NULL FROM xmltest;
ERROR: unsupported XML feature ?column?
DETAIL: This functionality requires libxml support. ----------
HINT: You need to re-compile PostgreSQL using --with-libxml. (0 rows)
CONTEXT: SQL function "xmlpath" statement 1
SELECT xmlpath('', '<!-- error -->'); SELECT xpath('', '<!-- error -->');
ERROR: unsupported XML feature ERROR: unsupported XML feature
DETAIL: This functionality requires libxml support. DETAIL: This functionality requires libxml support.
HINT: You need to re-compile PostgreSQL using --with-libxml. HINT: You need to re-compile PostgreSQL using --with-libxml.
SELECT xmlpath('//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('//text()', '<local:data xmlns:local="http://127.0.0.1"><local:piece id="1">number one</local:piece><local:piece id="2" /></local:data>');
ERROR: unsupported XML feature ERROR: unsupported XML feature
DETAIL: This functionality requires libxml support. DETAIL: This functionality requires libxml support.
HINT: You need to re-compile PostgreSQL using --with-libxml. HINT: You need to re-compile PostgreSQL using --with-libxml.
SELECT xmlpath('//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'], ARRAY['http://127.0.0.1']]); 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']]);
ERROR: unsupported XML feature ERROR: unsupported XML feature
DETAIL: This functionality requires libxml support. DETAIL: This functionality requires libxml support.
HINT: You need to re-compile PostgreSQL using --with-libxml. HINT: You need to re-compile PostgreSQL using --with-libxml.
SELECT xmlpath('//b', '<a>one <b>two</b> three <b>etc</b></a>'); SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
ERROR: unsupported XML feature ERROR: unsupported XML feature
DETAIL: This functionality requires libxml support. DETAIL: This functionality requires libxml support.
HINT: You need to re-compile PostgreSQL using --with-libxml. HINT: You need to re-compile PostgreSQL using --with-libxml.
...@@ -147,9 +147,9 @@ SELECT table_name, view_definition FROM information_schema.views ...@@ -147,9 +147,9 @@ SELECT table_name, view_definition FROM information_schema.views
-- Text XPath expressions evaluation -- Text XPath expressions evaluation
SELECT xmlpath('/value', data) FROM xmltest; SELECT xpath('/value', data) FROM xmltest;
SELECT xmlpath(NULL, NULL) IS NULL FROM xmltest; SELECT xpath(NULL, NULL) IS NULL FROM xmltest;
SELECT xmlpath('', '<!-- error -->'); SELECT xpath('', '<!-- error -->');
SELECT xmlpath('//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('//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 xmlpath('//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'], ARRAY['http://127.0.0.1']]); 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 xmlpath('//b', '<a>one <b>two</b> three <b>etc</b></a>'); SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment