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