Bug#24747 XPath error with the node name "Text"
mysql-test/r/xml.result: Adding test case mysql-test/t/xml.test: Adding test case sql/item_xmlfunc.cc: Bug#24747 XPath error with the node name "Text" Problem: keywords, nodetype names and axis names didn't work in node name context. Fix: 1. Changes in lexem scanner behaviour when an identifier has been read: - search through axis names and return MY_XPATH_AXIS_xxx only when identifier is followed by two semicolons. Don't check axis names and return MY_XPATH_IDENT of not followed by two semicolons. - search through nodetype names and return MY_XPATH_LEX_NODETYPE only when identifier is followed by left parenthesis. Don't check nodetype names and return MY_XPATH_LEX_IDENT when not followed by parenthesis 2. Change in syntax analizer: QName scanner now accepts keywords AND, OR, MOD, DIV as valid node names.
This commit is contained in:
parent
61c7864ced
commit
38fd186721
@ -809,3 +809,78 @@ ExtractValue(@xml, "/entry[(50<pt)]/id")
|
|||||||
select ExtractValue(@xml, "/entry[(50<=pt)]/id");
|
select ExtractValue(@xml, "/entry[(50<=pt)]/id");
|
||||||
ExtractValue(@xml, "/entry[(50<=pt)]/id")
|
ExtractValue(@xml, "/entry[(50<=pt)]/id")
|
||||||
pt50
|
pt50
|
||||||
|
select ExtractValue('<a><b><Text>test</Text></b></a>','/a/b/Text');
|
||||||
|
ExtractValue('<a><b><Text>test</Text></b></a>','/a/b/Text')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><b><comment>test</comment></b></a>','/a/b/comment');
|
||||||
|
ExtractValue('<a><b><comment>test</comment></b></a>','/a/b/comment')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><b><node>test</node></b></a>','/a/b/node');
|
||||||
|
ExtractValue('<a><b><node>test</node></b></a>','/a/b/node')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><b><processing-instruction>test</processing-instruction></b></a>','/a/b/processing-instruction');
|
||||||
|
ExtractValue('<a><b><processing-instruction>test</processing-instruction></b></a>','/a/b/processing-instruction')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><and>test</and></a>', '/a/and');
|
||||||
|
ExtractValue('<a><and>test</and></a>', '/a/and')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><or>test</or></a>', '/a/or');
|
||||||
|
ExtractValue('<a><or>test</or></a>', '/a/or')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><mod>test</mod></a>', '/a/mod');
|
||||||
|
ExtractValue('<a><mod>test</mod></a>', '/a/mod')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><div>test</div></a>', '/a/div');
|
||||||
|
ExtractValue('<a><div>test</div></a>', '/a/div')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><and:and>test</and:and></a>', '/a/and:and');
|
||||||
|
ExtractValue('<a><and:and>test</and:and></a>', '/a/and:and')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><or:or>test</or:or></a>', '/a/or:or');
|
||||||
|
ExtractValue('<a><or:or>test</or:or></a>', '/a/or:or')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><mod:mod>test</mod:mod></a>', '/a/mod:mod');
|
||||||
|
ExtractValue('<a><mod:mod>test</mod:mod></a>', '/a/mod:mod')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><div:div>test</div:div></a>', '/a/div:div');
|
||||||
|
ExtractValue('<a><div:div>test</div:div></a>', '/a/div:div')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><ancestor>test</ancestor></a>', '/a/ancestor');
|
||||||
|
ExtractValue('<a><ancestor>test</ancestor></a>', '/a/ancestor')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><ancestor-or-self>test</ancestor-or-self></a>', '/a/ancestor-or-self');
|
||||||
|
ExtractValue('<a><ancestor-or-self>test</ancestor-or-self></a>', '/a/ancestor-or-self')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><attribute>test</attribute></a>', '/a/attribute');
|
||||||
|
ExtractValue('<a><attribute>test</attribute></a>', '/a/attribute')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><child>test</child></a>', '/a/child');
|
||||||
|
ExtractValue('<a><child>test</child></a>', '/a/child')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><descendant>test</descendant></a>', '/a/descendant');
|
||||||
|
ExtractValue('<a><descendant>test</descendant></a>', '/a/descendant')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><descendant-or-self>test</descendant-or-self></a>', '/a/descendant-or-self');
|
||||||
|
ExtractValue('<a><descendant-or-self>test</descendant-or-self></a>', '/a/descendant-or-self')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><following>test</following></a>', '/a/following');
|
||||||
|
ExtractValue('<a><following>test</following></a>', '/a/following')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><following-sibling>test</following-sibling></a>', '/a/following-sibling');
|
||||||
|
ExtractValue('<a><following-sibling>test</following-sibling></a>', '/a/following-sibling')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><namespace>test</namespace></a>', '/a/namespace');
|
||||||
|
ExtractValue('<a><namespace>test</namespace></a>', '/a/namespace')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><parent>test</parent></a>', '/a/parent');
|
||||||
|
ExtractValue('<a><parent>test</parent></a>', '/a/parent')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><preceding>test</preceding></a>', '/a/preceding');
|
||||||
|
ExtractValue('<a><preceding>test</preceding></a>', '/a/preceding')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><preceding-sibling>test</preceding-sibling></a>', '/a/preceding-sibling');
|
||||||
|
ExtractValue('<a><preceding-sibling>test</preceding-sibling></a>', '/a/preceding-sibling')
|
||||||
|
test
|
||||||
|
select ExtractValue('<a><self>test</self></a>', '/a/self');
|
||||||
|
ExtractValue('<a><self>test</self></a>', '/a/self')
|
||||||
|
test
|
||||||
|
@ -406,3 +406,41 @@ select ExtractValue(@xml, "/entry[(50>pt)]/id");
|
|||||||
select ExtractValue(@xml, "/entry[(50>=pt)]/id");
|
select ExtractValue(@xml, "/entry[(50>=pt)]/id");
|
||||||
select ExtractValue(@xml, "/entry[(50<pt)]/id");
|
select ExtractValue(@xml, "/entry[(50<pt)]/id");
|
||||||
select ExtractValue(@xml, "/entry[(50<=pt)]/id");
|
select ExtractValue(@xml, "/entry[(50<=pt)]/id");
|
||||||
|
|
||||||
|
#
|
||||||
|
# Bug#24747 XPath error with the node name "Text"
|
||||||
|
#
|
||||||
|
#
|
||||||
|
# Test nodetypes in node name context
|
||||||
|
#
|
||||||
|
select ExtractValue('<a><b><Text>test</Text></b></a>','/a/b/Text');
|
||||||
|
select ExtractValue('<a><b><comment>test</comment></b></a>','/a/b/comment');
|
||||||
|
select ExtractValue('<a><b><node>test</node></b></a>','/a/b/node');
|
||||||
|
select ExtractValue('<a><b><processing-instruction>test</processing-instruction></b></a>','/a/b/processing-instruction');
|
||||||
|
#
|
||||||
|
# Test keywords in node name contexts
|
||||||
|
#
|
||||||
|
select ExtractValue('<a><and>test</and></a>', '/a/and');
|
||||||
|
select ExtractValue('<a><or>test</or></a>', '/a/or');
|
||||||
|
select ExtractValue('<a><mod>test</mod></a>', '/a/mod');
|
||||||
|
select ExtractValue('<a><div>test</div></a>', '/a/div');
|
||||||
|
select ExtractValue('<a><and:and>test</and:and></a>', '/a/and:and');
|
||||||
|
select ExtractValue('<a><or:or>test</or:or></a>', '/a/or:or');
|
||||||
|
select ExtractValue('<a><mod:mod>test</mod:mod></a>', '/a/mod:mod');
|
||||||
|
select ExtractValue('<a><div:div>test</div:div></a>', '/a/div:div');
|
||||||
|
#
|
||||||
|
# Test axis names in node name context
|
||||||
|
#
|
||||||
|
select ExtractValue('<a><ancestor>test</ancestor></a>', '/a/ancestor');
|
||||||
|
select ExtractValue('<a><ancestor-or-self>test</ancestor-or-self></a>', '/a/ancestor-or-self');
|
||||||
|
select ExtractValue('<a><attribute>test</attribute></a>', '/a/attribute');
|
||||||
|
select ExtractValue('<a><child>test</child></a>', '/a/child');
|
||||||
|
select ExtractValue('<a><descendant>test</descendant></a>', '/a/descendant');
|
||||||
|
select ExtractValue('<a><descendant-or-self>test</descendant-or-self></a>', '/a/descendant-or-self');
|
||||||
|
select ExtractValue('<a><following>test</following></a>', '/a/following');
|
||||||
|
select ExtractValue('<a><following-sibling>test</following-sibling></a>', '/a/following-sibling');
|
||||||
|
select ExtractValue('<a><namespace>test</namespace></a>', '/a/namespace');
|
||||||
|
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');
|
||||||
|
@ -1047,12 +1047,12 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
|
|||||||
{MY_XPATH_LEX_OR , "or" , 2, 0 },
|
{MY_XPATH_LEX_OR , "or" , 2, 0 },
|
||||||
{MY_XPATH_LEX_DIV , "div" , 3, 0 },
|
{MY_XPATH_LEX_DIV , "div" , 3, 0 },
|
||||||
{MY_XPATH_LEX_MOD , "mod" , 3, 0 },
|
{MY_XPATH_LEX_MOD , "mod" , 3, 0 },
|
||||||
|
{0,NULL,0,0}
|
||||||
|
};
|
||||||
|
|
||||||
{MY_XPATH_LEX_NODETYPE, "comment" , 7, 0 },
|
|
||||||
{MY_XPATH_LEX_NODETYPE, "text" , 4, 0 },
|
|
||||||
{MY_XPATH_LEX_NODETYPE, "processing-instruction" , 22,0 },
|
|
||||||
{MY_XPATH_LEX_NODETYPE, "node" , 4, 0 },
|
|
||||||
|
|
||||||
|
static struct my_xpath_keyword_names_st my_axis_names[]=
|
||||||
|
{
|
||||||
{MY_XPATH_LEX_AXIS,"ancestor" , 8,MY_XPATH_AXIS_ANCESTOR },
|
{MY_XPATH_LEX_AXIS,"ancestor" , 8,MY_XPATH_AXIS_ANCESTOR },
|
||||||
{MY_XPATH_LEX_AXIS,"ancestor-or-self" ,16,MY_XPATH_AXIS_ANCESTOR_OR_SELF },
|
{MY_XPATH_LEX_AXIS,"ancestor-or-self" ,16,MY_XPATH_AXIS_ANCESTOR_OR_SELF },
|
||||||
{MY_XPATH_LEX_AXIS,"attribute" , 9,MY_XPATH_AXIS_ATTRIBUTE },
|
{MY_XPATH_LEX_AXIS,"attribute" , 9,MY_XPATH_AXIS_ATTRIBUTE },
|
||||||
@ -1066,7 +1066,16 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
|
|||||||
{MY_XPATH_LEX_AXIS,"preceding" , 9,MY_XPATH_AXIS_PRECEDING },
|
{MY_XPATH_LEX_AXIS,"preceding" , 9,MY_XPATH_AXIS_PRECEDING },
|
||||||
{MY_XPATH_LEX_AXIS,"preceding-sibling" ,17,MY_XPATH_AXIS_PRECEDING_SIBLING },
|
{MY_XPATH_LEX_AXIS,"preceding-sibling" ,17,MY_XPATH_AXIS_PRECEDING_SIBLING },
|
||||||
{MY_XPATH_LEX_AXIS,"self" , 4,MY_XPATH_AXIS_SELF },
|
{MY_XPATH_LEX_AXIS,"self" , 4,MY_XPATH_AXIS_SELF },
|
||||||
|
{0,NULL,0,0}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
static struct my_xpath_keyword_names_st my_nodetype_names[]=
|
||||||
|
{
|
||||||
|
{MY_XPATH_LEX_NODETYPE, "comment" , 7, 0 },
|
||||||
|
{MY_XPATH_LEX_NODETYPE, "text" , 4, 0 },
|
||||||
|
{MY_XPATH_LEX_NODETYPE, "processing-instruction" , 22,0 },
|
||||||
|
{MY_XPATH_LEX_NODETYPE, "node" , 4, 0 },
|
||||||
{0,NULL,0,0}
|
{0,NULL,0,0}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1081,11 +1090,14 @@ static struct my_xpath_keyword_names_st my_keyword_names[] =
|
|||||||
- Token type, on lookup success.
|
- Token type, on lookup success.
|
||||||
- MY_XPATH_LEX_IDENT, on lookup failure.
|
- MY_XPATH_LEX_IDENT, on lookup failure.
|
||||||
*/
|
*/
|
||||||
static int my_xpath_keyword(MY_XPATH *x, const char *beg, const char *end)
|
static int
|
||||||
|
my_xpath_keyword(MY_XPATH *x,
|
||||||
|
struct my_xpath_keyword_names_st *keyword_names,
|
||||||
|
const char *beg, const char *end)
|
||||||
{
|
{
|
||||||
struct my_xpath_keyword_names_st *k;
|
struct my_xpath_keyword_names_st *k;
|
||||||
size_t length= end-beg;
|
size_t length= end-beg;
|
||||||
for (k= my_keyword_names; k->name; k++)
|
for (k= keyword_names; k->name; k++)
|
||||||
{
|
{
|
||||||
if (length == k->length && !strncasecmp(beg, k->name, length))
|
if (length == k->length && !strncasecmp(beg, k->name, length))
|
||||||
{
|
{
|
||||||
@ -1371,15 +1383,32 @@ my_xpath_lex_scan(MY_XPATH *xpath,
|
|||||||
beg+= length) /* no op */;
|
beg+= length) /* no op */;
|
||||||
lex->end= beg;
|
lex->end= beg;
|
||||||
|
|
||||||
// check if a function call
|
if (beg < end)
|
||||||
if (*beg == '(' && (xpath->func= my_xpath_function(lex->beg, beg)))
|
|
||||||
{
|
{
|
||||||
|
if (*beg == '(')
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
check if a function call, e.g.: count(/a/b)
|
||||||
|
or a nodetype test, e.g.: /a/b/text()
|
||||||
|
*/
|
||||||
|
if ((xpath->func= my_xpath_function(lex->beg, beg)))
|
||||||
lex->term= MY_XPATH_LEX_FUNC;
|
lex->term= MY_XPATH_LEX_FUNC;
|
||||||
|
else
|
||||||
|
lex->term= my_xpath_keyword(xpath, my_nodetype_names,
|
||||||
|
lex->beg, beg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// check if an axis specifier, e.g.: /a/b/child::*
|
||||||
|
else if (*beg == ':' && beg + 1 < end && beg[1] == ':')
|
||||||
|
{
|
||||||
|
lex->term= my_xpath_keyword(xpath, my_axis_names,
|
||||||
|
lex->beg, beg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
// check if a keyword
|
// check if a keyword
|
||||||
lex->term= my_xpath_keyword(xpath, lex->beg, beg);
|
lex->term= my_xpath_keyword(xpath, my_keyword_names,
|
||||||
|
lex->beg, beg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2333,6 +2362,36 @@ static int my_xpath_parse_Number(MY_XPATH *xpath)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Scan NCName.
|
||||||
|
|
||||||
|
SYNOPSYS
|
||||||
|
|
||||||
|
The keywords AND, OR, MOD, DIV are valid identitiers
|
||||||
|
when they are in identifier context:
|
||||||
|
|
||||||
|
SELECT
|
||||||
|
ExtractValue('<and><or><mod><div>VALUE</div></mod></or></and>',
|
||||||
|
'/and/or/mod/div')
|
||||||
|
-> VALUE
|
||||||
|
|
||||||
|
RETURN
|
||||||
|
1 - success
|
||||||
|
0 - failure
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
my_xpath_parse_NCName(MY_XPATH *xpath)
|
||||||
|
{
|
||||||
|
return
|
||||||
|
my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT) ||
|
||||||
|
my_xpath_parse_term(xpath, MY_XPATH_LEX_AND) ||
|
||||||
|
my_xpath_parse_term(xpath, MY_XPATH_LEX_OR) ||
|
||||||
|
my_xpath_parse_term(xpath, MY_XPATH_LEX_MOD) ||
|
||||||
|
my_xpath_parse_term(xpath, MY_XPATH_LEX_DIV) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
QName grammar can be found in a separate document
|
QName grammar can be found in a separate document
|
||||||
http://www.w3.org/TR/REC-xml-names/#NT-QName
|
http://www.w3.org/TR/REC-xml-names/#NT-QName
|
||||||
@ -2341,16 +2400,17 @@ static int my_xpath_parse_Number(MY_XPATH *xpath)
|
|||||||
[7] Prefix ::= NCName
|
[7] Prefix ::= NCName
|
||||||
[8] LocalPart ::= NCName
|
[8] LocalPart ::= NCName
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
my_xpath_parse_QName(MY_XPATH *xpath)
|
my_xpath_parse_QName(MY_XPATH *xpath)
|
||||||
{
|
{
|
||||||
const char *beg;
|
const char *beg;
|
||||||
if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))
|
if (!my_xpath_parse_NCName(xpath))
|
||||||
return 0;
|
return 0;
|
||||||
beg= xpath->prevtok.beg;
|
beg= xpath->prevtok.beg;
|
||||||
if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_COLON))
|
if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_COLON))
|
||||||
return 1; /* Non qualified name */
|
return 1; /* Non qualified name */
|
||||||
if (!my_xpath_parse_term(xpath, MY_XPATH_LEX_IDENT))
|
if (!my_xpath_parse_NCName(xpath))
|
||||||
return 0;
|
return 0;
|
||||||
xpath->prevtok.beg= beg;
|
xpath->prevtok.beg= beg;
|
||||||
return 1;
|
return 1;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user