mirror of
https://github.com/MariaDB/server.git
synced 2026-05-08 08:04:29 +02:00
Implementation of MWL#172: Add support for prepared statements to HANDLER READ
It includes speed optimizations for HANDLER READ by caching as much as possible in HANDLER OPEN Other things: - Added mysqld option --disable-thr-alarm to be able to benchmark things without thr_alarm - Changed 'Locked' state to 'System lock' and 'Table lock' (these where used in the code but never shown to end user) - Better error message if mysql_install_db.sh fails - Moved handler function prototypes to sql_handler.h - Remove not anymore used 'thd->locked' member include/thr_alarm.h: Added my_disable_thr_alarm include/thr_lock.h: Add new member to THR_LOCK_DATA to remember original lock type state. This is needed as thr_unlock() resets type to TL_UNLOCK. mysql-test/include/check_no_concurrent_insert.inc: Locked -> Table lock mysql-test/include/handler.inc: Locked -> Table lock mysql-test/r/handler_innodb.result: Updated results for new tests mysql-test/r/handler_myisam.result: Updated results for new tests mysql-test/r/sp-threads.result: Locked -> Table lock mysql-test/suite/binlog/t/binlog_stm_row.test: Locked -> Table lock mysql-test/suite/funcs_1/datadict/processlist_val.inc: Locked -> Table lock mysql-test/suite/pbxt/t/lock_multi.test: Locked -> Table lock mysql-test/suite/sys_vars/r/concurrent_insert_func.result: Locked -> Table lock mysql-test/suite/sys_vars/t/concurrent_insert_func.test: Locked -> Table lock mysql-test/suite/sys_vars/t/delayed_insert_limit_func.test: Locked -> Table lock mysql-test/suite/sys_vars/t/query_cache_wlock_invalidate_func.test: Locked -> Table lock mysql-test/suite/sys_vars/t/sql_low_priority_updates_func.test: Locked -> Table lock mysql-test/t/insert_notembedded.test: Locked -> Table lock mysql-test/t/lock_multi.test: Locked -> Table lock mysql-test/t/merge-big.test: Locked -> Table lock mysql-test/t/multi_update.test: Locked -> Table lock mysql-test/t/query_cache_28249.test: Locked -> Table lock mysql-test/t/sp_notembedded.test: Locked -> Table lock mysql-test/t/sp_sync.test: Locked -> Table lock mysql-test/t/status.test: Locked -> Table lock mysql-test/t/trigger_notembedded.test: Locked -> Table lock mysys/thr_alarm.c: Added option to disable thr_alarm mysys/thr_lock.c: Detect loops scripts/mysql_install_db.sh: Give better error message if something goes wrong sql/Makefile.am: Added sql_handler.h sql/lock.cc: Split functions to allow one to cache value if store_lock() (for HANDLER functions). - Split mysql_lock_tables() into two functions, where first one allocates MYSQL_LOCK and other other one uses it. - Made get_lock_data() an external function. - Added argument to mysql_unlock_tables() to not free sql_lock. - Added argument to reset_lock_data() to reset lock structure to initial state (as after get_lock_data()) sql/mysql_priv.h: Moved handler function prototypes to sql_handler.h Added new lock functions. sql/mysqld.cc: Added --thread-alarm startup option sql/net_serv.cc: Don't call vio_blocking() if not needed sql/sql_base.cc: include sql_handler.h sql/sql_class.cc: include sql_handler.h Remove not anymore used 'thd->locked' member sql/sql_class.h: Remove not anymore used 'thd->locked' member sql/sql_db.cc: include sql_handler.h sql/sql_delete.cc: include sql_handler.h sql/sql_handler.cc: Rewrote all code to use SQL_HANDLER instead of TABLE_LIST (original interface) Rewrote mysql_ha_open() to cache all things from TABLE_LIST and items for field list, where etc. In mysql_ha_open() also cache MYSQL_LOCK structure from get_lock_data(). Split functions into smaller sub functions (needed to be able to implement mysql_ha_read_prepare()) Added mysql_ha_read_prepare() to allow one to prepare HANDLER READ. sql/sql_handler.h: Interface to sql_handler.cc sql/sql_parse.cc: include sql_handler.h sql/sql_prepare.cc: Added mysql_test_handler_read(), prepare for HANDLER READ sql/sql_rename.cc: include sql_handler.h sql/sql_show.cc: Removed usage of thd->locked sql/sql_table.cc: include sql_handler.h sql/sql_trigger.cc: include sql_handler.h
This commit is contained in:
parent
1eb21dc4be
commit
e63b5546c5
45 changed files with 1110 additions and 466 deletions
|
|
@ -88,6 +88,7 @@ typedef struct st_alarm {
|
|||
|
||||
extern uint thr_client_alarm;
|
||||
extern pthread_t alarm_thread;
|
||||
extern my_bool my_disable_thr_alarm;
|
||||
|
||||
#define thr_alarm_init(A) (*(A))=0
|
||||
#define thr_alarm_in_use(A) (*(A)!= 0)
|
||||
|
|
|
|||
|
|
@ -123,8 +123,10 @@ typedef struct st_thr_lock_data {
|
|||
struct st_thr_lock *lock;
|
||||
pthread_cond_t *cond;
|
||||
void *status_param; /* Param to status functions */
|
||||
void *debug_print_param;
|
||||
enum thr_lock_type type;
|
||||
|
||||
enum thr_lock_type org_type; /* Cache for MariaDB */
|
||||
void *debug_print_param; /* For error messages */
|
||||
uint priority;
|
||||
} THR_LOCK_DATA;
|
||||
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ connection default;
|
|||
# of our statement.
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "insert into $table (i) values (0)";
|
||||
where state = "Table lock" and info = "insert into $table (i) values (0)";
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--disable_result_log
|
||||
|
|
|
|||
|
|
@ -77,8 +77,9 @@ handler t2 read a prev limit 10;
|
|||
|
||||
handler t2 read a>=(16) limit 4;
|
||||
handler t2 read a>=(16) limit 2,2;
|
||||
select * from t1 where a>=16 limit 2,2;
|
||||
handler t2 read a last limit 3;
|
||||
|
||||
handler t2 read a=(16) limit 1,3;
|
||||
handler t2 read a=(19);
|
||||
handler t2 read a=(19) where b="yyy";
|
||||
|
||||
|
|
@ -105,6 +106,79 @@ eval alter table t1 engine = $engine_type;
|
|||
--error 1109
|
||||
handler t2 read first;
|
||||
|
||||
handler t1 open;
|
||||
handler t1 read a=(16) limit 1,3;
|
||||
flush tables;
|
||||
handler t1 read a=(16) limit 1,3;
|
||||
handler t1 close;
|
||||
|
||||
#
|
||||
# Test with prepared statements
|
||||
#
|
||||
|
||||
handler t1 open;
|
||||
prepare stmt from 'handler t1 read a=(?) limit ?,?';
|
||||
set @a=16,@b=1,@c=100;
|
||||
execute stmt using @a,@b,@c;
|
||||
set @a=16,@b=2,@c=1;
|
||||
execute stmt using @a,@b,@c;
|
||||
set @a=16,@b=0,@c=2;
|
||||
execute stmt using @a,@b,@c;
|
||||
deallocate prepare stmt;
|
||||
|
||||
prepare stmt from 'handler t1 read a next limit ?';
|
||||
handler t1 read a>=(11);
|
||||
set @a=3;
|
||||
execute stmt using @a;
|
||||
execute stmt using @a;
|
||||
execute stmt using @a;
|
||||
deallocate prepare stmt;
|
||||
|
||||
prepare stmt from 'handler t1 read b prev limit ?';
|
||||
execute stmt using @a;
|
||||
execute stmt using @a;
|
||||
execute stmt using @a;
|
||||
execute stmt using @a;
|
||||
deallocate prepare stmt;
|
||||
|
||||
prepare stmt from 'handler t1 read b=(?,?)';
|
||||
set @a=14, @b='aaa';
|
||||
execute stmt using @a,@b;
|
||||
set @a=14, @b='not found';
|
||||
execute stmt using @a,@b;
|
||||
deallocate prepare stmt;
|
||||
|
||||
prepare stmt from 'handler t1 read b=(1+?) limit 10';
|
||||
set @a=15;
|
||||
execute stmt using @a;
|
||||
execute stmt using @a;
|
||||
deallocate prepare stmt;
|
||||
|
||||
prepare stmt from 'handler t1 read a>=(?) where a < ? limit 5';
|
||||
set @a=15, @b=20;
|
||||
execute stmt using @a,@b;
|
||||
execute stmt using @a,@b;
|
||||
deallocate prepare stmt;
|
||||
|
||||
prepare stmt from 'handler t1 read a=(?)';
|
||||
set @a=16;
|
||||
execute stmt using @a;
|
||||
alter table t1 add c int;
|
||||
--error 1109
|
||||
execute stmt using @a;
|
||||
deallocate prepare stmt;
|
||||
--error 1109
|
||||
handler t1 close;
|
||||
|
||||
handler t1 open;
|
||||
prepare stmt from 'handler t1 read a=(?)';
|
||||
flush tables;
|
||||
set @a=16;
|
||||
--error ER_NEED_REPREPARE
|
||||
execute stmt using @a;
|
||||
deallocate prepare stmt;
|
||||
handler t1 close;
|
||||
|
||||
#
|
||||
# DROP TABLE / ALTER TABLE
|
||||
#
|
||||
|
|
|
|||
|
|
@ -115,11 +115,18 @@ handler t2 read a>=(16) limit 2,2;
|
|||
a b
|
||||
17 ddd
|
||||
18 eee
|
||||
select * from t1 where a>=16 limit 2,2;
|
||||
a b
|
||||
17 ddd
|
||||
18 eee
|
||||
handler t2 read a last limit 3;
|
||||
a b
|
||||
22 iii
|
||||
21 hhh
|
||||
20 ggg
|
||||
handler t2 read a=(16) limit 1,3;
|
||||
a b
|
||||
16 xxx
|
||||
handler t2 read a=(19);
|
||||
a b
|
||||
19 fff
|
||||
|
|
@ -161,6 +168,128 @@ a b
|
|||
alter table t1 engine = InnoDB;
|
||||
handler t2 read first;
|
||||
ERROR 42S02: Unknown table 't2' in HANDLER
|
||||
handler t1 open;
|
||||
handler t1 read a=(16) limit 1,3;
|
||||
a b
|
||||
16 xxx
|
||||
flush tables;
|
||||
handler t1 read a=(16) limit 1,3;
|
||||
a b
|
||||
16 xxx
|
||||
handler t1 close;
|
||||
handler t1 open;
|
||||
prepare stmt from 'handler t1 read a=(?) limit ?,?';
|
||||
set @a=16,@b=1,@c=100;
|
||||
execute stmt using @a,@b,@c;
|
||||
a b
|
||||
16 xxx
|
||||
set @a=16,@b=2,@c=1;
|
||||
execute stmt using @a,@b,@c;
|
||||
a b
|
||||
set @a=16,@b=0,@c=2;
|
||||
execute stmt using @a,@b,@c;
|
||||
a b
|
||||
16 ccc
|
||||
16 xxx
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read a next limit ?';
|
||||
handler t1 read a>=(11);
|
||||
a b
|
||||
14 aaa
|
||||
set @a=3;
|
||||
execute stmt using @a;
|
||||
a b
|
||||
15 bbb
|
||||
16 ccc
|
||||
16 xxx
|
||||
execute stmt using @a;
|
||||
a b
|
||||
17 ddd
|
||||
18 eee
|
||||
19 fff
|
||||
execute stmt using @a;
|
||||
a b
|
||||
19 yyy
|
||||
20 ggg
|
||||
21 hhh
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read b prev limit ?';
|
||||
execute stmt using @a;
|
||||
a b
|
||||
22 iii
|
||||
21 hhh
|
||||
20 ggg
|
||||
execute stmt using @a;
|
||||
a b
|
||||
19 yyy
|
||||
19 fff
|
||||
18 eee
|
||||
execute stmt using @a;
|
||||
a b
|
||||
17 ddd
|
||||
16 xxx
|
||||
16 ccc
|
||||
execute stmt using @a;
|
||||
a b
|
||||
15 bbb
|
||||
14 aaa
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read b=(?,?)';
|
||||
set @a=14, @b='aaa';
|
||||
execute stmt using @a,@b;
|
||||
a b
|
||||
14 aaa
|
||||
set @a=14, @b='not found';
|
||||
execute stmt using @a,@b;
|
||||
a b
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read b=(1+?) limit 10';
|
||||
set @a=15;
|
||||
execute stmt using @a;
|
||||
a b
|
||||
16 ccc
|
||||
16 xxx
|
||||
execute stmt using @a;
|
||||
a b
|
||||
16 ccc
|
||||
16 xxx
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read a>=(?) where a < ? limit 5';
|
||||
set @a=15, @b=20;
|
||||
execute stmt using @a,@b;
|
||||
a b
|
||||
15 bbb
|
||||
16 ccc
|
||||
16 xxx
|
||||
17 ddd
|
||||
18 eee
|
||||
execute stmt using @a,@b;
|
||||
a b
|
||||
15 bbb
|
||||
16 ccc
|
||||
16 xxx
|
||||
17 ddd
|
||||
18 eee
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read a=(?)';
|
||||
set @a=16;
|
||||
execute stmt using @a;
|
||||
a b
|
||||
16 ccc
|
||||
alter table t1 add c int;
|
||||
execute stmt using @a;
|
||||
ERROR 42S02: Unknown table 't1' in HANDLER
|
||||
deallocate prepare stmt;
|
||||
handler t1 close;
|
||||
ERROR 42S02: Unknown table 't1' in HANDLER
|
||||
handler t1 open;
|
||||
prepare stmt from 'handler t1 read a=(?)';
|
||||
flush tables;
|
||||
set @a=16;
|
||||
execute stmt using @a;
|
||||
ERROR HY000: Prepared statement needs to be re-prepared
|
||||
deallocate prepare stmt;
|
||||
handler t1 close;
|
||||
handler t1 open as t2;
|
||||
drop table t1;
|
||||
create table t1 (a int);
|
||||
|
|
|
|||
|
|
@ -115,11 +115,18 @@ handler t2 read a>=(16) limit 2,2;
|
|||
a b
|
||||
17 ddd
|
||||
18 eee
|
||||
select * from t1 where a>=16 limit 2,2;
|
||||
a b
|
||||
17 ddd
|
||||
18 eee
|
||||
handler t2 read a last limit 3;
|
||||
a b
|
||||
22 iii
|
||||
21 hhh
|
||||
20 ggg
|
||||
handler t2 read a=(16) limit 1,3;
|
||||
a b
|
||||
16 xxx
|
||||
handler t2 read a=(19);
|
||||
a b
|
||||
19 fff
|
||||
|
|
@ -161,6 +168,128 @@ a b
|
|||
alter table t1 engine = MyISAM;
|
||||
handler t2 read first;
|
||||
ERROR 42S02: Unknown table 't2' in HANDLER
|
||||
handler t1 open;
|
||||
handler t1 read a=(16) limit 1,3;
|
||||
a b
|
||||
16 xxx
|
||||
flush tables;
|
||||
handler t1 read a=(16) limit 1,3;
|
||||
a b
|
||||
16 xxx
|
||||
handler t1 close;
|
||||
handler t1 open;
|
||||
prepare stmt from 'handler t1 read a=(?) limit ?,?';
|
||||
set @a=16,@b=1,@c=100;
|
||||
execute stmt using @a,@b,@c;
|
||||
a b
|
||||
16 xxx
|
||||
set @a=16,@b=2,@c=1;
|
||||
execute stmt using @a,@b,@c;
|
||||
a b
|
||||
set @a=16,@b=0,@c=2;
|
||||
execute stmt using @a,@b,@c;
|
||||
a b
|
||||
16 ccc
|
||||
16 xxx
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read a next limit ?';
|
||||
handler t1 read a>=(11);
|
||||
a b
|
||||
14 aaa
|
||||
set @a=3;
|
||||
execute stmt using @a;
|
||||
a b
|
||||
15 bbb
|
||||
16 ccc
|
||||
16 xxx
|
||||
execute stmt using @a;
|
||||
a b
|
||||
17 ddd
|
||||
18 eee
|
||||
19 fff
|
||||
execute stmt using @a;
|
||||
a b
|
||||
19 yyy
|
||||
20 ggg
|
||||
21 hhh
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read b prev limit ?';
|
||||
execute stmt using @a;
|
||||
a b
|
||||
22 iii
|
||||
21 hhh
|
||||
20 ggg
|
||||
execute stmt using @a;
|
||||
a b
|
||||
19 yyy
|
||||
19 fff
|
||||
18 eee
|
||||
execute stmt using @a;
|
||||
a b
|
||||
17 ddd
|
||||
16 xxx
|
||||
16 ccc
|
||||
execute stmt using @a;
|
||||
a b
|
||||
15 bbb
|
||||
14 aaa
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read b=(?,?)';
|
||||
set @a=14, @b='aaa';
|
||||
execute stmt using @a,@b;
|
||||
a b
|
||||
14 aaa
|
||||
set @a=14, @b='not found';
|
||||
execute stmt using @a,@b;
|
||||
a b
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read b=(1+?) limit 10';
|
||||
set @a=15;
|
||||
execute stmt using @a;
|
||||
a b
|
||||
16 ccc
|
||||
16 xxx
|
||||
execute stmt using @a;
|
||||
a b
|
||||
16 ccc
|
||||
16 xxx
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read a>=(?) where a < ? limit 5';
|
||||
set @a=15, @b=20;
|
||||
execute stmt using @a,@b;
|
||||
a b
|
||||
15 bbb
|
||||
16 ccc
|
||||
16 xxx
|
||||
17 ddd
|
||||
18 eee
|
||||
execute stmt using @a,@b;
|
||||
a b
|
||||
15 bbb
|
||||
16 ccc
|
||||
16 xxx
|
||||
17 ddd
|
||||
18 eee
|
||||
deallocate prepare stmt;
|
||||
prepare stmt from 'handler t1 read a=(?)';
|
||||
set @a=16;
|
||||
execute stmt using @a;
|
||||
a b
|
||||
16 ccc
|
||||
alter table t1 add c int;
|
||||
execute stmt using @a;
|
||||
ERROR 42S02: Unknown table 't1' in HANDLER
|
||||
deallocate prepare stmt;
|
||||
handler t1 close;
|
||||
ERROR 42S02: Unknown table 't1' in HANDLER
|
||||
handler t1 open;
|
||||
prepare stmt from 'handler t1 read a=(?)';
|
||||
flush tables;
|
||||
set @a=16;
|
||||
execute stmt using @a;
|
||||
ERROR HY000: Prepared statement needs to be re-prepared
|
||||
deallocate prepare stmt;
|
||||
handler t1 close;
|
||||
handler t1 open as t2;
|
||||
drop table t1;
|
||||
create table t1 (a int);
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ call bug9486();
|
|||
show processlist;
|
||||
Id User Host db Command Time State Info
|
||||
# root localhost test Sleep # NULL
|
||||
# root localhost test Query # Locked update t1, t2 set val= 1 where id1=id2
|
||||
# root localhost test Query # Table lock update t1, t2 set val= 1 where id1=id2
|
||||
# root localhost test Query # NULL show processlist
|
||||
# root localhost test Sleep # NULL
|
||||
unlock tables;
|
||||
|
|
|
|||
|
|
@ -60,7 +60,7 @@ let $wait_condition=
|
|||
--echo # con1
|
||||
let $wait_condition=
|
||||
SELECT COUNT(*) = 1 FROM information_schema.processlist WHERE
|
||||
state = "Locked" and info = "INSERT INTO t2 VALUES (3)";
|
||||
state = "Table Lock" and info = "INSERT INTO t2 VALUES (3)";
|
||||
--source include/wait_condition.inc
|
||||
SELECT RELEASE_LOCK('Bug#34306');
|
||||
--connection con2
|
||||
|
|
|
|||
|
|
@ -368,13 +368,13 @@ echo
|
|||
;
|
||||
connection default;
|
||||
echo
|
||||
# Poll till INFO is no more NULL and State = 'Locked'.
|
||||
# Poll till INFO is no more NULL and State = "Table Lock".
|
||||
;
|
||||
let $wait_condition= SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
WHERE INFO IS NOT NULL AND STATE = 'Locked';
|
||||
WHERE INFO IS NOT NULL AND STATE = "Table Lock";
|
||||
--source include/wait_condition.inc
|
||||
#
|
||||
# Expect to see the state 'Locked' for the third connection because the SELECT
|
||||
# Expect to see the state "Table Lock" for the third connection because the SELECT
|
||||
# collides with the WRITE TABLE LOCK.
|
||||
--replace_column 1 <ID> 3 <HOST_NAME> 6 <TIME> 9 <TIME_MS>
|
||||
SELECT * FROM INFORMATION_SCHEMA.PROCESSLIST;
|
||||
|
|
@ -423,10 +423,10 @@ echo
|
|||
;
|
||||
connection default;
|
||||
echo
|
||||
# Poll till INFO is no more NULL and State = 'Locked'.
|
||||
# Poll till INFO is no more NULL and State = "Table Lock".
|
||||
;
|
||||
let $wait_condition= SELECT COUNT(*) FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
WHERE INFO IS NOT NULL AND STATE = 'Locked';
|
||||
WHERE INFO IS NOT NULL AND STATE = "Table Lock";
|
||||
--source include/wait_condition.inc
|
||||
echo
|
||||
# Expect result:
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ insert t1 select * from t2;
|
|||
connection locker;
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "insert t1 select * from t2";
|
||||
where state = "Table Lock" and info = "insert t1 select * from t2";
|
||||
--source include/wait_condition.inc
|
||||
drop table t2;
|
||||
connection reader;
|
||||
|
|
@ -72,7 +72,7 @@ connection locker;
|
|||
# Sleep a bit till the insert of connection reader is in work and hangs
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "insert t1 select * from t2";
|
||||
where state = "Table Lock" and info = "insert t1 select * from t2";
|
||||
--source include/wait_condition.inc
|
||||
drop table t2;
|
||||
connection reader;
|
||||
|
|
@ -251,7 +251,7 @@ connection reader;
|
|||
# Wait till connection writer is blocked
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "alter table t1 auto_increment=0";
|
||||
where state = "Table Lock" and info = "alter table t1 auto_increment=0";
|
||||
--source include/wait_condition.inc
|
||||
send
|
||||
alter table t1 auto_increment=0;
|
||||
|
|
@ -259,7 +259,7 @@ connection locker;
|
|||
# Wait till connection reader is blocked
|
||||
let $wait_condition=
|
||||
select count(*) = 2 from information_schema.processlist
|
||||
where state = "Locked" and info = "alter table t1 auto_increment=0";
|
||||
where state = "Table Lock" and info = "alter table t1 auto_increment=0";
|
||||
--source include/wait_condition.inc
|
||||
unlock tables;
|
||||
connection writer;
|
||||
|
|
@ -414,16 +414,16 @@ update t1 set i= 10;
|
|||
connection reader;
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "update t1 set i= 10";
|
||||
where state = "Table Lock" and info = "update t1 set i= 10";
|
||||
--source include/wait_condition.inc
|
||||
send
|
||||
select * from t1;
|
||||
connection default;
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "select * from t1";
|
||||
where state = "Table Lock" and info = "select * from t1";
|
||||
--source include/wait_condition.inc
|
||||
let $ID= `select id from information_schema.processlist where state = "Locked" and info = "update t1 set i= 10"`;
|
||||
let $ID= `select id from information_schema.processlist where state = "Table Lock" and info = "update t1 set i= 10"`;
|
||||
--replace_result $ID ID
|
||||
eval kill query $ID;
|
||||
connection reader;
|
||||
|
|
@ -557,7 +557,7 @@ connection waiter;
|
|||
connection default;
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "insert into t1 values(1)";
|
||||
where state = "Table Lock" and info = "insert into t1 values(1)";
|
||||
--source include/wait_condition.inc
|
||||
let $tlwb= `show status like 'Table_locks_waited'`;
|
||||
unlock tables;
|
||||
|
|
|
|||
|
|
@ -37,9 +37,9 @@ INSERT INTO t1(name) VALUES('Record_7');
|
|||
connection default;
|
||||
## show processlist info and state ##
|
||||
SELECT state,info FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
WHERE state= "Locked" AND info LIKE "INSERT INTO t1%";
|
||||
WHERE state= "Table Lock" AND info LIKE "INSERT INTO t1%";
|
||||
state info
|
||||
Locked INSERT INTO t1(name) VALUES('Record_7')
|
||||
Table lock INSERT INTO t1(name) VALUES('Record_7')
|
||||
## table contents befor UNLOCK ##
|
||||
SELECT * FROM t1;
|
||||
name
|
||||
|
|
|
|||
|
|
@ -98,12 +98,12 @@ INSERT INTO t1(name) VALUES('Record_7');
|
|||
connection default;
|
||||
# wait until INSERT will be locked (low performance)
|
||||
let $wait_condition= SELECT COUNT(*) = 1 FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
WHERE state= "Locked" AND info LIKE "INSERT INTO t1%";
|
||||
WHERE state= "Table Lock" AND info LIKE "INSERT INTO t1%";
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--echo ## show processlist info and state ##
|
||||
SELECT state,info FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
WHERE state= "Locked" AND info LIKE "INSERT INTO t1%";
|
||||
WHERE state= "Table Lock" AND info LIKE "INSERT INTO t1%";
|
||||
--echo ## table contents befor UNLOCK ##
|
||||
SELECT * FROM t1;
|
||||
UNLOCK TABLES;
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ connection default;
|
|||
--echo ** Wait till con0 is blocked **
|
||||
let $wait_condition=
|
||||
SELECT COUNT(*) = 1 FROM information_schema.processlist
|
||||
WHERE state = 'Locked' AND info = '$my_select';
|
||||
WHERE state = "Table Lock" AND info = '$my_select';
|
||||
--source include/wait_condition.inc
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
|
@ -207,7 +207,7 @@ connection default;
|
|||
--echo ** Wait till con0 is blocked **
|
||||
let $wait_condition=
|
||||
SELECT COUNT(*) = 1 FROM information_schema.processlist
|
||||
WHERE state = 'Locked' AND info = '$my_select';
|
||||
WHERE state = "Table Lock" AND info = '$my_select';
|
||||
--source include/wait_condition.inc
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ send SELECT * FROM t1;
|
|||
connection con0;
|
||||
|
||||
--echo wait until table is locked
|
||||
let $wait_condition= SELECT count(*) > 0 FROM information_schema.processlist WHERE state= 'Locked';
|
||||
let $wait_condition= SELECT count(*) > 0 FROM information_schema.processlist WHERE state= "Table Lock";
|
||||
--source include/wait_condition.inc
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ delimiter ;|
|
|||
--echo ** Connection con0 **
|
||||
connection con0;
|
||||
|
||||
let $wait_condition = SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state='Locked' AND info LIKE 'UPDATE t1 SET a = CONCAT(a,"-updated")';
|
||||
let $wait_condition = SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state="Table Lock" AND info LIKE 'UPDATE t1 SET a = CONCAT(a,"-updated")';
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--echo ** Asynchronous Execution **
|
||||
|
|
@ -101,7 +101,7 @@ delimiter ;|
|
|||
--echo ** Connection default **
|
||||
connection default;
|
||||
|
||||
let $wait_condition= SELECT count(*) = 2 FROM information_schema.processlist WHERE state LIKE 'Locked';
|
||||
let $wait_condition= SELECT count(*) = 2 FROM information_schema.processlist WHERE state LIKE "Table Lock";
|
||||
--source include/wait_condition.inc
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
|
@ -156,7 +156,7 @@ delimiter ;|
|
|||
--echo ** Connection con0 **
|
||||
connection con0;
|
||||
|
||||
let $wait_condition = SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state='Locked' AND info LIKE 'UPDATE t1 SET a = CONCAT(a,"-updated")';
|
||||
let $wait_condition = SELECT COUNT(*) > 0 FROM information_schema.processlist WHERE state="Table Lock" AND info LIKE 'UPDATE t1 SET a = CONCAT(a,"-updated")';
|
||||
--source include/wait_condition.inc
|
||||
|
||||
--echo ** Asynchronous Execution **
|
||||
|
|
@ -172,7 +172,7 @@ delimiter ;|
|
|||
--echo ** Connection default **
|
||||
connection default;
|
||||
|
||||
let $wait_condition= SELECT count(*) = 2 FROM information_schema.processlist WHERE state LIKE 'Locked';
|
||||
let $wait_condition= SELECT count(*) = 2 FROM information_schema.processlist WHERE state LIKE "Table Lock";
|
||||
--source include/wait_condition.inc
|
||||
UNLOCK TABLES;
|
||||
|
||||
|
|
|
|||
|
|
@ -174,7 +174,7 @@ connection default;
|
|||
# we must wait till the insert opens and locks the table
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and id = $ID;
|
||||
where state = "Table lock" and id = $ID;
|
||||
--source include/wait_condition.inc
|
||||
connect (select,localhost,root,,);
|
||||
--echo connection: select
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ connection reader;
|
|||
# Sleep a bit till the update of connection writer is in work and hangs
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "update low_priority t1 set n = 4";
|
||||
where state = "Table lock" and info = "update low_priority t1 set n = 4";
|
||||
--source include/wait_condition.inc
|
||||
send
|
||||
select n from t1;
|
||||
|
|
@ -32,7 +32,7 @@ connection locker;
|
|||
# Sleep a bit till the select of connection reader is in work and hangs
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "select n from t1";
|
||||
where state = "Table lock" and info = "select n from t1";
|
||||
--source include/wait_condition.inc
|
||||
unlock tables;
|
||||
connection writer;
|
||||
|
|
@ -52,7 +52,7 @@ connection reader;
|
|||
# Sleep a bit till the update of connection writer is in work and hangs
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "update low_priority t1 set n = 4";
|
||||
where state = "Table Lock" and info = "update low_priority t1 set n = 4";
|
||||
--source include/wait_condition.inc
|
||||
select n from t1;
|
||||
connection locker;
|
||||
|
|
@ -96,7 +96,7 @@ insert t1 select * from t2;
|
|||
connection locker;
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "insert t1 select * from t2";
|
||||
where state = "Table Lock" and info = "insert t1 select * from t2";
|
||||
--source include/wait_condition.inc
|
||||
drop table t2;
|
||||
connection reader;
|
||||
|
|
@ -120,7 +120,7 @@ connection locker;
|
|||
# Sleep a bit till the insert of connection reader is in work and hangs
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "insert t1 select * from t2";
|
||||
where state = "Table Lock" and info = "insert t1 select * from t2";
|
||||
--source include/wait_condition.inc
|
||||
drop table t2;
|
||||
connection reader;
|
||||
|
|
@ -299,7 +299,7 @@ connection reader;
|
|||
# Wait till connection writer is blocked
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "alter table t1 auto_increment=0";
|
||||
where state = "Table Lock" and info = "alter table t1 auto_increment=0";
|
||||
--source include/wait_condition.inc
|
||||
send
|
||||
alter table t1 auto_increment=0;
|
||||
|
|
@ -307,7 +307,7 @@ connection locker;
|
|||
# Wait till connection reader is blocked
|
||||
let $wait_condition=
|
||||
select count(*) = 2 from information_schema.processlist
|
||||
where state = "Locked" and info = "alter table t1 auto_increment=0";
|
||||
where state = "Table Lock" and info = "alter table t1 auto_increment=0";
|
||||
--source include/wait_condition.inc
|
||||
unlock tables;
|
||||
connection writer;
|
||||
|
|
@ -462,16 +462,16 @@ update t1 set i= 10;
|
|||
connection reader;
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "update t1 set i= 10";
|
||||
where state = "Table Lock" and info = "update t1 set i= 10";
|
||||
--source include/wait_condition.inc
|
||||
send
|
||||
select * from t1;
|
||||
connection default;
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "select * from t1";
|
||||
where state = "Table Lock" and info = "select * from t1";
|
||||
--source include/wait_condition.inc
|
||||
let $ID= `select id from information_schema.processlist where state = "Locked" and info = "update t1 set i= 10"`;
|
||||
let $ID= `select id from information_schema.processlist where state = "Table Lock" and info = "update t1 set i= 10"`;
|
||||
--replace_result $ID ID
|
||||
eval kill query $ID;
|
||||
connection reader;
|
||||
|
|
@ -622,7 +622,7 @@ connection waiter;
|
|||
connection default;
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and info = "insert into t1 values(1)";
|
||||
where state = "Table Lock" and info = "insert into t1 values(1)";
|
||||
--source include/wait_condition.inc
|
||||
let $tlwb= `show status like 'Table_locks_waited'`;
|
||||
unlock tables;
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ connection default;
|
|||
#--sleep 8
|
||||
#SELECT ID,STATE,INFO FROM INFORMATION_SCHEMA.PROCESSLIST;
|
||||
let $wait_condition= SELECT 1 FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
WHERE ID = $con1_id AND STATE = 'Locked';
|
||||
WHERE ID = $con1_id AND STATE = "Table Lock";
|
||||
--source include/wait_condition.inc
|
||||
#SELECT NOW();
|
||||
--echo # Kick INSERT out of thr_multi_lock().
|
||||
|
|
|
|||
|
|
@ -498,9 +498,9 @@ send alter table t1 add column c int default 100 after a;
|
|||
connect (updater,localhost,root,,test);
|
||||
connection updater;
|
||||
# Wait till "alter table t1 ..." of session changer is in work.
|
||||
# = There is one session is in state "Locked".
|
||||
# = There is one session is in state "Table Lock".
|
||||
let $wait_condition= select count(*)= 1 from information_schema.processlist
|
||||
where state= 'Locked';
|
||||
where state= "Table Lock";
|
||||
--source include/wait_condition.inc
|
||||
send update t1, v1 set t1.b=t1.a+t1.b+v1.b where t1.a=v1.a;
|
||||
|
||||
|
|
@ -509,9 +509,9 @@ connection locker;
|
|||
# - "alter table t1 ..." of session changer and
|
||||
# - "update t1, v1 ..." of session updater
|
||||
# are in work.
|
||||
# = There are two session is in state "Locked".
|
||||
# = There are two session is in state "Table Lock".
|
||||
let $wait_condition= select count(*)= 2 from information_schema.processlist
|
||||
where state= 'Locked';
|
||||
where state= "Table Lock";
|
||||
--source include/wait_condition.inc
|
||||
unlock tables;
|
||||
|
||||
|
|
|
|||
|
|
@ -64,12 +64,12 @@ connection user3;
|
|||
# The values marked with 'X' must be reached.
|
||||
--echo # Poll till the select of connection user1 is blocked by the write lock on t1.
|
||||
let $wait_condition= SELECT COUNT(*) = 1 FROM information_schema.processlist
|
||||
WHERE state = 'Locked'
|
||||
WHERE state = "Table Lock"
|
||||
AND info = '$select_for_qc';
|
||||
--source include/wait_condition.inc
|
||||
eval
|
||||
SELECT user,command,state,info FROM information_schema.processlist
|
||||
WHERE state = 'Locked'
|
||||
WHERE state = "Table Lock"
|
||||
AND info = '$select_for_qc';
|
||||
INSERT INTO t1 VALUES (4);
|
||||
|
||||
|
|
|
|||
|
|
@ -276,7 +276,7 @@ set session low_priority_updates=on;
|
|||
connection rl_wait;
|
||||
let $wait_condition=
|
||||
select count(*) = 1 from information_schema.processlist
|
||||
where state = "Locked" and
|
||||
where state = "Table lock" and
|
||||
info = "update t1 set value='updated' where value='old'";
|
||||
--source include/wait_condition.inc
|
||||
|
||||
|
|
|
|||
|
|
@ -34,7 +34,7 @@ SET DEBUG_SYNC = 'multi_update_reopen_tables SIGNAL parked WAIT_FOR go';
|
|||
|
||||
connection con1;
|
||||
let $wait_condition= SELECT 1 FROM information_schema.processlist WHERE ID = $ID AND
|
||||
state = "Locked";
|
||||
state = "Table lock";
|
||||
--source include/wait_condition.inc
|
||||
DROP TABLE t1, t2;
|
||||
SET DEBUG_SYNC = 'now WAIT_FOR parked';
|
||||
|
|
|
|||
|
|
@ -58,7 +58,7 @@ let $ID= `select connection_id()`;
|
|||
connection con2;
|
||||
--echo # Switched to connection: con2
|
||||
# wait for the other query to start executing
|
||||
let $wait_condition= select 1 from INFORMATION_SCHEMA.PROCESSLIST where ID = $ID and STATE = "Locked";
|
||||
let $wait_condition= select 1 from INFORMATION_SCHEMA.PROCESSLIST where ID = $ID and STATE = "Table Lock";
|
||||
--source include/wait_condition.inc
|
||||
unlock tables;
|
||||
|
||||
|
|
|
|||
|
|
@ -916,7 +916,7 @@ INSERT INTO t1 VALUES (5);
|
|||
CONNECTION rl_contender;
|
||||
# Wait until wl_acquirer is waiting for the read lock on t2 to be released.
|
||||
let $wait_condition=
|
||||
SELECT STATE = 'Locked' FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
SELECT STATE = "Table Lock" FROM INFORMATION_SCHEMA.PROCESSLIST
|
||||
WHERE ID = $wl_acquirer_thread_id;
|
||||
--source include/wait_condition.inc
|
||||
# must not "see" the row inserted by the INSERT (as it must run before the
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@
|
|||
|
||||
uint thr_client_alarm;
|
||||
static int alarm_aborted=1; /* No alarm thread */
|
||||
my_bool thr_alarm_inited= 0;
|
||||
my_bool thr_alarm_inited= 0, my_disable_thr_alarm= 0;
|
||||
volatile my_bool alarm_thread_running= 0;
|
||||
time_t next_alarm_expire_time= ~ (time_t) 0;
|
||||
static sig_handler process_alarm_part2(int sig);
|
||||
|
|
@ -173,6 +173,21 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
|
|||
DBUG_ENTER("thr_alarm");
|
||||
DBUG_PRINT("enter",("thread: %s sec: %d",my_thread_name(),sec));
|
||||
|
||||
if (my_disable_thr_alarm)
|
||||
{
|
||||
(*alrm)= &alarm_data->alarmed;
|
||||
alarm_data->alarmed= 1; /* Abort if interrupted */
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
if (unlikely(alarm_aborted))
|
||||
{ /* No signal thread */
|
||||
DBUG_PRINT("info", ("alarm aborted"));
|
||||
if (alarm_aborted > 0)
|
||||
goto abort_no_unlock;
|
||||
sec= 1; /* Abort mode */
|
||||
}
|
||||
|
||||
now= my_time(0);
|
||||
if (!alarm_data)
|
||||
{
|
||||
|
|
@ -190,13 +205,6 @@ my_bool thr_alarm(thr_alarm_t *alrm, uint sec, ALARM *alarm_data)
|
|||
|
||||
one_signal_hand_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
|
||||
pthread_mutex_lock(&LOCK_alarm); /* Lock from threads & alarms */
|
||||
if (unlikely(alarm_aborted))
|
||||
{ /* No signal thread */
|
||||
DBUG_PRINT("info", ("alarm aborted"));
|
||||
if (alarm_aborted > 0)
|
||||
goto abort;
|
||||
sec= 1; /* Abort mode */
|
||||
}
|
||||
if (alarm_queue.elements >= max_used_alarms)
|
||||
{
|
||||
if (alarm_queue.elements == alarm_queue.max_elements)
|
||||
|
|
@ -251,6 +259,8 @@ void thr_end_alarm(thr_alarm_t *alarmed)
|
|||
#endif
|
||||
DBUG_ENTER("thr_end_alarm");
|
||||
|
||||
if (my_disable_thr_alarm)
|
||||
DBUG_VOID_RETURN;
|
||||
one_signal_hand_sigmask(SIG_BLOCK,&full_signal_set,&old_mask);
|
||||
alarm_data= (ALARM*) ((uchar*) *alarmed - offsetof(ALARM,alarmed));
|
||||
pthread_mutex_lock(&LOCK_alarm);
|
||||
|
|
|
|||
|
|
@ -230,14 +230,16 @@ static void check_locks(THR_LOCK *lock, const char *where,
|
|||
|
||||
if (found_errors < MAX_FOUND_ERRORS)
|
||||
{
|
||||
uint count=0;
|
||||
uint count=0, count2= 0;
|
||||
THR_LOCK_DATA *data;
|
||||
for (data=lock->read.data ; data ; data=data->next)
|
||||
{
|
||||
count2++;
|
||||
if (data->type == TL_READ_NO_INSERT)
|
||||
count++;
|
||||
/* Protect against infinite loop. */
|
||||
DBUG_ASSERT(count <= lock->read_no_write_count);
|
||||
DBUG_ASSERT(count <= lock->read_no_write_count &&
|
||||
count2 <= MAX_LOCKS);
|
||||
}
|
||||
if (count != lock->read_no_write_count)
|
||||
{
|
||||
|
|
@ -288,7 +290,10 @@ static void check_locks(THR_LOCK *lock, const char *where,
|
|||
if (lock->write.data->type == TL_WRITE_CONCURRENT_INSERT)
|
||||
{
|
||||
THR_LOCK_DATA *data;
|
||||
for (data=lock->write.data->next ; data ; data=data->next)
|
||||
uint count= 0;
|
||||
for (data=lock->write.data->next;
|
||||
data && count < MAX_LOCKS;
|
||||
data=data->next)
|
||||
{
|
||||
if (data->type != TL_WRITE_CONCURRENT_INSERT)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -398,9 +398,14 @@ else
|
|||
echo "Installation of system tables failed! Examine the logs in"
|
||||
echo "$ldata for more information."
|
||||
echo
|
||||
echo "You can try to start the mysqld daemon with:"
|
||||
echo "The problem could be conflicting information in an external"
|
||||
echo "my.cnf files. You can ignore these by doing:"
|
||||
echo
|
||||
echo " shell> $mysqld --skip-grant &"
|
||||
echo " shell> /scripts/mysql_install_db --defaults-file=~/.my.cnf"
|
||||
echo
|
||||
echo "You can also try to start the mysqld daemon with:"
|
||||
echo
|
||||
echo " shell> $mysqld --skip-grant --general-log &"
|
||||
echo
|
||||
echo "and use the command line tool $bindir/mysql"
|
||||
echo "to connect to the mysql database and look at the grant tables:"
|
||||
|
|
@ -408,9 +413,6 @@ else
|
|||
echo " shell> $bindir/mysql -u root mysql"
|
||||
echo " mysql> show tables"
|
||||
echo
|
||||
echo "Try 'mysqld --help' if you have problems with paths. Using"
|
||||
echo "--general-log gives you a log in $ldata that may be helpful."
|
||||
echo
|
||||
echo "The latest information about mysql_install_db is available at"
|
||||
echo "http://kb.askmonty.org/v/installing-system-tables-mysql_install_db."
|
||||
echo "MariaDB is hosted on launchpad; You can find the latest source and"
|
||||
|
|
|
|||
|
|
@ -81,7 +81,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
|
|||
event_data_objects.h event_scheduler.h \
|
||||
sql_partition.h partition_info.h partition_element.h \
|
||||
contributors.h sql_servers.h \
|
||||
multi_range_read.h \
|
||||
multi_range_read.h sql_handler.h \
|
||||
sql_join_cache.h \
|
||||
create_options.h \
|
||||
sql_expression_cache.h
|
||||
|
|
|
|||
308
sql/lock.cc
308
sql/lock.cc
|
|
@ -84,41 +84,11 @@
|
|||
|
||||
extern HASH open_cache;
|
||||
|
||||
/* flags for get_lock_data */
|
||||
#define GET_LOCK_UNLOCK 1
|
||||
#define GET_LOCK_STORE_LOCKS 2
|
||||
|
||||
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table,uint count,
|
||||
uint flags, TABLE **write_locked);
|
||||
static void reset_lock_data(MYSQL_LOCK *sql_lock);
|
||||
static void reset_lock_data(MYSQL_LOCK *sql_lock, bool unlock);
|
||||
static int lock_external(THD *thd, TABLE **table,uint count);
|
||||
static int unlock_external(THD *thd, TABLE **table,uint count);
|
||||
static void print_lock_error(int error, const char *);
|
||||
|
||||
/*
|
||||
Lock tables.
|
||||
|
||||
SYNOPSIS
|
||||
mysql_lock_tables()
|
||||
thd The current thread.
|
||||
tables An array of pointers to the tables to lock.
|
||||
count The number of tables to lock.
|
||||
flags Options:
|
||||
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
|
||||
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
|
||||
MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables.
|
||||
MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
|
||||
or dropped tables by itself,
|
||||
mysql_lock_tables() should
|
||||
notify upper level and rely
|
||||
on caller doing this.
|
||||
need_reopen Out parameter, TRUE if some tables were altered
|
||||
or deleted and should be reopened by caller.
|
||||
|
||||
RETURN
|
||||
A lock structure pointer on success.
|
||||
NULL on error or if some tables should be reopen.
|
||||
*/
|
||||
|
||||
/* Map the return value of thr_lock to an error from errmsg.txt */
|
||||
static int thr_lock_errno_to_mysql[]=
|
||||
|
|
@ -132,6 +102,7 @@ static int thr_lock_errno_to_mysql[]=
|
|||
@param flags Lock flags
|
||||
@return 0 if all the check passed, non zero if a check failed.
|
||||
*/
|
||||
|
||||
int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
|
||||
{
|
||||
bool log_table_write_query;
|
||||
|
|
@ -194,81 +165,118 @@ int mysql_lock_tables_check(THD *thd, TABLE **tables, uint count, uint flags)
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Lock tables.
|
||||
|
||||
SYNOPSIS
|
||||
mysql_lock_tables()
|
||||
thd The current thread.
|
||||
tables An array of pointers to the tables to lock.
|
||||
count The number of tables to lock.
|
||||
flags Options:
|
||||
MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK Ignore a global read lock
|
||||
MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY Ignore SET GLOBAL READ_ONLY
|
||||
MYSQL_LOCK_IGNORE_FLUSH Ignore a flush tables.
|
||||
MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN Instead of reopening altered
|
||||
or dropped tables by itself,
|
||||
mysql_lock_tables() should
|
||||
notify upper level and rely
|
||||
on caller doing this.
|
||||
need_reopen Out parameter, TRUE if some tables were altered
|
||||
or deleted and should be reopened by caller.
|
||||
|
||||
RETURN
|
||||
A lock structure pointer on success.
|
||||
NULL on error or if some tables should be reopen.
|
||||
*/
|
||||
|
||||
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
|
||||
uint flags, bool *need_reopen)
|
||||
{
|
||||
MYSQL_LOCK *sql_lock;
|
||||
TABLE *write_lock_used;
|
||||
int rc;
|
||||
|
||||
DBUG_ENTER("mysql_lock_tables");
|
||||
MYSQL_LOCK *sql_lock;
|
||||
DBUG_ENTER("mysql_lock_tables(tables)");
|
||||
|
||||
*need_reopen= FALSE;
|
||||
|
||||
if (mysql_lock_tables_check(thd, tables, count, flags))
|
||||
DBUG_RETURN (NULL);
|
||||
DBUG_RETURN(NULL);
|
||||
|
||||
if (!(sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
|
||||
&write_lock_used)) ||
|
||||
! sql_lock->table_count)
|
||||
DBUG_RETURN(sql_lock);
|
||||
|
||||
if (mysql_lock_tables(thd, sql_lock, write_lock_used != 0, flags,
|
||||
need_reopen))
|
||||
{
|
||||
/* Clear the lock type of all lock data to avoid reusage. */
|
||||
reset_lock_data(sql_lock, 1);
|
||||
my_free(sql_lock, MYF(0));
|
||||
sql_lock= 0;
|
||||
}
|
||||
DBUG_RETURN(sql_lock);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Lock a table based on a MYSQL_LOCK structure.
|
||||
|
||||
mysql_lock_tables()
|
||||
|
||||
@param thd The current thread.
|
||||
@param sql_lock Tables that should be locked
|
||||
@param write_lock_used 1 if any of the tables are write locked
|
||||
@param flags See mysql_lock_tables()
|
||||
@param need_reopen Out parameter, TRUE if some tables were altered
|
||||
or deleted and should be reopened by caller.
|
||||
|
||||
@return 0 ok
|
||||
@return 1 error
|
||||
*/
|
||||
|
||||
bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock,
|
||||
bool write_lock_used,
|
||||
uint flags, bool *need_reopen)
|
||||
{
|
||||
int rc;
|
||||
bool error= 1;
|
||||
DBUG_ENTER("mysql_lock_tables(sql_lock)");
|
||||
|
||||
*need_reopen= FALSE;
|
||||
for (;;)
|
||||
{
|
||||
if (! (sql_lock= get_lock_data(thd, tables, count, GET_LOCK_STORE_LOCKS,
|
||||
&write_lock_used)) ||
|
||||
! sql_lock->table_count)
|
||||
break;
|
||||
|
||||
if (global_read_lock && write_lock_used &&
|
||||
! (flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))
|
||||
if (write_lock_used && !(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK))
|
||||
{
|
||||
/*
|
||||
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
|
||||
Wait until the lock is gone
|
||||
*/
|
||||
if (wait_if_global_read_lock(thd, 1, 1))
|
||||
if (global_read_lock)
|
||||
{
|
||||
/* Clear the lock type of all lock data to avoid reusage. */
|
||||
reset_lock_data(sql_lock);
|
||||
my_free((uchar*) sql_lock,MYF(0));
|
||||
sql_lock=0;
|
||||
break;
|
||||
/*
|
||||
Someone has issued LOCK ALL TABLES FOR READ and we want a write lock
|
||||
Wait until the lock is gone
|
||||
*/
|
||||
if (wait_if_global_read_lock(thd, 1, 1))
|
||||
break;
|
||||
if (thd->version != refresh_version)
|
||||
goto retry;
|
||||
}
|
||||
if (thd->version != refresh_version)
|
||||
{
|
||||
/* Clear the lock type of all lock data to avoid reusage. */
|
||||
reset_lock_data(sql_lock);
|
||||
my_free((uchar*) sql_lock,MYF(0));
|
||||
goto retry;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(flags & MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY) &&
|
||||
write_lock_used &&
|
||||
opt_readonly &&
|
||||
!(thd->security_ctx->master_access & SUPER_ACL) &&
|
||||
!thd->slave_thread)
|
||||
{
|
||||
/*
|
||||
Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
|
||||
We do not wait for READ_ONLY=0, and fail.
|
||||
*/
|
||||
reset_lock_data(sql_lock);
|
||||
my_free((uchar*) sql_lock, MYF(0));
|
||||
sql_lock=0;
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
|
||||
break;
|
||||
if (opt_readonly &&
|
||||
!(thd->security_ctx->master_access & SUPER_ACL) &&
|
||||
!thd->slave_thread)
|
||||
{
|
||||
/*
|
||||
Someone has issued SET GLOBAL READ_ONLY=1 and we want a write lock.
|
||||
We do not wait for READ_ONLY=0, and fail.
|
||||
*/
|
||||
my_error(ER_OPTION_PREVENTS_STATEMENT, MYF(0), "--read-only");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
thd_proc_info(thd, "System lock");
|
||||
DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
|
||||
if (lock_external(thd, sql_lock->table, sql_lock->table_count))
|
||||
{
|
||||
/* Clear the lock type of all lock data to avoid reusage. */
|
||||
reset_lock_data(sql_lock);
|
||||
my_free((uchar*) sql_lock,MYF(0));
|
||||
sql_lock=0;
|
||||
break;
|
||||
}
|
||||
thd_proc_info(thd, "Table lock");
|
||||
DBUG_PRINT("info", ("thd->proc_info %s", thd->proc_info));
|
||||
thd->locked=1;
|
||||
/* Copy the lock data array. thr_multi_lock() reorders its contens. */
|
||||
memcpy(sql_lock->locks + sql_lock->lock_count, sql_lock->locks,
|
||||
sql_lock->lock_count * sizeof(*sql_lock->locks));
|
||||
|
|
@ -277,70 +285,66 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **tables, uint count,
|
|||
sql_lock->lock_count,
|
||||
sql_lock->lock_count,
|
||||
thd->lock_id)];
|
||||
if (rc > 1) /* a timeout or a deadlock */
|
||||
if (rc) /* Locking failed */
|
||||
{
|
||||
VOID(unlock_external(thd, sql_lock->table, sql_lock->table_count));
|
||||
my_error(rc, MYF(0));
|
||||
my_free((uchar*) sql_lock,MYF(0));
|
||||
sql_lock= 0;
|
||||
break;
|
||||
if (rc > 1)
|
||||
{
|
||||
/* a timeout or a deadlock */
|
||||
my_error(rc, MYF(0));
|
||||
break;
|
||||
}
|
||||
/* We where aborted and should try again from upper level*/
|
||||
thd->some_tables_deleted= 1;
|
||||
}
|
||||
else if (rc == 1) /* aborted */
|
||||
else
|
||||
{
|
||||
/*
|
||||
reset_lock_data is required here. If thr_multi_lock fails it
|
||||
resets lock type for tables, which were locked before (and
|
||||
including) one that caused error. Lock type for other tables
|
||||
preserved.
|
||||
Lock worked. Now check that nothing happend while we where waiting
|
||||
to get the lock that would require us to free it.
|
||||
*/
|
||||
reset_lock_data(sql_lock);
|
||||
thd->some_tables_deleted=1; // Try again
|
||||
sql_lock->lock_count= 0; // Locks are already freed
|
||||
}
|
||||
else if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
|
||||
{
|
||||
/*
|
||||
Thread was killed or lock aborted. Let upper level close all
|
||||
used tables and retry or give error.
|
||||
*/
|
||||
thd->locked=0;
|
||||
break;
|
||||
}
|
||||
else if (!thd->open_tables)
|
||||
{
|
||||
// Only using temporary tables, no need to unlock
|
||||
thd->some_tables_deleted=0;
|
||||
thd->locked=0;
|
||||
break;
|
||||
}
|
||||
thd_proc_info(thd, 0);
|
||||
error= 0;
|
||||
if (!thd->some_tables_deleted || (flags & MYSQL_LOCK_IGNORE_FLUSH))
|
||||
{
|
||||
/*
|
||||
Table was not signaled for deletion or we don't care if it was.
|
||||
Return with table as locked.
|
||||
*/
|
||||
break;
|
||||
}
|
||||
else if (!thd->open_tables && !(flags & MYSQL_LOCK_NOT_TEMPORARY))
|
||||
{
|
||||
/*
|
||||
Only using temporary tables, no need to unlock.
|
||||
We need the flag as open_tables is not enough to distingush if
|
||||
we are only using temporary tables for tables used trough
|
||||
the HANDLER interface.
|
||||
|
||||
We reset some_tables_deleted as it doesn't make sense to have this
|
||||
one when we are only using temporary tables.
|
||||
*/
|
||||
thd->some_tables_deleted=0;
|
||||
break;
|
||||
}
|
||||
/* some table was altered or deleted. reopen tables marked deleted */
|
||||
error= 1;
|
||||
mysql_unlock_tables(thd, sql_lock, 0);
|
||||
}
|
||||
|
||||
/* some table was altered or deleted. reopen tables marked deleted */
|
||||
mysql_unlock_tables(thd,sql_lock);
|
||||
thd->locked=0;
|
||||
retry:
|
||||
sql_lock=0;
|
||||
if (flags & MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN)
|
||||
{
|
||||
*need_reopen= TRUE;
|
||||
break;
|
||||
}
|
||||
if (wait_for_tables(thd))
|
||||
break; // Couldn't open tables
|
||||
}
|
||||
thd_proc_info(thd, 0);
|
||||
if (thd->killed)
|
||||
{
|
||||
thd->send_kill_message();
|
||||
if (sql_lock)
|
||||
{
|
||||
mysql_unlock_tables(thd,sql_lock);
|
||||
sql_lock=0;
|
||||
}
|
||||
break; // Couldn't open tables
|
||||
reset_lock_data(sql_lock, 0); // Set org locks and retry
|
||||
}
|
||||
|
||||
thd_proc_info(thd, 0);
|
||||
thd->set_time_after_lock();
|
||||
DBUG_RETURN (sql_lock);
|
||||
DBUG_RETURN(error);
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -380,15 +384,15 @@ static int lock_external(THD *thd, TABLE **tables, uint count)
|
|||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock)
|
||||
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock)
|
||||
{
|
||||
DBUG_ENTER("mysql_unlock_tables");
|
||||
if (sql_lock->table_count)
|
||||
VOID(unlock_external(thd,sql_lock->table,sql_lock->table_count));
|
||||
if (sql_lock->lock_count)
|
||||
thr_multi_unlock(sql_lock->locks,sql_lock->lock_count, 0);
|
||||
my_free((uchar*) sql_lock,MYF(0));
|
||||
if (free_lock)
|
||||
my_free((uchar*) sql_lock,MYF(0));
|
||||
DBUG_VOID_RETURN;
|
||||
}
|
||||
|
||||
|
|
@ -847,12 +851,12 @@ static int unlock_external(THD *thd, TABLE **table,uint count)
|
|||
@param write_lock_used Store pointer to last table with WRITE_ALLOW_WRITE
|
||||
*/
|
||||
|
||||
static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
||||
uint flags, TABLE **write_lock_used)
|
||||
MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
||||
uint flags, TABLE **write_lock_used)
|
||||
{
|
||||
uint i,tables,lock_count;
|
||||
MYSQL_LOCK *sql_lock;
|
||||
THR_LOCK_DATA **locks, **locks_buf, **locks_start;
|
||||
THR_LOCK_DATA **locks, **locks_buf;
|
||||
TABLE **to, **table_buf;
|
||||
DBUG_ENTER("get_lock_data");
|
||||
|
||||
|
|
@ -891,7 +895,7 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
|||
{
|
||||
TABLE *table;
|
||||
enum thr_lock_type lock_type;
|
||||
|
||||
THR_LOCK_DATA **locks_start;
|
||||
if ((table=table_ptr[i])->s->tmp_table == NON_TRANSACTIONAL_TMP_TABLE)
|
||||
continue;
|
||||
lock_type= table->reginfo.lock_type;
|
||||
|
|
@ -904,12 +908,11 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
|||
my_error(ER_OPEN_AS_READONLY,MYF(0),table->alias.c_ptr());
|
||||
/* Clear the lock type of the lock data that are stored already. */
|
||||
sql_lock->lock_count= (uint) (locks - sql_lock->locks);
|
||||
reset_lock_data(sql_lock);
|
||||
reset_lock_data(sql_lock, 1);
|
||||
my_free((uchar*) sql_lock,MYF(0));
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
}
|
||||
THR_LOCK_DATA **org_locks = locks;
|
||||
locks_start= locks;
|
||||
locks= table->file->store_lock(thd, locks,
|
||||
(flags & GET_LOCK_UNLOCK) ? TL_IGNORE :
|
||||
|
|
@ -922,8 +925,13 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
|||
}
|
||||
*to++= table;
|
||||
if (locks)
|
||||
for ( ; org_locks != locks ; org_locks++)
|
||||
(*org_locks)->debug_print_param= (void *) table;
|
||||
{
|
||||
for ( ; locks_start != locks ; locks_start++)
|
||||
{
|
||||
(*locks_start)->debug_print_param= (void *) table;
|
||||
(*locks_start)->org_type= (*locks_start)->type;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
We do not use 'tables', because there are cases where store_lock()
|
||||
|
|
@ -964,10 +972,13 @@ static MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
|||
Clear the lock type of all lock data. This ensures that the next
|
||||
lock request will set its lock type properly.
|
||||
|
||||
@param sql_lock The MySQL lock.
|
||||
@param sql_lock The MySQL lock.
|
||||
@param unlock If set, then set lock type to TL_UNLOCK,
|
||||
otherwise set to original lock type from
|
||||
get_store_lock().
|
||||
*/
|
||||
|
||||
static void reset_lock_data(MYSQL_LOCK *sql_lock)
|
||||
static void reset_lock_data(MYSQL_LOCK *sql_lock, bool unlock)
|
||||
{
|
||||
THR_LOCK_DATA **ldata;
|
||||
THR_LOCK_DATA **ldata_end;
|
||||
|
|
@ -975,10 +986,7 @@ static void reset_lock_data(MYSQL_LOCK *sql_lock)
|
|||
for (ldata= sql_lock->locks, ldata_end= ldata + sql_lock->lock_count;
|
||||
ldata < ldata_end;
|
||||
ldata++)
|
||||
{
|
||||
/* Reset lock type. */
|
||||
(*ldata)->type= TL_UNLOCK;
|
||||
}
|
||||
(*ldata)->type= unlock ? TL_UNLOCK : (*ldata)->org_type;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -1487,15 +1487,6 @@ void mysqld_stmt_reset(THD *thd, char *packet);
|
|||
void mysql_stmt_get_longdata(THD *thd, char *pos, ulong packet_length);
|
||||
void reinit_stmt_before_use(THD *thd, LEX *lex);
|
||||
|
||||
/* sql_handler.cc */
|
||||
bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen);
|
||||
bool mysql_ha_close(THD *thd, TABLE_LIST *tables);
|
||||
bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
|
||||
List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
|
||||
void mysql_ha_flush(THD *thd);
|
||||
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked);
|
||||
void mysql_ha_cleanup(THD *thd);
|
||||
|
||||
/* sql_base.cc */
|
||||
#define TMP_TABLE_KEY_EXTRA 8
|
||||
void set_item_name(Item *item,char *pos,uint length);
|
||||
|
|
@ -2194,6 +2185,10 @@ extern struct st_VioSSLFd * ssl_acceptor_fd;
|
|||
|
||||
MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
|
||||
uint flags, bool *need_reopen);
|
||||
bool mysql_lock_tables(THD *thd, MYSQL_LOCK *sql_lock,
|
||||
bool write_lock_used,
|
||||
uint flags, bool *need_reopen);
|
||||
|
||||
/* mysql_lock_tables() and open_table() flags bits */
|
||||
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_LOCK 0x0001
|
||||
#define MYSQL_LOCK_IGNORE_FLUSH 0x0002
|
||||
|
|
@ -2201,8 +2196,12 @@ MYSQL_LOCK *mysql_lock_tables(THD *thd, TABLE **table, uint count,
|
|||
#define MYSQL_OPEN_TEMPORARY_ONLY 0x0008
|
||||
#define MYSQL_LOCK_IGNORE_GLOBAL_READ_ONLY 0x0010
|
||||
#define MYSQL_LOCK_PERF_SCHEMA 0x0020
|
||||
#define MYSQL_LOCK_NOT_TEMPORARY 0x0040
|
||||
/* flags for get_lock_data */
|
||||
#define GET_LOCK_UNLOCK 1
|
||||
#define GET_LOCK_STORE_LOCKS 2
|
||||
|
||||
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock);
|
||||
void mysql_unlock_tables(THD *thd, MYSQL_LOCK *sql_lock, bool free_lock= 1);
|
||||
void mysql_unlock_read_tables(THD *thd, MYSQL_LOCK *sql_lock);
|
||||
void mysql_unlock_some_tables(THD *thd, TABLE **table,uint count);
|
||||
void mysql_lock_remove(THD *thd, MYSQL_LOCK *locked,TABLE *table,
|
||||
|
|
@ -2223,6 +2222,8 @@ bool make_global_read_lock_block_commit(THD *thd);
|
|||
bool set_protect_against_global_read_lock(void);
|
||||
void unset_protect_against_global_read_lock(void);
|
||||
void broadcast_refresh(void);
|
||||
MYSQL_LOCK *get_lock_data(THD *thd, TABLE **table_ptr, uint count,
|
||||
uint flags, TABLE **write_lock_used);
|
||||
|
||||
/* Lock based on name */
|
||||
int lock_and_wait_for_table_name(THD *thd, TABLE_LIST *table_list);
|
||||
|
|
|
|||
|
|
@ -457,7 +457,7 @@ static bool volatile ready_to_exit;
|
|||
static my_bool opt_debugging= 0, opt_external_locking= 0, opt_console= 0;
|
||||
static my_bool opt_short_log_format= 0;
|
||||
static my_bool opt_ignore_wrong_options= 0, opt_expect_abort= 0;
|
||||
static my_bool opt_sync= 0;
|
||||
static my_bool opt_sync= 0, opt_thread_alarm;
|
||||
static uint kill_cached_threads, wake_thread;
|
||||
ulong thread_created;
|
||||
uint thread_handling;
|
||||
|
|
@ -6003,7 +6003,7 @@ enum options_mysqld
|
|||
OPT_RANGE_ALLOC_BLOCK_SIZE, OPT_ALLOW_SUSPICIOUS_UDFS,
|
||||
OPT_QUERY_ALLOC_BLOCK_SIZE, OPT_QUERY_PREALLOC_SIZE,
|
||||
OPT_TRANS_ALLOC_BLOCK_SIZE, OPT_TRANS_PREALLOC_SIZE,
|
||||
OPT_SYNC_FRM, OPT_SYNC_BINLOG, OPT_SYNC,
|
||||
OPT_SYNC_FRM, OPT_SYNC_BINLOG, OPT_SYNC, OPT_THREAD_ALARM,
|
||||
OPT_SYNC_REPLICATION,
|
||||
OPT_SYNC_REPLICATION_SLAVE_ID,
|
||||
OPT_SYNC_REPLICATION_TIMEOUT,
|
||||
|
|
@ -6328,7 +6328,7 @@ struct my_option my_long_options[] =
|
|||
"Disable initialization of builtin InnoDB plugin.",
|
||||
0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
|
||||
{"init-connect", OPT_INIT_CONNECT,
|
||||
"Command(s) that are executed for each new connection.",
|
||||
"Command(s) that are executed for each new connection (but not for SUPER users).",
|
||||
&opt_init_connect, &opt_init_connect, 0, GET_STR_ALLOC,
|
||||
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
|
||||
#ifndef DISABLE_GRANT_OPTIONS
|
||||
|
|
@ -7579,6 +7579,10 @@ thread is in the relay logs.",
|
|||
"error. Used only if the connection has active cursors.",
|
||||
&table_lock_wait_timeout, &table_lock_wait_timeout,
|
||||
0, GET_ULONG, REQUIRED_ARG, 50, 1, 1024 * 1024 * 1024, 0, 1, 0},
|
||||
{"thread-alarm", OPT_THREAD_ALARM,
|
||||
"Enable/disable system thread alarm calls. Should only be turned off when running tests or debugging!!",
|
||||
&opt_thread_alarm, &opt_thread_alarm, 0, GET_BOOL, NO_ARG, 1, 0, 0, 0, 0,
|
||||
0},
|
||||
{"thread_cache_size", OPT_THREAD_CACHE_SIZE,
|
||||
"How many threads we should keep in a cache for reuse.",
|
||||
&thread_cache_size, &thread_cache_size, 0, GET_ULONG,
|
||||
|
|
@ -9358,6 +9362,7 @@ static int get_options(int *argc,char **argv)
|
|||
*/
|
||||
my_disable_locking= myisam_single_user= test(opt_external_locking == 0);
|
||||
my_disable_sync= opt_sync == 0;
|
||||
my_disable_thr_alarm= opt_thread_alarm == 0;
|
||||
my_default_record_cache_size=global_system_variables.read_buff_size;
|
||||
myisam_max_temp_length=
|
||||
(my_off_t) global_system_variables.myisam_max_sort_file_size;
|
||||
|
|
|
|||
|
|
@ -697,7 +697,8 @@ net_real_write(NET *net,const uchar *packet, size_t len)
|
|||
{
|
||||
my_bool old_mode;
|
||||
thr_end_alarm(&alarmed);
|
||||
vio_blocking(net->vio, net_blocking, &old_mode);
|
||||
if (!net_blocking)
|
||||
vio_blocking(net->vio, net_blocking, &old_mode);
|
||||
}
|
||||
net->reading_or_writing=0;
|
||||
DBUG_RETURN(((int) (pos != end)));
|
||||
|
|
@ -988,7 +989,8 @@ end:
|
|||
{
|
||||
my_bool old_mode;
|
||||
thr_end_alarm(&alarmed);
|
||||
vio_blocking(net->vio, net_blocking, &old_mode);
|
||||
if (!net_blocking)
|
||||
vio_blocking(net->vio, net_blocking, &old_mode);
|
||||
}
|
||||
net->reading_or_writing=0;
|
||||
#ifdef DEBUG_DATA_PACKETS
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "sp_head.h"
|
||||
#include "sp.h"
|
||||
#include "sql_trigger.h"
|
||||
#include "sql_handler.h"
|
||||
#include <m_ctype.h>
|
||||
#include <my_dir.h>
|
||||
#include <hash.h>
|
||||
|
|
|
|||
|
|
@ -44,6 +44,7 @@
|
|||
#include "sp_cache.h"
|
||||
#include "sql_select.h" /* declares create_tmp_table() */
|
||||
#include "debug_sync.h"
|
||||
#include "sql_handler.h"
|
||||
|
||||
/*
|
||||
The following is used to initialise Table_ident with a internal
|
||||
|
|
@ -702,7 +703,7 @@ THD::THD()
|
|||
catalog= (char*)"std"; // the only catalog we have for now
|
||||
main_security_ctx.init();
|
||||
security_ctx= &main_security_ctx;
|
||||
locked=some_tables_deleted=no_errors=password= 0;
|
||||
some_tables_deleted=no_errors=password= 0;
|
||||
query_start_used= 0;
|
||||
count_cuted_fields= CHECK_FIELD_IGNORE;
|
||||
killed= NOT_KILLED;
|
||||
|
|
|
|||
|
|
@ -1944,7 +1944,7 @@ public:
|
|||
bool slave_thread, one_shot_set;
|
||||
/* tells if current statement should binlog row-based(1) or stmt-based(0) */
|
||||
bool current_stmt_binlog_row_based;
|
||||
bool locked, some_tables_deleted;
|
||||
bool some_tables_deleted;
|
||||
bool last_cuted_field;
|
||||
bool no_errors, password;
|
||||
bool extra_port; /* If extra connection */
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
#include <mysys_err.h>
|
||||
#include "sp.h"
|
||||
#include "events.h"
|
||||
#include "sql_handler.h"
|
||||
#include <my_dir.h>
|
||||
#include <m_ctype.h>
|
||||
#include "log.h"
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@
|
|||
#include "sql_select.h"
|
||||
#include "sp_head.h"
|
||||
#include "sql_trigger.h"
|
||||
#include "sql_handler.h"
|
||||
|
||||
/**
|
||||
Implement DELETE SQL word.
|
||||
|
|
|
|||
|
|
@ -56,15 +56,41 @@
|
|||
second container. When the table is flushed, the pointer is cleared.
|
||||
*/
|
||||
|
||||
#ifdef USE_PRAGMA_IMPLEMENTATION
|
||||
#pragma implementation // gcc: Class implementation
|
||||
#endif
|
||||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_select.h"
|
||||
#include <assert.h>
|
||||
#include "sql_handler.h"
|
||||
|
||||
#define HANDLER_TABLES_HASH_SIZE 120
|
||||
|
||||
static enum enum_ha_read_modes rkey_to_rnext[]=
|
||||
{ RNEXT_SAME, RNEXT, RPREV, RNEXT, RPREV, RNEXT, RPREV, RPREV };
|
||||
|
||||
/*
|
||||
Set handler to state after create, but keep base information about
|
||||
which table is used
|
||||
*/
|
||||
|
||||
void SQL_HANDLER::reset()
|
||||
{
|
||||
fields.empty();
|
||||
arena.free_items();
|
||||
free_root(&mem_root, MYF(0));
|
||||
my_free(lock, MYF(MY_ALLOW_ZERO_PTR));
|
||||
init();
|
||||
}
|
||||
|
||||
/* Free all allocated data */
|
||||
|
||||
SQL_HANDLER::~SQL_HANDLER()
|
||||
{
|
||||
reset();
|
||||
my_free(base_data, MYF(MY_ALLOW_ZERO_PTR));
|
||||
}
|
||||
|
||||
/*
|
||||
Get hash key and hash key length.
|
||||
|
||||
|
|
@ -84,11 +110,11 @@ static enum enum_ha_read_modes rkey_to_rnext[]=
|
|||
Pointer to the TABLE_LIST struct.
|
||||
*/
|
||||
|
||||
static char *mysql_ha_hash_get_key(TABLE_LIST *tables, size_t *key_len_p,
|
||||
static char *mysql_ha_hash_get_key(SQL_HANDLER *table, size_t *key_len,
|
||||
my_bool first __attribute__((unused)))
|
||||
{
|
||||
*key_len_p= strlen(tables->alias) + 1 ; /* include '\0' in comparisons */
|
||||
return tables->alias;
|
||||
*key_len= table->handler_name.length + 1 ; /* include '\0' in comparisons */
|
||||
return table->handler_name.str;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -106,9 +132,9 @@ static char *mysql_ha_hash_get_key(TABLE_LIST *tables, size_t *key_len_p,
|
|||
Nothing
|
||||
*/
|
||||
|
||||
static void mysql_ha_hash_free(TABLE_LIST *tables)
|
||||
static void mysql_ha_hash_free(SQL_HANDLER *table)
|
||||
{
|
||||
my_free((char*) tables, MYF(0));
|
||||
delete table;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -120,14 +146,21 @@ static void mysql_ha_hash_free(TABLE_LIST *tables)
|
|||
|
||||
@note Though this function takes a list of tables, only the first list entry
|
||||
will be closed.
|
||||
@mote handler_object is not deleted!
|
||||
@note Broadcasts refresh if it closed a table with old version.
|
||||
*/
|
||||
|
||||
static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
|
||||
static void mysql_ha_close_table(SQL_HANDLER *handler,
|
||||
bool is_locked)
|
||||
{
|
||||
THD *thd= handler->thd;
|
||||
TABLE *table= handler->table;
|
||||
TABLE **table_ptr;
|
||||
|
||||
/* check if table was already closed */
|
||||
if (!table)
|
||||
return;
|
||||
|
||||
/*
|
||||
Though we could take the table pointer from hash_tables->table,
|
||||
we must follow the thd->handler_tables chain anyway, as we need the
|
||||
|
|
@ -135,13 +168,13 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
|
|||
for close_thread_table().
|
||||
*/
|
||||
for (table_ptr= &(thd->handler_tables);
|
||||
*table_ptr && (*table_ptr != tables->table);
|
||||
*table_ptr && (*table_ptr != table);
|
||||
table_ptr= &(*table_ptr)->next)
|
||||
;
|
||||
|
||||
if (*table_ptr)
|
||||
{
|
||||
(*table_ptr)->file->ha_index_or_rnd_end();
|
||||
table->file->ha_index_or_rnd_end();
|
||||
if (! is_locked)
|
||||
VOID(pthread_mutex_lock(&LOCK_open));
|
||||
if (close_thread_table(thd, table_ptr))
|
||||
|
|
@ -152,17 +185,15 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
|
|||
if (! is_locked)
|
||||
VOID(pthread_mutex_unlock(&LOCK_open));
|
||||
}
|
||||
else if (tables->table)
|
||||
else
|
||||
{
|
||||
/* Must be a temporary table */
|
||||
TABLE *table= tables->table;
|
||||
table->file->ha_index_or_rnd_end();
|
||||
table->query_id= thd->query_id;
|
||||
table->open_by_handler= 0;
|
||||
}
|
||||
|
||||
/* Mark table as closed, ready for re-open if necessary. */
|
||||
tables->table= NULL;
|
||||
my_free(handler->lock, MYF(MY_ALLOW_ZERO_PTR));
|
||||
handler->init();
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -178,7 +209,7 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
|
|||
Though this function takes a list of tables, only the first list entry
|
||||
will be opened.
|
||||
'reopen' is set when a handler table is to be re-opened. In this case,
|
||||
'tables' is the pointer to the hashed TABLE_LIST object which has been
|
||||
'tables' is the pointer to the hashed SQL_HANDLER object which has been
|
||||
saved on the original open.
|
||||
'reopen' is also used to suppress the sending of an 'ok' message.
|
||||
|
||||
|
|
@ -187,17 +218,17 @@ static void mysql_ha_close_table(THD *thd, TABLE_LIST *tables,
|
|||
TRUE Error
|
||||
*/
|
||||
|
||||
bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
|
||||
bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen)
|
||||
{
|
||||
TABLE_LIST *hash_tables = NULL;
|
||||
char *db, *name, *alias;
|
||||
uint dblen, namelen, aliaslen, counter;
|
||||
SQL_HANDLER *sql_handler= 0;
|
||||
uint counter;
|
||||
int error;
|
||||
TABLE *backup_open_tables;
|
||||
TABLE *table, *backup_open_tables, *write_lock_used;
|
||||
Query_arena backup_arena;
|
||||
DBUG_ENTER("mysql_ha_open");
|
||||
DBUG_PRINT("enter",("'%s'.'%s' as '%s' reopen: %d",
|
||||
tables->db, tables->table_name, tables->alias,
|
||||
(int) reopen));
|
||||
reopen != 0));
|
||||
|
||||
if (tables->schema_table)
|
||||
{
|
||||
|
|
@ -210,7 +241,7 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
|
|||
if (! hash_inited(&thd->handler_tables_hash))
|
||||
{
|
||||
/*
|
||||
HASH entries are of type TABLE_LIST.
|
||||
HASH entries are of type SQL_HANDLER
|
||||
*/
|
||||
if (hash_init(&thd->handler_tables_hash, &my_charset_latin1,
|
||||
HANDLER_TABLES_HASH_SIZE, 0, 0,
|
||||
|
|
@ -288,8 +319,10 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
|
|||
if (error)
|
||||
goto err;
|
||||
|
||||
table= tables->table;
|
||||
|
||||
/* There can be only one table in '*tables'. */
|
||||
if (! (tables->table->file->ha_table_flags() & HA_CAN_SQL_HANDLER))
|
||||
if (! (table->file->ha_table_flags() & HA_CAN_SQL_HANDLER))
|
||||
{
|
||||
my_error(ER_ILLEGAL_HA, MYF(0), tables->alias);
|
||||
goto err;
|
||||
|
|
@ -297,36 +330,69 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
|
|||
|
||||
if (! reopen)
|
||||
{
|
||||
/* copy the TABLE_LIST struct */
|
||||
dblen= strlen(tables->db) + 1;
|
||||
namelen= strlen(tables->table_name) + 1;
|
||||
aliaslen= strlen(tables->alias) + 1;
|
||||
if (!(my_multi_malloc(MYF(MY_WME),
|
||||
&hash_tables, (uint) sizeof(*hash_tables),
|
||||
&db, (uint) dblen,
|
||||
&name, (uint) namelen,
|
||||
&alias, (uint) aliaslen,
|
||||
/* copy data to sql_handler */
|
||||
if (!(sql_handler= new SQL_HANDLER(thd)))
|
||||
goto err;
|
||||
init_alloc_root(&sql_handler->mem_root, 1024, 0);
|
||||
|
||||
sql_handler->table= table;
|
||||
sql_handler->db.length= strlen(tables->db);
|
||||
sql_handler->table_name.length= strlen(tables->table_name);
|
||||
sql_handler->handler_name.length= strlen(tables->alias);
|
||||
|
||||
if (!(my_multi_malloc(MY_WME,
|
||||
&sql_handler->db.str,
|
||||
(uint) sql_handler->db.length + 1,
|
||||
&sql_handler->table_name.str,
|
||||
(uint) sql_handler->table_name.length + 1,
|
||||
&sql_handler->handler_name.str,
|
||||
(uint) sql_handler->handler_name.length + 1,
|
||||
NullS)))
|
||||
goto err;
|
||||
/* structure copy */
|
||||
*hash_tables= *tables;
|
||||
hash_tables->db= db;
|
||||
hash_tables->table_name= name;
|
||||
hash_tables->alias= alias;
|
||||
memcpy(hash_tables->db, tables->db, dblen);
|
||||
memcpy(hash_tables->table_name, tables->table_name, namelen);
|
||||
memcpy(hash_tables->alias, tables->alias, aliaslen);
|
||||
sql_handler->base_data= sql_handler->db.str; // Free this
|
||||
memcpy(sql_handler->db.str, tables->db, sql_handler->db.length +1);
|
||||
memcpy(sql_handler->table_name.str, tables->table_name,
|
||||
sql_handler->table_name.length+1);
|
||||
memcpy(sql_handler->handler_name.str, tables->alias,
|
||||
sql_handler->handler_name.length +1);
|
||||
|
||||
/* add to hash */
|
||||
if (my_hash_insert(&thd->handler_tables_hash, (uchar*) hash_tables))
|
||||
if (my_hash_insert(&thd->handler_tables_hash, (uchar*) sql_handler))
|
||||
goto err;
|
||||
}
|
||||
else
|
||||
{
|
||||
sql_handler= reopen;
|
||||
sql_handler->reset();
|
||||
}
|
||||
sql_handler->table= table;
|
||||
|
||||
if (!(sql_handler->lock= get_lock_data(thd, &sql_handler->table, 1,
|
||||
GET_LOCK_STORE_LOCKS,
|
||||
&write_lock_used)))
|
||||
goto err;
|
||||
|
||||
/* Get a list of all fields for send_fields */
|
||||
thd->set_n_backup_active_arena(&sql_handler->arena, &backup_arena);
|
||||
error= table->fill_item_list(&sql_handler->fields);
|
||||
thd->restore_active_arena(&sql_handler->arena, &backup_arena);
|
||||
|
||||
if (error)
|
||||
{
|
||||
if (reopen)
|
||||
sql_handler= 0;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* Always read all columns */
|
||||
table->read_set= &table->s->all_set;
|
||||
table->vcol_set= &table->s->all_set;
|
||||
|
||||
/*
|
||||
If it's a temp table, don't reset table->query_id as the table is
|
||||
being used by this handler. Otherwise, no meaning at all.
|
||||
*/
|
||||
tables->table->open_by_handler= 1;
|
||||
table->open_by_handler= 1;
|
||||
|
||||
if (! reopen)
|
||||
my_ok(thd);
|
||||
|
|
@ -334,10 +400,13 @@ bool mysql_ha_open(THD *thd, TABLE_LIST *tables, bool reopen)
|
|||
DBUG_RETURN(FALSE);
|
||||
|
||||
err:
|
||||
if (hash_tables)
|
||||
my_free((char*) hash_tables, MYF(0));
|
||||
delete sql_handler;
|
||||
if (tables->table)
|
||||
mysql_ha_close_table(thd, tables, FALSE);
|
||||
{
|
||||
SQL_HANDLER tmp_sql_handler(thd);
|
||||
tmp_sql_handler.table= tables->table;
|
||||
mysql_ha_close_table(&tmp_sql_handler, FALSE);
|
||||
}
|
||||
DBUG_PRINT("exit",("ERROR"));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
|
@ -362,17 +431,17 @@ err:
|
|||
|
||||
bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
TABLE_LIST *hash_tables;
|
||||
SQL_HANDLER *handler;
|
||||
DBUG_ENTER("mysql_ha_close");
|
||||
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
|
||||
tables->db, tables->table_name, tables->alias));
|
||||
|
||||
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
|
||||
(uchar*) tables->alias,
|
||||
strlen(tables->alias) + 1)))
|
||||
if ((handler= (SQL_HANDLER*) hash_search(&thd->handler_tables_hash,
|
||||
(uchar*) tables->alias,
|
||||
strlen(tables->alias) + 1)))
|
||||
{
|
||||
mysql_ha_close_table(thd, hash_tables, FALSE);
|
||||
hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
|
||||
mysql_ha_close_table(handler, FALSE);
|
||||
hash_delete(&thd->handler_tables_hash, (uchar*) handler);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -387,6 +456,161 @@ bool mysql_ha_close(THD *thd, TABLE_LIST *tables)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
Finds an open HANDLER table.
|
||||
|
||||
@params name Name of handler to open
|
||||
|
||||
@return 0 failure
|
||||
@return handler
|
||||
*/
|
||||
|
||||
SQL_HANDLER *mysql_ha_find_handler(THD *thd, const char *name)
|
||||
{
|
||||
SQL_HANDLER *handler;
|
||||
if ((handler= (SQL_HANDLER*) hash_search(&thd->handler_tables_hash,
|
||||
(uchar*) name,
|
||||
strlen(name) + 1)))
|
||||
{
|
||||
DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' table: %p",
|
||||
handler->db.str,
|
||||
handler->table_name.str,
|
||||
handler->handler_name.str, handler->table));
|
||||
if (!handler->table)
|
||||
{
|
||||
/* The handler table has been closed. Re-open it. */
|
||||
TABLE_LIST tmp;
|
||||
tmp.init_one_table(handler->db.str, handler->table_name.str,
|
||||
TL_READ);
|
||||
tmp.alias= handler->handler_name.str;
|
||||
|
||||
if (mysql_ha_open(thd, &tmp, handler))
|
||||
{
|
||||
DBUG_PRINT("exit",("reopen failed"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
my_error(ER_UNKNOWN_TABLE, MYF(0), name, "HANDLER");
|
||||
return 0;
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Check that condition and key name are ok
|
||||
|
||||
@param handler
|
||||
@param mode Read mode (RFIRST, RNEXT etc...)
|
||||
@param keyname Key to use.
|
||||
@param key_expr List of key column values
|
||||
@param cond Where clause
|
||||
@param in_prepare If we are in prepare phase (we can't evalute items yet)
|
||||
|
||||
@return 0 ok
|
||||
@return 1 error
|
||||
|
||||
In ok, then values of used key and mode is stored in sql_handler
|
||||
*/
|
||||
|
||||
static bool
|
||||
mysql_ha_fix_cond_and_key(SQL_HANDLER *handler,
|
||||
enum enum_ha_read_modes mode, char *keyname,
|
||||
List<Item> *key_expr,
|
||||
Item *cond, bool in_prepare)
|
||||
{
|
||||
THD *thd= handler->thd;
|
||||
TABLE *table= handler->table;
|
||||
if (cond)
|
||||
{
|
||||
/* This can only be true for temp tables */
|
||||
if (table->query_id != thd->query_id)
|
||||
cond->cleanup(); // File was reopened
|
||||
if ((!cond->fixed &&
|
||||
cond->fix_fields(thd, &cond)) || cond->check_cols(1))
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (keyname)
|
||||
{
|
||||
/* Check if same as last keyname. If not, do a full lookup */
|
||||
if (handler->keyno < 0 ||
|
||||
my_strcasecmp(&my_charset_latin1,
|
||||
keyname,
|
||||
table->s->key_info[handler->keyno].name))
|
||||
{
|
||||
if ((handler->keyno= find_type(keyname, &table->s->keynames, 1+2)-1)<0)
|
||||
{
|
||||
my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), keyname,
|
||||
handler->handler_name);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check key parts */
|
||||
if (mode == RKEY)
|
||||
{
|
||||
TABLE *table= handler->table;
|
||||
KEY *keyinfo= table->key_info + handler->keyno;
|
||||
KEY_PART_INFO *key_part= keyinfo->key_part;
|
||||
List_iterator<Item> it_ke(*key_expr);
|
||||
Item *item;
|
||||
key_part_map keypart_map;
|
||||
uint key_len;
|
||||
|
||||
if (key_expr->elements > keyinfo->key_parts)
|
||||
{
|
||||
my_error(ER_TOO_MANY_KEY_PARTS, MYF(0), keyinfo->key_parts);
|
||||
return 1;
|
||||
}
|
||||
for (keypart_map= key_len=0 ; (item=it_ke++) ; key_part++)
|
||||
{
|
||||
my_bitmap_map *old_map;
|
||||
/* note that 'item' can be changed by fix_fields() call */
|
||||
if ((!item->fixed &&
|
||||
item->fix_fields(thd, it_ke.ref())) ||
|
||||
(item= *it_ke.ref())->check_cols(1))
|
||||
return 1;
|
||||
if (item->used_tables() & ~(RAND_TABLE_BIT | PARAM_TABLE_BIT))
|
||||
{
|
||||
my_error(ER_WRONG_ARGUMENTS,MYF(0),"HANDLER ... READ");
|
||||
return 1;
|
||||
}
|
||||
if (!in_prepare)
|
||||
{
|
||||
old_map= dbug_tmp_use_all_columns(table, table->write_set);
|
||||
(void) item->save_in_field(key_part->field, 1);
|
||||
dbug_tmp_restore_column_map(table->write_set, old_map);
|
||||
}
|
||||
key_len+= key_part->store_length;
|
||||
keypart_map= (keypart_map << 1) | 1;
|
||||
}
|
||||
handler->keypart_map= keypart_map;
|
||||
handler->key_len= key_len;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*
|
||||
Check if the same index involved.
|
||||
We need to always do this check because we may not have yet
|
||||
called the handler since the last keyno change.
|
||||
*/
|
||||
if ((uint) handler->keyno != table->file->get_index())
|
||||
{
|
||||
if (mode == RNEXT)
|
||||
mode= RFIRST;
|
||||
else if (mode == RPREV)
|
||||
mode= RLAST;
|
||||
}
|
||||
}
|
||||
}
|
||||
handler->mode= mode; // Store adjusted mode
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
Read from a HANDLER table.
|
||||
|
||||
|
|
@ -413,147 +637,77 @@ bool mysql_ha_read(THD *thd, TABLE_LIST *tables,
|
|||
enum ha_rkey_function ha_rkey_mode, Item *cond,
|
||||
ha_rows select_limit_cnt, ha_rows offset_limit_cnt)
|
||||
{
|
||||
TABLE_LIST *hash_tables;
|
||||
TABLE *table, *backup_open_tables;
|
||||
MYSQL_LOCK *lock;
|
||||
SQL_HANDLER *handler;
|
||||
TABLE *table;
|
||||
List<Item> list;
|
||||
Protocol *protocol= thd->protocol;
|
||||
char buff[MAX_FIELD_WIDTH];
|
||||
String buffer(buff, sizeof(buff), system_charset_info);
|
||||
int error, keyno= -1;
|
||||
int error, keyno;
|
||||
uint num_rows;
|
||||
uchar *UNINIT_VAR(key);
|
||||
uint UNINIT_VAR(key_len);
|
||||
bool need_reopen;
|
||||
List_iterator<Item> it;
|
||||
DBUG_ENTER("mysql_ha_read");
|
||||
DBUG_PRINT("enter",("'%s'.'%s' as '%s'",
|
||||
tables->db, tables->table_name, tables->alias));
|
||||
|
||||
thd->lex->select_lex.context.resolve_in_table_list_only(tables);
|
||||
list.push_front(new Item_field(&thd->lex->select_lex.context,
|
||||
NULL, NULL, "*"));
|
||||
List_iterator<Item> it(list);
|
||||
it++;
|
||||
|
||||
retry:
|
||||
if ((hash_tables= (TABLE_LIST*) hash_search(&thd->handler_tables_hash,
|
||||
(uchar*) tables->alias,
|
||||
strlen(tables->alias) + 1)))
|
||||
if (!(handler= mysql_ha_find_handler(thd, tables->alias)))
|
||||
goto err0;
|
||||
|
||||
table= handler->table;
|
||||
tables->table= table; // This is used by fix_fields
|
||||
|
||||
/* save open_tables state */
|
||||
if (handler->lock->lock_count > 0)
|
||||
{
|
||||
table= hash_tables->table;
|
||||
DBUG_PRINT("info-in-hash",("'%s'.'%s' as '%s' table: 0x%lx",
|
||||
hash_tables->db, hash_tables->table_name,
|
||||
hash_tables->alias, (long) table));
|
||||
if (!table)
|
||||
bool lock_error;
|
||||
|
||||
handler->lock->locks[0]->type= handler->lock->locks[0]->org_type;
|
||||
lock_error= mysql_lock_tables(thd, handler->lock, 0,
|
||||
(MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN |
|
||||
(handler->table->s->tmp_table ==
|
||||
NO_TMP_TABLE ?
|
||||
MYSQL_LOCK_NOT_TEMPORARY : 0)),
|
||||
&need_reopen);
|
||||
if (need_reopen)
|
||||
{
|
||||
/*
|
||||
The handler table has been closed. Re-open it.
|
||||
*/
|
||||
if (mysql_ha_open(thd, hash_tables, 1))
|
||||
mysql_ha_close_table(handler, FALSE);
|
||||
if (thd->stmt_arena->is_stmt_execute())
|
||||
{
|
||||
DBUG_PRINT("exit",("reopen failed"));
|
||||
/*
|
||||
As we have already sent field list and types to the client, we can't
|
||||
handle any changes in the table format for prepared statements.
|
||||
Better to force a reprepare.
|
||||
*/
|
||||
my_error(ER_NEED_REPREPARE, MYF(0));
|
||||
goto err0;
|
||||
}
|
||||
|
||||
table= hash_tables->table;
|
||||
DBUG_PRINT("info",("re-opened '%s'.'%s' as '%s' tab %p",
|
||||
hash_tables->db, hash_tables->table_name,
|
||||
hash_tables->alias, table));
|
||||
/*
|
||||
The lock might have been aborted, we need to manually reset
|
||||
thd->some_tables_deleted because handler's tables are closed
|
||||
in a non-standard way. Otherwise we might loop indefinitely.
|
||||
*/
|
||||
thd->some_tables_deleted= 0;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
#if MYSQL_VERSION_ID < 40100
|
||||
if (*tables->db && strcmp(table->table_cache_key, tables->db))
|
||||
{
|
||||
DBUG_PRINT("info",("wrong db"));
|
||||
table= NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
table= NULL;
|
||||
|
||||
if (!table)
|
||||
{
|
||||
#if MYSQL_VERSION_ID < 40100
|
||||
char buff[MAX_DBKEY_LENGTH];
|
||||
if (*tables->db)
|
||||
strxnmov(buff, sizeof(buff)-1, tables->db, ".", tables->table_name,
|
||||
NullS);
|
||||
else
|
||||
strncpy(buff, tables->alias, sizeof(buff));
|
||||
my_error(ER_UNKNOWN_TABLE, MYF(0), buff, "HANDLER");
|
||||
#else
|
||||
my_error(ER_UNKNOWN_TABLE, MYF(0), tables->alias, "HANDLER");
|
||||
#endif
|
||||
goto err0;
|
||||
}
|
||||
tables->table=table;
|
||||
|
||||
/* save open_tables state */
|
||||
backup_open_tables= thd->open_tables;
|
||||
/*
|
||||
mysql_lock_tables() needs thd->open_tables to be set correctly to
|
||||
be able to handle aborts properly. When the abort happens, it's
|
||||
safe to not protect thd->handler_tables because it won't close any
|
||||
tables.
|
||||
*/
|
||||
thd->open_tables= thd->handler_tables;
|
||||
|
||||
lock= mysql_lock_tables(thd, &tables->table, 1,
|
||||
MYSQL_LOCK_NOTIFY_IF_NEED_REOPEN, &need_reopen);
|
||||
|
||||
/* restore previous context */
|
||||
thd->open_tables= backup_open_tables;
|
||||
|
||||
if (need_reopen)
|
||||
{
|
||||
mysql_ha_close_table(thd, hash_tables, FALSE);
|
||||
/*
|
||||
The lock might have been aborted, we need to manually reset
|
||||
thd->some_tables_deleted because handler's tables are closed
|
||||
in a non-standard way. Otherwise we might loop indefinitely.
|
||||
*/
|
||||
thd->some_tables_deleted= 0;
|
||||
goto retry;
|
||||
if (lock_error)
|
||||
goto err0; // mysql_lock_tables() printed error message already
|
||||
}
|
||||
|
||||
if (!lock)
|
||||
goto err0; // mysql_lock_tables() printed error message already
|
||||
|
||||
// Always read all columns
|
||||
tables->table->read_set= &tables->table->s->all_set;
|
||||
|
||||
if (cond)
|
||||
{
|
||||
if (table->query_id != thd->query_id)
|
||||
cond->cleanup(); // File was reopened
|
||||
if ((!cond->fixed &&
|
||||
cond->fix_fields(thd, &cond)) || cond->check_cols(1))
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (keyname)
|
||||
{
|
||||
if ((keyno=find_type(keyname, &table->s->keynames, 1+2)-1)<0)
|
||||
{
|
||||
my_error(ER_KEY_DOES_NOT_EXITS, MYF(0), keyname, tables->alias);
|
||||
goto err;
|
||||
}
|
||||
/* Check if the same index involved. */
|
||||
if ((uint) keyno != table->file->get_index())
|
||||
{
|
||||
if (mode == RNEXT)
|
||||
mode= RFIRST;
|
||||
else if (mode == RPREV)
|
||||
mode= RLAST;
|
||||
}
|
||||
}
|
||||
|
||||
if (insert_fields(thd, &thd->lex->select_lex.context,
|
||||
tables->db, tables->alias, &it, 0))
|
||||
if (mysql_ha_fix_cond_and_key(handler, mode, keyname, key_expr, cond, 0))
|
||||
goto err;
|
||||
mode= handler->mode;
|
||||
keyno= handler->keyno;
|
||||
|
||||
protocol->send_fields(&list, Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
|
||||
it.init(handler->fields);
|
||||
protocol->send_fields(&handler->fields,
|
||||
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF);
|
||||
|
||||
/*
|
||||
In ::external_lock InnoDB resets the fields which tell it that
|
||||
|
|
@ -576,9 +730,7 @@ retry:
|
|||
error= table->file->ha_index_next(table->record[0]);
|
||||
}
|
||||
else
|
||||
{
|
||||
error= table->file->ha_rnd_next(table->record[0]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
/* else fall through */
|
||||
|
|
@ -595,7 +747,7 @@ retry:
|
|||
if (!(error= table->file->ha_rnd_init(1)))
|
||||
error= table->file->ha_rnd_next(table->record[0]);
|
||||
}
|
||||
mode=RNEXT;
|
||||
mode= RNEXT;
|
||||
break;
|
||||
case RPREV:
|
||||
DBUG_ASSERT(keyname != 0);
|
||||
|
|
@ -612,7 +764,7 @@ retry:
|
|||
table->file->ha_index_or_rnd_end();
|
||||
table->file->ha_index_init(keyno, 1);
|
||||
error= table->file->ha_index_last(table->record[0]);
|
||||
mode=RPREV;
|
||||
mode= RPREV;
|
||||
break;
|
||||
case RNEXT_SAME:
|
||||
/* Continue scan on "(keypart1,keypart2,...)=(c1, c2, ...) */
|
||||
|
|
@ -622,44 +774,17 @@ retry:
|
|||
case RKEY:
|
||||
{
|
||||
DBUG_ASSERT(keyname != 0);
|
||||
KEY *keyinfo=table->key_info+keyno;
|
||||
KEY_PART_INFO *key_part=keyinfo->key_part;
|
||||
if (key_expr->elements > keyinfo->key_parts)
|
||||
{
|
||||
my_error(ER_TOO_MANY_KEY_PARTS, MYF(0), keyinfo->key_parts);
|
||||
goto err;
|
||||
}
|
||||
List_iterator<Item> it_ke(*key_expr);
|
||||
Item *item;
|
||||
key_part_map keypart_map;
|
||||
for (keypart_map= key_len=0 ; (item=it_ke++) ; key_part++)
|
||||
{
|
||||
my_bitmap_map *old_map;
|
||||
// 'item' can be changed by fix_fields() call
|
||||
if ((!item->fixed &&
|
||||
item->fix_fields(thd, it_ke.ref())) ||
|
||||
(item= *it_ke.ref())->check_cols(1))
|
||||
goto err;
|
||||
if (item->used_tables() & ~RAND_TABLE_BIT)
|
||||
{
|
||||
my_error(ER_WRONG_ARGUMENTS,MYF(0),"HANDLER ... READ");
|
||||
goto err;
|
||||
}
|
||||
old_map= dbug_tmp_use_all_columns(table, table->write_set);
|
||||
(void) item->save_in_field(key_part->field, 1);
|
||||
dbug_tmp_restore_column_map(table->write_set, old_map);
|
||||
key_len+=key_part->store_length;
|
||||
keypart_map= (keypart_map << 1) | 1;
|
||||
}
|
||||
|
||||
if (!(key= (uchar*) thd->calloc(ALIGN_SIZE(key_len))))
|
||||
if (!(key= (uchar*) thd->calloc(ALIGN_SIZE(handler->key_len))))
|
||||
goto err;
|
||||
table->file->ha_index_or_rnd_end();
|
||||
table->file->ha_index_init(keyno, 1);
|
||||
key_copy(key, table->record[0], table->key_info + keyno, key_len);
|
||||
key_copy(key, table->record[0], table->key_info + keyno,
|
||||
handler->key_len);
|
||||
error= table->file->ha_index_read_map(table->record[0],
|
||||
key, keypart_map, ha_rkey_mode);
|
||||
mode=rkey_to_rnext[(int)ha_rkey_mode];
|
||||
key, handler->keypart_map,
|
||||
ha_rkey_mode);
|
||||
mode= rkey_to_rnext[(int)ha_rkey_mode];
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
|
@ -703,19 +828,41 @@ retry:
|
|||
num_rows++;
|
||||
}
|
||||
ok:
|
||||
mysql_unlock_tables(thd,lock);
|
||||
mysql_unlock_tables(thd, handler->lock, 0);
|
||||
my_eof(thd);
|
||||
DBUG_PRINT("exit",("OK"));
|
||||
DBUG_RETURN(FALSE);
|
||||
|
||||
err:
|
||||
mysql_unlock_tables(thd,lock);
|
||||
mysql_unlock_tables(thd, handler->lock, 0);
|
||||
err0:
|
||||
DBUG_PRINT("exit",("ERROR"));
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Prepare for handler read
|
||||
|
||||
For parameters, see mysql_ha_read()
|
||||
*/
|
||||
|
||||
SQL_HANDLER *mysql_ha_read_prepare(THD *thd, TABLE_LIST *tables,
|
||||
enum enum_ha_read_modes mode, char *keyname,
|
||||
List<Item> *key_expr, Item *cond)
|
||||
{
|
||||
SQL_HANDLER *handler;
|
||||
DBUG_ENTER("mysql_ha_read_prepare");
|
||||
if (!(handler= mysql_ha_find_handler(thd, tables->alias)))
|
||||
DBUG_RETURN(0);
|
||||
tables->table= handler->table; // This is used by fix_fields
|
||||
if (mysql_ha_fix_cond_and_key(handler, mode, keyname, key_expr, cond, 1))
|
||||
DBUG_RETURN(0);
|
||||
DBUG_RETURN(handler);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
Scan the handler tables hash for matching tables.
|
||||
|
||||
|
|
@ -727,30 +874,32 @@ err0:
|
|||
table was matched.
|
||||
*/
|
||||
|
||||
static TABLE_LIST *mysql_ha_find(THD *thd, TABLE_LIST *tables)
|
||||
static SQL_HANDLER *mysql_ha_find_match(THD *thd, TABLE_LIST *tables)
|
||||
{
|
||||
TABLE_LIST *hash_tables, *head= NULL, *first= tables;
|
||||
DBUG_ENTER("mysql_ha_find");
|
||||
SQL_HANDLER *hash_tables, *head= NULL;
|
||||
TABLE_LIST *first= tables;
|
||||
DBUG_ENTER("mysql_ha_find_match");
|
||||
|
||||
/* search for all handlers with matching table names */
|
||||
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
|
||||
{
|
||||
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
|
||||
hash_tables= (SQL_HANDLER*) hash_element(&thd->handler_tables_hash, i);
|
||||
|
||||
for (tables= first; tables; tables= tables->next_local)
|
||||
{
|
||||
if ((! *tables->db ||
|
||||
! my_strcasecmp(&my_charset_latin1, hash_tables->db, tables->db)) &&
|
||||
! my_strcasecmp(&my_charset_latin1, hash_tables->table_name,
|
||||
! my_strcasecmp(&my_charset_latin1, hash_tables->db.str,
|
||||
tables->db)) &&
|
||||
! my_strcasecmp(&my_charset_latin1, hash_tables->table_name.str,
|
||||
tables->table_name))
|
||||
{
|
||||
/* Link into hash_tables list */
|
||||
hash_tables->next= head;
|
||||
head= hash_tables;
|
||||
break;
|
||||
}
|
||||
if (tables)
|
||||
{
|
||||
hash_tables->next_local= head;
|
||||
head= hash_tables;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DBUG_RETURN(head);
|
||||
}
|
||||
|
||||
|
|
@ -767,18 +916,18 @@ static TABLE_LIST *mysql_ha_find(THD *thd, TABLE_LIST *tables)
|
|||
|
||||
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked)
|
||||
{
|
||||
TABLE_LIST *hash_tables, *next;
|
||||
SQL_HANDLER *hash_tables, *next;
|
||||
DBUG_ENTER("mysql_ha_rm_tables");
|
||||
|
||||
DBUG_ASSERT(tables);
|
||||
|
||||
hash_tables= mysql_ha_find(thd, tables);
|
||||
hash_tables= mysql_ha_find_match(thd, tables);
|
||||
|
||||
while (hash_tables)
|
||||
{
|
||||
next= hash_tables->next_local;
|
||||
next= hash_tables->next;
|
||||
if (hash_tables->table)
|
||||
mysql_ha_close_table(thd, hash_tables, is_locked);
|
||||
mysql_ha_close_table(hash_tables, is_locked);
|
||||
hash_delete(&thd->handler_tables_hash, (uchar*) hash_tables);
|
||||
hash_tables= next;
|
||||
}
|
||||
|
|
@ -798,16 +947,16 @@ void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked)
|
|||
|
||||
void mysql_ha_flush(THD *thd)
|
||||
{
|
||||
TABLE_LIST *hash_tables;
|
||||
SQL_HANDLER *hash_tables;
|
||||
DBUG_ENTER("mysql_ha_flush");
|
||||
|
||||
safe_mutex_assert_owner(&LOCK_open);
|
||||
|
||||
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
|
||||
{
|
||||
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
|
||||
hash_tables= (SQL_HANDLER*) hash_element(&thd->handler_tables_hash, i);
|
||||
if (hash_tables->table && hash_tables->table->needs_reopen_or_name_lock())
|
||||
mysql_ha_close_table(thd, hash_tables, TRUE);
|
||||
mysql_ha_close_table(hash_tables, TRUE);
|
||||
}
|
||||
|
||||
DBUG_VOID_RETURN;
|
||||
|
|
@ -824,14 +973,14 @@ void mysql_ha_flush(THD *thd)
|
|||
|
||||
void mysql_ha_cleanup(THD *thd)
|
||||
{
|
||||
TABLE_LIST *hash_tables;
|
||||
SQL_HANDLER *hash_tables;
|
||||
DBUG_ENTER("mysql_ha_cleanup");
|
||||
|
||||
for (uint i= 0; i < thd->handler_tables_hash.records; i++)
|
||||
{
|
||||
hash_tables= (TABLE_LIST*) hash_element(&thd->handler_tables_hash, i);
|
||||
hash_tables= (SQL_HANDLER*) hash_element(&thd->handler_tables_hash, i);
|
||||
if (hash_tables->table)
|
||||
mysql_ha_close_table(thd, hash_tables, FALSE);
|
||||
mysql_ha_close_table(hash_tables, FALSE);
|
||||
}
|
||||
|
||||
hash_free(&thd->handler_tables_hash);
|
||||
|
|
|
|||
61
sql/sql_handler.h
Normal file
61
sql/sql_handler.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/* Copyright (C) 2010 Monty Program Ab
|
||||
This program is free software; you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation; version 2 of the License.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||
|
||||
#ifdef USE_PRAGMA_INTERFACE
|
||||
#pragma interface /* gcc class implementation */
|
||||
#endif
|
||||
|
||||
/* Open handlers are stored here */
|
||||
|
||||
class SQL_HANDLER {
|
||||
public:
|
||||
TABLE *table;
|
||||
List<Item> fields; /* Fields, set on open */
|
||||
THD *thd;
|
||||
LEX_STRING handler_name;
|
||||
LEX_STRING db;
|
||||
LEX_STRING table_name;
|
||||
MEM_ROOT mem_root;
|
||||
MYSQL_LOCK *lock;
|
||||
|
||||
key_part_map keypart_map;
|
||||
int keyno; /* Used key */
|
||||
uint key_len;
|
||||
enum enum_ha_read_modes mode;
|
||||
|
||||
/* This is only used when deleting many handler objects */
|
||||
SQL_HANDLER *next;
|
||||
|
||||
Query_arena arena;
|
||||
char *base_data;
|
||||
SQL_HANDLER(THD *thd_arg) :
|
||||
thd(thd_arg), arena(&mem_root, Query_arena::INITIALIZED)
|
||||
{ init(); clear_alloc_root(&mem_root); base_data= 0; }
|
||||
void init() { keyno= -1; table= 0; lock= 0; }
|
||||
void reset();
|
||||
|
||||
~SQL_HANDLER();
|
||||
};
|
||||
|
||||
bool mysql_ha_open(THD *thd, TABLE_LIST *tables, SQL_HANDLER *reopen);
|
||||
bool mysql_ha_close(THD *thd, TABLE_LIST *tables);
|
||||
bool mysql_ha_read(THD *, TABLE_LIST *,enum enum_ha_read_modes,char *,
|
||||
List<Item> *,enum ha_rkey_function,Item *,ha_rows,ha_rows);
|
||||
void mysql_ha_flush(THD *thd);
|
||||
void mysql_ha_rm_tables(THD *thd, TABLE_LIST *tables, bool is_locked);
|
||||
void mysql_ha_cleanup(THD *thd);
|
||||
|
||||
SQL_HANDLER *mysql_ha_read_prepare(THD *thd, TABLE_LIST *tables,
|
||||
enum enum_ha_read_modes mode, char *keyname,
|
||||
List<Item> *key_expr, Item *cond);
|
||||
|
|
@ -28,6 +28,7 @@
|
|||
#include "events.h"
|
||||
#include "sql_trigger.h"
|
||||
#include "debug_sync.h"
|
||||
#include "sql_handler.h"
|
||||
|
||||
#ifdef WITH_ARIA_STORAGE_ENGINE
|
||||
#include "../storage/maria/ha_maria.h"
|
||||
|
|
|
|||
|
|
@ -95,6 +95,7 @@ When one supplies long data for a placeholder:
|
|||
#else
|
||||
#include <mysql_com.h>
|
||||
#endif
|
||||
#include "sql_handler.h"
|
||||
|
||||
/**
|
||||
A result class used to send cursor rows using the binary protocol.
|
||||
|
|
@ -243,6 +244,8 @@ static bool send_prep_stmt(Prepared_statement *stmt, uint columns)
|
|||
int error;
|
||||
THD *thd= stmt->thd;
|
||||
DBUG_ENTER("send_prep_stmt");
|
||||
DBUG_PRINT("enter",("stmt->id: %lu columns: %d param_count: %d",
|
||||
stmt->id, columns, stmt->param_count));
|
||||
|
||||
buff[0]= 0; /* OK packet indicator */
|
||||
int4store(buff+1, stmt->id);
|
||||
|
|
@ -1835,6 +1838,56 @@ static bool mysql_test_insert_select(Prepared_statement *stmt,
|
|||
return res;
|
||||
}
|
||||
|
||||
/**
|
||||
Validate SELECT statement.
|
||||
|
||||
In case of success, if this query is not EXPLAIN, send column list info
|
||||
back to the client.
|
||||
|
||||
@param stmt prepared statement
|
||||
@param tables list of tables used in the query
|
||||
|
||||
@retval 0 success
|
||||
@retval 1 error, error message is set in THD
|
||||
@retval 2 success, and statement metadata has been sent
|
||||
*/
|
||||
|
||||
static int mysql_test_handler_read(Prepared_statement *stmt,
|
||||
TABLE_LIST *tables)
|
||||
{
|
||||
THD *thd= stmt->thd;
|
||||
LEX *lex= stmt->lex;
|
||||
SQL_HANDLER *ha_table;
|
||||
DBUG_ENTER("mysql_test_select");
|
||||
|
||||
lex->select_lex.context.resolve_in_select_list= TRUE;
|
||||
|
||||
/*
|
||||
We don't have to test for permissions as this is already done during
|
||||
HANDLER OPEN
|
||||
*/
|
||||
if (!(ha_table= mysql_ha_read_prepare(thd, tables, lex->ha_read_mode,
|
||||
lex->ident.str,
|
||||
lex->insert_list,
|
||||
lex->select_lex.where)))
|
||||
DBUG_RETURN(1);
|
||||
|
||||
if (!stmt->is_sql_prepare())
|
||||
{
|
||||
if (!lex->result && !(lex->result= new (stmt->mem_root) select_send))
|
||||
{
|
||||
my_error(ER_OUTOFMEMORY, MYF(0), sizeof(select_send));
|
||||
DBUG_RETURN(1);
|
||||
}
|
||||
if (send_prep_stmt(stmt, ha_table->fields.elements) ||
|
||||
lex->result->send_fields(ha_table->fields, Protocol::SEND_EOF) ||
|
||||
thd->protocol->flush())
|
||||
DBUG_RETURN(1);
|
||||
DBUG_RETURN(2);
|
||||
}
|
||||
DBUG_RETURN(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
Perform semantic analysis of the parsed tree and send a response packet
|
||||
|
|
@ -1949,6 +2002,14 @@ static bool check_prepared_statement(Prepared_statement *stmt)
|
|||
res= mysql_test_insert_select(stmt, tables);
|
||||
break;
|
||||
|
||||
case SQLCOM_HA_READ:
|
||||
res= mysql_test_handler_read(stmt, tables);
|
||||
{
|
||||
/* Statement and field info has already been sent */
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
Note that we don't need to have cases in this list if they are
|
||||
marked with CF_STATUS_COMMAND in sql_command_flags
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
|
||||
#include "mysql_priv.h"
|
||||
#include "sql_trigger.h"
|
||||
|
||||
#include "sql_handler.h"
|
||||
|
||||
static TABLE_LIST *rename_tables(THD *thd, TABLE_LIST *table_list,
|
||||
bool skip_error);
|
||||
|
|
|
|||
|
|
@ -1942,8 +1942,7 @@ void mysqld_list_processes(THD *thd,const char *user, bool verbose)
|
|||
pthread_mutex_lock(&mysys_var->mutex);
|
||||
thd_info->proc_info= (char*) (tmp->killed == THD::KILL_CONNECTION? "Killed" : 0);
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
thd_info->state_info= (char*) (tmp->locked ? "Locked" :
|
||||
tmp->net.reading_or_writing ?
|
||||
thd_info->state_info= (char*) (tmp->net.reading_or_writing ?
|
||||
(tmp->net.reading_or_writing == 2 ?
|
||||
"Writing to net" :
|
||||
thd_info->command == COM_SLEEP ? "" :
|
||||
|
|
@ -2068,8 +2067,7 @@ int fill_schema_processlist(THD* thd, TABLE_LIST* tables, COND* cond)
|
|||
table->field[5]->store(utime / 1000000, TRUE);
|
||||
/* STATE */
|
||||
#ifndef EMBEDDED_LIBRARY
|
||||
val= (char*) (tmp->locked ? "Locked" :
|
||||
tmp->net.reading_or_writing ?
|
||||
val= (char*) (tmp->net.reading_or_writing ?
|
||||
(tmp->net.reading_or_writing == 2 ?
|
||||
"Writing to net" :
|
||||
tmp->command == COM_SLEEP ? "" :
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@
|
|||
#include "sql_trigger.h"
|
||||
#include "sql_show.h"
|
||||
#include "debug_sync.h"
|
||||
#include "sql_handler.h"
|
||||
|
||||
#ifdef __WIN__
|
||||
#include <io.h>
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@
|
|||
#include "sp_head.h"
|
||||
#include "sql_trigger.h"
|
||||
#include "parse_file.h"
|
||||
#include "sql_handler.h"
|
||||
|
||||
/*************************************************************************/
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue