Commit c9232c60 authored by unknown's avatar unknown

Various bug fixes:

  - Duplicate parameters/variables, conditions and cursors (not allowed).
  - ITERATE in labelled BEGIN-END (not allowed).
  - Missing SQLSTATE [VALUE] keywords in CONDITION/HANDLER declaration (added).
  - Empty BEGIN-END (now allowed).
  - End label (now optional).


include/mysqld_error.h:
  New error code for duplicate things (vars et al) in SPs.
mysql-test/r/sp-error.result:
  New error tests for ITERATE in begin-end block and duplicate variables,
  conditions and cursors.
mysql-test/r/sp.result:
  New tests for empty begin-end blocks, overriding local variables outside scope
  only, leave a begin-end block, and SQLSTATE [VALUE] words for CONDITION/HANDLER
  declarations.
mysql-test/t/sp-error.test:
  New error tests for ITERATE in begin-end block and duplicate variables,
  conditions and cursors.
mysql-test/t/sp.test:
  New tests for empty begin-end blocks, overriding local variables outside scope
  only, leave a begin-end block, and SQLSTATE [VALUE] words for CONDITION/HANDLER
  declarations.
sql/lex.h:
  New SQLSTATE keyword.
sql/share/czech/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/danish/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/dutch/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/english/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/estonian/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/french/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/german/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/greek/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/hungarian/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/italian/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/japanese/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/korean/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/norwegian-ny/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/norwegian/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/polish/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/portuguese/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/romanian/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/russian/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/serbian/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/slovak/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/spanish/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/swedish/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/share/ukrainian/errmsg.txt:
  New error message for duplicate things (vars et al) in SPs.
sql/sp_pcontext.cc:
  Keep track on scope limits for error checking of duplicate variables,
  conditions and cursors.
sql/sp_pcontext.h:
  Keep track on scope limits for error checking of duplicate variables,
  conditions and cursors.
  Also need to flag BEGIN labels to check for illegal ITERATEs.
sql/sql_yacc.yy:
  End-labels in SPs loop and begin-end blocks are now optional.
  SQLSTATE [VALUE] added to syntax for sqlstates.
  Check for duplicate variable, condition and cursor declarations, but
  only in the same scope.
  Empty BEGIN-END statements now allowed.
  Check if ITERATE is referring to a BEGIN label.
