Commit f516d1f9 authored by bar@mysql.com's avatar bar@mysql.com

Bug#16318: XML: extractvalue() incorrectly returns last() = 1

xml.result, xml.test:
  Adding test case.
item_xmlfunc.cc:
  - adding "size" member into MY_XPATH_FLT struct,
  to pass parent's context size when iterating
  in a predicate. Previously, temporaty context
  size was calculated instead, which is always 1.
  As a result, things like last() and count() 
  didn't work fine.
  - adding iteration into Item_func_xpath_elementbyindex:
  similar to Item_func_xpath_predicate.
  This is to make things like last() and count()
  work inside square brackets.
parent c7837821
...@@ -561,3 +561,39 @@ A B C ...@@ -561,3 +561,39 @@ A B C
select extractvalue('<A_B>A</A_B>','/A_B'); select extractvalue('<A_B>A</A_B>','/A_B');
extractvalue('<A_B>A</A_B>','/A_B') extractvalue('<A_B>A</A_B>','/A_B')
A A
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[position()]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[position()]')
B1 B2
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=last()]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=last()]')
B1 B2
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()]')
B2
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()-1]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()-1]')
B1
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=1]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=1]')
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=2]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=2]')
B1 B2
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=position()]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=position()]')
B2
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)]')
B2
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)-1]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)-1]')
B1
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=1]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=1]')
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=2]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=2]')
B1 B2
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=position()]');
extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=position()]')
B2
...@@ -254,3 +254,19 @@ select extractvalue('<a>A<b>B<c>C</c></b></a>','/a/descendant-or-self::*'); ...@@ -254,3 +254,19 @@ select extractvalue('<a>A<b>B<c>C</c></b></a>','/a/descendant-or-self::*');
# Bug #16320 XML: extractvalue() won't accept names containing underscores # Bug #16320 XML: extractvalue() won't accept names containing underscores
# #
select extractvalue('<A_B>A</A_B>','/A_B'); select extractvalue('<A_B>A</A_B>','/A_B');
#
# Bug#16318: XML: extractvalue() incorrectly returns last() = 1
#
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[position()]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=last()]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()-1]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=1]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=2]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[last()=position()]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)-1]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=1]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=2]');
select extractvalue('<a>A<b>B1</b><b>B2</b></a>','/a/b[count(.)=position()]');
...@@ -30,7 +30,6 @@ ...@@ -30,7 +30,6 @@
2. add nodeset_to_nodeset_comparator 2. add nodeset_to_nodeset_comparator
3. add lacking functions: 3. add lacking functions:
- name() - name()
- last()
- lang() - lang()
- string() - string()
- id() - id()
...@@ -75,6 +74,7 @@ typedef struct my_xpath_flt_st ...@@ -75,6 +74,7 @@ typedef struct my_xpath_flt_st
{ {
uint num; /* absolute position in MY_XML_NODE array */ uint num; /* absolute position in MY_XML_NODE array */
uint pos; /* relative position in context */ uint pos; /* relative position in context */
uint size; /* context size */
} MY_XPATH_FLT; } MY_XPATH_FLT;
...@@ -123,6 +123,15 @@ class XPathFilter :public String ...@@ -123,6 +123,15 @@ class XPathFilter :public String
MY_XPATH_FLT add; MY_XPATH_FLT add;
add.num= num; add.num= num;
add.pos= pos; add.pos= pos;
add.size= 0;
return append_element(&add);
}
inline bool append_element(uint32 num, uint32 pos, uint32 size)
{
MY_XPATH_FLT add;
add.num= num;
add.pos= pos;
add.size= size;
return append_element(&add); return append_element(&add);
} }
inline MY_XPATH_FLT *element(uint i) inline MY_XPATH_FLT *element(uint i)
...@@ -451,7 +460,11 @@ class Item_func_xpath_count :public Item_int_func ...@@ -451,7 +460,11 @@ class Item_func_xpath_count :public Item_int_func
void fix_length_and_dec() { max_length=10; } void fix_length_and_dec() { max_length=10; }
longlong val_int() longlong val_int()
{ {
uint predicate_supplied_context_size;
String *res= args[0]->val_nodeset(&tmp_value); String *res= args[0]->val_nodeset(&tmp_value);
if (res->length() == sizeof(MY_XPATH_FLT) &&
(predicate_supplied_context_size= ((MY_XPATH_FLT*)res->ptr())->size))
return predicate_supplied_context_size;
return res->length() / sizeof(MY_XPATH_FLT); return res->length() / sizeof(MY_XPATH_FLT);
} }
}; };
...@@ -731,13 +744,15 @@ String *Item_nodeset_func_predicate::val_nodeset(String *str) ...@@ -731,13 +744,15 @@ String *Item_nodeset_func_predicate::val_nodeset(String *str)
{ {
Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0]; Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
Item_func *comp_func= (Item_func*)args[1]; Item_func *comp_func= (Item_func*)args[1];
uint pos= 0; uint pos= 0, size;
prepare(str); prepare(str);
size= fltend - fltbeg;
for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++) for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
{ {
nodeset_func->context_cache.length(0); nodeset_func->context_cache.length(0);
((XPathFilter*)(&nodeset_func->context_cache))->append_element(flt->num, ((XPathFilter*)(&nodeset_func->context_cache))->append_element(flt->num,
flt->pos); flt->pos,
size);
if (comp_func->val_int()) if (comp_func->val_int())
((XPathFilter*)str)->append_element(flt->num, pos++); ((XPathFilter*)str)->append_element(flt->num, pos++);
} }
...@@ -747,18 +762,20 @@ String *Item_nodeset_func_predicate::val_nodeset(String *str) ...@@ -747,18 +762,20 @@ String *Item_nodeset_func_predicate::val_nodeset(String *str)
String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset) String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset)
{ {
Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
prepare(nodeset); prepare(nodeset);
int index= args[1]->val_int() - 1;
if (index >= 0)
{
MY_XPATH_FLT *flt; MY_XPATH_FLT *flt;
uint pos; uint pos, size= fltend - fltbeg;
for (pos= 0, flt= fltbeg; flt < fltend; flt++) for (pos= 0, flt= fltbeg; flt < fltend; flt++)
{ {
if (flt->pos == (uint) index || args[1]->is_bool_func()) nodeset_func->context_cache.length(0);
((XPathFilter*)(&nodeset_func->context_cache))->append_element(flt->num,
flt->pos,
size);
int index= args[1]->val_int() - 1;
if (index >= 0 && (flt->pos == (uint) index || args[1]->is_bool_func()))
((XPathFilter*)nodeset)->append_element(flt->num, pos++); ((XPathFilter*)nodeset)->append_element(flt->num, pos++);
} }
}
return nodeset; return nodeset;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment