From a5694ba4cf36bbb4434d319665831fb25b1c995e Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 3 Mar 2006 18:36:14 +0400 Subject: 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. --- mysql-test/r/xml.result | 36 ++++++++++++++++++++++++++++++++++++ mysql-test/t/xml.test | 16 ++++++++++++++++ sql/item_xmlfunc.cc | 41 +++++++++++++++++++++++++++++------------ 3 files changed, 81 insertions(+), 12 deletions(-) diff --git a/mysql-test/r/xml.result b/mysql-test/r/xml.result index 0b75b50f754..da2e2e400ad 100644 --- a/mysql-test/r/xml.result +++ b/mysql-test/r/xml.result @@ -561,3 +561,39 @@ A B C select extractvalue('A','/A_B'); extractvalue('A','/A_B') A +select extractvalue('AB1B2','/a/b[position()]'); +extractvalue('AB1B2','/a/b[position()]') +B1 B2 +select extractvalue('AB1B2','/a/b[count(.)=last()]'); +extractvalue('AB1B2','/a/b[count(.)=last()]') +B1 B2 +select extractvalue('AB1B2','/a/b[last()]'); +extractvalue('AB1B2','/a/b[last()]') +B2 +select extractvalue('AB1B2','/a/b[last()-1]'); +extractvalue('AB1B2','/a/b[last()-1]') +B1 +select extractvalue('AB1B2','/a/b[last()=1]'); +extractvalue('AB1B2','/a/b[last()=1]') + +select extractvalue('AB1B2','/a/b[last()=2]'); +extractvalue('AB1B2','/a/b[last()=2]') +B1 B2 +select extractvalue('AB1B2','/a/b[last()=position()]'); +extractvalue('AB1B2','/a/b[last()=position()]') +B2 +select extractvalue('AB1B2','/a/b[count(.)]'); +extractvalue('AB1B2','/a/b[count(.)]') +B2 +select extractvalue('AB1B2','/a/b[count(.)-1]'); +extractvalue('AB1B2','/a/b[count(.)-1]') +B1 +select extractvalue('AB1B2','/a/b[count(.)=1]'); +extractvalue('AB1B2','/a/b[count(.)=1]') + +select extractvalue('AB1B2','/a/b[count(.)=2]'); +extractvalue('AB1B2','/a/b[count(.)=2]') +B1 B2 +select extractvalue('AB1B2','/a/b[count(.)=position()]'); +extractvalue('AB1B2','/a/b[count(.)=position()]') +B2 diff --git a/mysql-test/t/xml.test b/mysql-test/t/xml.test index 6a91d785d4e..b4272c7cabc 100644 --- a/mysql-test/t/xml.test +++ b/mysql-test/t/xml.test @@ -254,3 +254,19 @@ select extractvalue('ABC','/a/descendant-or-self::*'); # Bug #16320 XML: extractvalue() won't accept names containing underscores # select extractvalue('A','/A_B'); + +# +# Bug#16318: XML: extractvalue() incorrectly returns last() = 1 +# +select extractvalue('AB1B2','/a/b[position()]'); +select extractvalue('AB1B2','/a/b[count(.)=last()]'); +select extractvalue('AB1B2','/a/b[last()]'); +select extractvalue('AB1B2','/a/b[last()-1]'); +select extractvalue('AB1B2','/a/b[last()=1]'); +select extractvalue('AB1B2','/a/b[last()=2]'); +select extractvalue('AB1B2','/a/b[last()=position()]'); +select extractvalue('AB1B2','/a/b[count(.)]'); +select extractvalue('AB1B2','/a/b[count(.)-1]'); +select extractvalue('AB1B2','/a/b[count(.)=1]'); +select extractvalue('AB1B2','/a/b[count(.)=2]'); +select extractvalue('AB1B2','/a/b[count(.)=position()]'); diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc index 26c2e84f8dd..453865e17a8 100644 --- a/sql/item_xmlfunc.cc +++ b/sql/item_xmlfunc.cc @@ -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 @@ public: 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 @@ public: 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,17 +762,19 @@ 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, size= fltend - fltbeg; + for (pos= 0, flt= fltbeg; flt < fltend; flt++) { - MY_XPATH_FLT *flt; - uint pos; - for (pos= 0, flt= fltbeg; flt < fltend; flt++) - { - if (flt->pos == (uint) index || args[1]->is_bool_func()) - ((XPathFilter*)nodeset)->append_element(flt->num, pos++); - } + 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; } -- cgit v1.2.1