MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
item_xmlfunc.cc
1 /* Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
2 
3  This program is free software; you can redistribute it and/or modify
4  it under the terms of the GNU General Public License as published by
5  the Free Software Foundation; version 2 of the License.
6 
7  This program is distributed in the hope that it will be useful,
8  but WITHOUT ANY WARRANTY; without even the implied warranty of
9  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  GNU General Public License for more details.
11 
12  You should have received a copy of the GNU General Public License
13  along with this program; if not, write to the Free Software
14  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
15 
16 #include "sql_priv.h"
17 /*
18  It is necessary to include set_var.h instead of item.h because there
19  are dependencies on include order for set_var.h and item.h. This
20  will be resolved later.
21 */
22 #include "sql_class.h" // set_var.h: THD
23 #include "set_var.h"
24 #include "my_xml.h"
25 #include "sp_pcontext.h"
26 #include "sql_class.h" // THD
27 
28 /*
29  TODO: future development directions:
30  1. add real constants for XPATH_NODESET_CMP and XPATH_NODESET
31  into enum Type in item.h.
32  2. add nodeset_to_nodeset_comparator
33  3. add lacking functions:
34  - name()
35  - lang()
36  - string()
37  - id()
38  - translate()
39  - local-name()
40  - starts-with()
41  - namespace-uri()
42  - substring-after()
43  - normalize-space()
44  - substring-before()
45  4. add lacking axis:
46  - following-sibling
47  - following,
48  - preceding-sibling
49  - preceding
50 */
51 
52 
53 /* Structure to store a parsed XML tree */
54 typedef struct my_xml_node_st
55 {
56  uint level; /* level in XML tree, 0 means root node */
57  enum my_xml_node_type type; /* node type: node, or attribute, or text */
58  uint parent; /* link to the parent */
59  const char *beg; /* beginning of the name or text */
60  const char *end; /* end of the name or text */
61  const char *tagend; /* where this tag ends */
62 } MY_XML_NODE;
63 
64 
65 /* Lexical analizer token */
66 typedef struct my_xpath_lex_st
67 {
68  int term; /* token type, see MY_XPATH_LEX_XXXXX below */
69  const char *beg; /* beginnign of the token */
70  const char *end; /* end of the token */
71 } MY_XPATH_LEX;
72 
73 
74 /* Structure to store nodesets */
75 typedef struct my_xpath_flt_st
76 {
77  uint num; /* absolute position in MY_XML_NODE array */
78  uint pos; /* relative position in context */
79  uint size; /* context size */
80 } MY_XPATH_FLT;
81 
82 
83 /* XPath function creator */
85 {
86  const char *name; /* function name */
87  size_t length; /* function name length */
88  size_t minargs; /* min number of arguments */
89  size_t maxargs; /* max number of arguments */
90  Item *(*create)(struct my_xpath_st *xpath, Item **args, uint nargs);
92 
93 
94 /* XPath query parser */
95 typedef struct my_xpath_st
96 {
97  int debug;
98  MY_XPATH_LEX query; /* Whole query */
99  MY_XPATH_LEX lasttok; /* last scanned token */
100  MY_XPATH_LEX prevtok; /* previous scanned token */
101  int axis; /* last scanned axis */
102  int extra; /* last scanned "extra", context dependent */
103  MY_XPATH_FUNC *func; /* last scanned function creator */
104  Item *item; /* current expression */
105  Item *context; /* last scanned context */
106  Item *rootelement; /* The root element */
107  String *context_cache; /* last context provider */
108  String *pxml; /* Parsed XML, an array of MY_XML_NODE */
109  const CHARSET_INFO *cs;/* character set/collation string comparison */
110  int error;
111 } MY_XPATH;
112 
113 
114 /* Dynamic array of MY_XPATH_FLT */
115 class XPathFilter :public String
116 {
117 public:
118  XPathFilter() :String() {}
119  inline bool append_element(MY_XPATH_FLT *flt)
120  {
121  String *str= this;
122  return str->append((const char*)flt, (uint32) sizeof(MY_XPATH_FLT));
123  }
124  inline bool append_element(uint32 num, uint32 pos)
125  {
126  MY_XPATH_FLT add;
127  add.num= num;
128  add.pos= pos;
129  add.size= 0;
130  return append_element(&add);
131  }
132  inline bool append_element(uint32 num, uint32 pos, uint32 size)
133  {
134  MY_XPATH_FLT add;
135  add.num= num;
136  add.pos= pos;
137  add.size= size;
138  return append_element(&add);
139  }
140  inline MY_XPATH_FLT *element(uint i)
141  {
142  return (MY_XPATH_FLT*) (ptr() + i * sizeof(MY_XPATH_FLT));
143  }
144  inline uint32 numelements()
145  {
146  return length() / sizeof(MY_XPATH_FLT);
147  }
148 };
149 
150 
151 /*
152  Common features of the functions returning a node set.
153 */
155 {
156 protected:
157  String tmp_value, tmp2_value;
158  MY_XPATH_FLT *fltbeg, *fltend;
159  MY_XML_NODE *nodebeg, *nodeend;
160  uint numnodes;
161 public:
162  String *pxml;
163  String context_cache;
164  Item_nodeset_func(String *pxml_arg) :Item_str_func(), pxml(pxml_arg) {}
165  Item_nodeset_func(Item *a, String *pxml_arg)
166  :Item_str_func(a), pxml(pxml_arg) {}
167  Item_nodeset_func(Item *a, Item *b, String *pxml_arg)
168  :Item_str_func(a, b), pxml(pxml_arg) {}
169  Item_nodeset_func(Item *a, Item *b, Item *c, String *pxml_arg)
170  :Item_str_func(a,b,c), pxml(pxml_arg) {}
171  void prepare_nodes()
172  {
173  nodebeg= (MY_XML_NODE*) pxml->ptr();
174  nodeend= (MY_XML_NODE*) (pxml->ptr() + pxml->length());
175  numnodes= nodeend - nodebeg;
176  }
177  void prepare(String *nodeset)
178  {
179  prepare_nodes();
180  String *res= args[0]->val_nodeset(&tmp_value);
181  fltbeg= (MY_XPATH_FLT*) res->ptr();
182  fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
183  nodeset->length(0);
184  }
185  enum Type type() const { return XPATH_NODESET; }
186  String *val_str(String *str)
187  {
188  prepare_nodes();
189  String *res= val_nodeset(&tmp2_value);
190  fltbeg= (MY_XPATH_FLT*) res->ptr();
191  fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
192  String active;
193  active.alloc(numnodes);
194  memset(const_cast<char*>(active.ptr()), 0, numnodes);
195  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
196  {
197  MY_XML_NODE *node;
198  uint j;
199  for (j=0, node= nodebeg ; j < numnodes; j++, node++)
200  {
201  if (node->type == MY_XML_NODE_TEXT &&
202  node->parent == flt->num)
203  active[j]= 1;
204  }
205  }
206 
207  str->length(0);
208  str->set_charset(collation.collation);
209  for (uint i=0 ; i < numnodes; i++)
210  {
211  if(active[i])
212  {
213  if (str->length())
214  str->append(" ", 1, &my_charset_latin1);
215  str->append(nodebeg[i].beg, nodebeg[i].end - nodebeg[i].beg);
216  }
217  }
218  return str;
219  }
220  enum Item_result result_type () const { return STRING_RESULT; }
221  void fix_length_and_dec()
222  {
223  max_length= MAX_BLOB_WIDTH;
224  collation.collation= pxml->charset();
225  }
226  const char *func_name() const { return "nodeset"; }
227 };
228 
229 
230 /* Returns an XML root */
232 {
233 public:
235  const char *func_name() const { return "xpath_rootelement"; }
236  String *val_nodeset(String *nodeset);
237 };
238 
239 
240 /* Returns a Union of two node sets */
242 {
243 public:
244  Item_nodeset_func_union(Item *a, Item *b, String *pxml)
245  :Item_nodeset_func(a, b, pxml) {}
246  const char *func_name() const { return "xpath_union"; }
247  String *val_nodeset(String *nodeset);
248 };
249 
250 
251 /* Makes one step towards the given axis */
253 {
254  const char *node_name;
255  uint node_namelen;
256 public:
257  Item_nodeset_func_axisbyname(Item *a, const char *n_arg, uint l_arg,
258  String *pxml):
259  Item_nodeset_func(a, pxml), node_name(n_arg), node_namelen(l_arg) { }
260  const char *func_name() const { return "xpath_axisbyname"; }
261  bool validname(MY_XML_NODE *n)
262  {
263  if (node_name[0] == '*')
264  return 1;
265  return (node_namelen == (uint) (n->end - n->beg)) &&
266  !memcmp(node_name, n->beg, node_namelen);
267  }
268 };
269 
270 
271 /* Returns self */
273 {
274 public:
275  Item_nodeset_func_selfbyname(Item *a, const char *n_arg, uint l_arg,
276  String *pxml):
277  Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml) {}
278  const char *func_name() const { return "xpath_selfbyname"; }
279  String *val_nodeset(String *nodeset);
280 };
281 
282 
283 /* Returns children */
285 {
286 public:
287  Item_nodeset_func_childbyname(Item *a, const char *n_arg, uint l_arg,
288  String *pxml):
289  Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml) {}
290  const char *func_name() const { return "xpath_childbyname"; }
291  String *val_nodeset(String *nodeset);
292 };
293 
294 
295 /* Returns descendants */
297 {
298  bool need_self;
299 public:
300  Item_nodeset_func_descendantbyname(Item *a, const char *n_arg, uint l_arg,
301  String *pxml, bool need_self_arg):
302  Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml),
303  need_self(need_self_arg) {}
304  const char *func_name() const { return "xpath_descendantbyname"; }
305  String *val_nodeset(String *nodeset);
306 };
307 
308 
309 /* Returns ancestors */
311 {
312  bool need_self;
313 public:
314  Item_nodeset_func_ancestorbyname(Item *a, const char *n_arg, uint l_arg,
315  String *pxml, bool need_self_arg):
316  Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml),
317  need_self(need_self_arg) {}
318  const char *func_name() const { return "xpath_ancestorbyname"; }
319  String *val_nodeset(String *nodeset);
320 };
321 
322 
323 /* Returns parents */
325 {
326 public:
327  Item_nodeset_func_parentbyname(Item *a, const char *n_arg, uint l_arg,
328  String *pxml):
329  Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml) {}
330  const char *func_name() const { return "xpath_parentbyname"; }
331  String *val_nodeset(String *nodeset);
332 };
333 
334 
335 /* Returns attributes */
337 {
338 public:
339  Item_nodeset_func_attributebyname(Item *a, const char *n_arg, uint l_arg,
340  String *pxml):
341  Item_nodeset_func_axisbyname(a, n_arg, l_arg, pxml) {}
342  const char *func_name() const { return "xpath_attributebyname"; }
343  String *val_nodeset(String *nodeset);
344 };
345 
346 
347 /*
348  Condition iterator: goes through all nodes in the current
349  context and checks a condition, returning those nodes
350  giving TRUE condition result.
351 */
353 {
354 public:
356  Item_nodeset_func(a, b, pxml) {}
357  const char *func_name() const { return "xpath_predicate"; }
358  String *val_nodeset(String *nodeset);
359 };
360 
361 
362 /* Selects nodes with a given position in context */
364 {
365 public:
367  Item_nodeset_func(a, b, pxml) { }
368  const char *func_name() const { return "xpath_elementbyindex"; }
369  String *val_nodeset(String *nodeset);
370 };
371 
372 
373 /*
374  We need to distinguish a number from a boolean:
375  a[1] and a[true] are different things in XPath.
376 */
377 class Item_bool :public Item_int
378 {
379 public:
380  Item_bool(int32 i): Item_int(i) {}
381  const char *func_name() const { return "xpath_bool"; }
382  bool is_bool_func() { return 1; }
383 };
384 
385 
386 /*
387  Converts its argument into a boolean value.
388  * a number is true if it is non-zero
389  * a node-set is true if and only if it is non-empty
390  * a string is true if and only if its length is non-zero
391 */
393 {
394  String *pxml;
395  String tmp_value;
396 public:
397  Item_xpath_cast_bool(Item *a, String *pxml_arg)
398  :Item_int_func(a), pxml(pxml_arg) {}
399  const char *func_name() const { return "xpath_cast_bool"; }
400  bool is_bool_func() { return 1; }
401  longlong val_int()
402  {
403  if (args[0]->type() == XPATH_NODESET)
404  {
405  String *flt= args[0]->val_nodeset(&tmp_value);
406  return flt->length() == sizeof(MY_XPATH_FLT) ? 1 : 0;
407  }
408  return args[0]->val_real() ? 1 : 0;
409  }
410 };
411 
412 
413 /*
414  Converts its argument into a number
415 */
417 {
418 public:
420  const char *func_name() const { return "xpath_cast_number"; }
421  virtual double val_real() { return args[0]->val_real(); }
422 };
423 
424 
425 /*
426  Context cache, for predicate
427 */
429 {
430 public:
431  String *string_cache;
432  Item_nodeset_context_cache(String *str_arg, String *pxml):
433  Item_nodeset_func(pxml), string_cache(str_arg) { }
434  String *val_nodeset(String *res)
435  { return string_cache; }
436  void fix_length_and_dec() { max_length= MAX_BLOB_WIDTH; }
437 };
438 
439 
441 {
442  String *pxml;
443  String tmp_value;
444 public:
446  :Item_int_func(a), pxml(p) {}
447  const char *func_name() const { return "xpath_position"; }
448  void fix_length_and_dec() { max_length=10; }
449  longlong val_int()
450  {
451  String *flt= args[0]->val_nodeset(&tmp_value);
452  if (flt->length() == sizeof(MY_XPATH_FLT))
453  return ((MY_XPATH_FLT*)flt->ptr())->pos + 1;
454  return 0;
455  }
456 };
457 
458 
460 {
461  String *pxml;
462  String tmp_value;
463 public:
465  :Item_int_func(a), pxml(p) {}
466  const char *func_name() const { return "xpath_count"; }
467  void fix_length_and_dec() { max_length=10; }
468  longlong val_int()
469  {
470  uint predicate_supplied_context_size;
471  String *res= args[0]->val_nodeset(&tmp_value);
472  if (res->length() == sizeof(MY_XPATH_FLT) &&
473  (predicate_supplied_context_size= ((MY_XPATH_FLT*)res->ptr())->size))
474  return predicate_supplied_context_size;
475  return res->length() / sizeof(MY_XPATH_FLT);
476  }
477 };
478 
479 
481 {
482  String *pxml;
483  String tmp_value;
484 public:
486  :Item_real_func(a), pxml(p) {}
487 
488  const char *func_name() const { return "xpath_sum"; }
489  double val_real()
490  {
491  double sum= 0;
492  String *res= args[0]->val_nodeset(&tmp_value);
493  MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr();
494  MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
495  uint numnodes= pxml->length() / sizeof(MY_XML_NODE);
496  MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml->ptr();
497 
498  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
499  {
500  MY_XML_NODE *self= &nodebeg[flt->num];
501  for (uint j= flt->num + 1; j < numnodes; j++)
502  {
503  MY_XML_NODE *node= &nodebeg[j];
504  if (node->level <= self->level)
505  break;
506  if ((node->parent == flt->num) &&
507  (node->type == MY_XML_NODE_TEXT))
508  {
509  char *end;
510  int err;
511  double add= my_strntod(collation.collation, (char*) node->beg,
512  node->end - node->beg, &end, &err);
513  if (!err)
514  sum+= add;
515  }
516  }
517  }
518  return sum;
519  }
520 };
521 
522 
524 {
525  String *pxml;
526  String tmp_nodeset;
527 public:
528  Item_nodeset_to_const_comparator(Item *nodeset, Item *cmpfunc, String *p)
529  :Item_bool_func(nodeset,cmpfunc), pxml(p) {}
530  enum Type type() const { return XPATH_NODESET_CMP; };
531  const char *func_name() const { return "xpath_nodeset_to_const_comparator"; }
532  bool is_bool_func() { return 1; }
533 
534  longlong val_int()
535  {
536  Item_func *comp= (Item_func*)args[1];
537  Item_string *fake= (Item_string*)(comp->arguments()[0]);
538  String *res= args[0]->val_nodeset(&tmp_nodeset);
539  MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) res->ptr();
540  MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (res->ptr() + res->length());
541  MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml->ptr();
542  uint numnodes= pxml->length() / sizeof(MY_XML_NODE);
543 
544  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
545  {
546  MY_XML_NODE *self= &nodebeg[flt->num];
547  for (uint j= flt->num + 1; j < numnodes; j++)
548  {
549  MY_XML_NODE *node= &nodebeg[j];
550  if (node->level <= self->level)
551  break;
552  if ((node->parent == flt->num) &&
553  (node->type == MY_XML_NODE_TEXT))
554  {
555  fake->str_value.set(node->beg, node->end - node->beg,
556  collation.collation);
557  if (args[1]->val_int())
558  return 1;
559  }
560  }
561  }
562  return 0;
563  }
564 };
565 
566 
567 String *Item_nodeset_func_rootelement::val_nodeset(String *nodeset)
568 {
569  nodeset->length(0);
570  ((XPathFilter*)nodeset)->append_element(0, 0);
571  return nodeset;
572 }
573 
574 
575 String * Item_nodeset_func_union::val_nodeset(String *nodeset)
576 {
577  uint num_nodes= pxml->length() / sizeof(MY_XML_NODE);
578  String set0, *s0= args[0]->val_nodeset(&set0);
579  String set1, *s1= args[1]->val_nodeset(&set1);
580  String both_str;
581  both_str.alloc(num_nodes);
582  char *both= (char*) both_str.ptr();
583  memset(both, 0, num_nodes);
584  MY_XPATH_FLT *flt;
585 
586  fltbeg= (MY_XPATH_FLT*) s0->ptr();
587  fltend= (MY_XPATH_FLT*) (s0->ptr() + s0->length());
588  for (flt= fltbeg; flt < fltend; flt++)
589  both[flt->num]= 1;
590 
591  fltbeg= (MY_XPATH_FLT*) s1->ptr();
592  fltend= (MY_XPATH_FLT*) (s1->ptr() + s1->length());
593  for (flt= fltbeg; flt < fltend; flt++)
594  both[flt->num]= 1;
595 
596  nodeset->length(0);
597  for (uint i= 0, pos= 0; i < num_nodes; i++)
598  {
599  if (both[i])
600  ((XPathFilter*)nodeset)->append_element(i, pos++);
601  }
602  return nodeset;
603 }
604 
605 
606 String *Item_nodeset_func_selfbyname::val_nodeset(String *nodeset)
607 {
608  prepare(nodeset);
609  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
610  {
611  uint pos= 0;
612  MY_XML_NODE *self= &nodebeg[flt->num];
613  if (validname(self))
614  ((XPathFilter*)nodeset)->append_element(flt->num,pos++);
615  }
616  return nodeset;
617 }
618 
619 
620 String *Item_nodeset_func_childbyname::val_nodeset(String *nodeset)
621 {
622  prepare(nodeset);
623  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
624  {
625  MY_XML_NODE *self= &nodebeg[flt->num];
626  for (uint pos= 0, j= flt->num + 1 ; j < numnodes; j++)
627  {
628  MY_XML_NODE *node= &nodebeg[j];
629  if (node->level <= self->level)
630  break;
631  if ((node->parent == flt->num) &&
632  (node->type == MY_XML_NODE_TAG) &&
633  validname(node))
634  ((XPathFilter*)nodeset)->append_element(j, pos++);
635  }
636  }
637  return nodeset;
638 }
639 
640 
641 String *Item_nodeset_func_descendantbyname::val_nodeset(String *nodeset)
642 {
643  prepare(nodeset);
644  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
645  {
646  uint pos= 0;
647  MY_XML_NODE *self= &nodebeg[flt->num];
648  if (need_self && validname(self))
649  ((XPathFilter*)nodeset)->append_element(flt->num,pos++);
650  for (uint j= flt->num + 1 ; j < numnodes ; j++)
651  {
652  MY_XML_NODE *node= &nodebeg[j];
653  if (node->level <= self->level)
654  break;
655  if ((node->type == MY_XML_NODE_TAG) && validname(node))
656  ((XPathFilter*)nodeset)->append_element(j,pos++);
657  }
658  }
659  return nodeset;
660 }
661 
662 
663 String *Item_nodeset_func_ancestorbyname::val_nodeset(String *nodeset)
664 {
665  char *active;
666  String active_str;
667  prepare(nodeset);
668  active_str.alloc(numnodes);
669  active= (char*) active_str.ptr();
670  memset(active, 0, numnodes);
671  uint pos= 0;
672 
673  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
674  {
675  /*
676  Go to the root and add all nodes on the way.
677  Don't add the root if context is the root itelf
678  */
679  MY_XML_NODE *self= &nodebeg[flt->num];
680  if (need_self && validname(self))
681  {
682  active[flt->num]= 1;
683  pos++;
684  }
685 
686  for (uint j= self->parent; nodebeg[j].parent != j; j= nodebeg[j].parent)
687  {
688  if (flt->num && validname(&nodebeg[j]))
689  {
690  active[j]= 1;
691  pos++;
692  }
693  }
694  }
695 
696  for (uint j= 0; j < numnodes ; j++)
697  {
698  if (active[j])
699  ((XPathFilter*)nodeset)->append_element(j, --pos);
700  }
701  return nodeset;
702 }
703 
704 
705 String *Item_nodeset_func_parentbyname::val_nodeset(String *nodeset)
706 {
707  char *active;
708  String active_str;
709  prepare(nodeset);
710  active_str.alloc(numnodes);
711  active= (char*) active_str.ptr();
712  memset(active, 0, numnodes);
713  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
714  {
715  uint j= nodebeg[flt->num].parent;
716  if (flt->num && validname(&nodebeg[j]))
717  active[j]= 1;
718  }
719  for (uint j= 0, pos= 0; j < numnodes ; j++)
720  {
721  if (active[j])
722  ((XPathFilter*)nodeset)->append_element(j, pos++);
723  }
724  return nodeset;
725 }
726 
727 
728 String *Item_nodeset_func_attributebyname::val_nodeset(String *nodeset)
729 {
730  prepare(nodeset);
731  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
732  {
733  MY_XML_NODE *self= &nodebeg[flt->num];
734  for (uint pos=0, j= flt->num + 1 ; j < numnodes; j++)
735  {
736  MY_XML_NODE *node= &nodebeg[j];
737  if (node->level <= self->level)
738  break;
739  if ((node->parent == flt->num) &&
740  (node->type == MY_XML_NODE_ATTR) &&
741  validname(node))
742  ((XPathFilter*)nodeset)->append_element(j, pos++);
743  }
744  }
745  return nodeset;
746 }
747 
748 
749 String *Item_nodeset_func_predicate::val_nodeset(String *str)
750 {
751  Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
752  Item_func *comp_func= (Item_func*)args[1];
753  uint pos= 0, size;
754  prepare(str);
755  size= fltend - fltbeg;
756  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
757  {
758  nodeset_func->context_cache.length(0);
759  ((XPathFilter*)(&nodeset_func->context_cache))->append_element(flt->num,
760  flt->pos,
761  size);
762  if (comp_func->val_int())
763  ((XPathFilter*)str)->append_element(flt->num, pos++);
764  }
765  return str;
766 }
767 
768 
769 String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset)
770 {
771  Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
772  prepare(nodeset);
773  MY_XPATH_FLT *flt;
774  uint pos, size= fltend - fltbeg;
775  for (pos= 0, flt= fltbeg; flt < fltend; flt++)
776  {
777  nodeset_func->context_cache.length(0);
778  ((XPathFilter*)(&nodeset_func->context_cache))->append_element(flt->num,
779  flt->pos,
780  size);
781  int index= (int) (args[1]->val_int()) - 1;
782  if (index >= 0 && (flt->pos == (uint) index || args[1]->is_bool_func()))
783  ((XPathFilter*)nodeset)->append_element(flt->num, pos++);
784  }
785  return nodeset;
786 }
787 
788 
789 /*
790  If item is a node set, then casts it to boolean,
791  otherwise returns the item itself.
792 */
793 static Item* nodeset2bool(MY_XPATH *xpath, Item *item)
794 {
795  if (item->type() == Item::XPATH_NODESET)
796  return new Item_xpath_cast_bool(item, xpath->pxml);
797  return item;
798 }
799 
800 
801 /*
802  XPath lexical tokens
803 */
804 #define MY_XPATH_LEX_DIGITS 'd'
805 #define MY_XPATH_LEX_IDENT 'i'
806 #define MY_XPATH_LEX_STRING 's'
807 #define MY_XPATH_LEX_SLASH '/'
808 #define MY_XPATH_LEX_LB '['
809 #define MY_XPATH_LEX_RB ']'
810 #define MY_XPATH_LEX_LP '('
811 #define MY_XPATH_LEX_RP ')'
812 #define MY_XPATH_LEX_EQ '='
813 #define MY_XPATH_LEX_LESS '<'
814 #define MY_XPATH_LEX_GREATER '>'
815 #define MY_XPATH_LEX_AT '@'
816 #define MY_XPATH_LEX_COLON ':'
817 #define MY_XPATH_LEX_ASTERISK '*'
818 #define MY_XPATH_LEX_DOT '.'
819 #define MY_XPATH_LEX_VLINE '|'
820 #define MY_XPATH_LEX_MINUS '-'
821 #define MY_XPATH_LEX_PLUS '+'
822 #define MY_XPATH_LEX_EXCL '!'
823 #define MY_XPATH_LEX_COMMA ','
824 #define MY_XPATH_LEX_DOLLAR '$'
825 #define MY_XPATH_LEX_ERROR 'A'
826 #define MY_XPATH_LEX_EOF 'B'
827 #define MY_XPATH_LEX_AND 'C'
828 #define MY_XPATH_LEX_OR 'D'
829 #define MY_XPATH_LEX_DIV 'E'
830 #define MY_XPATH_LEX_MOD 'F'
831 #define MY_XPATH_LEX_FUNC 'G'
832 #define MY_XPATH_LEX_NODETYPE 'H'
833 #define MY_XPATH_LEX_AXIS 'I'
834 #define MY_XPATH_LEX_LE 'J'
835 #define MY_XPATH_LEX_GE 'K'
836 
837 
838 /*
839  XPath axis type
840 */
841 #define MY_XPATH_AXIS_ANCESTOR 0
842 #define MY_XPATH_AXIS_ANCESTOR_OR_SELF 1
843 #define MY_XPATH_AXIS_ATTRIBUTE 2
844 #define MY_XPATH_AXIS_CHILD 3
845 #define MY_XPATH_AXIS_DESCENDANT 4
846 #define MY_XPATH_AXIS_DESCENDANT_OR_SELF 5
847 #define MY_XPATH_AXIS_FOLLOWING 6
848 #define MY_XPATH_AXIS_FOLLOWING_SIBLING 7
849 #define MY_XPATH_AXIS_NAMESPACE 8
850 #define MY_XPATH_AXIS_PARENT 9
851 #define MY_XPATH_AXIS_PRECEDING 10
852 #define MY_XPATH_AXIS_PRECEDING_SIBLING 11
853 #define MY_XPATH_AXIS_SELF 12
854 
855 
856 /*
857  Create scalar comparator
858 
859  SYNOPSYS
860  Create a comparator function for scalar arguments,
861  for the given arguments and operation.
862 
863  RETURN
864  The newly created item.
865 */
866 static Item *eq_func(int oper, Item *a, Item *b)
867 {
868  switch (oper)
869  {
870  case '=': return new Item_func_eq(a, b);
871  case '!': return new Item_func_ne(a, b);
872  case MY_XPATH_LEX_GE: return new Item_func_ge(a, b);
873  case MY_XPATH_LEX_LE: return new Item_func_le(a, b);
874  case MY_XPATH_LEX_GREATER: return new Item_func_gt(a, b);
875  case MY_XPATH_LEX_LESS: return new Item_func_lt(a, b);
876  }
877  return 0;
878 }
879 
880 
881 /*
882  Create scalar comparator
883 
884  SYNOPSYS
885  Create a comparator function for scalar arguments,
886  for the given arguments and reverse operation, e.g.
887 
888  A > B is converted into B < A
889 
890  RETURN
891  The newly created item.
892 */
893 static Item *eq_func_reverse(int oper, Item *a, Item *b)
894 {
895  switch (oper)
896  {
897  case '=': return new Item_func_eq(a, b);
898  case '!': return new Item_func_ne(a, b);
899  case MY_XPATH_LEX_GE: return new Item_func_le(a, b);
900  case MY_XPATH_LEX_LE: return new Item_func_ge(a, b);
901  case MY_XPATH_LEX_GREATER: return new Item_func_lt(a, b);
902  case MY_XPATH_LEX_LESS: return new Item_func_gt(a, b);
903  }
904  return 0;
905 }
906 
907 
908 /*
909  Create a comparator
910 
911  SYNOPSYS
912  Create a comparator for scalar or non-scalar arguments,
913  for the given arguments and operation.
914 
915  RETURN
916  The newly created item.
917 */
918 static Item *create_comparator(MY_XPATH *xpath,
919  int oper, MY_XPATH_LEX *context,
920  Item *a, Item *b)
921 {
922  if (a->type() != Item::XPATH_NODESET &&
923  b->type() != Item::XPATH_NODESET)
924  {
925  return eq_func(oper, a, b); // two scalar arguments
926  }
927  else if (a->type() == Item::XPATH_NODESET &&
928  b->type() == Item::XPATH_NODESET)
929  {
930  uint len= xpath->query.end - context->beg;
931  set_if_smaller(len, 32);
932  my_printf_error(ER_UNKNOWN_ERROR,
933  "XPATH error: "
934  "comparison of two nodesets is not supported: '%.*s'",
935  MYF(0), len, context->beg);
936 
937  return 0; // TODO: Comparison of two nodesets
938  }
939  else
940  {
941  /*
942  Compare a node set to a scalar value.
943  We just create a fake Item_string() argument,
944  which will be filled to the partular value
945  in a loop through all of the nodes in the node set.
946  */
947 
948  Item_string *fake= new Item_string("", 0, xpath->cs);
949  /* Don't cache fake because its value will be changed during comparison.*/
950  fake->set_used_tables(RAND_TABLE_BIT);
951  Item_nodeset_func *nodeset;
952  Item *scalar, *comp;
953  if (a->type() == Item::XPATH_NODESET)
954  {
955  nodeset= (Item_nodeset_func*) a;
956  scalar= b;
957  comp= eq_func(oper, (Item*)fake, scalar);
958  }
959  else
960  {
961  nodeset= (Item_nodeset_func*) b;
962  scalar= a;
963  comp= eq_func_reverse(oper, fake, scalar);
964  }
965  return new Item_nodeset_to_const_comparator(nodeset, comp, xpath->pxml);
966  }
967 }
968 
969 
970 /*
971  Create a step
972 
973  SYNOPSYS
974  Create a step function for the given argument and axis.
975 
976  RETURN
977  The newly created item.
978 */
979 static Item* nametestfunc(MY_XPATH *xpath,
980  int type, Item *arg, const char *beg, uint len)
981 {
982  DBUG_ASSERT(arg != 0);
983  DBUG_ASSERT(arg->type() == Item::XPATH_NODESET);
984  DBUG_ASSERT(beg != 0);
985  DBUG_ASSERT(len > 0);
986 
987  Item *res;
988  switch (type)
989  {
990  case MY_XPATH_AXIS_ANCESTOR:
991  res= new Item_nodeset_func_ancestorbyname(arg, beg, len, xpath->pxml, 0);
992  break;
993  case MY_XPATH_AXIS_ANCESTOR_OR_SELF:
994  res= new Item_nodeset_func_ancestorbyname(arg, beg, len, xpath->pxml, 1);
995  break;
996  case MY_XPATH_AXIS_PARENT:
997  res= new Item_nodeset_func_parentbyname(arg, beg, len, xpath->pxml);
998  break;
999  case MY_XPATH_AXIS_DESCENDANT:
1000  res= new Item_nodeset_func_descendantbyname(arg, beg, len, xpath->pxml, 0);
1001  break;
1002  case MY_XPATH_AXIS_DESCENDANT_OR_SELF:
1003  res= new Item_nodeset_func_descendantbyname(arg, beg, len, xpath->pxml, 1);
1004  break;
1005  case MY_XPATH_AXIS_ATTRIBUTE:
1006  res= new Item_nodeset_func_attributebyname(arg, beg, len, xpath->pxml);
1007  break;
1008  case MY_XPATH_AXIS_SELF:
1009  res= new Item_nodeset_func_selfbyname(arg, beg, len, xpath->pxml);
1010  break;
1011  default:
1012  res= new Item_nodeset_func_childbyname(arg, beg, len, xpath->pxml);
1013  }
1014  return res;
1015 }
1016 
1017 
1018 /*
1019  Tokens consisting of one character, for faster lexical analizer.
1020 */
1021 static char simpletok[128]=
1022 {
1023  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,
1024 /*
1025  ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
1026  @ 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  ` 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 { | } ~ €
1028 */
1029  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,
1030  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,
1031  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
1032 };
1033 
1034 
1035 /*
1036  XPath keywords
1037 */
1039 {
1040  int tok;
1041  const char *name;
1042  size_t length;
1043  int extra;
1044 };
1045 
1046 
1047 static struct my_xpath_keyword_names_st my_keyword_names[] =
1048 {
1049  {MY_XPATH_LEX_AND , "and" , 3, 0 },
1050  {MY_XPATH_LEX_OR , "or" , 2, 0 },
1051  {MY_XPATH_LEX_DIV , "div" , 3, 0 },
1052  {MY_XPATH_LEX_MOD , "mod" , 3, 0 },
1053  {0,NULL,0,0}
1054 };
1055 
1056 
1057 static struct my_xpath_keyword_names_st my_axis_names[]=
1058 {
1059  {MY_XPATH_LEX_AXIS,"ancestor" , 8,MY_XPATH_AXIS_ANCESTOR },
1060  {MY_XPATH_LEX_AXIS,"ancestor-or-self" ,16,MY_XPATH_AXIS_ANCESTOR_OR_SELF },
1061  {MY_XPATH_LEX_AXIS,"attribute" , 9,MY_XPATH_AXIS_ATTRIBUTE },
1062  {MY_XPATH_LEX_AXIS,"child" , 5,MY_XPATH_AXIS_CHILD },
1063  {MY_XPATH_LEX_AXIS,"descendant" ,10,MY_XPATH_AXIS_DESCENDANT },
1064  {MY_XPATH_LEX_AXIS,"descendant-or-self",18,MY_XPATH_AXIS_DESCENDANT_OR_SELF},
1065  {MY_XPATH_LEX_AXIS,"following" , 9,MY_XPATH_AXIS_FOLLOWING },
1066  {MY_XPATH_LEX_AXIS,"following-sibling" ,17,MY_XPATH_AXIS_FOLLOWING_SIBLING },
1067  {MY_XPATH_LEX_AXIS,"namespace" , 9,MY_XPATH_AXIS_NAMESPACE },
1068  {MY_XPATH_LEX_AXIS,"parent" , 6,MY_XPATH_AXIS_PARENT },
1069  {MY_XPATH_LEX_AXIS,"preceding" , 9,MY_XPATH_AXIS_PRECEDING },
1070  {MY_XPATH_LEX_AXIS,"preceding-sibling" ,17,MY_XPATH_AXIS_PRECEDING_SIBLING },
1071  {MY_XPATH_LEX_AXIS,"self" , 4,MY_XPATH_AXIS_SELF },
1072  {0,NULL,0,0}
1073 };
1074 
1075 
1076 static struct my_xpath_keyword_names_st my_nodetype_names[]=
1077 {
1078  {MY_XPATH_LEX_NODETYPE, "comment" , 7, 0 },
1079  {MY_XPATH_LEX_NODETYPE, "text" , 4, 0 },
1080  {MY_XPATH_LEX_NODETYPE, "processing-instruction" , 22,0 },
1081  {MY_XPATH_LEX_NODETYPE, "node" , 4, 0 },
1082  {0,NULL,0,0}
1083 };
1084 
1085 
1086 /*
1087  Lookup a keyword
1088 
1089  SYNOPSYS
1090  Check that the last scanned identifier is a keyword.
1091 
1092  RETURN
1093  - Token type, on lookup success.
1094  - MY_XPATH_LEX_IDENT, on lookup failure.
1095 */
1096 static int
1097 my_xpath_keyword(MY_XPATH *x,
1098  struct my_xpath_keyword_names_st *keyword_names,
1099  const char *beg, const char *end)
1100 {
1101  struct my_xpath_keyword_names_st *k;
1102  size_t length= end-beg;
1103  for (k= keyword_names; k->name; k++)
1104  {
1105  if (length == k->length && !strncasecmp(beg, k->name, length))
1106  {
1107  x->extra= k->extra;
1108  return k->tok;
1109  }
1110  }
1111  return MY_XPATH_LEX_IDENT;
1112 }
1113 
1114 
1115 /*
1116  Functions to create an item, a-la those in item_create.cc
1117 */
1118 
1119 static Item *create_func_true(MY_XPATH *xpath, Item **args, uint nargs)
1120 {
1121  return new Item_bool(1);
1122 }
1123 
1124 
1125 static Item *create_func_false(MY_XPATH *xpath, Item **args, uint nargs)
1126 {
1127  return new Item_bool(0);
1128 }
1129 
1130 
1131 static Item *create_func_not(MY_XPATH *xpath, Item **args, uint nargs)
1132 {
1133  return new Item_func_not(nodeset2bool(xpath, args[0]));
1134 }
1135 
1136 
1137 static Item *create_func_ceiling(MY_XPATH *xpath, Item **args, uint nargs)
1138 {
1139  return new Item_func_ceiling(args[0]);
1140 }
1141 
1142 
1143 static Item *create_func_floor(MY_XPATH *xpath, Item **args, uint nargs)
1144 {
1145  return new Item_func_floor(args[0]);
1146 }
1147 
1148 
1149 static Item *create_func_bool(MY_XPATH *xpath, Item **args, uint nargs)
1150 {
1151  return new Item_xpath_cast_bool(args[0], xpath->pxml);
1152 }
1153 
1154 
1155 static Item *create_func_number(MY_XPATH *xpath, Item **args, uint nargs)
1156 {
1157  return new Item_xpath_cast_number(args[0]);
1158 }
1159 
1160 
1161 static Item *create_func_string_length(MY_XPATH *xpath, Item **args, uint nargs)
1162 {
1163  Item *arg= nargs ? args[0] : xpath->context;
1164  return arg ? new Item_func_char_length(arg) : 0;
1165 }
1166 
1167 
1168 static Item *create_func_round(MY_XPATH *xpath, Item **args, uint nargs)
1169 {
1170  return new Item_func_round(args[0], new Item_int_0(), 0);
1171 }
1172 
1173 
1174 static Item *create_func_last(MY_XPATH *xpath, Item **args, uint nargs)
1175 {
1176  return xpath->context ?
1177  new Item_func_xpath_count(xpath->context, xpath->pxml) : NULL;
1178 }
1179 
1180 
1181 static Item *create_func_position(MY_XPATH *xpath, Item **args, uint nargs)
1182 {
1183  return xpath->context ?
1184  new Item_func_xpath_position(xpath->context, xpath->pxml) : NULL;
1185 }
1186 
1187 
1188 static Item *create_func_contains(MY_XPATH *xpath, Item **args, uint nargs)
1189 {
1190  return new Item_xpath_cast_bool(new Item_func_locate(args[0], args[1]),
1191  xpath->pxml);
1192 }
1193 
1194 
1195 static Item *create_func_concat(MY_XPATH *xpath, Item **args, uint nargs)
1196 {
1197  return new Item_func_concat(args[0], args[1]);
1198 }
1199 
1200 
1201 static Item *create_func_substr(MY_XPATH *xpath, Item **args, uint nargs)
1202 {
1203  if (nargs == 2)
1204  return new Item_func_substr(args[0], args[1]);
1205  else
1206  return new Item_func_substr(args[0], args[1], args[2]);
1207 }
1208 
1209 
1210 static Item *create_func_count(MY_XPATH *xpath, Item **args, uint nargs)
1211 {
1212  if (args[0]->type() != Item::XPATH_NODESET)
1213  return 0;
1214  return new Item_func_xpath_count(args[0], xpath->pxml);
1215 }
1216 
1217 
1218 static Item *create_func_sum(MY_XPATH *xpath, Item **args, uint nargs)
1219 {
1220  if (args[0]->type() != Item::XPATH_NODESET)
1221  return 0;
1222  return new Item_func_xpath_sum(args[0], xpath->pxml);
1223 }
1224 
1225 
1226 /*
1227  Functions names. Separate lists for names with
1228  lengths 3,4,5 and 6 for faster lookups.
1229 */
1230 static MY_XPATH_FUNC my_func_names3[]=
1231 {
1232  {"sum", 3, 1 , 1 , create_func_sum},
1233  {"not", 3, 1 , 1 , create_func_not},
1234  {0 , 0, 0 , 0, 0}
1235 };
1236 
1237 
1238 static MY_XPATH_FUNC my_func_names4[]=
1239 {
1240  {"last", 4, 0, 0, create_func_last},
1241  {"true", 4, 0, 0, create_func_true},
1242  {"name", 4, 0, 1, 0},
1243  {"lang", 4, 1, 1, 0},
1244  {0 , 0, 0, 0, 0}
1245 };
1246 
1247 
1248 static MY_XPATH_FUNC my_func_names5[]=
1249 {
1250  {"count", 5, 1, 1, create_func_count},
1251  {"false", 5, 0, 0, create_func_false},
1252  {"floor", 5, 1, 1, create_func_floor},
1253  {"round", 5, 1, 1, create_func_round},
1254  {0 , 0, 0, 0, 0}
1255 };
1256 
1257 
1258 static MY_XPATH_FUNC my_func_names6[]=
1259 {
1260  {"concat", 6, 2, 255, create_func_concat},
1261  {"number", 6, 0, 1 , create_func_number},
1262  {"string", 6, 0, 1 , 0},
1263  {0 , 0, 0, 0 , 0}
1264 };
1265 
1266 
1267 /* Other functions, with name longer than 6, all together */
1268 static MY_XPATH_FUNC my_func_names[] =
1269 {
1270  {"id" , 2 , 1 , 1 , 0},
1271  {"boolean" , 7 , 1 , 1 , create_func_bool},
1272  {"ceiling" , 7 , 1 , 1 , create_func_ceiling},
1273  {"position" , 8 , 0 , 0 , create_func_position},
1274  {"contains" , 8 , 2 , 2 , create_func_contains},
1275  {"substring" , 9 , 2 , 3 , create_func_substr},
1276  {"translate" , 9 , 3 , 3 , 0},
1277 
1278  {"local-name" , 10 , 0 , 1 , 0},
1279  {"starts-with" , 11 , 2 , 2 , 0},
1280  {"namespace-uri" , 13 , 0 , 1 , 0},
1281  {"string-length" , 13 , 0 , 1 , create_func_string_length},
1282  {"substring-after" , 15 , 2 , 2 , 0},
1283  {"normalize-space" , 15 , 0 , 1 , 0},
1284  {"substring-before" , 16 , 2 , 2 , 0},
1285 
1286  {NULL,0,0,0,0}
1287 };
1288 
1289 
1290 /*
1291  Lookup a function by name
1292 
1293  SYNOPSYS
1294  Lookup a function by its name.
1295 
1296  RETURN
1297  Pointer to a MY_XPATH_FUNC variable on success.
1298  0 - on failure.
1299 
1300 */
1301 MY_XPATH_FUNC *
1302 my_xpath_function(const char *beg, const char *end)
1303 {
1304  MY_XPATH_FUNC *k, *function_names;
1305  uint length= end-beg;
1306  switch (length)
1307  {
1308  case 1: return 0;
1309  case 3: function_names= my_func_names3; break;
1310  case 4: function_names= my_func_names4; break;
1311  case 5: function_names= my_func_names5; break;
1312  case 6: function_names= my_func_names6; break;
1313  default: function_names= my_func_names;
1314  }
1315  for (k= function_names; k->name; k++)
1316  if (k->create && length == k->length && !strncasecmp(beg, k->name, length))
1317  return k;
1318  return NULL;
1319 }
1320 
1321 
1322 /* Initialize a lex analizer token */
1323 static void
1324 my_xpath_lex_init(MY_XPATH_LEX *lex,
1325  const char *str, const char *strend)
1326 {
1327  lex->beg= str;
1328  lex->end= strend;
1329 }
1330 
1331 
1332 /* Initialize an XPath query parser */
1333 static void
1334 my_xpath_init(MY_XPATH *xpath)
1335 {
1336  memset(xpath, 0, sizeof(xpath[0]));
1337 }
1338 
1339 
1340 static int
1341 my_xdigit(int c)
1342 {
1343  return ((c) >= '0' && (c) <= '9');
1344 }
1345 
1346 
1347 /*
1348  Scan the next token
1349 
1350  SYNOPSYS
1351  Scan the next token from the input.
1352  lex->term is set to the scanned token type.
1353  lex->beg and lex->end are set to the beginnig
1354  and to the end of the token.
1355  RETURN
1356  N/A
1357 */
1358 static void
1359 my_xpath_lex_scan(MY_XPATH *xpath,
1360  MY_XPATH_LEX *lex, const char *beg, const char *end)
1361 {
1362  int ch, ctype, length;
1363  for ( ; beg < end && *beg == ' ' ; beg++) ; // skip leading spaces
1364  lex->beg= beg;
1365 
1366  if (beg >= end)
1367  {
1368  lex->end= beg;
1369  lex->term= MY_XPATH_LEX_EOF; // end of line reached
1370  return;
1371  }
1372 
1373  // Check ident, or a function call, or a keyword
1374  if ((length= xpath->cs->cset->ctype(xpath->cs, &ctype,
1375  (const uchar*) beg,
1376  (const uchar*) end)) > 0 &&
1377  ((ctype & (_MY_L | _MY_U)) || *beg == '_'))
1378  {
1379  // scan untill the end of the idenfitier
1380  for (beg+= length;
1381  (length= xpath->cs->cset->ctype(xpath->cs, &ctype,
1382  (const uchar*) beg,
1383  (const uchar*) end)) > 0 &&
1384  ((ctype & (_MY_L | _MY_U | _MY_NMR)) ||
1385  *beg == '_' || *beg == '-' || *beg == '.') ;
1386  beg+= length) /* no op */;
1387  lex->end= beg;
1388 
1389  if (beg < end)
1390  {
1391  if (*beg == '(')
1392  {
1393  /*
1394  check if a function call, e.g.: count(/a/b)
1395  or a nodetype test, e.g.: /a/b/text()
1396  */
1397  if ((xpath->func= my_xpath_function(lex->beg, beg)))
1398  lex->term= MY_XPATH_LEX_FUNC;
1399  else
1400  lex->term= my_xpath_keyword(xpath, my_nodetype_names,
1401  lex->beg, beg);
1402  return;
1403  }
1404  // check if an axis specifier, e.g.: /a/b/child::*
1405  else if (*beg == ':' && beg + 1 < end && beg[1] == ':')
1406  {
1407  lex->term= my_xpath_keyword(xpath, my_axis_names,
1408  lex->beg, beg);
1409  return;
1410  }
1411  }
1412  // check if a keyword
1413  lex->term= my_xpath_keyword(xpath, my_keyword_names,
1414  lex->beg, beg);
1415  return;
1416  }
1417 
1418 
1419  ch= *beg++;
1420 
1421  if (ch > 0 && ch < 128 && simpletok[ch])
1422  {
1423  // a token consisting of one character found
1424  lex->end= beg;
1425  lex->term= ch;
1426  return;
1427  }
1428 
1429 
1430  if (my_xdigit(ch)) // a sequence of digits
1431  {
1432  for ( ; beg < end && my_xdigit(*beg) ; beg++) ;
1433  lex->end= beg;
1434  lex->term= MY_XPATH_LEX_DIGITS;
1435  return;
1436  }
1437 
1438  if (ch == '"' || ch == '\'') // a string: either '...' or "..."
1439  {
1440  for ( ; beg < end && *beg != ch ; beg++) ;
1441  if (beg < end)
1442  {
1443  lex->end= beg+1;
1444  lex->term= MY_XPATH_LEX_STRING;
1445  return;
1446  }
1447  else
1448  {
1449  // unexpected end-of-line, without closing quot sign
1450  lex->end= end;
1451  lex->term= MY_XPATH_LEX_ERROR;
1452  return;
1453  }
1454  }
1455 
1456  lex->end= beg;
1457  lex->term= MY_XPATH_LEX_ERROR; // unknown character
1458  return;
1459 }
1460 
1461 
1462 /*
1463  Scan the given token
1464 
1465  SYNOPSYS
1466  Scan the given token and rotate lasttok to prevtok on success.
1467 
1468  RETURN
1469  1 - success
1470  0 - failure
1471 */
1472 static int
1473 my_xpath_parse_term(MY_XPATH *xpath, int term)
1474 {
1475  if (xpath->lasttok.term == term && !xpath->error)
1476  {
1477  xpath->prevtok= xpath->lasttok;
1478  my_xpath_lex_scan(xpath, &xpath->lasttok,
1479  xpath->lasttok.end, xpath->query.end);
1480  return 1;
1481  }
1482  return 0;
1483 }
1484 
1485 
1486 /*
1487  Scan AxisName
1488 
1489  SYNOPSYS
1490  Scan an axis name and store the scanned axis type into xpath->axis.
1491 
1492  RETURN
1493  1 - success
1494  0 - failure
1495 */
1496 static int my_xpath_parse_AxisName(MY_XPATH *xpath)
1497 {
1498  int rc= my_xpath_parse_term(xpath, MY_XPATH_LEX_AXIS);
1499  xpath->axis= xpath->extra;
1500  return rc;
1501 }
1502 
1503 
1504 /*********************************************
1505 ** Grammar rules, according to http://www.w3.org/TR/xpath
1506 ** Implemented using recursive descendant method.
1507 ** All the following grammar processing functions accept
1508 ** a signle "xpath" argument and return 1 on success and 0 on error.
1509 ** They also modify "xpath" argument by creating new items.
1510 */
1511 
1512 /* [9] PredicateExpr ::= Expr */
1513 #define my_xpath_parse_PredicateExpr(x) my_xpath_parse_Expr((x))
1514 
1515 /* [14] Expr ::= OrExpr */
1516 #define my_xpath_parse_Expr(x) my_xpath_parse_OrExpr((x))
1517 
1518 static int my_xpath_parse_LocationPath(MY_XPATH *xpath);
1519 static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH *xpath);
1520 static int my_xpath_parse_RelativeLocationPath(MY_XPATH *xpath);
1521 static int my_xpath_parse_AbbreviatedStep(MY_XPATH *xpath);
1522 static int my_xpath_parse_Step(MY_XPATH *xpath);
1523 static int my_xpath_parse_AxisSpecifier(MY_XPATH *xpath);
1524 static int my_xpath_parse_NodeTest(MY_XPATH *xpath);
1525 static int my_xpath_parse_AbbreviatedAxisSpecifier(MY_XPATH *xpath);
1526 static int my_xpath_parse_NameTest(MY_XPATH *xpath);
1527 static int my_xpath_parse_FunctionCall(MY_XPATH *xpath);
1528 static int my_xpath_parse_Number(MY_XPATH *xpath);
1529 static int my_xpath_parse_FilterExpr(MY_XPATH *xpath);
1530 static int my_xpath_parse_PathExpr(MY_XPATH *xpath);
1531 static int my_xpath_parse_OrExpr(MY_XPATH *xpath);
1532 static int my_xpath_parse_UnaryExpr(MY_XPATH *xpath);
1533 static int my_xpath_parse_MultiplicativeExpr(MY_XPATH *xpath);
1534 static int my_xpath_parse_AdditiveExpr(MY_XPATH *xpath);
1535 static int my_xpath_parse_RelationalExpr(MY_XPATH *xpath);
1536 static int my_xpath_parse_AndExpr(MY_XPATH *xpath);
1537 static int my_xpath_parse_EqualityExpr(MY_XPATH *xpath);
1538 static int my_xpath_parse_VariableReference(MY_XPATH *xpath);
1539 
1540 
1541 /*
1542  Scan LocationPath
1543 
1544  SYNOPSYS
1545 
1546  [1] LocationPath ::= RelativeLocationPath
1547  | AbsoluteLocationPath
1548 
1549  RETURN
1550  1 - success
1551  0 - failure
1552 */
1553 static int my_xpath_parse_LocationPath(MY_XPATH *xpath)
1554 {
1555  Item *context= xpath->context;
1556 
1557  if (!xpath->context)
1558  xpath->context= xpath->rootelement;
1559  int rc= my_xpath_parse_RelativeLocationPath(xpath) ||
1560  my_xpath_parse_AbsoluteLocationPath(xpath);
1561 
1562  xpath->item= xpath->context;
1563  xpath->context= context;
1564  return rc;
1565 }
1566 
1567 
1568 /*
1569  Scan Absolute Location Path
1570 
1571  SYNOPSYS
1572 
1573  [2] AbsoluteLocationPath ::= '/' RelativeLocationPath?
1574  | AbbreviatedAbsoluteLocationPath
1575  [10] AbbreviatedAbsoluteLocationPath ::= '//' RelativeLocationPath
1576 
1577  We combine these two rules into one rule for better performance:
1578 
1579  [2,10] AbsoluteLocationPath ::= '/' RelativeLocationPath?
1580  | '//' RelativeLocationPath
1581 
1582  RETURN
1583  1 - success
1584  0 - failure
1585 */
1586 static int my_xpath_parse_AbsoluteLocationPath(MY_XPATH *xpath)
1587 {
1588  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
1589  return 0;
1590 
1591  xpath->context= xpath->rootelement;
1592 
1593  if (my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
1594  {
1595  xpath->context= new Item_nodeset_func_descendantbyname(xpath->context,
1596  "*", 1,
1597  xpath->pxml, 1);
1598  return my_xpath_parse_RelativeLocationPath(xpath);
1599  }
1600 
1601  my_xpath_parse_RelativeLocationPath(xpath);
1602 
1603  return (xpath->error == 0);
1604 }
1605 
1606 
1607 /*
1608  Scan Relative Location Path
1609 
1610  SYNOPSYS
1611 
1612  For better performance we combine these two rules
1613 
1614  [3] RelativeLocationPath ::= Step
1615  | RelativeLocationPath '/' Step
1616  | AbbreviatedRelativeLocationPath
1617  [11] AbbreviatedRelativeLocationPath ::= RelativeLocationPath '//' Step
1618 
1619 
1620  Into this one:
1621 
1622  [3-11] RelativeLocationPath ::= Step
1623  | RelativeLocationPath '/' Step
1624  | RelativeLocationPath '//' Step
1625  RETURN
1626  1 - success
1627  0 - failure
1628 */
1629 static int my_xpath_parse_RelativeLocationPath(MY_XPATH *xpath)
1630 {
1631  if (!my_xpath_parse_Step(xpath))
1632  return 0;
1633  while (my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
1634  {
1635  if (my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
1636  xpath->context= new Item_nodeset_func_descendantbyname(xpath->context,
1637  "*", 1,
1638  xpath->pxml, 1);
1639  if (!my_xpath_parse_Step(xpath))
1640  {
1641  xpath->error= 1;
1642  return 0;
1643  }
1644  }
1645  return 1;
1646 }
1647 
1648 
1649 /*
1650  Scan non-abbreviated or abbreviated Step
1651 
1652  SYNOPSYS
1653 
1654  [4] Step ::= AxisSpecifier NodeTest Predicate*
1655  | AbbreviatedStep
1656  [8] Predicate ::= '[' PredicateExpr ']'
1657 
1658  RETURN
1659  1 - success
1660  0 - failure
1661 */
1662 static int
1663 my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(MY_XPATH *xpath)
1664 {
1665  if (!my_xpath_parse_AxisSpecifier(xpath))
1666  return 0;
1667 
1668  if (!my_xpath_parse_NodeTest(xpath))
1669  return 0;
1670 
1671  while (my_xpath_parse_term(xpath, MY_XPATH_LEX_LB))
1672  {
1673  Item *prev_context= xpath->context;
1674  String *context_cache;
1675  context_cache= &((Item_nodeset_func*)xpath->context)->context_cache;
1676  xpath->context= new Item_nodeset_context_cache(context_cache, xpath->pxml);
1677  xpath->context_cache= context_cache;
1678 
1679  if(!my_xpath_parse_PredicateExpr(xpath))
1680  {
1681  xpath->error= 1;
1682  return 0;
1683  }
1684 
1685  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_RB))
1686  {
1687  xpath->error= 1;
1688  return 0;
1689  }
1690 
1691  xpath->item= nodeset2bool(xpath, xpath->item);
1692 
1693  if (xpath->item->is_bool_func())
1694  {
1695  xpath->context= new Item_nodeset_func_predicate(prev_context,
1696  xpath->item,
1697  xpath->pxml);
1698  }
1699  else
1700  {
1701  xpath->context= new Item_nodeset_func_elementbyindex(prev_context,
1702  xpath->item,
1703  xpath->pxml);
1704  }
1705  }
1706  return 1;
1707 }
1708 
1709 
1710 static int my_xpath_parse_Step(MY_XPATH *xpath)
1711 {
1712  return
1713  my_xpath_parse_AxisSpecifier_NodeTest_opt_Predicate_list(xpath) ||
1714  my_xpath_parse_AbbreviatedStep(xpath);
1715 }
1716 
1717 
1718 /*
1719  Scan Abbreviated Axis Specifier
1720 
1721  SYNOPSYS
1722  [5] AxisSpecifier ::= AxisName '::'
1723  | AbbreviatedAxisSpecifier
1724 
1725  RETURN
1726  1 - success
1727  0 - failure
1728 */
1729 static int my_xpath_parse_AbbreviatedAxisSpecifier(MY_XPATH *xpath)
1730 {
1731  if (my_xpath_parse_term(xpath, MY_XPATH_LEX_AT))
1732  xpath->axis= MY_XPATH_AXIS_ATTRIBUTE;
1733  else
1734  xpath->axis= MY_XPATH_AXIS_CHILD;
1735  return 1;
1736 }
1737 
1738 
1739 /*
1740  Scan non-abbreviated axis specifier
1741 
1742  SYNOPSYS
1743 
1744  RETURN
1745  1 - success
1746  0 - failure
1747 */
1748 static int my_xpath_parse_AxisName_colon_colon(MY_XPATH *xpath)
1749 {
1750  return my_xpath_parse_AxisName(xpath) &&
1751  my_xpath_parse_term(xpath, MY_XPATH_LEX_COLON) &&
1752  my_xpath_parse_term(xpath, MY_XPATH_LEX_COLON);
1753 }
1754 
1755 
1756 /*
1757  Scan Abbreviated AxisSpecifier
1758 
1759  SYNOPSYS
1760  [13] AbbreviatedAxisSpecifier ::= '@'?
1761 
1762  RETURN
1763  1 - success
1764  0 - failure
1765 */
1766 static int my_xpath_parse_AxisSpecifier(MY_XPATH *xpath)
1767 {
1768  return my_xpath_parse_AxisName_colon_colon(xpath) ||
1769  my_xpath_parse_AbbreviatedAxisSpecifier(xpath);
1770 }
1771 
1772 
1773 /*
1774  Scan NodeType followed by parens
1775 
1776  SYNOPSYS
1777 
1778  RETURN
1779  1 - success
1780  0 - failure
1781 */
1782 static int my_xpath_parse_NodeTest_lp_rp(MY_XPATH *xpath)
1783 {
1784  return my_xpath_parse_term(xpath, MY_XPATH_LEX_NODETYPE) &&
1785  my_xpath_parse_term(xpath, MY_XPATH_LEX_LP) &&
1786  my_xpath_parse_term(xpath, MY_XPATH_LEX_RP);
1787 }
1788 
1789 
1790 /*
1791  Scan NodeTest
1792 
1793  SYNOPSYS
1794 
1795  [7] NodeTest ::= NameTest
1796  | NodeType '(' ')'
1797  | 'processing-instruction' '(' Literal ')'
1798  RETURN
1799  1 - success
1800  0 - failure
1801 */
1802 static int my_xpath_parse_NodeTest(MY_XPATH *xpath)
1803 {
1804  return my_xpath_parse_NameTest(xpath) ||
1805  my_xpath_parse_NodeTest_lp_rp(xpath);
1806 }
1807 
1808 
1809 /*
1810  Scan Abbreviated Step
1811 
1812  SYNOPSYS
1813 
1814  [12] AbbreviatedStep ::= '.' | '..'
1815 
1816  RETURN
1817  1 - success
1818  0 - failure
1819 */
1820 static int my_xpath_parse_AbbreviatedStep(MY_XPATH *xpath)
1821 {
1822  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DOT))
1823  return 0;
1824  if (my_xpath_parse_term(xpath, MY_XPATH_LEX_DOT))
1825  xpath->context= new Item_nodeset_func_parentbyname(xpath->context, "*", 1,
1826  xpath->pxml);
1827  return 1;
1828 }
1829 
1830 
1831 /*
1832  Scan Primary Expression
1833 
1834  SYNOPSYS
1835 
1836  [15] PrimaryExpr ::= VariableReference
1837  | '(' Expr ')'
1838  | Literal
1839  | Number
1840  | FunctionCall
1841  RETURN
1842  1 - success
1843  0 - failure
1844 */
1845 static int my_xpath_parse_lp_Expr_rp(MY_XPATH *xpath)
1846 {
1847  return my_xpath_parse_term(xpath, MY_XPATH_LEX_LP) &&
1848  my_xpath_parse_Expr(xpath) &&
1849  my_xpath_parse_term(xpath, MY_XPATH_LEX_RP);
1850 }
1851 static int my_xpath_parse_PrimaryExpr_literal(MY_XPATH *xpath)
1852 {
1853  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_STRING))
1854  return 0;
1855  xpath->item= new Item_string(xpath->prevtok.beg + 1,
1856  xpath->prevtok.end - xpath->prevtok.beg - 2,
1857  xpath->cs);
1858  return 1;
1859 }
1860 static int my_xpath_parse_PrimaryExpr(MY_XPATH *xpath)
1861 {
1862  return
1863  my_xpath_parse_lp_Expr_rp(xpath) ||
1864  my_xpath_parse_VariableReference(xpath) ||
1865  my_xpath_parse_PrimaryExpr_literal(xpath) ||
1866  my_xpath_parse_Number(xpath) ||
1867  my_xpath_parse_FunctionCall(xpath);
1868 }
1869 
1870 
1871 /*
1872  Scan Function Call
1873 
1874  SYNOPSYS
1875  [16] FunctionCall ::= FunctionName '(' ( Argument ( ',' Argument )* )? ')'
1876  [17] Argument ::= Expr
1877 
1878  RETURN
1879  1 - success
1880  0 - failure
1881 
1882 */
1883 static int my_xpath_parse_FunctionCall(MY_XPATH *xpath)
1884 {
1885  Item *args[256];
1886  uint nargs;
1887 
1888  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_FUNC))
1889  return 0;
1890 
1891  MY_XPATH_FUNC *func= xpath->func;
1892 
1893  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_LP))
1894  return 0;
1895 
1896  for (nargs= 0 ; nargs < func->maxargs; )
1897  {
1898  if (!my_xpath_parse_Expr(xpath))
1899  {
1900  if (nargs < func->minargs)
1901  return 0;
1902  goto right_paren;
1903  }
1904  args[nargs++]= xpath->item;
1905  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_COMMA))
1906  {
1907  if (nargs < func->minargs)
1908  return 0;
1909  else
1910  break;
1911  }
1912  }
1913 
1914 right_paren:
1915  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_RP))
1916  return 0;
1917 
1918  return ((xpath->item= func->create(xpath, args, nargs))) ? 1 : 0;
1919 }
1920 
1921 
1922 /*
1923  Scan Union Expression
1924 
1925  SYNOPSYS
1926  [18] UnionExpr ::= PathExpr
1927  | UnionExpr '|' PathExpr
1928 
1929  RETURN
1930  1 - success
1931  0 - failure
1932 */
1933 static int my_xpath_parse_UnionExpr(MY_XPATH *xpath)
1934 {
1935  if (!my_xpath_parse_PathExpr(xpath))
1936  return 0;
1937 
1938  while (my_xpath_parse_term(xpath, MY_XPATH_LEX_VLINE))
1939  {
1940  Item *prev= xpath->item;
1941  if (prev->type() != Item::XPATH_NODESET)
1942  return 0;
1943 
1944  if (!my_xpath_parse_PathExpr(xpath)
1945  || xpath->item->type() != Item::XPATH_NODESET)
1946  {
1947  xpath->error= 1;
1948  return 0;
1949  }
1950  xpath->item= new Item_nodeset_func_union(prev, xpath->item, xpath->pxml);
1951  }
1952  return 1;
1953 }
1954 
1955 
1956 /*
1957  Scan Path Expression
1958 
1959  SYNOPSYS
1960 
1961  [19] PathExpr ::= LocationPath
1962  | FilterExpr
1963  | FilterExpr '/' RelativeLocationPath
1964  | FilterExpr '//' RelativeLocationPath
1965  RETURN
1966  1 - success
1967  0 - failure
1968 */
1969 static int
1970 my_xpath_parse_FilterExpr_opt_slashes_RelativeLocationPath(MY_XPATH *xpath)
1971 {
1972  Item *context= xpath->context;
1973  int rc;
1974 
1975  if (!my_xpath_parse_FilterExpr(xpath))
1976  return 0;
1977 
1978  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
1979  return 1;
1980 
1981  if (xpath->item->type() != Item::XPATH_NODESET)
1982  {
1983  xpath->lasttok= xpath->prevtok;
1984  xpath->error= 1;
1985  return 0;
1986  }
1987 
1988  /*
1989  The context for the next relative path is the nodeset
1990  returned by FilterExpr
1991  */
1992  xpath->context= xpath->item;
1993 
1994  /* treat double slash (//) as /descendant-or-self::node()/ */
1995  if (my_xpath_parse_term(xpath, MY_XPATH_LEX_SLASH))
1996  xpath->context= new Item_nodeset_func_descendantbyname(xpath->context,
1997  "*", 1, xpath->pxml, 1);
1998  rc= my_xpath_parse_RelativeLocationPath(xpath);
1999 
2000  /* push back the context and restore the item */
2001  xpath->item= xpath->context;
2002  xpath->context= context;
2003  return rc;
2004 }
2005 static int my_xpath_parse_PathExpr(MY_XPATH *xpath)
2006 {
2007  return my_xpath_parse_LocationPath(xpath) ||
2008  my_xpath_parse_FilterExpr_opt_slashes_RelativeLocationPath(xpath);
2009 }
2010 
2011 
2012 
2013 /*
2014  Scan Filter Expression
2015 
2016  SYNOPSYS
2017  [20] FilterExpr ::= PrimaryExpr
2018  | FilterExpr Predicate
2019 
2020  or in other words:
2021 
2022  [20] FilterExpr ::= PrimaryExpr Predicate*
2023 
2024  RETURN
2025  1 - success
2026  0 - failure
2027 
2028 */
2029 static int my_xpath_parse_FilterExpr(MY_XPATH *xpath)
2030 {
2031  return my_xpath_parse_PrimaryExpr(xpath);
2032 }
2033 
2034 
2035 /*
2036  Scan Or Expression
2037 
2038  SYNOPSYS
2039  [21] OrExpr ::= AndExpr
2040  | OrExpr 'or' AndExpr
2041 
2042  RETURN
2043  1 - success
2044  0 - failure
2045 */
2046 static int my_xpath_parse_OrExpr(MY_XPATH *xpath)
2047 {
2048  if (!my_xpath_parse_AndExpr(xpath))
2049  return 0;
2050 
2051  while (my_xpath_parse_term(xpath, MY_XPATH_LEX_OR))
2052  {
2053  Item *prev= xpath->item;
2054  if (!my_xpath_parse_AndExpr(xpath))
2055  {
2056  return 0;
2057  xpath->error= 1;
2058  }
2059  xpath->item= new Item_cond_or(nodeset2bool(xpath, prev),
2060  nodeset2bool(xpath, xpath->item));
2061  }
2062  return 1;
2063 }
2064 
2065 
2066 /*
2067  Scan And Expression
2068 
2069  SYNOPSYS
2070  [22] AndExpr ::= EqualityExpr
2071  | AndExpr 'and' EqualityExpr
2072 
2073  RETURN
2074  1 - success
2075  0 - failure
2076 */
2077 static int my_xpath_parse_AndExpr(MY_XPATH *xpath)
2078 {
2079  if (!my_xpath_parse_EqualityExpr(xpath))
2080  return 0;
2081 
2082  while (my_xpath_parse_term(xpath, MY_XPATH_LEX_AND))
2083  {
2084  Item *prev= xpath->item;
2085  if (!my_xpath_parse_EqualityExpr(xpath))
2086  {
2087  xpath->error= 1;
2088  return 0;
2089  }
2090 
2091  xpath->item= new Item_cond_and(nodeset2bool(xpath,prev),
2092  nodeset2bool(xpath,xpath->item));
2093  }
2094  return 1;
2095 }
2096 
2097 
2098 /*
2099  Scan Equality Expression
2100 
2101  SYNOPSYS
2102  [23] EqualityExpr ::= RelationalExpr
2103  | EqualityExpr '=' RelationalExpr
2104  | EqualityExpr '!=' RelationalExpr
2105  or in other words:
2106 
2107  [23] EqualityExpr ::= RelationalExpr ( EqualityOperator EqualityExpr )*
2108 
2109  RETURN
2110  1 - success
2111  0 - failure
2112 */
2113 static int my_xpath_parse_ne(MY_XPATH *xpath)
2114 {
2115  MY_XPATH_LEX prevtok= xpath->prevtok;
2116  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_EXCL))
2117  return 0;
2118  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_EQ))
2119  {
2120  /* Unget the exclamation mark */
2121  xpath->lasttok= xpath->prevtok;
2122  xpath->prevtok= prevtok;
2123  return 0;
2124  }
2125  return 1;
2126 }
2127 static int my_xpath_parse_EqualityOperator(MY_XPATH *xpath)
2128 {
2129  if (my_xpath_parse_ne(xpath))
2130  {
2131  xpath->extra= '!';
2132  return 1;
2133  }
2134  if (my_xpath_parse_term(xpath, MY_XPATH_LEX_EQ))
2135  {
2136  xpath->extra= '=';
2137  return 1;
2138  }
2139  return 0;
2140 }
2141 static int my_xpath_parse_EqualityExpr(MY_XPATH *xpath)
2142 {
2143  MY_XPATH_LEX operator_context;
2144  if (!my_xpath_parse_RelationalExpr(xpath))
2145  return 0;
2146 
2147  operator_context= xpath->lasttok;
2148  while (my_xpath_parse_EqualityOperator(xpath))
2149  {
2150  Item *prev= xpath->item;
2151  int oper= xpath->extra;
2152  if (!my_xpath_parse_RelationalExpr(xpath))
2153  {
2154  xpath->error= 1;
2155  return 0;
2156  }
2157 
2158  if (!(xpath->item= create_comparator(xpath, oper, &operator_context,
2159  prev, xpath->item)))
2160  return 0;
2161 
2162  operator_context= xpath->lasttok;
2163  }
2164  return 1;
2165 }
2166 
2167 
2168 /*
2169  Scan Relational Expression
2170 
2171  SYNOPSYS
2172 
2173  [24] RelationalExpr ::= AdditiveExpr
2174  | RelationalExpr '<' AdditiveExpr
2175  | RelationalExpr '>' AdditiveExpr
2176  | RelationalExpr '<=' AdditiveExpr
2177  | RelationalExpr '>=' AdditiveExpr
2178  or in other words:
2179 
2180  [24] RelationalExpr ::= AdditiveExpr (RelationalOperator RelationalExpr)*
2181 
2182  RETURN
2183  1 - success
2184  0 - failure
2185 */
2186 static int my_xpath_parse_RelationalOperator(MY_XPATH *xpath)
2187 {
2188  if (my_xpath_parse_term(xpath, MY_XPATH_LEX_LESS))
2189  {
2190  xpath->extra= my_xpath_parse_term(xpath, MY_XPATH_LEX_EQ) ?
2191  MY_XPATH_LEX_LE : MY_XPATH_LEX_LESS;
2192  return 1;
2193  }
2194  else if (my_xpath_parse_term(xpath, MY_XPATH_LEX_GREATER))
2195  {
2196  xpath->extra= my_xpath_parse_term(xpath, MY_XPATH_LEX_EQ) ?
2197  MY_XPATH_LEX_GE : MY_XPATH_LEX_GREATER;
2198  return 1;
2199  }
2200  return 0;
2201 }
2202 static int my_xpath_parse_RelationalExpr(MY_XPATH *xpath)
2203 {
2204  MY_XPATH_LEX operator_context;
2205  if (!my_xpath_parse_AdditiveExpr(xpath))
2206  return 0;
2207  operator_context= xpath->lasttok;
2208  while (my_xpath_parse_RelationalOperator(xpath))
2209  {
2210  Item *prev= xpath->item;
2211  int oper= xpath->extra;
2212 
2213  if (!my_xpath_parse_AdditiveExpr(xpath))
2214  {
2215  xpath->error= 1;
2216  return 0;
2217  }
2218 
2219  if (!(xpath->item= create_comparator(xpath, oper, &operator_context,
2220  prev, xpath->item)))
2221  return 0;
2222  operator_context= xpath->lasttok;
2223  }
2224  return 1;
2225 }
2226 
2227 
2228 /*
2229  Scan Additive Expression
2230 
2231  SYNOPSYS
2232 
2233  [25] AdditiveExpr ::= MultiplicativeExpr
2234  | AdditiveExpr '+' MultiplicativeExpr
2235  | AdditiveExpr '-' MultiplicativeExpr
2236  RETURN
2237  1 - success
2238  0 - failure
2239 */
2240 static int my_xpath_parse_AdditiveOperator(MY_XPATH *xpath)
2241 {
2242  return my_xpath_parse_term(xpath, MY_XPATH_LEX_PLUS) ||
2243  my_xpath_parse_term(xpath, MY_XPATH_LEX_MINUS);
2244 }
2245 static int my_xpath_parse_AdditiveExpr(MY_XPATH *xpath)
2246 {
2247  if (!my_xpath_parse_MultiplicativeExpr(xpath))
2248  return 0;
2249 
2250  while (my_xpath_parse_AdditiveOperator(xpath))
2251  {
2252  int oper= xpath->prevtok.term;
2253  Item *prev= xpath->item;
2254  if (!my_xpath_parse_MultiplicativeExpr(xpath))
2255  {
2256  xpath->error= 1;
2257  return 0;
2258  }
2259 
2260  if (oper == MY_XPATH_LEX_PLUS)
2261  xpath->item= new Item_func_plus(prev, xpath->item);
2262  else
2263  xpath->item= new Item_func_minus(prev, xpath->item);
2264  };
2265  return 1;
2266 }
2267 
2268 
2269 /*
2270  Scan Multiplicative Expression
2271 
2272  SYNOPSYS
2273 
2274  [26] MultiplicativeExpr ::= UnaryExpr
2275  | MultiplicativeExpr MultiplyOperator UnaryExpr
2276  | MultiplicativeExpr 'div' UnaryExpr
2277  | MultiplicativeExpr 'mod' UnaryExpr
2278  or in other words:
2279 
2280  [26] MultiplicativeExpr ::= UnaryExpr (MulOper MultiplicativeExpr)*
2281 
2282  RETURN
2283  1 - success
2284  0 - failure
2285 */
2286 static int my_xpath_parse_MultiplicativeOperator(MY_XPATH *xpath)
2287 {
2288  return
2289  my_xpath_parse_term(xpath, MY_XPATH_LEX_ASTERISK) ||
2290  my_xpath_parse_term(xpath, MY_XPATH_LEX_DIV) ||
2291  my_xpath_parse_term(xpath, MY_XPATH_LEX_MOD);
2292 }
2293 static int my_xpath_parse_MultiplicativeExpr(MY_XPATH *xpath)
2294 {
2295  if (!my_xpath_parse_UnaryExpr(xpath))
2296  return 0;
2297 
2298  while (my_xpath_parse_MultiplicativeOperator(xpath))
2299  {
2300  int oper= xpath->prevtok.term;
2301  Item *prev= xpath->item;
2302  if (!my_xpath_parse_UnaryExpr(xpath))
2303  {
2304  xpath->error= 1;
2305  return 0;
2306  }
2307  switch (oper)
2308  {
2309  case MY_XPATH_LEX_ASTERISK:
2310  xpath->item= new Item_func_mul(prev, xpath->item);
2311  break;
2312  case MY_XPATH_LEX_DIV:
2313  xpath->item= new Item_func_int_div(prev, xpath->item);
2314  break;
2315  case MY_XPATH_LEX_MOD:
2316  xpath->item= new Item_func_mod(prev, xpath->item);
2317  break;
2318  }
2319  }
2320  return 1;
2321 }
2322 
2323 
2324 /*
2325  Scan Unary Expression
2326 
2327  SYNOPSYS
2328 
2329  [27] UnaryExpr ::= UnionExpr
2330  | '-' UnaryExpr
2331  RETURN
2332  1 - success
2333  0 - failure
2334 */
2335 static int my_xpath_parse_UnaryExpr(MY_XPATH *xpath)
2336 {
2337  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_MINUS))
2338  return my_xpath_parse_UnionExpr(xpath);
2339  if (!my_xpath_parse_UnaryExpr(xpath))
2340  return 0;
2341  xpath->item= new Item_func_neg(xpath->item);
2342  return 1;
2343 }
2344 
2345 
2346 /*
2347  Scan Number
2348 
2349  SYNOPSYS
2350 
2351  [30] Number ::= Digits ('.' Digits?)? | '.' Digits)
2352 
2353  or in other words:
2354 
2355  [30] Number ::= Digits
2356  | Digits '.'
2357  | Digits '.' Digits
2358  | '.' Digits
2359 
2360  Note: the last rule is not supported yet,
2361  as it is in conflict with abbreviated step.
2362  1 + .123 does not work,
2363  1 + 0.123 does.
2364  Perhaps it is better to move this code into lex analizer.
2365 
2366  RETURN
2367  1 - success
2368  0 - failure
2369 */
2370 static int my_xpath_parse_Number(MY_XPATH *xpath)
2371 {
2372  const char *beg;
2373  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DIGITS))
2374  return 0;
2375  beg= xpath->prevtok.beg;
2376  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DOT))
2377  {
2378  xpath->item= new Item_int(xpath->prevtok.beg,
2379  xpath->prevtok.end - xpath->prevtok.beg);
2380  return 1;
2381  }
2382  my_xpath_parse_term(xpath, MY_XPATH_LEX_DIGITS);
2383 
2384  xpath->item= new Item_float(beg, xpath->prevtok.end - beg);
2385  return 1;
2386 }
2387 
2388 
2389 /*
2390  Scan NCName.
2391 
2392  SYNOPSYS
2393 
2394  The keywords AND, OR, MOD, DIV are valid identitiers
2395  when they are in identifier context:
2396 
2397  SELECT
2398  ExtractValue('<and><or><mod><div>VALUE</div></mod></or></and>',
2399  '/and/or/mod/div')
2400  -> VALUE
2401 
2402  RETURN
2403  1 - success
2404  0 - failure
2405 */
2406 
2407 static int
2408 my_xpath_parse_NCName(MY_XPATH *xpath)
2409 {
2410  return
2411  my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT) ||
2412  my_xpath_parse_term(xpath, MY_XPATH_LEX_AND) ||
2413  my_xpath_parse_term(xpath, MY_XPATH_LEX_OR) ||
2414  my_xpath_parse_term(xpath, MY_XPATH_LEX_MOD) ||
2415  my_xpath_parse_term(xpath, MY_XPATH_LEX_DIV) ? 1 : 0;
2416 }
2417 
2418 
2419 /*
2420  QName grammar can be found in a separate document
2421  http://www.w3.org/TR/REC-xml-names/#NT-QName
2422 
2423  [6] QName ::= (Prefix ':')? LocalPart
2424  [7] Prefix ::= NCName
2425  [8] LocalPart ::= NCName
2426 */
2427 
2428 static int
2429 my_xpath_parse_QName(MY_XPATH *xpath)
2430 {
2431  const char *beg;
2432  if (!my_xpath_parse_NCName(xpath))
2433  return 0;
2434  beg= xpath->prevtok.beg;
2435  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_COLON))
2436  return 1; /* Non qualified name */
2437  if (!my_xpath_parse_NCName(xpath))
2438  return 0;
2439  xpath->prevtok.beg= beg;
2440  return 1;
2441 }
2442 
2443 
2471 static int
2472 my_xpath_parse_VariableReference(MY_XPATH *xpath)
2473 {
2474  LEX_STRING name;
2475  int user_var;
2476  const char *dollar_pos;
2477  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DOLLAR) ||
2478  (!(dollar_pos= xpath->prevtok.beg)) ||
2479  (!((user_var= my_xpath_parse_term(xpath, MY_XPATH_LEX_AT) &&
2480  my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))) &&
2481  !my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT)))
2482  return 0;
2483 
2484  name.length= xpath->prevtok.end - xpath->prevtok.beg;
2485  name.str= (char*) xpath->prevtok.beg;
2486 
2487  if (user_var)
2488  xpath->item= new Item_func_get_user_var(Name_string(name, false));
2489  else
2490  {
2491  sp_variable *spv;
2492  sp_pcontext *spc;
2493  LEX *lex;
2494  if ((lex= current_thd->lex) &&
2495  (spc= lex->get_sp_current_parsing_ctx()) &&
2496  (spv= spc->find_variable(name, false)))
2497  {
2498  Item_splocal *splocal= new Item_splocal(Name_string(name, false),
2499  spv->offset, spv->type, 0);
2500 #ifndef DBUG_OFF
2501  if (splocal)
2502  splocal->m_sp= lex->sphead;
2503 #endif
2504  xpath->item= (Item*) splocal;
2505  }
2506  else
2507  {
2508  xpath->item= NULL;
2509  DBUG_ASSERT(xpath->query.end > dollar_pos);
2510  uint len= xpath->query.end - dollar_pos;
2511  set_if_smaller(len, 32);
2512  my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.*s'",
2513  MYF(0), len, dollar_pos);
2514  }
2515  }
2516  return xpath->item ? 1 : 0;
2517 }
2518 
2519 
2520 /*
2521  Scan Name Test
2522 
2523  SYNOPSYS
2524 
2525  [37] NameTest ::= '*'
2526  | NCName ':' '*'
2527  | QName
2528  RETURN
2529  1 - success
2530  0 - failure
2531 */
2532 static int
2533 my_xpath_parse_NodeTest_QName(MY_XPATH *xpath)
2534 {
2535  if (!my_xpath_parse_QName(xpath))
2536  return 0;
2537  DBUG_ASSERT(xpath->context);
2538  uint len= xpath->prevtok.end - xpath->prevtok.beg;
2539  xpath->context= nametestfunc(xpath, xpath->axis, xpath->context,
2540  xpath->prevtok.beg, len);
2541  return 1;
2542 }
2543 static int
2544 my_xpath_parse_NodeTest_asterisk(MY_XPATH *xpath)
2545 {
2546  if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_ASTERISK))
2547  return 0;
2548  DBUG_ASSERT(xpath->context);
2549  xpath->context= nametestfunc(xpath, xpath->axis, xpath->context, "*", 1);
2550  return 1;
2551 }
2552 static int
2553 my_xpath_parse_NameTest(MY_XPATH *xpath)
2554 {
2555  return my_xpath_parse_NodeTest_asterisk(xpath) ||
2556  my_xpath_parse_NodeTest_QName(xpath);
2557 }
2558 
2559 
2560 /*
2561  Scan an XPath expression
2562 
2563  SYNOPSYS
2564  Scan xpath expression.
2565  The expression is returned in xpath->expr.
2566 
2567  RETURN
2568  1 - success
2569  0 - failure
2570 */
2571 static int
2572 my_xpath_parse(MY_XPATH *xpath, const char *str, const char *strend)
2573 {
2574  my_xpath_lex_init(&xpath->query, str, strend);
2575  my_xpath_lex_init(&xpath->prevtok, str, strend);
2576  my_xpath_lex_scan(xpath, &xpath->lasttok, str, strend);
2577 
2578  xpath->rootelement= new Item_nodeset_func_rootelement(xpath->pxml);
2579 
2580  return
2581  my_xpath_parse_Expr(xpath) &&
2582  my_xpath_parse_term(xpath, MY_XPATH_LEX_EOF);
2583 }
2584 
2585 
2586 void Item_xml_str_func::fix_length_and_dec()
2587 {
2588  nodeset_func= 0;
2589 
2590  if (agg_arg_charsets_for_comparison(collation, args, arg_count))
2591  return;
2592 
2593  if (collation.collation->mbminlen > 1)
2594  {
2595  /* UCS2 is not supported */
2596  my_printf_error(ER_UNKNOWN_ERROR,
2597  "Character set '%s' is not supported by XPATH",
2598  MYF(0), collation.collation->csname);
2599  return;
2600  }
2601 
2602  if (!args[1]->const_during_execution())
2603  {
2604  my_printf_error(ER_UNKNOWN_ERROR,
2605  "Only constant XPATH queries are supported", MYF(0));
2606  return;
2607  }
2608 
2609  if (args[1]->const_item())
2610  parse_xpath(args[1]);
2611 
2612  max_length= MAX_BLOB_WIDTH;
2613 }
2614 
2616 {
2617  String *xp, tmp;
2618  MY_XPATH xpath;
2619 
2620  if (!(xp= xpath_expr->val_str(&tmp)))
2621  return;
2622 
2623  my_xpath_init(&xpath);
2624  xpath.cs= collation.collation;
2625  xpath.debug= 0;
2626  xpath.pxml= &pxml;
2627  pxml.set_charset(collation.collation);
2628 
2629  int rc= my_xpath_parse(&xpath, xp->ptr(), xp->ptr() + xp->length());
2630 
2631  if (!rc)
2632  {
2633  uint clen= xpath.query.end - xpath.lasttok.beg;
2634  set_if_smaller(clen, 32);
2635  my_printf_error(ER_UNKNOWN_ERROR, "XPATH syntax error: '%.*s'",
2636  MYF(0), clen, xpath.lasttok.beg);
2637  return;
2638  }
2639 
2640  nodeset_func= xpath.item;
2641  if (nodeset_func)
2642  nodeset_func->fix_fields(current_thd, &nodeset_func);
2643 }
2644 
2645 
2646 #define MAX_LEVEL 256
2647 typedef struct
2648 {
2649  uint level;
2650  String *pxml; // parsed XML
2651  uint pos[MAX_LEVEL]; // Tag position stack
2652  uint parent; // Offset of the parent of the current node
2654 
2655 
2656 static bool
2657 append_node(String *str, MY_XML_NODE *node)
2658 {
2659  /*
2660  If "str" doesn't have space for a new node,
2661  it will allocate two times more space that it has had so far.
2662  (2*len+512) is a heuristic value,
2663  which gave the best performance during tests.
2664  The ideas behind this formula are:
2665  - It allows to have a very small number of reallocs:
2666  about 10 reallocs on a 1Mb-long XML value.
2667  - At the same time, it avoids excessive memory use.
2668  */
2669  if (str->reserve(sizeof(MY_XML_NODE), 2 * str->length() + 512))
2670  return TRUE;
2671  str->q_append((const char*) node, sizeof(MY_XML_NODE));
2672  return FALSE;
2673 }
2674 
2675 
2676 /*
2677  Process tag beginning
2678 
2679  SYNOPSYS
2680 
2681  A call-back function executed when XML parser
2682  is entering a tag or an attribue.
2683  Appends the new node into data->pxml.
2684  Increments data->level.
2685 
2686  RETURN
2687  Currently only MY_XML_OK
2688 */
2689 extern "C" int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len);
2690 
2691 int xml_enter(MY_XML_PARSER *st,const char *attr, size_t len)
2692 {
2693  MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
2694  uint numnodes= data->pxml->length() / sizeof(MY_XML_NODE);
2695  MY_XML_NODE node;
2696 
2697  node.parent= data->parent; // Set parent for the new node to old parent
2698  data->parent= numnodes; // Remember current node as new parent
2699  DBUG_ASSERT(data->level <= MAX_LEVEL);
2700  data->pos[data->level]= numnodes;
2701  if (data->level < MAX_LEVEL)
2702  node.level= data->level++;
2703  else
2704  return MY_XML_ERROR;
2705  node.type= st->current_node_type; // TAG or ATTR
2706  node.beg= attr;
2707  node.end= attr + len;
2708  return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK;
2709 }
2710 
2711 
2712 /*
2713  Process text node
2714 
2715  SYNOPSYS
2716 
2717  A call-back function executed when XML parser
2718  is entering into a tag or an attribue textual value.
2719  The value is appended into data->pxml.
2720 
2721  RETURN
2722  Currently only MY_XML_OK
2723 */
2724 extern "C" int xml_value(MY_XML_PARSER *st,const char *attr, size_t len);
2725 
2726 int xml_value(MY_XML_PARSER *st,const char *attr, size_t len)
2727 {
2728  MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
2729  MY_XML_NODE node;
2730 
2731  node.parent= data->parent; // Set parent for the new text node to old parent
2732  node.level= data->level;
2733  node.type= MY_XML_NODE_TEXT;
2734  node.beg= attr;
2735  node.end= attr + len;
2736  return append_node(data->pxml, &node) ? MY_XML_ERROR : MY_XML_OK;
2737 }
2738 
2739 
2740 /*
2741  Leave a tag or an attribute
2742 
2743  SYNOPSYS
2744 
2745  A call-back function executed when XML parser
2746  is leaving a tag or an attribue.
2747  Decrements data->level.
2748 
2749  RETURN
2750  Currently only MY_XML_OK
2751 */
2752 extern "C" int xml_leave(MY_XML_PARSER *st,const char *attr, size_t len);
2753 
2754 int xml_leave(MY_XML_PARSER *st,const char *attr, size_t len)
2755 {
2756  MY_XML_USER_DATA *data= (MY_XML_USER_DATA*)st->user_data;
2757  DBUG_ASSERT(data->level > 0);
2758  data->level--;
2759 
2760  MY_XML_NODE *nodes= (MY_XML_NODE*) data->pxml->ptr();
2761  data->parent= nodes[data->parent].parent;
2762  nodes+= data->pos[data->level];
2763  nodes->tagend= st->cur;
2764 
2765  return MY_XML_OK;
2766 }
2767 
2768 
2769 /*
2770  Parse raw XML
2771 
2772  SYNOPSYS
2773 
2774 
2775  RETURN
2776  Currently pointer to parsed XML on success
2777  0 on parse error
2778 */
2779 String *Item_xml_str_func::parse_xml(String *raw_xml, String *parsed_xml_buf)
2780 {
2781  MY_XML_PARSER p;
2782  MY_XML_USER_DATA user_data;
2783  int rc;
2784 
2785  parsed_xml_buf->length(0);
2786 
2787  /* Prepare XML parser */
2788  my_xml_parser_create(&p);
2789  p.flags= MY_XML_FLAG_RELATIVE_NAMES | MY_XML_FLAG_SKIP_TEXT_NORMALIZATION;
2790  user_data.level= 0;
2791  user_data.pxml= parsed_xml_buf;
2792  user_data.parent= 0;
2793  my_xml_set_enter_handler(&p, xml_enter);
2794  my_xml_set_value_handler(&p, xml_value);
2795  my_xml_set_leave_handler(&p, xml_leave);
2796  my_xml_set_user_data(&p, (void*) &user_data);
2797 
2798  /* Add root node */
2799  p.current_node_type= MY_XML_NODE_TAG;
2800  xml_enter(&p, raw_xml->ptr(), 0);
2801 
2802  /* Execute XML parser */
2803  if ((rc= my_xml_parse(&p, raw_xml->ptr(), raw_xml->length())) != MY_XML_OK)
2804  {
2805  char buf[128];
2806  my_snprintf(buf, sizeof(buf)-1, "parse error at line %d pos %lu: %s",
2807  my_xml_error_lineno(&p) + 1,
2808  (ulong) my_xml_error_pos(&p) + 1,
2809  my_xml_error_string(&p));
2810  push_warning_printf(current_thd, Sql_condition::WARN_LEVEL_WARN,
2811  ER_WRONG_VALUE,
2812  ER(ER_WRONG_VALUE), "XML", buf);
2813  }
2814  my_xml_parser_free(&p);
2815 
2816  return rc == MY_XML_OK ? parsed_xml_buf : 0;
2817 }
2818 
2819 
2820 String *Item_func_xml_extractvalue::val_str(String *str)
2821 {
2822  String *res;
2823  null_value= 0;
2824  if (!nodeset_func)
2825  parse_xpath(args[1]);
2826  if (!nodeset_func ||
2827  !(res= args[0]->val_str(str)) ||
2828  !parse_xml(res, &pxml) ||
2829  !(res= nodeset_func->val_str(&tmp_value)))
2830  {
2831  null_value= 1;
2832  return 0;
2833  }
2834  return res;
2835 }
2836 
2837 
2838 String *Item_func_xml_update::val_str(String *str)
2839 {
2840  String *res, *nodeset, *rep;
2841 
2842  null_value= 0;
2843  if (!nodeset_func)
2844  parse_xpath(args[1]);
2845  if (!nodeset_func ||
2846  !(res= args[0]->val_str(str)) ||
2847  !(rep= args[2]->val_str(&tmp_value3)) ||
2848  !parse_xml(res, &pxml) ||
2849  !(nodeset= nodeset_func->val_nodeset(&tmp_value2)))
2850  {
2851  null_value= 1;
2852  return 0;
2853  }
2854 
2855  MY_XML_NODE *nodebeg= (MY_XML_NODE*) pxml.ptr();
2856  MY_XPATH_FLT *fltbeg= (MY_XPATH_FLT*) nodeset->ptr();
2857  MY_XPATH_FLT *fltend= (MY_XPATH_FLT*) (nodeset->ptr() + nodeset->length());
2858 
2859  /* Allow replacing of one tag only */
2860  if (fltend - fltbeg != 1)
2861  {
2862  /* TODO: perhaps add a warning that more than one tag selected */
2863  return res;
2864  }
2865 
2866  nodebeg+= fltbeg->num;
2867 
2868  if (!nodebeg->level)
2869  {
2870  /*
2871  Root element, without NameTest:
2872  UpdateXML(xml, '/', 'replacement');
2873  Just return the replacement string.
2874  */
2875  return rep;
2876  }
2877 
2878  tmp_value.length(0);
2879  tmp_value.set_charset(collation.collation);
2880  uint offs= nodebeg->type == MY_XML_NODE_TAG ? 1 : 0;
2881  tmp_value.append(res->ptr(), nodebeg->beg - res->ptr() - offs);
2882  tmp_value.append(rep->ptr(), rep->length());
2883  const char *end= nodebeg->tagend + offs;
2884  tmp_value.append(end, res->ptr() + res->length() - end);
2885  return &tmp_value;
2886 }