diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result index 58905a74507..adfecc151b7 100644 --- a/mysql-test/r/sp-error.result +++ b/mysql-test/r/sp-error.result @@ -187,7 +187,7 @@ end; call p(); ERROR HY000: Cursor is not open drop procedure p; -alter procedure bar3 SECURITY INVOKER; +alter procedure bar3 sql security invoker; ERROR HY000: PROCEDURE bar3 does not exist alter procedure bar3 name AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA; diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result index 990a8b7c2da..56f6bc59087 100644 --- a/mysql-test/r/sp.result +++ b/mysql-test/r/sp.result @@ -75,6 +75,23 @@ id data locset 21 delete from t1; drop procedure locset; +drop table if exists t3; +create table t3 ( d date, i int, f double, s varchar(32) ); +create procedure nullset() +begin +declare ld date; +declare li int; +declare lf double; +declare ls varchar(32); +set ld = null, li = null, lf = null, ls = null; +insert into t3 values (ld, li, lf, ls); +end; +call nullset(); +select * from t3; +d i f s +NULL NULL NULL NULL +drop table t3; +drop procedure nullset; create procedure mixset(x char(16), y int) begin declare z int; @@ -390,6 +407,47 @@ into 100 100 into2 102 100 delete from t1; drop procedure into_test2; +create procedure into_test3() +begin +declare x char(16); +declare y int; +select * into x,y from test.t1 limit 1; +insert into test.t2 values (x, y, 0.0); +end; +insert into t1 values ("into3", 19); +delete from t2; +call into_test3(); +call into_test3(); +select * from t2; +s i d +into3 19 0 +into3 19 0 +delete from t1; +delete from t2; +drop procedure into_test3; +create procedure into_test4() +begin +declare x int; +select data into x from test.t1 limit 1; +insert into test.t3 values ("into4", x); +end; +delete from t1; +drop table if exists t3; +create table t3 ( s char(16), d int); +call into_test4(); +Warnings: +select * from t3; +s d +into4 NULL +insert into t1 values ("i4", 77); +call into_test4(); +select * from t3; +s d +into4 NULL +into4 77 +delete from t1; +drop table t3; +drop procedure into_test4; create procedure into_outfile(x char(16), y int) begin insert into test.t1 values (x, y); @@ -475,9 +533,6 @@ s i d xxxyyy 12 2.71828182845905 select * from t2; s i d -a 1 1.1 -b 2 1.2 -c 3 1.3 xxxyyy 12 2.71828182845905 ab 24 1324.36598821719 delete from t2; @@ -551,7 +606,7 @@ create procedure hndlr4() begin declare x int default 0; declare val int; # No default -declare continue handler for sqlexception set x=1; +declare continue handler for 1306 set x=1; select data into val from test.t3 where id='z' limit 1; # No hits insert into test.t3 values ('z', val); end; @@ -695,6 +750,21 @@ select @1, @2; 2 NULL drop table t70; drop procedure bug1656; +drop table if exists t3; +create table t3(a int); +create procedure bug1862() +begin +insert into t3 values(2); +flush tables; +end; +call bug1862(); +call bug1862(); +select * from t3; +a +2 +2 +drop table t3; +drop procedure bug1862; drop table if exists fac; create table fac (n int unsigned not null primary key, f bigint unsigned); create procedure ifac(n int unsigned) @@ -839,21 +909,22 @@ drop table primes; drop procedure opp; drop procedure ip; create procedure bar(x char(16), y int) -comment "111111111111" SECURITY INVOKER +comment "111111111111" sql security invoker insert into test.t1 values (x, y); show procedure status like 'bar'; Name Type Creator Modified Created Suid Comment bar procedure root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 N 111111111111 -alter procedure bar name bar2 comment "2222222222" SECURITY DEFINER; +alter procedure bar name bar2 comment "2222222222" sql security definer; alter procedure bar2 name bar comment "3333333333"; alter procedure bar; show create procedure bar; Procedure Create Procedure bar create procedure bar(x char(16), y int) -comment "111111111111" SECURITY INVOKER +comment "111111111111" sql security invoker insert into test.t1 values (x, y) show procedure status like 'bar'; Name Type Creator Modified Created Suid Comment bar procedure root@localhost 0000-00-00 00:00:00 0000-00-00 00:00:00 Y 3333333333 +drop procedure bar; drop table t1; drop table t2; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 38f5a34a7bb..87f765cb7c8 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -257,7 +257,7 @@ call p()| drop procedure p| --error 1282 -alter procedure bar3 SECURITY INVOKER| +alter procedure bar3 sql security invoker| --error 1059 alter procedure bar3 name AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA| diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 5b2c9bf18f5..091a3e364ce 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -109,6 +109,29 @@ delete from t1| drop procedure locset| +# Set things to null +--disable_warnings +drop table if exists t3| +--enable_warnings +create table t3 ( d date, i int, f double, s varchar(32) )| + +create procedure nullset() +begin + declare ld date; + declare li int; + declare lf double; + declare ls varchar(32); + + set ld = null, li = null, lf = null, ls = null; + insert into t3 values (ld, li, lf, ls); +end| + +call nullset()| +select * from t3| +drop table t3| +drop procedure nullset| + + # The peculiar (non-standard) mixture of variables types in SET. create procedure mixset(x char(16), y int) begin @@ -460,6 +483,52 @@ delete from t1| drop procedure into_test2| +# SELECT * INTO ... (bug test) +create procedure into_test3() +begin + declare x char(16); + declare y int; + + select * into x,y from test.t1 limit 1; + insert into test.t2 values (x, y, 0.0); +end| + +insert into t1 values ("into3", 19)| +delete from t2| +# Two call needed for bug test +call into_test3()| +call into_test3()| +select * from t2| +delete from t1| +delete from t2| +drop procedure into_test3| + + +# SELECT INTO with no data is a warning ("no data", which we will +# not see normally). When not caught, execution proceeds. +create procedure into_test4() +begin + declare x int; + + select data into x from test.t1 limit 1; + insert into test.t3 values ("into4", x); +end| + +delete from t1| +--disable_warnings +drop table if exists t3| +--enable_warnings +create table t3 ( s char(16), d int)| +call into_test4()| +select * from t3| +insert into t1 values ("i4", 77)| +call into_test4()| +select * from t3| +delete from t1| +drop table t3| +drop procedure into_test4| + + # These two (and the two procedures above) caused an assert() to fail in # sql_base.cc:lock_tables() at some point. @@ -658,7 +727,7 @@ create procedure hndlr4() begin declare x int default 0; declare val int; # No default - declare continue handler for sqlexception set x=1; + declare continue handler for 1306 set x=1; select data into val from test.t3 where id='z' limit 1; # No hits @@ -823,6 +892,28 @@ drop table t70| drop procedure bug1656| +# +# BUG#1862 +# +--disable_warnings +drop table if exists t3| +--enable_warnings +create table t3(a int)| + +create procedure bug1862() +begin + insert into t3 values(2); + flush tables; +end| + +call bug1862()| +# the second call caused a segmentation +call bug1862()| +select * from t3| +drop table t3| +drop procedure bug1862| + + # # Some "real" examples # @@ -946,16 +1037,17 @@ drop procedure ip| # Comment & suid create procedure bar(x char(16), y int) - comment "111111111111" SECURITY INVOKER + comment "111111111111" sql security invoker insert into test.t1 values (x, y)| --replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' show procedure status like 'bar'| -alter procedure bar name bar2 comment "2222222222" SECURITY DEFINER| +alter procedure bar name bar2 comment "2222222222" sql security definer| alter procedure bar2 name bar comment "3333333333"| alter procedure bar| show create procedure bar| --replace_column 4 '0000-00-00 00:00:00' 5 '0000-00-00 00:00:00' show procedure status like 'bar'| +drop procedure bar| delimiter ;| drop table t1; diff --git a/sql/lex.h b/sql/lex.h index b267cdda66a..b136fc63813 100644 --- a/sql/lex.h +++ b/sql/lex.h @@ -130,7 +130,7 @@ static SYMBOL symbols[] = { { "DECLARE", SYM(DECLARE_SYM),0,0}, { "DES_KEY_FILE", SYM(DES_KEY_FILE),0,0}, { "DEFAULT", SYM(DEFAULT),0,0}, - { "DEFINER", SYM(DEFINER),0,0}, + { "DEFINER", SYM(DEFINER_SYM),0,0}, { "DELAYED", SYM(DELAYED_SYM),0,0}, { "DELAY_KEY_WRITE", SYM(DELAY_KEY_WRITE_SYM),0,0}, { "DELETE", SYM(DELETE_SYM),0,0}, @@ -233,7 +233,7 @@ static SYMBOL symbols[] = { { "ISOLATION", SYM(ISOLATION),0,0}, { "ISSUER", SYM(ISSUER_SYM),0,0}, { "ITERATE", SYM(ITERATE_SYM),0,0}, - { "INVOKER", SYM(INVOKER),0,0}, + { "INVOKER", SYM(INVOKER_SYM),0,0}, { "JOIN", SYM(JOIN_SYM),0,0}, { "KEY", SYM(KEY_SYM),0,0}, { "KEYS", SYM(KEYS),0,0}, @@ -370,7 +370,7 @@ static SYMBOL symbols[] = { { "SAVEPOINT", SYM(SAVEPOINT_SYM),0,0}, { "SECOND", SYM(SECOND_SYM),0,0}, { "SECOND_MICROSECOND", SYM(SECOND_MICROSECOND_SYM),0,0}, - { "SECURITY", SYM(SECURITY),0,0}, + { "SECURITY", SYM(SECURITY_SYM),0,0}, { "SEPARATOR", SYM(SEPARATOR_SYM),0,0}, { "SELECT", SYM(SELECT_SYM),0,0}, { "SENSITIVE", SYM(SENSITIVE_SYM),0,0}, @@ -389,6 +389,7 @@ static SYMBOL symbols[] = { { "SONAME", SYM(UDF_SONAME_SYM),0,0}, { "SPATIAL", SYM(SPATIAL_SYM),0,0}, { "SPECIFIC", SYM(SPECIFIC_SYM),0,0}, + { "SQL", SYM(SQL_SYM),0,0}, { "SQLEXCEPTION", SYM(SQLEXCEPTION_SYM),0,0}, { "SQLSTATE", SYM(SQLSTATE_SYM),0,0}, { "SQLWARNING", SYM(SQLWARNING_SYM),0,0}, diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 1cdc9ac740d..106f4c58fa6 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -234,7 +234,9 @@ sp_head::execute(THD *thd) DBUG_PRINT("execute", ("Instruction %u", ip)); ret= i->execute(thd, &ip); // Check if an exception has occurred and a handler has been found - if (ret && !thd->killed && ctx) + // Note: We havo to check even if ret==0, since warnings (and some + // errors don't return a non-zero value. + if (!thd->killed && ctx) { uint hf; @@ -509,12 +511,20 @@ sp_head::restore_lex(THD *thd) // Update some state in the old one first oldlex->ptr= sublex->ptr; oldlex->next_state= sublex->next_state; - // Save WHERE clause pointers to avoid damaging by optimisation for (SELECT_LEX *sl= sublex->all_selects_list ; sl ; sl= sl->next_select_in_list()) { + // Save WHERE clause pointers to avoid damaging by optimisation sl->prep_where= sl->where; + if (sl->with_wild) + { + // Copy item_list. We will restore it before calling the + // sub-statement, so it's ok to pop them. + sl->item_list_copy.empty(); + while (Item *it= sl->item_list.pop()) + sl->item_list_copy.push_back(it); + } } // Collect some data from the sub statement lex. @@ -687,14 +697,22 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex) sl ; sl= sl->next_select_in_list()) { + if (lex->sql_command == SQLCOM_CREATE_TABLE || + lex->sql_command == SQLCOM_INSERT_SELECT) + { // Destroys sl->table_list.first + sl->table_list_first_copy= sl->table_list.first; + } if (sl->with_wild) { - List_iterator_fast li(sl->item_list); + // Restore item_list + // Note: We have to do this before executing the sub-statement, + // to make sure that the list nodes are in the right + // memroot. + List_iterator_fast li(sl->item_list_copy); - // Copy item_list - sl->item_list_copy.empty(); + sl->item_list.empty(); while (Item *it= li++) - sl->item_list_copy.push_back(it); + sl->item_list.push_back(it); } sl->ref_pointer_array= 0; if (sl->prep_where) @@ -725,12 +743,19 @@ sp_instr_stmt::exec_stmt(THD *thd, LEX *lex) sl ; sl= sl->next_select_in_list()) { - if (sl->with_wild) + TABLE_LIST *tabs; + + // We have closed all tables, get rid of pointers to them + for (tabs=(TABLE_LIST *)sl->table_list.first ; + tabs ; + tabs= tabs->next) { - // Restore item_list - sl->item_list.empty(); - while (Item *it= sl->item_list_copy.pop()) - sl->item_list.push_back(it); + tabs->table= NULL; + } + if (lex->sql_command == SQLCOM_CREATE_TABLE || + lex->sql_command == SQLCOM_INSERT_SELECT) + { // Restore sl->table_list.first + sl->table_list.first= sl->table_list_first_copy; } for (ORDER *order= (ORDER *)sl->order_list.first ; order ; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index f3e57a0abbf..39e0df57ce6 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -1253,14 +1253,8 @@ bool select_dumpvar::send_data(List &items) bool select_dumpvar::send_eof() { - if (row_count) - { - ::send_ok(thd,row_count); - return 0; - } - else - { - my_error(ER_EMPTY_QUERY,MYF(0)); - return 1; - } + if (! row_count) + send_warning(thd, ER_SP_FETCH_NO_DATA); + ::send_ok(thd,row_count); + return 0; } diff --git a/sql/sql_lex.h b/sql/sql_lex.h index e9cd64450fc..e33784c88b0 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -362,6 +362,7 @@ public: SQL_LIST table_list, group_list; /* FROM & GROUP BY clauses */ List item_list; /* list of fields & expressions */ List item_list_copy; /* For SPs */ + byte *table_list_first_copy; /* For SPs */ List interval_list, use_index, *use_index_ptr, ignore_index, *ignore_index_ptr; /* diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 2e76989c558..f93c9e53275 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -137,7 +137,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token CREATE %token CROSS %token CUBE_SYM -%token DEFINER +%token DEFINER_SYM %token DELETE_SYM %token DUAL_SYM %token DO_SYM @@ -167,6 +167,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token SELECT_SYM %token SHOW %token SLAVE +%token SQL_SYM %token SQL_THREAD %token START_SYM %token STD_SYM @@ -270,7 +271,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token INOUT_SYM %token INTO %token IN_SYM -%token INVOKER +%token INVOKER_SYM %token ISOLATION %token JOIN_SYM %token KEYS @@ -364,7 +365,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b,int *yystacksize); %token ROW_FORMAT_SYM %token ROW_SYM %token RTREE_SYM -%token SECURITY +%token SECURITY_SYM %token SET %token SEPARATOR_SYM %token SERIAL_SYM @@ -1120,20 +1121,20 @@ create_function_tail: ; sp_comment: - /* Empty */ { $$.str=0; } + /* Empty */ { $$.str= 0; $$.length= 0; } | COMMENT_SYM TEXT_STRING_sys { $$= $2; } ; sp_newname: - /* Empty */ { $$.str=0; } + /* Empty */ { $$.str= 0; $$.length= 0; } | NAME_SYM ident { $$= $2; } ; sp_suid: - /* Empty */ { Lex->suid= IS_DEFAULT_SUID; } - | SECURITY DEFINER { Lex->suid= IS_SUID; } - | SECURITY INVOKER { Lex->suid= IS_NOT_SUID; } + /* Empty */ { Lex->suid= IS_DEFAULT_SUID; } + | SQL_SYM SECURITY_SYM DEFINER_SYM { Lex->suid= IS_SUID; } + | SQL_SYM SECURITY_SYM INVOKER_SYM { Lex->suid= IS_NOT_SUID; } ; call: @@ -2603,30 +2604,35 @@ alter: lex->name=$3.str; } | ALTER PROCEDURE ident sp_newname sp_comment sp_suid - /* QQ Characteristics missing for now */ opt_restrict { + THD *thd= YYTHD; LEX *lex=Lex; - /* This is essensially an no-op right now, since we haven't - put the characteristics in yet. */ lex->sql_command= SQLCOM_ALTER_PROCEDURE; lex->udf.name= $3; lex->name= $4.str; - lex->comment= &$5; + /* $5 is a yacc/bison internal struct, so we can't keep + the pointer to it for use outside the parser. */ + lex->comment= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING)); + lex->comment->str= $5.str; + lex->comment->length= $5.length; } | ALTER FUNCTION_SYM ident sp_newname sp_comment sp_suid - /* QQ Characteristics missing for now */ opt_restrict { + THD *thd= YYTHD; LEX *lex=Lex; - /* This is essensially an no-op right now, since we haven't - put the characteristics in yet. */ lex->sql_command= SQLCOM_ALTER_FUNCTION; lex->udf.name= $3; lex->name= $4.str; - lex->comment= &$5; + /* $5 is a yacc/bison internal struct, so we can't keep + the pointer to it for use outside the parser. */ + lex->comment= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING)); + lex->comment= (LEX_STRING *)thd->alloc(sizeof(LEX_STRING)); + lex->comment->str= $5.str; + lex->comment->length= $5.length; } ; @@ -5612,7 +5618,7 @@ keyword: | DATETIME {} | DATE_SYM {} | DAY_SYM {} - | DEFINER {} + | DEFINER_SYM {} | DELAY_KEY_WRITE_SYM {} | DES_KEY_FILE {} | DIRECTORY_SYM {} @@ -5648,7 +5654,7 @@ keyword: | HOSTS_SYM {} | HOUR_SYM {} | IDENTIFIED_SYM {} - | INVOKER {} + | INVOKER_SYM {} | IMPORT {} | INDEXES {} | ISOLATION {} @@ -5735,7 +5741,7 @@ keyword: | RTREE_SYM {} | SAVEPOINT_SYM {} | SECOND_SYM {} - | SECURITY {} + | SECURITY_SYM {} | SERIAL_SYM {} | SERIALIZABLE_SYM {} | SESSION_SYM {}