mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / sql / item_xmlfunc.cc
blobef2cd8fa2c16922b4b3532aff1f6d35962d5b4ba
1 /*
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
18 #ifdef __GNUC__
19 #pragma implementation
20 #endif
22 #include "mysql_priv.h"
23 #include "my_xml.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:
32 - name()
33 - lang()
34 - string()
35 - id()
36 - translate()
37 - local-name()
38 - starts-with()
39 - namespace-uri()
40 - substring-after()
41 - normalize-space()
42 - substring-before()
43 4. add lacking axis:
44 - following-sibling
45 - following,
46 - preceding-sibling
47 - preceding
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 */
60 } MY_XML_NODE;
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 */
69 } MY_XPATH_LEX;
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 */
78 } MY_XPATH_FLT;
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);
89 } MY_XPATH_FUNC;
92 /* XPath query parser */
93 typedef struct my_xpath_st
95 int debug;
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 */
108 int error;
109 } MY_XPATH;
112 /* Dynamic array of MY_XPATH_FLT */
113 class XPathFilter :public String
115 public:
116 XPathFilter() :String() {}
117 inline bool append_element(MY_XPATH_FLT *flt)
119 String *str= this;
120 return str->append((const char*)flt, (uint32) sizeof(MY_XPATH_FLT));
122 inline bool append_element(uint32 num, uint32 pos)
124 MY_XPATH_FLT add;
125 add.num= num;
126 add.pos= pos;
127 add.size= 0;
128 return append_element(&add);
130 inline bool append_element(uint32 num, uint32 pos, uint32 size)
132 MY_XPATH_FLT add;
133 add.num= num;
134 add.pos= pos;
135 add.size= 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
154 protected:
155 String tmp_value, tmp2_value;
156 MY_XPATH_FLT *fltbeg, *fltend;
157 MY_XML_NODE *nodebeg, *nodeend;
158 uint numnodes;
159 public:
160 String *pxml;
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) {}
169 void prepare_nodes()
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)
177 prepare_nodes();
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());
181 nodeset->length(0);
183 enum Type type() const { return XPATH_NODESET; }
184 String *val_str(String *str)
186 prepare_nodes();
187 String *res= val_nodeset(&tmp2_value);
188 fltbeg= (MY_XPATH_FLT*) res->ptr();
189 fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
190 String active;
191 active.alloc(numnodes);
192 bzero((char*) active.ptr(), numnodes);
193 for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
195 MY_XML_NODE *node;
196 uint j;
197 for (j=0, node= nodebeg ; j < numnodes; j++, node++)
199 if (node->type == MY_XML_NODE_TEXT &&
200 node->parent == flt->num)
201 active[j]= 1;
205 str->length(0);
206 str->set_charset(collation.collation);
207 for (uint i=0 ; i < numnodes; i++)
209 if(active[i])
211 if (str->length())
212 str->append(" ", 1, &my_charset_latin1);
213 str->append(nodebeg[i].beg, nodebeg[i].end - nodebeg[i].beg);
216 return str;
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
231 public:
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
241 public:
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;
253 uint node_namelen;
254 public:
255 Item_nodeset_func_axisbyname(Item *a, const char *n_arg, uint l_arg,
256 String *pxml):
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] == '*')
262 return 1;
263 return (node_namelen == (uint) (n->end - n->beg)) &&
264 !memcmp(node_name, n->beg, node_namelen);
269 /* Returns self */
270 class Item_nodeset_func_selfbyname: public Item_nodeset_func_axisbyname
272 public:
273 Item_nodeset_func_selfbyname(Item *a, const char *n_arg, uint l_arg,
274 String *pxml):
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
284 public:
285 Item_nodeset_func_childbyname(Item *a, const char *n_arg, uint l_arg,
286 String *pxml):
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
296 bool need_self;
297 public:
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
310 bool need_self;
311 public:
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
324 public:
325 Item_nodeset_func_parentbyname(Item *a, const char *n_arg, uint l_arg,
326 String *pxml):
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
336 public:
337 Item_nodeset_func_attributebyname(Item *a, const char *n_arg, uint l_arg,
338 String *pxml):
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
352 public:
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
363 public:
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
377 public:
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
392 String *pxml;
393 String tmp_value;
394 public:
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; }
399 longlong val_int()
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
416 public:
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
428 public:
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
440 String *pxml;
441 String tmp_value;
442 public:
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; }
447 longlong val_int()
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;
452 return 0;
457 class Item_func_xpath_count :public Item_int_func
459 String *pxml;
460 String tmp_value;
461 public:
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; }
466 longlong val_int()
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
480 String *pxml;
481 String tmp_value;
482 public:
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"; }
487 double val_real()
489 double sum= 0;
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)
503 break;
504 if ((node->parent == flt->num) &&
505 (node->type == MY_XML_NODE_TEXT))
507 char *end;
508 int err;
509 double add= my_strntod(collation.collation, (char*) node->beg,
510 node->end - node->beg, &end, &err);
511 if (!err)
512 sum+= add;
516 return sum;
521 class Item_nodeset_to_const_comparator :public Item_bool_func
523 String *pxml;
524 String tmp_nodeset;
525 public:
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; }
532 longlong val_int()
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)
549 break;
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())
556 return 1;
560 return 0;
565 String *Item_nodeset_func_rootelement::val_nodeset(String *nodeset)
567 nodeset->length(0);
568 ((XPathFilter*)nodeset)->append_element(0, 0);
569 return nodeset;
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);
578 String both_str;
579 both_str.alloc(num_nodes);
580 char *both= (char*) both_str.ptr();
581 bzero((void*)both, num_nodes);
582 MY_XPATH_FLT *flt;
584 fltbeg= (MY_XPATH_FLT*) s0->ptr();
585 fltend= (MY_XPATH_FLT*) (s0->ptr() + s0->length());
586 for (flt= fltbeg; flt < fltend; flt++)
587 both[flt->num]= 1;
589 fltbeg= (MY_XPATH_FLT*) s1->ptr();
590 fltend= (MY_XPATH_FLT*) (s1->ptr() + s1->length());
591 for (flt= fltbeg; flt < fltend; flt++)
592 both[flt->num]= 1;
594 nodeset->length(0);
595 for (uint i= 0, pos= 0; i < num_nodes; i++)
597 if (both[i])
598 ((XPathFilter*)nodeset)->append_element(i, pos++);
600 return nodeset;
604 String *Item_nodeset_func_selfbyname::val_nodeset(String *nodeset)
606 prepare(nodeset);
607 for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
609 uint pos= 0;
610 MY_XML_NODE *self= &nodebeg[flt->num];
611 if (validname(self))
612 ((XPathFilter*)nodeset)->append_element(flt->num,pos++);
614 return nodeset;
618 String *Item_nodeset_func_childbyname::val_nodeset(String *nodeset)
620 prepare(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)
628 break;
629 if ((node->parent == flt->num) &&
630 (node->type == MY_XML_NODE_TAG) &&
631 validname(node))
632 ((XPathFilter*)nodeset)->append_element(j, pos++);
635 return nodeset;
639 String *Item_nodeset_func_descendantbyname::val_nodeset(String *nodeset)
641 prepare(nodeset);
642 for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
644 uint pos= 0;
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)
652 break;
653 if ((node->type == MY_XML_NODE_TAG) && validname(node))
654 ((XPathFilter*)nodeset)->append_element(j,pos++);
657 return nodeset;
661 String *Item_nodeset_func_ancestorbyname::val_nodeset(String *nodeset)
663 char *active;
664 String active_str;
665 prepare(nodeset);
666 active_str.alloc(numnodes);
667 active= (char*) active_str.ptr();
668 bzero((void*)active, numnodes);
669 uint pos= 0;
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))
680 active[flt->num]= 1;
681 pos++;
684 for (uint j= self->parent; nodebeg[j].parent != j; j= nodebeg[j].parent)
686 if (flt->num && validname(&nodebeg[j]))
688 active[j]= 1;
689 pos++;
694 for (uint j= 0; j < numnodes ; j++)
696 if (active[j])
697 ((XPathFilter*)nodeset)->append_element(j, --pos);
699 return nodeset;
703 String *Item_nodeset_func_parentbyname::val_nodeset(String *nodeset)
705 char *active;
706 String active_str;
707 prepare(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]))
715 active[j]= 1;
717 for (uint j= 0, pos= 0; j < numnodes ; j++)
719 if (active[j])
720 ((XPathFilter*)nodeset)->append_element(j, pos++);
722 return nodeset;
726 String *Item_nodeset_func_attributebyname::val_nodeset(String *nodeset)
728 prepare(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)
736 break;
737 if ((node->parent == flt->num) &&
738 (node->type == MY_XML_NODE_ATTR) &&
739 validname(node))
740 ((XPathFilter*)nodeset)->append_element(j, pos++);
743 return nodeset;
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];
751 uint pos= 0, size;
752 prepare(str);
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,
758 flt->pos,
759 size);
760 if (comp_func->val_int())
761 ((XPathFilter*)str)->append_element(flt->num, pos++);
763 return str;
767 String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset)
769 Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
770 prepare(nodeset);
771 MY_XPATH_FLT *flt;
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,
777 flt->pos,
778 size);
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++);
783 return nodeset;
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);
795 return item;
800 XPath lexical tokens
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'
837 XPath axis type
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
857 SYNOPSYS
858 Create a comparator function for scalar arguments,
859 for the given arguments and operation.
861 RETURN
862 The newly created item.
864 static Item *eq_func(int oper, Item *a, Item *b)
866 switch (oper)
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);
875 return 0;
880 Create scalar comparator
882 SYNOPSYS
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
888 RETURN
889 The newly created item.
891 static Item *eq_func_reverse(int oper, Item *a, Item *b)
893 switch (oper)
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);
902 return 0;
907 Create a comparator
909 SYNOPSYS
910 Create a comparator for scalar or non-scalar arguments,
911 for the given arguments and operation.
913 RETURN
914 The newly created item.
916 static Item *create_comparator(MY_XPATH *xpath,
917 int oper, MY_XPATH_LEX *context,
918 Item *a, Item *b)
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,
931 "XPATH error: "
932 "comparison of two nodesets is not supported: '%.*s'",
933 MYF(0), len, context->beg);
935 return 0; // TODO: Comparison of two nodesets
937 else
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;
950 Item *scalar, *comp;
951 if (a->type() == Item::XPATH_NODESET)
953 nodeset= (Item_nodeset_func*) a;
954 scalar= b;
955 comp= eq_func(oper, (Item*)fake, scalar);
957 else
959 nodeset= (Item_nodeset_func*) b;
960 scalar= a;
961 comp= eq_func_reverse(oper, fake, scalar);
963 return new Item_nodeset_to_const_comparator(nodeset, comp, xpath->pxml);
969 Create a step
971 SYNOPSYS
972 Create a step function for the given argument and axis.
974 RETURN
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);
985 Item *res;
986 switch (type)
988 case MY_XPATH_AXIS_ANCESTOR:
989 res= new Item_nodeset_func_ancestorbyname(arg, beg, len, xpath->pxml, 0);
990 break;
991 case MY_XPATH_AXIS_ANCESTOR_OR_SELF:
992 res= new Item_nodeset_func_ancestorbyname(arg, beg, len, xpath->pxml, 1);
993 break;
994 case MY_XPATH_AXIS_PARENT:
995 res= new Item_nodeset_func_parentbyname(arg, beg, len, xpath->pxml);
996 break;
997 case MY_XPATH_AXIS_DESCENDANT:
998 res= new Item_nodeset_func_descendantbyname(arg, beg, len, xpath->pxml, 0);
999 break;
1000 case MY_XPATH_AXIS_DESCENDANT_OR_SELF:
1001 res= new Item_nodeset_func_descendantbyname(arg, beg, len, xpath->pxml, 1);
1002 break;
1003 case MY_XPATH_AXIS_ATTRIBUTE:
1004 res= new Item_nodeset_func_attributebyname(arg, beg, len, xpath->pxml);
1005 break;
1006 case MY_XPATH_AXIS_SELF:
1007 res= new Item_nodeset_func_selfbyname(arg, beg, len, xpath->pxml);
1008 break;
1009 default:
1010 res= new Item_nodeset_func_childbyname(arg, beg, len, xpath->pxml);
1012 return res;
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
1034 XPath keywords
1036 struct my_xpath_keyword_names_st
1038 int tok;
1039 const char *name;
1040 size_t length;
1041 int extra;
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 },
1051 {0,NULL,0,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 },
1070 {0,NULL,0,0}
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 },
1080 {0,NULL,0,0}
1085 Lookup a keyword
1087 SYNOPSYS
1088 Check that the last scanned identifier is a keyword.
1090 RETURN
1091 - Token type, on lookup success.
1092 - MY_XPATH_LEX_IDENT, on lookup failure.
1094 static int
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))
1105 x->extra= k->extra;
1106 return k->tok;
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]),
1189 xpath->pxml);
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)
1201 if (nargs == 2)
1202 return new Item_func_substr(args[0], args[1]);
1203 else
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)
1211 return 0;
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)
1219 return 0;
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},
1232 {0 , 0, 0 , 0, 0}
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},
1242 {0 , 0, 0, 0, 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},
1252 {0 , 0, 0, 0, 0}
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},
1261 {0 , 0, 0, 0 , 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},
1284 {NULL,0,0,0,0}
1289 Lookup a function by name
1291 SYNOPSYS
1292 Lookup a function by its name.
1294 RETURN
1295 Pointer to a MY_XPATH_FUNC variable on success.
1296 0 - on failure.
1299 MY_XPATH_FUNC *
1300 my_xpath_function(const char *beg, const char *end)
1302 MY_XPATH_FUNC *k, *function_names;
1303 uint length= end-beg;
1304 switch (length)
1306 case 1: return 0;
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))
1315 return k;
1316 return NULL;
1320 /* Initialize a lex analizer token */
1321 static void
1322 my_xpath_lex_init(MY_XPATH_LEX *lex,
1323 const char *str, const char *strend)
1325 lex->beg= str;
1326 lex->end= strend;
1330 /* Initialize an XPath query parser */
1331 static void
1332 my_xpath_init(MY_XPATH *xpath)
1334 bzero((void*)xpath, sizeof(xpath[0]));
1338 static int
1339 my_xdigit(int c)
1341 return ((c) >= '0' && (c) <= '9');
1346 Scan the next token
1348 SYNOPSYS
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.
1353 RETURN
1356 static void
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
1362 lex->beg= beg;
1364 if (beg >= end)
1366 lex->end= beg;
1367 lex->term= MY_XPATH_LEX_EOF; // end of line reached
1368 return;
1371 // Check ident, or a function call, or a keyword
1372 if ((length= xpath->cs->cset->ctype(xpath->cs, &ctype,
1373 (const uchar*) beg,
1374 (const uchar*) end)) > 0 &&
1375 ((ctype & (_MY_L | _MY_U)) || *beg == '_'))
1377 // scan untill the end of the idenfitier
1378 for (beg+= length;
1379 (length= xpath->cs->cset->ctype(xpath->cs, &ctype,
1380 (const uchar*) beg,
1381 (const uchar*) end)) > 0 &&
1382 ((ctype & (_MY_L | _MY_U | _MY_NMR)) ||
1383 *beg == '_' || *beg == '-' || *beg == '.') ;
1384 beg+= length) /* no op */;
1385 lex->end= beg;
1387 if (beg < end)
1389 if (*beg == '(')
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;
1397 else
1398 lex->term= my_xpath_keyword(xpath, my_nodetype_names,
1399 lex->beg, beg);
1400 return;
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,
1406 lex->beg, beg);
1407 return;
1410 // check if a keyword
1411 lex->term= my_xpath_keyword(xpath, my_keyword_names,
1412 lex->beg, beg);
1413 return;
1417 ch= *beg++;
1419 if (ch > 0 && ch < 128 && simpletok[ch])
1421 // a token consisting of one character found
1422 lex->end= beg;
1423 lex->term= ch;
1424 return;
1428 if (my_xdigit(ch)) // a sequence of digits
1430 for ( ; beg < end && my_xdigit(*beg) ; beg++) ;
1431 lex->end= beg;
1432 lex->term= MY_XPATH_LEX_DIGITS;
1433 return;
1436 if (ch == '"' || ch == '\'') // a string: either '...' or "..."
1438 for ( ; beg < end && *beg != ch ; beg++) ;
1439 if (beg < end)
1441 lex->end= beg+1;
1442 lex->term= MY_XPATH_LEX_STRING;
1443 return;
1445 else
1447 // unexpected end-of-line, without closing quot sign
1448 lex->end= end;
1449 lex->term= MY_XPATH_LEX_ERROR;
1450 return;
1454 lex->end= beg;
1455 lex->term= MY_XPATH_LEX_ERROR; // unknown character
1456 return;
1461 Scan the given token
1463 SYNOPSYS
1464 Scan the given token and rotate lasttok to prevtok on success.
1466 RETURN
1467 1 - success
1468 0 - failure
1470 static int
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);
1478 return 1;
1480 return 0;
1485 Scan AxisName
1487 SYNOPSYS
1488 Scan an axis name and store the scanned axis type into xpath->axis.
1490 RETURN
1491 1 - success
1492 0 - failure
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;
1498 return rc;
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);
1540 Scan LocationPath
1542 SYNOPSYS
1544 [1] LocationPath ::= RelativeLocationPath
1545 | AbsoluteLocationPath
1547 RETURN
1548 1 - success
1549 0 - failure
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;
1562 return rc;
1567 Scan Absolute Location Path
1569 SYNOPSYS
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
1580 RETURN
1581 1 - success
1582 0 - failure
1584 static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH *xpath)
1586 if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
1587 return 0;
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,
1594 "*", 1,
1595 xpath->pxml, 1);
1596 return my_xpath_parse_RelativeLocationPath(xpath);
1599 my_xpath_parse_RelativeLocationPath(xpath);
1601 return (xpath->error == 0);
1606 Scan Relative Location Path
1608 SYNOPSYS
1610 For better performance we combine these two rules
1612 [3] RelativeLocationPath ::= Step
1613 | RelativeLocationPath '/' Step
1614 | AbbreviatedRelativeLocationPath
1615 [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
1618 Into this one:
1620 [3-11] RelativeLocationPath ::= Step
1621 | RelativeLocationPath '/' Step
1622 | RelativeLocationPath '//' Step
1623 RETURN
1624 1 - success
1625 0 - failure
1627 static int my_xpath_parse_RelativeLocationPath(MY_XPATH *xpath)
1629 if (!my_xpath_parse_Step(xpath))
1630 return 0;
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,
1635 "*", 1,
1636 xpath->pxml, 1);
1637 if (!my_xpath_parse_Step(xpath))
1639 xpath->error= 1;
1640 return 0;
1643 return 1;
1648 Scan non-abbreviated or abbreviated Step
1650 SYNOPSYS
1652 [4] Step ::= AxisSpecifier NodeTest Predicate*
1653 | AbbreviatedStep
1654 [8] Predicate ::= '[' PredicateExpr ']'
1656 RETURN
1657 1 - success
1658 0 - failure
1660 static int
1661 my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(MY_XPATH *xpath)
1663 if (!my_xpath_parse_AxisSpecifier(xpath))
1664 return 0;
1666 if (!my_xpath_parse_NodeTest(xpath))
1667 return 0;
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))
1679 xpath->error= 1;
1680 return 0;
1683 if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_RB))
1685 xpath->error= 1;
1686 return 0;
1689 xpath->item= nodeset2bool(xpath, xpath->item);
1691 if (xpath->item->is_bool_func())
1693 xpath->context= new Item_nodeset_func_predicate(prev_context,
1694 xpath->item,
1695 xpath->pxml);
1697 else
1699 xpath->context= new Item_nodeset_func_elementbyindex(prev_context,
1700 xpath->item,
1701 xpath->pxml);
1704 return 1;
1708 static int my_xpath_parse_Step(MY_XPATH *xpath)
1710 return
1711 my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(xpath) ||
1712 my_xpath_parse_AbbreviatedStep(xpath);
1717 Scan Abbreviated Axis Specifier
1719 SYNOPSYS
1720 [5] AxisSpecifier ::= AxisName '::'
1721 | AbbreviatedAxisSpecifier
1723 RETURN
1724 1 - success
1725 0 - failure
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;
1731 else
1732 xpath->axis= MY_XPATH_AXIS_CHILD;
1733 return 1;
1738 Scan non-abbreviated axis specifier
1740 SYNOPSYS
1742 RETURN
1743 1 - success
1744 0 - failure
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
1757 SYNOPSYS
1758 [13] AbbreviatedAxisSpecifier ::= '@'?
1760 RETURN
1761 1 - success
1762 0 - failure
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
1774 SYNOPSYS
1776 RETURN
1777 1 - success
1778 0 - failure
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);
1789 Scan NodeTest
1791 SYNOPSYS
1793 [7] NodeTest ::= NameTest
1794 | NodeType '(' ')'
1795 | 'processing-instruction' '(' Literal ')'
1796 RETURN
1797 1 - success
1798 0 - failure
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
1810 SYNOPSYS
1812 [12] AbbreviatedStep ::= '.' | '..'
1814 RETURN
1815 1 - success
1816 0 - failure
1818 static int my_xpath_parse_AbbreviatedStep(MY_XPATH *xpath)
1820 if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DOT))
1821 return 0;
1822 if (my_xpath_parse_term(xpath, MY_XPATH_LEX_DOT))
1823 xpath->context= new Item_nodeset_func_parentbyname(xpath->context, "*", 1,
1824 xpath->pxml);
1825 return 1;
1830 Scan Primary Expression
1832 SYNOPSYS
1834 [15] PrimaryExpr ::= VariableReference
1835 | '(' Expr ')'
1836 | Literal
1837 | Number
1838 | FunctionCall
1839 RETURN
1840 1 - success
1841 0 - failure
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))
1852 return 0;
1853 xpath->item= new Item_string(xpath->prevtok.beg + 1,
1854 xpath->prevtok.end - xpath->prevtok.beg - 2,
1855 xpath->cs);
1856 return 1;
1858 static int my_xpath_parse_PrimaryExpr(MY_XPATH *xpath)
1860 return
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);
1870 Scan Function Call
1872 SYNOPSYS
1873 [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument )* )? ')'
1874 [17] Argument ::= Expr
1876 RETURN
1877 1 - success
1878 0 - failure
1881 static int my_xpath_parse_FunctionCall(MY_XPATH *xpath)
1883 Item *args[256];
1884 uint nargs;
1886 if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_FUNC))
1887 return 0;
1889 MY_XPATH_FUNC *func= xpath->func;
1891 if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_LP))
1892 return 0;
1894 for (nargs= 0 ; nargs < func->maxargs; )
1896 if (!my_xpath_parse_Expr(xpath))
1898 if (nargs < func->minargs)
1899 return 0;
1900 goto right_paren;
1902 args[nargs++]= xpath->item;
1903 if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_COMMA))
1905 if (nargs < func->minargs)
1906 return 0;
1907 else
1908 break;
1912 right_paren:
1913 if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_RP))
1914 return 0;
1916 return ((xpath->item= func->create(xpath, args, nargs))) ? 1 : 0;
1921 Scan Union Expression
1923 SYNOPSYS
1924 [18] UnionExpr ::= PathExpr
1925 | UnionExpr '|' PathExpr
1927 RETURN
1928 1 - success
1929 0 - failure
1931 static int my_xpath_parse_UnionExpr(MY_XPATH *xpath)
1933 if (!my_xpath_parse_PathExpr(xpath))
1934 return 0;
1936 while (my_xpath_parse_term(xpath, MY_XPATH_LEX_VLINE))
1938 Item *prev= xpath->item;
1939 if (prev->type() != Item::XPATH_NODESET)
1940 return 0;
1942 if (!my_xpath_parse_PathExpr(xpath)
1943 || xpath->item->type() != Item::XPATH_NODESET)
1945 xpath->error= 1;
1946 return 0;
1948 xpath->item= new Item_nodeset_func_union(prev, xpath->item, xpath->pxml);
1950 return 1;
1955 Scan Path Expression
1957 SYNOPSYS
1959 [19] PathExpr ::= LocationPath
1960 | FilterExpr
1961 | FilterExpr '/' RelativeLocationPath
1962 | FilterExpr '//' RelativeLocationPath
1963 RETURN
1964 1 - success
1965 0 - failure
1967 static int
1968 my_xpath_parse_FilterExpr_opt_slashes_RelativeLocationPath(MY_XPATH *xpath)
1970 if (!my_xpath_parse_FilterExpr(xpath))
1971 return 0;
1973 if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
1974 return 1;
1976 if (xpath->item->type() != Item::XPATH_NODESET)
1978 xpath->lasttok= xpath->prevtok;
1979 xpath->error= 1;
1980 return 0;
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
1997 SYNOPSYS
1998 [20] FilterExpr ::= PrimaryExpr
1999 | FilterExpr Predicate
2001 or in other words:
2003 [20] FilterExpr ::= PrimaryExpr Predicate*
2005 RETURN
2006 1 - success
2007 0 - failure
2010 static int my_xpath_parse_FilterExpr(MY_XPATH *xpath)
2012 return my_xpath_parse_PrimaryExpr(xpath);
2017 Scan Or Expression
2019 SYNOPSYS
2020 [21] OrExpr ::= AndExpr
2021 | OrExpr 'or' AndExpr
2023 RETURN
2024 1 - success
2025 0 - failure
2027 static int my_xpath_parse_OrExpr(MY_XPATH *xpath)
2029 if (!my_xpath_parse_AndExpr(xpath))
2030 return 0;
2032 while (my_xpath_parse_term(xpath, MY_XPATH_LEX_OR))
2034 Item *prev= xpath->item;
2035 if (!my_xpath_parse_AndExpr(xpath))
2037 return 0;
2038 xpath->error= 1;
2040 xpath->item= new Item_cond_or(nodeset2bool(xpath, prev),
2041 nodeset2bool(xpath, xpath->item));
2043 return 1;
2048 Scan And Expression
2050 SYNOPSYS
2051 [22] AndExpr ::= EqualityExpr
2052 | AndExpr 'and' EqualityExpr
2054 RETURN
2055 1 - success
2056 0 - failure
2058 static int my_xpath_parse_AndExpr(MY_XPATH *xpath)
2060 if (!my_xpath_parse_EqualityExpr(xpath))
2061 return 0;
2063 while (my_xpath_parse_term(xpath, MY_XPATH_LEX_AND))
2065 Item *prev= xpath->item;
2066 if (!my_xpath_parse_EqualityExpr(xpath))
2068 xpath->error= 1;
2069 return 0;
2072 xpath->item= new Item_cond_and(nodeset2bool(xpath,prev),
2073 nodeset2bool(xpath,xpath->item));
2075 return 1;
2080 Scan Equality Expression
2082 SYNOPSYS
2083 [23] EqualityExpr ::= RelationalExpr
2084 | EqualityExpr '=' RelationalExpr
2085 | EqualityExpr '!=' RelationalExpr
2086 or in other words:
2088 [23] EqualityExpr ::= RelationalExpr ( EqualityOperator EqualityExpr )*
2090 RETURN
2091 1 - success
2092 0 - failure
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))
2098 return 0;
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;
2104 return 0;
2106 return 1;
2108 static int my_xpath_parse_EqualityOperator(MY_XPATH *xpath)
2110 if (my_xpath_parse_ne(xpath))
2112 xpath->extra= '!';
2113 return 1;
2115 if (my_xpath_parse_term(xpath, MY_XPATH_LEX_EQ))
2117 xpath->extra= '=';
2118 return 1;
2120 return 0;
2122 static int my_xpath_parse_EqualityExpr(MY_XPATH *xpath)
2124 MY_XPATH_LEX operator_context;
2125 if (!my_xpath_parse_RelationalExpr(xpath))
2126 return 0;
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))
2135 xpath->error= 1;
2136 return 0;
2139 if (!(xpath->item= create_comparator(xpath, oper, &operator_context,
2140 prev, xpath->item)))
2141 return 0;
2143 operator_context= xpath->lasttok;
2145 return 1;
2150 Scan Relational Expression
2152 SYNOPSYS
2154 [24] RelationalExpr ::= AdditiveExpr
2155 | RelationalExpr '<' AdditiveExpr
2156 | RelationalExpr '>' AdditiveExpr
2157 | RelationalExpr '<=' AdditiveExpr
2158 | RelationalExpr '>=' AdditiveExpr
2159 or in other words:
2161 [24] RelationalExpr ::= AdditiveExpr (RelationalOperator RelationalExpr)*
2163 RETURN
2164 1 - success
2165 0 - failure
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;
2173 return 1;
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;
2179 return 1;
2181 return 0;
2183 static int my_xpath_parse_RelationalExpr(MY_XPATH *xpath)
2185 MY_XPATH_LEX operator_context;
2186 if (!my_xpath_parse_AdditiveExpr(xpath))
2187 return 0;
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))
2196 xpath->error= 1;
2197 return 0;
2200 if (!(xpath->item= create_comparator(xpath, oper, &operator_context,
2201 prev, xpath->item)))
2202 return 0;
2203 operator_context= xpath->lasttok;
2205 return 1;
2210 Scan Additive Expression
2212 SYNOPSYS
2214 [25] AdditiveExpr ::= MultiplicativeExpr
2215 | AdditiveExpr '+' MultiplicativeExpr
2216 | AdditiveExpr '-' MultiplicativeExpr
2217 RETURN
2218 1 - success
2219 0 - failure
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))
2229 return 0;
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))
2237 xpath->error= 1;
2238 return 0;
2241 if (oper == MY_XPATH_LEX_PLUS)
2242 xpath->item= new Item_func_plus(prev, xpath->item);
2243 else
2244 xpath->item= new Item_func_minus(prev, xpath->item);
2246 return 1;
2251 Scan Multiplicative Expression
2253 SYNOPSYS
2255 [26] MultiplicativeExpr ::= UnaryExpr
2256 | MultiplicativeExpr MultiplyOperator UnaryExpr
2257 | MultiplicativeExpr 'div' UnaryExpr
2258 | MultiplicativeExpr 'mod' UnaryExpr
2259 or in other words:
2261 [26] MultiplicativeExpr ::= UnaryExpr (MulOper MultiplicativeExpr)*
2263 RETURN
2264 1 - success
2265 0 - failure
2267 static int my_xpath_parse_MultiplicativeOperator(MY_XPATH *xpath)
2269 return
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))
2277 return 0;
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))
2285 xpath->error= 1;
2286 return 0;
2288 switch (oper)
2290 case MY_XPATH_LEX_ASTERISK:
2291 xpath->item= new Item_func_mul(prev, xpath->item);
2292 break;
2293 case MY_XPATH_LEX_DIV:
2294 xpath->item= new Item_func_int_div(prev, xpath->item);
2295 break;
2296 case MY_XPATH_LEX_MOD:
2297 xpath->item= new Item_func_mod(prev, xpath->item);
2298 break;
2301 return 1;
2306 Scan Unary Expression
2308 SYNOPSYS
2310 [27] UnaryExpr ::= UnionExpr
2311 | '-' UnaryExpr
2312 RETURN
2313 1 - success
2314 0 - failure
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))
2321 return 0;
2322 xpath->item= new Item_func_neg(xpath->item);
2323 return 1;
2328 Scan Number
2330 SYNOPSYS
2332 [30] Number ::= Digits ('.' Digits?)? | '.' Digits)
2334 or in other words:
2336 [30] Number ::= Digits
2337 | Digits '.'
2338 | Digits '.' Digits
2339 | '.' 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,
2344 1 + 0.123 does.
2345 Perhaps it is better to move this code into lex analizer.
2347 RETURN
2348 1 - success
2349 0 - failure
2351 static int my_xpath_parse_Number(MY_XPATH *xpath)
2353 const char *beg;
2354 if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DIGITS))
2355 return 0;
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);
2361 return 1;
2363 my_xpath_parse_term(xpath, MY_XPATH_LEX_DIGITS);
2365 xpath->item= new Item_float(beg, xpath->prevtok.end - beg);
2366 return 1;
2371 Scan NCName.
2373 SYNOPSYS
2375 The keywords AND, OR, MOD, DIV are valid identitiers
2376 when they are in identifier context:
2378 SELECT
2379 ExtractValue('<and><or><mod><div>VALUE</div></mod></or></and>',
2380 '/and/or/mod/div')
2381 -> VALUE
2383 RETURN
2384 1 - success
2385 0 - failure
2388 static int
2389 my_xpath_parse_NCName(MY_XPATH *xpath)
2391 return
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
2409 static int
2410 my_xpath_parse_QName(MY_XPATH *xpath)
2412 const char *beg;
2413 if (!my_xpath_parse_NCName(xpath))
2414 return 0;
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))
2419 return 0;
2420 xpath->prevtok.beg= beg;
2421 return 1;
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
2448 @retval 1 Success
2449 @retval 0 Failure
2452 static int
2453 my_xpath_parse_VariableReference(MY_XPATH *xpath)
2455 LEX_STRING name;
2456 int user_var;
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)))
2463 return 0;
2465 name.length= xpath->prevtok.end - xpath->prevtok.beg;
2466 name.str= (char*) xpath->prevtok.beg;
2468 if (user_var)
2469 xpath->item= new Item_func_get_user_var(name);
2470 else
2472 sp_variable_t *spv;
2473 sp_pcontext *spc;
2474 LEX *lex;
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);
2480 #ifndef DBUG_OFF
2481 if (splocal)
2482 splocal->m_sp= lex->sphead;
2483 #endif
2484 xpath->item= (Item*) splocal;
2486 else
2488 xpath->item= NULL;
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;
2501 Scan Name Test
2503 SYNOPSYS
2505 [37] NameTest ::= '*'
2506 | NCName ':' '*'
2507 | QName
2508 RETURN
2509 1 - success
2510 0 - failure
2512 static int
2513 my_xpath_parse_NodeTest_QName(MY_XPATH *xpath)
2515 if (!my_xpath_parse_QName(xpath))
2516 return 0;
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);
2521 return 1;
2523 static int
2524 my_xpath_parse_NodeTest_asterisk(MY_XPATH *xpath)
2526 if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_ASTERISK))
2527 return 0;
2528 DBUG_ASSERT(xpath->context);
2529 xpath->context= nametestfunc(xpath, xpath->axis, xpath->context, "*", 1);
2530 return 1;
2532 static int
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
2543 SYNOPSYS
2544 Scan xpath expression.
2545 The expression is returned in xpath->expr.
2547 RETURN
2548 1 - success
2549 0 - failure
2551 static int
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);
2560 return
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()
2568 String *xp, tmp;
2569 MY_XPATH xpath;
2570 int rc;
2572 nodeset_func= 0;
2574 if (agg_arg_charsets(collation, args, arg_count, MY_COLL_CMP_CONV, 1))
2575 return;
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);
2583 return;
2586 if (!args[1]->const_item())
2588 my_printf_error(ER_UNKNOWN_ERROR,
2589 "Only constant XPATH queries are supported", MYF(0));
2590 return;
2593 if (!(xp= args[1]->val_str(&tmp)))
2594 return;
2595 my_xpath_init(&xpath);
2596 xpath.cs= collation.collation;
2597 xpath.debug= 0;
2598 xpath.pxml= &pxml;
2599 pxml.set_charset(collation.collation);
2601 rc= my_xpath_parse(&xpath, xp->ptr(), xp->ptr() + xp->length());
2603 if (!rc)
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);
2609 return;
2612 nodeset_func= xpath.item;
2613 if (nodeset_func)
2614 nodeset_func->fix_fields(current_thd, &nodeset_func);
2615 max_length= MAX_BLOB_WIDTH;
2619 #define MAX_LEVEL 256
2620 typedef struct
2622 uint level;
2623 String *pxml; // parsed XML
2624 uint pos[MAX_LEVEL]; // Tag position stack
2625 uint parent; // Offset of the parent of the current node
2626 } MY_XML_USER_DATA;
2629 static bool
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))
2643 return TRUE;
2644 str->q_append((const char*) node, sizeof(MY_XML_NODE));
2645 return FALSE;
2650 Process tag beginning
2652 SYNOPSYS
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.
2659 RETURN
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);
2668 MY_XML_NODE 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++;
2676 else
2677 return MY_XML_ERROR;
2678 node.type= st->current_node_type; // TAG or ATTR
2679 node.beg= attr;
2680 node.end= attr + len;
2681 return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK;
2686 Process text node
2688 SYNOPSYS
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.
2694 RETURN
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;
2702 MY_XML_NODE node;
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;
2707 node.beg= attr;
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
2716 SYNOPSYS
2718 A call-back function executed when XML parser
2719 is leaving a tag or an attribue.
2720 Decrements data->level.
2722 RETURN
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);
2731 data->level--;
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;
2738 return MY_XML_OK;
2743 Parse raw XML
2745 SYNOPSYS
2748 RETURN
2749 Currently pointer to parsed XML on success
2750 0 on parse error
2752 String *Item_xml_str_func::parse_xml(String *raw_xml, String *parsed_xml_buf)
2754 MY_XML_PARSER p;
2755 MY_XML_USER_DATA user_data;
2756 int rc;
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;
2763 user_data.level= 0;
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);
2771 /* Add root node */
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)
2778 char buf[128];
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,
2784 ER_WRONG_VALUE,
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)
2795 String *res;
2796 null_value= 0;
2797 if (!nodeset_func ||
2798 !(res= args[0]->val_str(str)) ||
2799 !parse_xml(res, &pxml) ||
2800 !(res= nodeset_func->val_str(&tmp_value)))
2802 null_value= 1;
2803 return 0;
2805 return res;
2809 String *Item_func_xml_update::val_str(String *str)
2811 String *res, *nodeset, *rep;
2813 null_value= 0;
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)))
2820 null_value= 1;
2821 return 0;
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 */
2832 return res;
2835 nodebeg+= fltbeg->num;
2837 if (!nodebeg->level)
2840 Root element, without NameTest:
2841 UpdateXML(xml, '/', 'replacement');
2842 Just return the replacement string.
2844 return rep;
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);
2854 return &tmp_value;