summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <bar@mysql.com/bar.myoffice.izhnet.ru>2007-05-08 13:32:29 +0500
committerunknown <bar@mysql.com/bar.myoffice.izhnet.ru>2007-05-08 13:32:29 +0500
commit8ce067caead824123c16f190d606f8e0b061a6c0 (patch)
treebf966c606772dae56fc754b02433451de35e99c6
parent11aa04c993280023f46728f3ee57bf22a9adbb50 (diff)
downloadmariadb-git-8ce067caead824123c16f190d606f8e0b061a6c0.tar.gz
Bug#26518 XPath and variables problem
Problem: XPath variables didn't work. Fix: adding variables support, both user-defined and sp local variables are now supported by XPath. mysql-test/r/xml.result: Adding test case mysql-test/t/xml.test: Adding test case sql/item_xmlfunc.cc: Adding variables support: - SP variables with standard XPath syntax: $i - User variables with non-standard syntax: $@i
-rw-r--r--mysql-test/r/xml.result115
-rw-r--r--mysql-test/t/xml.test72
-rw-r--r--sql/item_xmlfunc.cc75
3 files changed, 253 insertions, 9 deletions
diff --git a/mysql-test/r/xml.result b/mysql-test/r/xml.result
index 236c50774bd..f5ef919fd93 100644
--- a/mysql-test/r/xml.result
+++ b/mysql-test/r/xml.result
@@ -884,3 +884,118 @@ test
select ExtractValue('<a><self>test</self></a>', '/a/self');
ExtractValue('<a><self>test</self></a>', '/a/self')
test
+set @i=1;
+select ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]')
+b1
+set @i=2;
+select ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]')
+b2
+set @i=NULL;
+select ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]')
+
+CREATE PROCEDURE spxml(xml VARCHAR(128))
+BEGIN
+DECLARE c INT;
+DECLARE i INT DEFAULT 1;
+SET c= ExtractValue(xml,'count(/a/b)');
+SET @i= c;
+WHILE i <= c DO
+BEGIN
+SELECT i, @i, ExtractValue(xml,'/a/b[$i]'), ExtractValue(xml,'/a/b[$@i]');
+SET i= i + 1;
+SET @i= @i - 1;
+END;
+END WHILE;
+END|
+call spxml('<a><b>b1</b><b>b2</b><b>b3</b></a>');
+i @i ExtractValue(xml,'/a/b[$i]') ExtractValue(xml,'/a/b[$@i]')
+1 3 b1 b3
+i @i ExtractValue(xml,'/a/b[$i]') ExtractValue(xml,'/a/b[$@i]')
+2 2 b2 b2
+i @i ExtractValue(xml,'/a/b[$i]') ExtractValue(xml,'/a/b[$@i]')
+3 1 b3 b1
+drop procedure spxml;
+Multiple matches, but no index specification
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b')
+b1 b2
+No matches
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/c');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/c')
+
+Index out of range
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[-1]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[-1]')
+
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[10]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[10]')
+
+With string-to-number conversion
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["1"]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["1"]')
+b1
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["1 and string"]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["1 and string"]')
+b1
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: '1 and string"]'
+Warning 1292 Truncated incorrect INTEGER value: '1 and string"]'
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["string and 1"]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["string and 1"]')
+
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: 'string and 1"]'
+Warning 1292 Truncated incorrect INTEGER value: 'string and 1"]'
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["string"]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["string"]')
+
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: 'string"]'
+Warning 1292 Truncated incorrect INTEGER value: 'string"]'
+String-to-number conversion from a user variable
+SET @i='1';
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]')
+b1
+SET @i='1 and string';
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]')
+b1
+SET @i='string and 1';
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]')
+
+SET @i='string';
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]')
+
+String-to-number conversion with a CHAR SP variable
+CREATE PROCEDURE spxml(xml VARCHAR(128), i CHAR(16))
+BEGIN
+SELECT ExtractValue(xml,'/a/b[$i]');
+END|
+CALL spxml('<a><b>b1</b><b>b2</b></a>', '1');
+ExtractValue(xml,'/a/b[$i]')
+b1
+CALL spxml('<a><b>b1</b><b>b2</b></a>', '1 and string');
+ExtractValue(xml,'/a/b[$i]')
+b1
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: '1 and string '
+Warning 1292 Truncated incorrect INTEGER value: '1 and string '
+CALL spxml('<a><b>b1</b><b>b2</b></a>', 'string and 1');
+ExtractValue(xml,'/a/b[$i]')
+
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: 'string and 1 '
+Warning 1292 Truncated incorrect INTEGER value: 'string and 1 '
+CALL spxml('<a><b>b1</b><b>b2</b></a>', 'string');
+ExtractValue(xml,'/a/b[$i]')
+
+Warnings:
+Warning 1292 Truncated incorrect INTEGER value: 'string '
+Warning 1292 Truncated incorrect INTEGER value: 'string '
+DROP PROCEDURE spxml;
diff --git a/mysql-test/t/xml.test b/mysql-test/t/xml.test
index 8517dce111f..94b45fa249f 100644
--- a/mysql-test/t/xml.test
+++ b/mysql-test/t/xml.test
@@ -444,3 +444,75 @@ select ExtractValue('<a><parent>test</parent></a>', '/a/parent');
select ExtractValue('<a><preceding>test</preceding></a>', '/a/preceding');
select ExtractValue('<a><preceding-sibling>test</preceding-sibling></a>', '/a/preceding-sibling');
select ExtractValue('<a><self>test</self></a>', '/a/self');
+
+#
+# Bug#26518 XPath and variables problem
+# Check with user defined variables
+#
+set @i=1;
+select ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+set @i=2;
+select ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+set @i=NULL;
+select ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+
+#
+# Check variables in a stored procedure - both local and user variables
+# Make sure that SP and local variables with the same name work together.
+#
+DELIMITER |;
+CREATE PROCEDURE spxml(xml VARCHAR(128))
+BEGIN
+ DECLARE c INT;
+ DECLARE i INT DEFAULT 1;
+ SET c= ExtractValue(xml,'count(/a/b)');
+ SET @i= c;
+ WHILE i <= c DO
+ BEGIN
+ SELECT i, @i, ExtractValue(xml,'/a/b[$i]'), ExtractValue(xml,'/a/b[$@i]');
+ SET i= i + 1;
+ SET @i= @i - 1;
+ END;
+ END WHILE;
+END|
+DELIMITER ;|
+
+call spxml('<a><b>b1</b><b>b2</b><b>b3</b></a>');
+drop procedure spxml;
+
+#
+# Additional tests for bug#26518
+--echo Multiple matches, but no index specification
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b');
+--echo No matches
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/c');
+--echo Index out of range
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[-1]');
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[10]');
+--echo With string-to-number conversion
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["1"]');
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["1 and string"]');
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["string and 1"]');
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b["string"]');
+--echo String-to-number conversion from a user variable
+SET @i='1';
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+SET @i='1 and string';
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+SET @i='string and 1';
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+SET @i='string';
+SELECT ExtractValue('<a><b>b1</b><b>b2</b></a>','/a/b[$@i]');
+
+--echo String-to-number conversion with a CHAR SP variable
+DELIMITER |;
+CREATE PROCEDURE spxml(xml VARCHAR(128), i CHAR(16))
+BEGIN
+ SELECT ExtractValue(xml,'/a/b[$i]');
+END|
+DELIMITER ;|
+CALL spxml('<a><b>b1</b><b>b2</b></a>', '1');
+CALL spxml('<a><b>b1</b><b>b2</b></a>', '1 and string');
+CALL spxml('<a><b>b1</b><b>b2</b></a>', 'string and 1');
+CALL spxml('<a><b>b1</b><b>b2</b></a>', 'string');
+DROP PROCEDURE spxml;
diff --git a/sql/item_xmlfunc.cc b/sql/item_xmlfunc.cc
index 26474990644..52962b3558e 100644
--- a/sql/item_xmlfunc.cc
+++ b/sql/item_xmlfunc.cc
@@ -19,7 +19,7 @@
#include "mysql_priv.h"
#include "my_xml.h"
-
+#include "sp_pcontext.h"
/*
TODO: future development directions:
@@ -2412,21 +2412,78 @@ my_xpath_parse_QName(MY_XPATH *xpath)
}
-/*
+/**
Scan Variable reference
- SYNOPSYS
+ @details Implements parsing of two syntax structures:
- [36] VariableReference ::= '$' QName
- RETURN
- 1 - success
- 0 - failure
+ 1. Standard XPath syntax [36], for SP variables:
+
+ VariableReference ::= '$' QName
+
+ Finds a SP variable with the given name.
+ If outside of a SP context, or variable with
+ the given name doesn't exists, then error is returned.
+
+ 2. Non-standard syntax - MySQL extension for user variables:
+
+ VariableReference ::= '$' '@' QName
+
+ Item, corresponding to the variable, is returned
+ in xpath->item in both cases.
+
+ @param xpath pointer to XPath structure
+
+ @return Operation status
+ @retval 1 Success
+ @retval 0 Failure
*/
+
static int
my_xpath_parse_VariableReference(MY_XPATH *xpath)
{
- return my_xpath_parse_term(xpath, MY_XPATH_LEX_DOLLAR) &&
- my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT);
+ LEX_STRING name;
+ int user_var;
+ const char *dollar_pos;
+ if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_DOLLAR) ||
+ (!(dollar_pos= xpath->prevtok.beg)) ||
+ (!((user_var= my_xpath_parse_term(xpath, MY_XPATH_LEX_AT) &&
+ my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))) &&
+ !my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT)))
+ return 0;
+
+ name.length= xpath->prevtok.end - xpath->prevtok.beg;
+ name.str= (char*) xpath->prevtok.beg;
+
+ if (user_var)
+ xpath->item= new Item_func_get_user_var(name);
+ else
+ {
+ sp_variable_t *spv;
+ sp_pcontext *spc;
+ LEX *lex;
+ if ((lex= current_thd->lex) &&
+ (spc= lex->spcont) &&
+ (spv= spc->find_variable(&name)))
+ {
+ Item_splocal *splocal= new Item_splocal(name, spv->offset, spv->type, 0);
+#ifndef DBUG_OFF
+ if (splocal)
+ splocal->m_sp= lex->sphead;
+#endif
+ xpath->item= (Item*) splocal;
+ }
+ else
+ {
+ xpath->item= NULL;
+ DBUG_ASSERT(xpath->query.end > dollar_pos);
+ uint len= xpath->query.end - dollar_pos;
+ set_if_smaller(len, 32);
+ my_printf_error(ER_UNKNOWN_ERROR, "Unknown XPATH variable at: '%.*s'",
+ MYF(0), len, dollar_pos);
+ }
+ }
+ return xpath->item ? 1 : 0;
}