parent 4696bb41
...@@ -323,4 +323,5 @@ ...@@ -323,4 +323,5 @@
#define ER_SP_UNDECLARED_VAR 1304 #define ER_SP_UNDECLARED_VAR 1304
#define ER_SP_WRONG_NO_OF_FETCH_ARGS 1305 #define ER_SP_WRONG_NO_OF_FETCH_ARGS 1305
#define ER_SP_FETCH_NO_DATA 1306 #define ER_SP_FETCH_NO_DATA 1306
#define ER_ERROR_MESSAGES 307 #define ER_SP_DUP_THING 1307
#define ER_ERROR_MESSAGES 308
...@@ -47,6 +47,11 @@ iterate bar; ...@@ -47,6 +47,11 @@ iterate bar;
end loop; end loop;
ERROR HY000: ITERATE with no matching label: bar ERROR HY000: ITERATE with no matching label: bar
create procedure foo() create procedure foo()
foo: begin
iterate foo;
end;
ERROR HY000: ITERATE with no matching label: foo
create procedure foo()
foo: loop foo: loop
foo: loop foo: loop
set @x=2; set @x=2;
...@@ -219,4 +224,30 @@ end; ...@@ -219,4 +224,30 @@ end;
call p(); call p();
ERROR HY000: Wrong number of FETCH variables ERROR HY000: Wrong number of FETCH variables
drop procedure p; drop procedure p;
create procedure p(in x int, x char(10))
begin
end;
ERROR HY000: Duplicate parameter: x
create function p(x int, x char(10))
begin
end;
ERROR HY000: Duplicate parameter: x
create procedure p()
begin
declare x float;
declare x int;
end;
ERROR HY000: Duplicate parameter: x
create procedure p()
begin
declare c condition for 1064;
declare c condition for 1065;
end;
ERROR HY000: Duplicate condition: c
create procedure p()
begin
declare c cursor for select * from t1;
declare c cursor for select field from t1;
end;
ERROR HY000: Duplicate cursor: c
drop table t1; drop table t1;
...@@ -36,6 +36,20 @@ select * from t1; ...@@ -36,6 +36,20 @@ select * from t1;
id data id data
bar 666 bar 666
delete from t1; delete from t1;
create procedure empty()
begin
end;
call empty();
drop procedure empty;
create procedure scope(a int, b float)
begin
declare b int;
declare c float;
begin
declare c int;
end;
end;
drop procedure scope;
create procedure two(x1 char(16), x2 char(16), y int) create procedure two(x1 char(16), x2 char(16), y int)
begin begin
insert into test.t1 values (x1, y); insert into test.t1 values (x1, y);
...@@ -256,7 +270,7 @@ insert into test.t1 values ("d", x); ...@@ -256,7 +270,7 @@ insert into test.t1 values ("d", x);
set x = x-1; set x = x-1;
leave hmm; leave hmm;
insert into test.t1 values ("x", x); insert into test.t1 values ("x", x);
end while hmm; end while;
call d(3); call d(3);
select * from t1; select * from t1;
id data id data
...@@ -335,6 +349,21 @@ h1 1 ...@@ -335,6 +349,21 @@ h1 1
h? 17 h? 17
delete from t1; delete from t1;
drop procedure h; drop procedure h;
create procedure i(x int)
foo:
begin
if x = 0 then
leave foo;
end if;
insert into test.t1 values ("i", x);
end foo;
call i(0);
call i(3);
select * from t1;
id data
i 3
delete from t1;
drop procedure i;
create procedure into_test(x char(16), y int) create procedure into_test(x char(16), y int)
begin begin
insert into test.t1 values (x, y); insert into test.t1 values (x, y);
...@@ -461,6 +490,8 @@ create procedure hndlr1(val int) ...@@ -461,6 +490,8 @@ create procedure hndlr1(val int)
begin begin
declare x int default 0; declare x int default 0;
declare foo condition for 1146; declare foo condition for 1146;
declare bar condition for sqlstate '42S98'; # Just for testing syntax
declare zip condition for sqlstate value '42S99'; # Just for testing syntax
declare continue handler for foo set x = 1; declare continue handler for foo set x = 1;
insert into test.t666 values ("hndlr1", val); # Non-existing table insert into test.t666 values ("hndlr1", val); # Non-existing table
if (x) then if (x) then
...@@ -477,7 +508,7 @@ create procedure hndlr2(val int) ...@@ -477,7 +508,7 @@ create procedure hndlr2(val int)
begin begin
declare x int default 0; declare x int default 0;
begin begin
declare exit handler for '42S02' set x = 1; declare exit handler for sqlstate '42S02' set x = 1;
insert into test.t666 values ("hndlr2", val); # Non-existing table insert into test.t666 values ("hndlr2", val); # Non-existing table
end; end;
insert into test.t1 values ("hndlr2", x); insert into test.t1 values ("hndlr2", x);
...@@ -744,7 +775,7 @@ end if; ...@@ -744,7 +775,7 @@ end if;
set s = s+1; set s = s+1;
end; end;
end if; end if;
end loop again; end loop;
end; end;
create procedure ip(m int unsigned) create procedure ip(m int unsigned)
begin begin
......
...@@ -74,6 +74,11 @@ create procedure foo() ...@@ -74,6 +74,11 @@ create procedure foo()
foo: loop foo: loop
iterate bar; iterate bar;
end loop| end loop|
--error 1285
create procedure foo()
foo: begin
iterate foo;
end|
# Redefining label # Redefining label
--error 1286 --error 1286
...@@ -298,6 +303,33 @@ end| ...@@ -298,6 +303,33 @@ end|
call p()| call p()|
drop procedure p| drop procedure p|
--error 1307
create procedure p(in x int, x char(10))
begin
end|
--error 1307
create function p(x int, x char(10))
begin
end|
--error 1307
create procedure p()
begin
declare x float;
declare x int;
end|
--error 1307
create procedure p()
begin
declare c condition for 1064;
declare c condition for 1065;
end|
--error 1307
create procedure p()
begin
declare c cursor for select * from t1;
declare c cursor for select field from t1;
end|
drop table t1| drop table t1|
delimiter ;| delimiter ;|
...@@ -59,6 +59,28 @@ delete from t1; ...@@ -59,6 +59,28 @@ delete from t1;
# Now for multiple statements... # Now for multiple statements...
delimiter |; delimiter |;
# Empty statement
create procedure empty()
begin
end|
call empty()|
drop procedure empty|
# Scope test. This is legal (warnings might be possible in the future,
# but for the time being, we just accept it).
create procedure scope(a int, b float)
begin
declare b int;
declare c float;
begin
declare c int;
end;
end|
drop procedure scope|
# Two statements. # Two statements.
create procedure two(x1 char(16), x2 char(16), y int) create procedure two(x1 char(16), x2 char(16), y int)
begin begin
...@@ -313,7 +335,7 @@ hmm: while x > 0 do ...@@ -313,7 +335,7 @@ hmm: while x > 0 do
set x = x-1; set x = x-1;
leave hmm; leave hmm;
insert into test.t1 values ("x", x); insert into test.t1 values ("x", x);
end while hmm| end while|
call d(3)| call d(3)|
select * from t1| select * from t1|
...@@ -393,6 +415,23 @@ delete from t1| ...@@ -393,6 +415,23 @@ delete from t1|
drop procedure h| drop procedure h|
# It's actually possible to LEAVE a BEGIN-END block
create procedure i(x int)
foo:
begin
if x = 0 then
leave foo;
end if;
insert into test.t1 values ("i", x);
end foo|
call i(0)|
call i(3)|
select * from t1|
delete from t1|
drop procedure i|
# SELECT INTO local variables # SELECT INTO local variables
create procedure into_test(x char(16), y int) create procedure into_test(x char(16), y int)
begin begin
...@@ -543,6 +582,8 @@ create procedure hndlr1(val int) ...@@ -543,6 +582,8 @@ create procedure hndlr1(val int)
begin begin
declare x int default 0; declare x int default 0;
declare foo condition for 1146; declare foo condition for 1146;
declare bar condition for sqlstate '42S98'; # Just for testing syntax
declare zip condition for sqlstate value '42S99'; # Just for testing syntax
declare continue handler for foo set x = 1; declare continue handler for foo set x = 1;
insert into test.t666 values ("hndlr1", val); # Non-existing table insert into test.t666 values ("hndlr1", val); # Non-existing table
...@@ -561,7 +602,7 @@ begin ...@@ -561,7 +602,7 @@ begin
declare x int default 0; declare x int default 0;
begin begin
declare exit handler for '42S02' set x = 1; declare exit handler for sqlstate '42S02' set x = 1;
insert into test.t666 values ("hndlr2", val); # Non-existing table insert into test.t666 values ("hndlr2", val); # Non-existing table
end; end;
...@@ -864,7 +905,7 @@ begin ...@@ -864,7 +905,7 @@ begin
set s = s+1; set s = s+1;
end; end;
end if; end if;
end loop again; end loop;
end| end|
create procedure ip(m int unsigned) create procedure ip(m int unsigned)
......
...@@ -386,6 +386,7 @@ static SYMBOL symbols[] = { ...@@ -386,6 +386,7 @@ static SYMBOL symbols[] = {
{ "SPATIAL", SYM(SPATIAL_SYM),0,0}, { "SPATIAL", SYM(SPATIAL_SYM),0,0},
{ "SPECIFIC", SYM(SPECIFIC_SYM),0,0}, { "SPECIFIC", SYM(SPECIFIC_SYM),0,0},
{ "SQLEXCEPTION", SYM(SQLEXCEPTION_SYM),0,0}, { "SQLEXCEPTION", SYM(SQLEXCEPTION_SYM),0,0},
{ "SQLSTATE", SYM(SQLSTATE_SYM),0,0},
{ "SQLWARNING", SYM(SQLWARNING_SYM),0,0}, { "SQLWARNING", SYM(SQLWARNING_SYM),0,0},
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0}, { "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0}, { "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
......
...@@ -319,3 +319,4 @@ character-set=latin2 ...@@ -319,3 +319,4 @@ character-set=latin2
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -313,3 +313,4 @@ character-set=latin1 ...@@ -313,3 +313,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -321,3 +321,4 @@ character-set=latin1 ...@@ -321,3 +321,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -310,3 +310,4 @@ character-set=latin1 ...@@ -310,3 +310,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -315,3 +315,4 @@ character-set=latin7 ...@@ -315,3 +315,4 @@ character-set=latin7
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -310,3 +310,4 @@ character-set=latin1 ...@@ -310,3 +310,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -322,3 +322,4 @@ character-set=latin1 ...@@ -322,3 +322,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -310,3 +310,4 @@ character-set=greek ...@@ -310,3 +310,4 @@ character-set=greek
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -312,3 +312,4 @@ character-set=latin2 ...@@ -312,3 +312,4 @@ character-set=latin2
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -310,3 +310,4 @@ character-set=latin1 ...@@ -310,3 +310,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -312,3 +312,4 @@ character-set=ujis ...@@ -312,3 +312,4 @@ character-set=ujis
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -310,3 +310,4 @@ character-set=euckr ...@@ -310,3 +310,4 @@ character-set=euckr
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -312,3 +312,4 @@ character-set=latin1 ...@@ -312,3 +312,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -312,3 +312,4 @@ character-set=latin1 ...@@ -312,3 +312,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -314,3 +314,4 @@ character-set=latin2 ...@@ -314,3 +314,4 @@ character-set=latin2
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -311,3 +311,4 @@ character-set=latin1 ...@@ -311,3 +311,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -314,3 +314,4 @@ character-set=latin2 ...@@ -314,3 +314,4 @@ character-set=latin2
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -312,3 +312,4 @@ character-set=koi8r ...@@ -312,3 +312,4 @@ character-set=koi8r
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -305,3 +305,4 @@ character-set=cp1250 ...@@ -305,3 +305,4 @@ character-set=cp1250
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -318,3 +318,4 @@ character-set=latin2 ...@@ -318,3 +318,4 @@ character-set=latin2
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -312,3 +312,4 @@ character-set=latin1 ...@@ -312,3 +312,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -310,3 +310,4 @@ character-set=latin1 ...@@ -310,3 +310,4 @@ character-set=latin1
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -315,3 +315,4 @@ character-set=koi8u ...@@ -315,3 +315,4 @@ character-set=koi8u
"Undeclared variable: %s" "Undeclared variable: %s"
"Wrong number of FETCH variables" "Wrong number of FETCH variables"
"No data to FETCH" "No data to FETCH"
"Duplicate %s: %s"
...@@ -32,6 +32,7 @@ sp_pcontext::sp_pcontext() ...@@ -32,6 +32,7 @@ sp_pcontext::sp_pcontext()
VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8)); VOID(my_init_dynamic_array(&m_pvar, sizeof(sp_pvar_t *), 16, 8));
VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8)); VOID(my_init_dynamic_array(&m_cond, sizeof(sp_cond_type_t *), 16, 8));
VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8)); VOID(my_init_dynamic_array(&m_cursor, sizeof(LEX_STRING), 16, 8));
VOID(my_init_dynamic_array(&m_scopes, sizeof(sp_scope_t), 16, 8));
m_label.empty(); m_label.empty();
} }
...@@ -41,23 +42,52 @@ sp_pcontext::destroy() ...@@ -41,23 +42,52 @@ sp_pcontext::destroy()
delete_dynamic(&m_pvar); delete_dynamic(&m_pvar);
delete_dynamic(&m_cond); delete_dynamic(&m_cond);
delete_dynamic(&m_cursor); delete_dynamic(&m_cursor);
delete_dynamic(&m_scopes);
m_label.empty(); m_label.empty();
} }
void
sp_pcontext::push_scope()
{
sp_scope_t s;
s.vars= m_pvar.elements;
s.conds= m_cond.elements;
s.curs= m_cursor.elements;
insert_dynamic(&m_scopes, (gptr)&s);
}
void
sp_pcontext::pop_scope()
{
(void)pop_dynamic(&m_scopes);
}
/* This does a linear search (from newer to older variables, in case /* This does a linear search (from newer to older variables, in case
** we have shadowed names). ** we have shadowed names).
** It's possible to have a more efficient allocation and search method, ** It's possible to have a more efficient allocation and search method,
** but it might not be worth it. The typical number of parameters and ** but it might not be worth it. The typical number of parameters and
** variables will in most cases be low (a handfull). ** variables will in most cases be low (a handfull).
** And this is only called during parsing. ** ...and, this is only called during parsing.
*/ */
sp_pvar_t * sp_pvar_t *
sp_pcontext::find_pvar(LEX_STRING *name) sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped)
{ {
uint i = m_pvar.elements; uint i = m_pvar.elements;
uint limit;
while (i-- > 0) if (! scoped || m_scopes.elements == 0)
limit= 0;
else
{
sp_scope_t s;
get_dynamic(&m_scopes, (gptr)&s, m_scopes.elements-1);
limit= s.vars;
}
while (i-- > limit)
{ {
sp_pvar_t *p; sp_pvar_t *p;
...@@ -101,6 +131,7 @@ sp_pcontext::push_label(char *name, uint ip) ...@@ -101,6 +131,7 @@ sp_pcontext::push_label(char *name, uint ip)
{ {
lab->name= name; lab->name= name;
lab->ip= ip; lab->ip= ip;
lab->isbegin= FALSE;
m_label.push_front(lab); m_label.push_front(lab);
} }
return lab; return lab;
...@@ -137,11 +168,22 @@ sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val) ...@@ -137,11 +168,22 @@ sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val)
* See comment for find_pvar() above * See comment for find_pvar() above
*/ */
sp_cond_type_t * sp_cond_type_t *
sp_pcontext::find_cond(LEX_STRING *name) sp_pcontext::find_cond(LEX_STRING *name, my_bool scoped)
{ {
uint i = m_cond.elements; uint i = m_cond.elements;
uint limit;
while (i-- > 0) if (! scoped || m_scopes.elements == 0)
limit= 0;
else
{
sp_scope_t s;
get_dynamic(&m_scopes, (gptr)&s, m_scopes.elements-1);
limit= s.conds;
}
while (i-- > limit)
{ {
sp_cond_t *p; sp_cond_t *p;
...@@ -172,11 +214,22 @@ sp_pcontext::push_cursor(LEX_STRING *name) ...@@ -172,11 +214,22 @@ sp_pcontext::push_cursor(LEX_STRING *name)
* See comment for find_pvar() above * See comment for find_pvar() above
*/ */
my_bool my_bool
sp_pcontext::find_cursor(LEX_STRING *name, uint *poff) sp_pcontext::find_cursor(LEX_STRING *name, uint *poff, my_bool scoped)
{ {
uint i = m_cursor.elements; uint i = m_cursor.elements;
uint limit;
if (! scoped || m_scopes.elements == 0)
limit= 0;
else
{
sp_scope_t s;
while (i-- > 0) get_dynamic(&m_scopes, (gptr)&s, m_scopes.elements-1);
limit= s.curs;
}
while (i-- > limit)
{ {
LEX_STRING n; LEX_STRING n;
......
...@@ -42,6 +42,7 @@ typedef struct sp_label ...@@ -42,6 +42,7 @@ typedef struct sp_label
{ {
char *name; char *name;
uint ip; // Instruction index uint ip; // Instruction index
my_bool isbegin; // For ITERATE error checking
} sp_label_t; } sp_label_t;
typedef struct sp_cond_type typedef struct sp_cond_type
...@@ -57,6 +58,11 @@ typedef struct sp_cond ...@@ -57,6 +58,11 @@ typedef struct sp_cond
sp_cond_type_t *val; sp_cond_type_t *val;
} sp_cond_t; } sp_cond_t;
typedef struct sp_scope
{
uint vars, conds, curs;
} sp_scope_t;
class sp_pcontext : public Sql_alloc class sp_pcontext : public Sql_alloc
{ {
sp_pcontext(const sp_pcontext &); /* Prevent use of these */ sp_pcontext(const sp_pcontext &); /* Prevent use of these */
...@@ -70,6 +76,13 @@ class sp_pcontext : public Sql_alloc ...@@ -70,6 +76,13 @@ class sp_pcontext : public Sql_alloc
void void
destroy(); destroy();
// For error checking of duplicate things
void
push_scope();
void
pop_scope();
// //
// Parameters and variables // Parameters and variables
// //
...@@ -130,7 +143,7 @@ class sp_pcontext : public Sql_alloc ...@@ -130,7 +143,7 @@ class sp_pcontext : public Sql_alloc
// Find by name // Find by name
sp_pvar_t * sp_pvar_t *
find_pvar(LEX_STRING *name); find_pvar(LEX_STRING *name, my_bool scoped=0);
// Find by index // Find by index
sp_pvar_t * sp_pvar_t *
...@@ -182,7 +195,7 @@ class sp_pcontext : public Sql_alloc ...@@ -182,7 +195,7 @@ class sp_pcontext : public Sql_alloc
} }
sp_cond_type_t * sp_cond_type_t *
find_cond(LEX_STRING *name); find_cond(LEX_STRING *name, my_bool scoped=0);
// //
// Handlers // Handlers
...@@ -208,7 +221,7 @@ class sp_pcontext : public Sql_alloc ...@@ -208,7 +221,7 @@ class sp_pcontext : public Sql_alloc
push_cursor(LEX_STRING *name); push_cursor(LEX_STRING *name);
my_bool my_bool
find_cursor(LEX_STRING *name, uint *poff); find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0);
inline void inline void
pop_cursor(uint num) pop_cursor(uint num)
...@@ -233,6 +246,7 @@ class sp_pcontext : public Sql_alloc ...@@ -233,6 +246,7 @@ class sp_pcontext : public Sql_alloc
DYNAMIC_ARRAY m_pvar; // Parameters/variables DYNAMIC_ARRAY m_pvar; // Parameters/variables
DYNAMIC_ARRAY m_cond; // Conditions DYNAMIC_ARRAY m_cond; // Conditions
DYNAMIC_ARRAY m_cursor; // Cursors DYNAMIC_ARRAY m_cursor; // Cursors
DYNAMIC_ARRAY m_scopes; // For error checking
List<sp_label_t> m_label; // The label list List<sp_label_t> m_label; // The label list
......
...@@ -371,6 +371,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -371,6 +371,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
%token SPATIAL_SYM %token SPATIAL_SYM
%token SPECIFIC_SYM %token SPECIFIC_SYM
%token SQLEXCEPTION_SYM %token SQLEXCEPTION_SYM
%token SQLSTATE_SYM
%token SQLWARNING_SYM %token SQLWARNING_SYM
%token SSL_SYM %token SSL_SYM
%token STARTING %token STARTING
...@@ -618,7 +619,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); ...@@ -618,7 +619,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
ULONGLONG_NUM field_ident select_alias ident ident_or_text ULONGLONG_NUM field_ident select_alias ident ident_or_text
UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
NCHAR_STRING opt_component NCHAR_STRING opt_component
SP_FUNC ident_or_spfunc SP_FUNC ident_or_spfunc sp_opt_label
%type <lex_str_ptr> %type <lex_str_ptr>
opt_table_alias opt_table_alias
...@@ -1149,7 +1150,15 @@ sp_fdparams: ...@@ -1149,7 +1150,15 @@ sp_fdparams:
sp_fdparam: sp_fdparam:
ident type sp_opt_locator ident type sp_opt_locator
{ {
Lex->spcont->push_pvar(&$1, (enum enum_field_types)$2, sp_param_in); LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
if (spc->find_pvar(&$1, TRUE))
{
net_printf(YYTHD, ER_SP_DUP_THING, "parameter", $1.str);
YYABORT;
}
spc->push_pvar(&$1, (enum enum_field_types)$2, sp_param_in);
} }
; ;
...@@ -1167,9 +1176,16 @@ sp_pdparams: ...@@ -1167,9 +1176,16 @@ sp_pdparams:
sp_pdparam: sp_pdparam:
sp_opt_inout ident type sp_opt_locator sp_opt_inout ident type sp_opt_locator
{ {
Lex->spcont->push_pvar(&$2, LEX *lex= Lex;
(enum enum_field_types)$3, sp_pcontext *spc= lex->spcont;
(sp_param_mode_t)$1);
if (spc->find_pvar(&$2, TRUE))
{
net_printf(YYTHD, ER_SP_DUP_THING, "parameter", $2.str);
YYABORT;
}
spc->push_pvar(&$2, (enum enum_field_types)$3,
(sp_param_mode_t)$1);
} }
; ;
...@@ -1186,7 +1202,7 @@ sp_opt_locator: ...@@ -1186,7 +1202,7 @@ sp_opt_locator:
; ;
sp_proc_stmts: sp_proc_stmts:
sp_proc_stmt ';' /* Empty */ {}
| sp_proc_stmts sp_proc_stmt ';' | sp_proc_stmts sp_proc_stmt ';'
; ;
...@@ -1231,6 +1247,14 @@ sp_decl: ...@@ -1231,6 +1247,14 @@ sp_decl:
} }
| DECLARE_SYM ident CONDITION_SYM FOR_SYM sp_cond | DECLARE_SYM ident CONDITION_SYM FOR_SYM sp_cond
{ {
LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
if (spc->find_cond(&$2, TRUE))
{
net_printf(YYTHD, ER_SP_DUP_THING, "condition", $2.str);
YYABORT;
}
YYTHD->lex->spcont->push_cond(&$2, $5); YYTHD->lex->spcont->push_cond(&$2, $5);
$$.vars= $$.hndlrs= $$.curs= 0; $$.vars= $$.hndlrs= $$.curs= 0;
$$.conds= 1; $$.conds= 1;
...@@ -1272,8 +1296,16 @@ sp_decl: ...@@ -1272,8 +1296,16 @@ sp_decl:
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_head *sp= lex->sphead; sp_head *sp= lex->sphead;
sp_instr_cpush *i= new sp_instr_cpush(sp->instructions(), $5); sp_pcontext *spc= lex->spcont;
uint offp;
sp_instr_cpush *i;
if (spc->find_cursor(&$2, &offp, TRUE))
{
net_printf(YYTHD, ER_SP_DUP_THING, "cursor", $2.str);
YYABORT;
}
i= new sp_instr_cpush(sp->instructions(), $5);
sp->add_instr(i); sp->add_instr(i);
lex->spcont->push_cursor(&$2); lex->spcont->push_cursor(&$2);
$$.vars= $$.conds= $$.hndlrs= 0; $$.vars= $$.conds= $$.hndlrs= 0;
...@@ -1344,18 +1376,23 @@ sp_cond: ...@@ -1344,18 +1376,23 @@ sp_cond:
$$->type= sp_cond_type_t::number; $$->type= sp_cond_type_t::number;
$$->mysqlerr= $1; $$->mysqlerr= $1;
} }
| TEXT_STRING_literal | SQLSTATE_SYM opt_value TEXT_STRING_literal
{ /* SQLSTATE */ { /* SQLSTATE */
uint len= ($1.length < sizeof($$->sqlstate)-1 ? uint len= ($3.length < sizeof($$->sqlstate)-1 ?
$1.length : sizeof($$->sqlstate)-1); $3.length : sizeof($$->sqlstate)-1);
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t)); $$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
$$->type= sp_cond_type_t::state; $$->type= sp_cond_type_t::state;
memcpy($$->sqlstate, $1.str, len); memcpy($$->sqlstate, $3.str, len);
$$->sqlstate[len]= '\0'; $$->sqlstate[len]= '\0';
} }
; ;
opt_value:
/* Empty */ {}
| VALUE_SYM {}
;
sp_hcond: sp_hcond:
sp_cond sp_cond
{ {
...@@ -1390,12 +1427,28 @@ sp_hcond: ...@@ -1390,12 +1427,28 @@ sp_hcond:
sp_decl_idents: sp_decl_idents:
ident ident
{ {
Lex->spcont->push_pvar(&$1, (enum_field_types)0, sp_param_in); LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
if (spc->find_pvar(&$1, TRUE))
{
net_printf(YYTHD, ER_SP_DUP_THING, "parameter", $1.str);
YYABORT;
}
spc->push_pvar(&$1, (enum_field_types)0, sp_param_in);
$$= 1; $$= 1;
} }
| sp_decl_idents ',' ident | sp_decl_idents ',' ident
{ {
Lex->spcont->push_pvar(&$3, (enum_field_types)0, sp_param_in); LEX *lex= Lex;
sp_pcontext *spc= lex->spcont;
if (spc->find_pvar(&$3, TRUE))
{
net_printf(YYTHD, ER_SP_DUP_THING, "parameter", $3.str);
YYABORT;
}
spc->push_pvar(&$3, (enum_field_types)0, sp_param_in);
$$= $1 + 1; $$= $1 + 1;
} }
; ;
...@@ -1532,7 +1585,7 @@ sp_proc_stmt: ...@@ -1532,7 +1585,7 @@ sp_proc_stmt:
LEX *lex= Lex; LEX *lex= Lex;
sp_label_t *lab= lex->spcont->find_label($2.str); sp_label_t *lab= lex->spcont->find_label($2.str);
if (! lab) if (! lab || lab->isbegin)
{ {
net_printf(YYTHD, ER_SP_LILABEL_MISMATCH, "ITERATE", $2.str); net_printf(YYTHD, ER_SP_LILABEL_MISMATCH, "ITERATE", $2.str);
YYABORT; YYABORT;
...@@ -1736,32 +1789,43 @@ sp_labeled_control: ...@@ -1736,32 +1789,43 @@ sp_labeled_control:
lex->sphead->instructions()); lex->sphead->instructions());
} }
} }
sp_unlabeled_control IDENT sp_unlabeled_control sp_opt_label
{ {
LEX *lex= Lex; LEX *lex= Lex;
sp_label_t *lab= lex->spcont->find_label($5.str);
if (!lab || if ($5.str)
my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
{ {
net_printf(YYTHD, ER_SP_LABEL_MISMATCH, $5.str); sp_label_t *lab= lex->spcont->find_label($5.str);
YYABORT;
} if (!lab ||
else my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
{ {
lex->spcont->pop_label(); net_printf(YYTHD, ER_SP_LABEL_MISMATCH, $5.str);
lex->sphead->backpatch(lab); YYABORT;
}
} }
lex->sphead->backpatch(lex->spcont->pop_label());
} }
; ;
sp_opt_label:
/* Empty */
{ $$.str= NULL; $$.length= 0; }
| IDENT
{ $$= $1; }
;
sp_unlabeled_control: sp_unlabeled_control:
BEGIN_SYM BEGIN_SYM
{ /* QQ This is just a dummy for grouping declarations and statements { /* QQ This is just a dummy for grouping declarations and statements
together. No [[NOT] ATOMIC] yet, and we need to figure out how together. No [[NOT] ATOMIC] yet, and we need to figure out how
make it coexist with the existing BEGIN COMMIT/ROLLBACK. */ make it coexist with the existing BEGIN COMMIT/ROLLBACK. */
LEX *lex= Lex;
sp_label_t *lab= lex->spcont->last_label();
Lex->spcont->push_label((char *)"", 0); /* For end of block */ lab->isbegin= TRUE;
/* Scope duplicate checking */
lex->spcont->push_scope();
} }
sp_decls sp_decls
sp_proc_stmts sp_proc_stmts
...@@ -1771,7 +1835,7 @@ sp_unlabeled_control: ...@@ -1771,7 +1835,7 @@ sp_unlabeled_control:
sp_head *sp= lex->sphead; sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont; sp_pcontext *ctx= lex->spcont;
sp->backpatch(ctx->pop_label()); sp->backpatch(ctx->last_label()); /* We always has a label */
ctx->pop_pvar($3.vars); ctx->pop_pvar($3.vars);
ctx->pop_cond($3.conds); ctx->pop_cond($3.conds);
ctx->pop_cursor($3.curs); ctx->pop_cursor($3.curs);
...@@ -1779,6 +1843,7 @@ sp_unlabeled_control: ...@@ -1779,6 +1843,7 @@ sp_unlabeled_control:
sp->add_instr(new sp_instr_hpop(sp->instructions(),$3.hndlrs)); sp->add_instr(new sp_instr_hpop(sp->instructions(),$3.hndlrs));
if ($3.curs) if ($3.curs)
sp->add_instr(new sp_instr_cpop(sp->instructions(), $3.curs)); sp->add_instr(new sp_instr_cpop(sp->instructions(), $3.curs));
ctx->pop_scope();
} }
| LOOP_SYM | LOOP_SYM
sp_proc_stmts END LOOP_SYM sp_proc_stmts END LOOP_SYM
......
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