Commit bbf3a593 authored by konstantin@mysql.com's avatar konstantin@mysql.com

A fix and a test case for Bug#15441 "Running SP causes Server

to Crash": the bug was that due to non-standard name
resolution precedence in stored procedures (See Bug#5967)
a stored procedure variable took precedence over a table column
when the arguments for VALUES() function were resolved.
The implementation of VALUES() function was not designed to work
with Item_splocal and crashed.
VALUES() function is non-standard. It can refer to, and
is meaningful for, table columns only. The patch disables SP 
variables as possible arguments of VALUES() function.
parent 886ac06c
...@@ -4110,23 +4110,23 @@ call bug14376(4711)| ...@@ -4110,23 +4110,23 @@ call bug14376(4711)|
x x
4711 4711
drop procedure bug14376| drop procedure bug14376|
drop procedure if exists p1| drop procedure if exists bug5967|
drop table if exists t1| drop table if exists t3|
create table t1 (a varchar(255))| create table t3 (a varchar(255))|
insert into t1 (a) values ("a - table column")| insert into t3 (a) values ("a - table column")|
create procedure p1(a varchar(255)) create procedure bug5967(a varchar(255))
begin begin
declare i varchar(255); declare i varchar(255);
declare c cursor for select a from t1; declare c cursor for select a from t3;
select a; select a;
select a from t1 into i; select a from t3 into i;
select i as 'Parameter takes precedence over table column'; open c; select i as 'Parameter takes precedence over table column'; open c;
fetch c into i; fetch c into i;
close c; close c;
select i as 'Parameter takes precedence over table column in cursors'; select i as 'Parameter takes precedence over table column in cursors';
begin begin
declare a varchar(255) default 'a - local variable'; declare a varchar(255) default 'a - local variable';
declare c1 cursor for select a from t1; declare c1 cursor for select a from t3;
select a as 'A local variable takes precedence over parameter'; select a as 'A local variable takes precedence over parameter';
open c1; open c1;
fetch c1 into i; fetch c1 into i;
...@@ -4134,9 +4134,9 @@ close c1; ...@@ -4134,9 +4134,9 @@ close c1;
select i as 'A local variable takes precedence over parameter in cursors'; select i as 'A local variable takes precedence over parameter in cursors';
begin begin
declare a varchar(255) default 'a - local variable in a nested compound statement'; declare a varchar(255) default 'a - local variable in a nested compound statement';
declare c2 cursor for select a from t1; declare c2 cursor for select a from t3;
select a as 'A local variable in a nested compound statement takes precedence over a local variable in the outer statement'; select a as 'A local variable in a nested compound statement takes precedence over a local variable in the outer statement';
select a from t1 into i; select a from t3 into i;
select i as 'A local variable in a nested compound statement takes precedence over table column'; select i as 'A local variable in a nested compound statement takes precedence over table column';
open c2; open c2;
fetch c2 into i; fetch c2 into i;
...@@ -4145,7 +4145,7 @@ select i as 'A local variable in a nested compound statement takes precedence o ...@@ -4145,7 +4145,7 @@ select i as 'A local variable in a nested compound statement takes precedence o
end; end;
end; end;
end| end|
call p1("a - stored procedure parameter")| call bug5967("a - stored procedure parameter")|
a a
a - stored procedure parameter a - stored procedure parameter
Parameter takes precedence over table column Parameter takes precedence over table column
...@@ -4162,7 +4162,7 @@ A local variable in a nested compound statement takes precedence over table colu ...@@ -4162,7 +4162,7 @@ A local variable in a nested compound statement takes precedence over table colu
a - local variable in a nested compound statement a - local variable in a nested compound statement
A local variable in a nested compound statement takes precedence over table column in cursors A local variable in a nested compound statement takes precedence over table column in cursors
a - local variable in a nested compound statement a - local variable in a nested compound statement
drop procedure p1| drop procedure bug5967|
drop procedure if exists bug13012| drop procedure if exists bug13012|
create procedure bug13012() create procedure bug13012()
BEGIN BEGIN
...@@ -4190,17 +4190,17 @@ call bug13012()| ...@@ -4190,17 +4190,17 @@ call bug13012()|
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 repair status OK test.t1 repair status OK
test.t2 repair status OK test.t2 repair status OK
test.t3 repair error Table 'test.t3' doesn't exist test.t3 repair status OK
test.v1 repair error 'test.v1' is not BASE TABLE test.v1 repair error 'test.v1' is not BASE TABLE
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 optimize status OK test.t1 optimize status OK
test.t2 optimize status OK test.t2 optimize status OK
test.t3 optimize error Table 'test.t3' doesn't exist test.t3 optimize status OK
test.v1 optimize error 'test.v1' is not BASE TABLE test.v1 optimize error 'test.v1' is not BASE TABLE
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 analyze status Table is already up to date test.t1 analyze status Table is already up to date
test.t2 analyze status Table is already up to date test.t2 analyze status Table is already up to date
test.t3 analyze error Table 'test.t3' doesn't exist test.t3 analyze status Table is already up to date
test.v1 analyze error 'test.v1' is not BASE TABLE test.v1 analyze error 'test.v1' is not BASE TABLE
Warnings: Warnings:
Error 1347 'test.v1' is not BASE TABLE Error 1347 'test.v1' is not BASE TABLE
...@@ -4208,17 +4208,17 @@ call bug13012()| ...@@ -4208,17 +4208,17 @@ call bug13012()|
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 repair status OK test.t1 repair status OK
test.t2 repair status OK test.t2 repair status OK
test.t3 repair error Table 'test.t3' doesn't exist test.t3 repair status OK
test.v1 repair error 'test.v1' is not BASE TABLE test.v1 repair error 'test.v1' is not BASE TABLE
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 optimize status OK test.t1 optimize status OK
test.t2 optimize status OK test.t2 optimize status OK
test.t3 optimize error Table 'test.t3' doesn't exist test.t3 optimize status OK
test.v1 optimize error 'test.v1' is not BASE TABLE test.v1 optimize error 'test.v1' is not BASE TABLE
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 analyze status Table is already up to date test.t1 analyze status Table is already up to date
test.t2 analyze status Table is already up to date test.t2 analyze status Table is already up to date
test.t3 analyze error Table 'test.t3' doesn't exist test.t3 analyze status Table is already up to date
test.v1 analyze error 'test.v1' is not BASE TABLE test.v1 analyze error 'test.v1' is not BASE TABLE
Warnings: Warnings:
Error 1347 'test.v1' is not BASE TABLE Error 1347 'test.v1' is not BASE TABLE
...@@ -4226,25 +4226,34 @@ call bug13012()| ...@@ -4226,25 +4226,34 @@ call bug13012()|
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 repair status OK test.t1 repair status OK
test.t2 repair status OK test.t2 repair status OK
test.t3 repair error Table 'test.t3' doesn't exist test.t3 repair status OK
test.v1 repair error 'test.v1' is not BASE TABLE test.v1 repair error 'test.v1' is not BASE TABLE
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 optimize status OK test.t1 optimize status OK
test.t2 optimize status OK test.t2 optimize status OK
test.t3 optimize error Table 'test.t3' doesn't exist test.t3 optimize status OK
test.v1 optimize error 'test.v1' is not BASE TABLE test.v1 optimize error 'test.v1' is not BASE TABLE
Table Op Msg_type Msg_text Table Op Msg_type Msg_text
test.t1 analyze status Table is already up to date test.t1 analyze status Table is already up to date
test.t2 analyze status Table is already up to date test.t2 analyze status Table is already up to date
test.t3 analyze error Table 'test.t3' doesn't exist test.t3 analyze status Table is already up to date
test.v1 analyze error 'test.v1' is not BASE TABLE test.v1 analyze error 'test.v1' is not BASE TABLE
Warnings: Warnings:
Error 1347 'test.v1' is not BASE TABLE Error 1347 'test.v1' is not BASE TABLE
drop procedure bug13012| drop procedure bug13012|
drop view v1; drop view v1;
select * from t1| select * from t1|
a id data
a - table column aa 0
aa 1
aa 2
aa 3
aa 4
aa 5
aa 6
aa 7
aa 8
aa 9
drop schema if exists mysqltest1| drop schema if exists mysqltest1|
Warnings: Warnings:
Note 1008 Can't drop database 'mysqltest1'; database doesn't exist Note 1008 Can't drop database 'mysqltest1'; database doesn't exist
...@@ -4284,4 +4293,31 @@ drop schema if exists mysqltest1| ...@@ -4284,4 +4293,31 @@ drop schema if exists mysqltest1|
drop schema if exists mysqltest2| drop schema if exists mysqltest2|
drop schema if exists mysqltest3| drop schema if exists mysqltest3|
use test| use test|
drop table if exists t3|
drop procedure if exists bug15441|
create table t3 (id int not null primary key, county varchar(25))|
insert into t3 (id, county) values (1, 'York')|
create procedure bug15441(c varchar(25))
begin
update t3 set id=2, county=values(c);
end|
call bug15441('county')|
ERROR 42S22: Unknown column 'c' in 'field list'
drop procedure bug15441|
create procedure bug15441(county varchar(25))
begin
declare c varchar(25) default "hello";
insert into t3 (id, county) values (1, county)
on duplicate key update county= values(county);
select * from t3;
update t3 set id=2, county=values(id);
select * from t3;
end|
call bug15441('Yale')|
id county
1 Yale
id county
2 NULL
drop table t3|
drop procedure bug15441|
drop table t1,t2; drop table t1,t2;
...@@ -4914,24 +4914,24 @@ drop procedure bug14376| ...@@ -4914,24 +4914,24 @@ drop procedure bug14376|
# #
--disable_warnings --disable_warnings
drop procedure if exists p1| drop procedure if exists bug5967|
drop table if exists t1| drop table if exists t3|
--enable_warnings --enable_warnings
create table t1 (a varchar(255))| create table t3 (a varchar(255))|
insert into t1 (a) values ("a - table column")| insert into t3 (a) values ("a - table column")|
create procedure p1(a varchar(255)) create procedure bug5967(a varchar(255))
begin begin
declare i varchar(255); declare i varchar(255);
declare c cursor for select a from t1; declare c cursor for select a from t3;
select a; select a;
select a from t1 into i; select a from t3 into i;
select i as 'Parameter takes precedence over table column'; open c; select i as 'Parameter takes precedence over table column'; open c;
fetch c into i; fetch c into i;
close c; close c;
select i as 'Parameter takes precedence over table column in cursors'; select i as 'Parameter takes precedence over table column in cursors';
begin begin
declare a varchar(255) default 'a - local variable'; declare a varchar(255) default 'a - local variable';
declare c1 cursor for select a from t1; declare c1 cursor for select a from t3;
select a as 'A local variable takes precedence over parameter'; select a as 'A local variable takes precedence over parameter';
open c1; open c1;
fetch c1 into i; fetch c1 into i;
...@@ -4939,9 +4939,9 @@ begin ...@@ -4939,9 +4939,9 @@ begin
select i as 'A local variable takes precedence over parameter in cursors'; select i as 'A local variable takes precedence over parameter in cursors';
begin begin
declare a varchar(255) default 'a - local variable in a nested compound statement'; declare a varchar(255) default 'a - local variable in a nested compound statement';
declare c2 cursor for select a from t1; declare c2 cursor for select a from t3;
select a as 'A local variable in a nested compound statement takes precedence over a local variable in the outer statement'; select a as 'A local variable in a nested compound statement takes precedence over a local variable in the outer statement';
select a from t1 into i; select a from t3 into i;
select i as 'A local variable in a nested compound statement takes precedence over table column'; select i as 'A local variable in a nested compound statement takes precedence over table column';
open c2; open c2;
fetch c2 into i; fetch c2 into i;
...@@ -4950,8 +4950,8 @@ begin ...@@ -4950,8 +4950,8 @@ begin
end; end;
end; end;
end| end|
call p1("a - stored procedure parameter")| call bug5967("a - stored procedure parameter")|
drop procedure p1| drop procedure bug5967|
# #
# Bug#13012 "SP: REPAIR/BACKUP/RESTORE TABLE crashes the server" # Bug#13012 "SP: REPAIR/BACKUP/RESTORE TABLE crashes the server"
...@@ -5028,6 +5028,56 @@ drop schema if exists mysqltest2| ...@@ -5028,6 +5028,56 @@ drop schema if exists mysqltest2|
drop schema if exists mysqltest3| drop schema if exists mysqltest3|
use test| use test|
#
# Bug#15441 "Running SP causes Server to Crash": check that an SP variable
# can not be used in VALUES() function.
#
--disable_warnings
drop table if exists t3|
drop procedure if exists bug15441|
--enable_warnings
create table t3 (id int not null primary key, county varchar(25))|
insert into t3 (id, county) values (1, 'York')|
# First check that a stored procedure that refers to a parameter in VALUES()
# function won't parse.
create procedure bug15441(c varchar(25))
begin
update t3 set id=2, county=values(c);
end|
--error ER_BAD_FIELD_ERROR
call bug15441('county')|
drop procedure bug15441|
# Now check the case when there is an ambiguity between column names
# and stored procedure parameters: the parser shall resolve the argument
# of VALUES() function to the column name.
# It's hard to deduce what county refers to in every case (INSERT statement):
# 1st county refers to the column
# 2nd county refers to the procedure parameter
# 3d and 4th county refers to the column, again, but
# for 4th county it has the value of SP parameter
# In UPDATE statement, just check that values() function returns NULL for
# non- INSERT...UPDATE statements, as stated in the manual.
create procedure bug15441(county varchar(25))
begin
declare c varchar(25) default "hello";
insert into t3 (id, county) values (1, county)
on duplicate key update county= values(county);
select * from t3;
update t3 set id=2, county=values(id);
select * from t3;
end|
call bug15441('Yale')|
drop table t3|
drop procedure bug15441|
# #
# BUG#NNNN: New bug synopsis # BUG#NNNN: New bug synopsis
# #
......
...@@ -5148,10 +5148,17 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items) ...@@ -5148,10 +5148,17 @@ bool Item_insert_value::fix_fields(THD *thd, Item **items)
Item_ref *ref= (Item_ref *)arg; Item_ref *ref= (Item_ref *)arg;
if (ref->ref[0]->type() != FIELD_ITEM) if (ref->ref[0]->type() != FIELD_ITEM)
{ {
my_error(ER_BAD_FIELD_ERROR, MYF(0), "", "VALUES() function");
return TRUE; return TRUE;
} }
arg= ref->ref[0]; arg= ref->ref[0];
} }
/*
According to our SQL grammar, VALUES() function can reference
only to a column.
*/
DBUG_ASSERT(arg->type() == FIELD_ITEM);
Item_field *field_arg= (Item_field *)arg; Item_field *field_arg= (Item_field *)arg;
if (field_arg->field->table->insert_values) if (field_arg->field->table->insert_values)
......
...@@ -2056,6 +2056,16 @@ public: ...@@ -2056,6 +2056,16 @@ public:
} }
}; };
/*
Item_insert_value -- an implementation of VALUES() function.
You can use the VALUES(col_name) function in the UPDATE clause
to refer to column values from the INSERT portion of the INSERT
... UPDATE statement. In other words, VALUES(col_name) in the
UPDATE clause refers to the value of col_name that would be
inserted, had no duplicate-key conflict occurred.
In all other places this function returns NULL.
*/
class Item_insert_value : public Item_field class Item_insert_value : public Item_field
{ {
public: public:
......
...@@ -4438,7 +4438,7 @@ simple_expr: ...@@ -4438,7 +4438,7 @@ simple_expr:
} }
$$= new Item_default_value(Lex->current_context(), $3); $$= new Item_default_value(Lex->current_context(), $3);
} }
| VALUES '(' simple_ident ')' | VALUES '(' simple_ident_nospvar ')'
{ $$= new Item_insert_value(Lex->current_context(), $3); } { $$= new Item_insert_value(Lex->current_context(), $3); }
| FUNC_ARG0 '(' ')' | FUNC_ARG0 '(' ')'
{ {
......
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