summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--include/mysqld_error.h3
-rw-r--r--mysql-test/r/sp-error.result31
-rw-r--r--mysql-test/r/sp.result37
-rw-r--r--mysql-test/t/sp-error.test32
-rw-r--r--mysql-test/t/sp.test47
-rw-r--r--sql/lex.h1
-rw-r--r--sql/share/czech/errmsg.txt1
-rw-r--r--sql/share/danish/errmsg.txt1
-rw-r--r--sql/share/dutch/errmsg.txt1
-rw-r--r--sql/share/english/errmsg.txt1
-rw-r--r--sql/share/estonian/errmsg.txt1
-rw-r--r--sql/share/french/errmsg.txt1
-rw-r--r--sql/share/german/errmsg.txt1
-rw-r--r--sql/share/greek/errmsg.txt1
-rw-r--r--sql/share/hungarian/errmsg.txt1
-rw-r--r--sql/share/italian/errmsg.txt1
-rw-r--r--sql/share/japanese/errmsg.txt1
-rw-r--r--sql/share/korean/errmsg.txt1
-rw-r--r--sql/share/norwegian-ny/errmsg.txt1
-rw-r--r--sql/share/norwegian/errmsg.txt1
-rw-r--r--sql/share/polish/errmsg.txt1
-rw-r--r--sql/share/portuguese/errmsg.txt1
-rw-r--r--sql/share/romanian/errmsg.txt1
-rw-r--r--sql/share/russian/errmsg.txt1
-rw-r--r--sql/share/serbian/errmsg.txt1
-rw-r--r--sql/share/slovak/errmsg.txt1
-rw-r--r--sql/share/spanish/errmsg.txt1
-rw-r--r--sql/share/swedish/errmsg.txt1
-rw-r--r--sql/share/ukrainian/errmsg.txt1
-rw-r--r--sql/sp_pcontext.cc67
-rw-r--r--sql/sp_pcontext.h20
-rw-r--r--sql/sql_yacc.yy119
32 files changed, 336 insertions, 44 deletions
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
index f12cdda257a..4304235055f 100644
--- a/include/mysqld_error.h
+++ b/include/mysqld_error.h
@@ -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
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index 4cd1c4c961c..2ece3e61d1d 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -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;
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index c5cd1c6a1b9..4f66dafbe81 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -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
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index 7c541029452..09a1e196786 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -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 ;|
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 83fabcce34e..b9f62d4fb0a 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -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)
diff --git a/sql/lex.h b/sql/lex.h
index 8fbf504076b..f4368cacb5d 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -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},
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 7e992880c45..1f85a5fb84b 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -319,3 +319,4 @@ character-set=latin2
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index b2bb5f58525..f66b1492433 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -313,3 +313,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index f8e5fafa198..d4ea5803390 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -321,3 +321,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index 085a1e7389f..b52762aaac9 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -310,3 +310,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index b70649390b6..18201380fbd 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -315,3 +315,4 @@ character-set=latin7
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index 10c3c72c371..c5912d59d23 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -310,3 +310,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 37d15882798..cc3a9d88a45 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -322,3 +322,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index 9ea7b97f07f..b64a1971e35 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -310,3 +310,4 @@ character-set=greek
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index 99246b28298..911cf3a09b6 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -312,3 +312,4 @@ character-set=latin2
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index 18ecc9e4539..152bd2dd922 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -310,3 +310,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index e17cfa9c315..963642a6348 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -312,3 +312,4 @@ character-set=ujis
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 9e1e85c959b..7f721cd999e 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -310,3 +310,4 @@ character-set=euckr
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index 798434f9720..ab9c428e3b0 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -312,3 +312,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index 58f607b91ae..29e14d3b580 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -312,3 +312,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 4770cd5332e..c0caecfd5a0 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -314,3 +314,4 @@ character-set=latin2
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index e0d93563665..4044abdbcb2 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -311,3 +311,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index d715847c27e..1fdcec122b8 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -314,3 +314,4 @@ character-set=latin2
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index d96a4fca293..9736cf23d2b 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -312,3 +312,4 @@ character-set=koi8r
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index cb6645dd67f..d95500183f0 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -305,3 +305,4 @@ character-set=cp1250
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index 6f1f6a7e267..2cf355e2659 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -318,3 +318,4 @@ character-set=latin2
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index ceb0458a2ac..53d3c26b990 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -312,3 +312,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index bb2711fd0b3..ac9ac52c0f3 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -310,3 +310,4 @@ character-set=latin1
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index 5cdac39ce93..3e3e06d31ea 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -315,3 +315,4 @@ character-set=koi8u
"Undeclared variable: %s"
"Wrong number of FETCH variables"
"No data to FETCH"
+"Duplicate %s: %s"
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index 3730230d47d..b7e23c9f5ad 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -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;
+
+ 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;
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 23be38edcbf..02134e3604f 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -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
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 3eaaa4e1414..391cac37ceb 100644
--- a/sql/sql_yacc.yy
+++ b/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,9 +1176,16 @@ sp_pdparams:
sp_pdparam:
sp_opt_inout ident type sp_opt_locator
{
- Lex->spcont->push_pvar(&$2,
- (enum enum_field_types)$3,
- (sp_param_mode_t)$1);
+ 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,32 +1789,43 @@ sp_labeled_control:
lex->sphead->instructions());
}
}
- sp_unlabeled_control IDENT
+ sp_unlabeled_control sp_opt_label
{
LEX *lex= Lex;
- sp_label_t *lab= lex->spcont->find_label($5.str);
- if (!lab ||
- my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
+ if ($5.str)
{
- net_printf(YYTHD, ER_SP_LABEL_MISMATCH, $5.str);
- YYABORT;
- }
- else
- {
- lex->spcont->pop_label();
- lex->sphead->backpatch(lab);
+ sp_label_t *lab= lex->spcont->find_label($5.str);
+
+ if (!lab ||
+ my_strcasecmp(system_charset_info, $5.str, lab->name) != 0)
+ {
+ net_printf(YYTHD, ER_SP_LABEL_MISMATCH, $5.str);
+ YYABORT;
+ }
}
+ 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