2 Copyright (c) 2005, 2012, Oracle and/or its affiliates. All rights reserved.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; version 2 of the License.
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 #pragma implementation
22 #include "mysql_priv.h"
24 #include "sp_pcontext.h"
27 TODO: future development directions:
28 1. add real constants for XPATH_NODESET_CMP and XPATH_NODESET
29 into enum Type in item.h.
30 2. add nodeset_to_nodeset_comparator
31 3. add lacking functions:
51 /* Structure to store a parsed XML tree */
52 typedef struct my_xml_node_st
54 uint level
; /* level in XML tree, 0 means root node */
55 enum my_xml_node_type type
; /* node type: node, or attribute, or text */
56 uint parent
; /* link to the parent */
57 const char *beg
; /* beginning of the name or text */
58 const char *end
; /* end of the name or text */
59 const char *tagend
; /* where this tag ends */
63 /* Lexical analizer token */
64 typedef struct my_xpath_lex_st
66 int term
; /* token type, see MY_XPATH_LEX_XXXXX below */
67 const char *beg
; /* beginnign of the token */
68 const char *end
; /* end of the token */
72 /* Structure to store nodesets */
73 typedef struct my_xpath_flt_st
75 uint num
; /* absolute position in MY_XML_NODE array */
76 uint pos
; /* relative position in context */
77 uint size
; /* context size */
81 /* XPath function creator */
82 typedef struct my_xpath_function_names_st
84 const char *name
; /* function name */
85 size_t length
; /* function name length */
86 size_t minargs
; /* min number of arguments */
87 size_t maxargs
; /* max number of arguments */
88 Item
*(*create
)(struct my_xpath_st
*xpath
, Item
**args
, uint nargs
);
92 /* XPath query parser */
93 typedef struct my_xpath_st
96 MY_XPATH_LEX query
; /* Whole query */
97 MY_XPATH_LEX lasttok
; /* last scanned token */
98 MY_XPATH_LEX prevtok
; /* previous scanned token */
99 int axis
; /* last scanned axis */
100 int extra
; /* last scanned "extra", context dependent */
101 MY_XPATH_FUNC
*func
; /* last scanned function creator */
102 Item
*item
; /* current expression */
103 Item
*context
; /* last scanned context */
104 Item
*rootelement
; /* The root element */
105 String
*context_cache
; /* last context provider */
106 String
*pxml
; /* Parsed XML, an array of MY_XML_NODE */
107 CHARSET_INFO
*cs
; /* character set/collation string comparison */
112 /* Dynamic array of MY_XPATH_FLT */
113 class XPathFilter
:public String
116 XPathFilter() :String() {}
117 inline bool append_element(MY_XPATH_FLT
*flt
)
120 return str
->append((const char*)flt
, (uint32
) sizeof(MY_XPATH_FLT
));
122 inline bool append_element(uint32 num
, uint32 pos
)
128 return append_element(&add
);
130 inline bool append_element(uint32 num
, uint32 pos
, uint32 size
)
136 return append_element(&add
);
138 inline MY_XPATH_FLT
*element(uint i
)
140 return (MY_XPATH_FLT
*) (ptr() + i
* sizeof(MY_XPATH_FLT
));
142 inline uint32
numelements()
144 return length() / sizeof(MY_XPATH_FLT
);
150 Common features of the functions returning a node set.
152 class Item_nodeset_func
:public Item_str_func
155 String tmp_value
, tmp2_value
;
156 MY_XPATH_FLT
*fltbeg
, *fltend
;
157 MY_XML_NODE
*nodebeg
, *nodeend
;
161 String context_cache
;
162 Item_nodeset_func(String
*pxml_arg
) :Item_str_func(), pxml(pxml_arg
) {}
163 Item_nodeset_func(Item
*a
, String
*pxml_arg
)
164 :Item_str_func(a
), pxml(pxml_arg
) {}
165 Item_nodeset_func(Item
*a
, Item
*b
, String
*pxml_arg
)
166 :Item_str_func(a
, b
), pxml(pxml_arg
) {}
167 Item_nodeset_func(Item
*a
, Item
*b
, Item
*c
, String
*pxml_arg
)
168 :Item_str_func(a
,b
,c
), pxml(pxml_arg
) {}
171 nodebeg
= (MY_XML_NODE
*) pxml
->ptr();
172 nodeend
= (MY_XML_NODE
*) (pxml
->ptr() + pxml
->length());
173 numnodes
= nodeend
- nodebeg
;
175 void prepare(String
*nodeset
)
178 String
*res
= args
[0]->val_nodeset(&tmp_value
);
179 fltbeg
= (MY_XPATH_FLT
*) res
->ptr();
180 fltend
= (MY_XPATH_FLT
*) (res
->ptr() + res
->length());
183 enum Type
type() const { return XPATH_NODESET
; }
184 String
*val_str(String
*str
)
187 String
*res
= val_nodeset(&tmp2_value
);
188 fltbeg
= (MY_XPATH_FLT
*) res
->ptr();
189 fltend
= (MY_XPATH_FLT
*) (res
->ptr() + res
->length());
191 active
.alloc(numnodes
);
192 bzero((char*) active
.ptr(), numnodes
);
193 for (MY_XPATH_FLT
*flt
= fltbeg
; flt
< fltend
; flt
++)
197 for (j
=0, node
= nodebeg
; j
< numnodes
; j
++, node
++)
199 if (node
->type
== MY_XML_NODE_TEXT
&&
200 node
->parent
== flt
->num
)
206 str
->set_charset(collation
.collation
);
207 for (uint i
=0 ; i
< numnodes
; i
++)
212 str
->append(" ", 1, &my_charset_latin1
);
213 str
->append(nodebeg
[i
].beg
, nodebeg
[i
].end
- nodebeg
[i
].beg
);
218 enum Item_result
result_type () const { return STRING_RESULT
; }
219 void fix_length_and_dec()
221 max_length
= MAX_BLOB_WIDTH
;
222 collation
.collation
= pxml
->charset();
224 const char *func_name() const { return "nodeset"; }
228 /* Returns an XML root */
229 class Item_nodeset_func_rootelement
:public Item_nodeset_func
232 Item_nodeset_func_rootelement(String
*pxml
): Item_nodeset_func(pxml
) {}
233 const char *func_name() const { return "xpath_rootelement"; }
234 String
*val_nodeset(String
*nodeset
);
238 /* Returns a Union of two node sets */
239 class Item_nodeset_func_union
:public Item_nodeset_func
242 Item_nodeset_func_union(Item
*a
, Item
*b
, String
*pxml
)
243 :Item_nodeset_func(a
, b
, pxml
) {}
244 const char *func_name() const { return "xpath_union"; }
245 String
*val_nodeset(String
*nodeset
);
249 /* Makes one step towards the given axis */
250 class Item_nodeset_func_axisbyname
:public Item_nodeset_func
252 const char *node_name
;
255 Item_nodeset_func_axisbyname(Item
*a
, const char *n_arg
, uint l_arg
,
257 Item_nodeset_func(a
, pxml
), node_name(n_arg
), node_namelen(l_arg
) { }
258 const char *func_name() const { return "xpath_axisbyname"; }
259 bool validname(MY_XML_NODE
*n
)
261 if (node_name
[0] == '*')
263 return (node_namelen
== (uint
) (n
->end
- n
->beg
)) &&
264 !memcmp(node_name
, n
->beg
, node_namelen
);
270 class Item_nodeset_func_selfbyname
: public Item_nodeset_func_axisbyname
273 Item_nodeset_func_selfbyname(Item
*a
, const char *n_arg
, uint l_arg
,
275 Item_nodeset_func_axisbyname(a
, n_arg
, l_arg
, pxml
) {}
276 const char *func_name() const { return "xpath_selfbyname"; }
277 String
*val_nodeset(String
*nodeset
);
281 /* Returns children */
282 class Item_nodeset_func_childbyname
: public Item_nodeset_func_axisbyname
285 Item_nodeset_func_childbyname(Item
*a
, const char *n_arg
, uint l_arg
,
287 Item_nodeset_func_axisbyname(a
, n_arg
, l_arg
, pxml
) {}
288 const char *func_name() const { return "xpath_childbyname"; }
289 String
*val_nodeset(String
*nodeset
);
293 /* Returns descendants */
294 class Item_nodeset_func_descendantbyname
: public Item_nodeset_func_axisbyname
298 Item_nodeset_func_descendantbyname(Item
*a
, const char *n_arg
, uint l_arg
,
299 String
*pxml
, bool need_self_arg
):
300 Item_nodeset_func_axisbyname(a
, n_arg
, l_arg
, pxml
),
301 need_self(need_self_arg
) {}
302 const char *func_name() const { return "xpath_descendantbyname"; }
303 String
*val_nodeset(String
*nodeset
);
307 /* Returns ancestors */
308 class Item_nodeset_func_ancestorbyname
: public Item_nodeset_func_axisbyname
312 Item_nodeset_func_ancestorbyname(Item
*a
, const char *n_arg
, uint l_arg
,
313 String
*pxml
, bool need_self_arg
):
314 Item_nodeset_func_axisbyname(a
, n_arg
, l_arg
, pxml
),
315 need_self(need_self_arg
) {}
316 const char *func_name() const { return "xpath_ancestorbyname"; }
317 String
*val_nodeset(String
*nodeset
);
321 /* Returns parents */
322 class Item_nodeset_func_parentbyname
: public Item_nodeset_func_axisbyname
325 Item_nodeset_func_parentbyname(Item
*a
, const char *n_arg
, uint l_arg
,
327 Item_nodeset_func_axisbyname(a
, n_arg
, l_arg
, pxml
) {}
328 const char *func_name() const { return "xpath_parentbyname"; }
329 String
*val_nodeset(String
*nodeset
);
333 /* Returns attributes */
334 class Item_nodeset_func_attributebyname
: public Item_nodeset_func_axisbyname
337 Item_nodeset_func_attributebyname(Item
*a
, const char *n_arg
, uint l_arg
,
339 Item_nodeset_func_axisbyname(a
, n_arg
, l_arg
, pxml
) {}
340 const char *func_name() const { return "xpath_attributebyname"; }
341 String
*val_nodeset(String
*nodeset
);
346 Condition iterator: goes through all nodes in the current
347 context and checks a condition, returning those nodes
348 giving TRUE condition result.
350 class Item_nodeset_func_predicate
:public Item_nodeset_func
353 Item_nodeset_func_predicate(Item
*a
, Item
*b
, String
*pxml
):
354 Item_nodeset_func(a
, b
, pxml
) {}
355 const char *func_name() const { return "xpath_predicate"; }
356 String
*val_nodeset(String
*nodeset
);
360 /* Selects nodes with a given position in context */
361 class Item_nodeset_func_elementbyindex
:public Item_nodeset_func
364 Item_nodeset_func_elementbyindex(Item
*a
, Item
*b
, String
*pxml
):
365 Item_nodeset_func(a
, b
, pxml
) { }
366 const char *func_name() const { return "xpath_elementbyindex"; }
367 String
*val_nodeset(String
*nodeset
);
372 We need to distinguish a number from a boolean:
373 a[1] and a[true] are different things in XPath.
375 class Item_bool
:public Item_int
378 Item_bool(int32 i
): Item_int(i
) {}
379 const char *func_name() const { return "xpath_bool"; }
380 bool is_bool_func() { return 1; }
385 Converts its argument into a boolean value.
386 * a number is true if it is non-zero
387 * a node-set is true if and only if it is non-empty
388 * a string is true if and only if its length is non-zero
390 class Item_xpath_cast_bool
:public Item_int_func
395 Item_xpath_cast_bool(Item
*a
, String
*pxml_arg
)
396 :Item_int_func(a
), pxml(pxml_arg
) {}
397 const char *func_name() const { return "xpath_cast_bool"; }
398 bool is_bool_func() { return 1; }
401 if (args
[0]->type() == XPATH_NODESET
)
403 String
*flt
= args
[0]->val_nodeset(&tmp_value
);
404 return flt
->length() == sizeof(MY_XPATH_FLT
) ? 1 : 0;
406 return args
[0]->val_real() ? 1 : 0;
412 Converts its argument into a number
414 class Item_xpath_cast_number
:public Item_real_func
417 Item_xpath_cast_number(Item
*a
): Item_real_func(a
) {}
418 const char *func_name() const { return "xpath_cast_number"; }
419 virtual double val_real() { return args
[0]->val_real(); }
424 Context cache, for predicate
426 class Item_nodeset_context_cache
:public Item_nodeset_func
429 String
*string_cache
;
430 Item_nodeset_context_cache(String
*str_arg
, String
*pxml
):
431 Item_nodeset_func(pxml
), string_cache(str_arg
) { }
432 String
*val_nodeset(String
*res
)
433 { return string_cache
; }
434 void fix_length_and_dec() { max_length
= MAX_BLOB_WIDTH
; }
438 class Item_func_xpath_position
:public Item_int_func
443 Item_func_xpath_position(Item
*a
, String
*p
)
444 :Item_int_func(a
), pxml(p
) {}
445 const char *func_name() const { return "xpath_position"; }
446 void fix_length_and_dec() { max_length
=10; }
449 String
*flt
= args
[0]->val_nodeset(&tmp_value
);
450 if (flt
->length() == sizeof(MY_XPATH_FLT
))
451 return ((MY_XPATH_FLT
*)flt
->ptr())->pos
+ 1;
457 class Item_func_xpath_count
:public Item_int_func
462 Item_func_xpath_count(Item
*a
, String
*p
)
463 :Item_int_func(a
), pxml(p
) {}
464 const char *func_name() const { return "xpath_count"; }
465 void fix_length_and_dec() { max_length
=10; }
468 uint predicate_supplied_context_size
;
469 String
*res
= args
[0]->val_nodeset(&tmp_value
);
470 if (res
->length() == sizeof(MY_XPATH_FLT
) &&
471 (predicate_supplied_context_size
= ((MY_XPATH_FLT
*)res
->ptr())->size
))
472 return predicate_supplied_context_size
;
473 return res
->length() / sizeof(MY_XPATH_FLT
);
478 class Item_func_xpath_sum
:public Item_real_func
483 Item_func_xpath_sum(Item
*a
, String
*p
)
484 :Item_real_func(a
), pxml(p
) {}
486 const char *func_name() const { return "xpath_sum"; }
490 String
*res
= args
[0]->val_nodeset(&tmp_value
);
491 MY_XPATH_FLT
*fltbeg
= (MY_XPATH_FLT
*) res
->ptr();
492 MY_XPATH_FLT
*fltend
= (MY_XPATH_FLT
*) (res
->ptr() + res
->length());
493 uint numnodes
= pxml
->length() / sizeof(MY_XML_NODE
);
494 MY_XML_NODE
*nodebeg
= (MY_XML_NODE
*) pxml
->ptr();
496 for (MY_XPATH_FLT
*flt
= fltbeg
; flt
< fltend
; flt
++)
498 MY_XML_NODE
*self
= &nodebeg
[flt
->num
];
499 for (uint j
= flt
->num
+ 1; j
< numnodes
; j
++)
501 MY_XML_NODE
*node
= &nodebeg
[j
];
502 if (node
->level
<= self
->level
)
504 if ((node
->parent
== flt
->num
) &&
505 (node
->type
== MY_XML_NODE_TEXT
))
509 double add
= my_strntod(collation
.collation
, (char*) node
->beg
,
510 node
->end
- node
->beg
, &end
, &err
);
521 class Item_nodeset_to_const_comparator
:public Item_bool_func
526 Item_nodeset_to_const_comparator(Item
*nodeset
, Item
*cmpfunc
, String
*p
)
527 :Item_bool_func(nodeset
,cmpfunc
), pxml(p
) {}
528 enum Type
type() const { return XPATH_NODESET_CMP
; };
529 const char *func_name() const { return "xpath_nodeset_to_const_comparator"; }
530 bool is_bool_func() { return 1; }
534 Item_func
*comp
= (Item_func
*)args
[1];
535 Item_string
*fake
= (Item_string
*)(comp
->arguments()[0]);
536 String
*res
= args
[0]->val_nodeset(&tmp_nodeset
);
537 MY_XPATH_FLT
*fltbeg
= (MY_XPATH_FLT
*) res
->ptr();
538 MY_XPATH_FLT
*fltend
= (MY_XPATH_FLT
*) (res
->ptr() + res
->length());
539 MY_XML_NODE
*nodebeg
= (MY_XML_NODE
*) pxml
->ptr();
540 uint numnodes
= pxml
->length() / sizeof(MY_XML_NODE
);
542 for (MY_XPATH_FLT
*flt
= fltbeg
; flt
< fltend
; flt
++)
544 MY_XML_NODE
*self
= &nodebeg
[flt
->num
];
545 for (uint j
= flt
->num
+ 1; j
< numnodes
; j
++)
547 MY_XML_NODE
*node
= &nodebeg
[j
];
548 if (node
->level
<= self
->level
)
550 if ((node
->parent
== flt
->num
) &&
551 (node
->type
== MY_XML_NODE_TEXT
))
553 fake
->str_value
.set(node
->beg
, node
->end
- node
->beg
,
554 collation
.collation
);
555 if (args
[1]->val_int())
565 String
*Item_nodeset_func_rootelement::val_nodeset(String
*nodeset
)
568 ((XPathFilter
*)nodeset
)->append_element(0, 0);
573 String
* Item_nodeset_func_union::val_nodeset(String
*nodeset
)
575 uint num_nodes
= pxml
->length() / sizeof(MY_XML_NODE
);
576 String set0
, *s0
= args
[0]->val_nodeset(&set0
);
577 String set1
, *s1
= args
[1]->val_nodeset(&set1
);
579 both_str
.alloc(num_nodes
);
580 char *both
= (char*) both_str
.ptr();
581 bzero((void*)both
, num_nodes
);
584 fltbeg
= (MY_XPATH_FLT
*) s0
->ptr();
585 fltend
= (MY_XPATH_FLT
*) (s0
->ptr() + s0
->length());
586 for (flt
= fltbeg
; flt
< fltend
; flt
++)
589 fltbeg
= (MY_XPATH_FLT
*) s1
->ptr();
590 fltend
= (MY_XPATH_FLT
*) (s1
->ptr() + s1
->length());
591 for (flt
= fltbeg
; flt
< fltend
; flt
++)
595 for (uint i
= 0, pos
= 0; i
< num_nodes
; i
++)
598 ((XPathFilter
*)nodeset
)->append_element(i
, pos
++);
604 String
*Item_nodeset_func_selfbyname::val_nodeset(String
*nodeset
)
607 for (MY_XPATH_FLT
*flt
= fltbeg
; flt
< fltend
; flt
++)
610 MY_XML_NODE
*self
= &nodebeg
[flt
->num
];
612 ((XPathFilter
*)nodeset
)->append_element(flt
->num
,pos
++);
618 String
*Item_nodeset_func_childbyname::val_nodeset(String
*nodeset
)
621 for (MY_XPATH_FLT
*flt
= fltbeg
; flt
< fltend
; flt
++)
623 MY_XML_NODE
*self
= &nodebeg
[flt
->num
];
624 for (uint pos
= 0, j
= flt
->num
+ 1 ; j
< numnodes
; j
++)
626 MY_XML_NODE
*node
= &nodebeg
[j
];
627 if (node
->level
<= self
->level
)
629 if ((node
->parent
== flt
->num
) &&
630 (node
->type
== MY_XML_NODE_TAG
) &&
632 ((XPathFilter
*)nodeset
)->append_element(j
, pos
++);
639 String
*Item_nodeset_func_descendantbyname::val_nodeset(String
*nodeset
)
642 for (MY_XPATH_FLT
*flt
= fltbeg
; flt
< fltend
; flt
++)
645 MY_XML_NODE
*self
= &nodebeg
[flt
->num
];
646 if (need_self
&& validname(self
))
647 ((XPathFilter
*)nodeset
)->append_element(flt
->num
,pos
++);
648 for (uint j
= flt
->num
+ 1 ; j
< numnodes
; j
++)
650 MY_XML_NODE
*node
= &nodebeg
[j
];
651 if (node
->level
<= self
->level
)
653 if ((node
->type
== MY_XML_NODE_TAG
) && validname(node
))
654 ((XPathFilter
*)nodeset
)->append_element(j
,pos
++);
661 String
*Item_nodeset_func_ancestorbyname::val_nodeset(String
*nodeset
)
666 active_str
.alloc(numnodes
);
667 active
= (char*) active_str
.ptr();
668 bzero((void*)active
, numnodes
);
671 for (MY_XPATH_FLT
*flt
= fltbeg
; flt
< fltend
; flt
++)
674 Go to the root and add all nodes on the way.
675 Don't add the root if context is the root itelf
677 MY_XML_NODE
*self
= &nodebeg
[flt
->num
];
678 if (need_self
&& validname(self
))
684 for (uint j
= self
->parent
; nodebeg
[j
].parent
!= j
; j
= nodebeg
[j
].parent
)
686 if (flt
->num
&& validname(&nodebeg
[j
]))
694 for (uint j
= 0; j
< numnodes
; j
++)
697 ((XPathFilter
*)nodeset
)->append_element(j
, --pos
);
703 String
*Item_nodeset_func_parentbyname::val_nodeset(String
*nodeset
)
708 active_str
.alloc(numnodes
);
709 active
= (char*) active_str
.ptr();
710 bzero((void*)active
, numnodes
);
711 for (MY_XPATH_FLT
*flt
= fltbeg
; flt
< fltend
; flt
++)
713 uint j
= nodebeg
[flt
->num
].parent
;
714 if (flt
->num
&& validname(&nodebeg
[j
]))
717 for (uint j
= 0, pos
= 0; j
< numnodes
; j
++)
720 ((XPathFilter
*)nodeset
)->append_element(j
, pos
++);
726 String
*Item_nodeset_func_attributebyname::val_nodeset(String
*nodeset
)
729 for (MY_XPATH_FLT
*flt
= fltbeg
; flt
< fltend
; flt
++)
731 MY_XML_NODE
*self
= &nodebeg
[flt
->num
];
732 for (uint pos
=0, j
= flt
->num
+ 1 ; j
< numnodes
; j
++)
734 MY_XML_NODE
*node
= &nodebeg
[j
];
735 if (node
->level
<= self
->level
)
737 if ((node
->parent
== flt
->num
) &&
738 (node
->type
== MY_XML_NODE_ATTR
) &&
740 ((XPathFilter
*)nodeset
)->append_element(j
, pos
++);
747 String
*Item_nodeset_func_predicate::val_nodeset(String
*str
)
749 Item_nodeset_func
*nodeset_func
= (Item_nodeset_func
*) args
[0];
750 Item_func
*comp_func
= (Item_func
*)args
[1];
753 size
= fltend
- fltbeg
;
754 for (MY_XPATH_FLT
*flt
= fltbeg
; flt
< fltend
; flt
++)
756 nodeset_func
->context_cache
.length(0);
757 ((XPathFilter
*)(&nodeset_func
->context_cache
))->append_element(flt
->num
,
760 if (comp_func
->val_int())
761 ((XPathFilter
*)str
)->append_element(flt
->num
, pos
++);
767 String
*Item_nodeset_func_elementbyindex::val_nodeset(String
*nodeset
)
769 Item_nodeset_func
*nodeset_func
= (Item_nodeset_func
*) args
[0];
772 uint pos
, size
= fltend
- fltbeg
;
773 for (pos
= 0, flt
= fltbeg
; flt
< fltend
; flt
++)
775 nodeset_func
->context_cache
.length(0);
776 ((XPathFilter
*)(&nodeset_func
->context_cache
))->append_element(flt
->num
,
779 int index
= (int) (args
[1]->val_int()) - 1;
780 if (index
>= 0 && (flt
->pos
== (uint
) index
|| args
[1]->is_bool_func()))
781 ((XPathFilter
*)nodeset
)->append_element(flt
->num
, pos
++);
788 If item is a node set, then casts it to boolean,
789 otherwise returns the item itself.
791 static Item
* nodeset2bool(MY_XPATH
*xpath
, Item
*item
)
793 if (item
->type() == Item::XPATH_NODESET
)
794 return new Item_xpath_cast_bool(item
, xpath
->pxml
);
802 #define MY_XPATH_LEX_DIGITS 'd'
803 #define MY_XPATH_LEX_IDENT 'i'
804 #define MY_XPATH_LEX_STRING 's'
805 #define MY_XPATH_LEX_SLASH '/'
806 #define MY_XPATH_LEX_LB '['
807 #define MY_XPATH_LEX_RB ']'
808 #define MY_XPATH_LEX_LP '('
809 #define MY_XPATH_LEX_RP ')'
810 #define MY_XPATH_LEX_EQ '='
811 #define MY_XPATH_LEX_LESS '<'
812 #define MY_XPATH_LEX_GREATER '>'
813 #define MY_XPATH_LEX_AT '@'
814 #define MY_XPATH_LEX_COLON ':'
815 #define MY_XPATH_LEX_ASTERISK '*'
816 #define MY_XPATH_LEX_DOT '.'
817 #define MY_XPATH_LEX_VLINE '|'
818 #define MY_XPATH_LEX_MINUS '-'
819 #define MY_XPATH_LEX_PLUS '+'
820 #define MY_XPATH_LEX_EXCL '!'
821 #define MY_XPATH_LEX_COMMA ','
822 #define MY_XPATH_LEX_DOLLAR '$'
823 #define MY_XPATH_LEX_ERROR 'A'
824 #define MY_XPATH_LEX_EOF 'B'
825 #define MY_XPATH_LEX_AND 'C'
826 #define MY_XPATH_LEX_OR 'D'
827 #define MY_XPATH_LEX_DIV 'E'
828 #define MY_XPATH_LEX_MOD 'F'
829 #define MY_XPATH_LEX_FUNC 'G'
830 #define MY_XPATH_LEX_NODETYPE 'H'
831 #define MY_XPATH_LEX_AXIS 'I'
832 #define MY_XPATH_LEX_LE 'J'
833 #define MY_XPATH_LEX_GE 'K'
839 #define MY_XPATH_AXIS_ANCESTOR 0
840 #define MY_XPATH_AXIS_ANCESTOR_OR_SELF 1
841 #define MY_XPATH_AXIS_ATTRIBUTE 2
842 #define MY_XPATH_AXIS_CHILD 3
843 #define MY_XPATH_AXIS_DESCENDANT 4
844 #define MY_XPATH_AXIS_DESCENDANT_OR_SELF 5
845 #define MY_XPATH_AXIS_FOLLOWING 6
846 #define MY_XPATH_AXIS_FOLLOWING_SIBLING 7
847 #define MY_XPATH_AXIS_NAMESPACE 8
848 #define MY_XPATH_AXIS_PARENT 9
849 #define MY_XPATH_AXIS_PRECEDING 10
850 #define MY_XPATH_AXIS_PRECEDING_SIBLING 11
851 #define MY_XPATH_AXIS_SELF 12
855 Create scalar comparator
858 Create a comparator function for scalar arguments,
859 for the given arguments and operation.
862 The newly created item.
864 static Item
*eq_func(int oper
, Item
*a
, Item
*b
)
868 case '=': return new Item_func_eq(a
, b
);
869 case '!': return new Item_func_ne(a
, b
);
870 case MY_XPATH_LEX_GE
: return new Item_func_ge(a
, b
);
871 case MY_XPATH_LEX_LE
: return new Item_func_le(a
, b
);
872 case MY_XPATH_LEX_GREATER
: return new Item_func_gt(a
, b
);
873 case MY_XPATH_LEX_LESS
: return new Item_func_lt(a
, b
);
880 Create scalar comparator
883 Create a comparator function for scalar arguments,
884 for the given arguments and reverse operation, e.g.
886 A > B is converted into B < A
889 The newly created item.
891 static Item
*eq_func_reverse(int oper
, Item
*a
, Item
*b
)
895 case '=': return new Item_func_eq(a
, b
);
896 case '!': return new Item_func_ne(a
, b
);
897 case MY_XPATH_LEX_GE
: return new Item_func_le(a
, b
);
898 case MY_XPATH_LEX_LE
: return new Item_func_ge(a
, b
);
899 case MY_XPATH_LEX_GREATER
: return new Item_func_lt(a
, b
);
900 case MY_XPATH_LEX_LESS
: return new Item_func_gt(a
, b
);
910 Create a comparator for scalar or non-scalar arguments,
911 for the given arguments and operation.
914 The newly created item.
916 static Item
*create_comparator(MY_XPATH
*xpath
,
917 int oper
, MY_XPATH_LEX
*context
,
920 if (a
->type() != Item::XPATH_NODESET
&&
921 b
->type() != Item::XPATH_NODESET
)
923 return eq_func(oper
, a
, b
); // two scalar arguments
925 else if (a
->type() == Item::XPATH_NODESET
&&
926 b
->type() == Item::XPATH_NODESET
)
928 uint len
= xpath
->query
.end
- context
->beg
;
929 set_if_smaller(len
, 32);
930 my_printf_error(ER_UNKNOWN_ERROR
,
932 "comparison of two nodesets is not supported: '%.*s'",
933 MYF(0), len
, context
->beg
);
935 return 0; // TODO: Comparison of two nodesets
940 Compare a node set to a scalar value.
941 We just create a fake Item_string() argument,
942 which will be filled to the partular value
943 in a loop through all of the nodes in the node set.
946 Item_string
*fake
= new Item_string("", 0, xpath
->cs
);
947 /* Don't cache fake because its value will be changed during comparison.*/
948 fake
->set_used_tables(RAND_TABLE_BIT
);
949 Item_nodeset_func
*nodeset
;
951 if (a
->type() == Item::XPATH_NODESET
)
953 nodeset
= (Item_nodeset_func
*) a
;
955 comp
= eq_func(oper
, (Item
*)fake
, scalar
);
959 nodeset
= (Item_nodeset_func
*) b
;
961 comp
= eq_func_reverse(oper
, fake
, scalar
);
963 return new Item_nodeset_to_const_comparator(nodeset
, comp
, xpath
->pxml
);
972 Create a step function for the given argument and axis.
975 The newly created item.
977 static Item
* nametestfunc(MY_XPATH
*xpath
,
978 int type
, Item
*arg
, const char *beg
, uint len
)
980 DBUG_ASSERT(arg
!= 0);
981 DBUG_ASSERT(arg
->type() == Item::XPATH_NODESET
);
982 DBUG_ASSERT(beg
!= 0);
983 DBUG_ASSERT(len
> 0);
988 case MY_XPATH_AXIS_ANCESTOR
:
989 res
= new Item_nodeset_func_ancestorbyname(arg
, beg
, len
, xpath
->pxml
, 0);
991 case MY_XPATH_AXIS_ANCESTOR_OR_SELF
:
992 res
= new Item_nodeset_func_ancestorbyname(arg
, beg
, len
, xpath
->pxml
, 1);
994 case MY_XPATH_AXIS_PARENT
:
995 res
= new Item_nodeset_func_parentbyname(arg
, beg
, len
, xpath
->pxml
);
997 case MY_XPATH_AXIS_DESCENDANT
:
998 res
= new Item_nodeset_func_descendantbyname(arg
, beg
, len
, xpath
->pxml
, 0);
1000 case MY_XPATH_AXIS_DESCENDANT_OR_SELF
:
1001 res
= new Item_nodeset_func_descendantbyname(arg
, beg
, len
, xpath
->pxml
, 1);
1003 case MY_XPATH_AXIS_ATTRIBUTE
:
1004 res
= new Item_nodeset_func_attributebyname(arg
, beg
, len
, xpath
->pxml
);
1006 case MY_XPATH_AXIS_SELF
:
1007 res
= new Item_nodeset_func_selfbyname(arg
, beg
, len
, xpath
->pxml
);
1010 res
= new Item_nodeset_func_childbyname(arg
, beg
, len
, xpath
->pxml
);
1017 Tokens consisting of one character, for faster lexical analizer.
1019 static char simpletok
[128]=
1021 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
1023 ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
1024 @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _
1025 ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ €
1027 0,1,0,0,1,0,0,0,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,1,1,0,
1028 1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,
1029 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0
1036 struct my_xpath_keyword_names_st
1045 static struct my_xpath_keyword_names_st my_keyword_names
[] =
1047 {MY_XPATH_LEX_AND
, "and" , 3, 0 },
1048 {MY_XPATH_LEX_OR
, "or" , 2, 0 },
1049 {MY_XPATH_LEX_DIV
, "div" , 3, 0 },
1050 {MY_XPATH_LEX_MOD
, "mod" , 3, 0 },
1055 static struct my_xpath_keyword_names_st my_axis_names
[]=
1057 {MY_XPATH_LEX_AXIS
,"ancestor" , 8,MY_XPATH_AXIS_ANCESTOR
},
1058 {MY_XPATH_LEX_AXIS
,"ancestor-or-self" ,16,MY_XPATH_AXIS_ANCESTOR_OR_SELF
},
1059 {MY_XPATH_LEX_AXIS
,"attribute" , 9,MY_XPATH_AXIS_ATTRIBUTE
},
1060 {MY_XPATH_LEX_AXIS
,"child" , 5,MY_XPATH_AXIS_CHILD
},
1061 {MY_XPATH_LEX_AXIS
,"descendant" ,10,MY_XPATH_AXIS_DESCENDANT
},
1062 {MY_XPATH_LEX_AXIS
,"descendant-or-self",18,MY_XPATH_AXIS_DESCENDANT_OR_SELF
},
1063 {MY_XPATH_LEX_AXIS
,"following" , 9,MY_XPATH_AXIS_FOLLOWING
},
1064 {MY_XPATH_LEX_AXIS
,"following-sibling" ,17,MY_XPATH_AXIS_FOLLOWING_SIBLING
},
1065 {MY_XPATH_LEX_AXIS
,"namespace" , 9,MY_XPATH_AXIS_NAMESPACE
},
1066 {MY_XPATH_LEX_AXIS
,"parent" , 6,MY_XPATH_AXIS_PARENT
},
1067 {MY_XPATH_LEX_AXIS
,"preceding" , 9,MY_XPATH_AXIS_PRECEDING
},
1068 {MY_XPATH_LEX_AXIS
,"preceding-sibling" ,17,MY_XPATH_AXIS_PRECEDING_SIBLING
},
1069 {MY_XPATH_LEX_AXIS
,"self" , 4,MY_XPATH_AXIS_SELF
},
1074 static struct my_xpath_keyword_names_st my_nodetype_names
[]=
1076 {MY_XPATH_LEX_NODETYPE
, "comment" , 7, 0 },
1077 {MY_XPATH_LEX_NODETYPE
, "text" , 4, 0 },
1078 {MY_XPATH_LEX_NODETYPE
, "processing-instruction" , 22,0 },
1079 {MY_XPATH_LEX_NODETYPE
, "node" , 4, 0 },
1088 Check that the last scanned identifier is a keyword.
1091 - Token type, on lookup success.
1092 - MY_XPATH_LEX_IDENT, on lookup failure.
1095 my_xpath_keyword(MY_XPATH
*x
,
1096 struct my_xpath_keyword_names_st
*keyword_names
,
1097 const char *beg
, const char *end
)
1099 struct my_xpath_keyword_names_st
*k
;
1100 size_t length
= end
-beg
;
1101 for (k
= keyword_names
; k
->name
; k
++)
1103 if (length
== k
->length
&& !strncasecmp(beg
, k
->name
, length
))
1109 return MY_XPATH_LEX_IDENT
;
1114 Functions to create an item, a-la those in item_create.cc
1117 static Item
*create_func_true(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1119 return new Item_bool(1);
1123 static Item
*create_func_false(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1125 return new Item_bool(0);
1129 static Item
*create_func_not(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1131 return new Item_func_not(nodeset2bool(xpath
, args
[0]));
1135 static Item
*create_func_ceiling(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1137 return new Item_func_ceiling(args
[0]);
1141 static Item
*create_func_floor(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1143 return new Item_func_floor(args
[0]);
1147 static Item
*create_func_bool(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1149 return new Item_xpath_cast_bool(args
[0], xpath
->pxml
);
1153 static Item
*create_func_number(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1155 return new Item_xpath_cast_number(args
[0]);
1159 static Item
*create_func_string_length(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1161 Item
*arg
= nargs
? args
[0] : xpath
->context
;
1162 return arg
? new Item_func_char_length(arg
) : 0;
1166 static Item
*create_func_round(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1168 return new Item_func_round(args
[0], new Item_int((char*)"0",0,1),0);
1172 static Item
*create_func_last(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1174 return xpath
->context
?
1175 new Item_func_xpath_count(xpath
->context
, xpath
->pxml
) : NULL
;
1179 static Item
*create_func_position(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1181 return xpath
->context
?
1182 new Item_func_xpath_position(xpath
->context
, xpath
->pxml
) : NULL
;
1186 static Item
*create_func_contains(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1188 return new Item_xpath_cast_bool(new Item_func_locate(args
[0], args
[1]),
1193 static Item
*create_func_concat(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1195 return new Item_func_concat(args
[0], args
[1]);
1199 static Item
*create_func_substr(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1202 return new Item_func_substr(args
[0], args
[1]);
1204 return new Item_func_substr(args
[0], args
[1], args
[2]);
1208 static Item
*create_func_count(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1210 if (args
[0]->type() != Item::XPATH_NODESET
)
1212 return new Item_func_xpath_count(args
[0], xpath
->pxml
);
1216 static Item
*create_func_sum(MY_XPATH
*xpath
, Item
**args
, uint nargs
)
1218 if (args
[0]->type() != Item::XPATH_NODESET
)
1220 return new Item_func_xpath_sum(args
[0], xpath
->pxml
);
1225 Functions names. Separate lists for names with
1226 lengths 3,4,5 and 6 for faster lookups.
1228 static MY_XPATH_FUNC my_func_names3
[]=
1230 {"sum", 3, 1 , 1 , create_func_sum
},
1231 {"not", 3, 1 , 1 , create_func_not
},
1236 static MY_XPATH_FUNC my_func_names4
[]=
1238 {"last", 4, 0, 0, create_func_last
},
1239 {"true", 4, 0, 0, create_func_true
},
1240 {"name", 4, 0, 1, 0},
1241 {"lang", 4, 1, 1, 0},
1246 static MY_XPATH_FUNC my_func_names5
[]=
1248 {"count", 5, 1, 1, create_func_count
},
1249 {"false", 5, 0, 0, create_func_false
},
1250 {"floor", 5, 1, 1, create_func_floor
},
1251 {"round", 5, 1, 1, create_func_round
},
1256 static MY_XPATH_FUNC my_func_names6
[]=
1258 {"concat", 6, 2, 255, create_func_concat
},
1259 {"number", 6, 0, 1 , create_func_number
},
1260 {"string", 6, 0, 1 , 0},
1265 /* Other functions, with name longer than 6, all together */
1266 static MY_XPATH_FUNC my_func_names
[] =
1268 {"id" , 2 , 1 , 1 , 0},
1269 {"boolean" , 7 , 1 , 1 , create_func_bool
},
1270 {"ceiling" , 7 , 1 , 1 , create_func_ceiling
},
1271 {"position" , 8 , 0 , 0 , create_func_position
},
1272 {"contains" , 8 , 2 , 2 , create_func_contains
},
1273 {"substring" , 9 , 2 , 3 , create_func_substr
},
1274 {"translate" , 9 , 3 , 3 , 0},
1276 {"local-name" , 10 , 0 , 1 , 0},
1277 {"starts-with" , 11 , 2 , 2 , 0},
1278 {"namespace-uri" , 13 , 0 , 1 , 0},
1279 {"string-length" , 13 , 0 , 1 , create_func_string_length
},
1280 {"substring-after" , 15 , 2 , 2 , 0},
1281 {"normalize-space" , 15 , 0 , 1 , 0},
1282 {"substring-before" , 16 , 2 , 2 , 0},
1289 Lookup a function by name
1292 Lookup a function by its name.
1295 Pointer to a MY_XPATH_FUNC variable on success.
1300 my_xpath_function(const char *beg
, const char *end
)
1302 MY_XPATH_FUNC
*k
, *function_names
;
1303 uint length
= end
-beg
;
1307 case 3: function_names
= my_func_names3
; break;
1308 case 4: function_names
= my_func_names4
; break;
1309 case 5: function_names
= my_func_names5
; break;
1310 case 6: function_names
= my_func_names6
; break;
1311 default: function_names
= my_func_names
;
1313 for (k
= function_names
; k
->name
; k
++)
1314 if (k
->create
&& length
== k
->length
&& !strncasecmp(beg
, k
->name
, length
))
1320 /* Initialize a lex analizer token */
1322 my_xpath_lex_init(MY_XPATH_LEX
*lex
,
1323 const char *str
, const char *strend
)
1330 /* Initialize an XPath query parser */
1332 my_xpath_init(MY_XPATH
*xpath
)
1334 bzero((void*)xpath
, sizeof(xpath
[0]));
1341 return ((c
) >= '0' && (c
) <= '9');
1349 Scan the next token from the input.
1350 lex->term is set to the scanned token type.
1351 lex->beg and lex->end are set to the beginnig
1352 and to the end of the token.
1357 my_xpath_lex_scan(MY_XPATH
*xpath
,
1358 MY_XPATH_LEX
*lex
, const char *beg
, const char *end
)
1360 int ch
, ctype
, length
;
1361 for ( ; beg
< end
&& *beg
== ' ' ; beg
++) ; // skip leading spaces
1367 lex
->term
= MY_XPATH_LEX_EOF
; // end of line reached
1371 // Check ident, or a function call, or a keyword
1372 if ((length
= xpath
->cs
->cset
->ctype(xpath
->cs
, &ctype
,
1374 (const uchar
*) end
)) > 0 &&
1375 ((ctype
& (_MY_L
| _MY_U
)) || *beg
== '_'))
1377 // scan untill the end of the idenfitier
1379 (length
= xpath
->cs
->cset
->ctype(xpath
->cs
, &ctype
,
1381 (const uchar
*) end
)) > 0 &&
1382 ((ctype
& (_MY_L
| _MY_U
| _MY_NMR
)) ||
1383 *beg
== '_' || *beg
== '-' || *beg
== '.') ;
1384 beg
+= length
) /* no op */;
1392 check if a function call, e.g.: count(/a/b)
1393 or a nodetype test, e.g.: /a/b/text()
1395 if ((xpath
->func
= my_xpath_function(lex
->beg
, beg
)))
1396 lex
->term
= MY_XPATH_LEX_FUNC
;
1398 lex
->term
= my_xpath_keyword(xpath
, my_nodetype_names
,
1402 // check if an axis specifier, e.g.: /a/b/child::*
1403 else if (*beg
== ':' && beg
+ 1 < end
&& beg
[1] == ':')
1405 lex
->term
= my_xpath_keyword(xpath
, my_axis_names
,
1410 // check if a keyword
1411 lex
->term
= my_xpath_keyword(xpath
, my_keyword_names
,
1419 if (ch
> 0 && ch
< 128 && simpletok
[ch
])
1421 // a token consisting of one character found
1428 if (my_xdigit(ch
)) // a sequence of digits
1430 for ( ; beg
< end
&& my_xdigit(*beg
) ; beg
++) ;
1432 lex
->term
= MY_XPATH_LEX_DIGITS
;
1436 if (ch
== '"' || ch
== '\'') // a string: either '...' or "..."
1438 for ( ; beg
< end
&& *beg
!= ch
; beg
++) ;
1442 lex
->term
= MY_XPATH_LEX_STRING
;
1447 // unexpected end-of-line, without closing quot sign
1449 lex
->term
= MY_XPATH_LEX_ERROR
;
1455 lex
->term
= MY_XPATH_LEX_ERROR
; // unknown character
1461 Scan the given token
1464 Scan the given token and rotate lasttok to prevtok on success.
1471 my_xpath_parse_term(MY_XPATH
*xpath
, int term
)
1473 if (xpath
->lasttok
.term
== term
&& !xpath
->error
)
1475 xpath
->prevtok
= xpath
->lasttok
;
1476 my_xpath_lex_scan(xpath
, &xpath
->lasttok
,
1477 xpath
->lasttok
.end
, xpath
->query
.end
);
1488 Scan an axis name and store the scanned axis type into xpath->axis.
1494 static int my_xpath_parse_AxisName(MY_XPATH
*xpath
)
1496 int rc
= my_xpath_parse_term(xpath
, MY_XPATH_LEX_AXIS
);
1497 xpath
->axis
= xpath
->extra
;
1502 /*********************************************
1503 ** Grammar rules, according to http://www.w3.org/TR/xpath
1504 ** Implemented using recursive descendant method.
1505 ** All the following grammar processing functions accept
1506 ** a signle "xpath" argument and return 1 on success and 0 on error.
1507 ** They also modify "xpath" argument by creating new items.
1510 /* [9] PredicateExpr ::= Expr */
1511 #define my_xpath_parse_PredicateExpr(x) my_xpath_parse_Expr((x))
1513 /* [14] Expr ::= OrExpr */
1514 #define my_xpath_parse_Expr(x) my_xpath_parse_OrExpr((x))
1516 static int my_xpath_parse_LocationPath(MY_XPATH
*xpath
);
1517 static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH
*xpath
);
1518 static int my_xpath_parse_RelativeLocationPath(MY_XPATH
*xpath
);
1519 static int my_xpath_parse_AbbreviatedStep(MY_XPATH
*xpath
);
1520 static int my_xpath_parse_Step(MY_XPATH
*xpath
);
1521 static int my_xpath_parse_AxisSpecifier(MY_XPATH
*xpath
);
1522 static int my_xpath_parse_NodeTest(MY_XPATH
*xpath
);
1523 static int my_xpath_parse_AbbreviatedAxisSpecifier(MY_XPATH
*xpath
);
1524 static int my_xpath_parse_NameTest(MY_XPATH
*xpath
);
1525 static int my_xpath_parse_FunctionCall(MY_XPATH
*xpath
);
1526 static int my_xpath_parse_Number(MY_XPATH
*xpath
);
1527 static int my_xpath_parse_FilterExpr(MY_XPATH
*xpath
);
1528 static int my_xpath_parse_PathExpr(MY_XPATH
*xpath
);
1529 static int my_xpath_parse_OrExpr(MY_XPATH
*xpath
);
1530 static int my_xpath_parse_UnaryExpr(MY_XPATH
*xpath
);
1531 static int my_xpath_parse_MultiplicativeExpr(MY_XPATH
*xpath
);
1532 static int my_xpath_parse_AdditiveExpr(MY_XPATH
*xpath
);
1533 static int my_xpath_parse_RelationalExpr(MY_XPATH
*xpath
);
1534 static int my_xpath_parse_AndExpr(MY_XPATH
*xpath
);
1535 static int my_xpath_parse_EqualityExpr(MY_XPATH
*xpath
);
1536 static int my_xpath_parse_VariableReference(MY_XPATH
*xpath
);
1544 [1] LocationPath ::= RelativeLocationPath
1545 | AbsoluteLocationPath
1551 static int my_xpath_parse_LocationPath(MY_XPATH
*xpath
)
1553 Item
*context
= xpath
->context
;
1555 if (!xpath
->context
)
1556 xpath
->context
= xpath
->rootelement
;
1557 int rc
= my_xpath_parse_RelativeLocationPath(xpath
) ||
1558 my_xpath_parse_AbsoluteLocationPath(xpath
);
1560 xpath
->item
= xpath
->context
;
1561 xpath
->context
= context
;
1567 Scan Absolute Location Path
1571 [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
1572 | AbbreviatedAbsoluteLocationPath
1573 [10] AbbreviatedAbsoluteLocationPath ::= '//' RelativeLocationPath
1575 We combine these two rules into one rule for better performance:
1577 [2,10] AbsoluteLocationPath ::= '/' RelativeLocationPath?
1578 | '//' RelativeLocationPath
1584 static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH
*xpath
)
1586 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_SLASH
))
1589 xpath
->context
= xpath
->rootelement
;
1591 if (my_xpath_parse_term(xpath
, MY_XPATH_LEX_SLASH
))
1593 xpath
->context
= new Item_nodeset_func_descendantbyname(xpath
->context
,
1596 return my_xpath_parse_RelativeLocationPath(xpath
);
1599 my_xpath_parse_RelativeLocationPath(xpath
);
1601 return (xpath
->error
== 0);
1606 Scan Relative Location Path
1610 For better performance we combine these two rules
1612 [3] RelativeLocationPath ::= Step
1613 | RelativeLocationPath '/' Step
1614 | AbbreviatedRelativeLocationPath
1615 [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
1620 [3-11] RelativeLocationPath ::= Step
1621 | RelativeLocationPath '/' Step
1622 | RelativeLocationPath '//' Step
1627 static int my_xpath_parse_RelativeLocationPath(MY_XPATH
*xpath
)
1629 if (!my_xpath_parse_Step(xpath
))
1631 while (my_xpath_parse_term(xpath
, MY_XPATH_LEX_SLASH
))
1633 if (my_xpath_parse_term(xpath
, MY_XPATH_LEX_SLASH
))
1634 xpath
->context
= new Item_nodeset_func_descendantbyname(xpath
->context
,
1637 if (!my_xpath_parse_Step(xpath
))
1648 Scan non-abbreviated or abbreviated Step
1652 [4] Step ::= AxisSpecifier NodeTest Predicate*
1654 [8] Predicate ::= '[' PredicateExpr ']'
1661 my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(MY_XPATH
*xpath
)
1663 if (!my_xpath_parse_AxisSpecifier(xpath
))
1666 if (!my_xpath_parse_NodeTest(xpath
))
1669 while (my_xpath_parse_term(xpath
, MY_XPATH_LEX_LB
))
1671 Item
*prev_context
= xpath
->context
;
1672 String
*context_cache
;
1673 context_cache
= &((Item_nodeset_func
*)xpath
->context
)->context_cache
;
1674 xpath
->context
= new Item_nodeset_context_cache(context_cache
, xpath
->pxml
);
1675 xpath
->context_cache
= context_cache
;
1677 if(!my_xpath_parse_PredicateExpr(xpath
))
1683 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_RB
))
1689 xpath
->item
= nodeset2bool(xpath
, xpath
->item
);
1691 if (xpath
->item
->is_bool_func())
1693 xpath
->context
= new Item_nodeset_func_predicate(prev_context
,
1699 xpath
->context
= new Item_nodeset_func_elementbyindex(prev_context
,
1708 static int my_xpath_parse_Step(MY_XPATH
*xpath
)
1711 my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(xpath
) ||
1712 my_xpath_parse_AbbreviatedStep(xpath
);
1717 Scan Abbreviated Axis Specifier
1720 [5] AxisSpecifier ::= AxisName '::'
1721 | AbbreviatedAxisSpecifier
1727 static int my_xpath_parse_AbbreviatedAxisSpecifier(MY_XPATH
*xpath
)
1729 if (my_xpath_parse_term(xpath
, MY_XPATH_LEX_AT
))
1730 xpath
->axis
= MY_XPATH_AXIS_ATTRIBUTE
;
1732 xpath
->axis
= MY_XPATH_AXIS_CHILD
;
1738 Scan non-abbreviated axis specifier
1746 static int my_xpath_parse_AxisName_colon_colon(MY_XPATH
*xpath
)
1748 return my_xpath_parse_AxisName(xpath
) &&
1749 my_xpath_parse_term(xpath
, MY_XPATH_LEX_COLON
) &&
1750 my_xpath_parse_term(xpath
, MY_XPATH_LEX_COLON
);
1755 Scan Abbreviated AxisSpecifier
1758 [13] AbbreviatedAxisSpecifier ::= '@'?
1764 static int my_xpath_parse_AxisSpecifier(MY_XPATH
*xpath
)
1766 return my_xpath_parse_AxisName_colon_colon(xpath
) ||
1767 my_xpath_parse_AbbreviatedAxisSpecifier(xpath
);
1772 Scan NodeType followed by parens
1780 static int my_xpath_parse_NodeTest_lp_rp(MY_XPATH
*xpath
)
1782 return my_xpath_parse_term(xpath
, MY_XPATH_LEX_NODETYPE
) &&
1783 my_xpath_parse_term(xpath
, MY_XPATH_LEX_LP
) &&
1784 my_xpath_parse_term(xpath
, MY_XPATH_LEX_RP
);
1793 [7] NodeTest ::= NameTest
1795 | 'processing-instruction' '(' Literal ')'
1800 static int my_xpath_parse_NodeTest(MY_XPATH
*xpath
)
1802 return my_xpath_parse_NameTest(xpath
) ||
1803 my_xpath_parse_NodeTest_lp_rp(xpath
);
1808 Scan Abbreviated Step
1812 [12] AbbreviatedStep ::= '.' | '..'
1818 static int my_xpath_parse_AbbreviatedStep(MY_XPATH
*xpath
)
1820 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_DOT
))
1822 if (my_xpath_parse_term(xpath
, MY_XPATH_LEX_DOT
))
1823 xpath
->context
= new Item_nodeset_func_parentbyname(xpath
->context
, "*", 1,
1830 Scan Primary Expression
1834 [15] PrimaryExpr ::= VariableReference
1843 static int my_xpath_parse_lp_Expr_rp(MY_XPATH
*xpath
)
1845 return my_xpath_parse_term(xpath
, MY_XPATH_LEX_LP
) &&
1846 my_xpath_parse_Expr(xpath
) &&
1847 my_xpath_parse_term(xpath
, MY_XPATH_LEX_RP
);
1849 static int my_xpath_parse_PrimaryExpr_literal(MY_XPATH
*xpath
)
1851 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_STRING
))
1853 xpath
->item
= new Item_string(xpath
->prevtok
.beg
+ 1,
1854 xpath
->prevtok
.end
- xpath
->prevtok
.beg
- 2,
1858 static int my_xpath_parse_PrimaryExpr(MY_XPATH
*xpath
)
1861 my_xpath_parse_lp_Expr_rp(xpath
) ||
1862 my_xpath_parse_VariableReference(xpath
) ||
1863 my_xpath_parse_PrimaryExpr_literal(xpath
) ||
1864 my_xpath_parse_Number(xpath
) ||
1865 my_xpath_parse_FunctionCall(xpath
);
1873 [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument )* )? ')'
1874 [17] Argument ::= Expr
1881 static int my_xpath_parse_FunctionCall(MY_XPATH
*xpath
)
1886 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_FUNC
))
1889 MY_XPATH_FUNC
*func
= xpath
->func
;
1891 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_LP
))
1894 for (nargs
= 0 ; nargs
< func
->maxargs
; )
1896 if (!my_xpath_parse_Expr(xpath
))
1898 if (nargs
< func
->minargs
)
1902 args
[nargs
++]= xpath
->item
;
1903 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_COMMA
))
1905 if (nargs
< func
->minargs
)
1913 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_RP
))
1916 return ((xpath
->item
= func
->create(xpath
, args
, nargs
))) ? 1 : 0;
1921 Scan Union Expression
1924 [18] UnionExpr ::= PathExpr
1925 | UnionExpr '|' PathExpr
1931 static int my_xpath_parse_UnionExpr(MY_XPATH
*xpath
)
1933 if (!my_xpath_parse_PathExpr(xpath
))
1936 while (my_xpath_parse_term(xpath
, MY_XPATH_LEX_VLINE
))
1938 Item
*prev
= xpath
->item
;
1939 if (prev
->type() != Item::XPATH_NODESET
)
1942 if (!my_xpath_parse_PathExpr(xpath
)
1943 || xpath
->item
->type() != Item::XPATH_NODESET
)
1948 xpath
->item
= new Item_nodeset_func_union(prev
, xpath
->item
, xpath
->pxml
);
1955 Scan Path Expression
1959 [19] PathExpr ::= LocationPath
1961 | FilterExpr '/' RelativeLocationPath
1962 | FilterExpr '//' RelativeLocationPath
1968 my_xpath_parse_FilterExpr_opt_slashes_RelativeLocationPath(MY_XPATH
*xpath
)
1970 if (!my_xpath_parse_FilterExpr(xpath
))
1973 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_SLASH
))
1976 if (xpath
->item
->type() != Item::XPATH_NODESET
)
1978 xpath
->lasttok
= xpath
->prevtok
;
1983 my_xpath_parse_term(xpath
, MY_XPATH_LEX_SLASH
);
1984 return my_xpath_parse_RelativeLocationPath(xpath
);
1986 static int my_xpath_parse_PathExpr(MY_XPATH
*xpath
)
1988 return my_xpath_parse_LocationPath(xpath
) ||
1989 my_xpath_parse_FilterExpr_opt_slashes_RelativeLocationPath(xpath
);
1995 Scan Filter Expression
1998 [20] FilterExpr ::= PrimaryExpr
1999 | FilterExpr Predicate
2003 [20] FilterExpr ::= PrimaryExpr Predicate*
2010 static int my_xpath_parse_FilterExpr(MY_XPATH
*xpath
)
2012 return my_xpath_parse_PrimaryExpr(xpath
);
2020 [21] OrExpr ::= AndExpr
2021 | OrExpr 'or' AndExpr
2027 static int my_xpath_parse_OrExpr(MY_XPATH
*xpath
)
2029 if (!my_xpath_parse_AndExpr(xpath
))
2032 while (my_xpath_parse_term(xpath
, MY_XPATH_LEX_OR
))
2034 Item
*prev
= xpath
->item
;
2035 if (!my_xpath_parse_AndExpr(xpath
))
2040 xpath
->item
= new Item_cond_or(nodeset2bool(xpath
, prev
),
2041 nodeset2bool(xpath
, xpath
->item
));
2051 [22] AndExpr ::= EqualityExpr
2052 | AndExpr 'and' EqualityExpr
2058 static int my_xpath_parse_AndExpr(MY_XPATH
*xpath
)
2060 if (!my_xpath_parse_EqualityExpr(xpath
))
2063 while (my_xpath_parse_term(xpath
, MY_XPATH_LEX_AND
))
2065 Item
*prev
= xpath
->item
;
2066 if (!my_xpath_parse_EqualityExpr(xpath
))
2072 xpath
->item
= new Item_cond_and(nodeset2bool(xpath
,prev
),
2073 nodeset2bool(xpath
,xpath
->item
));
2080 Scan Equality Expression
2083 [23] EqualityExpr ::= RelationalExpr
2084 | EqualityExpr '=' RelationalExpr
2085 | EqualityExpr '!=' RelationalExpr
2088 [23] EqualityExpr ::= RelationalExpr ( EqualityOperator EqualityExpr )*
2094 static int my_xpath_parse_ne(MY_XPATH
*xpath
)
2096 MY_XPATH_LEX prevtok
= xpath
->prevtok
;
2097 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_EXCL
))
2099 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_EQ
))
2101 /* Unget the exclamation mark */
2102 xpath
->lasttok
= xpath
->prevtok
;
2103 xpath
->prevtok
= prevtok
;
2108 static int my_xpath_parse_EqualityOperator(MY_XPATH
*xpath
)
2110 if (my_xpath_parse_ne(xpath
))
2115 if (my_xpath_parse_term(xpath
, MY_XPATH_LEX_EQ
))
2122 static int my_xpath_parse_EqualityExpr(MY_XPATH
*xpath
)
2124 MY_XPATH_LEX operator_context
;
2125 if (!my_xpath_parse_RelationalExpr(xpath
))
2128 operator_context
= xpath
->lasttok
;
2129 while (my_xpath_parse_EqualityOperator(xpath
))
2131 Item
*prev
= xpath
->item
;
2132 int oper
= xpath
->extra
;
2133 if (!my_xpath_parse_RelationalExpr(xpath
))
2139 if (!(xpath
->item
= create_comparator(xpath
, oper
, &operator_context
,
2140 prev
, xpath
->item
)))
2143 operator_context
= xpath
->lasttok
;
2150 Scan Relational Expression
2154 [24] RelationalExpr ::= AdditiveExpr
2155 | RelationalExpr '<' AdditiveExpr
2156 | RelationalExpr '>' AdditiveExpr
2157 | RelationalExpr '<=' AdditiveExpr
2158 | RelationalExpr '>=' AdditiveExpr
2161 [24] RelationalExpr ::= AdditiveExpr (RelationalOperator RelationalExpr)*
2167 static int my_xpath_parse_RelationalOperator(MY_XPATH
*xpath
)
2169 if (my_xpath_parse_term(xpath
, MY_XPATH_LEX_LESS
))
2171 xpath
->extra
= my_xpath_parse_term(xpath
, MY_XPATH_LEX_EQ
) ?
2172 MY_XPATH_LEX_LE
: MY_XPATH_LEX_LESS
;
2175 else if (my_xpath_parse_term(xpath
, MY_XPATH_LEX_GREATER
))
2177 xpath
->extra
= my_xpath_parse_term(xpath
, MY_XPATH_LEX_EQ
) ?
2178 MY_XPATH_LEX_GE
: MY_XPATH_LEX_GREATER
;
2183 static int my_xpath_parse_RelationalExpr(MY_XPATH
*xpath
)
2185 MY_XPATH_LEX operator_context
;
2186 if (!my_xpath_parse_AdditiveExpr(xpath
))
2188 operator_context
= xpath
->lasttok
;
2189 while (my_xpath_parse_RelationalOperator(xpath
))
2191 Item
*prev
= xpath
->item
;
2192 int oper
= xpath
->extra
;
2194 if (!my_xpath_parse_AdditiveExpr(xpath
))
2200 if (!(xpath
->item
= create_comparator(xpath
, oper
, &operator_context
,
2201 prev
, xpath
->item
)))
2203 operator_context
= xpath
->lasttok
;
2210 Scan Additive Expression
2214 [25] AdditiveExpr ::= MultiplicativeExpr
2215 | AdditiveExpr '+' MultiplicativeExpr
2216 | AdditiveExpr '-' MultiplicativeExpr
2221 static int my_xpath_parse_AdditiveOperator(MY_XPATH
*xpath
)
2223 return my_xpath_parse_term(xpath
, MY_XPATH_LEX_PLUS
) ||
2224 my_xpath_parse_term(xpath
, MY_XPATH_LEX_MINUS
);
2226 static int my_xpath_parse_AdditiveExpr(MY_XPATH
*xpath
)
2228 if (!my_xpath_parse_MultiplicativeExpr(xpath
))
2231 while (my_xpath_parse_AdditiveOperator(xpath
))
2233 int oper
= xpath
->prevtok
.term
;
2234 Item
*prev
= xpath
->item
;
2235 if (!my_xpath_parse_MultiplicativeExpr(xpath
))
2241 if (oper
== MY_XPATH_LEX_PLUS
)
2242 xpath
->item
= new Item_func_plus(prev
, xpath
->item
);
2244 xpath
->item
= new Item_func_minus(prev
, xpath
->item
);
2251 Scan Multiplicative Expression
2255 [26] MultiplicativeExpr ::= UnaryExpr
2256 | MultiplicativeExpr MultiplyOperator UnaryExpr
2257 | MultiplicativeExpr 'div' UnaryExpr
2258 | MultiplicativeExpr 'mod' UnaryExpr
2261 [26] MultiplicativeExpr ::= UnaryExpr (MulOper MultiplicativeExpr)*
2267 static int my_xpath_parse_MultiplicativeOperator(MY_XPATH
*xpath
)
2270 my_xpath_parse_term(xpath
, MY_XPATH_LEX_ASTERISK
) ||
2271 my_xpath_parse_term(xpath
, MY_XPATH_LEX_DIV
) ||
2272 my_xpath_parse_term(xpath
, MY_XPATH_LEX_MOD
);
2274 static int my_xpath_parse_MultiplicativeExpr(MY_XPATH
*xpath
)
2276 if (!my_xpath_parse_UnaryExpr(xpath
))
2279 while (my_xpath_parse_MultiplicativeOperator(xpath
))
2281 int oper
= xpath
->prevtok
.term
;
2282 Item
*prev
= xpath
->item
;
2283 if (!my_xpath_parse_UnaryExpr(xpath
))
2290 case MY_XPATH_LEX_ASTERISK
:
2291 xpath
->item
= new Item_func_mul(prev
, xpath
->item
);
2293 case MY_XPATH_LEX_DIV
:
2294 xpath
->item
= new Item_func_int_div(prev
, xpath
->item
);
2296 case MY_XPATH_LEX_MOD
:
2297 xpath
->item
= new Item_func_mod(prev
, xpath
->item
);
2306 Scan Unary Expression
2310 [27] UnaryExpr ::= UnionExpr
2316 static int my_xpath_parse_UnaryExpr(MY_XPATH
*xpath
)
2318 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_MINUS
))
2319 return my_xpath_parse_UnionExpr(xpath
);
2320 if (!my_xpath_parse_UnaryExpr(xpath
))
2322 xpath
->item
= new Item_func_neg(xpath
->item
);
2332 [30] Number ::= Digits ('.' Digits?)? | '.' Digits)
2336 [30] Number ::= Digits
2341 Note: the last rule is not supported yet,
2342 as it is in conflict with abbreviated step.
2343 1 + .123 does not work,
2345 Perhaps it is better to move this code into lex analizer.
2351 static int my_xpath_parse_Number(MY_XPATH
*xpath
)
2354 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_DIGITS
))
2356 beg
= xpath
->prevtok
.beg
;
2357 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_DOT
))
2359 xpath
->item
= new Item_int(xpath
->prevtok
.beg
,
2360 xpath
->prevtok
.end
- xpath
->prevtok
.beg
);
2363 my_xpath_parse_term(xpath
, MY_XPATH_LEX_DIGITS
);
2365 xpath
->item
= new Item_float(beg
, xpath
->prevtok
.end
- beg
);
2375 The keywords AND, OR, MOD, DIV are valid identitiers
2376 when they are in identifier context:
2379 ExtractValue('<and><or><mod><div>VALUE</div></mod></or></and>',
2389 my_xpath_parse_NCName(MY_XPATH
*xpath
)
2392 my_xpath_parse_term(xpath
, MY_XPATH_LEX_IDENT
) ||
2393 my_xpath_parse_term(xpath
, MY_XPATH_LEX_AND
) ||
2394 my_xpath_parse_term(xpath
, MY_XPATH_LEX_OR
) ||
2395 my_xpath_parse_term(xpath
, MY_XPATH_LEX_MOD
) ||
2396 my_xpath_parse_term(xpath
, MY_XPATH_LEX_DIV
) ? 1 : 0;
2401 QName grammar can be found in a separate document
2402 http://www.w3.org/TR/REC-xml-names/#NT-QName
2404 [6] QName ::= (Prefix ':')? LocalPart
2405 [7] Prefix ::= NCName
2406 [8] LocalPart ::= NCName
2410 my_xpath_parse_QName(MY_XPATH
*xpath
)
2413 if (!my_xpath_parse_NCName(xpath
))
2415 beg
= xpath
->prevtok
.beg
;
2416 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_COLON
))
2417 return 1; /* Non qualified name */
2418 if (!my_xpath_parse_NCName(xpath
))
2420 xpath
->prevtok
.beg
= beg
;
2426 Scan Variable reference
2428 @details Implements parsing of two syntax structures:
2430 1. Standard XPath syntax [36], for SP variables:
2432 VariableReference ::= '$' QName
2434 Finds a SP variable with the given name.
2435 If outside of a SP context, or variable with
2436 the given name doesn't exists, then error is returned.
2438 2. Non-standard syntax - MySQL extension for user variables:
2440 VariableReference ::= '$' '@' QName
2442 Item, corresponding to the variable, is returned
2443 in xpath->item in both cases.
2445 @param xpath pointer to XPath structure
2447 @return Operation status
2453 my_xpath_parse_VariableReference(MY_XPATH
*xpath
)
2457 const char *dollar_pos
;
2458 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_DOLLAR
) ||
2459 (!(dollar_pos
= xpath
->prevtok
.beg
)) ||
2460 (!((user_var
= my_xpath_parse_term(xpath
, MY_XPATH_LEX_AT
) &&
2461 my_xpath_parse_term(xpath
, MY_XPATH_LEX_IDENT
))) &&
2462 !my_xpath_parse_term(xpath
, MY_XPATH_LEX_IDENT
)))
2465 name
.length
= xpath
->prevtok
.end
- xpath
->prevtok
.beg
;
2466 name
.str
= (char*) xpath
->prevtok
.beg
;
2469 xpath
->item
= new Item_func_get_user_var(name
);
2475 if ((lex
= current_thd
->lex
) &&
2476 (spc
= lex
->spcont
) &&
2477 (spv
= spc
->find_variable(&name
)))
2479 Item_splocal
*splocal
= new Item_splocal(name
, spv
->offset
, spv
->type
, 0);
2482 splocal
->m_sp
= lex
->sphead
;
2484 xpath
->item
= (Item
*) splocal
;
2489 DBUG_ASSERT(xpath
->query
.end
> dollar_pos
);
2490 uint len
= xpath
->query
.end
- dollar_pos
;
2491 set_if_smaller(len
, 32);
2492 my_printf_error(ER_UNKNOWN_ERROR
, "Unknown XPATH variable at: '%.*s'",
2493 MYF(0), len
, dollar_pos
);
2496 return xpath
->item
? 1 : 0;
2505 [37] NameTest ::= '*'
2513 my_xpath_parse_NodeTest_QName(MY_XPATH
*xpath
)
2515 if (!my_xpath_parse_QName(xpath
))
2517 DBUG_ASSERT(xpath
->context
);
2518 uint len
= xpath
->prevtok
.end
- xpath
->prevtok
.beg
;
2519 xpath
->context
= nametestfunc(xpath
, xpath
->axis
, xpath
->context
,
2520 xpath
->prevtok
.beg
, len
);
2524 my_xpath_parse_NodeTest_asterisk(MY_XPATH
*xpath
)
2526 if (!my_xpath_parse_term(xpath
, MY_XPATH_LEX_ASTERISK
))
2528 DBUG_ASSERT(xpath
->context
);
2529 xpath
->context
= nametestfunc(xpath
, xpath
->axis
, xpath
->context
, "*", 1);
2533 my_xpath_parse_NameTest(MY_XPATH
*xpath
)
2535 return my_xpath_parse_NodeTest_asterisk(xpath
) ||
2536 my_xpath_parse_NodeTest_QName(xpath
);
2541 Scan an XPath expression
2544 Scan xpath expression.
2545 The expression is returned in xpath->expr.
2552 my_xpath_parse(MY_XPATH
*xpath
, const char *str
, const char *strend
)
2554 my_xpath_lex_init(&xpath
->query
, str
, strend
);
2555 my_xpath_lex_init(&xpath
->prevtok
, str
, strend
);
2556 my_xpath_lex_scan(xpath
, &xpath
->lasttok
, str
, strend
);
2558 xpath
->rootelement
= new Item_nodeset_func_rootelement(xpath
->pxml
);
2561 my_xpath_parse_Expr(xpath
) &&
2562 my_xpath_parse_term(xpath
, MY_XPATH_LEX_EOF
);
2566 void Item_xml_str_func::fix_length_and_dec()
2574 if (agg_arg_charsets(collation
, args
, arg_count
, MY_COLL_CMP_CONV
, 1))
2577 if (collation
.collation
->mbminlen
> 1)
2579 /* UCS2 is not supported */
2580 my_printf_error(ER_UNKNOWN_ERROR
,
2581 "Character set '%s' is not supported by XPATH",
2582 MYF(0), collation
.collation
->csname
);
2586 if (!args
[1]->const_item())
2588 my_printf_error(ER_UNKNOWN_ERROR
,
2589 "Only constant XPATH queries are supported", MYF(0));
2593 if (!(xp
= args
[1]->val_str(&tmp
)))
2595 my_xpath_init(&xpath
);
2596 xpath
.cs
= collation
.collation
;
2599 pxml
.set_charset(collation
.collation
);
2601 rc
= my_xpath_parse(&xpath
, xp
->ptr(), xp
->ptr() + xp
->length());
2605 uint clen
= xpath
.query
.end
- xpath
.lasttok
.beg
;
2606 set_if_smaller(clen
, 32);
2607 my_printf_error(ER_UNKNOWN_ERROR
, "XPATH syntax error: '%.*s'",
2608 MYF(0), clen
, xpath
.lasttok
.beg
);
2612 nodeset_func
= xpath
.item
;
2614 nodeset_func
->fix_fields(current_thd
, &nodeset_func
);
2615 max_length
= MAX_BLOB_WIDTH
;
2619 #define MAX_LEVEL 256
2623 String
*pxml
; // parsed XML
2624 uint pos
[MAX_LEVEL
]; // Tag position stack
2625 uint parent
; // Offset of the parent of the current node
2630 append_node(String
*str
, MY_XML_NODE
*node
)
2633 If "str" doesn't have space for a new node,
2634 it will allocate two times more space that it has had so far.
2635 (2*len+512) is a heuristic value,
2636 which gave the best performance during tests.
2637 The ideas behind this formula are:
2638 - It allows to have a very small number of reallocs:
2639 about 10 reallocs on a 1Mb-long XML value.
2640 - At the same time, it avoids excessive memory use.
2642 if (str
->reserve(sizeof(MY_XML_NODE
), 2 * str
->length() + 512))
2644 str
->q_append((const char*) node
, sizeof(MY_XML_NODE
));
2650 Process tag beginning
2654 A call-back function executed when XML parser
2655 is entering a tag or an attribue.
2656 Appends the new node into data->pxml.
2657 Increments data->level.
2660 Currently only MY_XML_OK
2662 extern "C" int xml_enter(MY_XML_PARSER
*st
,const char *attr
, size_t len
);
2664 int xml_enter(MY_XML_PARSER
*st
,const char *attr
, size_t len
)
2666 MY_XML_USER_DATA
*data
= (MY_XML_USER_DATA
*)st
->user_data
;
2667 uint numnodes
= data
->pxml
->length() / sizeof(MY_XML_NODE
);
2670 node
.parent
= data
->parent
; // Set parent for the new node to old parent
2671 data
->parent
= numnodes
; // Remember current node as new parent
2672 DBUG_ASSERT(data
->level
<= MAX_LEVEL
);
2673 data
->pos
[data
->level
]= numnodes
;
2674 if (data
->level
< MAX_LEVEL
)
2675 node
.level
= data
->level
++;
2677 return MY_XML_ERROR
;
2678 node
.type
= st
->current_node_type
; // TAG or ATTR
2680 node
.end
= attr
+ len
;
2681 return append_node(data
->pxml
, &node
) ? MY_XML_ERROR
: MY_XML_OK
;
2690 A call-back function executed when XML parser
2691 is entering into a tag or an attribue textual value.
2692 The value is appended into data->pxml.
2695 Currently only MY_XML_OK
2697 extern "C" int xml_value(MY_XML_PARSER
*st
,const char *attr
, size_t len
);
2699 int xml_value(MY_XML_PARSER
*st
,const char *attr
, size_t len
)
2701 MY_XML_USER_DATA
*data
= (MY_XML_USER_DATA
*)st
->user_data
;
2704 node
.parent
= data
->parent
; // Set parent for the new text node to old parent
2705 node
.level
= data
->level
;
2706 node
.type
= MY_XML_NODE_TEXT
;
2708 node
.end
= attr
+ len
;
2709 return append_node(data
->pxml
, &node
) ? MY_XML_ERROR
: MY_XML_OK
;
2714 Leave a tag or an attribute
2718 A call-back function executed when XML parser
2719 is leaving a tag or an attribue.
2720 Decrements data->level.
2723 Currently only MY_XML_OK
2725 extern "C" int xml_leave(MY_XML_PARSER
*st
,const char *attr
, size_t len
);
2727 int xml_leave(MY_XML_PARSER
*st
,const char *attr
, size_t len
)
2729 MY_XML_USER_DATA
*data
= (MY_XML_USER_DATA
*)st
->user_data
;
2730 DBUG_ASSERT(data
->level
> 0);
2733 MY_XML_NODE
*nodes
= (MY_XML_NODE
*) data
->pxml
->ptr();
2734 data
->parent
= nodes
[data
->parent
].parent
;
2735 nodes
+= data
->pos
[data
->level
];
2736 nodes
->tagend
= st
->cur
;
2749 Currently pointer to parsed XML on success
2752 String
*Item_xml_str_func::parse_xml(String
*raw_xml
, String
*parsed_xml_buf
)
2755 MY_XML_USER_DATA user_data
;
2758 parsed_xml_buf
->length(0);
2760 /* Prepare XML parser */
2761 my_xml_parser_create(&p
);
2762 p
.flags
= MY_XML_FLAG_RELATIVE_NAMES
| MY_XML_FLAG_SKIP_TEXT_NORMALIZATION
;
2764 user_data
.pxml
= parsed_xml_buf
;
2765 user_data
.parent
= 0;
2766 my_xml_set_enter_handler(&p
, xml_enter
);
2767 my_xml_set_value_handler(&p
, xml_value
);
2768 my_xml_set_leave_handler(&p
, xml_leave
);
2769 my_xml_set_user_data(&p
, (void*) &user_data
);
2772 p
.current_node_type
= MY_XML_NODE_TAG
;
2773 xml_enter(&p
, raw_xml
->ptr(), 0);
2775 /* Execute XML parser */
2776 if ((rc
= my_xml_parse(&p
, raw_xml
->ptr(), raw_xml
->length())) != MY_XML_OK
)
2779 my_snprintf(buf
, sizeof(buf
)-1, "parse error at line %d pos %lu: %s",
2780 my_xml_error_lineno(&p
) + 1,
2781 (ulong
) my_xml_error_pos(&p
) + 1,
2782 my_xml_error_string(&p
));
2783 push_warning_printf(current_thd
, MYSQL_ERROR::WARN_LEVEL_WARN
,
2785 ER(ER_WRONG_VALUE
), "XML", buf
);
2787 my_xml_parser_free(&p
);
2789 return rc
== MY_XML_OK
? parsed_xml_buf
: 0;
2793 String
*Item_func_xml_extractvalue::val_str(String
*str
)
2797 if (!nodeset_func
||
2798 !(res
= args
[0]->val_str(str
)) ||
2799 !parse_xml(res
, &pxml
) ||
2800 !(res
= nodeset_func
->val_str(&tmp_value
)))
2809 String
*Item_func_xml_update::val_str(String
*str
)
2811 String
*res
, *nodeset
, *rep
;
2814 if (!nodeset_func
||
2815 !(res
= args
[0]->val_str(str
)) ||
2816 !(rep
= args
[2]->val_str(&tmp_value3
)) ||
2817 !parse_xml(res
, &pxml
) ||
2818 !(nodeset
= nodeset_func
->val_nodeset(&tmp_value2
)))
2824 MY_XML_NODE
*nodebeg
= (MY_XML_NODE
*) pxml
.ptr();
2825 MY_XPATH_FLT
*fltbeg
= (MY_XPATH_FLT
*) nodeset
->ptr();
2826 MY_XPATH_FLT
*fltend
= (MY_XPATH_FLT
*) (nodeset
->ptr() + nodeset
->length());
2828 /* Allow replacing of one tag only */
2829 if (fltend
- fltbeg
!= 1)
2831 /* TODO: perhaps add a warning that more than one tag selected */
2835 nodebeg
+= fltbeg
->num
;
2837 if (!nodebeg
->level
)
2840 Root element, without NameTest:
2841 UpdateXML(xml, '/', 'replacement');
2842 Just return the replacement string.
2847 tmp_value
.length(0);
2848 tmp_value
.set_charset(collation
.collation
);
2849 uint offs
= nodebeg
->type
== MY_XML_NODE_TAG
? 1 : 0;
2850 tmp_value
.append(res
->ptr(), nodebeg
->beg
- res
->ptr() - offs
);
2851 tmp_value
.append(rep
->ptr(), rep
->length());
2852 const char *end
= nodebeg
->tagend
+ offs
;
2853 tmp_value
.append(end
, res
->ptr() + res
->length() - end
);