diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 748fda6c4ec..07835201acb 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -283,4 +283,39 @@ create table t3 (column_1 int)| call bug1653()| drop procedure bug1653| drop table t3| +create procedure bug2259() +begin +declare v1 int; +declare c1 cursor for select s1 from t10; +fetch c1 into v1; +end| +call bug2259()| +ERROR 24000: Cursor is not open +drop procedure bug2259| +create procedure bug2272() +begin +declare v int; +update t1 set v = 42; +end| +insert into t1 values (666, 51.3)| +call bug2272()| +ERROR 42S22: Unknown column 'v' in 'field list' +delete from t1| +drop procedure bug2272| +create procedure bug2329_1() +begin +declare v int; +insert into t1 (v) values (5); +end| +create procedure bug2329_2() +begin +declare v int; +replace t1 set v = 5; +end| +call bug2329_1()| +ERROR 42S22: Unknown column 'v' in 'field list' +call bug2329_2()| +ERROR 42S22: Unknown column 'v' in 'field list' +drop procedure bug2329_1| +drop procedure bug2329_2| drop table t1| diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 37839fdb650..f77f0787f20 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -75,6 +75,20 @@ id data locset 21 delete from t1| drop procedure locset| +create procedure setcontext() +begin +declare data int default 2; +insert into t1 (id, data) values ("foo", 1); +replace t1 set data = data, id = "bar"; +update t1 set id = "kaka", data = 3 where t1.data = data; +end| +call setcontext()| +select * from t1| +id data +foo 1 +kaka 3 +delete from t1| +drop procedure setcontext| drop table if exists t3| create table t3 ( d date, i int, f double, s varchar(32) )| create procedure nullset() @@ -893,6 +907,67 @@ avg 0 4.4 delete from t1| delete from t2| drop procedure bug1874| +create procedure bug2260() +begin +declare v1 int; +declare continue handler for not found set @x2 = 1; +declare c1 cursor for select data from t1; +open c1; +fetch c1 into v1; +set @x2 = 2; +close c1; +end| +call bug2260()| +select @x2| +@x2 +2 +drop procedure bug2260| +create procedure bug2267_1() +begin +show procedure status; +end| +create procedure bug2267_2() +begin +show function status; +end| +create procedure bug2267_3() +begin +show create procedure bug2267_1; +end| +create procedure bug2267_4() +begin +show create function fac; +end| +call bug2267_1()| +Name Type Definer Modified Created Security_type Comment +bug2267_1 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +bug2267_2 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +bug2267_3 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +bug2267_4 PROCEDURE root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +call bug2267_2()| +Name Type Definer Modified Created Security_type Comment +fac FUNCTION root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 DEFINER +call bug2267_3()| +Procedure Create Procedure +bug2267_1 CREATE PROCEDURE `bug2267_1`() +begin +show procedure status; +end +call bug2267_4()| +Function Create Function +fac CREATE FUNCTION `fac`(n int unsigned) RETURNS bigint unsigned +begin +declare f bigint unsigned default 1; +while n > 1 do +set f = f * n; +set n = n - 1; +end while; +return f; +end +drop procedure bug2267_1| +drop procedure bug2267_2| +drop procedure bug2267_3| +drop procedure bug2267_4| drop table if exists fac| create table fac (n int unsigned not null primary key, f bigint unsigned)| create procedure ifac(n int unsigned) diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index b8b60ac8dde..c72dcaedb4e 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -388,6 +388,62 @@ call bug1653()| drop procedure bug1653| drop table t3| +# +# BUG#2259 +# +# Note: When this bug existed, it did not necessarily cause a crash +# in all builds, but valgrind did give warnings. +create procedure bug2259() +begin + declare v1 int; + declare c1 cursor for select s1 from t10; + + fetch c1 into v1; +end| + +--error 1310 +call bug2259()| +drop procedure bug2259| + +# +# BUG#2272 +# +create procedure bug2272() +begin + declare v int; + + update t1 set v = 42; +end| + +insert into t1 values (666, 51.3)| +--error 1054 +call bug2272()| +delete from t1| +drop procedure bug2272| + +# +# BUG#2329 +# +create procedure bug2329_1() +begin + declare v int; + + insert into t1 (v) values (5); +end| + +create procedure bug2329_2() +begin + declare v int; + + replace t1 set v = 5; +end| + +--error 1054 +call bug2329_1()| +--error 1054 +call bug2329_2()| +drop procedure bug2329_1| +drop procedure bug2329_2| drop table t1| diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 11a00c51996..298120bca2f 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -109,6 +109,23 @@ delete from t1| drop procedure locset| +# In some contexts local variables are not recognized +# (and in some, you have to qualify the identifier). +create procedure setcontext() +begin + declare data int default 2; + + insert into t1 (id, data) values ("foo", 1); + replace t1 set data = data, id = "bar"; + update t1 set id = "kaka", data = 3 where t1.data = data; +end| + +call setcontext()| +select * from t1| +delete from t1| +drop procedure setcontext| + + # Set things to null --disable_warnings drop table if exists t3| @@ -1036,6 +1053,60 @@ delete from t1| delete from t2| drop procedure bug1874| +# +# BUG#2260 +# +create procedure bug2260() +begin + declare v1 int; + declare continue handler for not found set @x2 = 1; + declare c1 cursor for select data from t1; + + open c1; + fetch c1 into v1; + set @x2 = 2; + close c1; +end| + +call bug2260()| +select @x2| +drop procedure bug2260| + +# +# BUG#2267 +# +create procedure bug2267_1() +begin + show procedure status; +end| + +create procedure bug2267_2() +begin + show function status; +end| + +create procedure bug2267_3() +begin + show create procedure bug2267_1; +end| + +create procedure bug2267_4() +begin + show create function fac; +end| + +--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +call bug2267_1()| +--replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' +call bug2267_2()| +call bug2267_3()| +call bug2267_4()| + +drop procedure bug2267_1| +drop procedure bug2267_2| +drop procedure bug2267_3| +drop procedure bug2267_4| + # # Some "real" examples diff --git a/sql/sp.cc b/sql/sp.cc index dca67f803a4..0d657cddc37 100644 --- a/sql/sp.cc +++ b/sql/sp.cc @@ -570,20 +570,25 @@ sp_find_procedure(THD *thd, LEX_STRING *name) int sp_create_procedure(THD *thd, sp_head *sp) { + int ret; DBUG_ENTER("sp_create_procedure"); DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str)); - DBUG_RETURN(db_create_routine(thd, TYPE_ENUM_PROCEDURE, sp)); + + ret= db_create_routine(thd, TYPE_ENUM_PROCEDURE, sp); + DBUG_RETURN(ret); } int sp_drop_procedure(THD *thd, char *name, uint namelen) { + int ret; DBUG_ENTER("sp_drop_procedure"); DBUG_PRINT("enter", ("name: %*s", namelen, name)); sp_cache_remove(&thd->sp_proc_cache, name, namelen); - DBUG_RETURN(db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen)); + ret= db_drop_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen); + DBUG_RETURN(ret); } @@ -592,12 +597,14 @@ sp_update_procedure(THD *thd, char *name, uint namelen, char *newname, uint newnamelen, st_sp_chistics *chistics) { + int ret; DBUG_ENTER("sp_update_procedure"); DBUG_PRINT("enter", ("name: %*s", namelen, name)); sp_cache_remove(&thd->sp_proc_cache, name, namelen); - DBUG_RETURN(db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen, - newname, newnamelen, chistics)); + ret= db_update_routine(thd, TYPE_ENUM_PROCEDURE, name, namelen, + newname, newnamelen, chistics); + DBUG_RETURN(ret); } @@ -609,7 +616,11 @@ sp_show_create_procedure(THD *thd, LEX_STRING *name) DBUG_PRINT("enter", ("name: %*s", name->length, name->str)); if ((sp= sp_find_procedure(thd, name))) - DBUG_RETURN(sp->show_create_procedure(thd)); + { + int ret= sp->show_create_procedure(thd); + + DBUG_RETURN(ret); + } DBUG_RETURN(SP_KEY_NOT_FOUND); } @@ -618,8 +629,11 @@ sp_show_create_procedure(THD *thd, LEX_STRING *name) int sp_show_status_procedure(THD *thd, const char *wild) { + int ret; DBUG_ENTER("sp_show_status_procedure"); - DBUG_RETURN(db_show_routine_status(thd, TYPE_ENUM_PROCEDURE, wild)); + + ret= db_show_routine_status(thd, TYPE_ENUM_PROCEDURE, wild); + DBUG_RETURN(ret); } @@ -649,21 +663,25 @@ sp_find_function(THD *thd, LEX_STRING *name) int sp_create_function(THD *thd, sp_head *sp) { + int ret; DBUG_ENTER("sp_create_function"); DBUG_PRINT("enter", ("name: %*s", sp->m_name.length, sp->m_name.str)); - DBUG_RETURN(db_create_routine(thd, TYPE_ENUM_FUNCTION, sp)); + ret= db_create_routine(thd, TYPE_ENUM_FUNCTION, sp); + DBUG_RETURN(ret); } int sp_drop_function(THD *thd, char *name, uint namelen) { + int ret; DBUG_ENTER("sp_drop_function"); DBUG_PRINT("enter", ("name: %*s", namelen, name)); sp_cache_remove(&thd->sp_func_cache, name, namelen); - DBUG_RETURN(db_drop_routine(thd, TYPE_ENUM_FUNCTION, name, namelen)); + ret= db_drop_routine(thd, TYPE_ENUM_FUNCTION, name, namelen); + DBUG_RETURN(ret); } @@ -672,12 +690,14 @@ sp_update_function(THD *thd, char *name, uint namelen, char *newname, uint newnamelen, st_sp_chistics *chistics) { + int ret; DBUG_ENTER("sp_update_procedure"); DBUG_PRINT("enter", ("name: %*s", namelen, name)); sp_cache_remove(&thd->sp_func_cache, name, namelen); - DBUG_RETURN(db_update_routine(thd, TYPE_ENUM_FUNCTION, name, namelen, - newname, newnamelen, chistics)); + ret= db_update_routine(thd, TYPE_ENUM_FUNCTION, name, namelen, + newname, newnamelen, chistics); + DBUG_RETURN(ret); } @@ -689,7 +709,11 @@ sp_show_create_function(THD *thd, LEX_STRING *name) DBUG_PRINT("enter", ("name: %*s", name->length, name->str)); if ((sp= sp_find_function(thd, name))) - DBUG_RETURN(sp->show_create_function(thd)); + { + int ret= sp->show_create_function(thd); + + DBUG_RETURN(ret); + } DBUG_RETURN(SP_KEY_NOT_FOUND); } @@ -697,8 +721,10 @@ sp_show_create_function(THD *thd, LEX_STRING *name) int sp_show_status_function(THD *thd, const char *wild) { + int ret; DBUG_ENTER("sp_show_status_function"); - DBUG_RETURN(db_show_routine_status(thd, TYPE_ENUM_FUNCTION, wild)); + ret= db_show_routine_status(thd, TYPE_ENUM_FUNCTION, wild); + DBUG_RETURN(ret); } diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 11fa6ab20fa..b263fb22c0e 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -286,6 +286,7 @@ sp_head::execute(THD *thd) if (ctx) ctx->clear_handler(); + thd->query_error= 0; do { sp_instr *i; @@ -318,10 +319,11 @@ sp_head::execute(THD *thd) continue; } } - } while (ret == 0 && !thd->killed); + } while (ret == 0 && !thd->killed && !thd->query_error); - DBUG_PRINT("info", ("ret=%d killed=%d", ret, thd->killed)); - if (thd->killed) + DBUG_PRINT("info", ("ret=%d killed=%d query_error=%d", + ret, thd->killed, thd->query_error)); + if (thd->killed || thd->query_error) ret= -1; /* If the DB has changed, the pointer has changed too, but the original thd->db will then have been freed */ @@ -1032,7 +1034,7 @@ sp_instr_copen::execute(THD *thd, uint *nextp) res= -1; else res= exec_stmt(thd, lex); - c->post_open(thd, (res == 0 ? TRUE : FALSE)); + c->post_open(thd, (lex ? TRUE : FALSE)); } *nextp= m_ip+1; diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc index 41502618cda..0b2b20fe3b3 100644 --- a/sql/sp_rcontext.cc +++ b/sql/sp_rcontext.cc @@ -72,15 +72,15 @@ sp_rcontext::find_handler(uint sql_errno) found= 1; break; case sp_cond_type_t::warning: - if (sqlstate[0] == '0' && sqlstate[0] == '1') + if (sqlstate[0] == '0' && sqlstate[1] == '1') found= 1; break; case sp_cond_type_t::notfound: - if (sqlstate[0] == '0' && sqlstate[0] == '2') + if (sqlstate[0] == '0' && sqlstate[1] == '2') found= 1; break; case sp_cond_type_t::exception: - if (sqlstate[0] != '0' || sqlstate[0] > '2') + if (sqlstate[0] != '0' || sqlstate[1] > '2') found= 1; break; } @@ -153,12 +153,15 @@ sp_cursor::pre_open(THD *thd) } void -sp_cursor::post_open(THD *thd, my_bool isopen) +sp_cursor::post_open(THD *thd, my_bool was_opened) { thd->net.no_send_eof= m_nseof; // Restore the originals thd->protocol= m_oprot; - m_isopen= isopen; - m_current_row= m_prot->data; + if (was_opened) + { + m_isopen= was_opened; + m_current_row= m_prot->data; + } } int @@ -176,10 +179,13 @@ sp_cursor::close(THD *thd) void sp_cursor::destroy() { - delete m_prot; - m_prot= NULL; - free_root(&m_mem_root, MYF(0)); - bzero((char *)&m_mem_root, sizeof(m_mem_root)); + if (m_prot) + { + delete m_prot; + m_prot= NULL; + free_root(&m_mem_root, MYF(0)); + bzero((char *)&m_mem_root, sizeof(m_mem_root)); + } m_isopen= FALSE; } @@ -190,14 +196,12 @@ sp_cursor::fetch(THD *thd, List *vars) sp_pvar_t *pv; MYSQL_ROW row; uint fldcount; - MYSQL_FIELD *fields= m_prot->fields; if (! m_isopen) { send_error(thd, ER_SP_CURSOR_NOT_OPEN); return -1; } - if (m_current_row == NULL) { send_error(thd, ER_SP_FETCH_NO_DATA); diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h index 5d836998cb1..1b83d3518b6 100644 --- a/sql/sp_rcontext.h +++ b/sql/sp_rcontext.h @@ -205,7 +205,7 @@ class sp_cursor : public Sql_alloc public: sp_cursor(LEX *lex) - : m_lex(lex), m_isopen(0), m_current_row(NULL) + : m_lex(lex), m_prot(NULL), m_isopen(0), m_current_row(NULL) { /* Empty */ } @@ -220,7 +220,7 @@ public: LEX * pre_open(THD *thd); void - post_open(THD *thd, my_bool isopen); + post_open(THD *thd, my_bool was_opened); int close(THD *thd); diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index a5ec1a20959..f35b7f12fd1 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -679,6 +679,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); param_marker singlerow_subselect singlerow_subselect_init signed_literal NUM_literal exists_subselect exists_subselect_init sp_opt_default + simple_ident_nospvar simple_ident_q %type expr_list sp_expr_list udf_expr_list udf_expr_list2 when_list @@ -1257,7 +1258,7 @@ sp_fdparams: ; sp_fdparam: - ident type sp_opt_locator + ident type { LEX *lex= Lex; sp_pcontext *spc= lex->spcont; @@ -1283,7 +1284,7 @@ sp_pdparams: ; sp_pdparam: - sp_opt_inout ident type sp_opt_locator + sp_opt_inout ident type { LEX *lex= Lex; sp_pcontext *spc= lex->spcont; @@ -1305,11 +1306,6 @@ sp_opt_inout: | INOUT_SYM { $$= sp_param_inout; } ; -sp_opt_locator: - /* Empty */ - | AS LOCATOR_SYM - ; - sp_proc_stmts: /* Empty */ {} | sp_proc_stmts sp_proc_stmt ';' @@ -1576,7 +1572,13 @@ sp_proc_stmt: { LEX *lex= Lex; - if (lex->sql_command == SQLCOM_SELECT && !lex->result) + /* QQ What else? This doesn't seem to be a practical way, + but at the moment we can't think of anything better... */ + if ((lex->sql_command == SQLCOM_SELECT && !lex->result) || + lex->sql_command == SQLCOM_SHOW_CREATE_PROC || + lex->sql_command == SQLCOM_SHOW_CREATE_FUNC || + lex->sql_command == SQLCOM_SHOW_STATUS_PROC || + lex->sql_command == SQLCOM_SHOW_STATUS_FUNC) { /* We maybe have one or more SELECT without INTO */ lex->sphead->m_multi_results= TRUE; @@ -4907,7 +4909,7 @@ ident_eq_list: ident_eq_value; ident_eq_value: - simple_ident equal expr_or_default + simple_ident_nospvar equal expr_or_default { LEX *lex=Lex; if (lex->field_list.push_back($1) || @@ -4994,12 +4996,12 @@ update: ; update_list: - update_list ',' simple_ident equal expr_or_default + update_list ',' simple_ident_nospvar equal expr_or_default { if (add_item_to_list(YYTHD, $3) || add_value_to_list(YYTHD, $5)) YYABORT; } - | simple_ident equal expr_or_default + | simple_ident_nospvar equal expr_or_default { if (add_item_to_list(YYTHD, $1) || add_value_to_list(YYTHD, $3)) YYABORT; @@ -5633,7 +5635,7 @@ NUM_literal: **********************************************************************/ insert_ident: - simple_ident { $$=$1; } + simple_ident_nospvar { $$=$1; } | table_wild { $$=$1; }; table_wild: @@ -5680,7 +5682,23 @@ simple_ident: (Item*) new Item_ref(NullS,NullS,$1.str); } } - | ident '.' ident + | simple_ident_q { $$= $1; } + ; + +simple_ident_nospvar: + ident + { + SELECT_LEX *sel=Select; + $$= (sel->parsing_place != SELECT_LEX_NODE::IN_HAVING || + sel->get_in_sum_expr() > 0) ? + (Item*) new Item_field(NullS,NullS,$1.str) : + (Item*) new Item_ref(NullS,NullS,$1.str); + } + | simple_ident_q { $$= $1; } + ; + +simple_ident_q: + ident '.' ident { THD *thd= YYTHD; LEX *lex= thd->lex;