On 21/07/10 08:33, Mike Fowler wrote:

Why is the first argument AexprConst instead of a_expr? The SQL
standard says it's a character string literal, but I think we can very
well allow arbitrary expressions.

Yes, it was AexprConst because of the specification. I also found that
using it solved my shift/reduce problems, but I can change it a_expr as
see if I can work them out in a different way.

[snip]

Why c_expr?

As with the AexprConst, it's choice was partially influenced by the fact
it solved the shift/reduce errors I was getting. I'm guessing than that
I should really use a_expr and resolve the shift/reduce problem
differently?


Attached is the revised version of the patch addressing all the issues raised in the review, except for the use of AexprConst and c_expr. With my limited knowledge of bison I've failed to resolve the shift/reduce errors that are introduced by using a_expr. I'm open to suggestions as my desk is getting annoyed with me beating it in frustration!

Thanks again for taking the time to review my work.

Regards,

--
Mike Fowler
Registered Linux user: 379787
*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 8554,8562 **** SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab;
  ]]></screen>
      </para>
     </sect3>
  
!    <sect3>
      <title>XML Predicates</title>
  
      <indexterm>
       <primary>IS DOCUMENT</primary>
--- 8554,8570 ----
  ]]></screen>
      </para>
     </sect3>
+    </sect2>
  
!    <sect2>
      <title>XML Predicates</title>
+     
+     <indexterm>
+      <primary>XML Predicates</primary>
+     </indexterm>
+  
+    <sect3>
+     <title>IS DOCUMENT</title>
  
      <indexterm>
       <primary>IS DOCUMENT</primary>
***************
*** 8574,8579 **** SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab;
--- 8582,8619 ----
       between documents and content fragments.
      </para>
     </sect3>
+    
+    <sect3>
+     <title>XMLEXISTS</title>
+     
+     <indexterm>
+      <primary>XMLEXISTS</primary>
+     </indexterm>
+     
+ <synopsis>
+ <function>XMLEXISTS</function>(<replaceable>xpath</replaceable> <optional>PASSING BY REF <replaceable>xml</replaceable> <optional>BY REF</optional></optional>)
+ </synopsis>
+     
+     <para>
+      The function <function>xmlexists</function> returns true if the <replaceable>xpath</replaceable> 
+      returns any nodes and false otherwise. If no <replaceable>xml</replaceable> is passed, the function
+      will return false as a XPath cannot be evaluated without content. See the
+      <ulink url="http://www.w3.org/TR/xpath/#section-Introduction";>W3C recommendation 'XML Path Language'</ulink>
+      for a detailed explanation of why.
+     </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>    
+    </sect3>
    </sect2>
  
    <sect2 id="functions-xml-processing">
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
***************
*** 423,431 **** static TypeName *TableFuncTypeName(List *columns);
  %type <list>	opt_check_option
  
  %type <target>	xml_attribute_el
! %type <list>	xml_attribute_list xml_attributes
  %type <node>	xml_root_version opt_xml_root_standalone
! %type <ival>	document_or_content
  %type <boolean> xml_whitespace_option
  
  %type <node> 	common_table_expr
--- 423,432 ----
  %type <list>	opt_check_option
  
  %type <target>	xml_attribute_el
! %type <list>	xml_attribute_list xml_attributes xmlexists_list
  %type <node>	xml_root_version opt_xml_root_standalone
! %type <node>	xmlexists_query_argument_list
! %type <ival>	document_or_content 
  %type <boolean> xml_whitespace_option
  
  %type <node> 	common_table_expr
***************
*** 511,523 **** static TypeName *TableFuncTypeName(List *columns);
  	OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR
  	ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
  
! 	PARSER PARTIAL PARTITION PASSWORD PLACING PLANS POSITION
  	PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
  	PRIOR PRIVILEGES PROCEDURAL PROCEDURE
  
  	QUOTE
  
! 	RANGE READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REINDEX
  	RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART
  	RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
  
--- 512,524 ----
  	OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR
  	ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
  
! 	PARSER PARTIAL PARTITION PASSING PASSWORD PLACING PLANS POSITION
  	PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
  	PRIOR PRIVILEGES PROCEDURAL PROCEDURE
  
  	QUOTE
  
