mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
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.
This commit is contained in:
@ -323,4 +323,5 @@
|
||||
#define ER_SP_UNDECLARED_VAR 1304
|
||||
#define ER_SP_WRONG_NO_OF_FETCH_ARGS 1305
|
||||
#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;
|
||||
end loop;
|
||||
ERROR HY000: ITERATE with no matching label: bar
|
||||
create procedure foo()
|
||||
foo: begin
|
||||
iterate foo;
|
||||
end;
|
||||
ERROR HY000: ITERATE with no matching label: foo
|
||||
create procedure foo()
|
||||
foo: loop
|
||||
foo: loop
|
||||
set @x=2;
|
||||
@ -219,4 +224,30 @@ end;
|
||||
call p();
|
||||
ERROR HY000: Wrong number of FETCH variables
|
||||
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;
|
||||
|
@ -36,6 +36,20 @@ select * from t1;
|
||||
id data
|
||||
bar 666
|
||||
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)
|
||||
begin
|
||||
insert into test.t1 values (x1, y);
|
||||
@ -256,7 +270,7 @@ insert into test.t1 values ("d", x);
|
||||
set x = x-1;
|
||||
leave hmm;
|
||||
insert into test.t1 values ("x", x);
|
||||
end while hmm;
|
||||
end while;
|
||||
call d(3);
|
||||
select * from t1;
|
||||
id data
|
||||
@ -335,6 +349,21 @@ h1 1
|
||||
h? 17
|
||||
delete from t1;
|
||||
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)
|
||||
begin
|
||||
insert into test.t1 values (x, y);
|
||||
@ -461,6 +490,8 @@ create procedure hndlr1(val int)
|
||||
begin
|
||||
declare x int default 0;
|
||||
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;
|
||||
insert into test.t666 values ("hndlr1", val); # Non-existing table
|
||||
if (x) then
|
||||
@ -477,7 +508,7 @@ create procedure hndlr2(val int)
|
||||
begin
|
||||
declare x int default 0;
|
||||
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
|
||||
end;
|
||||
insert into test.t1 values ("hndlr2", x);
|
||||
@ -744,7 +775,7 @@ end if;
|
||||
set s = s+1;
|
||||
end;
|
||||
end if;
|
||||
end loop again;
|
||||
end loop;
|
||||
end;
|
||||
create procedure ip(m int unsigned)
|
||||
begin
|
||||
|
@ -74,6 +74,11 @@ create procedure foo()
|
||||
foo: loop
|
||||
iterate bar;
|
||||
end loop|
|
||||
--error 1285
|
||||
create procedure foo()
|
||||
foo: begin
|
||||
iterate foo;
|
||||
end|
|
||||
|
||||
# Redefining label
|
||||
--error 1286
|
||||
@ -298,6 +303,33 @@ end|
|
||||
call 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|
|
||||
|
||||
delimiter ;|
|
||||
|
@ -59,6 +59,28 @@ delete from t1;
|
||||
# Now for multiple statements...
|
||||
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.
|
||||
create procedure two(x1 char(16), x2 char(16), y int)
|
||||
begin
|
||||
@ -313,7 +335,7 @@ hmm: while x > 0 do
|
||||
set x = x-1;
|
||||
leave hmm;
|
||||
insert into test.t1 values ("x", x);
|
||||
end while hmm|
|
||||
end while|
|
||||
|
||||
call d(3)|
|
||||
select * from t1|
|
||||
@ -393,6 +415,23 @@ delete from t1|
|
||||
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
|
||||
create procedure into_test(x char(16), y int)
|
||||
begin
|
||||
@ -543,6 +582,8 @@ create procedure hndlr1(val int)
|
||||
begin
|
||||
declare x int default 0;
|
||||
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;
|
||||
|
||||
insert into test.t666 values ("hndlr1", val); # Non-existing table
|
||||
@ -561,7 +602,7 @@ begin
|
||||
declare x int default 0;
|
||||
|
||||
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
|
||||
end;
|
||||
@ -864,7 +905,7 @@ begin
|
||||
set s = s+1;
|
||||
end;
|
||||
end if;
|
||||
end loop again;
|
||||
end loop;
|
||||
end|
|
||||
|
||||
create procedure ip(m int unsigned)
|
||||
|
@ -386,6 +386,7 @@ static SYMBOL symbols[] = {
|
||||
{ "SPATIAL", SYM(SPATIAL_SYM),0,0},
|
||||
{ "SPECIFIC", SYM(SPECIFIC_SYM),0,0},
|
||||
{ "SQLEXCEPTION", SYM(SQLEXCEPTION_SYM),0,0},
|
||||
{ "SQLSTATE", SYM(SQLSTATE_SYM),0,0},
|
||||
{ "SQLWARNING", SYM(SQLWARNING_SYM),0,0},
|
||||
{ "SQL_BIG_RESULT", SYM(SQL_BIG_RESULT),0,0},
|
||||
{ "SQL_BUFFER_RESULT", SYM(SQL_BUFFER_RESULT),0,0},
|
||||
|
@ -319,3 +319,4 @@ character-set=latin2
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -313,3 +313,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -321,3 +321,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -310,3 +310,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -315,3 +315,4 @@ character-set=latin7
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -310,3 +310,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -322,3 +322,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -310,3 +310,4 @@ character-set=greek
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -312,3 +312,4 @@ character-set=latin2
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -310,3 +310,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -312,3 +312,4 @@ character-set=ujis
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -310,3 +310,4 @@ character-set=euckr
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -312,3 +312,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -312,3 +312,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -314,3 +314,4 @@ character-set=latin2
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -311,3 +311,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -314,3 +314,4 @@ character-set=latin2
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -312,3 +312,4 @@ character-set=koi8r
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -305,3 +305,4 @@ character-set=cp1250
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -318,3 +318,4 @@ character-set=latin2
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -312,3 +312,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -310,3 +310,4 @@ character-set=latin1
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -315,3 +315,4 @@ character-set=koi8u
|
||||
"Undeclared variable: %s"
|
||||
"Wrong number of FETCH variables"
|
||||
"No data to FETCH"
|
||||
"Duplicate %s: %s"
|
||||
|
@ -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_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_scopes, sizeof(sp_scope_t), 16, 8));
|
||||
m_label.empty();
|
||||
}
|
||||
|
||||
@ -41,23 +42,52 @@ sp_pcontext::destroy()
|
||||
delete_dynamic(&m_pvar);
|
||||
delete_dynamic(&m_cond);
|
||||
delete_dynamic(&m_cursor);
|
||||
delete_dynamic(&m_scopes);
|
||||
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
|
||||
** we have shadowed names).
|
||||
** 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
|
||||
** 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_pcontext::find_pvar(LEX_STRING *name)
|
||||
sp_pcontext::find_pvar(LEX_STRING *name, my_bool scoped)
|
||||
{
|
||||
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;
|
||||
|
||||
@ -101,6 +131,7 @@ sp_pcontext::push_label(char *name, uint ip)
|
||||
{
|
||||
lab->name= name;
|
||||
lab->ip= ip;
|
||||
lab->isbegin= FALSE;
|
||||
m_label.push_front(lab);
|
||||
}
|
||||
return lab;
|
||||
@ -137,11 +168,22 @@ sp_pcontext::push_cond(LEX_STRING *name, sp_cond_type_t *val)
|
||||
* See comment for find_pvar() above
|
||||
*/
|
||||
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 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;
|
||||
|
||||
@ -172,11 +214,22 @@ sp_pcontext::push_cursor(LEX_STRING *name)
|
||||
* See comment for find_pvar() above
|
||||
*/
|
||||
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 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.curs;
|
||||
}
|
||||
|
||||
while (i-- > limit)
|
||||
{
|
||||
LEX_STRING n;
|
||||
|
||||
|
@ -42,6 +42,7 @@ typedef struct sp_label
|
||||
{
|
||||
char *name;
|
||||
uint ip; // Instruction index
|
||||
my_bool isbegin; // For ITERATE error checking
|
||||
} sp_label_t;
|
||||
|
||||
typedef struct sp_cond_type
|
||||
@ -57,6 +58,11 @@ typedef struct sp_cond
|
||||
sp_cond_type_t *val;
|
||||
} sp_cond_t;
|
||||
|
||||
typedef struct sp_scope
|
||||
{
|
||||
uint vars, conds, curs;
|
||||
} sp_scope_t;
|
||||
|
||||
class sp_pcontext : public Sql_alloc
|
||||
{
|
||||
sp_pcontext(const sp_pcontext &); /* Prevent use of these */
|
||||
@ -70,6 +76,13 @@ class sp_pcontext : public Sql_alloc
|
||||
void
|
||||
destroy();
|
||||
|
||||
// For error checking of duplicate things
|
||||
void
|
||||
push_scope();
|
||||
|
||||
void
|
||||
pop_scope();
|
||||
|
||||
//
|
||||
// Parameters and variables
|
||||
//
|
||||
@ -130,7 +143,7 @@ class sp_pcontext : public Sql_alloc
|
||||
|
||||
// Find by name
|
||||
sp_pvar_t *
|
||||
find_pvar(LEX_STRING *name);
|
||||
find_pvar(LEX_STRING *name, my_bool scoped=0);
|
||||
|
||||
// Find by index
|
||||
sp_pvar_t *
|
||||
@ -182,7 +195,7 @@ class sp_pcontext : public Sql_alloc
|
||||
}
|
||||
|
||||
sp_cond_type_t *
|
||||
find_cond(LEX_STRING *name);
|
||||
find_cond(LEX_STRING *name, my_bool scoped=0);
|
||||
|
||||
//
|
||||
// Handlers
|
||||
@ -208,7 +221,7 @@ class sp_pcontext : public Sql_alloc
|
||||
push_cursor(LEX_STRING *name);
|
||||
|
||||
my_bool
|
||||
find_cursor(LEX_STRING *name, uint *poff);
|
||||
find_cursor(LEX_STRING *name, uint *poff, my_bool scoped=0);
|
||||
|
||||
inline void
|
||||
pop_cursor(uint num)
|
||||
@ -233,6 +246,7 @@ private:
|
||||
DYNAMIC_ARRAY m_pvar; // Parameters/variables
|
||||
DYNAMIC_ARRAY m_cond; // Conditions
|
||||
DYNAMIC_ARRAY m_cursor; // Cursors
|
||||
DYNAMIC_ARRAY m_scopes; // For error checking
|
||||
|
||||
List<sp_label_t> m_label; // The label list
|
||||
|
||||
|
105
sql/sql_yacc.yy
105
sql/sql_yacc.yy
@ -371,6 +371,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
||||
%token SPATIAL_SYM
|
||||
%token SPECIFIC_SYM
|
||||
%token SQLEXCEPTION_SYM
|
||||
%token SQLSTATE_SYM
|
||||
%token SQLWARNING_SYM
|
||||
%token SSL_SYM
|
||||
%token STARTING
|
||||
@ -618,7 +619,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize);
|
||||
ULONGLONG_NUM field_ident select_alias ident ident_or_text
|
||||
UNDERSCORE_CHARSET IDENT_sys TEXT_STRING_sys TEXT_STRING_literal
|
||||
NCHAR_STRING opt_component
|
||||
SP_FUNC ident_or_spfunc
|
||||
SP_FUNC ident_or_spfunc sp_opt_label
|
||||
|
||||
%type <lex_str_ptr>
|
||||
opt_table_alias
|
||||
@ -1149,7 +1150,15 @@ sp_fdparams:
|
||||
sp_fdparam:
|
||||
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,8 +1176,15 @@ sp_pdparams:
|
||||
sp_pdparam:
|
||||
sp_opt_inout ident type sp_opt_locator
|
||||
{
|
||||
Lex->spcont->push_pvar(&$2,
|
||||
(enum enum_field_types)$3,
|
||||
LEX *lex= Lex;
|
||||
sp_pcontext *spc= lex->spcont;
|
||||
|
||||
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:
|
||||
;
|
||||
|
||||
sp_proc_stmts:
|
||||
sp_proc_stmt ';'
|
||||
/* Empty */ {}
|
||||
| sp_proc_stmts sp_proc_stmt ';'
|
||||
;
|
||||
|
||||
@ -1231,6 +1247,14 @@ sp_decl:
|
||||
}
|
||||
| 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);
|
||||
$$.vars= $$.hndlrs= $$.curs= 0;
|
||||
$$.conds= 1;
|
||||
@ -1272,8 +1296,16 @@ sp_decl:
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
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);
|
||||
lex->spcont->push_cursor(&$2);
|
||||
$$.vars= $$.conds= $$.hndlrs= 0;
|
||||
@ -1344,18 +1376,23 @@ sp_cond:
|
||||
$$->type= sp_cond_type_t::number;
|
||||
$$->mysqlerr= $1;
|
||||
}
|
||||
| TEXT_STRING_literal
|
||||
| SQLSTATE_SYM opt_value TEXT_STRING_literal
|
||||
{ /* SQLSTATE */
|
||||
uint len= ($1.length < sizeof($$->sqlstate)-1 ?
|
||||
$1.length : sizeof($$->sqlstate)-1);
|
||||
uint len= ($3.length < sizeof($$->sqlstate)-1 ?
|
||||
$3.length : sizeof($$->sqlstate)-1);
|
||||
|
||||
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
|
||||
$$->type= sp_cond_type_t::state;
|
||||
memcpy($$->sqlstate, $1.str, len);
|
||||
memcpy($$->sqlstate, $3.str, len);
|
||||
$$->sqlstate[len]= '\0';
|
||||
}
|
||||
;
|
||||
|
||||
opt_value:
|
||||
/* Empty */ {}
|
||||
| VALUE_SYM {}
|
||||
;
|
||||
|
||||
sp_hcond:
|
||||
sp_cond
|
||||
{
|
||||
@ -1390,12 +1427,28 @@ sp_hcond:
|
||||
sp_decl_idents:
|
||||
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;
|
||||
}
|
||||
| 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;
|
||||
}
|
||||
;
|
||||
@ -1532,7 +1585,7 @@ sp_proc_stmt:
|
||||
LEX *lex= Lex;
|
||||
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);
|
||||
YYABORT;
|
||||
@ -1736,9 +1789,12 @@ sp_labeled_control:
|
||||
lex->sphead->instructions());
|
||||
}
|
||||
}
|
||||
sp_unlabeled_control IDENT
|
||||
sp_unlabeled_control sp_opt_label
|
||||
{
|
||||
LEX *lex= Lex;
|
||||
|
||||
if ($5.str)
|
||||
{
|
||||
sp_label_t *lab= lex->spcont->find_label($5.str);
|
||||
|
||||
if (!lab ||
|
||||
@ -1747,21 +1803,29 @@ sp_labeled_control:
|
||||
net_printf(YYTHD, ER_SP_LABEL_MISMATCH, $5.str);
|
||||
YYABORT;
|
||||
}
|
||||
else
|
||||
{
|
||||
lex->spcont->pop_label();
|
||||
lex->sphead->backpatch(lab);
|
||||
}
|
||||
lex->sphead->backpatch(lex->spcont->pop_label());
|
||||
}
|
||||
;
|
||||
|
||||
sp_opt_label:
|
||||
/* Empty */
|
||||
{ $$.str= NULL; $$.length= 0; }
|
||||
| IDENT
|
||||
{ $$= $1; }
|
||||
;
|
||||
|
||||
sp_unlabeled_control:
|
||||
BEGIN_SYM
|
||||
{ /* QQ This is just a dummy for grouping declarations and statements
|
||||
together. No [[NOT] ATOMIC] yet, and we need to figure out how
|
||||
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_proc_stmts
|
||||
@ -1771,7 +1835,7 @@ sp_unlabeled_control:
|
||||
sp_head *sp= lex->sphead;
|
||||
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_cond($3.conds);
|
||||
ctx->pop_cursor($3.curs);
|
||||
@ -1779,6 +1843,7 @@ sp_unlabeled_control:
|
||||
sp->add_instr(new sp_instr_hpop(sp->instructions(),$3.hndlrs));
|
||||
if ($3.curs)
|
||||
sp->add_instr(new sp_instr_cpop(sp->instructions(), $3.curs));
|
||||
ctx->pop_scope();
|
||||
}
|
||||
| LOOP_SYM
|
||||
sp_proc_stmts END LOOP_SYM
|
||||
|
Reference in New Issue
Block a user