Add xmlexists function
by Mike Fowler, reviewed by Peter Eisentraut
This commit is contained in:
parent
26e47efb66
commit
641459f269
@ -1,4 +1,4 @@
|
|||||||
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.522 2010/07/29 19:34:40 petere Exp $ -->
|
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.523 2010/08/05 04:21:53 petere Exp $ -->
|
||||||
|
|
||||||
<chapter id="functions">
|
<chapter id="functions">
|
||||||
<title>Functions and Operators</title>
|
<title>Functions and Operators</title>
|
||||||
@ -8554,9 +8554,18 @@ SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab;
|
|||||||
]]></screen>
|
]]></screen>
|
||||||
</para>
|
</para>
|
||||||
</sect3>
|
</sect3>
|
||||||
|
</sect2>
|
||||||
|
|
||||||
|
<sect2>
|
||||||
|
<title>XML Predicates</title>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The expressions described in this section check properties
|
||||||
|
of <type>xml</type> values.
|
||||||
|
</para>
|
||||||
|
|
||||||
<sect3>
|
<sect3>
|
||||||
<title>XML Predicates</title>
|
<title>IS DOCUMENT</title>
|
||||||
|
|
||||||
<indexterm>
|
<indexterm>
|
||||||
<primary>IS DOCUMENT</primary>
|
<primary>IS DOCUMENT</primary>
|
||||||
@ -8574,6 +8583,48 @@ SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab;
|
|||||||
between documents and content fragments.
|
between documents and content fragments.
|
||||||
</para>
|
</para>
|
||||||
</sect3>
|
</sect3>
|
||||||
|
|
||||||
|
<sect3>
|
||||||
|
<title>XMLEXISTS</title>
|
||||||
|
|
||||||
|
<indexterm>
|
||||||
|
<primary>XMLEXISTS</primary>
|
||||||
|
</indexterm>
|
||||||
|
|
||||||
|
<synopsis>
|
||||||
|
<function>XMLEXISTS</function>(<replaceable>text</replaceable> PASSING <optional>BY REF</optional> <replaceable>xml</replaceable> <optional>BY REF</optional>)
|
||||||
|
</synopsis>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The function <function>xmlexists</function> returns true if the
|
||||||
|
XPath expression in the first argument returns any nodes, and
|
||||||
|
false otherwise. (If either argument is null, the result is
|
||||||
|
null.)
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
Example:
|
||||||
|
<screen><![CDATA[
|
||||||
|
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Toronto</town><town>Ottawa</town></towns>');
|
||||||
|
|
||||||
|
xmlexists
|
||||||
|
------------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
]]></screen>
|
||||||
|
</para>
|
||||||
|
|
||||||
|
<para>
|
||||||
|
The <literal>BY REF</literal> clauses have no effect in
|
||||||
|
PostgreSQL, but are allowed for SQL conformance and compatibility
|
||||||
|
with other implementations. Per SQL standard, the
|
||||||
|
first <literal>BY REF</literal> is required, the second is
|
||||||
|
optional. Also note that the SQL standard specifies
|
||||||
|
the <function>xmlexists</function> construct to take an XQuery
|
||||||
|
expression as first argument, but PostgreSQL currently only
|
||||||
|
supports XPath, which is a subset of XQuery.
|
||||||
|
</para>
|
||||||
|
</sect3>
|
||||||
</sect2>
|
</sect2>
|
||||||
|
|
||||||
<sect2 id="functions-xml-processing">
|
<sect2 id="functions-xml-processing">
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.714 2010/07/25 23:21:21 rhaas Exp $
|
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.715 2010/08/05 04:21:53 petere Exp $
|
||||||
*
|
*
|
||||||
* HISTORY
|
* HISTORY
|
||||||
* AUTHOR DATE MAJOR EVENT
|
* AUTHOR DATE MAJOR EVENT
|
||||||
@ -425,6 +425,7 @@ static TypeName *TableFuncTypeName(List *columns);
|
|||||||
%type <target> xml_attribute_el
|
%type <target> xml_attribute_el
|
||||||
%type <list> xml_attribute_list xml_attributes
|
%type <list> xml_attribute_list xml_attributes
|
||||||
%type <node> xml_root_version opt_xml_root_standalone
|
%type <node> xml_root_version opt_xml_root_standalone
|
||||||
|
%type <node> xmlexists_argument
|
||||||
%type <ival> document_or_content
|
%type <ival> document_or_content
|
||||||
%type <boolean> xml_whitespace_option
|
%type <boolean> xml_whitespace_option
|
||||||
|
|
||||||
@ -511,13 +512,13 @@ static TypeName *TableFuncTypeName(List *columns);
|
|||||||
OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR
|
OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR
|
||||||
ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
|
ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
|
||||||
|
|
||||||
PARSER PARTIAL PARTITION PASSWORD PLACING PLANS POSITION
|
PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POSITION
|
||||||
PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
|
PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
|
||||||
PRIOR PRIVILEGES PROCEDURAL PROCEDURE
|
PRIOR PRIVILEGES PROCEDURAL PROCEDURE
|
||||||
|
|
||||||
QUOTE
|
QUOTE
|
||||||
|
|
||||||
RANGE READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REINDEX
|
RANGE READ REAL REASSIGN RECHECK RECURSIVE REF REFERENCES REINDEX
|
||||||
RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART
|
RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART
|
||||||
RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
|
RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
|
||||||
|
|
||||||
@ -539,7 +540,7 @@ static TypeName *TableFuncTypeName(List *columns);
|
|||||||
|
|
||||||
WHEN WHERE WHITESPACE_P WINDOW WITH WITHOUT WORK WRAPPER WRITE
|
WHEN WHERE WHITESPACE_P WINDOW WITH WITHOUT WORK WRAPPER WRITE
|
||||||
|
|
||||||
XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
|
XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLEXISTS XMLFOREST XMLPARSE
|
||||||
XMLPI XMLROOT XMLSERIALIZE
|
XMLPI XMLROOT XMLSERIALIZE
|
||||||
|
|
||||||
YEAR_P YES_P
|
YEAR_P YES_P
|
||||||
@ -9839,6 +9840,21 @@ func_expr: func_name '(' ')' over_clause
|
|||||||
{
|
{
|
||||||
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
|
$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
|
||||||
}
|
}
|
||||||
|
| XMLEXISTS '(' c_expr xmlexists_argument ')'
|
||||||
|
{
|
||||||
|
/* xmlexists(A PASSING [BY REF] B [BY REF]) is
|
||||||
|
* converted to xmlexists(A, B)*/
|
||||||
|
FuncCall *n = makeNode(FuncCall);
|
||||||
|
n->funcname = SystemFuncName("xmlexists");
|
||||||
|
n->args = list_make2($3, $4);
|
||||||
|
n->agg_order = NIL;
|
||||||
|
n->agg_star = FALSE;
|
||||||
|
n->agg_distinct = FALSE;
|
||||||
|
n->func_variadic = FALSE;
|
||||||
|
n->over = NULL;
|
||||||
|
n->location = @1;
|
||||||
|
$$ = (Node *)n;
|
||||||
|
}
|
||||||
| XMLFOREST '(' xml_attribute_list ')'
|
| XMLFOREST '(' xml_attribute_list ')'
|
||||||
{
|
{
|
||||||
$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
|
$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
|
||||||
@ -9929,6 +9945,27 @@ xml_whitespace_option: PRESERVE WHITESPACE_P { $$ = TRUE; }
|
|||||||
| /*EMPTY*/ { $$ = FALSE; }
|
| /*EMPTY*/ { $$ = FALSE; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
/* We allow several variants for SQL and other compatibility. */
|
||||||
|
xmlexists_argument:
|
||||||
|
PASSING c_expr
|
||||||
|
{
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
| PASSING c_expr BY REF
|
||||||
|
{
|
||||||
|
$$ = $2;
|
||||||
|
}
|
||||||
|
| PASSING BY REF c_expr
|
||||||
|
{
|
||||||
|
$$ = $4;
|
||||||
|
}
|
||||||
|
| PASSING BY REF c_expr BY REF
|
||||||
|
{
|
||||||
|
$$ = $4;
|
||||||
|
}
|
||||||
|
;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Window Definitions
|
* Window Definitions
|
||||||
*/
|
*/
|
||||||
@ -10999,6 +11036,7 @@ unreserved_keyword:
|
|||||||
| PARSER
|
| PARSER
|
||||||
| PARTIAL
|
| PARTIAL
|
||||||
| PARTITION
|
| PARTITION
|
||||||
|
| PASSING
|
||||||
| PASSWORD
|
| PASSWORD
|
||||||
| PLANS
|
| PLANS
|
||||||
| PRECEDING
|
| PRECEDING
|
||||||
@ -11015,6 +11053,7 @@ unreserved_keyword:
|
|||||||
| REASSIGN
|
| REASSIGN
|
||||||
| RECHECK
|
| RECHECK
|
||||||
| RECURSIVE
|
| RECURSIVE
|
||||||
|
| REF
|
||||||
| REINDEX
|
| REINDEX
|
||||||
| RELATIVE_P
|
| RELATIVE_P
|
||||||
| RELEASE
|
| RELEASE
|
||||||
@ -11148,6 +11187,7 @@ col_name_keyword:
|
|||||||
| XMLATTRIBUTES
|
| XMLATTRIBUTES
|
||||||
| XMLCONCAT
|
| XMLCONCAT
|
||||||
| XMLELEMENT
|
| XMLELEMENT
|
||||||
|
| XMLEXISTS
|
||||||
| XMLFOREST
|
| XMLFOREST
|
||||||
| XMLPARSE
|
| XMLPARSE
|
||||||
| XMLPI
|
| XMLPI
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2010, 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.98 2010/07/06 19:18:58 momjian Exp $
|
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.99 2010/08/05 04:21:54 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -3295,24 +3295,20 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Evaluate XPath expression and return array of XML values.
|
* Common code for xpath() and xmlexists()
|
||||||
*
|
*
|
||||||
* As we have no support of XQuery sequences yet, this function seems
|
* Evaluate XPath expression and return number of nodes in res_items
|
||||||
* to be the most useful one (array of XML functions plays a role of
|
* and array of XML values in astate.
|
||||||
* some kind of substitution for XQuery sequences).
|
|
||||||
*
|
*
|
||||||
* It is up to the user to ensure that the XML passed is in fact
|
* It is up to the user to ensure that the XML passed is in fact
|
||||||
* an XML document - XPath doesn't work easily on fragments without
|
* an XML document - XPath doesn't work easily on fragments without
|
||||||
* a context node being known.
|
* a context node being known.
|
||||||
*/
|
*/
|
||||||
Datum
|
|
||||||
xpath(PG_FUNCTION_ARGS)
|
|
||||||
{
|
|
||||||
#ifdef USE_LIBXML
|
#ifdef USE_LIBXML
|
||||||
text *xpath_expr_text = PG_GETARG_TEXT_P(0);
|
static void
|
||||||
xmltype *data = PG_GETARG_XML_P(1);
|
xpath_internal(text *xpath_expr_text, xmltype *data, ArrayType *namespaces,
|
||||||
ArrayType *namespaces = PG_GETARG_ARRAYTYPE_P(2);
|
int *res_nitems, ArrayBuildState **astate)
|
||||||
ArrayBuildState *astate = NULL;
|
{
|
||||||
xmlParserCtxtPtr ctxt = NULL;
|
xmlParserCtxtPtr ctxt = NULL;
|
||||||
xmlDocPtr doc = NULL;
|
xmlDocPtr doc = NULL;
|
||||||
xmlXPathContextPtr xpathctx = NULL;
|
xmlXPathContextPtr xpathctx = NULL;
|
||||||
@ -3324,7 +3320,6 @@ xpath(PG_FUNCTION_ARGS)
|
|||||||
xmlChar *string;
|
xmlChar *string;
|
||||||
xmlChar *xpath_expr;
|
xmlChar *xpath_expr;
|
||||||
int i;
|
int i;
|
||||||
int res_nitems;
|
|
||||||
int ndim;
|
int ndim;
|
||||||
Datum *ns_names_uris;
|
Datum *ns_names_uris;
|
||||||
bool *ns_names_uris_nulls;
|
bool *ns_names_uris_nulls;
|
||||||
@ -3339,7 +3334,7 @@ xpath(PG_FUNCTION_ARGS)
|
|||||||
* ARRAY[ARRAY['myns', 'http://example.com'], ARRAY['myns2',
|
* ARRAY[ARRAY['myns', 'http://example.com'], ARRAY['myns2',
|
||||||
* 'http://example2.com']].
|
* 'http://example2.com']].
|
||||||
*/
|
*/
|
||||||
ndim = ARR_NDIM(namespaces);
|
ndim = namespaces ? ARR_NDIM(namespaces) : 0;
|
||||||
if (ndim != 0)
|
if (ndim != 0)
|
||||||
{
|
{
|
||||||
int *dims;
|
int *dims;
|
||||||
@ -3439,6 +3434,13 @@ xpath(PG_FUNCTION_ARGS)
|
|||||||
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
|
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
|
||||||
"invalid XPath expression");
|
"invalid XPath expression");
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Version 2.6.27 introduces a function named
|
||||||
|
* xmlXPathCompiledEvalToBoolean, which would be enough for
|
||||||
|
* xmlexists, but we can derive the existence by whether any
|
||||||
|
* nodes are returned, thereby preventing a library version
|
||||||
|
* upgrade and keeping the code the same.
|
||||||
|
*/
|
||||||
xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
|
xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
|
||||||
if (xpathobj == NULL) /* TODO: reason? */
|
if (xpathobj == NULL) /* TODO: reason? */
|
||||||
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
|
xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
|
||||||
@ -3446,21 +3448,22 @@ xpath(PG_FUNCTION_ARGS)
|
|||||||
|
|
||||||
/* return empty array in cases when nothing is found */
|
/* return empty array in cases when nothing is found */
|
||||||
if (xpathobj->nodesetval == NULL)
|
if (xpathobj->nodesetval == NULL)
|
||||||
res_nitems = 0;
|
*res_nitems = 0;
|
||||||
else
|
else
|
||||||
res_nitems = xpathobj->nodesetval->nodeNr;
|
*res_nitems = xpathobj->nodesetval->nodeNr;
|
||||||
|
|
||||||
if (res_nitems)
|
if (*res_nitems && astate)
|
||||||
{
|
{
|
||||||
|
*astate = NULL;
|
||||||
for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
|
for (i = 0; i < xpathobj->nodesetval->nodeNr; i++)
|
||||||
{
|
{
|
||||||
Datum elem;
|
Datum elem;
|
||||||
bool elemisnull = false;
|
bool elemisnull = false;
|
||||||
|
|
||||||
elem = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
|
elem = PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
|
||||||
astate = accumArrayResult(astate, elem,
|
*astate = accumArrayResult(*astate, elem,
|
||||||
elemisnull, XMLOID,
|
elemisnull, XMLOID,
|
||||||
CurrentMemoryContext);
|
CurrentMemoryContext);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -3485,6 +3488,28 @@ xpath(PG_FUNCTION_ARGS)
|
|||||||
xmlXPathFreeContext(xpathctx);
|
xmlXPathFreeContext(xpathctx);
|
||||||
xmlFreeDoc(doc);
|
xmlFreeDoc(doc);
|
||||||
xmlFreeParserCtxt(ctxt);
|
xmlFreeParserCtxt(ctxt);
|
||||||
|
}
|
||||||
|
#endif /* USE_LIBXML */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Evaluate XPath expression and return array of XML values.
|
||||||
|
*
|
||||||
|
* As we have no support of XQuery sequences yet, this function seems
|
||||||
|
* to be the most useful one (array of XML functions plays a role of
|
||||||
|
* some kind of substitution for XQuery sequences).
|
||||||
|
*/
|
||||||
|
Datum
|
||||||
|
xpath(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
#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);
|
||||||
|
int res_nitems;
|
||||||
|
ArrayBuildState *astate;
|
||||||
|
|
||||||
|
xpath_internal(xpath_expr_text, data, namespaces,
|
||||||
|
&res_nitems, &astate);
|
||||||
|
|
||||||
if (res_nitems == 0)
|
if (res_nitems == 0)
|
||||||
PG_RETURN_ARRAYTYPE_P(construct_empty_array(XMLOID));
|
PG_RETURN_ARRAYTYPE_P(construct_empty_array(XMLOID));
|
||||||
@ -3495,3 +3520,24 @@ xpath(PG_FUNCTION_ARGS)
|
|||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Determines if the node specified by the supplied XPath exists
|
||||||
|
* in a given XML document, returning a boolean.
|
||||||
|
*/
|
||||||
|
Datum xmlexists(PG_FUNCTION_ARGS)
|
||||||
|
{
|
||||||
|
#ifdef USE_LIBXML
|
||||||
|
text *xpath_expr_text = PG_GETARG_TEXT_P(0);
|
||||||
|
xmltype *data = PG_GETARG_XML_P(1);
|
||||||
|
int res_nitems;
|
||||||
|
|
||||||
|
xpath_internal(xpath_expr_text, data, NULL,
|
||||||
|
&res_nitems, NULL);
|
||||||
|
|
||||||
|
PG_RETURN_BOOL(res_nitems > 0);
|
||||||
|
#else
|
||||||
|
NO_XML_SUPPORT();
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
@ -37,7 +37,7 @@
|
|||||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2010, 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.588 2010/07/16 02:15:54 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.589 2010/08/05 04:21:54 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -53,6 +53,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
/* yyyymmddN */
|
/* yyyymmddN */
|
||||||
#define CATALOG_VERSION_NO 201007151
|
#define CATALOG_VERSION_NO 201008051
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2010, 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.573 2010/07/29 20:09:25 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.574 2010/08/05 04:21:54 petere Exp $
|
||||||
*
|
*
|
||||||
* NOTES
|
* NOTES
|
||||||
* The script catalog/genbki.pl reads this file and generates .bki
|
* The script catalog/genbki.pl reads this file and generates .bki
|
||||||
@ -4391,6 +4391,9 @@ DESCR("evaluate XPath expression, with namespaces support");
|
|||||||
DATA(insert OID = 2932 ( xpath PGNSP PGUID 14 1 0 0 f f f t f i 2 0 143 "25 142" _null_ _null_ _null_ _null_ "select pg_catalog.xpath($1, $2, ''{}''::pg_catalog.text[])" _null_ _null_ _null_ ));
|
DATA(insert OID = 2932 ( xpath PGNSP PGUID 14 1 0 0 f f f t f i 2 0 143 "25 142" _null_ _null_ _null_ _null_ "select pg_catalog.xpath($1, $2, ''{}''::pg_catalog.text[])" _null_ _null_ _null_ ));
|
||||||
DESCR("evaluate XPath expression");
|
DESCR("evaluate XPath expression");
|
||||||
|
|
||||||
|
DATA(insert OID = 2614 ( xmlexists PGNSP PGUID 12 1 0 0 f f f t f i 2 0 16 "25 142" _null_ _null_ _null_ _null_ xmlexists _null_ _null_ _null_ ));
|
||||||
|
DESCR("test XML value against XPath expression");
|
||||||
|
|
||||||
/* uuid */
|
/* uuid */
|
||||||
DATA(insert OID = 2952 ( uuid_in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2950 "2275" _null_ _null_ _null_ _null_ uuid_in _null_ _null_ _null_ ));
|
DATA(insert OID = 2952 ( uuid_in PGNSP PGUID 12 1 0 0 f f f t f i 1 0 2950 "2275" _null_ _null_ _null_ _null_ uuid_in _null_ _null_ _null_ ));
|
||||||
DESCR("I/O");
|
DESCR("I/O");
|
||||||
|
@ -11,7 +11,7 @@
|
|||||||
* Portions Copyright (c) 1994, Regents of the University of California
|
* Portions Copyright (c) 1994, Regents of the University of California
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.12 2010/02/12 17:33:21 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/parser/kwlist.h,v 1.13 2010/08/05 04:21:54 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -280,6 +280,7 @@ PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD)
|
|||||||
PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
|
PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
|
PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD)
|
PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD)
|
||||||
|
PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
|
PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
|
PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
|
||||||
PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
|
PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
|
||||||
@ -301,6 +302,7 @@ PG_KEYWORD("real", REAL, COL_NAME_KEYWORD)
|
|||||||
PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
|
PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD)
|
PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD)
|
PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD)
|
||||||
|
PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD)
|
PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD)
|
||||||
PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD)
|
PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD)
|
||||||
PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD)
|
PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD)
|
||||||
@ -413,6 +415,7 @@ PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD)
|
|||||||
PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD)
|
PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD)
|
||||||
PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD)
|
PG_KEYWORD("xmlconcat", XMLCONCAT, COL_NAME_KEYWORD)
|
||||||
PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD)
|
PG_KEYWORD("xmlelement", XMLELEMENT, COL_NAME_KEYWORD)
|
||||||
|
PG_KEYWORD("xmlexists", XMLEXISTS, COL_NAME_KEYWORD)
|
||||||
PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD)
|
PG_KEYWORD("xmlforest", XMLFOREST, COL_NAME_KEYWORD)
|
||||||
PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD)
|
PG_KEYWORD("xmlparse", XMLPARSE, COL_NAME_KEYWORD)
|
||||||
PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD)
|
PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD)
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
|
* Portions Copyright (c) 1996-2010, 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.31 2010/03/03 17:29:45 tgl Exp $
|
* $PostgreSQL: pgsql/src/include/utils/xml.h,v 1.32 2010/08/05 04:21:54 petere Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -37,6 +37,7 @@ 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 xpath(PG_FUNCTION_ARGS);
|
extern Datum xpath(PG_FUNCTION_ARGS);
|
||||||
|
extern Datum xmlexists(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);
|
||||||
|
@ -502,3 +502,52 @@ SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
|
|||||||
{<b>two</b>,<b>etc</b>}
|
{<b>two</b>,<b>etc</b>}
|
||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
|
-- Test xmlexists evaluation
|
||||||
|
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
|
||||||
|
xmlexists
|
||||||
|
-----------
|
||||||
|
f
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT xmlexists('//town[text() = ''Cwmbran'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
|
||||||
|
xmlexists
|
||||||
|
-----------
|
||||||
|
t
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||||
|
INSERT INTO xmltest VALUES (5, '<menu><beers><name>Molson</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||||
|
INSERT INTO xmltest VALUES (6, '<myns:menu xmlns:myns="http://myns.com"><myns:beers><myns:name>Budvar</myns:name><myns:cost>free</myns:cost><myns:name>Carling</myns:name><myns:cost>lots</myns:cost></myns:beers></myns:menu>'::xml);
|
||||||
|
INSERT INTO xmltest VALUES (7, '<myns:menu xmlns:myns="http://myns.com"><myns:beers><myns:name>Molson</myns:name><myns:cost>free</myns:cost><myns:name>Carling</myns:name><myns:cost>lots</myns:cost></myns:beers></myns:menu>'::xml);
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer' PASSING data);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer' PASSING BY REF data BY REF);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beers' PASSING BY REF data);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beers/name[text() = ''Molson'']' PASSING BY REF data);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
1
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
CREATE TABLE query ( expr TEXT );
|
||||||
|
INSERT INTO query VALUES ('/menu/beers/cost[text() = ''lots'']');
|
||||||
|
SELECT COUNT(id) FROM xmltest, query WHERE xmlexists(expr PASSING BY REF data);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
2
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
@ -456,3 +456,72 @@ 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.
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||||
|
-- Test xmlexists evaluation
|
||||||
|
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
|
||||||
|
LINE 1: ...sts('//town[text() = ''Toronto'']' PASSING BY REF '<towns><t...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||||
|
SELECT xmlexists('//town[text() = ''Cwmbran'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: ...sts('//town[text() = ''Cwmbran'']' PASSING BY REF '<towns><t...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||||
|
INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</n...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||||
|
INSERT INTO xmltest VALUES (5, '<menu><beers><name>Molson</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: INSERT INTO xmltest VALUES (5, '<menu><beers><name>Molson</n...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||||
|
INSERT INTO xmltest VALUES (6, '<myns:menu xmlns:myns="http://myns.com"><myns:beers><myns:name>Budvar</myns:name><myns:cost>free</myns:cost><myns:name>Carling</myns:name><myns:cost>lots</myns:cost></myns:beers></myns:menu>'::xml);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: INSERT INTO xmltest VALUES (6, '<myns:menu xmlns:myns="http:...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||||
|
INSERT INTO xmltest VALUES (7, '<myns:menu xmlns:myns="http://myns.com"><myns:beers><myns:name>Molson</myns:name><myns:cost>free</myns:cost><myns:name>Carling</myns:name><myns:cost>lots</myns:cost></myns:beers></myns:menu>'::xml);
|
||||||
|
ERROR: unsupported XML feature
|
||||||
|
LINE 1: INSERT INTO xmltest VALUES (7, '<myns:menu xmlns:myns="http:...
|
||||||
|
^
|
||||||
|
DETAIL: This functionality requires the server to be built with libxml support.
|
||||||
|
HINT: You need to rebuild PostgreSQL using --with-libxml.
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer' PASSING data);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer' PASSING BY REF data BY REF);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beers' PASSING BY REF data);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beers/name[text() = ''Molson'']' PASSING BY REF data);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
CREATE TABLE query ( expr TEXT );
|
||||||
|
INSERT INTO query VALUES ('/menu/beers/cost[text() = ''lots'']');
|
||||||
|
SELECT COUNT(id) FROM xmltest, query WHERE xmlexists(expr PASSING BY REF data);
|
||||||
|
count
|
||||||
|
-------
|
||||||
|
0
|
||||||
|
(1 row)
|
||||||
|
|
||||||
|
@ -163,3 +163,22 @@ 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('//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('//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('//b', '<a>one <b>two</b> three <b>etc</b></a>');
|
||||||
|
|
||||||
|
-- Test xmlexists evaluation
|
||||||
|
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
|
||||||
|
SELECT xmlexists('//town[text() = ''Cwmbran'']' PASSING BY REF '<towns><town>Bidford-on-Avon</town><town>Cwmbran</town><town>Bristol</town></towns>');
|
||||||
|
|
||||||
|
INSERT INTO xmltest VALUES (4, '<menu><beers><name>Budvar</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||||
|
INSERT INTO xmltest VALUES (5, '<menu><beers><name>Molson</name><cost>free</cost><name>Carling</name><cost>lots</cost></beers></menu>'::xml);
|
||||||
|
INSERT INTO xmltest VALUES (6, '<myns:menu xmlns:myns="http://myns.com"><myns:beers><myns:name>Budvar</myns:name><myns:cost>free</myns:cost><myns:name>Carling</myns:name><myns:cost>lots</myns:cost></myns:beers></myns:menu>'::xml);
|
||||||
|
INSERT INTO xmltest VALUES (7, '<myns:menu xmlns:myns="http://myns.com"><myns:beers><myns:name>Molson</myns:name><myns:cost>free</myns:cost><myns:name>Carling</myns:name><myns:cost>lots</myns:cost></myns:beers></myns:menu>'::xml);
|
||||||
|
|
||||||
|
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer' PASSING data);
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer' PASSING BY REF data BY REF);
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beers' PASSING BY REF data);
|
||||||
|
SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beers/name[text() = ''Molson'']' PASSING BY REF data);
|
||||||
|
|
||||||
|
CREATE TABLE query ( expr TEXT );
|
||||||
|
INSERT INTO query VALUES ('/menu/beers/cost[text() = ''lots'']');
|
||||||
|
SELECT COUNT(id) FROM xmltest, query WHERE xmlexists(expr PASSING BY REF data);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user