! 	RANGE READ REAL REASSIGN RECHECK RECURSIVE REF REFERENCES REINDEX
  	RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART
  	RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
  
***************
*** 539,545 **** static TypeName *TableFuncTypeName(List *columns);
  
  	WHEN WHERE WHITESPACE_P WINDOW WITH WITHOUT WORK WRAPPER WRITE
  
! 	XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
  	XMLPI XMLROOT XMLSERIALIZE
  
  	YEAR_P YES_P
--- 540,546 ----
  
  	WHEN WHERE WHITESPACE_P WINDOW WITH WITHOUT WORK WRAPPER WRITE
  
! 	XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLEXISTS XMLFOREST XMLPARSE
  	XMLPI XMLROOT XMLSERIALIZE
  
  	YEAR_P YES_P
***************
*** 9806,9811 **** func_expr:	func_name '(' ')' over_clause
--- 9807,9828 ----
  				{
  					$$ = makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
  				}
+ 			| XMLEXISTS '(' xmlexists_list ')'
+ 				{
+ 					/* xmlexists(A [PASSING BY REF B [BY REF]]) is converted to
+ 					 * xmlexists(A, B)*/
+ 					 
+ 					FuncCall *n = makeNode(FuncCall);
+ 					n->funcname = SystemFuncName("xmlexists");
+ 					n->args = $3;
+ 					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 ')'
  				{
  					$$ = makeXmlExpr(IS_XMLFOREST, NULL, $3, NIL, @1);
***************
*** 9896,9901 **** xml_whitespace_option: PRESERVE WHITESPACE_P		{ $$ = TRUE; }
--- 9913,9940 ----
  			| /*EMPTY*/								{ $$ = FALSE; }
  		;
  
+ xmlexists_list:
+ 			AexprConst xmlexists_query_argument_list
+ 				{
+ 					$$ = list_make2(makeTypeCast($1,SystemTypeName("text"), -1), $2);
+ 				}
+ 			| AexprConst
+ 				{
+ 					$$ = list_make1(makeTypeCast($1,SystemTypeName("text"), -1));
+ 				}
+ 		;
+ 
+ xmlexists_query_argument_list:
+ 			PASSING BY REF c_expr
+ 				{
+ 					$$ = $4;
+ 				}
+ 			| PASSING BY REF c_expr BY REF
+ 				{
+ 					$$ = $4;
+ 				}
+ 		;
+ 
  /*
   * Window Definitions
   */
***************
*** 10966,10971 **** unreserved_keyword:
--- 11005,11011 ----
  			| PARSER
  			| PARTIAL
  			| PARTITION
+ 			| PASSING
  			| PASSWORD
  			| PLANS
  			| PRECEDING
***************
*** 10982,10987 **** unreserved_keyword:
--- 11022,11028 ----
  			| REASSIGN
  			| RECHECK
  			| RECURSIVE
+ 			| REF
  			| REINDEX
  			| RELATIVE_P
  			| RELEASE
***************
*** 11115,11120 **** col_name_keyword:
--- 11156,11162 ----
  			| XMLATTRIBUTES
  			| XMLCONCAT
  			| XMLELEMENT
+ 			| XMLEXISTS
  			| XMLFOREST
  			| XMLPARSE
  			| XMLPI
*** a/src/backend/utils/adt/xml.c
--- b/src/backend/utils/adt/xml.c
***************
*** 3495,3497 **** xpath(PG_FUNCTION_ARGS)
--- 3495,3611 ----
  	return 0;
  #endif
  }
+ 
+ /*
+  * Determines if the node specified by the supplied XPath exists
+  * in a given XML document, returning a boolean.
+  *
+  * 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
+  * a context node being known.
+  */
+ Datum xmlexists(PG_FUNCTION_ARGS)
+ {
+ #ifdef USE_LIBXML
+ 	text	   *xpath_expr_text = PG_GETARG_TEXT_P(0);
+ 	xmltype    *data = PG_GETARG_XML_P(1);
+ 	xmlParserCtxtPtr ctxt = NULL;
+ 	xmlDocPtr	doc = NULL;
+ 	xmlXPathContextPtr xpathctx = NULL;
+ 	xmlXPathCompExprPtr xpathcomp = NULL;
+ 	xmlXPathObjectPtr xpathobj = NULL;
+ 	char	   *datastr;
+ 	int32		len;
+ 	int32		xpath_len;
+ 	xmlChar    *string;
+ 	xmlChar    *xpath_expr;
+ 	int			result = 0;
+ 
+ 	datastr = VARDATA(data);
+ 	len = VARSIZE(data) - VARHDRSZ;
+ 	xpath_len = VARSIZE(xpath_expr_text) - VARHDRSZ;
+ 	if (xpath_len == 0)
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_DATA_EXCEPTION),
+ 				 errmsg("empty XPath expression")));
+ 
+ 	string = (xmlChar *) palloc((len + 1) * sizeof(xmlChar));
+ 	memcpy(string, datastr, len);
+ 	string[len] = '\0';
+ 
+ 	xpath_expr = (xmlChar *) palloc((xpath_len + 1) * sizeof(xmlChar));
+ 	memcpy(xpath_expr, VARDATA(xpath_expr_text), xpath_len);
+ 	xpath_expr[xpath_len] = '\0';
+ 
+ 	pg_xml_init();
+ 	xmlInitParser();
+ 
+ 	PG_TRY();
+ 	{
+ 		/*
+ 		 * redundant XML parsing (two parsings for the same value during one
+ 		 * command execution are possible)
+ 		 */
+ 		ctxt = xmlNewParserCtxt();
+ 		if (ctxt == NULL)
+ 			xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
+ 						"could not allocate parser context");
+ 		doc = xmlCtxtReadMemory(ctxt, (char *) string, len, NULL, NULL, 0);
+ 		if (doc == NULL)
+ 			xml_ereport(ERROR, ERRCODE_INVALID_XML_DOCUMENT,
+ 						"could not parse XML document");
+ 		xpathctx = xmlXPathNewContext(doc);
+ 		if (xpathctx == NULL)
+ 			xml_ereport(ERROR, ERRCODE_OUT_OF_MEMORY,
+ 						"could not allocate XPath context");
+ 		xpathctx->node = xmlDocGetRootElement(doc);
+ 		if (xpathctx->node == NULL)
+ 			xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
+ 						"could not find root XML element");
+ 
+ 		xpathcomp = xmlXPathCompile(xpath_expr);
+ 		if (xpathcomp == NULL)	/* TODO: show proper XPath error details */
+ 			xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
+ 						"invalid XPath expression");
+ 
+ 		/* Version 2.6.27 introduces a function named xmlXPathCompiledEvalToBoolean
+ 		 * however we can derive the existence by whether any nodes are returned
+ 		 * thereby preventing a library version upgrade */
+ 		xpathobj = xmlXPathCompiledEval(xpathcomp, xpathctx);
+ 		if (xpathobj == NULL)	/* TODO: reason? */
+ 			xml_ereport(ERROR, ERRCODE_INTERNAL_ERROR,
+ 						"could not create XPath object");
+ 
+ 		if (xpathobj->nodesetval == NULL)
+ 			result = 0;
+ 		else
+ 			result = xpathobj->nodesetval->nodeNr;
+ 	}
+ 	PG_CATCH();
+ 	{
+ 		if (xpathobj)
+ 			xmlXPathFreeObject(xpathobj);
+ 		if (xpathcomp)
+ 			xmlXPathFreeCompExpr(xpathcomp);
+ 		if (xpathctx)
+ 			xmlXPathFreeContext(xpathctx);
+ 		if (doc)
+ 			xmlFreeDoc(doc);
+ 		if (ctxt)
+ 			xmlFreeParserCtxt(ctxt);
+ 		PG_RE_THROW();
+ 	}
+ 	PG_END_TRY();
+ 
+ 	xmlXPathFreeObject(xpathobj);
+ 	xmlXPathFreeCompExpr(xpathcomp);
+ 	xmlXPathFreeContext(xpathctx);
+ 	xmlFreeDoc(doc);
+ 	xmlFreeParserCtxt(ctxt);
+ 
+ 	return result;
+ #else
+ 	NO_XML_SUPPORT();
+ 	return 0;
+ #endif
+ }
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 4391,4396 **** DESCR("evaluate XPath expression, with namespaces support");
--- 4391,4401 ----
  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");
  
