summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/sp-error.result28
-rw-r--r--mysql-test/t/sp-error.test38
-rw-r--r--sql/share/errmsg.txt2
-rw-r--r--sql/sp_pcontext.cc24
-rw-r--r--sql/sp_pcontext.h6
-rw-r--r--sql/sql_yacc.yy12
6 files changed, 105 insertions, 5 deletions
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index 1c2f4662ef1..1182c3d3569 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -466,4 +466,32 @@ ERROR 70100: Query execution was interrupted
call bug6807()|
ERROR 70100: Query execution was interrupted
drop procedure bug6807|
+drop procedure if exists bug8776_1|
+drop procedure if exists bug8776_2|
+drop procedure if exists bug8776_3|
+drop procedure if exists bug8776_4|
+create procedure bug8776_1()
+begin
+declare continue handler for sqlstate '42S0200test' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '42S0200test'
+create procedure bug8776_2()
+begin
+declare continue handler for sqlstate '4200' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '4200'
+create procedure bug8776_3()
+begin
+declare continue handler for sqlstate '420000' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '420000'
+create procedure bug8776_4()
+begin
+declare continue handler for sqlstate '42x00' begin end;
+begin end;
+end|
+ERROR 42000: Bad SQLSTATE: '42x00'
drop table t1|
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index 594daf66fcb..0f775958d7a 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -641,6 +641,44 @@ call bug6807()|
drop procedure bug6807|
+#
+# BUG#876: Stored Procedures: Invalid SQLSTATE is allowed in
+# a DECLARE ? HANDLER FOR stmt.
+#
+--disable_warnings
+drop procedure if exists bug8776_1|
+drop procedure if exists bug8776_2|
+drop procedure if exists bug8776_3|
+drop procedure if exists bug8776_4|
+--enable_warnings
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_1()
+begin
+ declare continue handler for sqlstate '42S0200test' begin end;
+ begin end;
+end|
+
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_2()
+begin
+ declare continue handler for sqlstate '4200' begin end;
+ begin end;
+end|
+
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_3()
+begin
+ declare continue handler for sqlstate '420000' begin end;
+ begin end;
+end|
+
+--error ER_SP_BAD_SQLSTATE
+create procedure bug8776_4()
+begin
+ declare continue handler for sqlstate '42x00' begin end;
+ begin end;
+end|
+
drop table t1|
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index 5757510bfb4..ba4ef70486b 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5326,3 +5326,5 @@ ER_PROC_AUTO_REVOKE_FAIL
eng "Failed to revoke all privileges to dropped routine"
ER_DATA_TOO_LONG 22001
eng "Data too long for column '%s' at row %ld"
+ER_SP_BAD_SQLSTATE 42000
+ eng "Bad SQLSTATE: '%s'"
diff --git a/sql/sp_pcontext.cc b/sql/sp_pcontext.cc
index 7176498f276..15d3f87ff29 100644
--- a/sql/sp_pcontext.cc
+++ b/sql/sp_pcontext.cc
@@ -26,6 +26,30 @@
#include "sp_pcontext.h"
#include "sp_head.h"
+/*
+ * Sanity check for SQLSTATEs. Will not check if it's really an existing
+ * state (there are just too many), but will check length and bad characters.
+ * Returns TRUE if it's ok, FALSE if it's bad.
+ */
+bool
+sp_cond_check(LEX_STRING *sqlstate)
+{
+ int i;
+ const char *p;
+
+ if (sqlstate->length != 5)
+ return FALSE;
+ for (p= sqlstate->str, i= 0 ; i < 5 ; i++)
+ {
+ char c = p[i];
+
+ if ((c < '0' || '9' < c) &&
+ (c < 'A' || 'Z' < c))
+ return FALSE;
+ }
+ return TRUE;
+}
+
sp_pcontext::sp_pcontext(sp_pcontext *prev)
: Sql_alloc(), m_psubsize(0), m_csubsize(0), m_hsubsize(0),
m_handlers(0), m_parent(prev)
diff --git a/sql/sp_pcontext.h b/sql/sp_pcontext.h
index 66f631f4938..42d8140b78c 100644
--- a/sql/sp_pcontext.h
+++ b/sql/sp_pcontext.h
@@ -60,6 +60,12 @@ typedef struct sp_cond_type
uint mysqlerr;
} sp_cond_type_t;
+/* Sanity check for SQLSTATEs. Will not check if it's really an existing
+ * state (there are just too many), but will check length bad characters.
+ */
+extern bool
+sp_cond_check(LEX_STRING *sqlstate);
+
typedef struct sp_cond
{
LEX_STRING name;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 45c3e94f0ff..a69b6a96982 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1760,13 +1760,15 @@ sp_cond:
}
| SQLSTATE_SYM opt_value TEXT_STRING_literal
{ /* SQLSTATE */
- uint len= ($3.length < sizeof($$->sqlstate)-1 ?
- $3.length : sizeof($$->sqlstate)-1);
-
+ if (!sp_cond_check(&$3))
+ {
+ my_error(ER_SP_BAD_SQLSTATE, MYF(0), $3.str);
+ YYABORT;
+ }
$$= (sp_cond_type_t *)YYTHD->alloc(sizeof(sp_cond_type_t));
$$->type= sp_cond_type_t::state;
- memcpy($$->sqlstate, $3.str, len);
- $$->sqlstate[len]= '\0';
+ memcpy($$->sqlstate, $3.str, 5);
+ $$->sqlstate[5]= '\0';
}
;