diff options
34 files changed, 831 insertions, 377 deletions
diff --git a/mysql-test/r/rpl_trigger.result b/mysql-test/r/rpl_trigger.result new file mode 100644 index 00000000000..db824c9c423 --- /dev/null +++ b/mysql-test/r/rpl_trigger.result @@ -0,0 +1,108 @@ +stop slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +reset master; +reset slave; +drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9; +start slave; +create table t1 (a int auto_increment, primary key (a), b int, rand_value double not null); +create table t2 (a int auto_increment, primary key (a), b int); +create table t3 (a int auto_increment, primary key (a), name varchar(64) not null, old_a int, old_b int, rand_value double not null); +create trigger t1 before insert on t1 for each row +begin +insert into t3 values (NULL, "t1", new.a, new.b, rand()); +end| +create trigger t2 after insert on t2 for each row +begin +insert into t3 values (NULL, "t2", new.a, new.b, rand()); +end| +insert into t3 values(100,"log",0,0,0); +SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186; +insert into t1 values(1,1,rand()),(NULL,2,rand()); +insert into t2 (b) values(last_insert_id()); +insert into t2 values(3,0),(NULL,0); +insert into t2 values(NULL,0),(500,0); +select a,b, truncate(rand_value,4) from t1; +a b truncate(rand_value,4) +1 1 0.4320 +2 2 0.3055 +select * from t2; +a b +1 2 +3 0 +4 0 +5 0 +500 0 +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +a name old_a old_b truncate(rand_value,4) +100 log 0 0 0.0000 +101 t1 1 1 0.3203 +102 t1 0 2 0.5666 +103 t2 1 2 0.9164 +104 t2 3 0 0.8826 +105 t2 4 0 0.6635 +106 t2 5 0 0.6699 +107 t2 500 0 0.3593 + +--- On slave -- +select a,b, truncate(rand_value,4) from t1; +a b truncate(rand_value,4) +1 1 0.4320 +2 2 0.3055 +select * from t2; +a b +1 2 +3 0 +4 0 +5 0 +500 0 +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +a name old_a old_b truncate(rand_value,4) +100 log 0 0 0.0000 +101 t1 1 1 0.3203 +102 t1 0 2 0.5666 +103 t2 1 2 0.9164 +104 t2 3 0 0.8826 +105 t2 4 0 0.6635 +106 t2 5 0 0.6699 +107 t2 500 0 0.3593 +drop table t1,t2,t3; +select get_lock("bug12480",2); +get_lock("bug12480",2) +1 +create table t1 (a datetime,b datetime, c datetime); +drop function if exists bug12480; +Warnings: +Note 1305 FUNCTION bug12480 does not exist +create function bug12480() returns datetime +begin +set @a=get_lock("bug12480",2); +return now(); +end| +create trigger t1_first before insert on t1 +for each row begin +set @a=get_lock("bug12480",2); +set new.b= now(); +set new.c= bug12480(); +end +| +insert into t1 set a = now(); +select a=b && a=c from t1; +a=b && a=c +1 + +--- On slave -- +select a=b && a=c from t1; +a=b && a=c +1 +test +1 +truncate table t1; +drop trigger t1_first; +insert into t1 values ("2003-03-03","2003-03-03","2003-03-03"),(bug12480(),bug12480(),bug12480()),(now(),now(),now()); +select a=b && a=c from t1; +a=b && a=c +1 +1 +1 +drop function bug12480; +drop table t1; diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result index ee0a6f6b744..6a5063f54c9 100644 --- a/mysql-test/r/trigger.result +++ b/mysql-test/r/trigger.result @@ -664,3 +664,36 @@ end| update t1 set data = 1; update t1 set data = 2; drop table t1; +create table t1 (c1 int, c2 datetime); +create trigger tr1 before insert on t1 for each row +begin +set new.c2= '2004-04-01'; +select 'hello'; +end| +ERROR 0A000: Not allowed to return a result set from a trigger +insert into t1 (c1) values (1),(2),(3); +select * from t1; +c1 c2 +1 NULL +2 NULL +3 NULL +drop procedure if exists bug11587; +create procedure bug11587(x char(16)) +begin +select "hello"; +select "hello again"; +end| +create trigger tr1 before insert on t1 for each row +begin +call bug11587(); +set new.c2= '2004-04-02'; +end| +insert into t1 (c1) values (4),(5),(6); +ERROR 0A000: PROCEDURE test.bug11587 can't return a result set in the given context +select * from t1; +c1 c2 +1 NULL +2 NULL +3 NULL +drop procedure bug11587; +drop table t1; diff --git a/mysql-test/t/rpl_trigger.test b/mysql-test/t/rpl_trigger.test new file mode 100644 index 00000000000..715222f0314 --- /dev/null +++ b/mysql-test/t/rpl_trigger.test @@ -0,0 +1,118 @@ +# +# Test of triggers with replication +# + +source include/master-slave.inc; + +# +# #12482: Triggers has side effects with auto_increment values +# + +create table t1 (a int auto_increment, primary key (a), b int, rand_value double not null); +create table t2 (a int auto_increment, primary key (a), b int); +create table t3 (a int auto_increment, primary key (a), name varchar(64) not null, old_a int, old_b int, rand_value double not null); + +delimiter |; +create trigger t1 before insert on t1 for each row +begin + insert into t3 values (NULL, "t1", new.a, new.b, rand()); +end| + +create trigger t2 after insert on t2 for each row +begin + insert into t3 values (NULL, "t2", new.a, new.b, rand()); +end| +delimiter ;| + +insert into t3 values(100,"log",0,0,0); + +# Ensure we always have same random numbers +SET @@RAND_SEED1=658490765, @@RAND_SEED2=635893186; + +# Emulate that we have rows 2-9 deleted on the slave +insert into t1 values(1,1,rand()),(NULL,2,rand()); +insert into t2 (b) values(last_insert_id()); +insert into t2 values(3,0),(NULL,0); +insert into t2 values(NULL,0),(500,0); + +select a,b, truncate(rand_value,4) from t1; +select * from t2; +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +save_master_pos; +connection slave; +sync_with_master; +--disable_query_log +select "--- On slave --" as ""; +--enable_query_log +select a,b, truncate(rand_value,4) from t1; +select * from t2; +select a,name, old_a, old_b, truncate(rand_value,4) from t3; +connection master; +drop table t1,t2,t3; + +# +# #12480: NOW() is not constant in a trigger +# #12481: Using NOW() in a stored function breaks statement based replication +# + +# Start by getting a lock on 'bug12480' to be able to use get_lock() as sleep() +connect (con2,localhost,root,,); +connection con2; +select get_lock("bug12480",2); +connection default; + +create table t1 (a datetime,b datetime, c datetime); +--ignore_warnings +drop function if exists bug12480; +--enable_warnings + +delimiter |; + +create function bug12480() returns datetime +begin + set @a=get_lock("bug12480",2); + return now(); +end| + +create trigger t1_first before insert on t1 +for each row begin + set @a=get_lock("bug12480",2); + set new.b= now(); + set new.c= bug12480(); +end +| + +delimiter ;| +insert into t1 set a = now(); +select a=b && a=c from t1; +let $time=`select a from t1`; + +save_master_pos; +connection slave; +sync_with_master; +--disable_query_log +select "--- On slave --" as ""; +--enable_query_log +select a=b && a=c from t1; +--disable_query_log +eval select a='$time' as 'test' from t1; +--enable_query_log + +connection master; +disconnect con2; + +truncate table t1; +drop trigger t1_first; + +insert into t1 values ("2003-03-03","2003-03-03","2003-03-03"),(bug12480(),bug12480(),bug12480()),(now(),now(),now()); +select a=b && a=c from t1; + +drop function bug12480; +drop table t1; + +# +# End of test +# +save_master_pos; +connection slave; +sync_with_master; diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test index 349bd148814..85b81f72f40 100644 --- a/mysql-test/t/sp-error.test +++ b/mysql-test/t/sp-error.test @@ -811,19 +811,19 @@ end| # # Some things are caught when parsing ---error ER_SP_NO_RETSET_IN_FUNC +--error ER_SP_NO_RETSET create function bug8408() returns int begin select * from t1; return 0; end| ---error ER_SP_NO_RETSET_IN_FUNC +--error ER_SP_NO_RETSET create function bug8408() returns int begin show warnings; return 0; end| ---error ER_SP_NO_RETSET_IN_FUNC +--error ER_SP_NO_RETSET create function bug8408(a int) returns int begin declare b int; diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test index 017e1654c95..f4f527fd222 100644 --- a/mysql-test/t/sp.test +++ b/mysql-test/t/sp.test @@ -2468,25 +2468,26 @@ drop table t3| # # BUG#4318 # -#QQ Don't know if HANDLER commands can work with SPs, or at all... -# -#create table t3 (s1 int)| -#insert into t3 values (3), (4)| -# -#--disable_warnings -#drop procedure if exists bug4318| -#--enable_warnings -#create procedure bug4318() -# handler t3 read next| -# -#handler t3 open| -## Expect no results, as tables are closed, but there shouldn't be any errors -#call bug4318()| -#call bug4318()| -#handler t3 close| -# -#drop procedure bug4318| -#drop table t3| + +--disable_parsing Don't know if HANDLER commands can work with SPs, or at all.. +create table t3 (s1 int)| +insert into t3 values (3), (4)| + +--disable_warnings +drop procedure if exists bug4318| +--enable_warnings +create procedure bug4318() + handler t3 read next| + +handler t3 open| +# Expect no results, as tables are closed, but there shouldn't be any errors +call bug4318()| +call bug4318()| +handler t3 close| + +drop procedure bug4318| +drop table t3| +--enable_parsing # # BUG#4902: Stored procedure with SHOW WARNINGS leads to packet error @@ -2834,26 +2835,27 @@ drop table t3| # # BUG#6022: Stored procedure shutdown problem with self-calling function. # -# This part of test is disabled until we implement support for -# recursive stored functions. -#--disable_warnings -#drop function if exists bug6022| -#--enable_warnings -# -#--disable_warnings -#drop function if exists bug6022| -#--enable_warnings -#create function bug6022(x int) returns int -#begin -# if x < 0 then -# return 0; -# else -# return bug6022(x-1); -# end if; -#end| -# -#select bug6022(5)| -#drop function bug6022| + +--disable_parsing until we implement support for recursive stored functions. +--disable_warnings +drop function if exists bug6022| +--enable_warnings + +--disable_warnings +drop function if exists bug6022| +--enable_warnings +create function bug6022(x int) returns int +begin + if x < 0 then + return 0; + else + return bug6022(x-1); + end if; +end| + +select bug6022(5)| +drop function bug6022| +--enable_parsing # # BUG#6029: Stored procedure specific handlers should have priority @@ -3760,27 +3762,28 @@ drop procedure if exists bug7088_1| drop procedure if exists bug7088_2| --enable_warnings -# psergey: temporarily disabled until Bar fixes BUG#11986 -# create procedure bug6063() -# lâbel: begin end| -# call bug6063()| -# # QQ Known bug: this will not show the label correctly. -# show create procedure bug6063| -# -# set character set utf8| -# create procedure bug7088_1() -# label1: begin end label1| -# create procedure bug7088_2() -# läbel1: begin end| -# call bug7088_1()| -# call bug7088_2()| -# set character set default| -# show create procedure bug7088_1| -# show create procedure bug7088_2| -# -# drop procedure bug6063| -# drop procedure bug7088_1| -# drop procedure bug7088_2| +--disable_parsing temporarily disabled until Bar fixes BUG#11986 +create procedure bug6063() + lâbel: begin end| +call bug6063()| +# QQ Known bug: this will not show the label correctly. +show create procedure bug6063| + +set character set utf8| +create procedure bug7088_1() + label1: begin end label1| +create procedure bug7088_2() + läbel1: begin end| +call bug7088_1()| +call bug7088_2()| +set character set default| +show create procedure bug7088_1| +show create procedure bug7088_2| + +drop procedure bug6063| +drop procedure bug7088_1| +drop procedure bug7088_2| +--enable_parsing # # BUG#9565: "Wrong locking in stored procedure if a sub-sequent procedure diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test index 49ec42568ad..cbc9da2bf51 100644 --- a/mysql-test/t/trigger.test +++ b/mysql-test/t/trigger.test @@ -665,6 +665,7 @@ drop table t1; # Test for bug #11973 "SELECT .. INTO var_name; in trigger cause # crash on update" + create table t1 (id int, data int, username varchar(16)); insert into t1 (id, data) values (1, 0); delimiter |; @@ -684,4 +685,47 @@ connection addconroot; update t1 set data = 2; connection default; +disconnect addconroot; +drop table t1; + +# +# #11587 Trigger causes lost connection error +# + +create table t1 (c1 int, c2 datetime); +delimiter |; +--error ER_SP_NO_RETSET +create trigger tr1 before insert on t1 for each row +begin + set new.c2= '2004-04-01'; + select 'hello'; +end| +delimiter ;| + +insert into t1 (c1) values (1),(2),(3); +select * from t1; + +--disable_warnings +drop procedure if exists bug11587; +--enable_warnings + +delimiter |; +create procedure bug11587(x char(16)) +begin + select "hello"; + select "hello again"; +end| + +create trigger tr1 before insert on t1 for each row +begin + call bug11587(); + set new.c2= '2004-04-02'; +end| +delimiter ;| + +--error 1312 +insert into t1 (c1) values (4),(5),(6); +select * from t1; + +drop procedure bug11587; drop table t1; diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc index 4a7585d800e..b8a779c08cf 100644 --- a/sql/ha_berkeley.cc +++ b/sql/ha_berkeley.cc @@ -958,8 +958,6 @@ int ha_berkeley::write_row(byte * record) { DB_TXN *sub_trans = transaction; /* Don't use sub transactions in temporary tables */ - ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ? - table->in_use->options : 0); for (uint retry=0 ; retry < berkeley_trans_retry ; retry++) { key_map changed_keys(0); @@ -1070,7 +1068,7 @@ int ha_berkeley::key_cmp(uint keynr, const byte * old_row, int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed, const byte * old_row, DBT *old_key, const byte * new_row, DBT *new_key, - ulong thd_options, bool local_using_ignore) + bool local_using_ignore) { DBT row; int error; @@ -1119,8 +1117,7 @@ int ha_berkeley::update_primary_key(DB_TXN *trans, bool primary_key_changed, int ha_berkeley::restore_keys(DB_TXN *trans, key_map *changed_keys, uint primary_key, const byte *old_row, DBT *old_key, - const byte *new_row, DBT *new_key, - ulong thd_options) + const byte *new_row, DBT *new_key) { int error; DBT tmp_key; @@ -1130,7 +1127,7 @@ int ha_berkeley::restore_keys(DB_TXN *trans, key_map *changed_keys, /* Restore the old primary key, and the old row, but don't ignore duplicate key failure */ if ((error=update_primary_key(trans, TRUE, new_row, new_key, - old_row, old_key, thd_options, FALSE))) + old_row, old_key, FALSE))) goto err; /* purecov: inspected */ /* Remove the new key, and put back the old key @@ -1167,8 +1164,6 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) DBT prim_key, key, old_prim_key; int error; DB_TXN *sub_trans; - ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ? - table->in_use->options : 0); bool primary_key_changed; DBUG_ENTER("update_row"); LINT_INIT(error); @@ -1204,7 +1199,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) if (!(error=update_primary_key(sub_trans, primary_key_changed, old_row, &old_prim_key, new_row, &prim_key, - thd_options, using_ignore))) + using_ignore))) { // Update all other keys for (uint keynr=0 ; keynr < table->s->keys ; keynr++) @@ -1239,8 +1234,7 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row) int new_error = 0; if (!changed_keys.is_clear_all()) new_error=restore_keys(transaction, &changed_keys, primary_key, - old_row, &old_prim_key, new_row, &prim_key, - thd_options); + old_row, &old_prim_key, new_row, &prim_key); if (new_error) { /* This shouldn't happen */ @@ -1342,8 +1336,6 @@ int ha_berkeley::delete_row(const byte * record) int error; DBT row, prim_key; key_map keys= table->s->keys_in_use; - ulong thd_options= (table->s->tmp_table == NO_TMP_TABLE ? - table->in_use->options : 0); DBUG_ENTER("delete_row"); statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status); diff --git a/sql/ha_berkeley.h b/sql/ha_berkeley.h index aa92908ecde..282641e3f25 100644 --- a/sql/ha_berkeley.h +++ b/sql/ha_berkeley.h @@ -74,13 +74,12 @@ class ha_berkeley: public handler DBT *prim_key, key_map *keys); int restore_keys(DB_TXN *trans, key_map *changed_keys, uint primary_key, const byte *old_row, DBT *old_key, - const byte *new_row, DBT *new_key, - ulong thd_options); + const byte *new_row, DBT *new_key); int key_cmp(uint keynr, const byte * old_row, const byte * new_row); int update_primary_key(DB_TXN *trans, bool primary_key_changed, const byte * old_row, DBT *old_key, const byte * new_row, DBT *prim_key, - ulong thd_options, bool local_using_ignore); + bool local_using_ignore); int read_row(int error, char *buf, uint keynr, DBT *row, DBT *key, bool); DBT *get_pos(DBT *to, byte *pos); diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc index 7637b08c8ca..96d380d5ebb 100644 --- a/sql/ha_ndbcluster.cc +++ b/sql/ha_ndbcluster.cc @@ -6997,6 +6997,8 @@ ha_ndbcluster::build_scan_filter_predicate(Ndb_cond * &cond, break; Ndb_item *a= cond->next->ndb_item; Ndb_item *b, *field, *value= NULL; + LINT_INIT(field); + switch (cond->ndb_item->argument_count()) { case 1: field= diff --git a/sql/init.cc b/sql/init.cc index 4beb8db0c6f..e53eeab8902 100644 --- a/sql/init.cc +++ b/sql/init.cc @@ -39,12 +39,11 @@ void unireg_init(ulong options) #endif VOID(strmov(reg_ext,".frm")); - specialflag=SPECIAL_SAME_DB_NAME; + specialflag=SPECIAL_SAME_DB_NAME | options; /* Set options from argv */ /* Make a tab of powers of 10 */ for (i=0,nr=1.0; i < array_elements(log_10) ; i++) { /* It's used by filesort... */ log_10[i]= nr ; nr*= 10.0; } - specialflag|=options; /* Set options from argv */ DBUG_VOID_RETURN; } diff --git a/sql/item_func.cc b/sql/item_func.cc index ef1c85f6120..61467595424 100644 --- a/sql/item_func.cc +++ b/sql/item_func.cc @@ -1873,6 +1873,9 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref) Allocate rand structure once: we must use thd->current_arena to create rand in proper mem_root if it's a prepared statement or stored procedure. + + No need to send a Rand log event if seed was given eg: RAND(seed), + as it will be replicated in the query as such. */ if (!rand && !(rand= (struct rand_struct*) thd->current_arena->alloc(sizeof(*rand)))) @@ -1895,16 +1898,16 @@ bool Item_func_rand::fix_fields(THD *thd,Item **ref) else { /* - No need to send a Rand log event if seed was given eg: RAND(seed), - as it will be replicated in the query as such. - Save the seed only the first time RAND() is used in the query Once events are forwarded rather than recreated, the following can be skipped if inside the slave thread */ - thd->rand_used=1; - thd->rand_saved_seed1=thd->rand.seed1; - thd->rand_saved_seed2=thd->rand.seed2; + if (!thd->rand_used) + { + thd->rand_used= 1; + thd->rand_saved_seed1= thd->rand.seed1; + thd->rand_saved_seed2= thd->rand.seed2; + } rand= &thd->rand; } return FALSE; @@ -4665,10 +4668,9 @@ Item_func_sp::execute(Item **itp) { DBUG_ENTER("Item_func_sp::execute"); THD *thd= current_thd; - ulong old_client_capabilites; int res= -1; - bool save_in_sub_stmt= thd->in_sub_stmt; - my_bool save_no_send_ok; + Sub_statement_state statement_state; + #ifndef NO_EMBEDDED_ACCESS_CHECKS st_sp_security_context save_ctx; #endif @@ -4679,38 +4681,21 @@ Item_func_sp::execute(Item **itp) goto error; } - old_client_capabilites= thd->client_capabilities; - thd->client_capabilities &= ~CLIENT_MULTI_RESULTS; - -#ifndef EMBEDDED_LIBRARY - save_no_send_ok= thd->net.no_send_ok; - thd->net.no_send_ok= TRUE; -#endif - #ifndef NO_EMBEDDED_ACCESS_CHECKS if (check_routine_access(thd, EXECUTE_ACL, m_sp->m_db.str, m_sp->m_name.str, 0, 0)) - goto error_check; + goto error; sp_change_security_context(thd, m_sp, &save_ctx); if (save_ctx.changed && check_routine_access(thd, EXECUTE_ACL, m_sp->m_db.str, m_sp->m_name.str, 0, 0)) goto error_check_ctx; #endif - /* - Like for SPs, we don't binlog the substatements. If the statement which - called this function is an update statement, it will be binlogged; but if - it's not (e.g. SELECT myfunc()) it won't be binlogged (documented known - problem). - */ - - tmp_disable_binlog(thd); /* don't binlog the substatements */ - thd->in_sub_stmt= TRUE; + thd->reset_sub_statement_state(&statement_state, SUB_STMT_FUNCTION); res= m_sp->execute_function(thd, args, arg_count, itp); + thd->restore_sub_statement_state(&statement_state); - thd->in_sub_stmt= save_in_sub_stmt; - reenable_binlog(thd); if (res && mysql_bin_log.is_open() && (m_sp->m_chistics->daccess == SP_CONTAINS_SQL || m_sp->m_chistics->daccess == SP_MODIFIES_SQL_DATA)) @@ -4723,15 +4708,6 @@ error_check_ctx: sp_restore_security_context(thd, m_sp, &save_ctx); #endif - thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; - -error_check: -#ifndef EMBEDDED_LIBRARY - thd->net.no_send_ok= save_no_send_ok; -#endif - - thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; - error: DBUG_RETURN(res); } diff --git a/sql/item_sum.cc b/sql/item_sum.cc index 2d80a19aa55..e86d4f0d8ba 100644 --- a/sql/item_sum.cc +++ b/sql/item_sum.cc @@ -2291,8 +2291,7 @@ bool Item_sum_count_distinct::setup(THD *thd) DBUG_ASSERT(table == 0); if (!(table= create_tmp_table(thd, tmp_table_param, list, (ORDER*) 0, 1, 0, - (select_lex->options | thd->options) & - ~TMP_TABLE_FORCE_MYISAM, + (select_lex->options | thd->options), HA_POS_ERROR, (char*)""))) return TRUE; table->file->extra(HA_EXTRA_NO_ROWS); // Don't update rows @@ -3074,8 +3073,7 @@ bool Item_func_group_concat::setup(THD *thd) */ if (!(table= create_tmp_table(thd, tmp_table_param, all_fields, (ORDER*) 0, 0, TRUE, - (select_lex->options | thd->options) & - ~TMP_TABLE_FORCE_MYISAM, + (select_lex->options | thd->options), HA_POS_ERROR, (char*) ""))) DBUG_RETURN(TRUE); table->file->extra(HA_EXTRA_NO_ROWS); diff --git a/sql/lock.cc b/sql/lock.cc index 568ca2b68af..941d7baa76e 100644 --- a/sql/lock.cc +++ b/sql/lock.cc @@ -849,10 +849,6 @@ static void print_lock_error(int error, const char *table) So in this exceptional case the COMMIT should not be blocked by the FLUSH TABLES WITH READ LOCK. - TODO in MySQL 5.x: make_global_read_lock_block_commit() should be - killable. Normally CPU does not spend a long time in this function (COMMITs - are quite fast), but it would still be nice. - ****************************************************************************/ volatile uint global_read_lock=0; @@ -1003,7 +999,7 @@ bool make_global_read_lock_block_commit(THD *thd) pthread_cond_wait(&COND_refresh, &LOCK_global_read_lock); DBUG_EXECUTE_IF("make_global_read_lock_block_commit_loop", protect_against_global_read_lock--;); - if (error= thd->killed) + if ((error= test(thd->killed))) global_read_lock_blocks_commit--; // undo what we did else thd->global_read_lock= MADE_GLOBAL_READ_LOCK_BLOCK_COMMIT; diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h index 22b3cf989f8..ebb58c732bd 100644 --- a/sql/mysql_priv.h +++ b/sql/mysql_priv.h @@ -256,13 +256,6 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define OPTION_WARNINGS (1L << 13) // THD, user #define OPTION_AUTO_IS_NULL (1L << 14) // THD, user, binlog #define OPTION_FOUND_COMMENT (1L << 15) // SELECT, intern, parser -/* - Force the used temporary table to be a MyISAM table (because we will use - fulltext functions when reading from it. This uses the same constant as - OPTION_FOUND_COMMENT because we've run out of bits and these two values - are not used together. -*/ -#define TMP_TABLE_FORCE_MYISAM (1L << 15) #define OPTION_SAFE_UPDATES (1L << 16) // THD, user #define OPTION_BUFFER_RESULT (1L << 17) // SELECT, user #define OPTION_BIN_LOG (1L << 18) // THD, user @@ -291,6 +284,11 @@ extern CHARSET_INFO *national_charset_info, *table_alias_charset; #define OPTION_SETUP_TABLES_DONE (1L << 30) // intern /* If not set then the thread will ignore all warnings with level notes. */ #define OPTION_SQL_NOTES (1L << 31) // THD, user +/* + Force the used temporary table to be a MyISAM table (because we will use + fulltext functions when reading from it. +*/ +#define TMP_TABLE_FORCE_MYISAM (LL(1) << 32) /* Maximum length of time zone name that we support @@ -726,7 +724,7 @@ int mysql_update(THD *thd,TABLE_LIST *tables,List<Item> &fields, enum enum_duplicates handle_duplicates, bool ignore); bool mysql_multi_update(THD *thd, TABLE_LIST *table_list, List<Item> *fields, List<Item> *values, - COND *conds, ulong options, + COND *conds, ulonglong options, enum enum_duplicates handle_duplicates, bool ignore, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex); bool mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table, @@ -742,7 +740,7 @@ int check_that_all_fields_are_given_values(THD *thd, TABLE *entry, TABLE_LIST *table_list); bool mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds); bool mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, SQL_LIST *order, - ha_rows rows, ulong options); + ha_rows rows, ulonglong options); bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok); bool mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create); TABLE *open_ltable(THD *thd, TABLE_LIST *table_list, thr_lock_type update); @@ -1110,6 +1108,7 @@ extern char log_error_file[FN_REFLEN], *opt_tc_log_file; extern double log_10[32]; extern ulonglong log_10_int[20]; extern ulonglong keybuff_size; +extern ulonglong thd_startup_options; extern ulong refresh_version,flush_version, thread_id; extern ulong binlog_cache_use, binlog_cache_disk_use; extern ulong aborted_threads,aborted_connects; @@ -1119,7 +1118,7 @@ extern ulong delayed_insert_threads, delayed_insert_writes; extern ulong delayed_rows_in_use,delayed_insert_errors; extern ulong slave_open_temp_tables; extern ulong query_cache_size, query_cache_min_res_unit; -extern ulong thd_startup_options, slow_launch_threads, slow_launch_time; +extern ulong slow_launch_threads, slow_launch_time; extern ulong table_cache_size; extern ulong max_connections,max_connect_errors, connect_timeout; extern ulong slave_net_timeout, slave_trans_retries; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index eb5d2790acd..008aeaf87c5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -387,8 +387,8 @@ uint delay_key_write_options, protocol_version; uint lower_case_table_names; uint tc_heuristic_recover= 0; uint volatile thread_count, thread_running; -ulong back_log, connect_timeout, concurrency; -ulong server_id, thd_startup_options; +ulonglong thd_startup_options; +ulong back_log, connect_timeout, concurrency, server_id; ulong table_cache_size, thread_stack, what_to_log; ulong query_buff_size, slow_launch_time, slave_open_temp_tables; ulong open_files_limit, max_binlog_size, max_relay_log_size; @@ -1909,7 +1909,8 @@ static void check_data_home(const char *path) static void sig_reload(int signo) { // Flush everything - reload_acl_and_cache((THD*) 0,REFRESH_LOG, (TABLE_LIST*) 0, NULL); + bool not_used; + reload_acl_and_cache((THD*) 0,REFRESH_LOG, (TABLE_LIST*) 0, ¬_used); signal(signo, SIG_ACK); } @@ -2268,12 +2269,13 @@ static void *signal_hand(void *arg __attribute__((unused))) case SIGHUP: if (!abort_loop) { + bool not_used; mysql_print_status(); // Print some debug info reload_acl_and_cache((THD*) 0, (REFRESH_LOG | REFRESH_TABLES | REFRESH_FAST | REFRESH_GRANT | REFRESH_THREADS | REFRESH_HOSTS), - (TABLE_LIST*) 0, NULL); // Flush logs + (TABLE_LIST*) 0, ¬_used); // Flush logs } break; #ifdef USE_ONE_SIGNAL_HAND diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt index a035426db57..25f26fee487 100644 --- a/sql/share/errmsg.txt +++ b/sql/share/errmsg.txt @@ -5342,8 +5342,8 @@ ER_SP_DUP_HANDLER 42000 eng "Duplicate handler declared in the same block" ER_SP_NOT_VAR_ARG 42000 eng "OUT or INOUT argument %d for routine %s is not a variable" -ER_SP_NO_RETSET_IN_FUNC 0A000 - eng "Not allowed to return a result set from a function" +ER_SP_NO_RETSET 0A000 + eng "Not allowed to return a result set from a %s" ER_CANT_CREATE_GEOMETRY_OBJECT 22003 eng "Cannot get geometry object from data you send to the GEOMETRY field" ER_FAILED_ROUTINE_BREAK_BINLOG diff --git a/sql/sp_cache.cc b/sql/sp_cache.cc index 68e8dbb3252..495f969eeac 100644 --- a/sql/sp_cache.cc +++ b/sql/sp_cache.cc @@ -22,7 +22,7 @@ #include "sp_head.h" static pthread_mutex_t Cversion_lock; -static ulong Cversion = 0; +static ulong volatile Cversion= 0; /* @@ -86,9 +86,11 @@ void sp_cache_init() /* Clear the cache *cp and set *cp to NULL. + SYNOPSIS sp_cache_clear() - cp Pointer to cache to clear + cp Pointer to cache to clear + NOTE This function doesn't invalidate other caches. */ @@ -96,6 +98,7 @@ void sp_cache_init() void sp_cache_clear(sp_cache **cp) { sp_cache *c= *cp; + if (c) { delete c; @@ -109,8 +112,8 @@ void sp_cache_clear(sp_cache **cp) SYNOPSIS sp_cache_insert() - cp The cache to put routine into - sp Routine to insert. + cp The cache to put routine into + sp Routine to insert. TODO: Perhaps it will be more straightforward if in case we returned an error from this function when we couldn't allocate sp_cache. (right @@ -120,22 +123,19 @@ void sp_cache_clear(sp_cache **cp) void sp_cache_insert(sp_cache **cp, sp_head *sp) { - sp_cache *c= *cp; + sp_cache *c; + ulong v; - if (!c && (c= new sp_cache())) - { - pthread_mutex_lock(&Cversion_lock); // LOCK - c->version= Cversion; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK - } - if (c) + if (!(c= *cp)) { - DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, - sp->m_qname.str)); - c->insert(sp); - if (*cp == NULL) - *cp= c; + if (!(c= new sp_cache())) + return; // End of memory error + c->version= Cversion; // No need to lock when reading long variable } + DBUG_PRINT("info",("sp_cache: inserting: %*s", sp->m_qname.length, + sp->m_qname.str)); + c->insert(sp); + *cp= c; // Update *cp if it was NULL } @@ -158,7 +158,7 @@ void sp_cache_insert(sp_cache **cp, sp_head *sp) sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name) { sp_cache *c= *cp; - if (!c) + if (! c) return NULL; return c->lookup(name->m_qname.str, name->m_qname.length); } @@ -178,9 +178,7 @@ sp_head *sp_cache_lookup(sp_cache **cp, sp_name *name) void sp_cache_invalidate() { DBUG_PRINT("info",("sp_cache: invalidating")); - pthread_mutex_lock(&Cversion_lock); // LOCK - Cversion++; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK + thread_safe_increment(Cversion, &Cversion_lock); } @@ -202,9 +200,7 @@ void sp_cache_flush_obsolete(sp_cache **cp) if (c) { ulong v; - pthread_mutex_lock(&Cversion_lock); // LOCK - v= Cversion; - pthread_mutex_unlock(&Cversion_lock); // UNLOCK + v= Cversion; // No need to lock when reading long variable if (c->version < v) { DBUG_PRINT("info",("sp_cache: deleting all functions")); @@ -215,20 +211,20 @@ void sp_cache_flush_obsolete(sp_cache **cp) } } + /************************************************************************* Internal functions *************************************************************************/ -static byte * -hash_get_key_for_sp_head(const byte *ptr, uint *plen, +static byte *hash_get_key_for_sp_head(const byte *ptr, uint *plen, my_bool first) { sp_head *sp= (sp_head *)ptr; - *plen= sp->m_qname.length; return (byte*) sp->m_qname.str; } + static void hash_free_sp_head(void *p) { @@ -236,16 +232,19 @@ hash_free_sp_head(void *p) delete sp; } + sp_cache::sp_cache() { init(); } + sp_cache::~sp_cache() { hash_free(&m_hashtable); } + void sp_cache::init() { @@ -254,6 +253,7 @@ sp_cache::init() version= 0; } + void sp_cache::cleanup() { diff --git a/sql/sp_head.cc b/sql/sp_head.cc index eb671b5bcd0..50bb3a84ee7 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -659,7 +659,9 @@ sp_head::execute(THD *thd) if (i == NULL) break; DBUG_PRINT("execute", ("Instruction %u", ip)); - thd->set_time(); // Make current_time() et al work + /* Don't change NOW() in FUNCTION or TRIGGER */ + if (!thd->in_sub_stmt) + thd->set_time(); // Make current_time() et al work /* We have to set thd->current_arena before executing the instruction to store in the instruction free_list all new items, created @@ -678,18 +680,19 @@ sp_head::execute(THD *thd) cleanup_items(i->free_list); i->state= Query_arena::EXECUTED; - // Check if an exception has occurred and a handler has been found - // Note: We havo to check even if ret==0, since warnings (and some - // errors don't return a non-zero value. - // We also have to check even if thd->killed != 0, since some - // errors return with this even when a handler has been found - // (e.g. "bad data"). + /* + Check if an exception has occurred and a handler has been found + Note: We havo to check even if ret==0, since warnings (and some + errors don't return a non-zero value. + We also have to check even if thd->killed != 0, since some + errors return with this even when a handler has been found + (e.g. "bad data"). + */ if (ctx) { uint hf; - switch (ctx->found_handler(&hip, &hf)) - { + switch (ctx->found_handler(&hip, &hf)) { case SP_HANDLER_NONE: break; case SP_HANDLER_CONTINUE: @@ -759,8 +762,10 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) if (argcount != params) { - // Need to use my_printf_error here, or it will not terminate the - // invoking query properly. + /* + Need to use my_printf_error here, or it will not terminate the + invoking query properly. + */ my_error(ER_SP_WRONG_NO_OF_ARGS, MYF(0), "FUNCTION", m_qname.str, params, argcount); DBUG_RETURN(-1); @@ -784,9 +789,11 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) DBUG_RETURN(-1); } } - // The rest of the frame are local variables which are all IN. - // Default all variables to null (those with default clauses will - // be set by an set instruction). + /* + The rest of the frame are local variables which are all IN. + Default all variables to null (those with default clauses will + be set by an set instruction). + */ { Item_null *nit= NULL; // Re-use this, and only create if needed for (; i < csize ; i++) @@ -803,9 +810,11 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp) ret= execute(thd); - // Partially restore context now. - // We still need the call mem root and free list for processing - // of the result. + /* + Partially restore context now. + We still need the call mem root and free list for processing + of the result. + */ thd->restore_backup_item_arena(&call_arena, &backup_arena); if (m_type == TYPE_ENUM_FUNCTION && ret == 0) @@ -932,9 +941,11 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) close_thread_tables(thd, 0, 0); DBUG_PRINT("info",(" %.*s: eval args done", m_name.length, m_name.str)); - // The rest of the frame are local variables which are all IN. - // Default all variables to null (those with default clauses will - // be set by an set instruction). + /* + The rest of the frame are local variables which are all IN. + Default all variables to null (those with default clauses will + be set by an set instruction). + */ for (; i < csize ; i++) { if (! nit) @@ -956,8 +967,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) List_iterator<Item> li(*args); Item *it; - // Copy back all OUT or INOUT values to the previous frame, or - // set global user variables + /* + Copy back all OUT or INOUT values to the previous frame, or + set global user variables + */ for (uint i = 0 ; (it= li++) && i < params ; i++) { sp_pvar_t *pvar= m_pcont->find_pvar(i); @@ -987,8 +1000,10 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) octx->set_item(offset, copy); if (orig && copy == orig) { - // A reused item slot, where the constructor put it in the - // free_list, so we have to restore the list. + /* + A reused item slot, where the constructor put it in the + free_list, so we have to restore the list. + */ thd->free_list= o_free_list; copy->next= o_item_next; } @@ -1420,8 +1435,6 @@ sp_head::opt_mark(uint ip) ip= i->opt_mark(this); } -// ------------------------------------------------------------------ - /* Prepare LEX and thread for execution of instruction, if requested open @@ -1513,6 +1526,7 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, thd->proc_info="closing tables"; close_thread_tables(thd); + thd->proc_info= 0; if (m_lex->query_tables_own_last) { @@ -1549,9 +1563,10 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, } -// -// sp_instr -// +/* + sp_instr class functions +*/ + int sp_instr::exec_core(THD *thd, uint *nextp) { DBUG_ASSERT(0); @@ -1559,9 +1574,10 @@ int sp_instr::exec_core(THD *thd, uint *nextp) } -// -// sp_instr_stmt -// +/* + sp_instr_stmt class functions +*/ + int sp_instr_stmt::execute(THD *thd, uint *nextp) { @@ -1606,9 +1622,11 @@ sp_instr_stmt::exec_core(THD *thd, uint *nextp) return res; } -// -// sp_instr_set -// + +/* + sp_instr_set class functions +*/ + int sp_instr_set::execute(THD *thd, uint *nextp) { @@ -1618,6 +1636,7 @@ sp_instr_set::execute(THD *thd, uint *nextp) DBUG_RETURN(m_lex_keeper.reset_lex_and_exec_core(thd, nextp, TRUE, this)); } + int sp_instr_set::exec_core(THD *thd, uint *nextp) { @@ -1638,9 +1657,10 @@ sp_instr_set::print(String *str) } -// -// sp_instr_set_trigger_field -// +/* + sp_instr_set_trigger_field class functions +*/ + int sp_instr_set_trigger_field::execute(THD *thd, uint *nextp) { @@ -1671,9 +1691,11 @@ sp_instr_set_trigger_field::print(String *str) value->print(str); } -// -// sp_instr_jump -// + +/* + sp_instr_jump class functions +*/ + int sp_instr_jump::execute(THD *thd, uint *nextp) { @@ -1732,9 +1754,10 @@ sp_instr_jump::opt_move(uint dst, List<sp_instr> *bp) m_ip= dst; } -// -// sp_instr_jump_if -// + +/* + sp_instr_jump_if class functions +*/ int sp_instr_jump_if::execute(THD *thd, uint *nextp) @@ -1790,9 +1813,11 @@ sp_instr_jump_if::opt_mark(sp_head *sp) return m_ip+1; } -// -// sp_instr_jump_if_not -// + +/* + sp_instr_jump_if_not class functions +*/ + int sp_instr_jump_if_not::execute(THD *thd, uint *nextp) { @@ -1823,6 +1848,7 @@ sp_instr_jump_if_not::exec_core(THD *thd, uint *nextp) return res; } + void sp_instr_jump_if_not::print(String *str) { @@ -1833,6 +1859,7 @@ sp_instr_jump_if_not::print(String *str) m_expr->print(str); } + uint sp_instr_jump_if_not::opt_mark(sp_head *sp) { @@ -1848,9 +1875,10 @@ sp_instr_jump_if_not::opt_mark(sp_head *sp) return m_ip+1; } -// -// sp_instr_freturn -// + +/* + sp_instr_freturn class functions +*/ int sp_instr_freturn::execute(THD *thd, uint *nextp) @@ -1889,9 +1917,10 @@ sp_instr_freturn::print(String *str) m_value->print(str); } -// -// sp_instr_hpush_jump -// +/* + sp_instr_hpush_jump class functions +*/ + int sp_instr_hpush_jump::execute(THD *thd, uint *nextp) { @@ -1935,9 +1964,11 @@ sp_instr_hpush_jump::opt_mark(sp_head *sp) return m_ip+1; } -// -// sp_instr_hpop -// + +/* + sp_instr_hpop class functions +*/ + int sp_instr_hpop::execute(THD *thd, uint *nextp) { @@ -1962,9 +1993,10 @@ sp_instr_hpop::backpatch(uint dest, sp_pcontext *dst_ctx) } -// -// sp_instr_hreturn -// +/* + sp_instr_hreturn class functions +*/ + int sp_instr_hreturn::execute(THD *thd, uint *nextp) { @@ -1980,6 +2012,7 @@ sp_instr_hreturn::execute(THD *thd, uint *nextp) DBUG_RETURN(0); } + void sp_instr_hreturn::print(String *str) { @@ -1990,6 +2023,7 @@ sp_instr_hreturn::print(String *str) str->qs_append(m_dest); } + uint sp_instr_hreturn::opt_mark(sp_head *sp) { @@ -2003,9 +2037,10 @@ sp_instr_hreturn::opt_mark(sp_head *sp) } -// -// sp_instr_cpush -// +/* + sp_instr_cpush class functions +*/ + int sp_instr_cpush::execute(THD *thd, uint *nextp) { @@ -2015,15 +2050,18 @@ sp_instr_cpush::execute(THD *thd, uint *nextp) DBUG_RETURN(0); } + void sp_instr_cpush::print(String *str) { str->append("cpush"); } -// -// sp_instr_cpop -// + +/* + sp_instr_cpop class functions +*/ + int sp_instr_cpop::execute(THD *thd, uint *nextp) { @@ -2033,6 +2071,7 @@ sp_instr_cpop::execute(THD *thd, uint *nextp) DBUG_RETURN(0); } + void sp_instr_cpop::print(String *str) { @@ -2047,9 +2086,11 @@ sp_instr_cpop::backpatch(uint dest, sp_pcontext *dst_ctx) m_count= m_ctx->diff_cursors(dst_ctx); } -// -// sp_instr_copen -// + +/* + sp_instr_copen class functions +*/ + int sp_instr_copen::execute(THD *thd, uint *nextp) { @@ -2117,9 +2158,11 @@ sp_instr_copen::print(String *str) str->qs_append(m_cursor); } -// -// sp_instr_cclose -// + +/* + sp_instr_cclose class functions +*/ + int sp_instr_cclose::execute(THD *thd, uint *nextp) { @@ -2135,6 +2178,7 @@ sp_instr_cclose::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } + void sp_instr_cclose::print(String *str) { @@ -2143,9 +2187,11 @@ sp_instr_cclose::print(String *str) str->qs_append(m_cursor); } -// -// sp_instr_cfetch -// + +/* + sp_instr_cfetch class functions +*/ + int sp_instr_cfetch::execute(THD *thd, uint *nextp) { @@ -2161,6 +2207,7 @@ sp_instr_cfetch::execute(THD *thd, uint *nextp) DBUG_RETURN(res); } + void sp_instr_cfetch::print(String *str) { @@ -2178,9 +2225,11 @@ sp_instr_cfetch::print(String *str) } } -// -// sp_instr_error -// + +/* + sp_instr_error class functions +*/ + int sp_instr_error::execute(THD *thd, uint *nextp) { @@ -2191,6 +2240,7 @@ sp_instr_error::execute(THD *thd, uint *nextp) DBUG_RETURN(-1); } + void sp_instr_error::print(String *str) { @@ -2199,12 +2249,12 @@ sp_instr_error::print(String *str) str->qs_append(m_errcode); } -/* ------------------------------------------------------------------ */ +/* ------------------------------------------------------------------ */ -// -// Security context swapping -// +/* + Security context swapping +*/ #ifndef NO_EMBEDDED_ACCESS_CHECKS void @@ -2453,11 +2503,12 @@ sp_head::add_used_tables_to_table_list(THD *thd, DBUG_RETURN(result); } + /* - * Simple function for adding an explicetly named (systems) table to - * the global table list, e.g. "mysql", "proc". - * - */ + Simple function for adding an explicetly named (systems) table to + the global table list, e.g. "mysql", "proc". +*/ + TABLE_LIST * sp_add_to_query_tables(THD *thd, LEX *lex, const char *db, const char *name, diff --git a/sql/sql_base.cc b/sql/sql_base.cc index 4c1b8347466..5627b97c734 100644 --- a/sql/sql_base.cc +++ b/sql/sql_base.cc @@ -1921,8 +1921,7 @@ int open_tables(THD *thd, TABLE_LIST **start, uint *counter, uint flags) has added its base tables after itself, adjust the boundary pointer accordingly. */ - if (query_tables_last_own && - query_tables_last_own == &(tables->next_global) && + if (query_tables_last_own == &(tables->next_global) && tables->view->query_tables) query_tables_last_own= tables->view->query_tables_last; diff --git a/sql/sql_class.cc b/sql/sql_class.cc index 792d3c62169..d4f05456cad 100644 --- a/sql/sql_class.cc +++ b/sql/sql_class.cc @@ -174,7 +174,7 @@ THD::THD() :Statement(CONVENTIONAL_EXECUTION, 0, ALLOC_ROOT_MIN_BLOCK_SIZE, 0), Open_tables_state(refresh_version), lock_id(&main_lock_id), - user_time(0), in_sub_stmt(FALSE), global_read_lock(0), is_fatal_error(0), + user_time(0), in_sub_stmt(0), global_read_lock(0), is_fatal_error(0), rand_used(0), time_zone_used(0), last_insert_id_used(0), insert_id_used(0), clear_next_insert_id(0), in_lock_tables(0), bootstrap(0), derived_tables_processing(FALSE), @@ -1844,6 +1844,94 @@ void THD::restore_backup_open_tables_state(Open_tables_state *backup) DBUG_VOID_RETURN; } + + +/**************************************************************************** + Handling of statement states in functions and triggers. + + This is used to ensure that the function/trigger gets a clean state + to work with and does not cause any side effects of the calling statement. + + It also allows most stored functions and triggers to replicate even + if they are used items that would normally be stored in the binary + replication (like last_insert_id() etc...) + + The following things is done + - Disable binary logging for the duration of the statement + - Disable multi-result-sets for the duration of the statement + - Value of last_insert_id() is reset and restored + - Value set by 'SET INSERT_ID=#' is reset and restored + - Value for found_rows() is reset and restored + - examined_row_count is added to the total + - cuted_fields is added to the total + + NOTES: + Seed for random() is saved for the first! usage of RAND() + We reset examined_row_count and cuted_fields and add these to the + result to ensure that if we have a bug that would reset these within + a function, we are not loosing any rows from the main statement. +****************************************************************************/ + +void THD::reset_sub_statement_state(Sub_statement_state *backup, + uint new_state) +{ + backup->options= options; + backup->in_sub_stmt= in_sub_stmt; + backup->no_send_ok= net.no_send_ok; + backup->enable_slow_log= enable_slow_log; + backup->last_insert_id= last_insert_id; + backup->next_insert_id= next_insert_id; + backup->insert_id_used= insert_id_used; + backup->limit_found_rows= limit_found_rows; + backup->examined_row_count= examined_row_count; + backup->sent_row_count= sent_row_count; + backup->cuted_fields= cuted_fields; + backup->client_capabilities= client_capabilities; + + options&= ~OPTION_BIN_LOG; + /* Disable result sets */ + client_capabilities &= ~CLIENT_MULTI_RESULTS; + in_sub_stmt|= new_state; + last_insert_id= 0; + next_insert_id= 0; + insert_id_used= 0; + examined_row_count= 0; + sent_row_count= 0; + cuted_fields= 0; + +#ifndef EMBEDDED_LIBRARY + /* Surpress OK packets in case if we will execute statements */ + net.no_send_ok= TRUE; +#endif +} + + +void THD::restore_sub_statement_state(Sub_statement_state *backup) +{ + options= backup->options; + in_sub_stmt= backup->in_sub_stmt; + net.no_send_ok= backup->no_send_ok; + enable_slow_log= backup->enable_slow_log; + last_insert_id= backup->last_insert_id; + next_insert_id= backup->next_insert_id; + insert_id_used= backup->insert_id_used; + limit_found_rows= backup->limit_found_rows; + sent_row_count= backup->sent_row_count; + client_capabilities= backup->client_capabilities; + + /* + The following is added to the old values as we are interested in the + total complexity of the query + */ + examined_row_count+= backup->examined_row_count; + cuted_fields+= backup->cuted_fields; +} + + +/*************************************************************************** + Handling of XA id cacheing +***************************************************************************/ + pthread_mutex_t LOCK_xid_cache; HASH xid_cache; @@ -1884,6 +1972,7 @@ XID_STATE *xid_cache_search(XID *xid) return res; } + bool xid_cache_insert(XID *xid, enum xa_states xa_state) { XID_STATE *xs; @@ -1904,6 +1993,7 @@ bool xid_cache_insert(XID *xid, enum xa_states xa_state) return res; } + bool xid_cache_insert(XID_STATE *xid_state) { pthread_mutex_lock(&LOCK_xid_cache); @@ -1914,6 +2004,7 @@ bool xid_cache_insert(XID_STATE *xid_state) return res; } + void xid_cache_delete(XID_STATE *xid_state) { pthread_mutex_lock(&LOCK_xid_cache); diff --git a/sql/sql_class.h b/sql/sql_class.h index 494e113d65a..a8d45a3a6b4 100644 --- a/sql/sql_class.h +++ b/sql/sql_class.h @@ -1045,6 +1045,27 @@ public: }; +/* class to save context when executing a function or trigger */ + +/* Defines used for Sub_statement_state::in_sub_stmt */ + +#define SUB_STMT_TRIGGER 1 +#define SUB_STMT_FUNCTION 2 + +class Sub_statement_state +{ +public: + ulonglong options; + ulonglong last_insert_id, next_insert_id; + ulonglong limit_found_rows; + ha_rows cuted_fields, sent_row_count, examined_row_count; + ulong client_capabilities; + uint in_sub_stmt; + bool enable_slow_log, insert_id_used; + my_bool no_send_ok; +}; + + /* For each client connection we create a separate thread with THD serving as a thread/connection descriptor @@ -1151,10 +1172,9 @@ public: time_t connect_time,thr_create_time; // track down slow pthread_create thr_lock_type update_lock_default; delayed_insert *di; - my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ - /* TRUE if we are inside of trigger or stored function. */ - bool in_sub_stmt; + /* <> 0 if we are inside of trigger or stored function. */ + uint in_sub_stmt; /* container for handler's private per-connection data */ void *ha_data[MAX_HA]; @@ -1236,6 +1256,8 @@ public: */ ulonglong current_insert_id; ulonglong limit_found_rows; + ulonglong options; /* Bitmap of states */ + longlong row_count_func; /* For the ROW_COUNT() function */ ha_rows cuted_fields, sent_row_count, examined_row_count; /* @@ -1265,7 +1287,7 @@ public: update auto-updatable fields (like auto_increment and timestamp). */ query_id_t query_id, warn_id; - ulong options, thread_id, col_access; + ulong thread_id, col_access; /* Statement id is thread-wide. This counter is used to generate ids */ ulong statement_id_counter; @@ -1305,7 +1327,8 @@ public: bool no_warnings_for_error; /* no warnings on call to my_error() */ /* set during loop of derived table processing */ bool derived_tables_processing; - longlong row_count_func; /* For the ROW_COUNT() function */ + my_bool tablespace_op; /* This is TRUE in DISCARD/IMPORT TABLESPACE */ + sp_rcontext *spcont; // SP runtime context sp_cache *sp_proc_cache; sp_cache *sp_func_cache; @@ -1513,11 +1536,13 @@ public: { return current_arena->is_stmt_prepare() || lex->view_prepare_mode; } void reset_n_backup_open_tables_state(Open_tables_state *backup); void restore_backup_open_tables_state(Open_tables_state *backup); + void reset_sub_statement_state(Sub_statement_state *backup, uint new_state); + void restore_sub_statement_state(Sub_statement_state *backup); }; #define tmp_disable_binlog(A) \ - {ulong tmp_disable_binlog__save_options= (A)->options; \ + {ulonglong tmp_disable_binlog__save_options= (A)->options; \ (A)->options&= ~OPTION_BIN_LOG #define reenable_binlog(A) (A)->options= tmp_disable_binlog__save_options;} diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc index 334a013ca6e..35183fc959b 100644 --- a/sql/sql_delete.cc +++ b/sql/sql_delete.cc @@ -30,7 +30,7 @@ #include "sql_trigger.h" bool mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, - SQL_LIST *order, ha_rows limit, ulong options) + SQL_LIST *order, ha_rows limit, ulonglong options) { int error; TABLE *table; @@ -809,7 +809,7 @@ bool mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok) ha_enable_transaction(thd, FALSE); mysql_init_select(thd->lex); error= mysql_delete(thd, table_list, (COND*) 0, (SQL_LIST*) 0, - HA_POS_ERROR, 0); + HA_POS_ERROR, LL(0)); ha_enable_transaction(thd, TRUE); thd->options= save_options; DBUG_RETURN(error); diff --git a/sql/sql_derived.cc b/sql/sql_derived.cc index da1525fc133..7b9191cd841 100644 --- a/sql/sql_derived.cc +++ b/sql/sql_derived.cc @@ -147,8 +147,7 @@ int mysql_derived_prepare(THD *thd, LEX *lex, TABLE_LIST *orig_table_list) unit->types, (ORDER*) 0, FALSE, 1, (first_select->options | thd->options | - TMP_TABLE_ALL_COLUMNS) & - ~TMP_TABLE_FORCE_MYISAM, + TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, orig_table_list->alias))) { diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 2240f504290..59969ea09fa 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -305,7 +305,7 @@ protected: *link_next, **link_prev; /* list of whole SELECT_LEX */ public: - ulong options; + ulonglong options; /* result of this query can't be cached, bit field, can be : UNCACHEABLE_DEPENDENT diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 88719d52b83..eb54c44fa47 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -1101,11 +1101,11 @@ pthread_handler_decl(handle_one_connection,arg) execute_init_command(thd, &sys_init_connect, &LOCK_sys_init_connect); if (thd->query_error) thd->killed= THD::KILL_CONNECTION; + thd->proc_info=0; + thd->set_time(); + thd->init_for_queries(); } - thd->proc_info=0; - thd->set_time(); - thd->init_for_queries(); while (!net->error && net->vio != 0 && !(thd->killed == THD::KILL_CONNECTION)) { @@ -1464,6 +1464,7 @@ bool do_command(THD *thd) /* Perform one connection-level (COM_XXXX) command. + SYNOPSIS dispatch_command() thd connection handle @@ -1863,17 +1864,18 @@ bool dispatch_command(enum enum_server_command command, THD *thd, } #endif case COM_REFRESH: - { - statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH], - &LOCK_status); - ulong options= (ulong) (uchar) packet[0]; - if (check_global_access(thd,RELOAD_ACL)) - break; - mysql_log.write(thd,command,NullS); - if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, NULL)) - send_ok(thd); + { + bool not_used; + statistic_increment(thd->status_var.com_stat[SQLCOM_FLUSH], + &LOCK_status); + ulong options= (ulong) (uchar) packet[0]; + if (check_global_access(thd,RELOAD_ACL)) break; - } + mysql_log.write(thd,command,NullS); + if (!reload_acl_and_cache(thd, options, (TABLE_LIST*) 0, ¬_used)) + send_ok(thd); + break; + } #ifndef EMBEDDED_LIBRARY case COM_SHUTDOWN: { @@ -2043,7 +2045,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd, void log_slow_statement(THD *thd) { - time_t start_of_query=thd->start_time; + time_t start_of_query; + + /* + The following should never be true with our current code base, + but better to keep this here so we don't accidently try to log a + statement in a trigger or stored function + */ + if (unlikely(thd->in_sub_stmt)) + return; // Don't set time for sub stmt + + start_of_query= thd->start_time; thd->end_time(); // Set start time /* @@ -2949,8 +2961,8 @@ end_with_restore_list: */ if (thd->locked_tables || thd->active_transaction()) { - my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, ER(ER_LOCK_OR_ACTIVE_TRANSACTION), - MYF(0)); + my_message(ER_LOCK_OR_ACTIVE_TRANSACTION, + ER(ER_LOCK_OR_ACTIVE_TRANSACTION), MYF(0)); goto error; } { @@ -3836,13 +3848,13 @@ end_with_restore_list: lex->no_write_to_binlog= 1; case SQLCOM_FLUSH: { + bool write_to_binlog; if (check_global_access(thd,RELOAD_ACL) || check_db_used(thd, all_tables)) goto error; /* reload_acl_and_cache() will tell us if we are allowed to write to the binlog or not. */ - bool write_to_binlog; if (!reload_acl_and_cache(thd, lex->type, first_table, &write_to_binlog)) { /* @@ -5190,17 +5202,21 @@ void mysql_reset_thd_for_next_command(THD *thd) DBUG_ENTER("mysql_reset_thd_for_next_command"); thd->free_list= 0; thd->select_number= 1; - thd->total_warn_count=0; // Warnings for this query thd->last_insert_id_used= thd->query_start_used= thd->insert_id_used=0; - thd->sent_row_count= thd->examined_row_count= 0; - thd->is_fatal_error= thd->rand_used= thd->time_zone_used= 0; + thd->is_fatal_error= thd->time_zone_used= 0; thd->server_status&= ~ (SERVER_MORE_RESULTS_EXISTS | SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED); thd->tmp_table_used= 0; - if (opt_bin_log) - reset_dynamic(&thd->user_var_events); - thd->clear_error(); + if (!thd->in_sub_stmt) + { + if (opt_bin_log) + reset_dynamic(&thd->user_var_events); + thd->clear_error(); + thd->total_warn_count=0; // Warnings for this query + thd->rand_used= 0; + thd->sent_row_count= thd->examined_row_count= 0; + } DBUG_VOID_RETURN; } @@ -6492,13 +6508,13 @@ void add_join_natural(TABLE_LIST *a, TABLE_LIST *b, List<String> *using_fields) tables Tables to flush (if any) write_to_binlog Depending on 'options', it may be very bad to write the query to the binlog (e.g. FLUSH SLAVE); this is a - pointer where, if it is not NULL, reload_acl_and_cache() - will put 0 if it thinks we really should not write to - the binlog. Otherwise it will put 1. + pointer where reload_acl_and_cache() will put 0 if + it thinks we really should not write to the binlog. + Otherwise it will put 1. RETURN 0 ok - !=0 error + !=0 error. thd->killed or thd->net.report_error is set */ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, @@ -6593,10 +6609,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, */ tmp_write_to_binlog= 0; if (lock_global_read_lock(thd)) - return 1; + return 1; // Killed result=close_cached_tables(thd,(options & REFRESH_FAST) ? 0 : 1, tables); - if (make_global_read_lock_block_commit(thd)) + if (make_global_read_lock_block_commit(thd)) // Killed { /* Don't leave things in a half-locked state */ unlock_global_read_lock(thd); @@ -6618,7 +6634,10 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, { tmp_write_to_binlog= 0; if (reset_master(thd)) + { result=1; + thd->fatal_error(); // Ensure client get error + } } #endif #ifdef OPENSSL @@ -6640,8 +6659,7 @@ bool reload_acl_and_cache(THD *thd, ulong options, TABLE_LIST *tables, #endif if (options & REFRESH_USER_RESOURCES) reset_mqh((LEX_USER *) NULL); - if (write_to_binlog) - *write_to_binlog= tmp_write_to_binlog; + *write_to_binlog= tmp_write_to_binlog; return result; } diff --git a/sql/sql_select.cc b/sql/sql_select.cc index 464c350a602..901c4cbcede 100644 --- a/sql/sql_select.cc +++ b/sql/sql_select.cc @@ -1016,7 +1016,7 @@ JOIN::optimize() group_list : (ORDER*) 0), group_list ? 0 : select_distinct, group_list && simple_group, - select_options & ~TMP_TABLE_FORCE_MYISAM, + select_options, (order == 0 || skip_sort_order) ? select_limit : HA_POS_ERROR, (char *) ""))) @@ -1287,7 +1287,15 @@ JOIN::exec() if (need_tmp) { if (tmp_join) + { + /* + We are in a non cacheable sub query. Get the saved join structure + after optimization. + (curr_join may have been modified during last exection and we need + to reset it) + */ curr_join= tmp_join; + } curr_tmp_table= exec_tmp_table1; /* Copy data to the temporary table */ @@ -1397,8 +1405,7 @@ JOIN::exec() (ORDER*) 0, curr_join->select_distinct && !curr_join->group_list, - 1, curr_join->select_options - & ~TMP_TABLE_FORCE_MYISAM, + 1, curr_join->select_options, HA_POS_ERROR, (char *) ""))) DBUG_VOID_RETURN; @@ -8129,7 +8136,7 @@ Field *create_tmp_field(THD *thd, TABLE *table,Item *item, Item::Type type, TABLE * create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ORDER *group, bool distinct, bool save_sum_fields, - ulong select_options, ha_rows rows_limit, + ulonglong select_options, ha_rows rows_limit, char *table_alias) { TABLE *table; @@ -8383,7 +8390,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, /* If result table is small; use a heap */ if (blob_count || using_unique_constraint || (select_options & (OPTION_BIG_TABLES | SELECT_SMALL_RESULT)) == - OPTION_BIG_TABLES ||(select_options & TMP_TABLE_FORCE_MYISAM)) + OPTION_BIG_TABLES || (select_options & TMP_TABLE_FORCE_MYISAM)) { table->file=get_new_handler(table,table->s->db_type= DB_TYPE_MYISAM); if (group && diff --git a/sql/sql_select.h b/sql/sql_select.h index 3b9a3093682..78fa88801be 100644 --- a/sql/sql_select.h +++ b/sql/sql_select.h @@ -202,7 +202,7 @@ class JOIN :public Sql_alloc Item *having; Item *tmp_having; // To store having when processed temporary table Item *having_history; // Store having for explain - uint select_options; + ulonglong select_options; select_result *result; TMP_TABLE_PARAM tmp_table_param; MYSQL_LOCK *lock; @@ -258,14 +258,14 @@ class JOIN :public Sql_alloc bool union_part; // this subselect is part of union bool optimized; // flag to avoid double optimization in EXPLAIN - JOIN(THD *thd_arg, List<Item> &fields_arg, ulong select_options_arg, + JOIN(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg, select_result *result_arg) :fields_list(fields_arg) { init(thd_arg, fields_arg, select_options_arg, result_arg); } - void init(THD *thd_arg, List<Item> &fields_arg, ulong select_options_arg, + void init(THD *thd_arg, List<Item> &fields_arg, ulonglong select_options_arg, select_result *result_arg) { join_tab= join_tab_save= 0; @@ -437,7 +437,7 @@ void TEST_join(JOIN *join); bool store_val_in_field(Field *field,Item *val); TABLE *create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields, ORDER *group, bool distinct, bool save_sum_fields, - ulong select_options, ha_rows rows_limit, + ulonglong select_options, ha_rows rows_limit, char* alias); TABLE *create_virtual_tmp_table(THD *thd, List<create_field> &field_list); void free_tmp_table(THD *thd, TABLE *entry); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index c7a48c69cba..0a76e9fb753 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3338,8 +3338,7 @@ TABLE *create_schema_table(THD *thd, TABLE_LIST *table_list) if (!(table= create_tmp_table(thd, tmp_table_param, field_list, (ORDER*) 0, 0, 0, (select_lex->options | thd->options | - TMP_TABLE_ALL_COLUMNS) & - ~TMP_TABLE_FORCE_MYISAM, + TMP_TABLE_ALL_COLUMNS), HA_POS_ERROR, table_list->alias))) DBUG_RETURN(0); table_list->schema_table_param= tmp_table_param; diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc index 09eeff02de6..053dfdfc990 100644 --- a/sql/sql_trigger.cc +++ b/sql/sql_trigger.cc @@ -869,3 +869,39 @@ end: free_root(&table.mem_root, MYF(0)); DBUG_RETURN(result); } + + + +bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event, + trg_action_time_type time_type, + bool old_row_is_record1) +{ + int res= 0; + + if (bodies[event][time_type]) + { + Sub_statement_state statement_state; + + if (old_row_is_record1) + { + old_field= record1_field; + new_field= table->field; + } + else + { + new_field= record1_field; + old_field= table->field; + } + + /* + FIXME: We should juggle with security context here (because trigger + should be invoked with creator rights). + */ + + thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER); + res= bodies[event][time_type]->execute_function(thd, 0, 0, 0); + thd->restore_sub_statement_state(&statement_state); + } + + return res; +} diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h index e2ed4bcc0f4..d9b39cc3034 100644 --- a/sql/sql_trigger.h +++ b/sql/sql_trigger.h @@ -20,6 +20,7 @@ QQ: Will it be merged into TABLE in future ? */ + class Table_triggers_list: public Sql_alloc { /* Triggers as SPs grouped by event, action_time */ @@ -76,55 +77,7 @@ public: bool drop_trigger(THD *thd, TABLE_LIST *table); bool process_triggers(THD *thd, trg_event_type event, trg_action_time_type time_type, - bool old_row_is_record1) - { - int res= 0; - - if (bodies[event][time_type]) - { - bool save_in_sub_stmt= thd->in_sub_stmt; -#ifndef EMBEDDED_LIBRARY - /* Surpress OK packets in case if we will execute statements */ - my_bool nsok= thd->net.no_send_ok; - thd->net.no_send_ok= TRUE; -#endif - - if (old_row_is_record1) - { - old_field= record1_field; - new_field= table->field; - } - else - { - new_field= record1_field; - old_field= table->field; - } - - /* - FIXME: We should juggle with security context here (because trigger - should be invoked with creator rights). - */ - /* - We disable binlogging, as in SP/functions, even though currently - triggers can't do updates. When triggers can do updates, someone - should add such a trigger to rpl_sp.test to verify that the update - does NOT go into binlog. - */ - tmp_disable_binlog(thd); - thd->in_sub_stmt= TRUE; - - res= bodies[event][time_type]->execute_function(thd, 0, 0, 0); - - thd->in_sub_stmt= save_in_sub_stmt; - reenable_binlog(thd); - -#ifndef EMBEDDED_LIBRARY - thd->net.no_send_ok= nsok; -#endif - } - - return res; - } + bool old_row_is_record1); bool get_trigger_info(THD *thd, trg_event_type event, trg_action_time_type time_type, LEX_STRING *trigger_name, LEX_STRING *trigger_stmt, diff --git a/sql/sql_union.cc b/sql/sql_union.cc index c2888bee4c6..72c96e81682 100644 --- a/sql/sql_union.cc +++ b/sql/sql_union.cc @@ -289,7 +289,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, List_iterator_fast<Item> tp(types); Query_arena *arena= thd->current_arena; Item *type; - ulong create_options; + ulonglong create_options; while ((type= tp++)) { @@ -302,7 +302,7 @@ bool st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result, } create_options= (first_select_in_union()->options | thd_arg->options | - TMP_TABLE_ALL_COLUMNS) & ~TMP_TABLE_FORCE_MYISAM; + TMP_TABLE_ALL_COLUMNS); /* Force the temporary table to be a MyISAM table if we're going to use fullext functions (MATCH ... AGAINST .. IN BOOLEAN MODE) when reading diff --git a/sql/sql_update.cc b/sql/sql_update.cc index 17efd56372a..b596420692a 100644 --- a/sql/sql_update.cc +++ b/sql/sql_update.cc @@ -813,7 +813,7 @@ bool mysql_multi_update(THD *thd, List<Item> *fields, List<Item> *values, COND *conds, - ulong options, + ulonglong options, enum enum_duplicates handle_duplicates, bool ignore, SELECT_LEX_UNIT *unit, SELECT_LEX *select_lex) { diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 3fa015ad623..5085ac6698e 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1311,6 +1311,12 @@ create: YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES; sp->restore_thd_mem_root(YYTHD); + if (sp->m_multi_results) + { + my_error(ER_SP_NO_RETSET, MYF(0), "trigger"); + YYABORT; + } + /* We have to do it after parsing trigger body, because some of sp_proc_stmt alternatives are not saving/restoring LEX, so @@ -1463,8 +1469,7 @@ create_function_tail: if (sp->m_multi_results) { - my_message(ER_SP_NO_RETSET_IN_FUNC, ER(ER_SP_NO_RETSET_IN_FUNC), - MYF(0)); + my_error(ER_SP_NO_RETSET, MYF(0), "function"); YYABORT; } if (sp->check_backpatch(YYTHD)) @@ -7802,7 +7807,8 @@ sys_option_value: /* We are in trigger and assigning value to field of new row */ Item *it; Item_trigger_field *trg_fld; - sp_instr_set_trigger_field *i; + sp_instr_set_trigger_field *sp_fld; + LINT_INIT(sp_fld); if ($1) { yyerror(ER(ER_SYNTAX_ERROR)); @@ -7819,10 +7825,11 @@ sys_option_value: if (!(trg_fld= new Item_trigger_field(Lex->current_context(), Item_trigger_field::NEW_ROW, $2.base_name.str)) || - !(i= new sp_instr_set_trigger_field(lex->sphead-> - instructions(), - lex->spcont, trg_fld, - it, lex))) + !(sp_fld= new sp_instr_set_trigger_field(lex->sphead-> + instructions(), + lex->spcont, + trg_fld, + it, lex))) YYABORT; /* @@ -7832,7 +7839,7 @@ sys_option_value: lex->trg_table_fields.link_in_list((byte *)trg_fld, (byte **)&trg_fld->next_trg_field); - lex->sphead->add_instr(i); + lex->sphead->add_instr(sp_fld); } else if ($2.var) { /* System variable */ @@ -7846,7 +7853,7 @@ sys_option_value: /* An SP local variable */ sp_pcontext *ctx= lex->spcont; sp_pvar_t *spv; - sp_instr_set *i; + sp_instr_set *sp_set; Item *it; if ($1) { @@ -7862,9 +7869,9 @@ sys_option_value: it= spv->dflt; else it= new Item_null(); - i= new sp_instr_set(lex->sphead->instructions(), ctx, - spv->offset, it, spv->type, lex, TRUE); - lex->sphead->add_instr(i); + sp_set= new sp_instr_set(lex->sphead->instructions(), ctx, + spv->offset, it, spv->type, lex, TRUE); + lex->sphead->add_instr(sp_set); spv->isset= TRUE; } } diff --git a/tests/fork_big2.pl b/tests/fork_big2.pl index a1c55ac4c11..567cfafa176 100644 --- a/tests/fork_big2.pl +++ b/tests/fork_big2.pl @@ -300,7 +300,7 @@ sub test_select # # Do big select count(distinct..) over the table -# +# sub test_select_count { |