Commit a5694ba4 authored by unknown's avatar unknown
Browse files

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.


sql/item_xmlfunc.cc:
  Bug#16318: XML: extractvalue() incorrectly returns last() = 1
  - 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.
mysql-test/t/xml.test:
  Adding test case.
mysql-test/r/xml.result:
  Adding test case.
parent 104b9e78
Loading
Loading
Loading
Loading
+36 −0
Original line number Diff line number Diff line
@@ -561,3 +561,39 @@ A B C
select extractvalue('<A_B>A</A_B>','/A_B');
extractvalue('<A_B>A</A_B>','/A_B')
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
+16 −0
Original line number Diff line number Diff line
@@ -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
#
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()]');
+29 −12
Original line number Diff line number Diff line
@@ -30,7 +30,6 @@
  2. add nodeset_to_nodeset_comparator
  3. add lacking functions:
       - name()
       - last()
       - lang()
       - string()
       - id()
@@ -75,6 +74,7 @@ typedef struct my_xpath_flt_st
{
  uint num;     /* absolute position in MY_XML_NODE array */
  uint pos;     /* relative position in context           */
  uint size;    /* context size                           */
} MY_XPATH_FLT;


@@ -123,6 +123,15 @@ class XPathFilter :public String
    MY_XPATH_FLT add;
    add.num= num;
    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);
  }
  inline MY_XPATH_FLT *element(uint i)
@@ -451,7 +460,11 @@ class Item_func_xpath_count :public Item_int_func
  void fix_length_and_dec() { max_length=10; }
  longlong val_int()
  {
    uint predicate_supplied_context_size;
    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);
  }
};
@@ -731,13 +744,15 @@ String *Item_nodeset_func_predicate::val_nodeset(String *str)
{
  Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
  Item_func *comp_func= (Item_func*)args[1];
  uint pos= 0;
  uint pos= 0, size;
  prepare(str);
  size= fltend - fltbeg;
  for (MY_XPATH_FLT *flt= fltbeg; flt < fltend; flt++)
  {
    nodeset_func->context_cache.length(0);
    ((XPathFilter*)(&nodeset_func->context_cache))->append_element(flt->num,
                                                                   flt->pos);
                                                                   flt->pos,
                                                                   size);
    if (comp_func->val_int())
      ((XPathFilter*)str)->append_element(flt->num, pos++);
  }
@@ -747,18 +762,20 @@ String *Item_nodeset_func_predicate::val_nodeset(String *str)

String *Item_nodeset_func_elementbyindex::val_nodeset(String *nodeset)
{
  Item_nodeset_func *nodeset_func= (Item_nodeset_func*) args[0];
  prepare(nodeset);
  int index= args[1]->val_int() - 1;
  if (index >= 0)
  {
  MY_XPATH_FLT *flt;
    uint pos;
  uint pos, size= fltend - fltbeg;
  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++);
  }
  }
  return nodeset;
}