summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <monty@mishka.local>2004-09-15 22:36:57 +0300
committerunknown <monty@mishka.local>2004-09-15 22:36:57 +0300
commit4ff57e80f745412b9e4cea67fb51ad3ecd75995f (patch)
treec54782bf59455786d3d6b7abf02e40aaac69b1ff
parent8267fd7a714f27473a017f37b279452f0628985f (diff)
parent50226162fd5b1fa6f22238c62b62ce7426b30cfa (diff)
downloadmariadb-git-4ff57e80f745412b9e4cea67fb51ad3ecd75995f.tar.gz
Merge
BitKeeper/etc/logging_ok: auto-union sql/ha_berkeley.cc: Auto merged sql/ha_heap.cc: Auto merged sql/ha_innodb.cc: Auto merged sql/ha_myisam.cc: Auto merged sql/ha_ndbcluster.cc: Auto merged sql/handler.cc: Auto merged sql/mysql_priv.h: Auto merged sql/mysqld.cc: Auto merged sql/sql_class.cc: Auto merged sql/sql_help.cc: Auto merged sql/sql_insert.cc: Auto merged sql/sql_lex.cc: Auto merged sql/sql_table.cc: Auto merged sql/sql_class.h: SCCS merged sql/sql_parse.cc: SCCS merged
-rw-r--r--.bzrignore1
-rw-r--r--BitKeeper/etc/logging_ok2
-rw-r--r--include/my_sys.h6
-rw-r--r--include/mysqld_error.h7
-rw-r--r--libmysqld/Makefile.am2
-rw-r--r--mysql-test/r/lowercase_view.result24
-rw-r--r--mysql-test/r/merge.result2
-rw-r--r--mysql-test/r/sp-error.result9
-rw-r--r--mysql-test/r/sp.result29
-rw-r--r--mysql-test/r/trigger.result171
-rw-r--r--mysql-test/r/view.result49
-rw-r--r--mysql-test/t/lowercase_view-master.opt1
-rw-r--r--mysql-test/t/lowercase_view.test34
-rw-r--r--mysql-test/t/merge.test2
-rw-r--r--mysql-test/t/sp-error.test18
-rw-r--r--mysql-test/t/sp.test34
-rw-r--r--mysql-test/t/trigger.test195
-rw-r--r--mysql-test/t/view.test41
-rw-r--r--mysys/default.c6
-rw-r--r--scripts/mysql_fix_privilege_tables.sql12
-rw-r--r--sql/Makefile.am4
-rw-r--r--sql/filesort.cc10
-rw-r--r--sql/ha_berkeley.cc38
-rw-r--r--sql/ha_heap.cc26
-rw-r--r--sql/ha_innodb.cc27
-rw-r--r--sql/ha_isam.cc30
-rw-r--r--sql/ha_isammrg.cc9
-rw-r--r--sql/ha_myisam.cc31
-rw-r--r--sql/ha_myisammrg.cc28
-rw-r--r--sql/ha_ndbcluster.cc28
-rw-r--r--sql/handler.cc14
-rw-r--r--sql/item.cc117
-rw-r--r--sql/item.h56
-rw-r--r--sql/item_func.cc15
-rw-r--r--sql/item_func.h11
-rw-r--r--sql/item_strfunc.cc7
-rw-r--r--sql/item_subselect.cc59
-rw-r--r--sql/item_subselect.h2
-rw-r--r--sql/item_sum.cc2
-rw-r--r--sql/lex.h2
-rw-r--r--sql/mysql_priv.h33
-rw-r--r--sql/mysqld.cc294
-rw-r--r--sql/net_serv.cc15
-rw-r--r--sql/parse_file.cc15
-rw-r--r--sql/parse_file.h3
-rw-r--r--sql/protocol_cursor.cc3
-rw-r--r--sql/share/czech/errmsg.txt5
-rw-r--r--sql/share/danish/errmsg.txt5
-rw-r--r--sql/share/dutch/errmsg.txt5
-rw-r--r--sql/share/english/errmsg.txt5
-rw-r--r--sql/share/estonian/errmsg.txt5
-rw-r--r--sql/share/french/errmsg.txt5
-rw-r--r--sql/share/german/errmsg.txt5
-rw-r--r--sql/share/greek/errmsg.txt5
-rw-r--r--sql/share/hungarian/errmsg.txt5
-rw-r--r--sql/share/italian/errmsg.txt5
-rw-r--r--sql/share/japanese/errmsg.txt5
-rw-r--r--sql/share/korean/errmsg.txt5
-rw-r--r--sql/share/norwegian-ny/errmsg.txt5
-rw-r--r--sql/share/norwegian/errmsg.txt5
-rw-r--r--sql/share/polish/errmsg.txt5
-rw-r--r--sql/share/portuguese/errmsg.txt5
-rw-r--r--sql/share/romanian/errmsg.txt5
-rw-r--r--sql/share/russian/errmsg.txt7
-rw-r--r--sql/share/serbian/errmsg.txt5
-rw-r--r--sql/share/slovak/errmsg.txt5
-rw-r--r--sql/share/spanish/errmsg.txt5
-rw-r--r--sql/share/swedish/errmsg.txt5
-rw-r--r--sql/share/ukrainian/errmsg.txt5
-rw-r--r--sql/sp_head.cc142
-rw-r--r--sql/sp_head.h77
-rw-r--r--sql/sp_rcontext.cc30
-rw-r--r--sql/sp_rcontext.h2
-rw-r--r--sql/sql_base.cc114
-rw-r--r--sql/sql_class.cc47
-rw-r--r--sql/sql_class.h63
-rw-r--r--sql/sql_delete.cc14
-rw-r--r--sql/sql_handler.cc6
-rw-r--r--sql/sql_insert.cc14
-rw-r--r--sql/sql_lex.cc8
-rw-r--r--sql/sql_lex.h29
-rw-r--r--sql/sql_parse.cc230
-rw-r--r--sql/sql_select.cc36
-rw-r--r--sql/sql_show.cc43
-rw-r--r--sql/sql_table.cc10
-rw-r--r--sql/sql_test.cc12
-rw-r--r--sql/sql_trigger.cc433
-rw-r--r--sql/sql_trigger.h62
-rw-r--r--sql/sql_union.cc2
-rw-r--r--sql/sql_update.cc15
-rw-r--r--sql/sql_view.cc102
-rw-r--r--sql/sql_yacc.yy314
-rw-r--r--sql/structs.h3
-rw-r--r--sql/table.cc30
-rw-r--r--sql/table.h11
95 files changed, 2881 insertions, 609 deletions
diff --git a/.bzrignore b/.bzrignore
index be7211af9e2..1feab85d33d 100644
--- a/.bzrignore
+++ b/.bzrignore
@@ -440,6 +440,7 @@ libmysqld/sql_state.c
libmysqld/sql_string.cc
libmysqld/sql_table.cc
libmysqld/sql_test.cc
+libmysqld/sql_trigger.cc
libmysqld/sql_udf.cc
libmysqld/sql_union.cc
libmysqld/sql_unions.cc
diff --git a/BitKeeper/etc/logging_ok b/BitKeeper/etc/logging_ok
index f29057f1d38..abff7bb08e9 100644
--- a/BitKeeper/etc/logging_ok
+++ b/BitKeeper/etc/logging_ok
@@ -64,6 +64,7 @@ igor@rurik.mysql.com
ingo@mysql.com
jan@hundin.mysql.fi
jani@a80-186-24-72.elisa-laajakaista.fi
+jani@a80-186-8-224.elisa-laajakaista.fi
jani@dsl-jkl1657.dial.inet.fi
jani@dsl-kpogw4gb5.dial.inet.fi
jani@hynda.(none)
@@ -151,6 +152,7 @@ pem@per-erik-martins-dator.local
peter@linux.local
peter@mysql.com
peterg@mysql.com
+petr@mysql.com
pgulutzan@linux.local
pmartin@build.mysql2.com
psergey@psergey-rh8.(none)
diff --git a/include/my_sys.h b/include/my_sys.h
index 0d722a899f6..cc40b7a7693 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -738,7 +738,7 @@ extern void my_free_lock(byte *ptr,myf flags);
#define my_free_lock(A,B) my_free((A),(B))
#endif
#define alloc_root_inited(A) ((A)->min_malloc != 0)
-#define clear_alloc_root(A) { (A)->free= (A)->used= (A)->pre_alloc= 0; }
+#define clear_alloc_root(A) bzero((void *) (A), sizeof(MEM_ROOT))
extern void init_alloc_root(MEM_ROOT *mem_root, uint block_size,
uint pre_alloc_size);
extern gptr alloc_root(MEM_ROOT *mem_root,unsigned int Size);
@@ -788,6 +788,10 @@ extern void add_compiled_collation(CHARSET_INFO *cs);
extern ulong escape_string_for_mysql(CHARSET_INFO *charset_info, char *to,
const char *from, ulong length);
+extern void thd_increment_bytes_sent(ulong length);
+extern void thd_increment_bytes_received(ulong length);
+extern void thd_increment_net_big_packet_count(ulong length);
+
#ifdef __WIN__
extern my_bool have_tcpip; /* Is set if tcpip is used */
#endif
diff --git a/include/mysqld_error.h b/include/mysqld_error.h
index 125a39b2249..cf032380e2f 100644
--- a/include/mysqld_error.h
+++ b/include/mysqld_error.h
@@ -375,4 +375,9 @@
#define ER_VIEW_INVALID 1356
#define ER_SP_NO_DROP_SP 1357
#define ER_SP_GOTO_IN_HNDLR 1358
-#define ER_ERROR_MESSAGES 359
+#define ER_TRG_ALREADY_EXISTS 1359
+#define ER_TRG_DOES_NOT_EXIST 1360
+#define ER_TRG_ON_VIEW_OR_TEMP_TABLE 1361
+#define ER_TRG_CANT_CHANGE_ROW 1362
+#define ER_TRG_NO_SUCH_ROW_IN_TRG 1363
+#define ER_ERROR_MESSAGES 364
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index f0cda9ae524..56762f5771e 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -59,7 +59,7 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.cc \
spatial.cc gstream.cc sql_help.cc tztime.cc protocol_cursor.cc \
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
- parse_file.cc sql_view.cc
+ parse_file.cc sql_view.cc sql_trigger.cc
libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources)
libmysqld_a_SOURCES=
diff --git a/mysql-test/r/lowercase_view.result b/mysql-test/r/lowercase_view.result
new file mode 100644
index 00000000000..51f7dc758eb
--- /dev/null
+++ b/mysql-test/r/lowercase_view.result
@@ -0,0 +1,24 @@
+drop table if exists t1Aa,t2Aa,v1Aa,v2Aa;
+drop view if exists t1Aa,t2Aa,v1Aa,v2Aa;
+drop database if exists MySQLTest;
+create database MySQLTest;
+use MySQLTest;
+create table TaB (Field int);
+create view ViE as select * from TAb;
+show create table VIe;
+Table Create Table
+vie CREATE VIEW `mysqltest`.`vie` AS select `mysqltest`.`tab`.`Field` AS `Field` from `mysqltest`.`tab`
+drop database MySQLTest;
+use test;
+create table t1Aa (col1 int);
+create table t2Aa (col1 int);
+create view v1Aa as select * from t1Aa;
+create view v2Aa as select * from v1Aa;
+update v2aA set col1 = (select max(col1) from v1aA);
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+delete from v2aA where col1 = (select max(col1) from v1aA);
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+insert into v2aA values ((select max(col1) from v1aA));
+ERROR HY000: You can't specify target table 'v2aa' for update in FROM clause
+drop view v2Aa,v1Aa;
+drop table t1Aa,t2Aa;
diff --git a/mysql-test/r/merge.result b/mysql-test/r/merge.result
index 5755033190b..7334d5acf4d 100644
--- a/mysql-test/r/merge.result
+++ b/mysql-test/r/merge.result
@@ -650,4 +650,6 @@ create table t3 engine=merge union=(t1, t2) select * from t1;
ERROR HY000: You can't specify target table 't1' for update in FROM clause
create table t3 engine=merge union=(t1, t2) select * from t2;
ERROR HY000: You can't specify target table 't2' for update in FROM clause
+create table t3 engine=merge union=(t1, t2) select (select max(a) from t2);
+ERROR HY000: You can't specify target table 't2' for update in FROM clause
drop table t1, t2;
diff --git a/mysql-test/r/sp-error.result b/mysql-test/r/sp-error.result
index 55c34ca471f..540a5652197 100644
--- a/mysql-test/r/sp-error.result
+++ b/mysql-test/r/sp-error.result
@@ -485,4 +485,13 @@ create procedure bug4344() drop procedure bug4344|
ERROR HY000: Can't drop a PROCEDURE from within another stored routine
create procedure bug4344() drop function bug4344|
ERROR HY000: Can't drop a FUNCTION from within another stored routine
+drop procedure if exists bug3294|
+create procedure bug3294()
+begin
+declare continue handler for sqlexception drop table t5;
+drop table t5;
+end|
+call bug3294()|
+ERROR 42S02: Unknown table 't5'
+drop procedure bug3294|
drop table t1|
diff --git a/mysql-test/r/sp.result b/mysql-test/r/sp.result
index f0f51945f36..f84b224b8e0 100644
--- a/mysql-test/r/sp.result
+++ b/mysql-test/r/sp.result
@@ -1820,6 +1820,35 @@ Ok
Ok
drop procedure bug5258|
drop procedure bug5258_aux|
+create function bug4487() returns char
+begin
+declare v char;
+return v;
+end|
+Warnings:
+Warning 1311 Referring to uninitialized variable v
+select bug4487()|
+bug4487()
+NULL
+Warnings:
+Warning 1311 Referring to uninitialized variable v
+drop function bug4487|
+drop procedure if exists bug4941|
+create procedure bug4941(out x int)
+begin
+declare c cursor for select i from t2 limit 1;
+open c;
+fetch c into x;
+close c;
+end|
+insert into t2 values (null, null, null)|
+set @x = 42|
+call bug4941(@x)|
+select @x|
+@x
+NULL
+delete from t1|
+drop procedure bug4941|
drop table if exists fac|
create table fac (n int unsigned not null primary key, f bigint unsigned)|
create procedure ifac(n int unsigned)
diff --git a/mysql-test/r/trigger.result b/mysql-test/r/trigger.result
new file mode 100644
index 00000000000..a7a845fa3e0
--- /dev/null
+++ b/mysql-test/r/trigger.result
@@ -0,0 +1,171 @@
+drop table if exists t1, t2;
+drop view if exists v1;
+create table t1 (i int);
+create trigger trg before insert on t1 for each row set @a:=1;
+set @a:=0;
+select @a;
+@a
+0
+insert into t1 values (1);
+select @a;
+@a
+1
+drop trigger t1.trg;
+create trigger trg before insert on t1 for each row set @a:=new.i;
+insert into t1 values (123);
+select @a;
+@a
+123
+drop trigger t1.trg;
+drop table t1;
+create table t1 (i int not null, j int);
+create trigger trg before insert on t1 for each row
+begin
+if isnull(new.j) then
+set new.j:= new.i * 10;
+end if;
+end|
+insert into t1 (i) values (1)|
+insert into t1 (i,j) values (2, 3)|
+select * from t1|
+i j
+1 10
+2 3
+drop trigger t1.trg|
+drop table t1|
+create table t1 (i int not null primary key);
+create trigger trg after insert on t1 for each row
+set @a:= if(@a,concat(@a, ":", new.i), new.i);
+set @a:="";
+insert into t1 values (2),(3),(4),(5);
+select @a;
+@a
+2:3:4:5
+drop trigger t1.trg;
+drop table t1;
+create table t1 (aid int not null primary key, balance int not null default 0);
+insert into t1 values (1, 1000), (2,3000);
+create trigger trg before update on t1 for each row
+begin
+declare loc_err varchar(255);
+if abs(new.balance - old.balance) > 1000 then
+set new.balance:= old.balance;
+set loc_err := concat("Too big change for aid = ", new.aid);
+set @update_failed:= if(@update_failed, concat(@a, ":", loc_err), loc_err);
+end if;
+end|
+set @update_failed:=""|
+update t1 set balance=1500|
+select @update_failed;
+select * from t1|
+@update_failed
+Too big change for aid = 2
+aid balance
+1 1500
+2 3000
+drop trigger t1.trg|
+drop table t1|
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg after update on t1 for each row
+set @total_change:=@total_change + new.i - old.i;
+set @total_change:=0;
+update t1 set i=3;
+select @total_change;
+@total_change
+2
+drop trigger t1.trg;
+drop table t1;
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg before delete on t1 for each row
+set @del_sum:= @del_sum + old.i;
+set @del_sum:= 0;
+delete from t1 where i <= 3;
+select @del_sum;
+@del_sum
+6
+drop trigger t1.trg;
+drop table t1;
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg after delete on t1 for each row set @del:= 1;
+set @del:= 0;
+delete from t1 where i <> 0;
+select @del;
+@del
+1
+drop trigger t1.trg;
+drop table t1;
+create table t1 (i int, j int);
+create trigger trg1 before insert on t1 for each row
+begin
+if new.j > 10 then
+set new.j := 10;
+end if;
+end|
+create trigger trg2 before update on t1 for each row
+begin
+if old.i % 2 = 0 then
+set new.j := -1;
+end if;
+end|
+create trigger trg3 after update on t1 for each row
+begin
+if new.j = -1 then
+set @fired:= "Yes";
+end if;
+end|
+set @fired:="";
+insert into t1 values (1,2),(2,3),(3,14);
+select @fired;
+@fired
+
+select * from t1;
+i j
+1 2
+2 3
+3 10
+update t1 set j= 20;
+select @fired;
+@fired
+Yes
+select * from t1;
+i j
+1 20
+2 -1
+3 20
+drop trigger t1.trg1;
+drop trigger t1.trg2;
+drop trigger t1.trg3;
+drop table t1;
+create table t1 (i int);
+create trigger trg before insert on t1 for each row set @a:= old.i;
+ERROR HY000: There is no OLD row in on INSERT trigger
+create trigger trg before delete on t1 for each row set @a:= new.i;
+ERROR HY000: There is no NEW row in on DELETE trigger
+create trigger trg before update on t1 for each row set old.i:=1;
+ERROR HY000: Updating of OLD row is not allowed in trigger
+create trigger trg before delete on t1 for each row set new.i:=1;
+ERROR HY000: There is no NEW row in on DELETE trigger
+create trigger trg after update on t1 for each row set new.i:=1;
+ERROR HY000: Updating of NEW row is not allowed in after trigger
+create trigger trg before insert on t2 for each row set @a:=1;
+ERROR 42S02: Table 'test.t2' doesn't exist
+create trigger trg before insert on t1 for each row set @a:=1;
+create trigger trg after insert on t1 for each row set @a:=1;
+ERROR HY000: Trigger already exists
+create trigger trg2 before insert on t1 for each row set @a:=1;
+ERROR HY000: Trigger already exists
+drop trigger t1.trg;
+drop trigger t1.trg;
+ERROR HY000: Trigger does not exist
+create view v1 as select * from t1;
+create trigger trg before insert on v1 for each row set @a:=1;
+ERROR HY000: Trigger's 'v1' is view or temporary table
+drop view v1;
+drop table t1;
+create temporary table t1 (i int);
+create trigger trg before insert on t1 for each row set @a:=1;
+ERROR HY000: Trigger's 't1' is view or temporary table
+drop table t1;
diff --git a/mysql-test/r/view.result b/mysql-test/r/view.result
index 572db8a7324..2551977200e 100644
--- a/mysql-test/r/view.result
+++ b/mysql-test/r/view.result
@@ -55,7 +55,7 @@ Note 1003 select (`test`.`t1`.`b` + 1) AS `c` from `test`.`v1`
create algorithm=temptable view v2 (c) as select b+1 from t1;
show create table v2;
Table Create Table
-v2 CREATE ALGORITHM=TMPTABLE VIEW `test`.`v2` AS select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1`
+v2 CREATE ALGORITHM=TEMPTABLE VIEW `test`.`v2` AS select (`test`.`t1`.`b` + 1) AS `c` from `test`.`t1`
select c from v2;
c
3
@@ -313,7 +313,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
show create table mysqltest.v2;
Table Create Table
-v2 CREATE ALGORITHM=TMPTABLE VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1`
+v2 CREATE ALGORITHM=TEMPTABLE VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1`
explain select c from mysqltest.v3;
ERROR HY000: EXPLAIN/SHOW can not be issued; lacking privileges for underlying table
show create table mysqltest.v3;
@@ -335,7 +335,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
show create table mysqltest.v2;
Table Create Table
-v2 CREATE ALGORITHM=TMPTABLE VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1`
+v2 CREATE ALGORITHM=TEMPTABLE VIEW `mysqltest`.`v2` AS select (`mysqltest`.`t1`.`a` + 1) AS `c`,(`mysqltest`.`t1`.`b` + 1) AS `d` from `mysqltest`.`t1`
explain select c from mysqltest.v3;
id select_type table type possible_keys key key_len ref rows Extra
1 PRIMARY t2 system NULL NULL NULL NULL 0 const row not found
@@ -348,7 +348,7 @@ id select_type table type possible_keys key key_len ref rows Extra
2 DERIVED NULL NULL NULL NULL NULL NULL NULL no matching row in const table
show create table mysqltest.v4;
Table Create Table
-v4 CREATE ALGORITHM=TMPTABLE VIEW `mysqltest`.`v4` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2`
+v4 CREATE ALGORITHM=TEMPTABLE VIEW `mysqltest`.`v4` AS select (`mysqltest`.`t2`.`a` + 1) AS `c`,(`mysqltest`.`t2`.`b` + 1) AS `d` from `mysqltest`.`t2`
revoke all privileges on mysqltest.* from mysqltest_1@localhost;
delete from mysql.user where user='mysqltest_1';
drop database mysqltest;
@@ -1270,3 +1270,44 @@ s1
7
drop view v1;
drop table t1;
+create table t1 (col1 int);
+create table t2 (col1 int);
+create view v1 as select * from t1;
+create view v2 as select * from v1;
+update v2 set col1 = (select max(col1) from v1);
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+delete from v2 where col1 = (select max(col1) from v1);
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+insert into v2 values ((select max(col1) from v1));
+ERROR HY000: You can't specify target table 'v2' for update in FROM clause
+drop view v2,v1;
+drop table t1,t2;
+create table t1 (s1 int);
+create view v1 as select * from t1;
+handler v1 open as xx;
+ERROR HY000: 'test.v1' is not BASE TABLE
+drop view v1;
+drop table t1;
+create table t1(a int);
+insert into t1 values (0), (1), (2), (3);
+create table t2 (a int);
+insert into t2 select a from t1 where a > 1;
+create view v1 as select a from t1 where a > 1;
+select * from t1 left join (t2 as t, v1) on v1.a=t1.a;
+a a a
+0 NULL NULL
+1 NULL NULL
+2 2 2
+2 3 2
+3 2 3
+3 3 3
+select * from t1 left join (t2 as t, t2) on t2.a=t1.a;
+a a a
+0 NULL NULL
+1 NULL NULL
+2 2 2
+2 3 2
+3 2 3
+3 3 3
+drop view v1;
+drop table t1;
diff --git a/mysql-test/t/lowercase_view-master.opt b/mysql-test/t/lowercase_view-master.opt
new file mode 100644
index 00000000000..62ab6dad1e0
--- /dev/null
+++ b/mysql-test/t/lowercase_view-master.opt
@@ -0,0 +1 @@
+--lower_case_table_names=1
diff --git a/mysql-test/t/lowercase_view.test b/mysql-test/t/lowercase_view.test
new file mode 100644
index 00000000000..2a2757650ae
--- /dev/null
+++ b/mysql-test/t/lowercase_view.test
@@ -0,0 +1,34 @@
+--disable_warnings
+drop table if exists t1Aa,t2Aa,v1Aa,v2Aa;
+drop view if exists t1Aa,t2Aa,v1Aa,v2Aa;
+drop database if exists MySQLTest;
+--enable_warnings
+
+#
+# different cases in VIEW
+#
+create database MySQLTest;
+use MySQLTest;
+create table TaB (Field int);
+create view ViE as select * from TAb;
+show create table VIe;
+drop database MySQLTest;
+use test;
+
+#
+# test of updating and fetching from the same table check
+#
+create table t1Aa (col1 int);
+create table t2Aa (col1 int);
+create view v1Aa as select * from t1Aa;
+create view v2Aa as select * from v1Aa;
+-- error 1093
+update v2aA set col1 = (select max(col1) from v1aA);
+#update v2aA,t2aA set v2aA.col1 = (select max(col1) from v1aA) where v2aA.col1 = t2aA.col1;
+-- error 1093
+delete from v2aA where col1 = (select max(col1) from v1aA);
+#delete v2aA from v2aA,t2aA where (select max(col1) from v1aA) > 0 and v2aA.col1 = t2aA.col1;
+-- error 1093
+insert into v2aA values ((select max(col1) from v1aA));
+drop view v2Aa,v1Aa;
+drop table t1Aa,t2Aa;
diff --git a/mysql-test/t/merge.test b/mysql-test/t/merge.test
index 9580c1ab44c..9d367260049 100644
--- a/mysql-test/t/merge.test
+++ b/mysql-test/t/merge.test
@@ -284,4 +284,6 @@ insert into t2 values (1);
create table t3 engine=merge union=(t1, t2) select * from t1;
--error 1093
create table t3 engine=merge union=(t1, t2) select * from t2;
+--error 1093
+create table t3 engine=merge union=(t1, t2) select (select max(a) from t2);
drop table t1, t2;
diff --git a/mysql-test/t/sp-error.test b/mysql-test/t/sp-error.test
index 32c146141b5..46700293578 100644
--- a/mysql-test/t/sp-error.test
+++ b/mysql-test/t/sp-error.test
@@ -5,7 +5,7 @@
# Make sure we don't have any procedures left.
delete from mysql.proc;
-# A test "global" procedures, i.e. not belonging to any database.
+# A test of "global" procedures, i.e. not belonging to any database.
create function .f1() returns int return 1;
create procedure .p1() select 1, database();
create procedure p1() select 2, database();
@@ -650,6 +650,22 @@ create procedure bug4344() drop procedure bug4344|
--error 1357
create procedure bug4344() drop function bug4344|
+#
+# BUG#3294: Stored procedure crash if table dropped before use
+# (Actually, when an error occurs within an error handler.)
+--disable_warnings
+drop procedure if exists bug3294|
+--enable_warnings
+create procedure bug3294()
+begin
+ declare continue handler for sqlexception drop table t5;
+ drop table t5;
+end|
+
+--error 1051
+call bug3294()|
+drop procedure bug3294|
+
drop table t1|
diff --git a/mysql-test/t/sp.test b/mysql-test/t/sp.test
index 05d38d25956..e2c82c9f0da 100644
--- a/mysql-test/t/sp.test
+++ b/mysql-test/t/sp.test
@@ -1987,6 +1987,40 @@ call bug5258_aux()|
drop procedure bug5258|
drop procedure bug5258_aux|
+#
+# BUG#4487: Stored procedure connection aborted if uninitialized char
+#
+create function bug4487() returns char
+begin
+ declare v char;
+ return v;
+end|
+
+select bug4487()|
+drop function bug4487|
+
+
+#
+# BUG#4941: Stored procedure crash fetching null value into variable.
+#
+--disable_warnings
+drop procedure if exists bug4941|
+--enable_warnings
+create procedure bug4941(out x int)
+begin
+ declare c cursor for select i from t2 limit 1;
+ open c;
+ fetch c into x;
+ close c;
+end|
+
+insert into t2 values (null, null, null)|
+set @x = 42|
+call bug4941(@x)|
+select @x|
+delete from t1|
+drop procedure bug4941|
+
#
# Some "real" examples
diff --git a/mysql-test/t/trigger.test b/mysql-test/t/trigger.test
new file mode 100644
index 00000000000..8922f73661e
--- /dev/null
+++ b/mysql-test/t/trigger.test
@@ -0,0 +1,195 @@
+#
+# Basic triggers test
+#
+
+--disable_warnings
+drop table if exists t1, t2;
+drop view if exists v1;
+--enable_warnings
+
+create table t1 (i int);
+
+# let us test some very simple trigger
+create trigger trg before insert on t1 for each row set @a:=1;
+set @a:=0;
+select @a;
+insert into t1 values (1);
+select @a;
+drop trigger t1.trg;
+
+# let us test simple trigger reading some values
+create trigger trg before insert on t1 for each row set @a:=new.i;
+insert into t1 values (123);
+select @a;
+drop trigger t1.trg;
+
+drop table t1;
+
+# Let us test before insert trigger
+# Such triggers can be used for setting complex default values
+create table t1 (i int not null, j int);
+delimiter |;
+create trigger trg before insert on t1 for each row
+begin
+ if isnull(new.j) then
+ set new.j:= new.i * 10;
+ end if;
+end|
+insert into t1 (i) values (1)|
+insert into t1 (i,j) values (2, 3)|
+select * from t1|
+drop trigger t1.trg|
+drop table t1|
+delimiter ;|
+
+# After insert trigger
+# Useful for aggregating data
+create table t1 (i int not null primary key);
+create trigger trg after insert on t1 for each row
+ set @a:= if(@a,concat(@a, ":", new.i), new.i);
+set @a:="";
+insert into t1 values (2),(3),(4),(5);
+select @a;
+drop trigger t1.trg;
+drop table t1;
+
+# Before update trigger
+# (In future we will achieve this via proper error handling in triggers)
+create table t1 (aid int not null primary key, balance int not null default 0);
+insert into t1 values (1, 1000), (2,3000);
+delimiter |;
+create trigger trg before update on t1 for each row
+begin
+ declare loc_err varchar(255);
+ if abs(new.balance - old.balance) > 1000 then
+ set new.balance:= old.balance;
+ set loc_err := concat("Too big change for aid = ", new.aid);
+ set @update_failed:= if(@update_failed, concat(@a, ":", loc_err), loc_err);
+ end if;
+end|
+set @update_failed:=""|
+update t1 set balance=1500|
+select @update_failed;
+select * from t1|
+drop trigger t1.trg|
+drop table t1|
+delimiter ;|
+
+# After update trigger
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg after update on t1 for each row
+ set @total_change:=@total_change + new.i - old.i;
+set @total_change:=0;
+update t1 set i=3;
+select @total_change;
+drop trigger t1.trg;
+drop table t1;
+
+# Before delete trigger
+# This can be used for aggregation too :)
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg before delete on t1 for each row
+ set @del_sum:= @del_sum + old.i;
+set @del_sum:= 0;
+delete from t1 where i <= 3;
+select @del_sum;
+drop trigger t1.trg;
+drop table t1;
+
+# After delete trigger.
+# Just run out of imagination.
+create table t1 (i int);
+insert into t1 values (1),(2),(3),(4);
+create trigger trg after delete on t1 for each row set @del:= 1;
+set @del:= 0;
+delete from t1 where i <> 0;
+select @del;
+drop trigger t1.trg;
+drop table t1;
+
+# Several triggers on one table
+create table t1 (i int, j int);
+
+delimiter |;
+create trigger trg1 before insert on t1 for each row
+begin
+ if new.j > 10 then
+ set new.j := 10;
+ end if;
+end|
+create trigger trg2 before update on t1 for each row
+begin
+ if old.i % 2 = 0 then
+ set new.j := -1;
+ end if;
+end|
+create trigger trg3 after update on t1 for each row
+begin
+ if new.j = -1 then
+ set @fired:= "Yes";
+ end if;
+end|
+delimiter ;|
+set @fired:="";
+insert into t1 values (1,2),(2,3),(3,14);
+select @fired;
+select * from t1;
+update t1 set j= 20;
+select @fired;
+select * from t1;
+
+drop trigger t1.trg1;
+drop trigger t1.trg2;
+drop trigger t1.trg3;
+drop table t1;
+
+
+#
+# Test of wrong column specifiers in triggers
+#
+create table t1 (i int);
+
+--error 1363
+create trigger trg before insert on t1 for each row set @a:= old.i;
+--error 1363
+create trigger trg before delete on t1 for each row set @a:= new.i;
+--error 1362
+create trigger trg before update on t1 for each row set old.i:=1;
+--error 1363
+create trigger trg before delete on t1 for each row set new.i:=1;
+--error 1362
+create trigger trg after update on t1 for each row set new.i:=1;
+# TODO: We should also test wrong field names here, we don't do it now
+# because proper error handling is not in place yet.
+
+
+#
+# Let us test various trigger creation errors
+#
+#
+--error 1146
+create trigger trg before insert on t2 for each row set @a:=1;
+
+create trigger trg before insert on t1 for each row set @a:=1;
+--error 1359
+create trigger trg after insert on t1 for each row set @a:=1;
+--error 1359
+create trigger trg2 before insert on t1 for each row set @a:=1;
+drop trigger t1.trg;
+
+--error 1360
+drop trigger t1.trg;
+
+create view v1 as select * from t1;
+--error 1361
+create trigger trg before insert on v1 for each row set @a:=1;
+drop view v1;
+
+drop table t1;
+
+create temporary table t1 (i int);
+--error 1361
+create trigger trg before insert on t1 for each row set @a:=1;
+drop table t1;
diff --git a/mysql-test/t/view.test b/mysql-test/t/view.test
index 7d05dcb9ef8..682646a6c02 100644
--- a/mysql-test/t/view.test
+++ b/mysql-test/t/view.test
@@ -1230,3 +1230,44 @@ insert into v1 values (1) on duplicate key update s1 = 7;
select * from t1;
drop view v1;
drop table t1;
+
+#
+# test of updating and fetching from the same table check
+#
+create table t1 (col1 int);
+create table t2 (col1 int);
+create view v1 as select * from t1;
+create view v2 as select * from v1;
+-- error 1093
+update v2 set col1 = (select max(col1) from v1);
+#update v2,t2 set v2.col1 = (select max(col1) from v1) where v2.col1 = t2.col1;
+-- error 1093
+delete from v2 where col1 = (select max(col1) from v1);
+#delete v2 from v2,t2 where (select max(col1) from v1) > 0 and v2.col1 = t2.col1;
+-- error 1093
+insert into v2 values ((select max(col1) from v1));
+drop view v2,v1;
+drop table t1,t2;
+
+#
+# HANDLER with VIEW
+#
+create table t1 (s1 int);
+create view v1 as select * from t1;
+-- error 1347
+handler v1 open as xx;
+drop view v1;
+drop table t1;
+
+#
+# view with WHERE in nested join
+#
+create table t1(a int);
+insert into t1 values (0), (1), (2), (3);
+create table t2 (a int);
+insert into t2 select a from t1 where a > 1;
+create view v1 as select a from t1 where a > 1;
+select * from t1 left join (t2 as t, v1) on v1.a=t1.a;
+select * from t1 left join (t2 as t, t2) on t2.a=t1.a;
+drop view v1;
+drop table t1;
diff --git a/mysys/default.c b/mysys/default.c
index a8343c6a21d..198a6402b8b 100644
--- a/mysys/default.c
+++ b/mysys/default.c
@@ -119,8 +119,6 @@ static int search_files(const char *conf_file, int *argc, char ***argv,
int error= 0;
DBUG_ENTER("search_files");
- args_used= 0;
-
/* Check if we want to force the use a specific default file */
forced_default_file= 0;
if (*argc >= 2)
@@ -128,12 +126,12 @@ static int search_files(const char *conf_file, int *argc, char ***argv,
if (is_prefix(argv[0][1],"--defaults-file="))
{
forced_default_file= strchr(argv[0][1],'=') + 1;
- *args_used++;
+ (*args_used)++;
}
else if (is_prefix(argv[0][1],"--defaults-extra-file="))
{
defaults_extra_file= strchr(argv[0][1],'=') + 1;
- *args_used++;
+ (*args_used)++;
}
}
diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql
index 18dfe14bc45..5b335862584 100644
--- a/scripts/mysql_fix_privilege_tables.sql
+++ b/scripts/mysql_fix_privilege_tables.sql
@@ -144,6 +144,13 @@ alter table user comment='Users and global privileges';
alter table func comment='User defined functions';
alter table tables_priv comment='Table privileges';
alter table columns_priv comment='Column privileges';
+
+#
+# Detect whether we had Create_view_priv
+#
+SET @hadCreateViewPriv:=0;
+SELECT @hadCreateViewPriv:=1 FROM user WHERE Create_view_priv LIKE '%';
+
#
# Create VIEWs privileges (v5.0)
#
@@ -159,6 +166,11 @@ ALTER TABLE host ADD Show_view_priv enum('N','Y') DEFAULT 'N' NOT NULL AFTER Cre
ALTER TABLE user ADD Show_view_priv enum('N','Y') DEFAULT 'N' NOT NULL AFTER Create_view_priv;
#
+# Assign create/show view privileges to people who have create provileges
+#
+UPDATE user SET Create_view_priv=Create_priv, Show_view_priv=Create_priv where user<>"" AND @hadCreateViewPriv = 0;
+
+#
# Create some possible missing tables
#
CREATE TABLE IF NOT EXISTS help_topic (
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 7a55367c717..2c99d42f3ee 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -61,7 +61,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
spatial.h gstream.h client_settings.h tzfile.h \
tztime.h \
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
- parse_file.h sql_view.h \
+ parse_file.h sql_view.h sql_trigger.h \
examples/ha_example.h examples/ha_archive.h \
examples/ha_tina.h
@@ -97,7 +97,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc \
gstream.cc spatial.cc sql_help.cc protocol_cursor.cc \
tztime.cc my_time.c \
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
- sp_cache.cc parse_file.cc \
+ sp_cache.cc parse_file.cc sql_trigger.cc \
examples/ha_example.cc examples/ha_archive.cc \
examples/ha_tina.cc
gen_lex_hash_SOURCES = gen_lex_hash.cc
diff --git a/sql/filesort.cc b/sql/filesort.cc
index fe2b3850197..ef8148616e5 100644
--- a/sql/filesort.cc
+++ b/sql/filesort.cc
@@ -163,11 +163,11 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (select && select->quick)
{
- statistic_increment(filesort_range_count, &LOCK_status);
+ statistic_increment(thd->status_var.filesort_range_count, &LOCK_status);
}
else
{
- statistic_increment(filesort_scan_count, &LOCK_status);
+ statistic_increment(thd->status_var.filesort_scan_count, &LOCK_status);
}
#ifdef CAN_TRUST_RANGE
if (select && select->quick && select->quick->records > 0L)
@@ -280,7 +280,8 @@ ha_rows filesort(THD *thd, TABLE *table, SORT_FIELD *sortorder, uint s_length,
if (error)
my_error(ER_FILSORT_ABORT,MYF(ME_ERROR+ME_WAITTANG));
else
- statistic_add(filesort_rows, (ulong) records, &LOCK_status);
+ statistic_add(thd->status_var.filesort_rows,
+ (ulong) records, &LOCK_status);
*examined_rows= param.examined_rows;
#ifdef SKIP_DBUG_IN_FILESORT
DBUG_POP(); /* Ok to DBUG */
@@ -874,7 +875,8 @@ int merge_buffers(SORTPARAM *param, IO_CACHE *from_file,
THD::killed_state not_killable;
DBUG_ENTER("merge_buffers");
- statistic_increment(filesort_merge_passes, &LOCK_status);
+ statistic_increment(current_thd->status_var.filesort_merge_passes,
+ &LOCK_status);
if (param->not_killable)
{
killed= &not_killable;
diff --git a/sql/ha_berkeley.cc b/sql/ha_berkeley.cc
index 9f93437bc32..bbe73ee8674 100644
--- a/sql/ha_berkeley.cc
+++ b/sql/ha_berkeley.cc
@@ -855,7 +855,7 @@ int ha_berkeley::write_row(byte * record)
int error;
DBUG_ENTER("write_row");
- statistic_increment(ha_write_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_write_count, &LOCK_status);
if (table->timestamp_default_now)
update_timestamp(record+table->timestamp_default_now-1);
if (table->next_number_field && record == table->record[0])
@@ -1099,10 +1099,11 @@ int ha_berkeley::update_row(const byte * old_row, byte * new_row)
DB_TXN *sub_trans;
ulong thd_options = table->tmp_table == NO_TMP_TABLE ? table->in_use->options : 0;
bool primary_key_changed;
+
DBUG_ENTER("update_row");
LINT_INIT(error);
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_row+table->timestamp_on_update_now-1);
@@ -1292,7 +1293,7 @@ int ha_berkeley::delete_row(const byte * record)
key_map keys=table->keys_in_use;
ulong thd_options = table->tmp_table == NO_TMP_TABLE ? table->in_use->options : 0;
DBUG_ENTER("delete_row");
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_delete_count,&LOCK_status);
if ((error=pack_row(&row, record, 0)))
DBUG_RETURN((error)); /* purecov: inspected */
@@ -1439,7 +1440,7 @@ int ha_berkeley::read_row(int error, char *buf, uint keynr, DBT *row,
int ha_berkeley::index_read_idx(byte * buf, uint keynr, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,&LOCK_status);
DBUG_ENTER("index_read_idx");
current_row.flags=DB_DBT_REALLOC;
active_index=MAX_KEY;
@@ -1458,9 +1459,10 @@ int ha_berkeley::index_read(byte * buf, const byte * key,
int error;
KEY *key_info= &table->key_info[active_index];
int do_prev= 0;
+
DBUG_ENTER("ha_berkeley::index_read");
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,&LOCK_status);
bzero((char*) &row,sizeof(row));
if (find_flag == HA_READ_BEFORE_KEY)
{
@@ -1529,7 +1531,8 @@ int ha_berkeley::index_read_last(byte * buf, const byte * key, uint key_len)
KEY *key_info= &table->key_info[active_index];
DBUG_ENTER("ha_berkeley::index_read");
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_key_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
/* read of partial key */
@@ -1553,7 +1556,8 @@ int ha_berkeley::index_next(byte * buf)
{
DBT row;
DBUG_ENTER("index_next");
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT),
(char*) buf, active_index, &row, &last_key, 1));
@@ -1564,7 +1568,8 @@ int ha_berkeley::index_next_same(byte * buf, const byte *key, uint keylen)
DBT row;
int error;
DBUG_ENTER("index_next_same");
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_next_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
if (keylen == table->key_info[active_index].key_length)
error=read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT_DUP),
@@ -1584,7 +1589,8 @@ int ha_berkeley::index_prev(byte * buf)
{
DBT row;
DBUG_ENTER("index_prev");
- statistic_increment(ha_read_prev_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_prev_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_PREV),
(char*) buf, active_index, &row, &last_key, 1));
@@ -1595,7 +1601,8 @@ int ha_berkeley::index_first(byte * buf)
{
DBT row;
DBUG_ENTER("index_first");
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_first_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_FIRST),
(char*) buf, active_index, &row, &last_key, 1));
@@ -1605,7 +1612,8 @@ int ha_berkeley::index_last(byte * buf)
{
DBT row;
DBUG_ENTER("index_last");
- statistic_increment(ha_read_last_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_last_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_LAST),
(char*) buf, active_index, &row, &last_key, 0));
@@ -1627,7 +1635,8 @@ int ha_berkeley::rnd_next(byte *buf)
{
DBT row;
DBUG_ENTER("rnd_next");
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(table->in_use->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
bzero((char*) &row,sizeof(row));
DBUG_RETURN(read_row(cursor->c_get(cursor, &last_key, &row, DB_NEXT),
(char*) buf, primary_key, &row, &last_key, 1));
@@ -1658,9 +1667,10 @@ DBT *ha_berkeley::get_pos(DBT *to, byte *pos)
int ha_berkeley::rnd_pos(byte * buf, byte *pos)
{
DBT db_pos;
- statistic_increment(ha_read_rnd_count,&LOCK_status);
+
DBUG_ENTER("ha_berkeley::rnd_pos");
-
+ statistic_increment(table->in_use->status_var.ha_read_rnd_count,
+ &LOCK_status);
active_index= MAX_KEY;
DBUG_RETURN(read_row(file->get(file, transaction,
get_pos(&db_pos, pos),
diff --git a/sql/ha_heap.cc b/sql/ha_heap.cc
index 7340a6973b5..6dc5e85e1d4 100644
--- a/sql/ha_heap.cc
+++ b/sql/ha_heap.cc
@@ -86,7 +86,7 @@ void ha_heap::set_keys_for_scanning(void)
int ha_heap::write_row(byte * buf)
{
- statistic_increment(ha_write_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_write_count,&LOCK_status);
if (table->timestamp_default_now)
update_timestamp(buf+table->timestamp_default_now-1);
if (table->next_number_field && buf == table->record[0])
@@ -96,7 +96,7 @@ int ha_heap::write_row(byte * buf)
int ha_heap::update_row(const byte * old_data, byte * new_data)
{
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
return heap_update(file,old_data,new_data);
@@ -104,7 +104,7 @@ int ha_heap::update_row(const byte * old_data, byte * new_data)
int ha_heap::delete_row(const byte * buf)
{
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_delete_count,&LOCK_status);
return heap_delete(file,buf);
}
@@ -112,7 +112,7 @@ int ha_heap::index_read(byte * buf, const byte * key, uint key_len,
enum ha_rkey_function find_flag)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
int error = heap_rkey(file,buf,active_index, key, key_len, find_flag);
table->status = error ? STATUS_NOT_FOUND : 0;
return error;
@@ -121,7 +121,7 @@ int ha_heap::index_read(byte * buf, const byte * key, uint key_len,
int ha_heap::index_read_last(byte *buf, const byte *key, uint key_len)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
int error= heap_rkey(file, buf, active_index, key, key_len,
HA_READ_PREFIX_LAST);
table->status= error ? STATUS_NOT_FOUND : 0;
@@ -131,7 +131,7 @@ int ha_heap::index_read_last(byte *buf, const byte *key, uint key_len)
int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
int error = heap_rkey(file, buf, index, key, key_len, find_flag);
table->status = error ? STATUS_NOT_FOUND : 0;
return error;
@@ -140,7 +140,7 @@ int ha_heap::index_read_idx(byte * buf, uint index, const byte * key,
int ha_heap::index_next(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,&LOCK_status);
int error=heap_rnext(file,buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -149,7 +149,7 @@ int ha_heap::index_next(byte * buf)
int ha_heap::index_prev(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_prev_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_prev_count,&LOCK_status);
int error=heap_rprev(file,buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -158,7 +158,8 @@ int ha_heap::index_prev(byte * buf)
int ha_heap::index_first(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_first_count,
+ &LOCK_status);
int error=heap_rfirst(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -167,7 +168,7 @@ int ha_heap::index_first(byte * buf)
int ha_heap::index_last(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_last_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_last_count,&LOCK_status);
int error=heap_rlast(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -180,7 +181,8 @@ int ha_heap::rnd_init(bool scan)
int ha_heap::rnd_next(byte *buf)
{
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
int error=heap_scan(file, buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -190,7 +192,7 @@ int ha_heap::rnd_pos(byte * buf, byte *pos)
{
int error;
HEAP_PTR position;
- statistic_increment(ha_read_rnd_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_count, &LOCK_status);
memcpy_fixed((char*) &position,pos,sizeof(HEAP_PTR));
error=heap_rrnd(file, buf, position);
table->status=error ? STATUS_NOT_FOUND: 0;
diff --git a/sql/ha_innodb.cc b/sql/ha_innodb.cc
index 8da04ed0ab1..4d068cfc0ce 100644
--- a/sql/ha_innodb.cc
+++ b/sql/ha_innodb.cc
@@ -2218,7 +2218,8 @@ ha_innobase::write_row(
ut_error;
}
- statistic_increment(ha_write_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_write_count,
+ &LOCK_status);
if (table->timestamp_default_now)
update_timestamp(record + table->timestamp_default_now - 1);
@@ -2748,7 +2749,8 @@ ha_innobase::index_read(
ut_ad(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count,
+ &LOCK_status);
if (last_query_id != user_thd->query_id) {
prebuilt->sql_stat_start = TRUE;
@@ -2854,7 +2856,8 @@ ha_innobase::change_active_index(
{
row_prebuilt_t* prebuilt = (row_prebuilt_t*) innobase_prebuilt;
KEY* key=0;
- statistic_increment(ha_read_key_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count,
+ &LOCK_status);
DBUG_ENTER("change_active_index");
ut_ad(user_thd == current_thd);
@@ -2986,7 +2989,8 @@ ha_innobase::index_next(
mysql_byte* buf) /* in/out: buffer for next row in MySQL
format */
{
- statistic_increment(ha_read_next_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,
+ &LOCK_status);
return(general_fetch(buf, ROW_SEL_NEXT, 0));
}
@@ -3003,7 +3007,8 @@ ha_innobase::index_next_same(
const mysql_byte* key, /* in: key value */
uint keylen) /* in: key value length */
{
- statistic_increment(ha_read_next_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,
+ &LOCK_status);
return(general_fetch(buf, ROW_SEL_NEXT, last_match_mode));
}
@@ -3037,7 +3042,8 @@ ha_innobase::index_first(
int error;
DBUG_ENTER("index_first");
- statistic_increment(ha_read_first_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_first_count,
+ &LOCK_status);
error = index_read(buf, NULL, 0, HA_READ_AFTER_KEY);
@@ -3063,7 +3069,8 @@ ha_innobase::index_last(
int error;
DBUG_ENTER("index_first");
- statistic_increment(ha_read_last_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_last_count,
+ &LOCK_status);
error = index_read(buf, NULL, 0, HA_READ_BEFORE_KEY);
@@ -3128,7 +3135,8 @@ ha_innobase::rnd_next(
int error;
DBUG_ENTER("rnd_next");
- statistic_increment(ha_read_rnd_next_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
if (start_of_scan) {
error = index_first(buf);
@@ -3164,7 +3172,8 @@ ha_innobase::rnd_pos(
DBUG_ENTER("rnd_pos");
DBUG_DUMP("key", (char*) pos, ref_length);
- statistic_increment(ha_read_rnd_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_count,
+ &LOCK_status);
ut_ad(prebuilt->trx ==
(trx_t*) current_thd->transaction.all.innobase_tid);
diff --git a/sql/ha_isam.cc b/sql/ha_isam.cc
index 2fd75462329..201230c8aab 100644
--- a/sql/ha_isam.cc
+++ b/sql/ha_isam.cc
@@ -69,7 +69,7 @@ uint ha_isam::min_record_length(uint options) const
int ha_isam::write_row(byte * buf)
{
- statistic_increment(ha_write_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_write_count, &LOCK_status);
if (table->timestamp_default_now)
update_timestamp(buf+table->timestamp_default_now-1);
if (table->next_number_field && buf == table->record[0])
@@ -79,7 +79,7 @@ int ha_isam::write_row(byte * buf)
int ha_isam::update_row(const byte * old_data, byte * new_data)
{
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_update_count, &LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
return !nisam_update(file,old_data,new_data) ? 0 : my_errno ? my_errno : -1;
@@ -87,14 +87,14 @@ int ha_isam::update_row(const byte * old_data, byte * new_data)
int ha_isam::delete_row(const byte * buf)
{
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_delete_count, &LOCK_status);
return !nisam_delete(file,buf) ? 0 : my_errno ? my_errno : -1;
}
int ha_isam::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
int error=nisam_rkey(file, buf, active_index, key, key_len, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : -1;
@@ -103,7 +103,7 @@ int ha_isam::index_read(byte * buf, const byte * key,
int ha_isam::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
int error=nisam_rkey(file, buf, index, key, key_len, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : -1;
@@ -111,7 +111,7 @@ int ha_isam::index_read_idx(byte * buf, uint index, const byte * key,
int ha_isam::index_read_last(byte * buf, const byte * key, uint key_len)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
int error=nisam_rkey(file, buf, active_index, key, key_len,
HA_READ_PREFIX_LAST);
table->status=error ? STATUS_NOT_FOUND: 0;
@@ -120,7 +120,8 @@ int ha_isam::index_read_last(byte * buf, const byte * key, uint key_len)
int ha_isam::index_next(byte * buf)
{
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,
+ &LOCK_status);
int error=nisam_rnext(file,buf,active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
@@ -128,7 +129,8 @@ int ha_isam::index_next(byte * buf)
int ha_isam::index_prev(byte * buf)
{
- statistic_increment(ha_read_prev_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_prev_count,
+ &LOCK_status);
int error=nisam_rprev(file,buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
@@ -136,7 +138,8 @@ int ha_isam::index_prev(byte * buf)
int ha_isam::index_first(byte * buf)
{
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_first_count,
+ &LOCK_status);
int error=nisam_rfirst(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
@@ -144,7 +147,8 @@ int ha_isam::index_first(byte * buf)
int ha_isam::index_last(byte * buf)
{
- statistic_increment(ha_read_last_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_last_count,
+ &LOCK_status);
int error=nisam_rlast(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : HA_ERR_END_OF_FILE;
@@ -157,7 +161,8 @@ int ha_isam::rnd_init(bool scan)
int ha_isam::rnd_next(byte *buf)
{
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
int error=nisam_rrnd(file, buf, NI_POS_ERROR);
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : -1;
@@ -165,7 +170,8 @@ int ha_isam::rnd_next(byte *buf)
int ha_isam::rnd_pos(byte * buf, byte *pos)
{
- statistic_increment(ha_read_rnd_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_count,
+ &LOCK_status);
int error=nisam_rrnd(file, buf, (ulong) ha_get_ptr(pos,ref_length));
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : -1;
diff --git a/sql/ha_isammrg.cc b/sql/ha_isammrg.cc
index 20e2b4db423..19983e4b257 100644
--- a/sql/ha_isammrg.cc
+++ b/sql/ha_isammrg.cc
@@ -77,7 +77,7 @@ int ha_isammrg::write_row(byte * buf)
int ha_isammrg::update_row(const byte * old_data, byte * new_data)
{
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_update_count, &LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
return !mrg_update(file,old_data,new_data) ? 0 : my_errno ? my_errno : -1;
@@ -85,7 +85,7 @@ int ha_isammrg::update_row(const byte * old_data, byte * new_data)
int ha_isammrg::delete_row(const byte * buf)
{
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_delete_count, &LOCK_status);
return !mrg_delete(file,buf) ? 0 : my_errno ? my_errno : -1;
}
@@ -128,7 +128,8 @@ int ha_isammrg::rnd_init(bool scan)
int ha_isammrg::rnd_next(byte *buf)
{
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
int error=mrg_rrnd(file, buf, ~(mrg_off_t) 0);
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : -1;
@@ -136,7 +137,7 @@ int ha_isammrg::rnd_next(byte *buf)
int ha_isammrg::rnd_pos(byte * buf, byte *pos)
{
- statistic_increment(ha_read_rnd_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_count, &LOCK_status);
int error=mrg_rrnd(file, buf, (ulong) ha_get_ptr(pos,ref_length));
table->status=error ? STATUS_NOT_FOUND: 0;
return !error ? 0 : my_errno ? my_errno : -1;
diff --git a/sql/ha_myisam.cc b/sql/ha_myisam.cc
index 938f3a40629..7e86633da89 100644
--- a/sql/ha_myisam.cc
+++ b/sql/ha_myisam.cc
@@ -249,7 +249,7 @@ int ha_myisam::close(void)
int ha_myisam::write_row(byte * buf)
{
- statistic_increment(ha_write_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_write_count,&LOCK_status);
/* If we have a timestamp column, update it to the current time */
if (table->timestamp_default_now)
@@ -1070,7 +1070,7 @@ bool ha_myisam::is_crashed() const
int ha_myisam::update_row(const byte * old_data, byte * new_data)
{
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
return mi_update(file,old_data,new_data);
@@ -1078,7 +1078,7 @@ int ha_myisam::update_row(const byte * old_data, byte * new_data)
int ha_myisam::delete_row(const byte * buf)
{
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_delete_count,&LOCK_status);
return mi_delete(file,buf);
}
@@ -1086,7 +1086,7 @@ int ha_myisam::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count,&LOCK_status);
int error=mi_rkey(file,buf,active_index, key, key_len, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1095,7 +1095,7 @@ int ha_myisam::index_read(byte * buf, const byte * key,
int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count,&LOCK_status);
int error=mi_rkey(file,buf,index, key, key_len, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1104,7 +1104,7 @@ int ha_myisam::index_read_idx(byte * buf, uint index, const byte * key,
int ha_myisam::index_read_last(byte * buf, const byte * key, uint key_len)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count,&LOCK_status);
int error=mi_rkey(file,buf,active_index, key, key_len, HA_READ_PREFIX_LAST);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1113,7 +1113,7 @@ int ha_myisam::index_read_last(byte * buf, const byte * key, uint key_len)
int ha_myisam::index_next(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,&LOCK_status);
int error=mi_rnext(file,buf,active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1122,7 +1122,7 @@ int ha_myisam::index_next(byte * buf)
int ha_myisam::index_prev(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_prev_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_prev_count,&LOCK_status);
int error=mi_rprev(file,buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1131,7 +1131,8 @@ int ha_myisam::index_prev(byte * buf)
int ha_myisam::index_first(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_first_count,
+ &LOCK_status);
int error=mi_rfirst(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1140,7 +1141,7 @@ int ha_myisam::index_first(byte * buf)
int ha_myisam::index_last(byte * buf)
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_last_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_last_count,&LOCK_status);
int error=mi_rlast(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1151,7 +1152,7 @@ int ha_myisam::index_next_same(byte * buf,
uint length __attribute__((unused)))
{
DBUG_ASSERT(inited==INDEX);
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,&LOCK_status);
int error=mi_rnext_same(file,buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1167,7 +1168,8 @@ int ha_myisam::rnd_init(bool scan)
int ha_myisam::rnd_next(byte *buf)
{
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
int error=mi_scan(file, buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1180,7 +1182,7 @@ int ha_myisam::restart_rnd_next(byte *buf, byte *pos)
int ha_myisam::rnd_pos(byte * buf, byte *pos)
{
- statistic_increment(ha_read_rnd_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_count,&LOCK_status);
int error=mi_rrnd(file, buf, ha_get_ptr(pos,ref_length));
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -1589,7 +1591,8 @@ int ha_myisam::ft_read(byte * buf)
if (!ft_handler)
return -1;
- thread_safe_increment(ha_read_next_count,&LOCK_status); // why ?
+ thread_safe_increment(current_thd->status_var.ha_read_next_count,
+ &LOCK_status); // why ?
error=ft_handler->please->read_next(ft_handler,(char*) buf);
diff --git a/sql/ha_myisammrg.cc b/sql/ha_myisammrg.cc
index 895d025d6fc..29a31571380 100644
--- a/sql/ha_myisammrg.cc
+++ b/sql/ha_myisammrg.cc
@@ -81,7 +81,7 @@ int ha_myisammrg::close(void)
int ha_myisammrg::write_row(byte * buf)
{
- statistic_increment(ha_write_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_write_count,&LOCK_status);
if (table->timestamp_default_now)
update_timestamp(buf+table->timestamp_default_now-1);
if (table->next_number_field && buf == table->record[0])
@@ -91,7 +91,7 @@ int ha_myisammrg::write_row(byte * buf)
int ha_myisammrg::update_row(const byte * old_data, byte * new_data)
{
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_update_count,&LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now);
return myrg_update(file,old_data,new_data);
@@ -99,14 +99,14 @@ int ha_myisammrg::update_row(const byte * old_data, byte * new_data)
int ha_myisammrg::delete_row(const byte * buf)
{
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_delete_count,&LOCK_status);
return myrg_delete(file,buf);
}
int ha_myisammrg::index_read(byte * buf, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count,&LOCK_status);
int error=myrg_rkey(file,buf,active_index, key, key_len, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -115,7 +115,7 @@ int ha_myisammrg::index_read(byte * buf, const byte * key,
int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key,
uint key_len, enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count,&LOCK_status);
int error=myrg_rkey(file,buf,index, key, key_len, find_flag);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -123,7 +123,7 @@ int ha_myisammrg::index_read_idx(byte * buf, uint index, const byte * key,
int ha_myisammrg::index_read_last(byte * buf, const byte * key, uint key_len)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count,&LOCK_status);
int error=myrg_rkey(file,buf,active_index, key, key_len,
HA_READ_PREFIX_LAST);
table->status=error ? STATUS_NOT_FOUND: 0;
@@ -132,7 +132,7 @@ int ha_myisammrg::index_read_last(byte * buf, const byte * key, uint key_len)
int ha_myisammrg::index_next(byte * buf)
{
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,&LOCK_status);
int error=myrg_rnext(file,buf,active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -140,7 +140,7 @@ int ha_myisammrg::index_next(byte * buf)
int ha_myisammrg::index_prev(byte * buf)
{
- statistic_increment(ha_read_prev_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_prev_count,&LOCK_status);
int error=myrg_rprev(file,buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -148,7 +148,8 @@ int ha_myisammrg::index_prev(byte * buf)
int ha_myisammrg::index_first(byte * buf)
{
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_first_count,
+ &LOCK_status);
int error=myrg_rfirst(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -156,7 +157,7 @@ int ha_myisammrg::index_first(byte * buf)
int ha_myisammrg::index_last(byte * buf)
{
- statistic_increment(ha_read_last_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_last_count,&LOCK_status);
int error=myrg_rlast(file, buf, active_index);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -166,7 +167,7 @@ int ha_myisammrg::index_next_same(byte * buf,
const byte *key __attribute__((unused)),
uint length __attribute__((unused)))
{
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,&LOCK_status);
int error=myrg_rnext_same(file,buf);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -179,7 +180,8 @@ int ha_myisammrg::rnd_init(bool scan)
int ha_myisammrg::rnd_next(byte *buf)
{
- statistic_increment(ha_read_rnd_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
int error=myrg_rrnd(file, buf, HA_OFFSET_ERROR);
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
@@ -187,7 +189,7 @@ int ha_myisammrg::rnd_next(byte *buf)
int ha_myisammrg::rnd_pos(byte * buf, byte *pos)
{
- statistic_increment(ha_read_rnd_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_count,&LOCK_status);
int error=myrg_rrnd(file, buf, ha_get_ptr(pos,ref_length));
table->status=error ? STATUS_NOT_FOUND: 0;
return error;
diff --git a/sql/ha_ndbcluster.cc b/sql/ha_ndbcluster.cc
index 8b7b5e94965..1837500d8f7 100644
--- a/sql/ha_ndbcluster.cc
+++ b/sql/ha_ndbcluster.cc
@@ -1367,9 +1367,11 @@ int ha_ndbcluster::write_row(byte *record)
NdbConnection *trans= m_active_trans;
NdbOperation *op;
int res;
+ THD *thd= current_thd;
+
DBUG_ENTER("write_row");
- statistic_increment(ha_write_count,&LOCK_status);
+ statistic_increment(thd->status_var.ha_write_count, &LOCK_status);
if (table->timestamp_default_now)
update_timestamp(record+table->timestamp_default_now-1);
has_auto_increment= (table->next_number_field && record == table->record[0]);
@@ -1499,7 +1501,7 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
uint i;
DBUG_ENTER("update_row");
- statistic_increment(ha_update_count,&LOCK_status);
+ statistic_increment(thd->status_var.ha_update_count, &LOCK_status);
if (table->timestamp_on_update_now)
update_timestamp(new_data+table->timestamp_on_update_now-1);
@@ -1606,12 +1608,13 @@ int ha_ndbcluster::update_row(const byte *old_data, byte *new_data)
int ha_ndbcluster::delete_row(const byte *record)
{
+ THD *thd= current_thd;
NdbConnection *trans= m_active_trans;
NdbResultSet* cursor= m_active_cursor;
NdbOperation *op;
DBUG_ENTER("delete_row");
- statistic_increment(ha_delete_count,&LOCK_status);
+ statistic_increment(thd->status_var.ha_delete_count,&LOCK_status);
if (cursor)
{
@@ -1926,7 +1929,7 @@ int ha_ndbcluster::index_read_idx(byte *buf, uint index_no,
const byte *key, uint key_len,
enum ha_rkey_function find_flag)
{
- statistic_increment(ha_read_key_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_key_count, &LOCK_status);
DBUG_ENTER("index_read_idx");
DBUG_PRINT("enter", ("index_no: %u, key_len: %u", index_no, key_len));
index_init(index_no);
@@ -1939,7 +1942,8 @@ int ha_ndbcluster::index_next(byte *buf)
DBUG_ENTER("index_next");
int error= 1;
- statistic_increment(ha_read_next_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_next_count,
+ &LOCK_status);
DBUG_RETURN(next_result(buf));
}
@@ -1947,7 +1951,8 @@ int ha_ndbcluster::index_next(byte *buf)
int ha_ndbcluster::index_prev(byte *buf)
{
DBUG_ENTER("index_prev");
- statistic_increment(ha_read_prev_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_prev_count,
+ &LOCK_status);
DBUG_RETURN(1);
}
@@ -1955,7 +1960,8 @@ int ha_ndbcluster::index_prev(byte *buf)
int ha_ndbcluster::index_first(byte *buf)
{
DBUG_ENTER("index_first");
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_first_count,
+ &LOCK_status);
DBUG_RETURN(1);
}
@@ -1963,7 +1969,7 @@ int ha_ndbcluster::index_first(byte *buf)
int ha_ndbcluster::index_last(byte *buf)
{
DBUG_ENTER("index_last");
- statistic_increment(ha_read_last_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_last_count,&LOCK_status);
DBUG_RETURN(1);
}
@@ -2077,7 +2083,8 @@ int ha_ndbcluster::rnd_end()
int ha_ndbcluster::rnd_next(byte *buf)
{
DBUG_ENTER("rnd_next");
- statistic_increment(ha_read_rnd_next_count, &LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_next_count,
+ &LOCK_status);
if (!m_active_cursor)
DBUG_RETURN(full_table_scan(buf));
@@ -2095,7 +2102,8 @@ int ha_ndbcluster::rnd_next(byte *buf)
int ha_ndbcluster::rnd_pos(byte *buf, byte *pos)
{
DBUG_ENTER("rnd_pos");
- statistic_increment(ha_read_rnd_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_rnd_count,
+ &LOCK_status);
// The primary key for the record is stored in pos
// Perform a pk_read using primary key "index"
DBUG_RETURN(pk_read(pos, ref_length, buf));
diff --git a/sql/handler.cc b/sql/handler.cc
index 8a480b0f131..c3513ad819f 100644
--- a/sql/handler.cc
+++ b/sql/handler.cc
@@ -54,11 +54,7 @@
static int NEAR_F delete_file(const char *name,const char *ext,int extflag);
-ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count,
- ha_read_key_count, ha_read_next_count, ha_read_prev_count,
- ha_read_first_count, ha_read_last_count,
- ha_commit_count, ha_rollback_count,
- ha_read_rnd_count, ha_read_rnd_next_count, ha_discover_count;
+ulong ha_read_count, ha_discover_count;
static SHOW_COMP_OPTION have_yes= SHOW_OPTION_YES;
@@ -563,7 +559,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
thd->variables.tx_isolation=thd->session_tx_isolation;
if (operation_done)
{
- statistic_increment(ha_commit_count,&LOCK_status);
+ statistic_increment(thd->status_var.ha_commit_count,&LOCK_status);
thd->transaction.cleanup();
}
if (need_start_waiters)
@@ -652,7 +648,7 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
}
thd->variables.tx_isolation=thd->session_tx_isolation;
if (operation_done)
- statistic_increment(ha_rollback_count,&LOCK_status);
+ statistic_increment(thd->status_var.ha_rollback_count,&LOCK_status);
}
#endif /* USING_TRANSACTIONS */
DBUG_RETURN(error);
@@ -725,7 +721,7 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
operation_done=1;
#endif
if (operation_done)
- statistic_increment(ha_rollback_count,&LOCK_status);
+ statistic_increment(thd->status_var.ha_rollback_count,&LOCK_status);
}
#endif /* USING_TRANSACTIONS */
@@ -920,7 +916,7 @@ int handler::read_first_row(byte * buf, uint primary_key)
register int error;
DBUG_ENTER("handler::read_first_row");
- statistic_increment(ha_read_first_count,&LOCK_status);
+ statistic_increment(current_thd->status_var.ha_read_first_count,&LOCK_status);
/*
If there is very few deleted rows in the table, find the first row by
diff --git a/sql/item.cc b/sql/item.cc
index 18ae7efd852..cbb760156b3 100644
--- a/sql/item.cc
+++ b/sql/item.cc
@@ -24,6 +24,8 @@
#include "my_dir.h"
#include "sp_rcontext.h"
#include "sql_acl.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
static void mark_as_dependent(THD *thd,
SELECT_LEX *last, SELECT_LEX *current,
@@ -463,6 +465,24 @@ const char *Item_ident::full_name() const
void Item_ident::print(String *str)
{
THD *thd= current_thd;
+ char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
+ const char *d_name= db_name, *t_name= table_name;
+ if (lower_case_table_names)
+ {
+ if (table_name && table_name[0])
+ {
+ strmov(t_name_buff, table_name);
+ my_casedn_str(files_charset_info, t_name_buff);
+ t_name= t_name_buff;
+ }
+ if (db_name && db_name[0])
+ {
+ strmov(d_name_buff, db_name);
+ my_casedn_str(files_charset_info, d_name_buff);
+ d_name= d_name_buff;
+ }
+ }
+
if (!table_name || !field_name)
{
const char *nm= field_name ? field_name : name ? name : "tmp_field";
@@ -471,9 +491,9 @@ void Item_ident::print(String *str)
}
if (db_name && db_name[0])
{
- append_identifier(thd, str, db_name, strlen(db_name));
+ append_identifier(thd, str, d_name, strlen(d_name));
str->append('.');
- append_identifier(thd, str, table_name, strlen(table_name));
+ append_identifier(thd, str, t_name, strlen(t_name));
str->append('.');
append_identifier(thd, str, field_name, strlen(field_name));
}
@@ -481,7 +501,7 @@ void Item_ident::print(String *str)
{
if (table_name[0])
{
- append_identifier(thd, str, table_name, strlen(table_name));
+ append_identifier(thd, str, t_name, strlen(t_name));
str->append('.');
append_identifier(thd, str, field_name, strlen(field_name));
}
@@ -2444,6 +2464,97 @@ void Item_insert_value::print(String *str)
str->append(')');
}
+
+/*
+ Bind item representing field of row being changed in trigger
+ to appropriate Field object.
+
+ SYNOPSIS
+ setup_field()
+ thd - current thread context
+ table - table of trigger (and where we looking for fields)
+ event - type of trigger event
+
+ NOTE
+ This function does almost the same as fix_fields() for Item_field
+ but is invoked during trigger definition parsing and takes TABLE
+ object as its argument.
+
+ RETURN VALUES
+ 0 ok
+ 1 field was not found.
+*/
+bool Item_trigger_field::setup_field(THD *thd, TABLE *table,
+ enum trg_event_type event)
+{
+ bool result= 1;
+ uint field_idx= (uint)-1;
+ bool save_set_query_id= thd->set_query_id;
+
+ /* TODO: Think more about consequences of this step. */
+ thd->set_query_id= 0;
+
+ if (find_field_in_real_table(thd, table, field_name,
+ strlen(field_name), 0, 0,
+ &field_idx))
+ {
+ field= (row_version == OLD_ROW && event == TRG_EVENT_UPDATE) ?
+ table->triggers->old_field[field_idx] :
+ table->field[field_idx];
+ result= 0;
+ }
+
+ thd->set_query_id= save_set_query_id;
+
+ return result;
+}
+
+
+bool Item_trigger_field::eq(const Item *item, bool binary_cmp) const
+{
+ return item->type() == TRIGGER_FIELD_ITEM &&
+ row_version == ((Item_trigger_field *)item)->row_version &&
+ !my_strcasecmp(system_charset_info, field_name,
+ ((Item_trigger_field *)item)->field_name);
+}
+
+
+bool Item_trigger_field::fix_fields(THD *thd,
+ TABLE_LIST *table_list,
+ Item **items)
+{
+ /*
+ Since trigger is object tightly associated with TABLE object most
+ of its set up can be performed during trigger loading i.e. trigger
+ parsing! So we have little to do in fix_fields. :)
+ FIXME may be we still should bother about permissions here.
+ */
+ DBUG_ASSERT(fixed == 0);
+ // QQ: May be this should be moved to setup_field?
+ set_field(field);
+ fixed= 1;
+ return 0;
+}
+
+
+void Item_trigger_field::print(String *str)
+{
+ str->append((row_version == NEW_ROW) ? "NEW" : "OLD", 3);
+ str->append('.');
+ str->append(field_name);
+}
+
+
+void Item_trigger_field::cleanup()
+{
+ /*
+ Since special nature of Item_trigger_field we should not do most of
+ things from Item_field::cleanup() or Item_ident::cleanup() here.
+ */
+ Item::cleanup();
+}
+
+
/*
If item is a const function, calculate it and return a const item
The original item is freed if not returned
diff --git a/sql/item.h b/sql/item.h
index 1420a89c76a..a237e7ce6f5 100644
--- a/sql/item.h
+++ b/sql/item.h
@@ -105,7 +105,7 @@ public:
PROC_ITEM,COND_ITEM, REF_ITEM, FIELD_STD_ITEM,
FIELD_VARIANCE_ITEM, INSERT_VALUE_ITEM,
SUBSELECT_ITEM, ROW_ITEM, CACHE_ITEM, TYPE_HOLDER,
- PARAM_ITEM};
+ PARAM_ITEM, TRIGGER_FIELD_ITEM};
enum cond_result { COND_UNDEF,COND_OK,COND_TRUE,COND_FALSE };
@@ -434,12 +434,13 @@ public:
friend bool insert_fields(THD *thd,TABLE_LIST *tables, const char *db_name,
const char *table_name, List_iterator<Item> *it,
- bool any_privileges);
+ bool any_privileges, bool allocate_view_names);
};
class Item_field :public Item_ident
{
+protected:
void set_field(Field *field);
public:
Field *field,*result_field;
@@ -1198,6 +1199,57 @@ public:
}
};
+
+/*
+ We need this two enums here instead of sql_lex.h because
+ at least one of them is used by Item_trigger_field interface.
+
+ Time when trigger is invoked (i.e. before or after row actually
+ inserted/updated/deleted).
+*/
+enum trg_action_time_type
+{
+ TRG_ACTION_BEFORE= 0, TRG_ACTION_AFTER= 1
+};
+
+/*
+ Event on which trigger is invoked.
+*/
+enum trg_event_type
+{
+ TRG_EVENT_INSERT= 0 , TRG_EVENT_UPDATE= 1, TRG_EVENT_DELETE= 2
+};
+
+/*
+ Represents NEW/OLD version of field of row which is
+ changed/read in trigger.
+
+ Note: For this item actual binding to Field object happens not during
+ fix_fields() (like for Item_field) but during parsing of trigger
+ definition, when table is opened, with special setup_field() call.
+*/
+class Item_trigger_field : public Item_field
+{
+public:
+ /* Is this item represents row from NEW or OLD row ? */
+ enum row_version_type {OLD_ROW, NEW_ROW};
+ row_version_type row_version;
+
+ Item_trigger_field(row_version_type row_ver_par,
+ const char *field_name_par):
+ Item_field((const char *)NULL, (const char *)NULL, field_name_par),
+ row_version(row_ver_par)
+ {}
+ bool setup_field(THD *thd, TABLE *table, enum trg_event_type event);
+ enum Type type() const { return TRIGGER_FIELD_ITEM; }
+ bool eq(const Item *item, bool binary_cmp) const;
+ bool fix_fields(THD *, struct st_table_list *, Item **);
+ void print(String *str);
+ table_map used_tables() const { return (table_map)0L; }
+ void cleanup();
+};
+
+
class Item_cache: public Item
{
protected:
diff --git a/sql/item_func.cc b/sql/item_func.cc
index 45564e01e03..8300d139a71 100644
--- a/sql/item_func.cc
+++ b/sql/item_func.cc
@@ -2580,6 +2580,16 @@ void Item_func_set_user_var::print(String *str)
}
+void Item_func_set_user_var::print_as_stmt(String *str)
+{
+ str->append("set @", 5);
+ str->append(name.str, name.length);
+ str->append(":=", 2);
+ args[0]->print(str);
+ str->append(')');
+}
+
+
String *
Item_func_get_user_var::val_str(String *str)
{
@@ -3329,6 +3339,11 @@ Item_func_sp::execute(Item **itp)
sp_change_security_context(thd, m_sp, &save_ctx);
#endif
+ /*
+ We don't need to surpress senfing of ok packet here (by setting
+ thd->net.no_send_ok to true), because we are not allowing statements
+ in functions now.
+ */
res= m_sp->execute_function(thd, args, arg_count, itp);
#ifndef NO_EMBEDDED_ACCESS_CHECKS
diff --git a/sql/item_func.h b/sql/item_func.h
index 76d0346531e..48a33bad80d 100644
--- a/sql/item_func.h
+++ b/sql/item_func.h
@@ -948,6 +948,7 @@ public:
bool fix_fields(THD *thd, struct st_table_list *tables, Item **ref);
void fix_length_and_dec();
void print(String *str);
+ void print_as_stmt(String *str);
const char *func_name() const { return "set_user_var"; }
};
@@ -1130,25 +1131,31 @@ public:
double val()
{
Item *it;
+ double d;
if (execute(&it))
{
null_value= 1;
return 0.0;
}
- return it->val();
+ d= it->val();
+ null_value= it->null_value;
+ return d;
}
String *val_str(String *str)
{
Item *it;
+ String *s;
if (execute(&it))
{
null_value= 1;
return NULL;
}
- return it->val_str(str);
+ s= it->val_str(str);
+ null_value= it->null_value;
+ return s;
}
void fix_length_and_dec();
diff --git a/sql/item_strfunc.cc b/sql/item_strfunc.cc
index fc667eb61b0..b3665edad39 100644
--- a/sql/item_strfunc.cc
+++ b/sql/item_strfunc.cc
@@ -2850,6 +2850,8 @@ String *Item_func_uuid::val_str(String *str)
{
DBUG_ASSERT(fixed == 1);
char *s;
+ THD *thd= current_thd;
+
pthread_mutex_lock(&LOCK_uuid_generator);
if (! uuid_time) /* first UUID() call. initializing data */
{
@@ -2864,7 +2866,7 @@ String *Item_func_uuid::val_str(String *str)
with a clock_seq value (initialized random below), we use a separate
randominit() here
*/
- randominit(&uuid_rand, tmp + (ulong)current_thd, tmp + query_id);
+ randominit(&uuid_rand, tmp + (ulong) thd, tmp + query_id);
for (i=0; i < (int)sizeof(mac); i++)
mac[i]=(uchar)(my_rnd(&uuid_rand)*255);
}
@@ -2874,7 +2876,8 @@ String *Item_func_uuid::val_str(String *str)
*--s=_dig_vec_lower[mac[i] & 15];
*--s=_dig_vec_lower[mac[i] >> 4];
}
- randominit(&uuid_rand, tmp + (ulong)start_time, tmp + bytes_sent);
+ randominit(&uuid_rand, tmp + (ulong)start_time,
+ tmp + thd->status_var.bytes_sent);
set_clock_seq_str();
}
diff --git a/sql/item_subselect.cc b/sql/item_subselect.cc
index 23dbcf8af48..25bb2701101 100644
--- a/sql/item_subselect.cc
+++ b/sql/item_subselect.cc
@@ -272,7 +272,8 @@ Item_singlerow_subselect::Item_singlerow_subselect(st_select_lex *select_lex)
DBUG_VOID_RETURN;
}
-Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent,
+Item_maxmin_subselect::Item_maxmin_subselect(THD *thd_param,
+ Item_subselect *parent,
st_select_lex *select_lex,
bool max_arg)
:Item_singlerow_subselect()
@@ -291,6 +292,12 @@ Item_maxmin_subselect::Item_maxmin_subselect(Item_subselect *parent,
used_tables_cache= parent->get_used_tables_cache();
const_item_cache= parent->get_const_item_cache();
+ /*
+ this subquery alwais creates during preparation, so we can assign
+ thd here
+ */
+ thd= thd_param;
+
DBUG_VOID_RETURN;
}
@@ -316,9 +323,11 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
SELECT_LEX *select_lex= join->select_lex;
/* Juggle with current arena only if we're in prepared statement prepare */
- Item_arena *arena= join->thd->current_arena;
+ DBUG_PRINT("TANSF:", ("thd %p, select_lex->join->thd: %s",
+ thd, select_lex->join->thd));
+ Item_arena *arena= thd->current_arena;
Item_arena backup;
- if (!arena->is_stmt_prepare())
+ if (arena->is_conventional())
arena= 0; // For easier test
if (!select_lex->master_unit()->first_select()->next_select() &&
@@ -337,11 +346,11 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
{
have_to_be_excluded= 1;
- if (join->thd->lex->describe)
+ if (thd->lex->describe)
{
char warn_buff[MYSQL_ERRMSG_SIZE];
sprintf(warn_buff, ER(ER_SELECT_REDUCED), select_lex->select_number);
- push_warning(join->thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_SELECT_REDUCED, warn_buff);
}
substitution= select_lex->item_list.head();
@@ -367,9 +376,9 @@ Item_singlerow_subselect::select_transformer(JOIN *join)
if (!(substitution= new Item_func_if(cond, substitution,
new Item_null())))
goto err;
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
}
- if (arena)
- thd->restore_backup_item_arena(arena, &backup);
return RES_REDUCE;
}
return RES_OK;
@@ -654,11 +663,11 @@ Item_in_subselect::single_value_transformer(JOIN *join,
}
SELECT_LEX *select_lex= join->select_lex;
- Item_arena *arena= join->thd->current_arena, backup;
+ Item_arena *arena= thd->current_arena, backup;
thd->where= "scalar IN/ALL/ANY subquery";
- if (!arena->is_stmt_prepare())
+ if (arena->is_conventional())
arena= 0; // For easier test
else
thd->set_n_backup_item_arena(arena, &backup);
@@ -723,7 +732,7 @@ Item_in_subselect::single_value_transformer(JOIN *join,
// remove LIMIT placed by ALL/ANY subquery
select_lex->master_unit()->global_parameters->select_limit=
HA_POS_ERROR;
- subs= new Item_maxmin_subselect(this, select_lex, func->l_op());
+ subs= new Item_maxmin_subselect(thd, this, select_lex, func->l_op());
}
// left expression belong to outer select
SELECT_LEX *current= thd->lex->current_select, *up;
@@ -899,8 +908,8 @@ Item_in_subselect::row_value_transformer(JOIN *join)
}
thd->where= "row IN/ALL/ANY subquery";
- Item_arena *arena= join->thd->current_arena, backup;
- if (!arena->is_stmt_prepare())
+ Item_arena *arena= thd->current_arena, backup;
+ if (arena->is_conventional())
arena= 0;
else
thd->set_n_backup_item_arena(arena, &backup);
@@ -1192,17 +1201,17 @@ void subselect_uniquesubquery_engine::fix_length_and_dec(Item_cache **row)
int subselect_single_select_engine::exec()
{
DBUG_ENTER("subselect_single_select_engine::exec");
- char const *save_where= join->thd->where;
- SELECT_LEX *save_select= join->thd->lex->current_select;
- join->thd->lex->current_select= select_lex;
+ char const *save_where= thd->where;
+ SELECT_LEX *save_select= thd->lex->current_select;
+ thd->lex->current_select= select_lex;
if (!optimized)
{
optimized=1;
if (join->optimize())
{
- join->thd->where= save_where;
+ thd->where= save_where;
executed= 1;
- join->thd->lex->current_select= save_select;
+ thd->lex->current_select= save_select;
DBUG_RETURN(join->error ? join->error : 1);
}
if (item->engine_changed)
@@ -1214,8 +1223,8 @@ int subselect_single_select_engine::exec()
{
if (join->reinit())
{
- join->thd->where= save_where;
- join->thd->lex->current_select= save_select;
+ thd->where= save_where;
+ thd->lex->current_select= save_select;
DBUG_RETURN(1);
}
item->reset();
@@ -1225,20 +1234,20 @@ int subselect_single_select_engine::exec()
{
join->exec();
executed= 1;
- join->thd->where= save_where;
- join->thd->lex->current_select= save_select;
+ thd->where= save_where;
+ thd->lex->current_select= save_select;
DBUG_RETURN(join->error||thd->is_fatal_error);
}
- join->thd->where= save_where;
- join->thd->lex->current_select= save_select;
+ thd->where= save_where;
+ thd->lex->current_select= save_select;
DBUG_RETURN(0);
}
int subselect_union_engine::exec()
{
- char const *save_where= unit->thd->where;
+ char const *save_where= thd->where;
int res= unit->exec();
- unit->thd->where= save_where;
+ thd->where= save_where;
return res;
}
diff --git a/sql/item_subselect.h b/sql/item_subselect.h
index ed3dbfa9855..4ef680cea19 100644
--- a/sql/item_subselect.h
+++ b/sql/item_subselect.h
@@ -154,7 +154,7 @@ class Item_maxmin_subselect :public Item_singlerow_subselect
{
bool max;
public:
- Item_maxmin_subselect(Item_subselect *parent,
+ Item_maxmin_subselect(THD *thd, Item_subselect *parent,
st_select_lex *select_lex, bool max);
void print(String *str);
};
diff --git a/sql/item_sum.cc b/sql/item_sum.cc
index bfa0f86c744..d400c198828 100644
--- a/sql/item_sum.cc
+++ b/sql/item_sum.cc
@@ -77,7 +77,7 @@ Item_sum::Item_sum(THD *thd, Item_sum *item):
*/
bool Item_sum::save_args_for_prepared_statement(THD *thd)
{
- if (thd->current_arena->is_stmt_prepare() && args_copy == 0)
+ if (!thd->current_arena->is_conventional() && args_copy == 0)
return save_args(thd->current_arena);
return 0;
}
diff --git a/sql/lex.h b/sql/lex.h
index 4c44d53d5b1..434c8fb4d47 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -167,6 +167,7 @@ static SYMBOL symbols[] = {
{ "DUMPFILE", SYM(DUMPFILE)},
{ "DUPLICATE", SYM(DUPLICATE_SYM)},
{ "DYNAMIC", SYM(DYNAMIC_SYM)},
+ { "EACH", SYM(EACH_SYM)},
{ "ELSE", SYM(ELSE)},
{ "ELSEIF", SYM(ELSEIF_SYM)},
{ "ENABLE", SYM(ENABLE_SYM)},
@@ -470,6 +471,7 @@ static SYMBOL symbols[] = {
{ "TO", SYM(TO_SYM)},
{ "TRAILING", SYM(TRAILING)},
{ "TRANSACTION", SYM(TRANSACTION_SYM)},
+ { "TRIGGER", SYM(TRIGGER_SYM)},
{ "TRUE", SYM(TRUE_SYM)},
{ "TRUNCATE", SYM(TRUNCATE_SYM)},
{ "TYPE", SYM(TYPE_SYM)},
diff --git a/sql/mysql_priv.h b/sql/mysql_priv.h
index 73ac000d953..e7a0778d5cb 100644
--- a/sql/mysql_priv.h
+++ b/sql/mysql_priv.h
@@ -481,6 +481,7 @@ int mysql_rm_table_part2_with_lock(THD *thd, TABLE_LIST *tables,
bool log_query);
int quick_rm_table(enum db_type base,const char *db,
const char *table_name);
+void close_cached_table(THD *thd, TABLE *table);
bool mysql_rename_tables(THD *thd, TABLE_LIST *table_list);
bool mysql_change_db(THD *thd,const char *name);
void mysql_parse(THD *thd,char *inBuf,uint length);
@@ -622,6 +623,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds);
int mysql_delete(THD *thd, TABLE_LIST *table, COND *conds, SQL_LIST *order,
ha_rows rows, ulong options);
int mysql_truncate(THD *thd, TABLE_LIST *table_list, bool dont_send_ok);
+int 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);
TABLE *open_table(THD *thd, TABLE_LIST *table_list, MEM_ROOT* mem,
bool *refresh);
@@ -650,6 +652,10 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
bool check_grants_table, bool check_grants_view,
bool allow_rowid,
uint *cached_field_index_ptr);
+Field *
+find_field_in_real_table(THD *thd, TABLE *table, const char *name,
+ uint length, bool check_grants, bool allow_rowid,
+ uint *cached_field_index_ptr);
#ifdef HAVE_OPENSSL
#include <openssl/des.h>
struct st_des_keyblock
@@ -692,7 +698,8 @@ int mysqld_show_status(THD *thd);
int mysqld_show_variables(THD *thd,const char *wild);
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
enum enum_var_type value_type,
- pthread_mutex_t *mutex);
+ pthread_mutex_t *mutex,
+ struct system_status_var *status_var);
int mysql_find_files(THD *thd,List<char> *files, const char *db,
const char *path, const char *wild, bool dir);
int mysqld_show_charsets(THD *thd,const char *wild);
@@ -701,6 +708,7 @@ int mysqld_show_storage_engines(THD *thd);
int mysqld_show_privileges(THD *thd);
int mysqld_show_column_types(THD *thd);
int mysqld_help (THD *thd, const char *text);
+void calc_sum_of_all_status(STATUS_VAR *to);
/* sql_prepare.cc */
int mysql_stmt_prepare(THD *thd, char *packet, uint packet_length,
@@ -756,7 +764,8 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
List<String> *index_list);
bool insert_fields(THD *thd,TABLE_LIST *tables,
const char *db_name, const char *table_name,
- List_iterator<Item> *it, bool any_privileges);
+ List_iterator<Item> *it, bool any_privileges,
+ bool allocate_view_names);
bool setup_tables(THD *thd, TABLE_LIST *tables, Item **conds);
int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
List<Item> *sum_func_list, uint wild_num);
@@ -782,6 +791,7 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
uint offset_to_list,
const char *db_name,
const char *table_name);
+TABLE_LIST *unique_table(TABLE_LIST *table, TABLE_LIST *table_list);
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name);
bool close_temporary_table(THD *thd, const char *db, const char *table_name);
void close_temporary(TABLE *table, bool delete_table=1);
@@ -918,36 +928,28 @@ extern double last_query_cost;
extern double log_10[32];
extern ulonglong log_10_int[20];
extern ulonglong keybuff_size;
-extern ulong refresh_version,flush_version, thread_id,query_id,opened_tables;
-extern ulong created_tmp_tables, created_tmp_disk_tables, bytes_sent;
+extern ulong refresh_version,flush_version, thread_id,query_id;
extern ulong binlog_cache_use, binlog_cache_disk_use;
extern ulong aborted_threads,aborted_connects;
extern ulong delayed_insert_timeout;
extern ulong delayed_insert_limit, delayed_queue_size;
extern ulong delayed_insert_threads, delayed_insert_writes;
extern ulong delayed_rows_in_use,delayed_insert_errors;
-extern ulong filesort_rows, filesort_range_count, filesort_scan_count;
-extern ulong filesort_merge_passes;
-extern ulong select_range_check_count, select_range_count, select_scan_count;
-extern ulong select_full_range_join_count,select_full_join_count;
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 server_id, concurrency;
-extern ulong ha_read_count, ha_write_count, ha_delete_count, ha_update_count;
-extern ulong ha_read_key_count, ha_read_next_count, ha_read_prev_count;
-extern ulong ha_read_first_count, ha_read_last_count;
-extern ulong ha_read_rnd_count, ha_read_rnd_next_count, ha_discover_count;
-extern ulong ha_commit_count, ha_rollback_count,table_cache_size;
+extern ulong ha_read_count, ha_discover_count;
+extern ulong table_cache_size;
extern ulong max_connections,max_connect_errors, connect_timeout;
extern ulong slave_net_timeout;
extern ulong max_user_connections;
-extern ulong long_query_count, what_to_log,flush_time;
+extern ulong what_to_log,flush_time;
extern ulong query_buff_size, thread_stack,thread_stack_min;
extern ulong binlog_cache_size, max_binlog_cache_size, open_files_limit;
extern ulong max_binlog_size, max_relay_log_size;
extern ulong rpl_recovery_rank, thread_cache_size;
-extern ulong com_stat[(uint) SQLCOM_END], com_other, back_log;
+extern ulong back_log;
extern ulong specialflag, current_pid;
extern ulong expire_logs_days, sync_binlog_period, sync_binlog_counter;
extern my_bool relay_log_purge, opt_innodb_safe_binlog;
@@ -997,6 +999,7 @@ extern SHOW_COMP_OPTION have_berkeley_db;
extern SHOW_COMP_OPTION have_ndbcluster;
extern struct system_variables global_system_variables;
extern struct system_variables max_system_variables;
+extern struct system_status_var global_status_var;
extern struct rand_struct sql_rand;
extern KEY_CACHE *sql_key_cache;
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 50eabfaa903..21633858ad8 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -289,20 +289,13 @@ ulong open_files_limit, max_binlog_size, max_relay_log_size;
ulong slave_net_timeout;
ulong thread_cache_size=0, binlog_cache_size=0, max_binlog_cache_size=0;
ulong query_cache_size=0;
-ulong com_stat[(uint) SQLCOM_END], com_other;
-ulong bytes_sent, bytes_received, net_big_packet_count;
ulong refresh_version, flush_version; /* Increments on each reload */
-ulong query_id, long_query_count;
+ulong query_id;
ulong aborted_threads, killed_threads, aborted_connects;
ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size;
ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use;
ulong delayed_insert_errors,flush_time, thread_created;
-ulong filesort_rows, filesort_range_count, filesort_scan_count;
-ulong filesort_merge_passes;
-ulong select_range_check_count, select_range_count, select_scan_count;
-ulong select_full_range_join_count,select_full_join_count;
-ulong specialflag=0,opened_tables=0,created_tmp_tables=0,
- created_tmp_disk_tables=0;
+ulong specialflag=0;
ulong binlog_cache_use= 0, binlog_cache_disk_use= 0;
ulong max_connections,max_used_connections,
max_connect_errors, max_user_connections = 0;
@@ -361,6 +354,7 @@ I_List<NAMED_LIST> key_caches;
struct system_variables global_system_variables;
struct system_variables max_system_variables;
+struct system_status_var global_status_var;
MY_TMPDIR mysql_tmpdir_list;
MY_BITMAP temp_pool;
@@ -518,6 +512,8 @@ static void close_connections(void)
#ifdef EXTRA_DEBUG
int count=0;
#endif
+ THD *thd= current_thd;
+
DBUG_ENTER("close_connections");
/* Clear thread cache */
@@ -5193,118 +5189,137 @@ struct show_var_st status_vars[]= {
{"Aborted_connects", (char*) &aborted_connects, SHOW_LONG},
{"Binlog_cache_disk_use", (char*) &binlog_cache_disk_use, SHOW_LONG},
{"Binlog_cache_use", (char*) &binlog_cache_use, SHOW_LONG},
- {"Bytes_received", (char*) &bytes_received, SHOW_LONG},
- {"Bytes_sent", (char*) &bytes_sent, SHOW_LONG},
- {"Com_admin_commands", (char*) &com_other, SHOW_LONG},
- {"Com_alter_db", (char*) (com_stat+(uint) SQLCOM_ALTER_DB),SHOW_LONG},
- {"Com_alter_table", (char*) (com_stat+(uint) SQLCOM_ALTER_TABLE),SHOW_LONG},
- {"Com_analyze", (char*) (com_stat+(uint) SQLCOM_ANALYZE),SHOW_LONG},
- {"Com_backup_table", (char*) (com_stat+(uint) SQLCOM_BACKUP_TABLE),SHOW_LONG},
- {"Com_begin", (char*) (com_stat+(uint) SQLCOM_BEGIN),SHOW_LONG},
- {"Com_change_db", (char*) (com_stat+(uint) SQLCOM_CHANGE_DB),SHOW_LONG},
- {"Com_change_master", (char*) (com_stat+(uint) SQLCOM_CHANGE_MASTER),SHOW_LONG},
- {"Com_check", (char*) (com_stat+(uint) SQLCOM_CHECK),SHOW_LONG},
- {"Com_checksum", (char*) (com_stat+(uint) SQLCOM_CHECKSUM),SHOW_LONG},
- {"Com_commit", (char*) (com_stat+(uint) SQLCOM_COMMIT),SHOW_LONG},
- {"Com_create_db", (char*) (com_stat+(uint) SQLCOM_CREATE_DB),SHOW_LONG},
- {"Com_create_function", (char*) (com_stat+(uint) SQLCOM_CREATE_FUNCTION),SHOW_LONG},
- {"Com_create_index", (char*) (com_stat+(uint) SQLCOM_CREATE_INDEX),SHOW_LONG},
- {"Com_create_table", (char*) (com_stat+(uint) SQLCOM_CREATE_TABLE),SHOW_LONG},
- {"Com_dealloc_sql", (char*) (com_stat+(uint)
- SQLCOM_DEALLOCATE_PREPARE), SHOW_LONG},
- {"Com_delete", (char*) (com_stat+(uint) SQLCOM_DELETE),SHOW_LONG},
- {"Com_delete_multi", (char*) (com_stat+(uint) SQLCOM_DELETE_MULTI),SHOW_LONG},
- {"Com_do", (char*) (com_stat+(uint) SQLCOM_DO),SHOW_LONG},
- {"Com_drop_db", (char*) (com_stat+(uint) SQLCOM_DROP_DB),SHOW_LONG},
- {"Com_drop_function", (char*) (com_stat+(uint) SQLCOM_DROP_FUNCTION),SHOW_LONG},
- {"Com_drop_index", (char*) (com_stat+(uint) SQLCOM_DROP_INDEX),SHOW_LONG},
- {"Com_drop_table", (char*) (com_stat+(uint) SQLCOM_DROP_TABLE),SHOW_LONG},
- {"Com_drop_user", (char*) (com_stat+(uint) SQLCOM_DROP_USER),SHOW_LONG},
- {"Com_execute_sql", (char*) (com_stat+(uint) SQLCOM_EXECUTE),
- SHOW_LONG},
- {"Com_flush", (char*) (com_stat+(uint) SQLCOM_FLUSH),SHOW_LONG},
- {"Com_grant", (char*) (com_stat+(uint) SQLCOM_GRANT),SHOW_LONG},
- {"Com_ha_close", (char*) (com_stat+(uint) SQLCOM_HA_CLOSE),SHOW_LONG},
- {"Com_ha_open", (char*) (com_stat+(uint) SQLCOM_HA_OPEN),SHOW_LONG},
- {"Com_ha_read", (char*) (com_stat+(uint) SQLCOM_HA_READ),SHOW_LONG},
- {"Com_help", (char*) (com_stat+(uint) SQLCOM_HELP),SHOW_LONG},
- {"Com_insert", (char*) (com_stat+(uint) SQLCOM_INSERT),SHOW_LONG},
- {"Com_insert_select", (char*) (com_stat+(uint) SQLCOM_INSERT_SELECT),SHOW_LONG},
- {"Com_kill", (char*) (com_stat+(uint) SQLCOM_KILL),SHOW_LONG},
- {"Com_load", (char*) (com_stat+(uint) SQLCOM_LOAD),SHOW_LONG},
- {"Com_load_master_data", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_DATA),SHOW_LONG},
- {"Com_load_master_table", (char*) (com_stat+(uint) SQLCOM_LOAD_MASTER_TABLE),SHOW_LONG},
- {"Com_lock_tables", (char*) (com_stat+(uint) SQLCOM_LOCK_TABLES),SHOW_LONG},
- {"Com_optimize", (char*) (com_stat+(uint) SQLCOM_OPTIMIZE),SHOW_LONG},
- {"Com_preload_keys", (char*) (com_stat+(uint) SQLCOM_PRELOAD_KEYS),SHOW_LONG},
- {"Com_prepare_sql", (char*) (com_stat+(uint) SQLCOM_PREPARE),
- SHOW_LONG},
- {"Com_purge", (char*) (com_stat+(uint) SQLCOM_PURGE),SHOW_LONG},
- {"Com_purge_before_date", (char*) (com_stat+(uint) SQLCOM_PURGE_BEFORE),SHOW_LONG},
- {"Com_rename_table", (char*) (com_stat+(uint) SQLCOM_RENAME_TABLE),SHOW_LONG},
- {"Com_repair", (char*) (com_stat+(uint) SQLCOM_REPAIR),SHOW_LONG},
- {"Com_replace", (char*) (com_stat+(uint) SQLCOM_REPLACE),SHOW_LONG},
- {"Com_replace_select", (char*) (com_stat+(uint) SQLCOM_REPLACE_SELECT),SHOW_LONG},
- {"Com_reset", (char*) (com_stat+(uint) SQLCOM_RESET),SHOW_LONG},
- {"Com_restore_table", (char*) (com_stat+(uint) SQLCOM_RESTORE_TABLE),SHOW_LONG},
- {"Com_revoke", (char*) (com_stat+(uint) SQLCOM_REVOKE),SHOW_LONG},
- {"Com_revoke_all", (char*) (com_stat+(uint) SQLCOM_REVOKE_ALL),SHOW_LONG},
- {"Com_rollback", (char*) (com_stat+(uint) SQLCOM_ROLLBACK),SHOW_LONG},
- {"Com_savepoint", (char*) (com_stat+(uint) SQLCOM_SAVEPOINT),SHOW_LONG},
- {"Com_select", (char*) (com_stat+(uint) SQLCOM_SELECT),SHOW_LONG},
- {"Com_set_option", (char*) (com_stat+(uint) SQLCOM_SET_OPTION),SHOW_LONG},
- {"Com_show_binlog_events", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOG_EVENTS),SHOW_LONG},
- {"Com_show_binlogs", (char*) (com_stat+(uint) SQLCOM_SHOW_BINLOGS),SHOW_LONG},
- {"Com_show_charsets", (char*) (com_stat+(uint) SQLCOM_SHOW_CHARSETS),SHOW_LONG},
- {"Com_show_collations", (char*) (com_stat+(uint) SQLCOM_SHOW_COLLATIONS),SHOW_LONG},
- {"Com_show_column_types", (char*) (com_stat+(uint) SQLCOM_SHOW_COLUMN_TYPES),SHOW_LONG},
- {"Com_show_create_db", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE_DB),SHOW_LONG},
- {"Com_show_create_table", (char*) (com_stat+(uint) SQLCOM_SHOW_CREATE),SHOW_LONG},
- {"Com_show_databases", (char*) (com_stat+(uint) SQLCOM_SHOW_DATABASES),SHOW_LONG},
- {"Com_show_errors", (char*) (com_stat+(uint) SQLCOM_SHOW_ERRORS),SHOW_LONG},
- {"Com_show_fields", (char*) (com_stat+(uint) SQLCOM_SHOW_FIELDS),SHOW_LONG},
- {"Com_show_grants", (char*) (com_stat+(uint) SQLCOM_SHOW_GRANTS),SHOW_LONG},
- {"Com_show_innodb_status", (char*) (com_stat+(uint) SQLCOM_SHOW_INNODB_STATUS),SHOW_LONG},
- {"Com_show_keys", (char*) (com_stat+(uint) SQLCOM_SHOW_KEYS),SHOW_LONG},
- {"Com_show_logs", (char*) (com_stat+(uint) SQLCOM_SHOW_LOGS),SHOW_LONG},
- {"Com_show_master_status", (char*) (com_stat+(uint) SQLCOM_SHOW_MASTER_STAT),SHOW_LONG},
- {"Com_show_new_master", (char*) (com_stat+(uint) SQLCOM_SHOW_NEW_MASTER),SHOW_LONG},
- {"Com_show_open_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_OPEN_TABLES),SHOW_LONG},
- {"Com_show_privileges", (char*) (com_stat+(uint) SQLCOM_SHOW_PRIVILEGES),SHOW_LONG},
- {"Com_show_processlist", (char*) (com_stat+(uint) SQLCOM_SHOW_PROCESSLIST),SHOW_LONG},
- {"Com_show_slave_hosts", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_HOSTS),SHOW_LONG},
- {"Com_show_slave_status", (char*) (com_stat+(uint) SQLCOM_SHOW_SLAVE_STAT),SHOW_LONG},
- {"Com_show_status", (char*) (com_stat+(uint) SQLCOM_SHOW_STATUS),SHOW_LONG},
- {"Com_show_storage_engines", (char*) (com_stat+(uint) SQLCOM_SHOW_STORAGE_ENGINES),SHOW_LONG},
- {"Com_show_tables", (char*) (com_stat+(uint) SQLCOM_SHOW_TABLES),SHOW_LONG},
- {"Com_show_variables", (char*) (com_stat+(uint) SQLCOM_SHOW_VARIABLES),SHOW_LONG},
- {"Com_show_warnings", (char*) (com_stat+(uint) SQLCOM_SHOW_WARNS),SHOW_LONG},
- {"Com_slave_start", (char*) (com_stat+(uint) SQLCOM_SLAVE_START),SHOW_LONG},
- {"Com_slave_stop", (char*) (com_stat+(uint) SQLCOM_SLAVE_STOP),SHOW_LONG},
- {"Com_truncate", (char*) (com_stat+(uint) SQLCOM_TRUNCATE),SHOW_LONG},
- {"Com_unlock_tables", (char*) (com_stat+(uint) SQLCOM_UNLOCK_TABLES),SHOW_LONG},
- {"Com_update", (char*) (com_stat+(uint) SQLCOM_UPDATE),SHOW_LONG},
- {"Com_update_multi", (char*) (com_stat+(uint) SQLCOM_UPDATE_MULTI),SHOW_LONG},
+ {"Bytes_received", (char*) offsetof(STATUS_VAR, bytes_received),
+ SHOW_LONG_STATUS},
+ {"Bytes_sent", (char*) offsetof(STATUS_VAR, bytes_sent),
+ SHOW_LONG_STATUS},
+ {"Com_admin_commands", (char*) offsetof(STATUS_VAR, com_other),
+ SHOW_LONG_STATUS},
+ {"Com_alter_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_DB]), SHOW_LONG_STATUS},
+ {"Com_alter_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_TABLE]), SHOW_LONG_STATUS},
+ {"Com_analyze", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ANALYZE]), SHOW_LONG_STATUS},
+ {"Com_backup_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_BACKUP_TABLE]), SHOW_LONG_STATUS},
+ {"Com_begin", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_BEGIN]), SHOW_LONG_STATUS},
+ {"Com_change_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHANGE_DB]), SHOW_LONG_STATUS},
+ {"Com_change_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHANGE_MASTER]), SHOW_LONG_STATUS},
+ {"Com_check", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHECK]), SHOW_LONG_STATUS},
+ {"Com_checksum", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHECKSUM]), SHOW_LONG_STATUS},
+ {"Com_commit", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_COMMIT]), SHOW_LONG_STATUS},
+ {"Com_create_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_DB]), SHOW_LONG_STATUS},
+ {"Com_create_function", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_FUNCTION]), SHOW_LONG_STATUS},
+ {"Com_create_index", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_INDEX]), SHOW_LONG_STATUS},
+ {"Com_create_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_TABLE]), SHOW_LONG_STATUS},
+ {"Com_dealloc_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DEALLOCATE_PREPARE]), SHOW_LONG_STATUS},
+ {"Com_delete", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DELETE]), SHOW_LONG_STATUS},
+ {"Com_delete_multi", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DELETE_MULTI]), SHOW_LONG_STATUS},
+ {"Com_do", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DO]), SHOW_LONG_STATUS},
+ {"Com_drop_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_DB]), SHOW_LONG_STATUS},
+ {"Com_drop_function", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_FUNCTION]), SHOW_LONG_STATUS},
+ {"Com_drop_index", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_INDEX]), SHOW_LONG_STATUS},
+ {"Com_drop_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_TABLE]), SHOW_LONG_STATUS},
+ {"Com_drop_user", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_USER]), SHOW_LONG_STATUS},
+ {"Com_execute_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_EXECUTE]), SHOW_LONG_STATUS},
+ {"Com_flush", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_FLUSH]), SHOW_LONG_STATUS},
+ {"Com_grant", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_GRANT]), SHOW_LONG_STATUS},
+ {"Com_ha_close", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HA_CLOSE]), SHOW_LONG_STATUS},
+ {"Com_ha_open", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HA_OPEN]), SHOW_LONG_STATUS},
+ {"Com_ha_read", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HA_READ]), SHOW_LONG_STATUS},
+ {"Com_help", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_HELP]), SHOW_LONG_STATUS},
+ {"Com_insert", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_INSERT]), SHOW_LONG_STATUS},
+ {"Com_insert_select", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_INSERT_SELECT]), SHOW_LONG_STATUS},
+ {"Com_kill", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_KILL]), SHOW_LONG_STATUS},
+ {"Com_load", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOAD]), SHOW_LONG_STATUS},
+ {"Com_load_master_data", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOAD_MASTER_DATA]), SHOW_LONG_STATUS},
+ {"Com_load_master_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOAD_MASTER_TABLE]), SHOW_LONG_STATUS},
+ {"Com_lock_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_LOCK_TABLES]), SHOW_LONG_STATUS},
+ {"Com_optimize", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_OPTIMIZE]), SHOW_LONG_STATUS},
+ {"Com_preload_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PRELOAD_KEYS]), SHOW_LONG_STATUS},
+ {"Com_prepare_sql", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PREPARE]), SHOW_LONG_STATUS},
+ {"Com_purge", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PURGE]), SHOW_LONG_STATUS},
+ {"Com_purge_before_date", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_PURGE_BEFORE]), SHOW_LONG_STATUS},
+ {"Com_rename_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RENAME_TABLE]), SHOW_LONG_STATUS},
+ {"Com_repair", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPAIR]), SHOW_LONG_STATUS},
+ {"Com_replace", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPLACE]), SHOW_LONG_STATUS},
+ {"Com_replace_select", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REPLACE_SELECT]), SHOW_LONG_STATUS},
+ {"Com_reset", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESET]), SHOW_LONG_STATUS},
+ {"Com_restore_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_RESTORE_TABLE]), SHOW_LONG_STATUS},
+ {"Com_revoke", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REVOKE]), SHOW_LONG_STATUS},
+ {"Com_revoke_all", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_REVOKE_ALL]), SHOW_LONG_STATUS},
+ {"Com_rollback", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ROLLBACK]), SHOW_LONG_STATUS},
+ {"Com_savepoint", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SAVEPOINT]), SHOW_LONG_STATUS},
+ {"Com_select", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SELECT]), SHOW_LONG_STATUS},
+ {"Com_set_option", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SET_OPTION]), SHOW_LONG_STATUS},
+ {"Com_show_binlogs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOGS]), SHOW_LONG_STATUS},
+ {"Com_show_binlog_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_BINLOG_EVENTS]), SHOW_LONG_STATUS},
+ {"Com_show_charsets", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CHARSETS]), SHOW_LONG_STATUS},
+ {"Com_show_collations", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLLATIONS]), SHOW_LONG_STATUS},
+ {"Com_show_column_types", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLUMN_TYPES]), SHOW_LONG_STATUS},
+ {"Com_show_create_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CREATE]), SHOW_LONG_STATUS},
+ {"Com_show_create_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CREATE_DB]), SHOW_LONG_STATUS},
+ {"Com_show_databases", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_DATABASES]), SHOW_LONG_STATUS},
+ {"Com_show_errors", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_ERRORS]), SHOW_LONG_STATUS},
+ {"Com_show_fields", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_FIELDS]), SHOW_LONG_STATUS},
+ {"Com_show_grants", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_GRANTS]), SHOW_LONG_STATUS},
+ {"Com_show_innodb_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_INNODB_STATUS]), SHOW_LONG_STATUS},
+ {"Com_show_keys", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_KEYS]), SHOW_LONG_STATUS},
+ {"Com_show_logs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_LOGS]), SHOW_LONG_STATUS},
+ {"Com_show_master_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_MASTER_STAT]), SHOW_LONG_STATUS},
+ {"Com_show_new_master", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_NEW_MASTER]), SHOW_LONG_STATUS},
+ {"Com_show_open_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_OPEN_TABLES]), SHOW_LONG_STATUS},
+ {"Com_show_privileges", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PRIVILEGES]), SHOW_LONG_STATUS},
+ {"Com_show_processlist", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_PROCESSLIST]), SHOW_LONG_STATUS},
+ {"Com_show_slave_hosts", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_HOSTS]), SHOW_LONG_STATUS},
+ {"Com_show_slave_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_SLAVE_STAT]), SHOW_LONG_STATUS},
+ {"Com_show_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STATUS]), SHOW_LONG_STATUS},
+ {"Com_show_storage_engines", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_STORAGE_ENGINES]), SHOW_LONG_STATUS},
+ {"Com_show_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_TABLES]), SHOW_LONG_STATUS},
+ {"Com_show_variables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_VARIABLES]), SHOW_LONG_STATUS},
+ {"Com_show_warnings", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_WARNS]), SHOW_LONG_STATUS},
+ {"Com_slave_start", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_START]), SHOW_LONG_STATUS},
+ {"Com_slave_stop", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SLAVE_STOP]), SHOW_LONG_STATUS},
+ {"Com_truncate", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_TRUNCATE]), SHOW_LONG_STATUS},
+ {"Com_unlock_tables", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UNLOCK_TABLES]), SHOW_LONG_STATUS},
+ {"Com_update", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UPDATE]), SHOW_LONG_STATUS},
+ {"Com_update_multi", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_UPDATE_MULTI]), SHOW_LONG_STATUS},
{"Connections", (char*) &thread_id, SHOW_LONG_CONST},
- {"Created_tmp_disk_tables", (char*) &created_tmp_disk_tables,SHOW_LONG},
+ {"Created_tmp_disk_tables", (char*) offsetof(STATUS_VAR,
+ created_tmp_disk_tables),
+ SHOW_LONG_STATUS},
{"Created_tmp_files", (char*) &my_tmp_file_created, SHOW_LONG},
- {"Created_tmp_tables", (char*) &created_tmp_tables, SHOW_LONG},
+ {"Created_tmp_tables", (char*) offsetof(STATUS_VAR,
+ created_tmp_tables),
+ SHOW_LONG_STATUS},
{"Delayed_errors", (char*) &delayed_insert_errors, SHOW_LONG},
{"Delayed_insert_threads", (char*) &delayed_insert_threads, SHOW_LONG_CONST},
{"Delayed_writes", (char*) &delayed_insert_writes, SHOW_LONG},
{"Flush_commands", (char*) &refresh_version, SHOW_LONG_CONST},
- {"Handler_commit", (char*) &ha_commit_count, SHOW_LONG},
- {"Handler_delete", (char*) &ha_delete_count, SHOW_LONG},
+ {"Handler_commit", (char*) offsetof(STATUS_VAR, ha_commit_count),
+ SHOW_LONG_STATUS},
+ {"Handler_delete", (char*) offsetof(STATUS_VAR, ha_delete_count),
+ SHOW_LONG_STATUS},
{"Handler_discover", (char*) &ha_discover_count, SHOW_LONG},
- {"Handler_read_first", (char*) &ha_read_first_count, SHOW_LONG},
- {"Handler_read_key", (char*) &ha_read_key_count, SHOW_LONG},
- {"Handler_read_next", (char*) &ha_read_next_count, SHOW_LONG},
- {"Handler_read_prev", (char*) &ha_read_prev_count, SHOW_LONG},
- {"Handler_read_rnd", (char*) &ha_read_rnd_count, SHOW_LONG},
- {"Handler_read_rnd_next", (char*) &ha_read_rnd_next_count, SHOW_LONG},
- {"Handler_rollback", (char*) &ha_rollback_count, SHOW_LONG},
- {"Handler_update", (char*) &ha_update_count, SHOW_LONG},
- {"Handler_write", (char*) &ha_write_count, SHOW_LONG},
+ {"Handler_read_first", (char*) offsetof(STATUS_VAR,
+ ha_read_first_count),
+ SHOW_LONG_STATUS},
+ {"Handler_read_key", (char*) offsetof(STATUS_VAR, ha_read_key_count),
+ SHOW_LONG_STATUS},
+ {"Handler_read_next", (char*) offsetof(STATUS_VAR,
+ ha_read_next_count),
+ SHOW_LONG_STATUS},
+ {"Handler_read_prev", (char*) offsetof(STATUS_VAR,
+ ha_read_prev_count),
+ SHOW_LONG_STATUS},
+ {"Handler_read_rnd", (char*) offsetof(STATUS_VAR, ha_read_rnd_count),
+ SHOW_LONG_STATUS},
+ {"Handler_read_rnd_next", (char*) offsetof(STATUS_VAR,
+ ha_read_rnd_next_count),
+ SHOW_LONG_STATUS},
+ {"Handler_rollback", (char*) offsetof(STATUS_VAR, ha_rollback_count),
+ SHOW_LONG_STATUS},
+ {"Handler_update", (char*) offsetof(STATUS_VAR, ha_update_count),
+ SHOW_LONG_STATUS},
+ {"Handler_write", (char*) offsetof(STATUS_VAR, ha_write_count),
+ SHOW_LONG_STATUS},
{"Key_blocks_not_flushed", (char*) &dflt_key_cache_var.global_blocks_changed,
SHOW_KEY_CACHE_LONG},
{"Key_blocks_unused", (char*) &dflt_key_cache_var.blocks_unused,
@@ -5325,7 +5340,8 @@ struct show_var_st status_vars[]= {
{"Open_files", (char*) &my_file_opened, SHOW_LONG_CONST},
{"Open_streams", (char*) &my_stream_opened, SHOW_LONG_CONST},
{"Open_tables", (char*) 0, SHOW_OPENTABLES},
- {"Opened_tables", (char*) &opened_tables, SHOW_LONG},
+ {"Opened_tables", (char*) offsetof(STATUS_VAR, opened_tables),
+ SHOW_LONG_STATUS},
#ifdef HAVE_QUERY_CACHE
{"Qcache_free_blocks", (char*) &query_cache.free_memory_blocks,
SHOW_LONG_CONST},
@@ -5341,19 +5357,36 @@ struct show_var_st status_vars[]= {
#endif /*HAVE_QUERY_CACHE*/
{"Questions", (char*) 0, SHOW_QUESTION},
{"Rpl_status", (char*) 0, SHOW_RPL_STATUS},
- {"Select_full_join", (char*) &select_full_join_count, SHOW_LONG},
- {"Select_full_range_join", (char*) &select_full_range_join_count, SHOW_LONG},
- {"Select_range", (char*) &select_range_count, SHOW_LONG},
- {"Select_range_check", (char*) &select_range_check_count, SHOW_LONG},
- {"Select_scan", (char*) &select_scan_count, SHOW_LONG},
+ {"Select_full_join", (char*) offsetof(STATUS_VAR,
+ select_full_join_count),
+ SHOW_LONG_STATUS},
+ {"Select_full_range_join", (char*) offsetof(STATUS_VAR,
+ select_full_range_join_count),
+ SHOW_LONG_STATUS},
+ {"Select_range", (char*) offsetof(STATUS_VAR,
+ select_range_count),
+ SHOW_LONG_STATUS},
+ {"Select_range_check", (char*) offsetof(STATUS_VAR,
+ select_range_check_count),
+ SHOW_LONG_STATUS},
+ {"Select_scan", (char*) offsetof(STATUS_VAR, select_scan_count),
+ SHOW_LONG_STATUS},
{"Slave_open_temp_tables", (char*) &slave_open_temp_tables, SHOW_LONG},
{"Slave_running", (char*) 0, SHOW_SLAVE_RUNNING},
{"Slow_launch_threads", (char*) &slow_launch_threads, SHOW_LONG},
- {"Slow_queries", (char*) &long_query_count, SHOW_LONG},
- {"Sort_merge_passes", (char*) &filesort_merge_passes, SHOW_LONG},
- {"Sort_range", (char*) &filesort_range_count, SHOW_LONG},
- {"Sort_rows", (char*) &filesort_rows, SHOW_LONG},
- {"Sort_scan", (char*) &filesort_scan_count, SHOW_LONG},
+ {"Slow_queries", (char*) offsetof(STATUS_VAR, long_query_count),
+ SHOW_LONG_STATUS},
+ {"Sort_merge_passes", (char*) offsetof(STATUS_VAR,
+ filesort_merge_passes),
+ SHOW_LONG_STATUS},
+ {"Sort_range", (char*) offsetof(STATUS_VAR,
+ filesort_range_count),
+ SHOW_LONG_STATUS},
+ {"Sort_rows", (char*) offsetof(STATUS_VAR, filesort_rows),
+ SHOW_LONG_STATUS},
+ {"Sort_scan", (char*) offsetof(STATUS_VAR,
+ filesort_scan_count),
+ SHOW_LONG_STATUS},
#ifdef HAVE_OPENSSL
{"Ssl_accept_renegotiates", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT_RENEGOTIATE},
{"Ssl_accepts", (char*) 0, SHOW_SSL_CTX_SESS_ACCEPT},
@@ -5484,27 +5517,22 @@ static void mysql_init_variables(void)
test_flags= select_errors= dropping_tables= ha_open_options=0;
thread_count= thread_running= kill_cached_threads= wake_thread=0;
slave_open_temp_tables= 0;
- com_other= 0;
cached_thread_count= 0;
- bytes_sent= bytes_received= 0;
opt_endinfo= using_udf_functions= 0;
opt_using_transactions= using_update_log= 0;
abort_loop= select_thread_in_use= signal_thread_in_use= 0;
ready_to_exit= shutdown_in_progress= grant_option= 0;
- long_query_count= aborted_threads= aborted_connects= 0;
+ aborted_threads= aborted_connects= 0;
delayed_insert_threads= delayed_insert_writes= delayed_rows_in_use= 0;
delayed_insert_errors= thread_created= 0;
- filesort_rows= filesort_range_count= filesort_scan_count= 0;
- filesort_merge_passes= select_range_check_count= select_range_count= 0;
- select_scan_count= select_full_range_join_count= select_full_join_count= 0;
- specialflag= opened_tables= created_tmp_tables= created_tmp_disk_tables= 0;
+ specialflag= 0;
binlog_cache_use= binlog_cache_disk_use= 0;
max_used_connections= slow_launch_threads = 0;
mysqld_user= mysqld_chroot= opt_init_file= opt_bin_logname = 0;
errmesg= 0;
mysqld_unix_port= opt_mysql_tmpdir= my_bind_addr_str= NullS;
bzero((gptr) &mysql_tmpdir_list, sizeof(mysql_tmpdir_list));
- bzero((gptr) &com_stat, sizeof(com_stat));
+ bzero((char *) &global_status_var, sizeof(global_status_var));
/* Character sets */
system_charset_info= &my_charset_utf8_general_ci;
diff --git a/sql/net_serv.cc b/sql/net_serv.cc
index 36a10370508..82a3b1bd520 100644
--- a/sql/net_serv.cc
+++ b/sql/net_serv.cc
@@ -103,11 +103,10 @@ extern uint test_flags;
extern ulong bytes_sent, bytes_received, net_big_packet_count;
extern pthread_mutex_t LOCK_bytes_sent , LOCK_bytes_received;
extern void query_cache_insert(NET *net, const char *packet, ulong length);
+#define update_statistics(A) A
#else
-#undef statistic_add
-#undef statistic_increment
-#define statistic_add(A,B,C)
-#define statistic_increment(A,B)
+#define update_statistics(A)
+#define thd_increment_bytes_sent()
#endif
#define TEST_BLOCKING 8
@@ -565,7 +564,7 @@ net_real_write(NET *net,const char *packet,ulong len)
break;
}
pos+=length;
- statistic_add(bytes_sent,length,&LOCK_bytes_sent);
+ update_statistics(thd_increment_bytes_sent(length));
}
#ifndef __WIN__
end:
@@ -636,7 +635,7 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
DBUG_PRINT("enter",("bytes_to_skip: %u", (uint) remain));
/* The following is good for debugging */
- statistic_increment(net_big_packet_count,&LOCK_bytes_received);
+ update_statistics(thd_increment_net_big_packet_count(1));
if (!thr_alarm_in_use(alarmed))
{
@@ -652,7 +651,7 @@ static my_bool my_net_skip_rest(NET *net, uint32 remain, thr_alarm_t *alarmed,
uint length= min(remain, net->max_packet);
if (net_safe_read(net, (char*) net->buff, length, alarmed))
DBUG_RETURN(1);
- statistic_add(bytes_received, length, &LOCK_bytes_received);
+ update_statistics(thd_increment_bytes_received(length));
remain -= (uint32) length;
}
if (old != MAX_PACKET_LENGTH)
@@ -777,7 +776,7 @@ my_real_read(NET *net, ulong *complen)
}
remain -= (uint32) length;
pos+= (ulong) length;
- statistic_add(bytes_received,(ulong) length,&LOCK_bytes_received);
+ update_statistics(thd_increment_bytes_received(length));
}
if (i == 0)
{ /* First parts is packet length */
diff --git a/sql/parse_file.cc b/sql/parse_file.cc
index 729f49dcbbe..d10d395d6e5 100644
--- a/sql/parse_file.cc
+++ b/sql/parse_file.cc
@@ -46,7 +46,7 @@ write_escaped_string(IO_CACHE *file, LEX_STRING *val_s)
{
/*
Should be in sync with read_escaped_string() and
- parse_quated_escaped_string()
+ parse_quoted_escaped_string()
*/
switch(*ptr) {
case '\\': // escape character
@@ -154,11 +154,10 @@ write_parameter(IO_CACHE *file, gptr base, File_option *parameter,
LEX_STRING *str;
while ((str= it++))
{
- num.set((ulonglong)str->length, &my_charset_bin);
- // ',' after string to detect list continuation
+ // We need ' ' after string to detect list continuation
if ((!first && my_b_append(file, (const byte *)" ", 1)) ||
my_b_append(file, (const byte *)"\'", 1) ||
- my_b_append(file, (const byte *)str->str, str->length) ||
+ write_escaped_string(file, str) ||
my_b_append(file, (const byte *)"\'", 1))
{
DBUG_RETURN(TRUE);
@@ -486,7 +485,7 @@ read_escaped_string(char *ptr, char *eol, LEX_STRING *str)
return TRUE;
/*
Should be in sync with write_escaped_string() and
- parse_quated_escaped_string()
+ parse_quoted_escaped_string()
*/
switch(*ptr) {
case '\\':
@@ -562,7 +561,7 @@ parse_escaped_string(char *ptr, char *end, MEM_ROOT *mem_root, LEX_STRING *str)
*/
static char *
-parse_quated_escaped_string(char *ptr, char *end,
+parse_quoted_escaped_string(char *ptr, char *end,
MEM_ROOT *mem_root, LEX_STRING *str)
{
char *eol;
@@ -684,7 +683,6 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root,
my_error(ER_FPARSER_ERROR_IN_PARAMETER, MYF(0),
parameter->name.str, line);
DBUG_RETURN(TRUE);
- DBUG_RETURN(TRUE);
}
break;
}
@@ -724,6 +722,7 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root,
/*
TODO: remove play with mem_root, when List will be able
to store MEM_ROOT* pointer for list elements allocation
+ FIXME: we can't handle empty lists
*/
sql_mem= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
list= (List<LEX_STRING>*)(base + parameter->offset);
@@ -741,7 +740,7 @@ File_parser::parse(gptr base, MEM_ROOT *mem_root,
sizeof(LEX_STRING))) ||
list->push_back(str))
goto list_err;
- if(!(ptr= parse_quated_escaped_string(ptr, end, mem_root, str)))
+ if(!(ptr= parse_quoted_escaped_string(ptr, end, mem_root, str)))
goto list_err_w_message;
switch (*ptr) {
case '\n':
diff --git a/sql/parse_file.h b/sql/parse_file.h
index 6a426aa0423..cf34a5095a4 100644
--- a/sql/parse_file.h
+++ b/sql/parse_file.h
@@ -27,7 +27,8 @@ enum file_opt_type {
FILE_OPTIONS_REV, /* Revision version number (ulonglong) */
FILE_OPTIONS_TIMESTAMP, /* timestamp (LEX_STRING have to be
allocated with length 20 (19+1) */
- FILE_OPTIONS_STRLIST /* list of strings (List<char*>) */
+ FILE_OPTIONS_STRLIST /* list of escaped strings
+ (List<LEX_STRING>) */
};
struct File_option
diff --git a/sql/protocol_cursor.cc b/sql/protocol_cursor.cc
index 31eaa894045..8904aba7b88 100644
--- a/sql/protocol_cursor.cc
+++ b/sql/protocol_cursor.cc
@@ -112,7 +112,8 @@ bool Protocol_cursor::write()
for (; cur_field < fields_end; ++cur_field, ++data_tmp)
{
- if ((len= net_field_length((uchar **)&cp)) == 0)
+ if ((len= net_field_length((uchar **)&cp)) == 0 ||
+ len == NULL_LENGTH)
{
*data_tmp= 0;
}
diff --git a/sql/share/czech/errmsg.txt b/sql/share/czech/errmsg.txt
index 68f5fbff13c..c613a22088a 100644
--- a/sql/share/czech/errmsg.txt
+++ b/sql/share/czech/errmsg.txt
@@ -387,3 +387,8 @@ character-set=latin2
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/danish/errmsg.txt b/sql/share/danish/errmsg.txt
index 1153bbecbc8..0f3a8f6ffdb 100644
--- a/sql/share/danish/errmsg.txt
+++ b/sql/share/danish/errmsg.txt
@@ -378,3 +378,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/dutch/errmsg.txt b/sql/share/dutch/errmsg.txt
index 67b0934f2d2..d0d86a07b7e 100644
--- a/sql/share/dutch/errmsg.txt
+++ b/sql/share/dutch/errmsg.txt
@@ -387,3 +387,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/english/errmsg.txt b/sql/share/english/errmsg.txt
index cfe46055bbc..0b502244a64 100644
--- a/sql/share/english/errmsg.txt
+++ b/sql/share/english/errmsg.txt
@@ -375,3 +375,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/estonian/errmsg.txt b/sql/share/estonian/errmsg.txt
index e4c139d31b1..7886c785c40 100644
--- a/sql/share/estonian/errmsg.txt
+++ b/sql/share/estonian/errmsg.txt
@@ -380,3 +380,8 @@ character-set=latin7
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/french/errmsg.txt b/sql/share/french/errmsg.txt
index ee9e784ada6..9668cbf3c9f 100644
--- a/sql/share/french/errmsg.txt
+++ b/sql/share/french/errmsg.txt
@@ -375,3 +375,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/german/errmsg.txt b/sql/share/german/errmsg.txt
index 9bd7665ac97..c2c82443f91 100644
--- a/sql/share/german/errmsg.txt
+++ b/sql/share/german/errmsg.txt
@@ -388,3 +388,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/greek/errmsg.txt b/sql/share/greek/errmsg.txt
index e8ed72f6a0f..3aac21ec481 100644
--- a/sql/share/greek/errmsg.txt
+++ b/sql/share/greek/errmsg.txt
@@ -375,3 +375,8 @@ character-set=greek
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/hungarian/errmsg.txt b/sql/share/hungarian/errmsg.txt
index bd4f4e56d52..8f96a0bf183 100644
--- a/sql/share/hungarian/errmsg.txt
+++ b/sql/share/hungarian/errmsg.txt
@@ -380,3 +380,8 @@ character-set=latin2
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/italian/errmsg.txt b/sql/share/italian/errmsg.txt
index f1c9b10c8d4..8d63656bac2 100644
--- a/sql/share/italian/errmsg.txt
+++ b/sql/share/italian/errmsg.txt
@@ -375,3 +375,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/japanese/errmsg.txt b/sql/share/japanese/errmsg.txt
index 03af38e9172..30eb8daffa4 100644
--- a/sql/share/japanese/errmsg.txt
+++ b/sql/share/japanese/errmsg.txt
@@ -379,3 +379,8 @@ character-set=ujis
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/korean/errmsg.txt b/sql/share/korean/errmsg.txt
index 43b0cd2640e..dac28683a78 100644
--- a/sql/share/korean/errmsg.txt
+++ b/sql/share/korean/errmsg.txt
@@ -375,3 +375,8 @@ character-set=euckr
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/norwegian-ny/errmsg.txt b/sql/share/norwegian-ny/errmsg.txt
index b542ffb6a62..58661f16bcf 100644
--- a/sql/share/norwegian-ny/errmsg.txt
+++ b/sql/share/norwegian-ny/errmsg.txt
@@ -377,3 +377,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/norwegian/errmsg.txt b/sql/share/norwegian/errmsg.txt
index a435479f8a0..ea204145d54 100644
--- a/sql/share/norwegian/errmsg.txt
+++ b/sql/share/norwegian/errmsg.txt
@@ -377,3 +377,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/polish/errmsg.txt b/sql/share/polish/errmsg.txt
index 413e004cec1..db0d4914c19 100644
--- a/sql/share/polish/errmsg.txt
+++ b/sql/share/polish/errmsg.txt
@@ -380,3 +380,8 @@ character-set=latin2
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/portuguese/errmsg.txt b/sql/share/portuguese/errmsg.txt
index 85c8cd00dd5..d3508f120db 100644
--- a/sql/share/portuguese/errmsg.txt
+++ b/sql/share/portuguese/errmsg.txt
@@ -377,3 +377,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/romanian/errmsg.txt b/sql/share/romanian/errmsg.txt
index 1c7e2187084..65ab66e1256 100644
--- a/sql/share/romanian/errmsg.txt
+++ b/sql/share/romanian/errmsg.txt
@@ -380,3 +380,8 @@ character-set=latin2
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/russian/errmsg.txt b/sql/share/russian/errmsg.txt
index a9f1024db87..6501598383c 100644
--- a/sql/share/russian/errmsg.txt
+++ b/sql/share/russian/errmsg.txt
@@ -377,6 +377,11 @@ character-set=koi8r
"View SELECT É ÓÐÉÓÏË ÐÏÌÅÊ view ÉÍÅÀÔ ÒÁÚÎÏÅ ËÏÌÉÞÅÓÔ×Ï ÓÔÏÌÂÃÏ×"
"áÌÇÏÒÉÔÍ ÓÌÉÑÎÉÑ view ÎÅ ÍÏÖÅÔ ÂÙÔØ ÉÓÐÏÌØÚÏ×ÁÎ ÓÅÊÞÁÓ (ÁÌÇÏÒÉÔÍ ÂÕÄÅÔ ÎÅÏÐÅÒÅÄÅÌÅÎÎÙÍ)"
"ïÂÎÏ×ÌÑÅÍÙÊ view ÎÅ ÓÏÄÅÒÖÉÔ ËÌÀÞÁ ÉÓÐÏÌØÚÏ×ÁÎÎÏÊ × ÎÅÍ ÔÁÂÌÉÃ(Ù)"
-"View '%-.64s.%-.64s' ÓÓÙÌÁÅÔÓÑ ÎÁ ÎÅÓÕÝÅÓÔ×ÕÀÝÉÅ ÔÁÂÌÉÃÙ ÉÌÉ ÓÌÏÌÂÃÙ"
+"View '%-.64s.%-.64s' ÓÓÙÌÁÅÔÓÑ ÎÁ ÎÅÓÕÝÅÓÔ×ÕÀÝÉÅ ÔÁÂÌÉÃÙ ÉÌÉ ÓÔÏÌÂÃÙ"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/serbian/errmsg.txt b/sql/share/serbian/errmsg.txt
index 8f3bc3458e1..6e7826e33d6 100644
--- a/sql/share/serbian/errmsg.txt
+++ b/sql/share/serbian/errmsg.txt
@@ -368,3 +368,8 @@ character-set=cp1250
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/slovak/errmsg.txt b/sql/share/slovak/errmsg.txt
index c7b67540f2f..4c82ae5e3af 100644
--- a/sql/share/slovak/errmsg.txt
+++ b/sql/share/slovak/errmsg.txt
@@ -383,3 +383,8 @@ character-set=latin2
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/spanish/errmsg.txt b/sql/share/spanish/errmsg.txt
index c725caf93c0..c9a1d7229ea 100644
--- a/sql/share/spanish/errmsg.txt
+++ b/sql/share/spanish/errmsg.txt
@@ -379,3 +379,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/swedish/errmsg.txt b/sql/share/swedish/errmsg.txt
index 85d37c2ae9f..e80cb48d157 100644
--- a/sql/share/swedish/errmsg.txt
+++ b/sql/share/swedish/errmsg.txt
@@ -375,3 +375,8 @@ character-set=latin1
"View '%-.64s.%-.64s' references invalid table(s) or column(s)"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/share/ukrainian/errmsg.txt b/sql/share/ukrainian/errmsg.txt
index cd3917aa123..2a71aa088f4 100644
--- a/sql/share/ukrainian/errmsg.txt
+++ b/sql/share/ukrainian/errmsg.txt
@@ -381,3 +381,8 @@ character-set=koi8u
"View '%-.64s.%-.64s' ÐÏÓÉÌÁ¤ÔÓÑ ÎÁ ÎŦÓÎÕÀÞ¦ ÔÁÂÌÉæ ÁÂÏ ÓÔÏ×Âæ"
"Can't drop a %s from within another stored routine"
"GOTO is not allowed in a stored procedure handler"
+"Trigger already exists"
+"Trigger does not exist"
+"Trigger's '%-.64s' is view or temporary table"
+"Updating of %s row is not allowed in %strigger"
+"There is no %s row in %s trigger"
diff --git a/sql/sp_head.cc b/sql/sp_head.cc
index 8c35597fe99..6e4269ad8a5 100644
--- a/sql/sp_head.cc
+++ b/sql/sp_head.cc
@@ -293,26 +293,35 @@ sp_head::init_strings(THD *thd, LEX *lex, sp_name *name)
/* During parsing, we must use thd->mem_root */
MEM_ROOT *root= &thd->mem_root;
- DBUG_PRINT("info", ("name: %*.s%*s",
- name->m_db.length, name->m_db.str,
- name->m_name.length, name->m_name.str));
/* We have to copy strings to get them into the right memroot */
- m_db.length= name->m_db.length;
- if (name->m_db.length == 0)
- m_db.str= NULL;
- else
- m_db.str= strmake_root(root, name->m_db.str, name->m_db.length);
- m_name.length= name->m_name.length;
- m_name.str= strmake_root(root, name->m_name.str, name->m_name.length);
-
- if (name->m_qname.length == 0)
- name->init_qname(thd);
- m_qname.length= name->m_qname.length;
- m_qname.str= strmake_root(root, name->m_qname.str, m_qname.length);
-
- m_params.length= m_param_end- m_param_begin;
- m_params.str= strmake_root(root,
- (char *)m_param_begin, m_params.length);
+ if (name)
+ {
+ m_db.length= name->m_db.length;
+ if (name->m_db.length == 0)
+ m_db.str= NULL;
+ else
+ m_db.str= strmake_root(root, name->m_db.str, name->m_db.length);
+ m_name.length= name->m_name.length;
+ m_name.str= strmake_root(root, name->m_name.str, name->m_name.length);
+
+ if (name->m_qname.length == 0)
+ name->init_qname(thd);
+ m_qname.length= name->m_qname.length;
+ m_qname.str= strmake_root(root, name->m_qname.str, m_qname.length);
+ }
+ else if (thd->db)
+ {
+ m_db.length= thd->db_length;
+ m_db.str= strmake_root(root, thd->db, m_db.length);
+ }
+
+ if (m_param_begin && m_param_end)
+ {
+ m_params.length= m_param_end - m_param_begin;
+ m_params.str= strmake_root(root,
+ (char *)m_param_begin, m_params.length);
+ }
+
if (m_returns_begin && m_returns_end)
{
/* QQ KLUDGE: We can't seem to cut out just the type in the parser
@@ -490,6 +499,7 @@ sp_head::execute(THD *thd)
ip= hip;
ret= 0;
ctx->clear_handler();
+ ctx->in_handler= TRUE;
continue;
}
}
@@ -575,8 +585,10 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, Item **resp)
thd->spcont= nctx;
ret= execute(thd);
- if (ret == 0)
+
+ if (m_type == TYPE_ENUM_FUNCTION && ret == 0)
{
+ /* We need result only in function but not in trigger */
Item *it= nctx->get_result();
if (it)
@@ -763,6 +775,9 @@ sp_head::reset_lex(THD *thd)
/* And keep the SP stuff too */
sublex->sphead= oldlex->sphead;
sublex->spcont= oldlex->spcont;
+ /* And trigger related stuff too */
+ sublex->trg_chistics= oldlex->trg_chistics;
+ sublex->trg_table= oldlex->trg_table;
sublex->sp_lex_in_use= FALSE;
DBUG_VOID_RETURN;
}
@@ -1211,7 +1226,7 @@ sp_instr_set::execute(THD *thd, uint *nextp)
thd->spcont->set_item(m_offset, it);
}
*nextp = m_ip+1;
- if (thd->lock || thd->open_tables || thd->derived_tables)
+ if (tables && (thd->lock || thd->open_tables || thd->derived_tables))
close_thread_tables(thd);
DBUG_RETURN(res);
}
@@ -1227,6 +1242,60 @@ sp_instr_set::print(String *str)
}
//
+// sp_instr_set_user_var
+//
+int
+sp_instr_set_user_var::execute(THD *thd, uint *nextp)
+{
+ int res= 0;
+
+ DBUG_ENTER("sp_instr_set_user_var::execute");
+ /*
+ It is ok to pass 0 as 3rd argument to fix_fields() since
+ Item_func_set_user_var::fix_fields() won't use it.
+ QQ: Still unsure what should we return in case of error 1 or -1 ?
+ */
+ if (!m_set_var_item.fixed && m_set_var_item.fix_fields(thd, 0, 0) ||
+ m_set_var_item.check() || m_set_var_item.update())
+ res= -1;
+ *nextp= m_ip + 1;
+ DBUG_RETURN(res);
+}
+
+void
+sp_instr_set_user_var::print(String *str)
+{
+ m_set_var_item.print_as_stmt(str);
+}
+
+//
+// sp_instr_set_trigger_field
+//
+int
+sp_instr_set_trigger_field::execute(THD *thd, uint *nextp)
+{
+ int res= 0;
+
+ DBUG_ENTER("sp_instr_set_trigger_field::execute");
+ /* QQ: Still unsure what should we return in case of error 1 or -1 ? */
+ if (!value->fixed && value->fix_fields(thd, 0, &value) ||
+ trigger_field.fix_fields(thd, 0, 0) ||
+ (value->save_in_field(trigger_field.field, 0) < 0))
+ res= -1;
+ *nextp= m_ip + 1;
+ DBUG_RETURN(res);
+}
+
+void
+sp_instr_set_trigger_field::print(String *str)
+{
+ str->append("set ", 4);
+ trigger_field.print(str);
+ str->append(":=", 2);
+ value->print(str);
+}
+
+//
// sp_instr_jump
//
int
@@ -1314,7 +1383,7 @@ sp_instr_jump_if::execute(THD *thd, uint *nextp)
else
*nextp = m_ip+1;
}
- if (thd->lock || thd->open_tables || thd->derived_tables)
+ if (tables && (thd->lock || thd->open_tables || thd->derived_tables))
close_thread_tables(thd);
DBUG_RETURN(res);
}
@@ -1371,7 +1440,7 @@ sp_instr_jump_if_not::execute(THD *thd, uint *nextp)
else
*nextp = m_ip+1;
}
- if (thd->lock || thd->open_tables || thd->derived_tables)
+ if (tables && (thd->lock || thd->open_tables || thd->derived_tables))
close_thread_tables(thd);
DBUG_RETURN(res);
}
@@ -1518,19 +1587,40 @@ int
sp_instr_hreturn::execute(THD *thd, uint *nextp)
{
DBUG_ENTER("sp_instr_hreturn::execute");
- thd->spcont->restore_variables(m_frame);
- *nextp= thd->spcont->pop_hstack();
+ if (m_dest)
+ *nextp= m_dest;
+ else
+ {
+ thd->spcont->restore_variables(m_frame);
+ *nextp= thd->spcont->pop_hstack();
+ }
+ thd->spcont->in_handler= FALSE;
DBUG_RETURN(0);
}
void
sp_instr_hreturn::print(String *str)
{
- str->reserve(12);
+ str->reserve(16);
str->append("hreturn ");
str->qs_append(m_frame);
+ if (m_dest)
+ str->qs_append(m_dest);
+}
+
+uint
+sp_instr_hreturn::opt_mark(sp_head *sp)
+{
+ if (m_dest)
+ return sp_instr_jump::opt_mark(sp);
+ else
+ {
+ marked= 1;
+ return UINT_MAX;
+ }
}
+
//
// sp_instr_cpush
//
diff --git a/sql/sp_head.h b/sql/sp_head.h
index c0881661ad1..9c308961aa4 100644
--- a/sql/sp_head.h
+++ b/sql/sp_head.h
@@ -28,6 +28,7 @@
// in the CREATE TABLE command.
#define TYPE_ENUM_FUNCTION 1
#define TYPE_ENUM_PROCEDURE 2
+#define TYPE_ENUM_TRIGGER 3
Item_result
sp_map_result_type(enum enum_field_types type);
@@ -377,6 +378,72 @@ private:
}; // class sp_instr_set : public sp_instr
+/*
+ Set user variable instruction.
+ Used in functions and triggers to set user variables because we don't
+ want use sp_instr_stmt + "SET @a:=..." statement in this case since
+ latter will close all tables and thus will ruin execution of statement
+ calling/invoking this function/trigger.
+*/
+class sp_instr_set_user_var : public sp_instr
+{
+ sp_instr_set_user_var(const sp_instr_set_user_var &);
+ void operator=(sp_instr_set_user_var &);
+
+public:
+
+ sp_instr_set_user_var(uint ip, sp_pcontext *ctx, LEX_STRING var, Item *val)
+ : sp_instr(ip, ctx), m_set_var_item(var, val)
+ {}
+
+ virtual ~sp_instr_set_user_var()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+private:
+
+ Item_func_set_user_var m_set_var_item;
+}; // class sp_instr_set_user_var : public sp_instr
+
+
+/*
+ Set NEW/OLD row field value instruction. Used in triggers.
+*/
+class sp_instr_set_trigger_field : public sp_instr
+{
+ sp_instr_set_trigger_field(const sp_instr_set_trigger_field &);
+ void operator=(sp_instr_set_trigger_field &);
+
+public:
+
+ sp_instr_set_trigger_field(uint ip, sp_pcontext *ctx,
+ LEX_STRING field_name, Item *val)
+ : sp_instr(ip, ctx),
+ trigger_field(Item_trigger_field::NEW_ROW, field_name.str),
+ value(val)
+ {}
+
+ virtual ~sp_instr_set_trigger_field()
+ {}
+
+ virtual int execute(THD *thd, uint *nextp);
+
+ virtual void print(String *str);
+
+ bool setup_field(THD *thd, TABLE *table, enum trg_event_type event)
+ {
+ return trigger_field.setup_field(thd, table, event);
+ }
+private:
+
+ Item_trigger_field trigger_field;
+ Item *value;
+}; // class sp_instr_trigger_field : public sp_instr
+
+
class sp_instr_jump : public sp_instr
{
sp_instr_jump(const sp_instr_jump &); /* Prevent use of these */
@@ -610,7 +677,7 @@ private:
}; // class sp_instr_hpop : public sp_instr
-class sp_instr_hreturn : public sp_instr
+class sp_instr_hreturn : public sp_instr_jump
{
sp_instr_hreturn(const sp_instr_hreturn &); /* Prevent use of these */
void operator=(sp_instr_hreturn &);
@@ -618,7 +685,7 @@ class sp_instr_hreturn : public sp_instr
public:
sp_instr_hreturn(uint ip, sp_pcontext *ctx, uint fp)
- : sp_instr(ip, ctx), m_frame(fp)
+ : sp_instr_jump(ip, ctx), m_frame(fp)
{}
virtual ~sp_instr_hreturn()
@@ -628,11 +695,7 @@ public:
virtual void print(String *str);
- virtual uint opt_mark(sp_head *sp)
- {
- marked= 1;
- return UINT_MAX;
- }
+ virtual uint opt_mark(sp_head *sp);
private:
diff --git a/sql/sp_rcontext.cc b/sql/sp_rcontext.cc
index 7fa44f217f6..2f7bdbffa2b 100644
--- a/sql/sp_rcontext.cc
+++ b/sql/sp_rcontext.cc
@@ -32,6 +32,7 @@ sp_rcontext::sp_rcontext(uint fsize, uint hmax, uint cmax)
: m_count(0), m_fsize(fsize), m_result(NULL), m_hcount(0), m_hsp(0),
m_hfound(-1), m_ccount(0)
{
+ in_handler= FALSE;
m_frame= (Item **)sql_alloc(fsize * sizeof(Item*));
m_outs= (int *)sql_alloc(fsize * sizeof(int));
m_handler= (sp_handler_t *)sql_alloc(hmax * sizeof(sp_handler_t));
@@ -58,6 +59,8 @@ sp_rcontext::set_item_eval(uint idx, Item *i, enum_field_types type)
int
sp_rcontext::find_handler(uint sql_errno)
{
+ if (in_handler)
+ return 0; // Already executing a handler
if (m_hfound >= 0)
return 1; // Already got one
@@ -227,21 +230,24 @@ sp_cursor::fetch(THD *thd, List<struct sp_pvar> *vars)
return -1;
}
s= row[fldcount];
- switch (sp_map_result_type(pv->type))
- {
- case INT_RESULT:
- it= new Item_int(s);
- break;
- case REAL_RESULT:
- it= new Item_real(s, strlen(s));
- break;
- default:
+ if (!s)
+ it= new Item_null();
+ else
+ switch (sp_map_result_type(pv->type))
{
- uint len= strlen(s);
- it= new Item_string(thd->strmake(s, len), len, thd->db_charset);
+ case INT_RESULT:
+ it= new Item_int(s);
break;
+ case REAL_RESULT:
+ it= new Item_real(s, strlen(s));
+ break;
+ default:
+ {
+ uint len= strlen(s);
+ it= new Item_string(thd->strmake(s, len), len, thd->db_charset);
+ break;
+ }
}
- }
thd->spcont->set_item(pv->offset, it);
}
if (fldcount < m_prot->get_field_count())
diff --git a/sql/sp_rcontext.h b/sql/sp_rcontext.h
index 15a2fe62138..f26b6760310 100644
--- a/sql/sp_rcontext.h
+++ b/sql/sp_rcontext.h
@@ -46,6 +46,8 @@ class sp_rcontext : public Sql_alloc
public:
+ bool in_handler;
+
sp_rcontext(uint fsize, uint hmax, uint cmax);
~sp_rcontext()
diff --git a/sql/sql_base.cc b/sql/sql_base.cc
index e9847a09384..80090ba288e 100644
--- a/sql/sql_base.cc
+++ b/sql/sql_base.cc
@@ -20,6 +20,8 @@
#include "mysql_priv.h"
#include "sql_acl.h"
#include "sql_select.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
#include <m_ctype.h>
#include <my_dir.h>
#include <hash.h>
@@ -42,10 +44,6 @@ static my_bool open_new_frm(const char *path, const char *alias,
uint db_stat, uint prgflag,
uint ha_open_flags, TABLE *outparam,
TABLE_LIST *table_desc, MEM_ROOT *mem_root);
-static Field *find_field_in_real_table(THD *thd, TABLE *table,
- const char *name, uint length,
- bool check_grants, bool allow_rowid,
- uint *cached_field_index_ptr);
extern "C" byte *table_cache_key(const byte *record,uint *length,
my_bool not_used __attribute__((unused)))
@@ -210,6 +208,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd, const char *wild)
void intern_close_table(TABLE *table)
{ // Free all structures
free_io_cache(table);
+ delete table->triggers;
if (table->file)
VOID(closefrm(table)); // close file
}
@@ -574,16 +573,87 @@ TABLE_LIST *find_table_in_list(TABLE_LIST *table,
const char *db_name,
const char *table_name)
{
- for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
+ if (lower_case_table_names)
{
- if (!strcmp(table->db, db_name) &&
- !strcmp(table->real_name, table_name))
- break;
+ for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
+ {
+ if ((!strcmp(table->db, db_name) &&
+ !strcmp(table->real_name, table_name)) ||
+ (table->view &&
+ !my_strcasecmp(table_alias_charset,
+ table->table->table_cache_key, db_name) &&
+ !my_strcasecmp(table_alias_charset,
+ table->table->table_name, table_name)))
+ break;
+ }
+ }
+ else
+ {
+ for (; table; table= *(TABLE_LIST **) ((char*) table + offset))
+ {
+ if ((!strcmp(table->db, db_name) &&
+ !strcmp(table->real_name, table_name)) ||
+ (table->view &&
+ !strcmp(table->table->table_cache_key, db_name) &&
+ !strcmp(table->table->table_name, table_name)))
+ break;
+ }
}
return table;
}
+/*
+ Test that table is unique
+
+ SYNOPSIS
+ unique_table()
+ table table which should be chaked
+ table_list list of tables
+
+ RETURN
+ found duplicate
+ 0 if table is unique
+*/
+
+TABLE_LIST* unique_table(TABLE_LIST *table, TABLE_LIST *table_list)
+{
+ TABLE_LIST *res;
+ const char *d_name= table->db, *t_name= table->real_name;
+ char d_name_buff[MAX_ALIAS_NAME], t_name_buff[MAX_ALIAS_NAME];
+ if (table->view)
+ {
+ /* it is view and table opened */
+ if (lower_case_table_names)
+ {
+ strmov(t_name_buff, table->table->table_name);
+ my_casedn_str(files_charset_info, t_name_buff);
+ t_name= t_name_buff;
+ strmov(d_name_buff, table->table->table_cache_key);
+ my_casedn_str(files_charset_info, d_name_buff);
+ d_name= d_name_buff;
+ }
+ else
+ {
+ d_name= table->table->table_cache_key;
+ t_name= table->table->table_name;
+ }
+ if (d_name == 0)
+ {
+ /* it's temporary table => always unique */
+ return 0;
+ }
+ }
+ if ((res= find_table_in_global_list(table_list, d_name, t_name)) &&
+ res->table && res->table == table->table)
+ {
+ // we found entry of this table try again.
+ return find_table_in_global_list(res->next_global, d_name, t_name);
+ }
+ return res;
+}
+
+
TABLE **find_temporary_table(THD *thd, const char *db, const char *table_name)
{
char key[MAX_DBKEY_LENGTH];
@@ -747,6 +817,7 @@ TABLE *reopen_name_locked_table(THD* thd, TABLE_LIST* table_list)
!(table->table_cache_key =memdup_root(&table->mem_root,(char*) key,
key_length)))
{
+ delete table->triggers;
closefrm(table);
pthread_mutex_unlock(&LOCK_open);
DBUG_RETURN(0);
@@ -1010,6 +1081,7 @@ bool reopen_table(TABLE *table,bool locked)
if (!(tmp.table_cache_key= memdup_root(&tmp.mem_root,db,
table->key_length)))
{
+ delete tmp.triggers;
closefrm(&tmp); // End of memory
goto end;
}
@@ -1038,6 +1110,7 @@ bool reopen_table(TABLE *table,bool locked)
tmp.next= table->next;
tmp.prev= table->prev;
+ delete table->triggers;
if (table->file)
VOID(closefrm(table)); // close file, free everything
@@ -1424,6 +1497,9 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
if (error == 5)
DBUG_RETURN(0); // we have just opened VIEW
+ if (Table_triggers_list::check_n_load(thd, db, name, entry))
+ goto err;
+
/*
If we are here, there was no fatal error (but error may be still
unitialized).
@@ -1452,6 +1528,7 @@ static int open_unireg_entry(THD *thd, TABLE *entry, const char *db,
*/
sql_print_error("Error: when opening HEAP table, could not allocate \
memory to write 'DELETE FROM `%s`.`%s`' to the binary log",db,name);
+ delete entry->triggers;
if (entry->file)
closefrm(entry);
goto err;
@@ -1999,10 +2076,10 @@ find_field_in_table(THD *thd, TABLE_LIST *table_list,
# pointer to field
*/
-static Field *find_field_in_real_table(THD *thd, TABLE *table,
- const char *name, uint length,
- bool check_grants, bool allow_rowid,
- uint *cached_field_index_ptr)
+Field *find_field_in_real_table(THD *thd, TABLE *table,
+ const char *name, uint length,
+ bool check_grants, bool allow_rowid,
+ uint *cached_field_index_ptr)
{
Field **field_ptr, *field;
uint cached_field_index= *cached_field_index_ptr;
@@ -2440,7 +2517,7 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
Don't use arena if we are not in prepared statements or stored procedures
For PS/SP we have to use arena to remember the changes
*/
- if (arena->state == Item_arena::CONVENTIONAL_EXECUTION)
+ if (arena->is_conventional())
arena= 0; // For easier test later one
else
thd->set_n_backup_item_arena(arena, &backup);
@@ -2466,8 +2543,8 @@ int setup_wild(THD *thd, TABLE_LIST *tables, List<Item> &fields,
it.replace(new Item_int("Not_used", (longlong) 1, 21));
}
else if (insert_fields(thd,tables,((Item_field*) item)->db_name,
- ((Item_field*) item)->table_name, &it,
- any_privileges))
+ ((Item_field*) item)->table_name, &it,
+ any_privileges, arena != 0))
{
if (arena)
thd->restore_backup_item_arena(arena, &backup);
@@ -2653,6 +2730,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
any_privileges 0 If we should ensure that we have SELECT privileges
for all columns
1 If any privilege is ok
+ allocate_view_names if true view names will be copied to current Item_arena memory (made for SP/PS)
RETURN
0 ok
'it' is updated to point at last inserted
@@ -2662,7 +2740,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
bool
insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
const char *table_name, List_iterator<Item> *it,
- bool any_privileges)
+ bool any_privileges, bool allocate_view_names)
{
/* allocate variables on stack to avoid pool alloaction */
Field_iterator_table table_iter;
@@ -2822,7 +2900,7 @@ insert_fields(THD *thd, TABLE_LIST *tables, const char *db_name,
field->query_id=thd->query_id;
table->used_keys.intersect(field->part_of_key);
}
- else if (thd->current_arena->is_stmt_prepare() &&
+ else if (allocate_view_names &&
thd->lex->current_select->first_execution)
{
Item_field *item= new Item_field(thd->strdup(tables->view_db.str),
@@ -2867,7 +2945,7 @@ int setup_conds(THD *thd,TABLE_LIST *tables,COND **conds)
DBUG_ENTER("setup_conds");
if (select_lex->conds_processed_with_permanent_arena ||
- !arena->is_stmt_prepare())
+ arena->is_conventional())
arena= 0; // For easier test
thd->set_query_id=1;
diff --git a/sql/sql_class.cc b/sql/sql_class.cc
index 0c42c45bf59..cc6b86f4bc2 100644
--- a/sql/sql_class.cc
+++ b/sql/sql_class.cc
@@ -298,6 +298,7 @@ void THD::init(void)
bzero((char*) warn_count, sizeof(warn_count));
total_warn_count= 0;
update_charset();
+ bzero((char *) &status_var, sizeof(status_var));
}
@@ -388,6 +389,7 @@ THD::~THD()
/* Ensure that no one is using THD */
pthread_mutex_lock(&LOCK_delete);
pthread_mutex_unlock(&LOCK_delete);
+ add_to_status(&global_status_var, &status_var);
/* Close connection */
#ifndef EMBEDDED_LIBRARY
@@ -430,6 +432,27 @@ THD::~THD()
}
+/*
+ Add to one status variable another status variable
+
+ NOTES
+ This function assumes that all variables are long/ulong.
+ If this assumption will change, then we have to explictely add
+ the other variables after the while loop
+*/
+
+void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var)
+{
+ ulong *end= (ulong*) ((byte*) to_var + offsetof(STATUS_VAR,
+ last_system_status_var) +
+ sizeof(ulong));
+ ulong *to= (ulong*) to_var, *from= (ulong*) from_var;
+
+ while (to != end)
+ *(to++)+= *(from++);
+}
+
+
void THD::awake(THD::killed_state state_to_set)
{
THD_CHECK_SENTRY(this);
@@ -1646,3 +1669,27 @@ void TMP_TABLE_PARAM::init()
group_parts= group_length= group_null_parts= 0;
quick_group= 1;
}
+
+
+void thd_increment_bytes_sent(ulong length)
+{
+ current_thd->status_var.bytes_sent+= length;
+}
+
+
+void thd_increment_bytes_received(ulong length)
+{
+ current_thd->status_var.bytes_received+= length;
+}
+
+
+void thd_increment_net_big_packet_count(ulong length)
+{
+ current_thd->status_var.net_big_packet_count+= length;
+}
+
+
+void THD::set_status_var_init()
+{
+ bzero((char*) &status_var, sizeof(status_var));
+}
diff --git a/sql/sql_class.h b/sql/sql_class.h
index 761ffc133a3..d917eeef550 100644
--- a/sql/sql_class.h
+++ b/sql/sql_class.h
@@ -443,6 +443,61 @@ struct system_variables
DATE_TIME_FORMAT *time_format;
};
+
+/* per thread status variables */
+
+typedef struct system_status_var
+{
+ ulong bytes_received;
+ ulong bytes_sent;
+ ulong com_other;
+ ulong com_stat[(uint) SQLCOM_END];
+ ulong created_tmp_disk_tables;
+ ulong created_tmp_tables;
+ ulong ha_commit_count;
+ ulong ha_delete_count;
+ ulong ha_read_first_count;
+ ulong ha_read_last_count;
+ ulong ha_read_key_count;
+ ulong ha_read_next_count;
+ ulong ha_read_prev_count;
+ ulong ha_read_rnd_count;
+ ulong ha_read_rnd_next_count;
+ ulong ha_rollback_count;
+ ulong ha_update_count;
+ ulong ha_write_count;
+
+ /* KEY_CACHE parts. These are copies of the original */
+ ulong key_blocks_changed;
+ ulong key_blocks_used;
+ ulong key_cache_r_requests;
+ ulong key_cache_read;
+ ulong key_cache_w_requests;
+ ulong key_cache_write;
+ /* END OF KEY_CACHE parts */
+
+ ulong net_big_packet_count;
+ ulong opened_tables;
+ ulong select_full_join_count;
+ ulong select_full_range_join_count;
+ ulong select_range_count;
+ ulong select_range_check_count;
+ ulong select_scan_count;
+ ulong long_query_count;
+ ulong filesort_merge_passes;
+ ulong filesort_range_count;
+ ulong filesort_rows;
+ ulong filesort_scan_count;
+} STATUS_VAR;
+
+/*
+ This is used for 'show status'. It must be updated to the last ulong
+ variable in system_status_var
+*/
+
+#define last_system_status_var filesort_scan_count
+
+
void free_tmp_table(THD *thd, TABLE *entry);
@@ -477,6 +532,8 @@ public:
inline bool is_stmt_prepare() const { return (int)state < (int)PREPARED; }
inline bool is_first_stmt_execute() const { return state == PREPARED; }
+ inline bool is_conventional() const
+ { return state == CONVENTIONAL_EXECUTION; }
inline gptr alloc(unsigned int size) { return alloc_root(&mem_root,size); }
inline gptr calloc(unsigned int size)
{
@@ -682,6 +739,7 @@ public:
struct sockaddr_in remote; // client socket address
struct rand_struct rand; // used for authentication
struct system_variables variables; // Changeable local variables
+ struct system_status_var status_var; // Per thread statistic vars
pthread_mutex_t LOCK_delete; // Locked before thd is deleted
/*
Note that (A) if we set query = NULL, we must at the same time set
@@ -1073,6 +1131,7 @@ public:
{
my_error(killed_errno(), MYF(0));
}
+ void set_status_var_init();
};
/* Flags for the THD::system_thread (bitmap) variable */
@@ -1556,3 +1615,7 @@ public:
bool send_eof();
void cleanup();
};
+
+/* Functions in sql_class.cc */
+
+void add_to_status(STATUS_VAR *to_var, STATUS_VAR *from_var);
diff --git a/sql/sql_delete.cc b/sql/sql_delete.cc
index 030541a0093..f9dba49d2e3 100644
--- a/sql/sql_delete.cc
+++ b/sql/sql_delete.cc
@@ -26,6 +26,8 @@
#include "mysql_priv.h"
#include "ha_innodb.h"
#include "sql_select.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
ha_rows limit, ulong options)
@@ -160,6 +162,11 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
// thd->net.report_error is tested to disallow delete row on error
if (!(select && select->skip_record())&& !thd->net.report_error )
{
+
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
+ TRG_ACTION_BEFORE);
+
if (!(error=table->file->delete_row(table->record[0])))
{
deleted++;
@@ -183,6 +190,10 @@ int mysql_delete(THD *thd, TABLE_LIST *table_list, COND *conds, SQL_LIST *order,
error= 1;
break;
}
+
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_DELETE,
+ TRG_ACTION_AFTER);
}
else
table->file->unlock_row(); // Row failed selection, release lock on it
@@ -282,8 +293,7 @@ int mysql_prepare_delete(THD *thd, TABLE_LIST *table_list, Item **conds)
my_error(ER_NON_UPDATABLE_TABLE, MYF(0), table_list->alias, "DELETE");
DBUG_RETURN(-1);
}
- if (find_table_in_global_list(table_list->next_global,
- table_list->db, table_list->real_name))
+ if (unique_table(table_list, table_list->next_independent()))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
DBUG_RETURN(-1);
diff --git a/sql/sql_handler.cc b/sql/sql_handler.cc
index 0df3d617d7f..1443f9f9d5f 100644
--- a/sql/sql_handler.cc
+++ b/sql/sql_handler.cc
@@ -51,7 +51,11 @@ int mysql_ha_open(THD *thd, TABLE_LIST *tables)
{
HANDLER_TABLES_HACK(thd);
uint counter;
+
+ /* for now HANDLER can be used only for real TABLES */
+ tables->required_type= FRMTYPE_TABLE;
int err=open_tables(thd, tables, &counter);
+
HANDLER_TABLES_HACK(thd);
if (err)
return -1;
@@ -249,7 +253,7 @@ int mysql_ha_read(THD *thd, TABLE_LIST *tables,
it++; // Skip first NULL field
- insert_fields(thd, tables, tables->db, tables->alias, &it, 0);
+ insert_fields(thd, tables, tables->db, tables->alias, &it, 0, 0);
select_limit+=offset_limit;
protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
diff --git a/sql/sql_insert.cc b/sql/sql_insert.cc
index 3508e962c60..c30fdcd805f 100644
--- a/sql/sql_insert.cc
+++ b/sql/sql_insert.cc
@@ -19,6 +19,8 @@
#include "mysql_priv.h"
#include "sql_acl.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
static int check_null_fields(THD *thd,TABLE *entry);
#ifndef EMBEDDED_LIBRARY
@@ -302,6 +304,12 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
break;
}
}
+
+ // FIXME: Actually we should do this before check_null_fields.
+ // Or even go into write_record ?
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_INSERT, TRG_ACTION_BEFORE);
+
#ifndef EMBEDDED_LIBRARY
if (lock_type == TL_WRITE_DELAYED)
{
@@ -324,6 +332,9 @@ int mysql_insert(THD *thd,TABLE_LIST *table_list,
if (error)
break;
thd->row_count++;
+
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_INSERT, TRG_ACTION_AFTER);
}
/*
@@ -599,8 +610,7 @@ int mysql_prepare_insert(THD *thd, TABLE_LIST *table_list, TABLE *table,
setup_fields(thd, 0, table_list, update_values, 0, 0, 0))))
DBUG_RETURN(-1);
- if (find_table_in_global_list(table_list->next_global,
- table_list->db, table_list->real_name))
+ if (unique_table(table_list, table_list->next_independent()))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
DBUG_RETURN(-1);
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 241e9b863f1..f5382e6df99 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -24,6 +24,11 @@
#include "sp.h"
#include "sp_head.h"
+/*
+ We are using pointer to this variable for distinguishing between assignment
+ to NEW row field (when parsing trigger definition) and structured variable.
+*/
+sys_var_long_ptr trg_new_row_fake_var(0, 0);
/*
Fake table list object, pointer to which is used as special value for
@@ -139,6 +144,7 @@ void lex_start(THD *thd, uchar *buf,uint length)
lex->duplicates= DUP_ERROR;
lex->sphead= NULL;
lex->spcont= NULL;
+ lex->trg_table= NULL;
extern byte *sp_lex_spfuns_key(const byte *ptr, uint *plen, my_bool first);
hash_free(&lex->spfuns);
@@ -1795,7 +1801,7 @@ void st_lex::link_first_table_back(TABLE_LIST *first,
void st_select_lex::fix_prepare_information(THD *thd, Item **conds)
{
- if (thd->current_arena->is_stmt_prepare() && first_execution)
+ if (!thd->current_arena->is_conventional() && first_execution)
{
first_execution= 0;
prep_where= where;
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index 95c9772bac1..d43b1f81f3d 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -85,6 +85,7 @@ enum enum_sql_command {
SQLCOM_SHOW_STATUS_PROC, SQLCOM_SHOW_STATUS_FUNC,
SQLCOM_PREPARE, SQLCOM_EXECUTE, SQLCOM_DEALLOCATE_PREPARE,
SQLCOM_CREATE_VIEW, SQLCOM_DROP_VIEW,
+ SQLCOM_CREATE_TRIGGER, SQLCOM_DROP_TRIGGER,
/* This should be the last !!! */
SQLCOM_END
};
@@ -602,6 +603,15 @@ struct st_sp_chistics
bool detistic;
};
+
+struct st_trg_chistics
+{
+ enum trg_action_time_type action_time;
+ enum trg_event_type event;
+};
+
+extern sys_var_long_ptr trg_new_row_fake_var;
+
/* The state of the lex parsing. This is saved in the THD struct */
typedef struct st_lex
@@ -633,7 +643,11 @@ typedef struct st_lex
THD *thd;
CHARSET_INFO *charset;
TABLE_LIST *query_tables; /* global list of all tables in this query */
- /* last element next_global of previous list */
+ /*
+ last element next_global of previous list (used only for list building
+ during parsing and VIEW processing. This pointer is not valid in
+ mysql_execute_command
+ */
TABLE_LIST **query_tables_last;
TABLE_LIST *proc_table; /* refer to mysql.proc if it was opened by VIEW */
@@ -713,6 +727,14 @@ typedef struct st_lex
rexecuton
*/
bool empty_field_list_on_rset;
+ /* Characterstics of trigger being created */
+ st_trg_chistics trg_chistics;
+ /*
+ Points to table being opened when we are parsing trigger definition
+ while opening table. 0 if we are parsing user provided CREATE TRIGGER
+ or any other statement. Used for NEW/OLD row field lookup in trigger.
+ */
+ TABLE *trg_table;
st_lex() :result(0)
{
@@ -747,6 +769,11 @@ typedef struct st_lex
TABLE_LIST *unlink_first_table(bool *link_to_local);
void link_first_table_back(TABLE_LIST *first, bool link_to_local);
void first_lists_tables_same();
+ inline void add_to_query_tables(TABLE_LIST *table)
+ {
+ *(table->prev_global= query_tables_last)= table;
+ query_tables_last= &table->next_global;
+ }
bool can_be_merged();
bool can_use_merged();
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 1b4769d747e..156897682b3 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1327,6 +1327,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
this so that they will not get logged to the slow query log
*/
thd->slow_command=FALSE;
+ thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
thd->set_time();
VOID(pthread_mutex_lock(&LOCK_thread_count));
thd->query_id=query_id;
@@ -1342,7 +1343,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_INIT_DB:
{
LEX_STRING tmp;
- statistic_increment(com_stat[SQLCOM_CHANGE_DB],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_CHANGE_DB],
+ &LOCK_status);
thd->convert_string(&tmp, system_charset_info,
packet, strlen(packet), thd->charset());
if (!mysql_change_db(thd, tmp.str))
@@ -1363,7 +1365,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
uint db_len= *(uchar*) packet;
uint tbl_len= *(uchar*) (packet + db_len + 1);
- statistic_increment(com_other, &LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
thd->slow_command= TRUE;
db= thd->alloc(db_len + tbl_len + 2);
tbl_name= strmake(db, packet + 1, db_len)+1;
@@ -1377,7 +1379,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->change_user();
thd->clear_error(); // if errors from rollback
- statistic_increment(com_other, &LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
char *user= (char*) packet;
char *passwd= strend(user)+1;
/*
@@ -1544,7 +1546,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
TABLE_LIST table_list;
LEX_STRING conv_name;
- statistic_increment(com_stat[SQLCOM_SHOW_FIELDS],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_FIELDS],
+ &LOCK_status);
bzero((char*) &table_list,sizeof(table_list));
if (!(table_list.db=thd->db))
{
@@ -1570,7 +1573,17 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
if (grant_option &&
check_grant(thd, SELECT_ACL, &table_list, 2, UINT_MAX, 0))
break;
+ /* switch on VIEW optimisation: do not fill temporary tables */
+ thd->lex->sql_command= SQLCOM_SHOW_FIELDS;
+ /* init structures for VIEW processing */
+ table_list.select_lex= &(thd->lex->select_lex);
+ mysql_init_query(thd, (uchar*)"", 0);
+ thd->lex->
+ select_lex.table_list.link_in_list((byte*) &table_list,
+ (byte**) &table_list.next_local);
+
mysqld_list_fields(thd,&table_list,fields);
+ thd->lex->unit.cleanup();
thd->cleanup_after_query();
break;
}
@@ -1586,7 +1599,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
{
char *db=thd->strdup(packet), *alias;
- statistic_increment(com_stat[SQLCOM_CREATE_DB],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_CREATE_DB],
+ &LOCK_status);
// null test to handle EOM
if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
{
@@ -1601,7 +1615,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
}
case COM_DROP_DB: // QQ: To be removed
{
- statistic_increment(com_stat[SQLCOM_DROP_DB],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_DROP_DB],
+ &LOCK_status);
char *db=thd->strdup(packet), *alias;
/* null test to handle EOM */
if (!db || !(alias= thd->strdup(db)) || check_db_name(db))
@@ -1623,7 +1638,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#ifndef EMBEDDED_LIBRARY
case COM_BINLOG_DUMP:
{
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other,&LOCK_status);
thd->slow_command = TRUE;
if (check_global_access(thd, REPL_SLAVE_ACL))
break;
@@ -1649,7 +1664,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#endif
case COM_REFRESH:
{
- statistic_increment(com_stat[SQLCOM_FLUSH],&LOCK_status);
+ 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;
@@ -1663,7 +1679,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
#ifndef EMBEDDED_LIBRARY
case COM_SHUTDOWN:
{
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
if (check_global_access(thd,SHUTDOWN_ACL))
break; /* purecov: inspected */
/*
@@ -1702,7 +1718,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
case COM_STATISTICS:
{
mysql_log.write(thd,command,NullS);
- statistic_increment(com_stat[SQLCOM_SHOW_STATUS],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_STATUS],
+ &LOCK_status);
#ifndef EMBEDDED_LIBRARY
char buff[200];
#else
@@ -1712,8 +1729,8 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
sprintf((char*) buff,
"Uptime: %ld Threads: %d Questions: %lu Slow queries: %ld Opens: %ld Flush tables: %ld Open tables: %u Queries per second avg: %.3f",
uptime,
- (int) thread_count,thd->query_id,long_query_count,
- opened_tables,refresh_version, cached_tables(),
+ (int) thread_count,thd->query_id,thd->status_var.long_query_count,
+ thd->status_var.opened_tables,refresh_version, cached_tables(),
uptime ? (float)thd->query_id/(float)uptime : 0);
#ifdef SAFEMALLOC
if (sf_malloc_cur_memory) // Using SAFEMALLOC
@@ -1728,11 +1745,12 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_PING:
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
send_ok(thd); // Tell client we are alive
break;
case COM_PROCESS_INFO:
- statistic_increment(com_stat[SQLCOM_SHOW_PROCESSLIST],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SHOW_PROCESSLIST],
+ &LOCK_status);
if (!thd->priv_user[0] && check_global_access(thd,PROCESS_ACL))
break;
mysql_log.write(thd,command,NullS);
@@ -1742,14 +1760,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
case COM_PROCESS_KILL:
{
- statistic_increment(com_stat[SQLCOM_KILL],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_KILL], &LOCK_status);
ulong id=(ulong) uint4korr(packet);
kill_one_thread(thd,id,false);
break;
}
case COM_SET_OPTION:
{
- statistic_increment(com_stat[SQLCOM_SET_OPTION], &LOCK_status);
+ statistic_increment(thd->status_var.com_stat[SQLCOM_SET_OPTION],
+ &LOCK_status);
enum_mysql_set_option command= (enum_mysql_set_option) uint2korr(packet);
switch (command) {
case MYSQL_OPTION_MULTI_STATEMENTS_ON:
@@ -1767,7 +1786,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
break;
}
case COM_DEBUG:
- statistic_increment(com_other,&LOCK_status);
+ statistic_increment(thd->status_var.com_other, &LOCK_status);
if (check_global_access(thd, SUPER_ACL))
break; /* purecov: inspected */
mysql_print_status(thd);
@@ -1806,7 +1825,7 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
(SERVER_QUERY_NO_INDEX_USED | SERVER_QUERY_NO_GOOD_INDEX_USED)) &&
(specialflag & SPECIAL_LOG_QUERIES_NOT_USING_INDEXES)))
{
- long_query_count++;
+ thd->status_var.long_query_count++;
mysql_slow_log.write(thd, thd->query, thd->query_length, start_of_query);
}
}
@@ -1983,7 +2002,8 @@ mysql_execute_command(THD *thd)
DBUG_RETURN(-1);
}
- statistic_increment(com_stat[lex->sql_command],&LOCK_status);
+ statistic_increment(thd->status_var.com_stat[lex->sql_command],
+ &LOCK_status);
switch (lex->sql_command) {
case SQLCOM_SELECT:
{
@@ -2392,31 +2412,6 @@ mysql_execute_command(THD *thd)
if (select_lex->item_list.elements) // With select
{
select_result *result;
- /*
- Is table which we are changing used somewhere in other parts
- of query
- */
- if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
- find_table_in_global_list(select_tables, create_table->db,
- create_table->real_name))
- {
- net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name);
- goto create_error;
- }
- if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
- {
- TABLE_LIST *tab;
- for (tab= select_tables; tab; tab= tab->next_local)
- {
- if (find_table_in_local_list((TABLE_LIST*) lex->create_info.
- merge_list.first,
- select_tables->db, tab->real_name))
- {
- net_printf(thd, ER_UPDATE_TABLE_USED, tab->real_name);
- goto create_error;
- }
- }
- }
if (select_tables &&
check_table_access(thd, SELECT_ACL, select_tables, 0))
@@ -2426,6 +2421,32 @@ mysql_execute_command(THD *thd)
if (!(res= open_and_lock_tables(thd, select_tables)))
{
+ /*
+ Is table which we are changing used somewhere in other parts
+ of query
+ */
+ if (!(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
+ unique_table(create_table, select_tables))
+ {
+ net_printf(thd, ER_UPDATE_TABLE_USED, create_table->real_name);
+ goto create_error;
+ }
+ /* If we create merge table, we have to test tables in merge, too */
+ if (lex->create_info.used_fields & HA_CREATE_USED_UNION)
+ {
+ TABLE_LIST *tab;
+ for (tab= (TABLE_LIST*) lex->create_info.merge_list.first;
+ tab;
+ tab= tab->next_local)
+ {
+ if (unique_table(tab, select_tables))
+ {
+ net_printf(thd, ER_UPDATE_TABLE_USED, tab->real_name);
+ goto create_error;
+ }
+ }
+ }
+
if ((result= new select_create(create_table,
&lex->create_info,
lex->create_list,
@@ -2781,30 +2802,33 @@ unsent_create_error:
select_result *result;
unit->set_limit(select_lex, select_lex);
- // is table which we are changing used somewhere in other parts of query
- if (find_table_in_global_list(all_tables->next_global,
- first_table->db, first_table->real_name))
- {
- /* Using same table for INSERT and SELECT */
- select_lex->options |= OPTION_BUFFER_RESULT;
- }
-
- if (!(res= open_and_lock_tables(thd, all_tables)) &&
- !(res= mysql_insert_select_prepare(thd)) &&
- (result= new select_insert(first_table, first_table->table,
- &lex->field_list, lex->duplicates)))
+ if (!(res= open_and_lock_tables(thd, all_tables)))
{
- /* Skip first table, which is the table we are inserting in */
- lex->select_lex.table_list.first= (byte*) first_table->next_local;
/*
- insert/replace from SELECT give its SELECT_LEX for SELECT,
- and item_list belong to SELECT
+ Is table which we are changing used somewhere in other parts of
+ query
*/
- lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
- res= handle_select(thd, lex, result);
- lex->select_lex.table_list.first= (byte*) first_table;
- lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
- delete result;
+ if (unique_table(first_table, all_tables->next_independent()))
+ {
+ /* Using same table for INSERT and SELECT */
+ select_lex->options |= OPTION_BUFFER_RESULT;
+ }
+
+ if ((res= mysql_insert_select_prepare(thd)))
+ break;
+ if ((result= new select_insert(first_table, first_table->table,
+ &lex->field_list, lex->duplicates)))
+ /* Skip first table, which is the table we are inserting in */
+ lex->select_lex.table_list.first= (byte*) first_table->next_local;
+ /*
+ insert/replace from SELECT give its SELECT_LEX for SELECT,
+ and item_list belong to SELECT
+ */
+ lex->select_lex.resolve_mode= SELECT_LEX::SELECT_MODE;
+ res= handle_select(thd, lex, result);
+ /* revert changes for SP */
+ lex->select_lex.table_list.first= (byte*) first_table;
+ lex->select_lex.resolve_mode= SELECT_LEX::INSERT_MODE;
if (thd->net.report_error)
res= -1;
}
@@ -2960,13 +2984,23 @@ unsent_create_error:
res= mysqld_show_column_types(thd);
break;
case SQLCOM_SHOW_STATUS:
- res= mysqld_show(thd,(lex->wild ? lex->wild->ptr() : NullS),status_vars,
- OPT_GLOBAL, &LOCK_status);
+ STATUS_VAR tmp;
+ if (lex->option_type == OPT_GLOBAL)
+ {
+ pthread_mutex_lock(&LOCK_status);
+ calc_sum_of_all_status(&tmp);
+ }
+ res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
+ status_vars, OPT_GLOBAL, &LOCK_status,
+ (lex->option_type == OPT_GLOBAL ?
+ &tmp: &thd->status_var));
+ if (lex->option_type == OPT_GLOBAL)
+ pthread_mutex_unlock(&LOCK_status);
break;
case SQLCOM_SHOW_VARIABLES:
res= mysqld_show(thd, (lex->wild ? lex->wild->ptr() : NullS),
init_vars, lex->option_type,
- &LOCK_global_system_variables);
+ &LOCK_global_system_variables, 0);
break;
case SQLCOM_SHOW_LOGS:
#ifdef DONT_ALLOW_SHOW_COMMANDS
@@ -3861,6 +3895,20 @@ purposes internal to the MySQL server", MYF(0));
res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
break;
}
+ case SQLCOM_CREATE_TRIGGER:
+ {
+ /* We don't care much about trigger body at that point */
+ delete lex->sphead;
+ lex->sphead= 0;
+
+ res= mysql_create_or_drop_trigger(thd, all_tables, 1);
+ break;
+ }
+ case SQLCOM_DROP_TRIGGER:
+ {
+ res= mysql_create_or_drop_trigger(thd, all_tables, 0);
+ break;
+ }
default: /* Impossible */
send_ok(thd);
break;
@@ -5125,8 +5173,7 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
/* Link table in local list (list for current select) */
table_list.link_in_list((byte*) ptr, (byte**) &ptr->next_local);
/* Link table in global list (all used tables) */
- *(ptr->prev_global= lex->query_tables_last)= ptr;
- lex->query_tables_last= &ptr->next_global;
+ lex->add_to_query_tables(ptr);
DBUG_RETURN(ptr);
}
@@ -5135,9 +5182,9 @@ TABLE_LIST *st_select_lex::add_table_to_list(THD *thd,
Initialize a new table list for a nested join
SYNOPSIS
- init_table_list()
+ init_table_list()
thd current thread
-
+
DESCRIPTION
The function initializes a structure of the TABLE_LIST type
for a nested join. It sets up its nested join list as empty.
@@ -5157,7 +5204,7 @@ bool st_select_lex::init_nested_join(THD *thd)
TABLE_LIST *ptr;
NESTED_JOIN *nested_join;
DBUG_ENTER("init_nested_join");
-
+
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
!(nested_join= ptr->nested_join=
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
@@ -5182,7 +5229,7 @@ bool st_select_lex::init_nested_join(THD *thd)
DESCRIPTION
The function returns to the previous join nest level.
If the current level contains only one member, the function
- moves it one level up, eliminating the nest.
+ moves it one level up, eliminating the nest.
RETURN VALUE
Pointer to TABLE_LIST element added to the total table list, if success
@@ -5214,7 +5261,7 @@ TABLE_LIST *st_select_lex::end_nested_join(THD *thd)
Nest last join operation
SYNOPSIS
- nest_last_join()
+ nest_last_join()
thd current thread
DESCRIPTION
@@ -5230,7 +5277,7 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
TABLE_LIST *ptr;
NESTED_JOIN *nested_join;
DBUG_ENTER("nest_last_join");
-
+
if (!(ptr = (TABLE_LIST *) thd->calloc(sizeof(TABLE_LIST))) ||
!(nested_join= ptr->nested_join=
(NESTED_JOIN *) thd->calloc(sizeof(NESTED_JOIN))))
@@ -5254,7 +5301,7 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
/*
Save names for a join with using clase
-
+
SYNOPSIS
save_names_for_using_list
tab1 left table in join
@@ -5262,11 +5309,11 @@ TABLE_LIST *st_select_lex::nest_last_join(THD *thd)
DESCRIPTION
The function saves the full names of the tables in st_select_lex
- to be able to build later an on expression to replace the using clause.
-
+ to be able to build later an on expression to replace the using clause.
+
RETURN VALUE
- None
-*/
+ None
+*/
void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
TABLE_LIST *tab2)
@@ -5288,7 +5335,7 @@ void st_select_lex::save_names_for_using_list(TABLE_LIST *tab1,
db2= tab2->db;
table2= tab2->alias;
}
-
+
/*
Add a table to the current join list
@@ -5323,9 +5370,9 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
SYNOPSIS
convert_right_join()
thd current thread
-
- DESCRIPTION
- The function takes the current join list t[0],t[1] ... and
+
+ DESCRIPTION
+ The function takes the current join list t[0],t[1] ... and
effectively converts it into the list t[1],t[0] ...
Although the outer_join flag for the new nested table contains
JOIN_TYPE_RIGHT, it will be handled as the inner table of a left join
@@ -5349,10 +5396,10 @@ void st_select_lex::add_joined_table(TABLE_LIST *table)
0, otherwise
*/
-TABLE_LIST *st_select_lex::convert_right_join()
+TABLE_LIST *st_select_lex::convert_right_join()
{
TABLE_LIST *tab2= join_list->pop();
- TABLE_LIST *tab1= join_list->pop();
+ TABLE_LIST *tab1= join_list->pop();
DBUG_ENTER("convert_right_join");
join_list->push_front(tab2);
@@ -5416,7 +5463,7 @@ void add_join_on(TABLE_LIST *b,Item *expr)
add_join_natural()
a Table to do normal join with
b Do normal join with this table
-
+
IMPLEMENTATION
This function just marks that table b should be joined with a.
The function setup_cond() will create in b->on_expr a list
@@ -5637,6 +5684,13 @@ static void refresh_status(void)
(char*) &dflt_key_cache_var));
*(ulong*) value= 0;
}
+ else if (ptr->type == SHOW_LONG_STATUS)
+ {
+ THD *thd= current_thd;
+ /* We must update the global status before cleaning up the thread */
+ add_to_status(&global_status_var, &thd->status_var);
+ bzero((char*) &thd->status_var, sizeof(thd->status_var));
+ }
}
pthread_mutex_unlock(&LOCK_status);
}
diff --git a/sql/sql_select.cc b/sql/sql_select.cc
index def641d9616..cd2eb7c1516 100644
--- a/sql/sql_select.cc
+++ b/sql/sql_select.cc
@@ -232,8 +232,6 @@ int handle_select(THD *thd, LEX *lex, select_result *result)
result->abort();
res= 1; // Error sent to client
}
- if (result != lex->result)
- delete result;
DBUG_RETURN(res);
}
@@ -5145,6 +5143,7 @@ static void
make_join_readinfo(JOIN *join, uint options)
{
uint i;
+
bool statistics= test(!(join->select_options & SELECT_DESCRIBE));
DBUG_ENTER("make_join_readinfo");
@@ -5243,7 +5242,8 @@ make_join_readinfo(JOIN *join, uint options)
join->thd->server_status|=SERVER_QUERY_NO_GOOD_INDEX_USED;
tab->read_first_record= join_init_quick_read_record;
if (statistics)
- statistic_increment(select_range_check_count, &LOCK_status);
+ statistic_increment(join->thd->status_var.select_range_check_count,
+ &LOCK_status);
}
else
{
@@ -5253,13 +5253,15 @@ make_join_readinfo(JOIN *join, uint options)
if (tab->select && tab->select->quick)
{
if (statistics)
- statistic_increment(select_range_count, &LOCK_status);
+ statistic_increment(join->thd->status_var.select_range_count,
+ &LOCK_status);
}
else
{
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
if (statistics)
- statistic_increment(select_scan_count, &LOCK_status);
+ statistic_increment(join->thd->status_var.select_scan_count,
+ &LOCK_status);
}
}
else
@@ -5267,13 +5269,15 @@ make_join_readinfo(JOIN *join, uint options)
if (tab->select && tab->select->quick)
{
if (statistics)
- statistic_increment(select_full_range_join_count, &LOCK_status);
+ statistic_increment(join->thd->status_var.select_full_range_join_count,
+ &LOCK_status);
}
else
{
join->thd->server_status|=SERVER_QUERY_NO_INDEX_USED;
if (statistics)
- statistic_increment(select_full_join_count, &LOCK_status);
+ statistic_increment(join->thd->status_var.select_full_join_count,
+ &LOCK_status);
}
}
if (!table->no_keyread)
@@ -6156,16 +6160,21 @@ optimize_cond(JOIN *join, COND *conds, Item::cond_result *cond_value)
MEMROOT for prepared statements and stored procedures.
*/
- Item_arena *arena=thd->current_arena, backup;
- select->first_cond_optimization= 0;
+ Item_arena *arena= thd->current_arena, backup;
+ if (arena->is_conventional())
+ arena= 0; // For easier test
+ else
+ thd->set_n_backup_item_arena(arena, &backup);
- thd->set_n_backup_item_arena(arena, &backup);
+ select->first_cond_optimization= 0;
/* Convert all outer joins to inner joins if possible */
conds= simplify_joins(join, join->join_list, conds, TRUE);
select->prep_where= conds ? conds->copy_andor_structure(thd) : 0;
- thd->restore_backup_item_arena(arena, &backup);
+
+ if (arena)
+ thd->restore_backup_item_arena(arena, &backup);
}
if (!conds)
@@ -6649,7 +6658,7 @@ create_tmp_table(THD *thd,TMP_TABLE_PARAM *param,List<Item> &fields,
(int) distinct, (int) save_sum_fields,
(ulong) rows_limit,test(group)));
- statistic_increment(created_tmp_tables, &LOCK_status);
+ statistic_increment(thd->status_var.created_tmp_tables, &LOCK_status);
if (use_temp_pool)
temp_pool_slot = bitmap_set_next(&temp_pool);
@@ -7235,7 +7244,8 @@ static bool create_myisam_tmp_table(TABLE *table,TMP_TABLE_PARAM *param,
table->db_stat=0;
goto err;
}
- statistic_increment(created_tmp_disk_tables, &LOCK_status);
+ statistic_increment(table->in_use->status_var.created_tmp_disk_tables,
+ &LOCK_status);
table->db_record_offset=1;
DBUG_RETURN(0);
err:
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index c31eb4f147f..1209be6ac1d 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -1140,14 +1140,19 @@ void
mysqld_list_fields(THD *thd, TABLE_LIST *table_list, const char *wild)
{
TABLE *table;
+ int res;
DBUG_ENTER("mysqld_list_fields");
DBUG_PRINT("enter",("table: %s",table_list->real_name));
- if (!(table = open_ltable(thd, table_list, TL_UNLOCK)))
+ table_list->lock_type= TL_UNLOCK;
+ if ((res= open_and_lock_tables(thd, table_list)))
{
- send_error(thd);
+ if (res < 0)
+ send_error(thd);
DBUG_VOID_RETURN;
}
+ table= table_list->table;
+
List<Item> field_list;
Field **ptr,*field;
@@ -1596,7 +1601,7 @@ view_store_create_info(THD *thd, TABLE_LIST *table, String *buff)
{
buff->append("ALGORITHM=", 10);
if (table->algorithm == VIEW_ALGORITHM_TMPTABLE)
- buff->append("TMPTABLE ", 9);
+ buff->append("TEMPTABLE ", 10);
else
buff->append("MERGE ", 6);
}
@@ -1869,7 +1874,8 @@ err:
int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
enum enum_var_type value_type,
- pthread_mutex_t *mutex)
+ pthread_mutex_t *mutex,
+ struct system_status_var *status_var)
{
char buff[1024];
List<Item> field_list;
@@ -1907,6 +1913,10 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
pos= end= buff;
switch (show_type) {
+ case SHOW_LONG_STATUS:
+ case SHOW_LONG_CONST_STATUS:
+ value= ((char *) status_var + (uint) value);
+ /* fall through */
case SHOW_LONG:
case SHOW_LONG_CONST:
end= int10_to_str(*(long*) value, buff, 10);
@@ -2176,6 +2186,31 @@ int mysqld_show(THD *thd, const char *wild, show_var_st *variables,
DBUG_RETURN(1);
}
+
+/* collect status for all running threads */
+
+void calc_sum_of_all_status(STATUS_VAR *to)
+{
+ DBUG_ENTER("calc_sum_of_all_status");
+
+ /* Ensure that thread id not killed during loop */
+ VOID(pthread_mutex_lock(&LOCK_thread_count)); // For unlink from list
+
+ I_List_iterator<THD> it(threads);
+ THD *tmp;
+
+ /* Get global values as base */
+ *to= global_status_var;
+
+ /* Add to this status from existing threads */
+ while ((tmp= it++))
+ add_to_status(to, &tmp->status_var);
+
+ VOID(pthread_mutex_unlock(&LOCK_thread_count));
+ DBUG_VOID_RETURN;
+}
+
+
#ifdef __GNUC__
template class List_iterator_fast<char>;
template class List<char>;
diff --git a/sql/sql_table.cc b/sql/sql_table.cc
index 08cb90d2824..65be24ae537 100644
--- a/sql/sql_table.cc
+++ b/sql/sql_table.cc
@@ -1517,7 +1517,7 @@ static void wait_while_table_is_used(THD *thd,TABLE *table,
Win32 clients must also have a WRITE LOCK on the table !
*/
-static bool close_cached_table(THD *thd, TABLE *table)
+void close_cached_table(THD *thd, TABLE *table)
{
DBUG_ENTER("close_cached_table");
@@ -1533,7 +1533,6 @@ static bool close_cached_table(THD *thd, TABLE *table)
/* When lock on LOCK_open is freed other threads can continue */
pthread_cond_broadcast(&COND_refresh);
- DBUG_RETURN(0);
}
static int send_check_errmsg(THD *thd, TABLE_LIST* table,
@@ -3140,12 +3139,7 @@ int mysql_alter_table(THD *thd,char *new_db, char *new_name,
close the original table at before doing the rename
*/
table_name=thd->strdup(table_name); // must be saved
- if (close_cached_table(thd, table))
- { // Aborted
- VOID(quick_rm_table(new_db_type,new_db,tmp_name));
- VOID(pthread_mutex_unlock(&LOCK_open));
- goto err;
- }
+ close_cached_table(thd, table);
table=0; // Marker that table is closed
}
#if (!defined( __WIN__) && !defined( __EMX__) && !defined( OS2))
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 5c467402497..6cffa9df2c6 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -468,16 +468,20 @@ read_first: %10lu\n\
write: %10lu\n\
delete %10lu\n\
update: %10lu\n",
- ha_read_key_count, ha_read_next_count,
- ha_read_rnd_count, ha_read_first_count,
- ha_write_count, ha_delete_count, ha_update_count);
+ thd->status_var.ha_read_key_count,
+ thd->status_var.ha_read_next_count,
+ thd->status_var.ha_read_rnd_count,
+ thd->status_var.ha_read_first_count,
+ thd->status_var.ha_write_count,
+ thd->status_var.ha_delete_count,
+ thd->status_var.ha_update_count);
pthread_mutex_unlock(&LOCK_status);
printf("\nTable status:\n\
Opened tables: %10lu\n\
Open tables: %10lu\n\
Open files: %10lu\n\
Open streams: %10lu\n",
- opened_tables,
+ thd->status_var.opened_tables,
(ulong) cached_tables(),
(ulong) my_file_opened,
(ulong) my_stream_opened);
diff --git a/sql/sql_trigger.cc b/sql/sql_trigger.cc
new file mode 100644
index 00000000000..c376e86f18c
--- /dev/null
+++ b/sql/sql_trigger.cc
@@ -0,0 +1,433 @@
+#include "mysql_priv.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
+#include "parse_file.h"
+
+
+static const LEX_STRING triggers_file_type= {(char *)"TRIGGERS", 8};
+static const char * const triggers_file_ext= ".TRG";
+
+/*
+ Table of .TRG file field descriptors.
+ We have here only one field now because in nearest future .TRG
+ files will be merged into .FRM files (so we don't need something
+ like md5 or created fields).
+*/
+static File_option triggers_file_parameters[]=
+{
+ {{(char*)"triggers", 8}, offsetof(Table_triggers_list, definitions_list),
+ FILE_OPTIONS_STRLIST},
+ {{NULL, 0}, 0, FILE_OPTIONS_STRING}
+};
+
+
+/*
+ Create or drop trigger for table.
+
+ SYNOPSIS
+ mysql_create_or_drop_trigger()
+ thd - current thread context (including trigger definition in LEX)
+ tables - table list containing one table for which trigger is created.
+ create - whenever we create (true) or drop (false) trigger
+
+ NOTE
+ This function is mainly responsible for opening and locking of table and
+ invalidation of all its instances in table cache after trigger creation.
+ Real work on trigger creation/dropping is done inside Table_triggers_list
+ methods.
+
+ RETURN VALUE
+ 0 - Success, non-0 in case of error.
+*/
+int mysql_create_or_drop_trigger(THD *thd, TABLE_LIST *tables, bool create)
+{
+ TABLE *table;
+ int result= 0;
+
+ DBUG_ENTER("mysql_create_or_drop_trigger");
+
+ /*
+ QQ: This function could be merged in mysql_alter_table() function
+ But do we want this ?
+ */
+
+ if (open_and_lock_tables(thd, tables))
+ DBUG_RETURN(-1);
+
+ // TODO: We should check if user has TRIGGER privilege for table here.
+
+ table= tables->table;
+
+ /*
+ We do not allow creation of triggers on views or temporary tables.
+ We have to do this check here and not in
+ Table_triggers_list::create_trigger() because we want to avoid messing
+ with table cash for views and temporary tables.
+ */
+ if (tables->view || table->tmp_table != NO_TMP_TABLE)
+ {
+ my_error(ER_TRG_ON_VIEW_OR_TEMP_TABLE, MYF(0), tables->alias);
+ DBUG_RETURN(-1);
+ }
+
+ if (!table->triggers)
+ {
+ if (!create)
+ {
+ my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
+ DBUG_RETURN(-1);
+ }
+
+ if (!(table->triggers= new (&table->mem_root) Table_triggers_list()))
+ DBUG_RETURN(-1);
+ }
+
+ /*
+ We don't want perform our operations while global read lock is held
+ so we have to wait until its end and then prevent it from occuring
+ again until we are done. (Acquiring LOCK_open is not enough because
+ global read lock is held without helding LOCK_open).
+ */
+ if (wait_if_global_read_lock(thd, 0, 0))
+ DBUG_RETURN(-1);
+
+ VOID(pthread_mutex_lock(&LOCK_open));
+ if ((create ? table->triggers->create_trigger(thd, tables):
+ table->triggers->drop_trigger(thd, tables)))
+ result= -1;
+
+ /* It is sensible to invalidate table in any case */
+ close_cached_table(thd, table);
+ VOID(pthread_mutex_unlock(&LOCK_open));
+ start_waiting_global_read_lock(thd);
+
+ if (!result)
+ send_ok(thd);
+
+ DBUG_RETURN(result);
+}
+
+
+/*
+ Create trigger for table.
+
+ SYNOPSIS
+ create_trigger()
+ thd - current thread context (including trigger definition in LEX)
+ tables - table list containing one open table for which trigger is
+ created.
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables)
+{
+ LEX *lex= thd->lex;
+ TABLE *table= tables->table;
+ char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
+ LEX_STRING dir, file;
+ MEM_ROOT *old_global_root;
+ LEX_STRING *trg_def, *name;
+ List_iterator_fast<LEX_STRING> it(names_list);
+
+ /* We don't allow creation of several triggers of the same type yet */
+ if (bodies[lex->trg_chistics.event][lex->trg_chistics.action_time])
+ {
+ my_error(ER_TRG_ALREADY_EXISTS, MYF(0));
+ return 1;
+ }
+
+ /* Let us check if trigger with the same name exists */
+ while ((name= it++))
+ {
+ if (my_strcasecmp(system_charset_info, lex->name_and_length.str,
+ name->str) == 0)
+ {
+ my_error(ER_TRG_ALREADY_EXISTS, MYF(0));
+ return 1;
+ }
+ }
+
+ /*
+ Here we are creating file with triggers and save all triggers in it.
+ sql_create_definition_file() files handles renaming and backup of older
+ versions
+ */
+ strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", tables->db, "/", NullS);
+ dir.length= unpack_filename(dir_buff, dir_buff);
+ dir.str= dir_buff;
+ file.length= strxnmov(file_buff, FN_REFLEN, tables->real_name,
+ triggers_file_ext, NullS) - file_buff;
+ file.str= file_buff;
+
+ old_global_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
+ my_pthread_setspecific_ptr(THR_MALLOC, &table->mem_root);
+
+ /*
+ Soon we will invalidate table object and thus Table_triggers_list object
+ so don't care about place to which trg_def->ptr points and other
+ invariants (e.g. we don't bother to update names_list)
+
+ QQ: Hmm... probably we should not care about setting up active thread
+ mem_root too.
+ */
+ if (!(trg_def= (LEX_STRING *)alloc_root(&table->mem_root,
+ sizeof(LEX_STRING))) ||
+ definitions_list.push_back(trg_def))
+ {
+ my_pthread_setspecific_ptr(THR_MALLOC, old_global_root);
+ return 1;
+ }
+
+ trg_def->str= thd->query;
+ trg_def->length= thd->query_length;
+
+ my_pthread_setspecific_ptr(THR_MALLOC, old_global_root);
+
+ return sql_create_definition_file(&dir, &file, &triggers_file_type,
+ (gptr)this, triggers_file_parameters, 3);
+}
+
+
+/*
+ Drop trigger for table.
+
+ SYNOPSIS
+ drop_trigger()
+ thd - current thread context (including trigger definition in LEX)
+ tables - table list containing one open table for which trigger is
+ dropped.
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+bool Table_triggers_list::drop_trigger(THD *thd, TABLE_LIST *tables)
+{
+ LEX *lex= thd->lex;
+ LEX_STRING *name;
+ List_iterator_fast<LEX_STRING> it_name(names_list);
+ List_iterator<LEX_STRING> it_def(definitions_list);
+
+ while ((name= it_name++))
+ {
+ it_def++;
+
+ if (my_strcasecmp(system_charset_info, lex->name_and_length.str,
+ name->str) == 0)
+ {
+ /*
+ Again we don't care much about other things required for
+ clean trigger removing since table will be reopened anyway.
+ */
+ it_def.remove();
+
+ if (definitions_list.is_empty())
+ {
+ char path[FN_REFLEN];
+
+ /*
+ TODO: Probably instead of removing .TRG file we should move
+ to archive directory but this should be done as part of
+ parse_file.cc functionality (because we will need it
+ elsewhere).
+ */
+ strxnmov(path, FN_REFLEN, mysql_data_home, "/", tables->db, "/",
+ tables->real_name, triggers_file_ext, NullS);
+ unpack_filename(path, path);
+ return my_delete(path, MYF(MY_WME));
+ }
+ else
+ {
+ char dir_buff[FN_REFLEN], file_buff[FN_REFLEN];
+ LEX_STRING dir, file;
+
+ strxnmov(dir_buff, FN_REFLEN, mysql_data_home, "/", tables->db,
+ "/", NullS);
+ dir.length= unpack_filename(dir_buff, dir_buff);
+ dir.str= dir_buff;
+ file.length= strxnmov(file_buff, FN_REFLEN, tables->real_name,
+ triggers_file_ext, NullS) - file_buff;
+ file.str= file_buff;
+
+ return sql_create_definition_file(&dir, &file, &triggers_file_type,
+ (gptr)this,
+ triggers_file_parameters, 3);
+ }
+ }
+ }
+
+ my_error(ER_TRG_DOES_NOT_EXIST, MYF(0));
+ return 1;
+}
+
+
+Table_triggers_list::~Table_triggers_list()
+{
+ for (int i= 0; i < 3; i++)
+ for (int j= 0; j < 2; j++)
+ delete bodies[i][j];
+
+ if (old_field)
+ for (Field **fld_ptr= old_field; *fld_ptr; fld_ptr++)
+ delete *fld_ptr;
+}
+
+
+/*
+ Check whenever .TRG file for table exist and load all triggers it contains.
+
+ SYNOPSIS
+ check_n_load()
+ thd - current thread context
+ db - table's database name
+ table_name - table's name
+ table - pointer to table object
+
+ RETURN VALUE
+ False - success
+ True - error
+*/
+bool Table_triggers_list::check_n_load(THD *thd, const char *db,
+ const char *table_name, TABLE *table)
+{
+ char path_buff[FN_REFLEN];
+ LEX_STRING path;
+ File_parser *parser;
+ MEM_ROOT *old_global_mem_root;
+
+ DBUG_ENTER("Table_triggers_list::check_n_load");
+
+ strxnmov(path_buff, FN_REFLEN, mysql_data_home, "/", db, "/", table_name,
+ triggers_file_ext, NullS);
+ path.length= unpack_filename(path_buff, path_buff);
+ path.str= path_buff;
+
+ // QQ: should we analyze errno somehow ?
+ if (access(path_buff, F_OK))
+ DBUG_RETURN(0);
+
+ /*
+ File exists so we got to load triggers
+ FIXME: A lot of things to do here e.g. how about other funcs and being
+ more paranoical ?
+ */
+
+ if ((parser= sql_parse_prepare(&path, &table->mem_root, 1)))
+ {
+ if (!strncmp(triggers_file_type.str, parser->type()->str,
+ parser->type()->length))
+ {
+ Field **fld, **old_fld;
+ Table_triggers_list *triggers=
+ new (&table->mem_root) Table_triggers_list();
+
+ if (!triggers)
+ DBUG_RETURN(1);
+
+ if (parser->parse((gptr)triggers, &table->mem_root,
+ triggers_file_parameters, 1))
+ DBUG_RETURN(1);
+
+ table->triggers= triggers;
+
+ /*
+ We have to prepare array of Field objects which will represent OLD.*
+ row values by referencing to record[1] instead of record[0]
+
+ TODO: This could be avoided if there is no ON UPDATE trigger.
+ */
+ if (!(triggers->old_field=
+ (Field **)alloc_root(&table->mem_root, (table->fields + 1) *
+ sizeof(Field*))))
+ DBUG_RETURN(1);
+
+ for (fld= table->field, old_fld= triggers->old_field; *fld;
+ fld++, old_fld++)
+ {
+ /*
+ QQ: it is supposed that it is ok to use this function for field
+ cloning...
+ */
+ if (!(*old_fld= (*fld)->new_field(&table->mem_root, table)))
+ DBUG_RETURN(1);
+ (*old_fld)->move_field((my_ptrdiff_t)(table->record[1] -
+ table->record[0]));
+ }
+ *old_fld= 0;
+
+ List_iterator_fast<LEX_STRING> it(triggers->definitions_list);
+ LEX_STRING *trg_create_str, *trg_name_str;
+ char *trg_name_buff;
+ LEX *old_lex= thd->lex, lex;
+
+ thd->lex= &lex;
+
+ while ((trg_create_str= it++))
+ {
+ mysql_init_query(thd, (uchar*)trg_create_str->str,
+ trg_create_str->length, true);
+ lex.trg_table= table;
+ if (yyparse((void *)thd) || thd->is_fatal_error)
+ {
+ /*
+ Free lex associated resources
+ QQ: Do we really need all this stuff here ?
+ */
+ if (lex.sphead)
+ {
+ if (&lex != thd->lex)
+ thd->lex->sphead->restore_lex(thd);
+ delete lex.sphead;
+ }
+ goto err_with_lex_cleanup;
+ }
+
+ triggers->bodies[lex.trg_chistics.event]
+ [lex.trg_chistics.action_time]= lex.sphead;
+ lex.sphead= 0;
+
+ if (!(trg_name_buff= alloc_root(&table->mem_root,
+ sizeof(LEX_STRING) +
+ lex.name_and_length.length + 1)))
+ goto err_with_lex_cleanup;
+
+ trg_name_str= (LEX_STRING *)trg_name_buff;
+ trg_name_buff+= sizeof(LEX_STRING);
+ memcpy(trg_name_buff, lex.name_and_length.str,
+ lex.name_and_length.length + 1);
+ trg_name_str->str= trg_name_buff;
+ trg_name_str->length= lex.name_and_length.length;
+
+ old_global_mem_root= my_pthread_getspecific_ptr(MEM_ROOT*, THR_MALLOC);
+ my_pthread_setspecific_ptr(THR_MALLOC, &table->mem_root);
+
+ if (triggers->names_list.push_back(trg_name_str))
+ goto err_with_lex_cleanup;
+
+ my_pthread_setspecific_ptr(THR_MALLOC, old_global_mem_root);
+
+ lex_end(&lex);
+ }
+ thd->lex= old_lex;
+
+ DBUG_RETURN(0);
+
+err_with_lex_cleanup:
+ // QQ: anything else ?
+ lex_end(&lex);
+ thd->lex= old_lex;
+ DBUG_RETURN(1);
+ }
+
+ /*
+ We don't care about this error message much because .TRG files will
+ be merged into .FRM anyway.
+ */
+ my_error(ER_WRONG_OBJECT, MYF(0), table_name, triggers_file_ext, "TRIGGER");
+ DBUG_RETURN(1);
+ }
+
+ DBUG_RETURN(1);
+}
diff --git a/sql/sql_trigger.h b/sql/sql_trigger.h
new file mode 100644
index 00000000000..8ab2ab003f8
--- /dev/null
+++ b/sql/sql_trigger.h
@@ -0,0 +1,62 @@
+/*
+ This class holds all information about triggers of table.
+
+ QQ: Will it be merged into TABLE in future ?
+*/
+class Table_triggers_list: public Sql_alloc
+{
+ /* Triggers as SPs grouped by event, action_time */
+ sp_head *bodies[3][2];
+ /*
+ Copy of TABLE::Field array with field pointers set to old version
+ of record, used for OLD values in trigger on UPDATE.
+ */
+ Field **old_field;
+ /*
+ Names of triggers.
+ Should correspond to order of triggers on definitions_list,
+ used in CREATE/DROP TRIGGER for looking up trigger by name.
+ */
+ List<LEX_STRING> names_list;
+
+public:
+ /*
+ Field responsible for storing triggers definitions in file.
+ It have to be public because we are using it directly from parser.
+ */
+ List<LEX_STRING> definitions_list;
+
+ Table_triggers_list():
+ old_field(0)
+ {
+ bzero((char *)bodies, sizeof(bodies));
+ }
+ ~Table_triggers_list();
+
+ bool create_trigger(THD *thd, TABLE_LIST *table);
+ bool drop_trigger(THD *thd, TABLE_LIST *table);
+ bool process_triggers(THD *thd, trg_event_type event,
+ trg_action_time_type time_type)
+ {
+ int res= 0;
+
+ if (bodies[event][time_type])
+ {
+ /*
+ Similar to function invocation we don't need to surpress sending of
+ ok packets here because don't allow execute statements from trigger.
+
+ FIXME: We should juggle with security context here (because trigger
+ should be invoked with creator rights).
+ */
+ res= bodies[event][time_type]->execute_function(thd, 0, 0, 0);
+ }
+
+ return res;
+ }
+
+ static bool check_n_load(THD *thd, const char *db, const char *table_name,
+ TABLE *table);
+
+ friend class Item_trigger_field;
+};
diff --git a/sql/sql_union.cc b/sql/sql_union.cc
index d23e11d5443..1df419d04c3 100644
--- a/sql/sql_union.cc
+++ b/sql/sql_union.cc
@@ -293,7 +293,7 @@ int st_select_lex_unit::prepare(THD *thd_arg, select_result *sel_result,
Field **field;
Item_arena *arena= thd->current_arena;
Item_arena backup;
- if (!arena->is_stmt_prepare())
+ if (arena->is_conventional())
arena= 0;
else
thd->set_n_backup_item_arena(arena, &backup);
diff --git a/sql/sql_update.cc b/sql/sql_update.cc
index 9d7134aee84..dc867968262 100644
--- a/sql/sql_update.cc
+++ b/sql/sql_update.cc
@@ -23,6 +23,8 @@
#include "mysql_priv.h"
#include "sql_acl.h"
#include "sql_select.h"
+#include "sp_head.h"
+#include "sql_trigger.h"
static bool safe_update_on_fly(JOIN_TAB *join_tab, List<Item> *fields);
@@ -354,6 +356,10 @@ int mysql_update(THD *thd,
if (fill_record(fields,values, 0) || thd->net.report_error)
break; /* purecov: inspected */
found++;
+
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_BEFORE);
+
if (compare_record(table, query_id))
{
if (!(error=table->file->update_row((byte*) table->record[1],
@@ -369,6 +375,10 @@ int mysql_update(THD *thd,
break;
}
}
+
+ if (table->triggers)
+ table->triggers->process_triggers(thd, TRG_EVENT_UPDATE, TRG_ACTION_AFTER);
+
if (!--limit && using_limit)
{
error= -1; // Simulate end of file
@@ -496,8 +506,7 @@ int mysql_prepare_update(THD *thd, TABLE_LIST *table_list,
DBUG_RETURN(-1);
/* Check that we are not using table that we are updating in a sub select */
- if (find_table_in_global_list(table_list->next_global,
- table_list->db, table_list->real_name))
+ if (unique_table(table_list, table_list->next_independent()))
{
my_error(ER_UPDATE_TABLE_USED, MYF(0), table_list->real_name);
DBUG_RETURN(-1);
@@ -788,7 +797,7 @@ int multi_update::prepare(List<Item> &not_used_values,
{
TABLE *table=table_ref->table;
if (!(tables_to_update & table->map) &&
- find_table_in_global_list(update_tables, table_ref->db,
+ find_table_in_local_list(update_tables, table_ref->db,
table_ref->real_name))
table->no_cache= 1; // Disable row cache
}
diff --git a/sql/sql_view.cc b/sql/sql_view.cc
index 15f38f685dc..2364be228f8 100644
--- a/sql/sql_view.cc
+++ b/sql/sql_view.cc
@@ -45,6 +45,7 @@ TYPELIB sql_updatable_view_key_typelib=
-1 Error
1 Error and error message given
*/
+
int mysql_create_view(THD *thd,
enum_view_create_mode mode)
{
@@ -356,6 +357,7 @@ static LEX_STRING view_file_type[]= {{(char*)"VIEW", 4}};
-1 Error
1 Error and error message given
*/
+
static int mysql_register_view(THD *thd, TABLE_LIST *view,
enum_view_create_mode mode)
{
@@ -423,7 +425,7 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
/*
read revision number
-
+
TODO: read dependense list, too, to process cascade/restrict
TODO: special cascade/restrict procedure for alter?
*/
@@ -501,7 +503,6 @@ static int mysql_register_view(THD *thd, TABLE_LIST *view,
my_bool
mysql_make_view(File_parser *parser, TABLE_LIST *table)
{
- bool include_proc_table= 0;
DBUG_ENTER("mysql_make_view");
if (table->view)
@@ -512,7 +513,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
DBUG_RETURN(0);
}
- TABLE_LIST *old_next, *tbl_end, *tbl_next;
SELECT_LEX *end;
THD *thd= current_thd;
LEX *old_lex= thd->lex, *lex;
@@ -523,7 +523,7 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
will be TRUE as far as we make new table cache).
*/
Item_arena *arena= thd->current_arena, backup;
- if (!arena->is_stmt_prepare())
+ if (arena->is_conventional())
arena= 0;
else
thd->set_n_backup_item_arena(arena, &backup);
@@ -599,11 +599,14 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
TABLE_LIST *top_view= (table->belong_to_view ?
table->belong_to_view :
table);
+ TABLE_LIST *view_tables= lex->query_tables;
+ TABLE_LIST *view_tables_tail= 0;
if (lex->spfuns.records)
{
/* move SP to main LEX */
sp_merge_funs(old_lex, lex);
+ /* open mysq.proc for functions which are not in cache */
if (old_lex->proc_table == 0 &&
(old_lex->proc_table=
(TABLE_LIST*)thd->calloc(sizeof(TABLE_LIST))) != 0)
@@ -614,18 +617,20 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
table->real_name= table->alias= (char*)"proc";
table->real_name_length= 4;
table->cacheable_table= 1;
- include_proc_table= 1;
+ old_lex->add_to_query_tables(table);
}
}
+ /* cleanup LEX */
if (lex->spfuns.array.buffer)
hash_free(&lex->spfuns);
- old_next= table->next_global;
- if ((table->next_global= lex->query_tables))
- table->next_global->prev_global= &table->next_global;
-
- /* mark to avoid temporary table using and put view reference*/
- for (TABLE_LIST *tbl= table->next_global; tbl; tbl= tbl->next_global)
+ /*
+ mark to avoid temporary table using and put view reference and find
+ last view table
+ */
+ for (TABLE_LIST *tbl= view_tables;
+ tbl;
+ tbl= (view_tables_tail= tbl)->next_global)
{
tbl->skip_temporary= 1;
tbl->belong_to_view= top_view;
@@ -638,8 +643,8 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
if ((old_lex->sql_command == SQLCOM_SELECT && old_lex->describe) ||
old_lex->sql_command == SQLCOM_SHOW_CREATE)
{
- if (check_table_access(thd, SELECT_ACL, table->next_global, 1) &&
- check_table_access(thd, SHOW_VIEW_ACL, table->next_global, 1))
+ if (check_table_access(thd, SELECT_ACL, view_tables, 1) &&
+ check_table_access(thd, SHOW_VIEW_ACL, view_tables, 1))
{
my_error(ER_VIEW_NO_EXPLAIN, MYF(0));
goto err;
@@ -654,6 +659,29 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
old_lex->select_lex.options|= OPTION_TO_QUERY_CACHE;
/*
+ Put tables of VIEW after VIEW TABLE_LIST
+
+ NOTE: It is important for UPDATE/INSERT/DELETE checks to have this
+ tables just after VIEW instead of tail of list, to be able check that
+ table is unique. Also we store old next table for the same purpose.
+ */
+ table->old_next= table->next_global;
+ if (view_tables)
+ {
+ if (table->next_global)
+ {
+ table->next_global->prev_global= &view_tables_tail->next_global;
+ view_tables_tail->next_global= table->old_next;
+ }
+ else
+ {
+ lex->query_tables_last= &view_tables_tail->next_global;
+ }
+ view_tables->prev_global= &table->next_global;
+ table->next_global= view_tables;
+ }
+
+ /*
check MERGE algorithm ability
- algorithm is not explicit TEMPORARY TABLE
- VIEW SELECT allow marging
@@ -667,31 +695,26 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
{
/*
TODO: support multi tables substitutions
-
- table->next_global should be the same as
- (TABLE_LIST *)lex->select_lex.table_list.first;
*/
- TABLE_LIST *view_table= table->next_global;
/* lex should contain at least one table */
- DBUG_ASSERT(view_table != 0);
+ DBUG_ASSERT(view_tables != 0);
table->effective_algorithm= VIEW_ALGORITHM_MERGE;
DBUG_PRINT("info", ("algorithm: MERGE"));
table->updatable= (table->updatable_view != 0);
- if (old_next)
- {
- if ((view_table->next_global= old_next))
- old_next->prev_global= &view_table->next_global;
- }
- table->ancestor= view_table;
- // next table should include SELECT_LEX under this table SELECT_LEX
+ table->ancestor= view_tables;
+ /*
+ next table should include SELECT_LEX under this table SELECT_LEX
+
+ TODO: ehere should be loop for multi tables substitution
+ */
table->ancestor->select_lex= table->select_lex;
/*
move lock type (TODO: should we issue error in case of TMPTABLE
algorithm and non-read locking)?
*/
- view_table->lock_type= table->lock_type;
+ view_tables->lock_type= table->lock_type;
/* Store WHERE clause for postprocessing in setup_ancestor */
table->where= lex->select_lex.where;
@@ -714,22 +737,6 @@ mysql_make_view(File_parser *parser, TABLE_LIST *table)
lex->unit.include_down(table->select_lex);
lex->unit.slave= &lex->select_lex; // fix include_down initialisation
- if (old_next)
- {
- if ((tbl_end= table->next_global))
- {
- for (; (tbl_next= tbl_end->next_global); tbl_end= tbl_next)
- ;
- if ((tbl_end->next_global= old_next))
- tbl_end->next_global->prev_global= &tbl_end->next_global;
- }
- else
- {
- /* VIEW do not contain tables */
- table->next_global= old_next;
- }
- }
-
table->derived= &lex->unit;
}
else
@@ -746,17 +753,6 @@ ok:
lex->all_selects_list->link_prev=
(st_select_lex_node**)&old_lex->all_selects_list;
- if (include_proc_table)
- {
- TABLE_LIST *proc= old_lex->proc_table;
- if((proc->next_global= table->next_global))
- {
- table->next_global->prev_global= &proc->next_global;
- }
- proc->prev_global= &table->next_global;
- table->next_global= proc;
- }
-
thd->lex= old_lex;
DBUG_RETURN(0);
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 91a20e6e8e5..920f6fd4a82 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -242,6 +242,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token DISTINCT
%token DUPLICATE_SYM
%token DYNAMIC_SYM
+%token EACH_SYM
%token ENABLE_SYM
%token ENCLOSED
%token ESCAPED
@@ -411,6 +412,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token TO_SYM
%token TRAILING
%token TRANSACTION_SYM
+%token TRIGGER_SYM
%token TRUE_SYM
%token TYPE_SYM
%token TYPES_SYM
@@ -1208,6 +1210,65 @@ create:
}
opt_view_list AS select_init check_option
{}
+ | CREATE TRIGGER_SYM ident trg_action_time trg_event
+ ON table_ident FOR_SYM EACH_SYM ROW_SYM
+ {
+ LEX *lex= Lex;
+ sp_head *sp;
+
+ if (lex->sphead)
+ {
+ net_printf(YYTHD, ER_SP_NO_RECURSIVE_CREATE, "TRIGGER");
+ YYABORT;
+ }
+
+ sp= new sp_head();
+ sp->reset_thd_mem_root(YYTHD);
+ sp->init(lex);
+
+ sp->m_type= TYPE_ENUM_TRIGGER;
+ lex->sphead= sp;
+ /*
+ We have to turn of CLIENT_MULTI_QUERIES while parsing a
+ stored procedure, otherwise yylex will chop it into pieces
+ at each ';'.
+ */
+ sp->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
+ YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
+
+ bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
+ lex->sphead->m_chistics= &lex->sp_chistics;
+ lex->sphead->m_body_begin= lex->tok_start;
+ }
+ sp_proc_stmt
+ {
+ LEX *lex= Lex;
+ sp_head *sp= lex->sphead;
+
+ lex->sql_command= SQLCOM_CREATE_TRIGGER;
+ sp->init_strings(YYTHD, lex, NULL);
+ /* Restore flag if it was cleared above */
+ if (sp->m_old_cmq)
+ YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
+ sp->restore_thd_mem_root(YYTHD);
+
+ lex->name_and_length= $3;
+
+ /*
+ We have to do it after parsing trigger body, because some of
+ sp_proc_stmt alternatives are not saving/restoring LEX, so
+ lex->query_tables can be wiped out.
+
+ QQ: What are other consequences of this?
+
+ QQ: Could we loosen lock type in certain cases ?
+ */
+ if (!lex->select_lex.add_table_to_list(YYTHD, $7,
+ (LEX_STRING*) 0,
+ TL_OPTION_UPDATING,
+ TL_WRITE))
+ YYABORT;
+ }
;
sp_name:
@@ -1538,13 +1599,17 @@ sp_decl:
sp_head *sp= lex->sphead;
sp_pcontext *ctx= lex->spcont;
sp_label_t *hlab= lex->spcont->pop_label(); /* After this hdlr */
+ sp_instr_hreturn *i;
if ($2 == SP_HANDLER_CONTINUE)
- sp->add_instr(new sp_instr_hreturn(sp->instructions(), ctx,
- ctx->current_pvars()));
+ {
+ i= new sp_instr_hreturn(sp->instructions(), ctx,
+ ctx->current_pvars());
+ sp->add_instr(i);
+ }
else
{ /* EXIT or UNDO handler, just jump to the end of the block */
- sp_instr_jump *i= new sp_instr_jump(sp->instructions(), ctx);
+ i= new sp_instr_hreturn(sp->instructions(), ctx, 0);
sp->add_instr(i);
sp->push_backpatch(i, lex->spcont->last_label()); /* Block end */
@@ -1747,14 +1812,14 @@ sp_proc_stmt:
if (lex->sql_command != SQLCOM_SET_OPTION ||
! lex->var_list.is_empty())
{
- /* Currently we can't handle queries inside a FUNCTION,
- ** because of the way table locking works.
- ** This is unfortunate, and limits the usefulness of functions
- ** a great deal, but it's nothing we can do about this at the
- ** moment.
- */
- if (lex->sphead->m_type == TYPE_ENUM_FUNCTION &&
- lex->sql_command != SQLCOM_SET_OPTION)
+ /*
+ Currently we can't handle queries inside a FUNCTION or
+ TRIGGER, because of the way table locking works. This is
+ unfortunate, and limits the usefulness of functions and
+ especially triggers a tremendously, but it's nothing we
+ can do about this at the moment.
+ */
+ if (lex->sphead->m_type != TYPE_ENUM_PROCEDURE)
{
send_error(YYTHD, ER_SP_BADSTATEMENT);
YYABORT;
@@ -2289,6 +2354,22 @@ sp_unlabeled_control:
}
;
+trg_action_time:
+ BEFORE_SYM
+ { Lex->trg_chistics.action_time= TRG_ACTION_BEFORE; }
+ | AFTER_SYM
+ { Lex->trg_chistics.action_time= TRG_ACTION_AFTER; }
+ ;
+
+trg_event:
+ INSERT
+ { Lex->trg_chistics.event= TRG_EVENT_INSERT; }
+ | UPDATE_SYM
+ { Lex->trg_chistics.event= TRG_EVENT_UPDATE; }
+ | DELETE_SYM
+ { Lex->trg_chistics.event= TRG_EVENT_DELETE; }
+ ;
+
create2:
'(' create2a {}
| opt_create_table_options create3 {}
@@ -5422,7 +5503,21 @@ drop:
lex->sql_command= SQLCOM_DROP_VIEW;
lex->drop_if_exists= $3;
}
- ;
+ | DROP TRIGGER_SYM ident '.' ident
+ {
+ LEX *lex= Lex;
+
+ lex->sql_command= SQLCOM_DROP_TRIGGER;
+ /* QQ: Could we loosen lock type in certain cases ? */
+ if (!lex->select_lex.add_table_to_list(YYTHD,
+ new Table_ident($3),
+ (LEX_STRING*) 0,
+ TL_OPTION_UPDATING,
+ TL_WRITE))
+ YYABORT;
+ lex->name_and_length= $5;
+ }
+ ;
table_list:
table_name
@@ -5842,8 +5937,12 @@ show_param:
{ Lex->sql_command = SQLCOM_SHOW_WARNS;}
| ERRORS opt_limit_clause_init
{ Lex->sql_command = SQLCOM_SHOW_ERRORS;}
- | STATUS_SYM wild
- { Lex->sql_command= SQLCOM_SHOW_STATUS; }
+ | opt_var_type STATUS_SYM wild
+ {
+ THD *thd= YYTHD;
+ thd->lex->sql_command= SQLCOM_SHOW_STATUS;
+ thd->lex->option_type= (enum_var_type) $1;
+ }
| INNOBASE_SYM STATUS_SYM
{ Lex->sql_command = SQLCOM_SHOW_INNODB_STATUS; WARN_DEPRECATED("SHOW INNODB STATUS", "SHOW ENGINE INNODB STATUS"); }
| opt_full PROCESSLIST_SYM
@@ -6413,18 +6512,69 @@ simple_ident_q:
{
THD *thd= YYTHD;
LEX *lex= thd->lex;
- SELECT_LEX *sel= lex->current_select;
- if (sel->no_table_names_allowed)
- {
- my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
- ER(ER_TABLENAME_NOT_ALLOWED_HERE),
- MYF(0), $1.str, thd->where);
- }
- $$= (sel->parsing_place != IN_HAVING ||
- sel->get_in_sum_expr() > 0) ?
- (Item*) new Item_field(NullS,$1.str,$3.str) :
- (Item*) new Item_ref(0,0,NullS,$1.str,$3.str);
- }
+
+ /*
+ FIXME This will work ok in simple_ident_nospvar case because
+ we can't meet simple_ident_nospvar in trigger now. But it
+ should be changed in future.
+ */
+ if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
+ (!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
+ !my_strcasecmp(system_charset_info, $1.str, "OLD")))
+ {
+ bool new_row= ($1.str[0]=='N' || $1.str[0]=='n');
+
+ if (lex->trg_chistics.event == TRG_EVENT_INSERT &&
+ !new_row)
+ {
+ net_printf(YYTHD, ER_TRG_NO_SUCH_ROW_IN_TRG, "OLD",
+ "on INSERT");
+ YYABORT;
+ }
+
+ if (lex->trg_chistics.event == TRG_EVENT_DELETE &&
+ new_row)
+ {
+ net_printf(YYTHD, ER_TRG_NO_SUCH_ROW_IN_TRG, "NEW",
+ "on DELETE");
+ YYABORT;
+ }
+
+ Item_trigger_field *trg_fld=
+ new Item_trigger_field(new_row ? Item_trigger_field::NEW_ROW :
+ Item_trigger_field::OLD_ROW,
+ $3.str);
+
+ if (lex->trg_table &&
+ trg_fld->setup_field(thd, lex->trg_table,
+ lex->trg_chistics.event))
+ {
+ /*
+ FIXME. Far from perfect solution. See comment for
+ "SET NEW.field_name:=..." for more info.
+ */
+ net_printf(YYTHD, ER_BAD_FIELD_ERROR, $3.str,
+ new_row ? "NEW": "OLD");
+ YYABORT;
+ }
+
+ $$= (Item *)trg_fld;
+ }
+ else
+ {
+ SELECT_LEX *sel= lex->current_select;
+ if (sel->no_table_names_allowed)
+ {
+ my_printf_error(ER_TABLENAME_NOT_ALLOWED_HERE,
+ ER(ER_TABLENAME_NOT_ALLOWED_HERE),
+ MYF(0), $1.str, thd->where);
+ }
+ $$= (sel->parsing_place != IN_HAVING ||
+ sel->get_in_sum_expr() > 0) ?
+ (Item*) new Item_field(NullS,$1.str,$3.str) :
+ (Item*) new Item_ref(0,0,NullS,$1.str,$3.str);
+ }
+ }
| '.' ident '.' ident
{
THD *thd= YYTHD;
@@ -6649,6 +6799,7 @@ keyword:
| FIRST_SYM {}
| FIXED_SYM {}
| FLUSH_SYM {}
+ | FRAC_SECOND_SYM {}
| GEOMETRY_SYM {}
| GEOMETRYCOLLECTION {}
| GET_FORMAT {}
@@ -6854,13 +7005,78 @@ opt_var_ident_type:
option_value:
'@' ident_or_text equal expr
{
- Lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
+ LEX *lex= Lex;
+
+ if (lex->sphead && lex->sphead->m_type != TYPE_ENUM_PROCEDURE)
+ {
+ /*
+ We have to use special instruction in functions and triggers
+ because sp_instr_stmt will close all tables and thus ruin
+ execution of statement invoking function or trigger.
+
+ We also do not want to allow expression with subselects in
+ this case.
+ */
+ if (lex->query_tables)
+ {
+ send_error(YYTHD, ER_SP_SUBSELECT_NYI);
+ YYABORT;
+ }
+ sp_instr_set_user_var *i=
+ new sp_instr_set_user_var(lex->sphead->instructions(),
+ lex->spcont, $2, $4);
+ lex->sphead->add_instr(i);
+ }
+ else
+ lex->var_list.push_back(new set_var_user(new Item_func_set_user_var($2,$4)));
+
}
| internal_variable_name equal set_expr_or_default
{
LEX *lex=Lex;
- if ($1.var)
+ if ($1.var == &trg_new_row_fake_var)
+ {
+ /* We are in trigger and assigning value to field of new row */
+ Item *it;
+ sp_instr_set_trigger_field *i;
+ if (lex->query_tables)
+ {
+ send_error(YYTHD, ER_SP_SUBSELECT_NYI);
+ YYABORT;
+ }
+ if ($3)
+ it= $3;
+ else
+ {
+ /* QQ: Shouldn't this be field's default value ? */
+ it= new Item_null();
+ }
+ i= new sp_instr_set_trigger_field(lex->sphead->instructions(),
+ lex->spcont, $1.base_name, it);
+ if (lex->trg_table && i->setup_field(YYTHD, lex->trg_table,
+ lex->trg_chistics.event))
+ {
+ /*
+ FIXME. Now we are catching this kind of errors only
+ during opening tables. But this doesn't save us from most
+ common user error - misspelling field name, because we
+ will bark too late in this case... Moreover it is easy to
+ make table unusable with such kind of error...
+
+ So in future we either have to parse trigger definition
+ second time during create trigger or gather all trigger
+ fields in one list and perform setup_field() for them as
+ separate stage.
+
+ Error message also should be improved.
+ */
+ net_printf(YYTHD, ER_BAD_FIELD_ERROR, $1.base_name, "NEW");
+ YYABORT;
+ }
+ lex->sphead->add_instr(i);
+ }
+ else if ($1.var)
{ /* System variable */
lex->var_list.push_back(new set_var(lex->option_type, $1.var,
&$1.base_name, $3));
@@ -6975,18 +7191,46 @@ internal_variable_name:
}
| ident '.' ident
{
+ LEX *lex= Lex;
if (check_reserved_words(&$1))
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
- sys_var *tmp=find_sys_var($3.str, $3.length);
- if (!tmp)
- YYABORT;
- if (!tmp->is_struct())
- net_printf(YYTHD, ER_VARIABLE_IS_NOT_STRUCT, $3.str);
- $$.var= tmp;
- $$.base_name= $1;
+ if (lex->sphead && lex->sphead->m_type == TYPE_ENUM_TRIGGER &&
+ (!my_strcasecmp(system_charset_info, $1.str, "NEW") ||
+ !my_strcasecmp(system_charset_info, $1.str, "OLD")))
+ {
+ if ($1.str[0]=='O' || $1.str[0]=='o')
+ {
+ net_printf(YYTHD, ER_TRG_CANT_CHANGE_ROW, "OLD", "");
+ YYABORT;
+ }
+ if (lex->trg_chistics.event == TRG_EVENT_DELETE)
+ {
+ net_printf(YYTHD, ER_TRG_NO_SUCH_ROW_IN_TRG, "NEW",
+ "on DELETE");
+ YYABORT;
+ }
+ if (lex->trg_chistics.action_time == TRG_ACTION_AFTER)
+ {
+ net_printf(YYTHD, ER_TRG_CANT_CHANGE_ROW, "NEW", "after ");
+ YYABORT;
+ }
+ /* This special combination will denote field of NEW row */
+ $$.var= &trg_new_row_fake_var;
+ $$.base_name= $3;
+ }
+ else
+ {
+ sys_var *tmp=find_sys_var($3.str, $3.length);
+ if (!tmp)
+ YYABORT;
+ if (!tmp->is_struct())
+ net_printf(YYTHD, ER_VARIABLE_IS_NOT_STRUCT, $3.str);
+ $$.var= tmp;
+ $$.base_name= $1;
+ }
}
| DEFAULT '.' ident
{
diff --git a/sql/structs.h b/sql/structs.h
index 9f13ef54ce0..cc053e2e2fd 100644
--- a/sql/structs.h
+++ b/sql/structs.h
@@ -176,7 +176,8 @@ enum SHOW_TYPE
SHOW_SSL_GET_CIPHER_LIST,
#endif /* HAVE_OPENSSL */
SHOW_RPL_STATUS, SHOW_SLAVE_RUNNING,
- SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG
+ SHOW_KEY_CACHE_LONG, SHOW_KEY_CACHE_CONST_LONG,
+ SHOW_LONG_STATUS, SHOW_LONG_CONST_STATUS
};
enum SHOW_COMP_OPTION { SHOW_OPTION_YES, SHOW_OPTION_NO, SHOW_OPTION_DISABLED};
diff --git a/sql/table.cc b/sql/table.cc
index d07d2ca085d..1c216c44f66 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -733,7 +733,7 @@ int openfrm(const char *name, const char *alias, uint db_stat, uint prgflag,
outparam->db_low_byte_first=outparam->file->low_byte_first();
my_pthread_setspecific_ptr(THR_MALLOC,old_root);
- opened_tables++;
+ current_thd->status_var.opened_tables++;
#ifndef DBUG_OFF
if (use_hash)
(void) hash_check(&outparam->name_hash);
@@ -1583,7 +1583,8 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
if (where)
{
Item_arena *arena= thd->current_arena, backup;
- if (!arena->is_stmt_prepare())
+ TABLE_LIST *tbl= this;
+ if (arena->is_conventional())
arena= 0; // For easier test
if (!where->fixed && where->fix_fields(thd, ancestor, &where))
@@ -1591,17 +1592,23 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
if (arena)
thd->set_n_backup_item_arena(arena, &backup);
- if (outer_join)
+
+ /* Go up to join tree and try to find left join */
+ for (; tbl; tbl= tbl->embedding)
{
- /*
- Store WHERE condition to ON expression for outer join, because we
- can't use WHERE to correctly execute jeft joins on VIEWs and this
- expression will not be moved to WHERE condition (i.e. will be clean
- correctly for PS/SP)
- */
- on_expr= and_conds(on_expr, where);
+ if (tbl->outer_join)
+ {
+ /*
+ Store WHERE condition to ON expression for outer join, because we
+ can't use WHERE to correctly execute jeft joins on VIEWs and this
+ expression will not be moved to WHERE condition (i.e. will be clean
+ correctly for PS/SP)
+ */
+ tbl->on_expr= and_conds(tbl->on_expr, where);
+ break;
+ }
}
- else
+ if (tbl == 0)
{
/*
It is conds of JOIN, but it will be stored in st_select_lex::prep_where
@@ -1609,6 +1616,7 @@ bool st_table_list::setup_ancestor(THD *thd, Item **conds)
*/
*conds= and_conds(*conds, where);
}
+
if (arena)
thd->restore_backup_item_arena(arena, &backup);
}
diff --git a/sql/table.h b/sql/table.h
index b7cabe21638..f31c3c21d63 100644
--- a/sql/table.h
+++ b/sql/table.h
@@ -73,6 +73,7 @@ typedef struct st_filesort_info
class Field_timestamp;
class Field_blob;
+class Table_triggers_list;
struct st_table {
handler *file;
@@ -154,6 +155,8 @@ struct st_table {
REGINFO reginfo; /* field connections */
MEM_ROOT mem_root;
GRANT_INFO grant;
+ /* Table's triggers, 0 if there are no of them */
+ Table_triggers_list *triggers;
char *table_cache_key;
char *table_name,*real_name,*path;
@@ -217,6 +220,8 @@ typedef struct st_table_list
st_table_list *ancestor;
/* most upper view this table belongs to */
st_table_list *belong_to_view;
+ /* next_global before adding VIEW tables */
+ st_table_list *old_next;
Item *where; /* VIEW WHERE clause condition */
LEX_STRING query; /* text of (CRETE/SELECT) statement */
LEX_STRING md5; /* md5 of query tesxt */
@@ -260,6 +265,12 @@ typedef struct st_table_list
bool setup_ancestor(THD *thd, Item **conds);
bool placeholder() {return derived || view; }
void print(THD *thd, String *str);
+ inline st_table_list *next_independent()
+ {
+ if (view)
+ return old_next;
+ return next_global;
+ }
} TABLE_LIST;
class Item;