*** a/doc/src/sgml/func.sgml --- b/doc/src/sgml/func.sgml *************** *** 8693,8698 **** SELECT xpath('//mydefns:b/text()', 'test + + + xpath_exists + + + xpath_exists + + + + xpath_exists(xpath, xml, nsarray) + + + + The function xpath_exists is a specialised form + of the xpath function. Though the functions are + syntactically the same the xpath expressions are evaluated in differing + contexts. Instead of returning the XML values that satisfy the xpath, this + function returns a boolean indicating whether the query was satisfied or not. + + + + Example: + test', + ARRAY[ARRAY['my', 'http://example.com']]); + + xpath_exists + ------------ + t + (1 row) + ]]> + + *** a/src/backend/utils/adt/xml.c --- b/src/backend/utils/adt/xml.c *************** *** 3541,3543 **** Datum xmlexists(PG_FUNCTION_ARGS) --- 3541,3567 ---- return 0; #endif } + + /* + * Determines if the node specified by the supplied XPath exists + * in a given XML document, returning a boolean. Differs from + * xmlexists as it supports namespaces and is not defined in SQL/XML. + */ + Datum + xpath_exists(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; + + xpath_internal(xpath_expr_text, data, namespaces, + &res_nitems, NULL); + + PG_RETURN_BOOL(res_nitems > 0); + #else + NO_XML_SUPPORT(); + return 0; + #endif + } *** a/src/include/catalog/pg_proc.h --- b/src/include/catalog/pg_proc.h *************** *** 4390,4395 **** DESCR("evaluate XPath expression"); --- 4390,4400 ---- 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"); + DATA(insert OID = 3037 ( xpath_exists PGNSP PGUID 12 1 0 0 f f f t f i 3 0 16 "25 142 1009" _null_ _null_ _null_ _null_ xpath_exists _null_ _null_ _null_ )); + DESCR("evaluate XPath expression in a boolean context, with namespaces support"); + DATA(insert OID = 3038 ( xpath_exists PGNSP PGUID 14 1 0 0 f f f t f i 2 0 16 "25 142" _null_ _null_ _null_ _null_ "select pg_catalog.xpath_exists($1, $2, ''{}''::pg_catalog.text[])" _null_ _null_ _null_ )); + DESCR("evaluate XPath expression in a boolean context"); + /* 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_ )); DESCR("I/O"); *** a/src/include/utils/xml.h --- b/src/include/utils/xml.h *************** *** 37,42 **** extern Datum texttoxml(PG_FUNCTION_ARGS); --- 37,43 ---- extern Datum xmltotext(PG_FUNCTION_ARGS); extern Datum xmlvalidate(PG_FUNCTION_ARGS); extern Datum xpath(PG_FUNCTION_ARGS); + extern Datum xpath_exists(PG_FUNCTION_ARGS); extern Datum xmlexists(PG_FUNCTION_ARGS); extern Datum table_to_xml(PG_FUNCTION_ARGS); *** a/src/test/regress/expected/xml.out --- b/src/test/regress/expected/xml.out *************** *** 502,507 **** SELECT xpath('//b', 'one two three etc'); --- 502,560 ---- {two,etc} (1 row) + -- Test xpath_exists evaluation + SELECT xpath_exists('//town[text() = ''Toronto'']','Bidford-on-AvonCwmbranBristol'::xml); + xpath_exists + -------------- + f + (1 row) + + SELECT xpath_exists('//town[text() = ''Cwmbran'']','Bidford-on-AvonCwmbranBristol'::xml); + xpath_exists + -------------- + t + (1 row) + + INSERT INTO xmltest VALUES (4, 'BudvarfreeCarlinglots'::xml); + INSERT INTO xmltest VALUES (5, 'MolsonfreeCarlinglots'::xml); + INSERT INTO xmltest VALUES (6, 'BudvarfreeCarlinglots'::xml); + INSERT INTO xmltest VALUES (7, 'MolsonfreeCarlinglots'::xml); + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beer',data); + count + ------- + 0 + (1 row) + + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers',data); + count + ------- + 2 + (1 row) + + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers/name[text() = ''Molson'']',data); + count + ------- + 1 + (1 row) + + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beer',data,ARRAY[ARRAY['myns','http://myns.com']]); + count + ------- + 0 + (1 row) + + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers',data,ARRAY[ARRAY['myns','http://myns.com']]); + count + ------- + 2 + (1 row) + + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers/myns:name[text() = ''Molson'']',data,ARRAY[ARRAY['myns','http://myns.com']]); + count + ------- + 1 + (1 row) + -- Test xmlexists evaluation SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF 'Bidford-on-AvonCwmbranBristol'); xmlexists *************** *** 515,524 **** SELECT xmlexists('//town[text() = ''Cwmbran'']' PASSING BY REF 'Bid t (1 row) - INSERT INTO xmltest VALUES (4, 'BudvarfreeCarlinglots'::xml); - INSERT INTO xmltest VALUES (5, 'MolsonfreeCarlinglots'::xml); - INSERT INTO xmltest VALUES (6, 'BudvarfreeCarlinglots'::xml); - INSERT INTO xmltest VALUES (7, 'MolsonfreeCarlinglots'::xml); SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer' PASSING data); count ------- --- 568,573 ---- *** a/src/test/regress/sql/xml.sql --- b/src/test/regress/sql/xml.sql *************** *** 164,178 **** SELECT xpath('//text()', 'number one', ARRAY[ARRAY['loc', 'http://127.0.0.1']]); SELECT xpath('//b', 'one two three etc'); ! -- Test xmlexists evaluation ! SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF 'Bidford-on-AvonCwmbranBristol'); ! SELECT xmlexists('//town[text() = ''Cwmbran'']' PASSING BY REF 'Bidford-on-AvonCwmbranBristol'); INSERT INTO xmltest VALUES (4, 'BudvarfreeCarlinglots'::xml); INSERT INTO xmltest VALUES (5, 'MolsonfreeCarlinglots'::xml); INSERT INTO xmltest VALUES (6, 'BudvarfreeCarlinglots'::xml); INSERT INTO xmltest VALUES (7, 'MolsonfreeCarlinglots'::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); --- 164,188 ---- SELECT xpath('//loc:piece/@id', 'number one', ARRAY[ARRAY['loc', 'http://127.0.0.1']]); SELECT xpath('//b', 'one two three etc'); ! -- Test xpath_exists evaluation ! SELECT xpath_exists('//town[text() = ''Toronto'']','Bidford-on-AvonCwmbranBristol'::xml); ! SELECT xpath_exists('//town[text() = ''Cwmbran'']','Bidford-on-AvonCwmbranBristol'::xml); INSERT INTO xmltest VALUES (4, 'BudvarfreeCarlinglots'::xml); INSERT INTO xmltest VALUES (5, 'MolsonfreeCarlinglots'::xml); INSERT INTO xmltest VALUES (6, 'BudvarfreeCarlinglots'::xml); INSERT INTO xmltest VALUES (7, 'MolsonfreeCarlinglots'::xml); + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beer',data); + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers',data); + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/menu/beers/name[text() = ''Molson'']',data); + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beer',data,ARRAY[ARRAY['myns','http://myns.com']]); + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers',data,ARRAY[ARRAY['myns','http://myns.com']]); + SELECT COUNT(id) FROM xmltest WHERE xpath_exists('/myns:menu/myns:beers/myns:name[text() = ''Molson'']',data,ARRAY[ARRAY['myns','http://myns.com']]); + + -- Test xmlexists evaluation + SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF 'Bidford-on-AvonCwmbranBristol'); + SELECT xmlexists('//town[text() = ''Cwmbran'']' PASSING BY REF 'Bidford-on-AvonCwmbranBristol'); 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);