Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit641459f

Browse files
committed
Add xmlexists function
by Mike Fowler, reviewed by Peter Eisentraut
1 parent26e47ef commit641459f

File tree

10 files changed

+312
-31
lines changed

10 files changed

+312
-31
lines changed

‎doc/src/sgml/func.sgml

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.522 2010/07/29 19:34:40 petere Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.523 2010/08/05 04:21:53 petere Exp $ -->
22

33
<chapter id="functions">
44
<title>Functions and Operators</title>
@@ -8554,10 +8554,19 @@ SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab;
85548554
]]></screen>
85558555
</para>
85568556
</sect3>
8557+
</sect2>
85578558

8558-
<sect3>
8559+
<sect2>
85598560
<title>XML Predicates</title>
85608561

8562+
<para>
8563+
The expressions described in this section check properties
8564+
of <type>xml</type> values.
8565+
</para>
8566+
8567+
<sect3>
8568+
<title>IS DOCUMENT</title>
8569+
85618570
<indexterm>
85628571
<primary>IS DOCUMENT</primary>
85638572
</indexterm>
@@ -8574,6 +8583,48 @@ SELECT xmlagg(x) FROM (SELECT * FROM test ORDER BY y DESC) AS tab;
85748583
between documents and content fragments.
85758584
</para>
85768585
</sect3>
8586+
8587+
<sect3>
8588+
<title>XMLEXISTS</title>
8589+
8590+
<indexterm>
8591+
<primary>XMLEXISTS</primary>
8592+
</indexterm>
8593+
8594+
<synopsis>
8595+
<function>XMLEXISTS</function>(<replaceable>text</replaceable> PASSING <optional>BY REF</optional> <replaceable>xml</replaceable> <optional>BY REF</optional>)
8596+
</synopsis>
8597+
8598+
<para>
8599+
The function <function>xmlexists</function> returns true if the
8600+
XPath expression in the first argument returns any nodes, and
8601+
false otherwise. (If either argument is null, the result is
8602+
null.)
8603+
</para>
8604+
8605+
<para>
8606+
Example:
8607+
<screen><![CDATA[
8608+
SELECT xmlexists('//town[text() = ''Toronto'']' PASSING BY REF '<towns><town>Toronto</town><town>Ottawa</town></towns>');
8609+
8610+
xmlexists
8611+
------------
8612+
t
8613+
(1 row)
8614+
]]></screen>
8615+
</para>
8616+
8617+
<para>
8618+
The <literal>BY REF</literal> clauses have no effect in
8619+
PostgreSQL, but are allowed for SQL conformance and compatibility
8620+
with other implementations. Per SQL standard, the
8621+
first <literal>BY REF</literal> is required, the second is
8622+
optional. Also note that the SQL standard specifies
8623+
the <function>xmlexists</function> construct to take an XQuery
8624+
expression as first argument, but PostgreSQL currently only
8625+
supports XPath, which is a subset of XQuery.
8626+
</para>
8627+
</sect3>
85778628
</sect2>
85788629

85798630
<sect2 id="functions-xml-processing">

‎src/backend/parser/gram.y

Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
*
1212
*
1313
* IDENTIFICATION
14-
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.714 2010/07/25 23:21:21 rhaas Exp $
14+
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.715 2010/08/05 04:21:53 petere Exp $
1515
*
1616
* HISTORY
1717
* AUTHORDATEMAJOR EVENT
@@ -425,6 +425,7 @@ static TypeName *TableFuncTypeName(List *columns);
425425
%type<target>xml_attribute_el
426426
%type<list>xml_attribute_listxml_attributes
427427
%type<node>xml_root_versionopt_xml_root_standalone
428+
%type<node>xmlexists_argument
428429
%type<ival>document_or_content
429430
%type<boolean>xml_whitespace_option
430431

@@ -511,13 +512,13 @@ static TypeName *TableFuncTypeName(List *columns);
511512
OBJECT_P OF OFF OFFSET OIDS ON ONLY OPERATOR OPTION OPTIONS OR
512513
ORDER OUT_P OUTER_P OVER OVERLAPS OVERLAY OWNED OWNER
513514