+ DATA(insert OID = 3037 (  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("evaluate XPath expression in a boolean context");
+ DATA(insert OID = 3038 (  xmlexists	 PGNSP PGUID 14 1 0 0 f f f t f i 1 0 16 "25" _null_ _null_ _null_ _null_ "select false" _null_ _null_ _null_ ));
+ DESCR("evaluate XPath expression in a boolean context, with no content - always returns false");
+ 
  /* 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/parser/kwlist.h
--- b/src/include/parser/kwlist.h
***************
*** 280,285 **** PG_KEYWORD("owner", OWNER, UNRESERVED_KEYWORD)
--- 280,286 ----
  PG_KEYWORD("parser", PARSER, UNRESERVED_KEYWORD)
  PG_KEYWORD("partial", PARTIAL, UNRESERVED_KEYWORD)
  PG_KEYWORD("partition", PARTITION, UNRESERVED_KEYWORD)
+ PG_KEYWORD("passing", PASSING, UNRESERVED_KEYWORD)
  PG_KEYWORD("password", PASSWORD, UNRESERVED_KEYWORD)
  PG_KEYWORD("placing", PLACING, RESERVED_KEYWORD)
  PG_KEYWORD("plans", PLANS, UNRESERVED_KEYWORD)
***************
*** 301,306 **** PG_KEYWORD("real", REAL, COL_NAME_KEYWORD)
--- 302,308 ----
  PG_KEYWORD("reassign", REASSIGN, UNRESERVED_KEYWORD)
  PG_KEYWORD("recheck", RECHECK, UNRESERVED_KEYWORD)
  PG_KEYWORD("recursive", RECURSIVE, UNRESERVED_KEYWORD)
+ PG_KEYWORD("ref", REF, UNRESERVED_KEYWORD)
  PG_KEYWORD("references", REFERENCES, RESERVED_KEYWORD)
  PG_KEYWORD("reindex", REINDEX, UNRESERVED_KEYWORD)
  PG_KEYWORD("relative", RELATIVE_P, UNRESERVED_KEYWORD)
***************
*** 413,418 **** PG_KEYWORD("xml", XML_P, UNRESERVED_KEYWORD)
--- 415,421 ----
  PG_KEYWORD("xmlattributes", XMLATTRIBUTES, COL_NAME_KEYWORD)
  PG_KEYWORD("xmlconcat", XMLCONCAT, 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("xmlparse", XMLPARSE, COL_NAME_KEYWORD)
  PG_KEYWORD("xmlpi", XMLPI, COL_NAME_KEYWORD)
*** 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 xmlexists(PG_FUNCTION_ARGS);
  
  extern Datum table_to_xml(PG_FUNCTION_ARGS);
  extern Datum query_to_xml(PG_FUNCTION_ARGS);
*** a/src/test/regress/expected/xml.out
--- b/src/test/regress/expected/xml.out
***************
*** 502,504 **** SELECT xpath('//b', '<a>one <b>two</b> three <b>etc</b></a>');
--- 502,563 ----
   {<b>two</b>,<b>etc</b>}
  (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 BY REF 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/beer');
+  count 
+ -------
+      0
+ (1 row)
+ 
+ SELECT xmlexists('true()');
+  xmlexists 
+ -----------
+  f
+ (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);
+ ERROR:  syntax error at or near "PASSING"
+ LINE 1: ...COUNT(id) FROM xmltest,query WHERE xmlexists(expr PASSING BY...
+                                                              ^
*** a/src/test/regress/sql/xml.sql
--- b/src/test/regress/sql/xml.sql
***************
*** 163,165 **** SELECT xpath('', '<!-- error -->');
--- 163,186 ----
  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('//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 BY REF data);
+ SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer' PASSING BY REF data BY REF);
+ SELECT COUNT(id) FROM xmltest WHERE xmlexists('/menu/beer');
+ SELECT xmlexists('true()');
+ 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);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to