summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/rpl_trigger.result108
-rw-r--r--mysql-test/r/trigger.result33
-rw-r--r--mysql-test/t/rpl_trigger.test118
-rw-r--r--mysql-test/t/sp-error.test6
-rw-r--r--mysql-test/t/sp.test123
-rw-r--r--mysql-test/t/trigger.test44
-rw-r--r--sql/ha_berkeley.cc18
-rw-r--r--sql/ha_berkeley.h5
-rw-r--r--sql/ha_ndbcluster.cc2
-rw-r--r--sql/init.cc3
-rw-r--r--sql/item_func.cc52
-rw-r--r--sql/item_sum.cc6
-rw-r--r--sql/lock.cc6
-rw-r--r--sql/mysql_priv.h19
-rw-r--r--sql/mysqld.cc10
-rw-r--r--sql/share/errmsg.txt4
-rw-r--r--sql/sp_cache.cc54
-rw-r--r--sql/sp_head.cc221
-rw-r--r--sql/sql_base.cc3
-rw-r--r--sql/sql_class.cc93
-rw-r--r--sql/sql_class.h37
-rw-r--r--sql/sql_delete.cc4
-rw-r--r--sql/sql_derived.cc3
-rw-r--r--sql/sql_lex.h2
-rw-r--r--sql/sql_parse.cc80
-rw-r--r--sql/sql_select.cc17
-rw-r--r--sql/sql_select.h8
-rw-r--r--sql/sql_show.cc3
-rw-r--r--sql/sql_trigger.cc36
-rw-r--r--sql/sql_trigger.h51
-rw-r--r--sql/sql_union.cc4
-rw-r--r--sql/sql_update.cc2
-rw-r--r--sql/sql_yacc.yy31
-rw-r--r--tests/fork_big2.pl2
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, &not_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, &not_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, &not_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
{