514-
PARSER PARTIAL PARTITION PASSWORD PLACING PLANS POSITION
515+
PARSER PARTIAL PARTITIONPASSINGPASSWORD PLACING PLANS POSITION
515516
PRECEDING PRECISION PRESERVE PREPARE PREPARED PRIMARY
516517
PRIOR PRIVILEGES PROCEDURAL PROCEDURE
517518

518519
QUOTE
519520

520-
RANGE READ REAL REASSIGN RECHECK RECURSIVE REFERENCES REINDEX
521+
RANGE READ REAL REASSIGN RECHECK RECURSIVEREFREFERENCES REINDEX
521522
RELATIVE_P RELEASE RENAME REPEATABLE REPLACE REPLICA RESET RESTART
522523
RESTRICT RETURNING RETURNS REVOKE RIGHT ROLE ROLLBACK ROW ROWS RULE
523524

@@ -539,7 +540,7 @@ static TypeName *TableFuncTypeName(List *columns);
539540

540541
WHEN WHERE WHITESPACE_P WINDOW WITH WITHOUT WORK WRAPPER WRITE
541542

542-
XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENT XMLFOREST XMLPARSE
543+
XML_P XMLATTRIBUTES XMLCONCAT XMLELEMENTXMLEXISTSXMLFOREST XMLPARSE
543544
XMLPI XMLROOT XMLSERIALIZE
544545

