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