545546
YEAR_P YES_P
@@ -9839,6 +9840,21 @@ func_expr:func_name '(' ')' over_clause
98399840
{
98409841
$$ =makeXmlExpr(IS_XMLELEMENT, $4, $6, $8, @1);
98419842
}
9843+
| XMLEXISTS'(' c_expr xmlexists_argument')'
9844+
{
9845+
/* xmlexists(A PASSING [BY REF] B [BY REF]) is
9846+
* converted to xmlexists(A, B)*/
9847+
FuncCall *n =makeNode(FuncCall);
9848+
n->funcname =SystemFuncName("xmlexists");
9849+
n->args =list_make2($3, $4);
9850+
n->agg_order = NIL;
9851+
n->agg_star =FALSE;
9852+
n->agg_distinct =FALSE;
9853+
n->func_variadic =FALSE;
9854+
n->over =NULL;
9855+
n->location = @1;
9856+
$$ = (Node *)n;
9857+
}
98429858
| XMLFOREST'(' xml_attribute_list')'
98439859
{
98449860
$$ =makeXmlExpr(IS_XMLFOREST,NULL, $3, NIL, @1);
@@ -9929,6 +9945,27 @@ xml_whitespace_option: PRESERVE WHITESPACE_P{ $$ = TRUE; }
99299945
|/*EMPTY*/{ $$ =FALSE; }
99309946
;
99319947

9948+
/* We allow several variants for SQL and other compatibility.*/
9949+
xmlexists_argument:
9950+
PASSING c_expr
9951+
{
9952+
$$ = $2;
9953+
}
9954+
| PASSING c_expr BY REF
9955+
{
9956+
$$ = $2;
9957+
}
9958+
| PASSING BY REF c_expr
9959+
{
9960+
$$ = $4;
9961+
}
9962+
| PASSING BY REF c_expr BY REF
9963+
{
9964+
$$ = $4;
9965+
}
9966+
;
9967+
9968+
99329969
/*
99339970
* Window Definitions
99349971
*/
@@ -10999,6 +11036,7 @@ unreserved_keyword:
1099911036
| PARSER
1100011037
| PARTIAL
1100111038
| PARTITION
11039+
| PASSING
1100211040
| PASSWORD
1100311041
| PLANS
1100411042
| PRECEDING
@@ -11015,6 +11053,7 @@ unreserved_keyword:
1101511053
| REASSIGN
1101611054
| RECHECK
1101711055
| RECURSIVE
11056+
| REF
1101811057
| REINDEX
1101911058
| RELATIVE_P
1102011059
| RELEASE
@@ -11148,6 +11187,7 @@ col_name_keyword:
1114811187
| XMLATTRIBUTES
1114911188
| XMLCONCAT
1115011189
| XMLELEMENT
11190+
| XMLEXISTS
1115111191
| XMLFOREST
1115211192
| XMLPARSE
1115311193
| XMLPI

‎src/backend/utils/adt/xml.c

Lines changed: 66 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.98 2010/07/06 19:18:58 momjian Exp $
10+
* $PostgreSQL: pgsql/src/backend/utils/adt/xml.c,v 1.99 2010/08/05 04:21:54 petere Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -3295,24 +3295,20 @@ xml_xmlnodetoxmltype(xmlNodePtr cur)
32953295

32963296

32973297
/*
3298-
*Evaluate XPath expressionandreturn array of XML values.
3298+
*Common code for xpath()andxmlexists()
32993299
*
3300-
* As we have no support of XQuery sequences yet, this function seems
3301-
* to be the most useful one (array of XML functions plays a role of
3302-
* some kind of substitution for XQuery sequences).
3300+
* Evaluate XPath expression and return number of nodes in res_items
3301+
* and array of XML values in astate.
33033302
*
33043303
* It is up to the user to ensure that the XML passed is in fact
33053304
* an XML document - XPath doesn't work easily on fragments without
33063305
* a context node being known.
33073306
*/
3308-
Datum
3309-
xpath(PG_FUNCTION_ARGS)
3310-
{
33113307
#ifdefUSE_LIBXML
3312-
text*xpath_expr_text=PG_GETARG_TEXT_P(0);
3313-
xmltype*data=PG_GETARG_XML_P(1);
3314-
ArrayType*namespaces=PG_GETARG_ARRAYTYPE_P(2);
3315-
ArrayBuildState*astate=NULL;
3308+
staticvoid
3309+
xpath_internal(text*xpath_expr_text,xmltype*data,ArrayType*namespaces,
3310+
int*res_nitems,ArrayBuildState**astate)
3311+
{
33163312
xmlParserCtxtPtrctxt=NULL;
33173313
xmlDocPtrdoc=NULL;
33183314
xmlXPathContextPtrxpathctx=NULL;
@@ -3324,7 +3320,6 @@ xpath(PG_FUNCTION_ARGS)
33243320
xmlChar*string;
33253321
xmlChar*xpath_expr;
33263322
inti;
3327-
intres_nitems;
33283323
intndim;
33293324
Datum*ns_names_uris;
33303325
bool*ns_names_uris_nulls;
@@ -3339,7 +3334,7 @@ xpath(PG_FUNCTION_ARGS)
33393334
* ARRAY[ARRAY['myns', 'http://example.com'], ARRAY['myns2',
33403335
* 'http://example2.com']].
33413336
*/
3342-
ndim=ARR_NDIM(namespaces);
3337+
ndim=namespaces ?ARR_NDIM(namespaces) :0;
33433338
if (ndim!=0)
33443339
{
33453340
int*dims;
@@ -3439,28 +3434,36 @@ xpath(PG_FUNCTION_ARGS)
34393434
xml_ereport(ERROR,ERRCODE_INTERNAL_ERROR,
34403435
"invalid XPath expression");
34413436

3437+
/*
3438+
* Version 2.6.27 introduces a function named
3439+
* xmlXPathCompiledEvalToBoolean, which would be enough for
3440+
* xmlexists, but we can derive the existence by whether any
3441+
* nodes are returned, thereby preventing a library version
3442+
* upgrade and keeping the code the same.
3443+
*/
34423444
xpathobj=xmlXPathCompiledEval(xpathcomp,xpathctx);
34433445
if (xpathobj==NULL)/* TODO: reason? */
34443446
xml_ereport(ERROR,ERRCODE_INTERNAL_ERROR,
34453447
"could not create XPath object");
34463448

34473449
/* return empty array in cases when nothing is found */
34483450
if (xpathobj->nodesetval==NULL)
3449-
res_nitems=0;
3451+
*res_nitems=0;
34503452
else
3451-
res_nitems=xpathobj->nodesetval->nodeNr;
3453+
*res_nitems=xpathobj->nodesetval->nodeNr;
34523454

3453-
if (res_nitems)
3455+
if (*res_nitems&&astate)
34543456
{
3457+
*astate=NULL;
34553458
for (i=0;i<xpathobj->nodesetval->nodeNr;i++)
34563459
{
34573460
Datumelem;
34583461
boolelemisnull= false;
34593462

34603463
elem=PointerGetDatum(xml_xmlnodetoxmltype(xpathobj->nodesetval->nodeTab[i]));
3461-
astate=accumArrayResult(astate,elem,
3462-
elemisnull,XMLOID,
3463-
CurrentMemoryContext);
3464+
*astate=accumArrayResult(*astate,elem,
3465+
elemisnull,XMLOID,
3466+
CurrentMemoryContext);
34643467
}
34653468
}
34663469
}
@@ -3485,6 +3488,28 @@ xpath(PG_FUNCTION_ARGS)
34853488
xmlXPathFreeContext(xpathctx);
34863489
xmlFreeDoc(doc);
34873490
xmlFreeParserCtxt(ctxt);
3491+
}
3492+
#endif/* USE_LIBXML */
3493+
3494+
/*
3495+
* Evaluate XPath expression and return array of XML values.
3496+
*
3497+
* As we have no support of XQuery sequences yet, this function seems
3498+
* to be the most useful one (array of XML functions plays a role of
3499+
* some kind of substitution for XQuery sequences).
3500+
*/
3501+
Datum
3502+
xpath(PG_FUNCTION_ARGS)
3503+
{
3504+
#ifdefUSE_LIBXML
3505+
text*xpath_expr_text=PG_GETARG_TEXT_P(0);
3506+
xmltype*data=PG_GETARG_XML_P(1);
3507+
ArrayType*namespaces=PG_GETARG_ARRAYTYPE_P(2);
3508+
intres_nitems;
3509+
ArrayBuildState*astate;
3510+
3511+
xpath_internal(xpath_expr_text,data,namespaces,
3512+
&res_nitems,&astate);
34883513

34893514
if (res_nitems==0)
34903515
PG_RETURN_ARRAYTYPE_P(construct_empty_array(XMLOID));
@@ -3495,3 +3520,24 @@ xpath(PG_FUNCTION_ARGS)
34953520
return0;
34963521
#endif
34973522
}
3523+
3524+
/*
3525+
* Determines if the node specified by the supplied XPath exists
3526+
* in a given XML document, returning a boolean.
3527+
*/
3528+
Datumxmlexists(PG_FUNCTION_ARGS)
3529+
{
3530+
#ifdefUSE_LIBXML
3531+
text*xpath_expr_text=PG_GETARG_TEXT_P(0);
3532+
xmltype*data=PG_GETARG_XML_P(1);
3533+
intres_nitems;
3534+
3535+
xpath_internal(xpath_expr_text,data,NULL,
3536+
&res_nitems,NULL);
3537+
3538+
PG_RETURN_BOOL(res_nitems>0);
3539+
#else
3540+
NO_XML_SUPPORT();
3541+
return0;
3542+
#endif
3543+
}

‎src/include/catalog/catversion.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
3838
* Portions Copyright (c) 1994, Regents of the University of California
3939
*
40-
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.588 2010/07/16 02:15:54tgl Exp $
40+
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.589 2010/08/05 04:21:54petere Exp $
4141
*
4242
*-------------------------------------------------------------------------
4343
*/
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/*yyyymmddN */
56-
#defineCATALOG_VERSION_NO201007151
56+
#defineCATALOG_VERSION_NO201008051
5757

5858
#endif

‎src/include/catalog/pg_proc.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2010, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.573 2010/07/29 20:09:25 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/catalog/pg_proc.h,v 1.574 2010/08/05 04:21:54 petere Exp $
1111
*
1212
* NOTES
1313
* The script catalog/genbki.pl reads this file and generates .bki
@@ -4391,6 +4391,9 @@ DESCR("evaluate XPath expression, with namespaces support");
43914391
DATA(insertOID=2932 (xpathPGNSPPGUID14100ffftfi20143"25 142"_null__null__null__null_"select pg_catalog.xpath($1, $2, ''{}''::pg_catalog.text[])"_null__null__null_ ));
43924392
DESCR("evaluate XPath expression");
43934393

4394+
DATA(insertOID=2614 (xmlexistsPGNSPPGUID12100ffftfi2016"25 142"_null__null__null__null_xmlexists_null__null__null_ ));
4395+
DESCR("test XML value against XPath expression");
4396+
43944397
/* uuid */
43954398
DATA(insertOID=2952 (uuid_inPGNSPPGUID12100ffftfi102950"2275"_null__null__null__null_uuid_in_null__null__null_ ));
43964399
DESCR("I/O");

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp